Coverage for professional_python_exercises_2_githubcli\github_cli.py: 31%

113 statements  

« prev     ^ index     » next       coverage.py v6.5.0, created at 2022-11-05 16:48 +0100

1import os 

2import sys 

3import json 

4from typing import Optional 

5import dotenv 

6from github import Github 

7from github.NamedUser import NamedUser 

8import typer 

9import requests 

10 

11app = typer.Typer() 

12 

13 

14def get_user_form_input() -> NamedUser: 

15 """ 

16 Method used in the app commands to get the user from user input: 

17 

18 Returns: 

19 user : NamedUser 

20 """ 

21 name = input("User: ") 

22 if name == "": 

23 typer.echo("Empty Value inputted, try again") 

24 sys.exit("Failed to get user input") 

25 token = get_github_token() 

26 github_session = Github(token) 

27 if github_session.search_users(name).totalCount == 0: 

28 typer.echo("User not found, please try again.") 

29 sys.exit("Failed to find user.") 

30 user = github_session.get_user(name) 

31 return user 

32 

33 

34@app.command() 

35def countstars(json_format: Optional[bool] = False) -> int: 

36 """ 

37 Counts the stars of a specified user and gives a nice comment to the user 

38 

39 Parameters: 

40 json_format : Optional[bool] = False 

41 decides wether json or plain text format is required 

42 

43 Returns: 

44 starCount : int 

45 number of stars 

46 """ 

47 typer.echo("Enter user to count stars for.") 

48 user = get_user_form_input() 

49 name = user.name 

50 

51 repositories = user.get_repos() 

52 star_count = 0 

53 for repo in repositories: 

54 stars = repo.stargazers_count 

55 star_count += stars 

56 if json_format: 

57 output = {} 

58 output["username"] = name 

59 output["stars"] = star_count 

60 print(json.dumps(output)) 

61 else: 

62 typer.echo(f"User: {name} has {star_count}⭐ in {repositories.totalCount} repositories.") 

63 typer.echo(_rate_stars_to_repos(star_count, repositories.totalCount)) 

64 return star_count 

65 

66 

67def _rate_stars_to_repos(star_count: int, repository_count: int) -> str: 

68 """ 

69 Rates the star to repository count, a little fun never killed nobody. 

70 

71 Parameters: 

72 star_count : int 

73 the number of stars for the user 

74 repository_count : int 

75 the number of repositories for the user 

76 

77 Returns: 

78 message : str 

79 A message reflecting the rating 

80 """ 

81 

82 if star_count == 0 or repository_count == 0: 

83 return "This poor fellar. Work harder!" 

84 if star_count / repository_count > 100: 

85 return "Greetings, Mr. Starlord" 

86 if star_count / repository_count < 1: 

87 return "Keep doing what you're doing. But do more!" 

88 return "Not bad ey, not bad." 

89 

90 

91@app.command() 

92def getdetails(json_format: Optional[bool] = False) -> json: 

93 """ 

94 Gets the details for a specified user. 

95 

96 Parameters: 

97 json_format: Optional[bool] = False 

98 Decides wether nomal text output or json is required 

99 

100 Returns: 

101 raw : json 

102 Raw details in json format fron the get details request 

103 """ 

104 

105 typer.echo("Enter user to get details for.") 

106 user = get_user_form_input() 

107 name = user.name 

108 typer.echo(f"Getting the detials for: {name}") 

109 

110 bio = user.bio 

111 repocount = user.get_repos().totalCount 

112 star_count = 0 

113 for repo in user.get_repos(): 

114 stars = repo.stargazers_count 

115 star_count += stars 

116 followers = user.get_followers() 

117 following = user.get_following() 

118 blog = user.blog 

119 company = user.company 

120 contributions = user.contributions 

121 created = user.created_at 

122 email = user.email 

123 organizations = user.get_orgs() 

124 avatar_url = user.avatar_url 

125 starred = user.get_starred() 

126 subs = user.get_subscriptions() 

127 watched = user.get_watched() 

128 location = user.location 

129 hireable = user.hireable 

130 

131 raw = user.raw_data 

132 

133 if json_format: 

134 print(raw) 

135 else: 

136 typer.echo(f"Details about user:{user}, created at {created}, bio: {bio}") 

137 typer.echo( 

138 f"Stars: {star_count}, repos: {repocount}, followers: {followers.totalCount}" 

139 f", following: {following.totalCount}" 

140 ) 

141 typer.echo( 

142 f"Contributions: {contributions}, orgs: {organizations.totalCount}," 

143 f" starred: {starred.totalCount}, subs: {subs.totalCount}," 

144 f" watched: {watched.totalCount}" 

145 ) 

146 typer.echo(f"Get a visual impression at:{avatar_url}") 

147 typer.echo(f"The blog: {blog}") 

148 typer.echo(f"Mail: {email}, hireable: {hireable}, location: {location}, company: {company}") 

149 return raw 

150 

151 

152@app.command() 

153def setstatus() -> bool: 

154 """ 

155 Sets the status to something related to this repository: Drinking tea. 

156 Returns: 

157 success : bool 

158 success if successful status change could be accomplished 

159 """ 

160 

161 mutation = """mutation { 

162 changeUserStatus(input:{emoji:":tea:", message:"Drinking tea"}) { 

163 status{ 

164 emoji 

165 message 

166 } 

167 } 

168 } 

169 """ 

170 headers = {"Authorization": f"token {get_github_token()}"} 

171 request = requests.post( 

172 "https://api.github.com/graphql", json={"query": mutation}, headers=headers, timeout=30 

173 ) 

174 if request.status_code == 200: 

175 typer.echo("Success") 

176 return True 

177 typer.echo(f"Mutation failed to run by returning code of {request.status_code}. {mutation}") 

178 return False 

179 

180 

181def get_github_token() -> str: 

182 """ 

183 Checks, if API Key is set as an environment variable. If not, the user is 

184 asked to input it in the console. Length checks enabled for the API key. If 

185 key has non-valid length (!=32) the user is asked again to enter a valid key. 

186 The key is saved into a local .env file. 

187 Returns: 

188 github_token : str 

189 API Key for the Open Weather Map 

190 """ 

191 

192 dotenv_file = dotenv.find_dotenv() 

193 if dotenv_file == "": 

194 with open(os.getcwd() + "\\.env", mode="w", encoding="utf-8").close(): 

195 pass 

196 dotenv_file = dotenv.find_dotenv() 

197 dotenv.load_dotenv(dotenv_file) 

198 

199 if "TNT_EX2_GITHUB_TOKEN" not in os.environ: 

200 print( 

201 "No API Key found in your environment variables. \nPlease look at " 

202 "https://github.com/settings/tokens for getting an API key and enter " 

203 "it in the following line:", 

204 file=sys.stderr, 

205 ) 

206 os.environ["TNT_EX2_GITHUB_TOKEN"] = input("Please enter your API Key now: \n-->").strip() 

207 api_key = os.environ["TNT_EX2_GITHUB_TOKEN"] 

208 if len(api_key) != 40: 

209 print( 

210 "Wrong sized GitHub Accoss Token inputted (correct length: 40), " 

211 f"key found: {api_key}, \nplease look at https://github.com/settings/tokens " 

212 "for getting an API key and enter it in the following line:", 

213 file=sys.stderr, 

214 ) 

215 os.environ["TNT_EX2_GITHUB_TOKEN"] = input("Please enter your API Key now:\n-->").strip() 

216 return get_github_token() 

217 

218 dotenv.set_key(dotenv_file, "TNT_EX2_GITHUB_TOKEN", api_key) # save the API key to .env file 

219 return api_key 

220 

221 

222if __name__ == "__main__": 

223 app()