Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 14 additions & 9 deletions src/rune/runtime/metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from enum import Enum
from functools import partial, lru_cache
from decimal import Decimal
from typing import Any, Never, get_args
from typing import Any, Never, get_args, Iterable
from typing_extensions import Self, Tuple
from pydantic import (PlainSerializer, PlainValidator, WrapValidator,
WrapSerializer)
Expand All @@ -19,6 +19,10 @@
RUNE_OBJ_MAPS = '__rune_object_maps'


def _replaceable(prop):
return isinstance(prop, (BaseMetaDataMixin, UnresolvedReference, Reference))


def _py_to_ser_key(key: str) -> str:
if key[0] == '@':
return key
Expand Down Expand Up @@ -203,8 +207,9 @@ def get_rune_parent(self) -> Self | None:
def _get_meta_container(self) -> dict[str, Any]:
return self.__dict__.get(META_CONTAINER, {})

def _merged_allowed_meta(self, allowed_meta: set[str]) -> set[str]:
default_meta = getattr(self, DEFAULT_META, set())
def _merged_allowed_meta(
self, allowed_meta: set[str] | Iterable[str]) -> set[str]:
default_meta: set[str] = getattr(self, DEFAULT_META, set())
return set(allowed_meta) | default_meta

def _check_props_allowed(self, props: dict[str, Any]):
Expand All @@ -231,9 +236,10 @@ def _init_meta(self, allowed_meta: set[str]):

def _bind_property_to(self, property_nm: str, ref: Reference):
'''set the property to reference the object referenced by the key'''
old_val = getattr(self, property_nm)
allowed_ref_types = getattr(self, '_KEY_REF_CONSTRAINTS', {})
if ref.key_type.rune_ref_tag not in allowed_ref_types.get(
property_nm, {}):
if (ref.key_type.rune_ref_tag not in allowed_ref_types.get(
property_nm, {}) and not _replaceable(old_val)):
raise ValueError(f'Ref of type {ref.key_type} '
f'not allowed for {property_nm}. Allowed types '
f'are: {allowed_ref_types.get(property_nm, {})}')
Expand All @@ -245,18 +251,17 @@ def _bind_property_to(self, property_nm: str, ref: Reference):
raise ValueError("Can't set reference. Incompatible types: "
f"expected {allowed_type}, "
f"got {ref.target.__class__}")

refs = self.__dict__.setdefault(REFS_CONTAINER, {})
if property_nm not in refs:
# not a reference - check if allowed to replace with one
old_val = getattr(self, property_nm)
if not isinstance(
old_val,
(BaseMetaDataMixin, UnresolvedReference, Reference)):
if not _replaceable(old_val):
raise ValueError(f'Property {property_nm} of type '
f"{type(old_val)} can't be a reference")
# pylint: disable=protected-access
if isinstance(old_val, BaseMetaDataMixin):
old_val._check_props_allowed({ref.key_type.rune_ref_tag: ''})

# setattr(self, property_nm, ref.target) # nope - need to avoid here!
self.__dict__[property_nm] = ref.target # NOTE: avoid here setattr
refs[property_nm] = (ref.target_key, ref.key_type)
Expand Down