introduce new discovery mechanism

XXX experiment with using it before introducing it or wait
for feature request
This commit is contained in:
holger krekel 2010-11-24 22:01:04 +01:00
parent 03ee8b7fe0
commit 4cb2c74159
6 changed files with 124 additions and 8 deletions

View File

@ -258,6 +258,7 @@ class Config(object):
self.trace = self.pluginmanager.trace.root.get("config") self.trace = self.pluginmanager.trace.root.get("config")
self._conftest = Conftest(onimport=self._onimportconftest) self._conftest = Conftest(onimport=self._onimportconftest)
self.hook = self.pluginmanager.hook self.hook = self.pluginmanager.hook
self._inicache = {}
def _onimportconftest(self, conftestmodule): def _onimportconftest(self, conftestmodule):
self.trace("loaded conftestmodule %r" %(conftestmodule,)) self.trace("loaded conftestmodule %r" %(conftestmodule,))
@ -332,6 +333,13 @@ class Config(object):
""" return configuration value from an ini file. If the """ return configuration value from an ini file. If the
specified name hasn't been registered through a prior ``parse.addini`` specified name hasn't been registered through a prior ``parse.addini``
call (usually from a plugin), a ValueError is raised. """ 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: try:
description, type, default = self._parser._inidict[name] description, type, default = self._parser._inidict[name]
except KeyError: except KeyError:

View File

@ -13,6 +13,13 @@ def pytest_addoption(parser):
group.addoption('--funcargs', group.addoption('--funcargs',
action="store_true", dest="showfuncargs", default=False, action="store_true", dest="showfuncargs", default=False,
help="show available function arguments, sorted by plugin") 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): def pytest_cmdline_main(config):
if config.option.showfuncargs: if config.option.showfuncargs:
@ -46,8 +53,13 @@ def pytest_pyfunc_call(__multicall__, pyfuncitem):
def pytest_collect_file(path, parent): def pytest_collect_file(path, parent):
ext = path.ext ext = path.ext
pb = path.purebasename pb = path.purebasename
if ext == ".py" and (pb.startswith("test_") or pb.endswith("_test") or if ext == ".py":
parent.session.isinitpath(path)): 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( return parent.ihook.pytest_pycollect_makemodule(
path=path, parent=parent) path=path, parent=parent)
@ -145,9 +157,14 @@ class PyobjMixin(object):
class PyCollectorMixin(PyobjMixin, pytest.Collector): class PyCollectorMixin(PyobjMixin, pytest.Collector):
def funcnamefilter(self, name): 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): 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): def collect(self):
# NB. we avoid random getattrs and peek in the __dict__ instead # NB. we avoid random getattrs and peek in the __dict__ instead

View File

@ -86,3 +86,18 @@ builtin configuration file options
This would tell py.test to not recurse into typical subversion or This would tell py.test to not recurse into typical subversion or
sphinx-build directories or into any ``tmp`` prefixed directory. 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.

View File

@ -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. 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 You can use the ``--pyargs`` option to make py.test try
interpreting arguments as python package names, deriving interpreting arguments as python package names, deriving
their file system path and then running the test. Through their file system path and then running the test. For
an ini-file and the :confval:`addopts` option you can make example if you have unittest2 installed you can type::
this change more permanently::
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 # content of pytest.ini
[pytest] [pytest]
addopts = --pyargs 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 finding out what is collected
----------------------------------------------- -----------------------------------------------

View File

@ -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*",
])

View File

@ -73,3 +73,6 @@ minversion=2.0
plugins=pytester plugins=pytester
addopts= -rxf --pyargs --doctest-modules addopts= -rxf --pyargs --doctest-modules
rsyncdirs=tox.ini pytest.py _pytest testing rsyncdirs=tox.ini pytest.py _pytest testing
python_files=test_*.py *_test.py
python_classes=Test Acceptance
python_functions=test