Beispiel #1
0
    def serialize(self,
                  f,
                  full=False,
                  indent=None,
                  level=0):
        """Serialize the Element and it's sub-Elements."""

        if indent is None:
            f.write("""\
from __future__ import with_statement
import Tuke

""")
            indent = []
            self.serialize(f,full,indent=[],level=0)
        else:
            def out(s):
                for i in indent:
                    f.write(i)
                f.write(s)

            from Tuke.repr_helper import shortest_class_name
            cname = shortest_class_name(self.__class__)
            s = '%s = %s(' % (self.__shadowless__.id,cname)
            out(s)
            indent.append(' ' * len(s))

            kw = self._repr_kwargs()
            kw['id'] = self.__shadowless__.id
            kw['transform'] = self.__shadowless__.transform

            first = True
            for n,v in sorted(kw.iteritems()):
                if not first:
                    f.write(',\n')
                    out('%s=%s' % (n,repr(v)))
                else:
                    first = False
                    f.write('%s=%s' % (n,repr(v)))

            f.write('); ')
            if level > 0:
                f.write('__%d.add(%s)\n' % (level,self.__shadowless__.id))
            else:
                f.write('__%d = %s\n' % (level,self.__shadowless__.id))
            indent.pop()

            if not isinstance(self,ReprableByArgsElement) or full:
                subs = []
                for e in self: 
                    if isinstance(e,Element):
                        subs.append(e)
                subs.sort(key=lambda e: e.id)

                if subs:
                    out('with %s as __%d:\n' % (self.__shadowless__.id,level + 1))
                    for e in subs:
                        unwrap(e).serialize(f,full,
                                            indent=indent + ['    ',],
                                            level=level + 1)
Beispiel #2
0
    def _compute_implicit_callbacks(self):
        """Recompute the implicit callbacks chain.

        Starts fresh. The design here is to simply start fresh after each
        topology change. Given that most connects are going to be one or two
        levels deep, this is simpler, and probably more efficient, than a more
        complex "find what level changed" algorithm.

        """
        class Invalidator:
            def __init__(self,ref):
                self.ref = weakref.ref(ref)
                self.valid = True
            def __call__(self):
                if self.valid:
                    # One shot
                    self.valid = False

                    # Should only work if the original _elemref is alive.
                    ref = self.ref()
                    if ref is not None:
                        ref._compute_implicit_callbacks()

        # Old invalidator is deleted, garbage collection will take care of the
        # rest.
        self._invalidator_callable = Invalidator(self)

        # Walk from our parent element, to the destination, setting callbacks
        # along the way. While we're at it, the reverse path is being
        # calculated in p, for insertion into the target's implicitly connected
        # dict.
        e = unwrap(self.connects._parent)
        p = Tuke.Id('.')
        for i in tuple(tuple.__iter__(self.ref)) + (None,):
            if i is not None:
                e.topology_notify(Tuke.Id(i),self._invalidator_callable)

                if i == '..':
                    p = e.__shadowless__.id + p
                else:
                    p = Tuke.Id('..') + p
            try:
                e = unwrap(e[Tuke.Id(i)])
            except KeyError:
                # Didn't reach the last Element referenced in the path;
                # implicit connection doesn't exist because explicit connection
                # is dangling.
                break
            except TypeError:
                # Did reach the last Element referenced in the path. The
                # calculated reverse path is inserted as the key in
                # _implicitly_connected, the invalidator_callable is used as a
                # magic cookie. This is a WeakValueDict, so when the cookie
                # goes away, the entry does too.
                #
                # Note that gc-lag could turn this simple construct into a
                # problem when Element.remove is implemented.
                e.connects._implicitly_connected[p] = self._invalidator_callable
                break
Beispiel #3
0
    def test_unwrap(self):
        """unwrap()"""
        def T(got,expected = True):
            self.assert_(expected == got,'got: %s  expected: %s' % (got,expected))

        a = Element(id=Id('a'))
        u = unwrap(a)
        T(u.id,Id('.'))
        u = unwrap(u)
        T(u.id,Id('.'))
Beispiel #4
0
    def testElement_notify(self):
        """Element.notify()"""
        def T(got,expected = True):
            self.assert_(expected == got,'got: %s  expected: %s' % (got,expected))

        a = Element(id=Id('a'))

        class cb:
            def __init__(self):
                self.count = 0
            def __call__(self):
                self.count += 1

        self.assertRaises(ValueError,
                          lambda:a.topology_notify(Id('a'),lambda:None))
        self.assertRaises(ValueError,
                          lambda:a.topology_notify(Id('z/y'),lambda:None))
        self.assertRaises(TypeError,
                          lambda:a.topology_notify(Id('.'),None))

        # Test callback adding and deletion
        cb1 = cb()
        a.topology_notify(Id('a/b'),cb1)
        T(unwrap(a).__dict_callbacks__['b'],set((weakref.ref(cb1),)))
        cb2 = cb()
        a.topology_notify(Id('a/b'),cb2)
        T(unwrap(a).__dict_callbacks__['b'],
                set((weakref.ref(cb1),
                     weakref.ref(cb2))))

        del cb1
        T(unwrap(a).__dict_callbacks__['b'],set((weakref.ref(cb2),)))
        del cb2
        T(not unwrap(a).__dict_callbacks__.has_key('b')
          or unwrap(a).__dict_callbacks__['b'] == set())

        # Test that callbacks are actually called

        # Called for adding an object
        cb1 = cb()
        a.topology_notify(Id('a/b'),cb1)
        cb2 = cb()
        a.topology_notify(Id('a/b'),cb2)

        b = Element(id=Id('b'))
        cbp = cb()
        b.topology_notify(Id('.'),cbp)

        a.add(b)

        T(cb1.count,1)
        T(cb2.count,1)
        T(cbp.count,1)
        T(not unwrap(a).__dict_callbacks__.has_key('b'))
        T(not unwrap(b).__dict_callbacks__.has_key('parent'))

        # Test for removing an object, just a check that there is no .remove
        # for now.
        T(not hasattr(a,'remove'))
Beispiel #5
0
    def _common_parent(self, b):
        a = unwrap(self)
        b = unwrap(b)

        ap = set()
        bp = set()

        while ((not ap.intersection(bp))) and \
               (a is not None or b is not None):
            if a is not None:
                ap.add(a)
                a = unwrap(a.parent)
            if b is not None:
                bp.add(b)
                b = unwrap(b.parent)
        p = ap.intersection(bp)
        if p:
            assert (len(p) == 1)
            return p.pop()
        else:
            return None
Beispiel #6
0
    def _common_parent(self,b):
        a = unwrap(self)
        b = unwrap(b)

        ap = set()
        bp = set()

        while ((not ap.intersection(bp))) and \
               (a is not None or b is not None):
            if a is not None:
                ap.add(a)
                a = unwrap(a.parent)
            if b is not None:
                bp.add(b)
                b = unwrap(b.parent)
        p = ap.intersection(bp)
        if p:
            assert(len(p) == 1)
            return p.pop()
        else:
            return None
Beispiel #7
0
    def serialize(self, f, full=False, indent=None, level=0):
        """Serialize the Element and it's sub-Elements."""

        if indent is None:
            f.write("""\
from __future__ import with_statement
import Tuke

""")
            indent = []
            self.serialize(f, full, indent=[], level=0)
        else:

            def out(s):
                for i in indent:
                    f.write(i)
                f.write(s)

            from Tuke.repr_helper import shortest_class_name
            cname = shortest_class_name(self.__class__)
            s = '%s = %s(' % (self.__shadowless__.id, cname)
            out(s)
            indent.append(' ' * len(s))

            kw = self._repr_kwargs()
            kw['id'] = self.__shadowless__.id
            kw['transform'] = self.__shadowless__.transform

            first = True
            for n, v in sorted(kw.iteritems()):
                if not first:
                    f.write(',\n')
                    out('%s=%s' % (n, repr(v)))
                else:
                    first = False
                    f.write('%s=%s' % (n, repr(v)))

            f.write('); ')
            if level > 0:
                f.write('__%d.add(%s)\n' % (level, self.__shadowless__.id))
            else:
                f.write('__%d = %s\n' % (level, self.__shadowless__.id))
            indent.pop()

            if not isinstance(self, ReprableByArgsElement) or full:
                subs = []
                for e in self:
                    if isinstance(e, Element):
                        subs.append(e)
                subs.sort(key=lambda e: e.id)

                if subs:
                    out('with %s as __%d:\n' %
                        (self.__shadowless__.id, level + 1))
                    for e in subs:
                        unwrap(e).serialize(f,
                                            full,
                                            indent=indent + [
                                                '    ',
                                            ],
                                            level=level + 1)
Beispiel #8
0
    def _compute_implicit_callbacks(self):
        """Recompute the implicit callbacks chain.

        Starts fresh. The design here is to simply start fresh after each
        topology change. Given that most connects are going to be one or two
        levels deep, this is simpler, and probably more efficient, than a more
        complex "find what level changed" algorithm.

        """
        class Invalidator:
            def __init__(self, ref):
                self.ref = weakref.ref(ref)
                self.valid = True

            def __call__(self):
                if self.valid:
                    # One shot
                    self.valid = False

                    # Should only work if the original _elemref is alive.
                    ref = self.ref()
                    if ref is not None:
                        ref._compute_implicit_callbacks()

        # Old invalidator is deleted, garbage collection will take care of the
        # rest.
        self._invalidator_callable = Invalidator(self)

        # Walk from our parent element, to the destination, setting callbacks
        # along the way. While we're at it, the reverse path is being
        # calculated in p, for insertion into the target's implicitly connected
        # dict.
        e = unwrap(self.connects._parent)
        p = Tuke.Id('.')
        for i in tuple(tuple.__iter__(self.ref)) + (None, ):
            if i is not None:
                e.topology_notify(Tuke.Id(i), self._invalidator_callable)

                if i == '..':
                    p = e.__shadowless__.id + p
                else:
                    p = Tuke.Id('..') + p
            try:
                e = unwrap(e[Tuke.Id(i)])
            except KeyError:
                # Didn't reach the last Element referenced in the path;
                # implicit connection doesn't exist because explicit connection
                # is dangling.
                break
            except TypeError:
                # Did reach the last Element referenced in the path. The
                # calculated reverse path is inserted as the key in
                # _implicitly_connected, the invalidator_callable is used as a
                # magic cookie. This is a WeakValueDict, so when the cookie
                # goes away, the entry does too.
                #
                # Note that gc-lag could turn this simple construct into a
                # problem when Element.remove is implemented.
                e.connects._implicitly_connected[
                    p] = self._invalidator_callable
                break