def test_get_extension_modname_file_with_prefix(self): # We should only file a module if it's a directory and not a file even if it has the prefix tmp_dir = tempfile.mkdtemp() filename = EXTENSIONS_MOD_PREFIX + 'helloworld' open(os.path.join(tmp_dir, filename), 'a').close() with self.assertRaises(AssertionError): get_extension_modname(ext_dir=tmp_dir)
def test_get_extension_modname_too_many_mods_with_prefix(self): tmp_dir = tempfile.mkdtemp() modname1 = EXTENSIONS_MOD_PREFIX + 'helloworldmod1' modname2 = EXTENSIONS_MOD_PREFIX + 'helloworldmod2' os.makedirs(os.path.join(tmp_dir, modname1)) os.makedirs(os.path.join(tmp_dir, modname2)) with self.assertRaises(AssertionError): get_extension_modname(ext_dir=tmp_dir)
def _filter_modname(extensions): # Extension's name may not be the same as its modname. eg. name: virtual-wan, modname: azext_vwan filtered_extensions = [] for ext in extensions: ext_mod = get_extension_modname(ext.name, ext.path) # Filter the extensions according to the index if ext_mod in extension_modname: filtered_extensions.append(ext) extension_modname.remove(ext_mod) if extension_modname: logger.debug( "These extensions are not installed and will be skipped: %s", extension_modname) return filtered_extensions
def _update_command_table_from_extensions(ext_suppressions): def _handle_extension_suppressions(extensions): filtered_extensions = [] for ext in extensions: should_include = True for suppression in ext_suppressions: if should_include and suppression.handle_suppress(ext): should_include = False if should_include: filtered_extensions.append(ext) return filtered_extensions extensions = get_extensions() if extensions: logger.debug("Found %s extensions: %s", len(extensions), [e.name for e in extensions]) allowed_extensions = _handle_extension_suppressions(extensions) module_commands = set(self.command_table.keys()) for ext in allowed_extensions: ext_name = ext.name ext_dir = get_extension_path(ext_name) sys.path.append(ext_dir) try: ext_mod = get_extension_modname(ext_name, ext_dir=ext_dir) # Add to the map. This needs to happen before we load commands as registering a command # from an extension requires this map to be up-to-date. # self._mod_to_ext_map[ext_mod] = ext_name start_time = timeit.default_timer() extension_command_table, extension_group_table = \ _load_extension_command_loader(self, args, ext_mod) for cmd_name, cmd in extension_command_table.items(): cmd.command_source = ExtensionCommandSource( extension_name=ext_name, overrides_command=cmd_name in module_commands, preview=ext.preview) self.command_table.update(extension_command_table) self.command_group_table.update(extension_group_table) elapsed_time = timeit.default_timer() - start_time logger.debug("Loaded extension '%s' in %.3f seconds.", ext_name, elapsed_time) except Exception: # pylint: disable=broad-except self.cli_ctx.raise_event(EVENT_FAILED_EXTENSION_LOAD, extension_name=ext_name) logger.warning( "Unable to load extension '%s'. Use --debug for more information.", ext_name) logger.debug(traceback.format_exc())
def start_shell(cmd, update=None, style=None): from importlib import import_module try: get_extension(INTERACTIVE_EXTENSION_NAME) if update: logger.warning("Updating the Interactive extension to the latest available..") update_extension(INTERACTIVE_EXTENSION_NAME) reload_extension(INTERACTIVE_EXTENSION_NAME) except ExtensionNotInstalledException: logger.warning("Installing the Interactive extension..") add_extension(extension_name=INTERACTIVE_EXTENSION_NAME) add_extension_to_path(INTERACTIVE_EXTENSION_NAME) interactive_module = get_extension_modname(ext_name=INTERACTIVE_EXTENSION_NAME) azext_interactive = import_module(interactive_module) azext_interactive.start_shell(cmd, style=style)
def _update_command_table_from_extensions(ext_suppressions): def _handle_extension_suppressions(extensions): filtered_extensions = [] for ext in extensions: should_include = True for suppression in ext_suppressions: if should_include and suppression.handle_suppress(ext): should_include = False if should_include: filtered_extensions.append(ext) return filtered_extensions extensions = get_extensions() if extensions: logger.debug("Found %s extensions: %s", len(extensions), [e.name for e in extensions]) allowed_extensions = _handle_extension_suppressions(extensions) module_commands = set(self.command_table.keys()) for ext in allowed_extensions: ext_name = ext.name ext_dir = ext.path or get_extension_path(ext_name) sys.path.append(ext_dir) try: ext_mod = get_extension_modname(ext_name, ext_dir=ext_dir) # Add to the map. This needs to happen before we load commands as registering a command # from an extension requires this map to be up-to-date. # self._mod_to_ext_map[ext_mod] = ext_name start_time = timeit.default_timer() extension_command_table, extension_group_table = \ _load_extension_command_loader(self, args, ext_mod) for cmd_name, cmd in extension_command_table.items(): cmd.command_source = ExtensionCommandSource( extension_name=ext_name, overrides_command=cmd_name in module_commands, preview=ext.preview) self.command_table.update(extension_command_table) self.command_group_table.update(extension_group_table) elapsed_time = timeit.default_timer() - start_time logger.debug("Loaded extension '%s' in %.3f seconds.", ext_name, elapsed_time) except Exception: # pylint: disable=broad-except self.cli_ctx.raise_event(EVENT_FAILED_EXTENSION_LOAD, extension_name=ext_name) logger.warning("Unable to load extension '%s'. Use --debug for more information.", ext_name) logger.debug(traceback.format_exc())
def start_shell(cmd, update=None, style=None): from importlib import import_module try: get_extension(INTERACTIVE_EXTENSION_NAME) if update: logger.warning( "Updating the Interactive extension to the latest available..") update_extension(INTERACTIVE_EXTENSION_NAME) reload_extension(INTERACTIVE_EXTENSION_NAME) except ExtensionNotInstalledException: logger.warning("Installing the Interactive extension..") add_extension(extension_name=INTERACTIVE_EXTENSION_NAME) add_extension_to_path(INTERACTIVE_EXTENSION_NAME) interactive_module = get_extension_modname( ext_name=INTERACTIVE_EXTENSION_NAME) azext_interactive = import_module(interactive_module) azext_interactive.start_shell(cmd, style=style)
def get_extension_modules(): from importlib import import_module import pkgutil from azure.cli.core.extension import get_extensions, get_extension_path, get_extension_modname extension_whls = get_extensions() ext_modules = [] if extension_whls: for ext_name in [e.name for e in extension_whls]: ext_dir = get_extension_path(ext_name) sys.path.append(ext_dir) try: ext_mod = get_extension_modname(ext_name, ext_dir=ext_dir) module = import_module(ext_mod) setattr(module, 'path', module.__path__[0]) ext_modules.append((module, ext_mod)) except Exception as ex: display("Error importing '{}' extension: {}".format(ext_mod, ex)) return ext_modules
def get_extension_modules(): from importlib import import_module import pkgutil from azure.cli.core.extension import get_extensions, get_extension_path, get_extension_modname extension_whls = get_extensions() ext_modules = [] if extension_whls: for ext_name in [e.name for e in extension_whls]: ext_dir = get_extension_path(ext_name) sys.path.append(ext_dir) try: ext_mod = get_extension_modname(ext_name, ext_dir=ext_dir) module = import_module(ext_mod) setattr(module, 'path', module.__path__[0]) ext_modules.append((module, ext_mod)) except Exception as ex: display("Error importing '{}' extension: {}".format( ext_mod, ex)) return ext_modules
def update_cmd_tree(ext_name): print(f"Processing {ext_name}") ext_dir = get_extension_path(ext_name) ext_mod = get_extension_modname(ext_name, ext_dir=ext_dir) invoker = az_cli.invocation_cls( cli_ctx=az_cli, commands_loader_cls=az_cli.commands_loader_cls, parser_cls=az_cli.parser_cls, help_cls=az_cli.help_cls) az_cli.invocation = invoker sys.path.append(ext_dir) extension_command_table, _ = _load_extension_command_loader( invoker.commands_loader, None, ext_mod) EXT_CMD_TREE_TO_UPLOAD = Session() EXT_CMD_TREE_TO_UPLOAD.load( os.path.expanduser(os.path.join('~', '.azure', file_name))) root = {} for cmd_name, ext_cmd in extension_command_table.items(): try: # do not include hidden deprecated command if ext_cmd.deprecate_info.hide: print(f"Skip hidden deprecated command: {cmd_name}") continue except AttributeError: pass parts = cmd_name.split() parent = root for i, part in enumerate(parts): if part in parent: pass elif i == len(parts) - 1: parent[part] = ext_name else: parent[part] = {} parent = parent[part] print(root) for k, v in root.items(): merge(EXT_CMD_TREE_TO_UPLOAD.data, k, v) EXT_CMD_TREE_TO_UPLOAD.save_with_retry()
def _get_command_table_from_extensions(): extensions = get_extension_names() if extensions: logger.debug("Found {} extensions: {}".format(len(extensions), extensions)) for ext_name in extensions: ext_dir = get_extension_path(ext_name) sys.path.append(ext_dir) try: ext_mod = get_extension_modname(ext_dir=ext_dir) # Add to the map. This needs to happen before we load commands as registering a command # from an extension requires this map to be up-to-date. mod_to_ext_map[ext_mod] = ext_name start_time = timeit.default_timer() import_module(ext_mod).load_commands() elapsed_time = timeit.default_timer() - start_time logger.debug("Loaded extension '%s' in %.3f seconds.", ext_name, elapsed_time) except Exception: # pylint: disable=broad-except logger.warning("Unable to load extension '%s'. Use --debug for more information.", ext_name) logger.debug(traceback.format_exc())
def _get_command_table_from_extensions(): extensions = get_extension_names() if extensions: logger.debug("Found {} extensions: {}".format(len(extensions), extensions)) for ext_name in extensions: ext_dir = get_extension_path(ext_name) sys.path.append(ext_dir) try: ext_mod = get_extension_modname(ext_dir=ext_dir) # Add to the map. This needs to happen before we load commands as registering a command # from an extension requires this map to be up-to-date. mod_to_ext_map[ext_mod] = ext_name start_time = timeit.default_timer() import_module(ext_mod).load_commands() elapsed_time = timeit.default_timer() - start_time logger.debug("Loaded extension '%s' in %.3f seconds.", ext_name, elapsed_time) except Exception: # pylint: disable=broad-except logger.warning("Unable to load extension '%s'. Use --debug for more information.", ext_name) logger.debug(traceback.format_exc())
def _update_command_table_from_extensions(ext_suppressions, extension_modname=None): """Loads command tables from extensions and merge into the main command table. :param ext_suppressions: Extension suppression information. :param extension_modname: Command modules to load, in the format like ['azext_timeseriesinsights']. If None, will do extension discovery and load all extensions. If [], only ALWAYS_LOADED_EXTENSIONS will be loaded. Otherwise, the list will be extended using ALWAYS_LOADED_EXTENSIONS. If the extensions in the list are not installed, it will be skipped. """ def _handle_extension_suppressions(extensions): filtered_extensions = [] for ext in extensions: should_include = True for suppression in ext_suppressions: if should_include and suppression.handle_suppress(ext): should_include = False if should_include: filtered_extensions.append(ext) return filtered_extensions def _filter_modname(extensions): # Extension's name may not be the same as its modname. eg. name: virtual-wan, modname: azext_vwan filtered_extensions = [] for ext in extensions: ext_mod = get_extension_modname(ext.name, ext.path) # Filter the extensions according to the index if ext_mod in extension_modname: filtered_extensions.append(ext) extension_modname.remove(ext_mod) if extension_modname: logger.debug( "These extensions are not installed and will be skipped: %s", extension_modname) return filtered_extensions extensions = get_extensions() if extensions: if extension_modname is not None: extension_modname.extend(ALWAYS_LOADED_EXTENSIONS) extensions = _filter_modname(extensions) allowed_extensions = _handle_extension_suppressions(extensions) module_commands = set(self.command_table.keys()) count = 0 cumulative_elapsed_time = 0 cumulative_group_count = 0 cumulative_command_count = 0 logger.debug("Loading extensions:") logger.debug(self.header_ext) for ext in allowed_extensions: try: # Import in the `for` loop because `allowed_extensions` can be []. In such case we # don't need to import `check_version_compatibility` at all. from azure.cli.core.extension.operations import check_version_compatibility check_version_compatibility(ext.get_metadata()) except CLIError as ex: # issue warning and skip loading extensions that aren't compatible with the CLI core logger.warning(ex) continue ext_name = ext.name ext_dir = ext.path or get_extension_path(ext_name) sys.path.append(ext_dir) try: ext_mod = get_extension_modname(ext_name, ext_dir=ext_dir) # Add to the map. This needs to happen before we load commands as registering a command # from an extension requires this map to be up-to-date. # self._mod_to_ext_map[ext_mod] = ext_name start_time = timeit.default_timer() extension_command_table, extension_group_table = \ _load_extension_command_loader(self, args, ext_mod) for cmd_name, cmd in extension_command_table.items(): cmd.command_source = ExtensionCommandSource( extension_name=ext_name, overrides_command=cmd_name in module_commands, preview=ext.preview, experimental=ext.experimental) self.command_table.update(extension_command_table) self.command_group_table.update(extension_group_table) elapsed_time = timeit.default_timer() - start_time logger.debug(self.item_ext_format_string, ext_name, elapsed_time, len(extension_group_table), len(extension_command_table), ext_dir) count += 1 cumulative_elapsed_time += elapsed_time cumulative_group_count += len(extension_group_table) cumulative_command_count += len( extension_command_table) except Exception as ex: # pylint: disable=broad-except self.cli_ctx.raise_event(EVENT_FAILED_EXTENSION_LOAD, extension_name=ext_name) logger.warning( "Unable to load extension '%s: %s'. Use --debug for more information.", ext_name, ex) logger.debug(traceback.format_exc()) # Summary line logger.debug(self.item_ext_format_string, "Total ({})".format(count), cumulative_elapsed_time, cumulative_group_count, cumulative_command_count, "")
def reload_extension(extension_name, extension_module=None): return reload_module( extension_module if extension_module else get_extension_modname( ext_name=extension_name))
def test_get_extension_modname_no_mods_with_prefix(self): tmp_dir = tempfile.mkdtemp() with self.assertRaises(AssertionError): get_extension_modname(ext_dir=tmp_dir)
def test_get_extension_modname_okay(self): tmp_dir = tempfile.mkdtemp() expected_modname = EXTENSIONS_MOD_PREFIX + 'helloworldmod' os.makedirs(os.path.join(tmp_dir, expected_modname)) actual_modname = get_extension_modname(ext_dir=tmp_dir) self.assertEqual(expected_modname, actual_modname)
def reload_extension(extension_name, extension_module=None): return reload_module(extension_module if extension_module else get_extension_modname(ext_name=extension_name))
def test_get_extension_modname_no_mods_with_prefix(self): tmp_dir = tempfile.mkdtemp() with self.assertRaises(AssertionError): get_extension_modname(ext_dir=tmp_dir)
def test_get_extension_modname_okay(self): tmp_dir = tempfile.mkdtemp() expected_modname = EXTENSIONS_MOD_PREFIX + 'helloworldmod' os.makedirs(os.path.join(tmp_dir, expected_modname)) actual_modname = get_extension_modname(ext_dir=tmp_dir) self.assertEqual(expected_modname, actual_modname)