1010import builtins
1111import inspect
1212import linecache
13+ import pathlib
1314import textwrap
1415from dataclasses import asdict
1516from typing import Any
@@ -47,8 +48,11 @@ def encode_operand_reference(obj):
4748 return blosc2 .Ref .from_object (obj ).to_dict ()
4849
4950
50- def decode_operand_reference (payload ):
51- return blosc2 .Ref .from_dict (payload ).open ()
51+ def decode_operand_reference (payload , * , base_path = None ):
52+ ref = blosc2 .Ref .from_dict (payload )
53+ if ref .kind == "urlpath" and base_path is not None and not pathlib .Path (ref .urlpath ).is_absolute ():
54+ return blosc2 .open (base_path / ref .urlpath , mode = "r" )
55+ return ref .open ()
5256
5357
5458def encode_b2object_payload (obj ) -> dict [str , Any ] | None :
@@ -98,7 +102,7 @@ def encode_b2object_payload(obj) -> dict[str, Any] | None:
98102 return None
99103
100104
101- def decode_b2object_payload (payload : dict [str , Any ]):
105+ def decode_b2object_payload (payload : dict [str , Any ], * , carrier_path = None ):
102106 kind = payload .get ("kind" )
103107 version = payload .get ("version" )
104108 if version != _B2OBJECT_VERSION :
@@ -107,24 +111,39 @@ def decode_b2object_payload(payload: dict[str, Any]):
107111 ref = blosc2 .Ref .from_dict (payload )
108112 return ref .open ()
109113 if kind == "lazyexpr" :
110- return decode_structured_lazyexpr (payload )
114+ return decode_structured_lazyexpr (payload , carrier_path = carrier_path )
111115 if kind == "lazyudf" :
112- return decode_structured_lazyudf (payload )
116+ return decode_structured_lazyudf (payload , carrier_path = carrier_path )
113117 raise ValueError (f"Unsupported persisted Blosc2 object kind: { kind !r} " )
114118
115119
116- def decode_structured_lazyexpr (payload ):
120+ def decode_structured_lazyexpr (payload , * , carrier_path = None ):
117121 expression = payload .get ("expression" )
118122 if not isinstance (expression , str ):
119123 raise TypeError ("Structured LazyExpr payload requires a string 'expression'" )
120124 operands_payload = payload .get ("operands" )
121125 if not isinstance (operands_payload , dict ):
122126 raise TypeError ("Structured LazyExpr payload requires a mapping 'operands'" )
123- operands = {key : decode_operand_reference (value ) for key , value in operands_payload .items ()}
127+ operands = {}
128+ missing_ops = {}
129+ for key , value in operands_payload .items ():
130+ try :
131+ operands [key ] = decode_operand_reference (value , base_path = carrier_path )
132+ except FileNotFoundError :
133+ ref = blosc2 .Ref .from_dict (value )
134+ if ref .kind == "urlpath" :
135+ missing_ops [key ] = pathlib .Path (ref .urlpath )
136+ else :
137+ raise
138+ if missing_ops :
139+ exc = blosc2 .exceptions .MissingOperands (expression , missing_ops )
140+ exc .expr = expression
141+ exc .missing_ops = missing_ops
142+ raise exc
124143 return blosc2 .lazyexpr (expression , operands = operands )
125144
126145
127- def decode_structured_lazyudf (payload ):
146+ def decode_structured_lazyudf (payload , * , carrier_path = None ):
128147 function_kind = payload .get ("function_kind" )
129148 if function_kind != "dsl" :
130149 raise ValueError (f"Unsupported structured LazyUDF function kind: { function_kind !r} " )
@@ -167,7 +186,8 @@ def decode_structured_lazyudf(payload):
167186 func .dsl_source = dsl_source
168187
169188 operands = tuple (
170- decode_operand_reference (operands_payload [f"o{ n } " ]) for n in range (len (operands_payload ))
189+ decode_operand_reference (operands_payload [f"o{ n } " ], base_path = carrier_path )
190+ for n in range (len (operands_payload ))
171191 )
172192 return blosc2 .lazyudf (func , operands , dtype = np .dtype (dtype ), shape = tuple (shape_payload ), ** kwargs )
173193
@@ -194,4 +214,12 @@ def open_b2object(obj):
194214 raise ValueError (f"Unsupported persisted Blosc2 object version: { marker .get ('version' )!r} " )
195215 if marker .get ("kind" ) != payload .get ("kind" ):
196216 raise ValueError ("Persisted Blosc2 object marker/payload kind mismatch" )
197- return decode_b2object_payload (payload )
217+ carrier_path = None
218+ schunk = getattr (obj , "schunk" , obj )
219+ if getattr (schunk , "urlpath" , None ) is not None :
220+ carrier_path = pathlib .Path (schunk .urlpath ).parent
221+ opened = decode_b2object_payload (payload , carrier_path = carrier_path )
222+ if isinstance (opened , blosc2 .LazyExpr | blosc2 .LazyUDF ):
223+ opened .array = obj
224+ opened .schunk = schunk
225+ return opened
0 commit comments