Skip to content

Commit 65c9882

Browse files
committed
final exercise files
1 parent 3631ac6 commit 65c9882

File tree

17 files changed

+565
-0
lines changed

17 files changed

+565
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
class GitHubRepo:
2+
3+
def __init__(self, name, language, num_stars):
4+
self.name = name
5+
self.language = language
6+
self.num_stars = num_stars
7+
8+
def __str__(self):
9+
return f"-> {self.name} is a {self.language} repo with {self.num_stars} stars."
10+
11+
def __repr__(self):
12+
return f'GitHubRepo({self.name}, {self.language}, {self.num_stars})'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
"""
2+
GitHub API Application: Custom Exception Classes
3+
"""
4+
5+
class GitHubApiException(Exception):
6+
7+
def __init__(self, status_code):
8+
if status_code == 403:
9+
message = "Rate limit reached. Please wait a minute and try again."
10+
else:
11+
message = f"HTTP Status Code was: {status_code}."
12+
13+
super().__init__(message)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
#!/usr/bin/env python3
2+
3+
"""
4+
A small command line Python program that uses the GitHub search API to list
5+
the top projects by language, based on stars.
6+
7+
GitHub Search API documentation: https://developer.github.com/v3/search/
8+
9+
Requests to this endpoint are rate limited to 10 requests per
10+
minute per IP address.
11+
"""
12+
13+
import sys
14+
import requests
15+
16+
17+
GITHUB_API_URL = "https://api.github.com/search/repositories"
18+
19+
20+
class GitHubApiException(Exception):
21+
22+
def __init__(self, status_code):
23+
if status_code == 403:
24+
message = "Rate limit reached. Please wait a minute and try again."
25+
else:
26+
message = f"HTTP Status Code was: {status_code}."
27+
28+
super().__init__("A GitHub API Error Occurred: " + message)
29+
30+
31+
class GitHubRepo:
32+
"""
33+
A class used to represent a single GitHub Repository.
34+
"""
35+
36+
def __init__(self, name, language, num_stars):
37+
self.name = name
38+
self.language = language
39+
self.num_stars = num_stars
40+
41+
def __str__(self):
42+
return f"-> {self.name} is a {self.language} repo with {self.num_stars} stars."
43+
44+
def __repr__(self):
45+
return f'GitHubRepo({self.name}, {self.language}, {self.num_stars})'
46+
47+
48+
def create_query(languages, min_stars):
49+
"""
50+
Create the query string for the GitHub search API,
51+
based on the minimum amount of stars for a project, and
52+
the provided programming languages.
53+
"""
54+
# Notice we are calling .strip() on each language, to clear it of leading
55+
# and trailing whitespace
56+
query = " ".join(f"language:{language.strip()}" for language in languages)
57+
query = query + f" stars:>{min_stars}"
58+
return query
59+
60+
61+
def repos_with_most_stars(languages, min_stars=50000, sort="stars", order="desc"):
62+
query = create_query(languages, min_stars)
63+
parameters = {"q": query, "sort": sort, "order": order}
64+
response = requests.get(GITHUB_API_URL, params=parameters)
65+
66+
if response.status_code != 200:
67+
raise GitHubApiException(response.status_code)
68+
69+
response_json = response.json()
70+
items = response_json["items"]
71+
return [GitHubRepo(item["name"], item["language"], item["stargazers_count"]) for item in items]
72+
73+
74+
if __name__ == "__main__":
75+
# Accept an optional argument for minimum number of stars from the command line
76+
# $ ./gh_api 100000 # means an input of 100,000 minimum stars.
77+
script_arguments = sys.argv
78+
min_stars = 50000
79+
80+
if len(script_arguments) >= 2:
81+
try:
82+
min_stars = int(script_arguments[1])
83+
except ValueError:
84+
sys.exit("Error: Command line argument must be a valid number.")
85+
86+
# Accept the list of languages from the user, or provide a default list.
87+
languages = input(
88+
"Enter a comma separated list of programming languages (or press ENTER for defaults): "
89+
).strip()
90+
if not languages:
91+
languages = ["python", "javascript", "ruby"]
92+
else:
93+
languages = languages.split(",")
94+
95+
# Get the results
96+
result_repos = repos_with_most_stars(languages=languages, min_stars=min_stars)
97+
if not result_repos:
98+
print("No Results Found.")
99+
else:
100+
for repo in result_repos:
101+
print(repo)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
"""
2+
A Simple Flask Web Application interface
3+
For viewing popular GitHub Repos sorted by stars using the
4+
GitHub Search API.
5+
6+
To run:
7+
(env) $ python -m pip install -r requirements.txt
8+
(env) $ export FLASK_ENV=development; python3 -m flask run
9+
"""
10+
from flask import Flask, render_template, request
11+
12+
from repos.api import repos_with_most_stars
13+
from repos.exceptions import GitHubApiException
14+
15+
app = Flask(__name__)
16+
17+
available_languages = ["Python", "JavaScript", "Ruby", "Java"]
18+
19+
20+
@app.route('/', methods=['POST', 'GET'])
21+
def index():
22+
if request.method == 'GET':
23+
# Use the list of all languages
24+
selected_languages = available_languages
25+
elif request.method == 'POST':
26+
# Use the languages we selected in the request form
27+
selected_languages = request.form.getlist("languages")
28+
29+
results = repos_with_most_stars(selected_languages)
30+
31+
return render_template(
32+
'index.html',
33+
selected_languages=selected_languages,
34+
available_languages=available_languages,
35+
results=results)
36+
37+
38+
@app.errorhandler(GitHubApiException)
39+
def handle_api_error(error):
40+
return render_template('error.html', message=error)

pyworkshop/2_intermediate_python/chapter8/repos/__init__.py

Whitespace-only changes.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import requests
2+
3+
from repos.exceptions import GitHubApiException
4+
from repos.models import GitHubRepo
5+
6+
7+
GITHUB_API_URL = "https://api.github.com/search/repositories"
8+
9+
10+
def create_query(languages, min_stars):
11+
"""
12+
Create the query string for the GitHub search API,
13+
based on the minimum amount of stars for a project, and
14+
the provided programming languages.
15+
"""
16+
# Notice we are calling .strip() on each language,
17+
# to clear it of leading and trailing whitespace
18+
query = " ".join(f"language:{language.strip()}" for language in languages)
19+
query = query + f" stars:>{min_stars}"
20+
return query
21+
22+
23+
def repos_with_most_stars(languages, min_stars=40000, sort="stars", order="desc"):
24+
query = create_query(languages, min_stars)
25+
parameters = {"q": query, "sort": sort, "order": order}
26+
print(parameters)
27+
response = requests.get(GITHUB_API_URL, params=parameters)
28+
29+
if response.status_code != 200:
30+
raise GitHubApiException(response.status_code)
31+
32+
response_json = response.json()
33+
items = response_json["items"]
34+
return [GitHubRepo(item["name"], item["language"], item["stargazers_count"]) for item in items]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
"""
2+
GitHub API Application: Custom Exception Classes
3+
"""
4+
5+
class GitHubApiException(Exception):
6+
7+
def __init__(self, status_code):
8+
if status_code == 403:
9+
message = "Rate limit reached. Please wait a minute and try again."
10+
else:
11+
message = f"HTTP Status Code was: {status_code}."
12+
13+
super().__init__("A GitHub API Error Occurred: " + message)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
"""
2+
GitHub API Application: Custom Model Classes
3+
"""
4+
5+
class GitHubRepo:
6+
"""
7+
A class used to represent a single GitHub Repository.
8+
"""
9+
10+
def __init__(self, name, language, num_stars):
11+
self.name = name
12+
self.language = language
13+
self.num_stars = num_stars
14+
15+
def __str__(self):
16+
return f"-> {self.name} is a {self.language} repo with {self.num_stars} stars."
17+
18+
def __repr__(self):
19+
return f'GitHubRepo({self.name}, {self.language}, {self.num_stars})'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
flask
2+
requests
Loading

0 commit comments

Comments
 (0)