Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/master'
Browse files Browse the repository at this point in the history
  • Loading branch information
EricGoulart committed Oct 29, 2024
2 parents c499cc2 + b65571b commit 7510647
Show file tree
Hide file tree
Showing 13 changed files with 214 additions and 51 deletions.
46 changes: 46 additions & 0 deletions .github/workflows/test-dist.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# Test source distribution and pure-Python wheel.
name: test-dist

on:
push:
branches:
- "*"

jobs:
test-dist:
name: test-${{ matrix.build }}
runs-on: ubuntu-latest
strategy:
matrix:
build:
- sdist
- wheel

steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 2

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.12"

- name: Build dist
env:
FALCON_DISABLE_CYTHON: "Y"
run: |
pip install --upgrade pip
pip install --upgrade build
python -m build --${{ matrix.build }}
- name: Test sdist
if: matrix.build == 'sdist'
run: |
tools/test_dist.py dist/*.tar.gz
- name: Test pure-Python wheel
if: matrix.build == 'wheel'
run: |
tools/test_dist.py dist/*.whl
2 changes: 1 addition & 1 deletion .github/workflows/tox-sdist.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ on:

jobs:
run_tox:
name: tox (default envlist on ${{matrix.python-version}})
name: tox (python${{ matrix.python-version }})
runs-on: "ubuntu-latest"
strategy:
fail-fast: false
Expand Down
3 changes: 2 additions & 1 deletion .readthedocs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ build:
# Build documentation in the docs/ directory with Sphinx
sphinx:
configuration: docs/conf.py

formats:
- pdf
# We recommend specifying your dependencies to enable reproducible builds:
# https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html
python:
Expand Down
115 changes: 83 additions & 32 deletions docs/changes/4.0.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,30 +4,45 @@ Changelog for Falcon 4.0.0
Summary
-------

Falcon ``4.0.0b4`` is hopefully the final beta release before moving forward to
a release candidate.

As Falcon 4.0 is now feature-complete, we would really be thankful if you
could test this beta release with your apps, and
:ref:`let us know if you run into any issues <chat>`!
Please also check the list of **breaking changes** below.

If you make use of type annotations in your Falcon app, please run your type
checker of choice without any *typeshed* extensions for Falcon, and
:ref:`report back to us <chat>` how it went!

As always, you can grab the new release
`from PyPI <https://pypi.org/project/falcon/4.0.0b4/>`__::

pip install falcon==4.0.0b4

(Alternatively, continue reading these docs for more
:ref:`installation options <install>`.)

This release would have not been possible without contributions from the
fantastic group of 30 community members and maintainers.

Thank You!
We are happy to present Falcon 4.0, a new major version of the framework that
brings a couple of commonly requested features including support for matching
multiple path segments (using :class:`~falcon.routing.PathConverter`), and
a fully typed codebase. (Please read more about typing in the notes below.)

The timeframe for Falcon 4.0 was challenging due to the need to balance our
high standards with the CPython 3.13 timeline. We aimed to deliver the main
development branch in this release, without resorting to another compatibility
micro update (as we did with Falcon 3.1.1-3.1.3). Following community feedback,
we also want to improve our overall release schedule by shipping smaller
increments more often.
To support this goal, we have made several tooling and testing improvements:
the build process for :ref:`binary wheels <binary_wheels>` has been simplified
using `cibuildwheel <https://cibuildwheel.pypa.io/>`__, and our test suite now
only requires ``pytest`` as a hard dependency. Additionally, you can run
``pytest`` against our tests from any directory. We hope that these changes
should also benefit packaging Falcon in Linux distributions.

As with every SemVer major release, we have removed a number of previously
deprecated functions, classes, compatibility shims, as well as made other
potentially breaking changes that we could not risk in a minor version.
If you have been paying attention the deprecation warnings from the 3.x series,
the impact should be minimal, but please do take a look at the list of breaking
changes below.

This release would not have been possible without the numerous contributions
from our community. This release alone comprises a number of pull requests
submitted by a group of 30 talented individuals. What is more, we were
particularly impressed by the high-quality discussions and code submissions
during our
`EuroPython 2024 Sprint <https://ep2024.europython.eu/sprints#the-falcon-web-framework>`__.
Some notable sprint contributions include CHIPS support, and a new
:ref:`WebSocket Tutorial <tutorial-ws>`, among others.
In fact, according to the
`statistics on GitHub <https://github.com/falconry/falcon/graphs/contributors>`__,
we are thrilled to report that the total number of Falcon
contributors has now exceeded 200. We find it fascinating that our framework
has become a collaborative effort involving so many individuals, and would like
to thank everyone who has made this release possible!


Changes to Supported Platforms
Expand All @@ -43,14 +58,16 @@ Changes to Supported Platforms
(`#2074 <https://github.com/falconry/falcon/pull/2074>`__,
`#2273 <https://github.com/falconry/falcon/pull/2273>`__)
- End-of-life Python 3.8 is no longer actively supported, but
the framework should still continue to install from source and function.
the framework should still continue to install from the pure-Python wheel or
source distribution, and function normally.
- The Falcon 4.x series is guaranteed to support CPython 3.10 and
PyPy3.10 (v7.3.16).
This means that we may drop the support for Python 3.8 & 3.9 altogether in a
later 4.x release, especially if we are faced with incompatible ecosystem
changes in typing, Cython, etc.

Typing support

Typing Support
--------------

Type checking support was introduced in version 4.0. While most of the library is
Expand Down Expand Up @@ -79,6 +96,46 @@ runtime behavior, but may surface new or different errors with type checkers.
Also, make sure to :ref:`let us know <chat>` which essential aliases are
missing from the public interface!

Known typing limitations
^^^^^^^^^^^^^^^^^^^^^^^^

Falcon's emphasis on flexibility and performance has presented certain
challenges when it comes to adding type annotations to the existing code base.
One notable limitation involves using custom :class:`~falcon.Request` and/or
:class:`~falcon.Response` types in callbacks that are passed back
to the framework, such as when adding an
:meth:`error handler <falcon.App.add_error_handler>`.

For instance, the following application might unexpectedly not pass type
checking:

.. code-block:: python
from typing import Any
from falcon import App, HTTPInternalServerError, Request, Response
class MyRequest(Request):
...
def handle_os_error(req: MyRequest, resp: Response, ex: Exception,
params: dict[str, Any]) -> None:
raise HTTPInternalServerError(title='OS error!') from ex
app = App(request_type=MyRequest)
app.add_error_handler(OSError, handle_os_error)
(Please also see the following GitHub issue:
`#2372 <https://github.com/falconry/falcon/issues/2372>`__.)

.. important::
This is only a typing limitation that has no effect outside of type
checking -- the above ``app`` will run just fine!


Breaking Changes
----------------

Expand Down Expand Up @@ -407,12 +464,6 @@ Misc
Contributors to this Release
----------------------------

.. note::
If we missed you below, don’t worry!

We will refresh the full list of contributors before the 4.0.0 final
release.

Many thanks to all of our talented and stylish contributors for this release!

- `aarcex3 <https://github.com/aarcex3>`__
Expand Down
17 changes: 17 additions & 0 deletions docs/changes/4.0.1.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
Changelog for Falcon 4.0.1
==========================

Summary
-------

This is a minor point release addressing a Python distribution issue in
Falcon 4.0.0.


Fixed
-----

- Installing Falcon 4.0.0 unexpectedly copies many unintended directories from the
source tree to the venv's ``site-packages``. This issue has been rectified, and
our CI has been extended with new tests (that verify what is actually installed
from the distribution) to make sure this regression does not resurface. (`#2384 <https://github.com/falconry/falcon/issues/2384>`__)
25 changes: 25 additions & 0 deletions docs/changes/4.1.0.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
Changelog for Falcon 4.1.0
==========================

Summary
-------

Falcon 4.1 is in development. The progress is tracked via the
`Version 4.1 milestone <https://github.com/falconry/falcon/milestone/41>`__
on GitHub.


Changes to Supported Platforms
------------------------------

.. NOTE(vytas): No changes to the supported platforms (yet).
.. towncrier release notes start
Contributors to this Release
----------------------------

Many thanks to all of our talented and stylish contributors for this release!

- `vytas7 <https://github.com/vytas7>`__
2 changes: 2 additions & 0 deletions docs/changes/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ Changelogs

.. toctree::

4.1.0 <4.1.0>
4.0.1 <4.0.1>
4.0.0 <4.0.0>
3.1.3 <3.1.3>
3.1.2 <3.1.2>
Expand Down
2 changes: 1 addition & 1 deletion docs/user/install.rst
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ Binary Wheels
^^^^^^^^^^^^^

Binary Falcon wheels are automatically built for many CPython platforms,
courtesy of `cibuildwheel <https://cibuildwheel.pypa.io/en/stable/>`__.
courtesy of `cibuildwheel <https://cibuildwheel.pypa.io/>`__.

.. wheels:: .github/workflows/cibuildwheel.yaml

Expand Down
6 changes: 3 additions & 3 deletions docs/user/recipes/request-id.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@ to every log entry.

If you wish to trace each request throughout your application, including
from within components that are deeply nested or otherwise live outside of the
normal request context, you can use a `thread-local`_ context object to store
normal request context, you can use a `contextvars`_ object to store
the request ID:

.. literalinclude:: ../../../examples/recipes/request_id_context.py
:language: python

Then, you can create a :ref:`middleware <middleware>` class to generate a
unique ID for each request, persisting it in the thread local:
unique ID for each request, persisting it in the `contextvars` object:

.. literalinclude:: ../../../examples/recipes/request_id_middleware.py
:language: python
Expand Down Expand Up @@ -48,4 +48,4 @@ In a pinch, you can also output the request ID directly:
.. literalinclude:: ../../../examples/recipes/request_id_log.py
:language: python

.. _thread-local: https://docs.python.org/3/library/threading.html#thread-local-data
.. _contextvars: https://docs.python.org/3/library/contextvars.html
8 changes: 4 additions & 4 deletions examples/recipes/request_id_context.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
# context.py

import threading
import contextvars


class _Context:
def __init__(self):
self._thread_local = threading.local()
self._request_id_var = contextvars.ContextVar('request_id', default=None)

@property
def request_id(self):
return getattr(self._thread_local, 'request_id', None)
return self._request_id_var.get()

@request_id.setter
def request_id(self, value):
self._thread_local.request_id = value
self._request_id_var.set(value)


ctx = _Context()
2 changes: 1 addition & 1 deletion falcon/version.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,5 @@

"""Falcon version."""

__version__ = '4.0.0b4'
__version__ = '4.1.0.dev1'
"""Current version of Falcon."""
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ zip-safe = false
version = {attr = "falcon.version.__version__"}

[tool.setuptools.packages.find]
exclude = ["examples", "tests"]
include = ["falcon*"]

[tool.mypy]
exclude = [
Expand Down Expand Up @@ -116,7 +116,7 @@ exclude = ["examples", "tests"]
[tool.towncrier]
package = "falcon"
package_dir = ""
filename = "docs/changes/4.0.0.rst"
filename = "docs/changes/4.1.0.rst"
directory = "docs/_newsfragments"
issue_format = "`#{issue} <https://github.com/falconry/falcon/issues/{issue}>`__"

Expand Down
33 changes: 27 additions & 6 deletions tools/test_dist.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,22 +15,43 @@
REQUIREMENTS = FALCON_ROOT / 'requirements' / 'cibwtest'
TESTS = FALCON_ROOT / 'tests'

EXPECTED_SCRIPTS = set({'falcon-bench', 'falcon-inspect-app', 'falcon-print-routes'})
EXPECTED_PACKAGES = set({'falcon'})


def test_package(package):
with tempfile.TemporaryDirectory() as tmpdir:
venv = pathlib.Path(tmpdir) / 'venv'
venv_bin = venv / 'bin'
venv_pip = venv_bin / 'pip'
subprocess.check_call((sys.executable, '-m', 'venv', venv))
logging.info(f'Created a temporary venv in {venv}.')

subprocess.check_call((venv / 'bin' / 'pip', 'install', '--upgrade', 'pip'))
subprocess.check_call((venv / 'bin' / 'pip', 'install', '-r', REQUIREMENTS))
subprocess.check_call((venv_pip, 'install', '--upgrade', 'pip'))
subprocess.check_call((venv_pip, 'install', '-r', REQUIREMENTS))
logging.info(f'Installed test requirements in {venv}.')
subprocess.check_call(
(venv / 'bin' / 'pip', 'install', package),
)

(venv_site_pkg,) = venv.glob('lib/python*/site-packages')
bin_before = {path.name for path in venv_bin.iterdir()}
pkg_before = {path.name for path in venv_site_pkg.iterdir()}

subprocess.check_call((venv_pip, 'install', package))
logging.info(f'Installed {package} into {venv}.')

subprocess.check_call((venv / 'bin' / 'pytest', TESTS), cwd=venv)
bin_after = {path.name for path in venv_bin.iterdir()}
assert bin_after - bin_before == EXPECTED_SCRIPTS, (
f'Unexpected scripts installed in {venv_bin} from {package}: '
f'{bin_after - bin_before - EXPECTED_SCRIPTS}'
)
pkg_after = {
path.name for path in venv_site_pkg.iterdir() if path.suffix != '.dist-info'
}
assert pkg_after - pkg_before == EXPECTED_PACKAGES, (
f'Unexpected packages installed in {venv_site_pkg} from {package}: '
f'{pkg_after - pkg_before - EXPECTED_PACKAGES}'
)

subprocess.check_call((venv_bin / 'pytest', TESTS), cwd=venv)
logging.info(f'{package} passes tests.')


Expand Down

0 comments on commit 7510647

Please sign in to comment.