Skip to content

Commit 3aa5391

Browse files
authored
Merge branch 'main' into fix-13537
2 parents 89235a9 + c97a401 commit 3aa5391

File tree

17 files changed

+259
-134
lines changed

17 files changed

+259
-134
lines changed

.github/workflows/deploy.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ jobs:
3131
persist-credentials: false
3232

3333
- name: Build and Check Package
34-
uses: hynek/build-and-inspect-python-package@c52c3a4710070b50470d903818a7b25115dcd076
34+
uses: hynek/build-and-inspect-python-package@efb823f52190ad02594531168b7a2d5790e66516
3535
with:
3636
attest-build-provenance-github: 'true'
3737

.github/workflows/test.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ jobs:
4242
fetch-depth: 0
4343
persist-credentials: false
4444
- name: Build and Check Package
45-
uses: hynek/build-and-inspect-python-package@c52c3a4710070b50470d903818a7b25115dcd076
45+
uses: hynek/build-and-inspect-python-package@efb823f52190ad02594531168b7a2d5790e66516
4646

4747
build:
4848
needs: [package]

.pre-commit-config.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
repos:
22
- repo: https://github.com/astral-sh/ruff-pre-commit
3-
rev: "v0.13.3"
3+
rev: "v0.14.0"
44
hooks:
55
- id: ruff-check
66
args: ["--fix"]
@@ -66,13 +66,13 @@ repos:
6666
# Manual because passing pyright is a work in progress.
6767
stages: [manual]
6868
- repo: https://github.com/tox-dev/pyproject-fmt
69-
rev: "v2.7.0"
69+
rev: "v2.10.0"
7070
hooks:
7171
- id: pyproject-fmt
7272
# https://pyproject-fmt.readthedocs.io/en/latest/#calculating-max-supported-python-version
7373
additional_dependencies: ["tox>=4.9"]
7474
- repo: https://github.com/asottile/pyupgrade
75-
rev: v3.20.0
75+
rev: v3.21.0
7676
hooks:
7777
- id: pyupgrade
7878
args:

changelog/13574.improvement.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
The single argument ``--version`` no longer loads the entire plugin infrastructure, making it faster and more reliable when displaying only the pytest version.
2+
3+
Passing ``--version`` twice (e.g., ``pytest --version --version``) retains the original behavior, showing both the pytest version and plugin information.
4+
5+
.. note::
6+
7+
Since ``--version`` is now processed early, it only takes effect when passed directly via the command line. It will not work if set through other mechanisms, such as :envvar:`PYTEST_ADDOPTS` or :confval:`addopts`.

changelog/13807.deprecation.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
:meth:`monkeypatch.syspath_prepend() <pytest.MonkeyPatch.syspath_prepend>` now issues a deprecation warning when the prepended path contains legacy namespace packages (those using ``pkg_resources.declare_namespace()``).
2+
Users should migrate to native namespace packages (:pep:`420`).
3+
See :ref:`monkeypatch-fixup-namespace-packages` for details.

doc/en/deprecations.rst

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,41 @@ Below is a complete list of all pytest features which are considered deprecated.
1515
:class:`~pytest.PytestWarning` or subclasses, which can be filtered using :ref:`standard warning filters <warnings>`.
1616

1717

18+
.. _monkeypatch-fixup-namespace-packages:
19+
20+
``monkeypatch.syspath_prepend`` with legacy namespace packages
21+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
22+
23+
.. deprecated:: 9.0
24+
25+
When using :meth:`monkeypatch.syspath_prepend() <pytest.MonkeyPatch.syspath_prepend>`,
26+
pytest automatically calls ``pkg_resources.fixup_namespace_packages()`` if ``pkg_resources`` is imported.
27+
This is only needed for legacy namespace packages that use ``pkg_resources.declare_namespace()``.
28+
29+
Legacy namespace packages are deprecated in favor of native namespace packages (:pep:`420`).
30+
If you are using ``pkg_resources.declare_namespace()`` in your ``__init__.py`` files,
31+
you should migrate to native namespace packages by removing the ``__init__.py`` files from your namespace packages.
32+
33+
This deprecation warning will only be issued when:
34+
35+
1. ``pkg_resources`` is imported, and
36+
2. The specific path being prepended contains a declared namespace package (via ``pkg_resources.declare_namespace()``)
37+
38+
To fix this warning, convert your legacy namespace packages to native namespace packages:
39+
40+
**Legacy namespace package** (deprecated):
41+
42+
.. code-block:: python
43+
44+
# mypkg/__init__.py
45+
__import__("pkg_resources").declare_namespace(__name__)
46+
47+
**Native namespace package** (recommended):
48+
49+
Simply remove the ``__init__.py`` file entirely.
50+
Python 3.3+ natively supports namespace packages without ``__init__.py``.
51+
52+
1853
.. _sync-test-async-fixture:
1954

2055
sync test depending on async fixture

doc/en/reference/plugin_list.rst

Lines changed: 114 additions & 74 deletions
Large diffs are not rendered by default.

src/_pytest/config/__init__.py

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,8 @@ class ExitCode(enum.IntEnum):
110110
#: pytest couldn't find tests.
111111
NO_TESTS_COLLECTED = 5
112112

113+
__module__ = "pytest"
114+
113115

114116
class ConftestImportFailure(Exception):
115117
def __init__(
@@ -149,11 +151,17 @@ def main(
149151
150152
:returns: An exit code.
151153
"""
154+
# Handle a single `--version` argument early to avoid starting up the entire pytest infrastructure.
155+
new_args = sys.argv[1:] if args is None else args
156+
if isinstance(new_args, Sequence) and new_args.count("--version") == 1:
157+
sys.stdout.write(f"pytest {__version__}\n")
158+
return ExitCode.OK
159+
152160
old_pytest_version = os.environ.get("PYTEST_VERSION")
153161
try:
154162
os.environ["PYTEST_VERSION"] = __version__
155163
try:
156-
config = _prepareconfig(args, plugins)
164+
config = _prepareconfig(new_args, plugins)
157165
except ConftestImportFailure as e:
158166
exc_info = ExceptionInfo.from_exception(e.cause)
159167
tw = TerminalWriter(sys.stderr)
@@ -261,7 +269,6 @@ def directory_arg(path: str, optname: str) -> str:
261269
"junitxml",
262270
"doctest",
263271
"cacheprovider",
264-
"freeze_support",
265272
"setuponly",
266273
"setupplan",
267274
"stepwise",
@@ -317,12 +324,10 @@ def get_plugin_manager() -> PytestPluginManager:
317324

318325

319326
def _prepareconfig(
320-
args: list[str] | os.PathLike[str] | None = None,
327+
args: list[str] | os.PathLike[str],
321328
plugins: Sequence[str | _PluggyPlugin] | None = None,
322329
) -> Config:
323-
if args is None:
324-
args = sys.argv[1:]
325-
elif isinstance(args, os.PathLike):
330+
if isinstance(args, os.PathLike):
326331
args = [os.fspath(args)]
327332
elif not isinstance(args, list):
328333
msg = ( # type:ignore[unreachable]
@@ -1145,13 +1150,15 @@ def pytest_cmdline_parse(
11451150
try:
11461151
self.parse(args)
11471152
except UsageError:
1148-
# Handle --version and --help here in a minimal fashion.
1153+
# Handle `--version --version` and `--help` here in a minimal fashion.
11491154
# This gets done via helpconfig normally, but its
11501155
# pytest_cmdline_main is not called in case of errors.
11511156
if getattr(self.option, "version", False) or "--version" in args:
1152-
from _pytest.helpconfig import showversion
1157+
from _pytest.helpconfig import show_version_verbose
11531158

1154-
showversion(self)
1159+
# Note that `--version` (single argument) is handled early by `Config.main()`, so the only
1160+
# way we are reaching this point is via `--version --version`.
1161+
show_version_verbose(self)
11551162
elif (
11561163
getattr(self.option, "help", False) or "--help" in args or "-h" in args
11571164
):

src/_pytest/config/exceptions.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
class UsageError(Exception):
88
"""Error in pytest usage or invocation."""
99

10+
__module__ = "pytest"
11+
1012

1113
class PrintHelp(Exception):
1214
"""Raised when pytest should print its help to skip the rest of the

src/_pytest/deprecated.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
from _pytest.warning_types import PytestDeprecationWarning
1717
from _pytest.warning_types import PytestRemovedIn9Warning
18+
from _pytest.warning_types import PytestRemovedIn10Warning
1819
from _pytest.warning_types import UnformattedWarning
1920

2021

@@ -66,6 +67,13 @@
6667
"See docs: https://docs.pytest.org/en/stable/deprecations.html#applying-a-mark-to-a-fixture-function"
6768
)
6869

70+
MONKEYPATCH_LEGACY_NAMESPACE_PACKAGES = PytestRemovedIn10Warning(
71+
"monkeypatch.syspath_prepend() called with pkg_resources legacy namespace packages detected.\n"
72+
"Legacy namespace packages (using pkg_resources.declare_namespace) are deprecated.\n"
73+
"Please use native namespace packages (PEP 420) instead.\n"
74+
"See https://docs.pytest.org/en/stable/deprecations.html#monkeypatch-fixup-namespace-packages"
75+
)
76+
6977
# You want to make some `__init__` or function "private".
7078
#
7179
# def my_private_function(some, args):

0 commit comments

Comments
 (0)