Merge branch 'master' into merge-master-into-features
This commit is contained in:
		
						commit
						7704f73db9
					
				
							
								
								
									
										2
									
								
								AUTHORS
								
								
								
								
							
							
						
						
									
										2
									
								
								AUTHORS
								
								
								
								
							|  | @ -48,7 +48,6 @@ Eduardo Schettino | |||
| Elizaveta Shashkova | ||||
| Endre Galaczi | ||||
| Eric Hunsberger | ||||
| Eric Hunsberger | ||||
| Eric Siegerman | ||||
| Erik M. Bray | ||||
| Feng Ma | ||||
|  | @ -81,6 +80,7 @@ Lukas Bednar | |||
| Maciek Fijalkowski | ||||
| Maho | ||||
| Marc Schlaich | ||||
| Marcin Bachry | ||||
| Mark Abramowitz | ||||
| Markus Unterwaditzer | ||||
| Martijn Faassen | ||||
|  |  | |||
|  | @ -10,7 +10,7 @@ | |||
| * | ||||
| 
 | ||||
| 
 | ||||
| 3.0.1.dev | ||||
| 3.0.2.dev | ||||
| ========= | ||||
| 
 | ||||
| * | ||||
|  | @ -21,6 +21,33 @@ | |||
| 
 | ||||
| * | ||||
| 
 | ||||
| 3.0.1 | ||||
| ===== | ||||
| 
 | ||||
| * Fix regression when ``importorskip`` is used at module level (`#1822`_). | ||||
|   Thanks `@jaraco`_ and `@The-Compiler`_ for the report and `@nicoddemus`_ for the PR. | ||||
| 
 | ||||
| * Fix parametrization scope when session fixtures are used in conjunction | ||||
|   with normal parameters in the same call (`#1832`_). | ||||
|   Thanks `@The-Compiler`_ for the report, `@Kingdread`_ and `@nicoddemus`_ for the PR. | ||||
| 
 | ||||
| * Fix internal error when parametrizing tests or fixtures using an empty ``ids`` argument (`#1849`_). | ||||
|   Thanks `@OPpuolitaival`_ for the report and `@nicoddemus`_ for the PR. | ||||
| 
 | ||||
| * Fix loader error when running ``pytest`` embedded in a zipfile. | ||||
|   Thanks `@mbachry`_ for the PR. | ||||
| 
 | ||||
| 
 | ||||
| .. _@Kingdread: https://github.com/Kingdread | ||||
| .. _@mbachry: https://github.com/mbachry | ||||
| .. _@OPpuolitaival: https://github.com/OPpuolitaival | ||||
| 
 | ||||
| .. _#1822: https://github.com/pytest-dev/pytest/issues/1822 | ||||
| .. _#1832: https://github.com/pytest-dev/pytest/issues/1832 | ||||
| .. _#1849: https://github.com/pytest-dev/pytest/issues/1849 | ||||
| 
 | ||||
| >>>>>>> master | ||||
| 
 | ||||
| 3.0.0 | ||||
| ===== | ||||
| 
 | ||||
|  | @ -323,10 +350,6 @@ time or change existing behaviors in order to make them less surprising/more use | |||
|   identify bugs in ``conftest.py`` files (`#1516`_). Thanks `@txomon`_ for | ||||
|   the PR. | ||||
| 
 | ||||
| * Add an 'E' to the first line of error messages from FixtureLookupErrorRepr. | ||||
|   Fixes `#717`_. Thanks `@blueyed`_ for reporting, `@eolo999`_ for the PR | ||||
|   and `@tomviner`_ for his guidance during EuroPython2016 sprint. | ||||
| 
 | ||||
| * Text documents without any doctests no longer appear as "skipped". | ||||
|   Thanks `@graingert`_ for reporting and providing a full PR (`#1580`_). | ||||
| 
 | ||||
|  | @ -1225,7 +1248,7 @@ time or change existing behaviors in order to make them less surprising/more use | |||
|   dep).  Thanks Charles Cloud for analysing the issue. | ||||
| 
 | ||||
| - fix conftest related fixture visibility issue: when running with a | ||||
|   CWD outside a test package pytest would get fixture discovery wrong. | ||||
|   CWD outside of a test package pytest would get fixture discovery wrong. | ||||
|   Thanks to Wolfgang Schnerring for figuring out a reproducable example. | ||||
| 
 | ||||
| - Introduce pytest_enter_pdb hook (needed e.g. by pytest_timeout to cancel the | ||||
|  |  | |||
							
								
								
									
										111
									
								
								HOWTORELEASE.rst
								
								
								
								
							
							
						
						
									
										111
									
								
								HOWTORELEASE.rst
								
								
								
								
							|  | @ -3,90 +3,83 @@ How to release pytest | |||
| 
 | ||||
| Note: this assumes you have already registered on pypi. | ||||
| 
 | ||||
| 0. create the branch release-VERSION | ||||
|    use features as base for minor/major releases | ||||
|    and master as base for bugfix releases | ||||
| 1. Bump version numbers in ``_pytest/__init__.py`` (``setup.py`` reads it). | ||||
| 
 | ||||
| 1. Bump version numbers in _pytest/__init__.py (setup.py reads it) | ||||
| 2. Check and finalize ``CHANGELOG.rst``. | ||||
| 
 | ||||
| 2. Check and finalize CHANGELOG | ||||
| 3. Write ``doc/en/announce/release-VERSION.txt`` and include | ||||
|    it in ``doc/en/announce/index.txt``. Run this command to list names of authors involved:: | ||||
| 
 | ||||
| 3. Write doc/en/announce/release-VERSION.txt and include | ||||
|    it in doc/en/announce/index.txt:: | ||||
|         git log $(git describe --abbrev=0 --tags)..HEAD --format='%aN' | sort -u | ||||
| 
 | ||||
|         git log 2.8.2..HEAD --format='%aN' | sort -u # lists the names of authors involved | ||||
| 4. Regenerate the docs examples using tox:: | ||||
| 
 | ||||
| 4. Use devpi for uploading a release tarball to a staging area:: | ||||
|       tox -e regen | ||||
| 
 | ||||
| 5. At this point, open a PR named ``release-X`` so others can help find regressions or provide suggestions. | ||||
| 
 | ||||
| 6. Use devpi for uploading a release tarball to a staging area:: | ||||
| 
 | ||||
|      devpi use https://devpi.net/USER/dev | ||||
|      devpi upload --formats sdist,bdist_wheel | ||||
| 
 | ||||
| 5. Run from multiple machines:: | ||||
| 7. Run from multiple machines:: | ||||
| 
 | ||||
|      devpi use https://devpi.net/USER/dev | ||||
|      devpi test pytest==VERSION | ||||
| 
 | ||||
| 6. Check that tests pass for relevant combinations with:: | ||||
|    Alternatively, you can use `devpi-cloud-tester <https://github.com/nicoddemus/devpi-cloud-tester>`_ to test | ||||
|    the package on AppVeyor and Travis (follow instructions on the ``README``). | ||||
| 
 | ||||
| 8. Check that tests pass for relevant combinations with:: | ||||
| 
 | ||||
|        devpi list pytest | ||||
| 
 | ||||
|    or look at failures with "devpi list -f pytest". | ||||
| 
 | ||||
| 7. Regenerate the docs examples using tox, and check for regressions:: | ||||
| 
 | ||||
|       tox -e regen | ||||
|       git diff | ||||
| 
 | ||||
| 
 | ||||
| 8. Build the docs, you need a virtualenv with py and sphinx | ||||
|    installed:: | ||||
| 
 | ||||
|       cd doc/en | ||||
|       make html | ||||
| 
 | ||||
|    Commit any changes before tagging the release. | ||||
| 
 | ||||
| 9. Tag the release:: | ||||
| 
 | ||||
|       git tag VERSION | ||||
|       git push | ||||
| 
 | ||||
| 10. Upload the docs using doc/en/Makefile:: | ||||
| 
 | ||||
|       cd doc/en | ||||
|       make install  # or "installall" if you have LaTeX installed for PDF | ||||
| 
 | ||||
|     This requires ssh-login permission on pytest.org because it uses | ||||
|     rsync. | ||||
|     Note that the ``install`` target of ``doc/en/Makefile`` defines where the | ||||
|     rsync goes to, typically to the "latest" section of pytest.org. | ||||
| 
 | ||||
|     If you are making a minor release (e.g. 5.4), you also need to manually | ||||
|     create a symlink for "latest":: | ||||
| 
 | ||||
|        ssh pytest-dev@pytest.org | ||||
|        ln -s 5.4 latest | ||||
| 
 | ||||
|     Browse to pytest.org to verify. | ||||
| 
 | ||||
| 11. Publish to pypi:: | ||||
| 9. Feeling confident? Publish to pypi:: | ||||
| 
 | ||||
|       devpi push pytest==VERSION pypi:NAME | ||||
| 
 | ||||
|     where NAME is the name of pypi.python.org as configured in your ``~/.pypirc`` | ||||
|     file `for devpi <http://doc.devpi.net/latest/quickstart-releaseprocess.html?highlight=pypirc#devpi-push-releasing-to-an-external-index>`_. | ||||
|    where NAME is the name of pypi.python.org as configured in your ``~/.pypirc`` | ||||
|    file `for devpi <http://doc.devpi.net/latest/quickstart-releaseprocess.html?highlight=pypirc#devpi-push-releasing-to-an-external-index>`_. | ||||
| 
 | ||||
| 10. Tag the release:: | ||||
| 
 | ||||
| 12. Send release announcement to mailing lists: | ||||
|       git tag VERSION <hash> | ||||
|       git push origin VERSION | ||||
| 
 | ||||
|     - pytest-dev | ||||
|     - testing-in-python | ||||
|     Make sure ``<hash>`` is **exactly** the git hash at the time the package was created. | ||||
| 
 | ||||
| 11. Send release announcement to mailing lists: | ||||
| 
 | ||||
|     - pytest-dev@python.org | ||||
|     - testing-in-python@lists.idyll.org | ||||
|     - python-announce-list@python.org | ||||
| 
 | ||||
|     And announce the release on Twitter, making sure to add the hashtag ``#pytest``. | ||||
| 
 | ||||
| 12. **After the release** | ||||
| 
 | ||||
|   a. **patch release (2.8.3)**: | ||||
| 
 | ||||
|         1. Checkout ``master``. | ||||
|         2. Update version number in ``_pytest/__init__.py`` to ``"2.8.4.dev"``. | ||||
|         3. Create a new section in ``CHANGELOG.rst`` titled ``2.8.4.dev`` and add a few bullet points as placeholders for new entries. | ||||
|         4. Commit and push. | ||||
| 
 | ||||
|   b. **minor release (2.9.0)**: | ||||
| 
 | ||||
|         1. Merge ``features`` into ``master``. | ||||
|         2. Checkout ``master``. | ||||
|         3. Follow the same steps for a **patch release** above, using the next patch release: ``2.9.1.dev``. | ||||
|         4. Commit ``master``. | ||||
|         5. Checkout ``features`` and merge with ``master`` (should be a fast-forward at this point). | ||||
|         6. Update version number in ``_pytest/__init__.py`` to the next minor release: ``"2.10.0.dev"``. | ||||
|         7. Create a new section in ``CHANGELOG.rst`` titled ``2.10.0.dev``, above ``2.9.1.dev``, and add a few bullet points as placeholders for new entries. | ||||
|         8. Commit ``features``. | ||||
|         9. Push ``master`` and ``features``. | ||||
| 
 | ||||
|   c. **major release (3.0.0)**: same steps as that of a **minor release** | ||||
| 
 | ||||
| 13. **after the release** Bump the version number in ``_pytest/__init__.py``, | ||||
|     to the next Minor release version (i.e. if you released ``pytest-2.8.0``, | ||||
|     set it to ``pytest-2.9.0.dev1``). | ||||
| 
 | ||||
| 14. merge the actual release into the master branch and do a pull request against it | ||||
| 15. merge from master to features | ||||
|  |  | |||
							
								
								
									
										365
									
								
								ISSUES.txt
								
								
								
								
							
							
						
						
									
										365
									
								
								ISSUES.txt
								
								
								
								
							|  | @ -1,365 +0,0 @@ | |||
| 
 | ||||
| 
 | ||||
| recorder = monkeypatch.function(".......") | ||||
| ------------------------------------------------------------- | ||||
| tags: nice feature  | ||||
| 
 | ||||
| Like monkeypatch.replace but sets a mock-like call recorder: | ||||
| 
 | ||||
|     recorder = monkeypatch.function("os.path.abspath") | ||||
|     recorder.set_return("/hello") | ||||
|     os.path.abspath("hello") | ||||
|     call, = recorder.calls | ||||
|     assert call.args.path == "hello" | ||||
|     assert call.returned == "/hello" | ||||
|     ... | ||||
| 
 | ||||
| Unlike mock, "args.path" acts on the parsed auto-spec'ed ``os.path.abspath`` | ||||
| so it's independent from if the client side called "os.path.abspath(path=...)" | ||||
| or "os.path.abspath('positional')". | ||||
| 
 | ||||
| 
 | ||||
| refine parametrize API | ||||
| ------------------------------------------------------------- | ||||
| tags: critical feature  | ||||
| 
 | ||||
| extend metafunc.parametrize to directly support indirection, example: | ||||
| 
 | ||||
|     def setupdb(request, config): | ||||
|         # setup "resource" based on test request and the values passed  | ||||
|         # in to parametrize.  setupfunc is called for each such value. | ||||
|         # you may use request.addfinalizer() or request.cached_setup ... | ||||
|         return dynamic_setup_database(val) | ||||
| 
 | ||||
|     @pytest.mark.parametrize("db", ["pg", "mysql"], setupfunc=setupdb) | ||||
|     def test_heavy_functional_test(db): | ||||
|         ... | ||||
| 
 | ||||
| There would be no need to write or explain funcarg factories and | ||||
| their special __ syntax. | ||||
| 
 | ||||
| The examples and improvements should also show how to put the parametrize | ||||
| decorator to a class, to a module or even to a directory.  For the directory | ||||
| part a conftest.py content like this:: | ||||
| 
 | ||||
|     pytestmark = [ | ||||
|         @pytest.mark.parametrize_setup("db", ...), | ||||
|     ] | ||||
| 
 | ||||
| probably makes sense in order to keep the declarative nature.   This mirrors | ||||
| the marker-mechanism with respect to a test module but puts it to a directory | ||||
| scale. | ||||
| 
 | ||||
| When doing larger scoped parametrization it probably becomes necessary | ||||
| to allow parametrization to be ignored if the according parameter is not | ||||
| used (currently any parametrized argument that is not present in a function will cause a ValueError). Example: | ||||
| 
 | ||||
|         @pytest.mark.parametrize("db", ..., mustmatch=False) | ||||
| 
 | ||||
| means to not raise an error but simply ignore the parametrization | ||||
| if the signature of a decorated function does not match. XXX is it | ||||
| not sufficient to always allow non-matches? | ||||
| 
 | ||||
| 
 | ||||
| allow parametrized attributes on classes | ||||
| --------------------------------------------------  | ||||
| 
 | ||||
| tags: wish 2.4 | ||||
| 
 | ||||
| example: | ||||
| 
 | ||||
|     @pytest.mark.parametrize_attr("db", setupfunc, [1,2,3], scope="class") | ||||
|     @pytest.mark.parametrize_attr("tmp", setupfunc, scope="...") | ||||
|     class TestMe: | ||||
|         def test_hello(self): | ||||
|             access self.db ... | ||||
| 
 | ||||
| this would run the test_hello() function three times with three | ||||
| different values for self.db. This could also work with unittest/nose | ||||
| style tests, i.e. it leverages existing test suites without needing | ||||
| to rewrite them. Together with the previously mentioned setup_test() | ||||
| maybe the setupfunc could be omitted? | ||||
| 
 | ||||
| optimizations  | ||||
| --------------------------------------------------------------- | ||||
| tags: 2.4 core | ||||
| 
 | ||||
| - look at ihook optimization such that all lookups for | ||||
|   hooks relating to the same fspath are cached. | ||||
| 
 | ||||
| fix start/finish partial finailization problem | ||||
| --------------------------------------------------------------- | ||||
| tags: bug core | ||||
| 
 | ||||
| if a configure/runtest_setup/sessionstart/... hook invocation partially | ||||
| fails the sessionfinishes is not called.  Each hook implementation | ||||
| should better be repsonsible for registering a cleanup/finalizer | ||||
| appropriately to avoid this issue.  Moreover/Alternatively, we could  | ||||
| record which implementations of a hook succeeded and only call their | ||||
| teardown. | ||||
| 
 | ||||
| 
 | ||||
| relax requirement to have tests/testing contain an __init__ | ||||
| ---------------------------------------------------------------- | ||||
| tags: feature  | ||||
| bb: http://bitbucket.org/hpk42/py-trunk/issue/64 | ||||
| 
 | ||||
| A local test run of a "tests" directory may work | ||||
| but a remote one fail because the tests directory | ||||
| does not contain an "__init__.py". Either give | ||||
| an error or make it work without the __init__.py | ||||
| i.e. port the nose-logic of unloading a test module. | ||||
| 
 | ||||
| customize test function collection | ||||
| ------------------------------------------------------- | ||||
| tags: feature  | ||||
| 
 | ||||
| - introduce pytest.mark.nocollect for not considering a function for | ||||
|   test collection at all.  maybe also introduce a pytest.mark.test to | ||||
|   explicitly mark a function to become a tested one.  Lookup JUnit ways | ||||
|   of tagging tests. | ||||
| 
 | ||||
| introduce pytest.mark.importorskip | ||||
| ------------------------------------------------------- | ||||
| tags: feature  | ||||
| 
 | ||||
| in addition to the imperative pytest.importorskip also introduce | ||||
| a pytest.mark.importorskip so that the test count is more correct. | ||||
| 
 | ||||
| 
 | ||||
| introduce pytest.mark.platform | ||||
| ------------------------------------------------------- | ||||
| tags: feature  | ||||
| 
 | ||||
| Introduce nice-to-spell platform-skipping, examples: | ||||
| 
 | ||||
|     @pytest.mark.platform("python3") | ||||
|     @pytest.mark.platform("not python3") | ||||
|     @pytest.mark.platform("win32 and not python3") | ||||
|     @pytest.mark.platform("darwin") | ||||
|     @pytest.mark.platform("not (jython and win32)") | ||||
|     @pytest.mark.platform("not (jython and win32)", xfail=True) | ||||
| 
 | ||||
| etc. Idea is to allow Python expressions which can operate | ||||
| on common spellings for operating systems and python | ||||
| interpreter versions. | ||||
| 
 | ||||
| pytest.mark.xfail signature change | ||||
| ------------------------------------------------------- | ||||
| tags: feature  | ||||
| 
 | ||||
| change to pytest.mark.xfail(reason, (optional)condition) | ||||
| to better implement the word meaning.  It also signals | ||||
| better that we always have some kind of an implementation | ||||
| reason that can be formualated. | ||||
| Compatibility? how to introduce a new name/keep compat? | ||||
| 
 | ||||
| allow to non-intrusively apply skipfs/xfail/marks | ||||
| --------------------------------------------------- | ||||
| tags: feature  | ||||
| 
 | ||||
| use case: mark a module or directory structures | ||||
| to be skipped on certain platforms (i.e. no import | ||||
| attempt will be made). | ||||
| 
 | ||||
| consider introducing a hook/mechanism that allows to apply marks | ||||
| from conftests or plugins. (See extended parametrization) | ||||
| 
 | ||||
| 
 | ||||
| explicit referencing of conftest.py files | ||||
| ----------------------------------------- | ||||
| tags: feature  | ||||
| 
 | ||||
| allow to name conftest.py files (in sub directories) that should | ||||
| be imported early, as to include command line options. | ||||
| 
 | ||||
| improve central pytest ini file | ||||
| ------------------------------- | ||||
| tags: feature  | ||||
| 
 | ||||
| introduce more declarative configuration options: | ||||
| - (to-be-collected test directories) | ||||
| - required plugins | ||||
| - test func/class/file matching patterns | ||||
| - skip/xfail (non-intrusive) | ||||
| - pytest.ini and tox.ini and setup.cfg configuration in the same file | ||||
| 
 | ||||
| new documentation | ||||
| ---------------------------------- | ||||
| tags: feature  | ||||
| 
 | ||||
| - logo pytest | ||||
| - examples for unittest or functional testing | ||||
| - resource management for functional testing | ||||
| - patterns: page object | ||||
| 
 | ||||
| have imported module mismatch honour relative paths | ||||
| -------------------------------------------------------- | ||||
| tags: bug  | ||||
| 
 | ||||
| With 1.1.1 pytest fails at least on windows if an import | ||||
| is relative and compared against an absolute conftest.py | ||||
| path. Normalize. | ||||
| 
 | ||||
| consider globals: pytest.ensuretemp and config | ||||
| -------------------------------------------------------------- | ||||
| tags: experimental-wish  | ||||
| 
 | ||||
| consider deprecating pytest.ensuretemp and pytest.config | ||||
| to further reduce pytest globality.  Also consider | ||||
| having pytest.config and ensuretemp coming from | ||||
| a plugin rather than being there from the start. | ||||
| 
 | ||||
| 
 | ||||
| consider pytest_addsyspath hook | ||||
| ----------------------------------------- | ||||
| tags: wish | ||||
| 
 | ||||
| pytest could call a new pytest_addsyspath() in order to systematically | ||||
| allow manipulation of sys.path and to inhibit it via --no-addsyspath | ||||
| in order to more easily run against installed packages. | ||||
| 
 | ||||
| Alternatively it could also be done via the config object | ||||
| and pytest_configure. | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| deprecate global pytest.config usage | ||||
| ---------------------------------------------------------------- | ||||
| tags: feature  | ||||
| 
 | ||||
| pytest.ensuretemp and pytest.config are probably the last | ||||
| objects containing global state.  Often using them is not | ||||
| necessary.  This is about trying to get rid of them, i.e. | ||||
| deprecating them and checking with PyPy's usages as well | ||||
| as others. | ||||
| 
 | ||||
| remove deprecated bits in collect.py | ||||
| ------------------------------------------------------------------- | ||||
| tags: feature  | ||||
| 
 | ||||
| In an effort to further simplify code, review and remove deprecated bits | ||||
| in collect.py.  Probably good: | ||||
| - inline consider_file/dir methods, no need to have them | ||||
|   subclass-overridable because of hooks | ||||
| 
 | ||||
| implement fslayout decorator | ||||
| --------------------------------- | ||||
| tags: feature  | ||||
| 
 | ||||
| Improve the way how tests can work with pre-made examples, | ||||
| keeping the layout close to the test function: | ||||
| 
 | ||||
| @pytest.mark.fslayout(""" | ||||
|     conftest.py: | ||||
|         #  empty | ||||
|     tests/ | ||||
|         test_%(NAME)s:  # becomes test_run1.py | ||||
|             def test_function(self): | ||||
|                 pass | ||||
| """) | ||||
| def test_run(pytester, fslayout): | ||||
|     p = fslayout.findone("test_*.py") | ||||
|     result = pytester.runpytest(p) | ||||
|     assert result.ret == 0 | ||||
|     assert result.passed == 1 | ||||
| 
 | ||||
| Another idea is to allow to define a full scenario including the run | ||||
| in one content string:: | ||||
| 
 | ||||
|     runscenario(""" | ||||
|         test_{TESTNAME}.py: | ||||
|             import pytest | ||||
|             @pytest.mark.xfail | ||||
|             def test_that_fails(): | ||||
|                 assert 0 | ||||
| 
 | ||||
|             @pytest.mark.skipif("True") | ||||
|             def test_hello(): | ||||
|                 pass | ||||
| 
 | ||||
|         conftest.py: | ||||
|             import pytest | ||||
|             def pytest_runsetup_setup(item): | ||||
|                 pytest.skip("abc") | ||||
| 
 | ||||
|         runpytest -rsxX | ||||
|         *SKIP*{TESTNAME}* | ||||
|         *1 skipped*  | ||||
|     """) | ||||
| 
 | ||||
| This could be run with at least three different ways to invoke pytest: | ||||
| through the shell, through "python -m pytest" and inlined. As inlined | ||||
| would be the fastest it could be run first (or "--fast" mode). | ||||
| 
 | ||||
| 
 | ||||
| Create isolate plugin | ||||
| --------------------- | ||||
| tags: feature | ||||
| 
 | ||||
| The idea is that you can e.g. import modules in a test and afterwards | ||||
| sys.modules, sys.meta_path etc would be reverted.  It can go further | ||||
| then just importing however, e.g. current working directory, file | ||||
| descriptors, ... | ||||
| 
 | ||||
| This would probably be done by marking:: | ||||
| 
 | ||||
|     @pytest.mark.isolate(importing=True, cwd=True, fds=False) | ||||
|     def test_foo(): | ||||
|         ... | ||||
| 
 | ||||
| With the possibility of doing this globally in an ini-file. | ||||
| 
 | ||||
| 
 | ||||
| fnmatch for test names | ||||
| ---------------------- | ||||
| tags: feature-wish | ||||
| 
 | ||||
| various testsuites use suffixes instead of prefixes for test classes | ||||
| also it lends itself to bdd style test names:: | ||||
| 
 | ||||
|     class UserBehaviour: | ||||
|         def anonymous_should_not_have_inbox(user): | ||||
|             ... | ||||
|         def registred_should_have_inbox(user): | ||||
|             .. | ||||
| 
 | ||||
| using the following in pytest.ini:: | ||||
| 
 | ||||
|     [pytest] | ||||
|     python_classes = Test *Behaviour *Test | ||||
|     python_functions = test *_should_* | ||||
| 
 | ||||
| 
 | ||||
| mechanism for running named parts of tests with different reporting behaviour | ||||
| ------------------------------------------------------------------------------ | ||||
| tags: feature-wish-incomplete | ||||
| 
 | ||||
| a few use-cases come to mind: | ||||
| 
 | ||||
| * fail assertions and record that without stopping a complete test | ||||
| 
 | ||||
|   * this is in particular hepfull if a small bit of a test is known to fail/xfail:: | ||||
| 
 | ||||
|     def test_fun(): | ||||
|         with pytest.section('fdcheck, marks=pytest.mark.xfail_if(...)): | ||||
|             breaks_on_windows() | ||||
| 
 | ||||
| * divide functional/acceptance tests into sections | ||||
| * provide a different mechanism for generators, maybe something like:: | ||||
| 
 | ||||
|     def pytest_runtest_call(item) | ||||
|         if not generator: | ||||
|             ... | ||||
|         prepare_check = GeneratorCheckprepare() | ||||
| 
 | ||||
|         gen = item.obj(**fixtures) | ||||
|         for check in gen | ||||
|             id, call = prepare_check(check) | ||||
|             # bubble should only prevent exception propagation after a failure | ||||
|             # the whole test should still fail | ||||
|             # there might be need for a lower level api and taking custom markers into account | ||||
|             with pytest.section(id, bubble=False): | ||||
|                 call() | ||||
| 
 | ||||
| 
 | ||||
|  | @ -4,6 +4,7 @@ include AUTHORS | |||
| 
 | ||||
| include README.rst | ||||
| include CONTRIBUTING.rst | ||||
| include HOWTORELEASE.rst | ||||
| 
 | ||||
| include tox.ini | ||||
| include setup.py | ||||
|  | @ -29,6 +30,3 @@ recursive-exclude * *.pyc *.pyo | |||
| exclude appveyor/install.ps1 | ||||
| exclude appveyor.yml | ||||
| exclude appveyor | ||||
| 
 | ||||
| exclude ISSUES.txt | ||||
| exclude HOWTORELEASE.rst | ||||
|  |  | |||
|  | @ -687,7 +687,7 @@ class Session(FSCollector): | |||
|         # This method is sometimes invoked when AssertionRewritingHook, which | ||||
|         # does not define a get_filename method, is already in place: | ||||
|         try: | ||||
|             path = loader.get_filename() | ||||
|             path = loader.get_filename(x) | ||||
|         except AttributeError: | ||||
|             # Retrieve path from AssertionRewritingHook: | ||||
|             path = loader.modules[x][0].co_filename | ||||
|  |  | |||
|  | @ -283,6 +283,21 @@ class MarkDecorator: | |||
|         return self.__class__(self.name, args=args, kwargs=kw) | ||||
| 
 | ||||
| 
 | ||||
| def extract_argvalue(maybe_marked_args): | ||||
|     # TODO: incorrect mark data, the old code wanst able to collect lists | ||||
|     # individual parametrized argument sets can be wrapped in a series | ||||
|     # of markers in which case we unwrap the values and apply the mark | ||||
|     # at Function init | ||||
|     newmarks = {} | ||||
|     argval = maybe_marked_args | ||||
|     while isinstance(argval, MarkDecorator): | ||||
|         newmark = MarkDecorator(argval.markname, | ||||
|                                 argval.args[:-1], argval.kwargs) | ||||
|         newmarks[newmark.markname] = newmark | ||||
|         argval = argval.args[-1] | ||||
|     return argval, newmarks | ||||
| 
 | ||||
| 
 | ||||
| class MarkInfo: | ||||
|     """ Marking object created by :class:`MarkDecorator` instances. """ | ||||
|     def __init__(self, name, args, kwargs): | ||||
|  |  | |||
|  | @ -5,10 +5,11 @@ import inspect | |||
| import sys | ||||
| import collections | ||||
| import math | ||||
| from itertools import count | ||||
| 
 | ||||
| import py | ||||
| import pytest | ||||
| from _pytest.mark import MarkDecorator, MarkerError | ||||
| from _pytest.mark import MarkerError | ||||
| 
 | ||||
| 
 | ||||
| import _pytest | ||||
|  | @ -431,10 +432,12 @@ class Module(pytest.File, PyCollector): | |||
|                 "Make sure your test modules/packages have valid Python names." | ||||
|                 % (self.fspath, exc or exc_class) | ||||
|             ) | ||||
|         except _pytest.runner.Skipped: | ||||
|         except _pytest.runner.Skipped as e: | ||||
|             if e.allow_module_level: | ||||
|                 raise | ||||
|             raise self.CollectError( | ||||
|                 "Using @pytest.skip outside a test (e.g. as a test function " | ||||
|                 "decorator) is not allowed. Use @pytest.mark.skip or " | ||||
|                 "Using @pytest.skip outside of a test (e.g. as a test " | ||||
|                 "function decorator) is not allowed. Use @pytest.mark.skip or " | ||||
|                 "@pytest.mark.skipif instead." | ||||
|             ) | ||||
|         self.config.pluginmanager.consider_module(mod) | ||||
|  | @ -774,19 +777,14 @@ class Metafunc(fixtures.FuncargnamesCompatAttr): | |||
|             to set a dynamic scope using test context or configuration. | ||||
|         """ | ||||
|         from _pytest.fixtures import scopes | ||||
|         # individual parametrized argument sets can be wrapped in a series | ||||
|         # of markers in which case we unwrap the values and apply the mark | ||||
|         # at Function init | ||||
|         newkeywords = {} | ||||
|         from _pytest.mark import extract_argvalue | ||||
| 
 | ||||
|         unwrapped_argvalues = [] | ||||
|         for i, argval in enumerate(argvalues): | ||||
|             while isinstance(argval, MarkDecorator): | ||||
|                 newmark = MarkDecorator(argval.markname, | ||||
|                                         argval.args[:-1], argval.kwargs) | ||||
|                 newmarks = newkeywords.setdefault(i, {}) | ||||
|                 newmarks[newmark.markname] = newmark | ||||
|                 argval = argval.args[-1] | ||||
|         newkeywords = [] | ||||
|         for maybe_marked_args in argvalues: | ||||
|             argval, newmarks = extract_argvalue(maybe_marked_args) | ||||
|             unwrapped_argvalues.append(argval) | ||||
|             newkeywords.append(newmarks) | ||||
|         argvalues = unwrapped_argvalues | ||||
| 
 | ||||
|         if not isinstance(argnames, (tuple, list)): | ||||
|  | @ -801,18 +799,11 @@ class Metafunc(fixtures.FuncargnamesCompatAttr): | |||
|             newmark = pytest.mark.skip( | ||||
|                 reason="got empty parameter set %r, function %s at %s:%d" % ( | ||||
|                     argnames, self.function.__name__, fs, lineno)) | ||||
|             newmarks = newkeywords.setdefault(0, {}) | ||||
|             newmarks[newmark.markname] = newmark | ||||
|             newkeywords = [{newmark.markname: newmark}] | ||||
| 
 | ||||
|         if scope is None: | ||||
|             if self._arg2fixturedefs: | ||||
|                 # Takes the most narrow scope from used fixtures | ||||
|                 fixtures_scopes = [fixturedef[0].scope for fixturedef in self._arg2fixturedefs.values()] | ||||
|                 for scope in reversed(scopes): | ||||
|                     if scope in fixtures_scopes: | ||||
|                         break | ||||
|             else: | ||||
|                 scope = 'function' | ||||
|             scope = _find_parametrized_scope(argnames, self._arg2fixturedefs, indirect) | ||||
| 
 | ||||
|         scopenum = scopes.index(scope) | ||||
|         valtypes = {} | ||||
|         for arg in argnames: | ||||
|  | @ -846,12 +837,12 @@ class Metafunc(fixtures.FuncargnamesCompatAttr): | |||
|         ids = idmaker(argnames, argvalues, idfn, ids, self.config) | ||||
|         newcalls = [] | ||||
|         for callspec in self._calls or [CallSpec2(self)]: | ||||
|             for param_index, valset in enumerate(argvalues): | ||||
|             elements = zip(ids, argvalues, newkeywords, count()) | ||||
|             for a_id, valset, keywords, param_index in elements: | ||||
|                 assert len(valset) == len(argnames) | ||||
|                 newcallspec = callspec.copy(self) | ||||
|                 newcallspec.setmulti(valtypes, argnames, valset, ids[param_index], | ||||
|                                      newkeywords.get(param_index, {}), scopenum, | ||||
|                                      param_index) | ||||
|                 newcallspec.setmulti(valtypes, argnames, valset, a_id, | ||||
|                                      keywords, scopenum, param_index) | ||||
|                 newcalls.append(newcallspec) | ||||
|         self._calls = newcalls | ||||
| 
 | ||||
|  | @ -892,6 +883,30 @@ class Metafunc(fixtures.FuncargnamesCompatAttr): | |||
|         self._calls.append(cs) | ||||
| 
 | ||||
| 
 | ||||
| def _find_parametrized_scope(argnames, arg2fixturedefs, indirect): | ||||
|     """Find the most appropriate scope for a parametrized call based on its arguments. | ||||
| 
 | ||||
|     When there's at least one direct argument, always use "function" scope. | ||||
| 
 | ||||
|     When a test function is parametrized and all its arguments are indirect | ||||
|     (e.g. fixtures), return the most narrow scope based on the fixtures used. | ||||
| 
 | ||||
|     Related to issue #1832, based on code posted by @Kingdread. | ||||
|     """ | ||||
|     from _pytest.fixtures import scopes | ||||
|     indirect_as_list = isinstance(indirect, (list, tuple)) | ||||
|     all_arguments_are_fixtures = indirect is True or \ | ||||
|                                  indirect_as_list and len(indirect) == argnames | ||||
|     if all_arguments_are_fixtures: | ||||
|         fixturedefs = arg2fixturedefs or {} | ||||
|         used_scopes = [fixturedef[0].scope for name, fixturedef in fixturedefs.items()] | ||||
|         if used_scopes: | ||||
|             # Takes the most narrow scope from used fixtures | ||||
|             for scope in reversed(scopes): | ||||
|                 if scope in used_scopes: | ||||
|                     return scope | ||||
| 
 | ||||
|     return 'function' | ||||
| 
 | ||||
| 
 | ||||
| def _idval(val, argname, idx, idfn, config=None): | ||||
|  | @ -921,7 +936,7 @@ def _idval(val, argname, idx, idfn, config=None): | |||
|     return str(argname)+str(idx) | ||||
| 
 | ||||
| def _idvalset(idx, valset, argnames, idfn, ids, config=None): | ||||
|     if ids is None or ids[idx] is None: | ||||
|     if ids is None or (idx >= len(ids) or ids[idx] is None): | ||||
|         this_id = [_idval(val, argname, idx, idfn, config) | ||||
|                    for val, argname in zip(valset, argnames)] | ||||
|         return "-".join(this_id) | ||||
|  |  | |||
|  | @ -492,10 +492,16 @@ class Skipped(OutcomeException): | |||
|     # in order to have Skipped exception printing shorter/nicer | ||||
|     __module__ = 'builtins' | ||||
| 
 | ||||
|     def __init__(self, msg=None, pytrace=True, allow_module_level=False): | ||||
|         OutcomeException.__init__(self, msg=msg, pytrace=pytrace) | ||||
|         self.allow_module_level = allow_module_level | ||||
| 
 | ||||
| 
 | ||||
| class Failed(OutcomeException): | ||||
|     """ raised from an explicit call to pytest.fail() """ | ||||
|     __module__ = 'builtins' | ||||
| 
 | ||||
| 
 | ||||
| class Exit(KeyboardInterrupt): | ||||
|     """ raised for immediate program exits (no tracebacks/summaries)""" | ||||
|     def __init__(self, msg="unknown reason"): | ||||
|  | @ -546,7 +552,7 @@ def importorskip(modname, minversion=None): | |||
|         # Do not raise chained exception here(#1485) | ||||
|         should_skip = True | ||||
|     if should_skip: | ||||
|         skip("could not import %r" %(modname,)) | ||||
|         raise Skipped("could not import %r" %(modname,), allow_module_level=True) | ||||
|     mod = sys.modules[modname] | ||||
|     if minversion is None: | ||||
|         return mod | ||||
|  | @ -555,10 +561,11 @@ def importorskip(modname, minversion=None): | |||
|         try: | ||||
|             from pkg_resources import parse_version as pv | ||||
|         except ImportError: | ||||
|             skip("we have a required version for %r but can not import " | ||||
|                  "no pkg_resources to parse version strings." %(modname,)) | ||||
|             raise Skipped("we have a required version for %r but can not import " | ||||
|                           "pkg_resources to parse version strings." % (modname,), | ||||
|                           allow_module_level=True) | ||||
|         if verattr is None or pv(verattr) < pv(minversion): | ||||
|             skip("module %r has __version__ %r, required is: %r" %( | ||||
|                  modname, verattr, minversion)) | ||||
|             raise Skipped("module %r has __version__ %r, required is: %r" %( | ||||
|                           modname, verattr, minversion), allow_module_level=True) | ||||
|     return mod | ||||
| 
 | ||||
|  |  | |||
|  | @ -7,6 +7,8 @@ Release announcements | |||
| 
 | ||||
| 
 | ||||
|    sprint2016 | ||||
|    release-3.0.1 | ||||
|    release-3.0.0 | ||||
|    release-2.9.2 | ||||
|    release-2.9.1 | ||||
|    release-2.9.0 | ||||
|  |  | |||
|  | @ -41,7 +41,7 @@ Changes 2.6.3 | |||
|   dep).  Thanks Charles Cloud for analysing the issue. | ||||
| 
 | ||||
| - fix conftest related fixture visibility issue: when running with a | ||||
|   CWD outside a test package pytest would get fixture discovery wrong. | ||||
|   CWD outside of a test package pytest would get fixture discovery wrong. | ||||
|   Thanks to Wolfgang Schnerring for figuring out a reproducable example. | ||||
| 
 | ||||
| - Introduce pytest_enter_pdb hook (needed e.g. by pytest_timeout to cancel the | ||||
|  |  | |||
|  | @ -6,7 +6,7 @@ The pytest team is proud to announce the 3.0.0 release! | |||
| pytest is a mature Python testing tool with more than a 1600 tests | ||||
| against itself, passing on many different interpreters and platforms. | ||||
| 
 | ||||
| This release contains a lot of bugs and improvements, and much of | ||||
| This release contains a lot of bugs fixes and improvements, and much of | ||||
| the work done on it was possible because of the 2016 Sprint[1], which | ||||
| was funded by an indiegogo campaign which raised over US$12,000 with  | ||||
| nearly 100 backers.  | ||||
|  | @ -76,7 +76,7 @@ Thanks to all who contributed to this release, among them: | |||
| 
 | ||||
| 
 | ||||
| Happy testing, | ||||
| The py.test Development Team | ||||
| The Pytest Development Team | ||||
| 
 | ||||
| [1] http://blog.pytest.org/2016/pytest-development-sprint/ | ||||
| [2] http://blog.pytest.org/2016/whats-new-in-pytest-30/ | ||||
|  |  | |||
|  | @ -0,0 +1,26 @@ | |||
| pytest-3.0.1 | ||||
| ============ | ||||
| 
 | ||||
| pytest 3.0.1 has just been released to PyPI. | ||||
| 
 | ||||
| This release fixes some regressions reported in version 3.0.0, being a | ||||
| drop-in replacement. To upgrade: | ||||
| 
 | ||||
|   pip install --upgrade pytest | ||||
|    | ||||
| The changelog is available at http://doc.pytest.org/en/latest/changelog.html. | ||||
| 
 | ||||
| Thanks to all who contributed to this release, among them: | ||||
| 
 | ||||
|       Adam Chainz | ||||
|       Andrew Svetlov | ||||
|       Bruno Oliveira | ||||
|       Daniel Hahler | ||||
|       Dmitry Dygalo | ||||
|       Florian Bruhin | ||||
|       Marcin Bachry | ||||
|       Ronny Pfannschmidt | ||||
|       matthiasha | ||||
| 
 | ||||
| Happy testing, | ||||
| The py.test Development Team | ||||
|  | @ -26,7 +26,7 @@ you will see the return value of the function call:: | |||
| 
 | ||||
|     $ pytest test_assert1.py | ||||
|     ======= test session starts ======== | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.0, py-1.4.31, pluggy-0.3.1 | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.1, py-1.4.31, pluggy-0.3.1 | ||||
|     rootdir: $REGENDOC_TMPDIR, inifile:  | ||||
|     collected 1 items | ||||
|      | ||||
|  | @ -170,7 +170,7 @@ if you run this module:: | |||
| 
 | ||||
|     $ pytest test_assert2.py | ||||
|     ======= test session starts ======== | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.0, py-1.4.31, pluggy-0.3.1 | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.1, py-1.4.31, pluggy-0.3.1 | ||||
|     rootdir: $REGENDOC_TMPDIR, inifile:  | ||||
|     collected 1 items | ||||
|      | ||||
|  |  | |||
|  | @ -80,7 +80,7 @@ If you then run it with ``--lf``:: | |||
| 
 | ||||
|     $ pytest --lf | ||||
|     ======= test session starts ======== | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.0, py-1.4.31, pluggy-0.3.1 | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.1, py-1.4.31, pluggy-0.3.1 | ||||
|     run-last-failure: rerun last 2 failures | ||||
|     rootdir: $REGENDOC_TMPDIR, inifile:  | ||||
|     collected 50 items | ||||
|  | @ -122,7 +122,7 @@ of ``FF`` and dots):: | |||
| 
 | ||||
|     $ pytest --ff | ||||
|     ======= test session starts ======== | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.0, py-1.4.31, pluggy-0.3.1 | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.1, py-1.4.31, pluggy-0.3.1 | ||||
|     run-last-failure: rerun last 2 failures first | ||||
|     rootdir: $REGENDOC_TMPDIR, inifile:  | ||||
|     collected 50 items | ||||
|  | @ -227,7 +227,7 @@ You can always peek at the content of the cache using the | |||
| 
 | ||||
|     $ py.test --cache-show | ||||
|     ======= test session starts ======== | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.0, py-1.4.31, pluggy-0.3.1 | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.1, py-1.4.31, pluggy-0.3.1 | ||||
|     rootdir: $REGENDOC_TMPDIR, inifile:  | ||||
|     cachedir: $REGENDOC_TMPDIR/.cache | ||||
|     ------------------------------- cache values ------------------------------- | ||||
|  |  | |||
|  | @ -64,7 +64,7 @@ of the failing function and hide the other one:: | |||
| 
 | ||||
|     $ pytest | ||||
|     ======= test session starts ======== | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.0, py-1.4.31, pluggy-0.3.1 | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.1, py-1.4.31, pluggy-0.3.1 | ||||
|     rootdir: $REGENDOC_TMPDIR, inifile:  | ||||
|     collected 2 items | ||||
|      | ||||
|  |  | |||
|  | @ -48,7 +48,7 @@ then you can just invoke ``pytest`` without command line options:: | |||
| 
 | ||||
|     $ pytest | ||||
|     ======= test session starts ======== | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.0, py-1.4.31, pluggy-0.3.1 | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.1, py-1.4.31, pluggy-0.3.1 | ||||
|     rootdir: $REGENDOC_TMPDIR, inifile: pytest.ini | ||||
|     collected 1 items | ||||
|      | ||||
|  |  | |||
|  | @ -1,4 +0,0 @@ | |||
| [pytest] | ||||
| testfilepatterns = | ||||
|     ${topdir}/tests/unit/test_${basename} | ||||
|     ${topdir}/tests/functional/*.py | ||||
|  | @ -31,7 +31,7 @@ You can then restrict a test run to only run tests marked with ``webtest``:: | |||
| 
 | ||||
|     $ pytest -v -m webtest | ||||
|     ======= test session starts ======== | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.0, py-1.4.31, pluggy-0.3.1 -- $PYTHON_PREFIX/bin/python3.5 | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.1, py-1.4.31, pluggy-0.3.1 -- $PYTHON_PREFIX/bin/python3.5 | ||||
|     cachedir: .cache | ||||
|     rootdir: $REGENDOC_TMPDIR, inifile:  | ||||
|     collecting ... collected 4 items | ||||
|  | @ -45,7 +45,7 @@ Or the inverse, running all tests except the webtest ones:: | |||
| 
 | ||||
|     $ pytest -v -m "not webtest" | ||||
|     ======= test session starts ======== | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.0, py-1.4.31, pluggy-0.3.1 -- $PYTHON_PREFIX/bin/python3.5 | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.1, py-1.4.31, pluggy-0.3.1 -- $PYTHON_PREFIX/bin/python3.5 | ||||
|     cachedir: .cache | ||||
|     rootdir: $REGENDOC_TMPDIR, inifile:  | ||||
|     collecting ... collected 4 items | ||||
|  | @ -66,7 +66,7 @@ tests based on their module, class, method, or function name:: | |||
| 
 | ||||
|     $ pytest -v test_server.py::TestClass::test_method | ||||
|     ======= test session starts ======== | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.0, py-1.4.31, pluggy-0.3.1 -- $PYTHON_PREFIX/bin/python3.5 | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.1, py-1.4.31, pluggy-0.3.1 -- $PYTHON_PREFIX/bin/python3.5 | ||||
|     cachedir: .cache | ||||
|     rootdir: $REGENDOC_TMPDIR, inifile:  | ||||
|     collecting ... collected 5 items | ||||
|  | @ -79,7 +79,7 @@ You can also select on the class:: | |||
| 
 | ||||
|     $ pytest -v test_server.py::TestClass | ||||
|     ======= test session starts ======== | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.0, py-1.4.31, pluggy-0.3.1 -- $PYTHON_PREFIX/bin/python3.5 | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.1, py-1.4.31, pluggy-0.3.1 -- $PYTHON_PREFIX/bin/python3.5 | ||||
|     cachedir: .cache | ||||
|     rootdir: $REGENDOC_TMPDIR, inifile:  | ||||
|     collecting ... collected 4 items | ||||
|  | @ -92,7 +92,7 @@ Or select multiple nodes:: | |||
| 
 | ||||
|   $ pytest -v test_server.py::TestClass test_server.py::test_send_http | ||||
|   ======= test session starts ======== | ||||
|   platform linux -- Python 3.5.2, pytest-3.0.0, py-1.4.31, pluggy-0.3.1 -- $PYTHON_PREFIX/bin/python3.5 | ||||
|   platform linux -- Python 3.5.2, pytest-3.0.1, py-1.4.31, pluggy-0.3.1 -- $PYTHON_PREFIX/bin/python3.5 | ||||
|   cachedir: .cache | ||||
|   rootdir: $REGENDOC_TMPDIR, inifile:  | ||||
|   collecting ... collected 8 items | ||||
|  | @ -130,7 +130,7 @@ select tests based on their names:: | |||
| 
 | ||||
|     $ pytest -v -k http  # running with the above defined example module | ||||
|     ======= test session starts ======== | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.0, py-1.4.31, pluggy-0.3.1 -- $PYTHON_PREFIX/bin/python3.5 | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.1, py-1.4.31, pluggy-0.3.1 -- $PYTHON_PREFIX/bin/python3.5 | ||||
|     cachedir: .cache | ||||
|     rootdir: $REGENDOC_TMPDIR, inifile:  | ||||
|     collecting ... collected 4 items | ||||
|  | @ -144,7 +144,7 @@ And you can also run all tests except the ones that match the keyword:: | |||
| 
 | ||||
|     $ pytest -k "not send_http" -v | ||||
|     ======= test session starts ======== | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.0, py-1.4.31, pluggy-0.3.1 -- $PYTHON_PREFIX/bin/python3.5 | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.1, py-1.4.31, pluggy-0.3.1 -- $PYTHON_PREFIX/bin/python3.5 | ||||
|     cachedir: .cache | ||||
|     rootdir: $REGENDOC_TMPDIR, inifile:  | ||||
|     collecting ... collected 4 items | ||||
|  | @ -160,7 +160,7 @@ Or to select "http" and "quick" tests:: | |||
| 
 | ||||
|     $ pytest -k "http or quick" -v | ||||
|     ======= test session starts ======== | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.0, py-1.4.31, pluggy-0.3.1 -- $PYTHON_PREFIX/bin/python3.5 | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.1, py-1.4.31, pluggy-0.3.1 -- $PYTHON_PREFIX/bin/python3.5 | ||||
|     cachedir: .cache | ||||
|     rootdir: $REGENDOC_TMPDIR, inifile:  | ||||
|     collecting ... collected 4 items | ||||
|  | @ -352,7 +352,7 @@ the test needs:: | |||
| 
 | ||||
|     $ pytest -E stage2 | ||||
|     ======= test session starts ======== | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.0, py-1.4.31, pluggy-0.3.1 | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.1, py-1.4.31, pluggy-0.3.1 | ||||
|     rootdir: $REGENDOC_TMPDIR, inifile:  | ||||
|     collected 1 items | ||||
|      | ||||
|  | @ -364,7 +364,7 @@ and here is one that specifies exactly the environment needed:: | |||
| 
 | ||||
|     $ pytest -E stage1 | ||||
|     ======= test session starts ======== | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.0, py-1.4.31, pluggy-0.3.1 | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.1, py-1.4.31, pluggy-0.3.1 | ||||
|     rootdir: $REGENDOC_TMPDIR, inifile:  | ||||
|     collected 1 items | ||||
|      | ||||
|  | @ -485,7 +485,7 @@ then you will see two test skipped and two executed tests as expected:: | |||
| 
 | ||||
|     $ pytest -rs # this option reports skip reasons | ||||
|     ======= test session starts ======== | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.0, py-1.4.31, pluggy-0.3.1 | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.1, py-1.4.31, pluggy-0.3.1 | ||||
|     rootdir: $REGENDOC_TMPDIR, inifile:  | ||||
|     collected 4 items | ||||
|      | ||||
|  | @ -499,7 +499,7 @@ Note that if you specify a platform via the marker-command line option like this | |||
| 
 | ||||
|     $ pytest -m linux2 | ||||
|     ======= test session starts ======== | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.0, py-1.4.31, pluggy-0.3.1 | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.1, py-1.4.31, pluggy-0.3.1 | ||||
|     rootdir: $REGENDOC_TMPDIR, inifile:  | ||||
|     collected 4 items | ||||
|      | ||||
|  | @ -551,7 +551,7 @@ We can now use the ``-m option`` to select one set:: | |||
| 
 | ||||
|   $ pytest -m interface --tb=short | ||||
|   ======= test session starts ======== | ||||
|   platform linux -- Python 3.5.2, pytest-3.0.0, py-1.4.31, pluggy-0.3.1 | ||||
|   platform linux -- Python 3.5.2, pytest-3.0.1, py-1.4.31, pluggy-0.3.1 | ||||
|   rootdir: $REGENDOC_TMPDIR, inifile:  | ||||
|   collected 4 items | ||||
|    | ||||
|  | @ -573,7 +573,7 @@ or to select both "event" and "interface" tests:: | |||
| 
 | ||||
|   $ pytest -m "interface or event" --tb=short | ||||
|   ======= test session starts ======== | ||||
|   platform linux -- Python 3.5.2, pytest-3.0.0, py-1.4.31, pluggy-0.3.1 | ||||
|   platform linux -- Python 3.5.2, pytest-3.0.1, py-1.4.31, pluggy-0.3.1 | ||||
|   rootdir: $REGENDOC_TMPDIR, inifile:  | ||||
|   collected 4 items | ||||
|    | ||||
|  |  | |||
|  | @ -27,7 +27,7 @@ now execute the test specification:: | |||
| 
 | ||||
|     nonpython $ pytest test_simple.yml | ||||
|     ======= test session starts ======== | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.0, py-1.4.31, pluggy-0.3.1 | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.1, py-1.4.31, pluggy-0.3.1 | ||||
|     rootdir: $REGENDOC_TMPDIR/nonpython, inifile:  | ||||
|     collected 2 items | ||||
|      | ||||
|  | @ -59,7 +59,7 @@ consulted when reporting in ``verbose`` mode:: | |||
| 
 | ||||
|     nonpython $ pytest -v | ||||
|     ======= test session starts ======== | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.0, py-1.4.31, pluggy-0.3.1 -- $PYTHON_PREFIX/bin/python3.5 | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.1, py-1.4.31, pluggy-0.3.1 -- $PYTHON_PREFIX/bin/python3.5 | ||||
|     cachedir: .cache | ||||
|     rootdir: $REGENDOC_TMPDIR/nonpython, inifile:  | ||||
|     collecting ... collected 2 items | ||||
|  | @ -81,7 +81,7 @@ interesting to just look at the collection tree:: | |||
| 
 | ||||
|     nonpython $ pytest --collect-only | ||||
|     ======= test session starts ======== | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.0, py-1.4.31, pluggy-0.3.1 | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.1, py-1.4.31, pluggy-0.3.1 | ||||
|     rootdir: $REGENDOC_TMPDIR/nonpython, inifile:  | ||||
|     collected 2 items | ||||
|     <YamlFile 'test_simple.yml'> | ||||
|  |  | |||
|  | @ -130,7 +130,7 @@ objects, they are still using the default pytest representation:: | |||
| 
 | ||||
|     $ pytest test_time.py --collect-only | ||||
|     ======= test session starts ======== | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.0, py-1.4.31, pluggy-0.3.1 | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.1, py-1.4.31, pluggy-0.3.1 | ||||
|     rootdir: $REGENDOC_TMPDIR, inifile:  | ||||
|     collected 6 items | ||||
|     <Module 'test_time.py'> | ||||
|  | @ -181,7 +181,7 @@ this is a fully self-contained example which you can run with:: | |||
| 
 | ||||
|     $ pytest test_scenarios.py | ||||
|     ======= test session starts ======== | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.0, py-1.4.31, pluggy-0.3.1 | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.1, py-1.4.31, pluggy-0.3.1 | ||||
|     rootdir: $REGENDOC_TMPDIR, inifile:  | ||||
|     collected 4 items | ||||
|      | ||||
|  | @ -194,7 +194,7 @@ If you just collect tests you'll also nicely see 'advanced' and 'basic' as varia | |||
| 
 | ||||
|     $ pytest --collect-only test_scenarios.py | ||||
|     ======= test session starts ======== | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.0, py-1.4.31, pluggy-0.3.1 | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.1, py-1.4.31, pluggy-0.3.1 | ||||
|     rootdir: $REGENDOC_TMPDIR, inifile:  | ||||
|     collected 4 items | ||||
|     <Module 'test_scenarios.py'> | ||||
|  | @ -259,7 +259,7 @@ Let's first see how it looks like at collection time:: | |||
| 
 | ||||
|     $ pytest test_backends.py --collect-only | ||||
|     ======= test session starts ======== | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.0, py-1.4.31, pluggy-0.3.1 | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.1, py-1.4.31, pluggy-0.3.1 | ||||
|     rootdir: $REGENDOC_TMPDIR, inifile:  | ||||
|     collected 2 items | ||||
|     <Module 'test_backends.py'> | ||||
|  | @ -320,7 +320,7 @@ The result of this test will be successful:: | |||
| 
 | ||||
|     $ pytest test_indirect_list.py --collect-only | ||||
|     ======= test session starts ======== | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.0, py-1.4.31, pluggy-0.3.1 | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.1, py-1.4.31, pluggy-0.3.1 | ||||
|     rootdir: $REGENDOC_TMPDIR, inifile:  | ||||
|     collected 1 items | ||||
|     <Module 'test_indirect_list.py'> | ||||
|  | @ -447,7 +447,7 @@ If you run this with reporting for skips enabled:: | |||
| 
 | ||||
|     $ pytest -rs test_module.py | ||||
|     ======= test session starts ======== | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.0, py-1.4.31, pluggy-0.3.1 | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.1, py-1.4.31, pluggy-0.3.1 | ||||
|     rootdir: $REGENDOC_TMPDIR, inifile:  | ||||
|     collected 2 items | ||||
|      | ||||
|  |  | |||
|  | @ -117,7 +117,7 @@ then the test collection looks like this:: | |||
| 
 | ||||
|     $ pytest --collect-only | ||||
|     ======= test session starts ======== | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.0, py-1.4.31, pluggy-0.3.1 | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.1, py-1.4.31, pluggy-0.3.1 | ||||
|     rootdir: $REGENDOC_TMPDIR, inifile: pytest.ini | ||||
|     collected 2 items | ||||
|     <Module 'check_myapp.py'> | ||||
|  | @ -163,7 +163,7 @@ You can always peek at the collection tree without running tests like this:: | |||
| 
 | ||||
|     . $ pytest --collect-only pythoncollection.py | ||||
|     ======= test session starts ======== | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.0, py-1.4.31, pluggy-0.3.1 | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.1, py-1.4.31, pluggy-0.3.1 | ||||
|     rootdir: $REGENDOC_TMPDIR, inifile: pytest.ini | ||||
|     collected 3 items | ||||
|     <Module 'CWD/pythoncollection.py'> | ||||
|  | @ -230,7 +230,7 @@ will be left out:: | |||
| 
 | ||||
|     $ pytest --collect-only | ||||
|     ======= test session starts ======== | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.0, py-1.4.31, pluggy-0.3.1 | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.1, py-1.4.31, pluggy-0.3.1 | ||||
|     rootdir: $REGENDOC_TMPDIR, inifile: pytest.ini | ||||
|     collected 0 items | ||||
|      | ||||
|  |  | |||
|  | @ -13,7 +13,7 @@ get on the terminal - we are working on that): | |||
| 
 | ||||
|     assertion $ pytest failure_demo.py | ||||
|     ======= test session starts ======== | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.0, py-1.4.31, pluggy-0.3.1 | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.1, py-1.4.31, pluggy-0.3.1 | ||||
|     rootdir: $REGENDOC_TMPDIR/assertion, inifile:  | ||||
|     collected 42 items | ||||
|      | ||||
|  | @ -361,7 +361,7 @@ get on the terminal - we are working on that): | |||
|     >   int(s) | ||||
|     E   ValueError: invalid literal for int() with base 10: 'qwe' | ||||
|      | ||||
|     <0-codegen $PYTHON_PREFIX/lib/python3.5/site-packages/_pytest/python.py:1174>:1: ValueError | ||||
|     <0-codegen $PYTHON_PREFIX/lib/python3.5/site-packages/_pytest/python.py:1189>:1: ValueError | ||||
|     _______ TestRaises.test_raises_doesnt ________ | ||||
|      | ||||
|     self = <failure_demo.TestRaises object at 0xdeadbeef> | ||||
|  |  | |||
|  | @ -108,7 +108,7 @@ directory with the above conftest.py:: | |||
| 
 | ||||
|     $ pytest | ||||
|     ======= test session starts ======== | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.0, py-1.4.31, pluggy-0.3.1 | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.1, py-1.4.31, pluggy-0.3.1 | ||||
|     rootdir: $REGENDOC_TMPDIR, inifile:  | ||||
|     collected 0 items | ||||
|      | ||||
|  | @ -156,7 +156,7 @@ and when running it will see a skipped "slow" test:: | |||
| 
 | ||||
|     $ pytest -rs    # "-rs" means report details on the little 's' | ||||
|     ======= test session starts ======== | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.0, py-1.4.31, pluggy-0.3.1 | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.1, py-1.4.31, pluggy-0.3.1 | ||||
|     rootdir: $REGENDOC_TMPDIR, inifile:  | ||||
|     collected 2 items | ||||
|      | ||||
|  | @ -170,7 +170,7 @@ Or run it including the ``slow`` marked test:: | |||
| 
 | ||||
|     $ pytest --runslow | ||||
|     ======= test session starts ======== | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.0, py-1.4.31, pluggy-0.3.1 | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.1, py-1.4.31, pluggy-0.3.1 | ||||
|     rootdir: $REGENDOC_TMPDIR, inifile:  | ||||
|     collected 2 items | ||||
|      | ||||
|  | @ -284,7 +284,7 @@ which will add the string to the test header accordingly:: | |||
| 
 | ||||
|     $ pytest | ||||
|     ======= test session starts ======== | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.0, py-1.4.31, pluggy-0.3.1 | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.1, py-1.4.31, pluggy-0.3.1 | ||||
|     project deps: mylib-1.1 | ||||
|     rootdir: $REGENDOC_TMPDIR, inifile:  | ||||
|     collected 0 items | ||||
|  | @ -308,7 +308,7 @@ which will add info only when run with "--v":: | |||
| 
 | ||||
|     $ pytest -v | ||||
|     ======= test session starts ======== | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.0, py-1.4.31, pluggy-0.3.1 -- $PYTHON_PREFIX/bin/python3.5 | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.1, py-1.4.31, pluggy-0.3.1 -- $PYTHON_PREFIX/bin/python3.5 | ||||
|     cachedir: .cache | ||||
|     info1: did you know that ... | ||||
|     did you? | ||||
|  | @ -321,7 +321,7 @@ and nothing when run plainly:: | |||
| 
 | ||||
|     $ pytest | ||||
|     ======= test session starts ======== | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.0, py-1.4.31, pluggy-0.3.1 | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.1, py-1.4.31, pluggy-0.3.1 | ||||
|     rootdir: $REGENDOC_TMPDIR, inifile:  | ||||
|     collected 0 items | ||||
|      | ||||
|  | @ -354,7 +354,7 @@ Now we can profile which test functions execute the slowest:: | |||
| 
 | ||||
|     $ pytest --durations=3 | ||||
|     ======= test session starts ======== | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.0, py-1.4.31, pluggy-0.3.1 | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.1, py-1.4.31, pluggy-0.3.1 | ||||
|     rootdir: $REGENDOC_TMPDIR, inifile:  | ||||
|     collected 3 items | ||||
|      | ||||
|  | @ -416,7 +416,7 @@ If we run this:: | |||
| 
 | ||||
|     $ pytest -rx | ||||
|     ======= test session starts ======== | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.0, py-1.4.31, pluggy-0.3.1 | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.1, py-1.4.31, pluggy-0.3.1 | ||||
|     rootdir: $REGENDOC_TMPDIR, inifile:  | ||||
|     collected 4 items | ||||
|      | ||||
|  | @ -487,7 +487,7 @@ We can run this:: | |||
| 
 | ||||
|     $ pytest | ||||
|     ======= test session starts ======== | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.0, py-1.4.31, pluggy-0.3.1 | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.1, py-1.4.31, pluggy-0.3.1 | ||||
|     rootdir: $REGENDOC_TMPDIR, inifile:  | ||||
|     collected 7 items | ||||
|      | ||||
|  | @ -591,7 +591,7 @@ and run them:: | |||
| 
 | ||||
|     $ pytest test_module.py | ||||
|     ======= test session starts ======== | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.0, py-1.4.31, pluggy-0.3.1 | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.1, py-1.4.31, pluggy-0.3.1 | ||||
|     rootdir: $REGENDOC_TMPDIR, inifile:  | ||||
|     collected 2 items | ||||
|      | ||||
|  | @ -681,7 +681,7 @@ and run it:: | |||
| 
 | ||||
|     $ pytest -s test_module.py | ||||
|     ======= test session starts ======== | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.0, py-1.4.31, pluggy-0.3.1 | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.1, py-1.4.31, pluggy-0.3.1 | ||||
|     rootdir: $REGENDOC_TMPDIR, inifile:  | ||||
|     collected 3 items | ||||
|      | ||||
|  |  | |||
|  | @ -70,7 +70,7 @@ marked ``smtp`` fixture function.  Running the test looks like this:: | |||
| 
 | ||||
|     $ pytest test_smtpsimple.py | ||||
|     ======= test session starts ======== | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.0, py-1.4.31, pluggy-0.3.1 | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.1, py-1.4.31, pluggy-0.3.1 | ||||
|     rootdir: $REGENDOC_TMPDIR, inifile:  | ||||
|     collected 1 items | ||||
|      | ||||
|  | @ -188,7 +188,7 @@ inspect what is going on and can now run the tests:: | |||
| 
 | ||||
|     $ pytest test_module.py | ||||
|     ======= test session starts ======== | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.0, py-1.4.31, pluggy-0.3.1 | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.1, py-1.4.31, pluggy-0.3.1 | ||||
|     rootdir: $REGENDOC_TMPDIR, inifile:  | ||||
|     collected 2 items | ||||
|      | ||||
|  | @ -516,7 +516,7 @@ Running the above tests results in the following test IDs being used:: | |||
| 
 | ||||
|    $ pytest --collect-only | ||||
|    ======= test session starts ======== | ||||
|    platform linux -- Python 3.5.2, pytest-3.0.0, py-1.4.31, pluggy-0.3.1 | ||||
|    platform linux -- Python 3.5.2, pytest-3.0.1, py-1.4.31, pluggy-0.3.1 | ||||
|    rootdir: $REGENDOC_TMPDIR, inifile:  | ||||
|    collected 11 items | ||||
|    <Module 'test_anothersmtp.py'> | ||||
|  | @ -569,7 +569,7 @@ Here we declare an ``app`` fixture which receives the previously defined | |||
| 
 | ||||
|     $ pytest -v test_appsetup.py | ||||
|     ======= test session starts ======== | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.0, py-1.4.31, pluggy-0.3.1 -- $PYTHON_PREFIX/bin/python3.5 | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.1, py-1.4.31, pluggy-0.3.1 -- $PYTHON_PREFIX/bin/python3.5 | ||||
|     cachedir: .cache | ||||
|     rootdir: $REGENDOC_TMPDIR, inifile:  | ||||
|     collecting ... collected 2 items | ||||
|  | @ -638,7 +638,7 @@ Let's run the tests in verbose mode and with looking at the print-output:: | |||
| 
 | ||||
|     $ pytest -v -s test_module.py | ||||
|     ======= test session starts ======== | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.0, py-1.4.31, pluggy-0.3.1 -- $PYTHON_PREFIX/bin/python3.5 | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.1, py-1.4.31, pluggy-0.3.1 -- $PYTHON_PREFIX/bin/python3.5 | ||||
|     cachedir: .cache | ||||
|     rootdir: $REGENDOC_TMPDIR, inifile:  | ||||
|     collecting ... collected 8 items | ||||
|  |  | |||
|  | @ -27,7 +27,7 @@ Installation options:: | |||
| To check your installation has installed the correct version:: | ||||
| 
 | ||||
|     $ pytest --version | ||||
|     This is pytest version 3.0.0, imported from $PYTHON_PREFIX/lib/python3.5/site-packages/pytest.py | ||||
|     This is pytest version 3.0.1, imported from $PYTHON_PREFIX/lib/python3.5/site-packages/pytest.py | ||||
| 
 | ||||
| If you get an error checkout :ref:`installation issues`. | ||||
| 
 | ||||
|  | @ -49,7 +49,7 @@ That's it. You can execute the test function now:: | |||
| 
 | ||||
|     $ pytest | ||||
|     ======= test session starts ======== | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.0, py-1.4.31, pluggy-0.3.1 | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.1, py-1.4.31, pluggy-0.3.1 | ||||
|     rootdir: $REGENDOC_TMPDIR, inifile:  | ||||
|     collected 1 items | ||||
|      | ||||
|  |  | |||
|  | @ -55,7 +55,7 @@ them in turn:: | |||
| 
 | ||||
|     $ pytest | ||||
|     ======= test session starts ======== | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.0, py-1.4.31, pluggy-0.3.1 | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.1, py-1.4.31, pluggy-0.3.1 | ||||
|     rootdir: $REGENDOC_TMPDIR, inifile:  | ||||
|     collected 3 items | ||||
|      | ||||
|  | @ -103,7 +103,7 @@ Let's run this:: | |||
| 
 | ||||
|     $ pytest | ||||
|     ======= test session starts ======== | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.0, py-1.4.31, pluggy-0.3.1 | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.1, py-1.4.31, pluggy-0.3.1 | ||||
|     rootdir: $REGENDOC_TMPDIR, inifile:  | ||||
|     collected 3 items | ||||
|      | ||||
|  |  | |||
|  | @ -224,7 +224,7 @@ Running it with the report-on-xfail option gives this output:: | |||
| 
 | ||||
|     example $ pytest -rx xfail_demo.py | ||||
|     ======= test session starts ======== | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.0, py-1.4.31, pluggy-0.3.1 | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.1, py-1.4.31, pluggy-0.3.1 | ||||
|     rootdir: $REGENDOC_TMPDIR/example, inifile:  | ||||
|     collected 7 items | ||||
|      | ||||
|  |  | |||
|  | @ -29,7 +29,7 @@ Running this would result in a passed test except for the last | |||
| 
 | ||||
|     $ pytest test_tmpdir.py | ||||
|     ======= test session starts ======== | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.0, py-1.4.31, pluggy-0.3.1 | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.1, py-1.4.31, pluggy-0.3.1 | ||||
|     rootdir: $REGENDOC_TMPDIR, inifile:  | ||||
|     collected 1 items | ||||
|      | ||||
|  |  | |||
|  | @ -88,7 +88,7 @@ the ``self.db`` values in the traceback:: | |||
| 
 | ||||
|     $ pytest test_unittest_db.py | ||||
|     ======= test session starts ======== | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.0, py-1.4.31, pluggy-0.3.1 | ||||
|     platform linux -- Python 3.5.2, pytest-3.0.1, py-1.4.31, pluggy-0.3.1 | ||||
|     rootdir: $REGENDOC_TMPDIR, inifile:  | ||||
|     collected 2 items | ||||
|      | ||||
|  |  | |||
|  | @ -293,7 +293,7 @@ can use like this:: | |||
|                 pass | ||||
|         """) | ||||
|         result = testdir.runpytest("--verbose") | ||||
|         result.fnmatch_lines(""" | ||||
|         result.stdout.fnmatch_lines(""" | ||||
|             test_example* | ||||
|         """) | ||||
| 
 | ||||
|  |  | |||
|  | @ -763,3 +763,21 @@ class TestDurationWithFixture: | |||
|             * call *test_1* | ||||
|         """) | ||||
| 
 | ||||
| 
 | ||||
| def test_zipimport_hook(testdir, tmpdir): | ||||
|     """Test package loader is being used correctly (see #1837).""" | ||||
|     zipapp = pytest.importorskip('zipapp') | ||||
|     testdir.tmpdir.join('app').ensure(dir=1) | ||||
|     testdir.makepyfile(**{ | ||||
|         'app/foo.py': """ | ||||
|             import pytest | ||||
|             def main(): | ||||
|                 pytest.main(['--pyarg', 'foo']) | ||||
|         """, | ||||
|     }) | ||||
|     target = tmpdir.join('foo.zip') | ||||
|     zipapp.create_archive(str(testdir.tmpdir.join('app')), str(target), main='foo:main') | ||||
|     result = testdir.runpython(target) | ||||
|     assert result.ret == 0 | ||||
|     result.stderr.fnmatch_lines(['*not found*foo*']) | ||||
|     assert 'INTERNALERROR>' not in result.stdout.str() | ||||
|  |  | |||
|  | @ -889,6 +889,33 @@ class TestMetafuncFunctional: | |||
|             "*test_function*advanced*FAILED", | ||||
|         ]) | ||||
| 
 | ||||
|     def test_fixture_parametrized_empty_ids(self, testdir): | ||||
|         """Fixtures parametrized with empty ids cause an internal error (#1849).""" | ||||
|         testdir.makepyfile(''' | ||||
|             import pytest | ||||
| 
 | ||||
|             @pytest.fixture(scope="module", ids=[], params=[]) | ||||
|             def temp(request): | ||||
|                return request.param | ||||
| 
 | ||||
|             def test_temp(temp): | ||||
|                  pass | ||||
|         ''') | ||||
|         result = testdir.runpytest() | ||||
|         result.stdout.fnmatch_lines(['* 1 skipped *']) | ||||
| 
 | ||||
|     def test_parametrized_empty_ids(self, testdir): | ||||
|         """Tests parametrized with empty ids cause an internal error (#1849).""" | ||||
|         testdir.makepyfile(''' | ||||
|             import pytest | ||||
| 
 | ||||
|             @pytest.mark.parametrize('temp', [], ids=list()) | ||||
|             def test_temp(temp): | ||||
|                  pass | ||||
|         ''') | ||||
|         result = testdir.runpytest() | ||||
|         result.stdout.fnmatch_lines(['* 1 skipped *']) | ||||
| 
 | ||||
|     def test_parametrize_with_identical_ids_get_unique_names(self, testdir): | ||||
|         testdir.makepyfile(""" | ||||
|             import pytest | ||||
|  | @ -930,43 +957,6 @@ class TestMetafuncFunctional: | |||
|         reprec = testdir.inline_run() | ||||
|         reprec.assertoutcome(passed=5) | ||||
| 
 | ||||
|     def test_parametrize_issue634(self, testdir): | ||||
|         testdir.makepyfile(''' | ||||
|             import pytest | ||||
| 
 | ||||
|             @pytest.fixture(scope='module') | ||||
|             def foo(request): | ||||
|                 print('preparing foo-%d' % request.param) | ||||
|                 return 'foo-%d' % request.param | ||||
| 
 | ||||
| 
 | ||||
|             def test_one(foo): | ||||
|                 pass | ||||
| 
 | ||||
| 
 | ||||
|             def test_two(foo): | ||||
|                 pass | ||||
| 
 | ||||
| 
 | ||||
|             test_two.test_with = (2, 3) | ||||
| 
 | ||||
| 
 | ||||
|             def pytest_generate_tests(metafunc): | ||||
|                 params = (1, 2, 3, 4) | ||||
|                 if not 'foo' in metafunc.fixturenames: | ||||
|                     return | ||||
| 
 | ||||
|                 test_with = getattr(metafunc.function, 'test_with', None) | ||||
|                 if test_with: | ||||
|                     params = test_with | ||||
|                 metafunc.parametrize('foo', params, indirect=True) | ||||
| 
 | ||||
|         ''') | ||||
|         result = testdir.runpytest("-s") | ||||
|         output = result.stdout.str() | ||||
|         assert output.count('preparing foo-2') == 1 | ||||
|         assert output.count('preparing foo-3') == 1 | ||||
| 
 | ||||
|     def test_parametrize_issue323(self, testdir): | ||||
|         testdir.makepyfile(""" | ||||
|             import pytest | ||||
|  | @ -1047,6 +1037,125 @@ class TestMetafuncFunctional: | |||
|         assert expectederror in failures[0].longrepr.reprcrash.message | ||||
| 
 | ||||
| 
 | ||||
| class TestMetafuncFunctionalAuto: | ||||
|     """ | ||||
|     Tests related to automatically find out the correct scope for parametrized tests (#1832). | ||||
|     """ | ||||
| 
 | ||||
|     def test_parametrize_auto_scope(self, testdir): | ||||
|         testdir.makepyfile(''' | ||||
|             import pytest | ||||
| 
 | ||||
|             @pytest.fixture(scope='session', autouse=True) | ||||
|             def fixture(): | ||||
|                 return 1 | ||||
| 
 | ||||
|             @pytest.mark.parametrize('animal', ["dog", "cat"]) | ||||
|             def test_1(animal): | ||||
|                 assert animal in ('dog', 'cat') | ||||
| 
 | ||||
|             @pytest.mark.parametrize('animal', ['fish']) | ||||
|             def test_2(animal): | ||||
|                 assert animal == 'fish' | ||||
| 
 | ||||
|         ''') | ||||
|         result = testdir.runpytest() | ||||
|         result.stdout.fnmatch_lines(['* 3 passed *']) | ||||
| 
 | ||||
|     def test_parametrize_auto_scope_indirect(self, testdir): | ||||
|         testdir.makepyfile(''' | ||||
|             import pytest | ||||
| 
 | ||||
|             @pytest.fixture(scope='session') | ||||
|             def echo(request): | ||||
|                 return request.param | ||||
| 
 | ||||
|             @pytest.mark.parametrize('animal, echo', [("dog", 1), ("cat", 2)], indirect=['echo']) | ||||
|             def test_1(animal, echo): | ||||
|                 assert animal in ('dog', 'cat') | ||||
|                 assert echo in (1, 2, 3) | ||||
| 
 | ||||
|             @pytest.mark.parametrize('animal, echo', [('fish', 3)], indirect=['echo']) | ||||
|             def test_2(animal, echo): | ||||
|                 assert animal == 'fish' | ||||
|                 assert echo in (1, 2, 3) | ||||
|         ''') | ||||
|         result = testdir.runpytest() | ||||
|         result.stdout.fnmatch_lines(['* 3 passed *']) | ||||
| 
 | ||||
|     def test_parametrize_auto_scope_override_fixture(self, testdir): | ||||
|         testdir.makepyfile(''' | ||||
|             import pytest | ||||
| 
 | ||||
|             @pytest.fixture(scope='session', autouse=True) | ||||
|             def animal(): | ||||
|                 return 'fox' | ||||
| 
 | ||||
|             @pytest.mark.parametrize('animal', ["dog", "cat"]) | ||||
|             def test_1(animal): | ||||
|                 assert animal in ('dog', 'cat') | ||||
|         ''') | ||||
|         result = testdir.runpytest() | ||||
|         result.stdout.fnmatch_lines(['* 2 passed *']) | ||||
| 
 | ||||
|     def test_parametrize_all_indirects(self, testdir): | ||||
|         testdir.makepyfile(''' | ||||
|             import pytest | ||||
| 
 | ||||
|             @pytest.fixture() | ||||
|             def animal(request): | ||||
|                 return request.param | ||||
| 
 | ||||
|             @pytest.fixture(scope='session') | ||||
|             def echo(request): | ||||
|                 return request.param | ||||
| 
 | ||||
|             @pytest.mark.parametrize('animal, echo', [("dog", 1), ("cat", 2)], indirect=True) | ||||
|             def test_1(animal, echo): | ||||
|                 assert animal in ('dog', 'cat') | ||||
|                 assert echo in (1, 2, 3) | ||||
| 
 | ||||
|             @pytest.mark.parametrize('animal, echo', [("fish", 3)], indirect=True) | ||||
|             def test_2(animal, echo): | ||||
|                 assert animal == 'fish' | ||||
|                 assert echo in (1, 2, 3) | ||||
|         ''') | ||||
|         result = testdir.runpytest() | ||||
|         result.stdout.fnmatch_lines(['* 3 passed *']) | ||||
| 
 | ||||
|     def test_parametrize_issue634(self, testdir): | ||||
|         testdir.makepyfile(''' | ||||
|             import pytest | ||||
| 
 | ||||
|             @pytest.fixture(scope='module') | ||||
|             def foo(request): | ||||
|                 print('preparing foo-%d' % request.param) | ||||
|                 return 'foo-%d' % request.param | ||||
| 
 | ||||
|             def test_one(foo): | ||||
|                 pass | ||||
| 
 | ||||
|             def test_two(foo): | ||||
|                 pass | ||||
| 
 | ||||
|             test_two.test_with = (2, 3) | ||||
| 
 | ||||
|             def pytest_generate_tests(metafunc): | ||||
|                 params = (1, 2, 3, 4) | ||||
|                 if not 'foo' in metafunc.fixturenames: | ||||
|                     return | ||||
| 
 | ||||
|                 test_with = getattr(metafunc.function, 'test_with', None) | ||||
|                 if test_with: | ||||
|                     params = test_with | ||||
|                 metafunc.parametrize('foo', params, indirect=True) | ||||
|         ''') | ||||
|         result = testdir.runpytest("-s") | ||||
|         output = result.stdout.str() | ||||
|         assert output.count('preparing foo-2') == 1 | ||||
|         assert output.count('preparing foo-3') == 1 | ||||
| 
 | ||||
| 
 | ||||
| class TestMarkersWithParametrization: | ||||
|     pytestmark = pytest.mark.issue308 | ||||
|     def test_simple_mark(self, testdir): | ||||
|  |  | |||
|  | @ -571,6 +571,19 @@ def test_importorskip_dev_module(monkeypatch): | |||
|         pytest.fail("spurious skip") | ||||
| 
 | ||||
| 
 | ||||
| def test_importorskip_module_level(testdir): | ||||
|     """importorskip must be able to skip entire modules when used at module level""" | ||||
|     testdir.makepyfile(''' | ||||
|         import pytest | ||||
|         foobarbaz = pytest.importorskip("foobarbaz") | ||||
| 
 | ||||
|         def test_foo(): | ||||
|             pass | ||||
|     ''') | ||||
|     result = testdir.runpytest() | ||||
|     result.stdout.fnmatch_lines(['*collected 0 items / 1 skipped*']) | ||||
| 
 | ||||
| 
 | ||||
| def test_pytest_cmdline_main(testdir): | ||||
|     p = testdir.makepyfile(""" | ||||
|         import pytest | ||||
|  |  | |||
|  | @ -967,5 +967,5 @@ def test_module_level_skip_error(testdir): | |||
|     """) | ||||
|     result = testdir.runpytest() | ||||
|     result.stdout.fnmatch_lines( | ||||
|         "*Using @pytest.skip outside a test * is not allowed*" | ||||
|         "*Using @pytest.skip outside of a test * is not allowed*" | ||||
|     ) | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue