diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 64ef1bffd..b816291e8 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -39,15 +39,14 @@ jobs: - name: "Linux" runner: "ubuntu-latest" cpythons: - - "3.9" - "3.10" - "3.11" - "3.12" - "3.13" - "3.14" tox-post-environments: - - "py3.9-mindeps" - - "py3.9-orjson" + - "py3.10-mindeps" + - "py3.10-orjson" - "py3.14-orjson" - "py3.11-sphinxext" - "doctest" @@ -66,10 +65,10 @@ jobs: - name: "Windows" runner: "windows-latest" cpythons: - - "3.9" + - "3.10" - "3.11" tox-post-environments: - - "py3.9-mindeps" + - "py3.10-mindeps" - "py3.14-orjson" - "py3.11-sphinxext" - "doctest" @@ -78,12 +77,12 @@ jobs: - name: "Quality" runner: "ubuntu-latest" cpythons: - - "3.9" + - "3.10" - "3.14" tox-environments: - "check-min-python-is-tested" - "mypy-py3.14" - - "mypy-py3.9" + - "mypy-py3.10" - "mypy-test" - "mypy-docs" - "poetry-check" diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index db793b0d9..dfc38b709 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -20,7 +20,7 @@ repos: rev: v3.21.2 hooks: - id: pyupgrade - args: ["--py39-plus"] + args: ["--py310-plus"] - repo: https://github.com/psf/black-pre-commit-mirror rev: 26.10.0 hooks: diff --git a/changelog.d/20260923_110938_sirosen_drop_py39.rst b/changelog.d/20260923_110938_sirosen_drop_py39.rst new file mode 100644 index 000000000..90ab147ea --- /dev/null +++ b/changelog.d/20260923_110938_sirosen_drop_py39.rst @@ -0,0 +1,4 @@ +Python Support +-------------- + +- Removed support for Python 3.9. (:pr:`NUMBER`) diff --git a/pyproject.toml b/pyproject.toml index 5f6f6b030..602d2810a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -15,16 +15,15 @@ classifiers = [ "Intended Audience :: Developers", "License :: OSI Approved :: Apache Software License", "Programming Language :: Python", - "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", ] -requires-python = ">=3.9" +requires-python = ">=3.10" dependencies = [ - "requests>=2.19.1,<3.0.0", + "requests>=2.27.0,<3.0.0", "pyjwt[crypto]>=2.0.0,<3.0.0", # cryptography 3.4.0 is known-bugged, see: # https://github.com/pyca/cryptography/issues/5756 @@ -34,8 +33,6 @@ dependencies = [ # depend on the latest version of typing-extensions on python versions which do # not have all of the typing features we use 'typing_extensions>=4.0; python_version<"3.11"', - # python versions older than 3.9 don't have importlib.resources - 'importlib_resources>=5.12.0; python_version<"3.9"', ] [project.readme] @@ -65,10 +62,7 @@ test = [ ] test-mindeps = [ {include-group = "test"}, - # this version of requests is newer than the minimum in package data - # however, if we pin back to 2.19.1, we break 'responses' behaviors used by the - # testsuite - "requests==2.22.0", + "requests==2.27.0", "pyjwt==2.0.0", "cryptography==3.3.1", "typing_extensions==4.0", diff --git a/requirements/py3.9/test-mindeps.txt b/requirements/py3.10/test-mindeps.txt similarity index 71% rename from requirements/py3.9/test-mindeps.txt rename to requirements/py3.10/test-mindeps.txt index b870f0ff4..6d00af23e 100644 --- a/requirements/py3.9/test-mindeps.txt +++ b/requirements/py3.10/test-mindeps.txt @@ -1,16 +1,16 @@ # -# This file is autogenerated by pip-compile with Python 3.9 +# This file is autogenerated by pip-compile with Python 3.10 # by the following command: # # tox p -m freezedeps # -certifi==2026.5.20 +certifi==2026.7.22 # via requests -cffi==2.0.0 +cffi==2.1.1 # via cryptography -chardet==3.0.4 +charset-normalizer==2.0.12 # via requests -coverage==7.10.7 +coverage==7.16.1 # via -r .test-mindeps.in cryptography==3.3.1 # via -r .test-mindeps.in @@ -20,34 +20,32 @@ execnet==2.1.2 # via pytest-xdist flaky==3.8.1 # via -r .test-mindeps.in -idna==2.8 +idna==3.20 # via requests -importlib-metadata==8.7.1 - # via pytest-randomly -iniconfig==2.1.0 +iniconfig==2.3.0 # via pytest -packaging==26.2 +packaging==26.3 # via pytest pluggy==1.6.0 # via pytest -pycparser==2.23 +pycparser==3.0 # via cffi -pygments==2.20.0 +pygments==2.21.0 # via pytest pyjwt==2.0.0 # via -r .test-mindeps.in -pytest==8.4.2 +pytest==9.1.1 # via # -r .test-mindeps.in # pytest-randomly # pytest-xdist -pytest-randomly==4.0.1 +pytest-randomly==5.0.0 # via -r .test-mindeps.in pytest-xdist==3.8.0 # via -r .test-mindeps.in pyyaml==6.0.3 # via responses -requests==2.22.0 +requests==2.27.0 # via # -r .test-mindeps.in # responses @@ -59,13 +57,11 @@ tomli==2.4.1 # via # coverage # pytest -types-pyyaml==6.0.12.20250915 +types-pyyaml==6.0.12.20260906 # via responses typing-extensions==4.0.0 # via -r .test-mindeps.in -urllib3==1.25.11 +urllib3==1.26.20 # via # requests # responses -zipp==3.23.1 - # via importlib-metadata diff --git a/requirements/py3.10/test-orjson.txt b/requirements/py3.10/test-orjson.txt index fe94e4fb6..290192ddf 100644 --- a/requirements/py3.10/test-orjson.txt +++ b/requirements/py3.10/test-orjson.txt @@ -4,11 +4,11 @@ # # tox p -m freezedeps # -certifi==2026.5.20 +certifi==2026.7.22 # via requests -charset-normalizer==3.4.7 +charset-normalizer==3.5.1 # via requests -coverage==7.14.1 +coverage==7.16.1 # via -r .test.in exceptiongroup==1.3.1 # via pytest @@ -16,24 +16,24 @@ execnet==2.1.2 # via pytest-xdist flaky==3.8.1 # via -r .test.in -idna==3.16 +idna==3.20 # via requests iniconfig==2.3.0 # via pytest -orjson==3.11.9 +orjson==3.12.0 # via -r .orjson.in -packaging==26.2 +packaging==26.3 # via pytest pluggy==1.6.0 # via pytest -pygments==2.20.0 +pygments==2.21.0 # via pytest -pytest==9.0.3 +pytest==9.1.1 # via # -r .test.in # pytest-randomly # pytest-xdist -pytest-randomly==4.1.0 +pytest-randomly==5.0.0 # via -r .test.in pytest-xdist==3.8.0 # via -r .test.in @@ -41,15 +41,15 @@ pyyaml==6.0.3 # via responses requests==2.34.2 # via responses -responses==0.26.1 +responses==0.26.3 # via -r .test.in tomli==2.4.1 # via # coverage # pytest -typing-extensions==4.15.0 +typing-extensions==4.16.0 # via exceptiongroup -urllib3==2.7.0 +urllib3==2.8.0 # via # requests # responses diff --git a/requirements/py3.10/test.txt b/requirements/py3.10/test.txt index 4b259e49b..0f1649486 100644 --- a/requirements/py3.10/test.txt +++ b/requirements/py3.10/test.txt @@ -4,11 +4,11 @@ # # tox p -m freezedeps # -certifi==2026.5.20 +certifi==2026.7.22 # via requests -charset-normalizer==3.4.7 +charset-normalizer==3.5.1 # via requests -coverage==7.14.1 +coverage==7.16.1 # via -r .test.in exceptiongroup==1.3.1 # via pytest @@ -16,22 +16,22 @@ execnet==2.1.2 # via pytest-xdist flaky==3.8.1 # via -r .test.in -idna==3.16 +idna==3.20 # via requests iniconfig==2.3.0 # via pytest -packaging==26.2 +packaging==26.3 # via pytest pluggy==1.6.0 # via pytest -pygments==2.20.0 +pygments==2.21.0 # via pytest -pytest==9.0.3 +pytest==9.1.1 # via # -r .test.in # pytest-randomly # pytest-xdist -pytest-randomly==4.1.0 +pytest-randomly==5.0.0 # via -r .test.in pytest-xdist==3.8.0 # via -r .test.in @@ -39,15 +39,15 @@ pyyaml==6.0.3 # via responses requests==2.34.2 # via responses -responses==0.26.1 +responses==0.26.3 # via -r .test.in tomli==2.4.1 # via # coverage # pytest -typing-extensions==4.15.0 +typing-extensions==4.16.0 # via exceptiongroup -urllib3==2.7.0 +urllib3==2.8.0 # via # requests # responses diff --git a/requirements/py3.10/typing.txt b/requirements/py3.10/typing.txt index 6ed5c6351..b049bfad7 100644 --- a/requirements/py3.10/typing.txt +++ b/requirements/py3.10/typing.txt @@ -6,37 +6,37 @@ # alabaster==1.0.0 # via sphinx -ast-serialize==0.5.0 +ast-serialize==0.11.2 # via mypy babel==2.18.0 # via sphinx -certifi==2026.5.20 +certifi==2026.7.22 # via requests -charset-normalizer==3.4.7 +charset-normalizer==3.5.1 # via requests docutils==0.21.2 # via sphinx -idna==3.16 +idna==3.20 # via requests -imagesize==2.0.0 +imagesize==2.0.1 # via sphinx jinja2==3.1.6 # via sphinx -librt==0.11.0 +librt==0.15.0 # via mypy markupsafe==3.0.3 # via jinja2 -mypy==2.1.0 +mypy==2.3.1 # via -r .typing.in mypy-extensions==1.1.0 # via mypy -orjson==3.11.9 +orjson==3.12.0 # via -r .typing.in -packaging==26.2 +packaging==26.3 # via sphinx pathspec==1.1.1 # via mypy -pygments==2.20.0 +pygments==2.21.0 # via sphinx pyyaml==6.0.3 # via responses @@ -44,9 +44,9 @@ requests==2.34.2 # via # responses # sphinx -responses==0.26.1 +responses==0.26.3 # via -r .typing.in -snowballstemmer==3.1.0 +snowballstemmer==3.1.1 # via sphinx sphinx==8.1.3 # via -r .typing.in @@ -68,17 +68,17 @@ tomli==2.4.1 # sphinx types-cryptography==3.3.23.2 # via types-jwt -types-docutils==0.22.3.20260518 +types-docutils==0.23.0.20260923 # via -r .typing.in types-jwt==0.1.3 # via -r .typing.in -types-requests==2.33.0.20260518 +types-requests==2.33.0.20260906 # via -r .typing.in -typing-extensions==4.15.0 +typing-extensions==4.16.0 # via # -r .typing.in # mypy -urllib3==2.7.0 +urllib3==2.8.0 # via # requests # responses diff --git a/requirements/py3.11/docs.txt b/requirements/py3.11/docs.txt index 9159f8712..f78a9f2d2 100644 --- a/requirements/py3.11/docs.txt +++ b/requirements/py3.11/docs.txt @@ -12,13 +12,13 @@ attrs==26.1.0 # via scriv babel==2.18.0 # via sphinx -beautifulsoup4==4.14.3 +beautifulsoup4==4.15.0 # via furo -certifi==2026.5.20 +certifi==2026.7.22 # via requests -charset-normalizer==3.4.7 +charset-normalizer==3.5.1 # via requests -click==8.4.1 +click==8.5.0 # via # click-log # scriv @@ -28,9 +28,9 @@ docutils==0.22.4 # via sphinx furo==2025.12.19 # via -r .docs.in -idna==3.16 +idna==3.20 # via requests -imagesize==2.0.0 +imagesize==2.0.1 # via sphinx jinja2==3.1.6 # via @@ -42,9 +42,9 @@ markupsafe==3.0.3 # via jinja2 mdurl==0.1.2 # via markdown-it-py -packaging==26.2 +packaging==26.3 # via sphinx -pygments==2.20.0 +pygments==2.21.0 # via # accessible-pygments # furo @@ -56,15 +56,15 @@ requests==2.34.2 # responses # scriv # sphinx -responses==0.26.1 +responses==0.26.3 # via -r .docs.in roman-numerals==4.1.0 # via sphinx scriv==1.8.0 # via -r .docs.in -snowballstemmer==3.1.0 +snowballstemmer==3.1.1 # via sphinx -soupsieve==2.8.4 +soupsieve==2.9.2 # via beautifulsoup4 sphinx==9.0.4 # via @@ -94,9 +94,9 @@ sphinxcontrib-qthelp==2.0.0 # via sphinx sphinxcontrib-serializinghtml==2.0.0 # via sphinx -typing-extensions==4.15.0 +typing-extensions==4.16.0 # via beautifulsoup4 -urllib3==2.7.0 +urllib3==2.8.0 # via # requests # responses diff --git a/requirements/py3.11/test-orjson.txt b/requirements/py3.11/test-orjson.txt index 103feaf02..4c2a2a396 100644 --- a/requirements/py3.11/test-orjson.txt +++ b/requirements/py3.11/test-orjson.txt @@ -4,34 +4,34 @@ # # tox p -m freezedeps # -certifi==2026.5.20 +certifi==2026.7.22 # via requests -charset-normalizer==3.4.7 +charset-normalizer==3.5.1 # via requests -coverage==7.14.1 +coverage==7.16.1 # via -r .test.in execnet==2.1.2 # via pytest-xdist flaky==3.8.1 # via -r .test.in -idna==3.16 +idna==3.20 # via requests iniconfig==2.3.0 # via pytest -orjson==3.11.9 +orjson==3.12.0 # via -r .orjson.in -packaging==26.2 +packaging==26.3 # via pytest pluggy==1.6.0 # via pytest -pygments==2.20.0 +pygments==2.21.0 # via pytest -pytest==9.0.3 +pytest==9.1.1 # via # -r .test.in # pytest-randomly # pytest-xdist -pytest-randomly==4.1.0 +pytest-randomly==5.0.0 # via -r .test.in pytest-xdist==3.8.0 # via -r .test.in @@ -39,9 +39,9 @@ pyyaml==6.0.3 # via responses requests==2.34.2 # via responses -responses==0.26.1 +responses==0.26.3 # via -r .test.in -urllib3==2.7.0 +urllib3==2.8.0 # via # requests # responses diff --git a/requirements/py3.11/test.txt b/requirements/py3.11/test.txt index 6cc757f02..4a9cdd959 100644 --- a/requirements/py3.11/test.txt +++ b/requirements/py3.11/test.txt @@ -4,32 +4,32 @@ # # tox p -m freezedeps # -certifi==2026.5.20 +certifi==2026.7.22 # via requests -charset-normalizer==3.4.7 +charset-normalizer==3.5.1 # via requests -coverage==7.14.1 +coverage==7.16.1 # via -r .test.in execnet==2.1.2 # via pytest-xdist flaky==3.8.1 # via -r .test.in -idna==3.16 +idna==3.20 # via requests iniconfig==2.3.0 # via pytest -packaging==26.2 +packaging==26.3 # via pytest pluggy==1.6.0 # via pytest -pygments==2.20.0 +pygments==2.21.0 # via pytest -pytest==9.0.3 +pytest==9.1.1 # via # -r .test.in # pytest-randomly # pytest-xdist -pytest-randomly==4.1.0 +pytest-randomly==5.0.0 # via -r .test.in pytest-xdist==3.8.0 # via -r .test.in @@ -37,9 +37,9 @@ pyyaml==6.0.3 # via responses requests==2.34.2 # via responses -responses==0.26.1 +responses==0.26.3 # via -r .test.in -urllib3==2.7.0 +urllib3==2.8.0 # via # requests # responses diff --git a/requirements/py3.11/typing.txt b/requirements/py3.11/typing.txt index a9057b384..34c041976 100644 --- a/requirements/py3.11/typing.txt +++ b/requirements/py3.11/typing.txt @@ -6,37 +6,37 @@ # alabaster==1.0.0 # via sphinx -ast-serialize==0.5.0 +ast-serialize==0.11.2 # via mypy babel==2.18.0 # via sphinx -certifi==2026.5.20 +certifi==2026.7.22 # via requests -charset-normalizer==3.4.7 +charset-normalizer==3.5.1 # via requests docutils==0.22.4 # via sphinx -idna==3.16 +idna==3.20 # via requests -imagesize==2.0.0 +imagesize==2.0.1 # via sphinx jinja2==3.1.6 # via sphinx -librt==0.11.0 +librt==0.15.0 # via mypy markupsafe==3.0.3 # via jinja2 -mypy==2.1.0 +mypy==2.3.1 # via -r .typing.in mypy-extensions==1.1.0 # via mypy -orjson==3.11.9 +orjson==3.12.0 # via -r .typing.in -packaging==26.2 +packaging==26.3 # via sphinx pathspec==1.1.1 # via mypy -pygments==2.20.0 +pygments==2.21.0 # via sphinx pyyaml==6.0.3 # via responses @@ -44,11 +44,11 @@ requests==2.34.2 # via # responses # sphinx -responses==0.26.1 +responses==0.26.3 # via -r .typing.in roman-numerals==4.1.0 # via sphinx -snowballstemmer==3.1.0 +snowballstemmer==3.1.1 # via sphinx sphinx==9.0.4 # via -r .typing.in @@ -66,17 +66,17 @@ sphinxcontrib-serializinghtml==2.0.0 # via sphinx types-cryptography==3.3.23.2 # via types-jwt -types-docutils==0.22.3.20260518 +types-docutils==0.23.0.20260923 # via -r .typing.in types-jwt==0.1.3 # via -r .typing.in -types-requests==2.33.0.20260518 +types-requests==2.33.0.20260906 # via -r .typing.in -typing-extensions==4.15.0 +typing-extensions==4.16.0 # via # -r .typing.in # mypy -urllib3==2.7.0 +urllib3==2.8.0 # via # requests # responses diff --git a/requirements/py3.12/test-orjson.txt b/requirements/py3.12/test-orjson.txt index 9ee6ff82b..519dc04aa 100644 --- a/requirements/py3.12/test-orjson.txt +++ b/requirements/py3.12/test-orjson.txt @@ -4,34 +4,34 @@ # # tox p -m freezedeps # -certifi==2026.5.20 +certifi==2026.7.22 # via requests -charset-normalizer==3.4.7 +charset-normalizer==3.5.1 # via requests -coverage==7.14.1 +coverage==7.16.1 # via -r .test.in execnet==2.1.2 # via pytest-xdist flaky==3.8.1 # via -r .test.in -idna==3.16 +idna==3.20 # via requests iniconfig==2.3.0 # via pytest -orjson==3.11.9 +orjson==3.12.0 # via -r .orjson.in -packaging==26.2 +packaging==26.3 # via pytest pluggy==1.6.0 # via pytest -pygments==2.20.0 +pygments==2.21.0 # via pytest -pytest==9.0.3 +pytest==9.1.1 # via # -r .test.in # pytest-randomly # pytest-xdist -pytest-randomly==4.1.0 +pytest-randomly==5.0.0 # via -r .test.in pytest-xdist==3.8.0 # via -r .test.in @@ -39,9 +39,9 @@ pyyaml==6.0.3 # via responses requests==2.34.2 # via responses -responses==0.26.1 +responses==0.26.3 # via -r .test.in -urllib3==2.7.0 +urllib3==2.8.0 # via # requests # responses diff --git a/requirements/py3.12/test.txt b/requirements/py3.12/test.txt index 6e90eec6e..dd1db2070 100644 --- a/requirements/py3.12/test.txt +++ b/requirements/py3.12/test.txt @@ -4,32 +4,32 @@ # # tox p -m freezedeps # -certifi==2026.5.20 +certifi==2026.7.22 # via requests -charset-normalizer==3.4.7 +charset-normalizer==3.5.1 # via requests -coverage==7.14.1 +coverage==7.16.1 # via -r .test.in execnet==2.1.2 # via pytest-xdist flaky==3.8.1 # via -r .test.in -idna==3.16 +idna==3.20 # via requests iniconfig==2.3.0 # via pytest -packaging==26.2 +packaging==26.3 # via pytest pluggy==1.6.0 # via pytest -pygments==2.20.0 +pygments==2.21.0 # via pytest -pytest==9.0.3 +pytest==9.1.1 # via # -r .test.in # pytest-randomly # pytest-xdist -pytest-randomly==4.1.0 +pytest-randomly==5.0.0 # via -r .test.in pytest-xdist==3.8.0 # via -r .test.in @@ -37,9 +37,9 @@ pyyaml==6.0.3 # via responses requests==2.34.2 # via responses -responses==0.26.1 +responses==0.26.3 # via -r .test.in -urllib3==2.7.0 +urllib3==2.8.0 # via # requests # responses diff --git a/requirements/py3.12/typing.txt b/requirements/py3.12/typing.txt index f2f941d08..738bacc87 100644 --- a/requirements/py3.12/typing.txt +++ b/requirements/py3.12/typing.txt @@ -6,37 +6,37 @@ # alabaster==1.0.0 # via sphinx -ast-serialize==0.5.0 +ast-serialize==0.11.2 # via mypy babel==2.18.0 # via sphinx -certifi==2026.5.20 +certifi==2026.7.22 # via requests -charset-normalizer==3.4.7 +charset-normalizer==3.5.1 # via requests docutils==0.22.4 # via sphinx -idna==3.16 +idna==3.20 # via requests -imagesize==2.0.0 +imagesize==2.0.1 # via sphinx jinja2==3.1.6 # via sphinx -librt==0.11.0 +librt==0.15.0 # via mypy markupsafe==3.0.3 # via jinja2 -mypy==2.1.0 +mypy==2.3.1 # via -r .typing.in mypy-extensions==1.1.0 # via mypy -orjson==3.11.9 +orjson==3.12.0 # via -r .typing.in -packaging==26.2 +packaging==26.3 # via sphinx pathspec==1.1.1 # via mypy -pygments==2.20.0 +pygments==2.21.0 # via sphinx pyyaml==6.0.3 # via responses @@ -44,11 +44,11 @@ requests==2.34.2 # via # responses # sphinx -responses==0.26.1 +responses==0.26.3 # via -r .typing.in roman-numerals==4.1.0 # via sphinx -snowballstemmer==3.1.0 +snowballstemmer==3.1.1 # via sphinx sphinx==9.1.0 # via -r .typing.in @@ -66,17 +66,17 @@ sphinxcontrib-serializinghtml==2.0.0 # via sphinx types-cryptography==3.3.23.2 # via types-jwt -types-docutils==0.22.3.20260518 +types-docutils==0.23.0.20260923 # via -r .typing.in types-jwt==0.1.3 # via -r .typing.in -types-requests==2.33.0.20260518 +types-requests==2.33.0.20260906 # via -r .typing.in -typing-extensions==4.15.0 +typing-extensions==4.16.0 # via # -r .typing.in # mypy -urllib3==2.7.0 +urllib3==2.8.0 # via # requests # responses diff --git a/requirements/py3.13/test-orjson.txt b/requirements/py3.13/test-orjson.txt index 2aad40eed..5eabf2785 100644 --- a/requirements/py3.13/test-orjson.txt +++ b/requirements/py3.13/test-orjson.txt @@ -4,34 +4,34 @@ # # tox p -m freezedeps # -certifi==2026.5.20 +certifi==2026.7.22 # via requests -charset-normalizer==3.4.7 +charset-normalizer==3.5.1 # via requests -coverage==7.14.1 +coverage==7.16.1 # via -r .test.in execnet==2.1.2 # via pytest-xdist flaky==3.8.1 # via -r .test.in -idna==3.16 +idna==3.20 # via requests iniconfig==2.3.0 # via pytest -orjson==3.11.9 +orjson==3.12.0 # via -r .orjson.in -packaging==26.2 +packaging==26.3 # via pytest pluggy==1.6.0 # via pytest -pygments==2.20.0 +pygments==2.21.0 # via pytest -pytest==9.0.3 +pytest==9.1.1 # via # -r .test.in # pytest-randomly # pytest-xdist -pytest-randomly==4.1.0 +pytest-randomly==5.0.0 # via -r .test.in pytest-xdist==3.8.0 # via -r .test.in @@ -39,9 +39,9 @@ pyyaml==6.0.3 # via responses requests==2.34.2 # via responses -responses==0.26.1 +responses==0.26.3 # via -r .test.in -urllib3==2.7.0 +urllib3==2.8.0 # via # requests # responses diff --git a/requirements/py3.13/test.txt b/requirements/py3.13/test.txt index 64f4db27a..a27fc6305 100644 --- a/requirements/py3.13/test.txt +++ b/requirements/py3.13/test.txt @@ -4,32 +4,32 @@ # # tox p -m freezedeps # -certifi==2026.5.20 +certifi==2026.7.22 # via requests -charset-normalizer==3.4.7 +charset-normalizer==3.5.1 # via requests -coverage==7.14.1 +coverage==7.16.1 # via -r .test.in execnet==2.1.2 # via pytest-xdist flaky==3.8.1 # via -r .test.in -idna==3.16 +idna==3.20 # via requests iniconfig==2.3.0 # via pytest -packaging==26.2 +packaging==26.3 # via pytest pluggy==1.6.0 # via pytest -pygments==2.20.0 +pygments==2.21.0 # via pytest -pytest==9.0.3 +pytest==9.1.1 # via # -r .test.in # pytest-randomly # pytest-xdist -pytest-randomly==4.1.0 +pytest-randomly==5.0.0 # via -r .test.in pytest-xdist==3.8.0 # via -r .test.in @@ -37,9 +37,9 @@ pyyaml==6.0.3 # via responses requests==2.34.2 # via responses -responses==0.26.1 +responses==0.26.3 # via -r .test.in -urllib3==2.7.0 +urllib3==2.8.0 # via # requests # responses diff --git a/requirements/py3.13/typing.txt b/requirements/py3.13/typing.txt index 01d010399..15dc72576 100644 --- a/requirements/py3.13/typing.txt +++ b/requirements/py3.13/typing.txt @@ -6,37 +6,37 @@ # alabaster==1.0.0 # via sphinx -ast-serialize==0.5.0 +ast-serialize==0.11.2 # via mypy babel==2.18.0 # via sphinx -certifi==2026.5.20 +certifi==2026.7.22 # via requests -charset-normalizer==3.4.7 +charset-normalizer==3.5.1 # via requests docutils==0.22.4 # via sphinx -idna==3.16 +idna==3.20 # via requests -imagesize==2.0.0 +imagesize==2.0.1 # via sphinx jinja2==3.1.6 # via sphinx -librt==0.11.0 +librt==0.15.0 # via mypy markupsafe==3.0.3 # via jinja2 -mypy==2.1.0 +mypy==2.3.1 # via -r .typing.in mypy-extensions==1.1.0 # via mypy -orjson==3.11.9 +orjson==3.12.0 # via -r .typing.in -packaging==26.2 +packaging==26.3 # via sphinx pathspec==1.1.1 # via mypy -pygments==2.20.0 +pygments==2.21.0 # via sphinx pyyaml==6.0.3 # via responses @@ -44,11 +44,11 @@ requests==2.34.2 # via # responses # sphinx -responses==0.26.1 +responses==0.26.3 # via -r .typing.in roman-numerals==4.1.0 # via sphinx -snowballstemmer==3.1.0 +snowballstemmer==3.1.1 # via sphinx sphinx==9.1.0 # via -r .typing.in @@ -66,17 +66,17 @@ sphinxcontrib-serializinghtml==2.0.0 # via sphinx types-cryptography==3.3.23.2 # via types-jwt -types-docutils==0.22.3.20260518 +types-docutils==0.23.0.20260923 # via -r .typing.in types-jwt==0.1.3 # via -r .typing.in -types-requests==2.33.0.20260518 +types-requests==2.33.0.20260906 # via -r .typing.in -typing-extensions==4.15.0 +typing-extensions==4.16.0 # via # -r .typing.in # mypy -urllib3==2.7.0 +urllib3==2.8.0 # via # requests # responses diff --git a/requirements/py3.14/test-orjson.txt b/requirements/py3.14/test-orjson.txt index d897e5393..0a31a9e07 100644 --- a/requirements/py3.14/test-orjson.txt +++ b/requirements/py3.14/test-orjson.txt @@ -4,34 +4,34 @@ # # tox p -m freezedeps # -certifi==2026.5.20 +certifi==2026.7.22 # via requests -charset-normalizer==3.4.7 +charset-normalizer==3.5.1 # via requests -coverage==7.14.1 +coverage==7.16.1 # via -r .test.in execnet==2.1.2 # via pytest-xdist flaky==3.8.1 # via -r .test.in -idna==3.16 +idna==3.20 # via requests iniconfig==2.3.0 # via pytest -orjson==3.11.9 +orjson==3.12.0 # via -r .orjson.in -packaging==26.2 +packaging==26.3 # via pytest pluggy==1.6.0 # via pytest -pygments==2.20.0 +pygments==2.21.0 # via pytest -pytest==9.0.3 +pytest==9.1.1 # via # -r .test.in # pytest-randomly # pytest-xdist -pytest-randomly==4.1.0 +pytest-randomly==5.0.0 # via -r .test.in pytest-xdist==3.8.0 # via -r .test.in @@ -39,9 +39,9 @@ pyyaml==6.0.3 # via responses requests==2.34.2 # via responses -responses==0.26.1 +responses==0.26.3 # via -r .test.in -urllib3==2.7.0 +urllib3==2.8.0 # via # requests # responses diff --git a/requirements/py3.14/test.txt b/requirements/py3.14/test.txt index 17c8d53ba..861c0514d 100644 --- a/requirements/py3.14/test.txt +++ b/requirements/py3.14/test.txt @@ -4,32 +4,32 @@ # # tox p -m freezedeps # -certifi==2026.5.20 +certifi==2026.7.22 # via requests -charset-normalizer==3.4.7 +charset-normalizer==3.5.1 # via requests -coverage==7.14.1 +coverage==7.16.1 # via -r .test.in execnet==2.1.2 # via pytest-xdist flaky==3.8.1 # via -r .test.in -idna==3.16 +idna==3.20 # via requests iniconfig==2.3.0 # via pytest -packaging==26.2 +packaging==26.3 # via pytest pluggy==1.6.0 # via pytest -pygments==2.20.0 +pygments==2.21.0 # via pytest -pytest==9.0.3 +pytest==9.1.1 # via # -r .test.in # pytest-randomly # pytest-xdist -pytest-randomly==4.1.0 +pytest-randomly==5.0.0 # via -r .test.in pytest-xdist==3.8.0 # via -r .test.in @@ -37,9 +37,9 @@ pyyaml==6.0.3 # via responses requests==2.34.2 # via responses -responses==0.26.1 +responses==0.26.3 # via -r .test.in -urllib3==2.7.0 +urllib3==2.8.0 # via # requests # responses diff --git a/requirements/py3.14/typing.txt b/requirements/py3.14/typing.txt index 25993c968..b7fe66adc 100644 --- a/requirements/py3.14/typing.txt +++ b/requirements/py3.14/typing.txt @@ -6,37 +6,37 @@ # alabaster==1.0.0 # via sphinx -ast-serialize==0.5.0 +ast-serialize==0.11.2 # via mypy babel==2.18.0 # via sphinx -certifi==2026.5.20 +certifi==2026.7.22 # via requests -charset-normalizer==3.4.7 +charset-normalizer==3.5.1 # via requests docutils==0.22.4 # via sphinx -idna==3.16 +idna==3.20 # via requests -imagesize==2.0.0 +imagesize==2.0.1 # via sphinx jinja2==3.1.6 # via sphinx -librt==0.11.0 +librt==0.15.0 # via mypy markupsafe==3.0.3 # via jinja2 -mypy==2.1.0 +mypy==2.3.1 # via -r .typing.in mypy-extensions==1.1.0 # via mypy -orjson==3.11.9 +orjson==3.12.0 # via -r .typing.in -packaging==26.2 +packaging==26.3 # via sphinx pathspec==1.1.1 # via mypy -pygments==2.20.0 +pygments==2.21.0 # via sphinx pyyaml==6.0.3 # via responses @@ -44,11 +44,11 @@ requests==2.34.2 # via # responses # sphinx -responses==0.26.1 +responses==0.26.3 # via -r .typing.in roman-numerals==4.1.0 # via sphinx -snowballstemmer==3.1.0 +snowballstemmer==3.1.1 # via sphinx sphinx==9.1.0 # via -r .typing.in @@ -66,17 +66,17 @@ sphinxcontrib-serializinghtml==2.0.0 # via sphinx types-cryptography==3.3.23.2 # via types-jwt -types-docutils==0.22.3.20260518 +types-docutils==0.23.0.20260923 # via -r .typing.in types-jwt==0.1.3 # via -r .typing.in -types-requests==2.33.0.20260518 +types-requests==2.33.0.20260906 # via -r .typing.in -typing-extensions==4.15.0 +typing-extensions==4.16.0 # via # -r .typing.in # mypy -urllib3==2.7.0 +urllib3==2.8.0 # via # requests # responses diff --git a/requirements/py3.9/test-orjson.txt b/requirements/py3.9/test-orjson.txt deleted file mode 100644 index f054ca92d..000000000 --- a/requirements/py3.9/test-orjson.txt +++ /dev/null @@ -1,59 +0,0 @@ -# -# This file is autogenerated by pip-compile with Python 3.9 -# by the following command: -# -# tox p -m freezedeps -# -certifi==2026.5.20 - # via requests -charset-normalizer==3.4.7 - # via requests -coverage==7.10.7 - # via -r .test.in -exceptiongroup==1.3.1 - # via pytest -execnet==2.1.2 - # via pytest-xdist -flaky==3.8.1 - # via -r .test.in -idna==3.16 - # via requests -importlib-metadata==8.7.1 - # via pytest-randomly -iniconfig==2.1.0 - # via pytest -orjson==3.11.5 - # via -r .orjson.in -packaging==26.2 - # via pytest -pluggy==1.6.0 - # via pytest -pygments==2.20.0 - # via pytest -pytest==8.4.2 - # via - # -r .test.in - # pytest-randomly - # pytest-xdist -pytest-randomly==4.0.1 - # via -r .test.in -pytest-xdist==3.8.0 - # via -r .test.in -pyyaml==6.0.3 - # via responses -requests==2.32.5 - # via responses -responses==0.26.1 - # via -r .test.in -tomli==2.4.1 - # via - # coverage - # pytest -typing-extensions==4.15.0 - # via exceptiongroup -urllib3==2.6.3 - # via - # requests - # responses -zipp==3.23.1 - # via importlib-metadata diff --git a/requirements/py3.9/test.txt b/requirements/py3.9/test.txt deleted file mode 100644 index 769b633cd..000000000 --- a/requirements/py3.9/test.txt +++ /dev/null @@ -1,57 +0,0 @@ -# -# This file is autogenerated by pip-compile with Python 3.9 -# by the following command: -# -# tox p -m freezedeps -# -certifi==2026.5.20 - # via requests -charset-normalizer==3.4.7 - # via requests -coverage==7.10.7 - # via -r .test.in -exceptiongroup==1.3.1 - # via pytest -execnet==2.1.2 - # via pytest-xdist -flaky==3.8.1 - # via -r .test.in -idna==3.16 - # via requests -importlib-metadata==8.7.1 - # via pytest-randomly -iniconfig==2.1.0 - # via pytest -packaging==26.2 - # via pytest -pluggy==1.6.0 - # via pytest -pygments==2.20.0 - # via pytest -pytest==8.4.2 - # via - # -r .test.in - # pytest-randomly - # pytest-xdist -pytest-randomly==4.0.1 - # via -r .test.in -pytest-xdist==3.8.0 - # via -r .test.in -pyyaml==6.0.3 - # via responses -requests==2.32.5 - # via responses -responses==0.26.1 - # via -r .test.in -tomli==2.4.1 - # via - # coverage - # pytest -typing-extensions==4.15.0 - # via exceptiongroup -urllib3==2.6.3 - # via - # requests - # responses -zipp==3.23.1 - # via importlib-metadata diff --git a/requirements/py3.9/typing.txt b/requirements/py3.9/typing.txt deleted file mode 100644 index 5158e8933..000000000 --- a/requirements/py3.9/typing.txt +++ /dev/null @@ -1,87 +0,0 @@ -# -# This file is autogenerated by pip-compile with Python 3.9 -# by the following command: -# -# tox p -m freezedeps -# -alabaster==0.7.16 - # via sphinx -babel==2.18.0 - # via sphinx -certifi==2026.5.20 - # via requests -charset-normalizer==3.4.7 - # via requests -docutils==0.21.2 - # via sphinx -idna==3.16 - # via requests -imagesize==1.5.0 - # via sphinx -importlib-metadata==8.7.1 - # via sphinx -jinja2==3.1.6 - # via sphinx -librt==0.11.0 - # via mypy -markupsafe==3.0.3 - # via jinja2 -mypy==1.19.1 - # via -r .typing.in -mypy-extensions==1.1.0 - # via mypy -orjson==3.11.5 - # via -r .typing.in -packaging==26.2 - # via sphinx -pathspec==1.1.1 - # via mypy -pygments==2.20.0 - # via sphinx -pyyaml==6.0.3 - # via responses -requests==2.32.5 - # via - # responses - # sphinx -responses==0.26.1 - # via -r .typing.in -snowballstemmer==3.1.0 - # via sphinx -sphinx==7.4.7 - # via -r .typing.in -sphinxcontrib-applehelp==2.0.0 - # via sphinx -sphinxcontrib-devhelp==2.0.0 - # via sphinx -sphinxcontrib-htmlhelp==2.1.0 - # via sphinx -sphinxcontrib-jsmath==1.0.1 - # via sphinx -sphinxcontrib-qthelp==2.0.0 - # via sphinx -sphinxcontrib-serializinghtml==2.0.0 - # via sphinx -tomli==2.4.1 - # via - # mypy - # sphinx -types-cryptography==3.3.23.2 - # via types-jwt -types-docutils==0.22.3.20251115 - # via -r .typing.in -types-jwt==0.1.3 - # via -r .typing.in -types-requests==2.32.4.20260107 - # via -r .typing.in -typing-extensions==4.15.0 - # via - # -r .typing.in - # mypy -urllib3==2.6.3 - # via - # requests - # responses - # types-requests -zipp==3.23.1 - # via importlib-metadata diff --git a/src/globus_sdk/_internal/guards.py b/src/globus_sdk/_internal/guards.py index bd4d701cd..71e3c42d1 100644 --- a/src/globus_sdk/_internal/guards.py +++ b/src/globus_sdk/_internal/guards.py @@ -1,6 +1,5 @@ from __future__ import annotations -import sys import typing as t import uuid @@ -10,24 +9,19 @@ if t.TYPE_CHECKING: from globus_sdk._internal.serializable import Serializable -if sys.version_info >= (3, 10): - from typing import TypeGuard -else: - from typing_extensions import TypeGuard - T = t.TypeVar("T") S = t.TypeVar("S", bound="Serializable") -def is_list_of(data: t.Any, typ: type[T]) -> TypeGuard[list[T]]: +def is_list_of(data: t.Any, typ: type[T]) -> t.TypeGuard[list[T]]: return isinstance(data, list) and all(isinstance(item, typ) for item in data) -def is_optional(data: t.Any, typ: type[T]) -> TypeGuard[T | None]: +def is_optional(data: t.Any, typ: type[T]) -> t.TypeGuard[T | None]: return data is None or isinstance(data, typ) -def is_optional_list_of(data: t.Any, typ: type[T]) -> TypeGuard[list[T] | None]: +def is_optional_list_of(data: t.Any, typ: type[T]) -> t.TypeGuard[list[T] | None]: return data is None or ( isinstance(data, list) and all(isinstance(item, typ) for item in data) ) diff --git a/src/globus_sdk/_internal/remarshal.py b/src/globus_sdk/_internal/remarshal.py index 41fedbce3..53a014986 100644 --- a/src/globus_sdk/_internal/remarshal.py +++ b/src/globus_sdk/_internal/remarshal.py @@ -9,17 +9,11 @@ from __future__ import annotations import collections.abc -import sys import typing as t import uuid from globus_sdk._missing import MISSING, MissingType -if sys.version_info >= (3, 10): - from typing import TypeAlias -else: - from typing_extensions import TypeAlias - T = t.TypeVar("T") R = t.TypeVar("R") @@ -28,8 +22,8 @@ # # in type systems this kind of construction is sometimes called "Optional" or "Maybe" # but Python uses "Optional" to mean "T | None" and in the SDK, "None" means "null" -Omittable: TypeAlias[T] = t.Union[T, MissingType] -NullableOmittable: TypeAlias[T] = t.Union[Omittable[T], None] +Omittable: t.TypeAlias[T] = t.Union[T, MissingType] +NullableOmittable: t.TypeAlias[T] = t.Union[Omittable[T], None] def stringify(value: NullableOmittable[object]) -> NullableOmittable[str]: diff --git a/src/globus_sdk/_payload.py b/src/globus_sdk/_payload.py index 3e52857f0..cd9c65c09 100644 --- a/src/globus_sdk/_payload.py +++ b/src/globus_sdk/_payload.py @@ -9,16 +9,8 @@ else: from typing_extensions import Self -# TODO: Remove this dispatch after we drop Python 3.8 support. -# In 3.9+ `dict.__class_getitem__` is available. -if t.TYPE_CHECKING: - # pylint: disable=unsubscriptable-object - _PayloadBaseDict = t.Dict[str, t.Any] -else: - _PayloadBaseDict = dict - -class GlobusPayload(_PayloadBaseDict): +class GlobusPayload(dict[str, t.Any]): """ A class for defining helper objects which wrap some kind of "payload" dict. Typical for helper objects which formulate a request payload. diff --git a/src/globus_sdk/client.py b/src/globus_sdk/client.py index 6b185ebfe..7e390d587 100644 --- a/src/globus_sdk/client.py +++ b/src/globus_sdk/client.py @@ -17,11 +17,6 @@ from globus_sdk.transport import RequestCallerInfo, RequestsTransport, RetryConfig from globus_sdk.transport.default_retry_checks import DEFAULT_RETRY_CHECKS -if sys.version_info >= (3, 10): - from typing import TypeAlias -else: - from typing_extensions import TypeAlias - if sys.version_info >= (3, 11): from typing import Self else: @@ -32,7 +27,7 @@ log = logging.getLogger(__name__) -_DataParamType: TypeAlias = t.Union[None, str, bytes, t.Dict[str, t.Any]] +_DataParamType: t.TypeAlias = t.Union[None, str, bytes, dict[str, t.Any]] class BaseClient: diff --git a/src/globus_sdk/gare/_functional_api.py b/src/globus_sdk/gare/_functional_api.py index fcaaa005c..e9c3f2d0e 100644 --- a/src/globus_sdk/gare/_functional_api.py +++ b/src/globus_sdk/gare/_functional_api.py @@ -1,7 +1,6 @@ from __future__ import annotations import logging -import sys import typing as t from globus_sdk import exc @@ -15,13 +14,7 @@ LegacyDependentConsentRequiredAuthError, ) -if sys.version_info >= (3, 10): - from typing import TypeAlias -else: - from typing_extensions import TypeAlias - - -AnyErrorDocumentType: TypeAlias = ( +AnyErrorDocumentType: t.TypeAlias = ( "exc.GlobusAPIError | exc.ErrorSubdocument | dict[str, t.Any]" ) diff --git a/src/globus_sdk/paging/base.py b/src/globus_sdk/paging/base.py index ce5bb2bc3..c87ce0fda 100644 --- a/src/globus_sdk/paging/base.py +++ b/src/globus_sdk/paging/base.py @@ -3,18 +3,12 @@ import abc import functools import inspect -import sys import typing as t from globus_sdk.response import GlobusHTTPResponse -if sys.version_info >= (3, 10): - from typing import ParamSpec -else: - from typing_extensions import ParamSpec - PageT = t.TypeVar("PageT", bound=GlobusHTTPResponse) -P = ParamSpec("P") +P = t.ParamSpec("P") R = t.TypeVar("R", bound=GlobusHTTPResponse) C = t.TypeVar("C", bound=t.Callable[..., GlobusHTTPResponse]) diff --git a/src/globus_sdk/scopes/_graph_parser.py b/src/globus_sdk/scopes/_graph_parser.py index 9e7e7b649..49d30fea0 100644 --- a/src/globus_sdk/scopes/_graph_parser.py +++ b/src/globus_sdk/scopes/_graph_parser.py @@ -2,7 +2,6 @@ import dataclasses import enum -import sys import typing as t from collections import defaultdict, deque @@ -105,15 +104,7 @@ def _convert_trees(cls, trees: list[ScopeTreeNode]) -> ScopeGraph: return graph -# pass slots=True on 3.10+ -# it's not strictly necessary, but it improves performance -if sys.version_info >= (3, 10): - _add_dataclass_kwargs: dict[str, bool] = {"slots": True} -else: - _add_dataclass_kwargs: dict[str, bool] = {} - - -@dataclasses.dataclass(repr=False, eq=False, order=False, **_add_dataclass_kwargs) +@dataclasses.dataclass(repr=False, eq=False, order=False, slots=True) class ScopeTreeNode: # # This is an intermediate representation for scope parsing. diff --git a/src/globus_sdk/scopes/representation.py b/src/globus_sdk/scopes/representation.py index 5e215f23c..8e6499394 100644 --- a/src/globus_sdk/scopes/representation.py +++ b/src/globus_sdk/scopes/representation.py @@ -2,21 +2,12 @@ import dataclasses import re -import sys import typing as t -# pass slots=True on 3.10+ -# it's not strictly necessary, but it improves performance -if sys.version_info >= (3, 10): - _add_dataclass_kwargs: dict[str, bool] = {"slots": True} -else: - _add_dataclass_kwargs: dict[str, bool] = {} - - _BAD_SCOPE_CHARS_PATTERN: re.Pattern[str] = re.compile(r"[\[\]* ]") -@dataclasses.dataclass(frozen=True, repr=False, **_add_dataclass_kwargs) +@dataclasses.dataclass(frozen=True, repr=False, slots=True) class Scope: """ A scope object is a representation of a scope and its dynamic dependencies diff --git a/src/globus_sdk/services/groups/client.py b/src/globus_sdk/services/groups/client.py index 38be17a6c..ab411a7d1 100644 --- a/src/globus_sdk/services/groups/client.py +++ b/src/globus_sdk/services/groups/client.py @@ -1,6 +1,5 @@ from __future__ import annotations -import sys import typing as t import uuid @@ -12,12 +11,7 @@ from .data import BatchMembershipActions, GroupPolicies from .errors import GroupsAPIError -if sys.version_info >= (3, 10): - from typing import TypeAlias -else: - from typing_extensions import TypeAlias - -_VALID_STATUSES_T: TypeAlias = t.Literal[ +_VALID_STATUSES_T: t.TypeAlias = t.Literal[ "active", "declined", "invited", diff --git a/src/globus_sdk/services/search/client.py b/src/globus_sdk/services/search/client.py index f4e23e8e2..9f0c79f46 100644 --- a/src/globus_sdk/services/search/client.py +++ b/src/globus_sdk/services/search/client.py @@ -1,7 +1,6 @@ from __future__ import annotations import logging -import sys import typing as t import uuid @@ -14,14 +13,9 @@ from .errors import SearchAPIError from .response import IndexListResponse -if sys.version_info >= (3, 10): - from typing import TypeAlias -else: - from typing_extensions import TypeAlias - log = logging.getLogger(__name__) -_VALID_ROLE_NAMES_T: TypeAlias = t.Literal["owner", "admin", "writer"] +_VALID_ROLE_NAMES_T: t.TypeAlias = t.Literal["owner", "admin", "writer"] class SearchClient(client.BaseClient): diff --git a/src/globus_sdk/transport/encoders.py b/src/globus_sdk/transport/encoders.py index f01a913a0..92c72cac0 100644 --- a/src/globus_sdk/transport/encoders.py +++ b/src/globus_sdk/transport/encoders.py @@ -1,6 +1,6 @@ from __future__ import annotations -import sys +import typing as t from .representation_providers import ( RequestsHttpFormProvider, @@ -8,18 +8,12 @@ RequestsPlainTextProvider, ) -if sys.version_info >= (3, 10): - from typing import TypeAlias -else: - from typing_extensions import TypeAlias - - # shim these class names until the next major SDK version, at which point they can be # removed # # ideally, after soft-deprecation, we should start emitting deprecation warnings when # these names are imported, but this will also require handling in __init__.py -RequestEncoder: TypeAlias = RequestsPlainTextProvider -JSONRequestEncoder: TypeAlias = RequestsJsonProvider -FormRequestEncoder: TypeAlias = RequestsHttpFormProvider +RequestEncoder: t.TypeAlias = RequestsPlainTextProvider +JSONRequestEncoder: t.TypeAlias = RequestsJsonProvider +FormRequestEncoder: t.TypeAlias = RequestsHttpFormProvider diff --git a/tests/non-pytest/lazy-imports/test_for_import_cycles.py b/tests/non-pytest/lazy-imports/test_for_import_cycles.py index 38cdb07a8..7888a4415 100644 --- a/tests/non-pytest/lazy-imports/test_for_import_cycles.py +++ b/tests/non-pytest/lazy-imports/test_for_import_cycles.py @@ -30,7 +30,7 @@ @pytest.mark.parametrize( - "first_module, second_module", itertools.permutations(MODULE_NAMES, 2) + "first_module, second_module", list(itertools.permutations(MODULE_NAMES, 2)) ) def test_import_pairwise(first_module, second_module): command = ( diff --git a/tests/non-pytest/mypy-ignore-tests/auth_client_create_policy.py b/tests/non-pytest/mypy-ignore-tests/auth_client_create_policy.py index 62029dc79..f6d0440e4 100644 --- a/tests/non-pytest/mypy-ignore-tests/auth_client_create_policy.py +++ b/tests/non-pytest/mypy-ignore-tests/auth_client_create_policy.py @@ -10,7 +10,7 @@ ) # create using positional args (deprecated/unsupported) -ac.create_policy( # type: ignore[misc] +ac.create_policy( # type: ignore[call-arg] "foo", True, # type: ignore[arg-type] 101, # type: ignore[arg-type] diff --git a/tests/non-pytest/mypy-ignore-tests/pagination.py b/tests/non-pytest/mypy-ignore-tests/pagination.py index 8eeec1cef..eb6ddd2fb 100644 --- a/tests/non-pytest/mypy-ignore-tests/pagination.py +++ b/tests/non-pytest/mypy-ignore-tests/pagination.py @@ -11,10 +11,10 @@ tc.task_list(limit=10, offset=100, filter="hi") tc.task_list(limit="hi") # type: ignore [arg-type] -# too many positional args is 'misc' +# too many positional args is 'call-arg' # we also will trigger arg type because `str` does not match the first kwarg (limit) # of type `int` -tc.task_list("foo") # type: ignore [misc,arg-type] +tc.task_list("foo") # type: ignore [call-arg,arg-type] # the same basic should hold for a Paginator.wrap'ed variant @@ -26,4 +26,4 @@ paginated_call(limit="hi") # type: ignore [arg-type] # see note above on non-paginated case for why these ignores are correct -paginated_call("foo") # type: ignore [misc,arg-type] +paginated_call("foo") # type: ignore [call-arg,arg-type] diff --git a/tests/non-pytest/poetry-lock-test/pyproject.toml b/tests/non-pytest/poetry-lock-test/pyproject.toml index 7599ecd54..515df64eb 100644 --- a/tests/non-pytest/poetry-lock-test/pyproject.toml +++ b/tests/non-pytest/poetry-lock-test/pyproject.toml @@ -5,7 +5,7 @@ description = "" authors = ["Stephen Rosen "] [tool.poetry.dependencies] -python = "^3.9" +python = ">= 3.10" globus-sdk = { path = "../../.." } [build-system] diff --git a/tests/unit/helpers/gcs/test_collections.py b/tests/unit/helpers/gcs/test_collections.py index 0f923d2a5..8a151dbd1 100644 --- a/tests/unit/helpers/gcs/test_collections.py +++ b/tests/unit/helpers/gcs/test_collections.py @@ -1,5 +1,4 @@ import inspect -import sys import types import typing as t import uuid @@ -17,10 +16,7 @@ from globus_sdk._missing import MISSING, MissingType, filter_missing from globus_sdk.transport import JSONRequestEncoder -if sys.version_info >= (3, 10): - UnionTypes = (t.Union, types.UnionType) -else: - UnionTypes = (t.Union,) +UnionTypes = (t.Union, types.UnionType) STUB_SG_ID = uuid.uuid1() # storage gateway STUB_MC_ID = uuid.uuid1() # mapped collection diff --git a/tests/unit/helpers/gcs/test_connector_table.py b/tests/unit/helpers/gcs/test_connector_table.py index 9f8e16a8c..09a72eb17 100644 --- a/tests/unit/helpers/gcs/test_connector_table.py +++ b/tests/unit/helpers/gcs/test_connector_table.py @@ -1,7 +1,6 @@ from __future__ import annotations import inspect -import sys import uuid import pytest @@ -64,9 +63,6 @@ def test_all_connector_names_map_to_attributes(name): assert getattr(ConnectorTable, name) == connector -@pytest.mark.skipif( - sys.version_info < (3, 10), reason="inspect.get_annotations added in 3.10" -) def test_all_connector_attributes_are_assigned(): # build a list of attribute names annotated with # `t.ClassVar[GlobusConnectServerConnector]` diff --git a/tox.ini b/tox.ini index 9fdc0aa9a..b38697d16 100644 --- a/tox.ini +++ b/tox.ini @@ -6,15 +6,15 @@ envlist = pylint test-lazy-imports coverage_clean - py{3.14,3.13,3.12,3.11,3.10,3.9} - py{3.14,3.9}-orjson - py3.9-mindeps + py{3.14,3.13,3.12,3.11,3.10} + py{3.14,3.10}-orjson + py3.10-mindeps py3.11-sphinxext coverage_report docs minversion = 4.22.0 labels = - freezedeps = freezedeps-print,freezedeps-py{3.14,3.13,3.12,3.11,3.10,3.9} + freezedeps = freezedeps-print,freezedeps-py{3.14,3.13,3.12,3.11,3.10} [testenv] # build a wheel, not a tarball, and use a common env to do it (so that the wheel is shared) @@ -24,13 +24,13 @@ deps = -r requirements/py{py_dot_ver}/test.txt commands = coverage run -m pytest {posargs} depends = coverage_clean,lint -[testenv:py{3.14,3.13,3.12,3.11,3.10,3.9}-mindeps] +[testenv:py{3.14,3.13,3.12,3.11,3.10}-mindeps] deps = -r requirements/py{py_dot_ver}/test-mindeps.txt -[testenv:py{3.14,3.13,3.12,3.11,3.10,3.9}-orjson] +[testenv:py{3.14,3.13,3.12,3.11,3.10}-orjson] deps = -r requirements/py{py_dot_ver}/test-orjson.txt -[testenv:py{3.14,3.13,3.12,3.11,3.10,3.9}-sphinxext] +[testenv:py{3.14,3.13,3.12,3.11,3.10}-sphinxext] deps = -r requirements/py{py_dot_ver}/test.txt -r requirements/py{py_dot_ver}/docs.txt @@ -46,7 +46,7 @@ dependency_groups = coverage skip_install = true commands_pre = -coverage combine commands = coverage report --skip-covered -depends = py{3.14,3.13,3.12,3.11,3.10,3.9}{-mindeps,-sphinxext,} +depends = py{3.14,3.13,3.12,3.11,3.10}{-mindeps,-sphinxext,} [testenv:lint] deps = pre-commit @@ -54,7 +54,7 @@ skip_install = true commands = pre-commit run --all-files depends = -[testenv:mypy,mypy-{py3.9,py3.14}] +[testenv:mypy,mypy-{py3.10,py3.14}] deps = -r requirements/py{py_dot_ver}/typing.txt commands = mypy src/ {posargs} @@ -86,7 +86,7 @@ commands = !codspeed: pytest {posargs:tests/benchmark/} codspeed: pytest --codspeed {posargs:tests/benchmark/} -[testenv:pylint,pylint-{py3.9,py3.10,py3.11,py3.12,py3.13,py3.14}] +[testenv:pylint,pylint-{py3.10,py3.11,py3.12,py3.13,py3.14}] deps = pylint commands = pylint {posargs:src/} @@ -136,7 +136,7 @@ commands = python -m dependency_groups orjson -o requirements/.orjson.in python -m dependency_groups test-mindeps -o requirements/.test-mindeps.in python -m dependency_groups docs -o requirements/.docs.in -[testenv:freezedeps-py{3.14,3.13,3.12,3.11,3.10,3.9}] +[testenv:freezedeps-py{3.14,3.13,3.12,3.11,3.10}] description = freeze development dependencies using pip-compile skip_install = true setenv = @@ -148,7 +148,7 @@ commands = pip-compile --strip-extras -q -U --resolver=backtracking .typing.in -o py{py_dot_ver}/typing.txt # Minimum dependencies are only tested against the lowest supported Python version. - py3.9: pip-compile --strip-extras -q -U --resolver=backtracking .test-mindeps.in -o py{py_dot_ver}/test-mindeps.txt + py3.10: pip-compile --strip-extras -q -U --resolver=backtracking .test-mindeps.in -o py{py_dot_ver}/test-mindeps.txt # orjson testing happens on every version pip-compile --strip-extras -q -U --resolver=backtracking -r .test.in -r .orjson.in -o py{py_dot_ver}/test-orjson.txt