MIL-002 Lecture steps: URL paths, HTML, decorators, authentication #24

Merged
Tirsvad merged 3 commits from mil-002-lecture-steps into main 2026-11-06 05:47:50 +01:00
4 changed files with 104 additions and 81 deletions
Showing only changes of commit 34e376bea2 - Show all commits

No files matched your search

@@ -4,11 +4,47 @@
converter. converter.
""" """
from flask import Flask from flask import Blueprint, Flask
from markupsafe import escape from markupsafe import escape
from higher_lower.constants import HOST, PORT from higher_lower.constants import HOST, PORT
## Blueprint that holds the views of this lecture step.
_blueprint = Blueprint("step_02_url_paths", __name__)
@_blueprint.route("/")
def home() -> str:
"""Answer the home route."""
return "Hello, World!"
@_blueprint.route("/bye")
def say_bye() -> str:
"""Answer the fixed route /bye."""
return "Bye"
@_blueprint.route("/username/<name>")
def greet(name: str) -> str:
"""Greet the user whose name is the variable section of the URL.
@param name The text found in the URL after /username/.
@return The greeting, with the name escaped so it cannot inject HTML.
"""
return f"Hello there {escape(name)}!"
@_blueprint.route("/username/<name>/<int:number>")
def greet_with_number(name: str, number: int) -> str:
"""Greet the user and use the converter <int:number> for a number.
@param name The text found in the URL after /username/.
@param number The integer found after the name; other text gives 404.
@return The greeting that repeats the name and the number.
"""
return f"Hello there {escape(name)}, you are {number} years old!"
def create_app() -> Flask: def create_app() -> Flask:
"""Build the Flask application of this lecture step. """Build the Flask application of this lecture step.
@@ -16,36 +52,7 @@ def create_app() -> Flask:
@return The configured Flask application. @return The configured Flask application.
""" """
app = Flask(__name__) app = Flask(__name__)
app.register_blueprint(_blueprint)
@app.route("/")
def home() -> str:
"""Answer the home route."""
return "Hello, World!"
@app.route("/bye")
def say_bye() -> str:
"""Answer the fixed route /bye."""
return "Bye"
@app.route("/username/<name>")
def greet(name: str) -> str:
"""Greet the user whose name is the variable section of the URL.
@param name The text found in the URL after /username/.
@return The greeting, with the name escaped so it cannot inject HTML.
"""
return f"Hello there {escape(name)}!"
@app.route("/username/<name>/<int:number>")
def greet_with_number(name: str, number: int) -> str:
"""Greet the user and use the converter <int:number> for a number.
@param name The text found in the URL after /username/.
@param number The integer found after the name; other text gives 404.
@return The greeting that repeats the name and the number.
"""
return f"Hello there {escape(name)}, you are {number} years old!"
return app return app
@@ -3,7 +3,7 @@
@brief A route that returns a heading, a paragraph and two images as HTML. @brief A route that returns a heading, a paragraph and two images as HTML.
""" """
from flask import Flask from flask import Blueprint, Flask
from higher_lower.constants import HOST, LECTURE_IMAGE_WIDTH, PORT, STILL_IMAGE from higher_lower.constants import HOST, LECTURE_IMAGE_WIDTH, PORT, STILL_IMAGE
@@ -11,29 +11,34 @@ from higher_lower.constants import HOST, LECTURE_IMAGE_WIDTH, PORT, STILL_IMAGE
ANIMATED_IMAGE: str = STILL_IMAGE.replace("_s.gif", ".gif") ANIMATED_IMAGE: str = STILL_IMAGE.replace("_s.gif", ".gif")
## Blueprint that holds the views of this lecture step.
_blueprint = Blueprint("step_03_html", __name__)
@_blueprint.route("/")
def home() -> str:
"""Return structured HTML instead of a plain string.
The Python string uses double quotes and the HTML attributes use single
quotes, so the two never end each other.
@return A centred heading, a paragraph, a still picture and a GIF.
"""
return (
"<h1 style='text-align: center'>Hello, World!</h1>"
"<p>This is a paragraph.</p>"
f"<img src='{STILL_IMAGE}' width={LECTURE_IMAGE_WIDTH}>"
f"<img src='{ANIMATED_IMAGE}' width={LECTURE_IMAGE_WIDTH}>"
)
def create_app() -> Flask: def create_app() -> Flask:
"""Build the Flask application of this lecture step. """Build the Flask application of this lecture step.
@return The configured Flask application. @return The configured Flask application.
""" """
app = Flask(__name__) app = Flask(__name__)
app.register_blueprint(_blueprint)
@app.route("/")
def home() -> str:
"""Return structured HTML instead of a plain string.
The Python string uses double quotes and the HTML attributes use single
quotes, so the two never end each other.
@return A centred heading, a paragraph, a still picture and a GIF.
"""
return (
"<h1 style='text-align: center'>Hello, World!</h1>"
"<p>This is a paragraph.</p>"
f"<img src='{STILL_IMAGE}' width={LECTURE_IMAGE_WIDTH}>"
f"<img src='{ANIMATED_IMAGE}' width={LECTURE_IMAGE_WIDTH}>"
)
return app return app
@@ -7,7 +7,7 @@ the /bye route.
from collections.abc import Callable from collections.abc import Callable
from functools import wraps from functools import wraps
from flask import Flask from flask import Blueprint, Flask
from higher_lower.constants import HOST, PORT from higher_lower.constants import HOST, PORT
@@ -54,26 +54,32 @@ def make_underlined(function: Callable[..., str]) -> Callable[..., str]:
return _wrap_in_tag(function, "u") return _wrap_in_tag(function, "u")
## Blueprint that holds the views of this lecture step.
_blueprint = Blueprint("step_04_decorators", __name__)
@_blueprint.route("/")
def home() -> str:
"""Answer the home route."""
return "Hello, World!"
@_blueprint.route("/bye")
@make_bold
@make_emphasis
@make_underlined
def say_bye() -> str:
"""Answer /bye with bold, emphasised and underlined text."""
return "Bye"
def create_app() -> Flask: def create_app() -> Flask:
"""Build the Flask application of this lecture step. """Build the Flask application of this lecture step.
@return The configured Flask application. @return The configured Flask application.
""" """
app = Flask(__name__) app = Flask(__name__)
app.register_blueprint(_blueprint)
@app.route("/")
def home() -> str:
"""Answer the home route."""
return "Hello, World!"
@app.route("/bye")
@make_bold
@make_emphasis
@make_underlined
def say_bye() -> str:
"""Answer /bye with bold, emphasised and underlined text."""
return "Bye"
return app return app
@@ -7,7 +7,7 @@ only for a logged-in user.
from collections.abc import Callable from collections.abc import Callable
from functools import wraps from functools import wraps
from flask import Flask from flask import Blueprint, Flask
from markupsafe import escape from markupsafe import escape
from higher_lower.constants import HOST, PORT from higher_lower.constants import HOST, PORT
@@ -57,28 +57,33 @@ def create_blog_post(user: User) -> str:
return f"This is {user.name}'s new blog post." return f"This is {user.name}'s new blog post."
## Blueprint that holds the views of this lecture step.
_blueprint = Blueprint("step_05_authenticated", __name__)
@_blueprint.route("/")
def home() -> str:
"""Show the result of create_blog_post for a user in and out."""
lines = []
for name, logged_in in (("Angela", True), ("Bob", False)):
user = User(name)
user.is_logged_in = logged_in
state = "logged in" if logged_in else "logged out"
post = create_blog_post(user)
lines.append(
f"<p>{escape(name)} is {state}: "
f"{escape(post) if post else 'no post created'}</p>"
)
return "<h1>is_authenticated</h1>" + "".join(lines)
def create_app() -> Flask: def create_app() -> Flask:
"""Build the Flask application of this lecture step. """Build the Flask application of this lecture step.
@return The configured Flask application. @return The configured Flask application.
""" """
app = Flask(__name__) app = Flask(__name__)
app.register_blueprint(_blueprint)
@app.route("/")
def home() -> str:
"""Show the result of create_blog_post for a user in and out."""
lines = []
for name, logged_in in (("Angela", True), ("Bob", False)):
user = User(name)
user.is_logged_in = logged_in
state = "logged in" if logged_in else "logged out"
post = create_blog_post(user)
lines.append(
f"<p>{escape(name)} is {state}: "
f"{escape(post) if post else 'no post created'}</p>"
)
return "<h1>is_authenticated</h1>" + "".join(lines)
return app return app