fix: resolve string annotations from from __future__ import annotations#4508
Open
cluster2600 wants to merge 1 commit intozenml-io:developfrom
Open
fix: resolve string annotations from from __future__ import annotations#4508cluster2600 wants to merge 1 commit intozenml-io:developfrom
from __future__ import annotations#4508cluster2600 wants to merge 1 commit intozenml-io:developfrom
Conversation
…ons' Using 'from __future__ import annotations' (PEP 563) makes Python store all type annotations as plain strings instead of evaluated type objects. inspect.signature() preserves these strings, so any downstream code that calls key.__mro__ (e.g. MaterializerRegistry.__getitem__) would hit an AttributeError on older ZenML versions, or a RuntimeError on more recent ones that added an explicit string-type guard. This commit adds get_resolved_type_hints(), a thin wrapper around typing.get_type_hints(include_extras=True) that resolves forward references while preserving Annotated metadata. It is called in two places where annotations are first consumed: * parse_return_type_annotations() in steps/utils.py – for step output types. * validate_entrypoint_function() in steps/entrypoint_function_utils.py – for step input parameter types. Resolution failures (e.g. unresolvable forward references due to circular imports or TYPE_CHECKING-only imports) are swallowed silently; the original string annotation is kept, which will still surface a clear RuntimeError from MaterializerRegistry.__getitem__ with a message updated to reflect the actual root cause. Fixes zenml-io#2477 Co-authored-by: Maxime Grenu <maxime.grenu@gmail.com>
Contributor
|
@cluster2600 , thank you for your contribution. We'll take a look. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Using
from __future__ import annotations(PEP 563) in a module that defines ZenML steps makes Python store all type annotations as plain strings instead of evaluated type objects.inspect.signature()preserves these strings verbatim, so any downstream code that callskey.__mro__— such asMaterializerRegistry.__getitem__— breaks at pipeline compilation time.Reported in #2477. Originally the failure was a cryptic
AttributeError: 'str' object has no attribute '__mro__'. A later commit improved this to aRuntimeErrorwith a better message, but the underlying limitation remained:from __future__ import annotationswas entirely unsupported in step definition modules.Solution
Add
get_resolved_type_hints(), a thin wrapper aroundtyping.get_type_hints(include_extras=True):include_extras=TruepreservesAnnotated[…]metadata (artifact names, configs, etc.).inspect.unwrap()to reach the original function even when it is wrapped by the@stepdecorator.The helper is called in two places where annotations are first consumed:
parse_return_type_annotations()(steps/utils.py) — step output types.validate_entrypoint_function()(steps/entrypoint_function_utils.py) — step input parameter types.When resolution fails, the string annotation is kept;
MaterializerRegistry.__getitem__will then raise aRuntimeErrorwith an updated, more accurate message explaining the actual root cause (unresolvable forward reference) rather than telling users to removefrom __future__ import annotations.Changes
src/zenml/steps/utils.pyget_type_hintsimport; addget_resolved_type_hints()helper; resolve stringreturn_annotationinparse_return_type_annotations()src/zenml/steps/entrypoint_function_utils.pyget_resolved_type_hints; resolve string input annotations invalidate_entrypoint_function()src/zenml/materializers/materializer_registry.pytests/unit/steps/test_utils.pyget_resolved_type_hintserror handlingtests/unit/steps/test_entrypoint_function_utils.pyvalidate_entrypoint_functionTesting
After this fix, a step like:
compiles and runs correctly without any changes to the step code.
Closes #2477