Package MDSplus :: Module mdsdevice
[frames] | no frames]

Source Code for Module MDSplus.mdsdevice

  1  from treenode import TreeNode 
  2  from compound import * 
  3  from _treeshr import TreeStartConglomerate 
  4   
5 -class Device(TreeNode):
6 """Used for device support classes. Provides ORIGINAL_PART_NAME, PART_NAME and Add methods and allows referencing of subnodes as conglomerate node attributes. 7 8 Use this class as a superclass for device support classes. When creating a device support class include a class attribute called "parts" 9 which describe the subnodes of your device implementation. The parts attribute should be a list or tuple of dict objects where each dict is a 10 description of each subnode. The dict object should include a minimum of a 'path' key whose value is the relative path of the node (be sure to 11 include the leading period or colon) and a 'type' key whose value is the usage type of the node. In addition you may optionally specify a 12 'value' key whose value is the actual value to store into the node when it is first added in the tree. Instead of a 'value' key, you can 13 provide a 'valueExpr' key whose value is a string which is python code to be evaluated before writing the result into the node. Use a valueExpr 14 when you need to include references to other nodes in the device. Lastly the dict instance may contain an 'options' key whose values are 15 node options specified as a tuple of strings. Note if you only specify one option include a trailing comma in the tuple.The "parts" attribute 16 is used to implement the Add and PART_NAME and ORIGNAL_PART_NAME methods of the subclass. 17 18 You can also include a part_dict class attribute consisting of a dict() instance whose keys are attribute names and whose values are nid 19 offsets. If you do not provide a part_dict attribute then one will be created from the part_names attribute where the part names are converted 20 to lowercase and the colons and periods are replaced with underscores. Referencing a part name will return another instance of the same 21 device with that node as the node in the Device subclass instance. The Device class also supports the part_name and original_part_name 22 attributes which is the same as doing devinstance.PART_NAME(None). NOTE: Device subclass names MUST BE UPPERCASE! 23 24 Sample usage1:: 25 26 from MDSplus import Device 27 28 class MYDEV(Device): 29 parts=[{'path':':COMMENT','type':'text'}, 30 {'path':':INIT_ACTION','type':'action', 31 'valueExpr':"Action(Dispatch(2,'CAMAC_SERVER','INIT',50,None),Method(None,'INIT',head))", 32 'options':('no_write_shot',)}, 33 {'path':':STORE_ACTION','type':'action', 34 'valueExpr':"Action(Dispatch(2,'CAMAC_SERVER','STORE',50,None),Method(None,'STORE',head))", 35 'options':('no_write_shot',)}, 36 {'path':'.SETTINGS','type':'structure'}, 37 {'path':'.SETTINGS:KNOB1','type':'numeric'}, 38 {'path':'.SIGNALS','type':'structure'}, 39 {'path':'.SIGNALS:CHANNEL_1','type':'signal','options':('no_write_model','write_once')}] 40 41 def init(self,arg): 42 knob1=self.settings_knob1.record 43 return 1 44 45 def store(self,arg): 46 from MDSplus import Signal 47 self.signals_channel_1=Signal(32,None,42) 48 49 Sample usage2:: 50 51 from MDSplus import Device 52 53 parts=[{'path':':COMMENT','type':'text'}, 54 {'path':':INIT_ACTION','type':'action', 55 'valueExpr':"Action(Dispatch(2,'CAMAC_SERVER','INIT',50,None),Method(None,'INIT',head))", 56 'options':('no_write_shot',)}, 57 {'path':':STORE_ACTION','type':'action', 58 'valueExpr':"Action(Dispatch(2,'CAMAC_SERVER','STORE',50,None),Method(None,'STORE',head))", 59 'options':('no_write_shot',)}, 60 {'path':'.SETTINGS','type':'structure'}, 61 {'path':'.SETTINGS:KNOB1','type':'numeric'}, 62 {'path':'.SIGNALS','type':'structure'}, 63 {'path':'.SIGNALS:CHANNEL_1','type':'signal','options':('no_write_model','write_once')}] 64 65 part_dict={'knob1':5,'chan1':7} 66 67 def init(self,arg): 68 knob1=self.knob1.record 69 return 1 70 71 def store(self,arg): 72 from MDSplus import Signal 73 self.chan1=Signal(32,None,42) 74 75 If you need to reference attributes using computed names you can do something like:: 76 77 for i in range(16): 78 self.__setattr__('signals_channel_%02d' % (i+1,),Signal(...)) 79 """ 80
81 - def __class_init__(cls):
82 if not hasattr(cls,'initialized'): 83 if hasattr(cls,'parts'): 84 cls.part_names=list() 85 for elt in cls.parts: 86 cls.part_names.append(elt['path']) 87 if hasattr(cls,'part_names') and not hasattr(cls,'part_dict'): 88 cls.part_dict=dict() 89 for i in range(len(cls.part_names)): 90 try: 91 cls.part_dict[cls.part_names[i][1:].lower().replace(':','_').replace('.','_')]=i+1 92 except: 93 pass 94 cls.initialized=True
95 __class_init__=classmethod(__class_init__) 96
97 - def __new__(cls,node):
98 """Create class instance. Initialize part_dict class attribute if necessary. 99 @param node: Not used 100 @type node: TreeNode 101 @return: Instance of the device subclass 102 @rtype: Device subclass instance 103 """ 104 if cls.__name__ == 'Device': 105 raise TypeError,"Cannot create instances of Device class" 106 cls.__class_init__(); 107 return super(Device,cls).__new__(cls,node)
108
109 - def __init__(self,node):
110 """Initialize a Device instance 111 @param node: Conglomerate node of this device 112 @type node: TreeNode 113 @rtype: None 114 """ 115 try: 116 self.nids=node.conglomerate_nids.nid_number 117 self.head=int(self.nids[0]) 118 except Exception,e: 119 self.head=node.nid 120 super(Device,self).__init__(node.nid,node.tree)
121
122 - def ORIGINAL_PART_NAME(self,arg):
123 """Method to return the original part name. 124 Will return blank string if part_name class attribute not defined or node used to create instance is the head node or past the end of part_names tuple. 125 @param arg: Not used. Placeholder for do method argument 126 @type arg: Use None 127 @return: Part name of this node 128 @rtype: str 129 """ 130 name = "" 131 if self.nid != self.head: 132 try: 133 name = self.part_names[self.nid-self.head-1].upper() 134 except: 135 pass 136 return name
137 PART_NAME=ORIGINAL_PART_NAME 138
139 - def __getattr__(self,name):
140 """Return TreeNode of subpart if name matches mangled node name. 141 @param name: part name. Node path with colons and periods replaced by underscores. 142 @type name: str 143 @return: Device instance of device part 144 @rtype: Device 145 """ 146 if name == 'part_name' or name == 'original_part_name': 147 return self.ORIGINAL_PART_NAME(None) 148 try: 149 return self.__class__(TreeNode(self.part_dict[name]+self.head,self.tree)) 150 except KeyError: 151 return super(Device,self).__getattr__(name)
152
153 - def __setattr__(self,name,value):
154 """Set value into device subnode if name matches a mangled subpart node name. Otherwise assign value to class instance attribute. 155 @param name: Name of attribute or device subpart 156 @type name: str 157 @param value: Value of the attribute or device subpart 158 @type value: varied 159 @rtype: None 160 """ 161 try: 162 TreeNode(self.part_dict[name]+self.head,self.tree).record=value 163 except KeyError: 164 super(Device,self).__setattr__(name,value)
165
166 - def Add(cls,tree,path):
167 """Used to add a device instance to an MDSplus tree. 168 This method is invoked when a device is added to the tree when using utilities like mdstcl and the traverser. 169 For this to work the device class name (uppercase only) and the package name must be returned in the MdsDevices tdi function. 170 Also the Device subclass must include the parts attribute which is a list or tuple containing one dict instance per subnode of the device. 171 The dict instance should include a 'path' key set to the relative node name path of the subnode. a 'type' key set to the usage string of 172 the subnode and optionally a 'value' key or a 'valueExpr' key containing a value to initialized the node or a string containing python 173 code which when evaluated during the adding of the device after the subnode has been created produces a data item to store in the node. 174 And finally the dict instance can contain an 'options' key which should contain a list or tuple of strings of node attributes which will be turned 175 on (i.e. write_once). 176 """ 177 cls.__class_init__() 178 TreeStartConglomerate(tree,len(cls.parts)+1) 179 head=tree.addNode(path,'DEVICE') 180 head=cls(head) 181 head.record=Conglom('__python__',cls.__name__,None,"from %s import %s" % (cls.__module__[0:cls.__module__.index('.')],cls.__name__)) 182 head.write_once=True 183 for elt in cls.parts: 184 node=tree.addNode(path+elt['path'],elt['type']) 185 for elt in cls.parts: 186 node=tree.getNode(path+elt['path']) 187 if 'value' in elt: 188 node.record=elt['value'] 189 if 'valueExpr' in elt: 190 node.record=eval(elt['valueExpr']) 191 if 'options' in elt: 192 for option in elt['options']: 193 exec 'node.'+option+'=True'
194 Add=classmethod(Add)
195