@@ -26,20 +26,24 @@ def _resolve(self) -> np.ndarray:
2626 # Real chumpy Ch instances store the underlying ndarray on attribute ``x``;
2727 # legacy pickles unpickle by restoring ``__dict__`` without calling ``__init__``,
2828 # so try common attribute names before falling back to ``_data``.
29+ r = self .__dict__ .get ("r" )
30+ if isinstance (r , np .ndarray ):
31+ return np .asarray (r )
2932 for attr in ("x" , "_x" , "_data" ):
3033 val = self .__dict__ .get (attr )
3134 if val is not None :
3235 return np .asarray (val )
33- if self ._data is not None :
34- return np .asarray (self ._data )
36+ data = self .__dict__ .get ("_data" )
37+ if data is not None :
38+ return np .asarray (data )
3539 return np .zeros ((), dtype = np .float32 )
3640
37- @property
3841 def r (self ) -> np .ndarray :
42+ """Match real chumpy API (``ch.r()`` returns the underlying array)."""
3943 return self ._resolve ()
4044
4145 def __array__ (self , dtype = None ):
42- arr = self .r ()
46+ arr = self ._resolve ()
4347 if dtype is not None :
4448 arr = arr .astype (dtype , copy = False )
4549 return arr
@@ -49,10 +53,30 @@ class ChArray(np.ndarray):
4953 """Minimal stand-in for ``chumpy.ch.ChArray``."""
5054
5155
56+ def _unwrap_ch (value , dtype = np .float32 ) -> np .ndarray :
57+ """Resolve a chumpy ``Ch`` (method, property, or unpickled ``r``/``x`` attrs) to ndarray."""
58+ if isinstance (value , Ch ):
59+ return np .asarray (value ._resolve (), dtype = dtype )
60+ r = getattr (value , "r" , None )
61+ if isinstance (r , np .ndarray ):
62+ return np .asarray (r , dtype = dtype )
63+ if callable (r ):
64+ return np .asarray (r (), dtype = dtype )
65+ for attr in ("x" , "_x" , "_data" ):
66+ val = getattr (value , attr , None )
67+ if val is not None :
68+ return np .asarray (val , dtype = dtype )
69+ raise TypeError (f"Cannot materialize chumpy-like object: { type (value )!r} " )
70+
71+
5272def materialize (value , dtype = np .float32 ) -> np .ndarray :
5373 """Recursively unwrap ``Ch`` / object arrays from legacy SMAL pickles."""
54- if isinstance (value , Ch ):
55- return np .asarray (value .r (), dtype = dtype )
74+ if isinstance (value , Ch ) or (
75+ type (value ).__name__ == "Ch"
76+ and hasattr (value , "r" )
77+ and not isinstance (value , (np .ndarray , list , tuple , dict , str , bytes ))
78+ ):
79+ return _unwrap_ch (value , dtype = dtype )
5680 if isinstance (value , np .ndarray ):
5781 if value .dtype == object :
5882 flat = [materialize (x , dtype = dtype ) for x in value .ravel ()]
0 commit comments