comparison gmql_queries_statements.py @ 0:a80c93182db3 draft default tip

planemo upload for repository https://github.com/lu-brn/gmql-galaxy commit 953ee36ceda5814dc9baa03427bc0eb4ee2e93bd-dirty
author geco-team
date Tue, 26 Jun 2018 09:08:06 -0400
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:a80c93182db3
1 #!/usr/bin/env python
2 # --------------------------------------------------------------------------------
3 # GMQL Queries Statements Classes
4 # --------------------------------------------------------------------------------
5 # Luana Brancato, luana.brancato@mail.polimi.it
6 # --------------------------------------------------------------------------------
7
8 import yaml
9 from gmql_queries_constants import *
10
11 class Statement(object):
12
13 def __init__(self):
14
15 self.operator = Operator
16 self.variables = dict ()
17 self.params = dict ()
18
19 def save(self, syntax):
20
21 var_o = self.variables.get('output')
22 var_i = [self.variables.get('input1'),self.variables.get('input2','')]
23
24 stm = syntax['STATEMENT'].format(operator=self.operator.value,
25 out_var=var_o,
26 in_vars=" ".join(var_i),
27 parameters='{parameters}')
28
29 return stm
30
31 def write_query(self, syntax):
32 self.syntax = yaml.load(syntax)
33
34 def set_variable(self, var, var_name):
35 self.variables[var_name] = var
36
37 def set_param(self, param, param_type):
38 self.params[param_type] = param
39
40 class Materialize(Statement):
41
42 def __init__(self, filename, input_ds):
43 super(Materialize, self).__init__()
44 self.operator = Operator.MATERIALIZE
45 self.set_variable(filename, 'output')
46 self.set_variable(input_ds, 'input1')
47
48 def save(self, syntax):
49
50 stm = syntax['MATERIALIZE'].format(variable=self.variables.get('input1'),
51 file_name=self.variables.get('output'))
52
53 return stm
54
55
56 class Select(Statement):
57
58 def __init__(self):
59 super(Select, self).__init__()
60 self.operator = Operator.SELECT
61
62 def save(self, syntax):
63 stm = super(Select, self).save(syntax)
64 params_form = syntax['PARAMS']
65 select_params = params_form[self.operator.value]
66 sep = params_form['type_separator']
67
68 params = []
69
70 # Format conditions over metadata
71 predicate = self.params.get('metadata', None)
72
73 if predicate:
74 f_predicate = self.save_wff(params_form, predicate)
75 params.append(select_params['metadata'].format(predicate=f_predicate))
76
77 # Format conditions over samples fields
78 predicate = self.params.get('region', None)
79
80 if predicate:
81 f_predicate = self.save_wff(params_form, predicate)
82 params.append(select_params['region'].format(predicate=f_predicate))
83
84 # Format semijoin conditions
85 predicate = self.params.get('semijoin', None)
86
87 if predicate:
88 f_predicate = predicate.save(select_params['semijoin_predicates'], sep)
89 params.append(select_params['semijoin'].format(predicate=f_predicate))
90
91 stm = stm.format(parameters=sep.join(params))
92
93 return stm
94
95 @staticmethod
96 def save_wff(syntax, pred):
97 w_format = syntax['wff']
98
99 if isinstance(pred, list):
100 if pred[-1] is Wff.AND or Wff.OR:
101 return w_format[pred[-1].value].format(p1=Select.save_wff(syntax, pred[0]), p2=Select.save_wff(syntax, pred[1]))
102 if pred[-1] is Wff.NOT or Wff.BLOCK:
103 return w_format[pred[-1].value].format(p=Select.save_wff(syntax, pred[0]))
104 else :
105 if isinstance(pred, Predicate):
106 return pred.save(syntax)
107 else:
108 return pred
109
110 def set_output_var(self, var):
111 self.set_variable(var, 'output')
112
113 def set_input_var(self, var):
114 self.set_variable(var, 'input1')
115
116 def set_metadata_predicates(self, logicalPredicate):
117 self.set_param(logicalPredicate, 'metadata')
118
119 def set_region_predicates(self, logicalPredicate):
120 self.set_param(logicalPredicate, 'region')
121
122 def set_semijoin_predicates(self, sjClauses):
123 self.set_param(sjClauses, 'semijoin')
124
125
126 class Project(Statement):
127 def __init__(self):
128 super(Project, self).__init__()
129 self.operator = Operator.PROJECT
130
131 def set_output_var(self, var):
132 self.set_variable(var, 'output')
133
134 def set_input_var(self, var):
135 self.set_variable(var, 'input1')
136
137 def set_regions(self, regionsAttributes, type='keep'):
138 self.set_param((regionsAttributes, type), 'regions')
139
140 def set_metadata(self, metadataAttributes, type='keep'):
141 self.set_param((metadataAttributes, type),'metadata')
142
143 def set_new_regions(self, regionAttDef):
144 self.set_param(regionAttDef, 'newRegions')
145
146 def set_new_metadata(self, metadataAttDef):
147 self.set_param(metadataAttDef, 'newMetadata')
148
149 def save(self, syntax):
150 stm = super(Project, self).save(syntax)
151
152 params_form = syntax['PARAMS']
153 project_format = params_form[self.operator.value]
154 param_sep = params_form['param_separator']
155 type_sep = params_form['type_separator']
156
157 params = []
158
159 # Format regions attributes to keep
160 params_regs = self.params.get('regions', None)
161
162 if params_regs:
163 att_list = project_format['att_list'][params_regs[1]].format(att_list=params_regs[0].save('',type_sep))
164 regionsAtt = project_format['regions'].format(att_list=att_list)
165 params.append(regionsAtt)
166
167 # Format metadata attributes to keep
168 params_mets = self.params.get('metadata', None)
169
170 if params_mets:
171 att_list = project_format['att_list'][params_mets[1]].format(att_list=params_mets[0].save('',type_sep))
172 metadataAtt = project_format['metadata'].format(att_list=att_list)
173 params.append(metadataAtt)
174
175 # Format new regions attributes definitions
176 params_newReg = self.params.get('newRegions', None)
177
178 if params_newReg :
179 newRegions = map(lambda x: x.save(params_form),params_newReg)
180 params.append(project_format['newRegions'].format(newAttributes=param_sep.join(newRegions)))
181
182 # Format new metadata attributes definitions
183 params_newMeta = self.params.get('newMetadata', None)
184
185 if params_newMeta :
186 newMetadata = map(lambda x: x.save(params_form),params_newMeta)
187 params.append(project_format['newMetadata'].format(newAttributes=param_sep.join(newMetadata)))
188
189 stm = stm.format(parameters=type_sep.join(params))
190
191 return stm
192
193 class Extend(Statement):
194 def __init__(self):
195 super(Extend, self).__init__()
196 self.operator = Operator.EXTEND
197
198 def set_output_var(self, var):
199 self.set_variable(var, 'output')
200
201 def set_input_var(self, var):
202 self.set_variable(var, 'input1')
203
204 def set_new_attributes(self, newAttributes):
205 self.set_param(newAttributes, 'newMetadata')
206
207 def save(self, syntax):
208 stm = super(Extend, self).save(syntax)
209
210 params_form = syntax['PARAMS']
211 param_sep = params_form['param_separator']
212
213 # Get new metadata attributes definition and format them
214
215 params_newMeta = self.params.get('newMetadata')
216 newMetadata = map(lambda x: x.save(params_form),params_newMeta)
217
218 stm = stm.format(parameters=param_sep.join(newMetadata))
219
220 return stm
221
222 class Merge(Statement):
223 def __init__(self):
224 super(Merge, self).__init__()
225 self.operator = Operator.MERGE
226
227 def set_output_var(self, var):
228 self.set_variable(var, 'output')
229
230 def set_input_var(self, var):
231 self.set_variable(var, 'input1')
232
233 def set_groupy_clause(self, joinbyClause):
234 self.set_param(joinbyClause, 'groupby')
235
236 def save(self, syntax):
237 stm = super(Merge, self).save(syntax)
238
239 params_form = syntax['PARAMS']
240 merge_format = params_form[Operator.MERGE.value]
241 param_sep = params_form['param_separator']
242 type_sep = params_form['type_separator']
243
244 params = []
245
246 # Format groupby clause (if present)
247 gbc = self.params.get('groupby', None)
248
249 if gbc:
250 params.append(merge_format['groupby'].format(groupbyClause=gbc.save(params_form, param_sep)))
251
252 stm = stm.format(parameters=type_sep.join(params))
253
254 return stm
255
256 class Difference(Statement):
257 def __init__(self):
258 super(Difference, self).__init__()
259 self.operator = Operator.DIFFERENCE
260 self.exact_flag = False
261
262 def set_output_var(self, var):
263 self.set_variable(var, 'output')
264
265 def set_reference_var(self, var):
266 self.set_variable(var, 'input1')
267
268 def set_negative_var(self, var):
269 self.set_variable(var, 'input2')
270
271 def set_exact(self):
272 self.exact_flag = True
273
274 def set_joinby_clause(self, joinbyClause):
275 self.set_param(joinbyClause, 'joinby')
276
277 def save(self, syntax):
278 stm = super(Difference, self).save(syntax)
279
280 params_form = syntax['PARAMS']
281 difference_format = params_form[Operator.DIFFERENCE.value]
282 param_sep = params_form['param_separator']
283 type_sep = params_form['type_separator']
284
285 params = []
286
287 # Check if the the exact flag is set to true and in case write the option
288 if self.exact_flag:
289 params.append(difference_format['exact'].format(flag='true'))
290
291 # Format joinby clause (if present)
292 jbc = self.params.get('joinby', None)
293
294 if jbc:
295 params.append(difference_format['joinby'].format(joinbyClause=jbc.save(params_form, param_sep)))
296
297 stm = stm.format(parameters=type_sep.join(params))
298
299 return stm
300
301
302 class Union(Statement):
303 def __init__(self):
304 super(Union, self).__init__()
305 self.operator = Operator.UNION
306
307 def set_output_var(self, var):
308 self.set_variable(var, 'output')
309
310 def set_first_var(self, var):
311 self.set_variable(var, 'input1')
312
313 def set_second_var(self, var):
314 self.set_variable(var, 'input2')
315
316 def save(self, syntax):
317 stm = super(Union, self).save(syntax)
318 return stm.format(parameters='')
319
320
321 class Group(Statement):
322 def __init__(self):
323 super(Group, self).__init__()
324 self.operator = Operator.GROUP
325
326 def set_output_var(self, var):
327 self.set_variable(var, 'output')
328
329 def set_input_var(self, var):
330 self.set_variable(var, 'input1')
331
332 def set_group_meta(self, groupbyClause):
333 self.set_param(groupbyClause, 'meta')
334
335 def set_new_metadata(self, metaAttDef):
336 self.set_param(metaAttDef, 'newMetadata')
337
338 def set_group_regions(self, attList):
339 self.set_param(attList, 'regions')
340
341 def set_new_regions(self, regionsAttDef):
342 self.set_param(regionsAttDef, 'newRegions')
343
344 def save(self, syntax):
345 stm = super(Group, self).save(syntax)
346
347 params_form = syntax['PARAMS']
348 group_format = params_form[Operator.GROUP.value]
349 type_sep = params_form['type_separator']
350 param_sep = params_form['param_separator']
351
352 params = []
353
354 # Check if there are additional grouping options over metadata, and in case set them up
355 # (they are joinbyClause)
356
357 # Format joinby clause
358 jbc = self.params.get('meta', None)
359
360 if jbc:
361 params.append(group_format['meta'].format(groupMeta=jbc.save(params_form,param_sep)))
362
363
364 # Check if there are new metadata definitions and set them up
365 # (they are AttributesGenerator objects)
366
367 params_newMeta = self.params.get('newMetadata', None)
368 if params_newMeta:
369 newMetadata = map(lambda x: x.save(params_form), params_newMeta)
370 params.append(group_format['newMetadata'].format(newAttributes=param_sep.join(newMetadata)))
371
372
373 # Check if there are additional grouping options over regions attributes, and in case set them up
374 # (they are an AttributesList)
375
376 attList = self.params.get('regions', None)
377 if attList:
378 params.append(group_format['regions'].format(groupRegions=attList.save(params_form, param_sep)))
379
380 # Check if there are new metadata definitions and set them up
381 # (they are RegionGenerator objects)
382
383 params_newRegions = self.params.get('newRegions', None)
384 if params_newRegions:
385 newRegions = map(lambda x: x.save(params_form), params_newRegions)
386 params.append(group_format['newRegions'].format(newRegions=param_sep.join(newRegions)))
387
388 stm = stm.format(parameters=type_sep.join(params))
389
390 return stm
391
392
393 class Cover(Statement):
394 def __init__(self, cover_variant):
395 super(Cover, self).__init__()
396 self.operator = Operator(cover_variant)
397
398 def set_minAcc(self, minAcc):
399 self.minAcc = minAcc
400
401 def set_maxAcc(self, maxAcc):
402 self.maxAcc = maxAcc
403
404 def set_output_var(self, var):
405 self.set_variable(var, 'output')
406
407 def set_input_var(self, var):
408 self.set_variable(var, 'input1')
409
410 def set_new_regions(self, regionAttributes):
411 self.set_param(regionAttributes, 'newRegions')
412
413 def set_groupby_clause(self, groupbyClause):
414 self.set_param(groupbyClause, 'groupby')
415
416 def save(self, syntax):
417 stm = super(Cover, self).save(syntax)
418
419 params_form = syntax['PARAMS']
420 cover_format = params_form[Operator.COVER.value]
421 type_sep = params_form['type_separator']
422 param_sep = params_form['param_separator']
423
424 params = []
425
426 # minAcc and maxAcc are joined and then added to the list as they are
427 params.append(param_sep.join([self.minAcc,self.maxAcc]))
428
429 # Format groupby clause
430 jbc = self.params.get('groupby', None)
431
432 if jbc:
433 params.append(cover_format['groupby'].format(groupbyClause=jbc.save(params_form,param_sep)))
434
435 # Format new region attributes definitions
436
437 param_regs = self.params.get('newRegions', None)
438
439 if param_regs:
440 newRegions = map(lambda x: x.save(params_form), param_regs)
441 params.append(cover_format['regions'].format(newRegions=param_sep.join(newRegions)))
442
443 stm = stm.format(parameters=type_sep.join(params))
444
445 return stm
446
447
448 class Map(Statement):
449 def __init__(self):
450 super(Map, self).__init__()
451 self.operator = Operator.MAP
452 self.count_attribute = ''
453
454 def set_output_var(self, var):
455 self.set_variable(var, 'output')
456
457 def set_reference_var(self, var):
458 self.set_variable(var, 'input1')
459
460 def set_experiment_var(self, var):
461 self.set_variable(var, 'input2')
462
463 def set_count_attribute(self, name):
464 self.count_attribute = name
465
466 def set_new_regions(self, regionAttributes):
467 self.set_param(regionAttributes, 'newRegions')
468
469 def set_joinby_clause(self, joinbyClause):
470 self.set_param(joinbyClause, 'joinby')
471
472 def save(self, syntax):
473 stm = super(Map, self).save(syntax)
474
475 params_form = syntax['PARAMS']
476 map_format = params_form[self.operator.value]
477 type_sep = params_form['type_separator']
478 param_sep = params_form['param_separator']
479
480 params = []
481
482 # Format new region attributes definitions
483
484 param_regs = self.params.get('newRegions', None)
485
486 if param_regs :
487 newRegions = map(lambda x: x.save(params_form),param_regs)
488 params.append(map_format['regions'].format(newRegions=param_sep.join(newRegions)))
489
490
491 # Format user chosen name for the count attribute, if present
492 if self.count_attribute :
493 params.append(map_format['count'].format(count_name=self.count_attribute))
494
495 # Format joinby clause
496 jbc = self.params.get('joinby', None)
497
498 if jbc:
499 params.append(map_format['joinby'].format(joinbyClause=jbc.save(params_form,param_sep)))
500
501
502 stm = stm.format(parameters=type_sep.join(params))
503
504 return stm
505
506
507 class Order(Statement):
508
509 def __init__(self):
510 super(Order, self).__init__()
511 self.operator = Operator.ORDER
512
513 def set_output_var(self, var):
514 self.set_variable(var, 'output')
515
516 def set_input_var(self, var):
517 self.set_variable(var, 'input1')
518
519 def set_ordering_attributes(self, ordAtt, type):
520 # Type can be 'metadata' or 'region'
521 self.set_param(ordAtt,type+'OrderingAttributes')
522
523 def set_top_options(self, topts):
524 self.set_param(topts, 'top')
525
526 def save(self, syntax):
527 stm = super(Order,self).save(syntax)
528
529 params_form = syntax['PARAMS']
530 order_form = params_form[self.operator.value]
531 type_sep = params_form['type_separator']
532 sep = params_form['param_separator']
533
534 params = []
535
536 # Format metadata attribute lists
537 meta_att = self.params.get('metadataOrderingAttributes', None)
538 if meta_att:
539 params.append(order_form['metadata']['orderingAttributes']
540 .format(att_list=meta_att.save(order_form['att_list'],sep)))
541
542 # Top options
543 tops = self.params.get('top', None)
544 if tops:
545 m_tops = filter(lambda x: x[0] == 'metadata', tops)
546 if m_tops:
547 m_tops = map(lambda x: order_form[x[0]]['top'][x[1]].format(k=x[2]), m_tops)
548 params.append(type_sep.join(m_tops))
549
550 # Format region attribute lists
551 region_att = self.params.get('regionOrderingAttributes', None)
552 if region_att:
553 params.append(order_form['region']['orderingAttributes']
554 .format(att_list=region_att.save(order_form['att_list'],sep)))
555
556
557 # Top options
558 if tops:
559 r_tops = filter(lambda x: x[0] == 'region', tops)
560 if r_tops:
561 r_tops = map(lambda x: order_form[x[0]]['top'][x[1]].format(k=x[2]), r_tops)
562 params.append(type_sep.join(r_tops))
563
564 stm = stm.format(parameters=type_sep.join(params))
565
566 return stm
567
568 class Join(Statement):
569
570 def __init__(self):
571 super(Join, self).__init__()
572 self.operator = Operator.JOIN
573
574 def set_output_var(self, var):
575 self.set_variable(var, 'output')
576
577 def set_anchor_var(self, var):
578 self.set_variable(var, 'input1')
579
580 def set_experiment_var(self, var):
581 self.set_variable(var, 'input2')
582
583 def set_output_opt(self, coord_param):
584 self.set_param(CoordParam(coord_param), 'output_opt')
585
586 def set_joinby_clause(self, joinbyClause):
587 self.set_param(joinbyClause, 'joinby')
588
589 def set_equi_conditions(self, attributesList):
590 self.set_param(attributesList, 'equi_clause')
591
592 def set_genomic_predicate(self, genomicPredicate):
593 self.set_param(genomicPredicate, 'genomic_predicate')
594
595 def save(self, syntax):
596
597 stm = super(Join, self).save(syntax)
598
599 params_form = syntax['PARAMS']
600 join_format = params_form[self.operator.value]
601 type_sep = params_form['type_separator']
602 sep = params_form['param_separator']
603
604 params = []
605
606 # Format Genomic Predicate
607 gpred = self.params.get('genomic_predicate', None)
608 if gpred:
609 params.append(join_format['genomic_predicate'].format(genomic_predicate=gpred.save(join_format,sep)))
610
611
612 # Format predicate over attributes
613 equi_predicate = self.params.get('equi_clause', None)
614 if equi_predicate:
615 params.append(join_format['equi_clause'].format(att_list=equi_predicate.save(params_form, sep)))
616
617
618 # Format option over output
619 output_cond = self.params.get('output_opt').value
620 if output_cond:
621 params.append(join_format['output_opt'].format(coord_param=output_cond))
622
623 # Format Joinby clause
624 jbc = self.params.get('joinby', None)
625 if jbc:
626 params.append(join_format['joinby'].format(joinbyClause=jbc.save(params_form, sep)))
627
628 stm = stm.format(parameters=type_sep.join(params))
629
630 return stm
631
632
633
634 class Predicate(object):
635
636 def __init__(self, field1, field2, condition):
637
638 self.p_attribute = field1
639 self.p_value = field2
640 self.condition = condition
641 self.value_type = 'string'
642
643 def save(self, syntax):
644 p_format = syntax['predicate']
645
646 predicate = p_format[self.condition].format(att=self.p_attribute,
647 val=p_format['values'][self.value_type].format(p=self.p_value))
648
649 return predicate
650
651
652 class MetaPredicate(Predicate):
653
654 def __init__(self, attribute, value, condition):
655 super(MetaPredicate, self).__init__(attribute, value, condition)
656
657
658 class RegionPredicate(Predicate):
659
660 def __init__(self, attribute, value, condition):
661 super(RegionPredicate, self).__init__(attribute, value, condition)
662
663 def set_value_type(self, type=None):
664 """Possible values type are: coordinate, float, string, meta_attribute"""
665
666 if type is None :
667 if self.p_attribute in ['chr', 'left', 'right', 'strand'] :
668 #The region attribute given is a region coordinate attribute
669 self.value_type = 'coordinate'
670 else :
671 try:
672 self.p_value = int(self.p_value)
673 self.value_type = 'int'
674 except ValueError :
675 try:
676 self.p_value= float(self.p_value)
677 self.value_type = 'float'
678 except ValueError :
679 self.value_type = 'string'
680 else:
681 #The type is given.
682 self.value_type = type
683
684 class RegionGenerator(object):
685 def __init__(self, newRegion, function, argRegion):
686 self.newRegion = newRegion
687 self.function = function
688 self.argument = argRegion
689
690 def save(self, syntax):
691
692 f = syntax['function'].format(function=self.function.value,
693 arg=self.argument)
694
695 return syntax['new_region'].format(r=self.newRegion,
696 function=f)
697
698 class MetaAttributesGenerator(RegionGenerator):
699 def __init__(self, newAttribute, function, argRegion):
700 super(MetaAttributesGenerator, self).__init__(newAttribute, function, argRegion)
701
702 def save(self, syntax):
703 return super(MetaAttributesGenerator, self).save(syntax)
704
705 class ProjectGenerator(RegionGenerator):
706 def __init__(self, newRegion, function, arg):
707 super(ProjectGenerator, self).__init__(newRegion, function, arg)
708
709 def save(self, syntax):
710 if self.function == RegFunction.MATH:
711 f = self.argument
712 return syntax['new_region'].format(r=self.newRegion, function=f)
713 if self.function in ['rename','fixed'] :
714 f = self.argument
715 if self.function == 'fixed':
716 f = "{f}".format(f=f)
717 return syntax['new_region'].format(r=self.newRegion, function=f)
718 if self.function is RegFunction.META :
719 f = syntax['function'].format(function=self.function.value,
720 arg=syntax['param_separator'].join(self.argument))
721 return syntax['new_region'].format(r=self.newRegion,
722 function=f)
723 else:
724 return super(ProjectGenerator, self).save(syntax)
725
726
727
728 class AttributesList(object):
729
730 def __init__(self, attributes):
731 self.attributes = attributes
732
733 def save(self, syntax, sep):
734 attr = sep.join(self.attributes)
735 return attr
736
737 class OrderingAttributes(AttributesList):
738
739 def __init__(self):
740 attributes = list()
741 super(OrderingAttributes, self).__init__(attributes)
742
743 def add_attribute(self, att, desc):
744 self.attributes.append((att,desc))
745
746 def save(self, syntax, sep):
747 self.attributes = map(lambda x: syntax[x[1]].format(att=x[0]), self.attributes)
748 return super(OrderingAttributes, self).save(syntax,sep)
749
750
751 class JoinbyClause(AttributesList):
752
753 def __init__(self, attributes):
754 super(JoinbyClause, self).__init__(attributes)
755
756 def save(self, syntax, sep):
757 attributes = map(lambda x: syntax['metajoin_condition'][x[1]].format(att_name=x[0]), self.attributes)
758 return sep.join(attributes)
759
760 class GroupbyClause(JoinbyClause):
761 def __init__(self, attributes):
762 super(GroupbyClause, self).__init__(attributes)
763
764 def save(self, syntax, sep):
765 return super(GroupbyClause, self).save(syntax, sep)
766
767
768 class SemiJoinPredicate(AttributesList):
769
770 def __init__(self, attributes, dataset, condition):
771 super(SemiJoinPredicate, self).__init__(attributes)
772 self.ds_ext = dataset
773 self.condition = condition
774
775 def save(self, syntax, sep):
776 attributes = super(SemiJoinPredicate, self).save(syntax, sep)
777 return syntax[self.condition].format(attributes=attributes, ds_ext=self.ds_ext)
778
779
780 class GenomicPredicate(object):
781
782 def __init__(self):
783 self.distal_conditions = []
784 self.distal_stream = ''
785
786 def add_distal_condition(self, condition, n):
787 self.distal_conditions.append((DistalConditions(condition), n))
788
789 def add_distal_stream(self, direction):
790 self.distal_stream = DistalStream(direction)
791
792 def save(self, syntax, sep):
793 dc = map(lambda x: syntax['distal_condition'].format(dc=x[0].value, n=x[1]), self.distal_conditions)
794 if self.distal_stream:
795 dc.append(syntax['distal_stream'].format(ds=self.distal_stream.value))
796
797 return sep.join(dc)