Merge pull request #1124 from bukzor/unit-test-config-fromdictargs

tests of (and fixes for) Config.fromdictargs (2)
This commit is contained in:
Bruno Oliveira 2015-10-09 15:10:40 -03:00
commit cee828130c
3 changed files with 84 additions and 16 deletions

View File

@ -3,6 +3,9 @@
* New `pytest.mark.skip` mark, which unconditional skips marked tests. * New `pytest.mark.skip` mark, which unconditional skips marked tests.
Thanks Michael Aquilina for the complete PR. Thanks Michael Aquilina for the complete PR.
* fix issue #680: the -s and -c options should now work under xdist;
`Config.fromdictargs` now represents its input much more faithfully.
Thanks to Buck Evan for the complete PR.
2.8.2.dev 2.8.2.dev
--------- ---------

View File

@ -455,11 +455,11 @@ class Parser:
""" """
self._anonymous.addoption(*opts, **attrs) self._anonymous.addoption(*opts, **attrs)
def parse(self, args): def parse(self, args, namespace=None):
from _pytest._argcomplete import try_argcomplete from _pytest._argcomplete import try_argcomplete
self.optparser = self._getparser() self.optparser = self._getparser()
try_argcomplete(self.optparser) try_argcomplete(self.optparser)
return self.optparser.parse_args([str(x) for x in args]) return self.optparser.parse_args([str(x) for x in args], namespace=namespace)
def _getparser(self): def _getparser(self):
from _pytest._argcomplete import filescompleter from _pytest._argcomplete import filescompleter
@ -477,25 +477,25 @@ class Parser:
optparser.add_argument(FILE_OR_DIR, nargs='*').completer=filescompleter optparser.add_argument(FILE_OR_DIR, nargs='*').completer=filescompleter
return optparser return optparser
def parse_setoption(self, args, option): def parse_setoption(self, args, option, namespace=None):
parsedoption = self.parse(args) parsedoption = self.parse(args, namespace=namespace)
for name, value in parsedoption.__dict__.items(): for name, value in parsedoption.__dict__.items():
setattr(option, name, value) setattr(option, name, value)
return getattr(parsedoption, FILE_OR_DIR) return getattr(parsedoption, FILE_OR_DIR)
def parse_known_args(self, args): def parse_known_args(self, args, namespace=None):
"""parses and returns a namespace object with known arguments at this """parses and returns a namespace object with known arguments at this
point. point.
""" """
return self.parse_known_and_unknown_args(args)[0] return self.parse_known_and_unknown_args(args, namespace=namespace)[0]
def parse_known_and_unknown_args(self, args): def parse_known_and_unknown_args(self, args, namespace=None):
"""parses and returns a namespace object with known arguments, and """parses and returns a namespace object with known arguments, and
the remaining arguments unknown at this point. the remaining arguments unknown at this point.
""" """
optparser = self._getparser() optparser = self._getparser()
args = [str(x) for x in args] args = [str(x) for x in args]
return optparser.parse_known_args(args) return optparser.parse_known_args(args, namespace=namespace)
def addini(self, name, help, type=None, default=None): def addini(self, name, help, type=None, default=None):
""" register an ini-file option. """ register an ini-file option.
@ -779,10 +779,12 @@ def _ensure_removed_sysmodule(modname):
class CmdOptions(object): class CmdOptions(object):
""" holds cmdline options as attributes.""" """ holds cmdline options as attributes."""
def __init__(self, **kwargs): def __init__(self, values=()):
self.__dict__.update(kwargs) self.__dict__.update(values)
def __repr__(self): def __repr__(self):
return "<CmdOptions %r>" %(self.__dict__,) return "<CmdOptions %r>" %(self.__dict__,)
def copy(self):
return CmdOptions(self.__dict__)
class Notset: class Notset:
def __repr__(self): def __repr__(self):
@ -879,8 +881,8 @@ class Config(object):
def fromdictargs(cls, option_dict, args): def fromdictargs(cls, option_dict, args):
""" constructor useable for subprocesses. """ """ constructor useable for subprocesses. """
config = get_config() config = get_config()
config._preparse(args, addopts=False)
config.option.__dict__.update(option_dict) config.option.__dict__.update(option_dict)
config.parse(args, addopts=False)
for x in config.option.plugins: for x in config.option.plugins:
config.pluginmanager.consider_pluginarg(x) config.pluginmanager.consider_pluginarg(x)
return config return config
@ -898,7 +900,7 @@ class Config(object):
self.pluginmanager._set_initial_conftests(early_config.known_args_namespace) self.pluginmanager._set_initial_conftests(early_config.known_args_namespace)
def _initini(self, args): def _initini(self, args):
ns, unknown_args = self._parser.parse_known_and_unknown_args(args) ns, unknown_args = self._parser.parse_known_and_unknown_args(args, namespace=self.option.copy())
r = determine_setup(ns.inifilename, ns.file_or_dir + unknown_args) r = determine_setup(ns.inifilename, ns.file_or_dir + unknown_args)
self.rootdir, self.inifile, self.inicfg = r self.rootdir, self.inifile, self.inicfg = r
self._parser.extra_info['rootdir'] = self.rootdir self._parser.extra_info['rootdir'] = self.rootdir
@ -919,7 +921,7 @@ class Config(object):
except ImportError as e: except ImportError as e:
self.warn("I2", "could not load setuptools entry import: %s" % (e,)) self.warn("I2", "could not load setuptools entry import: %s" % (e,))
self.pluginmanager.consider_env() self.pluginmanager.consider_env()
self.known_args_namespace = ns = self._parser.parse_known_args(args) self.known_args_namespace = ns = self._parser.parse_known_args(args, namespace=self.option.copy())
if self.known_args_namespace.confcutdir is None and self.inifile: if self.known_args_namespace.confcutdir is None and self.inifile:
confcutdir = py.path.local(self.inifile).dirname confcutdir = py.path.local(self.inifile).dirname
self.known_args_namespace.confcutdir = confcutdir self.known_args_namespace.confcutdir = confcutdir
@ -947,17 +949,17 @@ class Config(object):
self.inicfg.config.path, self.inicfg.lineof('minversion'), self.inicfg.config.path, self.inicfg.lineof('minversion'),
minver, pytest.__version__)) minver, pytest.__version__))
def parse(self, args): def parse(self, args, addopts=True):
# parse given cmdline arguments into this config object. # parse given cmdline arguments into this config object.
assert not hasattr(self, 'args'), ( assert not hasattr(self, 'args'), (
"can only parse cmdline args at most once per Config object") "can only parse cmdline args at most once per Config object")
self._origargs = args self._origargs = args
self.hook.pytest_addhooks.call_historic( self.hook.pytest_addhooks.call_historic(
kwargs=dict(pluginmanager=self.pluginmanager)) kwargs=dict(pluginmanager=self.pluginmanager))
self._preparse(args) self._preparse(args, addopts=addopts)
# XXX deprecated hook: # XXX deprecated hook:
self.hook.pytest_cmdline_preparse(config=self, args=args) self.hook.pytest_cmdline_preparse(config=self, args=args)
args = self._parser.parse_setoption(args, self.option) args = self._parser.parse_setoption(args, self.option, namespace=self.option)
if not args: if not args:
cwd = os.getcwd() cwd = os.getcwd()
if cwd == self.rootdir: if cwd == self.rootdir:

View File

@ -264,6 +264,69 @@ class TestConfigAPI:
assert len(l) == 2 assert len(l) == 2
assert l == ["456", "123"] assert l == ["456", "123"]
class TestConfigFromdictargs:
def test_basic_behavior(self):
from _pytest.config import Config
option_dict = {
'verbose': 444,
'foo': 'bar',
'capture': 'no',
}
args = ['a', 'b']
config = Config.fromdictargs(option_dict, args)
with pytest.raises(AssertionError):
config.parse(['should refuse to parse again'])
assert config.option.verbose == 444
assert config.option.foo == 'bar'
assert config.option.capture == 'no'
assert config.args == args
def test_origargs(self):
"""Show that fromdictargs can handle args in their "orig" format"""
from _pytest.config import Config
option_dict = {}
args = ['-vvvv', '-s', 'a', 'b']
config = Config.fromdictargs(option_dict, args)
assert config.args == ['a', 'b']
assert config._origargs == args
assert config.option.verbose == 4
assert config.option.capture == 'no'
def test_inifilename(self, tmpdir):
tmpdir.join("foo/bar.ini").ensure().write(py.code.Source("""
[pytest]
name = value
"""))
from _pytest.config import Config
inifile = '../../foo/bar.ini'
option_dict = {
'inifilename': inifile,
'capture': 'no',
}
cwd = tmpdir.join('a/b')
cwd.join('pytest.ini').ensure().write(py.code.Source("""
[pytest]
name = wrong-value
should_not_be_set = true
"""))
with cwd.ensure(dir=True).as_cwd():
config = Config.fromdictargs(option_dict, ())
assert config.args == [str(cwd)]
assert config.option.inifilename == inifile
assert config.option.capture == 'no'
# this indicates this is the file used for getting configuration values
assert config.inifile == inifile
assert config.inicfg.get('name') == 'value'
assert config.inicfg.get('should_not_be_set') is None
def test_options_on_small_file_do_not_blow_up(testdir): def test_options_on_small_file_do_not_blow_up(testdir):
def runfiletest(opts): def runfiletest(opts):
reprec = testdir.inline_run(*opts) reprec = testdir.inline_run(*opts)