Merged changeset r9285:9377 from jblum/grc into trunk, with distcheck fixes
[debian/gnuradio] / grc / src / grc_gnuradio / Param.py
1 """
2 Copyright 2008 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 ##@package grc_gnuradio.Param
20 #Flow graph block parameters.
21 #@author Josh Blum
22
23 from utils import expr_utils
24 from grc.elements.Param import Param as _Param
25 import os
26
27 class Param(_Param):
28
29         _init = False
30         _hostage_cells = list()
31
32         ##possible param types
33         TYPES = _Param.TYPES + [
34                 'complex', 'real', 'int',
35                 'complex_vector', 'real_vector', 'int_vector',
36                 'hex', 'string',
37                 'file_open', 'file_save',
38                 'id',
39                 'grid_pos', 'import',
40         ]
41
42         def get_hide(self):
43                 """!
44                 Get the hide value from the base class.
45                 If hide was empty, and this is a type controller, set hide to part.
46                 If hide was empty, and this is an id of a non variable, set hide to part.
47                 @return hide the hide property string
48                 """
49                 hide = _Param.get_hide(self)
50                 #hide IO controlling params
51                 if not hide and self.get_key() in (
52                         'type', 'vlen', 'num_inputs', 'num_outputs'
53                 ): hide = 'part'
54                 #hide ID in non variable blocks
55                 elif not hide and self.get_key() == 'id' and self.get_parent().get_key() not in (
56                         'variable', 'variable_slider', 'variable_chooser', 'variable_text_box', 'parameter', 'options'
57                 ): hide = 'part'
58                 return hide
59
60         def evaluate(self):
61                 """!
62                 Evaluate the value.
63                 @return evaluated type
64                 """
65                 self._lisitify_flag = False
66                 self._stringify_flag = False
67                 self._hostage_cells = list()
68                 def eval_string(v):
69                         try:
70                                 e = self.get_parent().get_parent().evaluate(v)
71                                 assert(isinstance(e, str))
72                                 return e
73                         except:
74                                 self._stringify_flag = True
75                                 return v
76                 t = self.get_type()
77                 v = self.get_value()
78                 #########################
79                 # Enum Type
80                 #########################
81                 if self.is_enum(): return self.get_value()
82                 #########################
83                 # Numeric Types
84                 #########################
85                 elif t in ('raw', 'complex', 'real', 'int', 'complex_vector', 'real_vector', 'int_vector', 'hex'):
86                         #raise exception if python cannot evaluate this value
87                         try: e = self.get_parent().get_parent().evaluate(v)
88                         except:
89                                 self._add_error_message('Value "%s" cannot be evaluated.'%v)
90                                 raise Exception
91                         #raise an exception if the data is invalid
92                         if t == 'raw': return e
93                         elif t == 'complex':
94                                 try: assert(isinstance(e, (complex, float, int, long)))
95                                 except AssertionError:
96                                         self._add_error_message('Expression "%s" is invalid for type complex.'%str(e))
97                                         raise Exception
98                                 return e
99                         elif t == 'real':
100                                 try: assert(isinstance(e, (float, int, long)))
101                                 except AssertionError:
102                                         self._add_error_message('Expression "%s" is invalid for type real.'%str(e))
103                                         raise Exception
104                                 return e
105                         elif t == 'int':
106                                 try: assert(isinstance(e, (int, long)))
107                                 except AssertionError:
108                                         self._add_error_message('Expression "%s" is invalid for type integer.'%str(e))
109                                         raise Exception
110                                 return e
111                         elif t == 'complex_vector':
112                                 if not isinstance(e, (tuple, list, set)):
113                                         self._lisitify_flag = True
114                                         e = [e]
115                                 try:
116                                         for ei in e:
117                                                 assert(isinstance(ei, (complex, float, int, long)))
118                                 except AssertionError:
119                                         self._add_error_message('Expression "%s" is invalid for type complex vector.'%str(e))
120                                         raise Exception
121                                 return e
122                         elif t == 'real_vector':
123                                 if not isinstance(e, (tuple, list, set)):
124                                         self._lisitify_flag = True
125                                         e = [e]
126                                 try:
127                                         for ei in e:
128                                                 assert(isinstance(ei, (float, int, long)))
129                                 except AssertionError:
130                                         self._add_error_message('Expression "%s" is invalid for type real vector.'%str(e))
131                                         raise Exception
132                                 return e
133                         elif t == 'int_vector':
134                                 if not isinstance(e, (tuple, list, set)):
135                                         self._lisitify_flag = True
136                                         e = [e]
137                                 try:
138                                         for ei in e:
139                                                 assert(isinstance(ei, (int, long)))
140                                 except AssertionError:
141                                         self._add_error_message('Expression "%s" is invalid for type integer vector.'%str(e))
142                                         raise Exception
143                                 return e
144                         elif t == 'hex':
145                                 return hex(e)
146                         else: raise TypeError, 'Type "%s" not handled'%t
147                 #########################
148                 # String Types
149                 #########################
150                 elif t in ('string', 'file_open', 'file_save'):
151                         #do not check if file/directory exists, that is a runtime issue
152                         e = eval_string(v)
153                         return str(e)
154                 #########################
155                 # Unique ID Type
156                 #########################
157                 elif t == 'id':
158                         #can python use this as a variable?
159                         try:
160                                 assert(len(v) > 0)
161                                 assert(v[0].isalpha())
162                                 for c in v: assert(c.isalnum() or c in ('_',))
163                         except AssertionError:
164                                 self._add_error_message('ID "%s" must be alpha-numeric or underscored, and begin with a letter.'%v)
165                                 raise Exception
166                         params = self.get_all_params('id')
167                         keys = [param.get_value() for param in params]
168                         try: assert(len(keys) == len(set(keys)))
169                         except:
170                                 self._add_error_message('ID "%s" is not unique.'%v)
171                                 raise Exception
172                         return v
173                 #########################
174                 # Grid Position Type
175                 #########################
176                 elif t == 'grid_pos':
177                         if not v: return '' #allow for empty grid pos
178                         e = self.get_parent().get_parent().evaluate(v)
179                         try:
180                                 assert(isinstance(e, (list, tuple)) and len(e) == 4)
181                                 for ei in e: assert(isinstance(ei, int))
182                         except AssertionError:
183                                 self._add_error_message('A grid position must be a list of 4 integers.')
184                                 raise Exception
185                         row, col, row_span, col_span = e
186                         #check row, col
187                         try: assert(row >= 0 and col >= 0)
188                         except AssertionError:
189                                 self._add_error_message('Row and column must be non-negative.')
190                                 raise Exception
191                         #check row span, col span
192                         try: assert(row_span > 0 and col_span > 0)
193                         except AssertionError:
194                                 self._add_error_message('Row and column span must be greater than zero.')
195                                 raise Exception
196                         #calculate hostage cells
197                         for r in range(row_span):
198                                 for c in range(col_span):
199                                         self._hostage_cells.append((row+r, col+c))
200                         #avoid collisions
201                         params = filter(lambda p: p is not self, self.get_all_params('grid_pos'))
202                         for param in params:
203                                 for cell in param._hostage_cells:
204                                         if cell in self._hostage_cells:
205                                                 self._add_error_message('Another graphical element is using cell "%s".'%str(cell))
206                                                 raise Exception
207                         return e
208                 #########################
209                 # Import Type
210                 #########################
211                 elif t == 'import':
212                         n = dict() #new namespace
213                         try: exec v in n
214                         except ImportError:
215                                 self._add_error_message('Import "%s" failed.'%v)
216                                 raise Exception
217                         except Exception:
218                                 self._add_error_message('Bad import syntax: "%s".'%v)
219                                 raise Exception
220                         return filter(lambda k: str(k) != '__builtins__', n.keys())
221                 #########################
222                 else: raise TypeError, 'Type "%s" not handled'%t
223
224         def to_code(self):
225                 """!
226                 Convert the value to code.
227                 @return a string representing the code
228                 """
229                 #run init tasks in evaluate
230                 if not self._init:
231                         self.evaluate()
232                         self._init = True
233                 v = self.get_value()
234                 t = self.get_type()
235                 if t in ('string', 'file_open', 'file_save'): #string types
236                         if self._stringify_flag:
237                                 return '"%s"'%v.replace('"', '\"')
238                         else:
239                                 return v
240                 elif t in ('complex_vector', 'real_vector', 'int_vector'): #vector types
241                         if self._lisitify_flag:
242                                 return '(%s, )'%v
243                         else:
244                                 return '(%s)'%v
245                 else:
246                         return v
247
248         def get_all_params(self, type):
249                 """!
250                 Get all the params from the flowgraph that have the given type.
251                 @param type the specified type
252                 @return a list of params
253                 """
254                 return sum([filter(lambda p: p.get_type() == type, block.get_params()) for block in self.get_parent().get_parent().get_blocks()], [])
255