Skip to content

conda shell.posix <invalid-arg> raises exception instead of returning an error message #14397

@travishathaway

Description

@travishathaway

Checklist

  • I added a descriptive title
  • I searched open reports and couldn't find a duplicate

What happened?

When running the following command:

conda shell.posix blah

I get the following exception:

# >>>>>>>>>>>>>>>>>>>>>> ERROR REPORT <<<<<<<<<<<<<<<<<<<<<<

    Traceback (most recent call last):
      File "/Users/user_name/dev/conda/conda/exception_handler.py", line 18, in __call__
        return func(*args, **kwargs)
      File "/Users/user_name/dev/conda/conda/cli/main.py", line 87, in main_sourced
        print(activator.execute(), end="")
      File "/Users/user_name/dev/conda/conda/activate.py", line 234, in execute
        self._parse_and_set_args()
      File "/Users/user_name/dev/conda/conda/deprecations.py", line 174, in inner
        return func(*args, **kwargs)
      File "/Users/user_name/dev/conda/conda/activate.py", line 288, in _parse_and_set_args
        raise ArgumentError(
    UnboundLocalError: local variable 'ArgumentError' referenced before assignment

`$ /Users/user_name/dev/conda/devenv/Darwin/arm64/envs/devenv-3.10-c/bin/conda shell.posix balh`

This is happening because we think that we have imported the exception class here:

from .exceptions import ActivateHelp, ArgumentError, DeactivateHelp, GenericHelp

But, we later re-import the exception class in this method:

conda/conda/activate.py

Lines 280 to 345 in d16eb29

def _parse_and_set_args(self) -> None:
command, *arguments = self._raw_arguments or [None]
help_flags = ("-h", "--help", "/?")
non_help_args = tuple(arg for arg in arguments if arg not in help_flags)
help_requested = len(arguments) != len(non_help_args)
remainder_args = list(arg for arg in non_help_args if arg and arg != command)
if command not in BUILTIN_COMMANDS:
raise ArgumentError(
"'activate', 'deactivate', 'hook', 'commands', or 'reactivate' "
"command must be given." + (f", not '{command}'." if command else ".")
)
elif help_requested:
raise BUILTIN_COMMANDS[command]
if command.endswith("activate") or command == "hook":
try:
dev_idx = remainder_args.index("--dev")
except ValueError:
context.dev = False
else:
del remainder_args[dev_idx]
context.dev = True
if command == "activate":
self.stack = context.auto_stack and context.shlvl <= context.auto_stack
try:
stack_idx = remainder_args.index("--stack")
except ValueError:
stack_idx = -1
try:
no_stack_idx = remainder_args.index("--no-stack")
except ValueError:
no_stack_idx = -1
if stack_idx >= 0 and no_stack_idx >= 0:
from .exceptions import ArgumentError
raise ArgumentError(
"cannot specify both --stack and --no-stack to " + command
)
if stack_idx >= 0:
self.stack = True
del remainder_args[stack_idx]
if no_stack_idx >= 0:
self.stack = False
del remainder_args[no_stack_idx]
if len(remainder_args) > 1:
from .exceptions import ArgumentError
raise ArgumentError(
command
+ " does not accept more than one argument:\n"
+ str(remainder_args)
+ "\n"
)
self.env_name_or_prefix = remainder_args and remainder_args[0] or "base"
else:
if remainder_args:
from .exceptions import ArgumentError
raise ArgumentError(
f"{command} does not accept arguments\nremainder_args: {remainder_args}\n"
)
self.command = command

By doing the imports later, we must be binding the ArgumentError class definition to the local scope of that function. This is what causes Python to completely ignore and not use the class definition from the outer scope (i.e. the module's scope).

The fix is easy enough: we just need to remove those other import statements. But this reveals that we do not have enough coverage for this file 😦. Let's fix that!

Conda Info

n/a

Conda Config

n/a

Conda list

n/a

Additional Context

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    locked[bot] locked due to inactivityplugins::activatepertains to conda-activate or conda-deactivateseverity::4low; functionality is inconvenientsource::anacondacreated by members of Anaconda, Inc.type::bugdescribes erroneous operation, use severity::* to classify the type

    Type

    No type

    Projects

    Status

    🏁 Done

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions