From d217984129425321b07386cf66debd816675e07b Mon Sep 17 00:00:00 2001 From: Skylar Downes Date: Thu, 15 Sep 2016 10:46:15 -0700 Subject: [PATCH 01/42] documenting how to point pytest at local code Related to #1937 --- doc/en/customize.rst | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/doc/en/customize.rst b/doc/en/customize.rst index d12a49037..2a61aa1ef 100644 --- a/doc/en/customize.rst +++ b/doc/en/customize.rst @@ -97,6 +97,15 @@ check for ini-files as follows:: .. _`how to change command line options defaults`: .. _`adding default options`: +Change which files are added to sys.path +----------------------------------------------- +To tell pytest which files you want it to run your tests against +place both your pytest.ini file and a conftest.py file in a directory +above both your test folder and source folder. By having a conftest.py +in the root directory of your project, you can tell pytest to modify +your sys.path when it runs to include all submodules below the root of +your project. + How to change command line options defaults ------------------------------------------------ @@ -155,7 +164,7 @@ Builtin configuration file options * matches everything ? matches any single character - [seq] matches any character in seq + [seq] matches any character inbu seq [!seq] matches any char not in seq Default patterns are ``'.*', 'build', 'dist', 'CVS', '_darcs', '{arch}', '*.egg'``. From 383fc02ba6ffed96aa1f50f9e2f502caf0e9feb9 Mon Sep 17 00:00:00 2001 From: Skylar Downes Date: Thu, 15 Sep 2016 10:47:16 -0700 Subject: [PATCH 02/42] fix spacing --- doc/en/customize.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/en/customize.rst b/doc/en/customize.rst index 2a61aa1ef..7215c3e47 100644 --- a/doc/en/customize.rst +++ b/doc/en/customize.rst @@ -99,6 +99,7 @@ check for ini-files as follows:: Change which files are added to sys.path ----------------------------------------------- + To tell pytest which files you want it to run your tests against place both your pytest.ini file and a conftest.py file in a directory above both your test folder and source folder. By having a conftest.py From 69f72c6f4b21226a8223e05f8e1c27898347205e Mon Sep 17 00:00:00 2001 From: Skylar Downes Date: Thu, 15 Sep 2016 10:49:59 -0700 Subject: [PATCH 03/42] fix typo --- doc/en/customize.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/en/customize.rst b/doc/en/customize.rst index 7215c3e47..dc592f693 100644 --- a/doc/en/customize.rst +++ b/doc/en/customize.rst @@ -165,7 +165,7 @@ Builtin configuration file options * matches everything ? matches any single character - [seq] matches any character inbu seq + [seq] matches any character in seq [!seq] matches any char not in seq Default patterns are ``'.*', 'build', 'dist', 'CVS', '_darcs', '{arch}', '*.egg'``. From b4fd74c6ff18af275c0a99c4ab517de6a6ccf6b3 Mon Sep 17 00:00:00 2001 From: Skylar Downes Date: Thu, 15 Sep 2016 14:10:57 -0700 Subject: [PATCH 04/42] add mention of setup.py develop --- doc/en/customize.rst | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/doc/en/customize.rst b/doc/en/customize.rst index dc592f693..3b060a715 100644 --- a/doc/en/customize.rst +++ b/doc/en/customize.rst @@ -45,7 +45,7 @@ Here is the algorithm which finds the rootdir from ``args``: matched, it becomes the ini-file and its directory becomes the rootdir. - if no ini-file was found, use the already determined common ancestor as root - directory. This allows to work with pytest in structures that are not part of + directory. This allows the use of pytest in structures that are not part of a package and don't have any particular ini-file configuration. If no ``args`` are given, pytest collects test below the current working @@ -100,12 +100,15 @@ check for ini-files as follows:: Change which files are added to sys.path ----------------------------------------------- -To tell pytest which files you want it to run your tests against -place both your pytest.ini file and a conftest.py file in a directory -above both your test folder and source folder. By having a conftest.py -in the root directory of your project, you can tell pytest to modify -your sys.path when it runs to include all submodules below the root of -your project. +If you place a conftest.py file in the root directory of your project +(as determined by pytest, see above.) pytest will run tests against +the code below that directory by adding it to your sys.path instead of +running against your installed code. + +You may find yourself wanting to do this if you ran `python setup.py install` +to set up your project, as opposed to `python setup.py develop` or any of +the package manager equivalents. Installing with develop in a +virtual environment is recommended over using the conftest.py pattern. How to change command line options defaults ------------------------------------------------ From 07ad71e851fab1cf4640b9e44c62ddec66319ad2 Mon Sep 17 00:00:00 2001 From: Skylar Downes Date: Thu, 15 Sep 2016 14:55:54 -0700 Subject: [PATCH 05/42] clarified purpose of `pip install -e` command ref #1937 --- doc/en/goodpractices.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/doc/en/goodpractices.rst b/doc/en/goodpractices.rst index 7c2fdccf2..3950171aa 100644 --- a/doc/en/goodpractices.rst +++ b/doc/en/goodpractices.rst @@ -64,6 +64,12 @@ Important notes relating to both schemes: - **make sure that "mypkg" is importable**, for example by typing once:: pip install -e . # install package using setup.py in editable mode + # similar to running python setup.py develop + + This installs your package with a symlink to your development code + instead of placing the code directly in the install directory. + This way you can edit the code and run tests on your edits without + having to reinstall every time. - **avoid "__init__.py" files in your test directories**. This way your tests can run easily against an installed version From 81a733f2dcc16214568afeafcd84a12defe10097 Mon Sep 17 00:00:00 2001 From: Skylar Downes Date: Thu, 15 Sep 2016 15:09:47 -0700 Subject: [PATCH 06/42] add how-to for getting started on existing project ref #1937 --- doc/en/getting-started.rst | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/doc/en/getting-started.rst b/doc/en/getting-started.rst index 83462e3dc..d9fb3b1ff 100644 --- a/doc/en/getting-started.rst +++ b/doc/en/getting-started.rst @@ -185,6 +185,21 @@ You can find out what kind of builtin :ref:`fixtures` exist by typing:: pytest --fixtures # shows builtin and custom fixtures +Contributing tests to an existing project +------------------------------------- + +Say you want to contribute some tests to an existing repository. +After pulling the code into your development space using some +flavor of version control and (optionally) setting up a virtualenv +you will want to run:: + + pip install -e # Environment dependent alternatives include + # 'python setup.py develop' and 'conda develop' + +in your project root. This will set up a symlink to your code in +site-packages, allowing you to edit your code while your tests +run against it as if it were installed. + Where to go next ------------------------------------- From d781b76627c6b6db6c89641f63aed7b47366b3f2 Mon Sep 17 00:00:00 2001 From: Skylar Downes Date: Thu, 15 Sep 2016 15:20:47 -0700 Subject: [PATCH 07/42] Update AUTHORS --- AUTHORS | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS b/AUTHORS index c74aa4af6..6e4655f37 100644 --- a/AUTHORS +++ b/AUTHORS @@ -115,6 +115,7 @@ Russel Winder Ryan Wooden Samuele Pedroni Simon Gomizelj +Skylar Downes Stefan Farmbauer Stefan Zimmermann Stefano Taschini From f1faaea3fdebc72419d56309ece97c0f555aa3f5 Mon Sep 17 00:00:00 2001 From: Skylar Downes Date: Thu, 15 Sep 2016 15:22:53 -0700 Subject: [PATCH 08/42] Update CHANGELOG.rst --- CHANGELOG.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index cc4067fc1..beeefe1d3 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -13,7 +13,7 @@ * -* +* Added documentation related to issue #1937 .. _@philpep: https://github.com/philpep From 330a2f67841ff12f0fd69499cec39c4025fbbbe4 Mon Sep 17 00:00:00 2001 From: Skylar Downes Date: Thu, 15 Sep 2016 16:28:37 -0700 Subject: [PATCH 09/42] Update getting-started.rst --- doc/en/getting-started.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/doc/en/getting-started.rst b/doc/en/getting-started.rst index d9fb3b1ff..6ed6d9ed8 100644 --- a/doc/en/getting-started.rst +++ b/doc/en/getting-started.rst @@ -186,14 +186,15 @@ You can find out what kind of builtin :ref:`fixtures` exist by typing:: pytest --fixtures # shows builtin and custom fixtures Contributing tests to an existing project -------------------------------------- +------------------------------------------- Say you want to contribute some tests to an existing repository. After pulling the code into your development space using some flavor of version control and (optionally) setting up a virtualenv you will want to run:: - pip install -e # Environment dependent alternatives include + cd + pip install -e . # Environment dependent alternatives include # 'python setup.py develop' and 'conda develop' in your project root. This will set up a symlink to your code in From 34117be98b8c880787469e82df2c65ee7e534500 Mon Sep 17 00:00:00 2001 From: Skylar Downes Date: Thu, 15 Sep 2016 16:45:35 -0700 Subject: [PATCH 10/42] Update goodpractices.rst --- doc/en/goodpractices.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/en/goodpractices.rst b/doc/en/goodpractices.rst index 3950171aa..c125cc7ca 100644 --- a/doc/en/goodpractices.rst +++ b/doc/en/goodpractices.rst @@ -64,7 +64,8 @@ Important notes relating to both schemes: - **make sure that "mypkg" is importable**, for example by typing once:: pip install -e . # install package using setup.py in editable mode - # similar to running python setup.py develop + # similar to running `python setup.py develop` or + # `conda develop` This installs your package with a symlink to your development code instead of placing the code directly in the install directory. From 7e2f66adc38f3609b805ee006e0987b678f731de Mon Sep 17 00:00:00 2001 From: Skylar Downes Date: Tue, 27 Sep 2016 12:51:46 -0700 Subject: [PATCH 11/42] Create existingtestsuite.rst --- doc/en/existingtestsuite.rst | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 doc/en/existingtestsuite.rst diff --git a/doc/en/existingtestsuite.rst b/doc/en/existingtestsuite.rst new file mode 100644 index 000000000..96ce6339c --- /dev/null +++ b/doc/en/existingtestsuite.rst @@ -0,0 +1,32 @@ +Using pytest with an existing test suite +=========================================== + +Pytest can be used with most existing test suites, but it's +behavior differs from other test runners such as :ref:`nose` or +Python's default unittest framework. + +Before using this section you will want to :ref:`getting-started `. + +Running an existing test suite with pytest +--------------------------------------------- + +Say you want to contribute to an existing repository somewhere. +After pulling the code into your development space using some +flavor of version control and (optionally) setting up a virtualenv +you will want to run:: + + cd + pip install -e . # Environment dependent alternatives include + # 'python setup.py develop' and 'conda develop' + +in your project root. This will set up a symlink to your code in +site-packages, allowing you to edit your code while your tests +run against it as if it were installed. + +Setting up your project in development mode lets you avoid having to +reinstall every time you want to run your tests, and is less brittle than +mucking about with sys.path to point your tests at local code. + +Also consider using Tox - https://tox.readthedocs.io/en/latest/ + +.. include:: links.inc From 12ac3c7338d7a66e3c3b2e5fd742b0d49c61191b Mon Sep 17 00:00:00 2001 From: Skylar Downes Date: Tue, 27 Sep 2016 13:08:15 -0700 Subject: [PATCH 12/42] remove existing tests stuff, add link to new page Moved the "Contributing tests to an existing project" section to it's own page. --- doc/en/getting-started.rst | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/doc/en/getting-started.rst b/doc/en/getting-started.rst index 6ed6d9ed8..836498c69 100644 --- a/doc/en/getting-started.rst +++ b/doc/en/getting-started.rst @@ -185,28 +185,13 @@ You can find out what kind of builtin :ref:`fixtures` exist by typing:: pytest --fixtures # shows builtin and custom fixtures -Contributing tests to an existing project -------------------------------------------- - -Say you want to contribute some tests to an existing repository. -After pulling the code into your development space using some -flavor of version control and (optionally) setting up a virtualenv -you will want to run:: - - cd - pip install -e . # Environment dependent alternatives include - # 'python setup.py develop' and 'conda develop' - -in your project root. This will set up a symlink to your code in -site-packages, allowing you to edit your code while your tests -run against it as if it were installed. - Where to go next ------------------------------------- Here are a few suggestions where to go next: * :ref:`cmdline` for command line invocation examples +* :ref:`existingtestsuite` for working with pre-existing tests * :ref:`good practices ` for virtualenv, test layout * :ref:`fixtures` for providing a functional baseline to your tests * :ref:`plugins` managing and writing plugins From 1ab1962eb1aaae693b1dfd00aadae3e6ba23748e Mon Sep 17 00:00:00 2001 From: Skylar Downes Date: Tue, 27 Sep 2016 13:53:31 -0700 Subject: [PATCH 13/42] make issue #1934 reference a link --- CHANGELOG.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index beeefe1d3..f2119eb0b 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -13,7 +13,7 @@ * -* Added documentation related to issue #1937 +* Added documentation related to issue (`#1937`_) .. _@philpep: https://github.com/philpep From 3d211da9bda2e79cd52dad92f91744985e0fd9a3 Mon Sep 17 00:00:00 2001 From: Skylar Downes Date: Tue, 27 Sep 2016 14:01:54 -0700 Subject: [PATCH 14/42] add existing test suite page to table of contents --- doc/en/contents.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/en/contents.rst b/doc/en/contents.rst index d7f900810..ce6396e47 100644 --- a/doc/en/contents.rst +++ b/doc/en/contents.rst @@ -12,6 +12,7 @@ Full pytest documentation getting-started usage + existingtestsuite assert builtin fixture From b0c78c867dcc5b3c2ab0b3024bcaff1f29f7f975 Mon Sep 17 00:00:00 2001 From: Skylar Downes Date: Tue, 27 Sep 2016 15:50:45 -0700 Subject: [PATCH 15/42] Update CHANGELOG.rst --- CHANGELOG.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index f2119eb0b..c5fb31151 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -14,12 +14,14 @@ * * Added documentation related to issue (`#1937`_) - + Thanks `@skylarjhdownes`_ for the PR. .. _@philpep: https://github.com/philpep +.. _@skylarjhdownes: https://github.com/skylarjhdownes .. _#1905: https://github.com/pytest-dev/pytest/issues/1905 .. _#1934: https://github.com/pytest-dev/pytest/issues/1934 +.. _#1937: https://github.com/pytest-dev/pytest/issues/1937 3.0.2 From 841f73170751b237a15f64a489988f783da7982d Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Thu, 9 Mar 2017 20:41:33 -0300 Subject: [PATCH 16/42] Attempt to clarify the confusion regarding __init__ files and unique test names Fix #529 --- doc/en/goodpractices.rst | 85 ++++++++++++++++++---------------------- tox.ini | 2 + 2 files changed, 40 insertions(+), 47 deletions(-) diff --git a/doc/en/goodpractices.rst b/doc/en/goodpractices.rst index 48f80a9e2..65c5624fa 100644 --- a/doc/en/goodpractices.rst +++ b/doc/en/goodpractices.rst @@ -30,68 +30,58 @@ Within Python modules, ``pytest`` also discovers tests using the standard Choosing a test layout / import rules ------------------------------------------- +------------------------------------- ``pytest`` supports two common test layouts: -* putting tests into an extra directory outside your actual application - code, useful if you have many functional tests or for other reasons - want to keep tests separate from actual application code (often a good - idea):: +Tests outside application code +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - setup.py # your setuptools Python package metadata +Putting tests into an extra directory outside your actual application code +might be useful if you have many functional tests or for other reasons want +to keep tests separate from actual application code (often a good idea):: + + setup.py mypkg/ __init__.py - appmodule.py + app.py + view.py tests/ test_app.py + test_view.py ... +This way your tests can run easily against an installed version +of ``mypkg``. -* inlining test directories into your application package, useful if you - have direct relation between (unit-)test and application modules and - want to distribute your tests along with your application:: +Note that using this scheme your test files must have **unique names**, because +``pytest`` will import them as *top-level* modules since there are no packages +to derive a full package name from. - setup.py # your setuptools Python package metadata +Tests as part of application code +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Inlining test directories into your application package +is useful if you have direct relation between tests and application modules and +want to distribute them along with your application:: + + setup.py mypkg/ __init__.py - appmodule.py - ... + app.py + view.py test/ + __init__.py test_app.py + test_view.py ... -Important notes relating to both schemes: +In this scheme, it is easy to your tests using the ``--pyargs`` option:: -- **make sure that "mypkg" is importable**, for example by typing once:: + pytest --pyargs mypkg - pip install -e . # install package using setup.py in editable mode +``pytest`` will discover where ``mypkg`` is installed and collect tests from there. -- **avoid "__init__.py" files in your test directories**. - This way your tests can run easily against an installed version - of ``mypkg``, independently from the installed package if it contains - the tests or not. - -- With inlined tests you might put ``__init__.py`` into test - directories and make them installable as part of your application. - Using the ``pytest --pyargs mypkg`` invocation pytest will - discover where mypkg is installed and collect tests from there. - With the "external" test you can still distribute tests but they - will not be installed or become importable. - -Typically you can run tests by pointing to test directories or modules:: - - pytest tests/test_app.py # for external test dirs - pytest mypkg/test/test_app.py # for inlined test dirs - pytest mypkg # run tests in all below test directories - pytest # run all tests below current dir - ... - -Because of the above ``editable install`` mode you can change your -source code (both tests and the app) and rerun tests at will. -Once you are done with your work, you can `use tox`_ to make sure -that the package is really correct and tests pass in all -required configurations. .. note:: @@ -144,7 +134,13 @@ for installing your application and any dependencies as well as the ``pytest`` package itself. This ensures your code and dependencies are isolated from the system Python installation. -If you frequently release code and want to make sure that your actual +You can then install your package in "editable" mode:: + + pip install -e . + +which lets you change your source code (both tests and application) and rerun tests at will. + +Once you are done with your work and want to make sure that your actual package passes all tests you may want to look into `tox`_, the virtualenv test automation tool and its `pytest support `_. @@ -154,11 +150,6 @@ options. It will run tests against the installed package and not against your source code checkout, helping to detect packaging glitches. -Continuous integration services such as Jenkins_ can make use of the -``--junitxml=PATH`` option to create a JUnitXML file and generate reports (e.g. -by publishing the results in a nice format with the `Jenkins xUnit Plugin -`_). - Integrating with setuptools / ``python setup.py test`` / ``pytest-runner`` -------------------------------------------------------------------------- diff --git a/tox.ini b/tox.ini index 1b9fb9f5a..a47fc5132 100644 --- a/tox.ini +++ b/tox.ini @@ -106,6 +106,8 @@ commands= pytest -ra {posargs:testing/test_unittest.py} [testenv:docs] +skipsdist=True +usedevelop=True basepython=python changedir=doc/en deps= From 581857aab631b2a5a17232b3a332dd44b832e689 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Thu, 9 Mar 2017 20:46:22 -0300 Subject: [PATCH 17/42] Fix typo --- doc/en/goodpractices.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/en/goodpractices.rst b/doc/en/goodpractices.rst index 65c5624fa..5f6ea710b 100644 --- a/doc/en/goodpractices.rst +++ b/doc/en/goodpractices.rst @@ -76,7 +76,7 @@ want to distribute them along with your application:: test_view.py ... -In this scheme, it is easy to your tests using the ``--pyargs`` option:: +In this scheme, it is easy to your run tests using the ``--pyargs`` option:: pytest --pyargs mypkg From 4a9348324d414f4f7a68b8a096a9ff960101aa1f Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Tue, 14 Mar 2017 07:59:01 -0300 Subject: [PATCH 18/42] Add more information to test-layout docs as discussed during PR --- doc/en/goodpractices.rst | 39 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/doc/en/goodpractices.rst b/doc/en/goodpractices.rst index 5f6ea710b..ff71f1c9c 100644 --- a/doc/en/goodpractices.rst +++ b/doc/en/goodpractices.rst @@ -56,7 +56,44 @@ of ``mypkg``. Note that using this scheme your test files must have **unique names**, because ``pytest`` will import them as *top-level* modules since there are no packages -to derive a full package name from. +to derive a full package name from. In other words, the test files in the example above will +be imported as ``test_app`` and ``test_view`` top-level modules by adding ``tests/`` to +``sys.path``. + +If you need to have test modules with the same name, you might add ``__init__.py`` files to your +``tests`` folder and subfolders, changing them to packages:: + + mypkg/ + ... + tests/ + __init__.py + foo/ + __init__.py + test_view.py + bar/ + __init__.py + test_view.py + +Now pytest will load the modules as ``tests.foo.test_view`` and ``tests.bar.test_view``, allowing +you to have modules with the same name. But now this introduces a subtle problem: in order to load +the test modules from the ``tests`` directory, pytest prepends the root of the repository to +``sys.path``, which adds the side-effect that now ``mypkg`` is also importable. +This is problematic if you are using a tool like `tox`_ to test your package in a virtual environment, +because you want to test the *installed* version of your package, not the local code from the repository. + +There are a couple of solutions to this: + +* Do not add the ``tests/__init__.py`` file. This will cause your test modules to be loaded as + ``foo.test_view`` and ``bar.test_view``, which is usually fine and avoids having the root of + the repository being added to the ``PYTHONPATH``. + +* Add ``addopts=--import-mode=append`` to your ``pytest.ini`` file. This will cause ``pytest`` to + load your modules by *appending* the root directory instead of prepending. + +* Alternatively, consider using the ``src`` layout explained in detail in this excellent + `blog post by Ionel Cristian Mărieș `_ + which prevents a lot of the pitfalls described here. + Tests as part of application code ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ From 272aba98e2009aaa37841594691ff88cb866b7d3 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Tue, 14 Mar 2017 18:39:02 -0300 Subject: [PATCH 19/42] Mention the src layout as recommended practice --- doc/en/goodpractices.rst | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/doc/en/goodpractices.rst b/doc/en/goodpractices.rst index ff71f1c9c..c17fabbc9 100644 --- a/doc/en/goodpractices.rst +++ b/doc/en/goodpractices.rst @@ -63,6 +63,7 @@ be imported as ``test_app`` and ``test_view`` top-level modules by adding ``test If you need to have test modules with the same name, you might add ``__init__.py`` files to your ``tests`` folder and subfolders, changing them to packages:: + setup.py mypkg/ ... tests/ @@ -81,19 +82,27 @@ the test modules from the ``tests`` directory, pytest prepends the root of the r This is problematic if you are using a tool like `tox`_ to test your package in a virtual environment, because you want to test the *installed* version of your package, not the local code from the repository. -There are a couple of solutions to this: +In this situation, it is **strongly** suggested to use a ``src`` layout where application root package resides in a +sub-directory of your root:: -* Do not add the ``tests/__init__.py`` file. This will cause your test modules to be loaded as - ``foo.test_view`` and ``bar.test_view``, which is usually fine and avoids having the root of - the repository being added to the ``PYTHONPATH``. + setup.py + src/ + mypkg/ + __init__.py + app.py + view.py + tests/ + __init__.py + foo/ + __init__.py + test_view.py + bar/ + __init__.py + test_view.py -* Add ``addopts=--import-mode=append`` to your ``pytest.ini`` file. This will cause ``pytest`` to - load your modules by *appending* the root directory instead of prepending. - -* Alternatively, consider using the ``src`` layout explained in detail in this excellent - `blog post by Ionel Cristian Mărieș `_ - which prevents a lot of the pitfalls described here. +This layout prevents a lot of common pitfalls and has many benefits, which are better explained in this excellent +`blog post by Ionel Cristian Mărieș `_. Tests as part of application code ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -119,6 +128,8 @@ In this scheme, it is easy to your run tests using the ``--pyargs`` option:: ``pytest`` will discover where ``mypkg`` is installed and collect tests from there. +Note that this layout also works in conjunction with the ``src`` layout mentioned in the previous section. + .. note:: From dc6890709e19567219cc35a561a07dc8cd5d611c Mon Sep 17 00:00:00 2001 From: Xander Johnson Date: Tue, 14 Mar 2017 12:45:56 -0700 Subject: [PATCH 20/42] Change ValueError to io.UnsupportedOperation in capture.py. Resolves issue #2276 --- _pytest/capture.py | 3 ++- testing/test_capture.py | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/_pytest/capture.py b/_pytest/capture.py index eea81ca18..07ec662b6 100644 --- a/_pytest/capture.py +++ b/_pytest/capture.py @@ -13,6 +13,7 @@ import py import pytest from py.io import TextIO +from io import UnsupportedOperation unicode = py.builtin.text patchsysdict = {0: 'stdin', 1: 'stdout', 2: 'stderr'} @@ -448,7 +449,7 @@ class DontReadFromInput: __iter__ = read def fileno(self): - raise ValueError("redirected Stdin is pseudofile, has no fileno()") + raise UnsupportedOperation("redirected Stdin is pseudofile, has no fileno()") def isatty(self): return False diff --git a/testing/test_capture.py b/testing/test_capture.py index 763e28315..978e67b7e 100644 --- a/testing/test_capture.py +++ b/testing/test_capture.py @@ -4,6 +4,7 @@ from __future__ import with_statement import pickle import os import sys +from io import UnsupportedOperation import _pytest._code import py @@ -658,7 +659,7 @@ def test_dontreadfrominput(): pytest.raises(IOError, f.read) pytest.raises(IOError, f.readlines) pytest.raises(IOError, iter, f) - pytest.raises(ValueError, f.fileno) + pytest.raises(UnsupportedOperation, f.fileno) f.close() # just for completeness From 9062fbb9cc0aae758f97f90d26cffa56cc8bf5be Mon Sep 17 00:00:00 2001 From: Xander Johnson Date: Tue, 14 Mar 2017 12:52:37 -0700 Subject: [PATCH 21/42] Add AUTHORS & CHANGELOG --- AUTHORS | 1 + CHANGELOG.rst | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/AUTHORS b/AUTHORS index ce19f1f21..063593dd6 100644 --- a/AUTHORS +++ b/AUTHORS @@ -6,6 +6,7 @@ Contributors include:: Abdeali JK Abhijeet Kasurde Ahn Ki-Wook +Alexander Johnson Alexei Kozlenok Anatoly Bubenkoff Andreas Zeidler diff --git a/CHANGELOG.rst b/CHANGELOG.rst index beb0542be..7aceb200c 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -15,6 +15,9 @@ 3.0.7 (2017-03-14) ================== +* Change capture.py's DontReadFromInput class to throw io.UnsupportedOperation errors rather + than ValueErrors in the fileno method (`#2276`). + Thanks `@metasyn` for the PR. * Fix issue in assertion rewriting breaking due to modules silently discarding other modules when importing fails @@ -58,6 +61,7 @@ .. _@kkoukiou: https://github.com/KKoukiou .. _@omerhadari: https://github.com/omerhadari .. _@fbjorn: https://github.com/fbjorn +.. _@metasyn: https://github.com/metasyn .. _#2248: https://github.com/pytest-dev/pytest/issues/2248 .. _#2137: https://github.com/pytest-dev/pytest/issues/2137 @@ -66,6 +70,7 @@ .. _#2234: https://github.com/pytest-dev/pytest/issues/2234 .. _#2238: https://github.com/pytest-dev/pytest/issues/2238 .. _#2281: https://github.com/pytest-dev/pytest/issues/2281 +.. _#2276: https://github.com/pytest-dev/pytest/issues/2276 .. _PEP-479: https://www.python.org/dev/peps/pep-0479/ From aad4946fb665269a7771cc3ae6eb67a7392e8306 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Tue, 14 Mar 2017 18:58:28 -0300 Subject: [PATCH 22/42] Move CHANGELOG entry for #2276 to 3.0.8 --- CHANGELOG.rst | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 7aceb200c..c2e4e9ce7 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,7 +1,9 @@ 3.0.8 (unreleased) ================== -* +* Change capture.py's ``DontReadFromInput`` class to throw ``io.UnsupportedOperation`` errors rather + than ValueErrors in the ``fileno`` method (`#2276`_). + Thanks `@metasyn`_ for the PR. * @@ -12,16 +14,19 @@ * +.. _@metasyn: https://github.com/metasyn + + +.. _#2276: https://github.com/pytest-dev/pytest/issues/2276 + + 3.0.7 (2017-03-14) ================== -* Change capture.py's DontReadFromInput class to throw io.UnsupportedOperation errors rather - than ValueErrors in the fileno method (`#2276`). - Thanks `@metasyn` for the PR. * Fix issue in assertion rewriting breaking due to modules silently discarding other modules when importing fails - Notably, importing the `anydbm` module is fixed. (`#2248`_). + Notably, importing the ``anydbm`` module is fixed. (`#2248`_). Thanks `@pfhayes`_ for the PR. * junitxml: Fix problematic case where system-out tag occured twice per testcase @@ -61,7 +66,6 @@ .. _@kkoukiou: https://github.com/KKoukiou .. _@omerhadari: https://github.com/omerhadari .. _@fbjorn: https://github.com/fbjorn -.. _@metasyn: https://github.com/metasyn .. _#2248: https://github.com/pytest-dev/pytest/issues/2248 .. _#2137: https://github.com/pytest-dev/pytest/issues/2137 @@ -70,7 +74,6 @@ .. _#2234: https://github.com/pytest-dev/pytest/issues/2234 .. _#2238: https://github.com/pytest-dev/pytest/issues/2238 .. _#2281: https://github.com/pytest-dev/pytest/issues/2281 -.. _#2276: https://github.com/pytest-dev/pytest/issues/2276 .. _PEP-479: https://www.python.org/dev/peps/pep-0479/ From d58bc146459ae295256bbcf324c08eced354a086 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Adamczak?= Date: Sun, 19 Mar 2017 18:34:43 +0000 Subject: [PATCH 23/42] Added 'Possible exit codes' section to docs (#2239) --- doc/en/usage.rst | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/doc/en/usage.rst b/doc/en/usage.rst index a6fd4892e..8cc682787 100644 --- a/doc/en/usage.rst +++ b/doc/en/usage.rst @@ -19,6 +19,18 @@ You can invoke testing through the Python interpreter from the command line:: This is almost equivalent to invoking the command line script ``pytest [...]`` directly, except that python will also add the current directory to ``sys.path``. +Possible exit codes +-------------------------------------------------------------- + +Running ``pytest`` can result in six different exit codes: + +:Exit code 0: All tests were collected and passed successfully +:Exit code 1: Tests were collected and run but some of the tests failed +:Exit code 2: Test execution was interrupted by the user +:Exit code 3: Internal error happened while executing tests +:Exit code 4: pytest command line usage error +:Exit code 5: No tests were collected + Getting help on version, option names, environment variables -------------------------------------------------------------- From 8b57aaf94410f664d8b5bb2d952943a44d581067 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Adamczak?= Date: Sun, 19 Mar 2017 18:38:41 +0000 Subject: [PATCH 24/42] =?UTF-8?q?Added=20'Pawe=C5=82=20Adamczak'=20to=20AU?= =?UTF-8?q?THORS?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AUTHORS | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS b/AUTHORS index 063593dd6..025a3c8f6 100644 --- a/AUTHORS +++ b/AUTHORS @@ -117,6 +117,7 @@ Oliver Bestwalter Omar Kohl Omer Hadari Patrick Hayes +Paweł Adamczak Pieter Mulder Piotr Banaszkiewicz Punyashloka Biswal From 58ac4faf0c6338439f9b8335709a6bc216d7cd1c Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Wed, 29 Mar 2017 14:38:14 -0300 Subject: [PATCH 25/42] Fix exception formatting while importing test modules Fix #2336 --- CHANGELOG.rst | 9 +++++++-- _pytest/compat.py | 2 ++ _pytest/python.py | 4 ++-- testing/python/collect.py | 17 +++++++++++++++++ 4 files changed, 28 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index c2e4e9ce7..78d7501fb 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -5,8 +5,11 @@ than ValueErrors in the ``fileno`` method (`#2276`_). Thanks `@metasyn`_ for the PR. -* - +* Fix exception formatting while importing modules when the exception message + contains non-ascii characters (`#2336`_). + Thanks `@fabioz`_ for the report and `@nicoddemus`_ for the PR. + + * * @@ -14,10 +17,12 @@ * +.. _@fabioz: https://github.com/fabioz .. _@metasyn: https://github.com/metasyn .. _#2276: https://github.com/pytest-dev/pytest/issues/2276 +.. _#2336: https://github.com/pytest-dev/pytest/issues/2336 3.0.7 (2017-03-14) diff --git a/_pytest/compat.py b/_pytest/compat.py index d278b89cd..cc2954bff 100644 --- a/_pytest/compat.py +++ b/_pytest/compat.py @@ -237,5 +237,7 @@ else: try: return str(v) except UnicodeError: + if not isinstance(v, unicode): + v = unicode(v) errors = 'replace' return v.encode('ascii', errors) diff --git a/_pytest/python.py b/_pytest/python.py index 3e865e9df..59492bc41 100644 --- a/_pytest/python.py +++ b/_pytest/python.py @@ -19,7 +19,7 @@ from _pytest.compat import ( isclass, isfunction, is_generator, _escape_strings, REGEX_TYPE, STRING_TYPES, NoneType, NOTSET, get_real_func, getfslineno, safe_getattr, - getlocation, enum, + safe_str, getlocation, enum, ) cutdir1 = py.path.local(pluggy.__file__.rstrip("oc")) @@ -437,7 +437,7 @@ class Module(pytest.File, PyCollector): if self.config.getoption('verbose') < 2: exc_info.traceback = exc_info.traceback.filter(filter_traceback) exc_repr = exc_info.getrepr(style='short') if exc_info.traceback else exc_info.exconly() - formatted_tb = py._builtin._totext(exc_repr) + formatted_tb = safe_str(exc_repr) raise self.CollectError( "ImportError while importing test module '{fspath}'.\n" "Hint: make sure your test modules/packages have valid Python names.\n" diff --git a/testing/python/collect.py b/testing/python/collect.py index cce934ddc..d0e490832 100644 --- a/testing/python/collect.py +++ b/testing/python/collect.py @@ -105,6 +105,23 @@ class TestModule: assert name not in stdout + def test_show_traceback_import_error_unicode(self, testdir): + """Check test modules collected which raise ImportError with unicode messages + are handled properly (#2336). + """ + testdir.makepyfile(u""" + # -*- coding: utf-8 -*- + raise ImportError(u'Something bad happened ☺') + """) + result = testdir.runpytest() + result.stdout.fnmatch_lines([ + "ImportError while importing test module*", + "Traceback:", + "*raise ImportError*Something bad happened*", + ]) + assert result.ret == 2 + + class TestClass: def test_class_with_init_warning(self, testdir): testdir.makepyfile(""" From a542ed48a23cfbc526a1876ec135d4e43b37a38f Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Wed, 29 Mar 2017 15:18:41 -0300 Subject: [PATCH 26/42] Convert using utf-8 instead of ascii in safe_str() This way we don't lose information and the returned string is ascii-compatible anyway --- _pytest/compat.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_pytest/compat.py b/_pytest/compat.py index cc2954bff..4f2013dac 100644 --- a/_pytest/compat.py +++ b/_pytest/compat.py @@ -240,4 +240,4 @@ else: if not isinstance(v, unicode): v = unicode(v) errors = 'replace' - return v.encode('ascii', errors) + return v.encode('utf-8', errors) From 44a3db3dc668b28fa3892b3cd9fb2e14aa2d7c21 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Thu, 6 Apr 2017 18:02:49 -0300 Subject: [PATCH 27/42] Pin sphinx to 1.4 when generating docs to workaround search issues on RTD Fix #2302 --- doc/en/requirements.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 doc/en/requirements.txt diff --git a/doc/en/requirements.txt b/doc/en/requirements.txt new file mode 100644 index 000000000..72bb60a81 --- /dev/null +++ b/doc/en/requirements.txt @@ -0,0 +1,3 @@ +# pinning sphinx to 1.4.* due to search issues with rtd: +# https://github.com/rtfd/readthedocs-sphinx-ext/issues/25 +sphinx ==1.4.* From f7caa56a6b045b0541024374094c213fbcf58794 Mon Sep 17 00:00:00 2001 From: Skylar Downes Date: Thu, 6 Apr 2017 18:01:03 -0700 Subject: [PATCH 28/42] moved documentation of conftest.py hack to nose.rst --- doc/en/customize.rst | 13 +------------ doc/en/goodpractices.rst | 4 +--- doc/en/nose.rst | 11 +++++++++++ 3 files changed, 13 insertions(+), 15 deletions(-) diff --git a/doc/en/customize.rst b/doc/en/customize.rst index 3b060a715..e1d8fc571 100644 --- a/doc/en/customize.rst +++ b/doc/en/customize.rst @@ -49,7 +49,7 @@ Here is the algorithm which finds the rootdir from ``args``: a package and don't have any particular ini-file configuration. If no ``args`` are given, pytest collects test below the current working -directory and also starts determining the rootdir from there. +directory and also starts determining the rootdir from there. :warning: custom pytest plugin commandline arguments may include a path, as in ``pytest --log-output ../../test.log args``. Then ``args`` is mandatory, @@ -97,18 +97,7 @@ check for ini-files as follows:: .. _`how to change command line options defaults`: .. _`adding default options`: -Change which files are added to sys.path ------------------------------------------------ -If you place a conftest.py file in the root directory of your project -(as determined by pytest, see above.) pytest will run tests against -the code below that directory by adding it to your sys.path instead of -running against your installed code. - -You may find yourself wanting to do this if you ran `python setup.py install` -to set up your project, as opposed to `python setup.py develop` or any of -the package manager equivalents. Installing with develop in a -virtual environment is recommended over using the conftest.py pattern. How to change command line options defaults ------------------------------------------------ diff --git a/doc/en/goodpractices.rst b/doc/en/goodpractices.rst index 9e8811c7f..92cd9ed81 100644 --- a/doc/en/goodpractices.rst +++ b/doc/en/goodpractices.rst @@ -104,11 +104,9 @@ sub-directory of your root:: This layout prevents a lot of common pitfalls and has many benefits, which are better explained in this excellent `blog post by Ionel Cristian Mărieș `_. - Tests as part of application code ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Inlining test directories into your application package is useful if you have direct relation between tests and application modules and want to distribute them along with your application:: @@ -189,7 +187,7 @@ You can then install your package in "editable" mode:: pip install -e . which lets you change your source code (both tests and application) and rerun tests at will. -This is similar to running `python setup.py develop` or `conda develop` in that it installs +This is similar to running `python setup.py develop` or `conda develop` in that it installs your package using a symlink to your development code. Once you are done with your work and want to make sure that your actual diff --git a/doc/en/nose.rst b/doc/en/nose.rst index a785ecfaa..dcceff9b6 100644 --- a/doc/en/nose.rst +++ b/doc/en/nose.rst @@ -50,6 +50,16 @@ Unsupported idioms / known issues but there is discussion in `issue268 `_ for adding some support. Note that `nose2 choose to avoid this sys.path/import hackery `_. + If you place a conftest.py file in the root directory of your project + (as determined by pytest) pytest will run tests "nose style" against + the code below that directory by adding it to your sys.path instead of + running against your installed code. + + You may find yourself wanting to do this if you ran `python setup.py install` + to set up your project, as opposed to `python setup.py develop` or any of + the package manager equivalents. Installing with develop in a + virtual environment like Tox is recommended over this pattern. + - nose-style doctests are not collected and executed correctly, also doctest fixtures don't work. @@ -62,3 +72,4 @@ Unsupported idioms / known issues being the recommended alternative. + From 639c592f319c788ca0cf909a0ecef6fa23d47393 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Thu, 6 Apr 2017 22:59:24 -0300 Subject: [PATCH 29/42] Add missing link in CHANGELOG --- CHANGELOG.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index decea4b25..fbf43bd09 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -25,6 +25,7 @@ .. _@metasyn: https://github.com/metasyn +.. _#1937: https://github.com/pytest-dev/pytest/issues/1937 .. _#2276: https://github.com/pytest-dev/pytest/issues/2276 .. _#2336: https://github.com/pytest-dev/pytest/issues/2336 From 546269792483e7a6f6e0213bd5ef3dbb29b7373b Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Thu, 6 Apr 2017 23:01:26 -0300 Subject: [PATCH 30/42] Small formatting fixes to nose.rst --- doc/en/nose.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/en/nose.rst b/doc/en/nose.rst index dcceff9b6..5effd0d7b 100644 --- a/doc/en/nose.rst +++ b/doc/en/nose.rst @@ -47,16 +47,16 @@ Unsupported idioms / known issues ``tests.test_mod``) but different file system paths (e.g. ``tests/test_mode.py`` and ``other/tests/test_mode.py``) by extending sys.path/import semantics. pytest does not do that - but there is discussion in `issue268 `_ for adding some support. Note that + but there is discussion in `#268 `_ for adding some support. Note that `nose2 choose to avoid this sys.path/import hackery `_. If you place a conftest.py file in the root directory of your project (as determined by pytest) pytest will run tests "nose style" against - the code below that directory by adding it to your sys.path instead of + the code below that directory by adding it to your ``sys.path`` instead of running against your installed code. - You may find yourself wanting to do this if you ran `python setup.py install` - to set up your project, as opposed to `python setup.py develop` or any of + You may find yourself wanting to do this if you ran ``python setup.py install`` + to set up your project, as opposed to ``python setup.py develop`` or any of the package manager equivalents. Installing with develop in a virtual environment like Tox is recommended over this pattern. From 45852386e58e250951bbf06eb30a87e2daa5c107 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Thu, 6 Apr 2017 23:02:47 -0300 Subject: [PATCH 31/42] Fix small typo in docs --- doc/en/existingtestsuite.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/en/existingtestsuite.rst b/doc/en/existingtestsuite.rst index 96ce6339c..a85aaaeb5 100644 --- a/doc/en/existingtestsuite.rst +++ b/doc/en/existingtestsuite.rst @@ -1,7 +1,7 @@ Using pytest with an existing test suite =========================================== -Pytest can be used with most existing test suites, but it's +Pytest can be used with most existing test suites, but its behavior differs from other test runners such as :ref:`nose` or Python's default unittest framework. @@ -27,6 +27,6 @@ Setting up your project in development mode lets you avoid having to reinstall every time you want to run your tests, and is less brittle than mucking about with sys.path to point your tests at local code. -Also consider using Tox - https://tox.readthedocs.io/en/latest/ +Also consider using `Tox `_. .. include:: links.inc From f2300fbab2525d3d95f125e14c0bbd9d08c58d77 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Thu, 6 Apr 2017 23:29:41 -0300 Subject: [PATCH 32/42] Fix links in docs --- doc/en/existingtestsuite.rst | 26 ++++++++++++++------------ doc/en/getting-started.rst | 22 +++++++++++----------- 2 files changed, 25 insertions(+), 23 deletions(-) diff --git a/doc/en/existingtestsuite.rst b/doc/en/existingtestsuite.rst index a85aaaeb5..d304b30c9 100644 --- a/doc/en/existingtestsuite.rst +++ b/doc/en/existingtestsuite.rst @@ -1,32 +1,34 @@ +.. _existingtestsuite: + Using pytest with an existing test suite =========================================== -Pytest can be used with most existing test suites, but its -behavior differs from other test runners such as :ref:`nose` or -Python's default unittest framework. +Pytest can be used with most existing test suites, but its +behavior differs from other test runners such as :ref:`nose ` or +Python's default unittest framework. -Before using this section you will want to :ref:`getting-started `. +Before using this section you will want to :ref:`install pytest `. Running an existing test suite with pytest --------------------------------------------- -Say you want to contribute to an existing repository somewhere. -After pulling the code into your development space using some +Say you want to contribute to an existing repository somewhere. +After pulling the code into your development space using some flavor of version control and (optionally) setting up a virtualenv you will want to run:: - + cd - pip install -e . # Environment dependent alternatives include - # 'python setup.py develop' and 'conda develop' + pip install -e . # Environment dependent alternatives include + # 'python setup.py develop' and 'conda develop' in your project root. This will set up a symlink to your code in site-packages, allowing you to edit your code while your tests run against it as if it were installed. -Setting up your project in development mode lets you avoid having to -reinstall every time you want to run your tests, and is less brittle than +Setting up your project in development mode lets you avoid having to +reinstall every time you want to run your tests, and is less brittle than mucking about with sys.path to point your tests at local code. -Also consider using `Tox `_. +Also consider using :ref:`tox `. .. include:: links.inc diff --git a/doc/en/getting-started.rst b/doc/en/getting-started.rst index 071b296db..9f2aa2cda 100644 --- a/doc/en/getting-started.rst +++ b/doc/en/getting-started.rst @@ -49,17 +49,17 @@ That's it. You can execute the test function now:: platform linux -- Python 3.5.2, pytest-3.0.7, py-1.4.32, pluggy-0.4.0 rootdir: $REGENDOC_TMPDIR, inifile: collected 1 items - + test_sample.py F - + ======= FAILURES ======== _______ test_answer ________ - + def test_answer(): > assert func(3) == 5 E assert 4 == 5 E + where 4 = func(3) - + test_sample.py:5: AssertionError ======= 1 failed in 0.12 seconds ======== @@ -128,15 +128,15 @@ run the module by passing its filename:: .F ======= FAILURES ======== _______ TestClass.test_two ________ - + self = - + def test_two(self): x = "hello" > assert hasattr(x, 'check') E AssertionError: assert False E + where False = hasattr('hello', 'check') - + test_class.py:8: AssertionError 1 failed, 1 passed in 0.12 seconds @@ -165,14 +165,14 @@ before performing the test function call. Let's just run it:: F ======= FAILURES ======== _______ test_needsfiles ________ - + tmpdir = local('PYTEST_TMPDIR/test_needsfiles0') - + def test_needsfiles(tmpdir): print (tmpdir) > assert 0 E assert 0 - + test_tmpdir.py:3: AssertionError --------------------------- Captured stdout call --------------------------- PYTEST_TMPDIR/test_needsfiles0 @@ -191,8 +191,8 @@ Where to go next Here are a few suggestions where to go next: * :ref:`cmdline` for command line invocation examples -* :ref:`existingtestsuite` for working with pre-existing tests * :ref:`good practices ` for virtualenv, test layout +* :ref:`existingtestsuite` for working with pre-existing tests * :ref:`fixtures` for providing a functional baseline to your tests * :ref:`plugins` managing and writing plugins From 21f1c2b03f21db8aa54dea61d7f96d1c0573af79 Mon Sep 17 00:00:00 2001 From: Ben Lloyd Date: Fri, 7 Apr 2017 16:48:38 +0100 Subject: [PATCH 33/42] Update fixtures.py Corrected "or or" typo in docstring (and made indentation consistent). --- _pytest/fixtures.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/_pytest/fixtures.py b/_pytest/fixtures.py index 248708f6e..59315751d 100644 --- a/_pytest/fixtures.py +++ b/_pytest/fixtures.py @@ -841,8 +841,8 @@ class FixtureFunctionMarker: def fixture(scope="function", params=None, autouse=False, ids=None, name=None): """ (return a) decorator to mark a fixture factory function. - This decorator can be used (with or or without parameters) to define - a fixture function. The name of the fixture function can later be + This decorator can be used (with or without parameters) to define a + fixture function. The name of the fixture function can later be referenced to cause its invocation ahead of running tests: test modules or classes can use the pytest.mark.usefixtures(fixturename) marker. Test functions can directly use fixture names as input @@ -861,16 +861,16 @@ def fixture(scope="function", params=None, autouse=False, ids=None, name=None): reference is needed to activate the fixture. :arg ids: list of string ids each corresponding to the params - so that they are part of the test id. If no ids are provided - they will be generated automatically from the params. + so that they are part of the test id. If no ids are provided + they will be generated automatically from the params. :arg name: the name of the fixture. This defaults to the name of the - decorated function. If a fixture is used in the same module in - which it is defined, the function name of the fixture will be - shadowed by the function arg that requests the fixture; one way - to resolve this is to name the decorated function - ``fixture_`` and then use - ``@pytest.fixture(name='')``. + decorated function. If a fixture is used in the same module in + which it is defined, the function name of the fixture will be + shadowed by the function arg that requests the fixture; one way + to resolve this is to name the decorated function + ``fixture_`` and then use + ``@pytest.fixture(name='')``. Fixtures can optionally provide their values to test functions using a ``yield`` statement, instead of ``return``. In this case, the code block after the ``yield`` statement is executed From 7d4ac14a3170a0c0d1e9a8800e71393f5f9429fe Mon Sep 17 00:00:00 2001 From: Michael Howitz Date: Wed, 12 Apr 2017 08:18:09 +0200 Subject: [PATCH 34/42] Fix #2343: Replace version checks by constants. This way they do not have to be recomputed at runtime. --- _pytest/_code/code.py | 11 ++++++----- _pytest/compat.py | 1 + 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/_pytest/_code/code.py b/_pytest/_code/code.py index 6eceb0c7f..2b26e4a24 100644 --- a/_pytest/_code/code.py +++ b/_pytest/_code/code.py @@ -2,13 +2,14 @@ import sys from inspect import CO_VARARGS, CO_VARKEYWORDS import re from weakref import ref +from _pytest.compat import _PY2, _PY3, PY35 import py builtin_repr = repr reprlib = py.builtin._tryimport('repr', 'reprlib') -if sys.version_info[0] >= 3: +if _PY3: from traceback import format_exception_only else: from ._py2traceback import format_exception_only @@ -352,7 +353,7 @@ class ExceptionInfo(object): help for navigating the traceback. """ _striptext = '' - _assert_start_repr = "AssertionError(u\'assert " if sys.version_info[0] < 3 else "AssertionError(\'assert " + _assert_start_repr = "AssertionError(u\'assert " if _PY2 else "AssertionError(\'assert " def __init__(self, tup=None, exprinfo=None): import _pytest._code @@ -617,7 +618,7 @@ class FormattedExcinfo(object): def repr_excinfo(self, excinfo): - if sys.version_info[0] < 3: + if _PY2: reprtraceback = self.repr_traceback(excinfo) reprcrash = excinfo._getreprcrash() @@ -654,7 +655,7 @@ class FormattedExcinfo(object): class TerminalRepr(object): def __str__(self): s = self.__unicode__() - if sys.version_info[0] < 3: + if _PY2: s = s.encode('utf-8') return s @@ -850,7 +851,7 @@ def getrawcode(obj, trycall=True): return obj -if sys.version_info[:2] >= (3, 5): # RecursionError introduced in 3.5 +if PY35: # RecursionError introduced in 3.5 def is_recursion_error(excinfo): return excinfo.errisinstance(RecursionError) # noqa else: diff --git a/_pytest/compat.py b/_pytest/compat.py index 4f2013dac..d37fe1a48 100644 --- a/_pytest/compat.py +++ b/_pytest/compat.py @@ -27,6 +27,7 @@ _PY2 = not _PY3 NoneType = type(None) NOTSET = object() +PY35 = sys.version_info[:2] >= (3, 5) PY36 = sys.version_info[:2] >= (3, 6) MODULE_NOT_FOUND_ERROR = 'ModuleNotFoundError' if PY36 else 'ImportError' From 6e2bbe88b1050b07f4f91040a7ed1c1a4dc986fd Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Thu, 13 Apr 2017 17:54:56 -0300 Subject: [PATCH 35/42] Test against py36 official release for consistency with other python versions --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 41537a466..0a71e7dc1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -31,7 +31,7 @@ env: matrix: include: - env: TOXENV=py36 - python: '3.6-dev' + python: '3.6' - env: TOXENV=py37 python: 'nightly' allow_failures: From 90be44c8128a5a293f3045eea6da27643809081a Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Wed, 19 Apr 2017 08:19:19 -0300 Subject: [PATCH 36/42] Document PYTEST_DONT_REWRITE Fixes #2203 --- doc/en/assert.rst | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/doc/en/assert.rst b/doc/en/assert.rst index b674f90b0..1d5def87b 100644 --- a/doc/en/assert.rst +++ b/doc/en/assert.rst @@ -270,12 +270,21 @@ supporting modules which are not themselves test modules will not be rewritten. .. note:: - ``pytest`` rewrites test modules on import. It does this by using an import - hook to write new pyc files. Most of the time this works transparently. + ``pytest`` rewrites test modules on import by using an import + hook to write new ``pyc`` files. Most of the time this works transparently. However, if you are messing with import yourself, the import hook may - interfere. If this is the case, use ``--assert=plain``. Additionally, - rewriting will fail silently if it cannot write new pycs, i.e. in a read-only - filesystem or a zipfile. + interfere. + + If this is the case you have two options: + + * Disable rewriting for a specific module by adding the string + ``PYTEST_DONT_REWRITE`` to its docstring. + + * Disable rewriting for all modules by using ``--assert=plain``. + + Additionally, rewriting will fail silently if it cannot write new ``.pyc`` files, + i.e. in a read-only filesystem or a zipfile. + For further information, Benjamin Peterson wrote up `Behind the scenes of pytest's new assertion rewriting `_. From dcefb287fc2bd50c22af10f468e7146e7c4d48f5 Mon Sep 17 00:00:00 2001 From: Kodi Arfer Date: Wed, 19 Apr 2017 12:26:56 -0700 Subject: [PATCH 37/42] Try not to assume a module's file extension is .py --- AUTHORS | 1 + CHANGELOG.rst | 5 +++++ _pytest/python.py | 4 ++-- testing/python/collect.py | 28 ++++++++++++++++++++++++++++ 4 files changed, 36 insertions(+), 2 deletions(-) diff --git a/AUTHORS b/AUTHORS index 717595346..ae75eb3b6 100644 --- a/AUTHORS +++ b/AUTHORS @@ -85,6 +85,7 @@ Justyna Janczyszyn Kale Kundert Katarzyna Jachim Kevin Cox +Kodi B. Arfer Lee Kamentsky Lev Maximov Loic Esteve diff --git a/CHANGELOG.rst b/CHANGELOG.rst index fbf43bd09..254f9b79b 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -12,6 +12,9 @@ * Added documentation related to issue (`#1937`_) Thanks `@skylarjhdownes`_ for the PR. +* Allow collecting files with any file extension as Python modules (`#2369`_). + Thanks `@Kodiologist`_ for the PR. + * * @@ -23,11 +26,13 @@ .. _@skylarjhdownes: https://github.com/skylarjhdownes .. _@fabioz: https://github.com/fabioz .. _@metasyn: https://github.com/metasyn +.. _@Kodiologist: https://github.com/Kodiologist .. _#1937: https://github.com/pytest-dev/pytest/issues/1937 .. _#2276: https://github.com/pytest-dev/pytest/issues/2276 .. _#2336: https://github.com/pytest-dev/pytest/issues/2336 +.. _#2369: https://github.com/pytest-dev/pytest/issues/2369 3.0.7 (2017-03-14) diff --git a/_pytest/python.py b/_pytest/python.py index 59492bc41..fddfcc02e 100644 --- a/_pytest/python.py +++ b/_pytest/python.py @@ -3,6 +3,7 @@ import fnmatch import inspect import sys +import os import collections import math from itertools import count @@ -235,8 +236,7 @@ class PyobjMixin(PyobjContext): continue name = node.name if isinstance(node, Module): - assert name.endswith(".py") - name = name[:-3] + name = os.path.splitext(name)[0] if stopatmodule: if includemodule: parts.append(name) diff --git a/testing/python/collect.py b/testing/python/collect.py index d0e490832..ca8eb30a5 100644 --- a/testing/python/collect.py +++ b/testing/python/collect.py @@ -841,6 +841,34 @@ class TestConftestCustomization: l = modcol.collect() assert '_hello' not in l + def test_issue2369_collect_module_fileext(self, testdir): + """Ensure we can collect files with weird file extensions as Python + modules (#2369)""" + # We'll implement a little finder and loader to import files containing + # Python source code whose file extension is ".narf". + testdir.makeconftest(""" + import sys, os, imp + from _pytest.python import Module + + class Loader: + def load_module(self, name): + return imp.load_source(name, name + ".narf") + class Finder: + def find_module(self, name, path=None): + if os.path.exists(name + ".narf"): + return Loader() + sys.meta_path.append(Finder()) + + def pytest_collect_file(path, parent): + if path.ext == ".narf": + return Module(path, parent)""") + testdir.makefile(".narf", """ + def test_something(): + assert 1 + 1 == 2""") + # Use runpytest_subprocess, since we're futzing with sys.meta_path. + result = testdir.runpytest_subprocess() + result.stdout.fnmatch_lines('*1 passed*') + def test_setup_only_available_in_subdir(testdir): sub1 = testdir.mkpydir("sub1") sub2 = testdir.mkpydir("sub2") From a9b44c45298ca3d5560f9c9245914fd601a2fc14 Mon Sep 17 00:00:00 2001 From: Krzysztof Szularz Date: Tue, 25 Apr 2017 16:35:19 +0200 Subject: [PATCH 38/42] Update docs Remove not needed `request` arg in order to simplify the example. --- doc/en/fixture.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/en/fixture.rst b/doc/en/fixture.rst index 01706479d..51c5d6af3 100644 --- a/doc/en/fixture.rst +++ b/doc/en/fixture.rst @@ -287,7 +287,7 @@ Note that we can also seamlessly use the ``yield`` syntax with ``with`` statemen import pytest @pytest.fixture(scope="module") - def smtp(request): + def smtp(): with smtplib.SMTP("smtp.gmail.com") as smtp: yield smtp # provide the fixture value From f0533194ed99648bec45e5ae0120a3f6bf6c2eb1 Mon Sep 17 00:00:00 2001 From: Krzysztof Szularz Date: Wed, 26 Apr 2017 10:31:53 +0200 Subject: [PATCH 39/42] Update fixture.rst Remove yet another not needed `request` argument in fixture definition. --- doc/en/fixture.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/en/fixture.rst b/doc/en/fixture.rst index 51c5d6af3..9641d6aac 100644 --- a/doc/en/fixture.rst +++ b/doc/en/fixture.rst @@ -253,7 +253,7 @@ the code after the *yield* statement serves as the teardown code: import pytest @pytest.fixture(scope="module") - def smtp(request): + def smtp(): smtp = smtplib.SMTP("smtp.gmail.com") yield smtp # provide the fixture value print("teardown smtp") From 34f488757f05984f9a75dce69ef6f55c18b1db51 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Fri, 28 Apr 2017 12:51:40 -0300 Subject: [PATCH 40/42] Add badge for anaconda package version --- README.rst | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/README.rst b/README.rst index d5650af65..3a0abc5c1 100644 --- a/README.rst +++ b/README.rst @@ -6,13 +6,20 @@ ------ .. image:: https://img.shields.io/pypi/v/pytest.svg - :target: https://pypi.python.org/pypi/pytest + :target: https://pypi.python.org/pypi/pytest + +.. image:: https://anaconda.org/conda-forge/pytest/badges/version.svg + :target: https://anaconda.org/conda-forge/pytest + .. image:: https://img.shields.io/pypi/pyversions/pytest.svg - :target: https://pypi.python.org/pypi/pytest + :target: https://pypi.python.org/pypi/pytest + .. image:: https://img.shields.io/coveralls/pytest-dev/pytest/master.svg - :target: https://coveralls.io/r/pytest-dev/pytest + :target: https://coveralls.io/r/pytest-dev/pytest + .. image:: https://travis-ci.org/pytest-dev/pytest.svg?branch=master :target: https://travis-ci.org/pytest-dev/pytest + .. image:: https://ci.appveyor.com/api/projects/status/mrgbjaua7t33pg6b?svg=true :target: https://ci.appveyor.com/project/pytestbot/pytest @@ -34,7 +41,7 @@ An example of a simple test: To execute it:: $ pytest - ============================= test session starts ============================= + ============================= test session starts ============================= collected 1 items test_sample.py F From 60b8339166db2c7b6cc9e313bde46f6314228079 Mon Sep 17 00:00:00 2001 From: Vitaly Lashmanov Date: Sat, 29 Apr 2017 14:32:09 +0300 Subject: [PATCH 41/42] Issue #2383 - Show the correct error message when collect "parametrize" func with wrong args and add test for this case. --- AUTHORS | 1 + CHANGELOG.rst | 5 +++++ _pytest/python.py | 6 +++++- testing/test_mark.py | 17 +++++++++++++++++ 4 files changed, 28 insertions(+), 1 deletion(-) diff --git a/AUTHORS b/AUTHORS index ae75eb3b6..f8214a91e 100644 --- a/AUTHORS +++ b/AUTHORS @@ -151,5 +151,6 @@ Tyler Goodlet Vasily Kuznetsov Victor Uriarte Vidar T. Fauske +Vitaly Lashmanov Wouter van Ackooy Xuecong Liao diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 254f9b79b..fb3f7d2cf 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -15,6 +15,9 @@ * Allow collecting files with any file extension as Python modules (`#2369`_). Thanks `@Kodiologist`_ for the PR. +* Show the correct error message when collect "parametrize" func with wrong args (`#2383`_). + Thanks `@The-Compiler`_ for the report and `@robin0371`_ for the PR. + * * @@ -27,12 +30,14 @@ .. _@fabioz: https://github.com/fabioz .. _@metasyn: https://github.com/metasyn .. _@Kodiologist: https://github.com/Kodiologist +.. _@robin0371: https://github.com/robin0371 .. _#1937: https://github.com/pytest-dev/pytest/issues/1937 .. _#2276: https://github.com/pytest-dev/pytest/issues/2276 .. _#2336: https://github.com/pytest-dev/pytest/issues/2336 .. _#2369: https://github.com/pytest-dev/pytest/issues/2369 +.. _#2383: https://github.com/pytest-dev/pytest/issues/2383 3.0.7 (2017-03-14) diff --git a/_pytest/python.py b/_pytest/python.py index fddfcc02e..5a381fae3 100644 --- a/_pytest/python.py +++ b/_pytest/python.py @@ -853,7 +853,11 @@ class Metafunc(fixtures.FuncargnamesCompatAttr): for callspec in self._calls or [CallSpec2(self)]: elements = zip(ids, argvalues, newkeywords, count()) for a_id, valset, keywords, param_index in elements: - assert len(valset) == len(argnames) + if len(valset) != len(argnames): + raise ValueError( + 'In "parametrize" the number of values ({0}) must be ' + 'equal to the number of names ({1})'.format( + valset, argnames)) newcallspec = callspec.copy(self) newcallspec.setmulti(valtypes, argnames, valset, a_id, keywords, scopenum, param_index) diff --git a/testing/test_mark.py b/testing/test_mark.py index a4430b4c8..8f460586b 100644 --- a/testing/test_mark.py +++ b/testing/test_mark.py @@ -301,6 +301,23 @@ def test_parametrized_collected_from_command_line(testdir): rec.assertoutcome(passed=3) +def test_parametrized_collect_with_wrong_args(testdir): + """Test collect parametrized func with wrong number of args.""" + py_file = testdir.makepyfile(""" + import pytest + + @pytest.mark.parametrize('foo, bar', [(1, 2, 3)]) + def test_func(foo, bar): + pass + """) + + result = testdir.runpytest(py_file) + result.stdout.fnmatch_lines([ + 'E ValueError: In "parametrize" the number of values ((1, 2, 3)) ' + 'must be equal to the number of names ([\'foo\', \'bar\'])' + ]) + + class TestFunctional: def test_mark_per_function(self, testdir): From 630cca2fba4d74dee813708558d7a5fba30e1044 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Tue, 2 May 2017 21:05:42 -0300 Subject: [PATCH 42/42] Fix py35-trial environment After updating to twisted 17.1.0, again the trial tests started to fail; didn't investigate too deep, decided to just no longer delete "zope" modules when cleaning up after pytester because it seems more zope modules keep global state that shouldn't be discarded --- _pytest/pytester.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/_pytest/pytester.py b/_pytest/pytester.py index de24f9044..6ad26c918 100644 --- a/_pytest/pytester.py +++ b/_pytest/pytester.py @@ -447,9 +447,10 @@ class Testdir: the module is re-imported. """ for name in set(sys.modules).difference(self._savemodulekeys): - # zope.interface (used by twisted-related tests) keeps internal - # state and can't be deleted - if not name.startswith("zope.interface"): + # some zope modules used by twisted-related tests keeps internal + # state and can't be deleted; we had some trouble in the past + # with zope.interface for example + if not name.startswith("zope"): del sys.modules[name] def make_hook_recorder(self, pluginmanager):