Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 23 additions & 4 deletions fiddle/_src/codegen/auto_config/ir_printer.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"""

import inspect
import types
import typing
from typing import Any, List

Expand All @@ -28,9 +29,27 @@
from fiddle._src.codegen.auto_config import code_ir
import libcst as cst

# Values from the `typing` module. This probably pulls in too much stuff, but
# we don't have to be 100% precise in this module, it's just for debug printing.
typing_consts = [getattr(typing, name) for name in dir(typing)]

def _is_typing_or_generic(value: Any) -> bool:
"""Checks if a value is a typing construct or generic alias."""
union_type = getattr(types, "UnionType", None)
generic_alias = getattr(types, "GenericAlias", None)

types_to_check = []
if union_type is not None:
types_to_check.append(union_type)
if generic_alias is not None:
types_to_check.append(generic_alias)

if types_to_check and isinstance(value, tuple(types_to_check)):
return True

if hasattr(value, "__module__") and value.__module__ == "typing":
return True
t = type(value)
if hasattr(t, "__module__") and t.__module__ == "typing":
return True
return False


def format_py_reference(value: Any) -> str:
Expand Down Expand Up @@ -121,7 +140,7 @@ def traverse(value, state: daglish.State) -> str:
return value.value
elif isinstance(value, type) and value is not typing.Any:
return value.__name__
elif value in typing_consts or type(value) in typing_consts:
elif _is_typing_or_generic(value):
return str(value)
else:
return f"<<<custom:{repr(value)}>>>"
Expand Down
2 changes: 1 addition & 1 deletion fiddle/_src/codegen/auto_config/ir_printer_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ def test_format_expr_primitives(self):
self.assertIn(
ir_printer.format_expr(Optional[str]),
# This differs based on the Python verison.
{"typing.Union[str, NoneType]", "typing.Optional[str]"},
{"typing.Union[str, NoneType]", "typing.Optional[str]", "str | None"},
)

def test_format_containers(self):
Expand Down
8 changes: 4 additions & 4 deletions fiddle/_src/validation/check_types_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -201,10 +201,10 @@ def test_union_and_optional_types(self):
)
with self.assertRaisesRegex(
TypeError,
".*For attribute .*union_field provided type:"
" .*BadTokenEmbedder.* is not of annotated/declared"
" type: typing.Union.*str,"
" fiddle._src.testing.example.fake_encoder_decoder.TokenEmbedder.*",
r".*For attribute .*union_field provided type:"
r" .*BadTokenEmbedder.* is not of annotated/declared"
r" type: (typing.Union\[str,\s*|str\s*\|\s*)"
r"fiddle\._src\.testing\.example\.fake_encoder_decoder\.TokenEmbedder.*",
):
check_types.check_types(cfg)

Expand Down
Loading