Skip to content

Field overrides in subclasses lose range metadata, breaking IRI handling #85

Description

@simontaurus

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:

  1. IRI strings passed to the field raise ValidationError: value is not a valid dict
  2. 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

frompydantic.v1importFieldfromoold.model.v1importLinkedBaseModelfromoold.backend.document_storeimportSimpleDictDocumentStorefromoold.backend.interfaceimportset_backend, SetBackendParambackend=SimpleDictDocumentStore()
set_backend(SetBackendParam(iri="Item", backend=backend))
classParent(LinkedBaseModel):
classConfig:
schema_extra= {"uuid": "00000000-0000-0000-0000-000000000001"}
type: list[str] |None= ["Category:OSW00000000000000000000000000000001"]
id: str="Item:OSW00000000000000000000000000000001"name: str="parent"classProcessBase(LinkedBaseModel):
classConfig:
schema_extra= {"uuid": "00000000-0000-0000-0000-000000000010"}
tool: list[Parent] |None=Field(None, range="Category:Parent")
classGoodSubclass(ProcessBase):
"""Inherits tool with range metadata — works"""classConfig:
schema_extra= {"uuid": "00000000-0000-0000-0000-000000000011"}
classBadSubclass(ProcessBase):
"""Overrides tool, loses range metadata — breaks"""classConfig:
schema_extra= {"uuid": "00000000-0000-0000-0000-000000000012"}
tool: list[Parent] |None=Noneparent=Parent(name="test_parent")
parent_iri=parent.get_iri()
backend._store[parent_iri] =parent.dict()
# GoodSubclass: IRI resolved correctlygood=GoodSubclass(tool=[parent_iri])
print(good.__iris__.get("tool")) # ['Item:OSW...'] ✓print(good.tool[0].name) # 'test_parent' ✓# BadSubclass: ValidationErrorbad=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:

classFixedSubclass(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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions