diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 847d27c51..6ad73d0c2 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -9,13 +9,17 @@ expected warnings and the list of caught warnings is added to the error message. Thanks `@lesteve`_ for the PR. -* +* Specifying tests with colons like ``test_foo.py::test_bar`` for tests in + subdirectories with ini configuration files now uses the correct ini file + (`#2148`_). Thanks `@pelme`_. * .. _@lesteve: https://github.com/lesteve +.. _@pelme: https://github.com/pelme .. _#2150: https://github.com/pytest-dev/pytest/issues/2150 +.. _#2148: https://github.com/pytest-dev/pytest/issues/2148 3.0.5 (2016-12-05) diff --git a/_pytest/config.py b/_pytest/config.py index fe386ed0b..55326447e 100644 --- a/_pytest/config.py +++ b/_pytest/config.py @@ -1228,25 +1228,20 @@ def getcfg(args, warnfunc=None): return None, None, None -def get_common_ancestor(args): - # args are what we get after early command line parsing (usually - # strings, but can be py.path.local objects as well) +def get_common_ancestor(paths): common_ancestor = None - for arg in args: - if str(arg)[0] == "-": - continue - p = py.path.local(arg) - if not p.exists(): + for path in paths: + if not path.exists(): continue if common_ancestor is None: - common_ancestor = p + common_ancestor = path else: - if p.relto(common_ancestor) or p == common_ancestor: + if path.relto(common_ancestor) or path == common_ancestor: continue - elif common_ancestor.relto(p): - common_ancestor = p + elif common_ancestor.relto(path): + common_ancestor = path else: - shared = p.common(common_ancestor) + shared = path.common(common_ancestor) if shared is not None: common_ancestor = shared if common_ancestor is None: @@ -1257,9 +1252,29 @@ def get_common_ancestor(args): def get_dirs_from_args(args): - return [d for d in (py.path.local(x) for x in args - if not str(x).startswith("-")) - if d.exists()] + def is_option(x): + return str(x).startswith('-') + + def get_file_part_from_node_id(x): + return str(x).split('::')[0] + + def get_dir_from_path(path): + if path.isdir(): + return path + return py.path.local(path.dirname) + + # These look like paths but may not exist + possible_paths = ( + py.path.local(get_file_part_from_node_id(arg)) + for arg in args + if not is_option(arg) + ) + + return [ + get_dir_from_path(path) + for path in possible_paths + if path.exists() + ] def determine_setup(inifile, args, warnfunc=None): diff --git a/testing/test_config.py b/testing/test_config.py index 21ceab1e2..6bc867737 100644 --- a/testing/test_config.py +++ b/testing/test_config.py @@ -527,6 +527,29 @@ def test_toolongargs_issue224(testdir): result = testdir.runpytest("-m", "hello" * 500) assert result.ret == EXIT_NOTESTSCOLLECTED +def test_config_in_subdirectory_colon_command_line_issue2148(testdir): + conftest_source = ''' + def pytest_addoption(parser): + parser.addini('foo', 'foo') + ''' + + testdir.makefile('.ini', **{ + 'pytest': '[pytest]\nfoo = root', + 'subdir/pytest': '[pytest]\nfoo = subdir', + }) + + testdir.makepyfile(**{ + 'conftest': conftest_source, + 'subdir/conftest': conftest_source, + 'subdir/test_foo': ''' + def test_foo(pytestconfig): + assert pytestconfig.getini('foo') == 'subdir' + '''}) + + result = testdir.runpytest('subdir/test_foo.py::test_foo') + assert result.ret == 0 + + def test_notify_exception(testdir, capfd): config = testdir.parseconfig() excinfo = pytest.raises(ValueError, "raise ValueError(1)")