Summary
PipelineTemplate.instantiate(providers=None) auto-discovers provider entry
points, then eagerly instantiates every discovered provider class before it
checks which providers the template actually references. A valid template that
uses one provider can therefore fail because an unrelated installed provider has
constructor requirements, missing optional dependencies, import-time side
effects, or expensive client setup.
The method should resolve the template's referenced provider names first, then
instantiate only those providers.
Affected files
libs/core/genblaze_core/pipeline/template.py:125-137 (auto-discovery instantiates the full discovered map)
libs/core/genblaze_core/pipeline/template.py:150-156 (referenced provider lookup happens only after all providers have been constructed)
libs/core/tests/unit/test_pipeline_template.py:108-200 (instantiation tests always pass an explicit provider dict; no providers=None coverage)
docs/features/pipeline-templates.md:67 (documents auto-discovery as a supported path)
Evidence
Minimal reproduction from the requested conda env:
from genblaze_core.pipeline.template import PipelineTemplate, StepTemplate
from genblaze_core.providers import registry
from genblaze_core.testing import MockProvider
class BadProvider:
def __init__(self):
raise RuntimeError("requires credentials")
orig = registry.discover_providers
try:
registry.discover_providers = lambda: {"mock": MockProvider, "bad": BadProvider}
template = PipelineTemplate(
name="only-mock",
steps=[StepTemplate(provider_name="mock", model="m")],
)
template.instantiate()
finally:
registry.discover_providers = orig
Output:
GenblazeError
Failed to instantiate provider 'bad'. Pass providers= explicitly if constructor requires arguments: requires credentials
The template references only mock, but instantiation fails because the unused
bad entry point is constructed first.
There is a smaller version of the same problem for empty templates:
instantiate(providers=None) performs discovery and provider construction before
raising Template has no steps.
Why it matters
Auto-discovery is meant to make template loading ergonomic. In plugin-heavy
environments, constructing every installed provider is the opposite: unrelated
plugins can break templates, add startup latency, or force credentials for
providers the user is not using. It also makes debugging misleading because the
error names a provider absent from the template.
Suggested fix
Reorder and narrow the logic:
- Validate
self.steps before discovery.
- Compute
required_provider_names = {st.provider_name for st in self.steps}.
- If
providers is None, call discover_providers() to get classes, but
instantiate only the required names.
- Report missing required providers with the existing "Available" message.
- Add tests for
providers=None with an unused discovered provider whose
constructor raises, and for empty templates not invoking discovery.
If providers with credential kwargs should be supported by auto-discovery, reuse
or extend the existing instantiate_with_credential() helper in
genblaze_core.providers.registry instead of hand-rolling constructor fallback
inside templates.
Acceptance criteria
- A template that references provider
A can instantiate with auto-discovery
even if an unrelated discovered provider B cannot be constructed.
- Empty templates fail before provider discovery/instantiation.
- Missing referenced providers still produce a clear error listing available
provider names.
- Unit tests cover the
providers=None path.
Summary
PipelineTemplate.instantiate(providers=None)auto-discovers provider entrypoints, then eagerly instantiates every discovered provider class before it
checks which providers the template actually references. A valid template that
uses one provider can therefore fail because an unrelated installed provider has
constructor requirements, missing optional dependencies, import-time side
effects, or expensive client setup.
The method should resolve the template's referenced provider names first, then
instantiate only those providers.
Affected files
libs/core/genblaze_core/pipeline/template.py:125-137(auto-discovery instantiates the full discovered map)libs/core/genblaze_core/pipeline/template.py:150-156(referenced provider lookup happens only after all providers have been constructed)libs/core/tests/unit/test_pipeline_template.py:108-200(instantiation tests always pass an explicit provider dict; noproviders=Nonecoverage)docs/features/pipeline-templates.md:67(documents auto-discovery as a supported path)Evidence
Minimal reproduction from the requested conda env:
Output:
The template references only
mock, but instantiation fails because the unusedbadentry point is constructed first.There is a smaller version of the same problem for empty templates:
instantiate(providers=None)performs discovery and provider construction beforeraising
Template has no steps.Why it matters
Auto-discovery is meant to make template loading ergonomic. In plugin-heavy
environments, constructing every installed provider is the opposite: unrelated
plugins can break templates, add startup latency, or force credentials for
providers the user is not using. It also makes debugging misleading because the
error names a provider absent from the template.
Suggested fix
Reorder and narrow the logic:
self.stepsbefore discovery.required_provider_names = {st.provider_name for st in self.steps}.providers is None, calldiscover_providers()to get classes, butinstantiate only the required names.
providers=Nonewith an unused discovered provider whoseconstructor raises, and for empty templates not invoking discovery.
If providers with credential kwargs should be supported by auto-discovery, reuse
or extend the existing
instantiate_with_credential()helper ingenblaze_core.providers.registryinstead of hand-rolling constructor fallbackinside templates.
Acceptance criteria
Acan instantiate with auto-discoveryeven if an unrelated discovered provider
Bcannot be constructed.provider names.
providers=Nonepath.