From 5ccd3f2fc51adc022196fcbf0765a0bc78efe3c8 Mon Sep 17 00:00:00 2001 From: holger krekel Date: Mon, 28 Jul 2014 11:48:37 +0200 Subject: [PATCH 1/4] fix conftest detection if commandline arguments contain "::" syntax --HG-- branch : fix_initial_parsing --- CHANGELOG | 3 +++ _pytest/config.py | 5 +++++ testing/test_conftest.py | 18 ++++++++++++++++++ 3 files changed, 26 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index b49cea8b8..cd7ec0ca5 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -9,6 +9,9 @@ NEXT - fix integration of pytest with unittest.mock.patch decorator when it uses the "new" argument. Thanks Nicolas Delaby for test and PR. +- fix issue with detecting conftest files if the arguments contain + "::" node id specifications (copy pasted from "-v" output) + 2.6 ----------------------------------- diff --git a/_pytest/config.py b/_pytest/config.py index 51f178862..80a0c2c26 100644 --- a/_pytest/config.py +++ b/_pytest/config.py @@ -485,6 +485,11 @@ class Conftest(object): testpaths = namespace.file_or_dir foundanchor = False for path in testpaths: + path = str(path) + # remove node-id syntax + i = path.find("::") + if i != -1: + path = path[:i] anchor = current.join(path, abs=1) if exists(anchor): # we found some file object self._try_load_conftest(anchor) diff --git a/testing/test_conftest.py b/testing/test_conftest.py index 96df19550..8bf936dbe 100644 --- a/testing/test_conftest.py +++ b/testing/test_conftest.py @@ -237,3 +237,21 @@ def test_fixture_dependency(testdir, monkeypatch): """)) result = testdir.runpytest("sub") result.stdout.fnmatch_lines(["*1 passed*"]) + + +def test_conftest_found_with_double_dash(testdir): + sub = testdir.mkdir("sub") + sub.join("conftest.py").write(py.std.textwrap.dedent(""" + def pytest_addoption(parser): + parser.addoption("--hello-world", action="store_true") + """)) + p = sub.join("test_hello.py") + p.write(py.std.textwrap.dedent(""" + import pytest + def test_hello(found): + assert found == 1 + """)) + result = testdir.runpytest(str(p) + "@2::test_hello", "-h") + result.stdout.fnmatch_lines(""" + *--hello-world* + """) From 40eed363e8c0b699d71509ec4cd8ebfb05af954d Mon Sep 17 00:00:00 2001 From: holger krekel Date: Mon, 28 Jul 2014 12:07:15 +0200 Subject: [PATCH 2/4] fix issue544 by only removing "@NUM" at the end of a part (parts are separated by "::") and if the part has an .py extension. --HG-- branch : fix_initial_parsing --- CHANGELOG | 2 ++ _pytest/config.py | 10 +++++++--- testing/test_parseopt.py | 13 +++++++++++-- 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index cd7ec0ca5..ac2a6e686 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -12,6 +12,8 @@ NEXT - fix issue with detecting conftest files if the arguments contain "::" node id specifications (copy pasted from "-v" output) +- fix issue544 by only removing "@NUM" at the end of "::" separated parts + and if the part has an ".py" extension 2.6 ----------------------------------- diff --git a/_pytest/config.py b/_pytest/config.py index 80a0c2c26..0b04ff1cc 100644 --- a/_pytest/config.py +++ b/_pytest/config.py @@ -863,9 +863,13 @@ def getcfg(args, inibasenames): def node_with_line_number(string): - split = string.split('[') - split[0] = re.sub(r'@\d+', '', split[0]) - return '['.join(split) + newparts = [] + for part in string.split("::"): + m = re.match(r'.*\.py@\d+$', part) + if m is not None: + part = part[:part.rfind("@")] + newparts.append(part) + return "::".join(newparts) def setns(obj, dic): diff --git a/testing/test_parseopt.py b/testing/test_parseopt.py index 2e19a90f4..360bbd13b 100644 --- a/testing/test_parseopt.py +++ b/testing/test_parseopt.py @@ -146,8 +146,17 @@ class TestParser: assert args.S == False def test_parse_removes_line_number_from_positional_arguments(self, parser): - args = parser.parse(['path@2::func', 'path2@5::func2[param with @]']) - assert getattr(args, parseopt.FILE_OR_DIR) == ['path::func', 'path2::func2[param with @]'] + args = parser.parse(['path.txt@2::item', + 'path2.py::func2[param with .py@123]', + 'path.py@123', + 'hello/path.py@123', + ]) + assert getattr(args, parseopt.FILE_OR_DIR) == [ + 'path.txt@2::item', + 'path2.py::func2[param with .py@123]', + 'path.py', + 'hello/path.py', + ] def test_parse_defaultgetter(self): def defaultget(option): From 83e0b522945a22da99d12885e058033105351b62 Mon Sep 17 00:00:00 2001 From: holger krekel Date: Mon, 28 Jul 2014 13:53:53 +0200 Subject: [PATCH 3/4] speedup @ replacement for the massive lists from pytest-bdd :) --HG-- branch : fix_initial_parsing --- _pytest/config.py | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/_pytest/config.py b/_pytest/config.py index 0b04ff1cc..1eeb6b3b7 100644 --- a/_pytest/config.py +++ b/_pytest/config.py @@ -862,14 +862,11 @@ def getcfg(args, inibasenames): return {} +rex_pyat = re.compile(r'(.*\.py)@\d+$') + def node_with_line_number(string): - newparts = [] - for part in string.split("::"): - m = re.match(r'.*\.py@\d+$', part) - if m is not None: - part = part[:part.rfind("@")] - newparts.append(part) - return "::".join(newparts) + return "::".join(rex_pyat.sub(lambda m: m.group(1), part) + for part in string.split("::")) def setns(obj, dic): From 0d17dc1e194494c485ec399a9196f4ff8636cd82 Mon Sep 17 00:00:00 2001 From: holger krekel Date: Mon, 28 Jul 2014 13:56:10 +0200 Subject: [PATCH 4/4] add a comment for why we only consider .py files when removing @ --HG-- branch : fix_initial_parsing --- testing/test_parseopt.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/testing/test_parseopt.py b/testing/test_parseopt.py index 360bbd13b..36defef2c 100644 --- a/testing/test_parseopt.py +++ b/testing/test_parseopt.py @@ -151,11 +151,13 @@ class TestParser: 'path.py@123', 'hello/path.py@123', ]) + # we only remove "@NUM" syntax for .py files which are currently + # the only ones which can produce it. assert getattr(args, parseopt.FILE_OR_DIR) == [ - 'path.txt@2::item', - 'path2.py::func2[param with .py@123]', - 'path.py', - 'hello/path.py', + 'path.txt@2::item', + 'path2.py::func2[param with .py@123]', + 'path.py', + 'hello/path.py', ] def test_parse_defaultgetter(self):