1import itertools
2import common
3
4
5def _get_unpassable_types(arg):
6    """ Given an argument, returns a set of types contained in arg that are
7    unpassable. If arg is an atomic type (e.g. int) it either returns an
8    empty set (if the type is passable) or a singleton of the type (if the
9    type is not passable). """
10    if isinstance(arg, (basestring, int, long)):
11        return set()
12    elif isinstance(arg, (list, tuple, set, frozenset, dict)):
13        if isinstance(arg, dict):
14            # keys and values must both be passable
15            parts = itertools.chain(arg.iterkeys(), arg.itervalues())
16        else:
17            # for all other containers we just iterate
18            parts = iter(arg)
19        types = set()
20        for part in parts:
21            types |= _get_unpassable_types(part)
22        return types
23    else:
24        return set([type(arg)])
25
26
27def _validate_args(args):
28    """ Validates arguments. Lists and dictionaries are valid argument types,
29    so you can pass *args and **dargs in directly, rather than having to
30    iterate over them yourself. """
31    unpassable_types = _get_unpassable_types(args)
32    if unpassable_types:
33        msg = "arguments of type '%s' cannot be passed to remote profilers"
34        msg %= ", ".join(t.__name__ for t in unpassable_types)
35        raise TypeError(msg)
36
37
38class profiler_proxy(object):
39    """ This is a server-side class that acts as a proxy to a real client-side
40    profiler class."""
41
42    def __init__(self, profiler_name):
43        self.name = profiler_name
44
45        # does the profiler support rebooting?
46        profiler_module = common.setup_modules.import_module(
47            profiler_name, "autotest_lib.client.profilers.%s" % profiler_name)
48        profiler_class = getattr(profiler_module, profiler_name)
49        self.supports_reboot = profiler_class.supports_reboot
50
51
52    def initialize(self, *args, **dargs):
53        _validate_args(args)
54        _validate_args(dargs)
55        self.args, self.dargs = args, dargs
56
57
58    def setup(self, *args, **dargs):
59        assert self.args == args and self.dargs == dargs
60        # the actual setup happens lazily at start()
61
62
63    def start(self, test, host=None):
64        raise NotImplementedError('start not implemented')
65
66
67    def stop(self, test, host=None):
68        raise NotImplementedError('stop not implemented')
69
70
71    def report(self, test, host=None, wait_on_client=True):
72        raise NotImplementedError('report not implemented')
73