diff --git a/msgspec/_utils.py b/msgspec/_utils.py index 2a8a5715..7761b07f 100644 --- a/msgspec/_utils.py +++ b/msgspec/_utils.py @@ -50,12 +50,22 @@ def _eval_type(t, globalns, localns): def _apply_params(obj, mapping): - if params := getattr(obj, "__parameters__", None): - args = tuple(mapping.get(p, p) for p in params) - return obj[args] - elif isinstance(obj, typing.TypeVar): + if isinstance(obj, typing.TypeVar): return mapping.get(obj, obj) - return obj + + try: + parameters = tuple(obj.__parameters__) + except Exception: + # Not parameterized or __parameters__ is invalid, ignore + return obj + + if not parameters: + # Not parametrized + return obj + + # Parametrized + args = tuple(mapping.get(p, p) for p in parameters) + return obj[args] def _get_class_mro_and_typevar_mappings(obj): diff --git a/tests/test_utils.py b/tests/test_utils.py index 83630c93..a991b42f 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -190,3 +190,14 @@ class Sub2(Sub, Base[int]): z: str assert get_class_annotations(Sub2) == {"x": int, "y": float, "z": str} + + def test_generic_invalid_parameters(self): + class Invalid: + @property + def __parameters__(self): + pass + + class Sub(Base[Invalid]): + pass + + assert get_class_annotations(Sub) == {"x": Invalid}