Skip to content
Open
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
27 changes: 27 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ jobs:
"windows-py310-unittest-twisted25",
"windows-py310-pluggy",
"windows-py310-xdist",
"windows-py310-lowestdirect-onlymanaged",
"windows-py311",
"windows-py312",
"windows-py313",
Expand All @@ -73,13 +74,15 @@ jobs:
"ubuntu-py310-pluggy",
"ubuntu-py310-freeze",
"ubuntu-py310-xdist",
"ubuntu-py310-lowestdirect-onlymanaged",
"ubuntu-py311",
"ubuntu-py312",
"ubuntu-py313-pexpect",
"ubuntu-py314",
"ubuntu-pypy3-xdist",

"macos-py310",
"macos-py310-lowestdirect-onlymanaged",
"macos-py312",
"macos-py313",
"macos-py314",
Expand Down Expand Up @@ -119,6 +122,12 @@ jobs:
os: windows-latest
tox_env: "py310-xdist"

- name: "windows-py310-lowestdirect-onlymanaged"
python: "3.10"
os: windows-latest
tox_env: "py310-lowestdirect-onlymanaged"
use_uv: true

- name: "windows-py311"
python: "3.11"
os: windows-latest
Expand Down Expand Up @@ -182,6 +191,12 @@ jobs:
os: ubuntu-latest
tox_env: "py310-xdist"

- name: "ubuntu-py310-lowestdirect-onlymanaged"
python: "3.10"
os: ubuntu-latest
tox_env: "py310-lowestdirect-onlymanaged"
use_uv: true

- name: "ubuntu-py311"
python: "3.11"
os: ubuntu-latest
Expand Down Expand Up @@ -219,6 +234,13 @@ jobs:
tox_env: "py310-xdist"
xfail: true

- name: "macos-py310-lowestdirect-onlymanaged"
python: "3.10"
os: macos-latest
tox_env: "py310-lowestdirect-onlymanaged"
xfail: true
use_uv: true

- name: "macos-py312"
python: "3.12"
os: macos-latest
Expand Down Expand Up @@ -273,6 +295,11 @@ jobs:
python -m pip install --upgrade pip
pip install tox coverage

- name: Set up uv
if: "matrix.use_uv"
shell: bash
run: pip install tox-uv

- name: Test without coverage
if: "! matrix.use_coverage"
shell: bash
Expand Down
3 changes: 3 additions & 0 deletions changelog/13177.packaging.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Raised minimal versions of ``exceptiongroup``, ``iniconfig`` and ``pygments`` following uv powered test runs using the ``lowest-direct`` resolution strategy.

-- by :user:`sgaist`
20 changes: 10 additions & 10 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -47,21 +47,21 @@ dynamic = [
]
dependencies = [
"colorama>=0.4; sys_platform=='win32'",
"exceptiongroup>=1; python_version<'3.11'",
"iniconfig>=1.0.1",
"exceptiongroup>=1.1; python_version<'3.11'",
"iniconfig>=2",
"packaging>=22",
"pluggy>=1.5,<2",
"pygments>=2.7.2",
"pygments>=2.14",
"tomli>=1; python_version<'3.11'",
]
optional-dependencies.dev = [
"argcomplete",
"attrs>=19.2",
"hypothesis>=3.56",
"mock",
"requests",
"setuptools",
"xmlschema",
"argcomplete>=3.5",
"attrs>=21",
"hypothesis>=5",
"mock>=5",
"requests>=2.26",
"setuptools>=80",
"xmlschema>=3",
]
Comment on lines 48 to 65
Copy link
Member

@bluetech bluetech Oct 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are these changes needed? Is it from testing with lowest-direct?

For the dev deps I don't mind much, perhaps except for attrs and mock which we use for testing pytest integration features so being able to test with older versions is somewhat useful.

But for the runtime dependencies, how did you determine the lower bounds?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's correct, lowest-direct showed that the oldest version it could get were sometimes using obsolete APIs.

My first tries were to slowly bump the versions of the dependencies that were posing problems. Since some of them were a bit less cooperative, I went to check which years the packages had releases around Python 3.10 initial release. So, in the absolute, I would say it's worth revisiting them to ensure I did not miss something.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your method sounds good to me (cc @RonnyPfannschmidt on iniconfig).

Could you add a packaging changelog entry detailing the changes to the lower bounds of exceptiongroup, iniconfig and pygments?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done but I may have been a bit short

urls.Changelog = "https://docs.pytest.org/en/stable/changelog.html"
urls.Contact = "https://docs.pytest.org/en/stable/contact.html"
Expand Down
29 changes: 20 additions & 9 deletions testing/acceptance_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -1642,12 +1642,23 @@ def test_fail_call():
result = pytester.runpytest()
assert result.ret == ExitCode.TESTS_FAILED
result.assert_outcomes(failed=1, passed=1, errors=2)
result.stdout.fnmatch_lines(
[
"=* short test summary info =*",
"FAILED test_it.py::test_fail_call - StopIteration: 3",
"ERROR test_it.py::test_fail_setup - StopIteration: 1",
"ERROR test_it.py::test_fail_teardown - StopIteration: 2",
"=* 1 failed, 1 passed, 2 errors in * =*",
]
)

# uv managed python versions do not raise the same exception with regard to
# StopIteration.
# See PEP-0479
runtime_errors = {
"FAILED test_it.py::test_fail_call - RuntimeError: generator raised StopIteration",
"ERROR test_it.py::test_fail_setup - RuntimeError: generator raised StopIteration",
"ERROR test_it.py::test_fail_teardown - RuntimeError: generator raised StopIte...",
}
got_runtime_errors = runtime_errors.issubset(result.outlines)

stopiteration_errors = {
"FAILED test_it.py::test_fail_call - StopIteration: 3",
"ERROR test_it.py::test_fail_setup - StopIteration: 1",
"ERROR test_it.py::test_fail_teardown - StopIteration: 2",
}

got_stopiteration_errors = stopiteration_errors.issubset(result.outlines)

assert got_runtime_errors or got_stopiteration_errors
28 changes: 28 additions & 0 deletions tox-uv.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
[tox]
requires =
tox>=4
tox-uv>=1
isolated_build = True
distshare = {homedir}/.tox/uv-distshare
envlist =
py310

[testenv]
description =
run the tests
under `{basepython}`
uv_resolution = lowest-direct
uv_python_preference = only-managed
commands =
{env:_PYTEST_TOX_COVERAGE_RUN:} pytest {posargs:{env:_PYTEST_TOX_DEFAULT_POSARGS:}} --maxfail=1 --pdb
passenv =
PYTEST_ADDOPTS
TERM
SETUPTOOLS_SCM_PRETEND_VERSION_FOR_PYTEST
CI
setenv =
_PYTEST_TOX_DEFAULT_POSARGS={env:_PYTEST_TOX_POSARGS_DOCTESTING:} {env:_PYTEST_TOX_POSARGS_LSOF:} {env:_PYTEST_TOX_POSARGS_XDIST:} {env:_PYTEST_FILES:}

extras = dev
deps =
{env:_PYTEST_TOX_EXTRA_DEP:}
8 changes: 7 additions & 1 deletion tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ envlist =
py313
py314
pypy3
py310-{pexpect,xdist,twisted24,twisted25,asynctest,numpy,pluggymain,pylib}
py310-{pexpect,xdist,twisted24,twisted25,asynctest,numpy,pluggymain,pylib,lowestdirect,onlymanaged}
doctesting
doctesting-coverage
plugins
Expand Down Expand Up @@ -38,6 +38,8 @@ description =
twisted25: against the unit test extras with twisted 25.0 or later
asynctest: against the unit test extras with asynctest
xdist: with pytest in parallel mode
lowestdirect: using lowest-direct resolution when running with uv
onlymanaged: using only managed python running with uv
under `{basepython}`
doctesting: including doctests
commands =
Expand Down Expand Up @@ -79,6 +81,10 @@ setenv =
lsof: _PYTEST_TOX_POSARGS_LSOF=--lsof

xdist: _PYTEST_TOX_POSARGS_XDIST=-n auto
uv_resolution =
lowestdirect: lowest-direct
uv_python_preference =
onlymanaged: only-managed
extras = dev
deps =
doctesting: PyYAML
Expand Down