Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Set up Python 3.9
uses: actions/setup-python@v1
- name: Set up Python 3.10
uses: actions/setup-python@v4
with:
python-version: 3.9
python-version: "3.10"
- name: Checkout code
uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Install dependencies
run: |
python -m pip install --upgrade pip
Expand Down
16 changes: 13 additions & 3 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,13 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: ["3.9", "3.10", "3.11", "pypy3.9", "3.12"]
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14", "pypy3.11"]
flask: ["<3.0.0", ">=3.0.0"]
exclude:
- python-version: "3.13"
flask: "<3.0.0"
- python-version: "3.14"
flask: "<3.0.0"
steps:
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
Expand All @@ -28,6 +33,11 @@ jobs:
- name: Install dependencies
run: |
python -m pip install --upgrade pip
# PyPy: pin rpds-py before resolving jsonschema/referencing so pip picks manylinux wheels
# (sdists use maturin; builds are fragile on PyPy). CPython does not need this.
case "${{ matrix.python-version }}" in
pypy3.11) pip install 'rpds-py<0.30' 'readme-renderer>=35,<42' ;;
esac
pip install "flask${{ matrix.flask }}"
pip install ".[test]"
- name: Test with inv
Expand All @@ -41,10 +51,10 @@ jobs:
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'
steps:
- name: Set up Python 3.9
- name: Set up Python 3.12
uses: actions/setup-python@v4
with:
python-version: "3.9"
python-version: "3.12"
- name: Checkout ${{ github.base_ref }}
uses: actions/checkout@v3
with:
Expand Down
22 changes: 22 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,28 @@ Releases prior to 0.3.0 were “best effort” filled out, but are missing
some info. If you see your contribution missing info, please open a PR
on the Changelog!

.. _section-1.3.3:
1.3.3
-----
.. _enhancements-1.3.3
Enhancements
~~~~~~~~~~~~

::

* Drop support for Python 3.9 (EOL); require Python 3.10 or newer. [python-restx]
* Declare and test support for Python 3.13 and 3.14 (CPython). [python-restx]
* Expand GitHub Actions and tox coverage: PyPy 3.11 with both Flask 2.x and Flask 3.x; exclude Flask 2 on 3.13/3.14 where unsupported. [python-restx]
* Refresh test and release tooling (pytest, pytest-benchmark, pytest-profiling, twine) for newer interpreters. GitHub Actions pre-installs compatible ``rpds-py`` (and ``readme-renderer`` for PyPy 3.11) for PyPy jobs; tox pins ``rpds-py`` for local PyPy envs. [python-restx]

.. _bug_fixes-1.3.3
Bug Fixes
~~~~~~~~~

::

* Adjust field tests for Python 3.14 (``staticmethod`` around ``functools.partial`` used as a class attribute). [python-restx]

.. _section-1.3.1:
1.3.1
-----
Expand Down
2 changes: 1 addition & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ and expose its documentation properly using `Swagger`_.
Compatibility
=============

Flask-RESTX requires Python 3.9+.
Flask-RESTX requires Python 3.10+.

On Flask Compatibility
======================
Expand Down
2 changes: 1 addition & 1 deletion bumpr.rc
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ vcs = git
commit = true
tag = true
push = true
tests = tox -e py39
tests = tox -e py310
clean =
inv clean
files =
Expand Down
2 changes: 1 addition & 1 deletion doc/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ development and to support our users.
Compatibility
=============

Flask-RESTX requires Python 3.9+.
Flask-RESTX requires Python 3.10+.


Installation
Expand Down
2 changes: 1 addition & 1 deletion doc/installation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,5 @@ The development version can be downloaded from
pip install -e .[dev,test]


Flask-RESTX requires Python version 3.9+.
Flask-RESTX requires Python version 3.10+.
It's also working with PyPy and PyPy3.
5 changes: 2 additions & 3 deletions flask_restx/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
from .marshalling import marshal
from .utils import camel_to_dash, not_none


__all__ = (
"Raw",
"String",
Expand Down Expand Up @@ -880,10 +879,10 @@ def output(self, key, obj, ordered=False):
# complexity to O(n)
if ordered:
# Get first element if respecting order
(objkey, val) = self._flat.pop(0)
objkey, val = self._flat.pop(0)
else:
# Previous default retained
(objkey, val) = self._flat.pop()
objkey, val = self._flat.pop()
if (
objkey not in self._cache
and objkey not in self.exclude
Expand Down
1 change: 0 additions & 1 deletion flask_restx/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
from .utils import not_none
from ._http import HTTPStatus


RE_REQUIRED = re.compile(r"u?\'(?P<name>.*)\' is a required property", re.I | re.U)


Expand Down
1 change: 0 additions & 1 deletion flask_restx/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@

from ._http import HTTPStatus


FIRST_CAP_RE = re.compile("(.)([A-Z][a-z]+)")
ALL_CAP_RE = re.compile("([a-z0-9])([A-Z])")

Expand Down
9 changes: 4 additions & 5 deletions requirements/test.pip
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
blinker
Faker==2.0.0
mock==3.0.5
pytest==7.0.1
pytest-benchmark==3.4.1
pytest==8.4.2
pytest-benchmark==5.2.3
pytest-cov==4.0.0
pytest-flask==1.3.0
pytest-mock==3.6.1
pytest-profiling==1.7.0
pytest-profiling==1.8.1
invoke==2.2.0
twine==3.8.0
twine==6.2.0
setuptools
backports.zoneinfo;python_version<"3.9"
5 changes: 3 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,13 +102,14 @@ def pip(filename):
"Topic :: System :: Software Distribution",
"Programming Language :: Python",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3.14",
"Programming Language :: Python :: Implementation :: PyPy",
"Topic :: Software Development :: Libraries :: Python Modules",
"License :: OSI Approved :: BSD License",
],
python_requires=">=3.9",
python_requires=">=3.10",
)
8 changes: 4 additions & 4 deletions tests/test_fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -693,7 +693,7 @@ def test_unsupported_value_format(self):


class FormatedStringFieldTest(StringTestMixin, BaseFieldTestMixin, FieldTestCase):
field_class = partial(fields.FormattedString, "Hello {name}")
field_class = staticmethod(partial(fields.FormattedString, "Hello {name}"))

def test_defaults(self):
field = fields.FormattedString("Hello {name}")
Expand Down Expand Up @@ -731,7 +731,7 @@ def test_tuple(self):


class UrlFieldTest(StringTestMixin, BaseFieldTestMixin, FieldTestCase):
field_class = partial(fields.Url, "endpoint")
field_class = staticmethod(partial(fields.Url, "endpoint"))

def test_defaults(self):
field = fields.Url("endpoint")
Expand Down Expand Up @@ -931,7 +931,7 @@ def test_as_list_is_reusable(self, api):


class ListFieldTest(BaseFieldTestMixin, FieldTestCase):
field_class = partial(fields.List, fields.String)
field_class = staticmethod(partial(fields.List, fields.String))

def test_defaults(self):
field = fields.List(fields.String)
Expand Down Expand Up @@ -1025,7 +1025,7 @@ def test_list_of_raw(self):


class WildcardFieldTest(BaseFieldTestMixin, FieldTestCase):
field_class = partial(fields.Wildcard, fields.String)
field_class = staticmethod(partial(fields.Wildcard, fields.String))

def test_types(self):
with pytest.raises(fields.MarshallingError):
Expand Down
1 change: 0 additions & 1 deletion tests/test_postman.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@

from urllib.parse import parse_qs, urlparse


with open(join(dirname(__file__), "postman-v1.schema.json")) as f:
schema = json.load(f)

Expand Down
18 changes: 6 additions & 12 deletions tests/test_swagger.py
Original file line number Diff line number Diff line change
Expand Up @@ -1451,23 +1451,17 @@ def get(self):

description = lambda m: data["paths"]["/description/"][m]["description"] # noqa

assert description("get") == dedent(
"""\
assert description("get") == dedent("""\
Parent description.
Some details"""
)
Some details""")

assert description("post") == dedent(
"""\
assert description("post") == dedent("""\
Parent description.
Extra description"""
)
Extra description""")

assert description("delete") == dedent(
"""\
assert description("delete") == dedent("""\
Parent description.
A delete operation"""
)
A delete operation""")

assert description("put") == "Parent description."
assert "description" not in data["paths"]["/descriptionless/"]["get"]
Expand Down
13 changes: 10 additions & 3 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@

[tox]
envlist =
py{39, 310, 311}-flask2,
py{311, 312}-flask3
pypy3.9
py{310, 311, 312}-flask2,
py{311, 312, 313, 314}-flask3
pypy3.11-flask2
pypy3.11-flask3
doc

[testenv]
Expand All @@ -18,6 +19,12 @@ deps =
-r{toxinidir}/requirements/test.pip
-r{toxinidir}/requirements/develop.pip

[testenv:pypy3.11-flask{2,3}]
deps =
{[testenv]deps}
rpds-py<0.30
commands = {posargs:inv test}

[testenv:doc]
changedir = doc
deps = .[doc]
Expand Down
Loading