Source code for httk.core.vectors.vector_native
"""
Backend wrapping plain nested sequences (lists/tuples of numeric or string leaves).
"""
import decimal
import fractions
from typing import Any
from .fracvector import FracVector
from .vector_api import Fractions
from .vector_backend import VectorBackend
from .vector_frac import _fracvector_to_fractions
_LEAF_TYPES = (int, float, decimal.Decimal, fractions.Fraction, str)
def _is_native(obj: Any) -> bool:
"""
Conservatively validate that ``obj`` is a rectangular (possibly nested) list/tuple whose
leaves are all int/float/Decimal/Fraction/str.
"""
if not isinstance(obj, (list, tuple)):
return False
return _valid(obj)
def _valid(node: Any) -> bool:
if isinstance(node, (list, tuple)):
if len(node) == 0:
return True
child_is_seq = isinstance(node[0], (list, tuple))
length = len(node[0]) if child_is_seq else None
for c in node:
if isinstance(c, (list, tuple)) != child_is_seq:
return False
if child_is_seq and len(c) != length:
return False
if not _valid(c):
return False
return True
return isinstance(node, _LEAF_TYPES)
[docs]
class VectorNative(VectorBackend):
"""
Backend for a vector backed by plain nested sequences.
The native representation is a (possibly nested) rectangular list or tuple whose leaves are
``int``, ``float``, :class:`decimal.Decimal`, :class:`fractions.Fraction`, or ``str``.
Conversion into the exact ``fractions`` interchange goes through
:meth:`~httk.core.vectors.fracvector.FracVector.create`, so string-uncertainty parsing
(e.g. ``"0.33342(10)"``) works here too. ``unwrap`` returns the original raw object.
"""
_raw: Any
_fracvector_cache: FracVector | None
# Cannot type annotate __new__ as `Self | None` for some reason
def __new__(cls, obj: Any, **hints: Any) -> Any:
if hints and hints.get("kind", "native") != "native":
return None
if not _is_native(obj):
return None
return super().__new__(cls)
def __init__(self, obj: Any, **hints: Any) -> None:
self._raw = obj
self._fracvector_cache = None
@property
[docs]
def native(self) -> Any:
"""
The original nested list/tuple this backend wraps, leaves untouched.
This is the same object returned by :meth:`unwrap`, exposed as a named accessor so the
native view can present a natively-held vector's leaves *verbatim* (its preserve-original
default) without reaching into private state.
"""
return self._raw
def _as_fracvector(self) -> FracVector:
if self._fracvector_cache is None:
self._fracvector_cache = FracVector.create(self._raw)
return self._fracvector_cache
@property
[docs]
def fractions(self) -> Fractions:
return _fracvector_to_fractions(self._as_fracvector())
@property
[docs]
def dim(self) -> tuple[int, ...]:
return self._as_fracvector().dim
[docs]
def unwrap(self) -> Any:
return self._raw