From 973c84aea1d03a2363526dcd20d7bda87c885934 Mon Sep 17 00:00:00 2001 From: Ran Benita Date: Mon, 7 Feb 2022 21:14:38 +0200 Subject: [PATCH] pythonpath: make it compatible with pytest-pythonpath until pytest 8 Fix #9636. --- changelog/9636.bugfix.rst | 2 ++ doc/en/deprecations.rst | 18 ++++++++++++++++++ extra/setup-py.test/setup.py | 1 + src/_pytest/deprecated.py | 11 +++++++++++ src/_pytest/pythonpath.py | 34 ++++++++++++++++++++++++++++++++-- 5 files changed, 64 insertions(+), 2 deletions(-) create mode 100644 changelog/9636.bugfix.rst diff --git a/changelog/9636.bugfix.rst b/changelog/9636.bugfix.rst new file mode 100644 index 00000000000..37cd721d6bf --- /dev/null +++ b/changelog/9636.bugfix.rst @@ -0,0 +1,2 @@ +Restore compatiblity to users of the pytest-pythonpath plugins by adding two ini options ``python_paths`` and ``site_dirs``. +These options are immediately marked as deprecated. See :ref:`python_paths-site_dir-ini` for details. diff --git a/doc/en/deprecations.rst b/doc/en/deprecations.rst index d9fb4d6b04e..1d9d15c621e 100644 --- a/doc/en/deprecations.rst +++ b/doc/en/deprecations.rst @@ -18,6 +18,24 @@ Deprecated Features Below is a complete list of all pytest features which are considered deprecated. Using those features will issue :class:`PytestWarning` or subclasses, which can be filtered using :ref:`standard warning filters `. + +.. _python_paths-site_dir-ini: + +The ``python_paths`` and ``site_dirs`` ini options +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. deprecated:: 7.0.1 + +These two deprecations are relevant for users of the pytest-pythonpath plugin. +In pytest 7.0.0, a built-in ``pythonpath`` plugin was added with similar functionality to pytest-pythonpath. +In pytest 7.0.1, it was found that the built-in plugin prevents the external pytest-pythonpath from loading, +so to compensate, the options from the pytest-pythonpath plugins are implemented, but are immediately deprecated. + +The ``python_paths`` ini option is deprecated. Use :confval:`pythonpath` instead. + +The ``site_dirs`` ini option is deprecated. There is no replacement. If you use it, let the pytest developers know. + + .. _instance-collector-deprecation: The ``pytest.Instance`` collector diff --git a/extra/setup-py.test/setup.py b/extra/setup-py.test/setup.py index d0560ce1f5f..97883852e2e 100644 --- a/extra/setup-py.test/setup.py +++ b/extra/setup-py.test/setup.py @@ -1,4 +1,5 @@ import sys + from distutils.core import setup if __name__ == "__main__": diff --git a/src/_pytest/deprecated.py b/src/_pytest/deprecated.py index 4534fbcab82..4f41300f3bd 100644 --- a/src/_pytest/deprecated.py +++ b/src/_pytest/deprecated.py @@ -104,6 +104,17 @@ "See https://docs.pytest.org/en/latest/deprecations.html#the-pytest-instance-collector", ) +PYTHON_PATHS_INI = PytestRemovedIn8Warning( + "The python_paths ini option is deprecated. Use the pythonpath ini option instead. " + "If you are using the pytest-pythonpath plugin, you can remove it - it is built-in since pytest 7.0.0. " + "See https://docs.pytest.org/en/latest/deprecations.html#python_paths-site_dir-ini", +) + +SITE_DIRS_INI = PytestRemovedIn8Warning( + "The site_dirs ini option is deprecated. " + "See https://docs.pytest.org/en/latest/deprecations.html#python_paths-site_dir-ini", +) + # You want to make some `__init__` or function "private". # # def my_private_function(some, args): diff --git a/src/_pytest/pythonpath.py b/src/_pytest/pythonpath.py index cceabbca12a..1a70a62aca5 100644 --- a/src/_pytest/pythonpath.py +++ b/src/_pytest/pythonpath.py @@ -1,24 +1,54 @@ import sys import pytest +from _pytest.deprecated import PYTHON_PATHS_INI +from _pytest.deprecated import SITE_DIRS_INI from pytest import Config from pytest import Parser def pytest_addoption(parser: Parser) -> None: parser.addini("pythonpath", type="paths", help="Add paths to sys.path", default=[]) + parser.addini( + "python_paths", type="paths", help="Deprecated alias for pythonpath", default=[] + ) + parser.addini( + "site_dirs", + type="paths", + help="Deprecated: directory paths to add to via site.addsitedir(path)", + default=[], + ) @pytest.hookimpl(tryfirst=True) def pytest_load_initial_conftests(early_config: Config) -> None: + pythonpath = early_config.getini("pythonpath") + python_paths = early_config.getini("python_paths") + if python_paths: + early_config.issue_config_time_warning(PYTHON_PATHS_INI, 2) + if not pythonpath: + pythonpath = python_paths # `pythonpath = a b` will set `sys.path` to `[a, b, x, y, z, ...]` - for path in reversed(early_config.getini("pythonpath")): + for path in reversed(pythonpath): sys.path.insert(0, str(path)) + site_dirs = early_config.getini("site_dirs") + if site_dirs: + early_config.issue_config_time_warning(SITE_DIRS_INI, 2) + + import site + + for path in site_dirs: + site.addsitedir(str(path)) + @pytest.hookimpl(trylast=True) def pytest_unconfigure(config: Config) -> None: - for path in config.getini("pythonpath"): + pythonpath = config.getini("pythonpath") + python_paths = config.getini("python_paths") + if python_paths and not pythonpath: + pythonpath = python_paths + for path in pythonpath: path_str = str(path) if path_str in sys.path: sys.path.remove(path_str)