Skip to content

feat: MVP v2 — CLI standardization, lazy imports, Rich console redesign#313

Closed
tezheng wants to merge 11 commits into
mainfrom
feat/mvp-v2
Closed

feat: MVP v2 — CLI standardization, lazy imports, Rich console redesign#313
tezheng wants to merge 11 commits into
mainfrom
feat/mvp-v2

Conversation

@tezheng

@tezheng tezheng commented Apr 11, 2026

Copy link
Copy Markdown
Collaborator

Summary

Port of mvp/main2 feature branch (8 commits) to gh/main with improvements:

  • Lazy imports: PEP 562 _LAZY_IMPORTS dict pattern across 7 modules, CLI starts in 0.13s with zero heavy deps (torch/transformers/optimum)
  • LazyGroup CLI: Command discovery via filesystem scan + AST help parsing, no module imports at startup
  • Rich Live analyze: Real-time per-node stacked bar animation with on_node_result/on_ep_start callbacks
  • Rich config output: Formatted CONFIG GENERATION header with I/O specs and resolution display
  • Build StageLive: Per-stage progress with EP analyzer bars, artifact sizes
  • Inspect redesign: Rich formatted model inspection with _inspect_model_v2
  • Perf ONNX direct path: Bypasses HF build for .onnx files via WinMLSession
  • Config registry short-circuit: Skips Optimum when input_tensors pre-registered
  • Circular import fix (onnx ↔ compiler) via lazy detection module
  • Import time regression tests with _LAZY_IMPORTS validation

Commits

  1. perf: lazy imports, CLI startup optimization, and console utilities
  2. feat(analyzer): replace console_writer with Rich Live progress display
  3. fix(config): registry short-circuit, BERT flags, precision, Rich output
  4. feat(build): StageLive console redesign with EP bars
  5. refactor(cli): inspect, perf, export, and remaining fixes
  6. fix(tests): conftest should not catch AttributeError in EP mock

Verification

  • 2492 unit tests pass (28 skipped for hardware, 2 xfailed for upstream bugs)
  • All 11 CLI commands load without heavy imports
  • winml analyze, winml config, winml build verified with ConvNeXt model
  • Zero wmk references, zero legacy white/gray/black SupportLevel values
  • Ruff lint clean

🤖 Generated with Claude Code

Zheng Te added 6 commits April 10, 2026 14:12
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).
@tezheng tezheng requested a review from a team as a code owner April 11, 2026 16:03
The inspect command now has --list-tasks (ported from mvp/main2).
Update regression test from asserting absent to asserting present.
Comment thread src/winml/modelkit/commands/config.py Fixed
Comment thread src/winml/modelkit/commands/build.py Fixed
Comment thread src/winml/modelkit/commands/build.py Fixed
Comment thread src/winml/modelkit/commands/build.py Fixed
Comment thread src/winml/modelkit/commands/config.py Fixed
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
Zheng Te added 3 commits April 12, 2026 00:17
…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

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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_config

Per 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.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_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 in inspect/__init__.py
  • from ..inspect.types import ExporterInfo, InspectResult, LoaderInfo, SupportLevel, TensorInfo → also exported in inspect/__init__.py
  • from ..loader.config import resolve_loader_config → exported in loader/__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

Comment thread tests/test_import_time.py
@@ -0,0 +1,460 @@
# -------------------------------------------------------------------------

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 under tests/integration/, e2e under tests/e2e/

Since these are import-time regression tests, this should be moved to tests/regression/test_import_time.py.

🤖 Generated with Claude Code

@tezheng tezheng force-pushed the feat/mvp-v2 branch 2 times, most recently from d2fc0b0 to e46b9c9 Compare April 13, 2026 07:20
- 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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants