Repository: conan-io/conan
Pull request #18452 (2025-06-11 17:24:05)

Add test to verify that we always call parse_args for every command
Changelog: Omit
Docs: Omit

Follow-up to https://github.com/conan-io/conan/issues/18446


Patch:
diff --git a/conan/cli/commands/editable.py b/conan/cli/commands/editable.py
index 1653845be..23679fc65 100644
--- a/conan/cli/commands/editable.py
+++ b/conan/cli/commands/editable.py
@@ -77,5 +77,6 @@ def editable_list(conan_api, parser, subparser, *args):
     """
     List all the packages in editable mode.
     """
+    parser.parse_args(*args)
     editables = conan_api.local.editable_list()
     return editables
diff --git a/conan/cli/commands/profile.py b/conan/cli/commands/profile.py
index 68c32b943..236ef3f4f 100644
--- a/conan/cli/commands/profile.py
+++ b/conan/cli/commands/profile.py
@@ -103,6 +103,7 @@ def profile_list(conan_api, parser, subparser, *args):  # noqa
     """
     List all profiles in the cache.
     """
+    parser.parse_args(*args)
     result = conan_api.profiles.list()
     return result
 
diff --git a/conan/cli/commands/remote.py b/conan/cli/commands/remote.py
index 3cb5ab50b..671ecf75b 100644
--- a/conan/cli/commands/remote.py
+++ b/conan/cli/commands/remote.py
@@ -170,6 +170,7 @@ def remote_list_users(conan_api, parser, subparser, *args):  # noqa
     """
     List the users logged into all the remotes.
     """
+    parser.parse_args(*args)
     remotes = conan_api.remotes.list()
     ret = OrderedDict()
     if not remotes:
diff --git a/conan/cli/commands/version.py b/conan/cli/commands/version.py
index b2509afef..f7b8ee7ee 100644
--- a/conan/cli/commands/version.py
+++ b/conan/cli/commands/version.py
@@ -11,6 +11,7 @@ def version(conan_api, parser, *args):
     """
     Give information about the Conan client version.
     """
+    parser.parse_args(*args)
 
     return {
             'version': str(conan_version),
diff --git a/conan/cli/commands/workspace.py b/conan/cli/commands/workspace.py
index f1ea664e1..9704ad2df 100644
--- a/conan/cli/commands/workspace.py
+++ b/conan/cli/commands/workspace.py
@@ -18,6 +18,7 @@ def workspace_root(conan_api: ConanAPI, parser, subparser, *args):  # noqa
     """
     Return the folder containing the conanws.py/conanws.yml workspace file
     """
+    parser.parse_args(*args)
     ws = conan_api.workspace
     if not ws.folder():
         raise ConanException("No workspace defined, conanws.py file not found")
@@ -101,6 +102,7 @@ def workspace_info(conan_api: ConanAPI, parser, subparser, *args):  # noqa
     """
     Display info for current workspace
     """
+    parser.parse_args(*args)
     return {"info": conan_api.workspace.info()}
 
 


Test patch:
diff --git a/test/integration/command/help_test.py b/test/integration/command/help_test.py
index 2af1c84a0..25bb560bf 100644
--- a/test/integration/command/help_test.py
+++ b/test/integration/command/help_test.py
@@ -1,4 +1,10 @@
+import argparse
+
+import pytest
+from mock import patch
+
 from conan import __version__
+from conan.test.utils.env import environment_update
 from conan.test.utils.tools import TestClient
 
 
@@ -43,3 +49,30 @@ class TestHelp:
         assert "Perform file operations in the local cache (of recipes and/or packages)" in c.out
         c.run("cache path -h")
         assert "Show the path to the Conan cache for a given reference" in c.out
+
+
+def test_all_commands_call_args_parse():
+    tc = TestClient(light=True)
+    tc.run("-h")
+    commands = tc.api.command.cli._builtin_commands
+    with environment_update({"CONAN_WORKSPACE_ENABLE": "will_break_next"}):
+        for command, info in commands.items():
+            if len(info._subcommands) > 0:
+                for subcommand in info._subcommands.values():
+                    with patch("conan.cli.command.ConanArgumentParser.parse_args",
+                               side_effect=Exception("called")) as mock_run:
+                        try:
+                            tc.run(f"{command} {subcommand.name} -h")
+                        except:
+                            pass
+                        finally:
+                            assert mock_run.called, f'Command "conan {command} {subcommand.name}" did not call parse_args()'
+            else:
+                with patch("conan.cli.command.ConanArgumentParser.parse_args",
+                           side_effect=Exception("called")) as mock_run:
+                    try:
+                        tc.run(f"{command} -h")
+                    except:
+                        pass
+                    finally:
+                        assert mock_run.called, f'Command "conan {command}" did not call parse_args()'