feat: MVP v2 — CLI standardization, lazy imports, Rich console redesign#313
feat: MVP v2 — CLI standardization, lazy imports, Rich console redesign#313tezheng wants to merge 11 commits into
Conversation
Port of mvp/main2 commits b79712fa, 1c69ddf5, 6964866e (cli.py): - Standardized _LAZY_IMPORTS dict pattern across all __init__.py files (root, core, export, loader, quant, models, onnx) - LazyGroup CLI: filesystem scan + AST help parsing, no module imports - Remove torch dependency from model_input_generator (numpy) and onnx_utils - Lazy-load onnx.detection to break circular import (onnx <-> compiler) - Stackable -v verbosity, _PipelineNoiseFilter, category-specific warnings - New utils/console.py Rich console utilities (StageLive, formatters) - Import time regression tests with _LAZY_IMPORTS validation
Port of mvp/main2 commit 1be785a6: - runtime_checker: on_node_result callback with conditional tqdm skip - analyzer: callbacks threaded through analyze/analyze_from_proto - commands/analyze.py: Rich Live stacked bar visualization - Preserved --save-node, added --optim-config
Port of mvp/main2 commits 1e7815ba + 6964866e (config.py): - config/build.py: registry short-circuit, resolve_precision() - commands/config.py: Rich CONFIG GENERATION output - export/io.py: fix absolute import bug - models/hf/bert.py: remove hardcoded fusion flags - optim: short-circuit for compiled models, registry improvements
Port of mvp/main2 commit 5352dab8: - commands/build.py: Rich StageLive progress, EP analyzer bars - build/common.py: callback plumbing for analyze loop - Test adaptations for inlined pipeline (_run_single_build)
Port of mvp/main2 commit 6964866e (remaining files): - commands/inspect.py: Rich formatted inspection with _inspect_model_v2 - commands/perf.py: ONNX direct benchmark, shared loop functions - commands/export.py, optimize.py, quantize.py: Rich console output - inspect/: resolver.py rewrite, formatter.py, types.py - models/auto.py, base.py: device property, from_onnx - session/session.py: compile/device enhancements - Rename live_chart.py -> _live_chart.py - Test adaptations
Only catch ImportError (genuinely optional module), not AttributeError (which means the mock target was renamed — tests must fail loudly).
The inspect command now has --list-tasks (ported from mvp/main2). Update regression test from asserting absent to asserting present.
| return | ||
| from ..models import hf as _hf # noqa: F401 | ||
|
|
||
| _hf_models_registered = True |
| """ | ||
| total = onnx_path.stat().st_size | ||
| try: | ||
| import onnx |
| num_initializers: int | ||
| total_nodes: int | ||
| """ | ||
| import onnx |
…actor - Update call_count assertions for final validation pass in analyze loop - Add extra mock return values for the additional analyze_onnx call - Pre-quantized tests: assert_not_called (max_optim_iterations=0 skips loop)
- Add mock_result.output.results = [] so Rich rendering path doesn't crash - Fix model_path assertion: str comparison (command passes str(model))
- config.py: initialize configs=[] to prevent uninitialized variable - config.py: remove unused _compile variable - build.py: remove unnecessary _quant_elapsed/_compile_elapsed pre-assignment - build.py: add comment to empty except clause for datasets import
| ) | ||
| from ..loader import resolve_loader_config | ||
| from ..loader.config import WinMLLoaderConfig | ||
| from ..loader.config import WinMLLoaderConfig, resolve_loader_config |
There was a problem hiding this comment.
Import regression: this was previously the correct from ..loader import resolve_loader_config (through __init__.py). The new line bypasses loader/__init__.py by importing directly from the internal submodule.
Both WinMLLoaderConfig and resolve_loader_config are exported in loader/__init__.py, so this should be:
from ..loader import WinMLLoaderConfig, resolve_loader_configPer CLAUDE.md: source code must use "relative imports through __init__.py".
🤖 Generated with Claude Code
| # Licensed under the MIT License. | ||
| # -------------------------------------------------------------------------- | ||
|
|
||
| """Shared console output utilities for winml CLI commands. |
There was a problem hiding this comment.
This new module defines 15+ public functions (get_console, print_command_header, print_error, print_kv, print_success, print_io_specs_detail, print_setup, print_stages_header, print_final, print_stage_skip, detect_model_source, fmt_size, get_onnx_total_size, get_onnx_graph_summary, StageLive) — all imported by multiple command files — but none are exported in utils/__init__.py or added to its __all__.
Per CLAUDE.md: "Every symbol that external code needs must be exported in the package's __init__.py. When adding new public classes/functions, add them to both the import and __all__."
Please add the needed symbols to utils/__init__.py.
🤖 Generated with Claude Code
| from rich.logging import RichHandler | ||
|
|
||
| from ..utils.console import ( | ||
| detect_model_source, |
There was a problem hiding this comment.
These imports bypass utils/__init__.py by reaching into the internal utils.console submodule:
from ..utils.console import (
detect_model_source,
get_console,
...
)Once the symbols are exported in utils/__init__.py (see comment on console.py), this should become:
from ..utils import (
detect_model_source,
get_console,
...
)Same pattern applies to commands/config.py which has the same bypass.
🤖 Generated with Claude Code
| ) -> InspectResult: | ||
| """Inspect v2 core — calls shared loader/export modules directly. | ||
|
|
||
| Args: |
There was a problem hiding this comment.
_inspect_model_v2 imports from internal submodules instead of going through __init__.py:
from ..inspect.resolver import build_tensor_infos_from_io_specs, compile_support_status, resolve_cache, ...→ these are all exported ininspect/__init__.pyfrom ..inspect.types import ExporterInfo, InspectResult, LoaderInfo, SupportLevel, TensorInfo→ also exported ininspect/__init__.pyfrom ..loader.config import resolve_loader_config→ exported inloader/__init__.py
Should be:
from ..inspect import (
build_tensor_infos_from_io_specs,
compile_support_status,
resolve_cache,
resolve_io_config,
resolve_processor,
resolve_winml,
ExporterInfo,
InspectResult,
LoaderInfo,
SupportLevel,
TensorInfo,
)
from ..loader import resolve_loader_config🤖 Generated with Claude Code
| @@ -0,0 +1,460 @@ | |||
| # ------------------------------------------------------------------------- | |||
There was a problem hiding this comment.
This test file is placed directly under tests/ instead of in a proper subdirectory. Per tests/CLAUDE.md:
Place unit tests under
tests/unit/<module>/
Place integration tests undertests/integration/, e2e undertests/e2e/
Since these are import-time regression tests, this should be moved to tests/regression/test_import_time.py.
🤖 Generated with Claude Code
d2fc0b0 to
e46b9c9
Compare
- Complete rewrite with value proposition, hardware matrix, prerequisites - Two build paths: primitives vs config-driven pipeline comparison table - Quick start walkthrough with ConvNeXT (inspect, build, benchmark) - Built-in model catalog, scope/limitations, roadmap - Remove SharePoint download link - Mark cache/doctor/setting as coming soon - Add BYOM workflow diagram
Summary
Port of mvp/main2 feature branch (8 commits) to gh/main with improvements:
_LAZY_IMPORTSdict pattern across 7 modules, CLI starts in 0.13s with zero heavy deps (torch/transformers/optimum)Commits
perf: lazy imports, CLI startup optimization, and console utilitiesfeat(analyzer): replace console_writer with Rich Live progress displayfix(config): registry short-circuit, BERT flags, precision, Rich outputfeat(build): StageLive console redesign with EP barsrefactor(cli): inspect, perf, export, and remaining fixesfix(tests): conftest should not catch AttributeError in EP mockVerification
winml analyze,winml config,winml buildverified with ConvNeXt modelwmkreferences, zero legacywhite/gray/blackSupportLevel values🤖 Generated with Claude Code