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

View File

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

View File

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

View File

@ -18,6 +18,61 @@ with advance notice in the **Deprecations** section of releases.
.. 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)
=========================

View File

@ -1,4 +1,4 @@
import py
import six
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
release-3.7.3
release-3.7.2
release-3.7.1
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
import _pytest._code
import py
import six
def otherfunc(a, b):
@ -177,7 +177,7 @@ def test_dynamic_compile_shows_nicely():
name = "abc-123"
module = imp.new_module(name)
code = _pytest._code.compile(src, name, "exec")
py.builtin.exec_(code, module.__dict__)
six.exec_(code, module.__dict__)
sys.modules[name] = module
module.foo()

View File

@ -10,4 +10,4 @@ def pytest_runtest_setup(item):
return
mod = item.getparent(pytest.Module).obj
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
serialization via the pickle module.
"""
import textwrap
import py
import pytest
import _pytest._code
pythonlist = ["python2.7", "python3.4", "python3.5"]
@ -24,42 +25,44 @@ class Python(object):
def __init__(self, version, picklefile):
self.pythonpath = py.path.local.sysfind(version)
if not self.pythonpath:
pytest.skip("%r not found" % (version,))
pytest.skip("{!r} not found".format(version))
self.picklefile = picklefile
def dumps(self, obj):
dumpfile = self.picklefile.dirpath("dump.py")
dumpfile.write(
_pytest._code.Source(
"""
textwrap.dedent(
"""\
import pickle
f = open(%r, 'wb')
s = pickle.dump(%r, f, protocol=2)
f = open({!r}, 'wb')
s = pickle.dump({!r}, f, protocol=2)
f.close()
"""
% (str(self.picklefile), obj)
""".format(
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):
loadfile = self.picklefile.dirpath("load.py")
loadfile.write(
_pytest._code.Source(
"""
textwrap.dedent(
"""\
import pickle
f = open(%r, 'rb')
f = open({!r}, 'rb')
obj = pickle.load(f)
f.close()
res = eval(%r)
res = eval({!r})
if not res:
raise SystemExit(1)
"""
% (str(self.picklefile), expression)
""".format(
str(self.picklefile), expression
)
)
)
print(loadfile)
py.process.cmdexec("%s %s" % (self.pythonpath, loadfile))
py.process.cmdexec("{} {}".format(self.pythonpath, loadfile))
@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
...sss...sssssssss...sss... [100%]
========================= 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
Indirect parametrization of optional implementations/imports

View File

@ -100,9 +100,11 @@ Changing naming conventions
You can configure different naming conventions by setting
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
# Example 1: have pytest look for "check" instead of "test"
# can also be defined in tox.ini or setup.cfg file, although the section
# name in setup.cfg files should be "tool:pytest"
[pytest]
@ -121,7 +123,7 @@ that match ``*_check``. For example, if we have::
def complex_check(self):
pass
then the test collection looks like this::
The test collection would look like this::
$ pytest --collect-only
=========================== test session starts ============================
@ -136,11 +138,19 @@ then the test collection looks like this::
======================= 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::
the ``python_functions`` and ``python_classes`` options has no effect
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
-----------------------------------------------------

View File

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

View File

@ -4,6 +4,27 @@
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`:
.. _`Python test discovery`:
@ -177,19 +198,6 @@ Note that this layout also works in conjunction with the ``src`` layout mentione
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
package passes all tests you may want to look into `tox`_, the
virtualenv test automation tool and its `pytest support
@ -282,7 +290,7 @@ your own setuptools Test command for invoking pytest.
setup(
# ...,
tests_require=["pytest"],
cmdclass={"test": PyTest},
cmdclass={"pytest": PyTest},
)
Now if you run::

View File

@ -460,7 +460,7 @@ To use it, include in your top-most ``conftest.py`` file::
.. autoclass:: Testdir()
:members: runpytest,runpytest_subprocess,runpytest_inprocess,makeconftest,makepyfile
:members:
.. autoclass:: RunResult()
:members:
@ -1234,7 +1234,8 @@ passed multiple times. The expected format is ``name=value``. For example::
.. confval:: python_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
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
One or more Glob-style file patterns determining which python files
are considered as test modules. By default, pytest will consider
any file matching with ``test_*.py`` and ``*_test.py`` globs as a test
module.
are considered as test modules. Search for multiple glob patterns by
adding a space between patterns::
.. 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
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
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
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
the ``pytestmark`` name on the global level:

View File

@ -2,7 +2,7 @@
# CHANGES:
# - 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
from six import text_type
@ -51,17 +51,17 @@ def format_exception_only(etype, value):
pass
else:
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 isinstance(badline, bytes): # python 2 only
badline = badline.decode("utf-8", "replace")
lines.append(u" %s\n" % badline.strip())
lines.append(" {}\n".format(badline.strip()))
if offset is not None:
caretspace = badline.rstrip("\n")[:offset].lstrip()
# non-space whitespace (likes tabs) must be kept for alignment
caretspace = ((c.isspace() and c or " ") for c in caretspace)
# only three spaces to account for offset1 == pos 0
lines.append(" %s^\n" % "".join(caretspace))
lines.append(" {}^\n".format("".join(caretspace)))
value = msg
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"""
valuestr = _some_str(value)
if value is None or not valuestr:
line = "%s\n" % etype
line = "{}\n".format(etype)
else:
line = "%s: %s\n" % (etype, valuestr)
line = "{}: {}\n".format(etype, valuestr)
return line
@ -83,7 +83,7 @@ def _some_str(value):
return text_type(value)
except Exception:
try:
return str(value)
return bytes(value).decode("UTF-8", "replace")
except Exception:
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 six import text_type
import py
import six
builtin_repr = repr
@ -128,7 +129,7 @@ class Frame(object):
"""
f_locals = self.f_locals.copy()
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):
""" return a 'safe' (non-recursive, one-line) string repr for 'object'

View File

@ -223,7 +223,7 @@ class AssertionRewritingHook(object):
mod.__loader__ = self
# Normally, this attribute is 3.4+
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
if name in sys.modules:
del sys.modules[name]
@ -402,12 +402,11 @@ def _saferepr(obj):
JSON reprs.
"""
repr = py.io.saferepr(obj)
if isinstance(repr, six.text_type):
t = six.text_type
r = py.io.saferepr(obj)
if isinstance(r, six.text_type):
return r.replace(u"\n", u"\\n")
else:
t = six.binary_type
return repr.replace(t("\n"), t("\\n"))
return r.replace(b"\n", b"\\n")
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):
explanation = "(" + (is_or and " or " or " and ").join(explanations) + ")"
if isinstance(explanation, six.text_type):
t = six.text_type
return explanation.replace(u"%", u"%%")
else:
t = six.binary_type
return explanation.replace(t("%"), t("%%"))
return explanation.replace(b"%", b"%%")
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")
return r
if isinstance(left, six.binary_type):
if isinstance(left, bytes):
left = escape_for_readable_diff(left)
if isinstance(right, six.binary_type):
if isinstance(right, bytes):
right = escape_for_readable_diff(right)
if not verbose:
i = 0 # just in case left or right has zero length

View File

@ -14,7 +14,7 @@ from tempfile import TemporaryFile
import six
import pytest
from _pytest.compat import CaptureIO, dummy_context_manager
from _pytest.compat import CaptureIO
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)
capman.start_global_capturing()
outcome = yield
out, err = capman.suspend_global_capture()
capman.suspend_global_capture()
if outcome.excinfo is not None:
out, err = capman.read_global_capture()
sys.stdout.write(out)
sys.stderr.write(err)
@ -96,6 +97,8 @@ class CaptureManager(object):
else:
raise ValueError("unknown capturing method: %r" % method)
# Global capturing control
def start_global_capturing(self):
assert self._global_capturing is None
self._global_capturing = self._getcapture(self._method)
@ -110,29 +113,15 @@ class CaptureManager(object):
def resume_global_capture(self):
self._global_capturing.resume_capturing()
def suspend_global_capture(self, item=None, in_=False):
if item is not None:
self.deactivate_fixture(item)
def suspend_global_capture(self, in_=False):
cap = getattr(self, "_global_capturing", None)
if cap is not None:
try:
outerr = cap.readouterr()
finally:
cap.suspend_capturing(in_=in_)
return outerr
@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
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 read_global_capture(self):
return self._global_capturing.readouterr()
# Fixture Control (its just forwarding, think about removing this later)
def activate_fixture(self, item):
"""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:
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)
def pytest_make_collect_report(self, collector):
if isinstance(collector, pytest.File):
self.resume_global_capture()
outcome = yield
out, err = self.suspend_global_capture()
self.suspend_global_capture()
out, err = self.read_global_capture()
rep = outcome.get_result()
if out:
rep.sections.append(("Captured stdout", out))
@ -163,35 +193,25 @@ class CaptureManager(object):
yield
@pytest.hookimpl(hookwrapper=True)
def pytest_runtest_setup(self, item):
def pytest_runtest_protocol(self, 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
self.suspend_capture_item(item, "setup")
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)
def pytest_runtest_call(self, item):
self._current_item = item
self.resume_global_capture()
# it is important to activate this fixture during the call phase so it overwrites the "global"
# capture
self.activate_fixture(item)
with self.item_capture("call", item):
yield
self.suspend_capture_item(item, "call")
self._current_item = None
@pytest.hookimpl(hookwrapper=True)
def pytest_runtest_teardown(self, item):
self._current_item = item
self.resume_global_capture()
self.activate_fixture(item)
with self.item_capture("teardown", item):
yield
self.suspend_capture_item(item, "teardown")
self._current_item = None
@pytest.hookimpl(tryfirst=True)
def pytest_keyboard_interrupt(self, excinfo):
@ -201,11 +221,6 @@ class CaptureManager(object):
def pytest_internalerror(self, excinfo):
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"}
@ -309,36 +324,46 @@ class CaptureFixture(object):
def __init__(self, captureclass, request):
self.captureclass = captureclass
self.request = request
self._capture = None
self._captured_out = self.captureclass.EMPTY_BUFFER
self._captured_err = self.captureclass.EMPTY_BUFFER
def _start(self):
# Start if not started yet
if getattr(self, "_capture", None) is None:
self._capture = MultiCapture(
out=True, err=True, in_=False, Capture=self.captureclass
)
self._capture.start_capturing()
def close(self):
cap = self.__dict__.pop("_capture", None)
if cap is not None:
self._outerr = cap.pop_outerr_to_orig()
cap.stop_capturing()
if self._capture is not None:
out, err = self._capture.pop_outerr_to_orig()
self._captured_out += out
self._captured_err += err
self._capture.stop_capturing()
self._capture = None
def readouterr(self):
"""Read and return the captured output so far, resetting the internal buffer.
:return: captured content as a namedtuple with ``out`` and ``err`` string attributes
"""
try:
return self._capture.readouterr()
except AttributeError:
return self._outerr
captured_out, captured_err = self._captured_out, self._captured_err
if self._capture is not None:
out, err = self._capture.readouterr()
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):
"""Suspends this fixture's own capturing temporarily."""
self._capture.suspend_capturing()
try:
yield
finally:
def _resume(self):
"""Resumes this fixture's own capturing temporarily."""
self._capture.resume_capturing()
@contextlib.contextmanager
@ -463,6 +488,7 @@ class MultiCapture(object):
class NoCapture(object):
EMPTY_BUFFER = None
__init__ = start = done = suspend = resume = lambda *args: None
@ -472,6 +498,8 @@ class FDCaptureBinary(object):
snap() produces `bytes`
"""
EMPTY_BUFFER = bytes()
def __init__(self, targetfd, tmpfile=None):
self.targetfd = targetfd
try:
@ -545,6 +573,8 @@ class FDCapture(FDCaptureBinary):
snap() produces text
"""
EMPTY_BUFFER = str()
def snap(self):
res = FDCaptureBinary.snap(self)
enc = getattr(self.tmpfile, "encoding", None)
@ -554,6 +584,9 @@ class FDCapture(FDCaptureBinary):
class SysCapture(object):
EMPTY_BUFFER = str()
def __init__(self, fd, tmpfile=None):
name = patchsysdict[fd]
self._old = getattr(sys, name)
@ -591,6 +624,8 @@ class SysCapture(object):
class SysCaptureBinary(SysCapture):
EMPTY_BUFFER = bytes()
def snap(self):
res = self.tmpfile.buffer.getvalue()
self.tmpfile.seek(0)

View File

@ -2,6 +2,8 @@ import six
import warnings
import argparse
import py
FILE_OR_DIR = "file_or_dir"
@ -70,7 +72,8 @@ class Parser(object):
self.optparser = self._getparser()
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):
from _pytest._argcomplete import filescompleter
@ -106,7 +109,7 @@ class Parser(object):
the remaining arguments unknown at this point.
"""
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)
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):
capman = node.config.pluginmanager.getplugin("capturemanager")
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(err)
_enter_pdb(node, call.excinfo, report)

View File

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

View File

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

View File

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

View File

@ -22,6 +22,7 @@ import pytest
from _pytest.main import Session, EXIT_OK
from _pytest.assertion.rewrite import AssertionRewritingHook
from _pytest.compat import Path
from _pytest.compat import safe_str
IGNORE_PAM = [ # filenames added when obtaining details about the current user
u"/var/lib/sss/mc/passwd"
@ -34,7 +35,7 @@ def pytest_addoption(parser):
action="store_true",
dest="lsof",
default=False,
help=("run FD checks if lsof is available"),
help="run FD checks if lsof is available",
)
parser.addoption(
@ -273,7 +274,7 @@ class HookRecorder(object):
del self.calls[i]
return call
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))
def getcall(self, name):
@ -560,18 +561,22 @@ class Testdir(object):
return ret
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`.
args: All args will be treated as strings and joined using newlines.
: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.
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.
E.g. "testdir.makefile('.txt', 'line1', 'line2')"
kwargs: Each keyword is the name of a file, while the value of it will
:param kwargs: Each keyword is the name of a file, while the value of it will
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)
@ -677,7 +682,9 @@ class Testdir(object):
example_path.copy(result)
return result
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
@ -891,14 +898,12 @@ class Testdir(object):
return self._runpytest_method(*args, **kwargs)
def _ensure_basetemp(self, args):
args = [str(x) for x in args]
args = list(args)
for x in args:
if str(x).startswith("--basetemp"):
# print("basedtemp exists: %s" %(args,))
if safe_str(x).startswith("--basetemp"):
break
else:
args.append("--basetemp=%s" % self.tmpdir.dirpath("basetemp"))
# print("added basetemp: %s" %(args,))
return args
def parseconfig(self, *args):
@ -1024,7 +1029,7 @@ class Testdir(object):
"""
env = os.environ.copy()
env["PYTHONPATH"] = os.pathsep.join(
filter(None, [str(os.getcwd()), env.get("PYTHONPATH", "")])
filter(None, [os.getcwd(), env.get("PYTHONPATH", "")])
)
kw["env"] = env
@ -1043,14 +1048,13 @@ class Testdir(object):
Returns a :py:class:`RunResult`.
"""
return self._run(*cmdargs)
def _run(self, *cmdargs):
cmdargs = [str(x) for x in cmdargs]
cmdargs = [
str(arg) if isinstance(arg, py.path.local) else arg for arg in cmdargs
]
p1 = self.tmpdir.join("stdout")
p2 = self.tmpdir.join("stderr")
print("running:", " ".join(cmdargs))
print(" in:", str(py.path.local()))
print("running:", *cmdargs)
print(" in:", py.path.local())
f1 = codecs.open(str(p1), "w", encoding="utf8")
f2 = codecs.open(str(p2), "w", encoding="utf8")
try:
@ -1082,7 +1086,7 @@ class Testdir(object):
print("couldn't print to %s because of encoding" % (fp,))
def _getpytestargs(self):
return (sys.executable, "-mpytest")
return sys.executable, "-mpytest"
def runpython(self, script):
"""Run a python script using sys.executable as interpreter.

View File

@ -201,15 +201,19 @@ def pytest_collect_file(path, parent):
ext = path.ext
if ext == ".py":
if not parent.session.isinitpath(path):
for pat in parent.config.getini("python_files") + ["__init__.py"]:
if path.fnmatch(pat):
break
else:
if not path_matches_patterns(
path, parent.config.getini("python_files") + ["__init__.py"]
):
return
ihook = parent.session.gethookproxy(path)
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):
if path.basename == "__init__.py":
return Package(path, parent)
@ -590,17 +594,33 @@ class Package(Module):
self.session.config.pluginmanager._duplicatepaths.remove(path)
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):
# 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:
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
if path.isdir() and path.join("__init__.py").check(file=1):
pkg_prefixes.add(path)
for x in self._collectfile(path):
yield x
if isinstance(x, Package):
pkg_prefix = path.dirpath()
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"):
if excinfo.errisinstance(fail.Exception):
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)
def repr_failure(self, excinfo, outerr=None):

View File

@ -4,7 +4,7 @@ import sys
from numbers import Number
from decimal import Decimal
import py
import six
from six.moves import zip, filterfalse
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
try:
code = _pytest._code.Source(code).compile()
py.builtin.exec_(code, frame.f_globals, loc)
# XXX didn'T mean f_globals == f_locals something special?
six.exec_(code, frame.f_globals, loc)
# XXX didn't mean f_globals == f_locals something special?
# this is destroyed here ...
except expected_exception:
return _pytest._code.ExceptionInfo()

View File

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

View File

@ -6,7 +6,7 @@ import os
import sys
from time import time
import py
import six
from _pytest._code.code import ExceptionInfo
from _pytest.outcomes import skip, Skipped, TEST_OUTCOME
@ -317,7 +317,7 @@ class SetupState(object):
if exc is None:
exc = sys.exc_info()
if exc:
py.builtin._reraise(*exc)
six.reraise(*exc)
def _teardown_with_finalization(self, colitem):
self._callfinalizers(colitem)
@ -352,7 +352,7 @@ class SetupState(object):
if exc is None:
exc = sys.exc_info()
if exc:
py.builtin._reraise(*exc)
six.reraise(*exc)
def prepare(self, colitem):
""" 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
for col in self.stack:
if hasattr(col, "_prepare_exc"):
py.builtin._reraise(*col._prepare_exc)
six.reraise(*col._prepare_exc)
for col in needed_collectors[len(self.stack) :]:
self.stack.append(col)
try:

View File

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

View File

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

View File

@ -2,11 +2,11 @@
from __future__ import absolute_import, division, print_function
import os
import sys
import textwrap
import types
import six
import _pytest._code
import py
import pytest
from _pytest.main import EXIT_NOTESTSCOLLECTED, EXIT_USAGEERROR
@ -131,7 +131,7 @@ class TestGeneralUsage(object):
p2 = testdir.makefile(".pyc", "123")
result = testdir.runpytest(p1, p2)
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):
testdir.makepyfile("")
@ -201,8 +201,8 @@ class TestGeneralUsage(object):
testdir.tmpdir.join("py").mksymlinkto(py._pydir)
p = testdir.tmpdir.join("main.py")
p.write(
_pytest._code.Source(
"""
textwrap.dedent(
"""\
import sys, os
sys.path.insert(0, '')
import py
@ -453,7 +453,7 @@ class TestInvocationVariants(object):
@pytest.mark.xfail("sys.platform.startswith('java')")
def test_pydoc(self, testdir):
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
s = result.stdout.str()
assert "MarkGenerator" in s
@ -660,6 +660,16 @@ class TestInvocationVariants(object):
["*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")
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:
break
else:
raise AssertionError("not found %s %s" % (x, y))
raise AssertionError("not found {} {}".format(x, y))
def test_with_deselected(self, testdir):
testdir.makepyfile(self.source)

View File

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

View File

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

View File

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

View File

@ -1,6 +1,9 @@
"""Reproduces issue #3774"""
try:
import mock
except ImportError:
import unittest.mock as mock
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 contextlib
from functools import partial
from _pytest.capture import CaptureManager
from _pytest.logging import _LiveLoggingStreamHandler
class MockCaptureManager:
@ -890,10 +889,6 @@ def test_live_logging_suspends_capture(has_capture_manager, request):
yield
self.calls.append("exit disabled")
# sanity check
assert CaptureManager.suspend_capture_item
assert CaptureManager.resume_global_capture
class DummyTerminal(six.StringIO):
def section(self, *args, **kwargs):
pass

View File

@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
import os
import sys
from textwrap import dedent
import textwrap
import _pytest._code
import pytest
@ -47,13 +47,14 @@ class TestModule(object):
p = root2.join("test_x456.py")
monkeypatch.syspath_prepend(str(root1))
p.write(
dedent(
textwrap.dedent(
"""\
import x456
def test():
assert x456.__file__.startswith(%r)
"""
% str(root2)
assert x456.__file__.startswith({!r})
""".format(
str(root2)
)
)
)
with root2.as_cwd():
@ -929,8 +930,8 @@ class TestConftestCustomization(object):
def test_customized_pymakemodule_issue205_subdir(self, testdir):
b = testdir.mkdir("a").mkdir("b")
b.join("conftest.py").write(
_pytest._code.Source(
"""
textwrap.dedent(
"""\
import pytest
@pytest.hookimpl(hookwrapper=True)
def pytest_pycollect_makemodule():
@ -941,8 +942,8 @@ class TestConftestCustomization(object):
)
)
b.join("test_module.py").write(
_pytest._code.Source(
"""
textwrap.dedent(
"""\
def test_hello():
assert hello == "world"
"""
@ -954,8 +955,8 @@ class TestConftestCustomization(object):
def test_customized_pymakeitem(self, testdir):
b = testdir.mkdir("a").mkdir("b")
b.join("conftest.py").write(
_pytest._code.Source(
"""
textwrap.dedent(
"""\
import pytest
@pytest.hookimpl(hookwrapper=True)
def pytest_pycollect_makeitem():
@ -969,8 +970,8 @@ class TestConftestCustomization(object):
)
)
b.join("test_module.py").write(
_pytest._code.Source(
"""
textwrap.dedent(
"""\
import pytest
@pytest.fixture()
@ -1033,7 +1034,7 @@ class TestConftestCustomization(object):
)
testdir.makefile(
".narf",
"""
"""\
def test_something():
assert 1 + 1 == 2""",
)
@ -1046,8 +1047,8 @@ def test_setup_only_available_in_subdir(testdir):
sub1 = testdir.mkpydir("sub1")
sub2 = testdir.mkpydir("sub2")
sub1.join("conftest.py").write(
_pytest._code.Source(
"""
textwrap.dedent(
"""\
import pytest
def pytest_runtest_setup(item):
assert item.fspath.purebasename == "test_in_sub1"
@ -1059,8 +1060,8 @@ def test_setup_only_available_in_subdir(testdir):
)
)
sub2.join("conftest.py").write(
_pytest._code.Source(
"""
textwrap.dedent(
"""\
import pytest
def pytest_runtest_setup(item):
assert item.fspath.purebasename == "test_in_sub2"
@ -1547,8 +1548,8 @@ def test_skip_duplicates_by_default(testdir):
a = testdir.mkdir("a")
fh = a.join("test_a.py")
fh.write(
_pytest._code.Source(
"""
textwrap.dedent(
"""\
import pytest
def test_real():
pass
@ -1567,8 +1568,8 @@ def test_keep_duplicates(testdir):
a = testdir.mkdir("a")
fh = a.join("test_a.py")
fh.write(
_pytest._code.Source(
"""
textwrap.dedent(
"""\
import pytest
def test_real():
pass
@ -1623,3 +1624,38 @@ def test_package_with_modules(testdir):
root.chdir()
result = testdir.runpytest("-v", "-s")
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
from _pytest.pytester import get_public_names
from _pytest.fixtures import FixtureLookupError, FixtureRequest
@ -208,8 +208,8 @@ class TestFillFixtures(object):
)
subdir = testdir.mkpydir("subdir")
subdir.join("conftest.py").write(
_pytest._code.Source(
"""
textwrap.dedent(
"""\
import pytest
@pytest.fixture
@ -220,8 +220,8 @@ class TestFillFixtures(object):
)
testfile = subdir.join("test_spam.py")
testfile.write(
_pytest._code.Source(
"""
textwrap.dedent(
"""\
def test_spam(spam):
assert spam == "spam"
"""
@ -276,8 +276,8 @@ class TestFillFixtures(object):
)
subdir = testdir.mkpydir("subdir")
subdir.join("conftest.py").write(
_pytest._code.Source(
"""
textwrap.dedent(
"""\
import pytest
@pytest.fixture(params=[1, 2, 3])
@ -288,8 +288,8 @@ class TestFillFixtures(object):
)
testfile = subdir.join("test_spam.py")
testfile.write(
_pytest._code.Source(
"""
textwrap.dedent(
"""\
params = {'spam': 1}
def test_spam(spam):
@ -320,8 +320,8 @@ class TestFillFixtures(object):
)
subdir = testdir.mkpydir("subdir")
subdir.join("conftest.py").write(
_pytest._code.Source(
"""
textwrap.dedent(
"""\
import pytest
@pytest.fixture(params=[1, 2, 3])
@ -332,8 +332,8 @@ class TestFillFixtures(object):
)
testfile = subdir.join("test_spam.py")
testfile.write(
_pytest._code.Source(
"""
textwrap.dedent(
"""\
params = {'spam': 1}
def test_spam(spam):
@ -807,8 +807,8 @@ class TestRequestBasic(object):
# this tests that normalization of nodeids takes place
b = testdir.mkdir("tests").mkdir("unit")
b.join("conftest.py").write(
_pytest._code.Source(
"""
textwrap.dedent(
"""\
import pytest
@pytest.fixture
def arg1():
@ -1484,7 +1484,7 @@ class TestFixtureManagerParseFactories(object):
runner = testdir.mkdir("runner")
package = testdir.mkdir("package")
package.join("conftest.py").write(
dedent(
textwrap.dedent(
"""\
import pytest
@pytest.fixture
@ -1494,7 +1494,7 @@ class TestFixtureManagerParseFactories(object):
)
)
package.join("test_x.py").write(
dedent(
textwrap.dedent(
"""\
def test_x(one):
assert one == 1
@ -1504,7 +1504,7 @@ class TestFixtureManagerParseFactories(object):
sub = package.mkdir("sub")
sub.join("__init__.py").ensure()
sub.join("conftest.py").write(
dedent(
textwrap.dedent(
"""\
import pytest
@pytest.fixture
@ -1514,7 +1514,7 @@ class TestFixtureManagerParseFactories(object):
)
)
sub.join("test_y.py").write(
dedent(
textwrap.dedent(
"""\
def test_x(one):
assert one == 2
@ -1535,7 +1535,7 @@ class TestFixtureManagerParseFactories(object):
)
package = testdir.mkdir("package")
package.join("__init__.py").write(
dedent(
textwrap.dedent(
"""\
from .. import values
def setup_module():
@ -1546,7 +1546,7 @@ class TestFixtureManagerParseFactories(object):
)
)
package.join("test_x.py").write(
dedent(
textwrap.dedent(
"""\
from .. import values
def test_x():
@ -1556,7 +1556,7 @@ class TestFixtureManagerParseFactories(object):
)
package = testdir.mkdir("package2")
package.join("__init__.py").write(
dedent(
textwrap.dedent(
"""\
from .. import values
def setup_module():
@ -1567,7 +1567,7 @@ class TestFixtureManagerParseFactories(object):
)
)
package.join("test_x.py").write(
dedent(
textwrap.dedent(
"""\
from .. import values
def test_x():
@ -1587,7 +1587,7 @@ class TestFixtureManagerParseFactories(object):
package = testdir.mkdir("package")
package.join("__init__.py").write("")
package.join("conftest.py").write(
dedent(
textwrap.dedent(
"""\
import pytest
from .. import values
@ -1605,7 +1605,7 @@ class TestFixtureManagerParseFactories(object):
)
)
package.join("test_x.py").write(
dedent(
textwrap.dedent(
"""\
from .. import values
def test_package_autouse():
@ -1804,8 +1804,8 @@ class TestAutouseManagement(object):
def test_autouse_conftest_mid_directory(self, testdir):
pkgdir = testdir.mkpydir("xyz123")
pkgdir.join("conftest.py").write(
_pytest._code.Source(
"""
textwrap.dedent(
"""\
import pytest
@pytest.fixture(autouse=True)
def app():
@ -1816,8 +1816,8 @@ class TestAutouseManagement(object):
)
t = pkgdir.ensure("tests", "test_app.py")
t.write(
_pytest._code.Source(
"""
textwrap.dedent(
"""\
import sys
def test_app():
assert sys._myapp == "hello"
@ -2715,8 +2715,8 @@ class TestFixtureMarker(object):
)
b = testdir.mkdir("subdir")
b.join("test_overridden_fixture_finalizer.py").write(
dedent(
"""
textwrap.dedent(
"""\
import pytest
@pytest.fixture
def browser(browser):
@ -3217,8 +3217,8 @@ class TestShowFixtures(object):
def test_show_fixtures_trimmed_doc(self, testdir):
p = testdir.makepyfile(
dedent(
'''
textwrap.dedent(
'''\
import pytest
@pytest.fixture
def arg1():
@ -3239,8 +3239,8 @@ class TestShowFixtures(object):
)
result = testdir.runpytest("--fixtures", p)
result.stdout.fnmatch_lines(
dedent(
"""
textwrap.dedent(
"""\
* fixtures defined from test_show_fixtures_trimmed_doc *
arg2
line1
@ -3248,15 +3248,14 @@ class TestShowFixtures(object):
arg1
line1
line2
"""
)
)
def test_show_fixtures_indented_doc(self, testdir):
p = testdir.makepyfile(
dedent(
'''
textwrap.dedent(
'''\
import pytest
@pytest.fixture
def fixture1():
@ -3269,8 +3268,8 @@ class TestShowFixtures(object):
)
result = testdir.runpytest("--fixtures", p)
result.stdout.fnmatch_lines(
dedent(
"""
textwrap.dedent(
"""\
* fixtures defined from test_show_fixtures_indented_doc *
fixture1
line1
@ -3281,8 +3280,8 @@ class TestShowFixtures(object):
def test_show_fixtures_indented_doc_first_line_unindented(self, testdir):
p = testdir.makepyfile(
dedent(
'''
textwrap.dedent(
'''\
import pytest
@pytest.fixture
def fixture1():
@ -3295,8 +3294,8 @@ class TestShowFixtures(object):
)
result = testdir.runpytest("--fixtures", p)
result.stdout.fnmatch_lines(
dedent(
"""
textwrap.dedent(
"""\
* fixtures defined from test_show_fixtures_indented_doc_first_line_unindented *
fixture1
line1
@ -3308,8 +3307,8 @@ class TestShowFixtures(object):
def test_show_fixtures_indented_in_class(self, testdir):
p = testdir.makepyfile(
dedent(
'''
textwrap.dedent(
'''\
import pytest
class TestClass(object):
@pytest.fixture
@ -3323,8 +3322,8 @@ class TestShowFixtures(object):
)
result = testdir.runpytest("--fixtures", p)
result.stdout.fnmatch_lines(
dedent(
"""
textwrap.dedent(
"""\
* fixtures defined from test_show_fixtures_indented_in_class *
fixture1
line1
@ -3667,8 +3666,8 @@ class TestParameterizedSubRequest(object):
fixdir = testdir.mkdir("fixtures")
fixfile = fixdir.join("fix.py")
fixfile.write(
_pytest._code.Source(
"""
textwrap.dedent(
"""\
import pytest
@pytest.fixture(params=[0, 1, 2])
@ -3680,8 +3679,8 @@ class TestParameterizedSubRequest(object):
testfile = tests_dir.join("test_foos.py")
testfile.write(
_pytest._code.Source(
"""
textwrap.dedent(
"""\
from fix import fix_with_param
def test_foo(request):
@ -3698,9 +3697,9 @@ class TestParameterizedSubRequest(object):
E*Failed: The requested fixture has no parameter defined for the current test.
E*
E*Requested fixture 'fix_with_param' defined in:
E*fix.py:5
E*fix.py:4
E*Requested here:
E*test_foos.py:5
E*test_foos.py:4
*1 failed*
"""
)
@ -3979,3 +3978,71 @@ class TestScopeOrdering(object):
items, _ = testdir.inline_genitems()
request = FixtureRequest(items[0])
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 sys
import attr
import _pytest._code
import py
import textwrap
import pytest
from _pytest import python, fixtures
@ -295,9 +294,7 @@ class TestMetafunc(object):
)
assert result == ["a0-1.0", "a1-b1"]
# unicode mixing, issue250
result = idmaker(
(py.builtin._totext("a"), "b"), [pytest.param({}, b"\xc3\xb4")]
)
result = idmaker((u"a", "b"), [pytest.param({}, b"\xc3\xb4")])
assert result == ["a0-\\xc3\\xb4"]
def test_idmaker_with_bytes_regex(self):
@ -309,7 +306,6 @@ class TestMetafunc(object):
def test_idmaker_native_strings(self):
from _pytest.python import idmaker
totext = py.builtin._totext
result = idmaker(
("a", "b"),
[
@ -324,7 +320,7 @@ class TestMetafunc(object):
pytest.param({7}, set("seven")),
pytest.param(tuple("eight"), (8, -8, 8)),
pytest.param(b"\xc3\xb4", b"name"),
pytest.param(b"\xc3\xb4", totext("other")),
pytest.param(b"\xc3\xb4", u"other"),
],
)
assert result == [
@ -1275,16 +1271,16 @@ class TestMetafuncFunctional(object):
sub1 = testdir.mkpydir("sub1")
sub2 = testdir.mkpydir("sub2")
sub1.join("conftest.py").write(
_pytest._code.Source(
"""
textwrap.dedent(
"""\
def pytest_generate_tests(metafunc):
assert metafunc.function.__name__ == "test_1"
"""
)
)
sub2.join("conftest.py").write(
_pytest._code.Source(
"""
textwrap.dedent(
"""\
def pytest_generate_tests(metafunc):
assert metafunc.function.__name__ == "test_2"
"""

View File

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

View File

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

View File

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

View File

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

View File

@ -1,3 +1,4 @@
# -*- coding: utf-8 -*-
from __future__ import absolute_import, division, print_function
# note: py.io capture tests where copied from
@ -5,13 +6,13 @@ from __future__ import absolute_import, division, print_function
import pickle
import os
import sys
import textwrap
from io import UnsupportedOperation
import _pytest._code
import py
import pytest
import contextlib
from six import binary_type, text_type
from six import text_type
from _pytest import capture
from _pytest.capture import CaptureManager
from _pytest.main import EXIT_NOTESTSCOLLECTED
@ -23,12 +24,12 @@ needsosdup = pytest.mark.xfail("not hasattr(os, 'dup')")
def tobytes(obj):
if isinstance(obj, text_type):
obj = obj.encode("UTF-8")
assert isinstance(obj, binary_type)
assert isinstance(obj, bytes)
return obj
def totext(obj):
if isinstance(obj, binary_type):
if isinstance(obj, bytes):
obj = text_type(obj, "UTF-8")
assert isinstance(obj, text_type)
return obj
@ -70,19 +71,23 @@ class TestCaptureManager(object):
try:
capman = CaptureManager(method)
capman.start_global_capturing()
outerr = capman.suspend_global_capture()
capman.suspend_global_capture()
outerr = capman.read_global_capture()
assert outerr == ("", "")
outerr = capman.suspend_global_capture()
capman.suspend_global_capture()
outerr = capman.read_global_capture()
assert outerr == ("", "")
print("hello")
out, err = capman.suspend_global_capture()
capman.suspend_global_capture()
out, err = capman.read_global_capture()
if method == "no":
assert old == (sys.stdout, sys.stderr, sys.stdin)
else:
assert not out
capman.resume_global_capture()
print("hello")
out, err = capman.suspend_global_capture()
capman.suspend_global_capture()
out, err = capman.read_global_capture()
if method != "no":
assert out == "hello\n"
capman.stop_global_capturing()
@ -264,7 +269,7 @@ class TestPerTestCapturing(object):
def test_capturing_outerr(self, testdir):
p1 = testdir.makepyfile(
"""
"""\
import sys
def test_capturing():
print (42)
@ -293,7 +298,7 @@ class TestPerTestCapturing(object):
class TestLoggingInteraction(object):
def test_logging_stream_ownership(self, testdir):
p = testdir.makepyfile(
"""
"""\
def test_logging():
import logging
import pytest
@ -307,7 +312,7 @@ class TestLoggingInteraction(object):
def test_logging_and_immediate_setupteardown(self, testdir):
p = testdir.makepyfile(
"""
"""\
import logging
def setup_function(function):
logging.warn("hello1")
@ -333,7 +338,7 @@ class TestLoggingInteraction(object):
def test_logging_and_crossscope_fixtures(self, testdir):
p = testdir.makepyfile(
"""
"""\
import logging
def setup_module(function):
logging.warn("hello1")
@ -359,7 +364,7 @@ class TestLoggingInteraction(object):
def test_conftestlogging_is_shown(self, testdir):
testdir.makeconftest(
"""
"""\
import logging
logging.basicConfig()
logging.warn("hello435")
@ -373,14 +378,14 @@ class TestLoggingInteraction(object):
def test_conftestlogging_and_test_logging(self, testdir):
testdir.makeconftest(
"""
"""\
import logging
logging.basicConfig()
"""
)
# make sure that logging is still captured in tests
p = testdir.makepyfile(
"""
"""\
def test_hello():
import logging
logging.warn("hello433")
@ -398,7 +403,7 @@ class TestCaptureFixture(object):
@pytest.mark.parametrize("opt", [[], ["-s"]])
def test_std_functional(self, testdir, opt):
reprec = testdir.inline_runsource(
"""
"""\
def test_hello(capsys):
print (42)
out, err = capsys.readouterr()
@ -410,7 +415,7 @@ class TestCaptureFixture(object):
def test_capsyscapfd(self, testdir):
p = testdir.makepyfile(
"""
"""\
def test_one(capsys, capfd):
pass
def test_two(capfd, capsys):
@ -433,7 +438,7 @@ class TestCaptureFixture(object):
in the same test is an error.
"""
testdir.makepyfile(
"""
"""\
def test_one(capsys, request):
request.getfixturevalue("capfd")
def test_two(capfd, request):
@ -453,7 +458,7 @@ class TestCaptureFixture(object):
def test_capsyscapfdbinary(self, testdir):
p = testdir.makepyfile(
"""
"""\
def test_one(capsys, capfdbinary):
pass
"""
@ -466,12 +471,13 @@ class TestCaptureFixture(object):
@pytest.mark.parametrize("method", ["sys", "fd"])
def test_capture_is_represented_on_failure_issue128(self, testdir, method):
p = testdir.makepyfile(
"""
def test_hello(cap%s):
"""\
def test_hello(cap{}):
print ("xxx42xxx")
assert 0
"""
% method
""".format(
method
)
)
result = testdir.runpytest(p)
result.stdout.fnmatch_lines(["xxx42xxx"])
@ -479,7 +485,7 @@ class TestCaptureFixture(object):
@needsosdup
def test_stdfd_functional(self, testdir):
reprec = testdir.inline_runsource(
"""
"""\
def test_hello(capfd):
import os
os.write(1, "42".encode('ascii'))
@ -493,7 +499,7 @@ class TestCaptureFixture(object):
@needsosdup
def test_capfdbinary(self, testdir):
reprec = testdir.inline_runsource(
"""
"""\
def test_hello(capfdbinary):
import os
# some likely un-decodable bytes
@ -510,7 +516,7 @@ class TestCaptureFixture(object):
)
def test_capsysbinary(self, testdir):
reprec = testdir.inline_runsource(
"""
"""\
def test_hello(capsysbinary):
import sys
# some likely un-decodable bytes
@ -527,7 +533,7 @@ class TestCaptureFixture(object):
)
def test_capsysbinary_forbidden_in_python2(self, testdir):
testdir.makepyfile(
"""
"""\
def test_hello(capsysbinary):
pass
"""
@ -543,7 +549,7 @@ class TestCaptureFixture(object):
def test_partial_setup_failure(self, testdir):
p = testdir.makepyfile(
"""
"""\
def test_hello(capsys, missingarg):
pass
"""
@ -554,7 +560,7 @@ class TestCaptureFixture(object):
@needsosdup
def test_keyboardinterrupt_disables_capturing(self, testdir):
p = testdir.makepyfile(
"""
"""\
def test_hello(capfd):
import os
os.write(1, str(42).encode('ascii'))
@ -568,7 +574,7 @@ class TestCaptureFixture(object):
@pytest.mark.issue14
def test_capture_and_logging(self, testdir):
p = testdir.makepyfile(
"""
"""\
import logging
def test_log(capsys):
logging.error('x')
@ -581,7 +587,7 @@ class TestCaptureFixture(object):
@pytest.mark.parametrize("no_capture", [True, False])
def test_disabled_capture_fixture(self, testdir, fixture, no_capture):
testdir.makepyfile(
"""
"""\
def test_disabled({fixture}):
print('captured before')
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.
"""
testdir.makepyfile(
"""
"""\
from __future__ import print_function
import sys
import pytest
@ -647,12 +653,40 @@ class TestCaptureFixture(object):
assert "stdout 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):
sub1 = testdir.mkpydir("sub1")
sub1.join("conftest.py").write(
_pytest._code.Source(
"""
textwrap.dedent(
"""\
def pytest_runtest_setup(item):
raise ValueError(42)
"""
@ -1051,9 +1085,9 @@ class TestStdCapture(object):
def test_capturing_readouterr_unicode(self):
with self.getcapture() as cap:
print("hx\xc4\x85\xc4\x87")
print("hxąć")
out, err = cap.readouterr()
assert out == py.builtin._totext("hx\xc4\x85\xc4\x87\n", "utf8")
assert out == u"hxąć\n"
@pytest.mark.skipif(
"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
print("\xa6")
out, err = cap.readouterr()
assert out == py.builtin._totext("\ufffd\n", "unicode-escape")
assert out == u"\ufffd\n"
def test_reset_twice_error(self):
with self.getcapture() as cap:
@ -1387,9 +1421,69 @@ def test_pickling_and_unpickling_encoded_file():
pickle.loads(ef_as_str)
def test_capsys_with_cli_logging(testdir):
def test_global_capture_with_live_logging(testdir):
# 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(
"""
import logging
@ -1397,22 +1491,23 @@ def test_capsys_with_cli_logging(testdir):
logger = logging.getLogger(__name__)
def test_myoutput(capsys): # or use "capfd" for fd-level
def test_capture({0}):
print("hello")
sys.stderr.write("world\\n")
captured = capsys.readouterr()
captured = {0}.readouterr()
assert captured.out == "hello\\n"
assert captured.err == "world\\n"
logging.info("something")
print("next")
logging.info("something")
captured = capsys.readouterr()
captured = {0}.readouterr()
assert captured.out == "next\\n"
"""
""".format(
capture_fixture
)
)
result = testdir.runpytest_subprocess("--log-cli-level=INFO")
assert result.ret == 0

View File

@ -1,9 +1,9 @@
from __future__ import absolute_import, division, print_function
import pprint
import sys
import textwrap
import pytest
import _pytest._code
from _pytest.main import Session, EXIT_NOTESTSCOLLECTED, _in_venv
@ -913,8 +913,8 @@ def test_fixture_scope_sibling_conftests(testdir):
"""Regression test case for https://github.com/pytest-dev/pytest/issues/2836"""
foo_path = testdir.mkdir("foo")
foo_path.join("conftest.py").write(
_pytest._code.Source(
"""
textwrap.dedent(
"""\
import pytest
@pytest.fixture
def fix():
@ -938,3 +938,17 @@ def test_fixture_scope_sibling_conftests(testdir):
"*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,8 +17,8 @@ class TestParseIni(object):
sub = tmpdir.mkdir("sub")
sub.chdir()
tmpdir.join(filename).write(
_pytest._code.Source(
"""
textwrap.dedent(
"""\
[{section}]
name = value
""".format(
@ -38,8 +38,8 @@ class TestParseIni(object):
def test_append_parse_args(self, testdir, tmpdir, monkeypatch):
monkeypatch.setenv("PYTEST_ADDOPTS", '--color no -rs --tb="short"')
tmpdir.join("pytest.ini").write(
_pytest._code.Source(
"""
textwrap.dedent(
"""\
[pytest]
addopts = --verbose
"""
@ -438,8 +438,8 @@ class TestConfigFromdictargs(object):
def test_inifilename(self, tmpdir):
tmpdir.join("foo/bar.ini").ensure().write(
_pytest._code.Source(
"""
textwrap.dedent(
"""\
[pytest]
name = value
"""
@ -453,8 +453,8 @@ class TestConfigFromdictargs(object):
cwd = tmpdir.join("a/b")
cwd.join("pytest.ini").ensure().write(
_pytest._code.Source(
"""
textwrap.dedent(
"""\
[pytest]
name = wrong-value
should_not_be_set = true

View File

@ -1,7 +1,6 @@
from __future__ import absolute_import, division, print_function
from textwrap import dedent
import textwrap
import _pytest._code
import py
import pytest
from _pytest.config import PytestPluginManager
@ -174,8 +173,8 @@ def test_conftest_confcutdir(testdir):
testdir.makeconftest("assert 0")
x = testdir.mkdir("x")
x.join("conftest.py").write(
_pytest._code.Source(
"""
textwrap.dedent(
"""\
def pytest_addoption(parser):
parser.addoption("--xyz", action="store_true")
"""
@ -198,8 +197,8 @@ def test_no_conftest(testdir):
def test_conftest_existing_resultlog(testdir):
x = testdir.mkdir("tests")
x.join("conftest.py").write(
_pytest._code.Source(
"""
textwrap.dedent(
"""\
def pytest_addoption(parser):
parser.addoption("--xyz", action="store_true")
"""
@ -213,8 +212,8 @@ def test_conftest_existing_resultlog(testdir):
def test_conftest_existing_junitxml(testdir):
x = testdir.mkdir("tests")
x.join("conftest.py").write(
_pytest._code.Source(
"""
textwrap.dedent(
"""\
def pytest_addoption(parser):
parser.addoption("--xyz", action="store_true")
"""
@ -247,8 +246,8 @@ def test_fixture_dependency(testdir, monkeypatch):
sub = testdir.mkdir("sub")
sub.join("__init__.py").write("")
sub.join("conftest.py").write(
dedent(
"""
textwrap.dedent(
"""\
import pytest
@pytest.fixture
@ -268,8 +267,8 @@ def test_fixture_dependency(testdir, monkeypatch):
subsub = sub.mkdir("subsub")
subsub.join("__init__.py").write("")
subsub.join("test_bar.py").write(
dedent(
"""
textwrap.dedent(
"""\
import pytest
@pytest.fixture
@ -288,8 +287,8 @@ def test_fixture_dependency(testdir, monkeypatch):
def test_conftest_found_with_double_dash(testdir):
sub = testdir.mkdir("sub")
sub.join("conftest.py").write(
dedent(
"""
textwrap.dedent(
"""\
def pytest_addoption(parser):
parser.addoption("--hello-world", action="store_true")
"""
@ -313,7 +312,7 @@ class TestConftestVisibility(object):
package = testdir.mkdir("package")
package.join("conftest.py").write(
dedent(
textwrap.dedent(
"""\
import pytest
@pytest.fixture
@ -323,7 +322,7 @@ class TestConftestVisibility(object):
)
)
package.join("test_pkgroot.py").write(
dedent(
textwrap.dedent(
"""\
def test_pkgroot(fxtr):
assert fxtr == "from-package"
@ -334,7 +333,7 @@ class TestConftestVisibility(object):
swc = package.mkdir("swc")
swc.join("__init__.py").ensure()
swc.join("conftest.py").write(
dedent(
textwrap.dedent(
"""\
import pytest
@pytest.fixture
@ -344,11 +343,10 @@ class TestConftestVisibility(object):
)
)
swc.join("test_with_conftest.py").write(
dedent(
textwrap.dedent(
"""\
def test_with_conftest(fxtr):
assert fxtr == "from-swc"
"""
)
)
@ -356,12 +354,11 @@ class TestConftestVisibility(object):
snc = package.mkdir("snc")
snc.join("__init__.py").ensure()
snc.join("test_no_conftest.py").write(
dedent(
textwrap.dedent(
"""\
def test_no_conftest(fxtr):
assert fxtr == "from-package" # No local conftest.py, so should
# use value from parent dir's
"""
)
)
@ -422,8 +419,8 @@ def test_search_conftest_up_to_inifile(testdir, confcutdir, passed, error):
src = root.join("src").ensure(dir=1)
src.join("pytest.ini").write("[pytest]")
src.join("conftest.py").write(
_pytest._code.Source(
"""
textwrap.dedent(
"""\
import pytest
@pytest.fixture
def fix1(): pass
@ -431,8 +428,8 @@ def test_search_conftest_up_to_inifile(testdir, confcutdir, passed, error):
)
)
src.join("test_foo.py").write(
_pytest._code.Source(
"""
textwrap.dedent(
"""\
def test_1(fix1):
pass
def test_2(out_of_reach):
@ -441,8 +438,8 @@ def test_search_conftest_up_to_inifile(testdir, confcutdir, passed, error):
)
)
root.join("conftest.py").write(
_pytest._code.Source(
"""
textwrap.dedent(
"""\
import pytest
@pytest.fixture
def out_of_reach(): pass
@ -464,7 +461,7 @@ def test_search_conftest_up_to_inifile(testdir, confcutdir, passed, error):
def test_issue1073_conftest_special_objects(testdir):
testdir.makeconftest(
"""
"""\
class DontTouchMe(object):
def __getattr__(self, x):
raise Exception('cant touch me')
@ -473,7 +470,7 @@ def test_issue1073_conftest_special_objects(testdir):
"""
)
testdir.makepyfile(
"""
"""\
def test_some():
pass
"""
@ -484,12 +481,12 @@ def test_issue1073_conftest_special_objects(testdir):
def test_conftest_exception_handling(testdir):
testdir.makeconftest(
"""
"""\
raise ValueError()
"""
)
testdir.makepyfile(
"""
"""\
def test_some():
pass
"""
@ -507,7 +504,7 @@ def test_hook_proxy(testdir):
**{
"root/demo-0/test_foo1.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):
return True
""",
@ -525,8 +522,8 @@ def test_required_option_help(testdir):
testdir.makeconftest("assert 0")
x = testdir.mkdir("x")
x.join("conftest.py").write(
_pytest._code.Source(
"""
textwrap.dedent(
"""\
def pytest_addoption(parser):
parser.addoption("--xyz", action="store_true", required=True)
"""

View File

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

View File

@ -7,7 +7,9 @@ def test_version(testdir, pytestconfig):
result = testdir.runpytest("--version")
assert result.ret == 0
# 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():
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):
path = testdir.tmpdir.join("test.xml")
log = LogXML(str(path), None)
ustr = py.builtin._totext("ВНИ!", "utf-8")
ustr = u"ВНИ!"
class Report(BaseReport):
longrepr = ustr

View File

@ -228,11 +228,15 @@ def test_syspath_prepend(mp):
def test_syspath_prepend_double_undo(mp):
old_syspath = sys.path[:]
try:
mp.syspath_prepend("hello world")
mp.undo()
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):

View File

@ -294,7 +294,7 @@ def test_argcomplete(testdir, monkeypatch):
script = str(testdir.tmpdir.join("test_argcomplete"))
pytest_bin = sys.argv[0]
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:
# redirect output from argcomplete to stdin and stderr is not trivial

View File

@ -260,7 +260,9 @@ class TestPDB(object):
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"):
child.expect("captured log")
child.expect("get rekt")
@ -473,7 +475,7 @@ class TestPDB(object):
x = 5
"""
)
child = testdir.spawn("%s %s" % (sys.executable, p1))
child = testdir.spawn("{} {}".format(sys.executable, p1))
child.expect("x = 5")
child.sendeof()
self.flush(child)

View File

@ -25,7 +25,6 @@ class TestPytestPluginInteractions(object):
)
conf = testdir.makeconftest(
"""
import sys ; sys.path.insert(0, '.')
import newhooks
def pytest_addhooks(pluginmanager):
pluginmanager.addhooks(newhooks)
@ -263,8 +262,7 @@ class TestPytestPluginManager(object):
mod.pytest_plugins = "pytest_a"
aplugin = testdir.makepyfile(pytest_a="#")
reprec = testdir.make_hook_recorder(pytestpm)
# syspath.prepend(aplugin.dirpath())
sys.path.insert(0, str(aplugin.dirpath()))
testdir.syspathinsert(aplugin.dirpath())
pytestpm.consider_module(mod)
call = reprec.getcall(pytestpm.hook.pytest_plugin_registered.name)
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 CwdSnapshot, SysModulesSnapshot, SysPathsSnapshot
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):
@ -266,57 +266,6 @@ class TestInlineRunModulesCleanup(object):
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):
testdir.makepyfile("def test_foo(): assert True")
@ -447,3 +396,8 @@ class TestSysPathsSnapshot(object):
def test_testdir_subprocess(testdir):
testfile = testdir.makepyfile("def test_one(): pass")
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
import collections
import sys
import textwrap
import pluggy
import _pytest._code
import py
import pytest
from _pytest.main import EXIT_NOTESTSCOLLECTED
@ -161,8 +161,8 @@ class TestTerminal(object):
def test_itemreport_directclasses_not_shown_as_subclasses(self, testdir):
a = testdir.mkpydir("a123")
a.join("test_hello123.py").write(
_pytest._code.Source(
"""
textwrap.dedent(
"""\
class TestClass(object):
def test_method(self):
pass
@ -312,8 +312,8 @@ class TestCollectonly(object):
result = testdir.runpytest("--collect-only", p)
assert result.ret == 2
result.stdout.fnmatch_lines(
_pytest._code.Source(
"""
textwrap.dedent(
"""\
*ERROR*
*ImportError*
*No module named *Errlk*
@ -948,6 +948,46 @@ def pytest_report_header(config, startdir):
assert "!This is stderr!" 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')")
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):
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)
print('Actually got: "%s"; with color "%s"' % (line, color))
print('Actually got: "{}"; with color "{}"'.format(line, color))
assert line == exp_line
assert color == exp_color

View File

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