refine plugin registration, allow new "-p no:NAME" way to prevent/undo plugin registration
This commit is contained in:
parent
752965c298
commit
c7531705fc
|
@ -1,7 +1,11 @@
|
||||||
Changes between 2.0.0 and 2.0.1.dev1
|
Changes between 2.0.0 and 2.0.1.dev1
|
||||||
----------------------------------------------
|
----------------------------------------------
|
||||||
|
|
||||||
- refinements to terminal output
|
- refinements to "collecting" output on non-ttys
|
||||||
|
- refine internal plugin registration and --traceconfig output
|
||||||
|
- introduce a mechanism to prevent/unregister plugins from the
|
||||||
|
command line, see http://pytest.org/plugins.html#cmdunregister
|
||||||
|
- activate resultlog plugin by default
|
||||||
|
|
||||||
Changes between 1.3.4 and 2.0.0
|
Changes between 1.3.4 and 2.0.0
|
||||||
----------------------------------------------
|
----------------------------------------------
|
||||||
|
|
|
@ -300,9 +300,9 @@ class Config(object):
|
||||||
if addopts:
|
if addopts:
|
||||||
args[:] = self.getini("addopts") + args
|
args[:] = self.getini("addopts") + args
|
||||||
self._checkversion()
|
self._checkversion()
|
||||||
|
self.pluginmanager.consider_preparse(args)
|
||||||
self.pluginmanager.consider_setuptools_entrypoints()
|
self.pluginmanager.consider_setuptools_entrypoints()
|
||||||
self.pluginmanager.consider_env()
|
self.pluginmanager.consider_env()
|
||||||
self.pluginmanager.consider_preparse(args)
|
|
||||||
self._setinitialconftest(args)
|
self._setinitialconftest(args)
|
||||||
self.pluginmanager.do_addoption(self._parser)
|
self.pluginmanager.do_addoption(self._parser)
|
||||||
|
|
||||||
|
|
|
@ -11,11 +11,9 @@ assert py.__version__.split(".")[:2] >= ['1', '4'], ("installation problem: "
|
||||||
"%s is too old, remove or upgrade 'py'" % (py.__version__))
|
"%s is too old, remove or upgrade 'py'" % (py.__version__))
|
||||||
|
|
||||||
default_plugins = (
|
default_plugins = (
|
||||||
"config mark session terminal runner python pdb unittest capture skipping "
|
"config mark main terminal runner python pdb unittest capture skipping "
|
||||||
"tmpdir monkeypatch recwarn pastebin helpconfig nose assertion genscript "
|
"tmpdir monkeypatch recwarn pastebin helpconfig nose assertion genscript "
|
||||||
"junitxml doctest").split()
|
"junitxml resultlog doctest").split()
|
||||||
|
|
||||||
IMPORTPREFIX = "pytest_"
|
|
||||||
|
|
||||||
class TagTracer:
|
class TagTracer:
|
||||||
def __init__(self, prefix="[pytest] "):
|
def __init__(self, prefix="[pytest] "):
|
||||||
|
@ -79,20 +77,12 @@ class PluginManager(object):
|
||||||
for spec in default_plugins:
|
for spec in default_plugins:
|
||||||
self.import_plugin(spec)
|
self.import_plugin(spec)
|
||||||
|
|
||||||
def _getpluginname(self, plugin, name):
|
|
||||||
if name is None:
|
|
||||||
if hasattr(plugin, '__name__'):
|
|
||||||
name = plugin.__name__.split(".")[-1]
|
|
||||||
else:
|
|
||||||
name = id(plugin)
|
|
||||||
return name
|
|
||||||
|
|
||||||
def register(self, plugin, name=None, prepend=False):
|
def register(self, plugin, name=None, prepend=False):
|
||||||
assert not self.isregistered(plugin), plugin
|
assert not self.isregistered(plugin), plugin
|
||||||
assert not self.isregistered(plugin), plugin
|
name = name or getattr(plugin, '__name__', str(id(plugin)))
|
||||||
name = self._getpluginname(plugin, name)
|
|
||||||
if name in self._name2plugin:
|
if name in self._name2plugin:
|
||||||
return False
|
return False
|
||||||
|
#self.trace("registering", name, plugin)
|
||||||
self._name2plugin[name] = plugin
|
self._name2plugin[name] = plugin
|
||||||
self.call_plugin(plugin, "pytest_addhooks", {'pluginmanager': self})
|
self.call_plugin(plugin, "pytest_addhooks", {'pluginmanager': self})
|
||||||
self.hook.pytest_plugin_registered(manager=self, plugin=plugin)
|
self.hook.pytest_plugin_registered(manager=self, plugin=plugin)
|
||||||
|
@ -112,7 +102,7 @@ class PluginManager(object):
|
||||||
del self._name2plugin[name]
|
del self._name2plugin[name]
|
||||||
|
|
||||||
def isregistered(self, plugin, name=None):
|
def isregistered(self, plugin, name=None):
|
||||||
if self._getpluginname(plugin, name) in self._name2plugin:
|
if self.getplugin(name) is not None:
|
||||||
return True
|
return True
|
||||||
for val in self._name2plugin.values():
|
for val in self._name2plugin.values():
|
||||||
if plugin == val:
|
if plugin == val:
|
||||||
|
@ -136,11 +126,12 @@ class PluginManager(object):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def getplugin(self, name):
|
def getplugin(self, name):
|
||||||
|
if name is None:
|
||||||
|
return None
|
||||||
try:
|
try:
|
||||||
return self._name2plugin[name]
|
return self._name2plugin[name]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
impname = canonical_importname(name)
|
return self._name2plugin.get("_pytest." + name, None)
|
||||||
return self._name2plugin[impname]
|
|
||||||
|
|
||||||
# API for bootstrapping
|
# API for bootstrapping
|
||||||
#
|
#
|
||||||
|
@ -160,19 +151,28 @@ class PluginManager(object):
|
||||||
except ImportError:
|
except ImportError:
|
||||||
return # XXX issue a warning
|
return # XXX issue a warning
|
||||||
for ep in iter_entry_points('pytest11'):
|
for ep in iter_entry_points('pytest11'):
|
||||||
name = canonical_importname(ep.name)
|
if ep.name in self._name2plugin:
|
||||||
if name in self._name2plugin:
|
|
||||||
continue
|
continue
|
||||||
try:
|
try:
|
||||||
plugin = ep.load()
|
plugin = ep.load()
|
||||||
except DistributionNotFound:
|
except DistributionNotFound:
|
||||||
continue
|
continue
|
||||||
|
name = ep.name
|
||||||
|
if name.startswith("pytest_"):
|
||||||
|
name = name[7:]
|
||||||
self.register(plugin, name=name)
|
self.register(plugin, name=name)
|
||||||
|
|
||||||
def consider_preparse(self, args):
|
def consider_preparse(self, args):
|
||||||
for opt1,opt2 in zip(args, args[1:]):
|
for opt1,opt2 in zip(args, args[1:]):
|
||||||
if opt1 == "-p":
|
if opt1 == "-p":
|
||||||
self.import_plugin(opt2)
|
if opt2.startswith("no:"):
|
||||||
|
name = opt2[3:]
|
||||||
|
if self.getplugin(name) is not None:
|
||||||
|
self.unregister(None, name=name)
|
||||||
|
self._name2plugin[name] = -1
|
||||||
|
else:
|
||||||
|
if self.getplugin(opt2) is None:
|
||||||
|
self.import_plugin(opt2)
|
||||||
|
|
||||||
def consider_conftest(self, conftestmodule):
|
def consider_conftest(self, conftestmodule):
|
||||||
if self.register(conftestmodule, name=conftestmodule.__file__):
|
if self.register(conftestmodule, name=conftestmodule.__file__):
|
||||||
|
@ -186,15 +186,19 @@ class PluginManager(object):
|
||||||
for spec in attr:
|
for spec in attr:
|
||||||
self.import_plugin(spec)
|
self.import_plugin(spec)
|
||||||
|
|
||||||
def import_plugin(self, spec):
|
def import_plugin(self, modname):
|
||||||
assert isinstance(spec, str)
|
assert isinstance(modname, str)
|
||||||
modname = canonical_importname(spec)
|
if self.getplugin(modname) is not None:
|
||||||
if modname in self._name2plugin:
|
|
||||||
return
|
return
|
||||||
try:
|
try:
|
||||||
|
#self.trace("importing", modname)
|
||||||
mod = importplugin(modname)
|
mod = importplugin(modname)
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
raise
|
raise
|
||||||
|
except ImportError:
|
||||||
|
if modname.startswith("pytest_"):
|
||||||
|
return self.import_plugin(modname[7:])
|
||||||
|
raise
|
||||||
except:
|
except:
|
||||||
e = py.std.sys.exc_info()[1]
|
e = py.std.sys.exc_info()[1]
|
||||||
if not hasattr(py.test, 'skip'):
|
if not hasattr(py.test, 'skip'):
|
||||||
|
@ -290,34 +294,18 @@ class PluginManager(object):
|
||||||
return MultiCall(methods=self.listattr(methname, plugins=[plugin]),
|
return MultiCall(methods=self.listattr(methname, plugins=[plugin]),
|
||||||
kwargs=kwargs, firstresult=True).execute()
|
kwargs=kwargs, firstresult=True).execute()
|
||||||
|
|
||||||
def canonical_importname(name):
|
|
||||||
if '.' in name:
|
|
||||||
return name
|
|
||||||
name = name.lower()
|
|
||||||
if not name.startswith(IMPORTPREFIX):
|
|
||||||
name = IMPORTPREFIX + name
|
|
||||||
return name
|
|
||||||
|
|
||||||
def importplugin(importspec):
|
def importplugin(importspec):
|
||||||
#print "importing", importspec
|
name = importspec
|
||||||
try:
|
try:
|
||||||
return __import__(importspec, None, None, '__doc__')
|
mod = "_pytest." + name
|
||||||
|
return __import__(mod, None, None, '__doc__')
|
||||||
except ImportError:
|
except ImportError:
|
||||||
e = py.std.sys.exc_info()[1]
|
#e = py.std.sys.exc_info()[1]
|
||||||
if str(e).find(importspec) == -1:
|
#if str(e).find(name) == -1:
|
||||||
raise
|
# raise
|
||||||
name = importspec
|
pass #
|
||||||
try:
|
return __import__(importspec, None, None, '__doc__')
|
||||||
if name.startswith("pytest_"):
|
|
||||||
name = importspec[7:]
|
|
||||||
return __import__("_pytest.%s" %(name), None, None, '__doc__')
|
|
||||||
except ImportError:
|
|
||||||
e = py.std.sys.exc_info()[1]
|
|
||||||
if str(e).find(name) == -1:
|
|
||||||
raise
|
|
||||||
# show the original exception, not the failing internal one
|
|
||||||
return __import__(importspec, None, None, '__doc__')
|
|
||||||
|
|
||||||
|
|
||||||
class MultiCall:
|
class MultiCall:
|
||||||
""" execute a call into multiple python functions/methods. """
|
""" execute a call into multiple python functions/methods. """
|
||||||
|
|
|
@ -80,7 +80,11 @@ def pytest_report_header(config):
|
||||||
plugins = []
|
plugins = []
|
||||||
items = config.pluginmanager._name2plugin.items()
|
items = config.pluginmanager._name2plugin.items()
|
||||||
for name, plugin in items:
|
for name, plugin in items:
|
||||||
lines.append(" %-20s: %s" %(name, repr(plugin)))
|
if hasattr(plugin, '__file__'):
|
||||||
|
r = plugin.__file__
|
||||||
|
else:
|
||||||
|
r = repr(plugin)
|
||||||
|
lines.append(" %-20s: %s" %(name, r))
|
||||||
return lines
|
return lines
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -40,7 +40,7 @@ def pytest_addoption(parser):
|
||||||
help="only load conftest.py's relative to specified dir.")
|
help="only load conftest.py's relative to specified dir.")
|
||||||
|
|
||||||
group = parser.getgroup("debugconfig",
|
group = parser.getgroup("debugconfig",
|
||||||
"test process debugging and configuration")
|
"test session debugging and configuration")
|
||||||
group.addoption('--basetemp', dest="basetemp", default=None, metavar="dir",
|
group.addoption('--basetemp', dest="basetemp", default=None, metavar="dir",
|
||||||
help="base temporary directory for this test run.")
|
help="base temporary directory for this test run.")
|
||||||
|
|
||||||
|
@ -336,7 +336,7 @@ class Session(FSCollector):
|
||||||
def __init__(self, config):
|
def __init__(self, config):
|
||||||
super(Session, self).__init__(py.path.local(), parent=None,
|
super(Session, self).__init__(py.path.local(), parent=None,
|
||||||
config=config, session=self)
|
config=config, session=self)
|
||||||
self.config.pluginmanager.register(self, name="session", prepend=True)
|
assert self.config.pluginmanager.register(self, name="session", prepend=True)
|
||||||
self._testsfailed = 0
|
self._testsfailed = 0
|
||||||
self.shouldstop = False
|
self.shouldstop = False
|
||||||
self.trace = config.trace.root.get("collection")
|
self.trace = config.trace.root.get("collection")
|
|
@ -6,7 +6,7 @@ import re
|
||||||
import inspect
|
import inspect
|
||||||
import time
|
import time
|
||||||
from fnmatch import fnmatch
|
from fnmatch import fnmatch
|
||||||
from _pytest.session import Session
|
from _pytest.main import Session
|
||||||
from py.builtin import print_
|
from py.builtin import print_
|
||||||
from _pytest.core import HookRelay
|
from _pytest.core import HookRelay
|
||||||
|
|
||||||
|
|
|
@ -730,7 +730,7 @@ class FuncargRequest:
|
||||||
raise self.LookupError(msg)
|
raise self.LookupError(msg)
|
||||||
|
|
||||||
def showfuncargs(config):
|
def showfuncargs(config):
|
||||||
from _pytest.session import Session
|
from _pytest.main import Session
|
||||||
session = Session(config)
|
session = Session(config)
|
||||||
session.perform_collect()
|
session.perform_collect()
|
||||||
if session.items:
|
if session.items:
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
""" (disabled by default) create result information in a plain text file. """
|
""" (disabled by default) create result information in a plain text file. """
|
||||||
|
|
||||||
import py
|
import py
|
||||||
from py.builtin import print_
|
|
||||||
|
|
||||||
def pytest_addoption(parser):
|
def pytest_addoption(parser):
|
||||||
group = parser.getgroup("resultlog", "resultlog plugin options")
|
group = parser.getgroup("terminal reporting", "resultlog plugin options")
|
||||||
group.addoption('--resultlog', action="store", dest="resultlog", metavar="path", default=None,
|
group.addoption('--resultlog', action="store", dest="resultlog",
|
||||||
help="path for machine-readable result log.")
|
metavar="path", default=None,
|
||||||
|
help="path for machine-readable result log.")
|
||||||
|
|
||||||
def pytest_configure(config):
|
def pytest_configure(config):
|
||||||
resultlog = config.option.resultlog
|
resultlog = config.option.resultlog
|
||||||
|
@ -52,9 +52,9 @@ class ResultLog(object):
|
||||||
self.logfile = logfile # preferably line buffered
|
self.logfile = logfile # preferably line buffered
|
||||||
|
|
||||||
def write_log_entry(self, testpath, lettercode, longrepr):
|
def write_log_entry(self, testpath, lettercode, longrepr):
|
||||||
print_("%s %s" % (lettercode, testpath), file=self.logfile)
|
py.builtin.print_("%s %s" % (lettercode, testpath), file=self.logfile)
|
||||||
for line in longrepr.splitlines():
|
for line in longrepr.splitlines():
|
||||||
print_(" %s" % line, file=self.logfile)
|
py.builtin.print_(" %s" % line, file=self.logfile)
|
||||||
|
|
||||||
def log_outcome(self, report, lettercode, longrepr):
|
def log_outcome(self, report, lettercode, longrepr):
|
||||||
testpath = getattr(report, 'nodeid', None)
|
testpath = getattr(report, 'nodeid', None)
|
||||||
|
|
|
@ -10,7 +10,6 @@
|
||||||
.. _pytest: http://pypi.python.org/pypi/pytest
|
.. _pytest: http://pypi.python.org/pypi/pytest
|
||||||
.. _mercurial: http://mercurial.selenic.com/wiki/
|
.. _mercurial: http://mercurial.selenic.com/wiki/
|
||||||
.. _`setuptools`: http://pypi.python.org/pypi/setuptools
|
.. _`setuptools`: http://pypi.python.org/pypi/setuptools
|
||||||
|
|
||||||
.. _`easy_install`:
|
.. _`easy_install`:
|
||||||
.. _`distribute docs`:
|
.. _`distribute docs`:
|
||||||
.. _`distribute`: http://pypi.python.org/pypi/distribute
|
.. _`distribute`: http://pypi.python.org/pypi/distribute
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
Writing, managing and understanding plugins
|
Working with plugins and conftest files
|
||||||
=============================================
|
=============================================
|
||||||
|
|
||||||
.. _`local plugin`:
|
.. _`local plugin`:
|
||||||
|
@ -11,6 +11,7 @@ py.test implements all aspects of configuration, collection, running and reporti
|
||||||
|
|
||||||
.. _`pytest/plugin`: http://bitbucket.org/hpk42/pytest/src/tip/pytest/plugin/
|
.. _`pytest/plugin`: http://bitbucket.org/hpk42/pytest/src/tip/pytest/plugin/
|
||||||
.. _`conftest.py plugins`:
|
.. _`conftest.py plugins`:
|
||||||
|
.. _`conftest.py`:
|
||||||
|
|
||||||
conftest.py: local per-directory plugins
|
conftest.py: local per-directory plugins
|
||||||
--------------------------------------------------------------
|
--------------------------------------------------------------
|
||||||
|
@ -53,6 +54,7 @@ earlier than further away ones.
|
||||||
conftest.py file.
|
conftest.py file.
|
||||||
|
|
||||||
.. _`external plugins`:
|
.. _`external plugins`:
|
||||||
|
.. _`extplugins`:
|
||||||
|
|
||||||
Installing External Plugins / Searching
|
Installing External Plugins / Searching
|
||||||
------------------------------------------------------
|
------------------------------------------------------
|
||||||
|
@ -64,9 +66,26 @@ tool, for example::
|
||||||
pip uninstall pytest-NAME
|
pip uninstall pytest-NAME
|
||||||
|
|
||||||
If a plugin is installed, py.test automatically finds and integrates it,
|
If a plugin is installed, py.test automatically finds and integrates it,
|
||||||
there is no need to activate it. If you don't need a plugin anymore simply
|
there is no need to activate it. Here is a list of known plugins:
|
||||||
de-install it. You can find a list of available plugins through a
|
|
||||||
`pytest- pypi.python.org search`_.
|
* `pytest-capturelog <http://pypi.python.org/pypi/pytest-capturelog>`_:
|
||||||
|
to capture and assert about messages from the logging module
|
||||||
|
|
||||||
|
* `pytest-xdist <http://pypi.python.org/pypi/pytest-xdist>`_:
|
||||||
|
to distribute tests to CPUs and remote hosts, looponfailing mode,
|
||||||
|
see also :ref:`xdist`
|
||||||
|
|
||||||
|
* `pytest-cov <http://pypi.python.org/pypi/pytest-cov>`_:
|
||||||
|
coverage reporting, compatible with distributed testing
|
||||||
|
|
||||||
|
* `pytest-pep8 <http://pypi.python.org/pypi/pytest-pep8>`_:
|
||||||
|
a ``--pep8`` option to enable PEP8 compliancy checking.
|
||||||
|
|
||||||
|
* `oejskit <http://pypi.python.org/pypi/oejskit>`_:
|
||||||
|
a plugin to run javascript unittests in life browsers
|
||||||
|
(**version 0.8.9 not compatible with pytest-2.0**)
|
||||||
|
|
||||||
|
You may discover more plugins through a `pytest- pypi.python.org search`_.
|
||||||
|
|
||||||
.. _`available installable plugins`:
|
.. _`available installable plugins`:
|
||||||
.. _`pytest- pypi.python.org search`: http://pypi.python.org/pypi?%3Aaction=search&term=pytest-&submit=search
|
.. _`pytest- pypi.python.org search`: http://pypi.python.org/pypi?%3Aaction=search&term=pytest-&submit=search
|
||||||
|
@ -170,12 +189,42 @@ the plugin manager like this:
|
||||||
If you want to look at the names of existing plugins, use
|
If you want to look at the names of existing plugins, use
|
||||||
the ``--traceconfig`` option.
|
the ``--traceconfig`` option.
|
||||||
|
|
||||||
|
.. _`findpluginname`:
|
||||||
|
|
||||||
|
Finding out which plugins are active
|
||||||
|
----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
If you want to find out which plugins are active in your
|
||||||
|
environment you can type::
|
||||||
|
|
||||||
|
py.test --traceconfig
|
||||||
|
|
||||||
|
and will get an extended test header which shows activated plugins
|
||||||
|
and their names. It will also print local plugins aka
|
||||||
|
:ref:`conftest.py <conftest>` files when they are loaded.
|
||||||
|
|
||||||
|
.. _`cmdunregister`:
|
||||||
|
|
||||||
|
deactivate / unregister a plugin by name
|
||||||
|
----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
You can prevent plugins from loading or unregister them::
|
||||||
|
|
||||||
|
py.test -p no:NAME
|
||||||
|
|
||||||
|
This means that any subsequent try to activate/load the named
|
||||||
|
plugin will it already existing. See :ref:`findpluginname` for
|
||||||
|
how to obtain the name of a plugin.
|
||||||
|
|
||||||
.. _`builtin plugins`:
|
.. _`builtin plugins`:
|
||||||
|
|
||||||
py.test default plugin reference
|
py.test default plugin reference
|
||||||
====================================
|
====================================
|
||||||
|
|
||||||
|
|
||||||
|
You can find the source code for the following plugins
|
||||||
|
in the `pytest repository <http://bitbucket.org/hpk42/pytest/>`_.
|
||||||
|
|
||||||
.. autosummary::
|
.. autosummary::
|
||||||
|
|
||||||
_pytest.assertion
|
_pytest.assertion
|
||||||
|
@ -195,7 +244,7 @@ py.test default plugin reference
|
||||||
_pytest.recwarn
|
_pytest.recwarn
|
||||||
_pytest.resultlog
|
_pytest.resultlog
|
||||||
_pytest.runner
|
_pytest.runner
|
||||||
_pytest.session
|
_pytest.main
|
||||||
_pytest.skipping
|
_pytest.skipping
|
||||||
_pytest.terminal
|
_pytest.terminal
|
||||||
_pytest.tmpdir
|
_pytest.tmpdir
|
||||||
|
@ -288,14 +337,14 @@ Reference of important objects involved in hooks
|
||||||
.. autoclass:: _pytest.config.Parser
|
.. autoclass:: _pytest.config.Parser
|
||||||
:members:
|
:members:
|
||||||
|
|
||||||
.. autoclass:: _pytest.session.Node(name, parent)
|
.. autoclass:: _pytest.main.Node(name, parent)
|
||||||
:members:
|
:members:
|
||||||
|
|
||||||
..
|
..
|
||||||
.. autoclass:: _pytest.session.File(fspath, parent)
|
.. autoclass:: _pytest.main.File(fspath, parent)
|
||||||
:members:
|
:members:
|
||||||
|
|
||||||
.. autoclass:: _pytest.session.Item(name, parent)
|
.. autoclass:: _pytest.main.Item(name, parent)
|
||||||
:members:
|
:members:
|
||||||
|
|
||||||
.. autoclass:: _pytest.python.Module(name, parent)
|
.. autoclass:: _pytest.python.Module(name, parent)
|
||||||
|
@ -313,4 +362,3 @@ Reference of important objects involved in hooks
|
||||||
.. autoclass:: _pytest.runner.TestReport
|
.. autoclass:: _pytest.runner.TestReport
|
||||||
:members:
|
:members:
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ class TestGeneralUsage:
|
||||||
def test_option(pytestconfig):
|
def test_option(pytestconfig):
|
||||||
assert pytestconfig.option.xyz == "123"
|
assert pytestconfig.option.xyz == "123"
|
||||||
""")
|
""")
|
||||||
result = testdir.runpytest("-p", "xyz", "--xyz=123")
|
result = testdir.runpytest("-p", "pytest_xyz", "--xyz=123")
|
||||||
assert result.ret == 0
|
assert result.ret == 0
|
||||||
result.stdout.fnmatch_lines([
|
result.stdout.fnmatch_lines([
|
||||||
'*1 passed*',
|
'*1 passed*',
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import pytest, py
|
import pytest, py
|
||||||
|
|
||||||
from _pytest.session import Session
|
from _pytest.main import Session
|
||||||
|
|
||||||
class TestCollector:
|
class TestCollector:
|
||||||
def test_collect_versus_item(self):
|
def test_collect_versus_item(self):
|
||||||
|
|
|
@ -219,7 +219,7 @@ def test_options_on_small_file_do_not_blow_up(testdir):
|
||||||
['--traceconfig'], ['-v'], ['-v', '-v']):
|
['--traceconfig'], ['-v'], ['-v', '-v']):
|
||||||
runfiletest(opts + [path])
|
runfiletest(opts + [path])
|
||||||
|
|
||||||
def test_preparse_ordering(testdir, monkeypatch):
|
def test_preparse_ordering_with_setuptools(testdir, monkeypatch):
|
||||||
pkg_resources = py.test.importorskip("pkg_resources")
|
pkg_resources = py.test.importorskip("pkg_resources")
|
||||||
def my_iter(name):
|
def my_iter(name):
|
||||||
assert name == "pytest11"
|
assert name == "pytest11"
|
||||||
|
@ -239,3 +239,16 @@ def test_preparse_ordering(testdir, monkeypatch):
|
||||||
plugin = config.pluginmanager.getplugin("mytestplugin")
|
plugin = config.pluginmanager.getplugin("mytestplugin")
|
||||||
assert plugin.x == 42
|
assert plugin.x == 42
|
||||||
|
|
||||||
|
def test_plugin_preparse_prevents_setuptools_loading(testdir, monkeypatch):
|
||||||
|
pkg_resources = py.test.importorskip("pkg_resources")
|
||||||
|
def my_iter(name):
|
||||||
|
assert name == "pytest11"
|
||||||
|
class EntryPoint:
|
||||||
|
name = "mytestplugin"
|
||||||
|
def load(self):
|
||||||
|
assert 0, "should not arrive here"
|
||||||
|
return iter([EntryPoint()])
|
||||||
|
monkeypatch.setattr(pkg_resources, 'iter_entry_points', my_iter)
|
||||||
|
config = testdir.parseconfig("-p", "no:mytestplugin")
|
||||||
|
plugin = config.pluginmanager.getplugin("mytestplugin")
|
||||||
|
assert plugin == -1
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import pytest, py, os
|
import pytest, py, os
|
||||||
from _pytest.core import PluginManager, canonical_importname
|
from _pytest.core import PluginManager
|
||||||
from _pytest.core import MultiCall, HookRelay, varnames
|
from _pytest.core import MultiCall, HookRelay, varnames
|
||||||
|
|
||||||
|
|
||||||
|
@ -15,30 +15,47 @@ class TestBootstrapping:
|
||||||
pluginmanager.consider_preparse(["xyz", "-p", "hello123"])
|
pluginmanager.consider_preparse(["xyz", "-p", "hello123"])
|
||||||
""")
|
""")
|
||||||
|
|
||||||
|
def test_plugin_prevent_register(self):
|
||||||
|
pluginmanager = PluginManager()
|
||||||
|
pluginmanager.consider_preparse(["xyz", "-p", "no:abc"])
|
||||||
|
l1 = pluginmanager.getplugins()
|
||||||
|
pluginmanager.register(42, name="abc")
|
||||||
|
l2 = pluginmanager.getplugins()
|
||||||
|
assert len(l2) == len(l1)
|
||||||
|
|
||||||
|
def test_plugin_prevent_register_unregistered_alredy_registered(self):
|
||||||
|
pluginmanager = PluginManager()
|
||||||
|
pluginmanager.register(42, name="abc")
|
||||||
|
l1 = pluginmanager.getplugins()
|
||||||
|
assert 42 in l1
|
||||||
|
pluginmanager.consider_preparse(["xyz", "-p", "no:abc"])
|
||||||
|
l2 = pluginmanager.getplugins()
|
||||||
|
assert 42 not in l2
|
||||||
|
|
||||||
def test_plugin_skip(self, testdir, monkeypatch):
|
def test_plugin_skip(self, testdir, monkeypatch):
|
||||||
p = testdir.makepyfile(pytest_skipping1="""
|
p = testdir.makepyfile(skipping1="""
|
||||||
import pytest
|
import pytest
|
||||||
pytest.skip("hello")
|
pytest.skip("hello")
|
||||||
""")
|
""")
|
||||||
p.copy(p.dirpath("pytest_skipping2.py"))
|
p.copy(p.dirpath("skipping2.py"))
|
||||||
monkeypatch.setenv("PYTEST_PLUGINS", "skipping2")
|
monkeypatch.setenv("PYTEST_PLUGINS", "skipping2")
|
||||||
result = testdir.runpytest("-p", "skipping1", "--traceconfig")
|
result = testdir.runpytest("-p", "skipping1", "--traceconfig")
|
||||||
assert result.ret == 0
|
assert result.ret == 0
|
||||||
result.stdout.fnmatch_lines([
|
result.stdout.fnmatch_lines([
|
||||||
"*hint*skipping2*hello*",
|
|
||||||
"*hint*skipping1*hello*",
|
"*hint*skipping1*hello*",
|
||||||
|
"*hint*skipping2*hello*",
|
||||||
])
|
])
|
||||||
|
|
||||||
def test_consider_env_plugin_instantiation(self, testdir, monkeypatch):
|
def test_consider_env_plugin_instantiation(self, testdir, monkeypatch):
|
||||||
pluginmanager = PluginManager()
|
pluginmanager = PluginManager()
|
||||||
testdir.syspathinsert()
|
testdir.syspathinsert()
|
||||||
testdir.makepyfile(pytest_xy123="#")
|
testdir.makepyfile(xy123="#")
|
||||||
monkeypatch.setitem(os.environ, 'PYTEST_PLUGINS', 'xy123')
|
monkeypatch.setitem(os.environ, 'PYTEST_PLUGINS', 'xy123')
|
||||||
l1 = len(pluginmanager.getplugins())
|
l1 = len(pluginmanager.getplugins())
|
||||||
pluginmanager.consider_env()
|
pluginmanager.consider_env()
|
||||||
l2 = len(pluginmanager.getplugins())
|
l2 = len(pluginmanager.getplugins())
|
||||||
assert l2 == l1 + 1
|
assert l2 == l1 + 1
|
||||||
assert pluginmanager.getplugin('pytest_xy123')
|
assert pluginmanager.getplugin('xy123')
|
||||||
pluginmanager.consider_env()
|
pluginmanager.consider_env()
|
||||||
l3 = len(pluginmanager.getplugins())
|
l3 = len(pluginmanager.getplugins())
|
||||||
assert l2 == l3
|
assert l2 == l3
|
||||||
|
@ -48,7 +65,7 @@ class TestBootstrapping:
|
||||||
def my_iter(name):
|
def my_iter(name):
|
||||||
assert name == "pytest11"
|
assert name == "pytest11"
|
||||||
class EntryPoint:
|
class EntryPoint:
|
||||||
name = "mytestplugin"
|
name = "pytest_mytestplugin"
|
||||||
def load(self):
|
def load(self):
|
||||||
class PseudoPlugin:
|
class PseudoPlugin:
|
||||||
x = 42
|
x = 42
|
||||||
|
@ -60,8 +77,6 @@ class TestBootstrapping:
|
||||||
pluginmanager.consider_setuptools_entrypoints()
|
pluginmanager.consider_setuptools_entrypoints()
|
||||||
plugin = pluginmanager.getplugin("mytestplugin")
|
plugin = pluginmanager.getplugin("mytestplugin")
|
||||||
assert plugin.x == 42
|
assert plugin.x == 42
|
||||||
plugin2 = pluginmanager.getplugin("pytest_mytestplugin")
|
|
||||||
assert plugin2 == plugin
|
|
||||||
|
|
||||||
def test_consider_setuptools_not_installed(self, monkeypatch):
|
def test_consider_setuptools_not_installed(self, monkeypatch):
|
||||||
monkeypatch.setitem(py.std.sys.modules, 'pkg_resources',
|
monkeypatch.setitem(py.std.sys.modules, 'pkg_resources',
|
||||||
|
@ -75,7 +90,7 @@ class TestBootstrapping:
|
||||||
p = testdir.makepyfile("""
|
p = testdir.makepyfile("""
|
||||||
import pytest
|
import pytest
|
||||||
def test_hello(pytestconfig):
|
def test_hello(pytestconfig):
|
||||||
plugin = pytestconfig.pluginmanager.getplugin('x500')
|
plugin = pytestconfig.pluginmanager.getplugin('pytest_x500')
|
||||||
assert plugin is not None
|
assert plugin is not None
|
||||||
""")
|
""")
|
||||||
monkeypatch.setenv('PYTEST_PLUGINS', 'pytest_x500', prepend=",")
|
monkeypatch.setenv('PYTEST_PLUGINS', 'pytest_x500', prepend=",")
|
||||||
|
@ -91,14 +106,14 @@ class TestBootstrapping:
|
||||||
reset = testdir.syspathinsert()
|
reset = testdir.syspathinsert()
|
||||||
pluginname = "pytest_hello"
|
pluginname = "pytest_hello"
|
||||||
testdir.makepyfile(**{pluginname: ""})
|
testdir.makepyfile(**{pluginname: ""})
|
||||||
pluginmanager.import_plugin("hello")
|
pluginmanager.import_plugin("pytest_hello")
|
||||||
len1 = len(pluginmanager.getplugins())
|
len1 = len(pluginmanager.getplugins())
|
||||||
pluginmanager.import_plugin("pytest_hello")
|
pluginmanager.import_plugin("pytest_hello")
|
||||||
len2 = len(pluginmanager.getplugins())
|
len2 = len(pluginmanager.getplugins())
|
||||||
assert len1 == len2
|
assert len1 == len2
|
||||||
plugin1 = pluginmanager.getplugin("pytest_hello")
|
plugin1 = pluginmanager.getplugin("pytest_hello")
|
||||||
assert plugin1.__name__.endswith('pytest_hello')
|
assert plugin1.__name__.endswith('pytest_hello')
|
||||||
plugin2 = pluginmanager.getplugin("hello")
|
plugin2 = pluginmanager.getplugin("pytest_hello")
|
||||||
assert plugin2 is plugin1
|
assert plugin2 is plugin1
|
||||||
|
|
||||||
def test_import_plugin_dotted_name(self, testdir):
|
def test_import_plugin_dotted_name(self, testdir):
|
||||||
|
@ -116,13 +131,13 @@ class TestBootstrapping:
|
||||||
def test_consider_module(self, testdir):
|
def test_consider_module(self, testdir):
|
||||||
pluginmanager = PluginManager()
|
pluginmanager = PluginManager()
|
||||||
testdir.syspathinsert()
|
testdir.syspathinsert()
|
||||||
testdir.makepyfile(pytest_plug1="#")
|
testdir.makepyfile(pytest_p1="#")
|
||||||
testdir.makepyfile(pytest_plug2="#")
|
testdir.makepyfile(pytest_p2="#")
|
||||||
mod = py.std.types.ModuleType("temp")
|
mod = py.std.types.ModuleType("temp")
|
||||||
mod.pytest_plugins = ["pytest_plug1", "pytest_plug2"]
|
mod.pytest_plugins = ["pytest_p1", "pytest_p2"]
|
||||||
pluginmanager.consider_module(mod)
|
pluginmanager.consider_module(mod)
|
||||||
assert pluginmanager.getplugin("plug1").__name__ == "pytest_plug1"
|
assert pluginmanager.getplugin("pytest_p1").__name__ == "pytest_p1"
|
||||||
assert pluginmanager.getplugin("plug2").__name__ == "pytest_plug2"
|
assert pluginmanager.getplugin("pytest_p2").__name__ == "pytest_p2"
|
||||||
|
|
||||||
def test_consider_module_import_module(self, testdir):
|
def test_consider_module_import_module(self, testdir):
|
||||||
mod = py.std.types.ModuleType("x")
|
mod = py.std.types.ModuleType("x")
|
||||||
|
@ -198,8 +213,7 @@ class TestBootstrapping:
|
||||||
mod = py.std.types.ModuleType("pytest_xyz")
|
mod = py.std.types.ModuleType("pytest_xyz")
|
||||||
monkeypatch.setitem(py.std.sys.modules, 'pytest_xyz', mod)
|
monkeypatch.setitem(py.std.sys.modules, 'pytest_xyz', mod)
|
||||||
pp = PluginManager()
|
pp = PluginManager()
|
||||||
pp.import_plugin('xyz')
|
pp.import_plugin('pytest_xyz')
|
||||||
assert pp.getplugin('xyz') == mod
|
|
||||||
assert pp.getplugin('pytest_xyz') == mod
|
assert pp.getplugin('pytest_xyz') == mod
|
||||||
assert pp.isregistered(mod)
|
assert pp.isregistered(mod)
|
||||||
|
|
||||||
|
@ -217,9 +231,6 @@ class TestBootstrapping:
|
||||||
pass
|
pass
|
||||||
excinfo = pytest.raises(Exception, "pp.register(hello())")
|
excinfo = pytest.raises(Exception, "pp.register(hello())")
|
||||||
|
|
||||||
def test_canonical_importname(self):
|
|
||||||
for name in 'xyz', 'pytest_xyz', 'pytest_Xyz', 'Xyz':
|
|
||||||
impname = canonical_importname(name)
|
|
||||||
|
|
||||||
def test_notify_exception(self, capfd):
|
def test_notify_exception(self, capfd):
|
||||||
pp = PluginManager()
|
pp = PluginManager()
|
||||||
|
@ -400,7 +411,7 @@ class TestPytestPluginInteractions:
|
||||||
assert len(l) == 0
|
assert len(l) == 0
|
||||||
config.pluginmanager.do_configure(config=config)
|
config.pluginmanager.do_configure(config=config)
|
||||||
assert len(l) == 1
|
assert len(l) == 1
|
||||||
config.pluginmanager.register(A()) # this should lead to a configured() plugin
|
config.pluginmanager.register(A()) # leads to a configured() plugin
|
||||||
assert len(l) == 2
|
assert len(l) == 2
|
||||||
assert l[0] != l[1]
|
assert l[0] != l[1]
|
||||||
|
|
||||||
|
|
|
@ -2,10 +2,10 @@ import py, pytest
|
||||||
import os
|
import os
|
||||||
from _pytest.resultlog import generic_path, ResultLog, \
|
from _pytest.resultlog import generic_path, ResultLog, \
|
||||||
pytest_configure, pytest_unconfigure
|
pytest_configure, pytest_unconfigure
|
||||||
from _pytest.session import Node, Item, FSCollector
|
from _pytest.main import Node, Item, FSCollector
|
||||||
|
|
||||||
def test_generic_path(testdir):
|
def test_generic_path(testdir):
|
||||||
from _pytest.session import Session
|
from _pytest.main import Session
|
||||||
config = testdir.parseconfig()
|
config = testdir.parseconfig()
|
||||||
session = Session(config)
|
session = Session(config)
|
||||||
p1 = Node('a', config=config, session=session)
|
p1 = Node('a', config=config, session=session)
|
||||||
|
|
|
@ -212,8 +212,8 @@ def test_plugin_specify(testdir):
|
||||||
#)
|
#)
|
||||||
|
|
||||||
def test_plugin_already_exists(testdir):
|
def test_plugin_already_exists(testdir):
|
||||||
config = testdir.parseconfig("-p", "session")
|
config = testdir.parseconfig("-p", "terminal")
|
||||||
assert config.option.plugins == ['session']
|
assert config.option.plugins == ['terminal']
|
||||||
config.pluginmanager.do_configure(config)
|
config.pluginmanager.do_configure(config)
|
||||||
|
|
||||||
def test_exclude(testdir):
|
def test_exclude(testdir):
|
||||||
|
|
2
tox.ini
2
tox.ini
|
@ -68,7 +68,7 @@ commands=
|
||||||
[pytest]
|
[pytest]
|
||||||
minversion=2.0
|
minversion=2.0
|
||||||
plugins=pytester
|
plugins=pytester
|
||||||
addopts= -rxf --pyargs --doctest-modules --ignore=.tox
|
#addopts= -rxf --pyargs --doctest-modules --ignore=.tox
|
||||||
rsyncdirs=tox.ini pytest.py _pytest testing
|
rsyncdirs=tox.ini pytest.py _pytest testing
|
||||||
python_files=test_*.py *_test.py
|
python_files=test_*.py *_test.py
|
||||||
python_classes=Test Acceptance
|
python_classes=Test Acceptance
|
||||||
|
|
Loading…
Reference in New Issue