Switched the python classes to inherit from the base and gui classes.
[debian/gnuradio] / grc / python / FlowGraph.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 import expr_utils
21 from .. base.FlowGraph import FlowGraph as _FlowGraph
22 from .. gui.FlowGraph import FlowGraph as _GUIFlowGraph
23 from Block import Block
24 from Connection import Connection
25 import re
26
27 _variable_matcher = re.compile('^(variable\w*)$')
28 _parameter_matcher = re.compile('^(parameter)$')
29
30 class FlowGraph(_FlowGraph, _GUIFlowGraph):
31
32         def __init__(self, **kwargs):
33                 _FlowGraph.__init__(self, **kwargs)
34                 _GUIFlowGraph.__init__(self)
35
36         _eval_cache = dict()
37         def _eval(self, code, namespace, namespace_hash):
38                 """
39                 Evaluate the code with the given namespace.
40                 @param code a string with python code
41                 @param namespace a dict representing the namespace
42                 @param namespace_hash a unique hash for the namespace
43                 @return the resultant object
44                 """
45                 my_hash = hash(code) ^ namespace_hash
46                 #cache if does not exist
47                 if not self._eval_cache.has_key(my_hash):
48                         self._eval_cache[my_hash] = eval(code, namespace, namespace)
49                 #return from cache
50                 return self._eval_cache[my_hash]
51
52         def _get_io_signature(self, pad_key):
53                 """
54                 Get an io signature for this flow graph.
55                 The pad key determines the directionality of the io signature.
56                 @param pad_key a string of pad_source or pad_sink
57                 @return a dict with: type, nports, vlen, size
58                 """
59                 pads = filter(lambda b: b.get_key() == pad_key, self.get_enabled_blocks())
60                 if not pads: return {
61                         'nports': '0',
62                         'type': '',
63                         'vlen': '0',
64                         'size': '0',
65                 }
66                 pad = pads[0] #take only the first, user should not have more than 1
67                 #load io signature
68                 return {
69                         'nports': str(pad.get_param('nports').get_evaluated()),
70                         'type': str(pad.get_param('type').get_evaluated()),
71                         'vlen': str(pad.get_param('vlen').get_evaluated()),
72                         'size': pad.get_param('type').get_opt('size'),
73                 }
74
75         def get_input_signature(self):
76                 """
77                 Get the io signature for the input side of this flow graph.
78                 The io signature with be "0", "0" if no pad source is present.
79                 @return a string tuple of type, num_ports, port_size
80                 """
81                 return self._get_io_signature('pad_source')
82
83         def get_output_signature(self):
84                 """
85                 Get the io signature for the output side of this flow graph.
86                 The io signature with be "0", "0" if no pad sink is present.
87                 @return a string tuple of type, num_ports, port_size
88                 """
89                 return self._get_io_signature('pad_sink')
90
91         def get_imports(self):
92                 """
93                 Get a set of all import statments in this flow graph namespace.
94                 @return a set of import statements
95                 """
96                 imports = sum([block.get_imports() for block in self.get_enabled_blocks()], [])
97                 imports = sorted(set(imports))
98                 return imports
99
100         def get_variables(self):
101                 """
102                 Get a list of all variables in this flow graph namespace.
103                 Exclude paramterized variables.
104                 @return a sorted list of variable blocks in order of dependency (indep -> dep)
105                 """
106                 variables = filter(lambda b: _variable_matcher.match(b.get_key()), self.get_enabled_blocks())
107                 return expr_utils.sort_objects(variables, lambda v: v.get_id(), lambda v: v.get_var_make())
108
109         def get_parameters(self):
110                 """
111                 Get a list of all paramterized variables in this flow graph namespace.
112                 @return a list of paramterized variables
113                 """
114                 parameters = filter(lambda b: _parameter_matcher.match(b.get_key()), self.get_enabled_blocks())
115                 return parameters
116
117         def evaluate(self, expr):
118                 """
119                 Evaluate the expression.
120                 @param expr the string expression
121                 @throw Exception bad expression
122                 @return the evaluated data
123                 """
124                 if self.is_flagged():
125                         self.deflag()
126                         #reload namespace
127                         n = dict()
128                         #load imports
129                         for imp in self.get_imports():
130                                 try: exec imp in n
131                                 except: pass
132                         #load parameters
133                         np = dict()
134                         for parameter in self.get_parameters():
135                                 try:
136                                         e = eval(parameter.get_param('value').to_code(), n, n)
137                                         np[parameter.get_id()] = e
138                                 except: pass
139                         n.update(np) #merge param namespace
140                         #load variables
141                         for variable in self.get_variables():
142                                 try:
143                                         e = eval(variable.get_param('value').to_code(), n, n)
144                                         n[variable.get_id()] = e
145                                 except: pass
146                         #make namespace public
147                         self.n = n
148                         self.n_hash = hash(str(n))
149                 #evaluate
150                 e = self._eval(expr, self.n, self.n_hash)
151                 return e