Exemple #1
0
    def test_remove(self):
        objects = OrderedSet([1, 2, 3])
        self.assertEqual(3, len(objects))

        objects.remove(2)
        self.assertEqual(2, len(objects))
        self.assertEqual(1, objects[0])
        self.assertEqual(3, objects[1])

        objects.remove(3)
        self.assertEqual(1, len(objects))
        self.assertEqual(1, objects[0])

        objects.add(1)
        self.assertEqual(1, len(objects))
        self.assertEqual(1, objects[0])

        objects.remove(1)
        self.assertEqual(0, len(objects))
Exemple #2
0
class ModuleDescriptor(object):
    def __init__(self, module_code):
        super(ModuleDescriptor, self).__init__()
        self.__module_code = module_code
        self.__mtime = None
        self.modified()

        self.__dependencies = OrderedSet()
        self.__reverse_dependencies = OrderedSet()

    def __str__(self):
        return "<ModuleDescriptor '%s' (%s)>" % (self.name, self.filename)

    def __eq__(self, other):
        return self is other or (isinstance(other, type(self)) and self.module_code == other.module_code)

    def __hash__(self):
        return hash(self.module_code)

    def describe(self, indent=1, width=80, depth=None):
        """
        Return the formatted representation of ``ModuleDescriptor``
        as a string. *indent*, *width* and *depth* will be passed to
        the ``PrettyPrinter`` constructor as formatting parameters.
        """

        def _format_monitor_list(modules):
            import re
            from pprint import pformat

            s = pformat(list(m.name for m in modules), indent=indent, width=width, depth=depth)
            # bug?
            return re.sub(r"\[( +)", "[\n\\1 ", s)

        messages = []
        messages.append("%s: %s" % (self.name, relativepath(self.filename)))
        messages.append("  Dependencies: %s" % _format_monitor_list(self.__dependencies))
        messages.append("  Reverse: %s" % _format_monitor_list(self.__reverse_dependencies))
        return "\n".join(messages)

    @property
    def dependencies(self):
        return tuple(self.__dependencies)

    @property
    def reverse_dependencies(self):
        return tuple(self.__reverse_dependencies)

    @property
    def module_code(self):
        return self.__module_code

    @property
    def name(self):
        return self.module_code.name

    @property
    def package_name(self):
        return self.module_code.package_name

    @property
    def filename(self):
        return self.module_code.filename

    @property
    def context(self):
        return self.module_code.context

    def reload(self, descriptors, co=None):
        """
        Reload module code, update dependency graph
        """
        LOGGER.info("Reload module descriptor '%s' at %s" % (self.name, relativepath(self.filename)))

        try:
            self.module_code.reload(co)
        except SyntaxError:
            # SyntaxError is OK
            LOGGER.warn("SyntaxError found in %s" % self.filename, exc_info=True)
        else:
            self.update_dependencies(descriptors)

    def modified(self):
        """Update modification time and return ``True`` if modified"""
        mtime = self.__mtime
        try:
            mtime = os.path.getmtime(self.filename)
            return self.__mtime is None or mtime > self.__mtime
        finally:
            self.__mtime = mtime

    def add_dependency(self, descriptor):
        self.__dependencies.append(descriptor)
        descriptor.add_reverse_dependency(self)

    def add_reverse_dependency(self, descriptor):
        self.__reverse_dependencies.append(descriptor)

    def remove_reverse_dependencies(self, descriptor):
        self.__reverse_dependencies.remove(descriptor)

    def update_dependencies(self, descriptors):
        LOGGER.debug("Update dependencies of '%s'" % self.name)
        _update_module_dependencies(self, descriptors)

    def clear_dependencies(self):
        for d in self.__dependencies:
            d.remove_reverse_dependencies(self)
        self.__dependencies.clear()

    def walk_dependency_graph(self, reverse=False):
        """
        Walking on the module dependency graph.
        *reverse* is a boolean value. If set to ``True``,
        then the walking is in an imported module (self included)
        to a module imports order.
        """
        if reverse:
            graph_name = "reverse_dependencies"
        else:
            graph_name = "dependencies"

        # self first
        yield self

        # Use Breadth First Search (BFS) algorithm
        vqueue = [self]
        discovered = set(vqueue)
        while vqueue:
            u = vqueue.pop()
            for v in getattr(u, graph_name):
                if v not in discovered:
                    discovered.add(v)
                    vqueue.append(v)
                    yield v