Merge pull request #2315 from RonnyPfannschmidt/namespace-hook
remove pytest internal usage of the namespace hook
This commit is contained in:
commit
25371ddbfd
|
@ -27,6 +27,10 @@ New Features
|
||||||
Changes
|
Changes
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
* remove all internal uses of pytest_namespace hooks,
|
||||||
|
this is to prepare the removal of preloadconfig in pytest 4.0
|
||||||
|
Thanks to `@RonnyPfannschmidt`_ for the PR.
|
||||||
|
|
||||||
* Old-style classes have been changed to new-style classes in order to improve
|
* Old-style classes have been changed to new-style classes in order to improve
|
||||||
compatibility with Python 2. Thanks to `@MichalTHEDUDE`_ and `@mandeep`_ for the PR (`#2147`_).
|
compatibility with Python 2. Thanks to `@MichalTHEDUDE`_ and `@mandeep`_ for the PR (`#2147`_).
|
||||||
|
|
||||||
|
|
|
@ -25,9 +25,6 @@ def pytest_addoption(parser):
|
||||||
expression information.""")
|
expression information.""")
|
||||||
|
|
||||||
|
|
||||||
def pytest_namespace():
|
|
||||||
return {'register_assert_rewrite': register_assert_rewrite}
|
|
||||||
|
|
||||||
|
|
||||||
def register_assert_rewrite(*names):
|
def register_assert_rewrite(*names):
|
||||||
"""Register one or more module names to be rewritten on import.
|
"""Register one or more module names to be rewritten on import.
|
||||||
|
|
|
@ -254,6 +254,29 @@ else:
|
||||||
return v.encode('ascii', errors)
|
return v.encode('ascii', errors)
|
||||||
|
|
||||||
|
|
||||||
|
COLLECT_FAKEMODULE_ATTRIBUTES = (
|
||||||
|
'Collector',
|
||||||
|
'Module',
|
||||||
|
'Generator',
|
||||||
|
'Function',
|
||||||
|
'Instance',
|
||||||
|
'Session',
|
||||||
|
'Item',
|
||||||
|
'Class',
|
||||||
|
'File',
|
||||||
|
'_fillfuncargs',
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _setup_collect_fakemodule():
|
||||||
|
from types import ModuleType
|
||||||
|
import pytest
|
||||||
|
pytest.collect = ModuleType('pytest.collect')
|
||||||
|
pytest.collect.__all__ = [] # used for setns
|
||||||
|
for attr in COLLECT_FAKEMODULE_ATTRIBUTES:
|
||||||
|
setattr(pytest.collect, attr, getattr(pytest, attr))
|
||||||
|
|
||||||
|
|
||||||
if _PY2:
|
if _PY2:
|
||||||
from py.io import TextIO as CaptureIO
|
from py.io import TextIO as CaptureIO
|
||||||
else:
|
else:
|
||||||
|
@ -268,3 +291,12 @@ else:
|
||||||
|
|
||||||
def getvalue(self):
|
def getvalue(self):
|
||||||
return self.buffer.getvalue().decode('UTF-8')
|
return self.buffer.getvalue().decode('UTF-8')
|
||||||
|
|
||||||
|
class FuncargnamesCompatAttr(object):
|
||||||
|
""" helper class so that Metafunc, Function and FixtureRequest
|
||||||
|
don't need to each define the "funcargnames" compatibility attribute.
|
||||||
|
"""
|
||||||
|
@property
|
||||||
|
def funcargnames(self):
|
||||||
|
""" alias attribute for ``fixturenames`` for pre-2.3 compatibility"""
|
||||||
|
return self.fixturenames
|
||||||
|
|
|
@ -100,6 +100,7 @@ default_plugins = (
|
||||||
"junitxml resultlog doctest cacheprovider freeze_support "
|
"junitxml resultlog doctest cacheprovider freeze_support "
|
||||||
"setuponly setupplan warnings").split()
|
"setuponly setupplan warnings").split()
|
||||||
|
|
||||||
|
|
||||||
builtin_plugins = set(default_plugins)
|
builtin_plugins = set(default_plugins)
|
||||||
builtin_plugins.add("pytester")
|
builtin_plugins.add("pytester")
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,6 @@ from __future__ import absolute_import, division, print_function
|
||||||
import pdb
|
import pdb
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
import pytest
|
|
||||||
|
|
||||||
|
|
||||||
def pytest_addoption(parser):
|
def pytest_addoption(parser):
|
||||||
|
@ -16,8 +15,6 @@ def pytest_addoption(parser):
|
||||||
help="start a custom interactive Python debugger on errors. "
|
help="start a custom interactive Python debugger on errors. "
|
||||||
"For example: --pdbcls=IPython.terminal.debugger:TerminalPdb")
|
"For example: --pdbcls=IPython.terminal.debugger:TerminalPdb")
|
||||||
|
|
||||||
def pytest_namespace():
|
|
||||||
return {'set_trace': pytestPDB().set_trace}
|
|
||||||
|
|
||||||
def pytest_configure(config):
|
def pytest_configure(config):
|
||||||
if config.getvalue("usepdb_cls"):
|
if config.getvalue("usepdb_cls"):
|
||||||
|
@ -37,31 +34,33 @@ def pytest_configure(config):
|
||||||
pytestPDB._config = None
|
pytestPDB._config = None
|
||||||
pytestPDB._pdb_cls = pdb.Pdb
|
pytestPDB._pdb_cls = pdb.Pdb
|
||||||
|
|
||||||
pdb.set_trace = pytest.set_trace
|
pdb.set_trace = pytestPDB.set_trace
|
||||||
pytestPDB._pluginmanager = config.pluginmanager
|
pytestPDB._pluginmanager = config.pluginmanager
|
||||||
pytestPDB._config = config
|
pytestPDB._config = config
|
||||||
pytestPDB._pdb_cls = pdb_cls
|
pytestPDB._pdb_cls = pdb_cls
|
||||||
config._cleanup.append(fin)
|
config._cleanup.append(fin)
|
||||||
|
|
||||||
|
|
||||||
class pytestPDB(object):
|
class pytestPDB(object):
|
||||||
""" Pseudo PDB that defers to the real pdb. """
|
""" Pseudo PDB that defers to the real pdb. """
|
||||||
_pluginmanager = None
|
_pluginmanager = None
|
||||||
_config = None
|
_config = None
|
||||||
_pdb_cls = pdb.Pdb
|
_pdb_cls = pdb.Pdb
|
||||||
|
|
||||||
def set_trace(self):
|
@classmethod
|
||||||
|
def set_trace(cls):
|
||||||
""" invoke PDB set_trace debugging, dropping any IO capturing. """
|
""" invoke PDB set_trace debugging, dropping any IO capturing. """
|
||||||
import _pytest.config
|
import _pytest.config
|
||||||
frame = sys._getframe().f_back
|
frame = sys._getframe().f_back
|
||||||
if self._pluginmanager is not None:
|
if cls._pluginmanager is not None:
|
||||||
capman = self._pluginmanager.getplugin("capturemanager")
|
capman = cls._pluginmanager.getplugin("capturemanager")
|
||||||
if capman:
|
if capman:
|
||||||
capman.suspendcapture(in_=True)
|
capman.suspendcapture(in_=True)
|
||||||
tw = _pytest.config.create_terminal_writer(self._config)
|
tw = _pytest.config.create_terminal_writer(cls._config)
|
||||||
tw.line()
|
tw.line()
|
||||||
tw.sep(">", "PDB set_trace (IO-capturing turned off)")
|
tw.sep(">", "PDB set_trace (IO-capturing turned off)")
|
||||||
self._pluginmanager.hook.pytest_enter_pdb(config=self._config)
|
cls._pluginmanager.hook.pytest_enter_pdb(config=cls._config)
|
||||||
self._pdb_cls().set_trace(frame)
|
cls._pdb_cls().set_trace(frame)
|
||||||
|
|
||||||
|
|
||||||
class PdbInvoke(object):
|
class PdbInvoke(object):
|
||||||
|
@ -75,7 +74,7 @@ class PdbInvoke(object):
|
||||||
|
|
||||||
def pytest_internalerror(self, excrepr, excinfo):
|
def pytest_internalerror(self, excrepr, excinfo):
|
||||||
for line in str(excrepr).split("\n"):
|
for line in str(excrepr).split("\n"):
|
||||||
sys.stderr.write("INTERNALERROR> %s\n" %line)
|
sys.stderr.write("INTERNALERROR> %s\n" % line)
|
||||||
sys.stderr.flush()
|
sys.stderr.flush()
|
||||||
tb = _postmortem_traceback(excinfo)
|
tb = _postmortem_traceback(excinfo)
|
||||||
post_mortem(tb)
|
post_mortem(tb)
|
||||||
|
|
|
@ -4,7 +4,6 @@ import sys
|
||||||
from py._code.code import FormattedExcinfo
|
from py._code.code import FormattedExcinfo
|
||||||
|
|
||||||
import py
|
import py
|
||||||
import pytest
|
|
||||||
import warnings
|
import warnings
|
||||||
|
|
||||||
import inspect
|
import inspect
|
||||||
|
@ -17,8 +16,16 @@ from _pytest.compat import (
|
||||||
getlocation, getfuncargnames,
|
getlocation, getfuncargnames,
|
||||||
safe_getattr,
|
safe_getattr,
|
||||||
)
|
)
|
||||||
|
from _pytest.runner import fail
|
||||||
|
from _pytest.compat import FuncargnamesCompatAttr
|
||||||
|
|
||||||
def pytest_sessionstart(session):
|
def pytest_sessionstart(session):
|
||||||
|
import _pytest.python
|
||||||
|
scopename2class.update({
|
||||||
|
'class': _pytest.python.Class,
|
||||||
|
'module': _pytest.python.Module,
|
||||||
|
'function': _pytest.main.Item,
|
||||||
|
})
|
||||||
session._fixturemanager = FixtureManager(session)
|
session._fixturemanager = FixtureManager(session)
|
||||||
|
|
||||||
|
|
||||||
|
@ -45,19 +52,6 @@ def scopeproperty(name=None, doc=None):
|
||||||
return decoratescope
|
return decoratescope
|
||||||
|
|
||||||
|
|
||||||
def pytest_namespace():
|
|
||||||
scopename2class.update({
|
|
||||||
'class': pytest.Class,
|
|
||||||
'module': pytest.Module,
|
|
||||||
'function': pytest.Item,
|
|
||||||
})
|
|
||||||
return {
|
|
||||||
'fixture': fixture,
|
|
||||||
'yield_fixture': yield_fixture,
|
|
||||||
'collect': {'_fillfuncargs': fillfixtures}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def get_scope_node(node, scope):
|
def get_scope_node(node, scope):
|
||||||
cls = scopename2class.get(scope)
|
cls = scopename2class.get(scope)
|
||||||
if cls is None:
|
if cls is None:
|
||||||
|
@ -105,7 +99,7 @@ def add_funcarg_pseudo_fixture_def(collector, metafunc, fixturemanager):
|
||||||
if scope != "function":
|
if scope != "function":
|
||||||
node = get_scope_node(collector, scope)
|
node = get_scope_node(collector, scope)
|
||||||
if node is None:
|
if node is None:
|
||||||
assert scope == "class" and isinstance(collector, pytest.Module)
|
assert scope == "class" and isinstance(collector, _pytest.python.Module)
|
||||||
# use module-level collector for class-scope (for now)
|
# use module-level collector for class-scope (for now)
|
||||||
node = collector
|
node = collector
|
||||||
if node and argname in node._name2pseudofixturedef:
|
if node and argname in node._name2pseudofixturedef:
|
||||||
|
@ -221,17 +215,6 @@ def slice_items(items, ignore, scoped_argkeys_cache):
|
||||||
return items, None, None, None
|
return items, None, None, None
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class FuncargnamesCompatAttr(object):
|
|
||||||
""" helper class so that Metafunc, Function and FixtureRequest
|
|
||||||
don't need to each define the "funcargnames" compatibility attribute.
|
|
||||||
"""
|
|
||||||
@property
|
|
||||||
def funcargnames(self):
|
|
||||||
""" alias attribute for ``fixturenames`` for pre-2.3 compatibility"""
|
|
||||||
return self.fixturenames
|
|
||||||
|
|
||||||
|
|
||||||
def fillfixtures(function):
|
def fillfixtures(function):
|
||||||
""" fill missing funcargs for a test function. """
|
""" fill missing funcargs for a test function. """
|
||||||
try:
|
try:
|
||||||
|
@ -327,7 +310,7 @@ class FixtureRequest(FuncargnamesCompatAttr):
|
||||||
@scopeproperty("class")
|
@scopeproperty("class")
|
||||||
def cls(self):
|
def cls(self):
|
||||||
""" class (can be None) where the test function was collected. """
|
""" class (can be None) where the test function was collected. """
|
||||||
clscol = self._pyfuncitem.getparent(pytest.Class)
|
clscol = self._pyfuncitem.getparent(_pytest.python.Class)
|
||||||
if clscol:
|
if clscol:
|
||||||
return clscol.obj
|
return clscol.obj
|
||||||
|
|
||||||
|
@ -345,7 +328,7 @@ class FixtureRequest(FuncargnamesCompatAttr):
|
||||||
@scopeproperty()
|
@scopeproperty()
|
||||||
def module(self):
|
def module(self):
|
||||||
""" python module object where the test function was collected. """
|
""" python module object where the test function was collected. """
|
||||||
return self._pyfuncitem.getparent(pytest.Module).obj
|
return self._pyfuncitem.getparent(_pytest.python.Module).obj
|
||||||
|
|
||||||
@scopeproperty()
|
@scopeproperty()
|
||||||
def fspath(self):
|
def fspath(self):
|
||||||
|
@ -508,7 +491,7 @@ class FixtureRequest(FuncargnamesCompatAttr):
|
||||||
source_lineno,
|
source_lineno,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
pytest.fail(msg)
|
fail(msg)
|
||||||
else:
|
else:
|
||||||
# indices might not be set if old-style metafunc.addcall() was used
|
# indices might not be set if old-style metafunc.addcall() was used
|
||||||
param_index = funcitem.callspec.indices.get(argname, 0)
|
param_index = funcitem.callspec.indices.get(argname, 0)
|
||||||
|
@ -541,9 +524,9 @@ class FixtureRequest(FuncargnamesCompatAttr):
|
||||||
if scopemismatch(invoking_scope, requested_scope):
|
if scopemismatch(invoking_scope, requested_scope):
|
||||||
# try to report something helpful
|
# try to report something helpful
|
||||||
lines = self._factorytraceback()
|
lines = self._factorytraceback()
|
||||||
pytest.fail("ScopeMismatch: You tried to access the %r scoped "
|
fail("ScopeMismatch: You tried to access the %r scoped "
|
||||||
"fixture %r with a %r scoped request object, "
|
"fixture %r with a %r scoped request object, "
|
||||||
"involved factories\n%s" %(
|
"involved factories\n%s" % (
|
||||||
(requested_scope, argname, invoking_scope, "\n".join(lines))),
|
(requested_scope, argname, invoking_scope, "\n".join(lines))),
|
||||||
pytrace=False)
|
pytrace=False)
|
||||||
|
|
||||||
|
@ -554,7 +537,7 @@ class FixtureRequest(FuncargnamesCompatAttr):
|
||||||
fs, lineno = getfslineno(factory)
|
fs, lineno = getfslineno(factory)
|
||||||
p = self._pyfuncitem.session.fspath.bestrelpath(fs)
|
p = self._pyfuncitem.session.fspath.bestrelpath(fs)
|
||||||
args = _format_args(factory)
|
args = _format_args(factory)
|
||||||
lines.append("%s:%d: def %s%s" %(
|
lines.append("%s:%d: def %s%s" % (
|
||||||
p, lineno, factory.__name__, args))
|
p, lineno, factory.__name__, args))
|
||||||
return lines
|
return lines
|
||||||
|
|
||||||
|
@ -699,9 +682,10 @@ def fail_fixturefunc(fixturefunc, msg):
|
||||||
fs, lineno = getfslineno(fixturefunc)
|
fs, lineno = getfslineno(fixturefunc)
|
||||||
location = "%s:%s" % (fs, lineno+1)
|
location = "%s:%s" % (fs, lineno+1)
|
||||||
source = _pytest._code.Source(fixturefunc)
|
source = _pytest._code.Source(fixturefunc)
|
||||||
pytest.fail(msg + ":\n\n" + str(source.indent()) + "\n" + location,
|
fail(msg + ":\n\n" + str(source.indent()) + "\n" + location,
|
||||||
pytrace=False)
|
pytrace=False)
|
||||||
|
|
||||||
|
|
||||||
def call_fixture_func(fixturefunc, request, kwargs):
|
def call_fixture_func(fixturefunc, request, kwargs):
|
||||||
yieldctx = is_generator(fixturefunc)
|
yieldctx = is_generator(fixturefunc)
|
||||||
if yieldctx:
|
if yieldctx:
|
||||||
|
|
|
@ -5,9 +5,6 @@ pytest
|
||||||
from __future__ import absolute_import, division, print_function
|
from __future__ import absolute_import, division, print_function
|
||||||
|
|
||||||
|
|
||||||
def pytest_namespace():
|
|
||||||
return {'freeze_includes': freeze_includes}
|
|
||||||
|
|
||||||
|
|
||||||
def freeze_includes():
|
def freeze_includes():
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -16,7 +16,9 @@ def pytest_addhooks(pluginmanager):
|
||||||
|
|
||||||
@hookspec(historic=True)
|
@hookspec(historic=True)
|
||||||
def pytest_namespace():
|
def pytest_namespace():
|
||||||
"""return dict of name->object to be made globally available in
|
"""
|
||||||
|
DEPRECATED: this hook causes direct monkeypatching on pytest, its use is strongly discouraged
|
||||||
|
return dict of name->object to be made globally available in
|
||||||
the pytest namespace. This hook is called at plugin registration
|
the pytest namespace. This hook is called at plugin registration
|
||||||
time.
|
time.
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -8,14 +8,13 @@ import sys
|
||||||
import _pytest
|
import _pytest
|
||||||
import _pytest._code
|
import _pytest._code
|
||||||
import py
|
import py
|
||||||
import pytest
|
|
||||||
try:
|
try:
|
||||||
from collections import MutableMapping as MappingMixin
|
from collections import MutableMapping as MappingMixin
|
||||||
except ImportError:
|
except ImportError:
|
||||||
from UserDict import DictMixin as MappingMixin
|
from UserDict import DictMixin as MappingMixin
|
||||||
|
|
||||||
from _pytest.config import directory_arg
|
from _pytest.config import directory_arg, UsageError, hookimpl
|
||||||
from _pytest.runner import collect_one_node
|
from _pytest.runner import collect_one_node, exit
|
||||||
|
|
||||||
tracebackcutdir = py.path.local(_pytest.__file__).dirpath()
|
tracebackcutdir = py.path.local(_pytest.__file__).dirpath()
|
||||||
|
|
||||||
|
@ -27,6 +26,7 @@ EXIT_INTERNALERROR = 3
|
||||||
EXIT_USAGEERROR = 4
|
EXIT_USAGEERROR = 4
|
||||||
EXIT_NOTESTSCOLLECTED = 5
|
EXIT_NOTESTSCOLLECTED = 5
|
||||||
|
|
||||||
|
|
||||||
def pytest_addoption(parser):
|
def pytest_addoption(parser):
|
||||||
parser.addini("norecursedirs", "directory patterns to avoid for recursion",
|
parser.addini("norecursedirs", "directory patterns to avoid for recursion",
|
||||||
type="args", default=['.*', 'build', 'dist', 'CVS', '_darcs', '{arch}', '*.egg', 'venv'])
|
type="args", default=['.*', 'build', 'dist', 'CVS', '_darcs', '{arch}', '*.egg', 'venv'])
|
||||||
|
@ -77,13 +77,18 @@ def pytest_addoption(parser):
|
||||||
help="base temporary directory for this test run.")
|
help="base temporary directory for this test run.")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def pytest_namespace():
|
def pytest_namespace():
|
||||||
collect = dict(Item=Item, Collector=Collector, File=File, Session=Session)
|
"""keeping this one works around a deeper startup issue in pytest
|
||||||
return dict(collect=collect)
|
|
||||||
|
i tried to find it for a while but the amount of time turned unsustainable,
|
||||||
|
so i put a hack in to revisit later
|
||||||
|
"""
|
||||||
|
return {}
|
||||||
|
|
||||||
|
|
||||||
def pytest_configure(config):
|
def pytest_configure(config):
|
||||||
pytest.config = config # compatibility
|
__import__('pytest').config = config # compatibiltiy
|
||||||
|
|
||||||
|
|
||||||
def wrap_session(config, doit):
|
def wrap_session(config, doit):
|
||||||
|
@ -98,12 +103,11 @@ def wrap_session(config, doit):
|
||||||
config.hook.pytest_sessionstart(session=session)
|
config.hook.pytest_sessionstart(session=session)
|
||||||
initstate = 2
|
initstate = 2
|
||||||
session.exitstatus = doit(config, session) or 0
|
session.exitstatus = doit(config, session) or 0
|
||||||
except pytest.UsageError:
|
except UsageError:
|
||||||
raise
|
raise
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
excinfo = _pytest._code.ExceptionInfo()
|
excinfo = _pytest._code.ExceptionInfo()
|
||||||
if initstate < 2 and isinstance(
|
if initstate < 2 and isinstance(excinfo.value, exit.Exception):
|
||||||
excinfo.value, pytest.exit.Exception):
|
|
||||||
sys.stderr.write('{0}: {1}\n'.format(
|
sys.stderr.write('{0}: {1}\n'.format(
|
||||||
excinfo.typename, excinfo.value.msg))
|
excinfo.typename, excinfo.value.msg))
|
||||||
config.hook.pytest_keyboard_interrupt(excinfo=excinfo)
|
config.hook.pytest_keyboard_interrupt(excinfo=excinfo)
|
||||||
|
@ -125,9 +129,11 @@ def wrap_session(config, doit):
|
||||||
config._ensure_unconfigure()
|
config._ensure_unconfigure()
|
||||||
return session.exitstatus
|
return session.exitstatus
|
||||||
|
|
||||||
|
|
||||||
def pytest_cmdline_main(config):
|
def pytest_cmdline_main(config):
|
||||||
return wrap_session(config, _main)
|
return wrap_session(config, _main)
|
||||||
|
|
||||||
|
|
||||||
def _main(config, session):
|
def _main(config, session):
|
||||||
""" default command line protocol for initialization, session,
|
""" default command line protocol for initialization, session,
|
||||||
running tests and reporting. """
|
running tests and reporting. """
|
||||||
|
@ -139,9 +145,11 @@ def _main(config, session):
|
||||||
elif session.testscollected == 0:
|
elif session.testscollected == 0:
|
||||||
return EXIT_NOTESTSCOLLECTED
|
return EXIT_NOTESTSCOLLECTED
|
||||||
|
|
||||||
|
|
||||||
def pytest_collection(session):
|
def pytest_collection(session):
|
||||||
return session.perform_collect()
|
return session.perform_collect()
|
||||||
|
|
||||||
|
|
||||||
def pytest_runtestloop(session):
|
def pytest_runtestloop(session):
|
||||||
if (session.testsfailed and
|
if (session.testsfailed and
|
||||||
not session.config.option.continue_on_collection_errors):
|
not session.config.option.continue_on_collection_errors):
|
||||||
|
@ -158,6 +166,7 @@ def pytest_runtestloop(session):
|
||||||
raise session.Interrupted(session.shouldstop)
|
raise session.Interrupted(session.shouldstop)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def pytest_ignore_collect(path, config):
|
def pytest_ignore_collect(path, config):
|
||||||
p = path.dirpath()
|
p = path.dirpath()
|
||||||
ignore_paths = config._getconftest_pathlist("collect_ignore", path=p)
|
ignore_paths = config._getconftest_pathlist("collect_ignore", path=p)
|
||||||
|
@ -205,7 +214,7 @@ class _CompatProperty(object):
|
||||||
# "usage of {owner!r}.{name} is deprecated, please use pytest.{name} instead".format(
|
# "usage of {owner!r}.{name} is deprecated, please use pytest.{name} instead".format(
|
||||||
# name=self.name, owner=type(owner).__name__),
|
# name=self.name, owner=type(owner).__name__),
|
||||||
# PendingDeprecationWarning, stacklevel=2)
|
# PendingDeprecationWarning, stacklevel=2)
|
||||||
return getattr(pytest, self.name)
|
return getattr(__import__('pytest'), self.name)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -289,7 +298,7 @@ class Node(object):
|
||||||
def _getcustomclass(self, name):
|
def _getcustomclass(self, name):
|
||||||
maybe_compatprop = getattr(type(self), name)
|
maybe_compatprop = getattr(type(self), name)
|
||||||
if isinstance(maybe_compatprop, _CompatProperty):
|
if isinstance(maybe_compatprop, _CompatProperty):
|
||||||
return getattr(pytest, name)
|
return getattr(__import__('pytest'), name)
|
||||||
else:
|
else:
|
||||||
cls = getattr(self, name)
|
cls = getattr(self, name)
|
||||||
# TODO: reenable in the features branch
|
# TODO: reenable in the features branch
|
||||||
|
@ -369,9 +378,9 @@ class Node(object):
|
||||||
|
|
||||||
``marker`` can be a string or pytest.mark.* instance.
|
``marker`` can be a string or pytest.mark.* instance.
|
||||||
"""
|
"""
|
||||||
from _pytest.mark import MarkDecorator
|
from _pytest.mark import MarkDecorator, MARK_GEN
|
||||||
if isinstance(marker, py.builtin._basestring):
|
if isinstance(marker, py.builtin._basestring):
|
||||||
marker = getattr(pytest.mark, marker)
|
marker = getattr(MARK_GEN, marker)
|
||||||
elif not isinstance(marker, MarkDecorator):
|
elif not isinstance(marker, MarkDecorator):
|
||||||
raise ValueError("is not a string or pytest.mark.* Marker")
|
raise ValueError("is not a string or pytest.mark.* Marker")
|
||||||
self.keywords[marker.name] = marker
|
self.keywords[marker.name] = marker
|
||||||
|
@ -557,12 +566,12 @@ class Session(FSCollector):
|
||||||
def _makeid(self):
|
def _makeid(self):
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
@pytest.hookimpl(tryfirst=True)
|
@hookimpl(tryfirst=True)
|
||||||
def pytest_collectstart(self):
|
def pytest_collectstart(self):
|
||||||
if self.shouldstop:
|
if self.shouldstop:
|
||||||
raise self.Interrupted(self.shouldstop)
|
raise self.Interrupted(self.shouldstop)
|
||||||
|
|
||||||
@pytest.hookimpl(tryfirst=True)
|
@hookimpl(tryfirst=True)
|
||||||
def pytest_runtest_logreport(self, report):
|
def pytest_runtest_logreport(self, report):
|
||||||
if report.failed and not hasattr(report, 'wasxfail'):
|
if report.failed and not hasattr(report, 'wasxfail'):
|
||||||
self.testsfailed += 1
|
self.testsfailed += 1
|
||||||
|
@ -622,8 +631,8 @@ class Session(FSCollector):
|
||||||
for arg, exc in self._notfound:
|
for arg, exc in self._notfound:
|
||||||
line = "(no name %r in any of %r)" % (arg, exc.args[0])
|
line = "(no name %r in any of %r)" % (arg, exc.args[0])
|
||||||
errors.append("not found: %s\n%s" % (arg, line))
|
errors.append("not found: %s\n%s" % (arg, line))
|
||||||
#XXX: test this
|
# XXX: test this
|
||||||
raise pytest.UsageError(*errors)
|
raise UsageError(*errors)
|
||||||
if not genitems:
|
if not genitems:
|
||||||
return rep.result
|
return rep.result
|
||||||
else:
|
else:
|
||||||
|
@ -651,7 +660,7 @@ class Session(FSCollector):
|
||||||
names = self._parsearg(arg)
|
names = self._parsearg(arg)
|
||||||
path = names.pop(0)
|
path = names.pop(0)
|
||||||
if path.check(dir=1):
|
if path.check(dir=1):
|
||||||
assert not names, "invalid arg %r" %(arg,)
|
assert not names, "invalid arg %r" % (arg,)
|
||||||
for path in path.visit(fil=lambda x: x.check(file=1),
|
for path in path.visit(fil=lambda x: x.check(file=1),
|
||||||
rec=self._recurse, bf=True, sort=True):
|
rec=self._recurse, bf=True, sort=True):
|
||||||
for x in self._collectfile(path):
|
for x in self._collectfile(path):
|
||||||
|
@ -710,9 +719,11 @@ class Session(FSCollector):
|
||||||
path = self.config.invocation_dir.join(relpath, abs=True)
|
path = self.config.invocation_dir.join(relpath, abs=True)
|
||||||
if not path.check():
|
if not path.check():
|
||||||
if self.config.option.pyargs:
|
if self.config.option.pyargs:
|
||||||
raise pytest.UsageError("file or package not found: " + arg + " (missing __init__.py?)")
|
raise UsageError(
|
||||||
|
"file or package not found: " + arg +
|
||||||
|
" (missing __init__.py?)")
|
||||||
else:
|
else:
|
||||||
raise pytest.UsageError("file not found: " + arg)
|
raise UsageError("file not found: " + arg)
|
||||||
parts[0] = path
|
parts[0] = path
|
||||||
return parts
|
return parts
|
||||||
|
|
||||||
|
@ -735,11 +746,11 @@ class Session(FSCollector):
|
||||||
nextnames = names[1:]
|
nextnames = names[1:]
|
||||||
resultnodes = []
|
resultnodes = []
|
||||||
for node in matching:
|
for node in matching:
|
||||||
if isinstance(node, pytest.Item):
|
if isinstance(node, Item):
|
||||||
if not names:
|
if not names:
|
||||||
resultnodes.append(node)
|
resultnodes.append(node)
|
||||||
continue
|
continue
|
||||||
assert isinstance(node, pytest.Collector)
|
assert isinstance(node, Collector)
|
||||||
rep = collect_one_node(node)
|
rep = collect_one_node(node)
|
||||||
if rep.passed:
|
if rep.passed:
|
||||||
has_matched = False
|
has_matched = False
|
||||||
|
@ -757,11 +768,11 @@ class Session(FSCollector):
|
||||||
|
|
||||||
def genitems(self, node):
|
def genitems(self, node):
|
||||||
self.trace("genitems", node)
|
self.trace("genitems", node)
|
||||||
if isinstance(node, pytest.Item):
|
if isinstance(node, Item):
|
||||||
node.ihook.pytest_itemcollected(item=node)
|
node.ihook.pytest_itemcollected(item=node)
|
||||||
yield node
|
yield node
|
||||||
else:
|
else:
|
||||||
assert isinstance(node, pytest.Collector)
|
assert isinstance(node, Collector)
|
||||||
rep = collect_one_node(node)
|
rep = collect_one_node(node)
|
||||||
if rep.passed:
|
if rep.passed:
|
||||||
for subnode in rep.result:
|
for subnode in rep.result:
|
||||||
|
|
|
@ -66,12 +66,8 @@ class MarkerError(Exception):
|
||||||
"""Error in use of a pytest marker/attribute."""
|
"""Error in use of a pytest marker/attribute."""
|
||||||
|
|
||||||
|
|
||||||
|
def param(*values, **kw):
|
||||||
def pytest_namespace():
|
return ParameterSet.param(*values, **kw)
|
||||||
return {
|
|
||||||
'mark': MarkGenerator(),
|
|
||||||
'param': ParameterSet.param,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def pytest_addoption(parser):
|
def pytest_addoption(parser):
|
||||||
|
@ -225,9 +221,13 @@ def matchkeyword(colitem, keywordexpr):
|
||||||
|
|
||||||
|
|
||||||
def pytest_configure(config):
|
def pytest_configure(config):
|
||||||
import pytest
|
config._old_mark_config = MARK_GEN._config
|
||||||
if config.option.strict:
|
if config.option.strict:
|
||||||
pytest.mark._config = config
|
MARK_GEN._config = config
|
||||||
|
|
||||||
|
|
||||||
|
def pytest_unconfigure(config):
|
||||||
|
MARK_GEN._config = getattr(config, '_old_mark_config', None)
|
||||||
|
|
||||||
|
|
||||||
class MarkGenerator(object):
|
class MarkGenerator(object):
|
||||||
|
@ -241,11 +241,13 @@ class MarkGenerator(object):
|
||||||
|
|
||||||
will set a 'slowtest' :class:`MarkInfo` object
|
will set a 'slowtest' :class:`MarkInfo` object
|
||||||
on the ``test_function`` object. """
|
on the ``test_function`` object. """
|
||||||
|
_config = None
|
||||||
|
|
||||||
|
|
||||||
def __getattr__(self, name):
|
def __getattr__(self, name):
|
||||||
if name[0] == "_":
|
if name[0] == "_":
|
||||||
raise AttributeError("Marker name must NOT start with underscore")
|
raise AttributeError("Marker name must NOT start with underscore")
|
||||||
if hasattr(self, '_config'):
|
if self._config is not None:
|
||||||
self._check(name)
|
self._check(name)
|
||||||
return MarkDecorator(Mark(name, (), {}))
|
return MarkDecorator(Mark(name, (), {}))
|
||||||
|
|
||||||
|
@ -263,6 +265,7 @@ class MarkGenerator(object):
|
||||||
if name not in self._markers:
|
if name not in self._markers:
|
||||||
raise AttributeError("%r not a registered marker" % (name,))
|
raise AttributeError("%r not a registered marker" % (name,))
|
||||||
|
|
||||||
|
|
||||||
def istestfunc(func):
|
def istestfunc(func):
|
||||||
return hasattr(func, "__call__") and \
|
return hasattr(func, "__call__") and \
|
||||||
getattr(func, "__name__", "<lambda>") != "<lambda>"
|
getattr(func, "__name__", "<lambda>") != "<lambda>"
|
||||||
|
@ -384,3 +387,6 @@ class MarkInfo(object):
|
||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
""" yield MarkInfo objects each relating to a marking-call. """
|
""" yield MarkInfo objects each relating to a marking-call. """
|
||||||
return imap(MarkInfo, self._marks)
|
return imap(MarkInfo, self._marks)
|
||||||
|
|
||||||
|
|
||||||
|
MARK_GEN = MarkGenerator()
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
""" monkeypatching and mocking functionality. """
|
""" monkeypatching and mocking functionality. """
|
||||||
from __future__ import absolute_import, division, print_function
|
from __future__ import absolute_import, division, print_function
|
||||||
|
|
||||||
import os, sys
|
import os
|
||||||
|
import sys
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from py.builtin import _basestring
|
from py.builtin import _basestring
|
||||||
|
from _pytest.fixtures import fixture
|
||||||
import pytest
|
|
||||||
|
|
||||||
RE_IMPORT_ERROR_NAME = re.compile("^No module named (.*)$")
|
RE_IMPORT_ERROR_NAME = re.compile("^No module named (.*)$")
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@fixture
|
||||||
def monkeypatch():
|
def monkeypatch():
|
||||||
"""The returned ``monkeypatch`` fixture provides these
|
"""The returned ``monkeypatch`` fixture provides these
|
||||||
helper methods to modify objects, dictionaries or os.environ::
|
helper methods to modify objects, dictionaries or os.environ::
|
||||||
|
|
|
@ -4,8 +4,8 @@ from __future__ import absolute_import, division, print_function
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
import py
|
import py
|
||||||
import pytest
|
from _pytest import unittest, runner, python
|
||||||
from _pytest import unittest
|
from _pytest.config import hookimpl
|
||||||
|
|
||||||
|
|
||||||
def get_skip_exceptions():
|
def get_skip_exceptions():
|
||||||
|
@ -20,19 +20,19 @@ def get_skip_exceptions():
|
||||||
def pytest_runtest_makereport(item, call):
|
def pytest_runtest_makereport(item, call):
|
||||||
if call.excinfo and call.excinfo.errisinstance(get_skip_exceptions()):
|
if call.excinfo and call.excinfo.errisinstance(get_skip_exceptions()):
|
||||||
# let's substitute the excinfo with a pytest.skip one
|
# let's substitute the excinfo with a pytest.skip one
|
||||||
call2 = call.__class__(lambda:
|
call2 = call.__class__(
|
||||||
pytest.skip(str(call.excinfo.value)), call.when)
|
lambda: runner.skip(str(call.excinfo.value)), call.when)
|
||||||
call.excinfo = call2.excinfo
|
call.excinfo = call2.excinfo
|
||||||
|
|
||||||
|
|
||||||
@pytest.hookimpl(trylast=True)
|
@hookimpl(trylast=True)
|
||||||
def pytest_runtest_setup(item):
|
def pytest_runtest_setup(item):
|
||||||
if is_potential_nosetest(item):
|
if is_potential_nosetest(item):
|
||||||
if isinstance(item.parent, pytest.Generator):
|
if isinstance(item.parent, python.Generator):
|
||||||
gen = item.parent
|
gen = item.parent
|
||||||
if not hasattr(gen, '_nosegensetup'):
|
if not hasattr(gen, '_nosegensetup'):
|
||||||
call_optional(gen.obj, 'setup')
|
call_optional(gen.obj, 'setup')
|
||||||
if isinstance(gen.parent, pytest.Instance):
|
if isinstance(gen.parent, python.Instance):
|
||||||
call_optional(gen.parent.obj, 'setup')
|
call_optional(gen.parent.obj, 'setup')
|
||||||
gen._nosegensetup = True
|
gen._nosegensetup = True
|
||||||
if not call_optional(item.obj, 'setup'):
|
if not call_optional(item.obj, 'setup'):
|
||||||
|
@ -51,14 +51,14 @@ def teardown_nose(item):
|
||||||
|
|
||||||
|
|
||||||
def pytest_make_collect_report(collector):
|
def pytest_make_collect_report(collector):
|
||||||
if isinstance(collector, pytest.Generator):
|
if isinstance(collector, python.Generator):
|
||||||
call_optional(collector.obj, 'setup')
|
call_optional(collector.obj, 'setup')
|
||||||
|
|
||||||
|
|
||||||
def is_potential_nosetest(item):
|
def is_potential_nosetest(item):
|
||||||
# extra check needed since we do not do nose style setup/teardown
|
# extra check needed since we do not do nose style setup/teardown
|
||||||
# on direct unittest style classes
|
# on direct unittest style classes
|
||||||
return isinstance(item, pytest.Function) and \
|
return isinstance(item, python.Function) and \
|
||||||
not isinstance(item, unittest.TestCaseFunction)
|
not isinstance(item, unittest.TestCaseFunction)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -9,19 +9,20 @@ import math
|
||||||
from itertools import count
|
from itertools import count
|
||||||
|
|
||||||
import py
|
import py
|
||||||
import pytest
|
|
||||||
from _pytest.mark import MarkerError
|
from _pytest.mark import MarkerError
|
||||||
|
from _pytest.config import hookimpl
|
||||||
|
|
||||||
import _pytest
|
import _pytest
|
||||||
import _pytest._pluggy as pluggy
|
import _pytest._pluggy as pluggy
|
||||||
from _pytest import fixtures
|
from _pytest import fixtures
|
||||||
|
from _pytest import main
|
||||||
from _pytest.compat import (
|
from _pytest.compat import (
|
||||||
isclass, isfunction, is_generator, _escape_strings,
|
isclass, isfunction, is_generator, _escape_strings,
|
||||||
REGEX_TYPE, STRING_TYPES, NoneType, NOTSET,
|
REGEX_TYPE, STRING_TYPES, NoneType, NOTSET,
|
||||||
get_real_func, getfslineno, safe_getattr,
|
get_real_func, getfslineno, safe_getattr,
|
||||||
getlocation, enum,
|
getlocation, enum,
|
||||||
)
|
)
|
||||||
|
from _pytest.runner import fail
|
||||||
|
|
||||||
cutdir1 = py.path.local(pluggy.__file__.rstrip("oc"))
|
cutdir1 = py.path.local(pluggy.__file__.rstrip("oc"))
|
||||||
cutdir2 = py.path.local(_pytest.__file__).dirpath()
|
cutdir2 = py.path.local(_pytest.__file__).dirpath()
|
||||||
|
@ -49,7 +50,7 @@ def filter_traceback(entry):
|
||||||
|
|
||||||
def pyobj_property(name):
|
def pyobj_property(name):
|
||||||
def get(self):
|
def get(self):
|
||||||
node = self.getparent(getattr(pytest, name))
|
node = self.getparent(getattr(__import__('pytest'), name))
|
||||||
if node is not None:
|
if node is not None:
|
||||||
return node.obj
|
return node.obj
|
||||||
doc = "python %s object this node was collected from (can be None)." % (
|
doc = "python %s object this node was collected from (can be None)." % (
|
||||||
|
@ -126,23 +127,8 @@ def pytest_configure(config):
|
||||||
"all of the specified fixtures. see http://pytest.org/latest/fixture.html#usefixtures "
|
"all of the specified fixtures. see http://pytest.org/latest/fixture.html#usefixtures "
|
||||||
)
|
)
|
||||||
|
|
||||||
@pytest.hookimpl(trylast=True)
|
|
||||||
def pytest_namespace():
|
|
||||||
raises.Exception = pytest.fail.Exception
|
|
||||||
return {
|
|
||||||
'raises': raises,
|
|
||||||
'approx': approx,
|
|
||||||
'collect': {
|
|
||||||
'Module': Module,
|
|
||||||
'Class': Class,
|
|
||||||
'Instance': Instance,
|
|
||||||
'Function': Function,
|
|
||||||
'Generator': Generator,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
@hookimpl(trylast=True)
|
||||||
@pytest.hookimpl(trylast=True)
|
|
||||||
def pytest_pyfunc_call(pyfuncitem):
|
def pytest_pyfunc_call(pyfuncitem):
|
||||||
testfunction = pyfuncitem.obj
|
testfunction = pyfuncitem.obj
|
||||||
if pyfuncitem._isyieldedfunction():
|
if pyfuncitem._isyieldedfunction():
|
||||||
|
@ -155,6 +141,7 @@ def pytest_pyfunc_call(pyfuncitem):
|
||||||
testfunction(**testargs)
|
testfunction(**testargs)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def pytest_collect_file(path, parent):
|
def pytest_collect_file(path, parent):
|
||||||
ext = path.ext
|
ext = path.ext
|
||||||
if ext == ".py":
|
if ext == ".py":
|
||||||
|
@ -170,7 +157,7 @@ def pytest_collect_file(path, parent):
|
||||||
def pytest_pycollect_makemodule(path, parent):
|
def pytest_pycollect_makemodule(path, parent):
|
||||||
return Module(path, parent)
|
return Module(path, parent)
|
||||||
|
|
||||||
@pytest.hookimpl(hookwrapper=True)
|
@hookimpl(hookwrapper=True)
|
||||||
def pytest_pycollect_makeitem(collector, name, obj):
|
def pytest_pycollect_makeitem(collector, name, obj):
|
||||||
outcome = yield
|
outcome = yield
|
||||||
res = outcome.get_result()
|
res = outcome.get_result()
|
||||||
|
@ -266,7 +253,7 @@ class PyobjMixin(PyobjContext):
|
||||||
assert isinstance(lineno, int)
|
assert isinstance(lineno, int)
|
||||||
return fspath, lineno, modpath
|
return fspath, lineno, modpath
|
||||||
|
|
||||||
class PyCollector(PyobjMixin, pytest.Collector):
|
class PyCollector(PyobjMixin, main.Collector):
|
||||||
|
|
||||||
def funcnamefilter(self, name):
|
def funcnamefilter(self, name):
|
||||||
return self._matches_prefix_or_glob_option('python_functions', name)
|
return self._matches_prefix_or_glob_option('python_functions', name)
|
||||||
|
@ -403,7 +390,8 @@ def transfer_markers(funcobj, cls, mod):
|
||||||
if not _marked(funcobj, pytestmark):
|
if not _marked(funcobj, pytestmark):
|
||||||
pytestmark(funcobj)
|
pytestmark(funcobj)
|
||||||
|
|
||||||
class Module(pytest.File, PyCollector):
|
|
||||||
|
class Module(main.File, PyCollector):
|
||||||
""" Collector for test classes and functions. """
|
""" Collector for test classes and functions. """
|
||||||
|
|
||||||
def _getobj(self):
|
def _getobj(self):
|
||||||
|
@ -590,7 +578,7 @@ class FunctionMixin(PyobjMixin):
|
||||||
entry.set_repr_style('short')
|
entry.set_repr_style('short')
|
||||||
|
|
||||||
def _repr_failure_py(self, excinfo, style="long"):
|
def _repr_failure_py(self, excinfo, style="long"):
|
||||||
if excinfo.errisinstance(pytest.fail.Exception):
|
if excinfo.errisinstance(fail.Exception):
|
||||||
if not excinfo.value.pytrace:
|
if not excinfo.value.pytrace:
|
||||||
return py._builtin._totext(excinfo.value)
|
return py._builtin._totext(excinfo.value)
|
||||||
return super(FunctionMixin, self)._repr_failure_py(excinfo,
|
return super(FunctionMixin, self)._repr_failure_py(excinfo,
|
||||||
|
@ -788,7 +776,7 @@ class Metafunc(fixtures.FuncargnamesCompatAttr):
|
||||||
to set a dynamic scope using test context or configuration.
|
to set a dynamic scope using test context or configuration.
|
||||||
"""
|
"""
|
||||||
from _pytest.fixtures import scope2index
|
from _pytest.fixtures import scope2index
|
||||||
from _pytest.mark import ParameterSet
|
from _pytest.mark import MARK_GEN, ParameterSet
|
||||||
from py.io import saferepr
|
from py.io import saferepr
|
||||||
|
|
||||||
if not isinstance(argnames, (tuple, list)):
|
if not isinstance(argnames, (tuple, list)):
|
||||||
|
@ -801,12 +789,11 @@ class Metafunc(fixtures.FuncargnamesCompatAttr):
|
||||||
for x in argvalues]
|
for x in argvalues]
|
||||||
del argvalues
|
del argvalues
|
||||||
|
|
||||||
|
|
||||||
if not parameters:
|
if not parameters:
|
||||||
fs, lineno = getfslineno(self.function)
|
fs, lineno = getfslineno(self.function)
|
||||||
reason = "got empty parameter set %r, function %s at %s:%d" % (
|
reason = "got empty parameter set %r, function %s at %s:%d" % (
|
||||||
argnames, self.function.__name__, fs, lineno)
|
argnames, self.function.__name__, fs, lineno)
|
||||||
mark = pytest.mark.skip(reason=reason)
|
mark = MARK_GEN.skip(reason=reason)
|
||||||
parameters.append(ParameterSet(
|
parameters.append(ParameterSet(
|
||||||
values=(NOTSET,) * len(argnames),
|
values=(NOTSET,) * len(argnames),
|
||||||
marks=[mark],
|
marks=[mark],
|
||||||
|
@ -883,7 +870,7 @@ class Metafunc(fixtures.FuncargnamesCompatAttr):
|
||||||
if funcargs is not None:
|
if funcargs is not None:
|
||||||
for name in funcargs:
|
for name in funcargs:
|
||||||
if name not in self.fixturenames:
|
if name not in self.fixturenames:
|
||||||
pytest.fail("funcarg %r not used in this function." % name)
|
fail("funcarg %r not used in this function." % name)
|
||||||
else:
|
else:
|
||||||
funcargs = {}
|
funcargs = {}
|
||||||
if id is None:
|
if id is None:
|
||||||
|
@ -958,6 +945,7 @@ def _idval(val, argname, idx, idfn, config=None):
|
||||||
return val.__name__
|
return val.__name__
|
||||||
return str(argname)+str(idx)
|
return str(argname)+str(idx)
|
||||||
|
|
||||||
|
|
||||||
def _idvalset(idx, parameterset, argnames, idfn, ids, config=None):
|
def _idvalset(idx, parameterset, argnames, idfn, ids, config=None):
|
||||||
if parameterset.id is not None:
|
if parameterset.id is not None:
|
||||||
return parameterset.id
|
return parameterset.id
|
||||||
|
@ -968,6 +956,7 @@ def _idvalset(idx, parameterset, argnames, idfn, ids, config=None):
|
||||||
else:
|
else:
|
||||||
return _escape_strings(ids[idx])
|
return _escape_strings(ids[idx])
|
||||||
|
|
||||||
|
|
||||||
def idmaker(argnames, parametersets, idfn=None, ids=None, config=None):
|
def idmaker(argnames, parametersets, idfn=None, ids=None, config=None):
|
||||||
ids = [_idvalset(valindex, parameterset, argnames, idfn, ids, config)
|
ids = [_idvalset(valindex, parameterset, argnames, idfn, ids, config)
|
||||||
for valindex, parameterset in enumerate(parametersets)]
|
for valindex, parameterset in enumerate(parametersets)]
|
||||||
|
@ -1046,6 +1035,7 @@ def showfixtures(config):
|
||||||
from _pytest.main import wrap_session
|
from _pytest.main import wrap_session
|
||||||
return wrap_session(config, _showfixtures_main)
|
return wrap_session(config, _showfixtures_main)
|
||||||
|
|
||||||
|
|
||||||
def _showfixtures_main(config, session):
|
def _showfixtures_main(config, session):
|
||||||
import _pytest.config
|
import _pytest.config
|
||||||
session.perform_collect()
|
session.perform_collect()
|
||||||
|
@ -1234,7 +1224,11 @@ def raises(expected_exception, *args, **kwargs):
|
||||||
func(*args[1:], **kwargs)
|
func(*args[1:], **kwargs)
|
||||||
except expected_exception:
|
except expected_exception:
|
||||||
return _pytest._code.ExceptionInfo()
|
return _pytest._code.ExceptionInfo()
|
||||||
pytest.fail(message)
|
fail(message)
|
||||||
|
|
||||||
|
|
||||||
|
raises.Exception = fail.Exception
|
||||||
|
|
||||||
|
|
||||||
class RaisesContext(object):
|
class RaisesContext(object):
|
||||||
def __init__(self, expected_exception, message, match_expr):
|
def __init__(self, expected_exception, message, match_expr):
|
||||||
|
@ -1250,7 +1244,7 @@ class RaisesContext(object):
|
||||||
def __exit__(self, *tp):
|
def __exit__(self, *tp):
|
||||||
__tracebackhide__ = True
|
__tracebackhide__ = True
|
||||||
if tp[0] is None:
|
if tp[0] is None:
|
||||||
pytest.fail(self.message)
|
fail(self.message)
|
||||||
if sys.version_info < (2, 7):
|
if sys.version_info < (2, 7):
|
||||||
# py26: on __exit__() exc_value often does not contain the
|
# py26: on __exit__() exc_value often does not contain the
|
||||||
# exception value.
|
# exception value.
|
||||||
|
@ -1521,7 +1515,7 @@ class ApproxNonIterable(object):
|
||||||
# the basic pytest Function item
|
# the basic pytest Function item
|
||||||
#
|
#
|
||||||
|
|
||||||
class Function(FunctionMixin, pytest.Item, fixtures.FuncargnamesCompatAttr):
|
class Function(FunctionMixin, main.Item, fixtures.FuncargnamesCompatAttr):
|
||||||
""" a Function Item is responsible for setting up and executing a
|
""" a Function Item is responsible for setting up and executing a
|
||||||
Python test function.
|
Python test function.
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -7,10 +7,10 @@ import _pytest._code
|
||||||
import py
|
import py
|
||||||
import sys
|
import sys
|
||||||
import warnings
|
import warnings
|
||||||
import pytest
|
from _pytest.fixtures import yield_fixture
|
||||||
|
|
||||||
|
|
||||||
@pytest.yield_fixture
|
@yield_fixture
|
||||||
def recwarn():
|
def recwarn():
|
||||||
"""Return a WarningsRecorder instance that provides these methods:
|
"""Return a WarningsRecorder instance that provides these methods:
|
||||||
|
|
||||||
|
@ -26,11 +26,6 @@ def recwarn():
|
||||||
yield wrec
|
yield wrec
|
||||||
|
|
||||||
|
|
||||||
def pytest_namespace():
|
|
||||||
return {'deprecated_call': deprecated_call,
|
|
||||||
'warns': warns}
|
|
||||||
|
|
||||||
|
|
||||||
def deprecated_call(func=None, *args, **kwargs):
|
def deprecated_call(func=None, *args, **kwargs):
|
||||||
""" assert that calling ``func(*args, **kwargs)`` triggers a
|
""" assert that calling ``func(*args, **kwargs)`` triggers a
|
||||||
``DeprecationWarning`` or ``PendingDeprecationWarning``.
|
``DeprecationWarning`` or ``PendingDeprecationWarning``.
|
||||||
|
@ -195,7 +190,8 @@ class WarningsChecker(WarningsRecorder):
|
||||||
if not any(issubclass(r.category, self.expected_warning)
|
if not any(issubclass(r.category, self.expected_warning)
|
||||||
for r in self):
|
for r in self):
|
||||||
__tracebackhide__ = True
|
__tracebackhide__ = True
|
||||||
pytest.fail("DID NOT WARN. No warnings of type {0} was emitted. "
|
from _pytest.runner import fail
|
||||||
|
fail("DID NOT WARN. No warnings of type {0} was emitted. "
|
||||||
"The list of emitted warnings is: {1}.".format(
|
"The list of emitted warnings is: {1}.".format(
|
||||||
self.expected_warning,
|
self.expected_warning,
|
||||||
[each.message for each in self]))
|
[each.message for each in self]))
|
||||||
|
|
|
@ -6,17 +6,9 @@ import sys
|
||||||
from time import time
|
from time import time
|
||||||
|
|
||||||
import py
|
import py
|
||||||
import pytest
|
|
||||||
from _pytest._code.code import TerminalRepr, ExceptionInfo
|
from _pytest._code.code import TerminalRepr, ExceptionInfo
|
||||||
|
|
||||||
|
|
||||||
def pytest_namespace():
|
|
||||||
return {
|
|
||||||
'fail' : fail,
|
|
||||||
'skip' : skip,
|
|
||||||
'importorskip' : importorskip,
|
|
||||||
'exit' : exit,
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# pytest plugin hooks
|
# pytest plugin hooks
|
||||||
|
@ -264,7 +256,7 @@ def pytest_runtest_makereport(item, call):
|
||||||
if not isinstance(excinfo, ExceptionInfo):
|
if not isinstance(excinfo, ExceptionInfo):
|
||||||
outcome = "failed"
|
outcome = "failed"
|
||||||
longrepr = excinfo
|
longrepr = excinfo
|
||||||
elif excinfo.errisinstance(pytest.skip.Exception):
|
elif excinfo.errisinstance(skip.Exception):
|
||||||
outcome = "skipped"
|
outcome = "skipped"
|
||||||
r = excinfo._getreprcrash()
|
r = excinfo._getreprcrash()
|
||||||
longrepr = (str(r.path), r.lineno, r.message)
|
longrepr = (str(r.path), r.lineno, r.message)
|
||||||
|
|
|
@ -6,9 +6,9 @@ import sys
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
import py
|
import py
|
||||||
import pytest
|
from _pytest.config import hookimpl
|
||||||
from _pytest.mark import MarkInfo, MarkDecorator
|
from _pytest.mark import MarkInfo, MarkDecorator
|
||||||
|
from _pytest.runner import fail, skip
|
||||||
|
|
||||||
def pytest_addoption(parser):
|
def pytest_addoption(parser):
|
||||||
group = parser.getgroup("general")
|
group = parser.getgroup("general")
|
||||||
|
@ -25,6 +25,8 @@ def pytest_addoption(parser):
|
||||||
|
|
||||||
def pytest_configure(config):
|
def pytest_configure(config):
|
||||||
if config.option.runxfail:
|
if config.option.runxfail:
|
||||||
|
# yay a hack
|
||||||
|
import pytest
|
||||||
old = pytest.xfail
|
old = pytest.xfail
|
||||||
config._cleanup.append(lambda: setattr(pytest, "xfail", old))
|
config._cleanup.append(lambda: setattr(pytest, "xfail", old))
|
||||||
|
|
||||||
|
@ -57,11 +59,7 @@ def pytest_configure(config):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def pytest_namespace():
|
class XFailed(fail.Exception):
|
||||||
return dict(xfail=xfail)
|
|
||||||
|
|
||||||
|
|
||||||
class XFailed(pytest.fail.Exception):
|
|
||||||
""" raised from an explicit call to pytest.xfail() """
|
""" raised from an explicit call to pytest.xfail() """
|
||||||
|
|
||||||
|
|
||||||
|
@ -102,14 +100,14 @@ class MarkEvaluator(object):
|
||||||
except Exception:
|
except Exception:
|
||||||
self.exc = sys.exc_info()
|
self.exc = sys.exc_info()
|
||||||
if isinstance(self.exc[1], SyntaxError):
|
if isinstance(self.exc[1], SyntaxError):
|
||||||
msg = [" " * (self.exc[1].offset + 4) + "^",]
|
msg = [" " * (self.exc[1].offset + 4) + "^", ]
|
||||||
msg.append("SyntaxError: invalid syntax")
|
msg.append("SyntaxError: invalid syntax")
|
||||||
else:
|
else:
|
||||||
msg = traceback.format_exception_only(*self.exc[:2])
|
msg = traceback.format_exception_only(*self.exc[:2])
|
||||||
pytest.fail("Error evaluating %r expression\n"
|
fail("Error evaluating %r expression\n"
|
||||||
" %s\n"
|
" %s\n"
|
||||||
"%s"
|
"%s"
|
||||||
%(self.name, self.expr, "\n".join(msg)),
|
% (self.name, self.expr, "\n".join(msg)),
|
||||||
pytrace=False)
|
pytrace=False)
|
||||||
|
|
||||||
def _getglobals(self):
|
def _getglobals(self):
|
||||||
|
@ -142,7 +140,7 @@ class MarkEvaluator(object):
|
||||||
# XXX better be checked at collection time
|
# XXX better be checked at collection time
|
||||||
msg = "you need to specify reason=STRING " \
|
msg = "you need to specify reason=STRING " \
|
||||||
"when using booleans as conditions."
|
"when using booleans as conditions."
|
||||||
pytest.fail(msg)
|
fail(msg)
|
||||||
result = bool(expr)
|
result = bool(expr)
|
||||||
if result:
|
if result:
|
||||||
self.result = True
|
self.result = True
|
||||||
|
@ -166,7 +164,7 @@ class MarkEvaluator(object):
|
||||||
return expl
|
return expl
|
||||||
|
|
||||||
|
|
||||||
@pytest.hookimpl(tryfirst=True)
|
@hookimpl(tryfirst=True)
|
||||||
def pytest_runtest_setup(item):
|
def pytest_runtest_setup(item):
|
||||||
# Check if skip or skipif are specified as pytest marks
|
# Check if skip or skipif are specified as pytest marks
|
||||||
|
|
||||||
|
@ -175,23 +173,23 @@ def pytest_runtest_setup(item):
|
||||||
eval_skipif = MarkEvaluator(item, 'skipif')
|
eval_skipif = MarkEvaluator(item, 'skipif')
|
||||||
if eval_skipif.istrue():
|
if eval_skipif.istrue():
|
||||||
item._evalskip = eval_skipif
|
item._evalskip = eval_skipif
|
||||||
pytest.skip(eval_skipif.getexplanation())
|
skip(eval_skipif.getexplanation())
|
||||||
|
|
||||||
skip_info = item.keywords.get('skip')
|
skip_info = item.keywords.get('skip')
|
||||||
if isinstance(skip_info, (MarkInfo, MarkDecorator)):
|
if isinstance(skip_info, (MarkInfo, MarkDecorator)):
|
||||||
item._evalskip = True
|
item._evalskip = True
|
||||||
if 'reason' in skip_info.kwargs:
|
if 'reason' in skip_info.kwargs:
|
||||||
pytest.skip(skip_info.kwargs['reason'])
|
skip(skip_info.kwargs['reason'])
|
||||||
elif skip_info.args:
|
elif skip_info.args:
|
||||||
pytest.skip(skip_info.args[0])
|
skip(skip_info.args[0])
|
||||||
else:
|
else:
|
||||||
pytest.skip("unconditional skip")
|
skip("unconditional skip")
|
||||||
|
|
||||||
item._evalxfail = MarkEvaluator(item, 'xfail')
|
item._evalxfail = MarkEvaluator(item, 'xfail')
|
||||||
check_xfail_no_run(item)
|
check_xfail_no_run(item)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.hookwrapper
|
@hookimpl(hookwrapper=True)
|
||||||
def pytest_pyfunc_call(pyfuncitem):
|
def pytest_pyfunc_call(pyfuncitem):
|
||||||
check_xfail_no_run(pyfuncitem)
|
check_xfail_no_run(pyfuncitem)
|
||||||
outcome = yield
|
outcome = yield
|
||||||
|
@ -206,7 +204,7 @@ def check_xfail_no_run(item):
|
||||||
evalxfail = item._evalxfail
|
evalxfail = item._evalxfail
|
||||||
if evalxfail.istrue():
|
if evalxfail.istrue():
|
||||||
if not evalxfail.get('run', True):
|
if not evalxfail.get('run', True):
|
||||||
pytest.xfail("[NOTRUN] " + evalxfail.getexplanation())
|
xfail("[NOTRUN] " + evalxfail.getexplanation())
|
||||||
|
|
||||||
|
|
||||||
def check_strict_xfail(pyfuncitem):
|
def check_strict_xfail(pyfuncitem):
|
||||||
|
@ -218,10 +216,10 @@ def check_strict_xfail(pyfuncitem):
|
||||||
if is_strict_xfail:
|
if is_strict_xfail:
|
||||||
del pyfuncitem._evalxfail
|
del pyfuncitem._evalxfail
|
||||||
explanation = evalxfail.getexplanation()
|
explanation = evalxfail.getexplanation()
|
||||||
pytest.fail('[XPASS(strict)] ' + explanation, pytrace=False)
|
fail('[XPASS(strict)] ' + explanation, pytrace=False)
|
||||||
|
|
||||||
|
|
||||||
@pytest.hookimpl(hookwrapper=True)
|
@hookimpl(hookwrapper=True)
|
||||||
def pytest_runtest_makereport(item, call):
|
def pytest_runtest_makereport(item, call):
|
||||||
outcome = yield
|
outcome = yield
|
||||||
rep = outcome.get_result()
|
rep = outcome.get_result()
|
||||||
|
@ -241,7 +239,7 @@ def pytest_runtest_makereport(item, call):
|
||||||
rep.wasxfail = rep.longrepr
|
rep.wasxfail = rep.longrepr
|
||||||
elif item.config.option.runxfail:
|
elif item.config.option.runxfail:
|
||||||
pass # don't interefere
|
pass # don't interefere
|
||||||
elif call.excinfo and call.excinfo.errisinstance(pytest.xfail.Exception):
|
elif call.excinfo and call.excinfo.errisinstance(xfail.Exception):
|
||||||
rep.wasxfail = "reason: " + call.excinfo.value.msg
|
rep.wasxfail = "reason: " + call.excinfo.value.msg
|
||||||
rep.outcome = "skipped"
|
rep.outcome = "skipped"
|
||||||
elif evalxfail and not rep.skipped and evalxfail.wasvalid() and \
|
elif evalxfail and not rep.skipped and evalxfail.wasvalid() and \
|
||||||
|
@ -309,12 +307,14 @@ def pytest_terminal_summary(terminalreporter):
|
||||||
for line in lines:
|
for line in lines:
|
||||||
tr._tw.line(line)
|
tr._tw.line(line)
|
||||||
|
|
||||||
|
|
||||||
def show_simple(terminalreporter, lines, stat, format):
|
def show_simple(terminalreporter, lines, stat, format):
|
||||||
failed = terminalreporter.stats.get(stat)
|
failed = terminalreporter.stats.get(stat)
|
||||||
if failed:
|
if failed:
|
||||||
for rep in failed:
|
for rep in failed:
|
||||||
pos = terminalreporter.config.cwd_relative_nodeid(rep.nodeid)
|
pos = terminalreporter.config.cwd_relative_nodeid(rep.nodeid)
|
||||||
lines.append(format %(pos,))
|
lines.append(format % (pos,))
|
||||||
|
|
||||||
|
|
||||||
def show_xfailed(terminalreporter, lines):
|
def show_xfailed(terminalreporter, lines):
|
||||||
xfailed = terminalreporter.stats.get("xfailed")
|
xfailed = terminalreporter.stats.get("xfailed")
|
||||||
|
@ -326,13 +326,15 @@ def show_xfailed(terminalreporter, lines):
|
||||||
if reason:
|
if reason:
|
||||||
lines.append(" " + str(reason))
|
lines.append(" " + str(reason))
|
||||||
|
|
||||||
|
|
||||||
def show_xpassed(terminalreporter, lines):
|
def show_xpassed(terminalreporter, lines):
|
||||||
xpassed = terminalreporter.stats.get("xpassed")
|
xpassed = terminalreporter.stats.get("xpassed")
|
||||||
if xpassed:
|
if xpassed:
|
||||||
for rep in xpassed:
|
for rep in xpassed:
|
||||||
pos = terminalreporter.config.cwd_relative_nodeid(rep.nodeid)
|
pos = terminalreporter.config.cwd_relative_nodeid(rep.nodeid)
|
||||||
reason = rep.wasxfail
|
reason = rep.wasxfail
|
||||||
lines.append("XPASS %s %s" %(pos, reason))
|
lines.append("XPASS %s %s" % (pos, reason))
|
||||||
|
|
||||||
|
|
||||||
def cached_eval(config, expr, d):
|
def cached_eval(config, expr, d):
|
||||||
if not hasattr(config, '_evalcache'):
|
if not hasattr(config, '_evalcache'):
|
||||||
|
@ -357,6 +359,7 @@ def folded_skips(skipped):
|
||||||
l.append((len(events),) + key)
|
l.append((len(events),) + key)
|
||||||
return l
|
return l
|
||||||
|
|
||||||
|
|
||||||
def show_skipped(terminalreporter, lines):
|
def show_skipped(terminalreporter, lines):
|
||||||
tr = terminalreporter
|
tr = terminalreporter
|
||||||
skipped = tr.stats.get('skipped', [])
|
skipped = tr.stats.get('skipped', [])
|
||||||
|
@ -372,5 +375,6 @@ def show_skipped(terminalreporter, lines):
|
||||||
for num, fspath, lineno, reason in fskips:
|
for num, fspath, lineno, reason in fskips:
|
||||||
if reason.startswith("Skipped: "):
|
if reason.startswith("Skipped: "):
|
||||||
reason = reason[9:]
|
reason = reason[9:]
|
||||||
lines.append("SKIP [%d] %s:%d: %s" %
|
lines.append(
|
||||||
|
"SKIP [%d] %s:%d: %s" %
|
||||||
(num, fspath, lineno, reason))
|
(num, fspath, lineno, reason))
|
||||||
|
|
|
@ -4,11 +4,12 @@ from __future__ import absolute_import, division, print_function
|
||||||
import sys
|
import sys
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
import pytest
|
|
||||||
# for transferring markers
|
# for transferring markers
|
||||||
import _pytest._code
|
import _pytest._code
|
||||||
from _pytest.python import transfer_markers
|
from _pytest.config import hookimpl
|
||||||
from _pytest.skipping import MarkEvaluator
|
from _pytest.runner import fail, skip
|
||||||
|
from _pytest.python import transfer_markers, Class, Module, Function
|
||||||
|
from _pytest.skipping import MarkEvaluator, xfail
|
||||||
|
|
||||||
|
|
||||||
def pytest_pycollect_makeitem(collector, name, obj):
|
def pytest_pycollect_makeitem(collector, name, obj):
|
||||||
|
@ -22,7 +23,7 @@ def pytest_pycollect_makeitem(collector, name, obj):
|
||||||
return UnitTestCase(name, parent=collector)
|
return UnitTestCase(name, parent=collector)
|
||||||
|
|
||||||
|
|
||||||
class UnitTestCase(pytest.Class):
|
class UnitTestCase(Class):
|
||||||
# marker for fixturemanger.getfixtureinfo()
|
# marker for fixturemanger.getfixtureinfo()
|
||||||
# to declare that our children do not support funcargs
|
# to declare that our children do not support funcargs
|
||||||
nofuncargs = True
|
nofuncargs = True
|
||||||
|
@ -46,7 +47,7 @@ class UnitTestCase(pytest.Class):
|
||||||
return
|
return
|
||||||
self.session._fixturemanager.parsefactories(self, unittest=True)
|
self.session._fixturemanager.parsefactories(self, unittest=True)
|
||||||
loader = TestLoader()
|
loader = TestLoader()
|
||||||
module = self.getparent(pytest.Module).obj
|
module = self.getparent(Module).obj
|
||||||
foundsomething = False
|
foundsomething = False
|
||||||
for name in loader.getTestCaseNames(self.obj):
|
for name in loader.getTestCaseNames(self.obj):
|
||||||
x = getattr(self.obj, name)
|
x = getattr(self.obj, name)
|
||||||
|
@ -65,7 +66,7 @@ class UnitTestCase(pytest.Class):
|
||||||
yield TestCaseFunction('runTest', parent=self)
|
yield TestCaseFunction('runTest', parent=self)
|
||||||
|
|
||||||
|
|
||||||
class TestCaseFunction(pytest.Function):
|
class TestCaseFunction(Function):
|
||||||
_excinfo = None
|
_excinfo = None
|
||||||
|
|
||||||
def setup(self):
|
def setup(self):
|
||||||
|
@ -111,35 +112,36 @@ class TestCaseFunction(pytest.Function):
|
||||||
l = traceback.format_exception(*rawexcinfo)
|
l = traceback.format_exception(*rawexcinfo)
|
||||||
l.insert(0, "NOTE: Incompatible Exception Representation, "
|
l.insert(0, "NOTE: Incompatible Exception Representation, "
|
||||||
"displaying natively:\n\n")
|
"displaying natively:\n\n")
|
||||||
pytest.fail("".join(l), pytrace=False)
|
fail("".join(l), pytrace=False)
|
||||||
except (pytest.fail.Exception, KeyboardInterrupt):
|
except (fail.Exception, KeyboardInterrupt):
|
||||||
raise
|
raise
|
||||||
except:
|
except:
|
||||||
pytest.fail("ERROR: Unknown Incompatible Exception "
|
fail("ERROR: Unknown Incompatible Exception "
|
||||||
"representation:\n%r" %(rawexcinfo,), pytrace=False)
|
"representation:\n%r" % (rawexcinfo,), pytrace=False)
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
raise
|
raise
|
||||||
except pytest.fail.Exception:
|
except fail.Exception:
|
||||||
excinfo = _pytest._code.ExceptionInfo()
|
excinfo = _pytest._code.ExceptionInfo()
|
||||||
self.__dict__.setdefault('_excinfo', []).append(excinfo)
|
self.__dict__.setdefault('_excinfo', []).append(excinfo)
|
||||||
|
|
||||||
def addError(self, testcase, rawexcinfo):
|
def addError(self, testcase, rawexcinfo):
|
||||||
self._addexcinfo(rawexcinfo)
|
self._addexcinfo(rawexcinfo)
|
||||||
|
|
||||||
def addFailure(self, testcase, rawexcinfo):
|
def addFailure(self, testcase, rawexcinfo):
|
||||||
self._addexcinfo(rawexcinfo)
|
self._addexcinfo(rawexcinfo)
|
||||||
|
|
||||||
def addSkip(self, testcase, reason):
|
def addSkip(self, testcase, reason):
|
||||||
try:
|
try:
|
||||||
pytest.skip(reason)
|
skip(reason)
|
||||||
except pytest.skip.Exception:
|
except skip.Exception:
|
||||||
self._evalskip = MarkEvaluator(self, 'SkipTest')
|
self._evalskip = MarkEvaluator(self, 'SkipTest')
|
||||||
self._evalskip.result = True
|
self._evalskip.result = True
|
||||||
self._addexcinfo(sys.exc_info())
|
self._addexcinfo(sys.exc_info())
|
||||||
|
|
||||||
def addExpectedFailure(self, testcase, rawexcinfo, reason=""):
|
def addExpectedFailure(self, testcase, rawexcinfo, reason=""):
|
||||||
try:
|
try:
|
||||||
pytest.xfail(str(reason))
|
xfail(str(reason))
|
||||||
except pytest.xfail.Exception:
|
except xfail.Exception:
|
||||||
self._addexcinfo(sys.exc_info())
|
self._addexcinfo(sys.exc_info())
|
||||||
|
|
||||||
def addUnexpectedSuccess(self, testcase, reason=""):
|
def addUnexpectedSuccess(self, testcase, reason=""):
|
||||||
|
@ -179,13 +181,14 @@ class TestCaseFunction(pytest.Function):
|
||||||
self._testcase.debug()
|
self._testcase.debug()
|
||||||
|
|
||||||
def _prunetraceback(self, excinfo):
|
def _prunetraceback(self, excinfo):
|
||||||
pytest.Function._prunetraceback(self, excinfo)
|
Function._prunetraceback(self, excinfo)
|
||||||
traceback = excinfo.traceback.filter(
|
traceback = excinfo.traceback.filter(
|
||||||
lambda x:not x.frame.f_globals.get('__unittest'))
|
lambda x: not x.frame.f_globals.get('__unittest'))
|
||||||
if traceback:
|
if traceback:
|
||||||
excinfo.traceback = traceback
|
excinfo.traceback = traceback
|
||||||
|
|
||||||
@pytest.hookimpl(tryfirst=True)
|
|
||||||
|
@hookimpl(tryfirst=True)
|
||||||
def pytest_runtest_makereport(item, call):
|
def pytest_runtest_makereport(item, call):
|
||||||
if isinstance(item, TestCaseFunction):
|
if isinstance(item, TestCaseFunction):
|
||||||
if item._excinfo:
|
if item._excinfo:
|
||||||
|
@ -197,7 +200,8 @@ def pytest_runtest_makereport(item, call):
|
||||||
|
|
||||||
# twisted trial support
|
# twisted trial support
|
||||||
|
|
||||||
@pytest.hookimpl(hookwrapper=True)
|
|
||||||
|
@hookimpl(hookwrapper=True)
|
||||||
def pytest_runtest_protocol(item):
|
def pytest_runtest_protocol(item):
|
||||||
if isinstance(item, TestCaseFunction) and \
|
if isinstance(item, TestCaseFunction) and \
|
||||||
'twisted.trial.unittest' in sys.modules:
|
'twisted.trial.unittest' in sys.modules:
|
||||||
|
|
|
@ -517,7 +517,6 @@ Initialization, command line and configuration hooks
|
||||||
.. autofunction:: pytest_load_initial_conftests
|
.. autofunction:: pytest_load_initial_conftests
|
||||||
.. autofunction:: pytest_cmdline_preparse
|
.. autofunction:: pytest_cmdline_preparse
|
||||||
.. autofunction:: pytest_cmdline_parse
|
.. autofunction:: pytest_cmdline_parse
|
||||||
.. autofunction:: pytest_namespace
|
|
||||||
.. autofunction:: pytest_addoption
|
.. autofunction:: pytest_addoption
|
||||||
.. autofunction:: pytest_cmdline_main
|
.. autofunction:: pytest_cmdline_main
|
||||||
.. autofunction:: pytest_configure
|
.. autofunction:: pytest_configure
|
||||||
|
|
76
pytest.py
76
pytest.py
|
@ -2,19 +2,7 @@
|
||||||
"""
|
"""
|
||||||
pytest: unit and functional testing with Python.
|
pytest: unit and functional testing with Python.
|
||||||
"""
|
"""
|
||||||
__all__ = [
|
|
||||||
'main',
|
|
||||||
'UsageError',
|
|
||||||
'cmdline',
|
|
||||||
'hookspec',
|
|
||||||
'hookimpl',
|
|
||||||
'__version__',
|
|
||||||
]
|
|
||||||
|
|
||||||
if __name__ == '__main__': # if run as a script or by 'python -m pytest'
|
|
||||||
# we trigger the below "else" condition by the following import
|
|
||||||
import pytest
|
|
||||||
raise SystemExit(pytest.main())
|
|
||||||
|
|
||||||
# else we are imported
|
# else we are imported
|
||||||
|
|
||||||
|
@ -22,7 +10,69 @@ from _pytest.config import (
|
||||||
main, UsageError, _preloadplugins, cmdline,
|
main, UsageError, _preloadplugins, cmdline,
|
||||||
hookspec, hookimpl
|
hookspec, hookimpl
|
||||||
)
|
)
|
||||||
|
from _pytest.fixtures import fixture, yield_fixture
|
||||||
|
from _pytest.assertion import register_assert_rewrite
|
||||||
|
from _pytest.freeze_support import freeze_includes
|
||||||
from _pytest import __version__
|
from _pytest import __version__
|
||||||
|
from _pytest.debugging import pytestPDB as __pytestPDB
|
||||||
|
from _pytest.recwarn import warns, deprecated_call
|
||||||
|
from _pytest.runner import fail, skip, importorskip, exit
|
||||||
|
from _pytest.mark import MARK_GEN as mark, param
|
||||||
|
from _pytest.skipping import xfail
|
||||||
|
from _pytest.main import Item, Collector, File, Session
|
||||||
|
from _pytest.fixtures import fillfixtures as _fillfuncargs
|
||||||
|
from _pytest.python import (
|
||||||
|
raises, approx,
|
||||||
|
Module, Class, Instance, Function, Generator,
|
||||||
|
)
|
||||||
|
|
||||||
_preloadplugins() # to populate pytest.* namespace so help(pytest) works
|
set_trace = __pytestPDB.set_trace
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
'main',
|
||||||
|
'UsageError',
|
||||||
|
'cmdline',
|
||||||
|
'hookspec',
|
||||||
|
'hookimpl',
|
||||||
|
'__version__',
|
||||||
|
'register_assert_rewrite',
|
||||||
|
'freeze_includes',
|
||||||
|
'set_trace',
|
||||||
|
'warns',
|
||||||
|
'deprecated_call',
|
||||||
|
'fixture',
|
||||||
|
'yield_fixture',
|
||||||
|
'fail',
|
||||||
|
'skip',
|
||||||
|
'xfail',
|
||||||
|
'importorskip',
|
||||||
|
'exit',
|
||||||
|
'mark',
|
||||||
|
'param',
|
||||||
|
'approx',
|
||||||
|
'_fillfuncargs',
|
||||||
|
|
||||||
|
'Item',
|
||||||
|
'File',
|
||||||
|
'Collector',
|
||||||
|
'Session',
|
||||||
|
'Module',
|
||||||
|
'Class',
|
||||||
|
'Instance',
|
||||||
|
'Function',
|
||||||
|
'Generator',
|
||||||
|
'raises',
|
||||||
|
|
||||||
|
|
||||||
|
]
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
# if run as a script or by 'python -m pytest'
|
||||||
|
# we trigger the below "else" condition by the following import
|
||||||
|
import pytest
|
||||||
|
raise SystemExit(pytest.main())
|
||||||
|
else:
|
||||||
|
|
||||||
|
from _pytest.compat import _setup_collect_fakemodule
|
||||||
|
_preloadplugins() # to populate pytest.* namespace so help(pytest) works
|
||||||
|
_setup_collect_fakemodule()
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
import py
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import pytest
|
||||||
|
import _pytest
|
||||||
|
|
||||||
|
MODSET = [
|
||||||
|
x for x in py.path.local(_pytest.__file__).dirpath().visit('*.py')
|
||||||
|
if x.purebasename != '__init__'
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('modfile', MODSET, ids=lambda x: x.purebasename)
|
||||||
|
def test_fileimport(modfile):
|
||||||
|
# this test ensures all internal packages can import
|
||||||
|
# without needing the pytest namespace being set
|
||||||
|
# this is critical for the initialization of xdist
|
||||||
|
|
||||||
|
res = subprocess.call([
|
||||||
|
sys.executable,
|
||||||
|
'-c', 'import sys, py; py.path.local(sys.argv[1]).pyimport()',
|
||||||
|
modfile.strpath,
|
||||||
|
])
|
||||||
|
if res:
|
||||||
|
pytest.fail("command result %s" % res)
|
Loading…
Reference in New Issue