Example #1
0
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)()
Example #2
0
    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)
Example #3
0
    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