Merge remote-tracking branch 'upstream/features' into features
This commit is contained in:
commit
7d923c389e
1
AUTHORS
1
AUTHORS
|
@ -191,6 +191,7 @@ Tareq Alayan
|
||||||
Ted Xiao
|
Ted Xiao
|
||||||
Thomas Grainger
|
Thomas Grainger
|
||||||
Thomas Hisch
|
Thomas Hisch
|
||||||
|
Tim Strazny
|
||||||
Tom Dalton
|
Tom Dalton
|
||||||
Tom Viner
|
Tom Viner
|
||||||
Trevor Bekolay
|
Trevor Bekolay
|
||||||
|
|
|
@ -136,7 +136,7 @@ Trivial/Internal Changes
|
||||||
- Internal ``mark.py`` module has been turned into a package. (`#3250
|
- Internal ``mark.py`` module has been turned into a package. (`#3250
|
||||||
<https://github.com/pytest-dev/pytest/issues/3250>`_)
|
<https://github.com/pytest-dev/pytest/issues/3250>`_)
|
||||||
|
|
||||||
- ``pytest`` now depends on the `more_itertools
|
- ``pytest`` now depends on the `more-itertools
|
||||||
<https://github.com/erikrose/more-itertools>`_ package. (`#3265
|
<https://github.com/erikrose/more-itertools>`_ package. (`#3265
|
||||||
<https://github.com/pytest-dev/pytest/issues/3265>`_)
|
<https://github.com/pytest-dev/pytest/issues/3265>`_)
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,9 @@ import struct
|
||||||
import sys
|
import sys
|
||||||
import types
|
import types
|
||||||
|
|
||||||
|
import atomicwrites
|
||||||
import py
|
import py
|
||||||
|
|
||||||
from _pytest.assertion import util
|
from _pytest.assertion import util
|
||||||
|
|
||||||
|
|
||||||
|
@ -140,7 +142,7 @@ class AssertionRewritingHook(object):
|
||||||
# Probably a SyntaxError in the test.
|
# Probably a SyntaxError in the test.
|
||||||
return None
|
return None
|
||||||
if write:
|
if write:
|
||||||
_make_rewritten_pyc(state, source_stat, pyc, co)
|
_write_pyc(state, co, source_stat, pyc)
|
||||||
else:
|
else:
|
||||||
state.trace("found cached rewritten pyc for %r" % (fn,))
|
state.trace("found cached rewritten pyc for %r" % (fn,))
|
||||||
self.modules[name] = co, pyc
|
self.modules[name] = co, pyc
|
||||||
|
@ -258,22 +260,21 @@ def _write_pyc(state, co, source_stat, pyc):
|
||||||
# sometime to be able to use imp.load_compiled to load them. (See
|
# sometime to be able to use imp.load_compiled to load them. (See
|
||||||
# the comment in load_module above.)
|
# the comment in load_module above.)
|
||||||
try:
|
try:
|
||||||
fp = open(pyc, "wb")
|
with atomicwrites.atomic_write(pyc, mode="wb", overwrite=True) as fp:
|
||||||
except IOError:
|
fp.write(imp.get_magic())
|
||||||
err = sys.exc_info()[1].errno
|
mtime = int(source_stat.mtime)
|
||||||
state.trace("error writing pyc file at %s: errno=%s" % (pyc, err))
|
size = source_stat.size & 0xFFFFFFFF
|
||||||
|
fp.write(struct.pack("<ll", mtime, size))
|
||||||
|
if six.PY2:
|
||||||
|
marshal.dump(co, fp.file)
|
||||||
|
else:
|
||||||
|
marshal.dump(co, fp)
|
||||||
|
except EnvironmentError as e:
|
||||||
|
state.trace("error writing pyc file at %s: errno=%s" % (pyc, e.errno))
|
||||||
# we ignore any failure to write the cache file
|
# we ignore any failure to write the cache file
|
||||||
# there are many reasons, permission-denied, __pycache__ being a
|
# there are many reasons, permission-denied, __pycache__ being a
|
||||||
# file etc.
|
# file etc.
|
||||||
return False
|
return False
|
||||||
try:
|
|
||||||
fp.write(imp.get_magic())
|
|
||||||
mtime = int(source_stat.mtime)
|
|
||||||
size = source_stat.size & 0xFFFFFFFF
|
|
||||||
fp.write(struct.pack("<ll", mtime, size))
|
|
||||||
marshal.dump(co, fp)
|
|
||||||
finally:
|
|
||||||
fp.close()
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
@ -338,20 +339,6 @@ def _rewrite_test(config, fn):
|
||||||
return stat, co
|
return stat, co
|
||||||
|
|
||||||
|
|
||||||
def _make_rewritten_pyc(state, source_stat, pyc, co):
|
|
||||||
"""Try to dump rewritten code to *pyc*."""
|
|
||||||
if sys.platform.startswith("win"):
|
|
||||||
# Windows grants exclusive access to open files and doesn't have atomic
|
|
||||||
# rename, so just write into the final file.
|
|
||||||
_write_pyc(state, co, source_stat, pyc)
|
|
||||||
else:
|
|
||||||
# When not on windows, assume rename is atomic. Dump the code object
|
|
||||||
# into a file specific to this process and atomically replace it.
|
|
||||||
proc_pyc = pyc + "." + str(os.getpid())
|
|
||||||
if _write_pyc(state, co, source_stat, proc_pyc):
|
|
||||||
os.rename(proc_pyc, pyc)
|
|
||||||
|
|
||||||
|
|
||||||
def _read_pyc(source, pyc, trace=lambda x: None):
|
def _read_pyc(source, pyc, trace=lambda x: None):
|
||||||
"""Possibly read a pytest pyc containing rewritten code.
|
"""Possibly read a pytest pyc containing rewritten code.
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ import pprint
|
||||||
import _pytest._code
|
import _pytest._code
|
||||||
import py
|
import py
|
||||||
import six
|
import six
|
||||||
from collections import Sequence
|
from ..compat import Sequence
|
||||||
|
|
||||||
u = six.text_type
|
u = six.text_type
|
||||||
|
|
||||||
|
|
|
@ -38,6 +38,14 @@ PY35 = sys.version_info[:2] >= (3, 5)
|
||||||
PY36 = sys.version_info[:2] >= (3, 6)
|
PY36 = sys.version_info[:2] >= (3, 6)
|
||||||
MODULE_NOT_FOUND_ERROR = 'ModuleNotFoundError' if PY36 else 'ImportError'
|
MODULE_NOT_FOUND_ERROR = 'ModuleNotFoundError' if PY36 else 'ImportError'
|
||||||
|
|
||||||
|
if _PY3:
|
||||||
|
from collections.abc import MutableMapping as MappingMixin # noqa
|
||||||
|
from collections.abc import Sequence # noqa
|
||||||
|
else:
|
||||||
|
# those raise DeprecationWarnings in Python >=3.7
|
||||||
|
from collections import MutableMapping as MappingMixin # noqa
|
||||||
|
from collections import Sequence # noqa
|
||||||
|
|
||||||
|
|
||||||
def _format_args(func):
|
def _format_args(func):
|
||||||
return str(signature(func))
|
return str(signature(func))
|
||||||
|
|
|
@ -413,14 +413,15 @@ def pytest_fixture_post_finalizer(fixturedef, request):
|
||||||
|
|
||||||
|
|
||||||
def pytest_sessionstart(session):
|
def pytest_sessionstart(session):
|
||||||
""" before session.main() is called.
|
""" called after the ``Session`` object has been created and before performing collection
|
||||||
|
and entering the run test loop.
|
||||||
|
|
||||||
:param _pytest.main.Session session: the pytest session object
|
:param _pytest.main.Session session: the pytest session object
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
def pytest_sessionfinish(session, exitstatus):
|
def pytest_sessionfinish(session, exitstatus):
|
||||||
""" whole test run finishes.
|
""" called after whole test run finished, right before returning the exit status to the system.
|
||||||
|
|
||||||
:param _pytest.main.Session session: the pytest session object
|
:param _pytest.main.Session session: the pytest session object
|
||||||
:param int exitstatus: the status which pytest will return to the system
|
:param int exitstatus: the status which pytest will return to the system
|
||||||
|
|
|
@ -245,11 +245,6 @@ def record_property(request):
|
||||||
def test_function(record_property):
|
def test_function(record_property):
|
||||||
record_property("example_key", 1)
|
record_property("example_key", 1)
|
||||||
"""
|
"""
|
||||||
request.node.warn(
|
|
||||||
code='C3',
|
|
||||||
message='record_property is an experimental feature',
|
|
||||||
)
|
|
||||||
|
|
||||||
def append_property(name, value):
|
def append_property(name, value):
|
||||||
request.node.user_properties.append((name, value))
|
request.node.user_properties.append((name, value))
|
||||||
return append_property
|
return append_property
|
||||||
|
|
|
@ -20,7 +20,8 @@ class MarkerError(Exception):
|
||||||
|
|
||||||
|
|
||||||
def param(*values, **kw):
|
def param(*values, **kw):
|
||||||
"""Specify a parameter in a `pytest.mark.parametrize`_ call.
|
"""Specify a parameter in `pytest.mark.parametrize`_ calls or
|
||||||
|
:ref:`parametrized fixtures <fixture-parametrize-marks>`.
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
from collections import namedtuple, MutableMapping as MappingMixin
|
|
||||||
import warnings
|
|
||||||
from operator import attrgetter
|
|
||||||
import inspect
|
import inspect
|
||||||
|
import warnings
|
||||||
|
from collections import namedtuple
|
||||||
|
from operator import attrgetter
|
||||||
|
|
||||||
import attr
|
import attr
|
||||||
|
|
||||||
from ..deprecated import MARK_PARAMETERSET_UNPACKING, MARK_INFO_ATTRIBUTE
|
from ..deprecated import MARK_PARAMETERSET_UNPACKING, MARK_INFO_ATTRIBUTE
|
||||||
from ..compat import NOTSET, getfslineno
|
from ..compat import NOTSET, getfslineno, MappingMixin
|
||||||
from six.moves import map, reduce
|
from six.moves import map, reduce
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ import math
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
import py
|
import py
|
||||||
|
from six import binary_type, text_type
|
||||||
from six.moves import zip, filterfalse
|
from six.moves import zip, filterfalse
|
||||||
from more_itertools.more import always_iterable
|
from more_itertools.more import always_iterable
|
||||||
|
|
||||||
|
@ -584,7 +585,8 @@ def raises(expected_exception, *args, **kwargs):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
__tracebackhide__ = True
|
__tracebackhide__ = True
|
||||||
for exc in filterfalse(isclass, always_iterable(expected_exception)):
|
base_type = (type, text_type, binary_type)
|
||||||
|
for exc in filterfalse(isclass, always_iterable(expected_exception, base_type)):
|
||||||
msg = ("exceptions must be old-style classes or"
|
msg = ("exceptions must be old-style classes or"
|
||||||
" derived from BaseException, not %s")
|
" derived from BaseException, not %s")
|
||||||
raise TypeError(msg % type(exc))
|
raise TypeError(msg % type(exc))
|
||||||
|
@ -597,6 +599,10 @@ def raises(expected_exception, *args, **kwargs):
|
||||||
message = kwargs.pop("message")
|
message = kwargs.pop("message")
|
||||||
if "match" in kwargs:
|
if "match" in kwargs:
|
||||||
match_expr = kwargs.pop("match")
|
match_expr = kwargs.pop("match")
|
||||||
|
if kwargs:
|
||||||
|
msg = 'Unexpected keyword arguments passed to pytest.raises: '
|
||||||
|
msg += ', '.join(kwargs.keys())
|
||||||
|
raise TypeError(msg)
|
||||||
return RaisesContext(expected_exception, message, match_expr)
|
return RaisesContext(expected_exception, message, match_expr)
|
||||||
elif isinstance(args[0], str):
|
elif isinstance(args[0], str):
|
||||||
code, = args
|
code, = args
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
New ``--show-capture`` command-line option that allows to specify how to display captured output when tests fail: ``no``, ``stdout``, ``stderr``, ``log`` or ``all`` (the default).
|
|
|
@ -1 +0,0 @@
|
||||||
New ``--rootdir`` command-line option to override the rules for discovering the root directory. See `customize <https://docs.pytest.org/en/latest/customize.html>`_ in the documentation for details.
|
|
|
@ -1 +0,0 @@
|
||||||
Added a `reference <https://docs.pytest.org/en/latest/reference.html>`_ page to the docs.
|
|
|
@ -1 +0,0 @@
|
||||||
Suppress ``IOError`` when closing the temporary file used for capturing streams in Python 2.7.
|
|
|
@ -1 +0,0 @@
|
||||||
Fixtures are now instantiated based on their scopes, with higher-scoped fixtures (such as ``session``) being instantiated first than lower-scoped fixtures (such as ``function``). The relative order of fixtures of the same scope is kept unchanged, based in their declaration order and their dependencies.
|
|
|
@ -1,2 +0,0 @@
|
||||||
``record_xml_property`` renamed to ``record_property`` and is now compatible with xdist, markers and any reporter.
|
|
||||||
``record_xml_property`` name is now deprecated.
|
|
|
@ -1 +0,0 @@
|
||||||
``record_xml_property`` fixture is now deprecated in favor of the more generic ``record_property``.
|
|
|
@ -0,0 +1 @@
|
||||||
|
A rare race-condition which might result in corrupted ``.pyc`` files on Windows has been hopefully solved.
|
|
@ -0,0 +1 @@
|
||||||
|
``pytest`` now depends on the `python-atomicwrites <https://github.com/untitaker/python-atomicwrites>`_ library.
|
|
@ -1 +0,0 @@
|
||||||
New ``--nf``, ``--new-first`` options: run new tests first followed by the rest of the tests, in both cases tests are also sorted by the file modified time, with more recent files coming first.
|
|
|
@ -1 +0,0 @@
|
||||||
Defining ``pytest_plugins`` is now deprecated in non-top-level conftest.py files, because they "leak" to the entire directory tree.
|
|
|
@ -1 +0,0 @@
|
||||||
New ``--last-failed-no-failures`` command-line option that allows to specify the behavior of the cache plugin's ```--last-failed`` feature when no tests failed in the last run (or no cache was found): ``none`` or ``all`` (the default).
|
|
|
@ -1 +0,0 @@
|
||||||
New ``--doctest-continue-on-failure`` command-line option to enable doctests to show multiple failures for each snippet, instead of stopping at the first failure.
|
|
|
@ -1 +0,0 @@
|
||||||
Captured log messages are added to the ``<system-out>`` tag in the generated junit xml file if the ``junit_logging`` ini option is set to ``system-out``. If the value of this ini option is ``system-err`, the logs are written to ``<system-err>``. The default value for ``junit_logging`` is ``no``, meaning captured logs are not written to the output file.
|
|
|
@ -1 +0,0 @@
|
||||||
Allow the logging plugin to handle ``pytest_runtest_logstart`` and ``pytest_runtest_logfinish`` hooks when live logs are enabled.
|
|
|
@ -1 +0,0 @@
|
||||||
Passing `--log-cli-level` in the command-line now automatically activates live logging.
|
|
|
@ -1 +0,0 @@
|
||||||
Add command line option ``--deselect`` to allow deselection of individual tests at collection time.
|
|
|
@ -1 +0,0 @@
|
||||||
Captured logs are printed before entering pdb.
|
|
|
@ -1 +0,0 @@
|
||||||
Deselected item count is now shown before tests are run, e.g. ``collected X items / Y deselected``.
|
|
|
@ -1 +0,0 @@
|
||||||
Change minimum requirement of ``attrs`` to ``17.4.0``.
|
|
|
@ -1 +0,0 @@
|
||||||
The builtin module ``platform`` is now available for use in expressions in ``pytest.mark``.
|
|
|
@ -1 +0,0 @@
|
||||||
Renamed example directories so all tests pass when ran from the base directory.
|
|
|
@ -1 +0,0 @@
|
||||||
Remove usage of deprecated ``metafunc.addcall`` in our own tests.
|
|
|
@ -1 +0,0 @@
|
||||||
Internal ``mark.py`` module has been turned into a package.
|
|
|
@ -1 +0,0 @@
|
||||||
The *short test summary info* section now is displayed after tracebacks and warnings in the terminal.
|
|
|
@ -1 +0,0 @@
|
||||||
``pytest`` now depends on the `more_itertools <https://github.com/erikrose/more-itertools>`_ package.
|
|
|
@ -1 +0,0 @@
|
||||||
Added warning when ``[pytest]`` section is used in a ``.cfg`` file passed with ``-c``
|
|
|
@ -1 +0,0 @@
|
||||||
``nodeids`` can now be passed explicitly to ``FSCollector`` and ``Node`` constructors.
|
|
|
@ -1 +0,0 @@
|
||||||
Internal refactoring of ``FormattedExcinfo`` to use ``attrs`` facilities and remove old support code for legacy Python versions.
|
|
|
@ -1 +0,0 @@
|
||||||
New ``--verbosity`` flag to set verbosity level explicitly.
|
|
|
@ -1 +0,0 @@
|
||||||
Refactoring to unify how verbosity is handled internally.
|
|
|
@ -1,2 +0,0 @@
|
||||||
Fixed ``clear()`` method on ``caplog`` fixture which cleared ``records``,
|
|
||||||
but not the ``text`` property.
|
|
|
@ -1 +0,0 @@
|
||||||
Internal refactoring to better integrate with argparse.
|
|
|
@ -1 +0,0 @@
|
||||||
Fix a python example when calling a fixture in doc/en/usage.rst
|
|
|
@ -1 +0,0 @@
|
||||||
``pytest.approx`` now accepts comparing a numpy array with a scalar.
|
|
|
@ -1,3 +0,0 @@
|
||||||
During test collection, when stdin is not allowed to be read, the
|
|
||||||
``DontReadFromStdin`` object still allow itself to be iterable and
|
|
||||||
resolved to an iterator without crashing.
|
|
|
@ -0,0 +1 @@
|
||||||
|
Import some modules from ``collections`` instead of ``collections.abc`` as the former modules trigger ``DeprecationWarning`` in Python 3.7.
|
|
@ -0,0 +1 @@
|
||||||
|
``pytest.raises`` now raises ``TypeError`` when receiving an unknown keyword argument.
|
|
@ -0,0 +1,2 @@
|
||||||
|
record_property is no longer experimental, removing the warnings was forgotten.
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
``pytest.raises`` now works with exception classes that look like iterables.
|
|
@ -2,7 +2,7 @@
|
||||||
Development Guide
|
Development Guide
|
||||||
=================
|
=================
|
||||||
|
|
||||||
Some general guidelines regarding development in pytest for core maintainers and general contributors. Nothing here
|
Some general guidelines regarding development in pytest for maintainers and contributors. Nothing here
|
||||||
is set in stone and can't be changed, feel free to suggest improvements or changes in the workflow.
|
is set in stone and can't be changed, feel free to suggest improvements or changes in the workflow.
|
||||||
|
|
||||||
|
|
||||||
|
@ -37,72 +37,19 @@ Any question, feature, bug or proposal is welcome as an issue. Users are encoura
|
||||||
GitHub issues should use labels to categorize them. Labels should be created sporadically, to fill a niche; we should
|
GitHub issues should use labels to categorize them. Labels should be created sporadically, to fill a niche; we should
|
||||||
avoid creating labels just for the sake of creating them.
|
avoid creating labels just for the sake of creating them.
|
||||||
|
|
||||||
Here is a list of labels and a brief description mentioning their intent.
|
Each label should include a description in the GitHub's interface stating its purpose.
|
||||||
|
|
||||||
|
Temporary labels
|
||||||
|
~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
**Type**
|
To classify issues for a special event it is encouraged to create a temporary label. This helps those involved to find
|
||||||
|
the relevant issues to work on. Examples of that are sprints in Python events or global hacking events.
|
||||||
|
|
||||||
* ``type: backward compatibility``: issue that will cause problems with old pytest versions.
|
* ``temporary: EP2017 sprint``: candidate issues or PRs tackled during the EuroPython 2017
|
||||||
* ``type: bug``: problem that needs to be addressed.
|
|
||||||
* ``type: deprecation``: feature that will be deprecated in the future.
|
|
||||||
* ``type: docs``: documentation missing or needing clarification.
|
|
||||||
* ``type: enhancement``: new feature or API change, should be merged into ``features``.
|
|
||||||
* ``type: feature-branch``: new feature or API change, should be merged into ``features``.
|
|
||||||
* ``type: infrastructure``: improvement to development/releases/CI structure.
|
|
||||||
* ``type: performance``: performance or memory problem/improvement.
|
|
||||||
* ``type: proposal``: proposal for a new feature, often to gather opinions or design the API around the new feature.
|
|
||||||
* ``type: question``: question regarding usage, installation, internals or how to test something.
|
|
||||||
* ``type: refactoring``: internal improvements to the code.
|
|
||||||
* ``type: regression``: indicates a problem that was introduced in a release which was working previously.
|
|
||||||
|
|
||||||
**Status**
|
Issues created at those events should have other relevant labels added as well.
|
||||||
|
|
||||||
* ``status: critical``: grave problem or usability issue that affects lots of users.
|
Those labels should be removed after they are no longer relevant.
|
||||||
* ``status: easy``: easy issue that is friendly to new contributors.
|
|
||||||
* ``status: help wanted``: core developers need help from experts on this topic.
|
|
||||||
* ``status: needs information``: reporter needs to provide more information; can be closed after 2 or more weeks of inactivity.
|
|
||||||
|
|
||||||
**Topic**
|
|
||||||
|
|
||||||
* ``topic: collection``
|
|
||||||
* ``topic: fixtures``
|
|
||||||
* ``topic: parametrize``
|
|
||||||
* ``topic: reporting``
|
|
||||||
* ``topic: selection``
|
|
||||||
* ``topic: tracebacks``
|
|
||||||
|
|
||||||
**Plugin (internal or external)**
|
|
||||||
|
|
||||||
* ``plugin: cache``
|
|
||||||
* ``plugin: capture``
|
|
||||||
* ``plugin: doctests``
|
|
||||||
* ``plugin: junitxml``
|
|
||||||
* ``plugin: monkeypatch``
|
|
||||||
* ``plugin: nose``
|
|
||||||
* ``plugin: pastebin``
|
|
||||||
* ``plugin: pytester``
|
|
||||||
* ``plugin: tmpdir``
|
|
||||||
* ``plugin: unittest``
|
|
||||||
* ``plugin: warnings``
|
|
||||||
* ``plugin: xdist``
|
|
||||||
|
|
||||||
|
|
||||||
**OS**
|
|
||||||
|
|
||||||
Issues specific to a single operating system. Do not use as a means to indicate where an issue originated from, only
|
|
||||||
for problems that happen **only** in that system.
|
|
||||||
|
|
||||||
* ``os: linux``
|
|
||||||
* ``os: mac``
|
|
||||||
* ``os: windows``
|
|
||||||
|
|
||||||
**Temporary**
|
|
||||||
|
|
||||||
Used to classify issues for limited time, to help find issues related in events for example.
|
|
||||||
They should be removed after they are no longer relevant.
|
|
||||||
|
|
||||||
* ``temporary: EP2017 sprint``:
|
|
||||||
* ``temporary: sprint-candidate``:
|
|
||||||
|
|
||||||
|
|
||||||
.. include:: ../../HOWTORELEASE.rst
|
.. include:: ../../HOWTORELEASE.rst
|
||||||
|
|
|
@ -358,7 +358,7 @@ get on the terminal - we are working on that)::
|
||||||
> int(s)
|
> int(s)
|
||||||
E ValueError: invalid literal for int() with base 10: 'qwe'
|
E ValueError: invalid literal for int() with base 10: 'qwe'
|
||||||
|
|
||||||
<0-codegen $PYTHON_PREFIX/lib/python3.5/site-packages/_pytest/python_api.py:609>:1: ValueError
|
<0-codegen $PYTHON_PREFIX/lib/python3.5/site-packages/_pytest/python_api.py:613>:1: ValueError
|
||||||
______________________ TestRaises.test_raises_doesnt _______________________
|
______________________ TestRaises.test_raises_doesnt _______________________
|
||||||
|
|
||||||
self = <failure_demo.TestRaises object at 0xdeadbeef>
|
self = <failure_demo.TestRaises object at 0xdeadbeef>
|
||||||
|
|
|
@ -294,7 +294,7 @@ The fixtures requested by ``test_foo`` will be instantiated in the following ord
|
||||||
|
|
||||||
1. ``s1``: is the highest-scoped fixture (``session``).
|
1. ``s1``: is the highest-scoped fixture (``session``).
|
||||||
2. ``m1``: is the second highest-scoped fixture (``module``).
|
2. ``m1``: is the second highest-scoped fixture (``module``).
|
||||||
3. ``tempdir``: is a ``function``-scoped fixture, required by ``f1``: it needs to be instantiated at this point
|
3. ``tmpdir``: is a ``function``-scoped fixture, required by ``f1``: it needs to be instantiated at this point
|
||||||
because it is a dependency of ``f1``.
|
because it is a dependency of ``f1``.
|
||||||
4. ``f1``: is the first ``function``-scoped fixture in ``test_foo`` parameter list.
|
4. ``f1``: is the first ``function``-scoped fixture in ``test_foo`` parameter list.
|
||||||
5. ``f2``: is the last ``function``-scoped fixture in ``test_foo`` parameter list.
|
5. ``f2``: is the last ``function``-scoped fixture in ``test_foo`` parameter list.
|
||||||
|
@ -623,6 +623,40 @@ Running the above tests results in the following test IDs being used::
|
||||||
|
|
||||||
======================= no tests ran in 0.12 seconds =======================
|
======================= no tests ran in 0.12 seconds =======================
|
||||||
|
|
||||||
|
.. _`fixture-parametrize-marks`:
|
||||||
|
|
||||||
|
Using marks with parametrized fixtures
|
||||||
|
--------------------------------------
|
||||||
|
|
||||||
|
:func:`pytest.param` can be used to apply marks in values sets of parametrized fixtures in the same way
|
||||||
|
that they can be used with :ref:`@pytest.mark.parametrize <@pytest.mark.parametrize>`.
|
||||||
|
|
||||||
|
Example::
|
||||||
|
|
||||||
|
# content of test_fixture_marks.py
|
||||||
|
import pytest
|
||||||
|
@pytest.fixture(params=[0, 1, pytest.param(2, marks=pytest.mark.skip)])
|
||||||
|
def data_set(request):
|
||||||
|
return request.param
|
||||||
|
|
||||||
|
def test_data(data_set):
|
||||||
|
pass
|
||||||
|
|
||||||
|
Running this test will *skip* the invocation of ``data_set`` with value ``2``::
|
||||||
|
|
||||||
|
$ pytest test_fixture_marks.py -v
|
||||||
|
=========================== test session starts ============================
|
||||||
|
platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python3.5
|
||||||
|
cachedir: .pytest_cache
|
||||||
|
rootdir: $REGENDOC_TMPDIR, inifile:
|
||||||
|
collecting ... collected 3 items
|
||||||
|
|
||||||
|
test_fixture_marks.py::test_data[0] PASSED [ 33%]
|
||||||
|
test_fixture_marks.py::test_data[1] PASSED [ 66%]
|
||||||
|
test_fixture_marks.py::test_data[2] SKIPPED [100%]
|
||||||
|
|
||||||
|
=================== 2 passed, 1 skipped in 0.12 seconds ====================
|
||||||
|
|
||||||
.. _`interdependent fixtures`:
|
.. _`interdependent fixtures`:
|
||||||
|
|
||||||
Modularity: using fixtures from a fixture function
|
Modularity: using fixtures from a fixture function
|
||||||
|
|
|
@ -529,6 +529,8 @@ Initialization hooks called for plugins and ``conftest.py`` files.
|
||||||
.. autofunction:: pytest_addhooks
|
.. autofunction:: pytest_addhooks
|
||||||
.. autofunction:: pytest_configure
|
.. autofunction:: pytest_configure
|
||||||
.. autofunction:: pytest_unconfigure
|
.. autofunction:: pytest_unconfigure
|
||||||
|
.. autofunction:: pytest_sessionstart
|
||||||
|
.. autofunction:: pytest_sessionfinish
|
||||||
|
|
||||||
Test running hooks
|
Test running hooks
|
||||||
~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~
|
||||||
|
|
|
@ -85,8 +85,8 @@ sub directory but not for other directories::
|
||||||
|
|
||||||
Here is how you might run it::
|
Here is how you might run it::
|
||||||
|
|
||||||
pytest test_flat.py # will not show "setting up"
|
pytest test_flat.py --capture=no # will not show "setting up"
|
||||||
pytest a/test_sub.py # will show "setting up"
|
pytest a/test_sub.py --capture=no # will show "setting up"
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
If you have ``conftest.py`` files which do not reside in a
|
If you have ``conftest.py`` files which do not reside in a
|
||||||
|
|
3
setup.py
3
setup.py
|
@ -60,7 +60,8 @@ def main():
|
||||||
'six>=1.10.0',
|
'six>=1.10.0',
|
||||||
'setuptools',
|
'setuptools',
|
||||||
'attrs>=17.4.0',
|
'attrs>=17.4.0',
|
||||||
'more_itertools>=4.0.0',
|
'more-itertools>=4.0.0',
|
||||||
|
'atomicwrites>=1.0',
|
||||||
]
|
]
|
||||||
# if _PYTEST_SETUP_SKIP_PLUGGY_DEP is set, skip installing pluggy;
|
# if _PYTEST_SETUP_SKIP_PLUGGY_DEP is set, skip installing pluggy;
|
||||||
# used by tox.ini to test with pluggy master
|
# used by tox.ini to test with pluggy master
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
from _pytest.outcomes import Failed
|
||||||
import pytest
|
import pytest
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
@ -61,6 +62,11 @@ class TestRaises(object):
|
||||||
with pytest.raises(TypeError):
|
with pytest.raises(TypeError):
|
||||||
pytest.raises('wrong', lambda: None)
|
pytest.raises('wrong', lambda: None)
|
||||||
|
|
||||||
|
def test_invalid_arguments_to_raises(self):
|
||||||
|
with pytest.raises(TypeError, match='unknown'):
|
||||||
|
with pytest.raises(TypeError, unknown='bogus'):
|
||||||
|
raise ValueError()
|
||||||
|
|
||||||
def test_tuple(self):
|
def test_tuple(self):
|
||||||
with pytest.raises((KeyError, ValueError)):
|
with pytest.raises((KeyError, ValueError)):
|
||||||
raise KeyError('oops')
|
raise KeyError('oops')
|
||||||
|
@ -142,3 +148,20 @@ class TestRaises(object):
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
with pytest.raises(IndexError, match='nomatch'):
|
with pytest.raises(IndexError, match='nomatch'):
|
||||||
int('asdf')
|
int('asdf')
|
||||||
|
|
||||||
|
def test_raises_exception_looks_iterable(self):
|
||||||
|
from six import add_metaclass
|
||||||
|
|
||||||
|
class Meta(type(object)):
|
||||||
|
def __getitem__(self, item):
|
||||||
|
return 1/0
|
||||||
|
|
||||||
|
def __len__(self):
|
||||||
|
return 1
|
||||||
|
|
||||||
|
@add_metaclass(Meta)
|
||||||
|
class ClassLooksIterableException(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
with pytest.raises(Failed, match="DID NOT RAISE <class 'raises.ClassLooksIterableException'>"):
|
||||||
|
pytest.raises(ClassLooksIterableException, lambda: None)
|
||||||
|
|
|
@ -839,22 +839,22 @@ class TestAssertionRewriteHookDetails(object):
|
||||||
def test_write_pyc(self, testdir, tmpdir, monkeypatch):
|
def test_write_pyc(self, testdir, tmpdir, monkeypatch):
|
||||||
from _pytest.assertion.rewrite import _write_pyc
|
from _pytest.assertion.rewrite import _write_pyc
|
||||||
from _pytest.assertion import AssertionState
|
from _pytest.assertion import AssertionState
|
||||||
try:
|
import atomicwrites
|
||||||
import __builtin__ as b
|
from contextlib import contextmanager
|
||||||
except ImportError:
|
|
||||||
import builtins as b
|
|
||||||
config = testdir.parseconfig([])
|
config = testdir.parseconfig([])
|
||||||
state = AssertionState(config, "rewrite")
|
state = AssertionState(config, "rewrite")
|
||||||
source_path = tmpdir.ensure("source.py")
|
source_path = tmpdir.ensure("source.py")
|
||||||
pycpath = tmpdir.join("pyc").strpath
|
pycpath = tmpdir.join("pyc").strpath
|
||||||
assert _write_pyc(state, [1], source_path.stat(), pycpath)
|
assert _write_pyc(state, [1], source_path.stat(), pycpath)
|
||||||
|
|
||||||
def open(*args):
|
@contextmanager
|
||||||
|
def atomic_write_failed(fn, mode='r', overwrite=False):
|
||||||
e = IOError()
|
e = IOError()
|
||||||
e.errno = 10
|
e.errno = 10
|
||||||
raise e
|
raise e
|
||||||
|
yield # noqa
|
||||||
|
|
||||||
monkeypatch.setattr(b, "open", open)
|
monkeypatch.setattr(atomicwrites, "atomic_write", atomic_write_failed)
|
||||||
assert not _write_pyc(state, [1], source_path.stat(), pycpath)
|
assert not _write_pyc(state, [1], source_path.stat(), pycpath)
|
||||||
|
|
||||||
def test_resources_provider_for_loader(self, testdir):
|
def test_resources_provider_for_loader(self, testdir):
|
||||||
|
|
|
@ -868,17 +868,13 @@ def test_record_property(testdir):
|
||||||
def test_record(record_property, other):
|
def test_record(record_property, other):
|
||||||
record_property("foo", "<1");
|
record_property("foo", "<1");
|
||||||
""")
|
""")
|
||||||
result, dom = runandparse(testdir, '-rw')
|
result, dom = runandparse(testdir, '-rwv')
|
||||||
node = dom.find_first_by_tag("testsuite")
|
node = dom.find_first_by_tag("testsuite")
|
||||||
tnode = node.find_first_by_tag("testcase")
|
tnode = node.find_first_by_tag("testcase")
|
||||||
psnode = tnode.find_first_by_tag('properties')
|
psnode = tnode.find_first_by_tag('properties')
|
||||||
pnodes = psnode.find_by_tag('property')
|
pnodes = psnode.find_by_tag('property')
|
||||||
pnodes[0].assert_attr(name="bar", value="1")
|
pnodes[0].assert_attr(name="bar", value="1")
|
||||||
pnodes[1].assert_attr(name="foo", value="<1")
|
pnodes[1].assert_attr(name="foo", value="<1")
|
||||||
result.stdout.fnmatch_lines([
|
|
||||||
'test_record_property.py::test_record',
|
|
||||||
'*record_property*experimental*',
|
|
||||||
])
|
|
||||||
|
|
||||||
|
|
||||||
def test_record_property_same_name(testdir):
|
def test_record_property_same_name(testdir):
|
||||||
|
|
|
@ -113,7 +113,7 @@ class TestDeprecatedCall(object):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
msg = 'Did not produce DeprecationWarning or PendingDeprecationWarning'
|
msg = 'Did not produce DeprecationWarning or PendingDeprecationWarning'
|
||||||
with pytest.raises(AssertionError, matches=msg):
|
with pytest.raises(AssertionError, match=msg):
|
||||||
if mode == 'call':
|
if mode == 'call':
|
||||||
pytest.deprecated_call(f)
|
pytest.deprecated_call(f)
|
||||||
else:
|
else:
|
||||||
|
|
Loading…
Reference in New Issue