params-proto 3.2.0__py3-none-any.whl → 3.2.2__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.
@@ -57,6 +57,32 @@ def _normalize_class_name(class_name: str) -> str:
57
57
  return class_name.replace("-", "").replace("_", "").lower()
58
58
 
59
59
 
60
+ def _get_required_fields(cls) -> List[str]:
61
+ """Get list of required field names (fields without defaults) in order."""
62
+ import dataclasses
63
+
64
+ required = []
65
+
66
+ # Check if it's a dataclass
67
+ if dataclasses.is_dataclass(cls):
68
+ for field in dataclasses.fields(cls):
69
+ has_default = (
70
+ field.default is not dataclasses.MISSING
71
+ or field.default_factory is not dataclasses.MISSING
72
+ )
73
+ if not has_default:
74
+ required.append(field.name)
75
+ else:
76
+ # For regular classes, check annotations and class-level defaults
77
+ annotations = getattr(cls, "__annotations__", {})
78
+ for name in annotations:
79
+ if not hasattr(cls, name):
80
+ # No class-level default
81
+ required.append(name)
82
+
83
+ return required
84
+
85
+
60
86
  def _match_class_by_name(name: str, classes: list) -> Union[type, None]:
61
87
  """Match a string to one of the Union classes.
62
88
 
@@ -187,6 +213,8 @@ def parse_cli_args(wrapper) -> Dict[str, Any]:
187
213
  positional_values = []
188
214
  union_selections = {} # param_name -> selected_class
189
215
  union_attrs = {} # (param_name, attr_name) -> value
216
+ union_positional = {} # param_name -> [positional_args] for subcommand fields
217
+ current_union_param = None # Track which union we're collecting positionals for
190
218
 
191
219
  args = sys.argv[1:]
192
220
  i = 0
@@ -377,12 +405,18 @@ def parse_cli_args(wrapper) -> Dict[str, Any]:
377
405
  selected_class = _match_class_by_name(arg, union_classes)
378
406
  if selected_class:
379
407
  union_selections[param_name] = selected_class
408
+ current_union_param = param_name # Track for following positionals
409
+ union_positional[param_name] = []
380
410
  matched_union = True
381
411
  i += 1
382
412
  break
383
413
 
384
414
  if not matched_union:
385
- positional_values.append(arg)
415
+ # If we have a current union, add positional to its list
416
+ if current_union_param is not None:
417
+ union_positional[current_union_param].append(arg)
418
+ else:
419
+ positional_values.append(arg)
386
420
  i += 1
387
421
 
388
422
  # Assign positional arguments to required parameters
@@ -433,6 +467,33 @@ def parse_cli_args(wrapper) -> Dict[str, Any]:
433
467
  # No annotations, treat as string
434
468
  attrs[attr_name] = value_str
435
469
 
470
+ # Assign positional args to required fields of the selected class
471
+ if param_name in union_positional and union_positional[param_name]:
472
+ positionals = union_positional[param_name]
473
+ required_fields = _get_required_fields(selected_class)
474
+
475
+ for field_idx, field_name in enumerate(required_fields):
476
+ if field_name in attrs:
477
+ # Already set by named arg, skip
478
+ continue
479
+ if field_idx < len(positionals):
480
+ # Get type annotation for conversion
481
+ if hasattr(selected_class, "__annotations__"):
482
+ field_type = selected_class.__annotations__.get(field_name, str)
483
+ try:
484
+ attrs[field_name] = _convert_type(positionals[field_idx], field_type)
485
+ except (ValueError, TypeError):
486
+ raise SystemExit(
487
+ f"error: invalid value for {field_name}: {positionals[field_idx]}"
488
+ )
489
+ else:
490
+ attrs[field_name] = positionals[field_idx]
491
+
492
+ # Check for extra positional args
493
+ if len(positionals) > len(required_fields):
494
+ extra = positionals[len(required_fields):]
495
+ raise SystemExit(f"error: unrecognized arguments: {' '.join(extra)}")
496
+
436
497
  # If selected_class is a proto.prefix singleton, merge its overrides
437
498
  from params_proto.proto import _SINGLETONS, ptype
438
499
 
@@ -447,6 +508,14 @@ def parse_cli_args(wrapper) -> Dict[str, Any]:
447
508
  attrs[key] = value
448
509
  break
449
510
 
511
+ # Check for missing required fields
512
+ required_fields = _get_required_fields(selected_class)
513
+ for field_name in required_fields:
514
+ if field_name not in attrs:
515
+ raise SystemExit(
516
+ f"error: {selected_class.__name__} requires argument: {field_name}"
517
+ )
518
+
450
519
  # Instantiate the class with collected attributes
451
520
  try:
452
521
  instance = selected_class(**attrs)
params_proto/proto.py CHANGED
@@ -844,10 +844,15 @@ def proto(
844
844
  # Handle existing metaclass
845
845
  existing_meta = type(obj)
846
846
  if existing_meta is not type:
847
- # Merge with existing metaclass
848
- class MergedMeta(existing_meta, ptype):
849
- pass
850
- metaclass = MergedMeta
847
+ # Check if existing metaclass is already ptype or a subclass of ptype
848
+ if issubclass(existing_meta, ptype):
849
+ # Already using ptype, no need to merge
850
+ metaclass = existing_meta
851
+ else:
852
+ # Merge with existing metaclass
853
+ class MergedMeta(existing_meta, ptype):
854
+ pass
855
+ metaclass = MergedMeta
851
856
  else:
852
857
  metaclass = ptype
853
858
 
@@ -872,9 +877,12 @@ def proto(
872
877
  namespace[key] = value
873
878
 
874
879
  # Create new class with metaclass
880
+ # IMPORTANT: Use (obj,) as bases to make new class a SUBCLASS of original.
881
+ # This ensures super() works correctly - the original class is in the MRO,
882
+ # so Python's super() validation passes when checking isinstance(self, original_class).
875
883
  new_cls = metaclass(
876
884
  obj.__name__,
877
- obj.__bases__,
885
+ (obj,),
878
886
  namespace
879
887
  )
880
888
 
@@ -17,7 +17,13 @@ import inspect
17
17
  import re
18
18
  from typing import Callable, TypeVar, Union
19
19
 
20
- from waterbear import DefaultBear
20
+ try:
21
+ from waterbear import DefaultBear
22
+ except ImportError:
23
+ raise ImportError(
24
+ "params_proto.v1 requires waterbear. Install it with: pip install waterbear\n"
25
+ "Note: The v3 API (from params_proto import proto) does not require waterbear."
26
+ )
21
27
 
22
28
 
23
29
  def _strtobool(val):
params_proto/v2/proto.py CHANGED
@@ -8,7 +8,13 @@ from types import BuiltinFunctionType, SimpleNamespace
8
8
  from warnings import warn
9
9
 
10
10
  from expandvars import expandvars
11
- from waterbear import Bear
11
+ try:
12
+ from waterbear import Bear
13
+ except ImportError:
14
+ raise ImportError(
15
+ "params_proto.v2 requires waterbear. Install it with: pip install waterbear\n"
16
+ "Note: The v3 API (from params_proto import proto) does not require waterbear."
17
+ )
12
18
 
13
19
  from params_proto.parse_env_template import all_available
14
20
  from params_proto.v2.utils import dot_to_deps
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: params-proto
3
- Version: 3.2.0
3
+ Version: 3.2.2
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
@@ -23,7 +23,6 @@ Requires-Dist: argcomplete
23
23
  Requires-Dist: argparse
24
24
  Requires-Dist: expandvars
25
25
  Requires-Dist: termcolor
26
- Requires-Dist: waterbear>=2.6.8
27
26
  Provides-Extra: dev
28
27
  Requires-Dist: pandas; extra == 'dev'
29
28
  Requires-Dist: pytest; extra == 'dev'
@@ -3,24 +3,24 @@ 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=AGUHrU0OmWxqkYvJJqR6SzQTxZz_Zis0XYYaiFentmo,39077
6
+ params_proto/proto.py,sha256=B3TqH9nPQgq9sXWrwpPnbcGiiWMR9eNS_0gXnWw_QGc,39557
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=qf9HFTOIJiIMKboqxa6sWdfIEzG9VN8JUHq05L9XDls,16126
10
+ params_proto/cli/cli_parse.py,sha256=kVBSgCCVZk32NOfPfyj-pYWXBLyqitFZzsfme8LspcE,18835
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
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
- params_proto/v1/params_proto.py,sha256=g2TMTG0SXyp01gsvd9EO42m28Hr2aS79xzOnMeH_WVk,8728
17
+ params_proto/v1/params_proto.py,sha256=KUQCKr7HRHFjOQGurqfWspxcBMJ6k1RTjXKSFOJZpa4,8961
18
18
  params_proto/v2/__init__.py,sha256=C89S5VvAr4DSeRBwX4Z1p07lNDiVLu9PhosmcImYs1A,77
19
19
  params_proto/v2/hyper.py,sha256=onBAkT8Ja8IkeHEOq1AwCdTuBzAnthIe766ZE0lAy-M,11462
20
20
  params_proto/v2/partial.py,sha256=_ovi4NY8goYgHurfYt1OV0E9DSMXGYucjMVIyG1Q_xc,983
21
- params_proto/v2/proto.py,sha256=KvinzgzwRQr2bHDNtrU7App2kgAyB-SEfBe4SNYceh0,18995
21
+ params_proto/v2/proto.py,sha256=-BTTwFOhJsaPnujwFIDh14QMB8r_ZdridK9I2Jkqd_U,19228
22
22
  params_proto/v2/utils.py,sha256=5EWvwboZDTsCYfzSED_J6RVFyNLIlf95nIu4p_ZSVxA,3540
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,,
23
+ params_proto-3.2.2.dist-info/METADATA,sha256=EvdIaWolnBuaF6bU2orZOozwzDgGNVNipF4wYYw_CIU,8959
24
+ params_proto-3.2.2.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
25
+ params_proto-3.2.2.dist-info/licenses/LICENSE.md,sha256=c2qSYi9tUMZtzj9SEsMeKhub5LJUmHwBtDLiIMM5b6U,1526
26
+ params_proto-3.2.2.dist-info/RECORD,,