code-loader 1.0.195.dev0__tar.gz → 1.0.195.dev1__tar.gz

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.
Files changed (37) hide show
  1. {code_loader-1.0.195.dev0 → code_loader-1.0.195.dev1}/PKG-INFO +1 -1
  2. {code_loader-1.0.195.dev0 → code_loader-1.0.195.dev1}/code_loader/contract/datasetclasses.py +64 -51
  3. {code_loader-1.0.195.dev0 → code_loader-1.0.195.dev1}/code_loader/inner_leap_binder/leapbinder.py +24 -101
  4. {code_loader-1.0.195.dev0 → code_loader-1.0.195.dev1}/code_loader/inner_leap_binder/leapbinder_decorators.py +277 -903
  5. {code_loader-1.0.195.dev0 → code_loader-1.0.195.dev1}/code_loader/leaploader.py +255 -203
  6. {code_loader-1.0.195.dev0 → code_loader-1.0.195.dev1}/code_loader/leaploaderbase.py +3 -67
  7. {code_loader-1.0.195.dev0 → code_loader-1.0.195.dev1}/code_loader/utils.py +5 -51
  8. {code_loader-1.0.195.dev0 → code_loader-1.0.195.dev1}/pyproject.toml +1 -2
  9. {code_loader-1.0.195.dev0 → code_loader-1.0.195.dev1}/LICENSE +0 -0
  10. {code_loader-1.0.195.dev0 → code_loader-1.0.195.dev1}/README.md +0 -0
  11. {code_loader-1.0.195.dev0 → code_loader-1.0.195.dev1}/code_loader/__init__.py +0 -0
  12. {code_loader-1.0.195.dev0 → code_loader-1.0.195.dev1}/code_loader/contract/__init__.py +0 -0
  13. {code_loader-1.0.195.dev0 → code_loader-1.0.195.dev1}/code_loader/contract/enums.py +0 -0
  14. {code_loader-1.0.195.dev0 → code_loader-1.0.195.dev1}/code_loader/contract/exceptions.py +0 -0
  15. {code_loader-1.0.195.dev0 → code_loader-1.0.195.dev1}/code_loader/contract/mapping.py +0 -0
  16. {code_loader-1.0.195.dev0 → code_loader-1.0.195.dev1}/code_loader/contract/responsedataclasses.py +0 -0
  17. {code_loader-1.0.195.dev0 → code_loader-1.0.195.dev1}/code_loader/contract/sim_config.py +0 -0
  18. {code_loader-1.0.195.dev0 → code_loader-1.0.195.dev1}/code_loader/contract/visualizer_classes.py +0 -0
  19. {code_loader-1.0.195.dev0 → code_loader-1.0.195.dev1}/code_loader/default_losses.py +0 -0
  20. {code_loader-1.0.195.dev0 → code_loader-1.0.195.dev1}/code_loader/default_metrics.py +0 -0
  21. {code_loader-1.0.195.dev0 → code_loader-1.0.195.dev1}/code_loader/experiment_api/__init__.py +0 -0
  22. {code_loader-1.0.195.dev0 → code_loader-1.0.195.dev1}/code_loader/experiment_api/api.py +0 -0
  23. {code_loader-1.0.195.dev0 → code_loader-1.0.195.dev1}/code_loader/experiment_api/cli_config_utils.py +0 -0
  24. {code_loader-1.0.195.dev0 → code_loader-1.0.195.dev1}/code_loader/experiment_api/client.py +0 -0
  25. {code_loader-1.0.195.dev0 → code_loader-1.0.195.dev1}/code_loader/experiment_api/epoch.py +0 -0
  26. {code_loader-1.0.195.dev0 → code_loader-1.0.195.dev1}/code_loader/experiment_api/experiment.py +0 -0
  27. {code_loader-1.0.195.dev0 → code_loader-1.0.195.dev1}/code_loader/experiment_api/experiment_context.py +0 -0
  28. {code_loader-1.0.195.dev0 → code_loader-1.0.195.dev1}/code_loader/experiment_api/types.py +0 -0
  29. {code_loader-1.0.195.dev0 → code_loader-1.0.195.dev1}/code_loader/experiment_api/utils.py +0 -0
  30. {code_loader-1.0.195.dev0 → code_loader-1.0.195.dev1}/code_loader/experiment_api/workingspace_config_utils.py +0 -0
  31. {code_loader-1.0.195.dev0 → code_loader-1.0.195.dev1}/code_loader/inner_leap_binder/__init__.py +0 -0
  32. {code_loader-1.0.195.dev0 → code_loader-1.0.195.dev1}/code_loader/mixpanel_tracker.py +0 -0
  33. {code_loader-1.0.195.dev0 → code_loader-1.0.195.dev1}/code_loader/plot_functions/__init__.py +0 -0
  34. {code_loader-1.0.195.dev0 → code_loader-1.0.195.dev1}/code_loader/plot_functions/plot_functions.py +0 -0
  35. {code_loader-1.0.195.dev0 → code_loader-1.0.195.dev1}/code_loader/plot_functions/visualize.py +0 -0
  36. {code_loader-1.0.195.dev0 → code_loader-1.0.195.dev1}/code_loader/visualizers/__init__.py +0 -0
  37. {code_loader-1.0.195.dev0 → code_loader-1.0.195.dev1}/code_loader/visualizers/default_visualizers.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: code-loader
3
- Version: 1.0.195.dev0
3
+ Version: 1.0.195.dev1
4
4
  Summary:
5
5
  Home-page: https://github.com/tensorleap/code-loader
6
6
  License: MIT
@@ -1,6 +1,6 @@
1
1
  import warnings
2
2
  from dataclasses import dataclass, field
3
- from typing import Any, Callable, List, Optional, Dict, Union, Type, Literal, Tuple
3
+ from typing import Any, Callable, List, Optional, Dict, Union, Type, Literal, cast
4
4
  import re
5
5
  import numpy as np
6
6
  import numpy.typing as npt
@@ -15,6 +15,8 @@ custom_latent_space_attribute = "custom_latent_space"
15
15
 
16
16
  _simulation_context: Dict[str, bool] = {"active": False}
17
17
 
18
+ SampleId = Union[int, str]
19
+
18
20
 
19
21
  @dataclass
20
22
  class PreprocessResponse:
@@ -39,27 +41,44 @@ class PreprocessResponse:
39
41
  """
40
42
  length: Optional[int] = None # Deprecated. Please use sample_ids instead
41
43
  data: Any = None
42
- sample_ids: Optional[Union[List[str], List[int]]] = None
44
+ sample_ids: Optional[Union[List[SampleId], List[List[SampleId]]]] = None
43
45
  state: Optional[DataStateType] = None
44
46
  sample_id_type: Optional[Union[Type[str], Type[int]]] = None
45
47
  sample_ids_to_instance_mappings: Optional[Dict[str, List[str]]] = None # in use only for element instance
46
48
  instance_to_sample_ids_mappings: Optional[Dict[str, str]] = None # in use only for element instance
47
49
  tl_generated: bool = False
50
+ _grouped: bool = field(default=False, init=False, repr=False, compare=False)
48
51
 
49
52
  def __post_init__(self) -> None:
50
53
  assert self.sample_ids_to_instance_mappings is None, f"Keep sample_ids_to_instance_mappings None when initializing PreprocessResponse"
51
54
  assert self.instance_to_sample_ids_mappings is None, f"Keep instance_to_sample_ids_mappings None when initializing PreprocessResponse"
52
55
 
53
56
  if self.length is not None and self.sample_ids is None:
54
- self.sample_ids = [i for i in range(self.length)]
57
+ self.sample_ids = cast(List[SampleId], [i for i in range(self.length)])
55
58
  self.sample_id_type = int
59
+ self._grouped = False
56
60
  elif self.length is None and self.sample_ids is not None:
57
- self.length = len(self.sample_ids)
58
- if self.sample_id_type is None:
59
- self.sample_id_type = str
60
- if self.sample_id_type == str:
61
- for sample_id in self.sample_ids:
62
- assert isinstance(sample_id, str), f"Sample id should be of type str. Got: {type(sample_id)}"
61
+ self._grouped = len(self.sample_ids) > 0 and isinstance(self.sample_ids[0], list)
62
+ if self._grouped:
63
+ groups = cast(List[List[SampleId]], self.sample_ids)
64
+ assert len(groups) >= 1, "Grouped PreprocessResponse must have at least one group."
65
+ for group in groups:
66
+ assert isinstance(group, list) and len(group) > 0, \
67
+ "Each group in a grouped PreprocessResponse must be a non-empty list."
68
+ self.sample_id_type = type(groups[0][0])
69
+ for group in groups:
70
+ for sample_id in group:
71
+ assert isinstance(sample_id, self.sample_id_type), \
72
+ f"Sample id should be of type {self.sample_id_type.__name__}. Got: {type(sample_id)}"
73
+ self.length = sum(len(group) for group in groups)
74
+ else:
75
+ flat_ids = cast(List[SampleId], self.sample_ids)
76
+ self.length = len(flat_ids)
77
+ if self.sample_id_type is None:
78
+ self.sample_id_type = str
79
+ if self.sample_id_type == str:
80
+ for sample_id in flat_ids:
81
+ assert isinstance(sample_id, str), f"Sample id should be of type str. Got: {type(sample_id)}"
63
82
  else:
64
83
  raise Exception("length is deprecated, please use sample_ids instead.")
65
84
 
@@ -79,9 +98,36 @@ class PreprocessResponse:
79
98
  return id(self)
80
99
 
81
100
  def __len__(self) -> int:
101
+ assert self.length is not None
102
+ return self.length
103
+
104
+ @property
105
+ def is_grouped(self) -> bool:
106
+ return self._grouped
107
+
108
+ @property
109
+ def num_groups(self) -> int:
110
+ # Grouped: the number of groups. Flat: the (flat) sample count, since sample_ids is the
111
+ # flat id list and there is one sample per "group".
82
112
  assert self.sample_ids is not None
83
113
  return len(self.sample_ids)
84
114
 
115
+ @property
116
+ def groups(self) -> Optional[List[List[SampleId]]]:
117
+ # The nested list of groups when grouped, otherwise None. Callers should
118
+ # branch on is_grouped before relying on this.
119
+ return cast(List[List[SampleId]], self.sample_ids) if self._grouped else None
120
+
121
+ @property
122
+ def flat_sample_ids(self) -> List[SampleId]:
123
+ # All sample ids in order: concatenation of the groups when grouped,
124
+ # otherwise the flat sample_ids list as-is.
125
+ assert self.sample_ids is not None
126
+ if self._grouped:
127
+ groups = cast(List[List[SampleId]], self.sample_ids)
128
+ return [sample_id for group in groups for sample_id in group]
129
+ return cast(List[SampleId], self.sample_ids)
130
+
85
131
  @dataclass
86
132
  class ElementInstance:
87
133
  name: str
@@ -92,19 +138,15 @@ SectionCallableInterface = Callable[[Union[int, str], PreprocessResponse], npt.N
92
138
  InstanceCallableInterface = Callable[[Union[int, str], PreprocessResponse, int], Optional[ElementInstance]]
93
139
  InstanceLengthCallableInterface = Callable[[Union[int, str], PreprocessResponse], int]
94
140
 
95
- # (sample_id, prev_inputs, prev_outputs, state, preprocess) -> (next model inputs | None, state).
96
- # First call per chain receives prev_inputs=None, prev_outputs=None, state=None and returns the
97
- # initial model inputs plus the initial state. Returning next_inputs=None ends the chain the
98
- # terminating call still returns state, so the final step participates in state aggregation.
99
- # State is an arbitrary nest of dicts/lists holding numpy arrays, numbers, strings or bools; it is
100
- # never fed to the model and rides the engine's redis queue on every step, so accumulate
101
- # reductions, not raw per-step tensors. The hook must be stateless and deterministically seeded
102
- # (the engine may replay a step after crash recovery and relies on identical results).
103
- AutoregressiveChainState = Any
141
+ # (sample_id, prev_inputs, prev_outputs, preprocess) -> next model inputs, or None to end the chain.
142
+ # First call per chain receives prev_inputs=None, prev_outputs=None and returns the initial inputs.
143
+ # Keys starting with '_' are passthrough state: never fed to the model, handed back verbatim in
144
+ # prev_inputs on the next call. The hook must be stateless and deterministically seeded (the engine
145
+ # may replay a step after crash recovery and relies on identical results).
104
146
  AutoregressiveStepCallableInterface = Callable[
105
147
  [Union[int, str], Optional[Dict[str, npt.NDArray[np.float32]]], Optional[Dict[str, npt.NDArray[np.float32]]],
106
- AutoregressiveChainState, PreprocessResponse],
107
- Tuple[Optional[Dict[str, npt.NDArray[np.float32]]], AutoregressiveChainState]]
148
+ PreprocessResponse],
149
+ Optional[Dict[str, npt.NDArray[np.float32]]]]
108
150
 
109
151
  MetadataSectionCallableInterface = Union[
110
152
  Callable[[Union[int, str], PreprocessResponse], int],
@@ -260,42 +302,16 @@ class CustomLatentSpaceHandler:
260
302
  # dominates the model inputs). 'mean': every latent space is the elementwise mean over all steps.
261
303
  AUTOREGRESSIVE_LATENT_SPACE_AGGREGATIONS = ('last_step', 'mean')
262
304
 
263
- # Reserved argument names of autoregressive metrics/losses/visualizers, fed implicitly by the
264
- # platform from the finished chain (per-chain dicts, no batch axis). Any other argument is wired
265
- # to a ground-truth encoder through the integration test.
266
- AUTOREGRESSIVE_IMPLICIT_ARG_NAMES = ('inputs', 'outputs', 'state')
267
-
268
305
 
269
306
  @dataclass
270
307
  class AutoregressiveStepHandler:
271
308
  function: AutoregressiveStepCallableInterface
272
309
  name: str = 'autoregressive_step'
273
- # Per-model-input shapes (unbatched), discovered by running the hook's first call at parse
274
- # time. Fills the role InputHandler.shape plays for input encoders.
310
+ # Per-model-input shapes (unbatched, underscore passthrough keys excluded), discovered by running
311
+ # the hook's first call at parse time. Fills the role InputHandler.shape plays for input encoders.
275
312
  input_shapes: Optional[Dict[str, List[int]]] = None
276
313
  latent_space_aggregation: str = 'last_step'
277
314
 
278
-
279
- # Per-chain, unbatched callables: called once per finished chain with the final step's tensors —
280
- # inputs/outputs/state are fed implicitly by the platform (dicts, no batch axis; outputs keyed by
281
- # prediction-type names), remaining args are wired ground-truth encoder results.
282
- @dataclass
283
- class AutoregressiveMetricHandler:
284
- metric_handler_data: MetricHandlerData
285
- function: CustomCallableInterfaceMultiArgs
286
-
287
-
288
- @dataclass
289
- class AutoregressiveLossHandler:
290
- custom_loss_handler_data: CustomLossHandlerData
291
- function: CustomCallableInterface
292
-
293
-
294
- @dataclass
295
- class AutoregressiveVisualizerHandler:
296
- visualizer_handler_data: VisualizerHandlerData
297
- function: VisualizerCallableInterface
298
-
299
315
  @dataclass
300
316
  class PredictionTypeHandler:
301
317
  name: str
@@ -337,9 +353,6 @@ class DatasetIntegrationSetup:
337
353
  custom_latent_space: Optional[CustomLatentSpaceHandler] = None
338
354
  simulations: List[SimulationHandler] = field(default_factory=list)
339
355
  autoregressive_step: Optional[AutoregressiveStepHandler] = None
340
- autoregressive_metrics: List[AutoregressiveMetricHandler] = field(default_factory=list)
341
- autoregressive_losses: List[AutoregressiveLossHandler] = field(default_factory=list)
342
- autoregressive_visualizers: List[AutoregressiveVisualizerHandler] = field(default_factory=list)
343
356
 
344
357
 
345
358
  @dataclass
@@ -1,6 +1,6 @@
1
1
 
2
2
  import inspect
3
- from typing import Callable, List, Optional, Dict, Any, Type, Union, get_args
3
+ from typing import Callable, List, Optional, Dict, Any, Type, Union, get_args, cast
4
4
 
5
5
  import numpy as np
6
6
  import numpy.typing as npt
@@ -14,8 +14,7 @@ from code_loader.contract.datasetclasses import SectionCallableInterface, InputH
14
14
  RawInputsForHeatmap, VisualizerHandlerData, MetricHandlerData, CustomLossHandlerData, SamplePreprocessResponse, \
15
15
  ElementInstanceMasksHandler, InstanceCallableInterface, CustomLatentSpaceHandler, InstanceMetricHandler, \
16
16
  SimulationHandler, _simulation_context, AutoregressiveStepHandler, AutoregressiveStepCallableInterface, \
17
- AUTOREGRESSIVE_LATENT_SPACE_AGGREGATIONS, AUTOREGRESSIVE_IMPLICIT_ARG_NAMES, \
18
- AutoregressiveMetricHandler, AutoregressiveLossHandler, AutoregressiveVisualizerHandler
17
+ AUTOREGRESSIVE_LATENT_SPACE_AGGREGATIONS
19
18
  from code_loader.contract.enums import LeapDataType, DataStateEnum, DataStateType, MetricDirection, DatasetMetadataType
20
19
  from code_loader.contract.mapping import NodeConnection, NodeMapping, NodeMappingType
21
20
  from code_loader.contract.responsedataclasses import DatasetTestResultPayload, LeapAnalysisConfiguration
@@ -554,83 +553,6 @@ class LeapBinder:
554
553
 
555
554
  self.set_metadata(builtin_chain_metadata, 'builtin_chain')
556
555
 
557
- def _autoregressive_arg_names(self, function: Callable[..., Any], decorator_name: str,
558
- name: str) -> List[str]:
559
- """Split an autoregressive callable's signature into implicit chain args (validated
560
- present) and wired arg names (returned) — the wired args connect to ground-truth
561
- encoders through the integration test."""
562
- argspec = inspect.getfullargspec(function)
563
- for arg_name, arg_type in argspec.annotations.items():
564
- _reject_stringized_sample_preprocess_response(function, arg_name, arg_type)
565
- if arg_type == SamplePreprocessResponse:
566
- raise Exception(
567
- f'{decorator_name} "{name}": SamplePreprocessResponse arguments are not '
568
- f'supported for autoregressive decorators yet. Derive what you need inside '
569
- f'the autoregressive step hook and carry it in the state.')
570
- implicit = [arg_name for arg_name in argspec[0]
571
- if arg_name in AUTOREGRESSIVE_IMPLICIT_ARG_NAMES]
572
- if not implicit:
573
- raise Exception(
574
- f'{decorator_name} "{name}": the function must declare at least one of the '
575
- f'implicit chain arguments {list(AUTOREGRESSIVE_IMPLICIT_ARG_NAMES)} — they are '
576
- f'fed by the platform from the finished chain.')
577
- return [arg_name for arg_name in argspec[0]
578
- if arg_name not in AUTOREGRESSIVE_IMPLICIT_ARG_NAMES]
579
-
580
- def _assert_unique_metric_name(self, name: str) -> None:
581
- existing = [handler.metric_handler_data.name for handler in self.setup_container.metrics] \
582
- + [handler.metric_handler_data.name
583
- for handler in self.setup_container.autoregressive_metrics]
584
- if name in existing:
585
- raise Exception(f'Metric with name {name} already exists. Please choose another')
586
-
587
- def _assert_unique_loss_name(self, name: str) -> None:
588
- existing = [handler.custom_loss_handler_data.name
589
- for handler in self.setup_container.custom_loss_handlers] \
590
- + [handler.custom_loss_handler_data.name
591
- for handler in self.setup_container.autoregressive_losses]
592
- if name in existing:
593
- raise Exception(f'Custom loss with name {name} already exists. Please choose another')
594
-
595
- def _assert_unique_visualizer_name(self, name: str) -> None:
596
- existing = [handler.visualizer_handler_data.name
597
- for handler in self.setup_container.visualizers] \
598
- + [handler.visualizer_handler_data.name
599
- for handler in self.setup_container.autoregressive_visualizers]
600
- if name in existing:
601
- raise Exception(f'Visualizer with name {name} already exists. Please choose another')
602
-
603
- def add_autoregressive_metric(self, function: CustomCallableInterfaceMultiArgs, name: str,
604
- direction: Optional[Union[MetricDirection, Dict[str, MetricDirection]]]
605
- = MetricDirection.Downward,
606
- compute_insights: Optional[Union[bool, Dict[str, bool]]] = None) -> None:
607
- self._assert_unique_metric_name(name)
608
- arg_names = self._autoregressive_arg_names(function, 'tensorleap_autoregressive_metric',
609
- name)
610
- metric_handler_data = MetricHandlerData(name, arg_names, direction, compute_insights)
611
- self.setup_container.autoregressive_metrics.append(
612
- AutoregressiveMetricHandler(metric_handler_data, function))
613
-
614
- def add_autoregressive_loss(self, function: CustomCallableInterface, name: str) -> None:
615
- self._assert_unique_loss_name(name)
616
- arg_names = self._autoregressive_arg_names(function, 'tensorleap_autoregressive_loss',
617
- name)
618
- self.setup_container.autoregressive_losses.append(
619
- AutoregressiveLossHandler(CustomLossHandlerData(name, arg_names), function))
620
-
621
- def add_autoregressive_visualizer(self, function: VisualizerCallableInterface, name: str,
622
- visualizer_type: LeapDataType) -> None:
623
- self._assert_unique_visualizer_name(name)
624
- if visualizer_type.value not in map_leap_data_type_to_visualizer_class:
625
- raise Exception(
626
- f'The visualizer_type is invalid. current visualizer_type: {visualizer_type}, '
627
- f'should be one of : {", ".join([arg.__name__ for arg in get_args(LeapData)])}')
628
- arg_names = self._autoregressive_arg_names(
629
- function, 'tensorleap_autoregressive_visualizer', name)
630
- self.setup_container.autoregressive_visualizers.append(
631
- AutoregressiveVisualizerHandler(VisualizerHandlerData(name, visualizer_type,
632
- arg_names), function))
633
-
634
556
  def set_custom_layer(self, custom_layer: Type[Any], name: str, inspect_layer: bool = False,
635
557
  kernel_index: Optional[int] = None, use_custom_latent_space: bool = False) -> None:
636
558
  """
@@ -713,6 +635,15 @@ class LeapBinder:
713
635
  if state_enum in preprocess_result_dict:
714
636
  preprocess_result_dict_in_correct_order[state_enum] = preprocess_result_dict[state_enum]
715
637
 
638
+ # All-or-none: every state must agree on grouped (nested sample_ids) vs flat.
639
+ if len({r.is_grouped for r in preprocess_result_dict_in_correct_order.values()}) > 1:
640
+ shapes = ', '.join(
641
+ f"{state.name}={'grouped' if r.is_grouped else 'flat'}"
642
+ for state, r in preprocess_result_dict_in_correct_order.items())
643
+ raise Exception(
644
+ "All preprocess states must be either all grouped (nested sample_ids) or all flat, "
645
+ f"but got a mix: {shapes}.")
646
+
716
647
  return preprocess_result_dict_in_correct_order
717
648
 
718
649
  def get_preprocess_unlabeled_result(self) -> Optional[PreprocessResponse]:
@@ -733,7 +664,15 @@ class LeapBinder:
733
664
  preprocess_response: PreprocessResponse, test_result: List[DatasetTestResultPayload],
734
665
  dataset_base_handler: Union[DatasetBaseHandler, MetadataHandler], state: DataStateEnum) -> List[DatasetTestResultPayload]:
735
666
  assert preprocess_response.sample_ids is not None
736
- raw_result = dataset_base_handler.function(preprocess_response.sample_ids[0], preprocess_response)
667
+ if preprocess_response.is_grouped:
668
+ # Grouped: probe with the first group, then reduce to a single sample's result so the
669
+ # recorded shape/type is per-sample (matching the flat case), not the (B, *) batch.
670
+ # (casts: sample_ids[0] is a group list here, and the grouped result is a per-sample list.)
671
+ group = preprocess_response.sample_ids[0]
672
+ raw_result = cast(Any, dataset_base_handler.function(cast(Any, group), preprocess_response))[0]
673
+ else:
674
+ raw_result = dataset_base_handler.function(
675
+ cast(Union[int, str], preprocess_response.sample_ids[0]), preprocess_response)
737
676
  handler_type = 'metadata' if isinstance(dataset_base_handler, MetadataHandler) else None
738
677
  if isinstance(dataset_base_handler, MetadataHandler):
739
678
  if isinstance(raw_result, dict):
@@ -829,10 +768,11 @@ class LeapBinder:
829
768
  preprocess_response.tl_generated = True
830
769
  if not preprocess_response.length or preprocess_response.length < 1:
831
770
  raise Exception("Simulation '{}' returned PreprocessResponse with length < 1".format(sim.name))
832
- preprocess_response.sample_ids = [0]
771
+ preprocess_response.sample_ids = cast(List[Union[int, str]], [0])
772
+ sim_sample_ids = cast(List[Union[int, str]], preprocess_response.sample_ids)
833
773
  for handler in self.setup_container.inputs:
834
- out1 = handler.function(preprocess_response.sample_ids[0], preprocess_response)
835
- out2 = handler.function(preprocess_response.sample_ids[0], preprocess_response)
774
+ out1 = handler.function(sim_sample_ids[0], preprocess_response)
775
+ out2 = handler.function(sim_sample_ids[0], preprocess_response)
836
776
  if not np.allclose(out1, out2):
837
777
  raise Exception(
838
778
  "Simulation '{}': encoder '{}' is non-deterministic — consecutive calls with seed=0 returned different outputs".format(
@@ -856,23 +796,6 @@ class LeapBinder:
856
796
  appear in any order in the integration file.
857
797
  """
858
798
  if self.setup_container.autoregressive_step is None:
859
- declared_autoregressive = [
860
- ('tensorleap_autoregressive_metric',
861
- [handler.metric_handler_data.name
862
- for handler in self.setup_container.autoregressive_metrics]),
863
- ('tensorleap_autoregressive_loss',
864
- [handler.custom_loss_handler_data.name
865
- for handler in self.setup_container.autoregressive_losses]),
866
- ('tensorleap_autoregressive_visualizer',
867
- [handler.visualizer_handler_data.name
868
- for handler in self.setup_container.autoregressive_visualizers]),
869
- ]
870
- for decorator_name, names in declared_autoregressive:
871
- if names:
872
- raise Exception(
873
- f'{decorator_name} {names} requires a tensorleap_autoregressive_step '
874
- f'hook — autoregressive decorators consume the finished chain the hook '
875
- f'drives.')
876
799
  return
877
800
  if self.setup_container.inputs:
878
801
  raise Exception(