Description
When a subclass overrides a field that has range metadata (used by LinkedBaseModel.__init__ to handle IRI strings), the range information from the parent's Field() is lost. This causes:
- IRI strings passed to the field raise
ValidationError: value is not a valid dict
- Object refs don't get their IRI extracted to
__iris__
Root cause
In LinkedBaseModel.__init__, IRI handling checks field.field_info.extra for a "range" key. When a subclass overrides a field with a plain annotation (e.g. tool: list[Child] | None = None), pydantic v1 creates a new FieldInfo without the parent's extra kwargs, so "range" is absent.
Minimal reproduction
from pydantic.v1 import Field
from oold.model.v1 import LinkedBaseModel
from oold.backend.document_store import SimpleDictDocumentStore
from oold.backend.interface import set_backend, SetBackendParam
backend = SimpleDictDocumentStore()
set_backend(SetBackendParam(iri="Item", backend=backend))
class Parent(LinkedBaseModel):
class Config:
schema_extra = {"uuid": "00000000-0000-0000-0000-000000000001"}
type: list[str] | None = ["Category:OSW00000000000000000000000000000001"]
id: str = "Item:OSW00000000000000000000000000000001"
name: str = "parent"
class ProcessBase(LinkedBaseModel):
class Config:
schema_extra = {"uuid": "00000000-0000-0000-0000-000000000010"}
tool: list[Parent] | None = Field(None, range="Category:Parent")
class GoodSubclass(ProcessBase):
"""Inherits tool with range metadata — works"""
class Config:
schema_extra = {"uuid": "00000000-0000-0000-0000-000000000011"}
class BadSubclass(ProcessBase):
"""Overrides tool, loses range metadata — breaks"""
class Config:
schema_extra = {"uuid": "00000000-0000-0000-0000-000000000012"}
tool: list[Parent] | None = None
parent = Parent(name="test_parent")
parent_iri = parent.get_iri()
backend._store[parent_iri] = parent.dict()
# GoodSubclass: IRI resolved correctly
good = GoodSubclass(tool=[parent_iri])
print(good.__iris__.get("tool")) # ['Item:OSW...'] ✓
print(good.tool[0].name) # 'test_parent' ✓
# BadSubclass: ValidationError
bad = BadSubclass(tool=[parent_iri]) # ✗ raises ValidationError
Output:
['Item:OSW00000000000000000000000000000001']
test_parent
ValidationError: 1 validation error for BadSubclass
tool -> 0
value is not a valid dict (type=type_error.dict)
Workaround
Re-declare the field with explicit range in the subclass:
class FixedSubclass(ProcessBase):
tool: list[Parent] | None = Field(None, range="Category:Parent")
Suggestion
LinkedBaseModel.__init__ could fall back to checking parent class field extras when range is not found in the overriding field. Alternatively, the metaclass could propagate range metadata to subclass field overrides automatically.
Environment
- oold: 0.16.2
- pydantic: v1 compat mode (pydantic 2.x with
pydantic.v1)
- Python: 3.11
Description
When a subclass overrides a field that has
rangemetadata (used byLinkedBaseModel.__init__to handle IRI strings), therangeinformation from the parent'sField()is lost. This causes:ValidationError: value is not a valid dict__iris__Root cause
In
LinkedBaseModel.__init__, IRI handling checksfield.field_info.extrafor a"range"key. When a subclass overrides a field with a plain annotation (e.g.tool: list[Child] | None = None), pydantic v1 creates a newFieldInfowithout the parent's extra kwargs, so"range"is absent.Minimal reproduction
Output:
Workaround
Re-declare the field with explicit
rangein the subclass:Suggestion
LinkedBaseModel.__init__could fall back to checking parent class field extras whenrangeis not found in the overriding field. Alternatively, the metaclass could propagaterangemetadata to subclass field overrides automatically.Environment
pydantic.v1)