Source code for bridge.pipelines.protocols.none_propagation
"""
SafeAttr proxy class for safe attribute/item access and deep unwrapping utility.
"""
from collections.abc import Mapping, Sequence, Set
[docs]
class SafeAttr:
"""
A proxy class that safely accesses attributes and items of an underlying object.
If an attribute or item does not exist, it returns a SafeAttr wrapping None instead of raising an exception.
"""
__slots__ = ("_v",)
def __init__(self, v):
object.__setattr__(self, "_v", v)
def __getattr__(self, name):
try:
return SafeAttr(getattr(self._v, name))
except Exception:
return SafeAttr(None)
def __getitem__(self, key):
try:
return SafeAttr(self._v[key])
except Exception:
return SafeAttr(None)
def __call__(self, *args, **kwargs):
"""
Call the underlying object if it is callable, returning a SafeAttr wrapping the result.
"""
if callable(self._v):
try:
return SafeAttr(self._v(*args, **kwargs))
except Exception:
return SafeAttr(None)
return SafeAttr(None)
def __iter__(self):
v = self._v
if v is None or isinstance(v, (str, bytes, bytearray)) or isinstance(v, Mapping):
return iter(()) # don’t fake iteration
try:
it = iter(v)
except TypeError:
return iter(())
return (SafeAttr(x) for x in it)
def __len__(self):
try:
return len(self._v)
except Exception:
return 0
def __bool__(self):
return bool(self._v)
[docs]
def unwrap(self, default=None):
"""
Unwrap the underlying value, or return default if None.
Parameters
----------
default : Any
The default value to return if the underlying value is None.
Returns
-------
Any
The deeply unwrapped value.
"""
return self._v if self._v is not None else default
def __repr__(self):
return f"SafeAttr({self._v!r})"
[docs]
def deep_unwrap(v, *, _seen=None):
"""
Recursively unwrap SafeAttr instances within common container types.
Parameters
----------
v : Any
The value to unwrap.
_seen : set | None
Internal set to track seen object IDs for cycle detection.
Returns
-------
Any
The deeply unwrapped value.
"""
# Only unwrap SafeAttr and common container *interfaces*.
if isinstance(v, SafeAttr):
return deep_unwrap(v.unwrap(), _seen=_seen)
# Primitives / scalars just pass through.
if isinstance(v, (str, bytes, bytearray)) or v is None:
return v
# Cycle guard
if _seen is None:
_seen = set()
try:
oid = id(v)
if oid in _seen:
return v
_seen.add(oid)
except Exception:
# Unhashable / odd cases — just return as-is.
return v
if isinstance(v, Mapping):
return {deep_unwrap(k, _seen=_seen): deep_unwrap(val, _seen=_seen) for k, val in v.items()}
if isinstance(v, Set):
return {deep_unwrap(x, _seen=_seen) for x in v}
if isinstance(v, Sequence) and not isinstance(v, (str, bytes, bytearray)):
return [deep_unwrap(x, _seen=_seen) for x in v]
# Any other (your “hundreds of custom types”) — leave intact.
return v