Skip to content

Commit 8c25f0e

Browse files
refactor: export to smaller methods
1 parent a13d2fb commit 8c25f0e

File tree

1 file changed

+86
-51
lines changed

1 file changed

+86
-51
lines changed

src/azure-cli-core/azure/cli/core/__init__.py

Lines changed: 86 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
import sys
1111
import timeit
1212
from concurrent.futures import ThreadPoolExecutor
13+
from dataclasses import dataclass
14+
from typing import Dict, Any, Optional
1315

1416
from knack.cli import CLI
1517
from knack.commands import CLICommandsLoader
@@ -196,6 +198,15 @@ def _configure_style(self):
196198
format_styled_text.theme = theme
197199

198200

201+
@dataclass
202+
class ModuleLoadResult:
203+
module_name: str
204+
command_table: Dict[str, Any]
205+
group_table: Dict[str, Any]
206+
elapsed_time: float
207+
error: Optional[Exception] = None
208+
209+
199210
class MainCommandsLoader(CLICommandsLoader):
200211

201212
# Format string for pretty-print the command module table
@@ -222,11 +233,11 @@ def load_command_table(self, args):
222233
import pkgutil
223234
import traceback
224235
from azure.cli.core.commands import (
225-
_load_module_command_loader, _load_extension_command_loader, BLOCKED_MODS, ExtensionCommandSource)
236+
_load_extension_command_loader, ExtensionCommandSource)
226237
from azure.cli.core.extension import (
227238
get_extensions, get_extension_path, get_extension_modname)
228239
from azure.cli.core.breaking_change import (
229-
import_core_breaking_changes, import_module_breaking_changes, import_extension_breaking_changes)
240+
import_core_breaking_changes, import_extension_breaking_changes)
230241

231242
def _update_command_table_from_modules(args, command_modules=None):
232243
"""Loads command tables from modules and merge into the main command table.
@@ -252,55 +263,11 @@ def _update_command_table_from_modules(args, command_modules=None):
252263
except ImportError as e:
253264
logger.warning(e)
254265

255-
count = 0
256-
cumulative_elapsed_time = 0
257-
cumulative_group_count = 0
258-
cumulative_command_count = 0
259-
logger.debug("Loading command modules:")
260-
logger.debug(self.header_mod)
261-
262-
print(f"*** Starting SUT***")
263-
start_time_wrapper = timeit.default_timer()
264-
265-
def load_module_threaded(mod):
266-
try:
267-
start_time = timeit.default_timer()
268-
module_command_table, module_group_table = _load_module_command_loader(self, args, mod)
269-
import_module_breaking_changes(mod)
270-
elapsed_time = timeit.default_timer() - start_time
271-
return (mod, module_command_table, module_group_table, elapsed_time, None)
272-
except Exception as ex: # pylint: disable=broad-except
273-
return (mod, {}, {}, 0, ex)
274-
275-
# Use ThreadPoolExecutor to load modules in parallel
276-
with ThreadPoolExecutor(max_workers=4) as executor:
277-
futures = [executor.submit(load_module_threaded, mod)
278-
for mod in command_modules if mod not in BLOCKED_MODS]
279-
280-
for future in futures:
281-
mod, module_command_table, module_group_table, elapsed_time, error = future.result()
282-
if error:
283-
# Changing this error message requires updating CI script that checks for failed
284-
# module loading.
285-
from azure.cli.core import telemetry
286-
logger.error("Error loading command module '%s': %s", mod, error)
287-
telemetry.set_exception(exception=error, fault_type='module-load-error-' + mod,
288-
summary='Error loading module: {}'.format(mod))
289-
logger.debug(traceback.format_exc())
290-
else:
291-
for cmd in module_command_table.values():
292-
cmd.command_source = mod
293-
self.command_table.update(module_command_table)
294-
self.command_group_table.update(module_group_table)
295-
296-
logger.debug(self.item_format_string, mod, elapsed_time,
297-
len(module_group_table), len(module_command_table))
298-
count += 1
299-
cumulative_elapsed_time += elapsed_time
300-
cumulative_group_count += len(module_group_table)
301-
cumulative_command_count += len(module_command_table)
302-
elapsed_time = timeit.default_timer() - start_time_wrapper
303-
print(f"*** SUT operation *** took: {elapsed_time:.6f} seconds for {len(command_modules)} modules")
266+
results = self._load_modules_threaded(args, command_modules)
267+
268+
# @TODO: export to own method:
269+
count, cumulative_elapsed_time, cumulative_group_count, cumulative_command_count = \
270+
self._process_results_with_timing(results, command_modules)
304271
# Summary line
305272
logger.debug(self.item_format_string,
306273
"Total ({})".format(count), cumulative_elapsed_time,
@@ -577,6 +544,74 @@ def load_arguments(self, command=None):
577544
self.extra_argument_registry.update(loader.extra_argument_registry)
578545
loader._update_command_definitions() # pylint: disable=protected-access
579546

547+
def _load_modules_threaded(self, args, command_modules):
548+
"""Load command modules using ThreadPoolExecutor for parallel processing."""
549+
from azure.cli.core.commands import _load_module_command_loader, BLOCKED_MODS
550+
from azure.cli.core.breaking_change import import_module_breaking_changes
551+
552+
def load_single_module(mod):
553+
try:
554+
start_time = timeit.default_timer()
555+
module_command_table, module_group_table = _load_module_command_loader(self, args, mod)
556+
import_module_breaking_changes(mod)
557+
elapsed_time = timeit.default_timer() - start_time
558+
return ModuleLoadResult(mod, module_command_table, module_group_table, elapsed_time)
559+
except Exception as ex: # pylint: disable=broad-except
560+
return ModuleLoadResult(mod, {}, {}, 0, ex)
561+
562+
with ThreadPoolExecutor(max_workers=4) as executor:
563+
futures = [executor.submit(load_single_module, mod)
564+
for mod in command_modules if mod not in BLOCKED_MODS]
565+
return [future.result() for future in futures]
566+
567+
def _handle_module_load_error(self, result):
568+
"""Handle errors that occurred during module loading."""
569+
import traceback
570+
from azure.cli.core import telemetry
571+
572+
# Changing this error message requires updating CI script that checks for failed module loading.
573+
logger.error("Error loading command module '%s': %s", result.module_name, result.error)
574+
telemetry.set_exception(exception=result.error,
575+
fault_type='module-load-error-' + result.module_name,
576+
summary='Error loading module: {}'.format(result.module_name))
577+
logger.debug(traceback.format_exc())
578+
579+
def _process_successful_load(self, result):
580+
"""Process successfully loaded module results."""
581+
# Set command source for all commands in the module
582+
for cmd in result.command_table.values():
583+
cmd.command_source = result.module_name
584+
585+
# Update main command and group tables
586+
self.command_table.update(result.command_table)
587+
self.command_group_table.update(result.group_table)
588+
589+
# Log the results
590+
logger.debug(self.item_format_string, result.module_name, result.elapsed_time,
591+
len(result.group_table), len(result.command_table))
592+
593+
def _process_results_with_timing(self, results, command_modules):
594+
"""Process pre-loaded module results with timing and progress reporting."""
595+
logger.debug("Loading command modules:")
596+
logger.debug(self.header_mod)
597+
598+
count = 0
599+
cumulative_elapsed_time = 0
600+
cumulative_group_count = 0
601+
cumulative_command_count = 0
602+
603+
for result in results:
604+
if result.error:
605+
self._handle_module_load_error(result)
606+
else:
607+
self._process_successful_load(result)
608+
count += 1
609+
cumulative_elapsed_time += result.elapsed_time
610+
cumulative_group_count += len(result.group_table)
611+
cumulative_command_count += len(result.command_table)
612+
613+
return count, cumulative_elapsed_time, cumulative_group_count, cumulative_command_count
614+
580615

581616
class CommandIndex:
582617

0 commit comments

Comments
 (0)