switch source package format to 3.0 quilt
[debian/gnuradio] / grc / base / Block.py
1 """
2 Copyright 2008, 2009 Free Software Foundation, Inc.
3 This file is part of GNU Radio
4
5 GNU Radio Companion is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
9
10 GNU Radio Companion is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
18 """
19
20 from . import odict
21 from Element import Element
22
23 from Cheetah.Template import Template
24 from UserDict import UserDict
25
26 class TemplateArg(UserDict):
27         """
28         A cheetah template argument created from a param.
29         The str of this class evaluates to the param's to code method.
30         The use of this class as a dictionary (enum only) will reveal the enum opts.
31         The __call__ or () method can return the param evaluated to a raw python data type.
32         """
33
34         def __init__(self, param):
35                 UserDict.__init__(self)
36                 self._param = param
37                 if param.is_enum():
38                         for key in param.get_opt_keys():
39                                 self[key] = str(param.get_opt(key))
40
41         def __str__(self):
42                 return str(self._param.to_code())
43
44         def __call__(self):
45                 return self._param.get_evaluated()
46
47 def _get_keys(lst): return [elem.get_key() for elem in lst]
48 def _get_elem(lst, key):
49         try: return lst[_get_keys(lst).index(key)]
50         except ValueError: raise ValueError, 'Key "%s" not found in %s.'%(key, _get_keys(lst))
51
52 class Block(Element):
53
54         def __init__(self, flow_graph, n):
55                 """
56                 Make a new block from nested data.
57                 @param flow graph the parent element
58                 @param n the nested odict
59                 @return block a new block
60                 """
61                 #build the block
62                 Element.__init__(self, flow_graph)
63                 #grab the data
64                 params = n.findall('param')
65                 sources = n.findall('source')
66                 sinks = n.findall('sink')
67                 self._name = n.find('name')
68                 self._key = n.find('key')
69                 self._category = n.find('category') or ''
70                 self._block_wrapper_path = n.find('block_wrapper_path')
71                 #create the param objects
72                 self._params = list()
73                 #add the id param
74                 self.get_params().append(self.get_parent().get_parent().Param(
75                         block=self,
76                         n=odict({
77                                 'name': 'ID',
78                                 'key': 'id',
79                                 'type': 'id',
80                         })
81                 ))
82                 self.get_params().append(self.get_parent().get_parent().Param(
83                         block=self,
84                         n=odict({
85                                 'name': 'Enabled',
86                                 'key': '_enabled',
87                                 'type': 'raw',
88                                 'value': 'True',
89                                 'hide': 'all',
90                         })
91                 ))
92                 for param in map(lambda n: self.get_parent().get_parent().Param(block=self, n=n), params):
93                         key = param.get_key()
94                         #test against repeated keys
95                         try: assert key not in self.get_param_keys()
96                         except AssertionError: raise Exception, 'Key "%s" already exists in params'%key
97                         #store the param
98                         self.get_params().append(param)
99                 #create the source objects
100                 self._sources = list()
101                 for source in map(lambda n: self.get_parent().get_parent().Port(block=self, n=n, dir='source'), sources):
102                         key = source.get_key()
103                         #test against repeated keys
104                         try: assert key not in self.get_source_keys()
105                         except AssertionError: raise Exception, 'Key "%s" already exists in sources'%key
106                         #store the port
107                         self.get_sources().append(source)
108                 #create the sink objects
109                 self._sinks = list()
110                 for sink in map(lambda n: self.get_parent().get_parent().Port(block=self, n=n, dir='sink'), sinks):
111                         key = sink.get_key()
112                         #test against repeated keys
113                         try: assert key not in self.get_sink_keys()
114                         except AssertionError: raise Exception, 'Key "%s" already exists in sinks'%key
115                         #store the port
116                         self.get_sinks().append(sink)
117
118         def get_enabled(self):
119                 """
120                 Get the enabled state of the block.
121                 @return true for enabled
122                 """
123                 try: return eval(self.get_param('_enabled').get_value())
124                 except: return True
125
126         def set_enabled(self, enabled):
127                 """
128                 Set the enabled state of the block.
129                 @param enabled true for enabled
130                 """
131                 self.get_param('_enabled').set_value(str(enabled))
132
133         def __str__(self): return 'Block - %s - %s(%s)'%(self.get_id(), self.get_name(), self.get_key())
134
135         def get_id(self): return self.get_param('id').get_value()
136         def is_block(self): return True
137         def get_name(self): return self._name
138         def get_key(self): return self._key
139         def get_category(self): return self._category
140         def get_doc(self): return ''
141         def get_ports(self): return self.get_sources() + self.get_sinks()
142         def get_children(self): return self.get_ports() + self.get_params()
143         def get_block_wrapper_path(self): return self._block_wrapper_path
144
145         ##############################################
146         # Access Params
147         ##############################################
148         def get_param_keys(self): return _get_keys(self._params)
149         def get_param(self, key): return _get_elem(self._params, key)
150         def get_params(self): return self._params
151
152         ##############################################
153         # Access Sinks
154         ##############################################
155         def get_sink_keys(self): return _get_keys(self._sinks)
156         def get_sink(self, key): return _get_elem(self._sinks, key)
157         def get_sinks(self): return self._sinks
158
159         ##############################################
160         # Access Sources
161         ##############################################
162         def get_source_keys(self): return _get_keys(self._sources)
163         def get_source(self, key): return _get_elem(self._sources, key)
164         def get_sources(self): return self._sources
165
166         def get_connections(self):
167                 return sum([port.get_connections() for port in self.get_ports()], [])
168
169         def resolve_dependencies(self, tmpl):
170                 """
171                 Resolve a paramater dependency with cheetah templates.
172                 @param tmpl the string with dependencies
173                 @return the resolved value
174                 """
175                 tmpl = str(tmpl)
176                 if '$' not in tmpl: return tmpl
177                 n = dict((p.get_key(), TemplateArg(p)) for p in self.get_params())
178                 try: return str(Template(tmpl, n))
179                 except Exception, e: return "-------->\n%s: %s\n<--------"%(e, tmpl)
180
181         ##############################################
182         # Controller Modify
183         ##############################################
184         def type_controller_modify(self, direction):
185                 """
186                 Change the type controller.
187                 @param direction +1 or -1
188                 @return true for change
189                 """
190                 changed = False
191                 type_param = None
192                 for param in filter(lambda p: p.is_enum(), self.get_params()):
193                         children = self.get_ports() + self.get_params()
194                         #priority to the type controller
195                         if param.get_key() in ' '.join(map(lambda p: p._type, children)): type_param = param
196                         #use param if type param is unset
197                         if not type_param: type_param = param
198                 if type_param:
199                         #try to increment the enum by direction
200                         try:
201                                 keys = type_param.get_option_keys()
202                                 old_index = keys.index(type_param.get_value())
203                                 new_index = (old_index + direction + len(keys))%len(keys)
204                                 type_param.set_value(keys[new_index])
205                                 changed = True
206                         except: pass
207                 return changed
208
209         def port_controller_modify(self, direction):
210                 """
211                 Change the port controller.
212                 @param direction +1 or -1
213                 @return true for change
214                 """
215                 return False
216
217         ##############################################
218         ## Import/Export Methods
219         ##############################################
220         def export_data(self):
221                 """
222                 Export this block's params to nested data.
223                 @return a nested data odict
224                 """
225                 n = odict()
226                 n['key'] = self.get_key()
227                 n['param'] = map(lambda p: p.export_data(), self.get_params())
228                 return n
229
230         def import_data(self, n):
231                 """
232                 Import this block's params from nested data.
233                 Any param keys that do not exist will be ignored.
234                 Since params can be dynamically created based another param,
235                 call rewrite, and repeat the load until the params stick.
236                 This call to rewrite will also create any dynamic ports
237                 that are needed for the connections creation phase.
238                 @param n the nested data odict
239                 """
240                 get_hash = lambda: hash(tuple(map(hash, self.get_params())))
241                 my_hash = 0
242                 while get_hash() != my_hash:
243                         params_n = n.findall('param')
244                         for param_n in params_n:
245                                 key = param_n.find('key')
246                                 value = param_n.find('value')
247                                 #the key must exist in this block's params
248                                 if key in self.get_param_keys():
249                                         self.get_param(key).set_value(value)
250                         #store hash and call rewrite
251                         my_hash = get_hash()
252                         self.rewrite()