~ubuntu-branches/ubuntu/trusty/gnuradio/trusty

« back to all changes in this revision

Viewing changes to grc/python/Param.py

  • Committer: Bazaar Package Importer
  • Author(s): Kamal Mostafa
  • Date: 2010-03-13 07:46:01 UTC
  • mfrom: (2.1.2 sid)
  • Revision ID: james.westby@ubuntu.com-20100313074601-zjsa893a87bozyh7
Tags: 3.2.2.dfsg-1ubuntu1
* Fix build for Ubuntu lucid (LP: #260406)
  - add binary package dep for libusrp0, libusrp2-0: adduser
  - debian/rules clean: remove pre-built Qt moc files

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
import expr_utils
 
21
from .. base.Param import Param as _Param, EntryParam
 
22
import Constants
 
23
import numpy
 
24
import os
 
25
import pygtk
 
26
pygtk.require('2.0')
 
27
import gtk
 
28
from gnuradio import eng_notation
 
29
import re
 
30
from gnuradio import gr
 
31
 
 
32
_check_id_matcher = re.compile('^[a-z|A-Z]\w*$')
 
33
_show_id_matcher = re.compile('^(variable\w*|parameter|options|notebook)$')
 
34
 
 
35
class FileParam(EntryParam):
 
36
        """Provide an entry box for filename and a button to browse for a file."""
 
37
 
 
38
        def __init__(self, *args, **kwargs):
 
39
                EntryParam.__init__(self, *args, **kwargs)
 
40
                input = gtk.Button('...')
 
41
                input.connect('clicked', self._handle_clicked)
 
42
                self.pack_start(input, False)
 
43
 
 
44
        def _handle_clicked(self, widget=None):
 
45
                """
 
46
                If the button was clicked, open a file dialog in open/save format.
 
47
                Replace the text in the entry with the new filename from the file dialog.
 
48
                """
 
49
                #get the paths
 
50
                file_path = self.param.is_valid() and self.param.get_evaluated() or ''
 
51
                (dirname, basename) = os.path.isfile(file_path) and os.path.split(file_path) or (file_path, '')
 
52
                if not os.path.exists(dirname): dirname = os.getcwd() #fix bad paths
 
53
                #build the dialog
 
54
                if self.param.get_type() == 'file_open':
 
55
                        file_dialog = gtk.FileChooserDialog('Open a Data File...', None,
 
56
                                gtk.FILE_CHOOSER_ACTION_OPEN, ('gtk-cancel',gtk.RESPONSE_CANCEL,'gtk-open',gtk.RESPONSE_OK))
 
57
                elif self.param.get_type() == 'file_save':
 
58
                        file_dialog = gtk.FileChooserDialog('Save a Data File...', None,
 
59
                                gtk.FILE_CHOOSER_ACTION_SAVE, ('gtk-cancel',gtk.RESPONSE_CANCEL, 'gtk-save',gtk.RESPONSE_OK))
 
60
                        file_dialog.set_do_overwrite_confirmation(True)
 
61
                        file_dialog.set_current_name(basename) #show the current filename
 
62
                file_dialog.set_current_folder(dirname) #current directory
 
63
                file_dialog.set_select_multiple(False)
 
64
                file_dialog.set_local_only(True)
 
65
                if gtk.RESPONSE_OK == file_dialog.run(): #run the dialog
 
66
                        file_path = file_dialog.get_filename() #get the file path
 
67
                        self.entry.set_text(file_path)
 
68
                        self._handle_changed()
 
69
                file_dialog.destroy() #destroy the dialog
 
70
 
 
71
#blacklist certain ids, its not complete, but should help
 
72
import __builtin__
 
73
ID_BLACKLIST = ['self', 'options', 'gr', 'blks2', 'wxgui', 'wx', 'math', 'forms', 'firdes'] + \
 
74
        filter(lambda x: not x.startswith('_'), dir(gr.top_block())) + dir(__builtin__)
 
75
#define types, native python + numpy
 
76
VECTOR_TYPES = (tuple, list, set, numpy.ndarray)
 
77
COMPLEX_TYPES = [complex, numpy.complex, numpy.complex64, numpy.complex128]
 
78
REAL_TYPES = [float, numpy.float, numpy.float32, numpy.float64]
 
79
INT_TYPES = [int, long, numpy.int, numpy.int8, numpy.int16, numpy.int32, numpy.uint64,
 
80
        numpy.uint, numpy.uint8, numpy.uint16, numpy.uint32, numpy.uint64]
 
81
#cast to tuple for isinstance, concat subtypes
 
82
COMPLEX_TYPES = tuple(COMPLEX_TYPES + REAL_TYPES + INT_TYPES)
 
83
REAL_TYPES = tuple(REAL_TYPES + INT_TYPES)
 
84
INT_TYPES = tuple(INT_TYPES)
 
85
 
 
86
class Param(_Param):
 
87
 
 
88
        _init = False
 
89
        _hostage_cells = list()
 
90
 
 
91
        ##possible param types
 
92
        TYPES = _Param.TYPES + [
 
93
                'complex', 'real', 'int',
 
94
                'complex_vector', 'real_vector', 'int_vector',
 
95
                'hex', 'string', 'bool',
 
96
                'file_open', 'file_save',
 
97
                'id',
 
98
                'grid_pos', 'notebook',
 
99
                'import',
 
100
        ]
 
101
 
 
102
        def __repr__(self):
 
103
                """
 
104
                Get the repr (nice string format) for this param.
 
105
                @return the string representation
 
106
                """
 
107
                if not self.is_valid(): return self.get_value()
 
108
                if self.get_value() in self.get_option_keys(): return self.get_option(self.get_value()).get_name()
 
109
                ##################################################
 
110
                # display logic for numbers
 
111
                ##################################################
 
112
                def num_to_str(num):
 
113
                        if isinstance(num, COMPLEX_TYPES):
 
114
                                num = complex(num) #cast to python complex
 
115
                                if num == 0: return '0' #value is zero
 
116
                                elif num.imag == 0: return '%s'%eng_notation.num_to_str(num.real) #value is real
 
117
                                elif num.real == 0: return '%sj'%eng_notation.num_to_str(num.imag) #value is imaginary
 
118
                                elif num.imag < 0: return '%s-%sj'%(eng_notation.num_to_str(num.real), eng_notation.num_to_str(abs(num.imag)))
 
119
                                else: return '%s+%sj'%(eng_notation.num_to_str(num.real), eng_notation.num_to_str(num.imag))
 
120
                        else: return str(num)
 
121
                ##################################################
 
122
                # split up formatting by type
 
123
                ##################################################
 
124
                truncate = 0 #default center truncate
 
125
                max_len = max(27 - len(self.get_name()), 3)
 
126
                e = self.get_evaluated()
 
127
                t = self.get_type()
 
128
                if isinstance(e, bool): return str(e)
 
129
                elif isinstance(e, COMPLEX_TYPES): dt_str = num_to_str(e)
 
130
                elif isinstance(e, VECTOR_TYPES): #vector types
 
131
                        if len(e) > 8:
 
132
                                dt_str = self.get_value() #large vectors use code
 
133
                                truncate = 1
 
134
                        else: dt_str = ', '.join(map(num_to_str, e)) #small vectors use eval
 
135
                elif t in ('file_open', 'file_save'):
 
136
                        dt_str = self.get_value()
 
137
                        truncate = -1
 
138
                else: dt_str = str(e) #other types
 
139
                ##################################################
 
140
                # truncate
 
141
                ##################################################
 
142
                if len(dt_str) > max_len:
 
143
                        if truncate < 0: #front truncate
 
144
                                dt_str = '...' + dt_str[3-max_len:]
 
145
                        elif truncate == 0: #center truncate
 
146
                                dt_str = dt_str[:max_len/2 -3] + '...' + dt_str[-max_len/2:]
 
147
                        elif truncate > 0: #rear truncate
 
148
                                dt_str = dt_str[:max_len-3] + '...'
 
149
                return dt_str
 
150
 
 
151
        def get_input_class(self):
 
152
                if self.get_type() in ('file_open', 'file_save'): return FileParam
 
153
                return _Param.get_input_class(self)
 
154
 
 
155
        def get_color(self):
 
156
                """
 
157
                Get the color that represents this param's type.
 
158
                @return a hex color code.
 
159
                """
 
160
                try:
 
161
                        return {
 
162
                                #number types
 
163
                                'complex': Constants.COMPLEX_COLOR_SPEC,
 
164
                                'real': Constants.FLOAT_COLOR_SPEC,
 
165
                                'int': Constants.INT_COLOR_SPEC,
 
166
                                #vector types
 
167
                                'complex_vector': Constants.COMPLEX_VECTOR_COLOR_SPEC,
 
168
                                'real_vector': Constants.FLOAT_VECTOR_COLOR_SPEC,
 
169
                                'int_vector': Constants.INT_VECTOR_COLOR_SPEC,
 
170
                                #special
 
171
                                'bool': Constants.INT_COLOR_SPEC,
 
172
                                'hex': Constants.INT_COLOR_SPEC,
 
173
                                'string': Constants.BYTE_VECTOR_COLOR_SPEC,
 
174
                                'id': Constants.ID_COLOR_SPEC,
 
175
                                'grid_pos': Constants.INT_VECTOR_COLOR_SPEC,
 
176
                                'notebook': Constants.INT_VECTOR_COLOR_SPEC,
 
177
                                'raw': Constants.WILDCARD_COLOR_SPEC,
 
178
                        }[self.get_type()]
 
179
                except: return _Param.get_color(self)
 
180
 
 
181
        def get_hide(self):
 
182
                """
 
183
                Get the hide value from the base class.
 
184
                Hide the ID parameter for most blocks. Exceptions below.
 
185
                If the parameter controls a port type, vlen, or nports, return part.
 
186
                If the parameter is an empty grid position, return part.
 
187
                These parameters are redundant to display in the flow graph view.
 
188
                @return hide the hide property string
 
189
                """
 
190
                hide = _Param.get_hide(self)
 
191
                if hide: return hide
 
192
                #hide ID in non variable blocks
 
193
                if self.get_key() == 'id' and not _show_id_matcher.match(self.get_parent().get_key()): return 'part'
 
194
                #hide port controllers for type and nports
 
195
                if self.get_key() in ' '.join(map(
 
196
                        lambda p: ' '.join([p._type, p._nports]), self.get_parent().get_ports())
 
197
                ): return 'part'
 
198
                #hide port controllers for vlen, when == 1
 
199
                if self.get_key() in ' '.join(map(
 
200
                        lambda p: p._vlen, self.get_parent().get_ports())
 
201
                ):
 
202
                        try:
 
203
                                assert int(self.get_evaluated()) == 1
 
204
                                return 'part'
 
205
                        except: pass
 
206
                #hide empty grid positions
 
207
                if self.get_key() in ('grid_pos', 'notebook') and not self.get_value(): return 'part'
 
208
                return hide
 
209
 
 
210
        def validate(self):
 
211
                """
 
212
                Validate the param.
 
213
                A test evaluation is performed
 
214
                """
 
215
                _Param.validate(self) #checks type
 
216
                self._evaluated = None
 
217
                try: self._evaluated = self.evaluate()
 
218
                except Exception, e: self.add_error_message(str(e))
 
219
 
 
220
        def get_evaluated(self): return self._evaluated
 
221
 
 
222
        def evaluate(self):
 
223
                """
 
224
                Evaluate the value.
 
225
                @return evaluated type
 
226
                """
 
227
                self._init = True
 
228
                self._lisitify_flag = False
 
229
                self._stringify_flag = False
 
230
                self._hostage_cells = list()
 
231
                def eval_string(v):
 
232
                        try:
 
233
                                e = self.get_parent().get_parent().evaluate(v)
 
234
                                assert isinstance(e, str)
 
235
                                return e
 
236
                        except:
 
237
                                self._stringify_flag = True
 
238
                                return v
 
239
                t = self.get_type()
 
240
                v = self.get_value()
 
241
                #########################
 
242
                # Enum Type
 
243
                #########################
 
244
                if self.is_enum(): return v
 
245
                #########################
 
246
                # Numeric Types
 
247
                #########################
 
248
                elif t in ('raw', 'complex', 'real', 'int', 'complex_vector', 'real_vector', 'int_vector', 'hex', 'bool'):
 
249
                        #raise exception if python cannot evaluate this value
 
250
                        try: e = self.get_parent().get_parent().evaluate(v)
 
251
                        except Exception, e: raise Exception, 'Value "%s" cannot be evaluated: %s'%(v, e)
 
252
                        #raise an exception if the data is invalid
 
253
                        if t == 'raw': return e
 
254
                        elif t == 'complex':
 
255
                                try: assert isinstance(e, COMPLEX_TYPES)
 
256
                                except AssertionError: raise Exception, 'Expression "%s" is invalid for type complex.'%str(e)
 
257
                                return e
 
258
                        elif t == 'real':
 
259
                                try: assert isinstance(e, REAL_TYPES)
 
260
                                except AssertionError: raise Exception, 'Expression "%s" is invalid for type real.'%str(e)
 
261
                                return e
 
262
                        elif t == 'int':
 
263
                                try: assert isinstance(e, INT_TYPES)
 
264
                                except AssertionError: raise Exception, 'Expression "%s" is invalid for type integer.'%str(e)
 
265
                                return e
 
266
                        #########################
 
267
                        # Numeric Vector Types
 
268
                        #########################
 
269
                        elif t == 'complex_vector':
 
270
                                if not isinstance(e, VECTOR_TYPES):
 
271
                                        self._lisitify_flag = True
 
272
                                        e = [e]
 
273
                                try:
 
274
                                        for ei in e: assert isinstance(ei, COMPLEX_TYPES)
 
275
                                except AssertionError: raise Exception, 'Expression "%s" is invalid for type complex vector.'%str(e)
 
276
                                return e
 
277
                        elif t == 'real_vector':
 
278
                                if not isinstance(e, VECTOR_TYPES):
 
279
                                        self._lisitify_flag = True
 
280
                                        e = [e]
 
281
                                try:
 
282
                                        for ei in e: assert isinstance(ei, REAL_TYPES)
 
283
                                except AssertionError: raise Exception, 'Expression "%s" is invalid for type real vector.'%str(e)
 
284
                                return e
 
285
                        elif t == 'int_vector':
 
286
                                if not isinstance(e, VECTOR_TYPES):
 
287
                                        self._lisitify_flag = True
 
288
                                        e = [e]
 
289
                                try:
 
290
                                        for ei in e: assert isinstance(ei, INT_TYPES)
 
291
                                except AssertionError: raise Exception, 'Expression "%s" is invalid for type integer vector.'%str(e)
 
292
                                return e
 
293
                        elif t == 'hex': return hex(e)
 
294
                        elif t == 'bool':
 
295
                                try: assert isinstance(e, bool)
 
296
                                except AssertionError: raise Exception, 'Expression "%s" is invalid for type bool.'%str(e)
 
297
                                return e
 
298
                        else: raise TypeError, 'Type "%s" not handled'%t
 
299
                #########################
 
300
                # String Types
 
301
                #########################
 
302
                elif t in ('string', 'file_open', 'file_save'):
 
303
                        #do not check if file/directory exists, that is a runtime issue
 
304
                        e = eval_string(v)
 
305
                        return str(e)
 
306
                #########################
 
307
                # Unique ID Type
 
308
                #########################
 
309
                elif t == 'id':
 
310
                        #can python use this as a variable?
 
311
                        try: assert _check_id_matcher.match(v)
 
312
                        except AssertionError: raise Exception, 'ID "%s" must begin with a letter and may contain letters, numbers, and underscores.'%v
 
313
                        params = self.get_all_params('id')
 
314
                        keys = [param.get_value() for param in params]
 
315
                        try: assert keys.count(v) <= 1 #id should only appear once, or zero times if block is disabled
 
316
                        except: raise Exception, 'ID "%s" is not unique.'%v
 
317
                        try: assert v not in ID_BLACKLIST
 
318
                        except: raise Exception, 'ID "%s" is blacklisted.'%v
 
319
                        return v
 
320
                #########################
 
321
                # Grid Position Type
 
322
                #########################
 
323
                elif t == 'grid_pos':
 
324
                        if not v: return '' #allow for empty grid pos
 
325
                        e = self.get_parent().get_parent().evaluate(v)
 
326
                        try:
 
327
                                assert isinstance(e, (list, tuple)) and len(e) == 4
 
328
                                for ei in e: assert isinstance(ei, int)
 
329
                        except AssertionError: raise Exception, 'A grid position must be a list of 4 integers.'
 
330
                        row, col, row_span, col_span = e
 
331
                        #check row, col
 
332
                        try: assert row >= 0 and col >= 0
 
333
                        except AssertionError: raise Exception, 'Row and column must be non-negative.'
 
334
                        #check row span, col span
 
335
                        try: assert row_span > 0 and col_span > 0
 
336
                        except AssertionError: raise Exception, 'Row and column span must be greater than zero.'
 
337
                        #get hostage cell parent
 
338
                        try: my_parent = self.get_parent().get_param('notebook').evaluate()
 
339
                        except: my_parent = ''
 
340
                        #calculate hostage cells
 
341
                        for r in range(row_span):
 
342
                                for c in range(col_span):
 
343
                                        self._hostage_cells.append((my_parent, (row+r, col+c)))
 
344
                        #avoid collisions
 
345
                        params = filter(lambda p: p is not self, self.get_all_params('grid_pos'))
 
346
                        for param in params:
 
347
                                for parent, cell in param._hostage_cells:
 
348
                                        if (parent, cell) in self._hostage_cells:
 
349
                                                raise Exception, 'Another graphical element is using parent "%s", cell "%s".'%(str(parent), str(cell))
 
350
                        return e
 
351
                #########################
 
352
                # Notebook Page Type
 
353
                #########################
 
354
                elif t == 'notebook':
 
355
                        if not v: return '' #allow for empty notebook
 
356
                        #get a list of all notebooks
 
357
                        notebook_blocks = filter(lambda b: b.get_key() == 'notebook', self.get_parent().get_parent().get_enabled_blocks())
 
358
                        #check for notebook param syntax
 
359
                        try: notebook_id, page_index = map(str.strip, v.split(','))
 
360
                        except: raise Exception, 'Bad notebook page format.'
 
361
                        #check that the notebook id is valid
 
362
                        try: notebook_block = filter(lambda b: b.get_id() == notebook_id, notebook_blocks)[0]
 
363
                        except: raise Exception, 'Notebook id "%s" is not an existing notebook id.'%notebook_id
 
364
                        #check that page index exists
 
365
                        try: assert int(page_index) in range(len(notebook_block.get_param('labels').get_evaluated()))
 
366
                        except: raise Exception, 'Page index "%s" is not a valid index number.'%page_index
 
367
                        return notebook_id, page_index
 
368
                #########################
 
369
                # Import Type
 
370
                #########################
 
371
                elif t == 'import':
 
372
                        n = dict() #new namespace
 
373
                        try: exec v in n
 
374
                        except ImportError: raise Exception, 'Import "%s" failed.'%v
 
375
                        except Exception: raise Exception, 'Bad import syntax: "%s".'%v
 
376
                        return filter(lambda k: str(k) != '__builtins__', n.keys())
 
377
                #########################
 
378
                else: raise TypeError, 'Type "%s" not handled'%t
 
379
 
 
380
        def to_code(self):
 
381
                """
 
382
                Convert the value to code.
 
383
                @return a string representing the code
 
384
                """
 
385
                #run init tasks in evaluate
 
386
                #such as setting flags
 
387
                if not self._init: self.evaluate()
 
388
                v = self.get_value()
 
389
                t = self.get_type()
 
390
                if t in ('string', 'file_open', 'file_save'): #string types
 
391
                        if self._stringify_flag: return '"%s"'%v.replace('"', '\"')
 
392
                        else: return v
 
393
                elif t in ('complex_vector', 'real_vector', 'int_vector'): #vector types
 
394
                        if self._lisitify_flag: return '(%s, )'%v
 
395
                        else: return '(%s)'%v
 
396
                else: return v
 
397
 
 
398
        def get_all_params(self, type):
 
399
                """
 
400
                Get all the params from the flowgraph that have the given type.
 
401
                @param type the specified type
 
402
                @return a list of params
 
403
                """
 
404
                return sum([filter(lambda p: p.get_type() == type, block.get_params()) for block in self.get_parent().get_parent().get_enabled_blocks()], [])