Switch to pyproject.toml

This commit is contained in:
Taylor H. Perkins 2023-01-24 11:47:53 -08:00
commit ffb4293fca
21 changed files with 200 additions and 132 deletions

View file

@ -1,3 +1,4 @@
[flake8] [flake8]
extend-select = extend-select =
# bugbear # bugbear

View file

@ -52,7 +52,7 @@ jobs:
uses: actions/cache@58c146cc91c5b9e778e71775dfe9bf1442ad9a12 uses: actions/cache@58c146cc91c5b9e778e71775dfe9bf1442ad9a12
with: with:
path: ./.mypy_cache path: ./.mypy_cache
key: mypy|${{ matrix.python }}|${{ hashFiles('setup.cfg') }} key: mypy|${{ matrix.python }}|${{ hashFiles('pyproject.toml') }}
if: matrix.tox == 'typing' if: matrix.tox == 'typing'
- run: pip install tox - run: pip install tox
- run: tox run -e ${{ matrix.tox }} - run: tox run -e ${{ matrix.tox }}

View file

@ -1,5 +1,5 @@
ci: ci:
autoupdate_branch: "2.1.x" autoupdate_branch: "2.2.x"
autoupdate_schedule: monthly autoupdate_schedule: monthly
repos: repos:
- repo: https://github.com/asottile/pyupgrade - repo: https://github.com/asottile/pyupgrade

View file

@ -1,3 +1,13 @@
Version 2.3.0
-------------
Unreleased
- Use modern packaging metadata with ``pyproject.toml`` instead of ``setup.cfg``.
:pr:`4947`
- Ensure subdomains are applied with nested blueprints. :issue:`4834`
Version 2.2.3 Version 2.2.3
------------- -------------

View file

@ -140,6 +140,19 @@ name, and child URLs will be prefixed with the parent's URL prefix.
url_for('parent.child.create') url_for('parent.child.create')
/parent/child/create /parent/child/create
In addition a child blueprint's will gain their parent's subdomain,
with their subdomain as prefix if present i.e.
.. code-block:: python
parent = Blueprint('parent', __name__, subdomain='parent')
child = Blueprint('child', __name__, subdomain='child')
parent.register_blueprint(child)
app.register_blueprint(parent)
url_for('parent.child.create', _external=True)
"child.parent.domain.tld"
Blueprint-specific before request functions, etc. registered with the Blueprint-specific before request functions, etc. registered with the
parent will trigger for the child. If a child does not have an error parent will trigger for the child. If a child does not have an error
handler that can handle a given exception, the parent's will be tried. handler that can handle a given exception, the parent's will be tried.

View file

@ -95,7 +95,7 @@ the ``--debug`` option.
.. code-block:: console .. code-block:: console
$ flask --app hello --debug run $ flask --app hello run --debug
* Serving Flask app "hello" * Serving Flask app "hello"
* Debug mode: on * Debug mode: on
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit) * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
@ -550,7 +550,7 @@ a name such as "flask run".
Click the *Script path* dropdown and change it to *Module name*, then input ``flask``. Click the *Script path* dropdown and change it to *Module name*, then input ``flask``.
The *Parameters* field is set to the CLI command to execute along with any arguments. The *Parameters* field is set to the CLI command to execute along with any arguments.
This example uses ``--app hello --debug run``, which will run the development server in This example uses ``--app hello run --debug``, which will run the development server in
debug mode. ``--app hello`` should be the import or file with your Flask app. debug mode. ``--app hello`` should be the import or file with your Flask app.
If you installed your project as a package in your virtualenv, you may uncheck the If you installed your project as a package in your virtualenv, you may uncheck the

View file

@ -47,12 +47,12 @@ Debug Mode
The :data:`DEBUG` config value is special because it may behave inconsistently if The :data:`DEBUG` config value is special because it may behave inconsistently if
changed after the app has begun setting up. In order to set debug mode reliably, use the changed after the app has begun setting up. In order to set debug mode reliably, use the
``--debug`` option on the ``flask`` command. ``flask run`` will use the interactive ``--debug`` option on the ``flask run`` command. ``flask run`` will use the interactive
debugger and reloader by default in debug mode. debugger and reloader by default in debug mode.
.. code-block:: text .. code-block:: text
$ flask --app hello --debug run $ flask --app hello run --debug
Using the option is recommended. While it is possible to set :data:`DEBUG` in your Using the option is recommended. While it is possible to set :data:`DEBUG` in your
config or code, this is strongly discouraged. It can't be read early by the ``flask run`` config or code, this is strongly discouraged. It can't be read early by the ``flask run``

View file

@ -43,7 +43,7 @@ The debugger is enabled by default when the development server is run in debug m
.. code-block:: text .. code-block:: text
$ flask --app hello --debug run $ flask --app hello run --debug
When running from Python code, passing ``debug=True`` enables debug mode, which is When running from Python code, passing ``debug=True`` enables debug mode, which is
mostly equivalent. mostly equivalent.
@ -72,7 +72,7 @@ which can interfere.
.. code-block:: text .. code-block:: text
$ flask --app hello --debug run --no-debugger --no-reload $ flask --app hello run --debug --no-debugger --no-reload
When running from Python: When running from Python:

View file

@ -108,7 +108,7 @@ To enable debug mode, use the ``--debug`` option.
.. code-block:: text .. code-block:: text
$ flask --app hello --debug run $ flask --app hello run --debug
* Serving Flask app 'hello' * Serving Flask app 'hello'
* Debug mode: on * Debug mode: on
* Running on http://127.0.0.1:5000 (Press CTRL+C to quit) * Running on http://127.0.0.1:5000 (Press CTRL+C to quit)
@ -359,7 +359,7 @@ the application secure. Because of that Flask configures the `Jinja2
Templates can be used to generate any type of text file. For web applications, you'll Templates can be used to generate any type of text file. For web applications, you'll
primarily be generating HTML pages, but you can also generate markdown, plain text for primarily be generating HTML pages, but you can also generate markdown, plain text for
emails, any anything else. emails, and anything else.
For a reference to HTML, CSS, and other web APIs, use the `MDN Web Docs`_. For a reference to HTML, CSS, and other web APIs, use the `MDN Web Docs`_.

View file

@ -24,7 +24,7 @@ debug mode.
.. code-block:: text .. code-block:: text
$ flask --app hello --debug run $ flask --app hello run --debug
This enables debug mode, including the interactive debugger and reloader, and then This enables debug mode, including the interactive debugger and reloader, and then
starts the server on http://localhost:5000/. Use ``flask run --help`` to see the starts the server on http://localhost:5000/. Use ``flask run --help`` to see the

View file

@ -137,7 +137,7 @@ follow the tutorial.
.. code-block:: text .. code-block:: text
$ flask --app flaskr --debug run $ flask --app flaskr run --debug
You'll see output similar to this: You'll see output similar to this:

View file

@ -249,7 +249,7 @@ provide get (list) and post (create) methods.
init_every_request = False init_every_request = False
def __init__(self, model): def __init__(self, model):
self.model self.model = model
self.validator = generate_validator(model) self.validator = generate_validator(model)
def _get_item(self, id): def _get_item(self, id):
@ -297,7 +297,7 @@ provide get (list) and post (create) methods.
db.session.commit() db.session.commit()
return jsonify(item.to_json()) return jsonify(item.to_json())
def register_api(app, model, url): def register_api(app, model, name):
item = ItemAPI.as_view(f"{name}-item", model) item = ItemAPI.as_view(f"{name}-item", model)
group = GroupAPI.as_view(f"{name}-group", model) group = GroupAPI.as_view(f"{name}-group", model)
app.add_url_rule(f"/{name}/<int:id>", view_func=item) app.add_url_rule(f"/{name}/<int:id>", view_func=item)

View file

@ -48,7 +48,7 @@ Run
.. code-block:: text .. code-block:: text
$ flask --app flaskr init-db $ flask --app flaskr init-db
$ flask --app flaskr --debug run $ flask --app flaskr run --debug
Open http://127.0.0.1:5000 in a browser. Open http://127.0.0.1:5000 in a browser.

94
pyproject.toml Normal file
View file

@ -0,0 +1,94 @@
[project]
name = "Flask"
description = "A simple framework for building complex web applications."
readme = "README.rst"
license = {text = "BSD-3-Clause"}
maintainers = [{name = "Pallets", email = "contact@palletsprojects.com"}]
authors = [{name = "Armin Ronacher", email = "armin.ronacher@active-4.com"}]
classifiers = [
"Development Status :: 5 - Production/Stable",
"Environment :: Web Environment",
"Framework :: Flask",
"Intended Audience :: Developers",
"License :: OSI Approved :: BSD License",
"Operating System :: OS Independent",
"Programming Language :: Python",
"Topic :: Internet :: WWW/HTTP :: Dynamic Content",
"Topic :: Internet :: WWW/HTTP :: WSGI",
"Topic :: Internet :: WWW/HTTP :: WSGI :: Application",
"Topic :: Software Development :: Libraries :: Application Frameworks",
]
requires-python = ">=3.7"
dependencies = [
"Werkzeug>=2.2.2",
"Jinja2>=3.0",
"itsdangerous>=2.0",
"click>=8.0",
"importlib-metadata>=3.6.0; python_version < '3.10'",
]
dynamic = ["version"]
[project.urls]
Donate = "https://palletsprojects.com/donate"
Documentation = "https://flask.palletsprojects.com/"
Changes = "https://flask.palletsprojects.com/changes/"
"Source Code" = "https://github.com/pallets/flask/"
"Issue Tracker" = "https://github.com/pallets/flask/issues/"
Twitter = "https://twitter.com/PalletsTeam"
Chat = "https://discord.gg/pallets"
[project.optional-dependencies]
async = ["asgiref>=3.2"]
dotenv = ["python-dotenv"]
[project.scripts]
flask = "flask.cli:main"
[build-system]
requires = ["setuptools"]
build-backend = "setuptools.build_meta"
[tool.setuptools.dynamic]
version = {attr = "flask.__version__"}
[tool.pytest.ini_options]
testpaths = ["tests"]
filterwarnings = ["error"]
[tool.coverage.run]
branch = true
source = ["flask", "tests"]
[tool.coverage.paths]
source = ["src", "*/site-packages"]
[tool.mypy]
python_version = "3.7"
files = ["src/flask"]
show_error_codes = true
pretty = true
#strict = true
allow_redefinition = true
disallow_subclassing_any = true
#disallow_untyped_calls = true
#disallow_untyped_defs = true
#disallow_incomplete_defs = true
no_implicit_optional = true
local_partial_types = true
#no_implicit_reexport = true
strict_equality = true
warn_redundant_casts = true
warn_unused_configs = true
warn_unused_ignores = true
#warn_return_any = true
#warn_unreachable = true
[[tool.mypy.overrides]]
module = [
"asgiref.*",
"blinker.*",
"dotenv.*",
"cryptography.*",
"importlib_metadata",
]
ignore_missing_imports = true

View file

@ -1,96 +0,0 @@
[metadata]
name = Flask
version = attr: flask.__version__
url = https://palletsprojects.com/p/flask
project_urls =
Donate = https://palletsprojects.com/donate
Documentation = https://flask.palletsprojects.com/
Changes = https://flask.palletsprojects.com/changes/
Source Code = https://github.com/pallets/flask/
Issue Tracker = https://github.com/pallets/flask/issues/
Twitter = https://twitter.com/PalletsTeam
Chat = https://discord.gg/pallets
license = BSD-3-Clause
author = Armin Ronacher
author_email = armin.ronacher@active-4.com
maintainer = Pallets
maintainer_email = contact@palletsprojects.com
description = A simple framework for building complex web applications.
long_description = file: README.rst
long_description_content_type = text/x-rst
classifiers =
Development Status :: 5 - Production/Stable
Environment :: Web Environment
Framework :: Flask
Intended Audience :: Developers
License :: OSI Approved :: BSD License
Operating System :: OS Independent
Programming Language :: Python
Topic :: Internet :: WWW/HTTP :: Dynamic Content
Topic :: Internet :: WWW/HTTP :: WSGI
Topic :: Internet :: WWW/HTTP :: WSGI :: Application
Topic :: Software Development :: Libraries :: Application Frameworks
[options]
packages = find:
package_dir = = src
include_package_data = True
python_requires = >= 3.7
# Dependencies are in setup.py for GitHub's dependency graph.
[options.packages.find]
where = src
[options.entry_points]
console_scripts =
flask = flask.cli:main
[tool:pytest]
testpaths = tests
filterwarnings =
error
[coverage:run]
branch = True
source =
flask
tests
[coverage:paths]
source =
src
*/site-packages
[mypy]
files = src/flask, tests/typing
python_version = 3.7
show_error_codes = True
allow_redefinition = True
disallow_subclassing_any = True
# disallow_untyped_calls = True
# disallow_untyped_defs = True
# disallow_incomplete_defs = True
no_implicit_optional = True
local_partial_types = True
# no_implicit_reexport = True
strict_equality = True
warn_redundant_casts = True
warn_unused_configs = True
warn_unused_ignores = True
# warn_return_any = True
# warn_unreachable = True
[mypy-asgiref.*]
ignore_missing_imports = True
[mypy-blinker.*]
ignore_missing_imports = True
[mypy-dotenv.*]
ignore_missing_imports = True
[mypy-cryptography.*]
ignore_missing_imports = True
[mypy-importlib_metadata]
ignore_missing_imports = True

View file

@ -1,17 +0,0 @@
from setuptools import setup
# Metadata goes in setup.cfg. These are here for GitHub's dependency graph.
setup(
name="Flask",
install_requires=[
"Werkzeug >= 2.2.2",
"Jinja2 >= 3.0",
"itsdangerous >= 2.0",
"click >= 8.0",
"importlib-metadata >= 3.6.0; python_version < '3.10'",
],
extras_require={
"async": ["asgiref >= 3.2"],
"dotenv": ["python-dotenv"],
},
)

View file

@ -42,7 +42,7 @@ from .templating import render_template_string as render_template_string
from .templating import stream_template as stream_template from .templating import stream_template as stream_template
from .templating import stream_template_string as stream_template_string from .templating import stream_template_string as stream_template_string
__version__ = "2.2.3.dev" __version__ = "2.3.0.dev"
def __getattr__(name): def __getattr__(name):

View file

@ -2451,7 +2451,7 @@ class Flask(Scaffold):
:data:`request` point at the request for the created :data:`request` point at the request for the created
environment. :: environment. ::
with test_request_context(...): with app.test_request_context(...):
generate_report() generate_report()
When using the shell, it may be easier to push and pop the When using the shell, it may be easier to push and pop the

View file

@ -358,6 +358,9 @@ class Blueprint(Scaffold):
:param options: Keyword arguments forwarded from :param options: Keyword arguments forwarded from
:meth:`~Flask.register_blueprint`. :meth:`~Flask.register_blueprint`.
.. versionchanged:: 2.3
Nested blueprints now correctly apply subdomains.
.. versionchanged:: 2.0.1 .. versionchanged:: 2.0.1
Nested blueprints are registered with their dotted name. Nested blueprints are registered with their dotted name.
This allows different blueprints with the same name to be This allows different blueprints with the same name to be
@ -453,6 +456,17 @@ class Blueprint(Scaffold):
for blueprint, bp_options in self._blueprints: for blueprint, bp_options in self._blueprints:
bp_options = bp_options.copy() bp_options = bp_options.copy()
bp_url_prefix = bp_options.get("url_prefix") bp_url_prefix = bp_options.get("url_prefix")
bp_subdomain = bp_options.get("subdomain")
if bp_subdomain is None:
bp_subdomain = blueprint.subdomain
if state.subdomain is not None and bp_subdomain is not None:
bp_options["subdomain"] = bp_subdomain + "." + state.subdomain
elif bp_subdomain is not None:
bp_options["subdomain"] = bp_subdomain
elif state.subdomain is not None:
bp_options["subdomain"] = state.subdomain
if bp_url_prefix is None: if bp_url_prefix is None:
bp_url_prefix = blueprint.url_prefix bp_url_prefix = blueprint.url_prefix

View file

@ -950,6 +950,55 @@ def test_nesting_url_prefixes(
assert response.status_code == 200 assert response.status_code == 200
def test_nesting_subdomains(app, client) -> None:
subdomain = "api"
parent = flask.Blueprint("parent", __name__)
child = flask.Blueprint("child", __name__)
@child.route("/child/")
def index():
return "child"
parent.register_blueprint(child)
app.register_blueprint(parent, subdomain=subdomain)
client.allow_subdomain_redirects = True
domain_name = "domain.tld"
app.config["SERVER_NAME"] = domain_name
response = client.get("/child/", base_url="http://api." + domain_name)
assert response.status_code == 200
def test_child_and_parent_subdomain(app, client) -> None:
child_subdomain = "api"
parent_subdomain = "parent"
parent = flask.Blueprint("parent", __name__)
child = flask.Blueprint("child", __name__, subdomain=child_subdomain)
@child.route("/")
def index():
return "child"
parent.register_blueprint(child)
app.register_blueprint(parent, subdomain=parent_subdomain)
client.allow_subdomain_redirects = True
domain_name = "domain.tld"
app.config["SERVER_NAME"] = domain_name
response = client.get(
"/", base_url=f"http://{child_subdomain}.{parent_subdomain}.{domain_name}"
)
assert response.status_code == 200
response = client.get("/", base_url=f"http://{parent_subdomain}.{domain_name}")
assert response.status_code == 404
def test_unique_blueprint_names(app, client) -> None: def test_unique_blueprint_names(app, client) -> None:
bp = flask.Blueprint("bp", __name__) bp = flask.Blueprint("bp", __name__)
bp2 = flask.Blueprint("bp", __name__) bp2 = flask.Blueprint("bp", __name__)