Skip to content

Commit

Permalink
Merge branch 'master' into SimulateMultipartFile#1010
Browse files Browse the repository at this point in the history
  • Loading branch information
vytas7 authored Dec 27, 2023
2 parents 62275cc + 0648726 commit 5872d3d
Show file tree
Hide file tree
Showing 50 changed files with 585 additions and 230 deletions.
5 changes: 4 additions & 1 deletion .github/workflows/create-wheels.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ jobs:
- "3.8"
- "3.9"
- "3.10"
- "3.11.0-rc - 3.11"
- "3.11"
- "3.12"
architecture:
- x64

Expand Down Expand Up @@ -99,6 +100,7 @@ jobs:
- cp39-cp39
- cp310-cp310
- cp311-cp311
- cp312-cp312
architecture:
- x64

Expand Down Expand Up @@ -230,6 +232,7 @@ jobs:
- cp39-cp39
- cp310-cp310
- cp311-cp311
- cp312-cp312
architecture:
- aarch64
- s390x
Expand Down
3 changes: 2 additions & 1 deletion .github/workflows/mintest.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ jobs:
- "3.8"
- "3.10"
- "3.11"
- "3.12"

steps:
- name: Checkout repo
Expand All @@ -31,7 +32,7 @@ jobs:
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -U tox
pip install -U setuptools tox wheel
python --version
pip --version
tox --version
Expand Down
9 changes: 6 additions & 3 deletions .github/workflows/tests-mailman.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@ name: Run tests (GNU Mailman 3)
on:
# Trigger the workflow on master but also allow it to run manually.
workflow_dispatch:
push:
branches:
- master

# NOTE(vytas): Disabled as it is failing as of 2023-09.
# Maybe @maxking just needs to update the Docker image (?)
# push:
# branches:
# - master

jobs:
run_tox:
Expand Down
6 changes: 6 additions & 0 deletions .github/workflows/tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,12 @@ jobs:
- python-version: "3.11"
os: ubuntu-latest
toxenv: py311_cython
- python-version: "3.12"
os: ubuntu-latest
toxenv: py312
- python-version: "3.12"
os: ubuntu-latest
toxenv: py312_cython
- python-version: "3.10"
os: macos-latest
toxenv: py310_nocover
Expand Down
21 changes: 21 additions & 0 deletions .readthedocs.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Read the Docs configuration file
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details

# Required
version: 2

# Set the version of Python and other tools you might need
build:
os: ubuntu-22.04
tools:
python: "3.10"

# Build documentation in the docs/ directory with Sphinx
sphinx:
configuration: docs/conf.py

# We recommend specifying your dependencies to enable reproducible builds:
# https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html
python:
install:
- requirements: requirements/docs
1 change: 1 addition & 0 deletions AUTHORS
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ listed below by date of first contribution:
* John G G (john-g-g)
* Aryan Iyappan (aryaniyaps)
* Eujin Ong (euj1n0ng)
* Libor Jelínek (liborjelinek)

(et al.)

Expand Down
4 changes: 4 additions & 0 deletions docs/_newsfragments/1977.breakingchange.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Previously, it was possible to create an :class:`~falcon.App` with the
``cors_enable`` option, and add additional :class:`~falcon.CORSMiddleware`,
leading to unexpected behavior and dysfunctional CORS. This combination now
explicitly results in a :class:`ValueError`.
6 changes: 6 additions & 0 deletions docs/_newsfragments/1999.breakingchange.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
The default value of the ``csv`` parameter in
:func:`~falcon.uri.parse_query_string` was changed to ``False``, matching the
default behavior of other parts of the framework (such as
:attr:`req.params <falcon.Request.params>`, the test client, etc).
If the old behavior fits your use case better, pass the ``csv=True`` keyword
argument explicitly.
4 changes: 0 additions & 4 deletions docs/_newsfragments/2051.bugfix.rst

This file was deleted.

6 changes: 0 additions & 6 deletions docs/_newsfragments/2146.bugfix.rst

This file was deleted.

1 change: 0 additions & 1 deletion docs/_newsfragments/2157.bugfix.rst

This file was deleted.

12 changes: 9 additions & 3 deletions docs/api/cors.rst
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,15 @@ Usage
allow_origins='example.com', allow_credentials='*'))
.. note::
Passing the ``cors_enable`` parameter set to ``True`` should be seen as
mutually exclusive with directly passing an instance of
:class:`~falcon.CORSMiddleware` to the application's initializer.
Passing the ``cors_enable`` parameter set to ``True`` is mutually exclusive
with directly passing an instance of :class:`~falcon.CORSMiddleware` to the
application's initializer.

.. versionchanged:: 4.0

Attempt to use the combination of ``cors_enable=True`` and an additional
instance of :class:`~falcon.CORSMiddleware` now results in a
:class:`ValueError`.

CORSMiddleware
--------------
Expand Down
54 changes: 54 additions & 0 deletions docs/changes/3.1.2.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
Changelog for Falcon 3.1.2
==========================

Summary
-------

This is a minor point release fixing a couple of high impact bugs,
as well as publishing binary wheels for the recently released CPython 3.12.


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

- Falcon is now supported (including binary wheels) on CPython 3.12.
A couple of remaining stdlib deprecations from 3.11 and 3.12 will be
addressed in Falcon 4.0.
- As with the previous release, Python 3.5 & 3.6 remain deprecated and
will no longer be supported in Falcon 4.0.
- EOL Python 3.7 will no longer be actively supported in 4.0, but the framework
should still continue to install from source. We may remove the support for
3.7 altogether later in the 4.x series if we are faced with incompatible
ecosystem changes in typing, Cython, etc.


Fixed
-----

- Some essential files were unintentionally omitted from the source distribution
archive, rendering it unsuitable to run the test suite off.
This has been fixed, and the ``sdist`` tarball should now be usable as a base
for packaging Falcon in OS distributions. (`#2051 <https://github.com/falconry/falcon/issues/2051>`__)
- :ref:`WebSocket <ws>` implementation has been fixed to properly handle
:class:`~falcon.HTTPError` and :class:`~falcon.HTTPStatus` exceptions raised by
custom :func:`error handlers <falcon.asgi.App.add_error_handler>`.
The WebSocket connection is now correctly closed with an appropriate code
instead of bubbling up an unhandled error to the application server. (`#2146 <https://github.com/falconry/falcon/issues/2146>`__)
- Falcon's :class:`~falcon.testing.TestClient` mimics the behavior of real WSGI
servers (and the WSGI spec) by presenting the ``PATH_INFO`` CGI variable
already in the percent-decoded form. However, the client also used to
indiscriminately set the non-standard ``RAW_URI`` CGI variable to ``/``, which
made writing tests for apps :ref:`decoding raw URL path <raw_url_path_recipe>`
cumbersome. This has been fixed, and the raw path of a simulated request is now
preserved in ``RAW_URI``. (`#2157 <https://github.com/falconry/falcon/issues/2157>`__)


Contributors to this Release
----------------------------

Many thanks to those who contributed to this bugfix release:

- `CaselIT <https://github.com/CaselIT>`__
- `kgriffs <https://github.com/kgriffs>`__
- `liborjelinek <https://github.com/liborjelinek>`__
- `vytas7 <https://github.com/vytas7>`__
11 changes: 11 additions & 0 deletions docs/changes/3.1.3.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
Changelog for Falcon 3.1.3
==========================

Summary
-------

This is a minor bugfix release that only pins the ``pytest-asyncio`` test
dependency in order to prevent an incompatible version from interfering with
the build workflow.

This release is otherwise identical to :doc:`Falcon 3.1.2 <3.1.2>`.
5 changes: 5 additions & 0 deletions docs/changes/4.0.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,12 @@ Changes to Supported Platforms
------------------------------

- CPython 3.11 is now fully supported. (`#2072 <https://github.com/falconry/falcon/issues/2072>`__)
- CPython 3.12 will be fully supported. (`#2196 <https://github.com/falconry/falcon/issues/2196>`__)
- End-of-life Python 3.5 & 3.6 are no longer supported. (`#2074 <https://github.com/falconry/falcon/pull/2074>`__)
- Python 3.7 is no longer actively supported, but the framework should still
continue to install from source. We may remove the support for 3.7 altogether
later in the 4.x series if we are faced with incompatible ecosystem changes
in typing, Cython, etc.


.. towncrier release notes start
Expand Down
2 changes: 2 additions & 0 deletions docs/changes/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ Changelogs
.. toctree::

4.0.0 <4.0.0>
3.1.3 <3.1.3>
3.1.2 <3.1.2>
3.1.1 <3.1.1>
3.1.0 <3.1.0>
3.0.1 <3.0.1>
Expand Down
6 changes: 3 additions & 3 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,13 +82,13 @@

# General information about the project.
project = 'Falcon'
copyright = '{year} Falcon Contributors'.format(year=datetime.utcnow().year)
copyright = '{year} Falcon Contributors'.format(year=datetime.now().year)

# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.

cfg = configparser.SafeConfigParser()
cfg = configparser.ConfigParser()
cfg.read('../setup.cfg')
tag = cfg.get('egg_info', 'tag_build')

Expand Down Expand Up @@ -168,7 +168,7 @@
'github_user': 'falconry',
'github_repo': 'falcon',
'github_button': False,
'github_banner': not dash_build,
'github_banner': False,
'fixed_sidebar': False,
'show_powered_by': False,
'extra_nav_links': OrderedDict(
Expand Down
2 changes: 1 addition & 1 deletion docs/ext/rfc.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
import re


RFC_PATTERN = re.compile('RFC (\d{4}), Section ([\d\.]+)')
RFC_PATTERN = re.compile(r'RFC (\d{4}), Section ([\d\.]+)')


def _render_section(section_number, rfc_number):
Expand Down
9 changes: 8 additions & 1 deletion examples/asgilook/tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,15 @@ def storage_path(tmpdir_factory):

@pytest.fixture
def client(predictable_uuid, storage_path):
# NOTE(vytas): Unlike the sync FakeRedis, fakeredis.aioredis.FakeRedis
# seems to share a global state in 2.17.0 (by design or oversight).
# Make sure we initialize a new fake server for every test case.
def fake_redis_from_url(*args, **kwargs):
server = fakeredis.FakeServer()
return fakeredis.aioredis.FakeRedis(server=server)

config = Config()
config.redis_from_url = fakeredis.aioredis.FakeRedis.from_url
config.redis_from_url = fake_redis_from_url
config.redis_host = 'redis://localhost'
config.storage_path = storage_path
config.uuid_generator = predictable_uuid
Expand Down
32 changes: 29 additions & 3 deletions falcon/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import re
import traceback
from typing import Callable, Iterable, Optional, Tuple, Type, Union
import warnings

from falcon import app_helpers as helpers
from falcon import constants
Expand Down Expand Up @@ -243,6 +244,7 @@ def __init__(
cors_enable=False,
sink_before_static_route=True,
):
self._cors_enable = cors_enable
self._sink_before_static_route = sink_before_static_route
self._sinks = []
self._static_routes = []
Expand Down Expand Up @@ -446,7 +448,7 @@ def __call__( # noqa: C901
def router_options(self):
return self._router.options

def add_middleware(self, middleware: object) -> None:
def add_middleware(self, middleware: Union[object, Iterable]) -> None:
"""Add one or more additional middleware components.
Arguments:
Expand All @@ -460,10 +462,28 @@ def add_middleware(self, middleware: object) -> None:
# the chance that middleware may be None.
if middleware:
try:
self._unprepared_middleware += middleware
middleware = list(middleware) # type: ignore
except TypeError:
# middleware is not iterable; assume it is just one bare component
self._unprepared_middleware.append(middleware)
middleware = [middleware]

if (
self._cors_enable
and len(
[
mc
for mc in self._unprepared_middleware + middleware
if isinstance(mc, CORSMiddleware)
]
)
> 1
):
raise ValueError(
'CORSMiddleware is not allowed in conjunction with '
'cors_enable (which already constructs one instance)'
)

self._unprepared_middleware += middleware

# NOTE(kgriffs): Even if middleware is None or an empty list, we still
# need to make sure self._middleware is initialized if this is the
Expand Down Expand Up @@ -828,6 +848,12 @@ def handler(req, resp, ex, params):
('ex',),
('exception',),
) or arg_names[1:3] in (('req', 'resp'), ('request', 'response')):
warnings.warn(
f'handler is using a deprecated signature; please order its '
f'arguments as {handler.__qualname__}(req, resp, ex, params). '
f'This compatibility shim will be removed in Falcon 5.0.',
deprecation.DeprecatedWarning,
)
handler = wrap_old_handler(handler)

exception_tuple: tuple
Expand Down
4 changes: 3 additions & 1 deletion falcon/asgi/ws.py
Original file line number Diff line number Diff line change
Expand Up @@ -530,12 +530,14 @@ class WebSocketOptions:

__slots__ = ['error_close_code', 'max_receive_queue', 'media_handlers']

def __init__(self):
def __init__(self) -> None:
try:
import msgpack
except ImportError:
msgpack = None

bin_handler: media.BinaryBaseHandlerWS

if msgpack:
bin_handler = media.MessagePackHandlerWS()
else:
Expand Down
2 changes: 1 addition & 1 deletion falcon/cyutil/uri.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ cdef cy_parse_query_string(unsigned char* data, Py_ssize_t length,


def parse_query_string(unicode query_string not None, bint keep_blank=False,
bint csv=True):
bint csv=False):
cdef bytes byte_string = query_string.encode('utf-8')
cdef unsigned char* data = byte_string
return cy_parse_query_string(data, len(byte_string), keep_blank, csv)
Expand Down
6 changes: 3 additions & 3 deletions falcon/inspect.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@
"""Inspect utilities for falcon applications."""
from functools import partial
import inspect
from typing import Callable
from typing import Dict
from typing import Callable # NOQA: F401
from typing import Dict # NOQA: F401
from typing import List
from typing import Optional
from typing import Type
from typing import Type # NOQA: F401

from falcon import app_helpers
from falcon.app import App
Expand Down
Loading

0 comments on commit 5872d3d

Please sign in to comment.