Skip to content

Commit b1e7a9b

Browse files
feat(workflow): naming metadata for command parameters (#2071)
* feat(workflow): naming metadata for command parameters
1 parent 514f13b commit b1e7a9b

File tree

6 files changed

+246
-27
lines changed

6 files changed

+246
-27
lines changed

renku/core/models/workflow/dependency_graph.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ def __init__(self, plans=None):
4444
self._connect_all_nodes()
4545

4646
@property
47-
def plans(self):
47+
def plans(self) -> List[Plan]:
4848
"""A list of all plans in the graph."""
4949
return list(self._plans)
5050

renku/core/models/workflow/parameters.py

Lines changed: 59 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@
2727

2828
from renku.core.models.calamus import JsonLDSchema, Nested, fields, rdfs, renku, schema
2929
from renku.core.models.entities import CollectionSchema, EntitySchema
30+
from renku.core.utils.urls import get_slug
31+
32+
RANDOM_ID_LENGTH = 4
3033

3134

3235
@attr.s(eq=False, order=False)
@@ -80,25 +83,44 @@ def as_jsonld(self):
8083

8184

8285
@attr.s(eq=False, order=False)
83-
class CommandParameter(object):
86+
class CommandParameter:
8487
"""Represents a parameter for an execution template."""
8588

8689
_id = attr.ib(default=None, kw_only=True)
8790
_label = attr.ib(default=None, kw_only=True)
8891

92+
default_value = attr.ib(default=None, kw_only=True,)
93+
94+
description = attr.ib(default=None, kw_only=True,)
95+
96+
name: str = attr.ib(default=None, kw_only=True)
97+
8998
position = attr.ib(default=None, type=int, kw_only=True,)
9099

91100
prefix = attr.ib(default=None, type=str, kw_only=True,)
92101

93-
default_value = attr.ib(default=None, kw_only=True,)
94-
95102
@property
96103
def sanitized_id(self):
97104
"""Return ``_id`` sanitized for use in non-jsonld contexts."""
98105
if "/steps/" in self._id:
99106
return "/".join(self._id.split("/")[-4:])
100107
return "/".join(self._id.split("/")[-2:])
101108

109+
def default_label(self):
110+
"""Set default label."""
111+
raise NotImplementedError
112+
113+
def default_name(self):
114+
"""Create a default name."""
115+
raise NotImplementedError
116+
117+
def __attrs_post_init__(self):
118+
"""Post-init hook."""
119+
if not self._label:
120+
self._label = self.default_label()
121+
if not self.name:
122+
self.name = self.default_name()
123+
102124

103125
@attr.s(eq=False, order=False)
104126
class CommandArgument(CommandParameter):
@@ -119,6 +141,10 @@ def default_label(self):
119141
"""Set default label."""
120142
return 'Command Argument "{}"'.format(self.default_value)
121143

144+
def default_name(self):
145+
"""Create a default name."""
146+
return _generate_name(base="param", prefix=self.prefix, position=self.position)
147+
122148
def to_argv(self):
123149
"""String representation (sames as cmd argument)."""
124150
if self.prefix:
@@ -130,8 +156,7 @@ def to_argv(self):
130156

131157
def __attrs_post_init__(self):
132158
"""Post-init hook."""
133-
if not self._label:
134-
self._label = self.default_label()
159+
super().__attrs_post_init__()
135160

136161
if not self.default_value:
137162
self.default_value = self.value
@@ -172,6 +197,10 @@ def default_label(self):
172197
"""Set default label."""
173198
return 'Command Input "{}"'.format(self.default_value)
174199

200+
def default_name(self):
201+
"""Create a default name."""
202+
return _generate_name(base="input", prefix=self.prefix, position=self.position)
203+
175204
def to_argv(self):
176205
"""String representation (sames as cmd argument)."""
177206
if self.prefix:
@@ -190,8 +219,7 @@ def to_stream_repr(self):
190219

191220
def __attrs_post_init__(self):
192221
"""Post-init hook."""
193-
if not self._label:
194-
self._label = self.default_label()
222+
super().__attrs_post_init__()
195223

196224
if not self.default_value:
197225
self.default_value = self.consumes.path
@@ -224,6 +252,10 @@ def generate_id(plan_id, position=None, id_=None):
224252
id_ = str(position) if position else uuid.uuid4().hex
225253
return f"{plan_id}/inputs/{id_}"
226254

255+
def default_name(self):
256+
"""Create a default name."""
257+
return _generate_name(base="input", prefix=self.prefix, position=self.position)
258+
227259
def default_label(self):
228260
"""Set default label."""
229261
return 'Command Input Template "{}"'.format(self.default_value)
@@ -239,11 +271,6 @@ def to_stream_repr(self):
239271

240272
return " < {}".format(self.default_value)
241273

242-
def __attrs_post_init__(self):
243-
"""Post-init hook."""
244-
if not self._label:
245-
self._label = self.default_label()
246-
247274
@classmethod
248275
def from_jsonld(cls, data):
249276
"""Create an instance from JSON-LD data."""
@@ -282,6 +309,10 @@ def default_label(self):
282309
"""Set default label."""
283310
return 'Command Output "{}"'.format(self.default_value)
284311

312+
def default_name(self):
313+
"""Create a default name."""
314+
return _generate_name(base="output", prefix=self.prefix, position=self.position)
315+
285316
def to_argv(self):
286317
"""String representation (sames as cmd argument)."""
287318
if self.prefix:
@@ -303,12 +334,11 @@ def to_stream_repr(self):
303334

304335
def __attrs_post_init__(self):
305336
"""Post-init hook."""
337+
super().__attrs_post_init__()
338+
306339
if not self.default_value:
307340
self.default_value = self.produces.path
308341

309-
if not self._label:
310-
self._label = self.default_label()
311-
312342
@classmethod
313343
def from_jsonld(cls, data):
314344
"""Create an instance from JSON-LD data."""
@@ -389,6 +419,10 @@ def default_label(self):
389419
"""Set default label."""
390420
return 'Command Output Template "{}"'.format(self.default_value)
391421

422+
def default_name(self):
423+
"""Create a default name."""
424+
return _generate_name(base="output", prefix=self.prefix, position=self.position)
425+
392426
def to_argv(self):
393427
"""String representation (sames as cmd argument)."""
394428
raise RuntimeError("Cannot use CommandOutputTemplate in a command.")
@@ -403,11 +437,6 @@ def to_stream_repr(self):
403437

404438
return " 2> {}".format(self.default_value)
405439

406-
def __attrs_post_init__(self):
407-
"""Post-init hook."""
408-
if not self._label:
409-
self._label = self.default_label()
410-
411440
@classmethod
412441
def from_jsonld(cls, data):
413442
"""Create an instance from JSON-LD data."""
@@ -450,9 +479,11 @@ class Meta:
450479

451480
_id = fields.Id(init_name="id")
452481
_label = fields.String(rdfs.label, init_name="label")
482+
default_value = fields.Raw(schema.defaultValue, missing=None)
483+
description = fields.String(schema.description, missing=None)
484+
name = fields.String(schema.name, missing=None)
453485
position = fields.Integer(renku.position, missing=None)
454486
prefix = fields.String(renku.prefix, missing=None)
455-
default_value = fields.Raw(schema.defaultValue, missing=None)
456487

457488

458489
class CommandArgumentSchema(CommandParameterSchema):
@@ -525,7 +556,7 @@ class Meta:
525556

526557

527558
class RunParameterSchema(JsonLDSchema):
528-
"""CommandParameter schema."""
559+
"""RunParameter schema."""
529560

530561
class Meta:
531562
"""Meta class."""
@@ -539,3 +570,9 @@ class Meta:
539570
name = fields.String(schema.name)
540571
value = fields.String(renku.value)
541572
type = fields.String(renku.type)
573+
574+
575+
def _generate_name(base, prefix, position):
576+
name = get_slug(prefix.strip(" -=")) if prefix else base
577+
position = position or uuid.uuid4().hex[:RANDOM_ID_LENGTH]
578+
return f"{name}-{position}"

renku/core/models/workflow/plan.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ def _generate_name(run):
120120
if not run:
121121
return uuid.uuid4().hex[:MAX_GENERATED_NAME_LENGTH]
122122

123-
name = "-".join(run.to_argv())
123+
name = "-".join(str(a) for a in run.to_argv())
124124
name = secure_filename(name)
125125
rand_length = 5
126126
return f"{name[:MAX_GENERATED_NAME_LENGTH - rand_length -1]}-{uuid.uuid4().hex[:rand_length]}"
@@ -179,7 +179,9 @@ def convert_input(input_: CommandInputTemplate) -> CommandInput:
179179
return CommandInput(
180180
id=input_._id.replace(self.id_, run_id),
181181
consumes=entity,
182+
description=input_.description,
182183
mapped_to=input_.mapped_to,
184+
name=input_.name,
183185
position=input_.position,
184186
prefix=input_.prefix,
185187
)
@@ -192,11 +194,13 @@ def convert_output(output: CommandOutputTemplate) -> CommandOutput:
192194

193195
return CommandOutput(
194196
id=output._id.replace(self.id_, run_id),
195-
produces=entity,
197+
create_folder=output.create_folder,
198+
description=output.description,
196199
mapped_to=output.mapped_to,
200+
name=output.name,
197201
position=output.position,
198202
prefix=output.prefix,
199-
create_folder=output.create_folder,
203+
produces=entity,
200204
)
201205

202206
uuid_ = self._extract_uuid()
@@ -234,7 +238,9 @@ def _convert_command_input(input_: CommandInput, plan_id) -> CommandInputTemplat
234238
return CommandInputTemplate(
235239
id=CommandInputTemplate.generate_id(plan_id=plan_id, id_=Path(input_._id).name),
236240
default_value=consumes,
241+
description=input_.description,
237242
mapped_to=input_.mapped_to,
243+
name=input_.name,
238244
position=input_.position,
239245
prefix=input_.prefix,
240246
)
@@ -251,7 +257,9 @@ def _convert_command_output(output: CommandOutput, plan_id) -> CommandOutputTemp
251257
return CommandOutputTemplate(
252258
id=CommandOutputTemplate.generate_id(plan_id=plan_id, id_=Path(output._id).name),
253259
default_value=produces,
260+
description=output.description,
254261
mapped_to=output.mapped_to,
262+
name=output.name,
255263
position=output.position,
256264
prefix=output.prefix,
257265
create_folder=output.create_folder,

renku/data/new_graph_shacl_shape.json

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -862,12 +862,27 @@
862862
"closed": true,
863863
"targetClass": "prov:Plan",
864864
"property": [
865+
{
866+
"nodeKind": "sh:Literal",
867+
"path": "schema:description",
868+
"datatype": {
869+
"@id": "xsd:string"
870+
},
871+
"maxCount": 1
872+
},
865873
{
866874
"sh:class": {
867875
"@id": "renku:CommandArgument"
868876
},
869877
"path": "renku:hasArguments"
870878
},
879+
{
880+
"nodeKind": "sh:Literal",
881+
"path": "schema:keywords",
882+
"datatype": {
883+
"@id": "xsd:string"
884+
}
885+
},
871886
{
872887
"nodeKind": "sh:Literal",
873888
"path": "renku:command",
@@ -916,13 +931,30 @@
916931
"closed": true,
917932
"targetClass": "renku:CommandArgument",
918933
"property": [
934+
{
935+
"nodeKind": "sh:Literal",
936+
"path": "schema:description",
937+
"datatype": {
938+
"@id": "xsd:string"
939+
},
940+
"maxCount": 1
941+
},
919942
{
920943
"nodeKind": "sh:Literal",
921944
"path": "rdfs:label",
922945
"datatype": {
923946
"@id": "xsd:string"
924947
}
925948
},
949+
{
950+
"nodeKind": "sh:Literal",
951+
"path": "schema:name",
952+
"datatype": {
953+
"@id": "xsd:string"
954+
},
955+
"minCount": 1,
956+
"maxCount": 1
957+
},
926958
{
927959
"nodeKind": "sh:Literal",
928960
"path": "renku:position",
@@ -1013,13 +1045,29 @@
10131045
"closed": true,
10141046
"targetClass": "renku:CommandInputTemplate",
10151047
"property": [
1048+
{
1049+
"nodeKind": "sh:Literal",
1050+
"path": "schema:description",
1051+
"datatype": {
1052+
"@id": "xsd:string"
1053+
},
1054+
"maxCount": 1
1055+
},
10161056
{
10171057
"nodeKind": "sh:Literal",
10181058
"path": "rdfs:label",
10191059
"datatype": {
10201060
"@id": "xsd:string"
10211061
}
10221062
},
1063+
{
1064+
"nodeKind": "sh:Literal",
1065+
"path": "schema:name",
1066+
"datatype": {
1067+
"@id": "xsd:string"
1068+
},
1069+
"maxCount": 1
1070+
},
10231071
{
10241072
"nodeKind": "sh:Literal",
10251073
"path": "renku:position",
@@ -1064,13 +1112,29 @@
10641112
"closed": true,
10651113
"targetClass": "renku:CommandOutputTemplate",
10661114
"property": [
1115+
{
1116+
"nodeKind": "sh:Literal",
1117+
"path": "schema:description",
1118+
"datatype": {
1119+
"@id": "xsd:string"
1120+
},
1121+
"maxCount": 1
1122+
},
10671123
{
10681124
"nodeKind": "sh:Literal",
10691125
"path": "rdfs:label",
10701126
"datatype": {
10711127
"@id": "xsd:string"
10721128
}
10731129
},
1130+
{
1131+
"nodeKind": "sh:Literal",
1132+
"path": "schema:name",
1133+
"datatype": {
1134+
"@id": "xsd:string"
1135+
},
1136+
"maxCount": 1
1137+
},
10741138
{
10751139
"nodeKind": "sh:Literal",
10761140
"path": "renku:position",

0 commit comments

Comments
 (0)