Skip to content

Conflicting custom arguments bugfix #12824 #13393

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions AUTHORS
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ Andrzej Klajnert
Andrzej Ostrowski
Andy Freeland
Anita Hammer
Anna Tasiopoulou
Anthon van der Neut
Anthony Shaw
Anthony Sottile
Expand Down
2 changes: 2 additions & 0 deletions changelog/12824.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Improve option conflict detection to prevent silently overriding built-in options
like ``--keyword``.
39 changes: 23 additions & 16 deletions src/_pytest/config/argparsing.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,22 +85,6 @@ def getgroup(
self._groups.insert(i + 1, group)
return group

def addoption(self, *opts: str, **attrs: Any) -> None:
"""Register a command line option.

:param opts:
Option names, can be short or long options.
:param attrs:
Same attributes as the argparse library's :meth:`add_argument()
<argparse.ArgumentParser.add_argument>` function accepts.

After command line parsing, options are available on the pytest config
object via ``config.option.NAME`` where ``NAME`` is usually set
by passing a ``dest`` attribute, for example
``addoption("--long", dest="NAME", ...)``.
"""
self._anonymous.addoption(*opts, **attrs)

def parse(
self,
args: Sequence[str | os.PathLike[str]],
Expand Down Expand Up @@ -232,6 +216,29 @@ def addini(
self._inidict[name] = (help, type, default)
self._ininames.append(name)

def addoption(self, *opts: str, **attrs: Any) -> None:
"""Add an option to this parser."""
# Check for conflicts with built-in options
builtin_options = {
"--keyword",
"-k",
# Add other built-in options here
}

# Check if any of the provided options conflict with built-in ones
conflict = set(opts).intersection(builtin_options)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

instead of tracking builtin ones, we really should track registrations and warn/error early

currently what we do is defer errors to when we compose argparse

if conflict:
raise ValueError(
f"option names {conflict} conflict with existing registered options"
)

# Proceed with original implementation
if hasattr(self, "_anonymous"):
self._anonymous.addoption(*opts, **attrs)
else:
parser = self._getparser()
parser.add_argument(*opts, **attrs)


def get_ini_default_for_type(
type: Literal[
Expand Down
26 changes: 26 additions & 0 deletions testing/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -2537,3 +2537,29 @@ def test_level_matches_specified_override(
config.get_verbosity(TestVerbosity.SOME_OUTPUT_TYPE)
== TestVerbosity.SOME_OUTPUT_VERBOSITY_LEVEL
)


def test_conflicting_option_raises_error(pytester):
"""Test that adding conflicting options raises a clear error."""
pytester.makepyfile(
"""
def test_dummy():
pass
"""
)

pytester.makeconftest(
"""
def pytest_addoption(parser):

# This should raise a ValueError because --keyword already exists in pytest
parser.addoption("--keyword", action="store", default="False",

help="Conflicting option with built-in -k/--keyword")
"""
)

result = pytester.runpytest()
result.stderr.fnmatch_lines(
["*option names*--keyword*conflict with existing registered options*"]
)