Clarify PYTHONPATH changes and ``rootdir`` roles
- Also minor adjustments in the docs (wording, formatting, links, etc). Fix #2589
This commit is contained in:
		
							parent
							
								
									c92760dca8
								
							
						
					
					
						commit
						3d24485cae
					
				|  | @ -1079,7 +1079,6 @@ class Config(object): | ||||||
|         self.pluginmanager.load_setuptools_entrypoints('pytest11') |         self.pluginmanager.load_setuptools_entrypoints('pytest11') | ||||||
|         self.pluginmanager.consider_env() |         self.pluginmanager.consider_env() | ||||||
|         self.known_args_namespace = ns = self._parser.parse_known_args(args, namespace=self.option.copy()) |         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: |         if self.known_args_namespace.confcutdir is None and self.inifile: | ||||||
|             confcutdir = py.path.local(self.inifile).dirname |             confcutdir = py.path.local(self.inifile).dirname | ||||||
|             self.known_args_namespace.confcutdir = confcutdir |             self.known_args_namespace.confcutdir = confcutdir | ||||||
|  |  | ||||||
|  | @ -1,3 +1,5 @@ | ||||||
|  | .. _cache: | ||||||
|  | 
 | ||||||
| Cache: working with cross-testrun state | Cache: working with cross-testrun state | ||||||
| ======================================= | ======================================= | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -31,9 +31,10 @@ Full pytest documentation | ||||||
|    plugins |    plugins | ||||||
|    writing_plugins |    writing_plugins | ||||||
| 
 | 
 | ||||||
|    example/index |  | ||||||
|    goodpractices |    goodpractices | ||||||
|  |    pythonpath | ||||||
|    customize |    customize | ||||||
|  |    example/index | ||||||
|    bash-completion |    bash-completion | ||||||
| 
 | 
 | ||||||
|    backwards-compatibility |    backwards-compatibility | ||||||
|  |  | ||||||
|  | @ -1,5 +1,5 @@ | ||||||
| Basic test configuration | Configuration | ||||||
| =================================== | ============= | ||||||
| 
 | 
 | ||||||
| Command line options and configuration file settings | Command line options and configuration file settings | ||||||
| ----------------------------------------------------------------- | ----------------------------------------------------------------- | ||||||
|  | @ -15,17 +15,31 @@ which were registered by installed plugins. | ||||||
| .. _rootdir: | .. _rootdir: | ||||||
| .. _inifiles: | .. _inifiles: | ||||||
| 
 | 
 | ||||||
| initialization: determining rootdir and inifile | Initialization: determining rootdir and inifile | ||||||
| ----------------------------------------------- | ----------------------------------------------- | ||||||
| 
 | 
 | ||||||
| .. versionadded:: 2.7 | .. 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 command line arguments (specified test files, paths) and on | ||||||
| the existence of inifiles.  The determined rootdir and ini-file are | the existence of *ini-files*.  The determined ``rootdir`` and *ini-file* are | ||||||
| printed as part of the pytest header.  The rootdir is used for constructing | printed as part of the pytest header during startup. | ||||||
| "nodeids" during collection and may also be used by plugins to store | 
 | ||||||
| project/testrun-specific information. | 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 <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``: | Here is the algorithm which finds the rootdir from ``args``: | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1,8 +1,8 @@ | ||||||
| 
 | 
 | ||||||
| .. _examples: | .. _examples: | ||||||
| 
 | 
 | ||||||
| Usages and Examples | Examples and customization tricks | ||||||
| =========================================== | ================================= | ||||||
| 
 | 
 | ||||||
| Here is a (growing) list of examples. :ref:`Contact <contact>` us if you | Here is a (growing) list of examples. :ref:`Contact <contact>` us if you | ||||||
| need more examples or have questions. Also take a look at the | need more examples or have questions. Also take a look at the | ||||||
|  |  | ||||||
|  | @ -26,7 +26,7 @@ Supported nose Idioms | ||||||
| * setup and teardown at module/class/method level | * setup and teardown at module/class/method level | ||||||
| * SkipTest exceptions and markers | * SkipTest exceptions and markers | ||||||
| * setup/teardown decorators | * 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 | * ``__test__`` attribute on modules/classes/functions | ||||||
| * general usage of nose utilities | * general usage of nose utilities | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -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`. | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | @ -17,7 +17,7 @@ You can invoke testing through the Python interpreter from the command line:: | ||||||
|     python -m pytest [...] |     python -m pytest [...] | ||||||
| 
 | 
 | ||||||
| This is almost equivalent to invoking the command line script ``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 | Possible exit codes | ||||||
| -------------------------------------------------------------- | -------------------------------------------------------------- | ||||||
|  |  | ||||||
|  | @ -49,7 +49,7 @@ Plugin discovery order at tool startup | ||||||
| 
 | 
 | ||||||
|   Note that pytest does not find ``conftest.py`` files in deeper nested |   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 |   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 | * by recursively loading all plugins specified by the | ||||||
|   ``pytest_plugins`` variable in ``conftest.py`` files |   ``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 |     If you have ``conftest.py`` files which do not reside in a | ||||||
|     python package directory (i.e. one containing an ``__init__.py``) then |     python package directory (i.e. one containing an ``__init__.py``) then | ||||||
|     "import conftest" can be ambiguous because there might be other |     "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`` |     It is thus good practice for projects to either put ``conftest.py`` | ||||||
|     under a package scope or to never import anything from a |     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 | Writing your own plugin | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue