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,10 +331,26 @@ Reference of important objects involved in hooks | |||
| .. autoclass:: pytest.plugin.config.Config | ||||
|     :members: | ||||
| 
 | ||||
| .. autoclass:: pytest.plugin.session.Item | ||||
|     :inherited-members: | ||||
| .. autoclass:: pytest.plugin.config.Parser | ||||
|     :members: | ||||
| 
 | ||||
| .. autoclass:: pytest.plugin.session.Node | ||||
| .. 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 | ||||
|  | @ -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,11 +140,10 @@ 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): | ||||
|         if apiname.startswith("pytest_"): | ||||
|             methods[apiname] = getattr(obj, apiname) | ||||
|     return methods | ||||
| 
 | ||||
|  |  | |||
|  | @ -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