From 3d24485caef6631c43f4964d43a15dc05a67a74a Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Wed, 19 Jul 2017 21:11:17 -0300 Subject: [PATCH] Clarify PYTHONPATH changes and ``rootdir`` roles - Also minor adjustments in the docs (wording, formatting, links, etc). Fix #2589 --- _pytest/config.py | 1 - doc/en/cache.rst | 2 ++ doc/en/contents.rst | 3 +- doc/en/customize.rst | 30 +++++++++++----- doc/en/example/index.rst | 4 +-- doc/en/nose.rst | 2 +- doc/en/pythonpath.rst | 71 ++++++++++++++++++++++++++++++++++++++ doc/en/usage.rst | 2 +- doc/en/writing_plugins.rst | 8 +++-- 9 files changed, 106 insertions(+), 17 deletions(-) create mode 100644 doc/en/pythonpath.rst diff --git a/_pytest/config.py b/_pytest/config.py index 4698ba790..d0ec62096 100644 --- a/_pytest/config.py +++ b/_pytest/config.py @@ -1079,7 +1079,6 @@ class Config(object): self.pluginmanager.load_setuptools_entrypoints('pytest11') self.pluginmanager.consider_env() self.known_args_namespace = ns = self._parser.parse_known_args(args, namespace=self.option.copy()) - confcutdir = self.known_args_namespace.confcutdir if self.known_args_namespace.confcutdir is None and self.inifile: confcutdir = py.path.local(self.inifile).dirname self.known_args_namespace.confcutdir = confcutdir diff --git a/doc/en/cache.rst b/doc/en/cache.rst index 688b6dd04..f3da3e6d6 100644 --- a/doc/en/cache.rst +++ b/doc/en/cache.rst @@ -1,3 +1,5 @@ +.. _cache: + Cache: working with cross-testrun state ======================================= diff --git a/doc/en/contents.rst b/doc/en/contents.rst index 9f4a9a1be..4f5bf789f 100644 --- a/doc/en/contents.rst +++ b/doc/en/contents.rst @@ -31,9 +31,10 @@ Full pytest documentation plugins writing_plugins - example/index goodpractices + pythonpath customize + example/index bash-completion backwards-compatibility diff --git a/doc/en/customize.rst b/doc/en/customize.rst index ce0a36c11..215e6ddd0 100644 --- a/doc/en/customize.rst +++ b/doc/en/customize.rst @@ -1,5 +1,5 @@ -Basic test configuration -=================================== +Configuration +============= Command line options and configuration file settings ----------------------------------------------------------------- @@ -15,17 +15,31 @@ which were registered by installed plugins. .. _rootdir: .. _inifiles: -initialization: determining rootdir and inifile +Initialization: determining rootdir and inifile ----------------------------------------------- .. versionadded:: 2.7 -pytest determines a "rootdir" for each test run which depends on +pytest determines a ``rootdir`` for each test run which depends on the command line arguments (specified test files, paths) and on -the existence of inifiles. The determined rootdir and ini-file are -printed as part of the pytest header. The rootdir is used for constructing -"nodeids" during collection and may also be used by plugins to store -project/testrun-specific information. +the existence of *ini-files*. The determined ``rootdir`` and *ini-file* are +printed as part of the pytest header during startup. + +Here's a summary what ``pytest`` uses ``rootdir`` for: + +* Construct *nodeids* during collection; each test is assigned + a unique *nodeid* which is rooted at the ``rootdir`` and takes in account full path, + class name, function name and parametrization (if any). + +* Is used by plugins as a stable location to store project/test run specific information; + for example, the internal :ref:`cache ` plugin creates a ``.cache`` subdirectory + in ``rootdir`` to store its cross-test run state. + +Important to emphasize that ``rootdir`` is **NOT** used to modify ``sys.path``/``PYTHONPATH`` or +influence how modules are imported. See :ref:`pythonpath` for more details. + +Finding the ``rootdir`` +~~~~~~~~~~~~~~~~~~~~~~~ Here is the algorithm which finds the rootdir from ``args``: diff --git a/doc/en/example/index.rst b/doc/en/example/index.rst index 363de5ab7..f63cb822a 100644 --- a/doc/en/example/index.rst +++ b/doc/en/example/index.rst @@ -1,8 +1,8 @@ .. _examples: -Usages and Examples -=========================================== +Examples and customization tricks +================================= Here is a (growing) list of examples. :ref:`Contact ` us if you need more examples or have questions. Also take a look at the diff --git a/doc/en/nose.rst b/doc/en/nose.rst index 5effd0d7b..10a10633a 100644 --- a/doc/en/nose.rst +++ b/doc/en/nose.rst @@ -26,7 +26,7 @@ Supported nose Idioms * setup and teardown at module/class/method level * SkipTest exceptions and markers * setup/teardown decorators -* ``yield``-based tests and their setup +* ``yield``-based tests and their setup (considered deprecated as of pytest 3.0) * ``__test__`` attribute on modules/classes/functions * general usage of nose utilities diff --git a/doc/en/pythonpath.rst b/doc/en/pythonpath.rst new file mode 100644 index 000000000..67de7f5d2 --- /dev/null +++ b/doc/en/pythonpath.rst @@ -0,0 +1,71 @@ +.. _pythonpath: + +pytest import mechanisms and ``sys.path``/``PYTHONPATH`` +======================================================== + +Here's a list of scenarios where pytest may need to change ``sys.path`` in order +to import test modules or ``conftest.py`` files. + +Test modules / ``conftest.py`` files inside packages +---------------------------------------------------- + +Consider this file and directory layout:: + + root/ + |- foo/ + |- __init__.py + |- conftest.py + |- bar/ + |- __init__.py + |- tests/ + |- __init__.py + |- test_foo.py + + +When executing:: + + pytest root/ + + + +pytest will find ``foo/bar/tests/test_foo.py`` and realize it is part of a package given that +there's an ``__init__.py`` file in the same folder. It will then search upwards until it can find the +last folder which still contains an ``__init__.py`` file in order to find the package *root* (in +this case ``foo/``). To load the module, it will insert ``root/`` to the front of +``sys.path`` (if not there already) in order to load +``test_foo.py`` as the *module* ``foo.bar.tests.test_foo``. + +The same logic applies to the ``conftest.py`` file: it will be imported as ``foo.conftest`` module. + +Preserving the full package name is important when tests live in a package to avoid problems +and allow test modules to have duplicated names. This is also discussed in details in +:ref:`test discovery`. + +Standalone test modules / ``conftest.py`` files +----------------------------------------------- + +Consider this file and directory layout:: + + root/ + |- foo/ + |- conftest.py + |- bar/ + |- tests/ + |- test_foo.py + + +When executing:: + + pytest root/ + +pytest will find ``foo/bar/tests/test_foo.py`` and realize it is NOT part of a package given that +there's no ``__init__.py`` file in the same folder. It will then add ``root/foo/bar/tests`` to +``sys.path`` in order to import ``test_foo.py`` as the *module* ``test_foo``. The same is done +with the ``conftest.py`` file by adding ``root/foo`` to ``sys.path`` to import it as ``conftest``. + +For this reason this layout cannot have test modules with the same name, as they all will be +imported in the global import namespace. + +This is also discussed in details in :ref:`test discovery`. + + diff --git a/doc/en/usage.rst b/doc/en/usage.rst index 763328f5a..775297882 100644 --- a/doc/en/usage.rst +++ b/doc/en/usage.rst @@ -17,7 +17,7 @@ You can invoke testing through the Python interpreter from the command line:: python -m pytest [...] This is almost equivalent to invoking the command line script ``pytest [...]`` -directly, except that python will also add the current directory to ``sys.path``. +directly, except that Python will also add the current directory to ``sys.path``. Possible exit codes -------------------------------------------------------------- diff --git a/doc/en/writing_plugins.rst b/doc/en/writing_plugins.rst index 861f2f48a..26e1a8a69 100644 --- a/doc/en/writing_plugins.rst +++ b/doc/en/writing_plugins.rst @@ -49,7 +49,7 @@ Plugin discovery order at tool startup Note that pytest does not find ``conftest.py`` files in deeper nested sub directories at tool startup. It is usually a good idea to keep - your conftest.py file in the top level test or project root directory. + your ``conftest.py`` file in the top level test or project root directory. * by recursively loading all plugins specified by the ``pytest_plugins`` variable in ``conftest.py`` files @@ -94,10 +94,12 @@ Here is how you might run it:: If you have ``conftest.py`` files which do not reside in a python package directory (i.e. one containing an ``__init__.py``) then "import conftest" can be ambiguous because there might be other - ``conftest.py`` files as well on your PYTHONPATH or ``sys.path``. + ``conftest.py`` files as well on your ``PYTHONPATH`` or ``sys.path``. It is thus good practice for projects to either put ``conftest.py`` under a package scope or to never import anything from a - conftest.py file. + ``conftest.py`` file. + + See also: :ref:`pythonpath`. Writing your own plugin