1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 import types
19 import Numeric
20 import warnings
21 import array
22
23
25 """Base class for defining types of Ports which can handle single values
26 or arrays of arbitrary shape.
27
28 this class must be herited only !!!! get inspired by class IntType below
29
30 the construcor arguments are:
31
32 name: string used to identify an instance of a AnyArrayType object
33 ex: float
34
35 you can add the datashape to the name
36 ex: float(0,>=3,4,0)'
37
38 Multi dimensional arrays can be specified by passing
39 a datashape in parenthesis in the form of a string of comma separated
40 expressions. The number of expressions is the number of dimensions.
41 Valid expressions are :
42 0 : meaning there is no condition on this dimension.
43 (in addition, the leading 0 dimensions are optional)
44 x : length of this dimension must be x
45 >x : length of this dimension must be > x
46 <x : length of this dimension must be < x
47 >=x: length of this dimension must be >= x
48 <=x: length of this dimension must be <= x
49
50 for instance a list of vertices can be represented by float(0,3)
51 float: describe the smalest elementary datum (one coordinate).
52 you can introduce your own elementary type
53 (generaly inheriting basic types), this allow you to easily
54 define color and shape for this type (see InstancematType below)
55
56 3: because there are 3 coordinates per vertex.
57 0: because we don't have any limitation on the number of vertices.
58 It is a leading 0, therefore this dimension is optionnal
59 (meaning: if you're passing a single vertex [x,y,z],
60 your are not oblige to put it in a list.
61 ex: you can give [x,y,z] or [[x,y,z]])
62
63 """
64 - def __init__(self,
65
66 name='None',
67 datashape=None,
68 klass=None,
69
70 dataDescr=None,
71 color=None,
72 shape='diamond',
73 width=None, height=None,
74 ):
75
76
77
78 self['name'] = name
79 self['datashape'] = datashape
80 self['class'] = klass
81 self['dataDescr'] = dataDescr
82
83 if color is None:
84 color = 'white'
85 self['color'] = color
86
87 if shape is None:
88 shape = self._shape(datashape)
89 self['shape'] = shape
90
91 if width is None:
92 width = 12
93 self['width'] = width
94
95 if height is None:
96 if shape == 'circle' or shape == 'square':
97 height = self['width']
98 else:
99 height = 8
100 self['height'] = height
101
102
103 self.dimensionTest = []
104
105
106 if datashape is None:
107 self.lenDimensionTest = 0
108 else:
109
110 for dimlim in datashape[1:-1].split(','):
111
112
113
114
115
116 if dimlim.isdigit():
117 if int(dimlim)!=0:
118 self.dimensionTest.append( lambda x: x==int(dimlim) )
119 else:
120 self.dimensionTest.append( None )
121 else:
122 strg = ''
123 for c in dimlim:
124 if c in ['>', '<']:
125 strg += 'x '+c
126 else:
127 strg += c
128 self.dimensionTest.append( eval('lambda x: %s'%strg) )
129
130 self.lenDimensionTest = len(self.dimensionTest)
131
132
134 """data comes in as a numeric array, and returns True if required
135 shapes pass tests, returns False is tests fail, or returns number of missing
136 dimensions if test pass but optional dims are missing
137 """
138
139 missingDimensions = self.lenDimensionTest - len(data.shape)
140 for i in range(missingDimensions):
141 data.shape = (1,) + data.shape
142
143 for dim,f in zip(data.shape, self.dimensionTest):
144 if f is not None:
145 if not f(dim):
146 return False, data
147
148 if missingDimensions > 0:
149 return missingDimensions, data
150 else:
151 return True, data
152
153
155 """This function is called by the constructor to return the number of
156 edges used to draw the port icon based on the number of dimensions of the type.
157 NOTE: this function is only used if the icon shape is not specified as an
158 argument to the constructor.
159 """
160 if datashape is not None:
161 lDimensions = datashape[1:-1].split(',')
162 lShape = len(lDimensions) * 2 - 1
163 if lDimensions[0] == '0':
164 lShape -= 1
165 else:
166 lShape = 0
167
168 return lShape
169
170
171 - def cast(self, data):
172 return False, None
173
174
176 if self['class'] is None:
177 return True, data
178 if self['datashape'] is None:
179 if isinstance(data, self['class']):
180 return True, data
181 else:
182 return False, None
183 try:
184 lArray = Numeric.array(data)
185 lArray0 = lArray[0]
186 while hasattr(lArray0,'shape'):
187 lArray0 = lArray0[0]
188 if isinstance(lArray0, self['class']):
189 return True, lArray
190 else:
191 return False, None
192 except:
193 return False, None
194
195
196
197 from UserDict import UserDict
198 -class AnyType(
199 UserDict
200
201
202 ):
203
204 - def __init__(self, name='Old None', color='white', shape='diamond',
205 width=12, height=8, klass=None, dataDescr=None
206
207 ):
208 UserDict.__init__(self)
209
210
211
212
213
214
215
216
217
218
219 self.data['name'] = name
220 self.data['dataDescr'] = dataDescr
221 self.data['shape'] = shape
222 self.data['width'] = width
223 self.data['height'] = height
224 self.data['color'] = color
225 self.data['class'] = klass
226 self.data['datashape'] = None
227
228
229 - def cast(self, data):
230 """returns a success status (true, false) and the coerced data"""
231 assert True, data
232 return False, None
233
234
236 """returns true if data if of the proper type"""
237 return True
238
239
240
242
243 - def __init__(self, name='float', datashape=None, color='green',
244 shape='circle', width=None, height=None):
245 AnyArrayType.__init__(self, name=name, color=color,
246 shape=shape, width=width, height=height,
247 klass=float, datashape=datashape)
248
249
251 if self['datashape'] is None:
252 if type(data) == types.FloatType:
253 return True, data
254 else:
255 return False, None
256 try:
257 lArray = Numeric.array(data, 'f')
258 return True, lArray
259 except:
260 return False, None
261
262
263 - def cast(self, data):
264 if self['datashape'] is None:
265 if type(data) == types.FloatType:
266 return True, data
267 try:
268 data = float(data)
269 return True, data
270 except:
271 return False, data
272 try:
273 lArray = (Numeric.array(data)).astype('f')
274 return True, lArray
275 except:
276 return False, None
277
278
279
281
282 - def __init__(self, name='int', datashape=None,color='yellow',
283 shape='circle', width=None, height=None):
284 AnyArrayType.__init__(self, name=name, color=color,
285 shape=shape, width=width, height=height,
286 klass=int, datashape=datashape)
287
288
290 if self['datashape'] is None:
291 if type(data) == types.IntType:
292 return True, data
293 else:
294 return False, None
295 try:
296 lArray = Numeric.array(data, 'i')
297 return True, lArray
298 except:
299 return False, None
300
301
302 - def cast(self, data):
303 if self['datashape'] is None:
304 if type(data) == types.IntType:
305 return True, data
306 try:
307 data = int(data)
308 return True, data
309 except:
310 return False, data
311 try:
312 lArray = (Numeric.array(data)).astype('i')
313 return True, lArray
314 except:
315 return False, None
316
317
318
320
321 - def __init__(self, name='boolean', datashape=None, color='yellow',
322 shape='rect', width=None, height=None):
323
324 AnyArrayType.__init__(self, name=name, color=color,
325 shape=shape, width=width, height=height,
326 klass=bool, datashape=datashape)
327
328
330 if self['datashape'] is None:
331 if type(data) == types.BooleanType:
332 return True, data
333 else:
334 return False, None
335 try:
336 array = Numeric.array(data, 'b')
337 return True, array
338 except:
339 return False, None
340
341
342 - def cast(self, data):
343 if self['datashape'] is None:
344 if type(data) == types.BooleanType:
345 return True, data
346 try:
347 data = bool(data)
348 return True, data
349 except:
350 return False, data
351 try:
352
353 lArray = (Numeric.array(data)).astype('b')
354 return True, lArray
355 except:
356 return False, None
357
358
359
361
362 - def __init__(self, name='string', datashape=None, color='white',
363 shape='oval', width=None, height=None):
364
365 AnyArrayType.__init__(self, name=name, color=color,
366 shape=shape, width=width, height=height,
367 klass=str, datashape=datashape)
368
369
371 if self['datashape'] is None:
372 if type(data) == types.StringType:
373 return True, data
374 else:
375 return False, None
376 try:
377 array = Numeric.array(data, 'O')
378
379
380
381 return True, array
382 except:
383 return False, None
384
385
386 - def cast(self, data):
387 if self['datashape'] is None:
388 if type(data) == types.StringType:
389 return True, data
390 try:
391 data = str(data)
392 return True, data
393 except:
394 return False, data
395 try:
396 lArray = (Numeric.array(data)).astype('O')
397 return True, lArray
398 except:
399 return False, None
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
426
428 AnyType.__init__(self)
429 self.data['name'] = 'list'
430 self.data['color'] = 'cyan'
431 self.data['shape'] = 'oval'
432 self.data['width'] = 12
433 self.data['height'] = 12
434 self.data['class'] = list
435
436
439
440
441 - def cast(self, data):
442 try:
443 data = list(data)
444 return True, data
445 except:
446 return False, data
447
448
449
451
453 AnyType.__init__(self)
454 self.data['name'] = 'tuple'
455 self.data['color'] = 'cyan'
456 self.data['shape'] = 'oval'
457 self.data['width'] = 12
458 self.data['height'] = 12
459 self.data['class'] = tuple
460
461
464
465
466 - def cast(self, data):
467 try:
468 data = tuple(data)
469 return True, data
470 except:
471 return False, data
472
473
474
476
478 AnyType.__init__(self)
479 self.data['name'] = 'dict'
480 self.data['color'] = 'cyan'
481 self.data['shape'] = 'oval'
482 self.data['width'] = 12
483 self.data['height'] = 12
484 self.data['class'] = dict
485
486
489
490
491
493
495 AnyType.__init__(self)
496 self.data['name'] = 'array'
497 self.data['color'] = 'cyan'
498 self.data['shape'] = 'oval'
499 self.data['width'] = 12
500 self.data['height'] = 12
501 self.data['class'] = array.array
502
503
506
507
508
510
512 AnyType.__init__(self)
513 self.data['name'] = 'NumericArray'
514 self.data['color'] = 'orange'
515 self.data['shape'] = 'pentagon'
516 self.data['class'] = Numeric.array
517
518
520 return isinstance(data, Numeric.ArrayType)
521
522
523 - def cast(self, data):
524 try:
525 data = Numeric.array(data)
526 return True, data
527 except:
528 return False, data
529
530
531
533
535 AnyType.__init__(self)
536 self.data['name'] = 'vector'
537 self.data['color'] = 'cyan'
538 self.data['shape'] = 'oval'
539 self.data['width'] = 12
540 self.data['height'] = 12
541 self.data['class'] = None
542
543
545 try:
546 if type(data) != types.StringType:
547 len(data)
548 return True
549 else:
550 return False
551 except:
552 return False
553
554
555 - def cast(self, data):
556 """returns a success status (true, false) and the coerced data
557 """
558 if type(data) == types.StringType:
559 return True, (data, )
560 return False, None
561
562
563
565
567 AnyType.__init__(self)
568 self.data['name'] = 'triggerOut'
569 self.data['color'] = 'orange'
570 self.data['shape'] = 'square'
571 del self.data['class']
572
573
574
576
578 AnyType.__init__(self)
579 self.data['name'] = 'triggerIn'
580 self.data['color'] = 'orange'
581 self.data['shape'] = 'square'
582 del self.data['class']
583
584
585
587
589 AnyType.__init__(self)
590 self.data['name'] = 'tkcolor'
591 self.data['color'] = 'orange'
592 self.data['shape'] = 'square'
593 del self.data['class']
594
596 import Tkinter
597 try:
598 Tkinter._default_root.winfo_rgb(data)
599 return True
600 finally:
601 return False
602
603
604
606 """Port type object manager
607
608 This object is used to register port type instances which are associated with
609 port. new types can be registered by passing an instance of port type object
610 to the .addType(instance) method.
611
612 The .portTypeInstances dictionary provides a mapping between the a name used
613 to describe the data acceptable for a port and an instance of a subclass of
614 AnyArrayType. This name can be
615
616 The .reverseLookUp dictionary is used to obtain a port type from the class of
617 and object. This is used top propagate data types to ports that are mutatable
618 """
619
621
622 self.portTypeInstances = {}
623 self.reverseLookUp = {}
624
625 self.addType( AnyArrayType() )
626
627
628 self.addType( FloatType() )
629 self.addType( IntType() )
630
631
632 self.addType( BooleanType() )
633 self.addType( StringType() )
634
635 self.portTypeInstances['str'] = self.portTypeInstances['string']
636
637
638 self.addSynonym('coord2', 'float', '(2)',
639 color='green', shape='oval')
640 self.addSynonym('coord3', 'float', '(3)',
641 color='green', shape='rect')
642 self.addSynonym('normal3', 'float', '(3)',
643 color='blue', shape='rect')
644 self.addSynonym('colorfloat3or4', 'float', '(>=3 and <=4)',
645 color='orange', shape='rect')
646 self.addSynonym('instancemat', 'float', '(4,4)',
647 color='cyan', shape='rect')
648 self.addSynonym('indice2', 'int', '(2)',
649 color='purple', shape='rect')
650 self.addSynonym('indice2+', 'int', '(>=2)',
651 color='purple', shape='rect')
652 self.addSynonym('indice3or4', 'int', '(>=3 and <=4)',
653 color='purple', shape='rect')
654
655 self.addSynonym('2Darray', 'float', '(>0,>0)', color='cyan')
656
657 self.addSynonym('colorRGB', existingTypeName='colorfloat3or4')
658 self.addSynonym('colorsRGB', existingTypeName='colorRGB',datashape='(0)')
659 self.addSynonym('coordinates3D', existingTypeName='coord3',datashape='(0)')
660 self.addSynonym('faceIndices', existingTypeName='indice3or4',datashape='(0)')
661 self.addSynonym('normals3D', existingTypeName='normal3',datashape='(0)')
662
663 self.addType( AnyType() )
664 self.addType( DictType() )
665 self.addType( ListType() )
666 self.addType( TkColorType() )
667 self.addType( TupleType() )
668 self.addType( ArrayType() )
669 self.addType( NumericArrayType() )
670 self.addType( VectorType() )
671 self.addType( TriggerIn() )
672 self.addType( TriggerOut() )
673
674
675 - def addSynonym(self, synonymName, existingTypeName=None, datashape=None,
676 color=None, shape=None, width=None, height=None):
677 """ method to create synonym types
678 synonymName: can be an existing name with a diferent datashape:
679 (existingTypeName must be None, and the basename 'coord3' must be registered)
680 self.addSynonym('coord3(3,4)')
681 existingTypeName: must be a registered name
682 (it can be datatshaped, if it is already registered like that)
683 self.addSynonym('coordinates3D', existingTypeName='coord3',datashape='(3,4)')
684 self.addSynonym('coordinates3D', existingTypeName='coord3(4)',datashape='(3)')
685 self.addSynonym('coordinates3D', existingTypeName='coord3(3,4)')
686 """
687 if existingTypeName is None:
688 assert datashape is None
689 lSplitName = synonymName.split('(')
690 existingTypeName = lSplitName[0]
691 if len(lSplitName) == 2:
692 datashape = '(' + lSplitName[1]
693 basicInstance = self.portTypeInstances[existingTypeName]
694 innerDatashape = basicInstance['datashape']
695 if innerDatashape is not None:
696 if datashape is None:
697 datashape = innerDatashape
698 else:
699 innerDatashape = innerDatashape.split('(')[1]
700 datashape = datashape.split(')')[0]
701 datashape = datashape + ',' + innerDatashape
702 if color is None:
703 color = basicInstance['color']
704 if shape is None:
705 shape = basicInstance['shape']
706 if width is None:
707 width = basicInstance['width']
708 if height is None:
709 if shape == 'circle' or shape == 'square':
710 height = width
711 else:
712 height = 2 * width / 3
713 instance = basicInstance.__class__(
714 name=synonymName, datashape=datashape,
715 color=color, shape=shape, width=width, height=height)
716 self.addType( instance )
717
718
720 lDict = {}
721 typeInstance = self.portTypeInstances[synonymName]
722 lDict['existingTypeName'] = typeInstance.__class__()['name']
723 if lDict['existingTypeName'] == synonymName:
724 return None
725 lDict['synonymName'] = synonymName
726 lDict['datashape'] = typeInstance['datashape']
727 lDict['color'] = typeInstance['color']
728 lDict['shape'] = typeInstance['shape']
729 lDict['width'] = typeInstance['width']
730 lDict['height'] = typeInstance['height']
731 return lDict
732
733
735 if aDict.has_key('existingTypeName') is False:
736 aDict['existingTypeName'] = None
737 if aDict.has_key('datashape') is False:
738 aDict['datashape'] = None
739 if aDict.has_key('color') is False:
740 aDict['color'] = None
741 if aDict.has_key('shape') is False:
742 aDict['shape'] = None
743 if aDict.has_key('width') is False:
744 aDict['width'] = None
745 if aDict.has_key('height') is False:
746 aDict['height'] = None
747
748 self.addSynonym(aDict['synonymName'],
749 existingTypeName=aDict['existingTypeName'],
750 datashape=aDict['datashape'],
751 color=aDict['color'], shape=aDict['shape'],
752 width=aDict['width'], height=aDict['height'])
753
754
756 """register a port type instance
757 """
758
759
760
761 if isinstance(dtypeinstance, AnyType) or \
762 isinstance(dtypeinstance, AnyArrayType):
763
764
765 splittype = dtypeinstance['name'].split('(')
766 basetypename = splittype[0]
767
768 if dtypeinstance['datashape'] is not None:
769 if dtypeinstance['name'].endswith(dtypeinstance['datashape']):
770
771 if self.portTypeInstances.has_key(basetypename) is None:
772 msg = 'Warning: base datatype '+basetypename
773 msg += ' not found in types table when adding %s'%str(dtypeinstance)
774 warnings.warn(msg)
775 return
776 storagename = dtypeinstance['name']
777 else:
778 storagename = basetypename
779
780 if self.portTypeInstances.has_key(storagename):
781 if isinstance(dtypeinstance, AnyType):
782 if not ( \
783 isinstance(self.portTypeInstances[storagename], AnyType) \
784 and \
785 (dtypeinstance.data == self.portTypeInstances[storagename].data) \
786 ):
787 msg = 'Warning! datatype '+storagename+' already registered differently'
788 warnings.warn(msg)
789 return
790 elif isinstance(dtypeinstance, AnyArrayType):
791 if not ( \
792 isinstance(self.portTypeInstances[storagename], AnyArrayType) \
793 and \
794 (dtypeinstance == self.portTypeInstances[storagename]) \
795 ):
796 msg = 'Warning! datatype '+storagename+' already registered differently'
797 warnings.warn(msg)
798 return
799
800 self.portTypeInstances[storagename] = dtypeinstance
801
802 if dtypeinstance.has_key('class'):
803 if not self.reverseLookUp.has_key(dtypeinstance['class']):
804 self.reverseLookUp[dtypeinstance['class']] = dtypeinstance
805
806 else:
807 raise RuntimeError('bad dtypeinstance argument')
808
809
811
812
813
814 splittype = fullName.split('(')
815 typename = splittype[0]
816 datashape = None
817 if len(splittype)==2:
818 datashape = '(' + splittype[1]
819
820 if not self.portTypeInstances.has_key(typename):
821 msg = 'Warning: base datatype ' + typename
822 msg += ' not found in types table'
823 warnings.warn(msg)
824
825 return self.portTypeInstances['None']
826
827 if self.portTypeInstances.has_key(fullName) is False:
828
829 self.addSynonym(fullName, typename, datashape)
830
831 return self.portTypeInstances[fullName]
832
833
834
836 """ return the data type object for types that can be looked up i.e.
837 have a class attribute """
838 return self.reverseLookUp.get(klass, self.reverseLookUp.get(None))
839
840
841 - def get(self, key, default=None):
842 return self.portTypeInstances.get(key, default)
843