Esempio n. 1
0
 def class_info(self, class_list):
     self._raw_class_info = class_list
     # Dealing with `class_info`, which can be of different types
     self._class_info = ClassSetDict()
     for klass in class_list[:-1]:
         self._class_info[AllSubSetsOf(klass)] = klass
     # We use the last class of the list as a fallback
     self._class_info[AllSubSetsOf(object)] = class_list[-1]
Esempio n. 2
0
class Cast(object):

    def __init__(self, node_class_map, fallback_map={}):
        #TODO: fallback mightn't be needed, if checking type of dumped inpt
        self.node_class_map = ClassSetDict(node_class_map)
        self.fallback_map = ClassSetDict(fallback_map)
        self._depth_counter = 0
        self.debug = False

    def __call__(self, inpt, dumper=NodeInfo(), loader=NodeInfo()):
        self._depth_counter += 1

        # First, looking for a proper dumper for `inpt`.
        dschema = None
        if hasattr(inpt, '__dump__'):
            dumper = inpt
            inpt_iter = dumper.__dump__()
            if hasattr(inpt, '__dschema__'):
                dschema = inpt.__dschema__()
        else:
            # if neither `inpt` nor `dumper` actually have a `__dump__`
            # method, we need to find a suitable dumper from `node_class_map`.
            if not hasattr(dumper, '__dump__'):
                node_info = None
                if not isinstance(dumper, NodeInfo):
                    node_info = NodeInfo(dumper)
                else:
                    node_info = copy.copy(dumper)
                    if node_info.class_info is None:
                        node_info.class_info = [type(inpt)]
                dumper = self._resolve_node_class(inpt, node_info, '__dump__')

            inpt_iter = dumper.__dump__(inpt)
            if hasattr(dumper, '__dschema__'):
                dschema = dumper.__dschema__(inpt)

        if dschema is None:
            dschema = self.default_dschema()
        dschema = AttrDict(dschema)

        # if `loader` doesn't actually have a `__load__` method,
        # we need to find a suitable loader from `node_class_map`,
        # or `fallback_map`.
        if not hasattr(loader, '__load__'):
            node_info = None
            if not isinstance(loader, NodeInfo):
                node_info = NodeInfo(loader)
            else:
                node_info = copy.copy(loader)

            # If the NodeInfo doesn't provide any useful `class_info` about
            # the node class, we directly try to find a good fallback.
            if node_info.class_info is None:
                loader = self._get_fallback(inpt, dumper)
            else:
                loader = self._resolve_node_class(inpt, node_info, '__load__')

        if hasattr(loader, '__lschema__'):
            lschema = loader.__lschema__()
        else:
            lschema = self.default_lschema()
        lschema = AttrDict(lschema)

        # Generator iterating on the dumped data, and which will be passed
        # to the loader. Calls the casting recursively if the schema has any nesting.
        generator = _Generator(self, inpt_iter, dschema, lschema)

        # Finally, we load the casted object.
        self.log('%s <= %s' % (dumper, inpt))
        casted = loader.__load__(generator)
        self.log('%s => %s' % (loader, casted))
        self._depth_counter -= 1
        return casted

    def default_dschema(self):
        return {AttrDict.KeyAny: NodeInfo()}

    def default_lschema(self):
        return {AttrDict.KeyAny: NodeInfo()}

    def log(self, msg):
        if self.debug: print '\t' * self._depth_counter, msg

    def _get_fallback(self, inpt, dumper):
        """
        Gets a fallback node class for the output, as a last resort.
        """
        # we try to get a node class from the `fallback_map`
        node_class = self.fallback_map.subsetget(type(inpt))
        if not node_class is None:
            return node_class
        elif hasattr(dumper, '__load__'):
            return dumper
        else:
            raise NoNodeClassError('Couldn\'t find a fallback for %s' % inpt)

    def _resolve_node_class(self, inpt, node_info, method):
        """
        Resolves the node class from a node info.
        """
        # TODO: duck typing (get_subclass could be a function).
        klass = node_info.get_class(type(inpt))
        if hasattr(klass, method):
            return klass
        if not issubclass(klass, Node):
            node_class = self.node_class_map.subsetget(klass)
            if node_class is None:
                raise NoNodeClassError(klass)
            return node_class.get_subclass(klass=klass, **node_info.kwargs)
        # If the value picked is a node class, we use that.
        else:
            return klass.get_subclass(**node_info.kwargs)
Esempio n. 3
0
 def __init__(self, node_class_map, fallback_map={}):
     #TODO: fallback mightn't be needed, if checking type of dumped inpt
     self.node_class_map = ClassSetDict(node_class_map)
     self.fallback_map = ClassSetDict(fallback_map)
     self._depth_counter = 0
     self.debug = False