Skip to content

Commit 5ffacfd

Browse files
committed
Add support for a pipeline piping's title attribute
1 parent 301c0d7 commit 5ffacfd

File tree

4 files changed

+93
-22
lines changed

4 files changed

+93
-22
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Generated by Django 4.0 on 2022-10-02 16:47
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
('pipelines', '0005_alter_defaultpipingboolparameter_id_and_more'),
10+
]
11+
12+
operations = [
13+
migrations.AddField(
14+
model_name='pluginpiping',
15+
name='title',
16+
field=models.CharField(blank=True, max_length=100),
17+
),
18+
]

store_backend/pipelines/models.py

+1
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ class Meta:
7272

7373

7474
class PluginPiping(models.Model):
75+
title = models.CharField(max_length=100, blank=True)
7576
plugin = models.ForeignKey(Plugin, on_delete=models.CASCADE)
7677
pipeline = models.ForeignKey(Pipeline, on_delete=models.CASCADE,
7778
related_name='plugin_pipings')

store_backend/pipelines/serializers.py

+41-22
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,25 @@
1515
from .models import DefaultPipingBoolParameter, DefaultPipingStrParameter
1616

1717

18+
class PluginPipingSerializer(serializers.HyperlinkedModelSerializer):
19+
previous_id = serializers.ReadOnlyField(source='previous.id')
20+
plugin_id = serializers.ReadOnlyField(source='plugin.id')
21+
plugin_name = serializers.ReadOnlyField(source='plugin.meta.name')
22+
plugin_version = serializers.ReadOnlyField(source='plugin.version')
23+
pipeline_id = serializers.ReadOnlyField(source='pipeline.id')
24+
previous = serializers.HyperlinkedRelatedField(view_name='pluginpiping-detail',
25+
read_only=True)
26+
plugin = serializers.HyperlinkedRelatedField(view_name='plugin-detail',
27+
read_only=True)
28+
pipeline = serializers.HyperlinkedRelatedField(view_name='pipeline-detail',
29+
read_only=True)
30+
31+
class Meta:
32+
model = PluginPiping
33+
fields = ('url', 'id', 'previous_id', 'title', 'plugin_id', 'plugin_name',
34+
'plugin_version', 'pipeline_id', 'previous', 'plugin', 'pipeline')
35+
36+
1837
class PipelineSerializer(serializers.HyperlinkedModelSerializer):
1938
plugin_tree = serializers.JSONField(write_only=True, required=False)
2039
owner_username = serializers.ReadOnlyField(source='owner.username')
@@ -123,6 +142,16 @@ def validate_plugin_tree(self, plugin_tree):
123142
msg = [f"Plugin {plg} is of type 'fs' and therefore can not be used to "
124143
f"create a pipeline."]
125144
raise serializers.ValidationError(msg)
145+
title = d.get('title')
146+
if title is None:
147+
d['title'] = plg.meta.name
148+
else:
149+
piping_serializer = PluginPipingSerializer(data={'title': title})
150+
try:
151+
piping_serializer.is_valid(raise_exception=True)
152+
except serializers.ValidationError as e:
153+
raise serializers.ValidationError([f'Invalid title: {title}, '
154+
f'detail: {str(e)}'])
126155
if 'plugin_parameter_defaults' in d:
127156
param_defaults = d['plugin_parameter_defaults']
128157
PipelineSerializer.validate_plugin_parameter_defaults(plg, param_defaults)
@@ -192,16 +221,20 @@ def get_tree(tree_list):
192221
raise ValueError(f'Could not find the root of the tree in {tree_list}.')
193222
tree = [None] * len(tree_list)
194223
plugin_id = tree_list[root_ix]['plugin_id']
224+
title = tree_list[root_ix]['title']
195225
defaults = tree_list[root_ix]['plugin_parameter_defaults']
196226
tree[root_ix] = {'plugin_id': plugin_id,
227+
'title': title,
197228
'plugin_parameter_defaults': defaults,
198229
'child_indices': []}
199230
for ix, d in enumerate(tree_list):
200231
if ix != root_ix:
201232
if not tree[ix]:
202233
plugin_id = d['plugin_id']
234+
title = d['title']
203235
defaults = d['plugin_parameter_defaults']
204236
tree[ix] = {'plugin_id': plugin_id,
237+
'title': title,
205238
'plugin_parameter_defaults': defaults,
206239
'child_indices': []}
207240
prev_ix = d['previous_index']
@@ -210,8 +243,10 @@ def get_tree(tree_list):
210243
tree[prev_ix]['child_indices'].append(ix)
211244
else:
212245
plugin_id = tree_list[prev_ix]['plugin_id']
246+
title = tree_list[prev_ix]['title']
213247
defaults = tree_list[prev_ix]['plugin_parameter_defaults']
214248
tree[prev_ix] = {'plugin_id': plugin_id,
249+
'title': title,
215250
'plugin_parameter_defaults': defaults,
216251
'child_indices': [ix]}
217252
except (IndexError, TypeError):
@@ -247,7 +282,9 @@ def _add_plugin_tree_to_pipeline(pipeline, tree_dict):
247282
root_ix = tree_dict['root_index']
248283
tree = tree_dict['tree']
249284
root_plg = Plugin.objects.get(pk=tree[root_ix]['plugin_id'])
250-
root_plg_piping = PluginPiping.objects.create(pipeline=pipeline, plugin=root_plg)
285+
title = tree[root_ix]['title']
286+
root_plg_piping = PluginPiping.objects.create(title=title, pipeline=pipeline,
287+
plugin=root_plg)
251288
defaults = tree[root_ix]['plugin_parameter_defaults']
252289
root_plg_piping.save(parameter_defaults=defaults)
253290
# breath-first traversal
@@ -258,33 +295,15 @@ def _add_plugin_tree_to_pipeline(pipeline, tree_dict):
258295
curr_piping = piping_queue.pop(0)
259296
for ix in tree[curr_ix]['child_indices']:
260297
plg = Plugin.objects.get(pk=tree[ix]['plugin_id'])
261-
plg_piping = PluginPiping.objects.create(pipeline=pipeline, plugin=plg,
262-
previous=curr_piping)
298+
title = tree[ix]['title']
299+
plg_piping = PluginPiping.objects.create(title=title, pipeline=pipeline,
300+
plugin=plg, previous=curr_piping)
263301
defaults = tree[ix]['plugin_parameter_defaults']
264302
plg_piping.save(parameter_defaults=defaults)
265303
ix_queue.append(ix)
266304
piping_queue.append(plg_piping)
267305

268306

269-
class PluginPipingSerializer(serializers.HyperlinkedModelSerializer):
270-
plugin_id = serializers.ReadOnlyField(source='plugin.id')
271-
plugin_name = serializers.ReadOnlyField(source='plugin.meta.name')
272-
plugin_version = serializers.ReadOnlyField(source='plugin.version')
273-
pipeline_id = serializers.ReadOnlyField(source='pipeline.id')
274-
previous_id = serializers.ReadOnlyField(source='previous.id')
275-
previous = serializers.HyperlinkedRelatedField(view_name='pluginpiping-detail',
276-
read_only=True)
277-
plugin = serializers.HyperlinkedRelatedField(view_name='plugin-detail',
278-
read_only=True)
279-
pipeline = serializers.HyperlinkedRelatedField(view_name='pipeline-detail',
280-
read_only=True)
281-
282-
class Meta:
283-
model = PluginPiping
284-
fields = ('url', 'id', 'plugin_id', 'plugin_name', 'plugin_version',
285-
'pipeline_id', 'previous_id', 'previous', 'plugin', 'pipeline')
286-
287-
288307
class DefaultPipingStrParameterSerializer(serializers.HyperlinkedModelSerializer):
289308
previous_plugin_piping_id = serializers.ReadOnlyField(
290309
source='plugin_piping.previous_id')

store_backend/pipelines/tests/test_serializers.py

+33
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,7 @@ def test_validate_plugin_tree_raises_validation_error_if_get_tree_raises_value_e
203203
with self.assertRaises(serializers.ValidationError):
204204
pipeline_serializer.validate_plugin_tree(tree)
205205
get_tree_mock.assert_called_with([{"plugin_id": plugin_ds.id,
206+
"title": plugin_ds.meta.name,
206207
"plugin_parameter_defaults": [],
207208
"previous_index": None}])
208209

@@ -222,6 +223,23 @@ def test_validate_plugin_tree_raises_validation_error_if_validate_tree_raises_va
222223
pipeline_serializer.validate_plugin_tree(tree)
223224
validate_tree_mock.assert_called_with(tree_dict)
224225

226+
def test_validate_plugin_tree_raises_validation_error_if_title_too_long(self):
227+
"""
228+
Test whether overriden validate_plugin_tree method raises ValidationError if
229+
internal call to validate_tree method raises ValueError exception.
230+
"""
231+
pipeline = Pipeline.objects.get(name=self.pipeline_name)
232+
pipeline_serializer = PipelineSerializer(pipeline)
233+
plugin_ds = Plugin.objects.get(meta__name=self.plugin_ds_name)
234+
title = 200 * 's'
235+
tree = '[{"plugin_id": ' + str(plugin_ds.id) + ', "title": ' + title + ', previous_index": null}]'
236+
tree_dict = {'root_index': 0, 'tree': [{"plugin_id": plugin_ds.id, "title": title, "child_indices": []}]}
237+
with mock.patch('pipelines.serializers.PipelineSerializer.validate_tree') as validate_tree_mock:
238+
validate_tree_mock.return_value = None
239+
with self.assertRaises(serializers.ValidationError):
240+
pipeline_serializer.validate_plugin_tree(tree)
241+
validate_tree_mock.assert_called_with(tree_dict)
242+
225243
def test_validate_plugin_parameter_defaults_raises_validation_error_if_missing_name_or_default(self):
226244
"""
227245
Test whether custom validate_plugin_parameter_defaults method raises ValidationError if
@@ -269,22 +287,28 @@ def test_get_tree(self):
269287
(plugin_ds2, tf) = Plugin.objects.get_or_create(meta=meta)
270288

271289
tree_list = [{"plugin_id": plugin_ds1.id,
290+
"title": plugin_ds1.meta.name,
272291
"plugin_parameter_defaults": [],
273292
"previous_index": None},
274293
{"plugin_id": plugin_ds2.id,
294+
"title": plugin_ds2.meta.name,
275295
"plugin_parameter_defaults": [],
276296
"previous_index": 0},
277297
{"plugin_id": plugin_ds1.id,
298+
"title": "piping1",
278299
"plugin_parameter_defaults": [],
279300
"previous_index": 1}]
280301

281302
tree = [{"plugin_id": plugin_ds1.id,
303+
"title": plugin_ds1.meta.name,
282304
"plugin_parameter_defaults": [],
283305
"child_indices": [1]},
284306
{"plugin_id": plugin_ds2.id,
307+
"title": plugin_ds2.meta.name,
285308
"plugin_parameter_defaults": [],
286309
"child_indices": [2]},
287310
{"plugin_id": plugin_ds1.id,
311+
"title": "piping1",
288312
"plugin_parameter_defaults": [],
289313
"child_indices": []}]
290314
expected_tree_dict = {'root_index': 0, 'tree': tree}
@@ -320,24 +344,30 @@ def test_get_tree_raises_value_error_if_it_finds_invalid_previous_index(self):
320344
(plugin_ds2, tf) = Plugin.objects.get_or_create(meta=meta)
321345

322346
tree_list = [{"plugin_id": plugin_ds1.id,
347+
"title": plugin_ds1.meta.name,
323348
"plugin_parameter_defaults": [],
324349
"previous_index": None},
325350
{"plugin_id": plugin_ds2.id,
351+
"title": plugin_ds2.meta.name,
326352
"plugin_parameter_defaults": [],
327353
"previous_index": 0},
328354
{"plugin_id": plugin_ds1.id,
355+
"title": "piping1",
329356
"plugin_parameter_defaults": [],
330357
"previous_index": None}]
331358
with self.assertRaises(ValueError):
332359
pipeline_serializer.get_tree(tree_list)
333360

334361
tree_list = [{"plugin_id": plugin_ds1.id,
362+
"title": plugin_ds1.meta.name,
335363
"plugin_parameter_defaults": [],
336364
"previous_index": None},
337365
{"plugin_id": plugin_ds2.id,
366+
"title": plugin_ds2.meta.name,
338367
"plugin_parameter_defaults": [],
339368
"previous_index": 3},
340369
{"plugin_id": plugin_ds1.id,
370+
"title": "piping1",
341371
"plugin_parameter_defaults": [],
342372
"previous_index": 1}]
343373
with self.assertRaises(ValueError):
@@ -372,12 +402,15 @@ def test__add_plugin_tree_to_pipeline(self):
372402
(plugin_ds2, tf) = Plugin.objects.get_or_create(meta=meta)
373403

374404
tree = [{"plugin_id": plugin_ds1.id,
405+
"title": plugin_ds1.meta.name,
375406
"plugin_parameter_defaults": [],
376407
"child_indices": [1]},
377408
{"plugin_id": plugin_ds2.id,
409+
"title": "piping2",
378410
"plugin_parameter_defaults": [],
379411
"child_indices": [2]},
380412
{"plugin_id": plugin_ds1.id,
413+
"title": "piping1",
381414
"plugin_parameter_defaults": [],
382415
"child_indices": []}]
383416
tree_dict = {'root_index': 0, 'tree': tree}

0 commit comments

Comments
 (0)