summaryrefslogtreecommitdiff
path: root/grc/src/grc/elements/Param.py
blob: a8aa43004b3bfb3c20e48799a1d74d9731a6d019 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
"""
Copyright 2008 Free Software Foundation, Inc.
This file is part of GNU Radio

GNU Radio Companion is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

GNU Radio Companion is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
"""
##@package grc.elements.Param
#Flow graph block parameters.
#And options for enum type paramater.

from grc import Utils
from grc.Utils import odict
from grc.elements.Element import Element

class Option(Element):

	def __init__(self, param, name, key, opts):
		Element.__init__(self, param)
		self._name = name
		self._key = key
		self._opts = dict()
		for opt in opts:
			#separate the key:value
			try: key, value = opt.split(':')
			except: self._exit_with_error('Error separating "%s" into key:value'%opt)
			#test against repeated keys
			try: assert(not self._opts.has_key(key))
			except AssertionError: self._exit_with_error('Key "%s" already exists in option'%key)
			#store the option
			self._opts[key] = value

	def __str__(self): return 'Option %s(%s)'%(self.get_name(), self.get_key())

	def get_name(self): return self._name

	def get_key(self): return self._key

	##############################################
	# Access Opts
	##############################################
	def get_opt_keys(self): return self._opts.keys()
	def get_opt(self, key): return self._opts[key]
	def get_opts(self): return self._opts.values()

	##############################################
	## Static Make Methods
	##############################################
	def make_option_from_n(param, n):
		"""
		Make a new option from nested data.
		@param param the parent element
		@param n the nested odict
		@return a new option
		"""
		#grab the data
		name = n['name']
		key = n['key']
		opts = Utils.listify(n, 'opt')
		#build the option
		return Option(
			param=param,
			name=name,
			key=key,
			opts=opts,
		)
	make_option_from_n = staticmethod(make_option_from_n)

class Param(Element):

	##possible param types
	TYPES = ['enum', 'raw']

	def __init__(self, block, n):
		"""
		Make a new param from nested data.
		@param block the parent element
		@param n the nested odict
		@return a new param
		"""
		#grab the data
		name = n['name']
		key = n['key']
		value = Utils.exists_or_else(n, 'value', '')
		type = n['type']
		hide = Utils.exists_or_else(n, 'hide', '')
		options = Utils.listify(n, 'option')
		#build the param
		Element.__init__(self, block)
		self._name = name
		self._key = key
		self._type = type
		self._hide = hide
		#create the Option objects from the n data
		self._options = odict()
		for option in map(lambda o: Option.make_option_from_n(self, o), options):
			key = option.get_key()
			#test against repeated keys
			try: assert(key not in self.get_option_keys())
			except AssertionError: self._exit_with_error('Key "%s" already exists in options'%key)
			#store the option
			self._options[key] = option
		#test the enum options
		if self._options or self.is_enum():
			#test against bad combos of type and enum
			try: assert(self._options)
			except AssertionError: self._exit_with_error('At least one option must exist when type "enum" is set.')
			try: assert(self.is_enum())
			except AssertionError: self._exit_with_error('Type "enum" must be set when options are present.')
			#test against options with identical keys
			try: assert(len(set(self.get_option_keys())) == len(self._options))
			except AssertionError: self._exit_with_error('Options keys "%s" are not unique.'%self.get_option_keys())
			#test against inconsistent keys in options
			opt_keys = self._options.values()[0].get_opt_keys()
			for option in self._options.values():
				try: assert(set(opt_keys) == set(option.get_opt_keys()))
				except AssertionError: self._exit_with_error('Opt keys "%s" are not identical across all options.'%opt_keys)
			#if a value is specified, it must be in the options keys
			self._value = value or self.get_option_keys()[0]
			try: assert(self.get_value() in self.get_option_keys())
			except AssertionError: self._exit_with_error('The value "%s" is not in the possible values of "%s".'%(self.get_value(), self.get_option_keys()))
		else: self._value = value or ''

	def test(self):
		"""
		call test on all children
		"""
		map(lambda c: c.test(), self.get_options())

	def validate(self):
		"""
		Validate the param.
		The value must be evaluated and type must a possible type.
		"""
		try:
			assert(self.get_type() in self.TYPES)
			try: self.evaluate()
			except:
				#if the evaluate failed but added no error messages, add the generic one below
				if not self.get_error_messages():
					self._add_error_message('Value "%s" cannot be evaluated.'%self.get_value())
		except AssertionError: self._add_error_message('Type "%s" is not a possible type.'%self.get_type())

	def evaluate(self):
		"""!
		Evaluate the value of this param.
		@throw NotImplementedError
		"""
		raise NotImplementedError

	def to_code(self):
		"""!
		Convert the value to code.
		@throw NotImplementedError
		"""
		raise NotImplementedError

	def __str__(self): return 'Param - %s(%s)'%(self.get_name(), self.get_key())

	def is_param(self): return True

	def get_name(self): return self._name

	def get_key(self): return self._key

	def get_hide(self): return self.get_parent().resolve_dependencies(self._hide)

	def get_value(self):
		value = self._value
		if self.is_enum() and value not in self.get_option_keys():
			value = self.get_option_keys()[0]
			self.set_value(value)
		return value

	def set_value(self, value):
		self.flag()
		self._value = str(value) #must be a string

	def get_type(self): return self.get_parent().resolve_dependencies(self._type)

	def is_enum(self): return self._type == 'enum'

	def is_type_dependent(self): return '$' in self._type

	##############################################
	# Access Options
	##############################################
	def get_option_keys(self): return self._options.keys()
	def get_option(self, key): return self._options[key]
	def get_options(self): return self._options.values()

	##############################################
	# Access Opts
	##############################################
	def get_opt_keys(self): return self._options[self.get_value()].get_opt_keys()
	def get_opt(self, key): return self._options[self.get_value()].get_opt(key)
	def get_opts(self): return self._options[self.get_value()].get_opts()

	##############################################
	## Import/Export Methods
	##############################################
	def export_data(self):
		"""
		Export this param's key/value.
		@return a nested data odict
		"""
		n = odict()
		n['key'] = self.get_key()
		n['value'] = self.get_value()
		return n