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