code-loader 1.0.182.dev0__py3-none-any.whl → 1.0.184__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
code_loader/leaploader.py CHANGED
@@ -7,7 +7,7 @@ import sys
7
7
  from contextlib import redirect_stdout
8
8
  from functools import lru_cache
9
9
  from pathlib import Path
10
- from typing import Dict, List, Iterable, Union, Any, Type, Optional, Callable, Tuple
10
+ from typing import Dict, List, Iterable, Set, Union, Any, Type, Optional, Callable, Tuple
11
11
 
12
12
  import numpy as np
13
13
  import numpy.typing as npt
@@ -44,6 +44,8 @@ class LeapLoader(LeapLoaderBase):
44
44
  super().__init__(code_path, code_entry_name)
45
45
 
46
46
  self._preprocess_result_cached = None
47
+ self._synthetic_lookup: Dict[str, Tuple[PreprocessResponse, Any]] = {}
48
+ self._synthetic_populator: Optional[Callable[[str], None]] = None
47
49
 
48
50
  try:
49
51
  from code_loader.mixpanel_tracker import track_code_loader_loaded
@@ -187,8 +189,62 @@ class LeapLoader(LeapLoaderBase):
187
189
  for prediction_type in setup.prediction_types
188
190
  }
189
191
 
192
+ def set_synthetic_populator(self, populator: Optional[Callable[[str], None]]) -> None:
193
+ # Hook called by `_resolve_synthetic` when a synthetic sample_id is requested
194
+ # but not yet in `_synthetic_lookup`. The populator should call `run_simulation`
195
+ # for the recipe that produced sample_id, or raise if the recipe can't be
196
+ # resolved. After the call, the entire batch the recipe produced is in
197
+ # `_synthetic_lookup`, so subsequent lookups for sibling sample_ids skip the hook.
198
+ self._synthetic_populator = populator
199
+
200
+ def _user_additional_ids_set(self) -> Set[str]:
201
+ # Membership-test helper for distinguishing user-defined additional samples
202
+ # from synthetic ones. In consumer pods, the populator passes
203
+ # extend_preprocess=False to run_simulation, so additional.sample_ids stays
204
+ # uncontaminated and direct membership check is reliable.
205
+ additional = self._preprocess_result().get(DataStateEnum.additional)
206
+ if additional is None:
207
+ return set()
208
+ return set(additional.sample_ids)
209
+
210
+ def _resolve_synthetic(self, sample_id: Union[int, str],
211
+ state: Optional[DataStateEnum] = None
212
+ ) -> Optional[Tuple[PreprocessResponse, Any]]:
213
+ # Resolution flow for state==additional:
214
+ # 1. already-replayed synthetic ID (member of _synthetic_lookup) → cached synthetic flow
215
+ # 2. user-defined ID (member of preprocess[additional].sample_ids) → return None
216
+ # so caller falls through to normal preprocess flow (no recipe lookup built)
217
+ # 3. populator: builds recipe index lazily on first call, replays the missing
218
+ # recipe, populates _synthetic_lookup. Loud-raises on unresolvable IDs.
219
+ #
220
+ # Order rationale: _synthetic_lookup check sits before the user-response check
221
+ # to be robust against `_extend_additional_preprocess` mutation (producer side
222
+ # calls run_simulation with extend_preprocess=True, which appends synthetic IDs
223
+ # into preprocess[additional]). Once an ID is in _synthetic_lookup, that wins
224
+ # regardless of contamination in the preprocess response.
225
+ if not isinstance(sample_id, str):
226
+ return None
227
+ if state != DataStateEnum.additional:
228
+ return None
229
+ if sample_id in self._synthetic_lookup:
230
+ return self._synthetic_lookup[sample_id]
231
+ if sample_id in self._user_additional_ids_set():
232
+ return None
233
+ if self._synthetic_populator is None:
234
+ return None
235
+ self._synthetic_populator(sample_id)
236
+ return self._synthetic_lookup.get(sample_id)
237
+
190
238
  def get_sample(self, state: DataStateEnum, sample_id: Union[int, str], instance_id: int = None) -> DatasetSample:
191
239
  self.exec_script()
240
+
241
+ resolved = self._resolve_synthetic(sample_id, state=state)
242
+ if resolved is not None:
243
+ sim_preprocess, original_local_id = resolved
244
+ return self._get_sample_from_preprocess(
245
+ sim_preprocess, original_local_id, synthetic_index=sample_id
246
+ )
247
+
192
248
  preprocess_result = self._preprocess_result()
193
249
  if state == DataStateEnum.unlabeled and sample_id not in preprocess_result[state].sample_ids:
194
250
  self._preprocess_result(update_unlabeled_preprocess=True)
@@ -211,6 +267,50 @@ class LeapLoader(LeapLoaderBase):
211
267
  instance_masks=instance_mask)
212
268
  return sample
213
269
 
270
+ def _get_sample_from_preprocess(
271
+ self,
272
+ preprocess: "PreprocessResponse",
273
+ original_sample_id: Union[int, str],
274
+ synthetic_index: str,
275
+ ) -> DatasetSample:
276
+ inputs = {}
277
+ for handler in global_leap_binder.setup_container.inputs:
278
+ inputs[handler.name] = handler.function(original_sample_id, preprocess)
279
+
280
+ gt = {}
281
+ for handler in global_leap_binder.setup_container.ground_truths:
282
+ gt[handler.name] = handler.function(original_sample_id, preprocess)
283
+
284
+ metadata = {}
285
+ metadata_is_none = {}
286
+ for handler in global_leap_binder.setup_container.metadata:
287
+ handler_result = handler.function(original_sample_id, preprocess)
288
+ if isinstance(handler_result, dict):
289
+ for k, v in handler_result.items():
290
+ key = "{}_{}".format(handler.name, k)
291
+ metadata[key], metadata_is_none[key] = self._convert_metadata_to_correct_type(key, v)
292
+ else:
293
+ metadata[handler.name], metadata_is_none[handler.name] = self._convert_metadata_to_correct_type(
294
+ handler.name, handler_result
295
+ )
296
+
297
+ custom_latent_space = None
298
+ if global_leap_binder.setup_container.custom_latent_space is not None:
299
+ custom_latent_space = global_leap_binder.setup_container.custom_latent_space.function(
300
+ original_sample_id, preprocess
301
+ )
302
+
303
+ return DatasetSample(
304
+ inputs=inputs,
305
+ gt=gt if gt else None,
306
+ metadata=metadata,
307
+ metadata_is_none=metadata_is_none,
308
+ index=synthetic_index,
309
+ state=DataStateEnum.additional,
310
+ custom_latent_space=custom_latent_space,
311
+ instance_masks=None,
312
+ )
313
+
214
314
  def check_dataset(self) -> DatasetIntegParseResult:
215
315
  test_payloads: List[DatasetTestResultPayload] = []
216
316
  setup_response = None
@@ -345,8 +445,13 @@ class LeapLoader(LeapLoaderBase):
345
445
  result_payloads.append(test_result)
346
446
  return result_payloads
347
447
 
348
- def run_simulation(self, sim_name, params=None, n_samples=1, seed=0):
349
- # type: (str, Optional[Dict[str, Any]], int, int) -> Dict[str, npt.NDArray[np.float32]]
448
+ def run_simulation(self, sim_name, params=None, n_samples=1, seed=0,
449
+ sample_ids=None, extend_preprocess=True):
450
+ # type: (str, Optional[Dict[str, Any]], int, int, Optional[List[str]], bool) -> Dict[str, Any]
451
+ # extend_preprocess=True (default): also extend preprocess_result[additional] with the
452
+ # new synthetic sample_ids (producer-side behavior — synthetic worker needs this for
453
+ # enumeration / data_length tracking). Pass False from consumer-side populators that
454
+ # only need _synthetic_lookup filled, so user's additional response stays uncontaminated.
350
455
  self.exec_script()
351
456
  sim = next(
352
457
  (s for s in global_leap_binder.setup_container.simulations if s.name == sim_name),
@@ -364,11 +469,51 @@ class LeapLoader(LeapLoaderBase):
364
469
  _simulation_context["active"] = False
365
470
  sim_preprocess.state = DataStateType.additional
366
471
  sim_preprocess.tl_generated = True
472
+ original_sample_ids = list(sim_preprocess.sample_ids)
367
473
  per_encoder = {handler.name: [] for handler in global_leap_binder.setup_container.inputs}
368
- for sample_id in sim_preprocess.sample_ids:
474
+ for sample_id in original_sample_ids:
369
475
  for handler in global_leap_binder.setup_container.inputs:
370
476
  per_encoder[handler.name].append(handler.function(sample_id, sim_preprocess))
371
- return {name: np.stack(arrays) for name, arrays in per_encoder.items()}
477
+ encoded = {name: np.stack(arrays) for name, arrays in per_encoder.items()}
478
+ if sample_ids is not None:
479
+ if len(sample_ids) != len(original_sample_ids):
480
+ raise ValueError(
481
+ "sample_ids length ({}) does not match simulation output length ({})".format(
482
+ len(sample_ids), len(original_sample_ids)
483
+ )
484
+ )
485
+ for sid in sample_ids:
486
+ if not isinstance(sid, str):
487
+ raise TypeError(
488
+ "All sample_ids must be of type str. Got: {}".format(type(sid))
489
+ )
490
+ for synth_id, original_local_id in zip(sample_ids, original_sample_ids):
491
+ self._synthetic_lookup[synth_id] = (sim_preprocess, original_local_id)
492
+ if extend_preprocess:
493
+ self._extend_additional_preprocess(list(sample_ids))
494
+ returned_sample_ids = list(sample_ids)
495
+ else:
496
+ returned_sample_ids = original_sample_ids
497
+ return {"encoded": encoded, "sample_ids": returned_sample_ids}
498
+
499
+ def _extend_additional_preprocess(self, new_sample_ids: List[str]) -> None:
500
+ if self._preprocess_result_cached is None:
501
+ self._preprocess_result()
502
+ additional = self._preprocess_result_cached.get(DataStateEnum.additional)
503
+ if additional is None:
504
+ placeholder = PreprocessResponse(
505
+ sample_ids=list(new_sample_ids),
506
+ data={},
507
+ state=DataStateType.additional,
508
+ sample_id_type=str,
509
+ tl_generated=True,
510
+ )
511
+ self._preprocess_result_cached[DataStateEnum.additional] = placeholder
512
+ global_leap_binder.setup_container.preprocess.data_length[DataStateType.additional] = placeholder.length
513
+ else:
514
+ additional.sample_ids = list(additional.sample_ids) + list(new_sample_ids)
515
+ additional.length = len(additional.sample_ids)
516
+ global_leap_binder.setup_container.preprocess.data_length[DataStateType.additional] = additional.length
372
517
 
373
518
  @staticmethod
374
519
  def _get_all_dataset_base_handlers() -> List[Union[DatasetBaseHandler, MetadataHandler]]:
@@ -583,7 +728,13 @@ class LeapLoader(LeapLoaderBase):
583
728
  state: DataStateEnum, sample_id: Union[int, str]) -> Dict[str, npt.NDArray[np.float32]]:
584
729
  result_agg = {}
585
730
  preprocess_result = self._preprocess_result()
586
- preprocess_state = preprocess_result[state]
731
+ resolved = self._resolve_synthetic(sample_id, state=state)
732
+ if resolved is not None:
733
+ sim_preprocess, original_local_id = resolved
734
+ preprocess_state = sim_preprocess
735
+ sample_id = original_local_id
736
+ else:
737
+ preprocess_state = preprocess_result[state]
587
738
  for handler in handlers:
588
739
  handler_result = handler.function(sample_id, preprocess_state)
589
740
  handler_name = handler.name
@@ -597,7 +748,13 @@ class LeapLoader(LeapLoaderBase):
597
748
  if instance_id is None:
598
749
  return None
599
750
  preprocess_result = self._preprocess_result()
600
- preprocess_state = preprocess_result[state]
751
+ resolved = self._resolve_synthetic(sample_id, state=state)
752
+ if resolved is not None:
753
+ sim_preprocess, original_local_id = resolved
754
+ preprocess_state = sim_preprocess
755
+ sample_id = original_local_id
756
+ else:
757
+ preprocess_state = preprocess_result[state]
601
758
  result_agg = {}
602
759
  for handler in global_leap_binder.setup_container.instance_masks:
603
760
  handler_result = handler.function(sample_id, preprocess_state, instance_id)
@@ -657,7 +814,13 @@ class LeapLoader(LeapLoaderBase):
657
814
  result_agg = {}
658
815
  is_none = {}
659
816
  preprocess_result = self._preprocess_result()
660
- preprocess_state = preprocess_result[state]
817
+ resolved = self._resolve_synthetic(sample_id, state=state)
818
+ if resolved is not None:
819
+ sim_preprocess, original_local_id = resolved
820
+ preprocess_state = sim_preprocess
821
+ sample_id = original_local_id
822
+ else:
823
+ preprocess_state = preprocess_result[state]
661
824
  for handler in global_leap_binder.setup_container.metadata:
662
825
  if requested_metadata_names:
663
826
  if not is_metadata_name_starts_with_handler_name(handler):
@@ -698,17 +861,9 @@ class LeapLoader(LeapLoaderBase):
698
861
  return global_leap_binder.setup_container.custom_latent_space is not None
699
862
 
700
863
  def get_instances_data(self, state: DataStateEnum) -> Tuple[Dict[str, List[str]], Dict[str, str]]:
701
- """
702
- This Method get the data state and returns two dictionaries that holds the mapping of the sample ids to their
703
- instances and the other way around and the sample ids array.
704
- Args:
705
- state: DataStateEnum state
706
- Returns:
707
- sample_ids_to_instance_mappings: sample id to instance mappings
708
- instance_to_sample_ids_mappings: instance to sample ids mappings
709
- sample_ids: sample ids array
710
- """
711
864
  preprocess_result = self._preprocess_result()
712
- preprocess_state = preprocess_result[state]
865
+ preprocess_state = preprocess_result.get(state)
866
+ if preprocess_state is None:
867
+ return None, None
713
868
  return preprocess_state.sample_ids_to_instance_mappings, preprocess_state.instance_to_sample_ids_mappings
714
869
 
@@ -154,8 +154,8 @@ class LeapLoaderBase:
154
154
  pass
155
155
 
156
156
  @abstractmethod
157
- def run_simulation(self, sim_name, params=None, n_samples=1, seed=0):
158
- # type: (str, Optional[Dict[str, Any]], int, int) -> Dict[str, Any]
157
+ def run_simulation(self, sim_name, params=None, n_samples=1, seed=0, sample_ids=None):
158
+ # type: (str, Optional[Dict[str, Any]], int, int, Optional[List[str]]) -> Dict[str, Any]
159
159
  pass
160
160
 
161
161
  def is_custom_latent_space(self) -> bool:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: code-loader
3
- Version: 1.0.182.dev0
3
+ Version: 1.0.184
4
4
  Summary:
5
5
  Home-page: https://github.com/tensorleap/code-loader
6
6
  License: MIT
@@ -23,8 +23,8 @@ code_loader/experiment_api/workingspace_config_utils.py,sha256=DLzXQCg4dgTV_YgaS
23
23
  code_loader/inner_leap_binder/__init__.py,sha256=koOlJyMNYzGbEsoIbXathSmQ-L38N_pEXH_HvL7beXU,99
24
24
  code_loader/inner_leap_binder/leapbinder.py,sha256=XLYYcV50qjMvoC1S6WW0tLBch_0g5gl1UyHiVSWYbvg,40491
25
25
  code_loader/inner_leap_binder/leapbinder_decorators.py,sha256=YlK51b5Ryo396f7tOA7Ole3vYCLs3f5ZLm2qDQ9K1NE,105781
26
- code_loader/leaploader.py,sha256=Md-CsdLiBVfeGIlVqpVjNVF_fEAFbg2ahmVCCPl3iOw,36758
27
- code_loader/leaploaderbase.py,sha256=HrOGX9H8eRbyrFOEdvC2OISJvtZWKMVDah0cry8PXlo,6492
26
+ code_loader/leaploader.py,sha256=K9Q5kiCZ_A2GkS5qOEantAMvWGaz3bmO1X8buXDSpgg,44682
27
+ code_loader/leaploaderbase.py,sha256=l36qDA00GhZEG5NLKpEtAXgWJA-UQQIhNFGxywK7mUA,6530
28
28
  code_loader/mixpanel_tracker.py,sha256=rNwRmFifNbdUoqLQvvhhgpKczWpWiEmd8MfyJe27sxw,9131
29
29
  code_loader/plot_functions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
30
30
  code_loader/plot_functions/plot_functions.py,sha256=6Q7VWGxetL2W0EK2QeCdObVATvBuHs3YBA09H4uoIk0,14996
@@ -32,7 +32,7 @@ code_loader/plot_functions/visualize.py,sha256=gsBAYYkwMh7jIpJeDMPS8G4CW-pxwx6Lz
32
32
  code_loader/utils.py,sha256=YecipkdTA-VcE9F0RQcY9cFnY8P3AksPnHM2Db7xUSk,3972
33
33
  code_loader/visualizers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
34
34
  code_loader/visualizers/default_visualizers.py,sha256=onRnLE_TXfgLN4o52hQIOOhUcFexGlqJ3xSpQDVLuZM,2604
35
- code_loader-1.0.182.dev0.dist-info/LICENSE,sha256=qIwWjdspQeSMTtnFZBC8MuT-95L02FPvzRUdWFxrwJY,1067
36
- code_loader-1.0.182.dev0.dist-info/METADATA,sha256=qmRxIYq5blbCPlBU8gavN-RNdC8fK3pxS-ckMVME2fI,1095
37
- code_loader-1.0.182.dev0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
38
- code_loader-1.0.182.dev0.dist-info/RECORD,,
35
+ code_loader-1.0.184.dist-info/LICENSE,sha256=qIwWjdspQeSMTtnFZBC8MuT-95L02FPvzRUdWFxrwJY,1067
36
+ code_loader-1.0.184.dist-info/METADATA,sha256=iOj4cFbRfozrJ0PW7vnYNeTHxqDkT5F0IJHW8kbkrX4,1090
37
+ code_loader-1.0.184.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
38
+ code_loader-1.0.184.dist-info/RECORD,,