From 33cd4144200173f5b06d82d8d5bc1d63c934e1b1 Mon Sep 17 00:00:00 2001 From: holger krekel Date: Tue, 6 Nov 2012 14:09:12 +0100 Subject: [PATCH] fix issue127 improve pytest_addoption docs, add new config.getoption(name) method for consistency. --- CHANGELOG | 3 +++ _pytest/__init__.py | 2 +- _pytest/config.py | 30 ++++++++++++++++++++++++------ _pytest/hookspec.py | 28 +++++++++++++++++++++++----- doc/en/customize.txt | 2 ++ doc/en/example/markers.txt | 4 ++-- doc/en/example/simple.txt | 4 ++-- doc/en/plugins.txt | 5 ++++- setup.py | 2 +- testing/test_config.py | 11 +++++++++++ 10 files changed, 73 insertions(+), 18 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 67f7d3421..8948480d6 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -27,6 +27,9 @@ Changes between 2.3.2 and 2.3.3.dev - fix issue217 - support mock.patch with pytest's fixtures - note that you need either mock-1.0.1 or the python3.3 builtin unittest.mock. +- fix issue127 - improve documentation for pytest_addoption() and + add a ``config.getoption(name)`` helper function for consistency. + Changes between 2.3.1 and 2.3.2 ----------------------------------- diff --git a/_pytest/__init__.py b/_pytest/__init__.py index cdd940d10..de8f7422a 100644 --- a/_pytest/__init__.py +++ b/_pytest/__init__.py @@ -1,2 +1,2 @@ # -__version__ = '2.3.3.dev4' +__version__ = '2.3.3.dev5' diff --git a/_pytest/config.py b/_pytest/config.py index 7bdc03a60..00848cc9d 100644 --- a/_pytest/config.py +++ b/_pytest/config.py @@ -271,9 +271,8 @@ class CmdOptions(object): class Config(object): """ access to configuration values, pluginmanager and plugin hooks. """ def __init__(self, pluginmanager=None): - #: command line option values, which must have been previously added - #: via calls like ``parser.addoption(...)`` or - #: ``parser.getgroup(groupname).addoption(...)`` + #: access to command line option as attributes. + #: (deprecated), use :py:func:`getoption() <_pytest.config.Config.getoption>` instead self.option = CmdOptions() self._parser = Parser( usage="usage: %prog [options] [file_or_dir] [file_or_dir] [...]", @@ -285,6 +284,7 @@ class Config(object): self._conftest = Conftest(onimport=self._onimportconftest) self.hook = self.pluginmanager.hook self._inicache = {} + self._opt2dest = {} self._cleanup = [] @classmethod @@ -305,6 +305,9 @@ class Config(object): self.pluginmanager.consider_conftest(conftestmodule) def _processopt(self, opt): + for name in opt._short_opts + opt._long_opts: + self._opt2dest[name] = opt.dest + if hasattr(opt, 'default') and opt.dest: if not hasattr(self.option, opt.dest): setattr(self.option, opt.dest, opt.default) @@ -383,8 +386,9 @@ class Config(object): x.append(line) # modifies the cached list inline def getini(self, name): - """ return configuration value from an ini file. If the - specified name hasn't been registered through a prior ``parse.addini`` + """ return configuration value from an :ref:`ini file `. If the + specified name hasn't been registered through a prior + :py:func:`parser.addini ` call (usually from a plugin), a ValueError is raised. """ try: return self._inicache[name] @@ -438,8 +442,22 @@ class Config(object): self._checkconftest(name) return self._conftest.rget(name, path) + def getoption(self, name): + """ return command line option value. + + :arg name: name of the option. You may also specify + the literal ``--OPT`` option instead of the "dest" option name. + """ + name = self._opt2dest.get(name, name) + try: + return getattr(self.option, name) + except AttributeError: + raise ValueError("no option named %r" % (name,)) + def getvalue(self, name, path=None): - """ return ``name`` value looked set from command line options. + """ return command line option value. + + :arg name: name of the command line option (deprecated) if we can't find the option also lookup the name in a matching conftest file. diff --git a/_pytest/hookspec.py b/_pytest/hookspec.py index f9f8b4ded..7c0027849 100644 --- a/_pytest/hookspec.py +++ b/_pytest/hookspec.py @@ -23,10 +23,28 @@ def pytest_cmdline_preparse(config, args): """modify command line arguments before option parsing. """ def pytest_addoption(parser): - """use the parser to add optparse-style options and ini-style - config values via calls, see :py:func:`parser.addoption(...) - <_pytest.config.Parser.addoption>` - and :py:func:`parser.addini(...) <_pytest.config.Parser.addini>`. + """register optparse-style options and ini-style config values. + + This function must be implemented in a :ref:`plugin ` and is + called once at the beginning of a test run. + + :arg parser: To add command line options, call + :py:func:`parser.addoption(...) <_pytest.config.Parser.addoption>`. + To add ini-file values call :py:func:`parser.addini(...) + <_pytest.config.Parser.addini>`. + + Options can later be accessed through the + :py:class:`config <_pytest.config.Config>` object, respectively: + + - :py:func:`config.getoption(name) <_pytest.config.Config.getoption>` to + retrieve the value of a command line option. + + - :py:func:`config.getini(name) <_pytest.config.Config.getini>` to retrieve + a value read from an ini-style file. + + The config object is passed around on many internal objects via the ``.config`` + attribute or can be retrieved as the ``pytestconfig`` fixture or accessed + via (deprecated) ``pytest.config``. """ def pytest_cmdline_main(config): @@ -35,7 +53,7 @@ def pytest_cmdline_main(config): pytest_cmdline_main.firstresult = True def pytest_configure(config): - """ called after command line options have been parsed. + """ called after command line options have been parsed and all plugins and initial conftest files been loaded. """ diff --git a/doc/en/customize.txt b/doc/en/customize.txt index 6719c01cb..6e1012807 100644 --- a/doc/en/customize.txt +++ b/doc/en/customize.txt @@ -12,6 +12,8 @@ configurations files by using the general help option:: This will display command line and configuration file settings which were registered by installed plugins. +.. _inifiles: + How test configuration is read from configuration INI-files ------------------------------------------------------------- diff --git a/doc/en/example/markers.txt b/doc/en/example/markers.txt index 033342e99..1d0ac838d 100644 --- a/doc/en/example/markers.txt +++ b/doc/en/example/markers.txt @@ -194,7 +194,7 @@ specifies via named environments:: import pytest def pytest_addoption(parser): - parser.addoption("-E", dest="env", action="store", metavar="NAME", + parser.addoption("-E", action="store", metavar="NAME", help="only run tests matching the environment NAME.") def pytest_configure(config): @@ -206,7 +206,7 @@ specifies via named environments:: envmarker = item.keywords.get("env", None) if envmarker is not None: envname = envmarker.args[0] - if envname != item.config.option.env: + if envname != item.config.getoption("-E"): pytest.skip("test requires env %r" % envname) A test file using this local plugin:: diff --git a/doc/en/example/simple.txt b/doc/en/example/simple.txt index c84c36080..b4057b89d 100644 --- a/doc/en/example/simple.txt +++ b/doc/en/example/simple.txt @@ -33,7 +33,7 @@ provide the ``cmdopt`` through a :ref:`fixture function `:: @pytest.fixture def cmdopt(request): - return request.config.option.cmdopt + return request.config.getoption("--cmdopt") Let's run this without supplying our new option:: @@ -129,7 +129,7 @@ line option to control skipping of ``slow`` marked tests:: help="run slow tests") def pytest_runtest_setup(item): - if 'slow' in item.keywords and not item.config.getvalue("runslow"): + if 'slow' in item.keywords and not item.config.getoption("--runslow"): pytest.skip("need --runslow option to run") We can now write a test module like this:: diff --git a/doc/en/plugins.txt b/doc/en/plugins.txt index d030d7cb5..ee941619b 100644 --- a/doc/en/plugins.txt +++ b/doc/en/plugins.txt @@ -5,7 +5,7 @@ Working with plugins and conftest files py.test implements all aspects of configuration, collection, running and reporting by calling `well specified hooks`_. Virtually any Python module can be registered as a plugin. It can implement any number of hook functions (usually two or three) which all have a ``pytest_`` prefix, making hook functions easy to distinguish and find. There are three basic location types: -* `builtin plugins`_: loaded from py.test's own ``pytest/plugin`` directory. +* `builtin plugins`_: loaded from py.test's internal ``_pytest`` directory. * `external plugins`_: modules discovered through `setuptools entry points`_ * `conftest.py plugins`_: modules auto-discovered in test directories @@ -155,6 +155,8 @@ If a package is installed this way, py.test will load ``myproject.pluginmodule`` as a plugin which can define `well specified hooks`_. +.. _`pluginorder`: + Plugin discovery order at tool startup -------------------------------------------- @@ -175,6 +177,7 @@ py.test loads plugin modules at tool startup in the following way: * by recursively loading all plugins specified by the ``pytest_plugins`` variable in ``conftest.py`` files + Requiring/Loading plugins in a test module or conftest file ------------------------------------------------------------- diff --git a/setup.py b/setup.py index 719681fd8..d69515483 100644 --- a/setup.py +++ b/setup.py @@ -24,7 +24,7 @@ def main(): name='pytest', description='py.test: simple powerful testing with Python', long_description = long_description, - version='2.3.3.dev4', + version='2.3.3.dev5', url='http://pytest.org', license='MIT license', platforms=['unix', 'linux', 'osx', 'cygwin', 'win32'], diff --git a/testing/test_config.py b/testing/test_config.py index 31e4eaf78..05ac490bf 100644 --- a/testing/test_config.py +++ b/testing/test_config.py @@ -103,6 +103,16 @@ class TestConfigAPI: assert config.getvalue("x", o) == 1 pytest.raises(KeyError, 'config.getvalue("y", o)') + def test_config_getoption(self, testdir): + testdir.makeconftest(""" + def pytest_addoption(parser): + parser.addoption("--hello", "-X", dest="hello") + """) + config = testdir.parseconfig("--hello=this") + for x in ("hello", "--hello", "-X"): + assert config.getoption(x) == "this" + pytest.raises(ValueError, "config.getoption('qweqwe')") + def test_config_getvalueorskip(self, testdir): config = testdir.parseconfig() pytest.raises(pytest.skip.Exception, @@ -304,3 +314,4 @@ def test_cmdline_processargs_simple(testdir): "*pytest*", "*-h*", ]) +