introduce new discovery mechanism
XXX experiment with using it before introducing it or wait for feature request
This commit is contained in:
parent
03ee8b7fe0
commit
4cb2c74159
|
@ -258,6 +258,7 @@ class Config(object):
|
|||
self.trace = self.pluginmanager.trace.root.get("config")
|
||||
self._conftest = Conftest(onimport=self._onimportconftest)
|
||||
self.hook = self.pluginmanager.hook
|
||||
self._inicache = {}
|
||||
|
||||
def _onimportconftest(self, conftestmodule):
|
||||
self.trace("loaded conftestmodule %r" %(conftestmodule,))
|
||||
|
@ -332,6 +333,13 @@ class Config(object):
|
|||
""" return configuration value from an ini file. If the
|
||||
specified name hasn't been registered through a prior ``parse.addini``
|
||||
call (usually from a plugin), a ValueError is raised. """
|
||||
try:
|
||||
return self._inicache[name]
|
||||
except KeyError:
|
||||
self._inicache[name] = val = self._getini(name)
|
||||
return val
|
||||
|
||||
def _getini(self, name):
|
||||
try:
|
||||
description, type, default = self._parser._inidict[name]
|
||||
except KeyError:
|
||||
|
|
|
@ -13,6 +13,13 @@ def pytest_addoption(parser):
|
|||
group.addoption('--funcargs',
|
||||
action="store_true", dest="showfuncargs", default=False,
|
||||
help="show available function arguments, sorted by plugin")
|
||||
parser.addini("python_files", type="args",
|
||||
default=('test_*.py', '*_test.py'),
|
||||
help="glob-style file patterns for Python test module discovery")
|
||||
parser.addini("python_classes", type="args", default=("Test",),
|
||||
help="prefixes for Python test class discovery")
|
||||
parser.addini("python_functions", type="args", default=("test",),
|
||||
help="prefixes for Python test function and method discovery")
|
||||
|
||||
def pytest_cmdline_main(config):
|
||||
if config.option.showfuncargs:
|
||||
|
@ -46,8 +53,13 @@ def pytest_pyfunc_call(__multicall__, pyfuncitem):
|
|||
def pytest_collect_file(path, parent):
|
||||
ext = path.ext
|
||||
pb = path.purebasename
|
||||
if ext == ".py" and (pb.startswith("test_") or pb.endswith("_test") or
|
||||
parent.session.isinitpath(path)):
|
||||
if ext == ".py":
|
||||
if not parent.session.isinitpath(path):
|
||||
for pat in parent.config.getini('python_files'):
|
||||
if path.fnmatch(pat):
|
||||
break
|
||||
else:
|
||||
return
|
||||
return parent.ihook.pytest_pycollect_makemodule(
|
||||
path=path, parent=parent)
|
||||
|
||||
|
@ -145,9 +157,14 @@ class PyobjMixin(object):
|
|||
class PyCollectorMixin(PyobjMixin, pytest.Collector):
|
||||
|
||||
def funcnamefilter(self, name):
|
||||
return name.startswith('test')
|
||||
for prefix in self.config.getini("python_functions"):
|
||||
if name.startswith(prefix):
|
||||
return True
|
||||
|
||||
def classnamefilter(self, name):
|
||||
return name.startswith('Test')
|
||||
for prefix in self.config.getini("python_classes"):
|
||||
if name.startswith(prefix):
|
||||
return True
|
||||
|
||||
def collect(self):
|
||||
# NB. we avoid random getattrs and peek in the __dict__ instead
|
||||
|
|
|
@ -86,3 +86,18 @@ builtin configuration file options
|
|||
This would tell py.test to not recurse into typical subversion or
|
||||
sphinx-build directories or into any ``tmp`` prefixed directory.
|
||||
|
||||
.. confval:: python_discovery
|
||||
|
||||
Determines names and patterns for finding Python tests, specified
|
||||
through indendent ``name = value`` settings with these possible names::
|
||||
|
||||
[pytest]
|
||||
python_discovery =
|
||||
file = <glob-pattern> <glob-pattern>
|
||||
func = <function-or-method-name-prefix>
|
||||
class = <class-name-prefix>
|
||||
|
||||
See :ref:`change naming conventions` for examples. the ``class``
|
||||
to be empty in which case all non-underscore empty classes
|
||||
will be considered.
|
||||
|
||||
|
|
|
@ -12,19 +12,63 @@ You can set the :confval:`norecursedirs` option in an ini-file, for example your
|
|||
|
||||
This would tell py.test to not recurse into typical subversion or sphinx-build directories or into any ``tmp`` prefixed directory.
|
||||
|
||||
always try to interpret arguments as Python packages
|
||||
.. _`change naming conventions`:
|
||||
|
||||
change naming conventions
|
||||
-----------------------------------------------------
|
||||
|
||||
You can configure different naming conventions by setting
|
||||
the :confval:`pytest_pycollect` configuration option. Example::
|
||||
|
||||
# content of setup.cfg
|
||||
# can also be defined in in tox.ini or pytest.ini file
|
||||
[pytest]
|
||||
python_files=check_*.py
|
||||
python_classes=Check
|
||||
python_functions=check
|
||||
|
||||
This would make py.test look for ``check_`` prefixes in
|
||||
Python filenames, ``Check`` prefixes in classes and ``check`` prefixes
|
||||
in functions and classes. For example, if we have::
|
||||
|
||||
# content of check_myapp.py
|
||||
class CheckMyApp:
|
||||
def check_simple(self):
|
||||
pass
|
||||
def check_complex(self):
|
||||
pass
|
||||
|
||||
then the test collection looks like this::
|
||||
|
||||
$ py.test --collectonly
|
||||
<Module 'check_myapp.py'>
|
||||
<Class 'CheckMyApp'>
|
||||
<Instance '()'>
|
||||
<Function 'check_simple'>
|
||||
<Function 'check_complex'>
|
||||
|
||||
interpret cmdline arguments as Python packages
|
||||
-----------------------------------------------------
|
||||
|
||||
You can use the ``--pyargs`` option to make py.test try
|
||||
interpreting arguments as python package names, deriving
|
||||
their file system path and then running the test. Through
|
||||
an ini-file and the :confval:`addopts` option you can make
|
||||
this change more permanently::
|
||||
their file system path and then running the test. For
|
||||
example if you have unittest2 installed you can type::
|
||||
|
||||
py.test --pyargs unittest2.test.test_skipping -q
|
||||
|
||||
which will run the respective test module. Like with
|
||||
other options, through an ini-file and the :confval:`addopts` option you
|
||||
can make this change more permanently::
|
||||
|
||||
# content of pytest.ini
|
||||
[pytest]
|
||||
addopts = --pyargs
|
||||
|
||||
Now a simple invocation of ``py.test NAME`` will check
|
||||
if NAME exists as an importable package/module and otherwise
|
||||
treat it as a filesystem path.
|
||||
|
||||
finding out what is collected
|
||||
-----------------------------------------------
|
||||
|
||||
|
|
|
@ -1208,3 +1208,32 @@ class TestRaises:
|
|||
|
||||
|
||||
|
||||
def test_customized_python_discovery(testdir):
|
||||
testdir.makeini("""
|
||||
[pytest]
|
||||
python_files=check_*.py
|
||||
python_classes=Check
|
||||
python_functions=check
|
||||
""")
|
||||
p = testdir.makepyfile("""
|
||||
def check_simple():
|
||||
pass
|
||||
class CheckMyApp:
|
||||
def check_meth(self):
|
||||
pass
|
||||
""")
|
||||
p2 = p.new(basename=p.basename.replace("test", "check"))
|
||||
p.move(p2)
|
||||
result = testdir.runpytest("--collectonly", "-s")
|
||||
result.stdout.fnmatch_lines([
|
||||
"*check_customized*",
|
||||
"*check_simple*",
|
||||
"*CheckMyApp*",
|
||||
"*check_meth*",
|
||||
])
|
||||
|
||||
result = testdir.runpytest()
|
||||
assert result.ret == 0
|
||||
result.stdout.fnmatch_lines([
|
||||
"*2 passed*",
|
||||
])
|
||||
|
|
Loading…
Reference in New Issue