66
77# SPDX-License-Identifier: BSD-3-Clause
88
9+ from __future__ import annotations
10+
911import shlex
1012from argparse import SUPPRESS , ArgumentParser , BooleanOptionalAction , Namespace
11- from typing import Any , Optional
13+ from typing import Any
1214
1315import pytest
1416
@@ -128,6 +130,30 @@ def test_strip_first_line() -> None:
128130 assert strip_first_line ("foo\n bar\n baz" ) == "bar\n baz"
129131
130132
133+ def remove_pytest_prefix (input_string : str ) -> str :
134+ """
135+ Remove ``-m pytest`` from the start of a space-delimited string.
136+
137+ In Python 3.14, pytest now uses the ``__main__`` module's
138+ ``__file__`` attribute to determine the entry point of the test run.
139+ This causes a command line invocation to include the pytest runner's
140+ arguments, which we then need to remove before comparing to expected
141+ output.
142+
143+ Args:
144+ input_string: The string to remove the prefix from.
145+
146+ Returns:
147+ The string without the prefix.
148+ """
149+ return input_string .removeprefix ("-m pytest" ).strip ()
150+
151+ def test_remove_pytest_prefix () -> None :
152+ """Ensure :func:`remove_pytest_prefix` works as expected."""
153+ assert remove_pytest_prefix ("-m pytest foo bar baz" ) == "foo bar baz"
154+ assert remove_pytest_prefix ("-m pytest" ) == ""
155+
156+
131157@pytest .mark .parametrize ("args" , COMPLETE_ARGS )
132158def test_get_effective_command_line_invocation (
133159 parser : ArgumentParser , args : str
@@ -143,8 +169,10 @@ def test_get_effective_command_line_invocation(
143169 "app-nargs2-val --const --app-const1 --app-const2 -vv --ext ext-val1 "
144170 "ext-val2 ext-val3 --no-bool-opt pos1-val1 pos1-val2 pos2-val"
145171 )
146- result = strip_first_entry (
147- unparser .get_effective_command_line_invocation ()
172+ result = remove_pytest_prefix (
173+ strip_first_entry (
174+ unparser .get_effective_command_line_invocation ()
175+ )
148176 )
149177 assert result == expected
150178
@@ -293,8 +321,10 @@ def test__arg_is_default_and_help_is_suppressed() -> None:
293321 parser .add_argument ("--suppressed" , default = 10 , help = SUPPRESS )
294322 namespace = parser .parse_args (shlex .split ("" ))
295323 unparser = ReverseArgumentParser (parser , namespace )
296- result = strip_first_entry (
297- unparser .get_effective_command_line_invocation ()
324+ result = remove_pytest_prefix (
325+ strip_first_entry (
326+ unparser .get_effective_command_line_invocation ()
327+ )
298328 )
299329 assert result == ""
300330
@@ -435,7 +465,7 @@ def test__unparse_store_const_action(
435465 ("args" , "expected" ), [(shlex .split ("--foo" ), " --foo" ), ([], None )]
436466)
437467def test__unparse_store_true_action (
438- args : list [str ], expected : Optional [ str ]
468+ args : list [str ], expected : str | None
439469) -> None :
440470 """Ensure ``store_true`` actions are handled appropriately."""
441471 parser = ArgumentParser ()
@@ -450,7 +480,7 @@ def test__unparse_store_true_action(
450480 ("args" , "expected" ), [(shlex .split ("--foo" ), " --foo" ), ([], None )]
451481)
452482def test__unparse_store_false_action (
453- args : list [str ], expected : Optional [ str ]
483+ args : list [str ], expected : str | None
454484) -> None :
455485 """Ensure ``store_false`` actions are handled appropriately."""
456486 parser = ArgumentParser ()
@@ -496,9 +526,7 @@ def test__unparse_append_action(
496526@pytest .mark .parametrize (
497527 ("args" , "expected" ), [("--foo" , " --foo" ), ("" , None )]
498528)
499- def test__unparse_append_const_action (
500- args : str , expected : Optional [str ]
501- ) -> None :
529+ def test__unparse_append_const_action (args : str , expected : str | None ) -> None :
502530 """Ensure ``append_const`` actions are handled appropriately."""
503531 parser = ArgumentParser ()
504532 action = parser .add_argument (
@@ -570,8 +598,10 @@ def test__unparse_sub_parsers_action(
570598 namespace = parser .parse_args (shlex .split (args ))
571599 unparser = ReverseArgumentParser (parser , namespace )
572600 unparser ._unparse_args ()
573- result = strip_first_entry (
574- unparser .get_effective_command_line_invocation ()
601+ result = remove_pytest_prefix (
602+ strip_first_entry (
603+ unparser .get_effective_command_line_invocation ()
604+ )
575605 )
576606 assert result == expected
577607 result = strip_first_line (unparser .get_pretty_command_line_invocation ())
@@ -612,8 +642,10 @@ def test__unparse_sub_parsers_action_nested() -> None:
612642 namespace = parser .parse_args (shlex .split (args ))
613643 unparser = ReverseArgumentParser (parser , namespace )
614644 unparser ._unparse_args ()
615- result = strip_first_entry (
616- unparser .get_effective_command_line_invocation ()
645+ result = remove_pytest_prefix (
646+ strip_first_entry (
647+ unparser .get_effective_command_line_invocation ()
648+ )
617649 )
618650 assert result == args
619651 result = strip_first_line (unparser .get_pretty_command_line_invocation ())
@@ -646,9 +678,9 @@ def test__unparse_extend_action() -> None:
646678 ],
647679)
648680def test__unparse_boolean_optional_action (
649- default : Optional [ bool ] , # noqa: FBT001
681+ default : bool | None , # noqa: FBT001
650682 args : str ,
651- expected : Optional [ str ] ,
683+ expected : str | None ,
652684) -> None :
653685 """Ensure ``BooleanOptionalAction`` actions are handled appropriately."""
654686 parser = ArgumentParser ()
0 commit comments