resolve_references does not traverse list members — @ref inside list elements remain unresolved
@plamen-neykov ci sta già lavorando.
Dal 15/9/2026.
Valutazione
Questa issue non è ancora stata valutata.
Descrizione
Bug Report
resolve_references does not traverse list members — @ref inside list elements remain unresolved
Steps to Reproduce
- Clone the repository and set up the development environment:
git clone https://github.com/regnosys/rune-python-runtime
cd rune-python-runtime
./dev_clean_setup.sh
source .pydevenv/bin/activate
- Run the following self-contained script (no external dependencies beyond the runtime itself):
import json
from typing import List
from typing_extensions import Annotated
from pydantic import Field
from rune.runtime.base_data_class import BaseDataClass
# A keyed type — instances can be registered under an external key
class Party(BaseDataClass):
_ALLOWED_METADATA = {'@key:external'}
name: str = Field(..., description='party name')
# A type whose partyReference field is a @ref to a Party
class Counterparty(BaseDataClass):
role: str = Field(..., description='role')
partyReference: Annotated[
Party,
Party.serializer(),
Party.validator(allowed_meta=('@ref:external',))
] = Field(..., description='reference to party')
_KEY_REF_CONSTRAINTS = {'partyReference': {'@ref:external'}}
# Trade holds parties (the keys) and counterparties (the refs) both as lists
class Trade(BaseDataClass):
party: List[Party] = Field(..., description='parties')
counterparty: List[Counterparty] = Field(..., description='counterparties')
data = json.dumps({
"party": [
{"@key:external": "p1", "name": "Party A"},
{"@key:external": "p2", "name": "Party B"}
],
"counterparty": [
{"role": "Party1", "partyReference": {"@ref:external": "p1"}},
{"role": "Party2", "partyReference": {"@ref:external": "p2"}}
]
})
# Step A — inspect reference type after deserialize with validate_model=False
t = Trade.rune_deserialize(data, validate_model=False)
print("counterparty[0].partyReference:", type(t.counterparty[0].partyReference).__name__)
print("counterparty[1].partyReference:", type(t.counterparty[1].partyReference).__name__)
# Step B — deserialize with validate_model=True (default)
t2 = Trade.rune_deserialize(data, validate_model=True)
Expected Result
Step A: both partyReference fields are resolved to Party instances after rune_deserialize.
Step B: deserialization completes without error.
Actual Result
Step A — references are not resolved:
counterparty[0].partyReference: UnresolvedReference
counterparty[1].partyReference: UnresolvedReference
Step B — ValidationError is raised because validate_attribs re-runs model_validate on the already-constructed model and Pydantic rejects the remaining UnresolvedReference objects:
pydantic.ValidationError: 2 validation errors for Trade
counterparty.0.partyReference
Expected either <class 'Party'> or dict but got <class 'rune.runtime.metadata.UnresolvedReference'>.
[type=Input Validation Error, input_type=UnresolvedReference]
counterparty.1.partyReference
Expected either <class 'Party'> or dict but got <class 'rune.runtime.metadata.UnresolvedReference'>.
[type=Input Validation Error, input_type=UnresolvedReference]
Root Cause
BaseDataClass.resolve_references recurses only into properties that are direct BaseDataClass instances. It does not descend into list members:
# base_data_class.py — resolve_references
if recurse:
for prop_nm, obj in self.__dict__.items():
if (isinstance(obj, BaseDataClass) # ← True for scalar fields only
and not prop_nm.startswith('__')):
obj.resolve_references(...)
# list-valued properties are silently skipped
Trade.counterparty is a list — isinstance(list, BaseDataClass) is False, so the Counterparty items inside it are never visited and their partyReference fields remain as UnresolvedReference.
Environment
rune-python-runtimeversion: 2.2.0- Python: 3.11
- OS: macOS Darwin 25.6.0
Additional Context
Proposed fix — extend the recursion in resolve_references to traverse list members:
if recurse:
for prop_nm, obj in self.__dict__.items():
if prop_nm.startswith('__'):
continue
if isinstance(obj, BaseDataClass):
obj.resolve_references(ignore_dangling=ignore_dangling,
recurse=recurse)
elif isinstance(obj, list):
for item in obj:
if isinstance(item, BaseDataClass):
item.resolve_references(ignore_dangling=ignore_dangling,
recurse=recurse)
Impact — any Rune model JSON that uses @ref inside a list-valued field is affected:
validate_model=False— reference silently remainsUnresolvedReference; downstream attribute access fails at runtimevalidate_model=True(default) —ValidationErrorraised immediately, preventing use of the deserialized object
- Lingua principale
- Python
- Stelle
- 0
- Fork
- 3
- Merge medio
- 8h 25m
- PR unite (30g)
- 3
Preparare l'ambiente
- Nessun Dockerfile né file Docker Compose
- Nessun modello di pull request
- Leggi la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di finos/rune-python-runtime
-
Difficoltà 5/5 Più di una settimana Idoneità per principianti 35/100
finos/rune-python-runtime#42 ·
-
Difficoltà 3/5 1-2 giorni Idoneità per principianti 62/100
finos/rune-python-runtime#27 ·
-
Difficoltà 5/5 Più di una settimana Idoneità per principianti 25/100
finos/rune-python-runtime#16 ·
-
Difficoltà 4/5 3-5 giorni Idoneità per principianti 35/100
finos/rune-python-runtime#15 · 1 commento ·
Tutte le issue di finos/rune-python-runtime
Issue simili
-
needs-human needs-triage
Difficoltà 2/5 1-3 ore Idoneità per principianti 76/100
gke-labs/kube-agents#2400 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno
-
Device Details tables: FS/SF columns contradict each other (nfet_01v8 Vt row, pfet_01v8 Idsat row)Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 75/100
google/skywater-pdk#450 ·
-
Drained trajectory arrays are overwritten when the sequence buffer is reusedForse già presa @sylvesterkaczmarek l’ha presa oggi. Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
google-deepmind/bsuite#56 ·
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 82/100
LearningCircuit/local-deep-research#7206 ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 68/100
chingu-voyages/V62-tier3-team-33#285 ·
I maintainer di solito rispondono entro 1 giorno