def randType(noneOkay=True, listOkay=True, nStructs=0): choices = [ T.LRNone, T.LRBool, T.LRInt, T.LRWord, T.LRStr, T.LRTime, lambda: T.LRValue(randUnits()), lambda: T.LRComplex(randUnits()), lambda: T.LRCluster(*[ randType(noneOkay=False, nStructs=nStructs + 1) for _ in range(randint(1, 5)) ]), lambda: T.LRList(randType( noneOkay=False, listOkay=False, nStructs=nStructs + 1), depth=randint(1, 3)), ] if not noneOkay: choices = choices[1:] if nStructs >= 3: choices = choices[:-2] elif not listOkay: choices = choices[:-1] return choice(choices)()
def testTags(self): """Test the parsing of type tags into LRType objects.""" tests = { '_': T.LRNone(), 'b': T.LRBool(), 'i': T.LRInt(), 'w': T.LRWord(), 's': T.LRStr(), 't': T.LRTime(), 'y': T.LRBytes(), # clusters 'ii': T.LRCluster(T.LRInt(), T.LRInt()), 'b(t)': T.LRCluster(T.LRBool(), T.LRCluster(T.LRTime())), '(ss)': T.LRCluster(T.LRStr(), T.LRStr()), '(s)': T.LRCluster(T.LRStr()), '((siw))': T.LRCluster(T.LRCluster(T.LRStr(), T.LRInt(), T.LRWord())), # lists '*b': T.LRList(T.LRBool()), '*_': T.LRList(), '*2b': T.LRList(T.LRBool(), depth=2), '*2_': T.LRList(depth=2), '*2v[Hz]': T.LRList(T.LRValue('Hz'), depth=2), '*3v': T.LRList(T.LRValue(), depth=3), '*v[]': T.LRList(T.LRValue(''), depth=1), # unit types 'v': T.LRValue(), 'v[]': T.LRValue(''), 'v[m/s]': T.LRValue('m/s'), 'c': T.LRComplex(), 'c[]': T.LRComplex(''), 'c[m/s]': T.LRComplex('m/s'), # errors 'E': T.LRError(), 'Ew': T.LRError(T.LRWord()), 'E(w)': T.LRError(T.LRCluster(T.LRWord())), # more complex stuff '*b*i': T.LRCluster(T.LRList(T.LRBool()), T.LRList(T.LRInt())), } for tag, type_ in tests.items(): self.assertEqual(T.parseTypeTag(tag), type_) newtag = str(type_) if isinstance(type_, T.LRCluster) and tag[0] + tag[-1] != '()': # just added parentheses in this case self.assertEqual(newtag, '(%s)' % tag) else: self.assertEqual(newtag, tag)
def decorated(f): args, varargs, varkw, defaults = getargspec(f) args = args[lr_num_params:] # handle generators as inlineCallbacks if _isGenerator(f): f = inlineCallbacks(f) # make sure that defined params are actually accepted by the function. # having extra params would not affect the running, but it is # unnecessary and hence may indicate other problems with the code for p in params: if p not in args: raise Exception("'%s' is not a valid parameter." % p) # turn single string annotations into lists if isinstance(params[p], str): params[p] = [params[p]] Nparams = len(args) Noptional = 0 if defaults is None else len(defaults) Nrequired = Nparams - Noptional if Nparams == 0: accepts_s = [''] # only accept notifier accepts_t = [T.parseTypeTag(s) for s in accepts_s] @wraps(f) def handleRequest(self, c, data): return f(self, c) elif Nparams == 1: accepts_s = params.get(args[0], []) accepts_t = [T.parseTypeTag(s) for s in accepts_s] if Nrequired == 0: # if accepted types were specified, add '' to the list # we don't add '' if the list of accepted types is empty, # since this would make '' the ONLY accepted type if len(accepts_t) and T.LRNone() not in accepts_t: accepts_s.append(': defaults [%s=%r]' \ % (args[0], defaults[0])) accepts_t.append(T.LRNone()) @wraps(f) def handleRequest(self, c, data): if data is None: return f(self, c) return f(self, c, data) else: # nothing special to do here handleRequest = f else: # sanity checks to make sure that we'll be able to # correctly dispatch to the function when called if Nrequired <= 1: if args[0] not in params: raise Exception('Must specify types for first argument ' 'when fewer than two args are required.') for s in params[args[0]]: t = T.parseTypeTag(s) if isinstance(t, (T.LRAny, T.LRCluster)): raise Exception('Cannot accept cluster or ? in first ' 'arg when fewer than two args are ' 'required.') # '' is not allowed on first arg when Nrequired > 1 types = [T.parseTypeTag(s) for s in params.get(args[0], [])] if Nrequired > 1 and T.LRNone() in types: raise Exception("'' not allowed when more than " "one arg is required.") # '' is never allowed on args after the first. for p in args[1:]: types = [T.parseTypeTag(s) for s in params.get(p, [])] if T.LRNone() in types: raise Exception("'' not allowed after first arg.") # allowed types are as follows: # one type for each parameter, with the number of # parameters ranging from the total number down to # and including the required number # we don't include any zero-length group groups = [] for n in range(Nparams, Nrequired - 1, -1): lists = [params.get(a, ['?']) for a in args[:n]] if len(lists): groups += _product(lists) for i, group in reversed(list(enumerate(groups))): # if there are any LRNones in the group, we remove it ts = [T.parseTypeTag(t) for t in group] if T.LRNone() in ts: groups.pop(i) accepts_t = [] accepts_s = [] for group in groups: if len(group) > 1: t = T.LRCluster(*[T.parseTypeTag(t) for t in group]) s = ', '.join('%s{%s}' % (sub_t, arg) for sub_t, arg in zip(t, args)) s = '(%s)' % s else: t = T.parseTypeTag(group[0]) if isinstance(t, T.LRCluster): raise Exception("Can't accept cluster in first param.") s = '%s{%s}' % (group[0], args[0]) # add information about default values of unused params if len(group) < Nparams: defstr = ', '.join('%s=%r' % (args[n], defaults[n - Nrequired]) for n in range(len(group), Nparams)) s = s + ': defaults [%s]' % defstr accepts_t.append(t) accepts_s.append(s) if Nrequired == 0: if T.LRNone() not in accepts_t: defstr = ', '.join('%s=%r' % (a, d) for a, d in zip(args, defaults)) accepts_s.append(': defaults [%s]' % defstr) accepts_t.append(T.LRNone()) @wraps(f) def handleRequest(self, c, data): if isinstance(data, tuple): return f(self, c, *data) elif data is None: return f(self, c) else: return f(self, c, data) else: @wraps(f) def handleRequest(self, c, data): if isinstance(data, tuple): return f(self, c, *data) else: return f(self, c, data) f.ID = lr_ID f.name = lr_name or f.__name__ f.accepts = accepts_s f.returns = [returns] if isinstance(returns, str) else returns f.isSetting = True f.handleRequest = handleRequest # this is the data that will be sent to the manager to # register this setting to be remotely callable f.description, f.notes = util.parseSettingDoc(f.__doc__) def getRegistrationInfo(): return (long(f.ID), f.name, f.description, f.accepts, f.returns, f.notes) f.getRegistrationInfo = getRegistrationInfo return f