Merge remote-tracking branch 'upstream/master' into merge-master-into-features

This commit is contained in:
Bruno Oliveira 2018-08-26 16:45:00 -03:00
commit 2f2d5861bb
65 changed files with 1299 additions and 909 deletions

View File

@ -5,13 +5,13 @@ repos:
hooks: hooks:
- id: black - id: black
args: [--safe, --quiet] args: [--safe, --quiet]
language_version: python3.6 language_version: python3
- repo: https://github.com/asottile/blacken-docs - repo: https://github.com/asottile/blacken-docs
rev: v0.2.0 rev: v0.2.0
hooks: hooks:
- id: blacken-docs - id: blacken-docs
additional_dependencies: [black==18.6b4] additional_dependencies: [black==18.6b4]
language_version: python3.6 language_version: python3
- repo: https://github.com/pre-commit/pre-commit-hooks - repo: https://github.com/pre-commit/pre-commit-hooks
rev: v1.3.0 rev: v1.3.0
hooks: hooks:
@ -37,7 +37,6 @@ repos:
files: ^(CHANGELOG.rst|HOWTORELEASE.rst|README.rst|changelog/.*)$ files: ^(CHANGELOG.rst|HOWTORELEASE.rst|README.rst|changelog/.*)$
language: python language: python
additional_dependencies: [pygments, restructuredtext_lint] additional_dependencies: [pygments, restructuredtext_lint]
python_version: python3.6
- id: changelogs-rst - id: changelogs-rst
name: changelog files must end in .rst name: changelog files must end in .rst
entry: ./scripts/fail entry: ./scripts/fail

View File

@ -62,12 +62,7 @@ jobs:
repo: pytest-dev/pytest repo: pytest-dev/pytest
- stage: linting - stage: linting
python: '3.6' python: '3.6'
env: env: TOXENV=linting
install:
- pip install pre-commit
- pre-commit install-hooks
script:
- pre-commit run --all-files
script: tox --recreate script: tox --recreate

View File

@ -98,6 +98,7 @@ Javier Domingo Cansino
Javier Romero Javier Romero
Jeff Rackauckas Jeff Rackauckas
Jeff Widman Jeff Widman
Jenni Rinker
John Eddie Ayson John Eddie Ayson
John Towler John Towler
Jon Sonesen Jon Sonesen

View File

@ -18,6 +18,61 @@ with advance notice in the **Deprecations** section of releases.
.. towncrier release notes start .. towncrier release notes start
pytest 3.7.3 (2018-08-26)
=========================
Bug Fixes
---------
- `#3033 <https://github.com/pytest-dev/pytest/issues/3033>`_: Fixtures during teardown can again use ``capsys`` and ``capfd`` to inspect output captured during tests.
- `#3773 <https://github.com/pytest-dev/pytest/issues/3773>`_: Fix collection of tests from ``__init__.py`` files if they match the ``python_files`` configuration option.
- `#3796 <https://github.com/pytest-dev/pytest/issues/3796>`_: Fix issue where teardown of fixtures of consecutive sub-packages were executed once, at the end of the outer
package.
- `#3816 <https://github.com/pytest-dev/pytest/issues/3816>`_: Fix bug where ``--show-capture=no`` option would still show logs printed during fixture teardown.
- `#3819 <https://github.com/pytest-dev/pytest/issues/3819>`_: Fix ``stdout/stderr`` not getting captured when real-time cli logging is active.
- `#3843 <https://github.com/pytest-dev/pytest/issues/3843>`_: Fix collection error when specifying test functions directly in the command line using ``test.py::test`` syntax together with ``--doctest-modules``.
- `#3848 <https://github.com/pytest-dev/pytest/issues/3848>`_: Fix bugs where unicode arguments could not be passed to ``testdir.runpytest`` on Python 2.
- `#3854 <https://github.com/pytest-dev/pytest/issues/3854>`_: Fix double collection of tests within packages when the filename starts with a capital letter.
Improved Documentation
----------------------
- `#3824 <https://github.com/pytest-dev/pytest/issues/3824>`_: Added example for multiple glob pattern matches in ``python_files``.
- `#3833 <https://github.com/pytest-dev/pytest/issues/3833>`_: Added missing docs for ``pytester.Testdir``.
- `#3870 <https://github.com/pytest-dev/pytest/issues/3870>`_: Correct documentation for setuptools integration.
Trivial/Internal Changes
------------------------
- `#3826 <https://github.com/pytest-dev/pytest/issues/3826>`_: Replace broken type annotations with type comments.
- `#3845 <https://github.com/pytest-dev/pytest/issues/3845>`_: Remove a reference to issue `#568 <https://github.com/pytest-dev/pytest/issues/568>`_ from the documentation, which has since been
fixed.
pytest 3.7.2 (2018-08-16) pytest 3.7.2 (2018-08-16)
========================= =========================

View File

@ -1,4 +1,4 @@
import py import six
for i in range(1000): for i in range(1000):
py.builtin.exec_("def test_func_%d(): pass" % i) six.exec_("def test_func_%d(): pass" % i)

View File

@ -1 +0,0 @@
Fix ``stdout/stderr`` not getting captured when real-time cli logging is active.

View File

@ -1 +0,0 @@
Replace broken type annotations with type comments.

View File

@ -6,6 +6,7 @@ Release announcements
:maxdepth: 2 :maxdepth: 2
release-3.7.3
release-3.7.2 release-3.7.2
release-3.7.1 release-3.7.1
release-3.7.0 release-3.7.0

View File

@ -0,0 +1,33 @@
pytest-3.7.3
=======================================
pytest 3.7.3 has just been released to PyPI.
This is a bug-fix release, being a drop-in replacement. To upgrade::
pip install --upgrade pytest
The full changelog is available at http://doc.pytest.org/en/latest/changelog.html.
Thanks to all who contributed to this release, among them:
* Andrew Champion
* Anthony Sottile
* Bruno Oliveira
* Daniel Hahler
* Gandalf Saxe
* Jennifer Rinker
* Natan Lao
* Ondřej Súkup
* Ronny Pfannschmidt
* Sankt Petersbug
* Tyler Richard
* Victor
* Vlad Shcherbina
* turturica
* victor
* wim glenn
Happy testing,
The pytest Development Team

View File

@ -1,6 +1,6 @@
from pytest import raises from pytest import raises
import _pytest._code import _pytest._code
import py import six
def otherfunc(a, b): def otherfunc(a, b):
@ -177,7 +177,7 @@ def test_dynamic_compile_shows_nicely():
name = "abc-123" name = "abc-123"
module = imp.new_module(name) module = imp.new_module(name)
code = _pytest._code.compile(src, name, "exec") code = _pytest._code.compile(src, name, "exec")
py.builtin.exec_(code, module.__dict__) six.exec_(code, module.__dict__)
sys.modules[name] = module sys.modules[name] = module
module.foo() module.foo()

View File

@ -10,4 +10,4 @@ def pytest_runtest_setup(item):
return return
mod = item.getparent(pytest.Module).obj mod = item.getparent(pytest.Module).obj
if hasattr(mod, "hello"): if hasattr(mod, "hello"):
print("mod.hello %r" % (mod.hello,)) print("mod.hello {!r}".format(mod.hello))

View File

@ -2,9 +2,10 @@
module containing a parametrized tests testing cross-python module containing a parametrized tests testing cross-python
serialization via the pickle module. serialization via the pickle module.
""" """
import textwrap
import py import py
import pytest import pytest
import _pytest._code
pythonlist = ["python2.7", "python3.4", "python3.5"] pythonlist = ["python2.7", "python3.4", "python3.5"]
@ -24,42 +25,44 @@ class Python(object):
def __init__(self, version, picklefile): def __init__(self, version, picklefile):
self.pythonpath = py.path.local.sysfind(version) self.pythonpath = py.path.local.sysfind(version)
if not self.pythonpath: if not self.pythonpath:
pytest.skip("%r not found" % (version,)) pytest.skip("{!r} not found".format(version))
self.picklefile = picklefile self.picklefile = picklefile
def dumps(self, obj): def dumps(self, obj):
dumpfile = self.picklefile.dirpath("dump.py") dumpfile = self.picklefile.dirpath("dump.py")
dumpfile.write( dumpfile.write(
_pytest._code.Source( textwrap.dedent(
""" """\
import pickle import pickle
f = open(%r, 'wb') f = open({!r}, 'wb')
s = pickle.dump(%r, f, protocol=2) s = pickle.dump({!r}, f, protocol=2)
f.close() f.close()
""" """.format(
% (str(self.picklefile), obj) str(self.picklefile), obj
)
) )
) )
py.process.cmdexec("%s %s" % (self.pythonpath, dumpfile)) py.process.cmdexec("{} {}".format(self.pythonpath, dumpfile))
def load_and_is_true(self, expression): def load_and_is_true(self, expression):
loadfile = self.picklefile.dirpath("load.py") loadfile = self.picklefile.dirpath("load.py")
loadfile.write( loadfile.write(
_pytest._code.Source( textwrap.dedent(
""" """\
import pickle import pickle
f = open(%r, 'rb') f = open({!r}, 'rb')
obj = pickle.load(f) obj = pickle.load(f)
f.close() f.close()
res = eval(%r) res = eval({!r})
if not res: if not res:
raise SystemExit(1) raise SystemExit(1)
""" """.format(
% (str(self.picklefile), expression) str(self.picklefile), expression
)
) )
) )
print(loadfile) print(loadfile)
py.process.cmdexec("%s %s" % (self.pythonpath, loadfile)) py.process.cmdexec("{} {}".format(self.pythonpath, loadfile))
@pytest.mark.parametrize("obj", [42, {}, {1: 3}]) @pytest.mark.parametrize("obj", [42, {}, {1: 3}])

View File

@ -413,7 +413,7 @@ Running it results in some skips if we don't have all the python interpreters in
. $ pytest -rs -q multipython.py . $ pytest -rs -q multipython.py
...sss...sssssssss...sss... [100%] ...sss...sssssssss...sss... [100%]
========================= short test summary info ========================== ========================= short test summary info ==========================
SKIP [15] $REGENDOC_TMPDIR/CWD/multipython.py:28: 'python3.4' not found SKIP [15] $REGENDOC_TMPDIR/CWD/multipython.py:29: 'python3.4' not found
12 passed, 15 skipped in 0.12 seconds 12 passed, 15 skipped in 0.12 seconds
Indirect parametrization of optional implementations/imports Indirect parametrization of optional implementations/imports

View File

@ -100,19 +100,21 @@ Changing naming conventions
You can configure different naming conventions by setting You can configure different naming conventions by setting
the :confval:`python_files`, :confval:`python_classes` and the :confval:`python_files`, :confval:`python_classes` and
:confval:`python_functions` configuration options. Example:: :confval:`python_functions` configuration options.
Here is an example::
# content of pytest.ini # content of pytest.ini
# Example 1: have pytest look for "check" instead of "test"
# can also be defined in tox.ini or setup.cfg file, although the section # can also be defined in tox.ini or setup.cfg file, although the section
# name in setup.cfg files should be "tool:pytest" # name in setup.cfg files should be "tool:pytest"
[pytest] [pytest]
python_files=check_*.py python_files = check_*.py
python_classes=Check python_classes = Check
python_functions=*_check python_functions = *_check
This would make ``pytest`` look for tests in files that match the ``check_* This would make ``pytest`` look for tests in files that match the ``check_*
.py`` glob-pattern, ``Check`` prefixes in classes, and functions and methods .py`` glob-pattern, ``Check`` prefixes in classes, and functions and methods
that match ``*_check``. For example, if we have:: that match ``*_check``. For example, if we have::
# content of check_myapp.py # content of check_myapp.py
class CheckMyApp(object): class CheckMyApp(object):
@ -121,7 +123,7 @@ that match ``*_check``. For example, if we have::
def complex_check(self): def complex_check(self):
pass pass
then the test collection looks like this:: The test collection would look like this::
$ pytest --collect-only $ pytest --collect-only
=========================== test session starts ============================ =========================== test session starts ============================
@ -136,11 +138,19 @@ then the test collection looks like this::
======================= no tests ran in 0.12 seconds ======================= ======================= no tests ran in 0.12 seconds =======================
You can check for multiple glob patterns by adding a space between the patterns::
# Example 2: have pytest look for files with "test" and "example"
# content of pytest.ini, tox.ini, or setup.cfg file (replace "pytest"
# with "tool:pytest" for setup.cfg)
[pytest]
python_files = test_*.py example_*.py
.. note:: .. note::
the ``python_functions`` and ``python_classes`` options has no effect the ``python_functions`` and ``python_classes`` options has no effect
for ``unittest.TestCase`` test discovery because pytest delegates for ``unittest.TestCase`` test discovery because pytest delegates
detection of test case methods to unittest code. discovery of test case methods to unittest code.
Interpreting cmdline arguments as Python packages Interpreting cmdline arguments as Python packages
----------------------------------------------------- -----------------------------------------------------

View File

@ -423,7 +423,7 @@ get on the terminal - we are working on that)::
name = "abc-123" name = "abc-123"
module = imp.new_module(name) module = imp.new_module(name)
code = _pytest._code.compile(src, name, "exec") code = _pytest._code.compile(src, name, "exec")
py.builtin.exec_(code, module.__dict__) six.exec_(code, module.__dict__)
sys.modules[name] = module sys.modules[name] = module
> module.foo() > module.foo()

View File

@ -4,6 +4,27 @@
Good Integration Practices Good Integration Practices
================================================= =================================================
Install package with pip
-------------------------------------------------
For development, we recommend to use virtualenv_ environments and pip_
for installing your application and any dependencies
as well as the ``pytest`` package itself. This ensures your code and
dependencies are isolated from the system Python installation.
First you need to place a ``setup.py`` file in the root of your package with the following minimum content::
from setuptools import setup, find_packages
setup(name="PACKAGENAME", packages=find_packages())
Where ``PACKAGENAME`` is the name of your package. You can then install your package in "editable" mode by running from the same directory::
pip install -e .
which lets you change your source code (both tests and application) and rerun tests at will.
This is similar to running ``python setup.py develop`` or ``conda develop`` in that it installs
your package using a symlink to your development code.
.. _`test discovery`: .. _`test discovery`:
.. _`Python test discovery`: .. _`Python test discovery`:
@ -177,19 +198,6 @@ Note that this layout also works in conjunction with the ``src`` layout mentione
tox tox
------ ------
For development, we recommend to use virtualenv_ environments and pip_
for installing your application and any dependencies
as well as the ``pytest`` package itself. This ensures your code and
dependencies are isolated from the system Python installation.
You can then install your package in "editable" mode::
pip install -e .
which lets you change your source code (both tests and application) and rerun tests at will.
This is similar to running ``python setup.py develop`` or ``conda develop`` in that it installs
your package using a symlink to your development code.
Once you are done with your work and want to make sure that your actual Once you are done with your work and want to make sure that your actual
package passes all tests you may want to look into `tox`_, the package passes all tests you may want to look into `tox`_, the
virtualenv test automation tool and its `pytest support virtualenv test automation tool and its `pytest support
@ -282,7 +290,7 @@ your own setuptools Test command for invoking pytest.
setup( setup(
# ..., # ...,
tests_require=["pytest"], tests_require=["pytest"],
cmdclass={"test": PyTest}, cmdclass={"pytest": PyTest},
) )
Now if you run:: Now if you run::

View File

@ -460,7 +460,7 @@ To use it, include in your top-most ``conftest.py`` file::
.. autoclass:: Testdir() .. autoclass:: Testdir()
:members: runpytest,runpytest_subprocess,runpytest_inprocess,makeconftest,makepyfile :members:
.. autoclass:: RunResult() .. autoclass:: RunResult()
:members: :members:
@ -1234,7 +1234,8 @@ passed multiple times. The expected format is ``name=value``. For example::
.. confval:: python_classes .. confval:: python_classes
One or more name prefixes or glob-style patterns determining which classes One or more name prefixes or glob-style patterns determining which classes
are considered for test collection. By default, pytest will consider any are considered for test collection. Search for multiple glob patterns by
adding a space between patterns. By default, pytest will consider any
class prefixed with ``Test`` as a test collection. Here is an example of how class prefixed with ``Test`` as a test collection. Here is an example of how
to collect tests from classes that end in ``Suite``: to collect tests from classes that end in ``Suite``:
@ -1251,15 +1252,23 @@ passed multiple times. The expected format is ``name=value``. For example::
.. confval:: python_files .. confval:: python_files
One or more Glob-style file patterns determining which python files One or more Glob-style file patterns determining which python files
are considered as test modules. By default, pytest will consider are considered as test modules. Search for multiple glob patterns by
any file matching with ``test_*.py`` and ``*_test.py`` globs as a test adding a space between patterns::
module.
.. code-block:: ini
[pytest]
python_files = test_*.py check_*.py example_*.py
By default, pytest will consider any file matching with ``test_*.py``
and ``*_test.py`` globs as a test module.
.. confval:: python_functions .. confval:: python_functions
One or more name prefixes or glob-patterns determining which test functions One or more name prefixes or glob-patterns determining which test functions
and methods are considered tests. By default, pytest will consider any and methods are considered tests. Search for multiple glob patterns by
adding a space between patterns. By default, pytest will consider any
function prefixed with ``test`` as a test. Here is an example of how function prefixed with ``test`` as a test. Here is an example of how
to collect test functions and methods that end in ``_test``: to collect test functions and methods that end in ``_test``:

View File

@ -136,12 +136,6 @@ You can use the ``skipif`` marker (as any other marker) on classes::
If the condition is ``True``, this marker will produce a skip result for If the condition is ``True``, this marker will produce a skip result for
each of the test methods of that class. each of the test methods of that class.
.. warning::
The use of ``skipif`` on classes that use inheritance is strongly
discouraged. `A Known bug <https://github.com/pytest-dev/pytest/issues/568>`_
in pytest's markers may cause unexpected behavior in super classes.
If you want to skip all test functions of a module, you may use If you want to skip all test functions of a module, you may use
the ``pytestmark`` name on the global level: the ``pytestmark`` name on the global level:

View File

@ -2,7 +2,7 @@
# CHANGES: # CHANGES:
# - some_str is replaced, trying to create unicode strings # - some_str is replaced, trying to create unicode strings
# #
from __future__ import absolute_import, division, print_function from __future__ import absolute_import, division, print_function, unicode_literals
import types import types
from six import text_type from six import text_type
@ -51,17 +51,17 @@ def format_exception_only(etype, value):
pass pass
else: else:
filename = filename or "<string>" filename = filename or "<string>"
lines.append(' File "%s", line %d\n' % (filename, lineno)) lines.append(' File "{}", line {}\n'.format(filename, lineno))
if badline is not None: if badline is not None:
if isinstance(badline, bytes): # python 2 only if isinstance(badline, bytes): # python 2 only
badline = badline.decode("utf-8", "replace") badline = badline.decode("utf-8", "replace")
lines.append(u" %s\n" % badline.strip()) lines.append(" {}\n".format(badline.strip()))
if offset is not None: if offset is not None:
caretspace = badline.rstrip("\n")[:offset].lstrip() caretspace = badline.rstrip("\n")[:offset].lstrip()
# non-space whitespace (likes tabs) must be kept for alignment # non-space whitespace (likes tabs) must be kept for alignment
caretspace = ((c.isspace() and c or " ") for c in caretspace) caretspace = ((c.isspace() and c or " ") for c in caretspace)
# only three spaces to account for offset1 == pos 0 # only three spaces to account for offset1 == pos 0
lines.append(" %s^\n" % "".join(caretspace)) lines.append(" {}^\n".format("".join(caretspace)))
value = msg value = msg
lines.append(_format_final_exc_line(stype, value)) lines.append(_format_final_exc_line(stype, value))
@ -72,9 +72,9 @@ def _format_final_exc_line(etype, value):
"""Return a list of a single line -- normal case for format_exception_only""" """Return a list of a single line -- normal case for format_exception_only"""
valuestr = _some_str(value) valuestr = _some_str(value)
if value is None or not valuestr: if value is None or not valuestr:
line = "%s\n" % etype line = "{}\n".format(etype)
else: else:
line = "%s: %s\n" % (etype, valuestr) line = "{}: {}\n".format(etype, valuestr)
return line return line
@ -83,7 +83,7 @@ def _some_str(value):
return text_type(value) return text_type(value)
except Exception: except Exception:
try: try:
return str(value) return bytes(value).decode("UTF-8", "replace")
except Exception: except Exception:
pass pass
return "<unprintable %s object>" % type(value).__name__ return "<unprintable {} object>".format(type(value).__name__)

View File

@ -11,6 +11,7 @@ from weakref import ref
from _pytest.compat import _PY2, _PY3, PY35, safe_str from _pytest.compat import _PY2, _PY3, PY35, safe_str
from six import text_type from six import text_type
import py import py
import six
builtin_repr = repr builtin_repr = repr
@ -128,7 +129,7 @@ class Frame(object):
""" """
f_locals = self.f_locals.copy() f_locals = self.f_locals.copy()
f_locals.update(vars) f_locals.update(vars)
py.builtin.exec_(code, self.f_globals, f_locals) six.exec_(code, self.f_globals, f_locals)
def repr(self, object): def repr(self, object):
""" return a 'safe' (non-recursive, one-line) string repr for 'object' """ return a 'safe' (non-recursive, one-line) string repr for 'object'

View File

@ -223,7 +223,7 @@ class AssertionRewritingHook(object):
mod.__loader__ = self mod.__loader__ = self
# Normally, this attribute is 3.4+ # Normally, this attribute is 3.4+
mod.__spec__ = spec_from_file_location(name, co.co_filename, loader=self) mod.__spec__ = spec_from_file_location(name, co.co_filename, loader=self)
py.builtin.exec_(co, mod.__dict__) six.exec_(co, mod.__dict__)
except: # noqa except: # noqa
if name in sys.modules: if name in sys.modules:
del sys.modules[name] del sys.modules[name]
@ -402,12 +402,11 @@ def _saferepr(obj):
JSON reprs. JSON reprs.
""" """
repr = py.io.saferepr(obj) r = py.io.saferepr(obj)
if isinstance(repr, six.text_type): if isinstance(r, six.text_type):
t = six.text_type return r.replace(u"\n", u"\\n")
else: else:
t = six.binary_type return r.replace(b"\n", b"\\n")
return repr.replace(t("\n"), t("\\n"))
from _pytest.assertion.util import format_explanation as _format_explanation # noqa from _pytest.assertion.util import format_explanation as _format_explanation # noqa
@ -446,10 +445,9 @@ def _should_repr_global_name(obj):
def _format_boolop(explanations, is_or): def _format_boolop(explanations, is_or):
explanation = "(" + (is_or and " or " or " and ").join(explanations) + ")" explanation = "(" + (is_or and " or " or " and ").join(explanations) + ")"
if isinstance(explanation, six.text_type): if isinstance(explanation, six.text_type):
t = six.text_type return explanation.replace(u"%", u"%%")
else: else:
t = six.binary_type return explanation.replace(b"%", b"%%")
return explanation.replace(t("%"), t("%%"))
def _call_reprcompare(ops, results, expls, each_obj): def _call_reprcompare(ops, results, expls, each_obj):

View File

@ -187,9 +187,9 @@ def _diff_text(left, right, verbose=False):
r = r.replace(r"\r", "\r") r = r.replace(r"\r", "\r")
return r return r
if isinstance(left, six.binary_type): if isinstance(left, bytes):
left = escape_for_readable_diff(left) left = escape_for_readable_diff(left)
if isinstance(right, six.binary_type): if isinstance(right, bytes):
right = escape_for_readable_diff(right) right = escape_for_readable_diff(right)
if not verbose: if not verbose:
i = 0 # just in case left or right has zero length i = 0 # just in case left or right has zero length

View File

@ -14,7 +14,7 @@ from tempfile import TemporaryFile
import six import six
import pytest import pytest
from _pytest.compat import CaptureIO, dummy_context_manager from _pytest.compat import CaptureIO
patchsysdict = {0: "stdin", 1: "stdout", 2: "stderr"} patchsysdict = {0: "stdin", 1: "stdout", 2: "stderr"}
@ -62,8 +62,9 @@ def pytest_load_initial_conftests(early_config, parser, args):
# finally trigger conftest loading but while capturing (issue93) # finally trigger conftest loading but while capturing (issue93)
capman.start_global_capturing() capman.start_global_capturing()
outcome = yield outcome = yield
out, err = capman.suspend_global_capture() capman.suspend_global_capture()
if outcome.excinfo is not None: if outcome.excinfo is not None:
out, err = capman.read_global_capture()
sys.stdout.write(out) sys.stdout.write(out)
sys.stderr.write(err) sys.stderr.write(err)
@ -96,6 +97,8 @@ class CaptureManager(object):
else: else:
raise ValueError("unknown capturing method: %r" % method) raise ValueError("unknown capturing method: %r" % method)
# Global capturing control
def start_global_capturing(self): def start_global_capturing(self):
assert self._global_capturing is None assert self._global_capturing is None
self._global_capturing = self._getcapture(self._method) self._global_capturing = self._getcapture(self._method)
@ -110,29 +113,15 @@ class CaptureManager(object):
def resume_global_capture(self): def resume_global_capture(self):
self._global_capturing.resume_capturing() self._global_capturing.resume_capturing()
def suspend_global_capture(self, item=None, in_=False): def suspend_global_capture(self, in_=False):
if item is not None:
self.deactivate_fixture(item)
cap = getattr(self, "_global_capturing", None) cap = getattr(self, "_global_capturing", None)
if cap is not None: if cap is not None:
try: cap.suspend_capturing(in_=in_)
outerr = cap.readouterr()
finally:
cap.suspend_capturing(in_=in_)
return outerr
@contextlib.contextmanager def read_global_capture(self):
def global_and_fixture_disabled(self): return self._global_capturing.readouterr()
"""Context manager to temporarily disables global and current fixture capturing."""
# Need to undo local capsys-et-al if exists before disabling global capture # Fixture Control (its just forwarding, think about removing this later)
fixture = getattr(self._current_item, "_capture_fixture", None)
ctx_manager = fixture._suspend() if fixture else dummy_context_manager()
with ctx_manager:
self.suspend_global_capture(item=None, in_=False)
try:
yield
finally:
self.resume_global_capture()
def activate_fixture(self, item): def activate_fixture(self, item):
"""If the current item is using ``capsys`` or ``capfd``, activate them so they take precedence over """If the current item is using ``capsys`` or ``capfd``, activate them so they take precedence over
@ -148,12 +137,53 @@ class CaptureManager(object):
if fixture is not None: if fixture is not None:
fixture.close() fixture.close()
def suspend_fixture(self, item):
fixture = getattr(item, "_capture_fixture", None)
if fixture is not None:
fixture._suspend()
def resume_fixture(self, item):
fixture = getattr(item, "_capture_fixture", None)
if fixture is not None:
fixture._resume()
# Helper context managers
@contextlib.contextmanager
def global_and_fixture_disabled(self):
"""Context manager to temporarily disables global and current fixture capturing."""
# Need to undo local capsys-et-al if exists before disabling global capture
self.suspend_fixture(self._current_item)
self.suspend_global_capture(in_=False)
try:
yield
finally:
self.resume_global_capture()
self.resume_fixture(self._current_item)
@contextlib.contextmanager
def item_capture(self, when, item):
self.resume_global_capture()
self.activate_fixture(item)
try:
yield
finally:
self.deactivate_fixture(item)
self.suspend_global_capture(in_=False)
out, err = self.read_global_capture()
item.add_report_section(when, "stdout", out)
item.add_report_section(when, "stderr", err)
# Hooks
@pytest.hookimpl(hookwrapper=True) @pytest.hookimpl(hookwrapper=True)
def pytest_make_collect_report(self, collector): def pytest_make_collect_report(self, collector):
if isinstance(collector, pytest.File): if isinstance(collector, pytest.File):
self.resume_global_capture() self.resume_global_capture()
outcome = yield outcome = yield
out, err = self.suspend_global_capture() self.suspend_global_capture()
out, err = self.read_global_capture()
rep = outcome.get_result() rep = outcome.get_result()
if out: if out:
rep.sections.append(("Captured stdout", out)) rep.sections.append(("Captured stdout", out))
@ -163,35 +193,25 @@ class CaptureManager(object):
yield yield
@pytest.hookimpl(hookwrapper=True) @pytest.hookimpl(hookwrapper=True)
def pytest_runtest_setup(self, item): def pytest_runtest_protocol(self, item):
self._current_item = item self._current_item = item
self.resume_global_capture()
# no need to activate a capture fixture because they activate themselves during creation; this
# only makes sense when a fixture uses a capture fixture, otherwise the capture fixture will
# be activated during pytest_runtest_call
yield yield
self.suspend_capture_item(item, "setup")
self._current_item = None self._current_item = None
@pytest.hookimpl(hookwrapper=True)
def pytest_runtest_setup(self, item):
with self.item_capture("setup", item):
yield
@pytest.hookimpl(hookwrapper=True) @pytest.hookimpl(hookwrapper=True)
def pytest_runtest_call(self, item): def pytest_runtest_call(self, item):
self._current_item = item with self.item_capture("call", item):
self.resume_global_capture() yield
# it is important to activate this fixture during the call phase so it overwrites the "global"
# capture
self.activate_fixture(item)
yield
self.suspend_capture_item(item, "call")
self._current_item = None
@pytest.hookimpl(hookwrapper=True) @pytest.hookimpl(hookwrapper=True)
def pytest_runtest_teardown(self, item): def pytest_runtest_teardown(self, item):
self._current_item = item with self.item_capture("teardown", item):
self.resume_global_capture() yield
self.activate_fixture(item)
yield
self.suspend_capture_item(item, "teardown")
self._current_item = None
@pytest.hookimpl(tryfirst=True) @pytest.hookimpl(tryfirst=True)
def pytest_keyboard_interrupt(self, excinfo): def pytest_keyboard_interrupt(self, excinfo):
@ -201,11 +221,6 @@ class CaptureManager(object):
def pytest_internalerror(self, excinfo): def pytest_internalerror(self, excinfo):
self.stop_global_capturing() self.stop_global_capturing()
def suspend_capture_item(self, item, when, in_=False):
out, err = self.suspend_global_capture(item, in_=in_)
item.add_report_section(when, "stdout", out)
item.add_report_section(when, "stderr", err)
capture_fixtures = {"capfd", "capfdbinary", "capsys", "capsysbinary"} capture_fixtures = {"capfd", "capfdbinary", "capsys", "capsysbinary"}
@ -309,37 +324,47 @@ class CaptureFixture(object):
def __init__(self, captureclass, request): def __init__(self, captureclass, request):
self.captureclass = captureclass self.captureclass = captureclass
self.request = request self.request = request
self._capture = None
self._captured_out = self.captureclass.EMPTY_BUFFER
self._captured_err = self.captureclass.EMPTY_BUFFER
def _start(self): def _start(self):
self._capture = MultiCapture( # Start if not started yet
out=True, err=True, in_=False, Capture=self.captureclass if getattr(self, "_capture", None) is None:
) self._capture = MultiCapture(
self._capture.start_capturing() out=True, err=True, in_=False, Capture=self.captureclass
)
self._capture.start_capturing()
def close(self): def close(self):
cap = self.__dict__.pop("_capture", None) if self._capture is not None:
if cap is not None: out, err = self._capture.pop_outerr_to_orig()
self._outerr = cap.pop_outerr_to_orig() self._captured_out += out
cap.stop_capturing() self._captured_err += err
self._capture.stop_capturing()
self._capture = None
def readouterr(self): def readouterr(self):
"""Read and return the captured output so far, resetting the internal buffer. """Read and return the captured output so far, resetting the internal buffer.
:return: captured content as a namedtuple with ``out`` and ``err`` string attributes :return: captured content as a namedtuple with ``out`` and ``err`` string attributes
""" """
try: captured_out, captured_err = self._captured_out, self._captured_err
return self._capture.readouterr() if self._capture is not None:
except AttributeError: out, err = self._capture.readouterr()
return self._outerr captured_out += out
captured_err += err
self._captured_out = self.captureclass.EMPTY_BUFFER
self._captured_err = self.captureclass.EMPTY_BUFFER
return CaptureResult(captured_out, captured_err)
@contextlib.contextmanager
def _suspend(self): def _suspend(self):
"""Suspends this fixture's own capturing temporarily.""" """Suspends this fixture's own capturing temporarily."""
self._capture.suspend_capturing() self._capture.suspend_capturing()
try:
yield def _resume(self):
finally: """Resumes this fixture's own capturing temporarily."""
self._capture.resume_capturing() self._capture.resume_capturing()
@contextlib.contextmanager @contextlib.contextmanager
def disabled(self): def disabled(self):
@ -463,6 +488,7 @@ class MultiCapture(object):
class NoCapture(object): class NoCapture(object):
EMPTY_BUFFER = None
__init__ = start = done = suspend = resume = lambda *args: None __init__ = start = done = suspend = resume = lambda *args: None
@ -472,6 +498,8 @@ class FDCaptureBinary(object):
snap() produces `bytes` snap() produces `bytes`
""" """
EMPTY_BUFFER = bytes()
def __init__(self, targetfd, tmpfile=None): def __init__(self, targetfd, tmpfile=None):
self.targetfd = targetfd self.targetfd = targetfd
try: try:
@ -545,6 +573,8 @@ class FDCapture(FDCaptureBinary):
snap() produces text snap() produces text
""" """
EMPTY_BUFFER = str()
def snap(self): def snap(self):
res = FDCaptureBinary.snap(self) res = FDCaptureBinary.snap(self)
enc = getattr(self.tmpfile, "encoding", None) enc = getattr(self.tmpfile, "encoding", None)
@ -554,6 +584,9 @@ class FDCapture(FDCaptureBinary):
class SysCapture(object): class SysCapture(object):
EMPTY_BUFFER = str()
def __init__(self, fd, tmpfile=None): def __init__(self, fd, tmpfile=None):
name = patchsysdict[fd] name = patchsysdict[fd]
self._old = getattr(sys, name) self._old = getattr(sys, name)
@ -591,6 +624,8 @@ class SysCapture(object):
class SysCaptureBinary(SysCapture): class SysCaptureBinary(SysCapture):
EMPTY_BUFFER = bytes()
def snap(self): def snap(self):
res = self.tmpfile.buffer.getvalue() res = self.tmpfile.buffer.getvalue()
self.tmpfile.seek(0) self.tmpfile.seek(0)

View File

@ -2,6 +2,8 @@ import six
import warnings import warnings
import argparse import argparse
import py
FILE_OR_DIR = "file_or_dir" FILE_OR_DIR = "file_or_dir"
@ -70,7 +72,8 @@ class Parser(object):
self.optparser = self._getparser() self.optparser = self._getparser()
try_argcomplete(self.optparser) try_argcomplete(self.optparser)
return self.optparser.parse_args([str(x) for x in args], namespace=namespace) args = [str(x) if isinstance(x, py.path.local) else x for x in args]
return self.optparser.parse_args(args, namespace=namespace)
def _getparser(self): def _getparser(self):
from _pytest._argcomplete import filescompleter from _pytest._argcomplete import filescompleter
@ -106,7 +109,7 @@ class Parser(object):
the remaining arguments unknown at this point. the remaining arguments unknown at this point.
""" """
optparser = self._getparser() optparser = self._getparser()
args = [str(x) for x in args] args = [str(x) if isinstance(x, py.path.local) else x for x in args]
return optparser.parse_known_args(args, namespace=namespace) return optparser.parse_known_args(args, namespace=namespace)
def addini(self, name, help, type=None, default=None): def addini(self, name, help, type=None, default=None):

View File

@ -102,7 +102,8 @@ class PdbInvoke(object):
def pytest_exception_interact(self, node, call, report): def pytest_exception_interact(self, node, call, report):
capman = node.config.pluginmanager.getplugin("capturemanager") capman = node.config.pluginmanager.getplugin("capturemanager")
if capman: if capman:
out, err = capman.suspend_global_capture(in_=True) capman.suspend_global_capture(in_=True)
out, err = capman.read_global_capture()
sys.stdout.write(out) sys.stdout.write(out)
sys.stdout.write(err) sys.stdout.write(err)
_enter_pdb(node, call.excinfo, report) _enter_pdb(node, call.excinfo, report)

View File

@ -2,7 +2,6 @@ from __future__ import absolute_import, division, print_function
import functools import functools
import inspect import inspect
import os
import sys import sys
import warnings import warnings
from collections import OrderedDict, deque, defaultdict from collections import OrderedDict, deque, defaultdict
@ -93,7 +92,7 @@ def get_scope_package(node, fixturedef):
cls = pytest.Package cls = pytest.Package
current = node current = node
fixture_package_name = os.path.join(fixturedef.baseid, "__init__.py") fixture_package_name = "%s/%s" % (fixturedef.baseid, "__init__.py")
while current and ( while current and (
type(current) is not cls or fixture_package_name != current.nodeid type(current) is not cls or fixture_package_name != current.nodeid
): ):
@ -858,7 +857,7 @@ class FixtureDef(object):
if exceptions: if exceptions:
e = exceptions[0] e = exceptions[0]
del exceptions # ensure we don't keep all frames alive because of the traceback del exceptions # ensure we don't keep all frames alive because of the traceback
py.builtin._reraise(*e) six.reraise(*e)
finally: finally:
hook = self._fixturemanager.session.gethookproxy(request.node.fspath) hook = self._fixturemanager.session.gethookproxy(request.node.fspath)
@ -885,7 +884,7 @@ class FixtureDef(object):
result, cache_key, err = cached_result result, cache_key, err = cached_result
if my_cache_key == cache_key: if my_cache_key == cache_key:
if err is not None: if err is not None:
py.builtin._reraise(*err) six.reraise(*err)
else: else:
return result return result
# we have a previous but differently parametrized fixture instance # we have a previous but differently parametrized fixture instance

View File

@ -625,11 +625,12 @@ class Session(nodes.FSCollector):
resultnodes.append(node) resultnodes.append(node)
continue continue
assert isinstance(node, nodes.Collector) assert isinstance(node, nodes.Collector)
if node.nodeid in self._node_cache: key = (type(node), node.nodeid)
rep = self._node_cache[node.nodeid] if key in self._node_cache:
rep = self._node_cache[key]
else: else:
rep = collect_one_node(node) rep = collect_one_node(node)
self._node_cache[node.nodeid] = rep self._node_cache[key] = rep
if rep.passed: if rep.passed:
has_matched = False has_matched = False
for x in rep.result: for x in rep.result:

View File

@ -3,7 +3,6 @@ exception classes and constants handling test outcomes
as well as functions creating them as well as functions creating them
""" """
from __future__ import absolute_import, division, print_function from __future__ import absolute_import, division, print_function
import py
import sys import sys
@ -21,7 +20,7 @@ class OutcomeException(BaseException):
if self.msg: if self.msg:
val = self.msg val = self.msg
if isinstance(val, bytes): if isinstance(val, bytes):
val = py._builtin._totext(val, errors="replace") val = val.decode("UTF-8", errors="replace")
return val return val
return "<%s instance>" % (self.__class__.__name__,) return "<%s instance>" % (self.__class__.__name__,)

View File

@ -22,6 +22,7 @@ import pytest
from _pytest.main import Session, EXIT_OK from _pytest.main import Session, EXIT_OK
from _pytest.assertion.rewrite import AssertionRewritingHook from _pytest.assertion.rewrite import AssertionRewritingHook
from _pytest.compat import Path from _pytest.compat import Path
from _pytest.compat import safe_str
IGNORE_PAM = [ # filenames added when obtaining details about the current user IGNORE_PAM = [ # filenames added when obtaining details about the current user
u"/var/lib/sss/mc/passwd" u"/var/lib/sss/mc/passwd"
@ -34,7 +35,7 @@ def pytest_addoption(parser):
action="store_true", action="store_true",
dest="lsof", dest="lsof",
default=False, default=False,
help=("run FD checks if lsof is available"), help="run FD checks if lsof is available",
) )
parser.addoption( parser.addoption(
@ -273,7 +274,7 @@ class HookRecorder(object):
del self.calls[i] del self.calls[i]
return call return call
lines = ["could not find call %r, in:" % (name,)] lines = ["could not find call %r, in:" % (name,)]
lines.extend([" %s" % str(x) for x in self.calls]) lines.extend([" %s" % x for x in self.calls])
pytest.fail("\n".join(lines)) pytest.fail("\n".join(lines))
def getcall(self, name): def getcall(self, name):
@ -560,18 +561,22 @@ class Testdir(object):
return ret return ret
def makefile(self, ext, *args, **kwargs): def makefile(self, ext, *args, **kwargs):
"""Create a new file in the testdir. r"""Create new file(s) in the testdir.
ext: The extension the file should use, including the dot, e.g. `.py`. :param str ext: The extension the file(s) should use, including the dot, e.g. `.py`.
:param list[str] args: All args will be treated as strings and joined using newlines.
args: All args will be treated as strings and joined using newlines.
The result will be written as contents to the file. The name of the The result will be written as contents to the file. The name of the
file will be based on the test function requesting this fixture. file will be based on the test function requesting this fixture.
E.g. "testdir.makefile('.txt', 'line1', 'line2')" :param kwargs: Each keyword is the name of a file, while the value of it will
kwargs: Each keyword is the name of a file, while the value of it will
be written as contents of the file. be written as contents of the file.
E.g. "testdir.makefile('.ini', pytest='[pytest]\naddopts=-rs\n')"
Examples:
.. code-block:: python
testdir.makefile(".txt", "line1", "line2")
testdir.makefile(".ini", pytest="[pytest]\naddopts=-rs\n")
""" """
return self._makefile(ext, args, kwargs) return self._makefile(ext, args, kwargs)
@ -677,7 +682,9 @@ class Testdir(object):
example_path.copy(result) example_path.copy(result)
return result return result
else: else:
raise LookupError("example is not found as a file or directory") raise LookupError(
'example "{}" is not found as a file or directory'.format(example_path)
)
Session = Session Session = Session
@ -891,14 +898,12 @@ class Testdir(object):
return self._runpytest_method(*args, **kwargs) return self._runpytest_method(*args, **kwargs)
def _ensure_basetemp(self, args): def _ensure_basetemp(self, args):
args = [str(x) for x in args] args = list(args)
for x in args: for x in args:
if str(x).startswith("--basetemp"): if safe_str(x).startswith("--basetemp"):
# print("basedtemp exists: %s" %(args,))
break break
else: else:
args.append("--basetemp=%s" % self.tmpdir.dirpath("basetemp")) args.append("--basetemp=%s" % self.tmpdir.dirpath("basetemp"))
# print("added basetemp: %s" %(args,))
return args return args
def parseconfig(self, *args): def parseconfig(self, *args):
@ -1024,7 +1029,7 @@ class Testdir(object):
""" """
env = os.environ.copy() env = os.environ.copy()
env["PYTHONPATH"] = os.pathsep.join( env["PYTHONPATH"] = os.pathsep.join(
filter(None, [str(os.getcwd()), env.get("PYTHONPATH", "")]) filter(None, [os.getcwd(), env.get("PYTHONPATH", "")])
) )
kw["env"] = env kw["env"] = env
@ -1043,14 +1048,13 @@ class Testdir(object):
Returns a :py:class:`RunResult`. Returns a :py:class:`RunResult`.
""" """
return self._run(*cmdargs) cmdargs = [
str(arg) if isinstance(arg, py.path.local) else arg for arg in cmdargs
def _run(self, *cmdargs): ]
cmdargs = [str(x) for x in cmdargs]
p1 = self.tmpdir.join("stdout") p1 = self.tmpdir.join("stdout")
p2 = self.tmpdir.join("stderr") p2 = self.tmpdir.join("stderr")
print("running:", " ".join(cmdargs)) print("running:", *cmdargs)
print(" in:", str(py.path.local())) print(" in:", py.path.local())
f1 = codecs.open(str(p1), "w", encoding="utf8") f1 = codecs.open(str(p1), "w", encoding="utf8")
f2 = codecs.open(str(p2), "w", encoding="utf8") f2 = codecs.open(str(p2), "w", encoding="utf8")
try: try:
@ -1082,7 +1086,7 @@ class Testdir(object):
print("couldn't print to %s because of encoding" % (fp,)) print("couldn't print to %s because of encoding" % (fp,))
def _getpytestargs(self): def _getpytestargs(self):
return (sys.executable, "-mpytest") return sys.executable, "-mpytest"
def runpython(self, script): def runpython(self, script):
"""Run a python script using sys.executable as interpreter. """Run a python script using sys.executable as interpreter.

View File

@ -201,15 +201,19 @@ def pytest_collect_file(path, parent):
ext = path.ext ext = path.ext
if ext == ".py": if ext == ".py":
if not parent.session.isinitpath(path): if not parent.session.isinitpath(path):
for pat in parent.config.getini("python_files") + ["__init__.py"]: if not path_matches_patterns(
if path.fnmatch(pat): path, parent.config.getini("python_files") + ["__init__.py"]
break ):
else:
return return
ihook = parent.session.gethookproxy(path) ihook = parent.session.gethookproxy(path)
return ihook.pytest_pycollect_makemodule(path=path, parent=parent) return ihook.pytest_pycollect_makemodule(path=path, parent=parent)
def path_matches_patterns(path, patterns):
"""Returns True if the given py.path.local matches one of the patterns in the list of globs given"""
return any(path.fnmatch(pattern) for pattern in patterns)
def pytest_pycollect_makemodule(path, parent): def pytest_pycollect_makemodule(path, parent):
if path.basename == "__init__.py": if path.basename == "__init__.py":
return Package(path, parent) return Package(path, parent)
@ -590,17 +594,33 @@ class Package(Module):
self.session.config.pluginmanager._duplicatepaths.remove(path) self.session.config.pluginmanager._duplicatepaths.remove(path)
this_path = self.fspath.dirpath() this_path = self.fspath.dirpath()
pkg_prefix = None init_module = this_path.join("__init__.py")
if init_module.check(file=1) and path_matches_patterns(
init_module, self.config.getini("python_files")
):
yield Module(init_module, self)
pkg_prefixes = set()
for path in this_path.visit(rec=self._recurse, bf=True, sort=True): for path in this_path.visit(rec=self._recurse, bf=True, sort=True):
# we will visit our own __init__.py file, in which case we skip it # we will visit our own __init__.py file, in which case we skip it
skip = False
if path.basename == "__init__.py" and path.dirpath() == this_path: if path.basename == "__init__.py" and path.dirpath() == this_path:
continue continue
if pkg_prefix and pkg_prefix in path.parts():
for pkg_prefix in pkg_prefixes:
if (
pkg_prefix in path.parts()
and pkg_prefix.join("__init__.py") != path
):
skip = True
if skip:
continue continue
if path.isdir() and path.join("__init__.py").check(file=1):
pkg_prefixes.add(path)
for x in self._collectfile(path): for x in self._collectfile(path):
yield x yield x
if isinstance(x, Package):
pkg_prefix = path.dirpath()
def _get_xunit_setup_teardown(holder, attr_name, param_obj=None): def _get_xunit_setup_teardown(holder, attr_name, param_obj=None):
@ -741,7 +761,7 @@ class FunctionMixin(PyobjMixin):
def _repr_failure_py(self, excinfo, style="long"): def _repr_failure_py(self, excinfo, style="long"):
if excinfo.errisinstance(fail.Exception): if excinfo.errisinstance(fail.Exception):
if not excinfo.value.pytrace: if not excinfo.value.pytrace:
return py._builtin._totext(excinfo.value) return six.text_type(excinfo.value)
return super(FunctionMixin, self)._repr_failure_py(excinfo, style=style) return super(FunctionMixin, self)._repr_failure_py(excinfo, style=style)
def repr_failure(self, excinfo, outerr=None): def repr_failure(self, excinfo, outerr=None):

View File

@ -4,7 +4,7 @@ import sys
from numbers import Number from numbers import Number
from decimal import Decimal from decimal import Decimal
import py import six
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
@ -680,8 +680,8 @@ def raises(expected_exception, *args, **kwargs):
# print "raises frame scope: %r" % frame.f_locals # print "raises frame scope: %r" % frame.f_locals
try: try:
code = _pytest._code.Source(code).compile() code = _pytest._code.Source(code).compile()
py.builtin.exec_(code, frame.f_globals, loc) six.exec_(code, frame.f_globals, loc)
# XXX didn'T mean f_globals == f_locals something special? # XXX didn't mean f_globals == f_locals something special?
# this is destroyed here ... # this is destroyed here ...
except expected_exception: except expected_exception:
return _pytest._code.ExceptionInfo() return _pytest._code.ExceptionInfo()

View File

@ -4,11 +4,11 @@ from __future__ import absolute_import, division, print_function
import inspect import inspect
import _pytest._code import _pytest._code
import py import re
import sys import sys
import warnings import warnings
import re import six
from _pytest.fixtures import yield_fixture from _pytest.fixtures import yield_fixture
from _pytest.outcomes import fail from _pytest.outcomes import fail
@ -130,7 +130,7 @@ def warns(expected_warning, *args, **kwargs):
with WarningsChecker(expected_warning, match_expr=match_expr): with WarningsChecker(expected_warning, match_expr=match_expr):
code = _pytest._code.Source(code).compile() code = _pytest._code.Source(code).compile()
py.builtin.exec_(code, frame.f_globals, loc) six.exec_(code, frame.f_globals, loc)
else: else:
func = args[0] func = args[0]
with WarningsChecker(expected_warning, match_expr=match_expr): with WarningsChecker(expected_warning, match_expr=match_expr):

View File

@ -6,7 +6,7 @@ import os
import sys import sys
from time import time from time import time
import py import six
from _pytest._code.code import ExceptionInfo from _pytest._code.code import ExceptionInfo
from _pytest.outcomes import skip, Skipped, TEST_OUTCOME from _pytest.outcomes import skip, Skipped, TEST_OUTCOME
@ -317,7 +317,7 @@ class SetupState(object):
if exc is None: if exc is None:
exc = sys.exc_info() exc = sys.exc_info()
if exc: if exc:
py.builtin._reraise(*exc) six.reraise(*exc)
def _teardown_with_finalization(self, colitem): def _teardown_with_finalization(self, colitem):
self._callfinalizers(colitem) self._callfinalizers(colitem)
@ -352,7 +352,7 @@ class SetupState(object):
if exc is None: if exc is None:
exc = sys.exc_info() exc = sys.exc_info()
if exc: if exc:
py.builtin._reraise(*exc) six.reraise(*exc)
def prepare(self, colitem): def prepare(self, colitem):
""" setup objects along the collector chain to the test-method """ setup objects along the collector chain to the test-method
@ -363,7 +363,7 @@ class SetupState(object):
# check if the last collection node has raised an error # check if the last collection node has raised an error
for col in self.stack: for col in self.stack:
if hasattr(col, "_prepare_exc"): if hasattr(col, "_prepare_exc"):
py.builtin._reraise(*col._prepare_exc) six.reraise(*col._prepare_exc)
for col in needed_collectors[len(self.stack) :]: for col in needed_collectors[len(self.stack) :]:
self.stack.append(col) self.stack.append(col)
try: try:

View File

@ -51,7 +51,8 @@ def _show_fixture_action(fixturedef, msg):
config = fixturedef._fixturemanager.config config = fixturedef._fixturemanager.config
capman = config.pluginmanager.getplugin("capturemanager") capman = config.pluginmanager.getplugin("capturemanager")
if capman: if capman:
out, err = capman.suspend_global_capture() capman.suspend_global_capture()
out, err = capman.read_global_capture()
tw = config.get_terminal_writer() tw = config.get_terminal_writer()
tw.line() tw.line()

View File

@ -706,7 +706,12 @@ class TerminalReporter(object):
self._outrep_summary(rep) self._outrep_summary(rep)
def print_teardown_sections(self, rep): def print_teardown_sections(self, rep):
showcapture = self.config.option.showcapture
if showcapture == "no":
return
for secname, content in rep.sections: for secname, content in rep.sections:
if showcapture != "all" and showcapture not in secname:
continue
if "teardown" in secname: if "teardown" in secname:
self._tw.sep("-", secname) self._tw.sep("-", secname)
if content[-1:] == "\n": if content[-1:] == "\n":

View File

@ -2,11 +2,11 @@
from __future__ import absolute_import, division, print_function from __future__ import absolute_import, division, print_function
import os import os
import sys import sys
import textwrap
import types import types
import six import six
import _pytest._code
import py import py
import pytest import pytest
from _pytest.main import EXIT_NOTESTSCOLLECTED, EXIT_USAGEERROR from _pytest.main import EXIT_NOTESTSCOLLECTED, EXIT_USAGEERROR
@ -131,7 +131,7 @@ class TestGeneralUsage(object):
p2 = testdir.makefile(".pyc", "123") p2 = testdir.makefile(".pyc", "123")
result = testdir.runpytest(p1, p2) result = testdir.runpytest(p1, p2)
assert result.ret assert result.ret
result.stderr.fnmatch_lines(["*ERROR: not found:*%s" % (p2.basename,)]) result.stderr.fnmatch_lines(["*ERROR: not found:*{}".format(p2.basename)])
def test_issue486_better_reporting_on_conftest_load_failure(self, testdir): def test_issue486_better_reporting_on_conftest_load_failure(self, testdir):
testdir.makepyfile("") testdir.makepyfile("")
@ -201,16 +201,16 @@ class TestGeneralUsage(object):
testdir.tmpdir.join("py").mksymlinkto(py._pydir) testdir.tmpdir.join("py").mksymlinkto(py._pydir)
p = testdir.tmpdir.join("main.py") p = testdir.tmpdir.join("main.py")
p.write( p.write(
_pytest._code.Source( textwrap.dedent(
"""\
import sys, os
sys.path.insert(0, '')
import py
print(py.__file__)
print(py.__path__)
os.chdir(os.path.dirname(os.getcwd()))
print(py.log)
""" """
import sys, os
sys.path.insert(0, '')
import py
print (py.__file__)
print (py.__path__)
os.chdir(os.path.dirname(os.getcwd()))
print (py.log)
"""
) )
) )
result = testdir.runpython(p) result = testdir.runpython(p)
@ -453,7 +453,7 @@ class TestInvocationVariants(object):
@pytest.mark.xfail("sys.platform.startswith('java')") @pytest.mark.xfail("sys.platform.startswith('java')")
def test_pydoc(self, testdir): def test_pydoc(self, testdir):
for name in ("py.test", "pytest"): for name in ("py.test", "pytest"):
result = testdir.runpython_c("import %s;help(%s)" % (name, name)) result = testdir.runpython_c("import {};help({})".format(name, name))
assert result.ret == 0 assert result.ret == 0
s = result.stdout.str() s = result.stdout.str()
assert "MarkGenerator" in s assert "MarkGenerator" in s
@ -660,6 +660,16 @@ class TestInvocationVariants(object):
["*test_world.py::test_other*PASSED*", "*1 passed*"] ["*test_world.py::test_other*PASSED*", "*1 passed*"]
) )
def test_invoke_test_and_doctestmodules(self, testdir):
p = testdir.makepyfile(
"""
def test():
pass
"""
)
result = testdir.runpytest(str(p) + "::test", "--doctest-modules")
result.stdout.fnmatch_lines(["*1 passed*"])
@pytest.mark.skipif(not hasattr(os, "symlink"), reason="requires symlinks") @pytest.mark.skipif(not hasattr(os, "symlink"), reason="requires symlinks")
def test_cmdline_python_package_symlink(self, testdir, monkeypatch): def test_cmdline_python_package_symlink(self, testdir, monkeypatch):
""" """
@ -826,7 +836,7 @@ class TestDurations(object):
if ("test_%s" % x) in line and y in line: if ("test_%s" % x) in line and y in line:
break break
else: else:
raise AssertionError("not found %s %s" % (x, y)) raise AssertionError("not found {} {}".format(x, y))
def test_with_deselected(self, testdir): def test_with_deselected(self, testdir):
testdir.makepyfile(self.source) testdir.makepyfile(self.source)

View File

@ -3,8 +3,8 @@ from __future__ import absolute_import, division, print_function
import sys import sys
import _pytest._code import _pytest._code
import py
import pytest import pytest
import mock
from test_excinfo import TWMock from test_excinfo import TWMock
from six import text_type from six import text_type
@ -68,12 +68,8 @@ def test_getstatement_empty_fullsource():
f = func() f = func()
f = _pytest._code.Frame(f) f = _pytest._code.Frame(f)
prop = f.code.__class__.fullsource with mock.patch.object(f.code.__class__, "fullsource", None):
try: assert f.statement == ""
f.code.__class__.fullsource = None
assert f.statement == _pytest._code.Source("")
finally:
f.code.__class__.fullsource = prop
def test_code_from_func(): def test_code_from_func():
@ -83,7 +79,7 @@ def test_code_from_func():
def test_unicode_handling(): def test_unicode_handling():
value = py.builtin._totext("\xc4\x85\xc4\x87\n", "utf-8").encode("utf8") value = u"ąć".encode("UTF-8")
def f(): def f():
raise Exception(value) raise Exception(value)
@ -96,7 +92,7 @@ def test_unicode_handling():
@pytest.mark.skipif(sys.version_info[0] >= 3, reason="python 2 only issue") @pytest.mark.skipif(sys.version_info[0] >= 3, reason="python 2 only issue")
def test_unicode_handling_syntax_error(): def test_unicode_handling_syntax_error():
value = py.builtin._totext("\xc4\x85\xc4\x87\n", "utf-8").encode("utf8") value = u"ąć".encode("UTF-8")
def f(): def f():
raise SyntaxError("invalid syntax", (None, 1, 3, value)) raise SyntaxError("invalid syntax", (None, 1, 3, value))

View File

@ -8,6 +8,7 @@ import textwrap
import _pytest import _pytest
import py import py
import pytest import pytest
import six
from _pytest._code.code import ( from _pytest._code.code import (
ExceptionInfo, ExceptionInfo,
FormattedExcinfo, FormattedExcinfo,
@ -148,7 +149,7 @@ class TestTraceback_f_g_h(object):
except somenoname: except somenoname:
pass pass
xyz() xyz()
""" """
) )
try: try:
exec(source.compile()) exec(source.compile())
@ -251,7 +252,7 @@ class TestTraceback_f_g_h(object):
import sys import sys
exc, val, tb = sys.exc_info() exc, val, tb = sys.exc_info()
py.builtin._reraise(exc, val, tb) six.reraise(exc, val, tb)
def f(n): def f(n):
try: try:
@ -269,7 +270,7 @@ class TestTraceback_f_g_h(object):
decorator = pytest.importorskip("decorator").decorator decorator = pytest.importorskip("decorator").decorator
def log(f, *k, **kw): def log(f, *k, **kw):
print("%s %s" % (k, kw)) print("{} {}".format(k, kw))
f(*k, **kw) f(*k, **kw)
log = decorator(log) log = decorator(log)
@ -425,7 +426,7 @@ class TestFormattedExcinfo(object):
@pytest.fixture @pytest.fixture
def importasmod(self, request): def importasmod(self, request):
def importasmod(source): def importasmod(source):
source = _pytest._code.Source(source) source = textwrap.dedent(source)
tmpdir = request.getfixturevalue("tmpdir") tmpdir = request.getfixturevalue("tmpdir")
modpath = tmpdir.join("mod.py") modpath = tmpdir.join("mod.py")
tmpdir.ensure("__init__.py") tmpdir.ensure("__init__.py")
@ -449,10 +450,10 @@ class TestFormattedExcinfo(object):
def test_repr_source(self): def test_repr_source(self):
pr = FormattedExcinfo() pr = FormattedExcinfo()
source = _pytest._code.Source( source = _pytest._code.Source(
""" """\
def f(x): def f(x):
pass pass
""" """
).strip() ).strip()
pr.flow_marker = "|" pr.flow_marker = "|"
lines = pr.get_source(source, 0) lines = pr.get_source(source, 0)
@ -884,10 +885,10 @@ raise ValueError()
class MyRepr(TerminalRepr): class MyRepr(TerminalRepr):
def toterminal(self, tw): def toterminal(self, tw):
tw.line(py.builtin._totext("я", "utf-8")) tw.line(u"я")
x = py.builtin._totext(MyRepr()) x = six.text_type(MyRepr())
assert x == py.builtin._totext("я", "utf-8") assert x == u"я"
def test_toterminal_long(self, importasmod): def test_toterminal_long(self, importasmod):
mod = importasmod( mod = importasmod(

View File

@ -6,8 +6,8 @@ import inspect
import sys import sys
import _pytest._code import _pytest._code
import py
import pytest import pytest
import six
from _pytest._code import Source from _pytest._code import Source
from _pytest._code.source import ast from _pytest._code.source import ast
@ -323,7 +323,7 @@ class TestSourceParsingAndCompiling(object):
def test_compile_and_getsource(self): def test_compile_and_getsource(self):
co = self.source.compile() co = self.source.compile()
py.builtin.exec_(co, globals()) six.exec_(co, globals())
f(7) f(7)
excinfo = pytest.raises(AssertionError, "f(6)") excinfo = pytest.raises(AssertionError, "f(6)")
frame = excinfo.traceback[-1].frame frame = excinfo.traceback[-1].frame
@ -392,7 +392,7 @@ def test_getfuncsource_dynamic():
def g(): pass def g(): pass
""" """
co = _pytest._code.compile(source) co = _pytest._code.compile(source)
py.builtin.exec_(co, globals()) six.exec_(co, globals())
assert str(_pytest._code.Source(f)).strip() == "def f():\n raise ValueError" assert str(_pytest._code.Source(f)).strip() == "def f():\n raise ValueError"
assert str(_pytest._code.Source(g)).strip() == "def g(): pass" assert str(_pytest._code.Source(g)).strip() == "def g(): pass"

View File

@ -1,6 +1,9 @@
"""Reproduces issue #3774""" """Reproduces issue #3774"""
import mock try:
import mock
except ImportError:
import unittest.mock as mock
import pytest import pytest

View File

@ -0,0 +1,2 @@
[pytest]
python_files = *.py

View File

@ -0,0 +1,2 @@
def test_init():
pass

View File

@ -0,0 +1,2 @@
def test_foo():
pass

View File

@ -878,7 +878,6 @@ def test_live_logging_suspends_capture(has_capture_manager, request):
import logging import logging
import contextlib import contextlib
from functools import partial from functools import partial
from _pytest.capture import CaptureManager
from _pytest.logging import _LiveLoggingStreamHandler from _pytest.logging import _LiveLoggingStreamHandler
class MockCaptureManager: class MockCaptureManager:
@ -890,10 +889,6 @@ def test_live_logging_suspends_capture(has_capture_manager, request):
yield yield
self.calls.append("exit disabled") self.calls.append("exit disabled")
# sanity check
assert CaptureManager.suspend_capture_item
assert CaptureManager.resume_global_capture
class DummyTerminal(six.StringIO): class DummyTerminal(six.StringIO):
def section(self, *args, **kwargs): def section(self, *args, **kwargs):
pass pass

View File

@ -1,7 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import os import os
import sys import sys
from textwrap import dedent import textwrap
import _pytest._code import _pytest._code
import pytest import pytest
@ -47,13 +47,14 @@ class TestModule(object):
p = root2.join("test_x456.py") p = root2.join("test_x456.py")
monkeypatch.syspath_prepend(str(root1)) monkeypatch.syspath_prepend(str(root1))
p.write( p.write(
dedent( textwrap.dedent(
"""\ """\
import x456 import x456
def test(): def test():
assert x456.__file__.startswith(%r) assert x456.__file__.startswith({!r})
""" """.format(
% str(root2) str(root2)
)
) )
) )
with root2.as_cwd(): with root2.as_cwd():
@ -929,23 +930,23 @@ class TestConftestCustomization(object):
def test_customized_pymakemodule_issue205_subdir(self, testdir): def test_customized_pymakemodule_issue205_subdir(self, testdir):
b = testdir.mkdir("a").mkdir("b") b = testdir.mkdir("a").mkdir("b")
b.join("conftest.py").write( b.join("conftest.py").write(
_pytest._code.Source( textwrap.dedent(
"""\
import pytest
@pytest.hookimpl(hookwrapper=True)
def pytest_pycollect_makemodule():
outcome = yield
mod = outcome.get_result()
mod.obj.hello = "world"
""" """
import pytest
@pytest.hookimpl(hookwrapper=True)
def pytest_pycollect_makemodule():
outcome = yield
mod = outcome.get_result()
mod.obj.hello = "world"
"""
) )
) )
b.join("test_module.py").write( b.join("test_module.py").write(
_pytest._code.Source( textwrap.dedent(
"""\
def test_hello():
assert hello == "world"
""" """
def test_hello():
assert hello == "world"
"""
) )
) )
reprec = testdir.inline_run() reprec = testdir.inline_run()
@ -954,31 +955,31 @@ class TestConftestCustomization(object):
def test_customized_pymakeitem(self, testdir): def test_customized_pymakeitem(self, testdir):
b = testdir.mkdir("a").mkdir("b") b = testdir.mkdir("a").mkdir("b")
b.join("conftest.py").write( b.join("conftest.py").write(
_pytest._code.Source( textwrap.dedent(
"""\
import pytest
@pytest.hookimpl(hookwrapper=True)
def pytest_pycollect_makeitem():
outcome = yield
if outcome.excinfo is None:
result = outcome.get_result()
if result:
for func in result:
func._some123 = "world"
""" """
import pytest
@pytest.hookimpl(hookwrapper=True)
def pytest_pycollect_makeitem():
outcome = yield
if outcome.excinfo is None:
result = outcome.get_result()
if result:
for func in result:
func._some123 = "world"
"""
) )
) )
b.join("test_module.py").write( b.join("test_module.py").write(
_pytest._code.Source( textwrap.dedent(
""" """\
import pytest import pytest
@pytest.fixture() @pytest.fixture()
def obj(request): def obj(request):
return request.node._some123 return request.node._some123
def test_hello(obj): def test_hello(obj):
assert obj == "world" assert obj == "world"
""" """
) )
) )
reprec = testdir.inline_run() reprec = testdir.inline_run()
@ -1033,7 +1034,7 @@ class TestConftestCustomization(object):
) )
testdir.makefile( testdir.makefile(
".narf", ".narf",
""" """\
def test_something(): def test_something():
assert 1 + 1 == 2""", assert 1 + 1 == 2""",
) )
@ -1046,29 +1047,29 @@ def test_setup_only_available_in_subdir(testdir):
sub1 = testdir.mkpydir("sub1") sub1 = testdir.mkpydir("sub1")
sub2 = testdir.mkpydir("sub2") sub2 = testdir.mkpydir("sub2")
sub1.join("conftest.py").write( sub1.join("conftest.py").write(
_pytest._code.Source( textwrap.dedent(
"""\
import pytest
def pytest_runtest_setup(item):
assert item.fspath.purebasename == "test_in_sub1"
def pytest_runtest_call(item):
assert item.fspath.purebasename == "test_in_sub1"
def pytest_runtest_teardown(item):
assert item.fspath.purebasename == "test_in_sub1"
""" """
import pytest
def pytest_runtest_setup(item):
assert item.fspath.purebasename == "test_in_sub1"
def pytest_runtest_call(item):
assert item.fspath.purebasename == "test_in_sub1"
def pytest_runtest_teardown(item):
assert item.fspath.purebasename == "test_in_sub1"
"""
) )
) )
sub2.join("conftest.py").write( sub2.join("conftest.py").write(
_pytest._code.Source( textwrap.dedent(
"""\
import pytest
def pytest_runtest_setup(item):
assert item.fspath.purebasename == "test_in_sub2"
def pytest_runtest_call(item):
assert item.fspath.purebasename == "test_in_sub2"
def pytest_runtest_teardown(item):
assert item.fspath.purebasename == "test_in_sub2"
""" """
import pytest
def pytest_runtest_setup(item):
assert item.fspath.purebasename == "test_in_sub2"
def pytest_runtest_call(item):
assert item.fspath.purebasename == "test_in_sub2"
def pytest_runtest_teardown(item):
assert item.fspath.purebasename == "test_in_sub2"
"""
) )
) )
sub1.join("test_in_sub1.py").write("def test_1(): pass") sub1.join("test_in_sub1.py").write("def test_1(): pass")
@ -1547,12 +1548,12 @@ def test_skip_duplicates_by_default(testdir):
a = testdir.mkdir("a") a = testdir.mkdir("a")
fh = a.join("test_a.py") fh = a.join("test_a.py")
fh.write( fh.write(
_pytest._code.Source( textwrap.dedent(
"""\
import pytest
def test_real():
pass
""" """
import pytest
def test_real():
pass
"""
) )
) )
result = testdir.runpytest(a.strpath, a.strpath) result = testdir.runpytest(a.strpath, a.strpath)
@ -1567,12 +1568,12 @@ def test_keep_duplicates(testdir):
a = testdir.mkdir("a") a = testdir.mkdir("a")
fh = a.join("test_a.py") fh = a.join("test_a.py")
fh.write( fh.write(
_pytest._code.Source( textwrap.dedent(
"""\
import pytest
def test_real():
pass
""" """
import pytest
def test_real():
pass
"""
) )
) )
result = testdir.runpytest("--keep-duplicates", a.strpath, a.strpath) result = testdir.runpytest("--keep-duplicates", a.strpath, a.strpath)
@ -1623,3 +1624,38 @@ def test_package_with_modules(testdir):
root.chdir() root.chdir()
result = testdir.runpytest("-v", "-s") result = testdir.runpytest("-v", "-s")
result.assert_outcomes(passed=2) result.assert_outcomes(passed=2)
def test_package_ordering(testdir):
"""
.
root
Test_root.py
__init__.py
sub1
Test_sub1.py
__init__.py
sub2
test
test_sub2.py
"""
testdir.makeini(
"""
[pytest]
python_files=*.py
"""
)
root = testdir.mkpydir("root")
sub1 = root.mkdir("sub1")
sub1.ensure("__init__.py")
sub2 = root.mkdir("sub2")
sub2_test = sub2.mkdir("sub2")
root.join("Test_root.py").write("def test_1(): pass")
sub1.join("Test_sub1.py").write("def test_2(): pass")
sub2_test.join("test_sub2.py").write("def test_3(): pass")
# Execute from .
result = testdir.runpytest("-v", "-s")
result.assert_outcomes(passed=3)

View File

@ -1,6 +1,6 @@
from textwrap import dedent # -*- coding: utf-8 -*-
import textwrap
import _pytest._code
import pytest import pytest
from _pytest.pytester import get_public_names from _pytest.pytester import get_public_names
from _pytest.fixtures import FixtureLookupError, FixtureRequest from _pytest.fixtures import FixtureLookupError, FixtureRequest
@ -208,23 +208,23 @@ class TestFillFixtures(object):
) )
subdir = testdir.mkpydir("subdir") subdir = testdir.mkpydir("subdir")
subdir.join("conftest.py").write( subdir.join("conftest.py").write(
_pytest._code.Source( textwrap.dedent(
""" """\
import pytest import pytest
@pytest.fixture @pytest.fixture
def spam(): def spam():
return 'spam' return 'spam'
""" """
) )
) )
testfile = subdir.join("test_spam.py") testfile = subdir.join("test_spam.py")
testfile.write( testfile.write(
_pytest._code.Source( textwrap.dedent(
"""\
def test_spam(spam):
assert spam == "spam"
""" """
def test_spam(spam):
assert spam == "spam"
"""
) )
) )
result = testdir.runpytest() result = testdir.runpytest()
@ -276,26 +276,26 @@ class TestFillFixtures(object):
) )
subdir = testdir.mkpydir("subdir") subdir = testdir.mkpydir("subdir")
subdir.join("conftest.py").write( subdir.join("conftest.py").write(
_pytest._code.Source( textwrap.dedent(
""" """\
import pytest import pytest
@pytest.fixture(params=[1, 2, 3]) @pytest.fixture(params=[1, 2, 3])
def spam(request): def spam(request):
return request.param return request.param
""" """
) )
) )
testfile = subdir.join("test_spam.py") testfile = subdir.join("test_spam.py")
testfile.write( testfile.write(
_pytest._code.Source( textwrap.dedent(
""" """\
params = {'spam': 1} params = {'spam': 1}
def test_spam(spam): def test_spam(spam):
assert spam == params['spam'] assert spam == params['spam']
params['spam'] += 1 params['spam'] += 1
""" """
) )
) )
result = testdir.runpytest() result = testdir.runpytest()
@ -320,26 +320,26 @@ class TestFillFixtures(object):
) )
subdir = testdir.mkpydir("subdir") subdir = testdir.mkpydir("subdir")
subdir.join("conftest.py").write( subdir.join("conftest.py").write(
_pytest._code.Source( textwrap.dedent(
""" """\
import pytest import pytest
@pytest.fixture(params=[1, 2, 3]) @pytest.fixture(params=[1, 2, 3])
def spam(request): def spam(request):
return request.param return request.param
""" """
) )
) )
testfile = subdir.join("test_spam.py") testfile = subdir.join("test_spam.py")
testfile.write( testfile.write(
_pytest._code.Source( textwrap.dedent(
""" """\
params = {'spam': 1} params = {'spam': 1}
def test_spam(spam): def test_spam(spam):
assert spam == params['spam'] assert spam == params['spam']
params['spam'] += 1 params['spam'] += 1
""" """
) )
) )
result = testdir.runpytest() result = testdir.runpytest()
@ -807,13 +807,13 @@ class TestRequestBasic(object):
# this tests that normalization of nodeids takes place # this tests that normalization of nodeids takes place
b = testdir.mkdir("tests").mkdir("unit") b = testdir.mkdir("tests").mkdir("unit")
b.join("conftest.py").write( b.join("conftest.py").write(
_pytest._code.Source( textwrap.dedent(
"""\
import pytest
@pytest.fixture
def arg1():
pass
""" """
import pytest
@pytest.fixture
def arg1():
pass
"""
) )
) )
p = b.join("test_module.py") p = b.join("test_module.py")
@ -1484,41 +1484,41 @@ class TestFixtureManagerParseFactories(object):
runner = testdir.mkdir("runner") runner = testdir.mkdir("runner")
package = testdir.mkdir("package") package = testdir.mkdir("package")
package.join("conftest.py").write( package.join("conftest.py").write(
dedent( textwrap.dedent(
"""\ """\
import pytest import pytest
@pytest.fixture @pytest.fixture
def one(): def one():
return 1 return 1
""" """
) )
) )
package.join("test_x.py").write( package.join("test_x.py").write(
dedent( textwrap.dedent(
"""\ """\
def test_x(one): def test_x(one):
assert one == 1 assert one == 1
""" """
) )
) )
sub = package.mkdir("sub") sub = package.mkdir("sub")
sub.join("__init__.py").ensure() sub.join("__init__.py").ensure()
sub.join("conftest.py").write( sub.join("conftest.py").write(
dedent( textwrap.dedent(
"""\ """\
import pytest import pytest
@pytest.fixture @pytest.fixture
def one(): def one():
return 2 return 2
""" """
) )
) )
sub.join("test_y.py").write( sub.join("test_y.py").write(
dedent( textwrap.dedent(
"""\ """\
def test_x(one): def test_x(one):
assert one == 2 assert one == 2
""" """
) )
) )
reprec = testdir.inline_run() reprec = testdir.inline_run()
@ -1535,44 +1535,44 @@ class TestFixtureManagerParseFactories(object):
) )
package = testdir.mkdir("package") package = testdir.mkdir("package")
package.join("__init__.py").write( package.join("__init__.py").write(
dedent( textwrap.dedent(
"""\ """\
from .. import values from .. import values
def setup_module(): def setup_module():
values.append("package") values.append("package")
def teardown_module(): def teardown_module():
values[:] = [] values[:] = []
""" """
) )
) )
package.join("test_x.py").write( package.join("test_x.py").write(
dedent( textwrap.dedent(
"""\ """\
from .. import values from .. import values
def test_x(): def test_x():
assert values == ["package"] assert values == ["package"]
""" """
) )
) )
package = testdir.mkdir("package2") package = testdir.mkdir("package2")
package.join("__init__.py").write( package.join("__init__.py").write(
dedent( textwrap.dedent(
"""\ """\
from .. import values from .. import values
def setup_module(): def setup_module():
values.append("package2") values.append("package2")
def teardown_module(): def teardown_module():
values[:] = [] values[:] = []
""" """
) )
) )
package.join("test_x.py").write( package.join("test_x.py").write(
dedent( textwrap.dedent(
"""\ """\
from .. import values from .. import values
def test_x(): def test_x():
assert values == ["package2"] assert values == ["package2"]
""" """
) )
) )
reprec = testdir.inline_run() reprec = testdir.inline_run()
@ -1587,32 +1587,32 @@ class TestFixtureManagerParseFactories(object):
package = testdir.mkdir("package") package = testdir.mkdir("package")
package.join("__init__.py").write("") package.join("__init__.py").write("")
package.join("conftest.py").write( package.join("conftest.py").write(
dedent( textwrap.dedent(
"""\ """\
import pytest import pytest
from .. import values from .. import values
@pytest.fixture(scope="package") @pytest.fixture(scope="package")
def one(): def one():
values.append("package") values.append("package")
yield values yield values
values.pop() values.pop()
@pytest.fixture(scope="package", autouse=True) @pytest.fixture(scope="package", autouse=True)
def two(): def two():
values.append("package-auto") values.append("package-auto")
yield values yield values
values.pop() values.pop()
""" """
) )
) )
package.join("test_x.py").write( package.join("test_x.py").write(
dedent( textwrap.dedent(
"""\ """\
from .. import values from .. import values
def test_package_autouse(): def test_package_autouse():
assert values == ["package-auto"] assert values == ["package-auto"]
def test_package(one): def test_package(one):
assert values == ["package-auto", "package"] assert values == ["package-auto", "package"]
""" """
) )
) )
reprec = testdir.inline_run() reprec = testdir.inline_run()
@ -1804,24 +1804,24 @@ class TestAutouseManagement(object):
def test_autouse_conftest_mid_directory(self, testdir): def test_autouse_conftest_mid_directory(self, testdir):
pkgdir = testdir.mkpydir("xyz123") pkgdir = testdir.mkpydir("xyz123")
pkgdir.join("conftest.py").write( pkgdir.join("conftest.py").write(
_pytest._code.Source( textwrap.dedent(
"""\
import pytest
@pytest.fixture(autouse=True)
def app():
import sys
sys._myapp = "hello"
""" """
import pytest
@pytest.fixture(autouse=True)
def app():
import sys
sys._myapp = "hello"
"""
) )
) )
t = pkgdir.ensure("tests", "test_app.py") t = pkgdir.ensure("tests", "test_app.py")
t.write( t.write(
_pytest._code.Source( textwrap.dedent(
"""\
import sys
def test_app():
assert sys._myapp == "hello"
""" """
import sys
def test_app():
assert sys._myapp == "hello"
"""
) )
) )
reprec = testdir.inline_run("-s") reprec = testdir.inline_run("-s")
@ -2715,17 +2715,17 @@ class TestFixtureMarker(object):
) )
b = testdir.mkdir("subdir") b = testdir.mkdir("subdir")
b.join("test_overridden_fixture_finalizer.py").write( b.join("test_overridden_fixture_finalizer.py").write(
dedent( textwrap.dedent(
""" """\
import pytest import pytest
@pytest.fixture @pytest.fixture
def browser(browser): def browser(browser):
browser['visited'] = True browser['visited'] = True
return browser return browser
def test_browser(browser): def test_browser(browser):
assert browser['visited'] is True assert browser['visited'] is True
""" """
) )
) )
reprec = testdir.runpytest("-s") reprec = testdir.runpytest("-s")
@ -3217,120 +3217,119 @@ class TestShowFixtures(object):
def test_show_fixtures_trimmed_doc(self, testdir): def test_show_fixtures_trimmed_doc(self, testdir):
p = testdir.makepyfile( p = testdir.makepyfile(
dedent( textwrap.dedent(
'''\
import pytest
@pytest.fixture
def arg1():
"""
line1
line2
"""
@pytest.fixture
def arg2():
"""
line1
line2
"""
''' '''
import pytest
@pytest.fixture
def arg1():
"""
line1
line2
"""
@pytest.fixture
def arg2():
"""
line1
line2
"""
'''
) )
) )
result = testdir.runpytest("--fixtures", p) result = testdir.runpytest("--fixtures", p)
result.stdout.fnmatch_lines( result.stdout.fnmatch_lines(
dedent( textwrap.dedent(
"""\
* fixtures defined from test_show_fixtures_trimmed_doc *
arg2
line1
line2
arg1
line1
line2
""" """
* fixtures defined from test_show_fixtures_trimmed_doc *
arg2
line1
line2
arg1
line1
line2
"""
) )
) )
def test_show_fixtures_indented_doc(self, testdir): def test_show_fixtures_indented_doc(self, testdir):
p = testdir.makepyfile( p = testdir.makepyfile(
dedent( textwrap.dedent(
'''\
import pytest
@pytest.fixture
def fixture1():
"""
line1
indented line
"""
''' '''
import pytest
@pytest.fixture
def fixture1():
"""
line1
indented line
"""
'''
) )
) )
result = testdir.runpytest("--fixtures", p) result = testdir.runpytest("--fixtures", p)
result.stdout.fnmatch_lines( result.stdout.fnmatch_lines(
dedent( textwrap.dedent(
"""\
* fixtures defined from test_show_fixtures_indented_doc *
fixture1
line1
indented line
""" """
* fixtures defined from test_show_fixtures_indented_doc *
fixture1
line1
indented line
"""
) )
) )
def test_show_fixtures_indented_doc_first_line_unindented(self, testdir): def test_show_fixtures_indented_doc_first_line_unindented(self, testdir):
p = testdir.makepyfile( p = testdir.makepyfile(
dedent( textwrap.dedent(
'''\
import pytest
@pytest.fixture
def fixture1():
"""line1
line2
indented line
"""
''' '''
import pytest
@pytest.fixture
def fixture1():
"""line1
line2
indented line
"""
'''
) )
) )
result = testdir.runpytest("--fixtures", p) result = testdir.runpytest("--fixtures", p)
result.stdout.fnmatch_lines( result.stdout.fnmatch_lines(
dedent( textwrap.dedent(
"""\
* fixtures defined from test_show_fixtures_indented_doc_first_line_unindented *
fixture1
line1
line2
indented line
""" """
* fixtures defined from test_show_fixtures_indented_doc_first_line_unindented *
fixture1
line1
line2
indented line
"""
) )
) )
def test_show_fixtures_indented_in_class(self, testdir): def test_show_fixtures_indented_in_class(self, testdir):
p = testdir.makepyfile( p = testdir.makepyfile(
dedent( textwrap.dedent(
'''\
import pytest
class TestClass(object):
@pytest.fixture
def fixture1(self):
"""line1
line2
indented line
"""
''' '''
import pytest
class TestClass(object):
@pytest.fixture
def fixture1(self):
"""line1
line2
indented line
"""
'''
) )
) )
result = testdir.runpytest("--fixtures", p) result = testdir.runpytest("--fixtures", p)
result.stdout.fnmatch_lines( result.stdout.fnmatch_lines(
dedent( textwrap.dedent(
"""\
* fixtures defined from test_show_fixtures_indented_in_class *
fixture1
line1
line2
indented line
""" """
* fixtures defined from test_show_fixtures_indented_in_class *
fixture1
line1
line2
indented line
"""
) )
) )
@ -3667,26 +3666,26 @@ class TestParameterizedSubRequest(object):
fixdir = testdir.mkdir("fixtures") fixdir = testdir.mkdir("fixtures")
fixfile = fixdir.join("fix.py") fixfile = fixdir.join("fix.py")
fixfile.write( fixfile.write(
_pytest._code.Source( textwrap.dedent(
""" """\
import pytest import pytest
@pytest.fixture(params=[0, 1, 2]) @pytest.fixture(params=[0, 1, 2])
def fix_with_param(request): def fix_with_param(request):
return request.param return request.param
""" """
) )
) )
testfile = tests_dir.join("test_foos.py") testfile = tests_dir.join("test_foos.py")
testfile.write( testfile.write(
_pytest._code.Source( textwrap.dedent(
""" """\
from fix import fix_with_param from fix import fix_with_param
def test_foo(request): def test_foo(request):
request.getfixturevalue('fix_with_param') request.getfixturevalue('fix_with_param')
""" """
) )
) )
@ -3698,9 +3697,9 @@ class TestParameterizedSubRequest(object):
E*Failed: The requested fixture has no parameter defined for the current test. E*Failed: The requested fixture has no parameter defined for the current test.
E* E*
E*Requested fixture 'fix_with_param' defined in: E*Requested fixture 'fix_with_param' defined in:
E*fix.py:5 E*fix.py:4
E*Requested here: E*Requested here:
E*test_foos.py:5 E*test_foos.py:4
*1 failed* *1 failed*
""" """
) )
@ -3979,3 +3978,71 @@ class TestScopeOrdering(object):
items, _ = testdir.inline_genitems() items, _ = testdir.inline_genitems()
request = FixtureRequest(items[0]) request = FixtureRequest(items[0])
assert request.fixturenames == "s1 p1 m1 m2 c1 f2 f1".split() assert request.fixturenames == "s1 p1 m1 m2 c1 f2 f1".split()
def test_multiple_packages(self, testdir):
"""Complex test involving multiple package fixtures. Make sure teardowns
are executed in order.
.
root
__init__.py
sub1
__init__.py
conftest.py
test_1.py
sub2
__init__.py
conftest.py
test_2.py
"""
root = testdir.mkdir("root")
root.join("__init__.py").write("values = []")
sub1 = root.mkdir("sub1")
sub1.ensure("__init__.py")
sub1.join("conftest.py").write(
textwrap.dedent(
"""\
import pytest
from .. import values
@pytest.fixture(scope="package")
def fix():
values.append("pre-sub1")
yield values
assert values.pop() == "pre-sub1"
"""
)
)
sub1.join("test_1.py").write(
textwrap.dedent(
"""\
from .. import values
def test_1(fix):
assert values == ["pre-sub1"]
"""
)
)
sub2 = root.mkdir("sub2")
sub2.ensure("__init__.py")
sub2.join("conftest.py").write(
textwrap.dedent(
"""\
import pytest
from .. import values
@pytest.fixture(scope="package")
def fix():
values.append("pre-sub2")
yield values
assert values.pop() == "pre-sub2"
"""
)
)
sub2.join("test_2.py").write(
textwrap.dedent(
"""\
from .. import values
def test_2(fix):
assert values == ["pre-sub2"]
"""
)
)
reprec = testdir.inline_run()
reprec.assertoutcome(passed=2)

View File

@ -2,8 +2,7 @@
import re import re
import sys import sys
import attr import attr
import _pytest._code import textwrap
import py
import pytest import pytest
from _pytest import python, fixtures from _pytest import python, fixtures
@ -295,9 +294,7 @@ class TestMetafunc(object):
) )
assert result == ["a0-1.0", "a1-b1"] assert result == ["a0-1.0", "a1-b1"]
# unicode mixing, issue250 # unicode mixing, issue250
result = idmaker( result = idmaker((u"a", "b"), [pytest.param({}, b"\xc3\xb4")])
(py.builtin._totext("a"), "b"), [pytest.param({}, b"\xc3\xb4")]
)
assert result == ["a0-\\xc3\\xb4"] assert result == ["a0-\\xc3\\xb4"]
def test_idmaker_with_bytes_regex(self): def test_idmaker_with_bytes_regex(self):
@ -309,7 +306,6 @@ class TestMetafunc(object):
def test_idmaker_native_strings(self): def test_idmaker_native_strings(self):
from _pytest.python import idmaker from _pytest.python import idmaker
totext = py.builtin._totext
result = idmaker( result = idmaker(
("a", "b"), ("a", "b"),
[ [
@ -324,7 +320,7 @@ class TestMetafunc(object):
pytest.param({7}, set("seven")), pytest.param({7}, set("seven")),
pytest.param(tuple("eight"), (8, -8, 8)), pytest.param(tuple("eight"), (8, -8, 8)),
pytest.param(b"\xc3\xb4", b"name"), pytest.param(b"\xc3\xb4", b"name"),
pytest.param(b"\xc3\xb4", totext("other")), pytest.param(b"\xc3\xb4", u"other"),
], ],
) )
assert result == [ assert result == [
@ -1275,19 +1271,19 @@ class TestMetafuncFunctional(object):
sub1 = testdir.mkpydir("sub1") sub1 = testdir.mkpydir("sub1")
sub2 = testdir.mkpydir("sub2") sub2 = testdir.mkpydir("sub2")
sub1.join("conftest.py").write( sub1.join("conftest.py").write(
_pytest._code.Source( textwrap.dedent(
"""\
def pytest_generate_tests(metafunc):
assert metafunc.function.__name__ == "test_1"
""" """
def pytest_generate_tests(metafunc):
assert metafunc.function.__name__ == "test_1"
"""
) )
) )
sub2.join("conftest.py").write( sub2.join("conftest.py").write(
_pytest._code.Source( textwrap.dedent(
"""\
def pytest_generate_tests(metafunc):
assert metafunc.function.__name__ == "test_2"
""" """
def pytest_generate_tests(metafunc):
assert metafunc.function.__name__ == "test_2"
"""
) )
) )
sub1.join("test_in_sub1.py").write("def test_1(): pass") sub1.join("test_in_sub1.py").write("def test_1(): pass")

View File

@ -11,7 +11,7 @@ def equal_with_bash(prefix, ffc, fc, out=None):
res_bash = set(fc(prefix)) res_bash = set(fc(prefix))
retval = set(res) == res_bash retval = set(res) == res_bash
if out: if out:
out.write("equal_with_bash %s %s\n" % (retval, res)) out.write("equal_with_bash {} {}\n".format(retval, res))
if not retval: if not retval:
out.write(" python - bash: %s\n" % (set(res) - res_bash)) out.write(" python - bash: %s\n" % (set(res) - res_bash))
out.write(" bash - python: %s\n" % (res_bash - set(res))) out.write(" bash - python: %s\n" % (res_bash - set(res)))

View File

@ -6,6 +6,7 @@ import textwrap
import _pytest.assertion as plugin import _pytest.assertion as plugin
import py import py
import pytest import pytest
import six
from _pytest.assertion import util from _pytest.assertion import util
from _pytest.assertion import truncate from _pytest.assertion import truncate
@ -509,12 +510,12 @@ class TestAssert_reprcompare(object):
assert "raised in repr()" not in expl assert "raised in repr()" not in expl
def test_unicode(self): def test_unicode(self):
left = py.builtin._totext("£€", "utf-8") left = u"£€"
right = py.builtin._totext("£", "utf-8") right = u"£"
expl = callequal(left, right) expl = callequal(left, right)
assert expl[0] == py.builtin._totext("'£€' == '£'", "utf-8") assert expl[0] == u"'£€' == '£'"
assert expl[1] == py.builtin._totext("- £€", "utf-8") assert expl[1] == u"- £€"
assert expl[2] == py.builtin._totext("+ £", "utf-8") assert expl[2] == u"+ £"
def test_nonascii_text(self): def test_nonascii_text(self):
""" """
@ -541,8 +542,8 @@ class TestAssert_reprcompare(object):
right = bytes(right, "utf-8") right = bytes(right, "utf-8")
expl = callequal(left, right) expl = callequal(left, right)
for line in expl: for line in expl:
assert isinstance(line, py.builtin.text) assert isinstance(line, six.text_type)
msg = py.builtin._totext("\n").join(expl) msg = u"\n".join(expl)
assert msg assert msg

View File

@ -9,6 +9,7 @@ import textwrap
import zipfile import zipfile
import py import py
import pytest import pytest
import six
import _pytest._code import _pytest._code
from _pytest.assertion import util from _pytest.assertion import util
@ -49,7 +50,7 @@ def getmsg(f, extra_ns=None, must_pass=False):
ns = {} ns = {}
if extra_ns is not None: if extra_ns is not None:
ns.update(extra_ns) ns.update(extra_ns)
py.builtin.exec_(code, ns) six.exec_(code, ns)
func = ns[f.__name__] func = ns[f.__name__]
try: try:
func() func()
@ -560,7 +561,7 @@ class TestAssertionRewrite(object):
assert getmsg(f) == "assert 42" assert getmsg(f) == "assert 42"
def my_reprcompare(op, left, right): def my_reprcompare(op, left, right):
return "%s %s %s" % (left, op, right) return "{} {} {}".format(left, op, right)
monkeypatch.setattr(util, "_reprcompare", my_reprcompare) monkeypatch.setattr(util, "_reprcompare", my_reprcompare)
@ -654,12 +655,10 @@ class TestRewriteOnImport(object):
def test_readonly(self, testdir): def test_readonly(self, testdir):
sub = testdir.mkdir("testing") sub = testdir.mkdir("testing")
sub.join("test_readonly.py").write( sub.join("test_readonly.py").write(
py.builtin._totext( b"""
"""
def test_rewritten(): def test_rewritten():
assert "@py_builtins" in globals() assert "@py_builtins" in globals()
""" """,
).encode("utf-8"),
"wb", "wb",
) )
old_mode = sub.stat().mode old_mode = sub.stat().mode
@ -1040,14 +1039,14 @@ class TestAssertionRewriteHookDetails(object):
""" """
path = testdir.mkpydir("foo") path = testdir.mkpydir("foo")
path.join("test_foo.py").write( path.join("test_foo.py").write(
_pytest._code.Source( textwrap.dedent(
"""\
class Test(object):
def test_foo(self):
import pkgutil
data = pkgutil.get_data('foo.test_foo', 'data.txt')
assert data == b'Hey'
""" """
class Test(object):
def test_foo(self):
import pkgutil
data = pkgutil.get_data('foo.test_foo', 'data.txt')
assert data == b'Hey'
"""
) )
) )
path.join("data.txt").write("Hey") path.join("data.txt").write("Hey")

View File

@ -1,9 +1,9 @@
from __future__ import absolute_import, division, print_function from __future__ import absolute_import, division, print_function
import sys import sys
import textwrap
import py import py
import _pytest
import pytest import pytest
import os import os
import shutil import shutil
@ -224,17 +224,17 @@ class TestLastFailed(object):
result = testdir.runpytest() result = testdir.runpytest()
result.stdout.fnmatch_lines(["*2 failed*"]) result.stdout.fnmatch_lines(["*2 failed*"])
p.write( p.write(
_pytest._code.Source( textwrap.dedent(
"""\
def test_1():
assert 1
def test_2():
assert 1
def test_3():
assert 0
""" """
def test_1():
assert 1
def test_2():
assert 1
def test_3():
assert 0
"""
) )
) )
result = testdir.runpytest("--lf") result = testdir.runpytest("--lf")
@ -252,19 +252,19 @@ class TestLastFailed(object):
def test_failedfirst_order(self, testdir): def test_failedfirst_order(self, testdir):
testdir.tmpdir.join("test_a.py").write( testdir.tmpdir.join("test_a.py").write(
_pytest._code.Source( textwrap.dedent(
"""\
def test_always_passes():
assert 1
""" """
def test_always_passes():
assert 1
"""
) )
) )
testdir.tmpdir.join("test_b.py").write( testdir.tmpdir.join("test_b.py").write(
_pytest._code.Source( textwrap.dedent(
"""\
def test_always_fails():
assert 0
""" """
def test_always_fails():
assert 0
"""
) )
) )
result = testdir.runpytest() result = testdir.runpytest()
@ -277,14 +277,14 @@ class TestLastFailed(object):
def test_lastfailed_failedfirst_order(self, testdir): def test_lastfailed_failedfirst_order(self, testdir):
testdir.makepyfile( testdir.makepyfile(
**{ **{
"test_a.py": """ "test_a.py": """\
def test_always_passes(): def test_always_passes():
assert 1 assert 1
""", """,
"test_b.py": """ "test_b.py": """\
def test_always_fails(): def test_always_fails():
assert 0 assert 0
""", """,
} }
) )
result = testdir.runpytest() result = testdir.runpytest()
@ -298,16 +298,16 @@ class TestLastFailed(object):
def test_lastfailed_difference_invocations(self, testdir, monkeypatch): def test_lastfailed_difference_invocations(self, testdir, monkeypatch):
monkeypatch.setenv("PYTHONDONTWRITEBYTECODE", 1) monkeypatch.setenv("PYTHONDONTWRITEBYTECODE", 1)
testdir.makepyfile( testdir.makepyfile(
test_a=""" test_a="""\
def test_a1(): def test_a1():
assert 0 assert 0
def test_a2(): def test_a2():
assert 1 assert 1
""", """,
test_b=""" test_b="""\
def test_b1(): def test_b1():
assert 0 assert 0
""", """,
) )
p = testdir.tmpdir.join("test_a.py") p = testdir.tmpdir.join("test_a.py")
p2 = testdir.tmpdir.join("test_b.py") p2 = testdir.tmpdir.join("test_b.py")
@ -317,11 +317,11 @@ class TestLastFailed(object):
result = testdir.runpytest("--lf", p2) result = testdir.runpytest("--lf", p2)
result.stdout.fnmatch_lines(["*1 failed*"]) result.stdout.fnmatch_lines(["*1 failed*"])
p2.write( p2.write(
_pytest._code.Source( textwrap.dedent(
"""\
def test_b1():
assert 1
""" """
def test_b1():
assert 1
"""
) )
) )
result = testdir.runpytest("--lf", p2) result = testdir.runpytest("--lf", p2)
@ -332,18 +332,18 @@ class TestLastFailed(object):
def test_lastfailed_usecase_splice(self, testdir, monkeypatch): def test_lastfailed_usecase_splice(self, testdir, monkeypatch):
monkeypatch.setenv("PYTHONDONTWRITEBYTECODE", 1) monkeypatch.setenv("PYTHONDONTWRITEBYTECODE", 1)
testdir.makepyfile( testdir.makepyfile(
""" """\
def test_1(): def test_1():
assert 0 assert 0
""" """
) )
p2 = testdir.tmpdir.join("test_something.py") p2 = testdir.tmpdir.join("test_something.py")
p2.write( p2.write(
_pytest._code.Source( textwrap.dedent(
"""\
def test_2():
assert 0
""" """
def test_2():
assert 0
"""
) )
) )
result = testdir.runpytest() result = testdir.runpytest()

View File

@ -1,3 +1,4 @@
# -*- coding: utf-8 -*-
from __future__ import absolute_import, division, print_function from __future__ import absolute_import, division, print_function
# note: py.io capture tests where copied from # note: py.io capture tests where copied from
@ -5,13 +6,13 @@ from __future__ import absolute_import, division, print_function
import pickle import pickle
import os import os
import sys import sys
import textwrap
from io import UnsupportedOperation from io import UnsupportedOperation
import _pytest._code
import py import py
import pytest import pytest
import contextlib import contextlib
from six import binary_type, text_type from six import text_type
from _pytest import capture from _pytest import capture
from _pytest.capture import CaptureManager from _pytest.capture import CaptureManager
from _pytest.main import EXIT_NOTESTSCOLLECTED from _pytest.main import EXIT_NOTESTSCOLLECTED
@ -23,12 +24,12 @@ needsosdup = pytest.mark.xfail("not hasattr(os, 'dup')")
def tobytes(obj): def tobytes(obj):
if isinstance(obj, text_type): if isinstance(obj, text_type):
obj = obj.encode("UTF-8") obj = obj.encode("UTF-8")
assert isinstance(obj, binary_type) assert isinstance(obj, bytes)
return obj return obj
def totext(obj): def totext(obj):
if isinstance(obj, binary_type): if isinstance(obj, bytes):
obj = text_type(obj, "UTF-8") obj = text_type(obj, "UTF-8")
assert isinstance(obj, text_type) assert isinstance(obj, text_type)
return obj return obj
@ -70,19 +71,23 @@ class TestCaptureManager(object):
try: try:
capman = CaptureManager(method) capman = CaptureManager(method)
capman.start_global_capturing() capman.start_global_capturing()
outerr = capman.suspend_global_capture() capman.suspend_global_capture()
outerr = capman.read_global_capture()
assert outerr == ("", "") assert outerr == ("", "")
outerr = capman.suspend_global_capture() capman.suspend_global_capture()
outerr = capman.read_global_capture()
assert outerr == ("", "") assert outerr == ("", "")
print("hello") print("hello")
out, err = capman.suspend_global_capture() capman.suspend_global_capture()
out, err = capman.read_global_capture()
if method == "no": if method == "no":
assert old == (sys.stdout, sys.stderr, sys.stdin) assert old == (sys.stdout, sys.stderr, sys.stdin)
else: else:
assert not out assert not out
capman.resume_global_capture() capman.resume_global_capture()
print("hello") print("hello")
out, err = capman.suspend_global_capture() capman.suspend_global_capture()
out, err = capman.read_global_capture()
if method != "no": if method != "no":
assert out == "hello\n" assert out == "hello\n"
capman.stop_global_capturing() capman.stop_global_capturing()
@ -264,7 +269,7 @@ class TestPerTestCapturing(object):
def test_capturing_outerr(self, testdir): def test_capturing_outerr(self, testdir):
p1 = testdir.makepyfile( p1 = testdir.makepyfile(
""" """\
import sys import sys
def test_capturing(): def test_capturing():
print (42) print (42)
@ -273,7 +278,7 @@ class TestPerTestCapturing(object):
print (1) print (1)
sys.stderr.write(str(2)) sys.stderr.write(str(2))
raise ValueError raise ValueError
""" """
) )
result = testdir.runpytest(p1) result = testdir.runpytest(p1)
result.stdout.fnmatch_lines( result.stdout.fnmatch_lines(
@ -293,21 +298,21 @@ class TestPerTestCapturing(object):
class TestLoggingInteraction(object): class TestLoggingInteraction(object):
def test_logging_stream_ownership(self, testdir): def test_logging_stream_ownership(self, testdir):
p = testdir.makepyfile( p = testdir.makepyfile(
""" """\
def test_logging(): def test_logging():
import logging import logging
import pytest import pytest
stream = capture.CaptureIO() stream = capture.CaptureIO()
logging.basicConfig(stream=stream) logging.basicConfig(stream=stream)
stream.close() # to free memory/release resources stream.close() # to free memory/release resources
""" """
) )
result = testdir.runpytest_subprocess(p) result = testdir.runpytest_subprocess(p)
assert result.stderr.str().find("atexit") == -1 assert result.stderr.str().find("atexit") == -1
def test_logging_and_immediate_setupteardown(self, testdir): def test_logging_and_immediate_setupteardown(self, testdir):
p = testdir.makepyfile( p = testdir.makepyfile(
""" """\
import logging import logging
def setup_function(function): def setup_function(function):
logging.warn("hello1") logging.warn("hello1")
@ -319,7 +324,7 @@ class TestLoggingInteraction(object):
def teardown_function(function): def teardown_function(function):
logging.warn("hello3") logging.warn("hello3")
assert 0 assert 0
""" """
) )
for optargs in (("--capture=sys",), ("--capture=fd",)): for optargs in (("--capture=sys",), ("--capture=fd",)):
print(optargs) print(optargs)
@ -333,7 +338,7 @@ class TestLoggingInteraction(object):
def test_logging_and_crossscope_fixtures(self, testdir): def test_logging_and_crossscope_fixtures(self, testdir):
p = testdir.makepyfile( p = testdir.makepyfile(
""" """\
import logging import logging
def setup_module(function): def setup_module(function):
logging.warn("hello1") logging.warn("hello1")
@ -345,7 +350,7 @@ class TestLoggingInteraction(object):
def teardown_module(function): def teardown_module(function):
logging.warn("hello3") logging.warn("hello3")
assert 0 assert 0
""" """
) )
for optargs in (("--capture=sys",), ("--capture=fd",)): for optargs in (("--capture=sys",), ("--capture=fd",)):
print(optargs) print(optargs)
@ -359,11 +364,11 @@ class TestLoggingInteraction(object):
def test_conftestlogging_is_shown(self, testdir): def test_conftestlogging_is_shown(self, testdir):
testdir.makeconftest( testdir.makeconftest(
""" """\
import logging import logging
logging.basicConfig() logging.basicConfig()
logging.warn("hello435") logging.warn("hello435")
""" """
) )
# make sure that logging is still captured in tests # make sure that logging is still captured in tests
result = testdir.runpytest_subprocess("-s", "-p", "no:capturelog") result = testdir.runpytest_subprocess("-s", "-p", "no:capturelog")
@ -373,19 +378,19 @@ class TestLoggingInteraction(object):
def test_conftestlogging_and_test_logging(self, testdir): def test_conftestlogging_and_test_logging(self, testdir):
testdir.makeconftest( testdir.makeconftest(
""" """\
import logging import logging
logging.basicConfig() logging.basicConfig()
""" """
) )
# make sure that logging is still captured in tests # make sure that logging is still captured in tests
p = testdir.makepyfile( p = testdir.makepyfile(
""" """\
def test_hello(): def test_hello():
import logging import logging
logging.warn("hello433") logging.warn("hello433")
assert 0 assert 0
""" """
) )
result = testdir.runpytest_subprocess(p, "-p", "no:capturelog") result = testdir.runpytest_subprocess(p, "-p", "no:capturelog")
assert result.ret != 0 assert result.ret != 0
@ -398,24 +403,24 @@ class TestCaptureFixture(object):
@pytest.mark.parametrize("opt", [[], ["-s"]]) @pytest.mark.parametrize("opt", [[], ["-s"]])
def test_std_functional(self, testdir, opt): def test_std_functional(self, testdir, opt):
reprec = testdir.inline_runsource( reprec = testdir.inline_runsource(
""" """\
def test_hello(capsys): def test_hello(capsys):
print (42) print (42)
out, err = capsys.readouterr() out, err = capsys.readouterr()
assert out.startswith("42") assert out.startswith("42")
""", """,
*opt *opt
) )
reprec.assertoutcome(passed=1) reprec.assertoutcome(passed=1)
def test_capsyscapfd(self, testdir): def test_capsyscapfd(self, testdir):
p = testdir.makepyfile( p = testdir.makepyfile(
""" """\
def test_one(capsys, capfd): def test_one(capsys, capfd):
pass pass
def test_two(capfd, capsys): def test_two(capfd, capsys):
pass pass
""" """
) )
result = testdir.runpytest(p) result = testdir.runpytest(p)
result.stdout.fnmatch_lines( result.stdout.fnmatch_lines(
@ -433,12 +438,12 @@ class TestCaptureFixture(object):
in the same test is an error. in the same test is an error.
""" """
testdir.makepyfile( testdir.makepyfile(
""" """\
def test_one(capsys, request): def test_one(capsys, request):
request.getfixturevalue("capfd") request.getfixturevalue("capfd")
def test_two(capfd, request): def test_two(capfd, request):
request.getfixturevalue("capsys") request.getfixturevalue("capsys")
""" """
) )
result = testdir.runpytest() result = testdir.runpytest()
result.stdout.fnmatch_lines( result.stdout.fnmatch_lines(
@ -453,10 +458,10 @@ class TestCaptureFixture(object):
def test_capsyscapfdbinary(self, testdir): def test_capsyscapfdbinary(self, testdir):
p = testdir.makepyfile( p = testdir.makepyfile(
""" """\
def test_one(capsys, capfdbinary): def test_one(capsys, capfdbinary):
pass pass
""" """
) )
result = testdir.runpytest(p) result = testdir.runpytest(p)
result.stdout.fnmatch_lines( result.stdout.fnmatch_lines(
@ -466,12 +471,13 @@ class TestCaptureFixture(object):
@pytest.mark.parametrize("method", ["sys", "fd"]) @pytest.mark.parametrize("method", ["sys", "fd"])
def test_capture_is_represented_on_failure_issue128(self, testdir, method): def test_capture_is_represented_on_failure_issue128(self, testdir, method):
p = testdir.makepyfile( p = testdir.makepyfile(
""" """\
def test_hello(cap%s): def test_hello(cap{}):
print ("xxx42xxx") print ("xxx42xxx")
assert 0 assert 0
""" """.format(
% method method
)
) )
result = testdir.runpytest(p) result = testdir.runpytest(p)
result.stdout.fnmatch_lines(["xxx42xxx"]) result.stdout.fnmatch_lines(["xxx42xxx"])
@ -479,21 +485,21 @@ class TestCaptureFixture(object):
@needsosdup @needsosdup
def test_stdfd_functional(self, testdir): def test_stdfd_functional(self, testdir):
reprec = testdir.inline_runsource( reprec = testdir.inline_runsource(
""" """\
def test_hello(capfd): def test_hello(capfd):
import os import os
os.write(1, "42".encode('ascii')) os.write(1, "42".encode('ascii'))
out, err = capfd.readouterr() out, err = capfd.readouterr()
assert out.startswith("42") assert out.startswith("42")
capfd.close() capfd.close()
""" """
) )
reprec.assertoutcome(passed=1) reprec.assertoutcome(passed=1)
@needsosdup @needsosdup
def test_capfdbinary(self, testdir): def test_capfdbinary(self, testdir):
reprec = testdir.inline_runsource( reprec = testdir.inline_runsource(
""" """\
def test_hello(capfdbinary): def test_hello(capfdbinary):
import os import os
# some likely un-decodable bytes # some likely un-decodable bytes
@ -501,7 +507,7 @@ class TestCaptureFixture(object):
out, err = capfdbinary.readouterr() out, err = capfdbinary.readouterr()
assert out == b'\\xfe\\x98\\x20' assert out == b'\\xfe\\x98\\x20'
assert err == b'' assert err == b''
""" """
) )
reprec.assertoutcome(passed=1) reprec.assertoutcome(passed=1)
@ -510,7 +516,7 @@ class TestCaptureFixture(object):
) )
def test_capsysbinary(self, testdir): def test_capsysbinary(self, testdir):
reprec = testdir.inline_runsource( reprec = testdir.inline_runsource(
""" """\
def test_hello(capsysbinary): def test_hello(capsysbinary):
import sys import sys
# some likely un-decodable bytes # some likely un-decodable bytes
@ -518,7 +524,7 @@ class TestCaptureFixture(object):
out, err = capsysbinary.readouterr() out, err = capsysbinary.readouterr()
assert out == b'\\xfe\\x98\\x20' assert out == b'\\xfe\\x98\\x20'
assert err == b'' assert err == b''
""" """
) )
reprec.assertoutcome(passed=1) reprec.assertoutcome(passed=1)
@ -527,10 +533,10 @@ class TestCaptureFixture(object):
) )
def test_capsysbinary_forbidden_in_python2(self, testdir): def test_capsysbinary_forbidden_in_python2(self, testdir):
testdir.makepyfile( testdir.makepyfile(
""" """\
def test_hello(capsysbinary): def test_hello(capsysbinary):
pass pass
""" """
) )
result = testdir.runpytest() result = testdir.runpytest()
result.stdout.fnmatch_lines( result.stdout.fnmatch_lines(
@ -543,10 +549,10 @@ class TestCaptureFixture(object):
def test_partial_setup_failure(self, testdir): def test_partial_setup_failure(self, testdir):
p = testdir.makepyfile( p = testdir.makepyfile(
""" """\
def test_hello(capsys, missingarg): def test_hello(capsys, missingarg):
pass pass
""" """
) )
result = testdir.runpytest(p) result = testdir.runpytest(p)
result.stdout.fnmatch_lines(["*test_partial_setup_failure*", "*1 error*"]) result.stdout.fnmatch_lines(["*test_partial_setup_failure*", "*1 error*"])
@ -554,12 +560,12 @@ class TestCaptureFixture(object):
@needsosdup @needsosdup
def test_keyboardinterrupt_disables_capturing(self, testdir): def test_keyboardinterrupt_disables_capturing(self, testdir):
p = testdir.makepyfile( p = testdir.makepyfile(
""" """\
def test_hello(capfd): def test_hello(capfd):
import os import os
os.write(1, str(42).encode('ascii')) os.write(1, str(42).encode('ascii'))
raise KeyboardInterrupt() raise KeyboardInterrupt()
""" """
) )
result = testdir.runpytest_subprocess(p) result = testdir.runpytest_subprocess(p)
result.stdout.fnmatch_lines(["*KeyboardInterrupt*"]) result.stdout.fnmatch_lines(["*KeyboardInterrupt*"])
@ -568,7 +574,7 @@ class TestCaptureFixture(object):
@pytest.mark.issue14 @pytest.mark.issue14
def test_capture_and_logging(self, testdir): def test_capture_and_logging(self, testdir):
p = testdir.makepyfile( p = testdir.makepyfile(
""" """\
import logging import logging
def test_log(capsys): def test_log(capsys):
logging.error('x') logging.error('x')
@ -581,7 +587,7 @@ class TestCaptureFixture(object):
@pytest.mark.parametrize("no_capture", [True, False]) @pytest.mark.parametrize("no_capture", [True, False])
def test_disabled_capture_fixture(self, testdir, fixture, no_capture): def test_disabled_capture_fixture(self, testdir, fixture, no_capture):
testdir.makepyfile( testdir.makepyfile(
""" """\
def test_disabled({fixture}): def test_disabled({fixture}):
print('captured before') print('captured before')
with {fixture}.disabled(): with {fixture}.disabled():
@ -615,7 +621,7 @@ class TestCaptureFixture(object):
Ensure that capsys and capfd can be used by other fixtures during setup and teardown. Ensure that capsys and capfd can be used by other fixtures during setup and teardown.
""" """
testdir.makepyfile( testdir.makepyfile(
""" """\
from __future__ import print_function from __future__ import print_function
import sys import sys
import pytest import pytest
@ -647,15 +653,43 @@ class TestCaptureFixture(object):
assert "stdout contents begin" not in result.stdout.str() assert "stdout contents begin" not in result.stdout.str()
assert "stderr contents begin" not in result.stdout.str() assert "stderr contents begin" not in result.stdout.str()
@pytest.mark.parametrize("cap", ["capsys", "capfd"])
def test_fixture_use_by_other_fixtures_teardown(self, testdir, cap):
"""Ensure we can access setup and teardown buffers from teardown when using capsys/capfd (##3033)"""
testdir.makepyfile(
"""\
import sys
import pytest
import os
@pytest.fixture()
def fix({cap}):
print("setup out")
sys.stderr.write("setup err\\n")
yield
out, err = {cap}.readouterr()
assert out == 'setup out\\ncall out\\n'
assert err == 'setup err\\ncall err\\n'
def test_a(fix):
print("call out")
sys.stderr.write("call err\\n")
""".format(
cap=cap
)
)
reprec = testdir.inline_run()
reprec.assertoutcome(passed=1)
def test_setup_failure_does_not_kill_capturing(testdir): def test_setup_failure_does_not_kill_capturing(testdir):
sub1 = testdir.mkpydir("sub1") sub1 = testdir.mkpydir("sub1")
sub1.join("conftest.py").write( sub1.join("conftest.py").write(
_pytest._code.Source( textwrap.dedent(
"""\
def pytest_runtest_setup(item):
raise ValueError(42)
""" """
def pytest_runtest_setup(item):
raise ValueError(42)
"""
) )
) )
sub1.join("test_mod.py").write("def test_func1(): pass") sub1.join("test_mod.py").write("def test_func1(): pass")
@ -1051,9 +1085,9 @@ class TestStdCapture(object):
def test_capturing_readouterr_unicode(self): def test_capturing_readouterr_unicode(self):
with self.getcapture() as cap: with self.getcapture() as cap:
print("hx\xc4\x85\xc4\x87") print("hxąć")
out, err = cap.readouterr() out, err = cap.readouterr()
assert out == py.builtin._totext("hx\xc4\x85\xc4\x87\n", "utf8") assert out == u"hxąć\n"
@pytest.mark.skipif( @pytest.mark.skipif(
"sys.version_info >= (3,)", reason="text output different for bytes on python3" "sys.version_info >= (3,)", reason="text output different for bytes on python3"
@ -1063,7 +1097,7 @@ class TestStdCapture(object):
# triggered an internal error in pytest # triggered an internal error in pytest
print("\xa6") print("\xa6")
out, err = cap.readouterr() out, err = cap.readouterr()
assert out == py.builtin._totext("\ufffd\n", "unicode-escape") assert out == u"\ufffd\n"
def test_reset_twice_error(self): def test_reset_twice_error(self):
with self.getcapture() as cap: with self.getcapture() as cap:
@ -1387,9 +1421,69 @@ def test_pickling_and_unpickling_encoded_file():
pickle.loads(ef_as_str) pickle.loads(ef_as_str)
def test_capsys_with_cli_logging(testdir): def test_global_capture_with_live_logging(testdir):
# Issue 3819 # Issue 3819
# capsys should work with real-time cli logging # capture should work with live cli logging
# Teardown report seems to have the capture for the whole process (setup, capture, teardown)
testdir.makeconftest(
"""
def pytest_runtest_logreport(report):
if "test_global" in report.nodeid:
if report.when == "teardown":
with open("caplog", "w") as f:
f.write(report.caplog)
with open("capstdout", "w") as f:
f.write(report.capstdout)
"""
)
testdir.makepyfile(
"""
import logging
import sys
import pytest
logger = logging.getLogger(__name__)
@pytest.fixture
def fix1():
print("fix setup")
logging.info("fix setup")
yield
logging.info("fix teardown")
print("fix teardown")
def test_global(fix1):
print("begin test")
logging.info("something in test")
print("end test")
"""
)
result = testdir.runpytest_subprocess("--log-cli-level=INFO")
assert result.ret == 0
with open("caplog", "r") as f:
caplog = f.read()
assert "fix setup" in caplog
assert "something in test" in caplog
assert "fix teardown" in caplog
with open("capstdout", "r") as f:
capstdout = f.read()
assert "fix setup" in capstdout
assert "begin test" in capstdout
assert "end test" in capstdout
assert "fix teardown" in capstdout
@pytest.mark.parametrize("capture_fixture", ["capsys", "capfd"])
def test_capture_with_live_logging(testdir, capture_fixture):
# Issue 3819
# capture should work with live cli logging
testdir.makepyfile( testdir.makepyfile(
""" """
import logging import logging
@ -1397,22 +1491,23 @@ def test_capsys_with_cli_logging(testdir):
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
def test_myoutput(capsys): # or use "capfd" for fd-level def test_capture({0}):
print("hello") print("hello")
sys.stderr.write("world\\n") sys.stderr.write("world\\n")
captured = capsys.readouterr() captured = {0}.readouterr()
assert captured.out == "hello\\n" assert captured.out == "hello\\n"
assert captured.err == "world\\n" assert captured.err == "world\\n"
logging.info("something") logging.info("something")
print("next") print("next")
logging.info("something") logging.info("something")
captured = capsys.readouterr() captured = {0}.readouterr()
assert captured.out == "next\\n" assert captured.out == "next\\n"
""" """.format(
capture_fixture
)
) )
result = testdir.runpytest_subprocess("--log-cli-level=INFO") result = testdir.runpytest_subprocess("--log-cli-level=INFO")
assert result.ret == 0 assert result.ret == 0

View File

@ -1,9 +1,9 @@
from __future__ import absolute_import, division, print_function from __future__ import absolute_import, division, print_function
import pprint import pprint
import sys import sys
import textwrap
import pytest import pytest
import _pytest._code
from _pytest.main import Session, EXIT_NOTESTSCOLLECTED, _in_venv from _pytest.main import Session, EXIT_NOTESTSCOLLECTED, _in_venv
@ -913,13 +913,13 @@ def test_fixture_scope_sibling_conftests(testdir):
"""Regression test case for https://github.com/pytest-dev/pytest/issues/2836""" """Regression test case for https://github.com/pytest-dev/pytest/issues/2836"""
foo_path = testdir.mkdir("foo") foo_path = testdir.mkdir("foo")
foo_path.join("conftest.py").write( foo_path.join("conftest.py").write(
_pytest._code.Source( textwrap.dedent(
"""\
import pytest
@pytest.fixture
def fix():
return 1
""" """
import pytest
@pytest.fixture
def fix():
return 1
"""
) )
) )
foo_path.join("test_foo.py").write("def test_foo(fix): assert fix == 1") foo_path.join("test_foo.py").write("def test_foo(fix): assert fix == 1")
@ -938,3 +938,17 @@ def test_fixture_scope_sibling_conftests(testdir):
"*1 passed, 1 error*", "*1 passed, 1 error*",
] ]
) )
def test_collect_init_tests(testdir):
"""Check that we collect files from __init__.py files when they patch the 'python_files' (#3773)"""
p = testdir.copy_example("collect/collect_init_tests")
result = testdir.runpytest(p, "--collect-only")
result.stdout.fnmatch_lines(
[
"*<Module '__init__.py'>",
"*<Function 'test_init'>",
"*<Module 'test_foo.py'>",
"*<Function 'test_foo'>",
]
)

View File

@ -17,11 +17,11 @@ class TestParseIni(object):
sub = tmpdir.mkdir("sub") sub = tmpdir.mkdir("sub")
sub.chdir() sub.chdir()
tmpdir.join(filename).write( tmpdir.join(filename).write(
_pytest._code.Source( textwrap.dedent(
""" """\
[{section}] [{section}]
name = value name = value
""".format( """.format(
section=section section=section
) )
) )
@ -38,11 +38,11 @@ class TestParseIni(object):
def test_append_parse_args(self, testdir, tmpdir, monkeypatch): def test_append_parse_args(self, testdir, tmpdir, monkeypatch):
monkeypatch.setenv("PYTEST_ADDOPTS", '--color no -rs --tb="short"') monkeypatch.setenv("PYTEST_ADDOPTS", '--color no -rs --tb="short"')
tmpdir.join("pytest.ini").write( tmpdir.join("pytest.ini").write(
_pytest._code.Source( textwrap.dedent(
"""\
[pytest]
addopts = --verbose
""" """
[pytest]
addopts = --verbose
"""
) )
) )
config = testdir.parseconfig(tmpdir) config = testdir.parseconfig(tmpdir)
@ -438,11 +438,11 @@ class TestConfigFromdictargs(object):
def test_inifilename(self, tmpdir): def test_inifilename(self, tmpdir):
tmpdir.join("foo/bar.ini").ensure().write( tmpdir.join("foo/bar.ini").ensure().write(
_pytest._code.Source( textwrap.dedent(
"""\
[pytest]
name = value
""" """
[pytest]
name = value
"""
) )
) )
@ -453,12 +453,12 @@ class TestConfigFromdictargs(object):
cwd = tmpdir.join("a/b") cwd = tmpdir.join("a/b")
cwd.join("pytest.ini").ensure().write( cwd.join("pytest.ini").ensure().write(
_pytest._code.Source( textwrap.dedent(
"""\
[pytest]
name = wrong-value
should_not_be_set = true
""" """
[pytest]
name = wrong-value
should_not_be_set = true
"""
) )
) )
with cwd.ensure(dir=True).as_cwd(): with cwd.ensure(dir=True).as_cwd():

View File

@ -1,7 +1,6 @@
from __future__ import absolute_import, division, print_function from __future__ import absolute_import, division, print_function
from textwrap import dedent import textwrap
import _pytest._code
import py import py
import pytest import pytest
from _pytest.config import PytestPluginManager from _pytest.config import PytestPluginManager
@ -174,11 +173,11 @@ def test_conftest_confcutdir(testdir):
testdir.makeconftest("assert 0") testdir.makeconftest("assert 0")
x = testdir.mkdir("x") x = testdir.mkdir("x")
x.join("conftest.py").write( x.join("conftest.py").write(
_pytest._code.Source( textwrap.dedent(
"""\
def pytest_addoption(parser):
parser.addoption("--xyz", action="store_true")
""" """
def pytest_addoption(parser):
parser.addoption("--xyz", action="store_true")
"""
) )
) )
result = testdir.runpytest("-h", "--confcutdir=%s" % x, x) result = testdir.runpytest("-h", "--confcutdir=%s" % x, x)
@ -198,11 +197,11 @@ def test_no_conftest(testdir):
def test_conftest_existing_resultlog(testdir): def test_conftest_existing_resultlog(testdir):
x = testdir.mkdir("tests") x = testdir.mkdir("tests")
x.join("conftest.py").write( x.join("conftest.py").write(
_pytest._code.Source( textwrap.dedent(
"""\
def pytest_addoption(parser):
parser.addoption("--xyz", action="store_true")
""" """
def pytest_addoption(parser):
parser.addoption("--xyz", action="store_true")
"""
) )
) )
testdir.makefile(ext=".log", result="") # Writes result.log testdir.makefile(ext=".log", result="") # Writes result.log
@ -213,11 +212,11 @@ def test_conftest_existing_resultlog(testdir):
def test_conftest_existing_junitxml(testdir): def test_conftest_existing_junitxml(testdir):
x = testdir.mkdir("tests") x = testdir.mkdir("tests")
x.join("conftest.py").write( x.join("conftest.py").write(
_pytest._code.Source( textwrap.dedent(
"""\
def pytest_addoption(parser):
parser.addoption("--xyz", action="store_true")
""" """
def pytest_addoption(parser):
parser.addoption("--xyz", action="store_true")
"""
) )
) )
testdir.makefile(ext=".xml", junit="") # Writes junit.xml testdir.makefile(ext=".xml", junit="") # Writes junit.xml
@ -247,38 +246,38 @@ def test_fixture_dependency(testdir, monkeypatch):
sub = testdir.mkdir("sub") sub = testdir.mkdir("sub")
sub.join("__init__.py").write("") sub.join("__init__.py").write("")
sub.join("conftest.py").write( sub.join("conftest.py").write(
dedent( textwrap.dedent(
"""\
import pytest
@pytest.fixture
def not_needed():
assert False, "Should not be called!"
@pytest.fixture
def foo():
assert False, "Should not be called!"
@pytest.fixture
def bar(foo):
return 'bar'
""" """
import pytest
@pytest.fixture
def not_needed():
assert False, "Should not be called!"
@pytest.fixture
def foo():
assert False, "Should not be called!"
@pytest.fixture
def bar(foo):
return 'bar'
"""
) )
) )
subsub = sub.mkdir("subsub") subsub = sub.mkdir("subsub")
subsub.join("__init__.py").write("") subsub.join("__init__.py").write("")
subsub.join("test_bar.py").write( subsub.join("test_bar.py").write(
dedent( textwrap.dedent(
"""\
import pytest
@pytest.fixture
def bar():
return 'sub bar'
def test_event_fixture(bar):
assert bar == 'sub bar'
""" """
import pytest
@pytest.fixture
def bar():
return 'sub bar'
def test_event_fixture(bar):
assert bar == 'sub bar'
"""
) )
) )
result = testdir.runpytest("sub") result = testdir.runpytest("sub")
@ -288,11 +287,11 @@ def test_fixture_dependency(testdir, monkeypatch):
def test_conftest_found_with_double_dash(testdir): def test_conftest_found_with_double_dash(testdir):
sub = testdir.mkdir("sub") sub = testdir.mkdir("sub")
sub.join("conftest.py").write( sub.join("conftest.py").write(
dedent( textwrap.dedent(
"""\
def pytest_addoption(parser):
parser.addoption("--hello-world", action="store_true")
""" """
def pytest_addoption(parser):
parser.addoption("--hello-world", action="store_true")
"""
) )
) )
p = sub.join("test_hello.py") p = sub.join("test_hello.py")
@ -313,56 +312,54 @@ class TestConftestVisibility(object):
package = testdir.mkdir("package") package = testdir.mkdir("package")
package.join("conftest.py").write( package.join("conftest.py").write(
dedent( textwrap.dedent(
"""\ """\
import pytest import pytest
@pytest.fixture @pytest.fixture
def fxtr(): def fxtr():
return "from-package" return "from-package"
""" """
) )
) )
package.join("test_pkgroot.py").write( package.join("test_pkgroot.py").write(
dedent( textwrap.dedent(
"""\ """\
def test_pkgroot(fxtr): def test_pkgroot(fxtr):
assert fxtr == "from-package" assert fxtr == "from-package"
""" """
) )
) )
swc = package.mkdir("swc") swc = package.mkdir("swc")
swc.join("__init__.py").ensure() swc.join("__init__.py").ensure()
swc.join("conftest.py").write( swc.join("conftest.py").write(
dedent( textwrap.dedent(
"""\ """\
import pytest import pytest
@pytest.fixture @pytest.fixture
def fxtr(): def fxtr():
return "from-swc" return "from-swc"
""" """
) )
) )
swc.join("test_with_conftest.py").write( swc.join("test_with_conftest.py").write(
dedent( textwrap.dedent(
"""\ """\
def test_with_conftest(fxtr): def test_with_conftest(fxtr):
assert fxtr == "from-swc" assert fxtr == "from-swc"
"""
"""
) )
) )
snc = package.mkdir("snc") snc = package.mkdir("snc")
snc.join("__init__.py").ensure() snc.join("__init__.py").ensure()
snc.join("test_no_conftest.py").write( snc.join("test_no_conftest.py").write(
dedent( textwrap.dedent(
"""\ """\
def test_no_conftest(fxtr): def test_no_conftest(fxtr):
assert fxtr == "from-package" # No local conftest.py, so should assert fxtr == "from-package" # No local conftest.py, so should
# use value from parent dir's # use value from parent dir's
"""
"""
) )
) )
print("created directory structure:") print("created directory structure:")
@ -422,31 +419,31 @@ def test_search_conftest_up_to_inifile(testdir, confcutdir, passed, error):
src = root.join("src").ensure(dir=1) src = root.join("src").ensure(dir=1)
src.join("pytest.ini").write("[pytest]") src.join("pytest.ini").write("[pytest]")
src.join("conftest.py").write( src.join("conftest.py").write(
_pytest._code.Source( textwrap.dedent(
"""\
import pytest
@pytest.fixture
def fix1(): pass
""" """
import pytest
@pytest.fixture
def fix1(): pass
"""
) )
) )
src.join("test_foo.py").write( src.join("test_foo.py").write(
_pytest._code.Source( textwrap.dedent(
"""\
def test_1(fix1):
pass
def test_2(out_of_reach):
pass
""" """
def test_1(fix1):
pass
def test_2(out_of_reach):
pass
"""
) )
) )
root.join("conftest.py").write( root.join("conftest.py").write(
_pytest._code.Source( textwrap.dedent(
"""\
import pytest
@pytest.fixture
def out_of_reach(): pass
""" """
import pytest
@pytest.fixture
def out_of_reach(): pass
"""
) )
) )
@ -464,19 +461,19 @@ def test_search_conftest_up_to_inifile(testdir, confcutdir, passed, error):
def test_issue1073_conftest_special_objects(testdir): def test_issue1073_conftest_special_objects(testdir):
testdir.makeconftest( testdir.makeconftest(
""" """\
class DontTouchMe(object): class DontTouchMe(object):
def __getattr__(self, x): def __getattr__(self, x):
raise Exception('cant touch me') raise Exception('cant touch me')
x = DontTouchMe() x = DontTouchMe()
""" """
) )
testdir.makepyfile( testdir.makepyfile(
""" """\
def test_some(): def test_some():
pass pass
""" """
) )
res = testdir.runpytest() res = testdir.runpytest()
assert res.ret == 0 assert res.ret == 0
@ -484,15 +481,15 @@ def test_issue1073_conftest_special_objects(testdir):
def test_conftest_exception_handling(testdir): def test_conftest_exception_handling(testdir):
testdir.makeconftest( testdir.makeconftest(
""" """\
raise ValueError() raise ValueError()
""" """
) )
testdir.makepyfile( testdir.makepyfile(
""" """\
def test_some(): def test_some():
pass pass
""" """
) )
res = testdir.runpytest() res = testdir.runpytest()
assert res.ret == 4 assert res.ret == 4
@ -507,7 +504,7 @@ def test_hook_proxy(testdir):
**{ **{
"root/demo-0/test_foo1.py": "def test1(): pass", "root/demo-0/test_foo1.py": "def test1(): pass",
"root/demo-a/test_foo2.py": "def test1(): pass", "root/demo-a/test_foo2.py": "def test1(): pass",
"root/demo-a/conftest.py": """ "root/demo-a/conftest.py": """\
def pytest_ignore_collect(path, config): def pytest_ignore_collect(path, config):
return True return True
""", """,
@ -525,11 +522,11 @@ def test_required_option_help(testdir):
testdir.makeconftest("assert 0") testdir.makeconftest("assert 0")
x = testdir.mkdir("x") x = testdir.mkdir("x")
x.join("conftest.py").write( x.join("conftest.py").write(
_pytest._code.Source( textwrap.dedent(
"""\
def pytest_addoption(parser):
parser.addoption("--xyz", action="store_true", required=True)
""" """
def pytest_addoption(parser):
parser.addoption("--xyz", action="store_true", required=True)
"""
) )
) )
result = testdir.runpytest("-h", x) result = testdir.runpytest("-h", x)

View File

@ -1,7 +1,7 @@
# encoding: utf-8 # encoding: utf-8
from __future__ import absolute_import, division, print_function from __future__ import absolute_import, division, print_function
import sys import sys
import _pytest._code import textwrap
from _pytest.compat import MODULE_NOT_FOUND_ERROR from _pytest.compat import MODULE_NOT_FOUND_ERROR
from _pytest.doctest import DoctestItem, DoctestModule, DoctestTextfile from _pytest.doctest import DoctestItem, DoctestModule, DoctestTextfile
import pytest import pytest
@ -258,16 +258,16 @@ class TestDoctests(object):
def test_doctest_linedata_missing(self, testdir): def test_doctest_linedata_missing(self, testdir):
testdir.tmpdir.join("hello.py").write( testdir.tmpdir.join("hello.py").write(
_pytest._code.Source( textwrap.dedent(
"""\
class Fun(object):
@property
def test(self):
'''
>>> a = 1
>>> 1/0
'''
""" """
class Fun(object):
@property
def test(self):
'''
>>> a = 1
>>> 1/0
'''
"""
) )
) )
result = testdir.runpytest("--doctest-modules") result = testdir.runpytest("--doctest-modules")
@ -300,10 +300,10 @@ class TestDoctests(object):
def test_doctest_unex_importerror_with_module(self, testdir): def test_doctest_unex_importerror_with_module(self, testdir):
testdir.tmpdir.join("hello.py").write( testdir.tmpdir.join("hello.py").write(
_pytest._code.Source( textwrap.dedent(
"""\
import asdalsdkjaslkdjasd
""" """
import asdalsdkjaslkdjasd
"""
) )
) )
testdir.maketxtfile( testdir.maketxtfile(
@ -339,27 +339,27 @@ class TestDoctests(object):
def test_doctestmodule_external_and_issue116(self, testdir): def test_doctestmodule_external_and_issue116(self, testdir):
p = testdir.mkpydir("hello") p = testdir.mkpydir("hello")
p.join("__init__.py").write( p.join("__init__.py").write(
_pytest._code.Source( textwrap.dedent(
"""\
def somefunc():
'''
>>> i = 0
>>> i + 1
2
'''
""" """
def somefunc():
'''
>>> i = 0
>>> i + 1
2
'''
"""
) )
) )
result = testdir.runpytest(p, "--doctest-modules") result = testdir.runpytest(p, "--doctest-modules")
result.stdout.fnmatch_lines( result.stdout.fnmatch_lines(
[ [
"004 *>>> i = 0", "003 *>>> i = 0",
"005 *>>> i + 1", "004 *>>> i + 1",
"*Expected:", "*Expected:",
"* 2", "* 2",
"*Got:", "*Got:",
"* 1", "* 1",
"*:5: DocTestFailure", "*:4: DocTestFailure",
] ]
) )

View File

@ -7,7 +7,9 @@ def test_version(testdir, pytestconfig):
result = testdir.runpytest("--version") result = testdir.runpytest("--version")
assert result.ret == 0 assert result.ret == 0
# p = py.path.local(py.__file__).dirpath() # p = py.path.local(py.__file__).dirpath()
result.stderr.fnmatch_lines(["*pytest*%s*imported from*" % (pytest.__version__,)]) result.stderr.fnmatch_lines(
["*pytest*{}*imported from*".format(pytest.__version__)]
)
if pytestconfig.pluginmanager.list_plugin_distinfo(): if pytestconfig.pluginmanager.list_plugin_distinfo():
result.stderr.fnmatch_lines(["*setuptools registered plugins:", "*at*"]) result.stderr.fnmatch_lines(["*setuptools registered plugins:", "*at*"])

View File

@ -941,7 +941,7 @@ def test_double_colon_split_method_issue469(testdir):
def test_unicode_issue368(testdir): def test_unicode_issue368(testdir):
path = testdir.tmpdir.join("test.xml") path = testdir.tmpdir.join("test.xml")
log = LogXML(str(path), None) log = LogXML(str(path), None)
ustr = py.builtin._totext("ВНИ!", "utf-8") ustr = u"ВНИ!"
class Report(BaseReport): class Report(BaseReport):
longrepr = ustr longrepr = ustr

View File

@ -228,11 +228,15 @@ def test_syspath_prepend(mp):
def test_syspath_prepend_double_undo(mp): def test_syspath_prepend_double_undo(mp):
mp.syspath_prepend("hello world") old_syspath = sys.path[:]
mp.undo() try:
sys.path.append("more hello world") mp.syspath_prepend("hello world")
mp.undo() mp.undo()
assert sys.path[-1] == "more hello world" sys.path.append("more hello world")
mp.undo()
assert sys.path[-1] == "more hello world"
finally:
sys.path[:] = old_syspath
def test_chdir_with_path_local(mp, tmpdir): def test_chdir_with_path_local(mp, tmpdir):

View File

@ -294,7 +294,7 @@ def test_argcomplete(testdir, monkeypatch):
script = str(testdir.tmpdir.join("test_argcomplete")) script = str(testdir.tmpdir.join("test_argcomplete"))
pytest_bin = sys.argv[0] pytest_bin = sys.argv[0]
if "pytest" not in os.path.basename(pytest_bin): if "pytest" not in os.path.basename(pytest_bin):
pytest.skip("need to be run with pytest executable, not %s" % (pytest_bin,)) pytest.skip("need to be run with pytest executable, not {}".format(pytest_bin))
with open(str(script), "w") as fp: with open(str(script), "w") as fp:
# redirect output from argcomplete to stdin and stderr is not trivial # redirect output from argcomplete to stdin and stderr is not trivial

View File

@ -260,7 +260,9 @@ class TestPDB(object):
assert False assert False
""" """
) )
child = testdir.spawn_pytest("--show-capture=%s --pdb %s" % (showcapture, p1)) child = testdir.spawn_pytest(
"--show-capture={} --pdb {}".format(showcapture, p1)
)
if showcapture in ("all", "log"): if showcapture in ("all", "log"):
child.expect("captured log") child.expect("captured log")
child.expect("get rekt") child.expect("get rekt")
@ -473,7 +475,7 @@ class TestPDB(object):
x = 5 x = 5
""" """
) )
child = testdir.spawn("%s %s" % (sys.executable, p1)) child = testdir.spawn("{} {}".format(sys.executable, p1))
child.expect("x = 5") child.expect("x = 5")
child.sendeof() child.sendeof()
self.flush(child) self.flush(child)

View File

@ -25,7 +25,6 @@ class TestPytestPluginInteractions(object):
) )
conf = testdir.makeconftest( conf = testdir.makeconftest(
""" """
import sys ; sys.path.insert(0, '.')
import newhooks import newhooks
def pytest_addhooks(pluginmanager): def pytest_addhooks(pluginmanager):
pluginmanager.addhooks(newhooks) pluginmanager.addhooks(newhooks)
@ -263,8 +262,7 @@ class TestPytestPluginManager(object):
mod.pytest_plugins = "pytest_a" mod.pytest_plugins = "pytest_a"
aplugin = testdir.makepyfile(pytest_a="#") aplugin = testdir.makepyfile(pytest_a="#")
reprec = testdir.make_hook_recorder(pytestpm) reprec = testdir.make_hook_recorder(pytestpm)
# syspath.prepend(aplugin.dirpath()) testdir.syspathinsert(aplugin.dirpath())
sys.path.insert(0, str(aplugin.dirpath()))
pytestpm.consider_module(mod) pytestpm.consider_module(mod)
call = reprec.getcall(pytestpm.hook.pytest_plugin_registered.name) call = reprec.getcall(pytestpm.hook.pytest_plugin_registered.name)
assert call.plugin.__name__ == "pytest_a" assert call.plugin.__name__ == "pytest_a"

View File

@ -8,7 +8,7 @@ import _pytest.pytester as pytester
from _pytest.pytester import HookRecorder from _pytest.pytester import HookRecorder
from _pytest.pytester import CwdSnapshot, SysModulesSnapshot, SysPathsSnapshot from _pytest.pytester import CwdSnapshot, SysModulesSnapshot, SysPathsSnapshot
from _pytest.config import PytestPluginManager from _pytest.config import PytestPluginManager
from _pytest.main import EXIT_OK, EXIT_TESTSFAILED from _pytest.main import EXIT_OK, EXIT_TESTSFAILED, EXIT_NOTESTSCOLLECTED
def test_make_hook_recorder(testdir): def test_make_hook_recorder(testdir):
@ -266,57 +266,6 @@ class TestInlineRunModulesCleanup(object):
assert imported.data == 42 assert imported.data == 42
def test_inline_run_clean_sys_paths(testdir):
def test_sys_path_change_cleanup(self, testdir):
test_path1 = testdir.tmpdir.join("boink1").strpath
test_path2 = testdir.tmpdir.join("boink2").strpath
test_path3 = testdir.tmpdir.join("boink3").strpath
sys.path.append(test_path1)
sys.meta_path.append(test_path1)
original_path = list(sys.path)
original_meta_path = list(sys.meta_path)
test_mod = testdir.makepyfile(
"""
import sys
sys.path.append({:test_path2})
sys.meta_path.append({:test_path2})
def test_foo():
sys.path.append({:test_path3})
sys.meta_path.append({:test_path3})""".format(
locals()
)
)
testdir.inline_run(str(test_mod))
assert sys.path == original_path
assert sys.meta_path == original_meta_path
def spy_factory(self):
class SysPathsSnapshotSpy(object):
instances = []
def __init__(self):
SysPathsSnapshotSpy.instances.append(self)
self._spy_restore_count = 0
self.__snapshot = SysPathsSnapshot()
def restore(self):
self._spy_restore_count += 1
return self.__snapshot.restore()
return SysPathsSnapshotSpy
def test_inline_run_taking_and_restoring_a_sys_paths_snapshot(
self, testdir, monkeypatch
):
spy_factory = self.spy_factory()
monkeypatch.setattr(pytester, "SysPathsSnapshot", spy_factory)
test_mod = testdir.makepyfile("def test_foo(): pass")
testdir.inline_run(str(test_mod))
assert len(spy_factory.instances) == 1
spy = spy_factory.instances[0]
assert spy._spy_restore_count == 1
def test_assert_outcomes_after_pytest_error(testdir): def test_assert_outcomes_after_pytest_error(testdir):
testdir.makepyfile("def test_foo(): assert True") testdir.makepyfile("def test_foo(): assert True")
@ -447,3 +396,8 @@ class TestSysPathsSnapshot(object):
def test_testdir_subprocess(testdir): def test_testdir_subprocess(testdir):
testfile = testdir.makepyfile("def test_one(): pass") testfile = testdir.makepyfile("def test_one(): pass")
assert testdir.runpytest_subprocess(testfile).ret == 0 assert testdir.runpytest_subprocess(testfile).ret == 0
def test_unicode_args(testdir):
result = testdir.runpytest("-k", u"💩")
assert result.ret == EXIT_NOTESTSCOLLECTED

View File

@ -4,9 +4,9 @@ terminal reporting of the full testing process.
from __future__ import absolute_import, division, print_function from __future__ import absolute_import, division, print_function
import collections import collections
import sys import sys
import textwrap
import pluggy import pluggy
import _pytest._code
import py import py
import pytest import pytest
from _pytest.main import EXIT_NOTESTSCOLLECTED from _pytest.main import EXIT_NOTESTSCOLLECTED
@ -161,12 +161,12 @@ class TestTerminal(object):
def test_itemreport_directclasses_not_shown_as_subclasses(self, testdir): def test_itemreport_directclasses_not_shown_as_subclasses(self, testdir):
a = testdir.mkpydir("a123") a = testdir.mkpydir("a123")
a.join("test_hello123.py").write( a.join("test_hello123.py").write(
_pytest._code.Source( textwrap.dedent(
"""\
class TestClass(object):
def test_method(self):
pass
""" """
class TestClass(object):
def test_method(self):
pass
"""
) )
) )
result = testdir.runpytest("-v") result = testdir.runpytest("-v")
@ -312,13 +312,13 @@ class TestCollectonly(object):
result = testdir.runpytest("--collect-only", p) result = testdir.runpytest("--collect-only", p)
assert result.ret == 2 assert result.ret == 2
result.stdout.fnmatch_lines( result.stdout.fnmatch_lines(
_pytest._code.Source( textwrap.dedent(
"""\
*ERROR*
*ImportError*
*No module named *Errlk*
*1 error*
""" """
*ERROR*
*ImportError*
*No module named *Errlk*
*1 error*
"""
).strip() ).strip()
) )
@ -948,6 +948,46 @@ def pytest_report_header(config, startdir):
assert "!This is stderr!" not in stdout assert "!This is stderr!" not in stdout
assert "!This is a warning log msg!" not in stdout assert "!This is a warning log msg!" not in stdout
def test_show_capture_with_teardown_logs(self, testdir):
"""Ensure that the capturing of teardown logs honor --show-capture setting"""
testdir.makepyfile(
"""
import logging
import sys
import pytest
@pytest.fixture(scope="function", autouse="True")
def hook_each_test(request):
yield
sys.stdout.write("!stdout!")
sys.stderr.write("!stderr!")
logging.warning("!log!")
def test_func():
assert False
"""
)
result = testdir.runpytest("--show-capture=stdout", "--tb=short").stdout.str()
assert "!stdout!" in result
assert "!stderr!" not in result
assert "!log!" not in result
result = testdir.runpytest("--show-capture=stderr", "--tb=short").stdout.str()
assert "!stdout!" not in result
assert "!stderr!" in result
assert "!log!" not in result
result = testdir.runpytest("--show-capture=log", "--tb=short").stdout.str()
assert "!stdout!" not in result
assert "!stderr!" not in result
assert "!log!" in result
result = testdir.runpytest("--show-capture=no", "--tb=short").stdout.str()
assert "!stdout!" not in result
assert "!stderr!" not in result
assert "!log!" not in result
@pytest.mark.xfail("not hasattr(os, 'dup')") @pytest.mark.xfail("not hasattr(os, 'dup')")
def test_fdopen_kept_alive_issue124(testdir): def test_fdopen_kept_alive_issue124(testdir):
@ -1078,9 +1118,9 @@ def test_terminal_summary_warnings_are_displayed(testdir):
) )
def test_summary_stats(exp_line, exp_color, stats_arg): def test_summary_stats(exp_line, exp_color, stats_arg):
print("Based on stats: %s" % stats_arg) print("Based on stats: %s" % stats_arg)
print('Expect summary: "%s"; with color "%s"' % (exp_line, exp_color)) print('Expect summary: "{}"; with color "{}"'.format(exp_line, exp_color))
(line, color) = build_summary_stats_line(stats_arg) (line, color) = build_summary_stats_line(stats_arg)
print('Actually got: "%s"; with color "%s"' % (line, color)) print('Actually got: "{}"; with color "{}"'.format(line, color))
assert line == exp_line assert line == exp_line
assert color == exp_color assert color == exp_color

View File

@ -36,8 +36,7 @@ commands =
[testenv:linting] [testenv:linting]
skipsdist = True skip_install = True
usedevelop = True
basepython = python3.6 basepython = python3.6
deps = pre-commit deps = pre-commit
commands = pre-commit run --all-files --show-diff-on-failure commands = pre-commit run --all-files --show-diff-on-failure
@ -163,16 +162,18 @@ commands =
[testenv:coveralls] [testenv:coveralls]
passenv = TRAVIS TRAVIS_JOB_ID TRAVIS_BRANCH COVERALLS_REPO_TOKEN passenv = CI TRAVIS TRAVIS_* COVERALLS_REPO_TOKEN
usedevelop = True usedevelop = True
changedir = . changedir = .
deps = deps =
{[testenv]deps} {[testenv]deps}
coveralls coveralls
codecov
commands = commands =
coverage run --source=_pytest -m pytest testing coverage run --source=_pytest -m pytest testing
coverage report -m coverage report -m
coveralls coveralls
codecov
[testenv:release] [testenv:release]
decription = do a release, required posarg of the version number decription = do a release, required posarg of the version number