Skip to content

Commit f2b32b9

Browse files
committed
Starter code for chapter 7, infinite scroll.
1 parent 36d0869 commit f2b32b9

140 files changed

Lines changed: 50488 additions & 0 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

code/ch7_infinite_scroll/ch7_final_video_collector/.idea/.name

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import sys
2+
3+
import flask
4+
import jinja_partials
5+
6+
from services import video_service
7+
8+
app = flask.Flask("app")
9+
10+
11+
def configure():
12+
print("Configuring Flask app:")
13+
14+
register_template_ops()
15+
print("Registered template helpers")
16+
17+
register_blueprints()
18+
print("Registered blueprints")
19+
20+
setup_db()
21+
print("DB setup completed.")
22+
print("", flush=True)
23+
24+
25+
def register_template_ops():
26+
jinja_partials.register_extensions(app)
27+
helpers = {
28+
'len': len,
29+
'isinstance': isinstance,
30+
'str': str,
31+
'type': type
32+
}
33+
app.jinja_env.globals.update(**helpers)
34+
35+
36+
def register_blueprints():
37+
from views import home
38+
from views import videos
39+
from views import feed
40+
41+
app.register_blueprint(home.blueprint)
42+
app.register_blueprint(videos.blueprint)
43+
app.register_blueprint(feed.blueprint)
44+
45+
46+
def setup_db():
47+
video_service.load_data()
48+
49+
50+
if __name__ == '__main__':
51+
configure()
52+
being_debugged = sys.gettrace() is not None
53+
app.run(debug=being_debugged)
54+
else:
55+
configure()
Lines changed: 256 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,256 @@
1+
[
2+
{
3+
"category": "Python",
4+
"image": "python.jpg",
5+
"videos": [
6+
{
7+
"id": "rDYKZG6Fn8o",
8+
"title": "Go Python, Go!",
9+
"url": "https://www.youtube.com/watch?v=rDYKZG6Fn8o",
10+
"author": "Python Bytes",
11+
"views": 347
12+
},
13+
{
14+
"id": "QltSJUlHbpw",
15+
"title": "A Space Filled Episode with Dr. Becky",
16+
"url": "https://www.youtube.com/watch?v=QltSJUlHbpw",
17+
"author": "Python Bytes",
18+
"views": 365
19+
},
20+
{
21+
"id": "4wjqsPtj2QY",
22+
"title": "HTMX - Clean Dynamic HTML Pages",
23+
"url": "https://www.youtube.com/watch?v=4wjqsPtj2QY",
24+
"author": "Talk Python",
25+
"views": 756
26+
},
27+
{
28+
"id": "cfrUF-UGehk",
29+
"title": "Python and Flask at the US Federal Election Commission",
30+
"url": "https://www.youtube.com/watch?v=cfrUF-UGehk",
31+
"author": "Talk Python",
32+
"views": 511
33+
},
34+
{
35+
"id": "36yw8VC3KU8",
36+
"title": "PyCon: Let's talk Databases in Python: SQLAlchemy and Alembic",
37+
"url": "https://www.youtube.com/watch?v=36yw8VC3KU8",
38+
"author": "Hannah Stepanek",
39+
"views": 10302
40+
},
41+
{
42+
"id": "pvaIi0l1GME",
43+
"title": "What we learned from Papermill to operationalize notebooks",
44+
"url": "https://www.youtube.com/watch?v=pvaIi0l1GME",
45+
"author": "Alan Yu and Vasu Bhog",
46+
"views": 789
47+
},
48+
{
49+
"id": "PnxlHfGdihI",
50+
"title": "A Python Developer Explores Apple's M1",
51+
"url": "https://www.youtube.com/watch?v=PnxlHfGdihI",
52+
"author": "Michael Kennedy",
53+
"views": 4654
54+
}
55+
]
56+
},
57+
{
58+
"category": "Apple",
59+
"image": "apple.jpg",
60+
"videos": [
61+
{
62+
"id": "R5BQ6yhhRJc",
63+
"title": "Andy's Pick & Pull - WWDC 2021",
64+
"url": "https://www.youtube.com/watch?v=R5BQ6yhhRJc",
65+
"author": "MacBreak Weekly",
66+
"views": 13720
67+
},
68+
{
69+
"id": "PnxlHfGdihI",
70+
"title": "A Python Developer Explores Apple's M1",
71+
"url": "https://www.youtube.com/watch?v=PnxlHfGdihI",
72+
"author": "Michael Kennedy",
73+
"views": 4654
74+
},
75+
{
76+
"id": "YisUywtzZK0",
77+
"title": "How Apple Private Relay Kills Data Profiling",
78+
"url": "https://www.youtube.com/watch?v=YisUywtzZK0",
79+
"author": "Rene Ritchie",
80+
"views": 65245
81+
},
82+
{
83+
"id": "vg0AF166eVI",
84+
"title": "Why the M1 Mac is SO FAST — Apple Silicon Explained!",
85+
"url": "https://www.youtube.com/watch?v=vg0AF166eVI",
86+
"author": "Rene Ritchie",
87+
"views": 523014
88+
},
89+
{
90+
"id": "0TD96VTf0Xs",
91+
"title": "WWDC 2021",
92+
"url": "https://www.youtube.com/watch?v=0TD96VTf0Xs",
93+
"author": "Apple",
94+
"views": 6655103
95+
},
96+
{
97+
"id": "4ecN7yGcqcQ",
98+
"title": "M1 iMac Unboxing and Review!",
99+
"url": "https://www.youtube.com/watch?v=4ecN7yGcqcQ",
100+
"author": "iJustine",
101+
"views": 623042
102+
}
103+
]
104+
},
105+
{
106+
"category": "JavaScript",
107+
"image": "javascript.jpg",
108+
"videos": [
109+
{
110+
"id": "4wjqsPtj2QY",
111+
"title": "HTMX - Clean Dynamic HTML Pages",
112+
"url": "https://www.youtube.com/watch?v=4wjqsPtj2QY",
113+
"author": "Talk Python",
114+
"views": 756
115+
},
116+
{
117+
"id": "qZXt1Aom3Cs",
118+
"title": "Vue JS Crash Course 2021",
119+
"url": "https://www.youtube.com/watch?v=qZXt1Aom3Cs",
120+
"author": "Traversy Media",
121+
"views": 265783
122+
},
123+
{
124+
"id": "OrxmtDw4pVI",
125+
"title": "Vue.js: The Documentary",
126+
"url": "https://www.youtube.com/watch?v=OrxmtDw4pVI",
127+
"author": "Honeypot",
128+
"views": 932606
129+
},
130+
{
131+
"id": "m_F8wSZT3QY",
132+
"title": "Wat - JavaScript misadventures",
133+
"url": "https://www.youtube.com/watch?v=3se2-thqf-A",
134+
"author": "Gary Bernhardt",
135+
"views": 866
136+
},
137+
{
138+
"id": "ahCwqrYpIuM",
139+
"title": "TypeScript - The Basics",
140+
"url": "https://www.youtube.com/watch?v=ahCwqrYpIuM",
141+
"author": "Fireship",
142+
"views": 772764
143+
}
144+
]
145+
},
146+
{
147+
"category": "EVs",
148+
"image": "ev.jpg",
149+
"videos": [
150+
{
151+
"id": "6RhtiPefVzM",
152+
"title": "Are Electric Cars Worse For The Environment? Myth Busted",
153+
"url": "https://www.youtube.com/watch?v=6RhtiPefVzM",
154+
"author": "Engineering Explained",
155+
"views": 1753659
156+
},
157+
{
158+
"id": "QMfxJEfb4lw",
159+
"title": "Rivian - Electric Adventure Vehicle",
160+
"url": "https://www.youtube.com/watch?v=QMfxJEfb4lw",
161+
"author": "Fully Charged Show",
162+
"views": 4029696
163+
},
164+
{
165+
"id": "A6RsmzCYB3I",
166+
"title": "New Hyundai Ioniq 5 full review - the 300-mile Tesla EV rival styled by Minecraft",
167+
"url": "https://www.youtube.com/watch?v=A6RsmzCYB3I",
168+
"author": "The Late Brake Show",
169+
"views": 938994
170+
},
171+
{
172+
"id": "QHOPFp1o3d0",
173+
"title": "Bolt: Best Non Tesla Electric Car?",
174+
"url": "https://www.youtube.com/watch?v=QHOPFp1o3d0",
175+
"author": "TheStraightPipes",
176+
"views": 512330
177+
},
178+
{
179+
"id": "3iRHYIwjFKw",
180+
"title": "Tesla Full Self Driving Beta Test Drive",
181+
"url": "https://www.youtube.com/watch?v=3iRHYIwjFKw",
182+
"author": "Tesla Raj",
183+
"views": 367345
184+
},
185+
{
186+
"id": "KOWz9-5T9pE",
187+
"title": "Formula E: 2021 Puebla E-Prix | Round 8",
188+
"url": "https://www.youtube.com/watch?v=KOWz9-5T9pE",
189+
"author": "ABB Formula E",
190+
"views": 43975
191+
}
192+
]
193+
},
194+
{
195+
"category": "Racing",
196+
"image": "racing.jpg",
197+
"videos": [
198+
{
199+
"id": "tvcuGoVhpxw",
200+
"title": "How to Trail Brake: A Step-by-Step Guide",
201+
"url": "https://www.youtube.com/watch?v=tvcuGoVhpxw",
202+
"author": "Driver61",
203+
"views": 210861
204+
},
205+
{
206+
"id": "eUdaWbr1KB4",
207+
"title": "Trail Braking: 5 Mistakes DESTROYING Your Lap Time",
208+
"url": "https://www.youtube.com/watch?v=eUdaWbr1KB4",
209+
"author": "Driver61",
210+
"views": 581747
211+
},
212+
{
213+
"id": "F5igCWjmeAU",
214+
"title": "My Very First Start in IndyCar",
215+
"url": "https://www.youtube.com/watch?v=F5igCWjmeAU",
216+
"author": "Romain Grosjean",
217+
"views": 960145
218+
},
219+
{
220+
"id": "KOWz9-5T9pE",
221+
"title": "Formula E: 2021 Puebla E-Prix | Round 8",
222+
"url": "https://www.youtube.com/watch?v=KOWz9-5T9pE",
223+
"author": "ABB Formula E",
224+
"views": 43975
225+
},
226+
{
227+
"id": "EU73gjQJXU4",
228+
"title": "IndyCar - Road America 2021 Highlights",
229+
"url": "https://www.youtube.com/watch?v=EU73gjQJXU4",
230+
"author": "Motorsports on NBC",
231+
"views": 43295
232+
},
233+
{
234+
"id": "9i2iA0R6IdA",
235+
"title": "The First Corner: Do's and Don'ts",
236+
"url": "https://www.youtube.com/watch?v=9i2iA0R6IdA",
237+
"author": "Driver61",
238+
"views": 46432
239+
},
240+
{
241+
"id": "X0WuN3poyVs",
242+
"title": "Biggest Sim Racing Tips (sim driver analysis)",
243+
"url": "https://www.youtube.com/watch?v=X0WuN3poyVs",
244+
"author": "Driver61",
245+
"views": 78817
246+
},
247+
{
248+
"id": "2wzy3HiW7SE",
249+
"title": "CAN YOU TELL THIS ISN'T REAL? - Corvette C8.R - Nordschleife",
250+
"url": "https://www.youtube.com/watch?v=2wzy3HiW7SE",
251+
"author": "Boosted Media",
252+
"views": 60007
253+
}
254+
]
255+
}
256+
]
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import flask
2+
from werkzeug.datastructures import MultiDict
3+
4+
5+
class RequestDictionary(dict):
6+
def __init__(self, *args, default_val=None, **kwargs):
7+
self.default_val = default_val
8+
super().__init__(*args, **kwargs)
9+
10+
def __getattr__(self, key):
11+
return self.get(key, self.default_val)
12+
13+
14+
def create(default_val=None, **route_args) -> RequestDictionary:
15+
request = flask.request
16+
17+
# Adding this retro actively. Some folks are experiencing issues where they
18+
# are getting a list rather than plain dict. I think it's from multiple
19+
# entries in the multidict. This should fix it.
20+
args = request.args
21+
if isinstance(request.args, MultiDict):
22+
args = request.args.to_dict()
23+
24+
form = request.form
25+
if isinstance(request.args, MultiDict):
26+
form = request.form.to_dict()
27+
28+
data = {
29+
**args, # The key/value pairs in the URL query string
30+
**request.headers, # Header values
31+
**form, # The key/value pairs in the body, from a HTML post form
32+
**route_args # And additional arguments the method access, if they want them merged.
33+
}
34+
35+
return RequestDictionary(data, default_val=default_val)
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
from functools import wraps
2+
3+
import flask
4+
import werkzeug
5+
import werkzeug.wrappers
6+
7+
8+
def response(*, mimetype: str = None, template_file: str = None):
9+
def response_inner(f):
10+
11+
@wraps(f)
12+
def view_method(*args, **kwargs):
13+
response_val = f(*args, **kwargs)
14+
15+
if isinstance(response_val, werkzeug.wrappers.Response):
16+
return response_val
17+
18+
if isinstance(response_val, flask.Response):
19+
return response_val
20+
21+
if isinstance(response_val, dict):
22+
model = dict(response_val)
23+
else:
24+
model = dict()
25+
26+
if template_file and not isinstance(response_val, dict):
27+
raise Exception(
28+
"Invalid return type {}, we expected a dict as the return value.".format(type(response_val)))
29+
30+
if template_file:
31+
response_val = flask.render_template(template_file, **response_val)
32+
33+
resp = flask.make_response(response_val)
34+
resp.model = model
35+
if mimetype:
36+
resp.mimetype = mimetype
37+
38+
return resp
39+
40+
return view_method
41+
42+
return response_inner

0 commit comments

Comments
 (0)