More attempts to fix a bug.

This commit is contained in:
Yaro Kasear 2025-10-21 08:54:15 -05:00
parent bd2daf921a
commit dd863dba99
3 changed files with 102 additions and 21 deletions

View file

@ -145,16 +145,18 @@ def _split_field_tokens(fields: Iterable[str]) -> Tuple[List[str], Dict[str, Lis
def _deep_get_loaded(obj: Any, dotted: str) -> Any:
"""
Deep get with no lazy loads:
- Walk intermediate hops via _safe_get_loaded_attr only.
- Final hop: prefer _safe_get_loaded_attr; if that returns an ORM object or a collection of ORM objects,
serialize to simple dicts; else return the plain value.
- Intermediate hops via _safe_get_loaded_attr only.
- Final hop:
* If relationship and not loaded: return None
* else allow getattr for non-relationship attrs (hybrids/properties) that compute from already-loaded data.
* Serialize ORM objects at the lead into dicts
"""
parts = dotted.split(".")
if not parts:
return None
cur = obj
# Traverse up to parent of last token without lazy-loads
# Traverse up to the parent of the last token safely
for part in parts[:-1]:
if cur is None:
return None
@ -163,24 +165,36 @@ def _deep_get_loaded(obj: Any, dotted: str) -> Any:
return None
last = parts[-1]
# If last is an ORM relationship, only return it if already loaded.
m = _sa_mapper(cur)
if m is not None and last in m.relationships:
val = _safe_get_loaded_attr(cur, last)
if val is None:
return None
# serialize relationship value
if _sa_mapper(val) is not None:
return _serialize_simple_obj(val)
if isinstance(val, (list, tuple)):
out = []
for v in val:
out.append(_serialize_simple_obj(v) if _sa_mapper(v) is not None else v)
return out
return val
# Not a relationship: try loaded value, else safe getattr
val = _safe_get_loaded_attr(cur, last)
if val is None:
# Do NOT lazy load. If it isn't loaded, treat as absent.
return None
try:
# getattr here will not lazy-load relationships because we already gated those
val = getattr(cur, last, None)
except Exception:
val = None
# If the final hop is an ORM object or collection, serialize it
if _sa_mapper(val) is not None:
return _serialize_simple_obj(val)
if isinstance(val, (list, tuple)):
out = []
for v in val:
if _sa_mapper(v) is not None:
out.append(_serialize_simple_obj(v))
else:
out.append(v)
return out
# Plain scalar/computed value
return [_serialize_simple_obj(v) if _sa_mapper(v) is not None else v for v in val]
return val
def _serialize_leaf(obj: Any) -> Any: