fix: migrate EPAlias to EPNameOrAlias for better alignment; fix infer_ihv_from_ep_name#1005
Conversation
Compare against the canonical EPName instead of a single alias literal (ep == "qnn"). An EP can have multiple aliases (e.g. nv_tensorrt_rtx / nvtensorrtrtx) and the canonical name itself would not match, so the alias-literal comparison was fragile. Normalize via normalize_ep_name first and widen the parameter to EPNameOrAlias.
The map covers every canonical EPName, so an unknown name now signals a bug rather than silently defaulting to IHVType.MICROSOFT. InformationEngine already catches ValueError (falls back to loading all rules) and the model validator catches it defensively. Replace the per-EP unit tests with one that verifies every EP_NAMES member resolves to an IHVType (enforcing map/Literal parity) plus an unknown-raises test. Update fixtures that relied on the old lenient behavior to use canonical EP names.
DingmaomaoBJTU
left a comment
There was a problem hiding this comment.
Reviewed the EPAlias -> EPNameOrAlias migration and the infer_ihv_from_ep_name rework. Overall this is a clean, well-motivated change — the map/Literal-parity test is a nice touch, and catching CUDAExecutionProvider -> NVIDIA (was silently MICROSOFT) is a good latent-bug fix.
One concern about the new raise on unknown EPs and one un-audited caller (output_aggregator.build_ep_support) — left inline. Not necessarily blocking, but worth resolving for consistency with the other two call sites.
Narrow inferred IHVType into a non-optional local before .value access, and annotate _model_type as str | None so the reordered composite-type branch type-checks.
DingmaomaoBJTU
left a comment
There was a problem hiding this comment.
Re-reviewed the two new commits (use IHVType.UNKNOWN instead of raise, resolve mypy union-attr and assignment narrowing).
My earlier concern is fully resolved. Switching infer_ihv_from_ep_name to return IHVType.UNKNOWN instead of raising makes inference total, so all three call sites — including the previously-unguarded output_aggregator.build_ep_support — are now safe. Verified end to end: UNKNOWN only flows into a debug log there; InformationEngine maps UNKNOWN -> None (loads all rules); the redundant try/except in BatchedConstMatMulValidator is correctly removed since UNKNOWN != INTEL. Tests updated accordingly and CI is green (lint/mypy + all test shards + CodeQL).
Two minor, non-blocking notes:
-
rule_loader.load_runtime_rules(None)iteratesfor ihv in IHVType, which now includesUNKNOWN, producing one extraNo rule files found for Unknown ... skippingwarning on the load-all path. It's harmless and exactly mirrors the existing behavior forMICROSOFT(also absent fromprefix_map), so no change needed — just flagging that adding an enum member has this ripple effect. -
models/auto.pyis unrelated to the EP migration — it's a legit mypy narrowing fix (_model_type: str | None) bundled into the mypy commit, and it also defersAutoConfig.from_pretraineduntil there's no explicitmodel_typeoverride (a small behavioral improvement). Fine to keep; noting it only because it's outside the PR's stated scope.
LGTM from my side.
DingmaomaoBJTU
left a comment
There was a problem hiding this comment.
Approving. My earlier concern about the unguarded output_aggregator.build_ep_support caller is fully resolved by making infer_ihv_from_ep_name total (returns IHVType.UNKNOWN instead of raising), which cleanly removes the inconsistency across all three call sites. Verified end to end, and CI is green (lint/mypy + all test shards + CodeQL). The two remaining items I noted (the harmless Unknown warning in rule_loader's load-all path, and the unrelated auto.py mypy fix) are non-blocking.
Summary
Close #646 (migrate
EPAliastoEPNamewhere possible).EPNameOrAliasis the public-facing input type;EPNameis the internal canonical form. This PR removes places where a bare alias was used where a canonical name belongs, and stops comparing against single alias literals.Changes
analyze/utils/ep_utils.py—infer_ihv_from_ep_namenow does a direct, exactdict[EPName, IHVType]lookup covering every member of theEPNameLiteral. An unknown name now raisesValueErrorinstead of silently defaulting toIHVType.MICROSOFT(the callers that matter already handle it:InformationEnginecatchesValueErrorand falls back to loading all rules; the model validator catches it defensively). Also fixes a latent miss whereCUDAExecutionProviderresolved toMICROSOFTinstead ofNVIDIA.serve/schema.py—EpSwitchRequest.epwas the onlyepfield still typed bareEPAlias; every sibling isEPNameOrAliasandmanager.switch_epalready acceptsEPNameOrAlias. Widened it for consistency so it accepts both"qnn"and"QNNExecutionProvider".compiler/utils.py—needs_format_conversioncomparedep == "qnn", a single alias literal. An EP can have multiple aliases (e.g.nv_tensorrt_rtx/nvtensorrtrtx), and the canonical name itself wouldn't match. Now normalizes vianormalize_ep_nameand compares against the canonical"QNNExecutionProvider"; parameter widened toEPNameOrAlias.Notes
EPConfig.providerdeliberately remains alias-typed: every value it holds is an alias (provider="qnn", etc.), so retyping toEPNamewould require a value migration with serialization back-compat — out of scope here.EPNameOrAliascall sites confirmed every one either normalizes before a canonical sink or forwards to a callee that does — no other un-normalized canonical-sink usages were found.Tests
infer_ihvunit tests with one that verifies everyEP_NAMESmember resolves to anIHVType(enforcing map/Literal parity) plus an unknown-raises test.ACEExecutionProvider→VitisAIExecutionProvider; alias"openvino"→"OpenVINOExecutionProvider"in the validator tests).test_qlinear_for_qnn_canonical_namecovering the canonical-name case that previously failed inneeds_format_conversion.