merge trunk
This commit is contained in:
commit
f73ab23003
|
@ -1,7 +1,11 @@
|
|||
Changes between 1.3.4 and 2.0.0dev0
|
||||
----------------------------------------------
|
||||
|
||||
- pytest-2.0 is now its own package and depends on pylib
|
||||
- pytest-2.0 is now its own package and depends on pylib-2.0
|
||||
- introduce a new way to set config options via ini-style files,
|
||||
by default setup.cfg and tox.ini files are searched. The old
|
||||
ways (certain environment variables, dynamic conftest.py reading
|
||||
is removed).
|
||||
- fix issue126 - introduce py.test.set_trace() to trace execution via
|
||||
PDB during the running of tests even if capturing is ongoing.
|
||||
- fix issue123 - new "python -m py.test" invocation for py.test
|
||||
|
|
|
@ -258,3 +258,9 @@ epub_copyright = u'2010, holger krekel et aliter'
|
|||
|
||||
# Example configuration for intersphinx: refer to the Python standard library.
|
||||
intersphinx_mapping = {'http://docs.python.org/': None}
|
||||
def setup(app):
|
||||
#from sphinx.ext.autodoc import cut_lines
|
||||
#app.connect('autodoc-process-docstring', cut_lines(4, what=['module']))
|
||||
app.add_description_unit('confval', 'confval',
|
||||
objname='configuration value',
|
||||
indextemplate='pair: %s; configuration value')
|
||||
|
|
|
@ -5,33 +5,57 @@ Customizing and Extending py.test
|
|||
basic test configuration
|
||||
===================================
|
||||
|
||||
Command line options
|
||||
---------------------------------
|
||||
Command line options and configuration file settings
|
||||
-----------------------------------------------------------------
|
||||
|
||||
You can see command line options by running::
|
||||
You can get help on options and configuration options by running::
|
||||
|
||||
py.test -h
|
||||
py.test -h # prints options _and_ config file settings
|
||||
|
||||
This will display all available command line options
|
||||
in your specific environment.
|
||||
This will display command line and configuration file settings
|
||||
which were registered by installed plugins.
|
||||
|
||||
how test configuration is read from setup/tox ini-files
|
||||
--------------------------------------------------------
|
||||
|
||||
setting persistent option defaults
|
||||
------------------------------------
|
||||
py.test looks for the first ``[pytest]`` section in either the first ``setup.cfg`` or the first ``tox.ini`` file found upwards from the arguments. Example::
|
||||
|
||||
py.test will lookup option values in this order:
|
||||
py.test path/to/testdir
|
||||
|
||||
* command line
|
||||
* conftest.py files
|
||||
* environment variables
|
||||
will look in the following dirs for a config file::
|
||||
|
||||
To get an overview on existing names and settings type::
|
||||
path/to/testdir/setup.cfg
|
||||
path/to/setup.cfg
|
||||
path/setup.cfg
|
||||
setup.cfg
|
||||
... # up until root of filesystem
|
||||
path/to/testdir/tox.ini
|
||||
path/to/tox.ini
|
||||
path/tox.ini
|
||||
... # up until root of filesystem
|
||||
|
||||
py.test --help-config
|
||||
If no path was provided at all the current working directory is used for the lookup.
|
||||
|
||||
This will print information about all available options
|
||||
in your environment, including your local plugins and
|
||||
command line options.
|
||||
builtin configuration file options
|
||||
----------------------------------------------
|
||||
|
||||
.. confval:: minversion = VERSTRING
|
||||
|
||||
specifies the minimal pytest version that is needed for this test suite.
|
||||
|
||||
minversion = 2.1 # will fail if we run with pytest-2.0
|
||||
|
||||
.. confval:: addargs = OPTS
|
||||
|
||||
add the specified ``OPTS`` to the set of command line arguments as if they
|
||||
had been specified by the user. Example: if you have this ini file content::
|
||||
|
||||
[pytest]
|
||||
addargs = --maxfail=2 -rf # exit after 2 failures, report fail info
|
||||
|
||||
issuing ``py.test test_hello.py`` actually means::
|
||||
|
||||
py.test --maxfail=2 -rf test_hello.py
|
||||
|
||||
.. _`function arguments`: funcargs.html
|
||||
.. _`extensions`:
|
||||
|
@ -49,10 +73,8 @@ extensions and customizations close to test code.
|
|||
local conftest.py plugins
|
||||
--------------------------------------------------------------
|
||||
|
||||
local `conftest.py` plugins are usually automatically loaded and
|
||||
registered but its contained hooks are only called when collecting or
|
||||
running tests in files or directories next to or below the ``conftest.py``
|
||||
file. Assume the following layout and content of files::
|
||||
local ``conftest.py`` plugins contain directory-specific hook implemenations. Its contained runtest- and collection- related hooks are called when collecting or running tests in files or directories next to or below the ``conftest.py``
|
||||
file. Example: Assume the following layout and content of files::
|
||||
|
||||
a/conftest.py:
|
||||
def pytest_runtest_setup(item):
|
||||
|
@ -72,20 +94,22 @@ Here is how you might run it::
|
|||
py.test a/test_sub.py # will show "setting up"
|
||||
|
||||
``py.test`` loads all ``conftest.py`` files upwards from the command
|
||||
line file arguments. It usually looks up configuration values or hooks
|
||||
right-to-left, i.e. the closer conftest files are checked before
|
||||
the further away ones. This means you can have a ``conftest.py``
|
||||
in your home directory to provide global configuration values.
|
||||
line file arguments. It usually performs look up right-to-left, i.e.
|
||||
the hooks in "closer" conftest files will be called earlier than further
|
||||
away ones. This means you can even have a ``conftest.py`` file in your home
|
||||
directory to customize test functionality globally for all of your projects.
|
||||
|
||||
.. Note::
|
||||
if you have ``conftest.py`` files which do not reside in a
|
||||
If you have ``conftest.py`` files which do not reside in a
|
||||
python package directory (i.e. one containing an ``__init__.py``) then
|
||||
"import conftest" will be ambigous and should be avoided. If you
|
||||
ever want to import anything from a ``conftest.py`` file
|
||||
put it inside a package. You avoid trouble this way.
|
||||
"import conftest" can be ambigous because there might be other
|
||||
``conftest.py`` files as well on your PYTHONPATH or ``sys.path``.
|
||||
It is good practise for projects to put ``conftest.py`` within a package
|
||||
scope or to never import anything from the conftest.py file.
|
||||
|
||||
.. _`named plugins`: plugin/index.html
|
||||
|
||||
|
||||
Plugin discovery at tool startup
|
||||
--------------------------------------------
|
||||
|
||||
|
@ -93,9 +117,6 @@ py.test loads plugin modules at tool startup in the following way:
|
|||
|
||||
* by loading all plugins registered through `setuptools entry points`_.
|
||||
|
||||
* by reading the ``PYTEST_PLUGINS`` environment variable
|
||||
and importing the comma-separated list of named plugins.
|
||||
|
||||
* by pre-scanning the command line for the ``-p name`` option
|
||||
and loading the specified plugin before actual command line parsing.
|
||||
|
||||
|
@ -105,39 +126,17 @@ py.test loads plugin modules at tool startup in the following way:
|
|||
not loaded at tool startup.
|
||||
|
||||
* by recursively loading all plugins specified by the
|
||||
``pytest_plugins`` variable in a ``conftest.py`` file
|
||||
``pytest_plugins`` variable in ``conftest.py`` files
|
||||
|
||||
Requiring/Loading plugins in a test module or plugin
|
||||
-------------------------------------------------------------
|
||||
|
||||
You can specify plugins in a test module or a plugin like this::
|
||||
You can require plugins in a test module or a plugin like this::
|
||||
|
||||
pytest_plugins = "name1", "name2",
|
||||
|
||||
When the test module or plugin is loaded the specified plugins
|
||||
will be loaded. If you specify plugins without the ``pytest_``
|
||||
prefix it will be automatically added. All plugin names
|
||||
must be lowercase.
|
||||
|
||||
.. _`conftest.py plugin`:
|
||||
.. _`conftestplugin`:
|
||||
|
||||
Writing per-project plugins (conftest.py)
|
||||
------------------------------------------------------
|
||||
|
||||
The purpose of :file:`conftest.py` files is to allow project-specific
|
||||
test customization. They thus make for a good place to implement
|
||||
project-specific test related features through hooks. For example you may
|
||||
set the ``collect_ignore`` variable depending on a command line option
|
||||
by defining the following hook in a ``conftest.py`` file::
|
||||
|
||||
# ./conftest.py in your root or package dir
|
||||
collect_ignore = ['hello', 'test_world.py']
|
||||
def pytest_addoption(parser):
|
||||
parser.addoption("--runall", action="store_true", default=False)
|
||||
def pytest_configure(config):
|
||||
if config.getvalue("runall"):
|
||||
collect_ignore[:] = []
|
||||
will be loaded.
|
||||
|
||||
.. _`setuptools entry points`:
|
||||
.. _registered:
|
||||
|
@ -332,12 +331,28 @@ Reference of important objects involved in hooks
|
|||
.. autoclass:: pytest.plugin.config.Config
|
||||
:members:
|
||||
|
||||
.. autoclass:: pytest.plugin.session.Item
|
||||
:inherited-members:
|
||||
|
||||
.. autoclass:: pytest.plugin.session.Node
|
||||
.. autoclass:: pytest.plugin.config.Parser
|
||||
:members:
|
||||
|
||||
.. autoclass:: pytest.plugin.session.Node(name, parent)
|
||||
:members:
|
||||
|
||||
..
|
||||
.. autoclass:: pytest.plugin.session.File(fspath, parent)
|
||||
:members:
|
||||
|
||||
.. autoclass:: pytest.plugin.session.Item(name, parent)
|
||||
:members:
|
||||
|
||||
.. autoclass:: pytest.plugin.python.Module(name, parent)
|
||||
:members:
|
||||
|
||||
.. autoclass:: pytest.plugin.python.Class(name, parent)
|
||||
:members:
|
||||
|
||||
.. autoclass:: pytest.plugin.python.Function(name, parent)
|
||||
:members:
|
||||
|
||||
.. autoclass:: pytest.plugin.runner.CallInfo
|
||||
:members:
|
||||
|
||||
|
@ -345,29 +360,3 @@ Reference of important objects involved in hooks
|
|||
:members:
|
||||
|
||||
|
||||
conftest.py configuration files
|
||||
=================================================
|
||||
|
||||
conftest.py reference docs
|
||||
|
||||
A unique feature of py.test are its ``conftest.py`` files which allow
|
||||
project and directory specific customizations to testing.
|
||||
|
||||
* `set option defaults`_
|
||||
|
||||
or set particular variables to influence the testing process:
|
||||
|
||||
* ``pytest_plugins``: list of named plugins to load
|
||||
|
||||
* ``collect_ignore``: list of paths to ignore during test collection, relative to the containing ``conftest.py`` file
|
||||
|
||||
* ``rsyncdirs``: list of to-be-rsynced directories for distributed
|
||||
testing, relative to the containing ``conftest.py`` file.
|
||||
|
||||
You may put a conftest.py files in your project root directory or into
|
||||
your package directory if you want to add project-specific test options.
|
||||
|
||||
|
||||
.. _`specify funcargs`: funcargs.html#application-setup-tutorial-example
|
||||
|
||||
.. _`set option defaults`:
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
|
||||
Customizing test function through marks and hooks
|
||||
====================================================
|
||||
|
||||
.. _`retrieved by hooks as item keywords`:
|
||||
|
||||
control skipping of tests according to command line option
|
|
@ -1,7 +1,4 @@
|
|||
|
||||
Misc examples
|
||||
====================================================
|
||||
|
||||
Detect if running from within a py.test run
|
||||
--------------------------------------------------------------
|
||||
|
|
@ -1,6 +1,8 @@
|
|||
|
||||
.. highlightlang:: python
|
||||
|
||||
.. _mysetup:
|
||||
|
||||
mysetup pattern: application specific test fixtures
|
||||
==========================================================
|
||||
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
|
||||
.. _`non-python tests`:
|
||||
|
||||
Working with non-python tests
|
||||
====================================================
|
||||
|
||||
a basic example for specifying tests in Yaml files
|
||||
--------------------------------------------------------------
|
||||
|
||||
.. _`pytest-yamlwsgi`: http://bitbucket.org/aafshar/pytest-yamlwsgi/src/tip/pytest_yamlwsgi.py
|
||||
.. _`PyYAML`: http://pypi.python.org/pypi/PyYAML/
|
||||
|
||||
Here is an example ``conftest.py`` (extracted from Ali Afshnars special purpose `pytest-yamlwsgi`_ plugin). This ``conftest.py`` will collect ``test*.yml`` files and will execute the yaml-formatted content as custom tests:
|
||||
|
||||
.. include:: nonpython/conftest.py
|
||||
:literal:
|
||||
|
||||
You can create a simple example file:
|
||||
|
||||
.. include:: nonpython/test_simple.yml
|
||||
:literal:
|
||||
|
||||
and if you installed `PyYAML`_ or a compatible YAML-parser you can
|
||||
now execute the test specification::
|
||||
|
||||
nonpython $ py.test
|
||||
=========================== test session starts ============================
|
||||
platform linux2 -- Python 2.6.5 -- pytest-2.0.0.dev10
|
||||
test path 1: /home/hpk/p/pytest/doc/example/nonpython
|
||||
|
||||
test_simple.yml .F
|
||||
|
||||
================================= FAILURES =================================
|
||||
______________________________ usecase: hello ______________________________
|
||||
usecase execution failed
|
||||
spec failed: 'some': 'other'
|
||||
no further details known at this point.
|
||||
==================== 1 failed, 1 passed in 0.06 seconds ====================
|
||||
|
||||
You get one dot for the passing ``sub1: sub1`` check and one failure.
|
||||
Obviously in the above ``conftest.py`` you'll want to implement a more
|
||||
interesting interpretation of the yaml-values. Note that ``reportinfo()``
|
||||
is used for representing the test location and is also consulted for
|
||||
reporting in ``verbose`` mode::
|
||||
|
||||
nonpython $ py.test -v
|
||||
=========================== test session starts ============================
|
||||
platform linux2 -- Python 2.6.5 -- pytest-2.0.0.dev10 -- /home/hpk/venv/0/bin/python
|
||||
test path 1: /home/hpk/p/pytest/doc/example/nonpython
|
||||
|
||||
test_simple.yml:1: usecase: ok PASSED
|
||||
test_simple.yml:1: usecase: hello FAILED
|
||||
|
||||
================================= FAILURES =================================
|
||||
______________________________ usecase: hello ______________________________
|
||||
usecase execution failed
|
||||
spec failed: 'some': 'other'
|
||||
no further details known at this point.
|
||||
==================== 1 failed, 1 passed in 0.06 seconds ====================
|
||||
|
||||
While developing your custom test collection and execution it's also
|
||||
interesting to just look at the collection tree::
|
||||
|
||||
nonpython $ py.test --collectonly
|
||||
<Directory 'nonpython'>
|
||||
<YamlFile 'test_simple.yml'>
|
||||
<UsecaseItem 'ok'>
|
||||
<UsecaseItem 'hello'>
|
|
@ -0,0 +1,40 @@
|
|||
# content of conftest.py
|
||||
|
||||
import py
|
||||
|
||||
def pytest_collect_file(path, parent):
|
||||
if path.ext == ".yml" and path.basename.startswith("test"):
|
||||
return YamlFile(path, parent)
|
||||
|
||||
class YamlFile(py.test.collect.File):
|
||||
def collect(self):
|
||||
import yaml # we need a yaml parser, e.g. PyYAML
|
||||
raw = yaml.load(self.fspath.open())
|
||||
for name, spec in raw.items():
|
||||
yield UsecaseItem(name, self, spec)
|
||||
|
||||
class UsecaseItem(py.test.collect.Item):
|
||||
def __init__(self, name, parent, spec):
|
||||
super(UsecaseItem, self).__init__(name, parent)
|
||||
self.spec = spec
|
||||
|
||||
def runtest(self):
|
||||
for name, value in self.spec.items():
|
||||
# some custom test execution (dumb example follows)
|
||||
if name != value:
|
||||
raise UsecaseException(self, name, value)
|
||||
|
||||
def repr_failure(self, excinfo):
|
||||
""" called when self.runtest() raises an exception. """
|
||||
if excinfo.errisinstance(UsecaseException):
|
||||
return "\n".join([
|
||||
"usecase execution failed",
|
||||
" spec failed: %r: %r" % excinfo.value.args[1:3],
|
||||
" no further details known at this point."
|
||||
])
|
||||
|
||||
def reportinfo(self):
|
||||
return self.fspath, 0, "usecase: %s" % self.name
|
||||
|
||||
class UsecaseException(Exception):
|
||||
""" custom exception for error reporting. """
|
|
@ -0,0 +1,7 @@
|
|||
# test_simple.yml
|
||||
ok:
|
||||
sub1: sub1
|
||||
|
||||
hello:
|
||||
world: world
|
||||
some: other
|
|
@ -7,6 +7,7 @@ Usages and Examples
|
|||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
example/marking.txt
|
||||
example/controlskip.txt
|
||||
example/mysetup.txt
|
||||
example/misc.txt
|
||||
example/detectpytest.txt
|
||||
example/nonpython.txt
|
||||
|
|
|
@ -45,7 +45,8 @@ supports several testing practises and methods
|
|||
|
||||
- supports extended `xUnit style setup`_
|
||||
- can integrate nose_, `unittest.py` and `doctest.py`_ style tests
|
||||
- supports generating testing coverage
|
||||
- supports generating testing coverage reports
|
||||
- supports :ref:`non-python tests`
|
||||
- `Javasript unit- and functional testing`_
|
||||
|
||||
.. _`Javasript unit- and functional testing`: plugin/oejskit.html
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
|
||||
.. highlightlang:: python
|
||||
.. _`good practises`:
|
||||
|
||||
Good Practises
|
||||
|
@ -28,8 +29,7 @@ py.test supports common test layouts.
|
|||
|
||||
XXX
|
||||
|
||||
|
||||
|
||||
.. _`genscript method`:
|
||||
|
||||
Generating a py.test standalone Script
|
||||
-------------------------------------------
|
||||
|
@ -38,12 +38,12 @@ If you are a maintainer or application developer and want users
|
|||
to run tests you can use a facility to generate a standalone
|
||||
"py.test" script that you can tell users to run::
|
||||
|
||||
py.test --genscript=mytest
|
||||
py.test --genscript=runtests.py
|
||||
|
||||
will generate a ``mytest`` script that is, in fact, a ``py.test`` under
|
||||
disguise. You can tell people to download and then e.g. run it like this::
|
||||
|
||||
python mytest --pastebin=all
|
||||
python runtests.py --pastebin=all
|
||||
|
||||
and ask them to send you the resulting URL. The resulting script has
|
||||
all core features and runs unchanged under Python2 and Python3 interpreters.
|
||||
|
@ -51,4 +51,46 @@ all core features and runs unchanged under Python2 and Python3 interpreters.
|
|||
.. _`Distribute for installation`: http://pypi.python.org/pypi/distribute#installation-instructions
|
||||
.. _`distribute installation`: http://pypi.python.org/pypi/distribute
|
||||
|
||||
|
||||
Integrating with distutils / ``python setup.py test``
|
||||
--------------------------------------------------------
|
||||
|
||||
You can easily integrate test runs into your distutils or
|
||||
setuptools based project. Use the `genscript method`_
|
||||
to generate a standalone py.test script::
|
||||
|
||||
py.test --genscript=runtests.py
|
||||
|
||||
and make this script part of your distribution and then add
|
||||
this to your ``setup.py`` file::
|
||||
|
||||
from distutils.core import setup, Command
|
||||
# you can also import from setuptools
|
||||
|
||||
class PyTest(Command):
|
||||
user_options = []
|
||||
def initialize_options(self):
|
||||
pass
|
||||
def finalize_options(self):
|
||||
pass
|
||||
def run(self):
|
||||
import sys,subprocess
|
||||
errno = subprocess.call([sys.executable, 'runtest.py'])
|
||||
raise SystemExit(errno)
|
||||
setup(
|
||||
#...,
|
||||
cmdclass = {'test': PyTest},
|
||||
#...,
|
||||
)
|
||||
|
||||
If you now type::
|
||||
|
||||
python setup.py test
|
||||
|
||||
this will execute your tests using ``runtest.py``. As this is a
|
||||
standalone version of ``py.test`` no prior installation whatsoever is
|
||||
required for calling the test command. You can also pass additional
|
||||
arguments to the subprocess-calls like your test directory or other
|
||||
options.
|
||||
|
||||
.. include:: links.inc
|
||||
|
|
|
@ -16,8 +16,8 @@ basic usage and funcargs:
|
|||
|
||||
function arguments:
|
||||
|
||||
- :ref:`mysetup`
|
||||
- `application setup in test functions with funcargs`_
|
||||
- `making funcargs dependendent on command line options`_
|
||||
- `monkey patching done right`_ (blog post, consult `monkeypatch
|
||||
plugin`_ for actual 1.0 API)
|
||||
|
||||
|
@ -39,7 +39,6 @@ plugin specific examples:
|
|||
- `many examples in the docs for plugins`_
|
||||
|
||||
.. _`skipping slow tests by default in py.test`: http://bruynooghe.blogspot.com/2009/12/skipping-slow-test-by-default-in-pytest.html
|
||||
.. _`making funcargs dependendent on command line options`: funcargs.html#tut-cmdlineoption
|
||||
.. _`many examples in the docs for plugins`: plugin/index.html
|
||||
.. _`monkeypatch plugin`: plugin/monkeypatch.html
|
||||
.. _`application setup in test functions with funcargs`: funcargs.html#appsetup
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
import py
|
||||
failure_demo = py.path.local(__file__).dirpath('failure_demo.py')
|
||||
|
||||
pytest_plugins = "pytest_pytester"
|
||||
|
||||
def test_failure_demo_fails_properly(testdir):
|
||||
target = testdir.tmpdir.join(failure_demo.basename)
|
||||
failure_demo.copy(target)
|
||||
|
|
|
@ -5,11 +5,12 @@ see http://pytest.org for documentation and details
|
|||
|
||||
(c) Holger Krekel and others, 2004-2010
|
||||
"""
|
||||
__version__ = '2.0.0.dev10'
|
||||
__version__ = '2.0.0.dev11'
|
||||
|
||||
__all__ = ['config', 'cmdline']
|
||||
|
||||
from pytest import _core as cmdline
|
||||
UsageError = cmdline.UsageError
|
||||
|
||||
def __main__():
|
||||
raise SystemExit(cmdline.main())
|
|
@ -345,13 +345,16 @@ def main(args=None):
|
|||
if args is None:
|
||||
args = sys.argv[1:]
|
||||
hook = pluginmanager.hook
|
||||
config = hook.pytest_cmdline_parse(pluginmanager=pluginmanager, args=args)
|
||||
try:
|
||||
config = hook.pytest_cmdline_parse(
|
||||
pluginmanager=pluginmanager, args=args)
|
||||
exitstatus = hook.pytest_cmdline_main(config=config)
|
||||
except config.Error:
|
||||
except UsageError:
|
||||
e = sys.exc_info()[1]
|
||||
sys.stderr.write("ERROR: %s\n" %(e.args[0],))
|
||||
exitstatus = 3
|
||||
pluginmanager = PluginManager(load=True)
|
||||
return exitstatus
|
||||
|
||||
class UsageError(Exception):
|
||||
""" error in py.test usage or invocation"""
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
import py
|
||||
import sys, os
|
||||
from pytest._core import PluginManager
|
||||
import pytest
|
||||
|
||||
|
||||
def pytest_cmdline_parse(pluginmanager, args):
|
||||
|
@ -9,6 +10,10 @@ def pytest_cmdline_parse(pluginmanager, args):
|
|||
config.parse(args)
|
||||
return config
|
||||
|
||||
def pytest_addoption(parser):
|
||||
parser.addini('addargs', 'default command line arguments')
|
||||
parser.addini('minversion', 'minimally required pytest version')
|
||||
|
||||
class Parser:
|
||||
""" Parser for command line arguments. """
|
||||
|
||||
|
@ -17,6 +22,7 @@ class Parser:
|
|||
self._groups = []
|
||||
self._processopt = processopt
|
||||
self._usage = usage
|
||||
self._inidict = {}
|
||||
self.hints = []
|
||||
|
||||
def processoption(self, option):
|
||||
|
@ -28,6 +34,12 @@ class Parser:
|
|||
self._notes.append(note)
|
||||
|
||||
def getgroup(self, name, description="", after=None):
|
||||
""" get (or create) a named option Group.
|
||||
|
||||
:name: unique name of the option group.
|
||||
:description: long description for --help output.
|
||||
:after: name of other group, used for ordering --help output.
|
||||
"""
|
||||
for group in self._groups:
|
||||
if group.name == name:
|
||||
return group
|
||||
|
@ -44,7 +56,7 @@ class Parser:
|
|||
self._anonymous.addoption(*opts, **attrs)
|
||||
|
||||
def parse(self, args):
|
||||
optparser = MyOptionParser(self)
|
||||
self.optparser = optparser = MyOptionParser(self)
|
||||
groups = self._groups + [self._anonymous]
|
||||
for group in groups:
|
||||
if group.options:
|
||||
|
@ -52,7 +64,7 @@ class Parser:
|
|||
optgroup = py.std.optparse.OptionGroup(optparser, desc)
|
||||
optgroup.add_options(group.options)
|
||||
optparser.add_option_group(optgroup)
|
||||
return optparser.parse_args([str(x) for x in args])
|
||||
return self.optparser.parse_args([str(x) for x in args])
|
||||
|
||||
def parse_setoption(self, args, option):
|
||||
parsedoption, args = self.parse(args)
|
||||
|
@ -60,6 +72,9 @@ class Parser:
|
|||
setattr(option, name, value)
|
||||
return args
|
||||
|
||||
def addini(self, name, description, type=None):
|
||||
""" add an ini-file option with the given name and description. """
|
||||
self._inidict[name] = (description, type)
|
||||
|
||||
class OptionGroup:
|
||||
def __init__(self, name, description="", parser=None):
|
||||
|
@ -90,7 +105,8 @@ class OptionGroup:
|
|||
class MyOptionParser(py.std.optparse.OptionParser):
|
||||
def __init__(self, parser):
|
||||
self._parser = parser
|
||||
py.std.optparse.OptionParser.__init__(self, usage=parser._usage)
|
||||
py.std.optparse.OptionParser.__init__(self, usage=parser._usage,
|
||||
add_help_option=False)
|
||||
def format_epilog(self, formatter):
|
||||
hints = self._parser.hints
|
||||
if hints:
|
||||
|
@ -226,13 +242,8 @@ class CmdOptions(object):
|
|||
def __repr__(self):
|
||||
return "<CmdOptions %r>" %(self.__dict__,)
|
||||
|
||||
class Error(Exception):
|
||||
""" Test Configuration Error. """
|
||||
|
||||
class Config(object):
|
||||
""" access to configuration values, pluginmanager and plugin hooks. """
|
||||
Option = py.std.optparse.Option
|
||||
Error = Error
|
||||
basetemp = None
|
||||
|
||||
def __init__(self, pluginmanager=None):
|
||||
|
@ -251,6 +262,11 @@ class Config(object):
|
|||
self.trace("loaded conftestmodule %r" %(conftestmodule,))
|
||||
self.pluginmanager.consider_conftest(conftestmodule)
|
||||
|
||||
def _processopt(self, opt):
|
||||
if hasattr(opt, 'default') and opt.dest:
|
||||
if not hasattr(self.option, opt.dest):
|
||||
setattr(self.option, opt.dest, opt.default)
|
||||
|
||||
def _getmatchingplugins(self, fspath):
|
||||
allconftests = self._conftest._conftestpath2mod.values()
|
||||
plugins = [x for x in self.pluginmanager.getplugins()
|
||||
|
@ -262,28 +278,6 @@ class Config(object):
|
|||
if getattr(self.option, 'traceconfig', None):
|
||||
self.hook.pytest_trace(category="config", msg=msg)
|
||||
|
||||
def _processopt(self, opt):
|
||||
if hasattr(opt, 'default') and opt.dest:
|
||||
val = os.environ.get("PYTEST_OPTION_" + opt.dest.upper(), None)
|
||||
if val is not None:
|
||||
if opt.type == "int":
|
||||
val = int(val)
|
||||
elif opt.type == "long":
|
||||
val = long(val)
|
||||
elif opt.type == "float":
|
||||
val = float(val)
|
||||
elif not opt.type and opt.action in ("store_true", "store_false"):
|
||||
val = eval(val)
|
||||
opt.default = val
|
||||
else:
|
||||
name = "option_" + opt.dest
|
||||
try:
|
||||
opt.default = self._conftest.rget(name)
|
||||
except (ValueError, KeyError):
|
||||
pass
|
||||
if not hasattr(self.option, opt.dest):
|
||||
setattr(self.option, opt.dest, opt.default)
|
||||
|
||||
def _setinitialconftest(self, args):
|
||||
# capture output during conftest init (#issue93)
|
||||
name = hasattr(os, 'dup') and 'StdCaptureFD' or 'StdCapture'
|
||||
|
@ -299,14 +293,31 @@ class Config(object):
|
|||
raise
|
||||
|
||||
def _preparse(self, args):
|
||||
self.inicfg = getcfg(args, ["setup.cfg", "tox.ini",])
|
||||
if self.inicfg:
|
||||
newargs = self.inicfg.get("addargs", None)
|
||||
if newargs:
|
||||
args[:] = args + py.std.shlex.split(newargs)
|
||||
self._checkversion()
|
||||
self.pluginmanager.consider_setuptools_entrypoints()
|
||||
self.pluginmanager.consider_env()
|
||||
self.pluginmanager.consider_preparse(args)
|
||||
self._setinitialconftest(args)
|
||||
self.pluginmanager.do_addoption(self._parser)
|
||||
|
||||
def _checkversion(self):
|
||||
minver = self.inicfg.get('minversion', None)
|
||||
if minver:
|
||||
ver = minver.split(".")
|
||||
myver = pytest.__version__.split(".")
|
||||
if myver < ver:
|
||||
raise pytest.UsageError(
|
||||
"%s:%d: requires pytest-%s, actual pytest-%s'" %(
|
||||
self.inicfg.config.path, self.inicfg.lineof('minversion'),
|
||||
minver, pytest.__version__))
|
||||
|
||||
def parse(self, args):
|
||||
# cmdline arguments into this config object.
|
||||
# parse given cmdline arguments into this config object.
|
||||
# Note that this can only be called once per testing process.
|
||||
assert not hasattr(self, 'args'), (
|
||||
"can only parse cmdline args at most once per Config object")
|
||||
|
@ -340,12 +351,28 @@ class Config(object):
|
|||
return py.path.local.make_numbered_dir(prefix=basename,
|
||||
keep=0, rootdir=basetemp, lock_timeout=None)
|
||||
|
||||
def getconftest_pathlist(self, name, path=None):
|
||||
""" return a matching value, which needs to be sequence
|
||||
of filenames that will be returned as a list of Path
|
||||
objects (they can be relative to the location
|
||||
where they were found).
|
||||
"""
|
||||
def getini(self, name):
|
||||
""" 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:
|
||||
description, type = self._parser._inidict[name]
|
||||
except KeyError:
|
||||
raise ValueError("unknown configuration value: %r" %(name,))
|
||||
try:
|
||||
value = self.inicfg[name]
|
||||
except KeyError:
|
||||
return # None indicates nothing found
|
||||
if type == "pathlist":
|
||||
dp = py.path.local(self.inicfg.config.path).dirpath()
|
||||
l = []
|
||||
for relpath in py.std.shlex.split(value):
|
||||
l.append(dp.join(relpath, abs=True))
|
||||
return l
|
||||
else:
|
||||
return value
|
||||
|
||||
def _getconftest_pathlist(self, name, path=None):
|
||||
try:
|
||||
mod, relroots = self._conftest.rget_with_confmod(name, path)
|
||||
except KeyError:
|
||||
|
@ -359,6 +386,22 @@ class Config(object):
|
|||
l.append(relroot)
|
||||
return l
|
||||
|
||||
def _getconftest(self, name, path=None, check=False):
|
||||
if check:
|
||||
self._checkconftest(name)
|
||||
return self._conftest.rget(name, path)
|
||||
|
||||
def getvalue(self, name, path=None):
|
||||
""" return ``name`` value looked set from command line options.
|
||||
|
||||
(deprecated) if we can't find the option also lookup
|
||||
the name in a matching conftest file.
|
||||
"""
|
||||
try:
|
||||
return getattr(self.option, name)
|
||||
except AttributeError:
|
||||
return self._getconftest(name, path, check=False)
|
||||
|
||||
def getvalueorskip(self, name, path=None):
|
||||
""" return getvalue(name) or call py.test.skip if no value exists. """
|
||||
try:
|
||||
|
@ -369,15 +412,27 @@ class Config(object):
|
|||
except KeyError:
|
||||
py.test.skip("no %r value found" %(name,))
|
||||
|
||||
def getvalue(self, name, path=None):
|
||||
""" return 'name' value looked up from the 'options'
|
||||
and then from the first conftest file found up
|
||||
the path (including the path itself).
|
||||
if path is None, lookup the value in the initial
|
||||
conftest modules found during command line parsing.
|
||||
"""
|
||||
try:
|
||||
return getattr(self.option, name)
|
||||
except AttributeError:
|
||||
return self._conftest.rget(name, path)
|
||||
|
||||
def getcfg(args, inibasenames):
|
||||
if not args:
|
||||
args = [py.path.local()]
|
||||
for inibasename in inibasenames:
|
||||
for p in args:
|
||||
x = findupwards(p, inibasename)
|
||||
if x is not None:
|
||||
iniconfig = py.iniconfig.IniConfig(x)
|
||||
if 'pytest' in iniconfig.sections:
|
||||
return iniconfig['pytest']
|
||||
return {}
|
||||
|
||||
def findupwards(current, basename):
|
||||
current = py.path.local(current)
|
||||
while 1:
|
||||
p = current.join(basename)
|
||||
if p.check():
|
||||
return p
|
||||
p = current.dirpath()
|
||||
if p == current:
|
||||
return
|
||||
current = p
|
||||
|
||||
|
|
|
@ -58,7 +58,7 @@ def pytest_cmdline_main(config):
|
|||
genscript = config.getvalue("genscript")
|
||||
if genscript:
|
||||
script = generate_script(
|
||||
'import py; py.test.cmdline.main()',
|
||||
'import py; raise SystemExit(py.test.cmdline.main())',
|
||||
['py', 'pytest'],
|
||||
)
|
||||
|
||||
|
|
|
@ -1,12 +1,15 @@
|
|||
""" provide version info, conftest/environment config names.
|
||||
"""
|
||||
import py
|
||||
import pytest
|
||||
import inspect, sys
|
||||
|
||||
def pytest_addoption(parser):
|
||||
group = parser.getgroup('debugconfig')
|
||||
group.addoption('--version', action="store_true",
|
||||
help="display py lib version and import information.")
|
||||
help="display pytest lib version and import information.")
|
||||
group._addoption("-h", "--help", action="store_true", dest="help",
|
||||
help="show help message and configuration info")
|
||||
group._addoption('-p', action="append", dest="plugins", default = [],
|
||||
metavar="name",
|
||||
help="early-load given plugin (multi-allowed).")
|
||||
|
@ -19,67 +22,55 @@ def pytest_addoption(parser):
|
|||
group.addoption('--debug',
|
||||
action="store_true", dest="debug", default=False,
|
||||
help="generate and show internal debugging information.")
|
||||
group.addoption("--help-config", action="store_true", dest="helpconfig",
|
||||
help="show available conftest.py and ENV-variable names.")
|
||||
|
||||
|
||||
def pytest_cmdline_main(config):
|
||||
if config.option.version:
|
||||
p = py.path.local(py.__file__).dirpath()
|
||||
p = py.path.local(pytest.__file__).dirpath()
|
||||
sys.stderr.write("This is py.test version %s, imported from %s\n" %
|
||||
(py.__version__, p))
|
||||
return 0
|
||||
elif config.option.helpconfig:
|
||||
elif config.option.help:
|
||||
config.pluginmanager.do_configure(config)
|
||||
showpluginhelp(config)
|
||||
showhelp(config)
|
||||
return 0
|
||||
|
||||
def showpluginhelp(config):
|
||||
options = []
|
||||
for group in config._parser._groups:
|
||||
options.extend(group.options)
|
||||
widths = [0] * 10
|
||||
def showhelp(config):
|
||||
tw = py.io.TerminalWriter()
|
||||
tw.sep("-")
|
||||
tw.line("%-13s | %-18s | %-25s | %s" %(
|
||||
"cmdline name", "conftest.py name", "ENV-variable name", "help"))
|
||||
tw.sep("-")
|
||||
tw.write(config._parser.optparser.format_help())
|
||||
tw.line()
|
||||
tw.line()
|
||||
#tw.sep( "=", "config file settings")
|
||||
tw.line("setup.cfg or tox.ini options to be put into [pytest] section:")
|
||||
tw.line()
|
||||
|
||||
options = [opt for opt in options if opt._long_opts]
|
||||
options.sort(key=lambda x: x._long_opts)
|
||||
for opt in options:
|
||||
if not opt._long_opts or not opt.dest:
|
||||
continue
|
||||
optstrings = list(opt._long_opts) # + list(opt._short_opts)
|
||||
optstrings = filter(None, optstrings)
|
||||
optstring = "|".join(optstrings)
|
||||
line = "%-13s | %-18s | %-25s | %s" %(
|
||||
optstring,
|
||||
"option_%s" % opt.dest,
|
||||
"PYTEST_OPTION_%s" % opt.dest.upper(),
|
||||
opt.help and opt.help or "",
|
||||
)
|
||||
for name, help in sorted(config._parser._inidict.items()):
|
||||
line = " %-15s %s" %(name, help)
|
||||
tw.line(line[:tw.fullwidth])
|
||||
for name, help in conftest_options:
|
||||
line = "%-13s | %-18s | %-25s | %s" %(
|
||||
"",
|
||||
name,
|
||||
"",
|
||||
help,
|
||||
)
|
||||
tw.line(line[:tw.fullwidth])
|
||||
tw.sep("-")
|
||||
|
||||
conftest_options = (
|
||||
tw.line() ; tw.line()
|
||||
#tw.sep("=")
|
||||
return
|
||||
|
||||
tw.line("conftest.py options:")
|
||||
tw.line()
|
||||
conftestitems = sorted(config._parser._conftestdict.items())
|
||||
for name, help in conftest_options + conftestitems:
|
||||
line = " %-15s %s" %(name, help)
|
||||
tw.line(line[:tw.fullwidth])
|
||||
tw.line()
|
||||
#tw.sep( "=")
|
||||
|
||||
conftest_options = [
|
||||
('pytest_plugins', 'list of plugin names to load'),
|
||||
('collect_ignore', '(relative) paths ignored during collection'),
|
||||
('rsyncdirs', 'to-be-rsynced directories for dist-testing'),
|
||||
)
|
||||
]
|
||||
|
||||
def pytest_report_header(config):
|
||||
lines = []
|
||||
if config.option.debug or config.option.traceconfig:
|
||||
lines.append("using py lib: %s" % (py.path.local(py.__file__).dirpath()))
|
||||
lines.append("using: pytest-%s pylib-%s" %
|
||||
(pytest.__version__,py.__version__))
|
||||
|
||||
if config.option.traceconfig:
|
||||
lines.append("active plugins:")
|
||||
plugins = []
|
||||
|
@ -149,12 +140,11 @@ def getargs(func):
|
|||
startindex = inspect.ismethod(func) and 1 or 0
|
||||
return args[startindex:]
|
||||
|
||||
def collectattr(obj, prefixes=("pytest_",)):
|
||||
def collectattr(obj):
|
||||
methods = {}
|
||||
for apiname in dir(obj):
|
||||
for prefix in prefixes:
|
||||
if apiname.startswith(prefix):
|
||||
methods[apiname] = getattr(obj, apiname)
|
||||
if apiname.startswith("pytest_"):
|
||||
methods[apiname] = getattr(obj, apiname)
|
||||
return methods
|
||||
|
||||
def formatdef(func):
|
||||
|
|
|
@ -242,9 +242,19 @@ class TmpTestdir:
|
|||
def makefile(self, ext, *args, **kwargs):
|
||||
return self._makefile(ext, args, kwargs)
|
||||
|
||||
def makeini(self, source):
|
||||
return self.makefile('cfg', setup=source)
|
||||
|
||||
def makeconftest(self, source):
|
||||
return self.makepyfile(conftest=source)
|
||||
|
||||
def makeini(self, source):
|
||||
return self.makefile('.ini', tox=source)
|
||||
|
||||
def getinicfg(self, source):
|
||||
p = self.makeini(source)
|
||||
return py.iniconfig.IniConfig(p)['pytest']
|
||||
|
||||
def makepyfile(self, *args, **kwargs):
|
||||
return self._makefile('.py', args, kwargs)
|
||||
|
||||
|
@ -375,6 +385,11 @@ class TmpTestdir:
|
|||
#config.pluginmanager.do_unconfigure(config)
|
||||
return node
|
||||
|
||||
def collect_by_name(self, modcol, name):
|
||||
for colitem in modcol._memocollect():
|
||||
if colitem.name == name:
|
||||
return colitem
|
||||
|
||||
def popen(self, cmdargs, stdout, stderr, **kw):
|
||||
if not hasattr(py.std, 'subprocess'):
|
||||
py.test.skip("no subprocess module")
|
||||
|
|
|
@ -9,6 +9,7 @@ import pytest
|
|||
import os, sys
|
||||
|
||||
def pytest_addoption(parser):
|
||||
|
||||
group = parser.getgroup("general", "running and selection options")
|
||||
group._addoption('-x', '--exitfirst', action="store_true", default=False,
|
||||
dest="exitfirst",
|
||||
|
@ -32,6 +33,7 @@ def pytest_addoption(parser):
|
|||
group.addoption('--basetemp', dest="basetemp", default=None, metavar="dir",
|
||||
help="base temporary directory for this test run.")
|
||||
|
||||
|
||||
def pytest_namespace():
|
||||
return dict(collect=dict(Item=Item, Collector=Collector,
|
||||
File=File, Directory=Directory))
|
||||
|
@ -64,7 +66,7 @@ def pytest_runtest_mainloop(session):
|
|||
|
||||
def pytest_ignore_collect(path, config):
|
||||
p = path.dirpath()
|
||||
ignore_paths = config.getconftest_pathlist("collect_ignore", path=p)
|
||||
ignore_paths = config._getconftest_pathlist("collect_ignore", path=p)
|
||||
ignore_paths = ignore_paths or []
|
||||
excludeopt = config.getvalue("ignore")
|
||||
if excludeopt:
|
||||
|
@ -128,7 +130,7 @@ class Session(object):
|
|||
config.hook.pytest_sessionstart(session=self)
|
||||
config.hook.pytest_perform_collection(session=self)
|
||||
config.hook.pytest_runtest_mainloop(session=self)
|
||||
except self.config.Error:
|
||||
except pytest.UsageError:
|
||||
raise
|
||||
except KeyboardInterrupt:
|
||||
excinfo = py.code.ExceptionInfo()
|
||||
|
@ -173,10 +175,10 @@ class Collection:
|
|||
parts = str(arg).split("::")
|
||||
path = base.join(parts[0], abs=True)
|
||||
if not path.check():
|
||||
raise self.config.Error("file not found: %s" %(path,))
|
||||
raise pytest.UsageError("file not found: %s" %(path,))
|
||||
topdir = self.topdir
|
||||
if path != topdir and not path.relto(topdir):
|
||||
raise self.config.Error("path %r is not relative to %r" %
|
||||
raise pytest.UsageError("path %r is not relative to %r" %
|
||||
(str(path), str(topdir)))
|
||||
topparts = path.relto(topdir).split(path.sep)
|
||||
return topparts + parts[1:]
|
||||
|
@ -213,7 +215,7 @@ class Collection:
|
|||
for node in self.matchnodes([self._topcollector], names):
|
||||
items.extend(self.genitems(node))
|
||||
except NoMatch:
|
||||
raise self.config.Error("can't collect: %s" % (arg,))
|
||||
raise pytest.UsageError("can't collect: %s" % (arg,))
|
||||
return items
|
||||
|
||||
def matchnodes(self, matching, names):
|
||||
|
@ -444,14 +446,8 @@ class Collector(Node):
|
|||
"""
|
||||
raise NotImplementedError("abstract")
|
||||
|
||||
def collect_by_name(self, name):
|
||||
""" return a child matching the given name, else None. """
|
||||
for colitem in self._memocollect():
|
||||
if colitem.name == name:
|
||||
return colitem
|
||||
|
||||
def repr_failure(self, excinfo):
|
||||
""" represent a failure. """
|
||||
""" represent a collection failure. """
|
||||
if excinfo.errisinstance(self.CollectError):
|
||||
exc = excinfo.value
|
||||
return str(exc.args[0])
|
||||
|
@ -524,8 +520,7 @@ class Directory(FSCollector):
|
|||
|
||||
class Item(Node):
|
||||
""" a basic test invocation item. Note that for a single function
|
||||
there might be multiple test invocation items. Attributes:
|
||||
|
||||
there might be multiple test invocation items.
|
||||
"""
|
||||
def reportinfo(self):
|
||||
return self.fspath, None, ""
|
||||
|
|
2
setup.py
2
setup.py
|
@ -22,7 +22,7 @@ def main():
|
|||
name='pytest',
|
||||
description='py.test: simple powerful testing with Python',
|
||||
long_description = long_description,
|
||||
version='2.0.0.dev10',
|
||||
version='2.0.0.dev11',
|
||||
url='http://pytest.org',
|
||||
license='MIT license',
|
||||
platforms=['unix', 'linux', 'osx', 'cygwin', 'win32'],
|
||||
|
|
|
@ -4,7 +4,8 @@ class TestGeneralUsage:
|
|||
def test_config_error(self, testdir):
|
||||
testdir.makeconftest("""
|
||||
def pytest_configure(config):
|
||||
raise config.Error("hello")
|
||||
import pytest
|
||||
raise pytest.UsageError("hello")
|
||||
""")
|
||||
result = testdir.runpytest(testdir.tmpdir)
|
||||
assert result.ret != 0
|
||||
|
|
|
@ -2,9 +2,6 @@ import py
|
|||
import sys
|
||||
|
||||
pytest_plugins = "pytester",
|
||||
collect_ignore = ['../build', '../doc/_build']
|
||||
|
||||
rsyncdirs = ['conftest.py', '../pytest', '../doc', '.']
|
||||
|
||||
import os, py
|
||||
pid = os.getpid()
|
||||
|
@ -41,6 +38,12 @@ def pytest_unconfigure(config, __multicall__):
|
|||
assert len2 < config._numfiles + 7, out2
|
||||
|
||||
|
||||
def pytest_runtest_setup(item):
|
||||
item._oldir = py.path.local()
|
||||
|
||||
def pytest_runtest_teardown(item):
|
||||
item._oldir.chdir()
|
||||
|
||||
def pytest_generate_tests(metafunc):
|
||||
multi = getattr(metafunc.function, 'multi', None)
|
||||
if multi is not None:
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import py
|
||||
|
||||
pytest_plugins = "pytester"
|
||||
import pytest.plugin
|
||||
plugindir = py.path.local(pytest.plugin.__file__).dirpath()
|
||||
from pytest._core import default_plugins
|
||||
|
|
|
@ -19,13 +19,14 @@ class Standalone:
|
|||
return testdir._run(anypython, self.script, *args)
|
||||
|
||||
def test_gen(testdir, anypython, standalone):
|
||||
result = standalone.run(anypython, testdir, '-h')
|
||||
assert result.ret == 0
|
||||
result = standalone.run(anypython, testdir, '--version')
|
||||
assert result.ret == 0
|
||||
result.stderr.fnmatch_lines([
|
||||
"*imported from*mypytest"
|
||||
])
|
||||
p = testdir.makepyfile("def test_func(): assert 0")
|
||||
result = standalone.run(anypython, testdir, p)
|
||||
assert result.ret != 0
|
||||
|
||||
@py.test.mark.xfail(reason="fix-dist", run=False)
|
||||
def test_rundist(testdir, pytestconfig, standalone):
|
||||
|
|
|
@ -10,11 +10,13 @@ def test_version(testdir):
|
|||
'*py.test*%s*imported from*' % (py.version, )
|
||||
])
|
||||
|
||||
def test_helpconfig(testdir):
|
||||
result = testdir.runpytest("--help-config")
|
||||
def test_help(testdir):
|
||||
result = testdir.runpytest("--help")
|
||||
assert result.ret == 0
|
||||
result.stdout.fnmatch_lines([
|
||||
"*cmdline*conftest*ENV*",
|
||||
"*-v*verbose*",
|
||||
"*setup.cfg*",
|
||||
"*minversion*",
|
||||
])
|
||||
|
||||
def test_collectattr():
|
||||
|
|
|
@ -268,9 +268,9 @@ class TestSorting:
|
|||
def test_pass(): pass
|
||||
def test_fail(): assert 0
|
||||
""")
|
||||
fn1 = modcol.collect_by_name("test_pass")
|
||||
fn1 = testdir.collect_by_name(modcol, "test_pass")
|
||||
assert isinstance(fn1, py.test.collect.Function)
|
||||
fn2 = modcol.collect_by_name("test_pass")
|
||||
fn2 = testdir.collect_by_name(modcol, "test_pass")
|
||||
assert isinstance(fn2, py.test.collect.Function)
|
||||
|
||||
assert fn1 == fn2
|
||||
|
@ -279,7 +279,7 @@ class TestSorting:
|
|||
assert cmp(fn1, fn2) == 0
|
||||
assert hash(fn1) == hash(fn2)
|
||||
|
||||
fn3 = modcol.collect_by_name("test_fail")
|
||||
fn3 = testdir.collect_by_name(modcol, "test_fail")
|
||||
assert isinstance(fn3, py.test.collect.Function)
|
||||
assert not (fn1 == fn3)
|
||||
assert fn1 != fn3
|
||||
|
@ -1092,7 +1092,7 @@ class TestReportInfo:
|
|||
class TestClass:
|
||||
def test_hello(self): pass
|
||||
""")
|
||||
classcol = modcol.collect_by_name("TestClass")
|
||||
classcol = testdir.collect_by_name(modcol, "TestClass")
|
||||
fspath, lineno, msg = classcol.reportinfo()
|
||||
assert fspath == modcol.fspath
|
||||
assert lineno == 1
|
||||
|
@ -1106,7 +1106,7 @@ class TestReportInfo:
|
|||
assert x
|
||||
yield check, 3
|
||||
""")
|
||||
gencol = modcol.collect_by_name("test_gen")
|
||||
gencol = testdir.collect_by_name(modcol, "test_gen")
|
||||
fspath, lineno, modpath = gencol.reportinfo()
|
||||
assert fspath == modcol.fspath
|
||||
assert lineno == 1
|
||||
|
|
|
@ -466,8 +466,8 @@ def test_getreportopt():
|
|||
testdict.update(dict(reportchars="sfx"))
|
||||
assert getreportopt(config) == "sfx"
|
||||
|
||||
def test_terminalreporter_reportopt_conftestsetting(testdir):
|
||||
testdir.makeconftest("option_report = 'skipped'")
|
||||
def test_terminalreporter_reportopt_addargs(testdir):
|
||||
testdir.makeini("[pytest]\naddargs=-rs")
|
||||
p = testdir.makepyfile("""
|
||||
def pytest_funcarg__tr(request):
|
||||
tr = request.config.pluginmanager.getplugin("terminalreporter")
|
||||
|
|
|
@ -28,9 +28,9 @@ class TestCollector:
|
|||
def test_pass(): pass
|
||||
def test_fail(): assert 0
|
||||
""")
|
||||
fn1 = modcol.collect_by_name("test_pass")
|
||||
fn1 = testdir.collect_by_name(modcol, "test_pass")
|
||||
assert isinstance(fn1, py.test.collect.Function)
|
||||
fn2 = modcol.collect_by_name("test_pass")
|
||||
fn2 = testdir.collect_by_name(modcol, "test_pass")
|
||||
assert isinstance(fn2, py.test.collect.Function)
|
||||
|
||||
assert fn1 == fn2
|
||||
|
@ -39,7 +39,7 @@ class TestCollector:
|
|||
assert cmp(fn1, fn2) == 0
|
||||
assert hash(fn1) == hash(fn2)
|
||||
|
||||
fn3 = modcol.collect_by_name("test_fail")
|
||||
fn3 = testdir.collect_by_name(modcol, "test_fail")
|
||||
assert isinstance(fn3, py.test.collect.Function)
|
||||
assert not (fn1 == fn3)
|
||||
assert fn1 != fn3
|
||||
|
@ -57,8 +57,9 @@ class TestCollector:
|
|||
def test_foo():
|
||||
pass
|
||||
""")
|
||||
cls = modcol.collect_by_name("TestClass")
|
||||
fn = cls.collect_by_name("()").collect_by_name("test_foo")
|
||||
cls = testdir.collect_by_name(modcol, "TestClass")
|
||||
fn = testdir.collect_by_name(
|
||||
testdir.collect_by_name(cls, "()"), "test_foo")
|
||||
|
||||
parent = fn.getparent(py.test.collect.Module)
|
||||
assert parent is modcol
|
||||
|
|
|
@ -1,32 +1,42 @@
|
|||
import py
|
||||
|
||||
class TestConfigCmdlineParsing:
|
||||
def test_parser_addoption_default_env(self, testdir, monkeypatch):
|
||||
import os
|
||||
config = testdir.Config()
|
||||
group = config._parser.getgroup("hello")
|
||||
from pytest.plugin.config import getcfg, Config
|
||||
|
||||
monkeypatch.setitem(os.environ, 'PYTEST_OPTION_OPTION1', 'True')
|
||||
group.addoption("--option1", action="store_true")
|
||||
assert group.options[0].default == True
|
||||
class TestParseIni:
|
||||
def test_getcfg_and_config(self, tmpdir):
|
||||
sub = tmpdir.mkdir("sub")
|
||||
sub.chdir()
|
||||
tmpdir.join("setup.cfg").write(py.code.Source("""
|
||||
[pytest]
|
||||
name = value
|
||||
"""))
|
||||
cfg = getcfg([sub], ["setup.cfg"])
|
||||
assert cfg['name'] == "value"
|
||||
config = Config()
|
||||
config._preparse([sub])
|
||||
assert config.inicfg['name'] == 'value'
|
||||
|
||||
monkeypatch.setitem(os.environ, 'PYTEST_OPTION_OPTION2', 'abc')
|
||||
group.addoption("--option2", action="store", default="x")
|
||||
assert group.options[1].default == "abc"
|
||||
|
||||
monkeypatch.setitem(os.environ, 'PYTEST_OPTION_OPTION3', '32')
|
||||
group.addoption("--option3", action="store", type="int")
|
||||
assert group.options[2].default == 32
|
||||
|
||||
group.addoption("--option4", action="store", type="int")
|
||||
assert group.options[3].default == ("NO", "DEFAULT")
|
||||
|
||||
def test_parser_addoption_default_conftest(self, testdir, monkeypatch):
|
||||
import os
|
||||
testdir.makeconftest("option_verbose=True")
|
||||
config = testdir.parseconfig()
|
||||
def test_append_parse_args(self, tmpdir):
|
||||
tmpdir.join("setup.cfg").write(py.code.Source("""
|
||||
[pytest]
|
||||
addargs = --verbose
|
||||
"""))
|
||||
config = Config()
|
||||
config.parse([tmpdir])
|
||||
assert config.option.verbose
|
||||
|
||||
def test_tox_ini_wrong_version(self, testdir):
|
||||
p = testdir.makefile('.ini', tox="""
|
||||
[pytest]
|
||||
minversion=9.0
|
||||
""")
|
||||
result = testdir.runpytest()
|
||||
assert result.ret != 0
|
||||
result.stderr.fnmatch_lines([
|
||||
"*tox.ini:2*requires*9.0*actual*"
|
||||
])
|
||||
|
||||
class TestConfigCmdlineParsing:
|
||||
def test_parsing_again_fails(self, testdir):
|
||||
config = testdir.reparseconfig([testdir.tmpdir])
|
||||
py.test.raises(AssertionError, "config.parse([])")
|
||||
|
@ -97,13 +107,43 @@ class TestConfigAPI:
|
|||
p = tmpdir.join("conftest.py")
|
||||
p.write("pathlist = ['.', %r]" % str(somepath))
|
||||
config = testdir.reparseconfig([p])
|
||||
assert config.getconftest_pathlist('notexist') is None
|
||||
pl = config.getconftest_pathlist('pathlist')
|
||||
assert config._getconftest_pathlist('notexist') is None
|
||||
pl = config._getconftest_pathlist('pathlist')
|
||||
print(pl)
|
||||
assert len(pl) == 2
|
||||
assert pl[0] == tmpdir
|
||||
assert pl[1] == somepath
|
||||
|
||||
def test_addini(self, testdir):
|
||||
testdir.makeconftest("""
|
||||
def pytest_addoption(parser):
|
||||
parser.addini("myname", "my new ini value")
|
||||
""")
|
||||
testdir.makeini("""
|
||||
[pytest]
|
||||
myname=hello
|
||||
""")
|
||||
config = testdir.parseconfig()
|
||||
val = config.getini("myname")
|
||||
assert val == "hello"
|
||||
py.test.raises(ValueError, config.getini, 'other')
|
||||
|
||||
def test_addini_pathlist(self, testdir):
|
||||
testdir.makeconftest("""
|
||||
def pytest_addoption(parser):
|
||||
parser.addini("paths", "my new ini value", type="pathlist")
|
||||
parser.addini("abc", "abc value")
|
||||
""")
|
||||
p = testdir.makeini("""
|
||||
[pytest]
|
||||
paths=hello world/sub.py
|
||||
""")
|
||||
config = testdir.parseconfig()
|
||||
l = config.getini("paths")
|
||||
assert len(l) == 2
|
||||
assert l[0] == p.dirpath('hello')
|
||||
assert l[1] == p.dirpath('world/sub.py')
|
||||
py.test.raises(ValueError, config.getini, 'other')
|
||||
|
||||
def test_options_on_small_file_do_not_blow_up(testdir):
|
||||
def runfiletest(opts):
|
||||
|
@ -140,3 +180,4 @@ def test_preparse_ordering(testdir, monkeypatch):
|
|||
config = testdir.parseconfig()
|
||||
plugin = config.pluginmanager.getplugin("mytestplugin")
|
||||
assert plugin.x == 42
|
||||
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
import py
|
||||
from pytest.plugin import config as parseopt
|
||||
from textwrap import dedent
|
||||
|
||||
class TestParser:
|
||||
def test_init(self, capsys):
|
||||
def test_no_help_by_default(self, capsys):
|
||||
parser = parseopt.Parser(usage="xyz")
|
||||
py.test.raises(SystemExit, 'parser.parse(["-h"])')
|
||||
out, err = capsys.readouterr()
|
||||
assert out.find("xyz") != -1
|
||||
assert err.find("no such option") != -1
|
||||
|
||||
def test_group_add_and_get(self):
|
||||
parser = parseopt.Parser()
|
||||
|
@ -100,6 +101,7 @@ class TestParser:
|
|||
assert option.hello == "world"
|
||||
assert option.this == 42
|
||||
|
||||
|
||||
@py.test.mark.skipif("sys.version_info < (2,5)")
|
||||
def test_addoption_parser_epilog(testdir):
|
||||
testdir.makeconftest("""
|
||||
|
|
Loading…
Reference in New Issue