Skip to content

Commit f9e443a

Browse files
committed
Add short form for params
Short-form allows simple literal values without the verbose `value:` wrapper: - 32 (int) - "adam" (str) - [1, 2, 3] (list) - {"key": "val"} (dict without V1Param keys) Full-form requires explicit V1Param fields: - {"value": 32} - {"value": "outputs.path", "ref": "ops.upstream"} - {"value": "data.csv", "toInit": True}
1 parent 3d1aa9b commit f9e443a

5 files changed

Lines changed: 501 additions & 11 deletions

File tree

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,6 @@
1-
from polyaxon._flow.params.params import ParamSpec, V1Param
1+
from polyaxon._flow.params.params import (
2+
ParamSpec,
3+
V1Param,
4+
is_short_form_param,
5+
normalize_param_value,
6+
)

cli/polyaxon/_flow/params/ops_params.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ def validate_params(
3333

3434
def parse_param(k, v) -> V1Param:
3535
if not isinstance(v, V1Param):
36-
v = V1Param.read(v, config_type=".yaml") if v else V1Param()
36+
v = V1Param.read(v, config_type=".yaml") if v is not None else V1Param()
3737
if v and k in contexts_by_keys:
3838
v.context_only = True
3939
if v.to_init is None:

cli/polyaxon/_flow/params/params.py

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,81 @@
1616
from polyaxon.exceptions import PolyaxonValidationError
1717

1818

19+
# V1Param fields that indicate full-form param definition
20+
# If a dict contains any of these keys, it's a full-form V1Param, not a short-form value
21+
V1_PARAM_KEYS = {
22+
"value",
23+
"ref",
24+
"toInit",
25+
"to_init",
26+
"toEnv",
27+
"to_env",
28+
"contextOnly",
29+
"context_only",
30+
"connection",
31+
}
32+
33+
34+
def is_short_form_param(value: Any) -> bool:
35+
"""
36+
Determines if a value is in short-form (direct value) or full-form (V1Param dict).
37+
38+
A value is considered "short-form" if it's NOT a dict containing V1Param keys.
39+
40+
Examples of short-form values:
41+
- 32 (int)
42+
- "adam" (str)
43+
- 0.8 (float)
44+
- [1, 2, 3] (list)
45+
- {"key1": "val1", "key2": "val2"} (dict without V1Param keys)
46+
47+
Examples of full-form values:
48+
- {} (empty dict - treated as full-form for backward compatibility)
49+
- {"value": 32}
50+
- {"value": "outputs.path", "ref": "ops.upstream"}
51+
- {"value": "data.csv", "toInit": True}
52+
53+
Args:
54+
value: The value to check
55+
56+
Returns:
57+
True if the value is in short-form, False if it's a full-form V1Param dict
58+
"""
59+
if not isinstance(value, Mapping):
60+
# Non-dict values are always short-form
61+
return True
62+
63+
# Empty dict is treated as full-form for backward compatibility
64+
# (passing {} means "no value specified", not "value is empty dict")
65+
if not value:
66+
return False
67+
68+
# A dict is short-form if it has NO V1Param keys
69+
return not bool(V1_PARAM_KEYS & set(value.keys()))
70+
71+
72+
def normalize_param_value(value: Any) -> Dict:
73+
"""
74+
Normalizes a param value to full-form V1Param dict.
75+
76+
If the value is already in full-form, returns it as-is.
77+
If the value is in short-form, wraps it in {"value": <value>}.
78+
79+
Args:
80+
value: The value to normalize (can be short-form or full-form)
81+
82+
Returns:
83+
A dict suitable for V1Param.from_dict()
84+
"""
85+
if value is None:
86+
return {"value": None}
87+
88+
if is_short_form_param(value):
89+
return {"value": value}
90+
91+
return value
92+
93+
1994
def validate_param_value(value, ref):
2095
if ref and not isinstance(value, str):
2196
raise ValueError(
@@ -201,6 +276,30 @@ class V1Param(BaseSchemaModel, ctx_refs.RefMixin, ParamValueMixin):
201276
202277
## YAML usage
203278
279+
Polyaxon supports two syntaxes for defining params: **short-form** and **full-form**.
280+
281+
### Short-form syntax
282+
283+
> **N.B**: Requires Polyaxon CLI version `>= 2.13`
284+
285+
For simple literal values, you can use the concise short-form syntax:
286+
287+
```yaml
288+
>>> params:
289+
>>> loss: MeanSquaredError
290+
>>> preprocess: true
291+
>>> accuracy: 0.1
292+
>>> batch_size: 32
293+
>>> layers: [64, 128, 256]
294+
>>> config:
295+
>>> optimizer: adam
296+
>>> lr: 0.001
297+
```
298+
299+
### Full-form syntax
300+
301+
The full-form syntax is required when using advanced features like `ref`, `toInit`, `toEnv`, `connection`, or `contextOnly`:
302+
204303
```yaml
205304
>>> params:
206305
>>> loss:
@@ -214,6 +313,22 @@ class V1Param(BaseSchemaModel, ctx_refs.RefMixin, ParamValueMixin):
214313
>>> value: outputs.images_path
215314
```
216315
316+
You can mix both syntaxes in the same params section:
317+
318+
```yaml
319+
>>> params:
320+
>>> # Short-form for simple values
321+
>>> batch_size: 32
322+
>>> learning_rate: 0.001
323+
>>> # Full-form when using refs or other options
324+
>>> upstream_output:
325+
>>> ref: ops.training
326+
>>> value: outputs.model_path
327+
>>> data_path:
328+
>>> value: /data/train
329+
>>> toInit: true
330+
```
331+
217332
## Python usage
218333
219334
```python
@@ -400,6 +515,34 @@ def check_ref(cls, ref, values):
400515
validate_param_value(value=cls.get_value_for_key("value", values), ref=ref)
401516
return ref
402517

518+
@classmethod
519+
def read(
520+
cls, values: Any, partial: bool = False, config_type: str = None
521+
) -> "V1Param":
522+
"""Create a V1Param, supporting both short-form and full-form.
523+
524+
Short-form allows simple literal values without the verbose `value:` wrapper:
525+
- 32 (int)
526+
- "adam" (str)
527+
- [1, 2, 3] (list)
528+
- {"key": "val"} (dict without V1Param keys)
529+
530+
Full-form requires explicit V1Param fields:
531+
- {"value": 32}
532+
- {"value": "outputs.path", "ref": "ops.upstream"}
533+
- {"value": "data.csv", "toInit": True}
534+
535+
Args:
536+
values: The value to convert (short-form or full-form)
537+
partial: If True, skip validation
538+
config_type: Optional config type for reading
539+
540+
Returns:
541+
V1Param instance
542+
"""
543+
normalized = normalize_param_value(values)
544+
return super().read(normalized, partial=partial, config_type=config_type)
545+
403546

404547
class ParamSpec(
405548
namedtuple(

0 commit comments

Comments
 (0)