azure-cli-extensions: Dataprotection ModuleNotFoundError 'azure.mgmt.resourcegraph'
I understand that of course I could just install this missing module via pip3 as a hotfix. But, I also think this is not how this extension should behave in the first place. Is there maybe something missing during installation of the extension? Didn’t experience any ModuleNotFoundErrors before. Find below the ‘az feedback --verbose’ output with the list of my installed extensions, I manually noted which of them is a preview version.
Extension name (the extension in question)
dataprotection
Description of issue (in as much detail as possible)
- ModuleNotFoundError: No module named ‘azure.mgmt.resourcegraph’
- command: az dataprotection backup-instance --help
This is autogenerated. Please review and update as needed.
Describe the bug
az feedback --verbose
Command Name
az dataprotection backup-instance
Errors:
The command failed with an unexpected error. Here is the traceback:
No module named 'azure.mgmt.resourcegraph'
Traceback (most recent call last):
File "/usr/local/Cellar/azure-cli/2.32.0/libexec/lib/python3.10/site-packages/knack/cli.py", line 231, in invoke
cmd_result = self.invocation.execute(args)
File "/usr/local/Cellar/azure-cli/2.32.0/libexec/lib/python3.10/site-packages/azure/cli/core/commands/__init__.py", line 583, in execute
parsed_args = self.parser.parse_args(args)
File "/usr/local/Cellar/azure-cli/2.32.0/libexec/lib/python3.10/site-packages/knack/parser.py", line 261, in parse_args
return super().parse_args(args)
File "/usr/local/Cellar/python@3.10/3.10.1/Frameworks/Python.framework/Versions/3.10/lib/python3.10/argparse.py", line 1821, in parse_args
args, argv = self.parse_known_args(args, namespace)
File "/usr/local/Cellar/azure-cli/2.32.0/libexec/lib/python3.10/site-packages/azure/cli/core/parser.py", line 284, in parse_known_args
self._namespace, self._raw_arguments = super().parse_known_args(args=args, namespace=namespace)
File "/usr/local/Cellar/python@3.10/3.10.1/Frameworks/Python.framework/Versions/3.10/lib/python3.10/argparse.py", line 1854, in parse_known_args
namespace, args = self._parse_known_args(args, namespace)
File "/usr/local/Cellar/python@3.10/3.10.1/Frameworks/Python.framework/Versions/3.10/lib/python3.10/argparse.py", line 2045, in _parse_known_args
positionals_end_index = consume_positionals(start_index)
File "/usr/local/Cellar/python@3.10/3.10.1/Frameworks/Python.framework/Versions/3.10/lib/python3.10/argparse.py", line 2022, in consume_positionals
take_action(action, args)
File "/usr/local/Cellar/python@3.10/3.10.1/Frameworks/Python.framework/Versions/3.10/lib/python3.10/argparse.py", line 1931, in take_action
action(self, namespace, argument_values, option_string)
File "/usr/local/Cellar/python@3.10/3.10.1/Frameworks/Python.framework/Versions/3.10/lib/python3.10/argparse.py", line 1210, in __call__
subnamespace, arg_strings = parser.parse_known_args(arg_strings, None)
File "/usr/local/Cellar/azure-cli/2.32.0/libexec/lib/python3.10/site-packages/azure/cli/core/parser.py", line 284, in parse_known_args
self._namespace, self._raw_arguments = super().parse_known_args(args=args, namespace=namespace)
File "/usr/local/Cellar/python@3.10/3.10.1/Frameworks/Python.framework/Versions/3.10/lib/python3.10/argparse.py", line 1854, in parse_known_args
namespace, args = self._parse_known_args(args, namespace)
File "/usr/local/Cellar/python@3.10/3.10.1/Frameworks/Python.framework/Versions/3.10/lib/python3.10/argparse.py", line 2045, in _parse_known_args
positionals_end_index = consume_positionals(start_index)
File "/usr/local/Cellar/python@3.10/3.10.1/Frameworks/Python.framework/Versions/3.10/lib/python3.10/argparse.py", line 2022, in consume_positionals
take_action(action, args)
File "/usr/local/Cellar/python@3.10/3.10.1/Frameworks/Python.framework/Versions/3.10/lib/python3.10/argparse.py", line 1931, in take_action
action(self, namespace, argument_values, option_string)
File "/usr/local/Cellar/python@3.10/3.10.1/Frameworks/Python.framework/Versions/3.10/lib/python3.10/argparse.py", line 1210, in __call__
subnamespace, arg_strings = parser.parse_known_args(arg_strings, None)
File "/usr/local/Cellar/azure-cli/2.32.0/libexec/lib/python3.10/site-packages/azure/cli/core/parser.py", line 284, in parse_known_args
self._namespace, self._raw_arguments = super().parse_known_args(args=args, namespace=namespace)
File "/usr/local/Cellar/python@3.10/3.10.1/Frameworks/Python.framework/Versions/3.10/lib/python3.10/argparse.py", line 1854, in parse_known_args
namespace, args = self._parse_known_args(args, namespace)
File "/usr/local/Cellar/python@3.10/3.10.1/Frameworks/Python.framework/Versions/3.10/lib/python3.10/argparse.py", line 2063, in _parse_known_args
start_index = consume_optional(start_index)
File "/usr/local/Cellar/python@3.10/3.10.1/Frameworks/Python.framework/Versions/3.10/lib/python3.10/argparse.py", line 2003, in consume_optional
take_action(action, args, option_string)
File "/usr/local/Cellar/python@3.10/3.10.1/Frameworks/Python.framework/Versions/3.10/lib/python3.10/argparse.py", line 1931, in take_action
action(self, namespace, argument_values, option_string)
File "/usr/local/Cellar/python@3.10/3.10.1/Frameworks/Python.framework/Versions/3.10/lib/python3.10/argparse.py", line 1095, in __call__
parser.print_help()
File "/usr/local/Cellar/python@3.10/3.10.1/Frameworks/Python.framework/Versions/3.10/lib/python3.10/argparse.py", line 2551, in print_help
self._print_message(self.format_help(), file)
File "/usr/local/Cellar/azure-cli/2.32.0/libexec/lib/python3.10/site-packages/azure/cli/core/parser.py", line 195, in format_help
super(AzCliCommandParser, self).format_help()
File "/usr/local/Cellar/azure-cli/2.32.0/libexec/lib/python3.10/site-packages/knack/parser.py", line 248, in format_help
self.cli_help.show_help(self.prog.split()[0],
File "/usr/local/Cellar/azure-cli/2.32.0/libexec/lib/python3.10/site-packages/azure/cli/core/_help.py", line 165, in show_help
else self.group_help_cls(self, delimiters, parser)
File "/usr/local/Cellar/azure-cli/2.32.0/libexec/lib/python3.10/site-packages/knack/help.py", line 253, in __init__
child.load(options)
File "/usr/local/Cellar/azure-cli/2.32.0/libexec/lib/python3.10/site-packages/azure/cli/core/_help.py", line 303, in load
loader.versioned_load(self, options)
File "/usr/local/Cellar/azure-cli/2.32.0/libexec/lib/python3.10/site-packages/azure/cli/core/_help_loaders.py", line 154, in versioned_load
super(CliHelpFile, help_obj).load(parser) # pylint:disable=bad-super-call
File "/usr/local/Cellar/azure-cli/2.32.0/libexec/lib/python3.10/site-packages/knack/help.py", line 198, in load
description = getattr(options, 'description', None)
File "/usr/local/Cellar/azure-cli/2.32.0/libexec/lib/python3.10/site-packages/knack/parser.py", line 241, in __getattribute__
self.description = self._description() \
File "/usr/local/Cellar/azure-cli/2.32.0/libexec/lib/python3.10/site-packages/azure/cli/core/commands/command_operation.py", line 133, in description_loader
op = self.get_op_handler(self.op_path)
File "/usr/local/Cellar/azure-cli/2.32.0/libexec/lib/python3.10/site-packages/azure/cli/core/commands/command_operation.py", line 59, in get_op_handler
handler = import_module(mod_to_import)
File "/usr/local/Cellar/python@3.10/3.10.1/Frameworks/Python.framework/Versions/3.10/lib/python3.10/importlib/__init__.py", line 126, in import_module
return _bootstrap._gcd_import(name[level:], package, level)
File "<frozen importlib._bootstrap>", line 1050, in _gcd_import
File "<frozen importlib._bootstrap>", line 1027, in _find_and_load
File "<frozen importlib._bootstrap>", line 1006, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 688, in _load_unlocked
File "<frozen importlib._bootstrap_external>", line 883, in exec_module
File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed
File "/Users/NJ62KD/.azure/cliextensions/dataprotection/azext_dataprotection/custom.py", line 20, in <module>
raise e
File "/Users/NJ62KD/.azure/cliextensions/dataprotection/azext_dataprotection/custom.py", line 15, in <module>
from .manual.custom import * # noqa: F403
File "/Users/NJ62KD/.azure/cliextensions/dataprotection/azext_dataprotection/manual/custom.py", line 17, in <module>
from azure.mgmt.resourcegraph.models import \
ModuleNotFoundError: No module named 'azure.mgmt.resourcegraph'
To Reproduce:
Steps to reproduce the behavior. Note that argument values have been redacted, as they may contain sensitive information.
- install extension via first use (implicit) or via
az extension add -n dataprotection
(explicit). Both ways led to the same outcome. az dataprotection backup-instance -h
or anyaz dataprotection backup-instance
subcommand.
Expected Behavior
Shows help output.
Environment Summary
macOS-12.2.1-x86_64-i386-64bit, Darwin 21.3.0
Python 3.10.1
Installer: HOMEBREW
azure-cli 2.32.0 *
Extensions:
front-door 1.0.16
alertsmanagement 0.1.1
logic 0.1.5 (manual note: preview)
resource-graph 2.1.0
sentinel 0.1.1
ssh 1.0.0 (manual note: preview)
dataprotection 0.2.0
application-insights 0.1.14 (manual note: preview)
Dependencies:
msal 1.16.0
azure-mgmt-resource 20.0.0
Additional Context
About this issue
- Original URL
- State: closed
- Created 2 years ago
- Comments: 15 (11 by maintainers)
This problem also happens in a virtual env, but not Azure CLI installed with MSI or DEB:
I tested with a sample script:
System python:
Virtual env python:
In a virtual env which installs Azure CLI from source code, under
azure
andazure/mgmt
folders, there are__init__.py
files containing one line:These files make
azure
andazure.mgmt
normal (non-namespace) packages, preventing Python from looking up additional library folders.Cause
Even though https://github.com/Azure/azure-cli/pull/13163 added the support to load
azure.mgmt
from extension installation folder:https://github.com/Azure/azure-cli/blob/e2f55ec7de8ff0b19c05e082d408992ac1a1139c/src/azure-cli-core/azure/cli/core/extension/operations.py#L501-L521
it is not used in core’s extension loading process (but in other modules like network):
https://github.com/Azure/azure-cli/blob/af0c73a37ca3f540cb0b3f0b18e0f362932ab191/src/azure-cli-core/azure/cli/core/__init__.py#L351
We can show what
azure
really is at this time:Because
azure
has already been loaded, addingext_dir
won’t affect existingazure
module.Solution
The common practice is to put SDKs in a
vendored_sdks
folder, instead of installing from PyPI.To my surprise, this extension was added by #3459 (Jun 3, 2021) but this bug is never discovered.
Let me clarify 2 things:
python3
’simport
won’t work because Azure CLI runs in an isolated virtual env, meaning it doesn’t share system’s python packages.python3
’s execution is a separate process, so even you can doimport
withpython3
, thisimport
statement only affects the currentpython3
process, so it doesn’t affect otherpython3
executions likeaz dataprotection backup-instance
.I am also able to reproduce this issue on Windows: