params-proto 3.1.1__py3-none-any.whl → 3.2.0__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.
- params_proto/cli/cli_parse.py +28 -0
- params_proto/hyper/sweep.py +71 -0
- params_proto/proto.py +28 -16
- {params_proto-3.1.1.dist-info → params_proto-3.2.0.dist-info}/METADATA +1 -1
- {params_proto-3.1.1.dist-info → params_proto-3.2.0.dist-info}/RECORD +7 -7
- {params_proto-3.1.1.dist-info → params_proto-3.2.0.dist-info}/WHEEL +0 -0
- {params_proto-3.1.1.dist-info → params_proto-3.2.0.dist-info}/licenses/LICENSE.md +0 -0
params_proto/cli/cli_parse.py
CHANGED
|
@@ -164,6 +164,23 @@ def parse_cli_args(wrapper) -> Dict[str, Any]:
|
|
|
164
164
|
is_bool = annotation == bool
|
|
165
165
|
prefix_params[kebab_key] = (singleton, param_name, annotation, is_bool)
|
|
166
166
|
|
|
167
|
+
# Build unprefixed union attribute map for classes NOT decorated with @proto.prefix
|
|
168
|
+
# Maps attr-name -> (union_param_name, attr_name_underscore)
|
|
169
|
+
# Classes in _SINGLETONS are @proto.prefix decorated and require prefixed attrs
|
|
170
|
+
unprefixed_attrs = {}
|
|
171
|
+
for kebab_name, (param_name, union_classes) in union_params.items():
|
|
172
|
+
for cls in union_classes:
|
|
173
|
+
# Skip if class is a @proto.prefix singleton (requires prefixed attrs)
|
|
174
|
+
is_prefix_class = cls in _SINGLETONS.values()
|
|
175
|
+
if is_prefix_class:
|
|
176
|
+
continue
|
|
177
|
+
if hasattr(cls, "__annotations__"):
|
|
178
|
+
for attr_name in cls.__annotations__:
|
|
179
|
+
kebab_attr = attr_name.replace("_", "-")
|
|
180
|
+
# Map to the union param (first one wins if multiple unions have same attr)
|
|
181
|
+
if kebab_attr not in unprefixed_attrs:
|
|
182
|
+
unprefixed_attrs[kebab_attr] = (param_name, attr_name)
|
|
183
|
+
|
|
167
184
|
# Parse arguments
|
|
168
185
|
result = {}
|
|
169
186
|
prefix_values = {} # (singleton, param_name) -> value
|
|
@@ -336,6 +353,17 @@ def parse_cli_args(wrapper) -> Dict[str, Any]:
|
|
|
336
353
|
i += 2
|
|
337
354
|
continue
|
|
338
355
|
|
|
356
|
+
# Check unprefixed union attrs when cli_prefix=False
|
|
357
|
+
if key in unprefixed_attrs:
|
|
358
|
+
union_param_name, attr_name = unprefixed_attrs[key]
|
|
359
|
+
# Get the value
|
|
360
|
+
if i + 1 >= len(args):
|
|
361
|
+
raise SystemExit(f"error: argument --{key} requires a value")
|
|
362
|
+
value_str = args[i + 1]
|
|
363
|
+
union_attrs[(union_param_name, attr_name)] = value_str
|
|
364
|
+
i += 2
|
|
365
|
+
continue
|
|
366
|
+
|
|
339
367
|
# Unknown argument
|
|
340
368
|
raise SystemExit(f"error: unrecognized argument: {arg}")
|
|
341
369
|
|
params_proto/hyper/sweep.py
CHANGED
|
@@ -143,6 +143,77 @@ class ParameterIterator:
|
|
|
143
143
|
"""Return number of configs (materializes list)."""
|
|
144
144
|
return len(self.list)
|
|
145
145
|
|
|
146
|
+
def save(self, filename="sweep.jsonl", overwrite=True, verbose=True):
|
|
147
|
+
"""
|
|
148
|
+
Save parameter configurations to JSONL file.
|
|
149
|
+
|
|
150
|
+
Args:
|
|
151
|
+
filename: Path to output file (str or PathLike)
|
|
152
|
+
overwrite: If True, overwrite existing file; if False, append
|
|
153
|
+
verbose: If True, print save confirmation
|
|
154
|
+
|
|
155
|
+
Example:
|
|
156
|
+
configs = piter @ {"lr": [0.001, 0.01]} * {"batch_size": [32, 64]}
|
|
157
|
+
configs.save("experiment.jsonl")
|
|
158
|
+
"""
|
|
159
|
+
import json
|
|
160
|
+
import os
|
|
161
|
+
from urllib import parse
|
|
162
|
+
|
|
163
|
+
# Convert Path objects to string
|
|
164
|
+
filename_str = os.fspath(filename) if hasattr(os, "fspath") else str(filename)
|
|
165
|
+
configs = self.list
|
|
166
|
+
|
|
167
|
+
with open(filename_str, "w" if overwrite else "a+") as f:
|
|
168
|
+
for item in configs:
|
|
169
|
+
f.write(json.dumps(item) + "\n")
|
|
170
|
+
|
|
171
|
+
if verbose:
|
|
172
|
+
try:
|
|
173
|
+
from termcolor import colored as c
|
|
174
|
+
|
|
175
|
+
print(
|
|
176
|
+
c("saved", "blue"),
|
|
177
|
+
c(len(configs), "green"),
|
|
178
|
+
c("items to", "blue"),
|
|
179
|
+
filename_str,
|
|
180
|
+
".",
|
|
181
|
+
"file://" + parse.quote(os.path.realpath(filename_str)),
|
|
182
|
+
)
|
|
183
|
+
except ImportError:
|
|
184
|
+
print(f"Saved {len(configs)} items to {filename_str}")
|
|
185
|
+
|
|
186
|
+
@staticmethod
|
|
187
|
+
def load(filename="sweep.jsonl"):
|
|
188
|
+
"""
|
|
189
|
+
Load parameter configurations from JSONL file.
|
|
190
|
+
|
|
191
|
+
Args:
|
|
192
|
+
filename: Path to input file (str or PathLike)
|
|
193
|
+
|
|
194
|
+
Returns:
|
|
195
|
+
ParameterIterator with loaded configurations
|
|
196
|
+
|
|
197
|
+
Example:
|
|
198
|
+
configs = ParameterIterator.load("experiment.jsonl")
|
|
199
|
+
for config in configs:
|
|
200
|
+
run_experiment(**config)
|
|
201
|
+
"""
|
|
202
|
+
import json
|
|
203
|
+
import os
|
|
204
|
+
|
|
205
|
+
# Convert Path objects to string
|
|
206
|
+
filename_str = os.fspath(filename) if hasattr(os, "fspath") else str(filename)
|
|
207
|
+
|
|
208
|
+
configs = []
|
|
209
|
+
with open(filename_str, "r") as f:
|
|
210
|
+
for line in f:
|
|
211
|
+
line = line.strip()
|
|
212
|
+
if line and not line.startswith("//"):
|
|
213
|
+
configs.append(json.loads(line))
|
|
214
|
+
|
|
215
|
+
return ParameterIterator(iter(configs))
|
|
216
|
+
|
|
146
217
|
|
|
147
218
|
class PiterFactory:
|
|
148
219
|
"""
|
params_proto/proto.py
CHANGED
|
@@ -669,20 +669,32 @@ class ptype(type):
|
|
|
669
669
|
|
|
670
670
|
# Get the original class
|
|
671
671
|
original_cls = type.__getattribute__(cls, "__proto_original_class__")
|
|
672
|
+
annotations = getattr(cls, "__proto_annotations__", {})
|
|
672
673
|
|
|
673
|
-
#
|
|
674
|
-
|
|
674
|
+
# Check if this is a dataclass (has generated __init__ that accepts kwargs)
|
|
675
|
+
is_dataclass = hasattr(original_cls, "__dataclass_fields__")
|
|
675
676
|
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
677
|
+
if is_dataclass:
|
|
678
|
+
# For dataclasses: use the constructor directly
|
|
679
|
+
instance = original_cls(**final_kwargs)
|
|
680
|
+
else:
|
|
681
|
+
# For regular classes: create instance and set attributes manually
|
|
682
|
+
instance = object.__new__(original_cls)
|
|
683
|
+
for name in annotations.keys():
|
|
684
|
+
if name in final_kwargs:
|
|
685
|
+
setattr(instance, name, final_kwargs[name])
|
|
686
|
+
elif hasattr(cls, "__proto_defaults__") and name in cls.__proto_defaults__:
|
|
687
|
+
setattr(instance, name, cls.__proto_defaults__[name])
|
|
688
|
+
else:
|
|
689
|
+
# Required field
|
|
690
|
+
setattr(instance, name, None)
|
|
691
|
+
# Call __post_init__ if defined (dataclasses call it in __init__)
|
|
692
|
+
if hasattr(instance, '__post_init__'):
|
|
693
|
+
instance.__post_init__()
|
|
694
|
+
|
|
695
|
+
# Update the instance's class to the decorated class
|
|
696
|
+
# This allows isinstance(instance, DecoratedClass) to work
|
|
697
|
+
object.__setattr__(instance, "__class__", cls)
|
|
686
698
|
|
|
687
699
|
# Copy methods from original class and wrap to return self
|
|
688
700
|
for name in dir(original_cls):
|
|
@@ -722,10 +734,6 @@ class ptype(type):
|
|
|
722
734
|
|
|
723
735
|
setattr(instance, name, make_wrapper(method))
|
|
724
736
|
|
|
725
|
-
# Call __post_init__ if defined (like dataclasses)
|
|
726
|
-
if hasattr(instance, '__post_init__'):
|
|
727
|
-
instance.__post_init__()
|
|
728
|
-
|
|
729
737
|
return instance
|
|
730
738
|
|
|
731
739
|
|
|
@@ -1013,6 +1021,10 @@ def cli(obj: Any = None, *, prog: str = None):
|
|
|
1013
1021
|
"""
|
|
1014
1022
|
Set up an object as a CLI entry point.
|
|
1015
1023
|
|
|
1024
|
+
By default, subcommand attributes don't require prefix (--epochs works).
|
|
1025
|
+
If the subcommand class is decorated with @proto.prefix, prefix is required
|
|
1026
|
+
(--config.epochs).
|
|
1027
|
+
|
|
1016
1028
|
Args:
|
|
1017
1029
|
obj: The class, function, or Union type to setup as CLI.
|
|
1018
1030
|
If None, returns a decorator.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: params-proto
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.2.0
|
|
4
4
|
Summary: Modern Hyper Parameter Management for Machine Learning
|
|
5
5
|
Project-URL: Homepage, https://github.com/geyang/params-proto
|
|
6
6
|
Project-URL: Documentation, https://params-proto.readthedocs.io
|
|
@@ -3,15 +3,15 @@ params_proto/app.py,sha256=UySpd1op3M44Szk6Ekyn0fJcnZsQvMTMPdaEybwWsLE,19
|
|
|
3
3
|
params_proto/documentation.py,sha256=mIqmcwGWo8tM1BuNzLIwVTzdbQ3qyPus7yWTaOce4dM,8091
|
|
4
4
|
params_proto/envvar.py,sha256=A87jxSAQ2tjbKLbrm96lblV90zNdtBGCSV6QRe2DrgA,8398
|
|
5
5
|
params_proto/parse_env_template.py,sha256=mXTvKpNhT2jGr3HpwKw42shd18O0QACmSJn6yWMDdKA,1298
|
|
6
|
-
params_proto/proto.py,sha256=
|
|
6
|
+
params_proto/proto.py,sha256=AGUHrU0OmWxqkYvJJqR6SzQTxZz_Zis0XYYaiFentmo,39077
|
|
7
7
|
params_proto/type_utils.py,sha256=x68rL5m76ZFRKsCRgH_i_4vLpt6ldWEsEAalgacFIH8,7364
|
|
8
8
|
params_proto/cli/__init__.py,sha256=sLpN3GmaBqd_d0J0nvUNOeGlV74_-jQGW0nDUU34tjA,493
|
|
9
9
|
params_proto/cli/ansi_help.py,sha256=-1gzbvOpi9GjPlqgiINOYQAfIstzg0-ukv1se88TYCQ,10967
|
|
10
|
-
params_proto/cli/cli_parse.py,sha256=
|
|
10
|
+
params_proto/cli/cli_parse.py,sha256=qf9HFTOIJiIMKboqxa6sWdfIEzG9VN8JUHq05L9XDls,16126
|
|
11
11
|
params_proto/cli/help_gen.py,sha256=Iv9MWC7TJT4_OUWozTfCr8-Nmp_-K8Ohoim_dtsN5AY,12921
|
|
12
12
|
params_proto/hyper/__init__.py,sha256=4zMnKk9H7NPlaTTRzbL2MC7anzwkBbd2_kW51aYhCPs,157
|
|
13
13
|
params_proto/hyper/proxies.py,sha256=OMiaKK-gQx-zT1xeCmZevBSDgWUwwkzz0n54A5_wC60,4492
|
|
14
|
-
params_proto/hyper/sweep.py,sha256=
|
|
14
|
+
params_proto/hyper/sweep.py,sha256=QUjsNdpJUoZU2WMF022LRqTh9rx5dgabpRCfs895q2Q,31444
|
|
15
15
|
params_proto/v1/__init__.py,sha256=NGYZ6Iqicc5M6iyWT6N8FsD0iGLl2by5yZUIsHKhjXw,48
|
|
16
16
|
params_proto/v1/hyper.py,sha256=zFzViWtSkQdqDJXuan33X2OZwKSHHY39Q5HSNPXl0iQ,2883
|
|
17
17
|
params_proto/v1/params_proto.py,sha256=g2TMTG0SXyp01gsvd9EO42m28Hr2aS79xzOnMeH_WVk,8728
|
|
@@ -20,7 +20,7 @@ params_proto/v2/hyper.py,sha256=onBAkT8Ja8IkeHEOq1AwCdTuBzAnthIe766ZE0lAy-M,1146
|
|
|
20
20
|
params_proto/v2/partial.py,sha256=_ovi4NY8goYgHurfYt1OV0E9DSMXGYucjMVIyG1Q_xc,983
|
|
21
21
|
params_proto/v2/proto.py,sha256=KvinzgzwRQr2bHDNtrU7App2kgAyB-SEfBe4SNYceh0,18995
|
|
22
22
|
params_proto/v2/utils.py,sha256=5EWvwboZDTsCYfzSED_J6RVFyNLIlf95nIu4p_ZSVxA,3540
|
|
23
|
-
params_proto-3.
|
|
24
|
-
params_proto-3.
|
|
25
|
-
params_proto-3.
|
|
26
|
-
params_proto-3.
|
|
23
|
+
params_proto-3.2.0.dist-info/METADATA,sha256=p5CeTi6QrS9C-ipTVzIsfQAvptl2gFLfLccdUBqsfGs,8991
|
|
24
|
+
params_proto-3.2.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
25
|
+
params_proto-3.2.0.dist-info/licenses/LICENSE.md,sha256=c2qSYi9tUMZtzj9SEsMeKhub5LJUmHwBtDLiIMM5b6U,1526
|
|
26
|
+
params_proto-3.2.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|