code-loader 1.0.197.dev1__tar.gz → 1.0.198__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.
- {code_loader-1.0.197.dev1 → code_loader-1.0.198}/PKG-INFO +1 -1
- {code_loader-1.0.197.dev1 → code_loader-1.0.198}/code_loader/contract/datasetclasses.py +66 -10
- {code_loader-1.0.197.dev1 → code_loader-1.0.198}/code_loader/inner_leap_binder/leapbinder.py +75 -7
- {code_loader-1.0.197.dev1 → code_loader-1.0.198}/code_loader/inner_leap_binder/leapbinder_decorators.py +219 -62
- {code_loader-1.0.197.dev1 → code_loader-1.0.198}/code_loader/leaploader.py +289 -9
- {code_loader-1.0.197.dev1 → code_loader-1.0.198}/code_loader/utils.py +10 -0
- {code_loader-1.0.197.dev1 → code_loader-1.0.198}/pyproject.toml +1 -2
- {code_loader-1.0.197.dev1 → code_loader-1.0.198}/LICENSE +0 -0
- {code_loader-1.0.197.dev1 → code_loader-1.0.198}/README.md +0 -0
- {code_loader-1.0.197.dev1 → code_loader-1.0.198}/code_loader/__init__.py +0 -0
- {code_loader-1.0.197.dev1 → code_loader-1.0.198}/code_loader/contract/__init__.py +0 -0
- {code_loader-1.0.197.dev1 → code_loader-1.0.198}/code_loader/contract/enums.py +0 -0
- {code_loader-1.0.197.dev1 → code_loader-1.0.198}/code_loader/contract/exceptions.py +0 -0
- {code_loader-1.0.197.dev1 → code_loader-1.0.198}/code_loader/contract/mapping.py +0 -0
- {code_loader-1.0.197.dev1 → code_loader-1.0.198}/code_loader/contract/responsedataclasses.py +0 -0
- {code_loader-1.0.197.dev1 → code_loader-1.0.198}/code_loader/contract/sim_config.py +0 -0
- {code_loader-1.0.197.dev1 → code_loader-1.0.198}/code_loader/contract/visualizer_classes.py +0 -0
- {code_loader-1.0.197.dev1 → code_loader-1.0.198}/code_loader/default_losses.py +0 -0
- {code_loader-1.0.197.dev1 → code_loader-1.0.198}/code_loader/default_metrics.py +0 -0
- {code_loader-1.0.197.dev1 → code_loader-1.0.198}/code_loader/experiment_api/__init__.py +0 -0
- {code_loader-1.0.197.dev1 → code_loader-1.0.198}/code_loader/experiment_api/api.py +0 -0
- {code_loader-1.0.197.dev1 → code_loader-1.0.198}/code_loader/experiment_api/cli_config_utils.py +0 -0
- {code_loader-1.0.197.dev1 → code_loader-1.0.198}/code_loader/experiment_api/client.py +0 -0
- {code_loader-1.0.197.dev1 → code_loader-1.0.198}/code_loader/experiment_api/epoch.py +0 -0
- {code_loader-1.0.197.dev1 → code_loader-1.0.198}/code_loader/experiment_api/experiment.py +0 -0
- {code_loader-1.0.197.dev1 → code_loader-1.0.198}/code_loader/experiment_api/experiment_context.py +0 -0
- {code_loader-1.0.197.dev1 → code_loader-1.0.198}/code_loader/experiment_api/types.py +0 -0
- {code_loader-1.0.197.dev1 → code_loader-1.0.198}/code_loader/experiment_api/utils.py +0 -0
- {code_loader-1.0.197.dev1 → code_loader-1.0.198}/code_loader/experiment_api/workingspace_config_utils.py +0 -0
- {code_loader-1.0.197.dev1 → code_loader-1.0.198}/code_loader/inner_leap_binder/__init__.py +0 -0
- {code_loader-1.0.197.dev1 → code_loader-1.0.198}/code_loader/leaploaderbase.py +0 -0
- {code_loader-1.0.197.dev1 → code_loader-1.0.198}/code_loader/mixpanel_tracker.py +0 -0
- {code_loader-1.0.197.dev1 → code_loader-1.0.198}/code_loader/plot_functions/__init__.py +0 -0
- {code_loader-1.0.197.dev1 → code_loader-1.0.198}/code_loader/plot_functions/plot_functions.py +0 -0
- {code_loader-1.0.197.dev1 → code_loader-1.0.198}/code_loader/plot_functions/visualize.py +0 -0
- {code_loader-1.0.197.dev1 → code_loader-1.0.198}/code_loader/visualizers/__init__.py +0 -0
- {code_loader-1.0.197.dev1 → code_loader-1.0.198}/code_loader/visualizers/default_visualizers.py +0 -0
|
@@ -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, Tuple, 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,54 @@ 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[
|
|
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)
|
|
51
|
+
_group_pos_cache: Optional[Dict[SampleId, Tuple[List[SampleId], int]]] = field(
|
|
52
|
+
default=None, init=False, repr=False, compare=False)
|
|
48
53
|
|
|
49
54
|
def __post_init__(self) -> None:
|
|
50
55
|
assert self.sample_ids_to_instance_mappings is None, f"Keep sample_ids_to_instance_mappings None when initializing PreprocessResponse"
|
|
51
56
|
assert self.instance_to_sample_ids_mappings is None, f"Keep instance_to_sample_ids_mappings None when initializing PreprocessResponse"
|
|
52
57
|
|
|
53
58
|
if self.length is not None and self.sample_ids is None:
|
|
54
|
-
self.sample_ids = [i for i in range(self.length)]
|
|
59
|
+
self.sample_ids = cast(List[SampleId], [i for i in range(self.length)])
|
|
55
60
|
self.sample_id_type = int
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
if self.
|
|
61
|
-
|
|
62
|
-
|
|
61
|
+
self._grouped = False
|
|
62
|
+
elif self.sample_ids is not None:
|
|
63
|
+
given_length = self.length
|
|
64
|
+
self._grouped = len(self.sample_ids) > 0 and isinstance(self.sample_ids[0], list)
|
|
65
|
+
if self._grouped:
|
|
66
|
+
groups = cast(List[List[SampleId]], self.sample_ids)
|
|
67
|
+
assert len(groups) >= 1, "Grouped PreprocessResponse must have at least one group."
|
|
68
|
+
for group in groups:
|
|
69
|
+
assert isinstance(group, list) and len(group) > 0, \
|
|
70
|
+
"Each group in a grouped PreprocessResponse must be a non-empty list."
|
|
71
|
+
self.sample_id_type = type(groups[0][0])
|
|
72
|
+
assert issubclass(self.sample_id_type, (str, int)), \
|
|
73
|
+
f"Sample id should be of type str or int. Got: {self.sample_id_type.__name__}"
|
|
74
|
+
for group in groups:
|
|
75
|
+
for sample_id in group:
|
|
76
|
+
assert isinstance(sample_id, self.sample_id_type), \
|
|
77
|
+
f"Sample id should be of type {self.sample_id_type.__name__}. Got: {type(sample_id)}"
|
|
78
|
+
self.length = sum(len(group) for group in groups)
|
|
79
|
+
else:
|
|
80
|
+
flat_ids = cast(List[SampleId], self.sample_ids)
|
|
81
|
+
self.length = len(flat_ids)
|
|
82
|
+
if self.sample_id_type is None:
|
|
83
|
+
self.sample_id_type = str
|
|
84
|
+
if self.sample_id_type == str:
|
|
85
|
+
for sample_id in flat_ids:
|
|
86
|
+
assert isinstance(sample_id, str), f"Sample id should be of type str. Got: {type(sample_id)}"
|
|
87
|
+
# dataclasses.replace() re-invokes __init__ with both fields already populated
|
|
88
|
+
# (length previously derived from sample_ids); only reject a genuine mismatch.
|
|
89
|
+
if given_length is not None:
|
|
90
|
+
assert given_length == self.length, \
|
|
91
|
+
f"Inconsistent PreprocessResponse: length={given_length} but sample_ids implies {self.length}."
|
|
63
92
|
else:
|
|
64
93
|
raise Exception("length is deprecated, please use sample_ids instead.")
|
|
65
94
|
|
|
@@ -79,9 +108,36 @@ class PreprocessResponse:
|
|
|
79
108
|
return id(self)
|
|
80
109
|
|
|
81
110
|
def __len__(self) -> int:
|
|
111
|
+
assert self.length is not None
|
|
112
|
+
return self.length
|
|
113
|
+
|
|
114
|
+
@property
|
|
115
|
+
def is_grouped(self) -> bool:
|
|
116
|
+
return self._grouped
|
|
117
|
+
|
|
118
|
+
@property
|
|
119
|
+
def num_groups(self) -> int:
|
|
120
|
+
# Grouped: the number of groups. Flat: the (flat) sample count, since sample_ids is the
|
|
121
|
+
# flat id list and there is one sample per "group".
|
|
82
122
|
assert self.sample_ids is not None
|
|
83
123
|
return len(self.sample_ids)
|
|
84
124
|
|
|
125
|
+
@property
|
|
126
|
+
def groups(self) -> Optional[List[List[SampleId]]]:
|
|
127
|
+
# The nested list of groups when grouped, otherwise None. Callers should
|
|
128
|
+
# branch on is_grouped before relying on this.
|
|
129
|
+
return cast(List[List[SampleId]], self.sample_ids) if self._grouped else None
|
|
130
|
+
|
|
131
|
+
@property
|
|
132
|
+
def flat_sample_ids(self) -> List[SampleId]:
|
|
133
|
+
# All sample ids in order: concatenation of the groups when grouped,
|
|
134
|
+
# otherwise the flat sample_ids list as-is.
|
|
135
|
+
assert self.sample_ids is not None
|
|
136
|
+
if self._grouped:
|
|
137
|
+
groups = cast(List[List[SampleId]], self.sample_ids)
|
|
138
|
+
return [sample_id for group in groups for sample_id in group]
|
|
139
|
+
return cast(List[SampleId], self.sample_ids)
|
|
140
|
+
|
|
85
141
|
@dataclass
|
|
86
142
|
class ElementInstance:
|
|
87
143
|
name: str
|
{code_loader-1.0.197.dev1 → code_loader-1.0.198}/code_loader/inner_leap_binder/leapbinder.py
RENAMED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
|
|
2
|
+
import builtins
|
|
2
3
|
import inspect
|
|
3
|
-
|
|
4
|
+
import os
|
|
5
|
+
from contextlib import contextmanager
|
|
6
|
+
from typing import Callable, List, Optional, Dict, Any, Type, Union, get_args, cast, Iterator, Set
|
|
4
7
|
|
|
5
8
|
import numpy as np
|
|
6
9
|
import numpy.typing as npt
|
|
@@ -16,7 +19,8 @@ from code_loader.contract.datasetclasses import SectionCallableInterface, InputH
|
|
|
16
19
|
SimulationHandler, _simulation_context, AutoregressiveStepHandler, AutoregressiveStepCallableInterface, \
|
|
17
20
|
AUTOREGRESSIVE_LATENT_SPACE_AGGREGATIONS, AUTOREGRESSIVE_IMPLICIT_ARG_NAMES, \
|
|
18
21
|
AutoregressiveMetricHandler, AutoregressiveLossHandler, AutoregressiveVisualizerHandler
|
|
19
|
-
from code_loader.contract.enums import LeapDataType, DataStateEnum, DataStateType, MetricDirection, DatasetMetadataType
|
|
22
|
+
from code_loader.contract.enums import LeapDataType, DataStateEnum, DataStateType, MetricDirection, DatasetMetadataType, \
|
|
23
|
+
TestingSectionEnum
|
|
20
24
|
from code_loader.contract.mapping import NodeConnection, NodeMapping, NodeMappingType
|
|
21
25
|
from code_loader.contract.responsedataclasses import DatasetTestResultPayload, LeapAnalysisConfiguration
|
|
22
26
|
from code_loader.contract.visualizer_classes import map_leap_data_type_to_visualizer_class
|
|
@@ -33,6 +37,25 @@ from code_loader.visualizers.default_visualizers import DefaultVisualizer, \
|
|
|
33
37
|
mapping_runtime_mode_env_var_mame = '__MAPPING_RUNTIME_MODE__'
|
|
34
38
|
|
|
35
39
|
|
|
40
|
+
@contextmanager
|
|
41
|
+
def _track_opened_files() -> Iterator[Set[str]]:
|
|
42
|
+
opened: Set[str] = set()
|
|
43
|
+
original_open = builtins.open
|
|
44
|
+
|
|
45
|
+
def tracking_open(file: Any, *args: Any, **kwargs: Any) -> Any:
|
|
46
|
+
mode = args[0] if args else kwargs.get('mode', 'r')
|
|
47
|
+
is_read_mode = isinstance(mode, str) and not any(c in mode for c in ('a', 'w', 'x'))
|
|
48
|
+
if is_read_mode and isinstance(file, (str, os.PathLike)):
|
|
49
|
+
opened.add(os.fspath(file))
|
|
50
|
+
return original_open(file, *args, **kwargs)
|
|
51
|
+
|
|
52
|
+
builtins.open = tracking_open
|
|
53
|
+
try:
|
|
54
|
+
yield opened
|
|
55
|
+
finally:
|
|
56
|
+
builtins.open = original_open
|
|
57
|
+
|
|
58
|
+
|
|
36
59
|
def _stringized_annotation_type_name(annotation: Any) -> Optional[str]:
|
|
37
60
|
"""Bare type name if ``annotation`` is a stringized annotation (from ``from __future__
|
|
38
61
|
import annotations`` or a quoted hint), else ``None``. code_loader inspects raw
|
|
@@ -585,7 +608,9 @@ class LeapBinder:
|
|
|
585
608
|
# Builtin chain metadata, declared at parse time so it survives the reporter's
|
|
586
609
|
# metadata type mapping; the placeholder values are overwritten by the engine when a
|
|
587
610
|
# chain finalizes (realized length, truncated-by-safety-cap flag).
|
|
588
|
-
def builtin_chain_metadata(idx: Any, preprocess: PreprocessResponse) ->
|
|
611
|
+
def builtin_chain_metadata(idx: Any, preprocess: PreprocessResponse) -> Any:
|
|
612
|
+
if isinstance(idx, list):
|
|
613
|
+
return [{'length': -1, 'truncated': False} for _ in idx]
|
|
589
614
|
return {'length': -1, 'truncated': False}
|
|
590
615
|
|
|
591
616
|
self.set_metadata(builtin_chain_metadata, 'builtin_chain')
|
|
@@ -749,6 +774,15 @@ class LeapBinder:
|
|
|
749
774
|
if state_enum in preprocess_result_dict:
|
|
750
775
|
preprocess_result_dict_in_correct_order[state_enum] = preprocess_result_dict[state_enum]
|
|
751
776
|
|
|
777
|
+
# All-or-none: every state must agree on grouped (nested sample_ids) vs flat.
|
|
778
|
+
if len({r.is_grouped for r in preprocess_result_dict_in_correct_order.values()}) > 1:
|
|
779
|
+
shapes = ', '.join(
|
|
780
|
+
f"{state.name}={'grouped' if r.is_grouped else 'flat'}"
|
|
781
|
+
for state, r in preprocess_result_dict_in_correct_order.items())
|
|
782
|
+
raise Exception(
|
|
783
|
+
"All preprocess states must be either all grouped (nested sample_ids) or all flat, "
|
|
784
|
+
f"but got a mix: {shapes}.")
|
|
785
|
+
|
|
752
786
|
return preprocess_result_dict_in_correct_order
|
|
753
787
|
|
|
754
788
|
def get_preprocess_unlabeled_result(self) -> Optional[PreprocessResponse]:
|
|
@@ -769,7 +803,34 @@ class LeapBinder:
|
|
|
769
803
|
preprocess_response: PreprocessResponse, test_result: List[DatasetTestResultPayload],
|
|
770
804
|
dataset_base_handler: Union[DatasetBaseHandler, MetadataHandler], state: DataStateEnum) -> List[DatasetTestResultPayload]:
|
|
771
805
|
assert preprocess_response.sample_ids is not None
|
|
772
|
-
|
|
806
|
+
opened_files: Optional[Set[str]] = None
|
|
807
|
+
if preprocess_response.is_grouped:
|
|
808
|
+
# Grouped: probe with the first group, then reduce to a single sample's result so the
|
|
809
|
+
# recorded shape/type is per-sample (matching the flat case), not the (B, *) batch.
|
|
810
|
+
# (casts: sample_ids[0] is a group list here, and the grouped result is a per-sample list.)
|
|
811
|
+
group = preprocess_response.sample_ids[0]
|
|
812
|
+
with _track_opened_files() as opened_files:
|
|
813
|
+
raw_result = cast(Any, dataset_base_handler.function(cast(Any, group), preprocess_response))[0]
|
|
814
|
+
else:
|
|
815
|
+
raw_result = dataset_base_handler.function(
|
|
816
|
+
cast(Union[int, str], preprocess_response.sample_ids[0]), preprocess_response)
|
|
817
|
+
|
|
818
|
+
def _warn_if_group_spans_multiple_files(payloads: List[DatasetTestResultPayload]) -> None:
|
|
819
|
+
if opened_files is None or len(opened_files) <= 1:
|
|
820
|
+
return
|
|
821
|
+
shown = sorted(opened_files)[:5]
|
|
822
|
+
suffix = f" (+{len(opened_files) - 5} more)" if len(opened_files) > 5 else ""
|
|
823
|
+
warning = (
|
|
824
|
+
f"Encoding declared group 0 (size {len(cast(List[Any], group))}) for '{dataset_base_handler.name}' opened "
|
|
825
|
+
f"{len(opened_files)} distinct files: {shown}{suffix}. If this group is meant to be one "
|
|
826
|
+
f"physical source (e.g. one Parquet file), it may be grouped incorrectly - check your "
|
|
827
|
+
f"preprocess grouping logic. (Only files opened via Python's open() are tracked, so this "
|
|
828
|
+
f"can miss other I/O paths or be a false positive if grouping isn't meant to reflect file "
|
|
829
|
+
f"locality.)")
|
|
830
|
+
for payload in payloads:
|
|
831
|
+
existing = payload.display.get(TestingSectionEnum.Errors.name, '')
|
|
832
|
+
payload.display[TestingSectionEnum.Errors.name] = (existing + '\n' if existing else '') + warning
|
|
833
|
+
|
|
773
834
|
handler_type = 'metadata' if isinstance(dataset_base_handler, MetadataHandler) else None
|
|
774
835
|
if isinstance(dataset_base_handler, MetadataHandler):
|
|
775
836
|
if isinstance(raw_result, dict):
|
|
@@ -809,6 +870,7 @@ class LeapBinder:
|
|
|
809
870
|
else:
|
|
810
871
|
if raw_result is None:
|
|
811
872
|
if state != DataStateEnum.training:
|
|
873
|
+
_warn_if_group_spans_multiple_files(test_result)
|
|
812
874
|
return test_result
|
|
813
875
|
|
|
814
876
|
if dataset_base_handler.metadata_type is None:
|
|
@@ -830,6 +892,7 @@ class LeapBinder:
|
|
|
830
892
|
# setting shape in setup for all encoders
|
|
831
893
|
if isinstance(dataset_base_handler, (InputHandler, GroundTruthHandler)):
|
|
832
894
|
dataset_base_handler.shape = result_shape
|
|
895
|
+
_warn_if_group_spans_multiple_files(test_result)
|
|
833
896
|
return test_result
|
|
834
897
|
|
|
835
898
|
def check_handlers(self, preprocess_result: Dict[DataStateEnum, PreprocessResponse]) -> None:
|
|
@@ -865,10 +928,15 @@ class LeapBinder:
|
|
|
865
928
|
preprocess_response.tl_generated = True
|
|
866
929
|
if not preprocess_response.length or preprocess_response.length < 1:
|
|
867
930
|
raise Exception("Simulation '{}' returned PreprocessResponse with length < 1".format(sim.name))
|
|
868
|
-
preprocess_response.
|
|
931
|
+
if preprocess_response.is_grouped:
|
|
932
|
+
raise Exception(
|
|
933
|
+
"Simulation '{}' returned a grouped PreprocessResponse; simulations must "
|
|
934
|
+
"return a flat (non-grouped) PreprocessResponse.".format(sim.name))
|
|
935
|
+
preprocess_response.sample_ids = cast(List[Union[int, str]], [0])
|
|
936
|
+
sim_sample_ids = cast(List[Union[int, str]], preprocess_response.sample_ids)
|
|
869
937
|
for handler in self.setup_container.inputs:
|
|
870
|
-
out1 = handler.function(
|
|
871
|
-
out2 = handler.function(
|
|
938
|
+
out1 = handler.function(sim_sample_ids[0], preprocess_response)
|
|
939
|
+
out2 = handler.function(sim_sample_ids[0], preprocess_response)
|
|
872
940
|
if not np.allclose(out1, out2):
|
|
873
941
|
raise Exception(
|
|
874
942
|
"Simulation '{}': encoder '{}' is non-deterministic — consecutive calls with seed=0 returned different outputs".format(
|