From 0fb58e0978918e54013f83873156d222038201cc Mon Sep 17 00:00:00 2001 From: Himanshu Date: Mon, 19 Oct 2026 14:36:47 +0530 Subject: [PATCH 1/2] Handle brackets in collection file paths Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- AUTHORS | 1 + src/_pytest/main.py | 16 ++++++++++++---- testing/test_main.py | 17 +++++++++++++++++ 3 files changed, 30 insertions(+), 4 deletions(-) diff --git a/AUTHORS b/AUTHORS index bd1e27cb37d..42942c8c84b 100644 --- a/AUTHORS +++ b/AUTHORS @@ -211,6 +211,7 @@ Harald Armin Massa Harshna Henk-Jaap Wagenaar Henry Schreiner +Himanshu Holger Kohr Hugo van Kemenade Hui Wang (coldnight) diff --git a/src/_pytest/main.py b/src/_pytest/main.py index d43a68b4679..554db2dfbeb 100644 --- a/src/_pytest/main.py +++ b/src/_pytest/main.py @@ -1152,11 +1152,19 @@ def resolve_collection_argument( If the path doesn't exist, raise UsageError. If the path is a directory and selection parts are present, raise UsageError. """ - base, squacket, rest = arg.partition("[") - strpath, *parts = base.split("::") - if squacket and not parts: + selection_start = arg.find("::") + strpath = arg if selection_start == -1 else arg[:selection_start] + if "[" in strpath and not safe_exists(absolutepath(invocation_path / strpath)): raise UsageError(f"path cannot contain [] parametrization: {arg}") - parametrization = f"{squacket}{rest}" if squacket else None + + path_and_parts = arg + parametrization = None + if selection_start != -1: + parametrization_start = arg.find("[", selection_start + 2) + if parametrization_start != -1: + path_and_parts = arg[:parametrization_start] + parametrization = arg[parametrization_start:] + strpath, *parts = path_and_parts.split("::") module_name = None if as_pypath: pyarg_strpath = search_pypath( diff --git a/testing/test_main.py b/testing/test_main.py index 41d7055df26..46fcb3b648b 100644 --- a/testing/test_main.py +++ b/testing/test_main.py @@ -166,6 +166,23 @@ def test_file(self, invocation_path: Path) -> None: original_index=40, ) + def test_file_with_brackets_in_name( + self, invocation_path: Path, pytester: Pytester + ) -> None: + path = invocation_path / "src/pkg/test_[helper].py" + path.write_text("def test_example(): pass\n", encoding="utf-8") + + assert resolve_collection_argument(invocation_path, str(path), 0) == ( + CollectionArgument( + path=path, + parts=[], + parametrization=None, + module_name=None, + original_index=0, + ) + ) + pytester.runpytest(str(path)).assert_outcomes(passed=1) + def test_dir(self, invocation_path: Path) -> None: """Directory and parts.""" assert resolve_collection_argument( From d9ba697f395b5d5b2609c6f8ddf05615e6bfd23e Mon Sep 17 00:00:00 2001 From: Himanshu Date: Mon, 19 Oct 2026 15:10:46 +0530 Subject: [PATCH 2/2] Add changelog for PR 15217 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- changelog/15217.bugfix.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog/15217.bugfix.rst diff --git a/changelog/15217.bugfix.rst b/changelog/15217.bugfix.rst new file mode 100644 index 00000000000..f81a7b2f07d --- /dev/null +++ b/changelog/15217.bugfix.rst @@ -0,0 +1 @@ +Fixed test collection for Python files whose names contain square brackets.