params-proto 3.1.0__py3-none-any.whl → 3.1.1__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/envvar.py CHANGED
@@ -153,24 +153,44 @@ class _EnvVar:
153
153
  return os.environ[name], True
154
154
  return None, False
155
155
 
156
- def get(self, *, lazy: bool = True) -> Any:
156
+ def invalidate_cache(self):
157
+ """Clear the cached value, forcing re-read from environment on next access."""
158
+ self._cached_value = None
159
+ self._is_cached = False
160
+
161
+ def __get__(self, obj, objtype=None):
157
162
  """
158
- Get the value from environment variable(s).
163
+ Descriptor protocol: auto-resolve EnvVar when accessed as a class attribute.
164
+
165
+ This enables EnvVar to work in plain classes (not decorated with @ParamsProto):
166
+
167
+ class MyConfig:
168
+ api_key: str = EnvVar @ "API_KEY" | "default"
169
+
170
+ # Accessing MyConfig.api_key returns the resolved value, not the _EnvVar object
171
+ print(MyConfig.api_key) # "default" or value of $API_KEY
159
172
 
160
- When multiple templates are specified (OR operation), tries each in order
161
- and returns the first one that is set in the environment.
173
+ Values are cached after first resolution. Use invalidate_cache() to force re-read:
174
+
175
+ envvar = MyConfig.__dict__['api_key'] # Get the _EnvVar object
176
+ envvar.invalidate_cache()
177
+ print(MyConfig.api_key) # Re-reads from environment
162
178
 
163
179
  Args:
164
- lazy: If True (default), cache the result for subsequent calls.
165
- Set to False to always re-read from environment.
180
+ obj: Instance (None if accessed on class)
181
+ objtype: The class being accessed
166
182
 
167
183
  Returns:
168
- Value from environment or default, converted to dtype if specified
184
+ The resolved environment variable value
169
185
  """
170
186
  from params_proto.type_utils import _convert_type
171
187
 
172
- # Return cached value if lazy loading is enabled and we have a cached value
173
- if lazy and self._is_cached:
188
+ # Don't resolve the singleton EnvVar instance itself (has no templates)
189
+ if not self.templates:
190
+ return self
191
+
192
+ # Return cached value if available
193
+ if self._is_cached:
174
194
  return self._cached_value
175
195
 
176
196
  # No templates means return default
@@ -192,18 +212,12 @@ class _EnvVar:
192
212
  if result is not None and self.dtype is not None:
193
213
  result = _convert_type(result, self.dtype)
194
214
 
195
- # Cache the result for lazy loading
196
- if lazy:
197
- self._cached_value = result
198
- self._is_cached = True
215
+ # Cache the result
216
+ self._cached_value = result
217
+ self._is_cached = True
199
218
 
200
219
  return result
201
220
 
202
- def invalidate_cache(self):
203
- """Clear the cached value, forcing re-read from environment on next get()."""
204
- self._cached_value = None
205
- self._is_cached = False
206
-
207
221
  def __repr__(self):
208
222
  if self.templates:
209
223
  if len(self.templates) == 1:
params_proto/proto.py CHANGED
@@ -177,7 +177,7 @@ class ProtoWrapper:
177
177
  if is_env_var:
178
178
  # Resolve env var at decoration time
179
179
  # NO auto-inference from parameter name for security reasons
180
- env_value = default.get()
180
+ env_value = default.__get__(None, None)
181
181
 
182
182
  # Apply type conversion based on dtype (if provided) or annotation
183
183
  if env_value is not None:
@@ -801,7 +801,17 @@ def proto(
801
801
 
802
802
  for name in annotations.keys():
803
803
  if hasattr(obj, name):
804
- value = getattr(obj, name)
804
+ # Look up value in class dict hierarchy to bypass descriptors like _EnvVar.__get__
805
+ value = None
806
+ for klass in obj.__mro__:
807
+ if klass is object:
808
+ continue
809
+ if name in vars(klass):
810
+ value = vars(klass)[name]
811
+ break
812
+ else:
813
+ value = getattr(obj, name)
814
+
805
815
  # Check for EnvVar first (before callable check, since _EnvVar has __call__)
806
816
  is_env_var = (
807
817
  hasattr(value, "__class__") and value.__class__.__name__ == "_EnvVar"
@@ -809,7 +819,7 @@ def proto(
809
819
 
810
820
  if is_env_var:
811
821
  # Resolve env var at decoration time
812
- env_value = value.get()
822
+ env_value = value.__get__(None, None)
813
823
  annotation = annotations.get(name, str)
814
824
 
815
825
  # Apply type conversion based on dtype (if provided) or annotation
@@ -848,6 +858,11 @@ def proto(
848
858
  except AttributeError:
849
859
  pass
850
860
 
861
+ # Replace _EnvVar objects with resolved values from defaults
862
+ # This ensures the descriptor doesn't interfere with class attribute access
863
+ for key, value in defaults.items():
864
+ namespace[key] = value
865
+
851
866
  # Create new class with metaclass
852
867
  new_cls = metaclass(
853
868
  obj.__name__,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: params-proto
3
- Version: 3.1.0
3
+ Version: 3.1.1
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
@@ -1,9 +1,9 @@
1
1
  params_proto/__init__.py,sha256=JJfjHf6dpkNpLDGOyH0KBWFo44nQoxSIzmwfGZb36ZU,114
2
2
  params_proto/app.py,sha256=UySpd1op3M44Szk6Ekyn0fJcnZsQvMTMPdaEybwWsLE,19
3
3
  params_proto/documentation.py,sha256=mIqmcwGWo8tM1BuNzLIwVTzdbQ3qyPus7yWTaOce4dM,8091
4
- params_proto/envvar.py,sha256=PxSgNkk-GHksMiAYhRozSjCX3aCinfaPfCpuhuEbeho,7964
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=r6o5baHpVa4WUCPcMbDfRBwdd_4sstOSCc3Xq56UZvw,37813
6
+ params_proto/proto.py,sha256=81q5EyPYtH7uHCT0L2ydiin5Na2kfJ2VO3LmDfu8AXM,38386
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
@@ -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.1.0.dist-info/METADATA,sha256=z_LZb9qVHv2YH_Y_wFkMut3BTgzQRLYsAo_AZnTfQWg,8991
24
- params_proto-3.1.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
25
- params_proto-3.1.0.dist-info/licenses/LICENSE.md,sha256=c2qSYi9tUMZtzj9SEsMeKhub5LJUmHwBtDLiIMM5b6U,1526
26
- params_proto-3.1.0.dist-info/RECORD,,
23
+ params_proto-3.1.1.dist-info/METADATA,sha256=Z8W21Wa1zInNKFoeY7TVXu2OQNo3TCQWjtX_RzmjgWM,8991
24
+ params_proto-3.1.1.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
25
+ params_proto-3.1.1.dist-info/licenses/LICENSE.md,sha256=c2qSYi9tUMZtzj9SEsMeKhub5LJUmHwBtDLiIMM5b6U,1526
26
+ params_proto-3.1.1.dist-info/RECORD,,