diff --git a/.env.example b/.env.example
index d1e83ee..a87c13c 100644
--- a/.env.example
+++ b/.env.example
@@ -1,7 +1,3 @@
-FLASK_APP=wsgi.py
+ENVIRONMENT=production
FLASK_DEBUG=False
-SECRET_KEY=randomstringofcharacters
-LESS_BIN=/usr/local/bin/lessc
-ASSETS_DEBUG=False
-LESS_RUN_IN_DEBUG=False
-COMPRESSOR_DEBUG=True
\ No newline at end of file
+SECRET_KEY=randomstringofcharacters
\ No newline at end of file
diff --git a/.flake8 b/.flake8
new file mode 100644
index 0000000..00e2b94
--- /dev/null
+++ b/.flake8
@@ -0,0 +1,4 @@
+[flake8]
+select = E9,F63,F7,F82
+exclude = .git,.github,__pycache__,.pytest_cache,.venv,logs,creds
+max-line-length = 120
\ No newline at end of file
diff --git a/.github/workflows/pythonapp.yml b/.github/workflows/pythonapp.yml
index 70bba55..f79bc01 100644
--- a/.github/workflows/pythonapp.yml
+++ b/.github/workflows/pythonapp.yml
@@ -5,32 +5,30 @@ name: Python application
on:
push:
- branches: [ master ]
+ branches: [master]
pull_request:
- branches: [ master ]
+ branches: [master]
jobs:
build:
-
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v2
- - name: Set up Python 3.9
- uses: actions/setup-python@v2
- with:
- python-version: 3.9
- - name: Install dependencies
- run: |
- python -m pip install --upgrade pip
- pip install flake8 pytest
- if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
- - name: Lint with flake8
- run: |
- # stop the build if there are Python syntax errors or undefined names
- flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
- # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
- flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
- - name: Test with pytest
- run: |
- pytest
+ - uses: actions/checkout@v4
+ - uses: actions/setup-python@v5
+ with:
+ python-version: "3.10"
+ cache: "pip" # caching pip dependencies
+
+ - name: Install dependencies
+ run: |
+ python -m pip install --upgrade pip
+ pip install flake8 pytest
+ if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
+
+ - name: Lint with flake8
+ run: |
+ # stop the build if there are Python syntax errors or undefined names
+ flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
+ # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
+ flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
diff --git a/LICENSE b/LICENSE
index b6ae3eb..425c816 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
MIT License
-Copyright (c) 2020 Hackers and Slackers
+Copyright (c) 2023 Hackers and Slackers
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/Makefile b/Makefile
index e96b655..e63ec93 100644
--- a/Makefile
+++ b/Makefile
@@ -30,13 +30,9 @@ $(VIRTUAL_ENV):
python3 -m venv $(VIRTUAL_ENV); \
fi
-.PHONY: dev
-dev: env
- $(LOCAL_PYTHON) -m main --reload
-
.PHONY: run
run: env
- $(LOCAL_PYTHON) -m main
+ $(LOCAL_PYTHON) -m gunicorn -w 4 wsgi:app
.PHONY: install
install: env
diff --git a/README.md b/README.md
index d412399..370fc33 100644
--- a/README.md
+++ b/README.md
@@ -1,8 +1,9 @@
# Flask Blueprint Tutorial
-![Python](https://img.shields.io/badge/Python-v^3.10-blue.svg?logo=python&longCache=true&logoColor=white&colorB=5e81ac&style=flat-square&colorA=4c566a)
-![Flask](https://img.shields.io/badge/Flask-v2.2.2-blue.svg?longCache=true&logo=flask&style=flat-square&logoColor=white&colorB=5e81ac&colorA=4c566a)
-![Flask-Assets](https://img.shields.io/badge/Flask--Assets-v2.0-blue.svg?longCache=true&logo=flask&style=flat-square&logoColor=white&colorB=5e81ac&colorA=4c566a)
+![Python](https://img.shields.io/badge/Python-v3.10-blue.svg?logo=python&longCache=true&logoColor=white&colorB=5e81ac&style=flat-square&colorA=4c566a)
+![Flask](https://img.shields.io/badge/Flask-v3.0.0-blue.svg?longCache=true&logo=flask&style=flat-square&logoColor=white&colorB=5e81ac&colorA=4c566a)
+![Flask-Assets](https://img.shields.io/badge/Flask--Assets-v2.1.0-blue.svg?longCache=true&logo=flask&style=flat-square&logoColor=white&colorB=5e81ac&colorA=4c566a)
+![Gunicorn](https://img.shields.io/badge/Gunicorn-v21.2.0-blue.svg?longCache=true&logo=gunicorn&style=flat-square&logoColor=white&colorB=a3be8c&colorA=4c566a)
![GitHub Last Commit](https://img.shields.io/github/last-commit/google/skia.svg?style=flat-square&colorA=4c566a&colorB=a3be8c&logo=GitHub)
[![GitHub Issues](https://img.shields.io/github/issues/hackersandslackers/flask-blueprint-tutorial.svg?style=flat-square&colorA=4c566a&logo=GitHub&colorB=ebcb8b)](https://github.com/hackersandslackers/flask-blueprint-tutorial/issues)
[![GitHub Stars](https://img.shields.io/github/stars/hackersandslackers/flask-blueprint-tutorial.svg?style=flat-square&colorA=4c566a&logo=GitHub&colorB=ebcb8b)](https://github.com/hackersandslackers/flask-blueprint-tutorial/stargazers)
@@ -13,7 +14,7 @@
Structure your Flask apps in a scalable and intelligent way using Blueprints.
* **Tutorial**: [https://hackersandslackers.com/flask-blueprints/](https://hackersandslackers.com/flask-blueprints/)
-* **Demo**: [https://flaskblueprints.hackersandslackers.app/](https://flaskblueprints.hackersandslackers.app/)
+* **Demo**: [https://flaskblueprints.hackersandslackers.app/](https://flaskblueprints.hackersandslackers.com/)
## Getting Started
@@ -23,13 +24,9 @@ Get set up locally in two steps:
Replace the values in **.env.example** with your values and rename this file to **.env**:
-* `FLASK_APP`: Entry point of your application; should be `wsgi.py`.
-* `FLASK_ENV`: The environment in which to run your application; either `development` or `production`.
+* `ENVIRONMENT`: The environment in which to run your application (either `development` or `production`).
+* `FLASK_DEBUG`: Set to `True` to enable Flask's debug mode (default to `False` in prod).
* `SECRET_KEY`: Randomly generated string of characters used to encrypt your app's data.
-* `LESS_BIN` *(optional for static assets)*: Path to your local LESS installation via `which lessc`.
-* `ASSETS_DEBUG` *(optional)*: Debug asset creation and bundling in `development`.
-* `LESS_RUN_IN_DEBUG` *(optional)*: Debug LESS while in `development`.
-* `COMPRESSOR_DEBUG` *(optional)*: Debug asset compression while in `development`.
*Remember never to commit secrets saved in .env files to Github.*
@@ -40,7 +37,7 @@ Get up and running with `make run`:
```shell
git clone https://github.com/hackersandslackers/flask-blueprint-tutorial.git
cd flask-blueprint-tutorial
-make run
+make deploy
```
-----
diff --git a/config.py b/config.py
index bb0280c..8e596b4 100644
--- a/config.py
+++ b/config.py
@@ -1,31 +1,34 @@
"""Class-based Flask app configuration."""
-from os import environ, path
+from os import environ, path, system
from dotenv import load_dotenv
-basedir = path.abspath(path.dirname(__file__))
-load_dotenv(path.join(basedir, ".env"))
+BASE_DIR = path.abspath(path.dirname(__file__))
+load_dotenv(path.join(BASE_DIR, ".env"))
class Config:
"""Configuration from environment variables."""
+ # General Config\
+ ENVIRONMENT = environ.get("ENVIRONMENT")
+
+ # Flask Config
SECRET_KEY = environ.get("SECRET_KEY")
- FLASK_ENV = environ.get("FLASK_DEBUG")
+ FLASK_DEBUG = environ.get("FLASK_DEBUG")
FLASK_APP = "wsgi.py"
- # Flask-Assets
- LESS_BIN = environ.get("LESS_BIN")
- ASSETS_DEBUG = True
- LESS_RUN_IN_DEBUG = True
-
# Static Assets
STATIC_FOLDER = "static"
TEMPLATES_FOLDER = "templates"
- COMPRESSOR_DEBUG = True
+ COMPRESSOR_DEBUG = False
- # Datadog
- DD_SERVICE = environ.get("DD_SERVICE")
-
- # API
- BEST_BUY_API_KEY = environ.get("BEST_BUY_API_KEY")
+ # Flask-Assets
+ LESS_BIN = system("which lessc")
+ ASSETS_DEBUG = False
+ LESS_RUN_IN_DEBUG = False
+ if ENVIRONMENT == "development" and LESS_BIN is None:
+ raise ValueError("Application running in `development` mode cannot create assets without `lessc` installed.")
+
+ # Hardcoded data
+ PRODUCT_DATA_FILEPATH = f"{BASE_DIR}/data/products.json"
diff --git a/data/products.json b/data/products.json
new file mode 100644
index 0000000..f14f40f
--- /dev/null
+++ b/data/products.json
@@ -0,0 +1,92 @@
+[
+ {
+ "customerReviewAverage": 5.00,
+ "customerReviewCount": 293,
+ "name": "Red Robin - $25 Gift Card",
+ "sku": 4259000,
+ "image": "https://pisces.bbystatic.com/prescaled/500/500/image2/BestBuy_US/images/products/4259/4259000_sd.jpg",
+ "manufacturer": "Red Robin",
+ "longDescription": "Come in and enjoy an outrageously delicious burger with Bottomless Steak Fries. Pair it with a cold beer or signature Freckled Lemonade - it's a duo that's sure to make you smile.",
+ "salePrice": 25.00
+ },
+ {
+ "customerReviewAverage": 5.00,
+ "customerReviewCount": 53,
+ "name": "Bowers & Wilkins - 700 Series 3-way Floorstanding Speaker w/5\" midrange, dual 5\" bass (each) - White",
+ "sku": 6023602,
+ "image": "https://pisces.bbystatic.com/prescaled/500/500/image2/BestBuy_US/images/products/6023/6023602_sd.jpg",
+ "manufacturer": "Bowers & Wilkins",
+ "longDescription": "Generate commanding sound with this Bowers & Wilkins loudspeaker. Its Carbon Dome tweeter plays accurate, clear highs, and the two Aerofoil bass drivers deliver stiffness and rigidity while producing dynamic bass. This vented Bowers & Wilkins loudspeaker has a 5-inch midrange driver to round out its full sound, and its slim construction makes it suitable for small or large spaces.",
+ "salePrice": 1487.99
+ },
+ {
+ "customerReviewAverage": 5.00,
+ "customerReviewCount": 53,
+ "name": "Bowers & Wilkins - 700 Series 3-way Floorstanding Speaker w/5\" midrange, dual 5\" bass (each) - Gloss Black",
+ "sku": 6027601,
+ "image": "https://pisces.bbystatic.com/prescaled/500/500/image2/BestBuy_US/images/products/6027/6027601_sd.jpg",
+ "manufacturer": "Bowers & Wilkins",
+ "longDescription": "Enjoy accurate, realistic sound with this black Bowers & Wilkins floor speaker. Its two bass drivers deliver thumping low frequencies, and the Carbon Dome tweeter and midrange driver offer commanding, studio-quality audio. This Bowers & Wilkins floor speaker integrates into your living space and entertainment system for seamless sound production with a frequency range of 48Hz - 28kHz.",
+ "salePrice": 1487.99
+ },
+ {
+ "customerReviewAverage": 5.00,
+ "customerReviewCount": 55,
+ "name": "Canon - RF50mm F1.2 L USM Standard Prime Lens for EOS R-Series Cameras - Black",
+ "sku": 6298180,
+ "image": "https://pisces.bbystatic.com/prescaled/500/500/image2/BestBuy_US/images/products/6298/6298180_sd.jpg",
+ "manufacturer": "Canon",
+ "longDescription": "Capture high-quality images and sharp details with this 50mm Canon lens. The 1.31-foot minimum focusing distance and 0.19x magnification let you photograph from a range of distances, and its UD lens reduces distortion. This Canon lens has an added coating to minimize lens flare and ghosting in various types of light.",
+ "salePrice": 2199.99
+ },
+ {
+ "customerReviewAverage": 5.00,
+ "customerReviewCount": 83,
+ "name": "Nikkor Z 24-70mm f/2.8 S Optical Zoom Lens for Nikon Z - Black",
+ "sku": 6334316,
+ "image": "https://pisces.bbystatic.com/prescaled/500/500/image2/BestBuy_US/images/products/6334/6334316_sd.jpg",
+ "manufacturer": "Nikon",
+ "longDescription": "Capture high-quality photographs whether shooting at close, medium or long range with this Nikon NIKKOR Z 24-70mm lens. The dust-resistant and drip-resistant design helps keep this lens in good condition, and the auto-focusing feature is quick and quiet. This Nikon NIKKOR Z 24-70mm lens features a Z system that produces images with enhanced sharpness and illumination.",
+ "salePrice": 2099.99
+ },
+ {
+ "customerReviewAverage": 5.00,
+ "customerReviewCount": 64,
+ "name": "Apple Watch Ultra (GPS + Cellular) 49mm Titanium Case with White Ocean Band - Titanium (Verizon)",
+ "sku": 6340050,
+ "image": "https://pisces.bbystatic.com/prescaled/500/500/image2/BestBuy_US/images/products/6340/6340050_sd.jpg",
+ "manufacturer": "Apple",
+ "longDescription": "The most rugged and capable Apple Watch ever, designed for exploration, adventure, and endurance. With a 49mm aerospace-grade titanium case, extra-long battery life,¹ specialized apps that work with the advanced sensors, and a new customizable Action button. See Dimension section below for band sizing information.",
+ "salePrice": 799.99
+ },
+ {
+ "customerReviewAverage": 5.00,
+ "customerReviewCount": 64,
+ "name": "Apple Watch Ultra (GPS + Cellular) 49mm Titanium Case with Yellow Ocean Band - Titanium (Verizon)",
+ "sku": 6340051,
+ "image": "https://pisces.bbystatic.com/prescaled/500/500/image2/BestBuy_US/images/products/6340/6340051_sd.jpg",
+ "manufacturer": "Apple",
+ "longDescription": "The most rugged and capable Apple Watch ever, designed for exploration, adventure, and endurance. With a 49mm aerospace-grade titanium case, extra-long battery life,¹ specialized apps that work with the advanced sensors, and a new customizable Action button. See Dimension section below for band sizing information.",
+ "salePrice": 799.99
+ },
+ {
+ "customerReviewAverage": 5.00,
+ "customerReviewCount": 64,
+ "name": "Apple Watch Ultra (GPS + Cellular) 49mm Titanium Case with Midnight Ocean Band - Titanium (Verizon)",
+ "sku": 6340057,
+ "image": "https://pisces.bbystatic.com/prescaled/500/500/image2/BestBuy_US/images/products/6340/6340057_sd.jpg",
+ "manufacturer": "Apple",
+ "longDescription": "The most rugged and capable Apple Watch ever, designed for exploration, adventure, and endurance. With a 49mm aerospace-grade titanium case, extra-long battery life,¹ specialized apps that work with the advanced sensors, and a new customizable Action button. See Dimension section below for band sizing information.",
+ "salePrice": 799.99
+ },
+ {
+ "customerReviewAverage": 5.00,
+ "customerReviewCount": 59,
+ "name": "NETGEAR - 8-Port 10/100/1000 Gigabit Ethernet PoE/PoE+ Unmanaged Switch",
+ "sku": 6356333,
+ "image": "https://pisces.bbystatic.com/prescaled/500/500/image2/BestBuy_US/images/products/6356/6356333_sd.jpg",
+ "manufacturer": "NETGEAR",
+ "longDescription": "Introducing the NETGEAR GS108LP 8-port Gigabit Ethernet unmanaged switch with 60W PoE budget. The flexible PoE+ integrated technology allows you to increase or decrease the PoE budget at any time to provide to your devices the power they need with interchangeable external power supply and an intuitive power selector. The compact and fanless design makes this switch an ideal solution to connect or power any device in any business environment.",
+ "salePrice": 98.99
+ }
+]
\ No newline at end of file
diff --git a/flask_blueprint_tutorial/__init__.py b/flask_blueprint_tutorial/__init__.py
index 16ffb5a..7b7ef82 100644
--- a/flask_blueprint_tutorial/__init__.py
+++ b/flask_blueprint_tutorial/__init__.py
@@ -2,10 +2,8 @@
from flask import Flask
from flask_assets import Environment
-from config import Config
-
-def init_app():
+def create_app():
"""Create Flask application."""
app = Flask(__name__, instance_relative_config=False)
app.config.from_object("config.Config")
@@ -20,8 +18,8 @@ def init_app():
from .profile import profile
# Register Blueprints
- app.register_blueprint(profile.profile_bp)
- app.register_blueprint(home.home_bp)
+ app.register_blueprint(profile.profile_blueprint)
+ app.register_blueprint(home.home_blueprint)
app.register_blueprint(products.product_bp)
# Compile static assets
diff --git a/flask_blueprint_tutorial/api.py b/flask_blueprint_tutorial/api.py
index f229fb6..4f803c1 100644
--- a/flask_blueprint_tutorial/api.py
+++ b/flask_blueprint_tutorial/api.py
@@ -1,19 +1,18 @@
-"""Source app with worthless data."""
-import requests
+"""Read placeholder data for demo purposes."""
+import json
+from flask import Flask
-def fetch_products(app):
- """Grab product listings from BestBuy."""
- endpoint = "https://api.bestbuy.com/v1/products(customerReviewAverage>=4&customerReviewCount>100&longDescription=*)"
- params = {
- "show": "customerReviewAverage,customerReviewCount,name,sku,image,description,manufacturer,longDescription,salePrice,sku",
- "apiKey": app.config["BEST_BUY_API_KEY"],
- "format": "json",
- "pageSize": 6,
- "totalPages": 1,
- "sort": "customerReviewAverage.dsc",
- }
- headers = {"Accept": "application/json", "Content-Type": "application/json"}
- req = requests.get(endpoint, params=params, headers=headers)
- products = req.json()["products"]
- return products
+
+def fetch_products(app: Flask) -> dict:
+ """
+ Grab hardcoded product listings.
+
+ :param Flask app: Flask application object.
+
+ :returns: dict
+ """
+ product_data_filepath = app.config["PRODUCT_DATA_FILEPATH"]
+ with open(product_data_filepath, encoding="utf-8") as file:
+ products_data = json.load(file)
+ return products_data
diff --git a/flask_blueprint_tutorial/assets.py b/flask_blueprint_tutorial/assets.py
index 10e19f5..fb83aeb 100644
--- a/flask_blueprint_tutorial/assets.py
+++ b/flask_blueprint_tutorial/assets.py
@@ -3,8 +3,14 @@
from flask_assets import Bundle
-def compile_static_assets(assets):
- """Create stylesheet bundles."""
+def compile_static_assets(assets: Bundle) -> Bundle:
+ """
+ Create CSS stylesheet bundles from .less files.
+
+ :param Bundle assets: Static asset bundle.
+
+ :returns: Bundle
+ """
assets.auto_build = True
assets.debug = False
common_style_bundle = Bundle(
@@ -14,19 +20,19 @@ def compile_static_assets(assets):
extra={"rel": "stylesheet/less"},
)
home_style_bundle = Bundle(
- "home_bp/less/home.less",
+ "home_blueprint/less/home.less",
filters="less,cssmin",
output="dist/css/home.css",
extra={"rel": "stylesheet/less"},
)
profile_style_bundle = Bundle(
- "profile_bp/less/profile.less",
+ "profile_blueprint/less/profile.less",
filters="less,cssmin",
output="dist/css/profile.css",
extra={"rel": "stylesheet/less"},
)
product_style_bundle = Bundle(
- "products_bp/less/products.less",
+ "products_blueprint/less/products.less",
filters="less,cssmin",
output="dist/css/products.css",
extra={"rel": "stylesheet/less"},
@@ -35,7 +41,7 @@ def compile_static_assets(assets):
assets.register("home_style_bundle", home_style_bundle)
assets.register("profile_style_bundle", profile_style_bundle)
assets.register("product_style_bundle", product_style_bundle)
- if app.config["FLASK_ENV"] == "development":
+ if app.config["ENVIRONMENT"] == "development":
common_style_bundle.build()
home_style_bundle.build()
profile_style_bundle.build()
diff --git a/flask_blueprint_tutorial/home/home.py b/flask_blueprint_tutorial/home/home.py
index 67b3114..20934c5 100644
--- a/flask_blueprint_tutorial/home/home.py
+++ b/flask_blueprint_tutorial/home/home.py
@@ -6,14 +6,16 @@
from flask_blueprint_tutorial.api import fetch_products
# Blueprint Configuration
-home_bp = Blueprint(
- "home_bp", __name__, template_folder="templates", static_folder="static"
-)
+home_blueprint = Blueprint("home_blueprint", __name__, template_folder="templates", static_folder="static")
-@home_bp.route("/", methods=["GET"])
-def home():
- """Homepage."""
+@home_blueprint.route("/", methods=["GET"])
+def home() -> str:
+ """
+ Serve `Home` page template.
+
+ :returns: str
+ """
products = fetch_products(app)
return render_template(
"index.jinja2",
@@ -24,9 +26,13 @@ def home():
)
-@home_bp.route("/about", methods=["GET"])
-def about():
- """About page."""
+@home_blueprint.route("/about", methods=["GET"])
+def about() -> str:
+ """
+ Serve `About` page template.
+
+ :returns: str
+ """
return render_template(
"index.jinja2",
title="About",
@@ -35,9 +41,13 @@ def about():
)
-@home_bp.route("/contact", methods=["GET"])
-def contact():
- """Contact page."""
+@home_blueprint.route("/contact", methods=["GET"])
+def contact() -> str:
+ """
+ Serve `Contact` page template.
+
+ :returns: str
+ """
return render_template(
"index.jinja2",
title="Contact",
diff --git a/flask_blueprint_tutorial/home/templates/index.jinja2 b/flask_blueprint_tutorial/home/templates/index.jinja2
index fd51f46..4989cb2 100644
--- a/flask_blueprint_tutorial/home/templates/index.jinja2
+++ b/flask_blueprint_tutorial/home/templates/index.jinja2
@@ -13,8 +13,8 @@
{{ title }}
{{ subtitle }}
diff --git a/flask_blueprint_tutorial/products/products.py b/flask_blueprint_tutorial/products/products.py
index 755e426..39884cc 100644
--- a/flask_blueprint_tutorial/products/products.py
+++ b/flask_blueprint_tutorial/products/products.py
@@ -6,14 +6,18 @@
from flask_blueprint_tutorial.api import fetch_products
# Blueprint Configuration
-product_bp = Blueprint(
- "products_bp", __name__, template_folder="templates", static_folder="static"
-)
+product_bp = Blueprint("products_blueprint", __name__, template_folder="templates", static_folder="static")
@product_bp.route("/products//", methods=["GET"])
-def product_page(product_id):
- """Product description page."""
+def product_page(product_id: int) -> str:
+ """
+ Product detail page for a given product ID.
+
+ :params int product_id: Unique product ID.
+
+ :returns: str
+ """
product = fetch_products(app)[product_id]
return render_template(
"products.jinja2",
diff --git a/flask_blueprint_tutorial/profile/profile.py b/flask_blueprint_tutorial/profile/profile.py
index 0d24c4c..2347019 100644
--- a/flask_blueprint_tutorial/profile/profile.py
+++ b/flask_blueprint_tutorial/profile/profile.py
@@ -5,14 +5,16 @@
fake = Faker()
# Blueprint Configuration
-profile_bp = Blueprint(
- "profile_bp", __name__, template_folder="templates", static_folder="static"
-)
+profile_blueprint = Blueprint("profile_blueprint", __name__, template_folder="templates", static_folder="static")
-@profile_bp.route("/profile", methods=["GET"])
-def user_profile():
- """Logged-in user profile page."""
+@profile_blueprint.route("/profile", methods=["GET"])
+def user_profile() -> str:
+ """
+ Logged-in user profile page.
+
+ :returns: str
+ """
user = fake.simple_profile()
job = fake.job()
return render_template(
diff --git a/flask_blueprint_tutorial/static/dist/css/style.css b/flask_blueprint_tutorial/static/dist/css/style.css
index 864a242..b0582ce 100644
--- a/flask_blueprint_tutorial/static/dist/css/style.css
+++ b/flask_blueprint_tutorial/static/dist/css/style.css
@@ -1 +1 @@
-nav{background:#fff;padding:30px;width:auto;margin-bottom:40px;box-shadow:0 0 5px #bec6cf}nav .nav-wrapper{max-width:1014px!important;display:flex;justify-content:space-between;align-items:center;width:auto;margin:0 auto}nav .nav-wrapper .left-nav{display:flex;justify-content:space-between;align-items:center}nav .nav-wrapper .left-nav a{margin-right:40px}@media(max-width:600px){nav .nav-wrapper .left-nav a{margin-right:25px!important}}nav .nav-wrapper .left-nav img{width:30px;margin-right:0}nav .nav-wrapper a{font-weight:600;color:#7d849a}@media(max-width:600px){nav .nav-wrapper a{font-size:.95em}}nav a{color:#4d545d;transition:all .2s ease-out;text-decoration:none;font-size:1.1em}nav a:hover{cursor:pointer;opacity:.7}nav{background:#fff;padding:30px;width:auto;margin-bottom:40px;box-shadow:0 0 5px #bec6cf}nav .nav-wrapper{max-width:1014px!important;display:flex;justify-content:space-between;align-items:center;width:auto;margin:0 auto}nav .nav-wrapper .left-nav{display:flex;justify-content:space-between;align-items:center}nav .nav-wrapper .left-nav a{margin-right:40px}@media(max-width:600px){nav .nav-wrapper .left-nav a{margin-right:25px!important}}nav .nav-wrapper .left-nav img{width:30px;margin-right:0}nav .nav-wrapper a{font-weight:600;color:#7d849a}@media(max-width:600px){nav .nav-wrapper a{font-size:.95em}}nav a{color:#4d545d;transition:all .2s ease-out;text-decoration:none;font-size:1.1em}nav a:hover{cursor:pointer;opacity:.7}body,html{font-family:'Poppins',sans-serif;margin:0;padding:0;background:#f0f0f0;height:100%;color:#5f6988}body .container,html .container{width:948px;max-width:88%;margin:0 auto;height:fit-content;background:white;padding:30px 40px;box-shadow:0 0 5px rgba(65,67,144,0.15)}@media(max-width:800px){body .container,html .container{width:82%;margin:0 auto 20px;padding:30px 6%}}body .container h1,html .container h1{line-height:1;margin:0 0 10px}body .container h2,html .container h2{margin:0;font-weight:400;font-size:1.2em;line-height:1}body .container a,html .container a{color:#5dbad7;transition:all .2s ease-out;text-decoration:none}body .container a:hover,html .container a:hover{cursor:pointer;opacity:.7}body .blueprint-info,html .blueprint-info{height:fit-content;margin:20px auto 0;width:968px;max-width:88%;background:white;padding:20px 30px;box-shadow:0 0 5px rgba(65,67,144,0.15)}@media(max-width:800px){body .blueprint-info,html .blueprint-info{width:82%;margin:0 auto;padding:30px 6%}}body .blueprint-info h3,html .blueprint-info h3{margin:0;font-size:1.4em;font-weight:500}body .blueprint-info ul,html .blueprint-info ul{list-style:none;border:1px solid #e6e6e6;padding:10px}body .blueprint-info ul li,html .blueprint-info ul li{display:flex;justify-content:space-between;align-items:center;border-bottom:1px solid #ececec;padding-bottom:10px;margin-bottom:10px;font-size:1.1em}body .blueprint-info ul li:last-of-type,html .blueprint-info ul li:last-of-type{border-bottom:none;margin-bottom:0;padding-bottom:0}body .blueprint-info ul li span,html .blueprint-info ul li span{font-weight:500;font-size:.9em}body .blueprint-info ul .attribute-value,html .blueprint-info ul .attribute-value{font-weight:300;font-size:.9em}
\ No newline at end of file
+nav{background:#fff;padding:30px;width:auto;margin-bottom:40px;box-shadow:0 0 5px #bec6cf}nav .nav-wrapper{max-width:1014px!important;display:flex;justify-content:space-between;align-items:center;width:auto;margin:0 auto}nav .nav-wrapper .left-nav{display:flex;justify-content:space-between;align-items:center}nav .nav-wrapper .left-nav a{margin-right:40px}@media(max-width:600px){nav .nav-wrapper .left-nav a{margin-right:25px!important}}nav .nav-wrapper .left-nav img{width:50px;margin-right:0}nav .nav-wrapper a{font-weight:600;color:#7d849a}@media(max-width:600px){nav .nav-wrapper a{font-size:.95em}}nav a{color:#4d545d;transition:all .2s ease-out;text-decoration:none;font-size:1.1em}nav a:hover{cursor:pointer;opacity:.7}nav{background:#fff;padding:30px;width:auto;margin-bottom:40px;box-shadow:0 0 5px #bec6cf}nav .nav-wrapper{max-width:1014px!important;display:flex;justify-content:space-between;align-items:center;width:auto;margin:0 auto}nav .nav-wrapper .left-nav{display:flex;justify-content:space-between;align-items:center}nav .nav-wrapper .left-nav a{margin-right:40px}@media(max-width:600px){nav .nav-wrapper .left-nav a{margin-right:25px!important}}nav .nav-wrapper .left-nav img{width:50px;margin-right:0}nav .nav-wrapper a{font-weight:600;color:#7d849a}@media(max-width:600px){nav .nav-wrapper a{font-size:.95em}}nav a{color:#4d545d;transition:all .2s ease-out;text-decoration:none;font-size:1.1em}nav a:hover{cursor:pointer;opacity:.7}body,html{font-family:'Poppins',sans-serif;margin:0;padding:0;background:#f0f0f0;height:100%;color:#5f6988}body .container,html .container{width:948px;max-width:88%;margin:0 auto;height:fit-content;background:white;padding:30px 40px;box-shadow:0 0 5px rgba(65,67,144,0.15)}@media(max-width:800px){body .container,html .container{width:82%;margin:0 auto 20px;padding:30px 6%}}body .container h1,html .container h1{line-height:1;margin:0 0 5px}body .container h2,html .container h2{margin:0;font-weight:400;font-size:1.2em;line-height:1}body .container a,html .container a{color:#5dbad7;transition:all .2s ease-out;text-decoration:none}body .container a:hover,html .container a:hover{cursor:pointer;opacity:.7}body .blueprint-info,html .blueprint-info{height:fit-content;margin:20px auto 0;width:968px;max-width:88%;background:white;padding:20px 30px;box-shadow:0 0 5px rgba(65,67,144,0.15)}@media(max-width:800px){body .blueprint-info,html .blueprint-info{width:82%;margin:0 auto;padding:30px 6%}}body .blueprint-info h3,html .blueprint-info h3{margin:0;font-size:1.4em;font-weight:500}body .blueprint-info ul,html .blueprint-info ul{list-style:none;border:1px solid #e6e6e6;padding:10px}body .blueprint-info ul li,html .blueprint-info ul li{display:flex;justify-content:space-between;align-items:center;border-bottom:1px solid #ececec;padding-bottom:10px;margin-bottom:10px;font-size:1.1em}body .blueprint-info ul li:last-of-type,html .blueprint-info ul li:last-of-type{border-bottom:none;margin-bottom:0;padding-bottom:0}body .blueprint-info ul li span,html .blueprint-info ul li span{font-weight:500;font-size:.9em}body .blueprint-info ul .attribute-value,html .blueprint-info ul .attribute-value{font-weight:300;font-size:.9em}
\ No newline at end of file
diff --git a/flask_blueprint_tutorial/static/img/avatar.png b/flask_blueprint_tutorial/static/dist/img/avatar.png
similarity index 100%
rename from flask_blueprint_tutorial/static/img/avatar.png
rename to flask_blueprint_tutorial/static/dist/img/avatar.png
diff --git a/flask_blueprint_tutorial/static/dist/img/favicon@2x.png b/flask_blueprint_tutorial/static/dist/img/favicon@2x.png
new file mode 100644
index 0000000..61bdc13
Binary files /dev/null and b/flask_blueprint_tutorial/static/dist/img/favicon@2x.png differ
diff --git a/flask_blueprint_tutorial/static/dist/img/logo@2x.png b/flask_blueprint_tutorial/static/dist/img/logo@2x.png
new file mode 100644
index 0000000..61bdc13
Binary files /dev/null and b/flask_blueprint_tutorial/static/dist/img/logo@2x.png differ
diff --git a/flask_blueprint_tutorial/static/img/favicon.png b/flask_blueprint_tutorial/static/img/favicon.png
deleted file mode 100644
index 7ba45c3..0000000
Binary files a/flask_blueprint_tutorial/static/img/favicon.png and /dev/null differ
diff --git a/flask_blueprint_tutorial/static/img/logo.png b/flask_blueprint_tutorial/static/img/logo.png
deleted file mode 100644
index d5474a6..0000000
Binary files a/flask_blueprint_tutorial/static/img/logo.png and /dev/null differ
diff --git a/flask_blueprint_tutorial/static/src/less/nav.less b/flask_blueprint_tutorial/static/src/less/nav.less
index 86ddea6..66a5c75 100644
--- a/flask_blueprint_tutorial/static/src/less/nav.less
+++ b/flask_blueprint_tutorial/static/src/less/nav.less
@@ -28,7 +28,7 @@ nav {
}
img {
- width: 30px;
+ width: 50px;
margin-right: 0;
}
}
diff --git a/flask_blueprint_tutorial/templates/blueprintinfo.jinja2 b/flask_blueprint_tutorial/templates/blueprintinfo.jinja2
index 347ae41..731ad3a 100644
--- a/flask_blueprint_tutorial/templates/blueprintinfo.jinja2
+++ b/flask_blueprint_tutorial/templates/blueprintinfo.jinja2
@@ -6,4 +6,4 @@
View: {{ request.endpoint }}
Route: {{ request.path }}
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/flask_blueprint_tutorial/templates/layout.jinja2 b/flask_blueprint_tutorial/templates/layout.jinja2
index 1cf2c72..4f830af 100644
--- a/flask_blueprint_tutorial/templates/layout.jinja2
+++ b/flask_blueprint_tutorial/templates/layout.jinja2
@@ -9,15 +9,15 @@
-
+
-
+
-
+
diff --git a/flask_blueprint_tutorial/templates/navigation.jinja2 b/flask_blueprint_tutorial/templates/navigation.jinja2
index 3a1ab7e..2297f4f 100644
--- a/flask_blueprint_tutorial/templates/navigation.jinja2
+++ b/flask_blueprint_tutorial/templates/navigation.jinja2
@@ -2,19 +2,19 @@
- {% if request.blueprint != 'profile_bp' %}
-
My Account
+ {% if request.blueprint != 'profile_blueprint' %}
+
My Account
{% else %}
-
Logout
+
Logout
{% endif %}
diff --git a/main.py b/main.py
deleted file mode 100644
index c45938b..0000000
--- a/main.py
+++ /dev/null
@@ -1,7 +0,0 @@
-"""Application entry point."""
-from flask_blueprint_tutorial import init_app
-
-app = init_app()
-
-if __name__ == "__main__":
- app.run(host="127.0.0.1", port=6416, debug=True)
diff --git a/poetry.lock b/poetry.lock
index f86b9f2..b215e39 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -2,33 +2,33 @@
[[package]]
name = "black"
-version = "23.7.0"
+version = "23.12.0"
description = "The uncompromising code formatter."
optional = false
python-versions = ">=3.8"
files = [
- {file = "black-23.7.0-cp310-cp310-macosx_10_16_arm64.whl", hash = "sha256:5c4bc552ab52f6c1c506ccae05681fab58c3f72d59ae6e6639e8885e94fe2587"},
- {file = "black-23.7.0-cp310-cp310-macosx_10_16_universal2.whl", hash = "sha256:552513d5cd5694590d7ef6f46e1767a4df9af168d449ff767b13b084c020e63f"},
- {file = "black-23.7.0-cp310-cp310-macosx_10_16_x86_64.whl", hash = "sha256:86cee259349b4448adb4ef9b204bb4467aae74a386bce85d56ba4f5dc0da27be"},
- {file = "black-23.7.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:501387a9edcb75d7ae8a4412bb8749900386eaef258f1aefab18adddea1936bc"},
- {file = "black-23.7.0-cp310-cp310-win_amd64.whl", hash = "sha256:fb074d8b213749fa1d077d630db0d5f8cc3b2ae63587ad4116e8a436e9bbe995"},
- {file = "black-23.7.0-cp311-cp311-macosx_10_16_arm64.whl", hash = "sha256:b5b0ee6d96b345a8b420100b7d71ebfdd19fab5e8301aff48ec270042cd40ac2"},
- {file = "black-23.7.0-cp311-cp311-macosx_10_16_universal2.whl", hash = "sha256:893695a76b140881531062d48476ebe4a48f5d1e9388177e175d76234ca247cd"},
- {file = "black-23.7.0-cp311-cp311-macosx_10_16_x86_64.whl", hash = "sha256:c333286dc3ddca6fdff74670b911cccedacb4ef0a60b34e491b8a67c833b343a"},
- {file = "black-23.7.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:831d8f54c3a8c8cf55f64d0422ee875eecac26f5f649fb6c1df65316b67c8926"},
- {file = "black-23.7.0-cp311-cp311-win_amd64.whl", hash = "sha256:7f3bf2dec7d541b4619b8ce526bda74a6b0bffc480a163fed32eb8b3c9aed8ad"},
- {file = "black-23.7.0-cp38-cp38-macosx_10_16_arm64.whl", hash = "sha256:f9062af71c59c004cd519e2fb8f5d25d39e46d3af011b41ab43b9c74e27e236f"},
- {file = "black-23.7.0-cp38-cp38-macosx_10_16_universal2.whl", hash = "sha256:01ede61aac8c154b55f35301fac3e730baf0c9cf8120f65a9cd61a81cfb4a0c3"},
- {file = "black-23.7.0-cp38-cp38-macosx_10_16_x86_64.whl", hash = "sha256:327a8c2550ddc573b51e2c352adb88143464bb9d92c10416feb86b0f5aee5ff6"},
- {file = "black-23.7.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d1c6022b86f83b632d06f2b02774134def5d4d4f1dac8bef16d90cda18ba28a"},
- {file = "black-23.7.0-cp38-cp38-win_amd64.whl", hash = "sha256:27eb7a0c71604d5de083757fbdb245b1a4fae60e9596514c6ec497eb63f95320"},
- {file = "black-23.7.0-cp39-cp39-macosx_10_16_arm64.whl", hash = "sha256:8417dbd2f57b5701492cd46edcecc4f9208dc75529bcf76c514864e48da867d9"},
- {file = "black-23.7.0-cp39-cp39-macosx_10_16_universal2.whl", hash = "sha256:47e56d83aad53ca140da0af87678fb38e44fd6bc0af71eebab2d1f59b1acf1d3"},
- {file = "black-23.7.0-cp39-cp39-macosx_10_16_x86_64.whl", hash = "sha256:25cc308838fe71f7065df53aedd20327969d05671bac95b38fdf37ebe70ac087"},
- {file = "black-23.7.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:642496b675095d423f9b8448243336f8ec71c9d4d57ec17bf795b67f08132a91"},
- {file = "black-23.7.0-cp39-cp39-win_amd64.whl", hash = "sha256:ad0014efc7acf0bd745792bd0d8857413652979200ab924fbf239062adc12491"},
- {file = "black-23.7.0-py3-none-any.whl", hash = "sha256:9fd59d418c60c0348505f2ddf9609c1e1de8e7493eab96198fc89d9f865e7a96"},
- {file = "black-23.7.0.tar.gz", hash = "sha256:022a582720b0d9480ed82576c920a8c1dde97cc38ff11d8d8859b3bd6ca9eedb"},
+ {file = "black-23.12.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:67f19562d367468ab59bd6c36a72b2c84bc2f16b59788690e02bbcb140a77175"},
+ {file = "black-23.12.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:bbd75d9f28a7283b7426160ca21c5bd640ca7cd8ef6630b4754b6df9e2da8462"},
+ {file = "black-23.12.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:593596f699ca2dcbbbdfa59fcda7d8ad6604370c10228223cd6cf6ce1ce7ed7e"},
+ {file = "black-23.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:12d5f10cce8dc27202e9a252acd1c9a426c83f95496c959406c96b785a92bb7d"},
+ {file = "black-23.12.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:e73c5e3d37e5a3513d16b33305713237a234396ae56769b839d7c40759b8a41c"},
+ {file = "black-23.12.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ba09cae1657c4f8a8c9ff6cfd4a6baaf915bb4ef7d03acffe6a2f6585fa1bd01"},
+ {file = "black-23.12.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ace64c1a349c162d6da3cef91e3b0e78c4fc596ffde9413efa0525456148873d"},
+ {file = "black-23.12.0-cp311-cp311-win_amd64.whl", hash = "sha256:72db37a2266b16d256b3ea88b9affcdd5c41a74db551ec3dd4609a59c17d25bf"},
+ {file = "black-23.12.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:fdf6f23c83078a6c8da2442f4d4eeb19c28ac2a6416da7671b72f0295c4a697b"},
+ {file = "black-23.12.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:39dda060b9b395a6b7bf9c5db28ac87b3c3f48d4fdff470fa8a94ab8271da47e"},
+ {file = "black-23.12.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7231670266ca5191a76cb838185d9be59cfa4f5dd401b7c1c70b993c58f6b1b5"},
+ {file = "black-23.12.0-cp312-cp312-win_amd64.whl", hash = "sha256:193946e634e80bfb3aec41830f5d7431f8dd5b20d11d89be14b84a97c6b8bc75"},
+ {file = "black-23.12.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bcf91b01ddd91a2fed9a8006d7baa94ccefe7e518556470cf40213bd3d44bbbc"},
+ {file = "black-23.12.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:996650a89fe5892714ea4ea87bc45e41a59a1e01675c42c433a35b490e5aa3f0"},
+ {file = "black-23.12.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bdbff34c487239a63d86db0c9385b27cdd68b1bfa4e706aa74bb94a435403672"},
+ {file = "black-23.12.0-cp38-cp38-win_amd64.whl", hash = "sha256:97af22278043a6a1272daca10a6f4d36c04dfa77e61cbaaf4482e08f3640e9f0"},
+ {file = "black-23.12.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ead25c273adfad1095a8ad32afdb8304933efba56e3c1d31b0fee4143a1e424a"},
+ {file = "black-23.12.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c71048345bdbced456cddf1622832276d98a710196b842407840ae8055ade6ee"},
+ {file = "black-23.12.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:81a832b6e00eef2c13b3239d514ea3b7d5cc3eaa03d0474eedcbbda59441ba5d"},
+ {file = "black-23.12.0-cp39-cp39-win_amd64.whl", hash = "sha256:6a82a711d13e61840fb11a6dfecc7287f2424f1ca34765e70c909a35ffa7fb95"},
+ {file = "black-23.12.0-py3-none-any.whl", hash = "sha256:a7c07db8200b5315dc07e331dda4d889a56f6bf4db6a9c2a526fa3166a81614f"},
+ {file = "black-23.12.0.tar.gz", hash = "sha256:330a327b422aca0634ecd115985c1c7fd7bdb5b5a2ef8aa9888a82e2ebe9437a"},
]
[package.dependencies]
@@ -38,117 +38,23 @@ packaging = ">=22.0"
pathspec = ">=0.9.0"
platformdirs = ">=2"
tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""}
+typing-extensions = {version = ">=4.0.1", markers = "python_version < \"3.11\""}
[package.extras]
colorama = ["colorama (>=0.4.3)"]
-d = ["aiohttp (>=3.7.4)"]
+d = ["aiohttp (>=3.7.4)", "aiohttp (>=3.7.4,!=3.9.0)"]
jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"]
uvloop = ["uvloop (>=0.15.2)"]
[[package]]
name = "blinker"
-version = "1.6.2"
+version = "1.7.0"
description = "Fast, simple object-to-object and broadcast signaling"
optional = false
-python-versions = ">=3.7"
-files = [
- {file = "blinker-1.6.2-py3-none-any.whl", hash = "sha256:c3d739772abb7bc2860abf5f2ec284223d9ad5c76da018234f6f50d6f31ab1f0"},
- {file = "blinker-1.6.2.tar.gz", hash = "sha256:4afd3de66ef3a9f8067559fb7a1cbe555c17dcbe15971b05d1b625c3e7abe213"},
-]
-
-[[package]]
-name = "certifi"
-version = "2023.7.22"
-description = "Python package for providing Mozilla's CA Bundle."
-optional = false
-python-versions = ">=3.6"
+python-versions = ">=3.8"
files = [
- {file = "certifi-2023.7.22-py3-none-any.whl", hash = "sha256:92d6037539857d8206b8f6ae472e8b77db8058fec5937a1ef3f54304089edbb9"},
- {file = "certifi-2023.7.22.tar.gz", hash = "sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082"},
-]
-
-[[package]]
-name = "charset-normalizer"
-version = "3.2.0"
-description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet."
-optional = false
-python-versions = ">=3.7.0"
-files = [
- {file = "charset-normalizer-3.2.0.tar.gz", hash = "sha256:3bb3d25a8e6c0aedd251753a79ae98a093c7e7b471faa3aa9a93a81431987ace"},
- {file = "charset_normalizer-3.2.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0b87549028f680ca955556e3bd57013ab47474c3124dc069faa0b6545b6c9710"},
- {file = "charset_normalizer-3.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7c70087bfee18a42b4040bb9ec1ca15a08242cf5867c58726530bdf3945672ed"},
- {file = "charset_normalizer-3.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a103b3a7069b62f5d4890ae1b8f0597618f628b286b03d4bc9195230b154bfa9"},
- {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:94aea8eff76ee6d1cdacb07dd2123a68283cb5569e0250feab1240058f53b623"},
- {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:db901e2ac34c931d73054d9797383d0f8009991e723dab15109740a63e7f902a"},
- {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b0dac0ff919ba34d4df1b6131f59ce95b08b9065233446be7e459f95554c0dc8"},
- {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:193cbc708ea3aca45e7221ae58f0fd63f933753a9bfb498a3b474878f12caaad"},
- {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:09393e1b2a9461950b1c9a45d5fd251dc7c6f228acab64da1c9c0165d9c7765c"},
- {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:baacc6aee0b2ef6f3d308e197b5d7a81c0e70b06beae1f1fcacffdbd124fe0e3"},
- {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:bf420121d4c8dce6b889f0e8e4ec0ca34b7f40186203f06a946fa0276ba54029"},
- {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:c04a46716adde8d927adb9457bbe39cf473e1e2c2f5d0a16ceb837e5d841ad4f"},
- {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:aaf63899c94de41fe3cf934601b0f7ccb6b428c6e4eeb80da72c58eab077b19a"},
- {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d62e51710986674142526ab9f78663ca2b0726066ae26b78b22e0f5e571238dd"},
- {file = "charset_normalizer-3.2.0-cp310-cp310-win32.whl", hash = "sha256:04e57ab9fbf9607b77f7d057974694b4f6b142da9ed4a199859d9d4d5c63fe96"},
- {file = "charset_normalizer-3.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:48021783bdf96e3d6de03a6e39a1171ed5bd7e8bb93fc84cc649d11490f87cea"},
- {file = "charset_normalizer-3.2.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:4957669ef390f0e6719db3613ab3a7631e68424604a7b448f079bee145da6e09"},
- {file = "charset_normalizer-3.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:46fb8c61d794b78ec7134a715a3e564aafc8f6b5e338417cb19fe9f57a5a9bf2"},
- {file = "charset_normalizer-3.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f779d3ad205f108d14e99bb3859aa7dd8e9c68874617c72354d7ecaec2a054ac"},
- {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f25c229a6ba38a35ae6e25ca1264621cc25d4d38dca2942a7fce0b67a4efe918"},
- {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2efb1bd13885392adfda4614c33d3b68dee4921fd0ac1d3988f8cbb7d589e72a"},
- {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f30b48dd7fa1474554b0b0f3fdfdd4c13b5c737a3c6284d3cdc424ec0ffff3a"},
- {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:246de67b99b6851627d945db38147d1b209a899311b1305dd84916f2b88526c6"},
- {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9bd9b3b31adcb054116447ea22caa61a285d92e94d710aa5ec97992ff5eb7cf3"},
- {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:8c2f5e83493748286002f9369f3e6607c565a6a90425a3a1fef5ae32a36d749d"},
- {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:3170c9399da12c9dc66366e9d14da8bf7147e1e9d9ea566067bbce7bb74bd9c2"},
- {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:7a4826ad2bd6b07ca615c74ab91f32f6c96d08f6fcc3902ceeedaec8cdc3bcd6"},
- {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:3b1613dd5aee995ec6d4c69f00378bbd07614702a315a2cf6c1d21461fe17c23"},
- {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9e608aafdb55eb9f255034709e20d5a83b6d60c054df0802fa9c9883d0a937aa"},
- {file = "charset_normalizer-3.2.0-cp311-cp311-win32.whl", hash = "sha256:f2a1d0fd4242bd8643ce6f98927cf9c04540af6efa92323e9d3124f57727bfc1"},
- {file = "charset_normalizer-3.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:681eb3d7e02e3c3655d1b16059fbfb605ac464c834a0c629048a30fad2b27489"},
- {file = "charset_normalizer-3.2.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c57921cda3a80d0f2b8aec7e25c8aa14479ea92b5b51b6876d975d925a2ea346"},
- {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:41b25eaa7d15909cf3ac4c96088c1f266a9a93ec44f87f1d13d4a0e86c81b982"},
- {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f058f6963fd82eb143c692cecdc89e075fa0828db2e5b291070485390b2f1c9c"},
- {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a7647ebdfb9682b7bb97e2a5e7cb6ae735b1c25008a70b906aecca294ee96cf4"},
- {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eef9df1eefada2c09a5e7a40991b9fc6ac6ef20b1372abd48d2794a316dc0449"},
- {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e03b8895a6990c9ab2cdcd0f2fe44088ca1c65ae592b8f795c3294af00a461c3"},
- {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:ee4006268ed33370957f55bf2e6f4d263eaf4dc3cfc473d1d90baff6ed36ce4a"},
- {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c4983bf937209c57240cff65906b18bb35e64ae872da6a0db937d7b4af845dd7"},
- {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:3bb7fda7260735efe66d5107fb7e6af6a7c04c7fce9b2514e04b7a74b06bf5dd"},
- {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:72814c01533f51d68702802d74f77ea026b5ec52793c791e2da806a3844a46c3"},
- {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:70c610f6cbe4b9fce272c407dd9d07e33e6bf7b4aa1b7ffb6f6ded8e634e3592"},
- {file = "charset_normalizer-3.2.0-cp37-cp37m-win32.whl", hash = "sha256:a401b4598e5d3f4a9a811f3daf42ee2291790c7f9d74b18d75d6e21dda98a1a1"},
- {file = "charset_normalizer-3.2.0-cp37-cp37m-win_amd64.whl", hash = "sha256:c0b21078a4b56965e2b12f247467b234734491897e99c1d51cee628da9786959"},
- {file = "charset_normalizer-3.2.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:95eb302ff792e12aba9a8b8f8474ab229a83c103d74a750ec0bd1c1eea32e669"},
- {file = "charset_normalizer-3.2.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1a100c6d595a7f316f1b6f01d20815d916e75ff98c27a01ae817439ea7726329"},
- {file = "charset_normalizer-3.2.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:6339d047dab2780cc6220f46306628e04d9750f02f983ddb37439ca47ced7149"},
- {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e4b749b9cc6ee664a3300bb3a273c1ca8068c46be705b6c31cf5d276f8628a94"},
- {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a38856a971c602f98472050165cea2cdc97709240373041b69030be15047691f"},
- {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f87f746ee241d30d6ed93969de31e5ffd09a2961a051e60ae6bddde9ec3583aa"},
- {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:89f1b185a01fe560bc8ae5f619e924407efca2191b56ce749ec84982fc59a32a"},
- {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e1c8a2f4c69e08e89632defbfabec2feb8a8d99edc9f89ce33c4b9e36ab63037"},
- {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2f4ac36d8e2b4cc1aa71df3dd84ff8efbe3bfb97ac41242fbcfc053c67434f46"},
- {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a386ebe437176aab38c041de1260cd3ea459c6ce5263594399880bbc398225b2"},
- {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:ccd16eb18a849fd8dcb23e23380e2f0a354e8daa0c984b8a732d9cfaba3a776d"},
- {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:e6a5bf2cba5ae1bb80b154ed68a3cfa2fa00fde979a7f50d6598d3e17d9ac20c"},
- {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:45de3f87179c1823e6d9e32156fb14c1927fcc9aba21433f088fdfb555b77c10"},
- {file = "charset_normalizer-3.2.0-cp38-cp38-win32.whl", hash = "sha256:1000fba1057b92a65daec275aec30586c3de2401ccdcd41f8a5c1e2c87078706"},
- {file = "charset_normalizer-3.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:8b2c760cfc7042b27ebdb4a43a4453bd829a5742503599144d54a032c5dc7e9e"},
- {file = "charset_normalizer-3.2.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:855eafa5d5a2034b4621c74925d89c5efef61418570e5ef9b37717d9c796419c"},
- {file = "charset_normalizer-3.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:203f0c8871d5a7987be20c72442488a0b8cfd0f43b7973771640fc593f56321f"},
- {file = "charset_normalizer-3.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e857a2232ba53ae940d3456f7533ce6ca98b81917d47adc3c7fd55dad8fab858"},
- {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5e86d77b090dbddbe78867a0275cb4df08ea195e660f1f7f13435a4649e954e5"},
- {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c4fb39a81950ec280984b3a44f5bd12819953dc5fa3a7e6fa7a80db5ee853952"},
- {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2dee8e57f052ef5353cf608e0b4c871aee320dd1b87d351c28764fc0ca55f9f4"},
- {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8700f06d0ce6f128de3ccdbc1acaea1ee264d2caa9ca05daaf492fde7c2a7200"},
- {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1920d4ff15ce893210c1f0c0e9d19bfbecb7983c76b33f046c13a8ffbd570252"},
- {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:c1c76a1743432b4b60ab3358c937a3fe1341c828ae6194108a94c69028247f22"},
- {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f7560358a6811e52e9c4d142d497f1a6e10103d3a6881f18d04dbce3729c0e2c"},
- {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:c8063cf17b19661471ecbdb3df1c84f24ad2e389e326ccaf89e3fb2484d8dd7e"},
- {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:cd6dbe0238f7743d0efe563ab46294f54f9bc8f4b9bcf57c3c666cc5bc9d1299"},
- {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:1249cbbf3d3b04902ff081ffbb33ce3377fa6e4c7356f759f3cd076cc138d020"},
- {file = "charset_normalizer-3.2.0-cp39-cp39-win32.whl", hash = "sha256:6c409c0deba34f147f77efaa67b8e4bb83d2f11c8806405f76397ae5b8c0d1c9"},
- {file = "charset_normalizer-3.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:7095f6fbfaa55defb6b733cfeb14efaae7a29f0b59d8cf213be4e7ca0b857b80"},
- {file = "charset_normalizer-3.2.0-py3-none-any.whl", hash = "sha256:8e098148dd37b4ce3baca71fb394c81dc5d9c7728c95df695d2dca218edf40e6"},
+ {file = "blinker-1.7.0-py3-none-any.whl", hash = "sha256:c3f865d4d54db7abc53758a01601cf343fe55b84c1de4e3fa910e420b438d5b9"},
+ {file = "blinker-1.7.0.tar.gz", hash = "sha256:e6820ff6fa4e4d1d8e2747c2283749c3f547e4fee112b98555cdcdae32996182"},
]
[[package]]
@@ -188,13 +94,13 @@ files = [
[[package]]
name = "faker"
-version = "19.3.1"
+version = "21.0.0"
description = "Faker is a Python package that generates fake data for you."
optional = false
python-versions = ">=3.8"
files = [
- {file = "Faker-19.3.1-py3-none-any.whl", hash = "sha256:e2722fdf622cf24e974aaba15a3dee97a6f8b98d869bd827ff1af9c87695af46"},
- {file = "Faker-19.3.1.tar.gz", hash = "sha256:a6624d9574623bb27dfca33fff94581cd7b23b562901db8ad59acbde9a52543e"},
+ {file = "Faker-21.0.0-py3-none-any.whl", hash = "sha256:ff61cca42547795bee8a11319792a8fee6d0f0cd191e831f7f3050c5851fcd8a"},
+ {file = "Faker-21.0.0.tar.gz", hash = "sha256:2d8a350e952225a145307d7461881c44a1c9320e90fbe8bd903d5947f133f3ec"},
]
[package.dependencies]
@@ -218,13 +124,13 @@ pyflakes = ">=3.1.0,<3.2.0"
[[package]]
name = "flask"
-version = "2.3.3"
+version = "3.0.0"
description = "A simple framework for building complex web applications."
optional = false
python-versions = ">=3.8"
files = [
- {file = "flask-2.3.3-py3-none-any.whl", hash = "sha256:f69fcd559dc907ed196ab9df0e48471709175e696d6e698dd4dbe940f96ce66b"},
- {file = "flask-2.3.3.tar.gz", hash = "sha256:09c347a92aa7ff4a8e7f3206795f30d826654baf38b873d0744cd571ca609efc"},
+ {file = "flask-3.0.0-py3-none-any.whl", hash = "sha256:21128f47e4e3b9d597a3e8521a329bf56909b690fcc3fa3e477725aa81367638"},
+ {file = "flask-3.0.0.tar.gz", hash = "sha256:cfadcdb638b609361d29ec22360d6070a77d7463dcb3ab08d2c2f2f168845f58"},
]
[package.dependencies]
@@ -232,7 +138,7 @@ blinker = ">=1.6.2"
click = ">=8.1.3"
itsdangerous = ">=2.1.2"
Jinja2 = ">=3.1.2"
-Werkzeug = ">=2.3.7"
+Werkzeug = ">=3.0.0"
[package.extras]
async = ["asgiref (>=3.2)"]
@@ -240,13 +146,13 @@ dotenv = ["python-dotenv"]
[[package]]
name = "flask-assets"
-version = "2.0"
+version = "2.1.0"
description = "Asset management for Flask, to compress and merge CSS and Javascript files."
optional = false
python-versions = "*"
files = [
- {file = "Flask-Assets-2.0.tar.gz", hash = "sha256:1dfdea35e40744d46aada72831f7613d67bf38e8b20ccaaa9e91fdc37aa3b8c2"},
- {file = "Flask_Assets-2.0-py3-none-any.whl", hash = "sha256:2845bd3b479be9db8556801e7ebc2746ce2d9edb4e7b64a1c786ecbfc1e5867b"},
+ {file = "Flask-Assets-2.1.0.tar.gz", hash = "sha256:f84d6532ffe59c9ff352885e8740ff4da25c0bcfacd805f0a806815e44354813"},
+ {file = "Flask_Assets-2.1.0-py3-none-any.whl", hash = "sha256:a56c476b15f84701712cc3b4b4a001ebbe62b1dcbe81c23f96fbe6f261b75324"},
]
[package.dependencies]
@@ -254,32 +160,38 @@ Flask = ">=0.8"
webassets = ">=2.0"
[[package]]
-name = "idna"
-version = "3.4"
-description = "Internationalized Domain Names in Applications (IDNA)"
+name = "gunicorn"
+version = "21.2.0"
+description = "WSGI HTTP Server for UNIX"
optional = false
python-versions = ">=3.5"
files = [
- {file = "idna-3.4-py3-none-any.whl", hash = "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"},
- {file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"},
+ {file = "gunicorn-21.2.0-py3-none-any.whl", hash = "sha256:3213aa5e8c24949e792bcacfc176fef362e7aac80b76c56f6b5122bf350722f0"},
+ {file = "gunicorn-21.2.0.tar.gz", hash = "sha256:88ec8bff1d634f98e61b9f65bc4bf3cd918a90806c6f5c48bc5603849ec81033"},
]
+[package.dependencies]
+packaging = "*"
+
+[package.extras]
+eventlet = ["eventlet (>=0.24.1)"]
+gevent = ["gevent (>=1.4.0)"]
+setproctitle = ["setproctitle"]
+tornado = ["tornado (>=0.2)"]
+
[[package]]
name = "isort"
-version = "5.12.0"
+version = "5.13.2"
description = "A Python utility / library to sort Python imports."
optional = false
python-versions = ">=3.8.0"
files = [
- {file = "isort-5.12.0-py3-none-any.whl", hash = "sha256:f84c2818376e66cf843d497486ea8fed8700b340f308f076c6fb1229dff318b6"},
- {file = "isort-5.12.0.tar.gz", hash = "sha256:8bef7dde241278824a6d83f44a544709b065191b95b6e50894bdc722fcba0504"},
+ {file = "isort-5.13.2-py3-none-any.whl", hash = "sha256:8ca5e72a8d85860d5a3fa69b8745237f2939afe12dbf656afbcb47fe72d947a6"},
+ {file = "isort-5.13.2.tar.gz", hash = "sha256:48fdfcb9face5d58a4f6dde2e72a1fb8dcaf8ab26f95ab49fab84c2ddefb0109"},
]
[package.extras]
-colors = ["colorama (>=0.4.3)"]
-pipfile-deprecated-finder = ["pip-shims (>=0.5.2)", "pipreqs", "requirementslib"]
-plugins = ["setuptools"]
-requirements-deprecated-finder = ["pip-api", "pipreqs"]
+colors = ["colorama (>=0.4.6)"]
[[package]]
name = "itsdangerous"
@@ -360,6 +272,16 @@ files = [
{file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac"},
{file = "MarkupSafe-2.1.3-cp311-cp311-win32.whl", hash = "sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb"},
{file = "MarkupSafe-2.1.3-cp311-cp311-win_amd64.whl", hash = "sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686"},
+ {file = "MarkupSafe-2.1.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:f698de3fd0c4e6972b92290a45bd9b1536bffe8c6759c62471efaa8acb4c37bc"},
+ {file = "MarkupSafe-2.1.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:aa57bd9cf8ae831a362185ee444e15a93ecb2e344c8e52e4d721ea3ab6ef1823"},
+ {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ffcc3f7c66b5f5b7931a5aa68fc9cecc51e685ef90282f4a82f0f5e9b704ad11"},
+ {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47d4f1c5f80fc62fdd7777d0d40a2e9dda0a05883ab11374334f6c4de38adffd"},
+ {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1f67c7038d560d92149c060157d623c542173016c4babc0c1913cca0564b9939"},
+ {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:9aad3c1755095ce347e26488214ef77e0485a3c34a50c5a5e2471dff60b9dd9c"},
+ {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:14ff806850827afd6b07a5f32bd917fb7f45b046ba40c57abdb636674a8b559c"},
+ {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8f9293864fe09b8149f0cc42ce56e3f0e54de883a9de90cd427f191c346eb2e1"},
+ {file = "MarkupSafe-2.1.3-cp312-cp312-win32.whl", hash = "sha256:715d3562f79d540f251b99ebd6d8baa547118974341db04f5ad06d5ea3eb8007"},
+ {file = "MarkupSafe-2.1.3-cp312-cp312-win_amd64.whl", hash = "sha256:1b8dd8c3fd14349433c79fa8abeb573a55fc0fdd769133baac1f5e07abf54aeb"},
{file = "MarkupSafe-2.1.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2"},
{file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b"},
{file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707"},
@@ -403,6 +325,53 @@ files = [
{file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"},
]
+[[package]]
+name = "mypy"
+version = "1.7.1"
+description = "Optional static typing for Python"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "mypy-1.7.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:12cce78e329838d70a204293e7b29af9faa3ab14899aec397798a4b41be7f340"},
+ {file = "mypy-1.7.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1484b8fa2c10adf4474f016e09d7a159602f3239075c7bf9f1627f5acf40ad49"},
+ {file = "mypy-1.7.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:31902408f4bf54108bbfb2e35369877c01c95adc6192958684473658c322c8a5"},
+ {file = "mypy-1.7.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f2c2521a8e4d6d769e3234350ba7b65ff5d527137cdcde13ff4d99114b0c8e7d"},
+ {file = "mypy-1.7.1-cp310-cp310-win_amd64.whl", hash = "sha256:fcd2572dd4519e8a6642b733cd3a8cfc1ef94bafd0c1ceed9c94fe736cb65b6a"},
+ {file = "mypy-1.7.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4b901927f16224d0d143b925ce9a4e6b3a758010673eeded9b748f250cf4e8f7"},
+ {file = "mypy-1.7.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2f7f6985d05a4e3ce8255396df363046c28bea790e40617654e91ed580ca7c51"},
+ {file = "mypy-1.7.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:944bdc21ebd620eafefc090cdf83158393ec2b1391578359776c00de00e8907a"},
+ {file = "mypy-1.7.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9c7ac372232c928fff0645d85f273a726970c014749b924ce5710d7d89763a28"},
+ {file = "mypy-1.7.1-cp311-cp311-win_amd64.whl", hash = "sha256:f6efc9bd72258f89a3816e3a98c09d36f079c223aa345c659622f056b760ab42"},
+ {file = "mypy-1.7.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6dbdec441c60699288adf051f51a5d512b0d818526d1dcfff5a41f8cd8b4aaf1"},
+ {file = "mypy-1.7.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4fc3d14ee80cd22367caaaf6e014494415bf440980a3045bf5045b525680ac33"},
+ {file = "mypy-1.7.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c6e4464ed5f01dc44dc9821caf67b60a4e5c3b04278286a85c067010653a0eb"},
+ {file = "mypy-1.7.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:d9b338c19fa2412f76e17525c1b4f2c687a55b156320acb588df79f2e6fa9fea"},
+ {file = "mypy-1.7.1-cp312-cp312-win_amd64.whl", hash = "sha256:204e0d6de5fd2317394a4eff62065614c4892d5a4d1a7ee55b765d7a3d9e3f82"},
+ {file = "mypy-1.7.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:84860e06ba363d9c0eeabd45ac0fde4b903ad7aa4f93cd8b648385a888e23200"},
+ {file = "mypy-1.7.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:8c5091ebd294f7628eb25ea554852a52058ac81472c921150e3a61cdd68f75a7"},
+ {file = "mypy-1.7.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40716d1f821b89838589e5b3106ebbc23636ffdef5abc31f7cd0266db936067e"},
+ {file = "mypy-1.7.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5cf3f0c5ac72139797953bd50bc6c95ac13075e62dbfcc923571180bebb662e9"},
+ {file = "mypy-1.7.1-cp38-cp38-win_amd64.whl", hash = "sha256:78e25b2fd6cbb55ddfb8058417df193f0129cad5f4ee75d1502248e588d9e0d7"},
+ {file = "mypy-1.7.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:75c4d2a6effd015786c87774e04331b6da863fc3fc4e8adfc3b40aa55ab516fe"},
+ {file = "mypy-1.7.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2643d145af5292ee956aa0a83c2ce1038a3bdb26e033dadeb2f7066fb0c9abce"},
+ {file = "mypy-1.7.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75aa828610b67462ffe3057d4d8a4112105ed211596b750b53cbfe182f44777a"},
+ {file = "mypy-1.7.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ee5d62d28b854eb61889cde4e1dbc10fbaa5560cb39780c3995f6737f7e82120"},
+ {file = "mypy-1.7.1-cp39-cp39-win_amd64.whl", hash = "sha256:72cf32ce7dd3562373f78bd751f73c96cfb441de147cc2448a92c1a308bd0ca6"},
+ {file = "mypy-1.7.1-py3-none-any.whl", hash = "sha256:f7c5d642db47376a0cc130f0de6d055056e010debdaf0707cd2b0fc7e7ef30ea"},
+ {file = "mypy-1.7.1.tar.gz", hash = "sha256:fcb6d9afb1b6208b4c712af0dafdc650f518836065df0d4fb1d800f5d6773db2"},
+]
+
+[package.dependencies]
+mypy-extensions = ">=1.0.0"
+tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""}
+typing-extensions = ">=4.1.0"
+
+[package.extras]
+dmypy = ["psutil (>=4.0)"]
+install-types = ["pip"]
+mypyc = ["setuptools (>=50)"]
+reports = ["lxml"]
+
[[package]]
name = "mypy-extensions"
version = "1.0.0"
@@ -416,35 +385,35 @@ files = [
[[package]]
name = "packaging"
-version = "23.1"
+version = "23.2"
description = "Core utilities for Python packages"
optional = false
python-versions = ">=3.7"
files = [
- {file = "packaging-23.1-py3-none-any.whl", hash = "sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61"},
- {file = "packaging-23.1.tar.gz", hash = "sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f"},
+ {file = "packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7"},
+ {file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"},
]
[[package]]
name = "pathspec"
-version = "0.11.2"
+version = "0.12.1"
description = "Utility library for gitignore style pattern matching of file paths."
optional = false
-python-versions = ">=3.7"
+python-versions = ">=3.8"
files = [
- {file = "pathspec-0.11.2-py3-none-any.whl", hash = "sha256:1d6ed233af05e679efb96b1851550ea95bbb64b7c490b0f5aa52996c11e92a20"},
- {file = "pathspec-0.11.2.tar.gz", hash = "sha256:e0d8d0ac2f12da61956eb2306b69f9469b42f4deb0f3cb6ed47b9cce9996ced3"},
+ {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"},
+ {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"},
]
[[package]]
name = "platformdirs"
-version = "3.10.0"
+version = "4.1.0"
description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
optional = false
-python-versions = ">=3.7"
+python-versions = ">=3.8"
files = [
- {file = "platformdirs-3.10.0-py3-none-any.whl", hash = "sha256:d7c24979f292f916dc9cbf8648319032f551ea8c49a4c9bf2fb556a02070ec1d"},
- {file = "platformdirs-3.10.0.tar.gz", hash = "sha256:b45696dab2d7cc691a3226759c0d3b00c47c8b6e293d96f6436f733303f77f6d"},
+ {file = "platformdirs-4.1.0-py3-none-any.whl", hash = "sha256:11c8f37bcca40db96d8144522d925583bdb7a31f7b0e37e3ed4318400a8e2380"},
+ {file = "platformdirs-4.1.0.tar.gz", hash = "sha256:906d548203468492d432bcb294d4bc2fff751bf84971fbb2c10918cc206ee420"},
]
[package.extras]
@@ -464,13 +433,13 @@ files = [
[[package]]
name = "pycodestyle"
-version = "2.11.0"
+version = "2.11.1"
description = "Python style guide checker"
optional = false
python-versions = ">=3.8"
files = [
- {file = "pycodestyle-2.11.0-py2.py3-none-any.whl", hash = "sha256:5d1013ba8dc7895b548be5afb05740ca82454fd899971563d2ef625d090326f8"},
- {file = "pycodestyle-2.11.0.tar.gz", hash = "sha256:259bcc17857d8a8b3b4a2327324b79e5f020a13c16074670f9c8c8f872ea76d0"},
+ {file = "pycodestyle-2.11.1-py2.py3-none-any.whl", hash = "sha256:44fe31000b2d866f2e41841b18528a505fbd7fef9017b04eff4e2648a0fadc67"},
+ {file = "pycodestyle-2.11.1.tar.gz", hash = "sha256:41ba0e7afc9752dfb53ced5489e89f8186be00e599e712660695b7a75ff2663f"},
]
[[package]]
@@ -512,27 +481,6 @@ files = [
[package.extras]
cli = ["click (>=5.0)"]
-[[package]]
-name = "requests"
-version = "2.31.0"
-description = "Python HTTP for Humans."
-optional = false
-python-versions = ">=3.7"
-files = [
- {file = "requests-2.31.0-py3-none-any.whl", hash = "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f"},
- {file = "requests-2.31.0.tar.gz", hash = "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"},
-]
-
-[package.dependencies]
-certifi = ">=2017.4.17"
-charset-normalizer = ">=2,<4"
-idna = ">=2.5,<4"
-urllib3 = ">=1.21.1,<3"
-
-[package.extras]
-socks = ["PySocks (>=1.5.6,!=1.5.7)"]
-use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"]
-
[[package]]
name = "six"
version = "1.16.0"
@@ -556,30 +504,14 @@ files = [
]
[[package]]
-name = "urllib3"
-version = "2.0.4"
-description = "HTTP library with thread-safe connection pooling, file post, and more."
-optional = false
-python-versions = ">=3.7"
-files = [
- {file = "urllib3-2.0.4-py3-none-any.whl", hash = "sha256:de7df1803967d2c2a98e4b11bb7d6bd9210474c46e8a0401514e3a42a75ebde4"},
- {file = "urllib3-2.0.4.tar.gz", hash = "sha256:8d22f86aae8ef5e410d4f539fde9ce6b2113a001bb4d189e0aed70642d602b11"},
-]
-
-[package.extras]
-brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"]
-secure = ["certifi", "cryptography (>=1.9)", "idna (>=2.0.0)", "pyopenssl (>=17.1.0)", "urllib3-secure-extra"]
-socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"]
-zstd = ["zstandard (>=0.18.0)"]
-
-[[package]]
-name = "uwsgi"
-version = "2.0.22"
-description = "The uWSGI server"
+name = "typing-extensions"
+version = "4.9.0"
+description = "Backported and Experimental Type Hints for Python 3.8+"
optional = false
-python-versions = "*"
+python-versions = ">=3.8"
files = [
- {file = "uwsgi-2.0.22.tar.gz", hash = "sha256:4cc4727258671ac5fa17ab422155e9aaef8a2008ebb86e4404b66deaae965db2"},
+ {file = "typing_extensions-4.9.0-py3-none-any.whl", hash = "sha256:af72aea155e91adfc61c3ae9e0e342dbc0cba726d6cba4b6c72c1f34e47291cd"},
+ {file = "typing_extensions-4.9.0.tar.gz", hash = "sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783"},
]
[[package]]
@@ -595,13 +527,13 @@ files = [
[[package]]
name = "werkzeug"
-version = "2.3.7"
+version = "3.0.1"
description = "The comprehensive WSGI web application library."
optional = false
python-versions = ">=3.8"
files = [
- {file = "werkzeug-2.3.7-py3-none-any.whl", hash = "sha256:effc12dba7f3bd72e605ce49807bbe692bd729c3bb122a3b91747a6ae77df528"},
- {file = "werkzeug-2.3.7.tar.gz", hash = "sha256:2b8c0e447b4b9dbcc85dd97b6eeb4dcbaf6c8b6c3be0bd654e25553e0a2157d8"},
+ {file = "werkzeug-3.0.1-py3-none-any.whl", hash = "sha256:90a285dc0e42ad56b34e696398b8122ee4c681833fb35b8334a095d82c56da10"},
+ {file = "werkzeug-3.0.1.tar.gz", hash = "sha256:507e811ecea72b18a404947aded4b3390e1db8f826b494d76550ef45bb3b1dcc"},
]
[package.dependencies]
@@ -613,4 +545,4 @@ watchdog = ["watchdog (>=2.3)"]
[metadata]
lock-version = "2.0"
python-versions = "^3.10,<4"
-content-hash = "ef10b54a8a2f0af5d929b0263dbc79ea035df0174565c52e7383fcbfbc225f2b"
+content-hash = "1e4fe841f5c19615414d95a92029bb80a192b1d659326cef63a641d0ffc15b06"
diff --git a/pyproject.toml b/pyproject.toml
index 865a2a4..86822c5 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,7 +1,7 @@
[tool.poetry]
name = "flask_blueprint_tutorial"
-version = "0.1.0"
-description = "Structure your Flask apps in a scalable and intelligent way using Blueprints."
+version = "0.1.1"
+description = "Organize your Flask applications neatly via Blueprints."
authors = ["Todd Birchard
"]
maintainers = ["Todd Birchard "]
license = "MIT"
@@ -15,19 +15,19 @@ keywords = ["Flask", "Flask-Blueprints", "Framework", "Python", "Tutorial"]
python = "^3.10,<4"
flask = "*"
flask_assets = "*"
-faker = "*"
-requests = "*"
python-dotenv = "*"
-uwsgi = "*"
+faker = "*"
lesscpy = "*"
cssmin = "*"
jsmin = "*"
black = "*"
isort = "*"
flake8 = "*"
+mypy = "*"
+gunicorn = "*"
[tool.poetry.scripts]
-run = "main:app"
+run = "wsgi:app"
[tool.poetry.urls]
issues = "https://github.com/hackersandslackers/flask-blueprint-tutorial/issues"
@@ -41,3 +41,8 @@ disable = "C0103,C0301,W0703,W0621"
[tool.black]
line-length = 120
+
+[tool.isort]
+profile = "black"
+multi_line_output = 3
+src_paths = ["flask_blueprint_tutorial", "config", "wsgi"]
diff --git a/requirements.txt b/requirements.txt
index a9b65f6..64ef952 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,16 +1,14 @@
-black==23.7.0 ; python_version >= "3.10" and python_version < "4.0"
-blinker==1.6.2 ; python_version >= "3.10" and python_version < "4.0"
-certifi==2023.7.22 ; python_version >= "3.10" and python_version < "4.0"
-charset-normalizer==3.2.0 ; python_version >= "3.10" and python_version < "4.0"
+black==23.12.0 ; python_version >= "3.10" and python_version < "4.0"
+blinker==1.7.0 ; python_version >= "3.10" and python_version < "4.0"
click==8.1.7 ; python_version >= "3.10" and python_version < "4.0"
colorama==0.4.6 ; python_version >= "3.10" and python_version < "4.0" and platform_system == "Windows"
cssmin==0.2.0 ; python_version >= "3.10" and python_version < "4.0"
-faker==19.3.1 ; python_version >= "3.10" and python_version < "4.0"
+faker==21.0.0 ; python_version >= "3.10" and python_version < "4.0"
flake8==6.1.0 ; python_version >= "3.10" and python_version < "4.0"
-flask-assets==2.0 ; python_version >= "3.10" and python_version < "4.0"
-flask==2.3.3 ; python_version >= "3.10" and python_version < "4.0"
-idna==3.4 ; python_version >= "3.10" and python_version < "4.0"
-isort==5.12.0 ; python_version >= "3.10" and python_version < "4.0"
+flask-assets==2.1.0 ; python_version >= "3.10" and python_version < "4.0"
+flask==3.0.0 ; python_version >= "3.10" and python_version < "4.0"
+gunicorn==21.2.0 ; python_version >= "3.10" and python_version < "4.0"
+isort==5.13.2 ; python_version >= "3.10" and python_version < "4.0"
itsdangerous==2.1.2 ; python_version >= "3.10" and python_version < "4.0"
jinja2==3.1.2 ; python_version >= "3.10" and python_version < "4.0"
jsmin==3.0.1 ; python_version >= "3.10" and python_version < "4.0"
@@ -18,18 +16,17 @@ lesscpy==0.15.1 ; python_version >= "3.10" and python_version < "4.0"
markupsafe==2.1.3 ; python_version >= "3.10" and python_version < "4.0"
mccabe==0.7.0 ; python_version >= "3.10" and python_version < "4.0"
mypy-extensions==1.0.0 ; python_version >= "3.10" and python_version < "4.0"
-packaging==23.1 ; python_version >= "3.10" and python_version < "4.0"
-pathspec==0.11.2 ; python_version >= "3.10" and python_version < "4.0"
-platformdirs==3.10.0 ; python_version >= "3.10" and python_version < "4.0"
+mypy==1.7.1 ; python_version >= "3.10" and python_version < "4.0"
+packaging==23.2 ; python_version >= "3.10" and python_version < "4.0"
+pathspec==0.12.1 ; python_version >= "3.10" and python_version < "4.0"
+platformdirs==4.1.0 ; python_version >= "3.10" and python_version < "4.0"
ply==3.11 ; python_version >= "3.10" and python_version < "4.0"
-pycodestyle==2.11.0 ; python_version >= "3.10" and python_version < "4.0"
+pycodestyle==2.11.1 ; python_version >= "3.10" and python_version < "4.0"
pyflakes==3.1.0 ; python_version >= "3.10" and python_version < "4.0"
python-dateutil==2.8.2 ; python_version >= "3.10" and python_version < "4.0"
python-dotenv==1.0.0 ; python_version >= "3.10" and python_version < "4.0"
-requests==2.31.0 ; python_version >= "3.10" and python_version < "4.0"
six==1.16.0 ; python_version >= "3.10" and python_version < "4.0"
tomli==2.0.1 ; python_version >= "3.10" and python_version < "3.11"
-urllib3==2.0.4 ; python_version >= "3.10" and python_version < "4.0"
-uwsgi==2.0.22 ; python_version >= "3.10" and python_version < "4.0"
+typing-extensions==4.9.0 ; python_version >= "3.10" and python_version < "4.0"
webassets==2.0 ; python_version >= "3.10" and python_version < "4.0"
-werkzeug==2.3.7 ; python_version >= "3.10" and python_version < "4.0"
+werkzeug==3.0.1 ; python_version >= "3.10" and python_version < "4.0"
diff --git a/wsgi.py b/wsgi.py
new file mode 100644
index 0000000..631a0e4
--- /dev/null
+++ b/wsgi.py
@@ -0,0 +1,4 @@
+"""Application entry point."""
+from flask_blueprint_tutorial import create_app
+
+app = create_app()