Summary
import osw.model.entity (and thus osw.express) fails on pydantic 2.11 with:
pydantic.errors.PydanticUndefinedAnnotation: name 'Keyword' is not defined
Currently masked by requiring pydantic>=2.12.0 (commit pins it), but the underlying defect is in the generated opensemantic/base/_model.py and could resurface if pydantic changes forward-ref resolution again.
Root cause
opensemantic/base/_model.py is datamodel-codegen output that:
- uses
from __future__ import annotations (all annotations are string forward-refs);
- imports its base classes from
opensemantic.core (Entity, Item, Place, DefinedTerm, ...) but not the field-value types those base classes reference;
- ends with a block of
X.model_rebuild() calls.
Every base model subclasses core.Entity, whose fields reference core types not imported into base/_model.py:
keywords: list[Keyword]
- statement fields referencing
ObjectStatement, DataStatement, QuantityStatement
Under pydantic 2.11, model_rebuild() resolves inherited fields' forward refs against the subclass module globals (opensemantic.base._model), where those names are absent -> NameError -> PydanticUndefinedAnnotation. Pydantic 2.12 resolves them against the defining class's module (core) again, so the import succeeds.
Reproduction (verified)
Same packages (opensemantic==0.2.1, opensemantic.base==0.42.7..., opensemantic.core==0.56.0...), only pydantic changed:
| pydantic |
import opensemantic.base |
| 2.11.3 |
FAIL: PydanticUndefinedAnnotation: name 'Keyword' is not defined |
| 2.12.0 |
OK |
Durable fix (in opensemantic-python codegen)
The generator must import every core type referenced by inherited field annotations, not only the direct base classes. Minimal verified fix is adding the four names to the from opensemantic.core import (...) block in base/_model.py:
Keyword, ObjectStatement, DataStatement, QuantityStatement
Same latent bug affects any generated module that subclasses core.Entity across a module boundary (other base/* namespaces, base/v1/_model.py).
Options (cleanest first):
- Emit explicit imports for inherited field-value types.
from opensemantic.core import * before the model_rebuild() block (needs core.__all__).
- Pass explicit namespace:
X.model_rebuild(_types_namespace={**vars(opensemantic.core), **globals()}).
Note
The real fix belongs in opensemantic-python (generated code). This issue tracks it from the osw-python side since that is where it surfaced. The pydantic>=2.12.0 pin is the current stopgap.
Summary
import osw.model.entity(and thusosw.express) fails on pydantic 2.11 with:Currently masked by requiring
pydantic>=2.12.0(commit pins it), but the underlying defect is in the generatedopensemantic/base/_model.pyand could resurface if pydantic changes forward-ref resolution again.Root cause
opensemantic/base/_model.pyis datamodel-codegen output that:from __future__ import annotations(all annotations are string forward-refs);opensemantic.core(Entity,Item,Place,DefinedTerm, ...) but not the field-value types those base classes reference;X.model_rebuild()calls.Every
basemodel subclassescore.Entity, whose fields referencecoretypes not imported intobase/_model.py:keywords: list[Keyword]ObjectStatement,DataStatement,QuantityStatementUnder pydantic 2.11,
model_rebuild()resolves inherited fields' forward refs against the subclass module globals (opensemantic.base._model), where those names are absent ->NameError->PydanticUndefinedAnnotation. Pydantic 2.12 resolves them against the defining class's module (core) again, so the import succeeds.Reproduction (verified)
Same packages (
opensemantic==0.2.1,opensemantic.base==0.42.7...,opensemantic.core==0.56.0...), only pydantic changed:import opensemantic.basePydanticUndefinedAnnotation: name 'Keyword' is not definedDurable fix (in opensemantic-python codegen)
The generator must import every
coretype referenced by inherited field annotations, not only the direct base classes. Minimal verified fix is adding the four names to thefrom opensemantic.core import (...)block inbase/_model.py:Same latent bug affects any generated module that subclasses
core.Entityacross a module boundary (otherbase/*namespaces,base/v1/_model.py).Options (cleanest first):
from opensemantic.core import *before themodel_rebuild()block (needscore.__all__).X.model_rebuild(_types_namespace={**vars(opensemantic.core), **globals()}).Note
The real fix belongs in opensemantic-python (generated code). This issue tracks it from the osw-python side since that is where it surfaced. The
pydantic>=2.12.0pin is the current stopgap.