params-proto 3.1.0__tar.gz → 3.1.2__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.
- {params_proto-3.1.0 → params_proto-3.1.2}/.idea/workspace.xml +2 -1
- {params_proto-3.1.0 → params_proto-3.1.2}/PKG-INFO +1 -1
- {params_proto-3.1.0 → params_proto-3.1.2}/docs/index.md +1 -1
- {params_proto-3.1.0 → params_proto-3.1.2}/docs/quick_start.md +1 -1
- {params_proto-3.1.0 → params_proto-3.1.2}/docs/release_notes.md +21 -4
- {params_proto-3.1.0 → params_proto-3.1.2}/pyproject.toml +1 -1
- {params_proto-3.1.0 → params_proto-3.1.2}/skills/params-proto/SKILL.md +2 -2
- params_proto-3.1.2/skills/params-proto.skill +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/src/params_proto/envvar.py +32 -18
- {params_proto-3.1.0 → params_proto-3.1.2}/src/params_proto/proto.py +18 -3
- {params_proto-3.1.0 → params_proto-3.1.2}/tests/test_v3/test_proto_envvar.py +145 -39
- params_proto-3.1.0/skills/params-proto.skill +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/.claude-plugin/marketplace.json +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/.claude-plugin/plugin.json +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/.editorconfig +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/.gitignore +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/.idea/.gitignore +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/.idea/codeStyles/codeStyleConfig.xml +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/.idea/inspectionProfiles/Project_Default.xml +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/.idea/inspectionProfiles/profiles_settings.xml +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/.idea/markdown.xml +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/.idea/misc.xml +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/.idea/modules.xml +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/.idea/params-proto.iml +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/.idea/ruff.xml +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/.idea/vcs.xml +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/.readthedocs.yaml +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/.run/pytest for test_neo_proto_cli.run.xml +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/.run/pytest in test_params_proto.run.xml +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/ANSI_HELP_CONSIDERATIONS.md +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/CLAUDE.md +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/LICENSE.md +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/Makefile +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/README +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/README.md +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/docs/Makefile +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/docs/_archive_v2/api/hyper.md +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/docs/_archive_v2/api/proto.md +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/docs/_archive_v2/api/utils.md +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/docs/_archive_v2/examples/advanced_features.md +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/docs/_archive_v2/examples/basic_usage.md +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/docs/_archive_v2/examples/environment_variables.md +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/docs/_archive_v2/examples/hyperparameter_sweeps.md +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/docs/_archive_v2/examples/index.md +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/docs/_archive_v2/examples/nested_configs.md +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/docs/_archive_v2/quick_start.md +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/docs/_static/ansi.css +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/docs/_static/custom.css +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/docs/api/index.md +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/docs/api/proto.md +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/docs/conf.py +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/docs/examples/basic_usage.md +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/docs/examples/cli_applications.md +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/docs/examples/ml_training.md +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/docs/examples/rl_agent.md +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/docs/key_concepts/advanced_patterns.md +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/docs/key_concepts/ansi_formatting.md +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/docs/key_concepts/cli-fundamentals.md +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/docs/key_concepts/cli-patterns.md +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/docs/key_concepts/configuration-patterns.md +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/docs/key_concepts/core-concepts.md +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/docs/key_concepts/environment_variables.md +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/docs/key_concepts/help-generation.md +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/docs/key_concepts/hyperparameter_sweeps.md +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/docs/key_concepts/naming-conventions.md +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/docs/key_concepts/parameter-iteration.md +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/docs/key_concepts/parameter-overrides.md +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/docs/key_concepts/type-system.md +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/docs/key_concepts/union_types.md +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/docs/key_concepts/welcome.md +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/docs/migration.md +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/docs/requirements.txt +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/examples/union_subcommands.py +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/figures/man-page.png +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/figures/params-proto-autocompletion.gif +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/figures/spec_files.png +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/scratch/demo_params_proto.py +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/scratch/demo_v3.py +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/scratch/proto_DAT_scratch.py +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/scratch/proto_dependency_tree_pattern.py +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/skills/params-proto/references/cli-and-types.md +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/skills/params-proto/references/environment-vars.md +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/skills/params-proto/references/patterns.md +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/skills/params-proto/references/sweeps.md +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/src/params_proto/__init__.py +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/src/params_proto/app.py +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/src/params_proto/cli/__init__.py +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/src/params_proto/cli/ansi_help.py +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/src/params_proto/cli/cli_parse.py +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/src/params_proto/cli/help_gen.py +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/src/params_proto/documentation.py +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/src/params_proto/hyper/__init__.py +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/src/params_proto/hyper/proxies.py +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/src/params_proto/hyper/sweep.py +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/src/params_proto/parse_env_template.py +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/src/params_proto/type_utils.py +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/src/params_proto/v1/__init__.py +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/src/params_proto/v1/hyper.py +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/src/params_proto/v1/params_proto.py +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/src/params_proto/v2/__init__.py +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/src/params_proto/v2/hyper.py +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/src/params_proto/v2/partial.py +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/src/params_proto/v2/proto.py +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/src/params_proto/v2/utils.py +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/tests/test_v1/__init__.py +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/tests/test_v1/test_hyper.py +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/tests/test_v1/test_params_proto.py +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/tests/test_v2/test_Eval.py +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/tests/test_v2/test_neo_hyper.py +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/tests/test_v2/test_neo_proto.py +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/tests/test_v2/test_neo_proto_cli.py +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/tests/test_v2/test_neo_proto_partial.py +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/tests/test_v2/test_utils.py +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/tests/test_v3/samples/train.py +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/tests/test_v3/test_advanced_types.py +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/tests/test_v3/test_class_level_methods.py +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/tests/test_v3/test_cli_parsing.py +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/tests/test_v3/test_help_strings.py +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/tests/test_v3/test_method_self_param.py +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/tests/test_v3/test_parse_env_template.py +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/tests/test_v3/test_piter.py +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/tests/test_v3/test_positional_example.sh +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/tests/test_v3/test_proto_comments.py +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/tests/test_v3/test_proto_core.py +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/tests/test_v3/test_proto_linebreaking.py +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/tests/test_v3/test_proto_partial.py +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/tests/test_v3/test_proto_required.py +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/tests/test_v3/test_strings.py +0 -0
- {params_proto-3.1.0 → params_proto-3.1.2}/tests/test_v3/test_sweep.py +0 -0
|
@@ -32,6 +32,7 @@
|
|
|
32
32
|
</component>
|
|
33
33
|
<component name="HighlightingSettingsPerFile">
|
|
34
34
|
<setting file="file://$USER_HOME$/Library/Caches/JetBrains/PyCharm2025.2/python_stubs/-1979844046/_typing.py" root0="SKIP_INSPECTION" />
|
|
35
|
+
<setting file="file://$PROJECT_DIR$/pyproject.toml" root0="SKIP_INSPECTION" />
|
|
35
36
|
</component>
|
|
36
37
|
<component name="KubernetesApiPersistence">{}</component>
|
|
37
38
|
<component name="KubernetesApiProvider">{
|
|
@@ -253,7 +254,7 @@
|
|
|
253
254
|
<workItem from="1767857192117" duration="3689000" />
|
|
254
255
|
<workItem from="1768126847510" duration="6729000" />
|
|
255
256
|
<workItem from="1768382679094" duration="3000" />
|
|
256
|
-
<workItem from="1769135684123" duration="
|
|
257
|
+
<workItem from="1769135684123" duration="4247000" />
|
|
257
258
|
</task>
|
|
258
259
|
<task id="LOCAL-00001" summary="add design specs">
|
|
259
260
|
<option name="closed" value="true" />
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: params-proto
|
|
3
|
-
Version: 3.1.
|
|
3
|
+
Version: 3.1.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
|
|
@@ -21,7 +21,7 @@ pip install params-proto=={VERSION}
|
|
|
21
21
|
|
|
22
22
|
```bash
|
|
23
23
|
/plugin marketplace add geyang/params-proto
|
|
24
|
-
/plugin install params-proto@
|
|
24
|
+
/plugin install params-proto@params-proto
|
|
25
25
|
```
|
|
26
26
|
|
|
27
27
|
Now you can convert this function into a CLI program:
|
|
@@ -18,7 +18,7 @@ params-proto includes a plugin that helps Claude write better configs and CLIs.
|
|
|
18
18
|
|
|
19
19
|
```bash
|
|
20
20
|
/plugin marketplace add geyang/params-proto
|
|
21
|
-
/plugin install params-proto@
|
|
21
|
+
/plugin install params-proto@params-proto
|
|
22
22
|
```
|
|
23
23
|
|
|
24
24
|
The plugin provides a skill that automatically activates when you're working with params-proto code.
|
|
@@ -2,6 +2,24 @@
|
|
|
2
2
|
|
|
3
3
|
This page contains the release history and changelog for params-proto.
|
|
4
4
|
|
|
5
|
+
## Version 3.1.1 (2025-01-25)
|
|
6
|
+
|
|
7
|
+
### 🐛 Bug Fixes
|
|
8
|
+
|
|
9
|
+
- **EnvVar Descriptor Protocol**: EnvVar now works in plain classes without `@proto` decorator
|
|
10
|
+
- Previously `EnvVar @ "VAR" | default` returned `_EnvVar` object in plain classes
|
|
11
|
+
- Now auto-resolves via `__get__` descriptor when accessed as class attribute
|
|
12
|
+
- Fixes: `AttributeError: '_EnvVar' object has no attribute 'decode'`
|
|
13
|
+
|
|
14
|
+
### ♻️ API Changes
|
|
15
|
+
|
|
16
|
+
- **Removed `.get()` method**: Use class attribute access instead
|
|
17
|
+
- Old: `EnvVar("PORT", dtype=int).get()`
|
|
18
|
+
- New: `class C: port = EnvVar("PORT", dtype=int)` then `C.port`
|
|
19
|
+
- Use `invalidate_cache()` to force re-read from environment
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
5
23
|
## Version 3.1.0 (2025-01-23)
|
|
6
24
|
|
|
7
25
|
### ✨ Features
|
|
@@ -34,10 +52,9 @@ This page contains the release history and changelog for params-proto.
|
|
|
34
52
|
- Function syntax: `EnvVar("PRIMARY", "FALLBACK", default="value")`
|
|
35
53
|
- Returns first env var that is set, or default if none are set
|
|
36
54
|
|
|
37
|
-
- **EnvVar Lazy Loading**: Environment variables are cached after first
|
|
38
|
-
-
|
|
39
|
-
- `
|
|
40
|
-
- `ev.invalidate_cache()` clears cached value
|
|
55
|
+
- **EnvVar Lazy Loading**: Environment variables are cached after first access
|
|
56
|
+
- Values cached after first access via descriptor
|
|
57
|
+
- `invalidate_cache()` clears cached value for re-read
|
|
41
58
|
|
|
42
59
|
### 🐛 Bug Fixes
|
|
43
60
|
|
|
@@ -10,14 +10,14 @@ description: |
|
|
|
10
10
|
(6) Work with Union types for subcommand-like CLI patterns
|
|
11
11
|
---
|
|
12
12
|
|
|
13
|
-
# params-proto v3.1.
|
|
13
|
+
# params-proto v3.1.1
|
|
14
14
|
|
|
15
15
|
Declarative hyperparameter management for ML experiments with automatic CLI generation.
|
|
16
16
|
|
|
17
17
|
## Installation
|
|
18
18
|
|
|
19
19
|
```bash
|
|
20
|
-
pip install params-proto==3.1.
|
|
20
|
+
pip install params-proto==3.1.1
|
|
21
21
|
```
|
|
22
22
|
|
|
23
23
|
## Three Decorators
|
|
Binary file
|
|
@@ -153,24 +153,44 @@ class _EnvVar:
|
|
|
153
153
|
return os.environ[name], True
|
|
154
154
|
return None, False
|
|
155
155
|
|
|
156
|
-
def
|
|
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
|
-
|
|
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
|
-
|
|
161
|
-
|
|
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
|
-
|
|
165
|
-
|
|
180
|
+
obj: Instance (None if accessed on class)
|
|
181
|
+
objtype: The class being accessed
|
|
166
182
|
|
|
167
183
|
Returns:
|
|
168
|
-
|
|
184
|
+
The resolved environment variable value
|
|
169
185
|
"""
|
|
170
186
|
from params_proto.type_utils import _convert_type
|
|
171
187
|
|
|
172
|
-
#
|
|
173
|
-
if
|
|
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
|
|
196
|
-
|
|
197
|
-
|
|
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:
|
|
@@ -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.
|
|
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
|
|
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.
|
|
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__,
|
|
@@ -445,11 +445,11 @@ def test_proto_envvar_class_with_type_conversion():
|
|
|
445
445
|
del os.environ["RATIO"]
|
|
446
446
|
|
|
447
447
|
|
|
448
|
-
def
|
|
449
|
-
"""Test EnvVar
|
|
448
|
+
def test_envvar_dtype_conversion():
|
|
449
|
+
"""Test EnvVar applies dtype conversion correctly via descriptor.
|
|
450
450
|
|
|
451
|
-
|
|
452
|
-
|
|
451
|
+
Tests that dtype parameter works for type conversion when accessed
|
|
452
|
+
as a class attribute (via __get__ descriptor).
|
|
453
453
|
"""
|
|
454
454
|
import os
|
|
455
455
|
|
|
@@ -463,37 +463,51 @@ def test_envvar_get_with_dtype():
|
|
|
463
463
|
|
|
464
464
|
try:
|
|
465
465
|
# Test int conversion
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
466
|
+
class IntConfig:
|
|
467
|
+
port = EnvVar("PORT", dtype=int, default=8012)
|
|
468
|
+
|
|
469
|
+
assert IntConfig.port == 9000, f"Expected 9000, got {IntConfig.port}"
|
|
470
|
+
assert isinstance(IntConfig.port, int), f"Expected int, got {type(IntConfig.port)}"
|
|
469
471
|
|
|
470
472
|
# Test float conversion
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
473
|
+
class FloatConfig:
|
|
474
|
+
threshold = EnvVar("THRESHOLD", dtype=float, default=0.5)
|
|
475
|
+
|
|
476
|
+
assert FloatConfig.threshold == 0.75, f"Expected 0.75, got {FloatConfig.threshold}"
|
|
477
|
+
assert isinstance(FloatConfig.threshold, float), f"Expected float, got {type(FloatConfig.threshold)}"
|
|
474
478
|
|
|
475
479
|
# Test bool conversion - "true"
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
480
|
+
class BoolConfig:
|
|
481
|
+
debug = EnvVar("DEBUG", dtype=bool, default=False)
|
|
482
|
+
|
|
483
|
+
assert BoolConfig.debug is True, f"Expected True, got {BoolConfig.debug}"
|
|
484
|
+
assert isinstance(BoolConfig.debug, bool), f"Expected bool, got {type(BoolConfig.debug)}"
|
|
479
485
|
|
|
480
486
|
# Test bool conversion - "1"
|
|
481
|
-
|
|
482
|
-
|
|
487
|
+
class EnabledConfig:
|
|
488
|
+
enabled = EnvVar("ENABLED", dtype=bool, default=False)
|
|
489
|
+
|
|
490
|
+
assert EnabledConfig.enabled is True, f"Expected True, got {EnabledConfig.enabled}"
|
|
483
491
|
|
|
484
492
|
# Test bool conversion - "false"
|
|
485
|
-
|
|
486
|
-
|
|
493
|
+
class DisabledConfig:
|
|
494
|
+
disabled = EnvVar("DISABLED", dtype=bool, default=True)
|
|
495
|
+
|
|
496
|
+
assert DisabledConfig.disabled is False, f"Expected False, got {DisabledConfig.disabled}"
|
|
487
497
|
|
|
488
498
|
# Test default value when env var not set
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
499
|
+
class MissingConfig:
|
|
500
|
+
missing = EnvVar("MISSING_VAR", dtype=int, default=42)
|
|
501
|
+
|
|
502
|
+
assert MissingConfig.missing == 42, f"Expected 42 (default), got {MissingConfig.missing}"
|
|
503
|
+
assert isinstance(MissingConfig.missing, int), f"Expected int, got {type(MissingConfig.missing)}"
|
|
492
504
|
|
|
493
505
|
# Test without dtype - should return string
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
506
|
+
class StrConfig:
|
|
507
|
+
port_str = EnvVar("PORT", default="8012")
|
|
508
|
+
|
|
509
|
+
assert StrConfig.port_str == "9000", f"Expected '9000', got {StrConfig.port_str}"
|
|
510
|
+
assert isinstance(StrConfig.port_str, str), f"Expected str, got {type(StrConfig.port_str)}"
|
|
497
511
|
|
|
498
512
|
finally:
|
|
499
513
|
del os.environ["PORT"]
|
|
@@ -503,8 +517,8 @@ def test_envvar_get_with_dtype():
|
|
|
503
517
|
del os.environ["DISABLED"]
|
|
504
518
|
|
|
505
519
|
|
|
506
|
-
def
|
|
507
|
-
"""Test EnvVar
|
|
520
|
+
def test_envvar_dtype_with_template():
|
|
521
|
+
"""Test EnvVar applies dtype with template syntax."""
|
|
508
522
|
import os
|
|
509
523
|
|
|
510
524
|
from params_proto import EnvVar
|
|
@@ -513,9 +527,11 @@ def test_envvar_get_with_dtype_template():
|
|
|
513
527
|
|
|
514
528
|
try:
|
|
515
529
|
# Test with $ prefix template
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
530
|
+
class TemplateConfig:
|
|
531
|
+
count = EnvVar("$COUNT", dtype=int, default=0)
|
|
532
|
+
|
|
533
|
+
assert TemplateConfig.count == 100, f"Expected 100, got {TemplateConfig.count}"
|
|
534
|
+
assert isinstance(TemplateConfig.count, int), f"Expected int, got {type(TemplateConfig.count)}"
|
|
519
535
|
|
|
520
536
|
finally:
|
|
521
537
|
del os.environ["COUNT"]
|
|
@@ -795,27 +811,117 @@ def test_envvar_lazy_loading():
|
|
|
795
811
|
os.environ.pop("LAZY_TEST_VAR", None)
|
|
796
812
|
|
|
797
813
|
try:
|
|
798
|
-
# Create EnvVar without env var set
|
|
799
|
-
|
|
814
|
+
# Create class with EnvVar without env var set
|
|
815
|
+
class LazyConfig:
|
|
816
|
+
value = EnvVar @ "LAZY_TEST_VAR" | "default"
|
|
800
817
|
|
|
801
|
-
# First
|
|
802
|
-
assert
|
|
818
|
+
# First access - should return default
|
|
819
|
+
assert LazyConfig.value == "default", f"Expected 'default', got {LazyConfig.value}"
|
|
803
820
|
|
|
804
|
-
# Set env var after
|
|
821
|
+
# Set env var after class was defined
|
|
805
822
|
os.environ["LAZY_TEST_VAR"] = "lazy_value"
|
|
806
823
|
|
|
807
824
|
# Cached value should still be default (lazy loading)
|
|
808
|
-
assert
|
|
825
|
+
assert LazyConfig.value == "default", f"Expected cached 'default', got {LazyConfig.value}"
|
|
809
826
|
|
|
810
|
-
# Invalidate cache
|
|
811
|
-
|
|
827
|
+
# Invalidate cache via class __dict__
|
|
828
|
+
LazyConfig.__dict__["value"].invalidate_cache()
|
|
812
829
|
|
|
813
830
|
# Now should read the new value
|
|
814
|
-
assert
|
|
831
|
+
assert LazyConfig.value == "lazy_value", f"Expected 'lazy_value', got {LazyConfig.value}"
|
|
815
832
|
|
|
816
|
-
# Test
|
|
833
|
+
# Test invalidate and re-read with updated value
|
|
817
834
|
os.environ["LAZY_TEST_VAR"] = "updated_value"
|
|
818
|
-
|
|
835
|
+
LazyConfig.__dict__["value"].invalidate_cache()
|
|
836
|
+
assert LazyConfig.value == "updated_value", f"Expected 'updated_value', got {LazyConfig.value}"
|
|
819
837
|
|
|
820
838
|
finally:
|
|
821
839
|
os.environ.pop("LAZY_TEST_VAR", None)
|
|
840
|
+
|
|
841
|
+
|
|
842
|
+
def test_envvar_descriptor_in_plain_class():
|
|
843
|
+
"""Test EnvVar auto-resolves in plain classes (without @proto decorator).
|
|
844
|
+
|
|
845
|
+
This is a critical feature for users who want to use EnvVar in classes
|
|
846
|
+
that are not decorated with @proto, such as:
|
|
847
|
+
|
|
848
|
+
class VuerClient:
|
|
849
|
+
URI: str = EnvVar @ "VUER_CLIENT_URI" | "ws://localhost:8012"
|
|
850
|
+
|
|
851
|
+
Without the descriptor protocol, accessing VuerClient.URI would return
|
|
852
|
+
an _EnvVar object instead of the resolved value.
|
|
853
|
+
"""
|
|
854
|
+
import os
|
|
855
|
+
|
|
856
|
+
from params_proto import EnvVar
|
|
857
|
+
|
|
858
|
+
# Clean up
|
|
859
|
+
os.environ.pop("PLAIN_CLASS_VAR", None)
|
|
860
|
+
os.environ.pop("PLAIN_CLASS_PORT", None)
|
|
861
|
+
|
|
862
|
+
try:
|
|
863
|
+
# Test 1: Plain class with EnvVar and default (env var NOT set)
|
|
864
|
+
class PlainConfig:
|
|
865
|
+
uri: str = EnvVar @ "PLAIN_CLASS_VAR" | "ws://localhost:8012"
|
|
866
|
+
port: int = EnvVar @ "PLAIN_CLASS_PORT" | 8080
|
|
867
|
+
|
|
868
|
+
# Accessing class attribute should return resolved value, not _EnvVar
|
|
869
|
+
assert PlainConfig.uri == "ws://localhost:8012", f"Expected default, got {PlainConfig.uri}"
|
|
870
|
+
assert isinstance(PlainConfig.uri, str), f"Expected str, got {type(PlainConfig.uri)}"
|
|
871
|
+
|
|
872
|
+
# Note: Without @proto, type conversion doesn't happen
|
|
873
|
+
# (the int annotation is not processed)
|
|
874
|
+
assert PlainConfig.port == 8080, f"Expected 8080, got {PlainConfig.port}"
|
|
875
|
+
|
|
876
|
+
# Test 2: With env var set
|
|
877
|
+
os.environ["PLAIN_CLASS_VAR"] = "ws://192.168.1.1:9000"
|
|
878
|
+
|
|
879
|
+
class PlainConfig2:
|
|
880
|
+
uri: str = EnvVar @ "PLAIN_CLASS_VAR" | "ws://localhost:8012"
|
|
881
|
+
|
|
882
|
+
assert PlainConfig2.uri == "ws://192.168.1.1:9000", f"Expected env value, got {PlainConfig2.uri}"
|
|
883
|
+
|
|
884
|
+
# Test 3: Instance access also works
|
|
885
|
+
c = PlainConfig2()
|
|
886
|
+
assert c.uri == "ws://192.168.1.1:9000", f"Expected env value on instance, got {c.uri}"
|
|
887
|
+
|
|
888
|
+
finally:
|
|
889
|
+
os.environ.pop("PLAIN_CLASS_VAR", None)
|
|
890
|
+
os.environ.pop("PLAIN_CLASS_PORT", None)
|
|
891
|
+
|
|
892
|
+
|
|
893
|
+
def test_envvar_descriptor_websocket_max_size():
|
|
894
|
+
"""Test EnvVar works for websocket max size pattern (the bug report case).
|
|
895
|
+
|
|
896
|
+
This tests the exact pattern that caused the original bug:
|
|
897
|
+
WEBSOCKET_MAX_SIZE: int = EnvVar @ "WEBSOCKET_MAX_SIZE" | 2**28
|
|
898
|
+
|
|
899
|
+
The issue was that accessing WEBSOCKET_MAX_SIZE returned an _EnvVar object
|
|
900
|
+
instead of the int value, causing: AttributeError: '_EnvVar' object has no attribute 'decode'
|
|
901
|
+
"""
|
|
902
|
+
import os
|
|
903
|
+
|
|
904
|
+
from params_proto import EnvVar
|
|
905
|
+
|
|
906
|
+
os.environ.pop("WEBSOCKET_MAX_SIZE", None)
|
|
907
|
+
|
|
908
|
+
try:
|
|
909
|
+
class VuerClient:
|
|
910
|
+
URI: str = EnvVar @ "VUER_CLIENT_URI" | "ws://localhost:8012"
|
|
911
|
+
WEBSOCKET_MAX_SIZE: int = EnvVar @ "WEBSOCKET_MAX_SIZE" | 2**28
|
|
912
|
+
|
|
913
|
+
# Both should resolve to values, not _EnvVar objects
|
|
914
|
+
assert VuerClient.URI == "ws://localhost:8012", f"Expected default URI, got {VuerClient.URI}"
|
|
915
|
+
assert VuerClient.WEBSOCKET_MAX_SIZE == 2**28, f"Expected 2**28, got {VuerClient.WEBSOCKET_MAX_SIZE}"
|
|
916
|
+
|
|
917
|
+
# Verify types
|
|
918
|
+
assert isinstance(VuerClient.URI, str), f"URI should be str, got {type(VuerClient.URI)}"
|
|
919
|
+
assert isinstance(VuerClient.WEBSOCKET_MAX_SIZE, int), f"WEBSOCKET_MAX_SIZE should be int, got {type(VuerClient.WEBSOCKET_MAX_SIZE)}"
|
|
920
|
+
|
|
921
|
+
# The value should be usable (the original bug was .decode() failing)
|
|
922
|
+
# This simulates websocket operations that need to check max size
|
|
923
|
+
assert VuerClient.WEBSOCKET_MAX_SIZE > 0
|
|
924
|
+
|
|
925
|
+
finally:
|
|
926
|
+
os.environ.pop("WEBSOCKET_MAX_SIZE", None)
|
|
927
|
+
os.environ.pop("VUER_CLIENT_URI", None)
|
|
Binary file
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{params_proto-3.1.0 → params_proto-3.1.2}/docs/_archive_v2/examples/environment_variables.md
RENAMED
|
File without changes
|
{params_proto-3.1.0 → params_proto-3.1.2}/docs/_archive_v2/examples/hyperparameter_sweeps.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{params_proto-3.1.0 → params_proto-3.1.2}/skills/params-proto/references/environment-vars.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|