Skip to content

Commit daedb0c

Browse files
bendichterclaude
andcommitted
Fix PEP 563 string annotations in JSON schema generation
When a module uses `from __future__ import annotations` (PEP 563), all type annotations are stored as strings at runtime. This causes pydantic to fail when creating models from method signatures, as it cannot resolve types like `DirectoryPath` from their string form. Use `typing.get_type_hints()` to resolve string annotations back to their actual types before passing them to pydantic. When a class is passed (rather than a method), target `__init__` for hint resolution since `inspect.signature` also uses `__init__` in that case. Fixes MiniscopeConverter schema generation failure. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 36a91c4 commit daedb0c

File tree

1 file changed

+12
-1
lines changed

1 file changed

+12
-1
lines changed

src/neuroconv/utils/json_schema.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import collections.abc
22
import inspect
33
import json
4+
import typing
45
import warnings
56
from datetime import datetime
67
from pathlib import Path
@@ -159,6 +160,15 @@ def get_json_schema_from_method_signature(method: Callable, exclude: list[str] |
159160
parameters = signature.parameters
160161
additional_properties = False
161162
arguments_to_annotations = {}
163+
164+
# Resolve string annotations from PEP 563 (from __future__ import annotations)
165+
# When a class is passed, inspect.signature uses __init__, so we must too
166+
hints_target = method.__init__ if inspect.isclass(method) else method
167+
try:
168+
type_hints = typing.get_type_hints(hints_target)
169+
except NameError:
170+
type_hints = {}
171+
162172
for argument_name in parameters:
163173
if argument_name in exclude:
164174
continue
@@ -181,7 +191,8 @@ def get_json_schema_from_method_signature(method: Callable, exclude: list[str] |
181191

182192
# Pydantic uses ellipsis for required
183193
pydantic_default = ... if parameter.default is inspect._empty else parameter.default
184-
arguments_to_annotations.update({argument_name: (parameter.annotation, pydantic_default)})
194+
resolved_annotation = type_hints.get(argument_name, parameter.annotation)
195+
arguments_to_annotations.update({argument_name: (resolved_annotation, pydantic_default)})
185196

186197
# The ConfigDict is required to support custom types like NumPy arrays
187198
model = pydantic.create_model(

0 commit comments

Comments
 (0)