Ejemplo n.º 1
0
class ObjectsCleaner(object):
    def __init__(self, attribute_name):
        self.attribute_name = attribute_name
        self.objects = WeakSet()

    def add(self, obj):
        self.objects.add(obj)

    def clear(self, instance=None):
        if instance is None:
            self._clear_all_objects()
        else:
            self._clear_obj(instance)
            try:
                self.objects.remove(instance)
            except KeyError:
                pass

    def _clear_all_objects(self):
        for obj in self.objects:
            self._clear_obj(obj)
        self.objects.clear()

    def _clear_obj(self, obj):
        try:
            delattr(obj, self.attribute_name)
        except AttributeError:
            pass
Ejemplo n.º 2
0
class BaseSubject(object):
    """ Object holding all the observers, aliased to dirigent.subject
    """
    def __init__(self, init=None):
        if init:
            self.observers = WeakSet(init)
        else:
            self.observers = WeakSet()

    def register(self, func):
        """ Registers a callable.
            Can be used as a decorator.
        """
        self.observers.add(func)
        return func

    def unregister(self, func):
        """ Unregisters a callable.
        """
        if func in self.observers:
            self.observers.remove(func)
            return func
        return False

    def notify(self, *args, **kwargs):
        """ Notifies all registered observers of an event.
        """
        return [observer(*args, **kwargs) for observer in self.observers]

    def __iter__(self):
        return (observer for observer in self.observers)

    __call__ = notify
    on = bind = register
    off = unbind = unregister
Ejemplo n.º 3
0
class _OngoingCalls:
    """Internal class used for have visibility of the ongoing calls."""

    _calls: AbstractSet[_base_call.RpcContext]

    def __init__(self):
        self._calls = WeakSet()

    def _remove_call(self, call: _base_call.RpcContext):
        try:
            self._calls.remove(call)
        except KeyError:
            pass

    @property
    def calls(self) -> AbstractSet[_base_call.RpcContext]:
        """Returns the set of ongoing calls."""
        return self._calls

    def size(self) -> int:
        """Returns the number of ongoing calls."""
        return len(self._calls)

    def trace_call(self, call: _base_call.RpcContext):
        """Adds and manages a new ongoing call."""
        self._calls.add(call)
        call.add_done_callback(self._remove_call)
Ejemplo n.º 4
0
class Signal(object):
    def __init__(self):
        self._functions = WeakSet()
        self._methods = WeakKeyDictionary()

    def __call__(self, *args, **kargs):
        for f in self._functions:
            f(*args, **kargs)

        for obj, functions in self._methods.items():
            for f in functions:
                f(obj, *args, **kargs)

    def connect(self, slot):
        if inspect.ismethod(slot):
            if not slot.__self__ in self._methods:
                self._methods[slot.__self__] = set()
            self._methods[slot.__self__].add(slot.__func__)
        else:
            self._functions.add(slot)

    def disconnect(self, slot):
        if inspect.ismethod(slot):
            if slot.__self__ in self._methods:
                self._methods[slot.__self__].remove(slot.__func__)
        else:
            if slot in self._functions:
                self._functions.remove(slot)
Ejemplo n.º 5
0
class Signal(object):
    def __init__(self):
        self._functions = WeakSet()
        self._methods = WeakKeyDictionary()

    def __call__(self, *args, **kargs):
        for f in self._functions:
            f(*args, **kargs)

        for obj, functions in self._methods.items():
            for f in functions:
                f(obj, *args, **kargs)

    def connect(self, slot):
        if inspect.ismethod(slot):
            if not slot.__self__ in self._methods:
                self._methods[slot.__self__] = set()
            self._methods[slot.__self__].add(slot.__func__)
        else:
            self._functions.add(slot)

    def disconnect(self, slot):
        if inspect.ismethod(slot):
            if slot.__self__ in self._methods:
                self._methods[slot.__self__].remove(slot.__func__)
        else:
            if slot in self._functions:
                self._functions.remove(slot)
Ejemplo n.º 6
0
class Signal(object):
    def __init__(self):
        self._functions = WeakSet()
        self._methods = WeakKeyDictionary()

    def __call__(self, *args, **kargs):
        # Call handler functions
        to_be_removed = []
        for func in self._functions.copy():
            try:
                func(*args, **kargs)
            except RuntimeError:
                Warning.warn(
                    'Signals func->RuntimeError: func "{}" will be removed.'.
                    format(func))
                to_be_removed.append(func)

        for remove in to_be_removed:
            self._functions.discard(remove)

        # Call handler methods
        to_be_removed = []
        emitters = self._methods.copy()
        for obj, funcs in emitters.items():
            msg_debug('obj is type "{}"'.format(type(obj)))
            for func in funcs.copy():
                try:
                    func(obj, *args, **kargs)
                except RuntimeError:
                    warnings.warn(
                        'Signals methods->RuntimeError, obj.func "{}.{}" will be removed'
                        .format(obj, func))
                    to_be_removed.append((obj, func))

        for obj, func in to_be_removed:
            self._methods[obj].discard(func)

    def connect(self, slot):
        if inspect.ismethod(slot):
            if slot.__self__ not in self._methods:
                self._methods[slot.__self__] = set()

            self._methods[slot.__self__].add(slot.__func__)

        else:
            self._functions.add(slot)

    def disconnect(self, slot):
        if inspect.ismethod(slot):
            if slot.__self__ in self._methods:
                self._methods[slot.__self__].remove(slot.__func__)
        else:
            if slot in self._functions:
                self._functions.remove(slot)

    def clear(self):
        self._functions.clear()
        self._methods.clear()
Ejemplo n.º 7
0
class Signal(object):
    """
    Simple class to emit signals to connected callable receivers.
    """

    def __init__(self):
        """
        Instantiate a new object
        """
        self.funcs = WeakSet()
        self.meths = WeakKeyDictionary()

    def connect(self, c):
        """
        Connect a callable as receiver for the signal
        @param c: signal receiver
        @type c: Callable
        """
        if inspect.ismethod(c):
            if c.__self__ not in self.meths:
                self.meths[c.__self__] = set()

            self.meths[c.__self__].add(c.__func__)
        else:
            if c not in self.funcs:
                self.funcs.add(c)

    def disconnect(self, c):
        """
        Disconnect the callable from receiving the signal
        @param c: signal receiver
        @type c: Callable
        """
        if inspect.ismethod(c):
            if c.__self__ in self.meths:
                self.meths[c.__self__].remove(c.__func__)
        else:
            if c in self.funcs:
                self.funcs.remove(c)

    def disconnectAll(self):
        """
        Disconnects all signal receivers
        """
        self.funcs.clear()
        self.meths.clear()

    def emit(self, *args, **kwargs):
        """
        Fires the signal to all connected receivers
        """
        for c in self.funcs:
            c(*args, **kwargs)

        for obj, funcs in self.meths.items():
            for func in funcs:
                func(obj, *args, **kwargs)
Ejemplo n.º 8
0
class Signal(object):
    def __init__(self):
        self._functions = WeakSet()
        self._methods = WeakKeyDictionary()
        self._activated = True

    def __call__(self, *args, **kargs):

        # call connected functions only if activated
        if self._activated:
            # Call handler functions
            for func in self._functions:
                func(*args, **kargs)

            # Call handler methods
            for obj, funcs in self._methods.items():
                for func in funcs:
                    func(obj, *args, **kargs)

    def connect(self, slot):
        if inspect.ismethod(slot):
            if slot.__self__ not in self._methods:
                self._methods[slot.__self__] = set()

            self._methods[slot.__self__].add(slot.__func__)

        else:
            self._functions.add(slot)

    def disconnect(self, slot):
        if inspect.ismethod(slot):
            if slot.__self__ in self._methods:
                self._methods[slot.__self__].remove(slot.__func__)
        else:
            if slot in self._functions:
                self._functions.remove(slot)

    def clear(self):
        self._functions.clear()
        self._methods.clear()

    def activate(self):
        """
        Activate the signal to emit.
        """

        self._activated = True

    def deactivate(self):
        """
        Deactivate the signal to emit.
        """

        self._activated = False
Ejemplo n.º 9
0
class Signal(object):
    def __init__(self):
        self._functions = WeakSet()
        self._methods = WeakKeyDictionary()

    def __call__(self, *args, **kargs):
        # Call handler functions
        to_be_removed = []
        for func in self._functions.copy():
            try:
                func(*args, **kargs)
            except RuntimeError:
                Warning.warn('Signals func->RuntimeError: func "{}" will be removed.'.format(func))
                to_be_removed.append(func)

        for remove in to_be_removed:
            self._functions.discard(remove)

        # Call handler methods
        to_be_removed = []
        emitters = self._methods.copy()
        for obj, funcs in emitters.items():
            msg_debug('obj is type "{}"'.format(type(obj)))
            for func in funcs.copy():
                try:
                    func(obj, *args, **kargs)
                except RuntimeError:
                    warnings.warn('Signals methods->RuntimeError, obj.func "{}.{}" will be removed'.format(obj, func))
                    to_be_removed.append((obj, func))

        for obj, func in to_be_removed:
            self._methods[obj].discard(func)

    def connect(self, slot):
        if inspect.ismethod(slot):
            if slot.__self__ not in self._methods:
                self._methods[slot.__self__] = set()

            self._methods[slot.__self__].add(slot.__func__)

        else:
            self._functions.add(slot)

    def disconnect(self, slot):
        if inspect.ismethod(slot):
            if slot.__self__ in self._methods:
                self._methods[slot.__self__].remove(slot.__func__)
        else:
            if slot in self._functions:
                self._functions.remove(slot)

    def clear(self):
        self._functions.clear()
        self._methods.clear()
Ejemplo n.º 10
0
class ConnectionPool:

    def __init__(self):
        self._config_dict = None
        self._queue = Queue()
        self._outstanding_connections = WeakSet()

    async def get_conn(self):
        self._check_config()
        try:
            while True:
                conn = self._queue.get_nowait()
                if conn.is_open():
                    break
                try:
                    await conn.close()
                except Exception:
                    l.debug('Exception in close rethink connection', exc_info=True)
        except QueueEmpty:
            conn = await r.connect(**self._config_dict)
        self._outstanding_connections.add(conn)
        return conn

    async def put_conn(self, conn):
        self._queue.put_nowait(conn)
        self._outstanding_connections.remove(conn)

    def set_config(self, config):
        self._config_dict = config

    def get_config(self):
        self._check_config()
        return self._config_dict

    async def teardown(self):
        while True:
            try:
                conn = self._queue.get_nowait()
            except QueueEmpty:
                break
            self._outstanding_connections.add(conn)
        for conn in self._outstanding_connections:
            try:
                await conn.close()
            except Exception:
                l.debug('Exception in close rethink connection', exc_info=True)

    def _check_config(self):
        assert self._config_dict is not None, "Did you remember to run resync.setup()?"
Ejemplo n.º 11
0
class Account(Entity):

    """A user account."""

    _uid_code = "A"

    type = "account"

    def __init__(self, data=None, active=False, savable=True):
        super().__init__(data, active, savable)
        self._sessions = WeakSet()

    def __repr__(self):
        if hasattr(self, "name") and self.name:
            return joins("Account<", self.name, ">", sep="")
        else:
            return "Account<(unnamed)>"

    def login(self, session):
        """Process an account login for a session.

        :param sessions.Session session: The session logging in
        :returns None:

        """
        with EVENTS.fire("account_login", session, self):
            log.info("%s has logged in to %s.", session, self)
            session.send("\nMOTD will go here!")
            if session not in self._sessions:
                self._sessions.add(session)
            if not self.active:
                self.active = True

    def logout(self, session):
        """Process an account logout for a session.

        :param sessions.Session session: The session logging out
        :returns None:

        """
        with EVENTS.fire("account_logout", session, self):
            log.info("%s has logged out of %s.", session, self)
            if session in self._sessions:
                self._sessions.remove(session)
            if not self._sessions:
                self.active = False
class SIGNAL(object):
    
    def __init__( self, name = None ):
        self._functions = WeakSet()
        self._methods = WeakKeyDictionary()
        self._name = name

    def __call__(self, *args, **kargs):
        # Call handler functions
        for func in self._functions:
            func(*args, **kargs)

        # Call handler methods
        for obj, funcs in self._methods.items():
            for func in funcs:
                func(obj, *args, **kargs)

    def connect(self, slot):
        if inspect.ismethod(slot):
            if slot.__self__ not in self._methods:
                self._methods[slot.__self__] = set()

            self._methods[slot.__self__].add(slot.__func__)

        else:
            self._functions.add(slot)

    def disconnect(self, slot):
        if inspect.ismethod(slot):
            if slot.__self__ in self._methods:
                self._methods[slot.__self__].remove(slot.__func__)
        else:
            if slot in self._functions:
                self._functions.remove(slot)

    def clear(self):
        self._functions.clear()
        self._methods.clear()
Ejemplo n.º 13
0
class Signal(object):
    def __init__(self):
        self._functions = WeakSet()
        self._methods = WeakKeyDictionary()

    def __call__(self, *args, **kargs):
        res = []
        # Call handler functions
        for func in self._functions:
            res.append(func(*args, **kargs))

        # Call handler methods
        for obj, funcs in self._methods.items():
            for func in funcs:
                res.append(func(obj, *args, **kargs))
        return res

    def connect(self, slot):
        if inspect.ismethod(slot):
            if slot.__self__ not in self._methods:
                self._methods[slot.__self__] = set()

            self._methods[slot.__self__].add(slot.__func__)

        else:
            self._functions.add(slot)

    def disconnect(self, slot):
        if inspect.ismethod(slot):
            if slot.__self__ in self._methods:
                self._methods[slot.__self__].remove(slot.__func__)
        else:
            if slot in self._functions:
                self._functions.remove(slot)

    def clear(self):
        self._functions.clear()
        self._methods.clear()
Ejemplo n.º 14
0
class SIGNAL(object):
    def __init__(self, name=None):
        self._functions = WeakSet()
        self._methods = WeakKeyDictionary()
        self._name = name

    def __call__(self, *args, **kargs):
        # Call handler functions
        for func in self._functions:
            func(*args, **kargs)

        # Call handler methods
        for obj, funcs in self._methods.items():
            for func in funcs:
                func(obj, *args, **kargs)

    def connect(self, slot):
        if inspect.ismethod(slot):
            if slot.__self__ not in self._methods:
                self._methods[slot.__self__] = set()

            self._methods[slot.__self__].add(slot.__func__)

        else:
            self._functions.add(slot)

    def disconnect(self, slot):
        if inspect.ismethod(slot):
            if slot.__self__ in self._methods:
                self._methods[slot.__self__].remove(slot.__func__)
        else:
            if slot in self._functions:
                self._functions.remove(slot)

    def clear(self):
        self._functions.clear()
        self._methods.clear()
Ejemplo n.º 15
0
class TestWeakSet(unittest.TestCase):

    def setUp(self):
        # need to keep references to them
        self.items = [SomeClass(c) for c in ('a', 'b', 'c')]
        self.items2 = [SomeClass(c) for c in ('x', 'y', 'z')]
        self.letters = [SomeClass(c) for c in string.ascii_letters]
        self.ab_items = [SomeClass(c) for c in 'ab']
        self.abcde_items = [SomeClass(c) for c in 'abcde']
        self.def_items = [SomeClass(c) for c in 'def']
        self.ab_weakset = WeakSet(self.ab_items)
        self.abcde_weakset = WeakSet(self.abcde_items)
        self.def_weakset = WeakSet(self.def_items)
        self.s = WeakSet(self.items)
        self.d = dict.fromkeys(self.items)
        self.obj = SomeClass('F')
        self.fs = WeakSet([self.obj])

    def test_methods(self):
        weaksetmethods = dir(WeakSet)
        for method in dir(set):
            if method == 'test_c_api' or method.startswith('_'):
                continue
            self.assertIn(method, weaksetmethods,
                         "WeakSet missing method " + method)

    def test_new_or_init(self):
        self.assertRaises(TypeError, WeakSet, [], 2)

    def test_len(self):
        self.assertEqual(len(self.s), len(self.d))
        self.assertEqual(len(self.fs), 1)
        del self.obj
        test_support.gc_collect()
        # len of weak collections is eventually consistent on
        # Jython. In practice this does not matter because of the
        # nature of weaksets - we cannot rely on what happens in the
        # reaper thread and how it interacts with gc
        self.assertIn(len(self.fs), (0, 1))

    def test_contains(self):
        for c in self.letters:
            self.assertEqual(c in self.s, c in self.d)
        # 1 is not weakref'able, but that TypeError is caught by __contains__
        self.assertNotIn(1, self.s)
        self.assertIn(self.obj, self.fs)
        del self.obj
        test_support.gc_collect()
        self.assertNotIn(SomeClass('F'), self.fs)

    def test_union(self):
        u = self.s.union(self.items2)
        for c in self.letters:
            self.assertEqual(c in u, c in self.d or c in self.items2)
        self.assertEqual(self.s, WeakSet(self.items))
        self.assertEqual(type(u), WeakSet)
        self.assertRaises(TypeError, self.s.union, [[]])
        for C in set, frozenset, dict.fromkeys, list, tuple:
            x = WeakSet(self.items + self.items2)
            c = C(self.items2)
            self.assertEqual(self.s.union(c), x)
            del c
            test_support.gc_collect()
        self.assertEqual(len(list(u)), len(list(self.items)) + len(list(self.items2)))
        self.items2.pop()
        test_support.gc_collect()
        self.assertEqual(len(list(u)), len(list(self.items)) + len(list(self.items2)))

    def test_or(self):
        i = self.s.union(self.items2)
        self.assertEqual(self.s | set(self.items2), i)
        self.assertEqual(self.s | frozenset(self.items2), i)

    def test_intersection(self):
        s = WeakSet(self.letters)
        i = s.intersection(self.items2)
        for c in self.letters:
            self.assertEqual(c in i, c in self.items2 and c in self.letters)
        self.assertEqual(s, WeakSet(self.letters))
        self.assertEqual(type(i), WeakSet)
        for C in set, frozenset, dict.fromkeys, list, tuple:
            x = WeakSet([])
            self.assertEqual(i.intersection(C(self.items)), x)
        self.assertEqual(len(i), len(self.items2))
        self.items2.pop()
        test_support.gc_collect()
        self.assertEqual(len(list(i)), len(list(self.items2)))

    def test_isdisjoint(self):
        self.assertTrue(self.s.isdisjoint(WeakSet(self.items2)))
        self.assertTrue(not self.s.isdisjoint(WeakSet(self.letters)))

    def test_and(self):
        i = self.s.intersection(self.items2)
        self.assertEqual(self.s & set(self.items2), i)
        self.assertEqual(self.s & frozenset(self.items2), i)

    def test_difference(self):
        i = self.s.difference(self.items2)
        for c in self.letters:
            self.assertEqual(c in i, c in self.d and c not in self.items2)
        self.assertEqual(self.s, WeakSet(self.items))
        self.assertEqual(type(i), WeakSet)
        self.assertRaises(TypeError, self.s.difference, [[]])

    def test_sub(self):
        i = self.s.difference(self.items2)
        self.assertEqual(self.s - set(self.items2), i)
        self.assertEqual(self.s - frozenset(self.items2), i)

    def test_symmetric_difference(self):
        i = self.s.symmetric_difference(self.items2)
        for c in self.letters:
            self.assertEqual(c in i, (c in self.d) ^ (c in self.items2))
        self.assertEqual(self.s, WeakSet(self.items))
        self.assertEqual(type(i), WeakSet)
        self.assertRaises(TypeError, self.s.symmetric_difference, [[]])
        self.assertEqual(len(i), len(self.items) + len(self.items2))
        self.items2.pop()
        test_support.gc_collect()
        self.assertEqual(len(list(i)), len(list(self.items)) + len(list(self.items2)))

    def test_xor(self):
        i = self.s.symmetric_difference(self.items2)
        self.assertEqual(self.s ^ set(self.items2), i)
        self.assertEqual(self.s ^ frozenset(self.items2), i)

    def test_sub_and_super(self):
        self.assertTrue(self.ab_weakset <= self.abcde_weakset)
        self.assertTrue(self.abcde_weakset <= self.abcde_weakset)
        self.assertTrue(self.abcde_weakset >= self.ab_weakset)
        self.assertFalse(self.abcde_weakset <= self.def_weakset)
        self.assertFalse(self.abcde_weakset >= self.def_weakset)
        self.assertTrue(set('a').issubset('abc'))
        self.assertTrue(set('abc').issuperset('a'))
        self.assertFalse(set('a').issubset('cbs'))
        self.assertFalse(set('cbs').issuperset('a'))

    def test_lt(self):
        self.assertTrue(self.ab_weakset < self.abcde_weakset)
        self.assertFalse(self.abcde_weakset < self.def_weakset)
        self.assertFalse(self.ab_weakset < self.ab_weakset)
        self.assertFalse(WeakSet() < WeakSet())

    def test_gt(self):
        self.assertTrue(self.abcde_weakset > self.ab_weakset)
        self.assertFalse(self.abcde_weakset > self.def_weakset)
        self.assertFalse(self.ab_weakset > self.ab_weakset)
        self.assertFalse(WeakSet() > WeakSet())

    def test_gc(self):
        # Create a nest of cycles to exercise overall ref count check
        s = WeakSet(Foo() for i in range(1000))
        for elem in s:
            elem.cycle = s
            elem.sub = elem
            elem.set = WeakSet([elem])

    def test_subclass_with_custom_hash(self):
        # Bug #1257731
        class H(WeakSet):
            def __hash__(self):
                return int(id(self) & 0x7fffffff)
        s=H()
        f=set()
        f.add(s)
        self.assertIn(s, f)
        f.remove(s)
        f.add(s)
        f.discard(s)

    def test_init(self):
        s = WeakSet()
        s.__init__(self.items)
        self.assertEqual(s, self.s)
        s.__init__(self.items2)
        self.assertEqual(s, WeakSet(self.items2))
        self.assertRaises(TypeError, s.__init__, s, 2);
        self.assertRaises(TypeError, s.__init__, 1);

    def test_constructor_identity(self):
        s = WeakSet(self.items)
        t = WeakSet(s)
        self.assertNotEqual(id(s), id(t))

    def test_hash(self):
        self.assertRaises(TypeError, hash, self.s)

    def test_clear(self):
        self.s.clear()
        self.assertEqual(self.s, WeakSet([]))
        self.assertEqual(len(self.s), 0)

    def test_copy(self):
        dup = self.s.copy()
        self.assertEqual(self.s, dup)
        self.assertNotEqual(id(self.s), id(dup))

    def test_add(self):
        x = SomeClass('Q')
        self.s.add(x)
        self.assertIn(x, self.s)
        dup = self.s.copy()
        self.s.add(x)
        self.assertEqual(self.s, dup)
        if not test_support.is_jython:  # Jython/JVM can weakly reference list and other objects
            self.assertRaises(TypeError, self.s.add, [])
        self.fs.add(Foo())
        test_support.gc_collect()  # CPython assumes Foo() went out of scope and was collected, so ensure the same
        self.assertEqual(len(list(self.fs)), 1)
        self.fs.add(self.obj)
        self.assertEqual(len(list(self.fs)), 1)

    def test_remove(self):
        x = SomeClass('a')
        self.s.remove(x)
        self.assertNotIn(x, self.s)
        self.assertRaises(KeyError, self.s.remove, x)
        if not test_support.is_jython:  # Jython/JVM can weakly reference list and other objects
            self.assertRaises(TypeError, self.s.remove, [])

    def test_discard(self):
        a, q = SomeClass('a'), SomeClass('Q')
        self.s.discard(a)
        self.assertNotIn(a, self.s)
        self.s.discard(q)
        if not test_support.is_jython:  # Jython/JVM can weakly reference list and other objects
            self.assertRaises(TypeError, self.s.discard, [])

    def test_pop(self):
        for i in range(len(self.s)):
            elem = self.s.pop()
            self.assertNotIn(elem, self.s)
        self.assertRaises(KeyError, self.s.pop)

    def test_update(self):
        retval = self.s.update(self.items2)
        self.assertEqual(retval, None)
        for c in (self.items + self.items2):
            self.assertIn(c, self.s)
        self.assertRaises(TypeError, self.s.update, [[]])

    def test_update_set(self):
        self.s.update(set(self.items2))
        for c in (self.items + self.items2):
            self.assertIn(c, self.s)

    def test_ior(self):
        self.s |= set(self.items2)
        for c in (self.items + self.items2):
            self.assertIn(c, self.s)

    def test_intersection_update(self):
        retval = self.s.intersection_update(self.items2)
        self.assertEqual(retval, None)
        for c in (self.items + self.items2):
            if c in self.items2 and c in self.items:
                self.assertIn(c, self.s)
            else:
                self.assertNotIn(c, self.s)
        self.assertRaises(TypeError, self.s.intersection_update, [[]])

    def test_iand(self):
        self.s &= set(self.items2)
        for c in (self.items + self.items2):
            if c in self.items2 and c in self.items:
                self.assertIn(c, self.s)
            else:
                self.assertNotIn(c, self.s)

    def test_difference_update(self):
        retval = self.s.difference_update(self.items2)
        self.assertEqual(retval, None)
        for c in (self.items + self.items2):
            if c in self.items and c not in self.items2:
                self.assertIn(c, self.s)
            else:
                self.assertNotIn(c, self.s)
        if not test_support.is_jython:  # Jython/JVM can weakly reference list and other objects
            self.assertRaises(TypeError, self.s.difference_update, [[]])
            self.assertRaises(TypeError, self.s.symmetric_difference_update, [[]])

    def test_isub(self):
        self.s -= set(self.items2)
        for c in (self.items + self.items2):
            if c in self.items and c not in self.items2:
                self.assertIn(c, self.s)
            else:
                self.assertNotIn(c, self.s)

    def test_symmetric_difference_update(self):
        retval = self.s.symmetric_difference_update(self.items2)
        self.assertEqual(retval, None)
        for c in (self.items + self.items2):
            if (c in self.items) ^ (c in self.items2):
                self.assertIn(c, self.s)
            else:
                self.assertNotIn(c, self.s)
        self.assertRaises(TypeError, self.s.symmetric_difference_update, [[]])

    def test_ixor(self):
        self.s ^= set(self.items2)
        for c in (self.items + self.items2):
            if (c in self.items) ^ (c in self.items2):
                self.assertIn(c, self.s)
            else:
                self.assertNotIn(c, self.s)

    def test_inplace_on_self(self):
        t = self.s.copy()
        t |= t
        self.assertEqual(t, self.s)
        t &= t
        self.assertEqual(t, self.s)
        t -= t
        self.assertEqual(t, WeakSet())
        t = self.s.copy()
        t ^= t
        self.assertEqual(t, WeakSet())

    def test_eq(self):
        # issue 5964 (http://bugs.python.org/issue5964)
        self.assertEqual(self.s, self.s)
        self.assertEqual(self.s, WeakSet(self.items))
        # Jython diverges here in the next test because it constructs
        # WeakSet as a subclass of set; this seems to be the proper
        # thing to do given what is the typical comparison
        self.assertEqual(self.s, set(self.items))
        self.assertNotEqual(self.s, list(self.items))
        self.assertNotEqual(self.s, tuple(self.items))
        self.assertNotEqual(self.s, 1)

    def test_weak_destroy_while_iterating(self):
        # Issue #7105: iterators shouldn't crash when a key is implicitly removed
        # Create new items to be sure no-one else holds a reference
        items = [SomeClass(c) for c in ('a', 'b', 'c')]
        s = WeakSet(items)
        it = iter(s)
        next(it)             # Trigger internal iteration
        # Destroy an item
        del items[-1]
        test_support.gc_collect()    # just in case
        # We have removed either the first consumed items, or another one
        self.assertIn(len(list(it)), [len(items), len(items) - 1])
        del it
        extra_collect()
        # The removal has been committed
        self.assertEqual(len(s), len(items))

    def test_weak_destroy_and_mutate_while_iterating(self):
        # Issue #7105: iterators shouldn't crash when a key is implicitly removed
        items = [SomeClass(c) for c in string.ascii_letters]
        s = WeakSet(items)
        @contextlib.contextmanager
        def testcontext():
            try:
                it = iter(s)
                next(it)
                # Schedule an item for removal and recreate it
                u = SomeClass(str(items.pop()))
                test_support.gc_collect()      # just in case
                yield u
            finally:
                it = None           # should commit all removals

        test_support.gc_collect()

        with testcontext() as u:
            self.assertNotIn(u, s)
        with testcontext() as u:
            self.assertRaises(KeyError, s.remove, u)
        self.assertNotIn(u, s)
        with testcontext() as u:
            s.add(u)
        self.assertIn(u, s)
        t = s.copy()
        with testcontext() as u:
            s.update(t)
        self.assertEqual(len(s), len(t))
        with testcontext() as u:
            s.clear()
        self.assertEqual(len(s), 0)

    def test_len_cycles(self):
        N = 20
        items = [RefCycle() for i in range(N)]
        s = WeakSet(items)
        del items
        # do some gc
        test_support.gc_collect()
        it = iter(s)
        try:
            next(it)
        except StopIteration:
            pass

        # do some gc
        test_support.gc_collect()

        n1 = len(s)
        del it
        # do some gc
        test_support.gc_collect()

        n2 = len(s)
        # one item may be kept alive inside the iterator
        self.assertIn(n1, (0, 1))
        self.assertEqual(n2, 0)

    @unittest.skipIf(test_support.is_jython, "GarbageCollection not deterministic in Jython")
    def test_len_race(self):
        # Extended sanity checks for len() in the face of cyclic collection
        self.addCleanup(gc.set_threshold, *gc.get_threshold())
        for th in range(1, 100):
            N = 20
            gc.collect(0)
            gc.set_threshold(th, th, th)
            items = [RefCycle() for i in range(N)]
            s = WeakSet(items)
            del items
            # All items will be collected at next garbage collection pass
            it = iter(s)
            try:
                next(it)
            except StopIteration:
                pass
            n1 = len(s)
            del it
            n2 = len(s)
            self.assertGreaterEqual(n1, 0)
            self.assertLessEqual(n1, N)
            self.assertGreaterEqual(n2, 0)
            self.assertLessEqual(n2, n1)
Ejemplo n.º 16
0
class Signal:
    ##  Signal types.
    #   These indicate the type of a signal, that is, how the signal handles calling the connected
    #   slots.
    #   - Direct connections immediately call the connected slots from the thread that called emit().
    #   - Auto connections will push the call onto the event loop if the current thread is
    #     not the main thread, but make a direct call if it is.
    #   - Queued connections will always push
    #     the call on to the event loop.
    Direct = 1
    Auto = 2
    Queued = 3

    ##  Initialize the instance.
    #
    #   \param kwargs Keyword arguments.
    #                 Possible keywords:
    #                 - type: The signal type. Defaults to Auto.
    def __init__(self, **kwargs):
        self.__functions = WeakSet()
        self.__methods = WeakKeyDictionary()
        self.__signals = WeakSet()
        self.__type = kwargs.get("type", Signal.Auto)

        self.__emitting = False
        self.__connect_queue = []
        self.__disconnect_queue = []

    ##  \exception NotImplementedError
    def __call__(self):
        raise NotImplementedError("Call emit() to emit a signal")

    ##  Get type of the signal
    #   \return \type{int} Direct(1), Auto(2) or Queued(3)
    def getType(self):
        return self.__type

    ##  Emit the signal which indirectly calls all of the connected slots.
    #
    #   \param args The positional arguments to pass along.
    #   \param kwargs The keyword arguments to pass along.
    #
    #   \note If the Signal type is Queued and this is not called from the application thread
    #   the call will be posted as an event to the application main thread, which means the
    #   function will be called on the next application event loop tick.
    @call_if_enabled(_traceEmit, _isTraceEnabled())
    def emit(self, *args, **kwargs):
        try:
            if self.__type == Signal.Queued:
                Signal._app.functionEvent(CallFunctionEvent(self.emit, args, kwargs))
                return

            if self.__type == Signal.Auto:
                if threading.current_thread() is not Signal._app.getMainThread():
                    Signal._app.functionEvent(CallFunctionEvent(self.emit, args, kwargs))
                    return
        except AttributeError: # If Signal._app is not set
            return

        self.__emitting = True

        # Call handler functions
        for func in self.__functions:
            func(*args, **kwargs)

        # Call handler methods
        for dest, funcs in self.__methods.items():
            for func in funcs:
                func(dest, *args, **kwargs)

        # Emit connected signals
        for signal in self.__signals:
            signal.emit(*args, **kwargs)

        self.__emitting = False
        for connector in self.__connect_queue:
            self.connect(connector)
        self.__connect_queue.clear()
        for connector in self.__disconnect_queue:
            self.disconnect(connector)
        self.__connect_queue.clear()

    ##  Connect to this signal.
    #   \param connector The signal or slot (function) to connect.
    @call_if_enabled(_traceConnect, _isTraceEnabled())
    def connect(self, connector):
        if self.__emitting:
            # When we try to connect to a signal we change the dictionary of connectors.
            # This will cause an Exception since we are iterating over a dictionary that changed.
            # So instead, defer the connections until after we are done emitting.
            self.__connect_queue.append(connector)
            return

        if isinstance(connector, Signal):
            if connector == self:
                return
            self.__signals.add(connector)
        elif inspect.ismethod(connector):
            if connector.__self__ not in self.__methods:
                self.__methods[connector.__self__] = set()

            self.__methods[connector.__self__].add(connector.__func__)
        else:
            self.__functions.add(connector)

    ##  Disconnect from this signal.
    #   \param connector The signal or slot (function) to disconnect.
    @call_if_enabled(_traceDisconnect, _isTraceEnabled())
    def disconnect(self, connector):
        if self.__emitting:
            # See above.
            self.__disconnect_queue.append(connector)
            return

        try:
            if connector in self.__signals:
                self.__signals.remove(connector)
            elif inspect.ismethod(connector) and connector.__self__ in self.__methods:
                self.__methods[connector.__self__].remove(connector.__func__)
            else:
                if connector in self.__functions:
                    self.__functions.remove(connector)

        except KeyError: #Ignore errors when connector is not connected to this signal.
            pass

    ##  Disconnect all connected slots.
    def disconnectAll(self):
        if self.__emitting:
            raise RuntimeError("Tried to disconnect signal while signal is being emitted")

        self.__functions.clear()
        self.__methods.clear()
        self.__signals.clear()

    ##  To support Pickle
    #
    #   Since Weak containers cannot be serialized by Pickle we just return an empty dict as state.
    def __getstate__(self):
        return {}

    ##  To proerly handle deepcopy in combination with __getstate__
    #
    #   Apparently deepcopy uses __getstate__ internally, which is not documented. The reimplementation
    #   of __getstate__ then breaks deepcopy. On the other hand, if we do not reimplement it like that,
    #   we break pickle. So instead make sure to also reimplement __deepcopy__.
    def __deepcopy__(self, memo):
        signal = Signal(type = self.__type)
        signal.__functions = copy.deepcopy(self.__functions, memo)
        signal.__methods = copy.deepcopy(self.__methods, memo)
        signal.__signals = copy.deepcopy(self.__signals, memo)
        return signal

    ##  private:

    #   To avoid circular references when importing Application, this should be
    #   set by the Application instance.
    _app = None
Ejemplo n.º 17
0
class AsyncTaskContext(AbstractAsyncTaskContext):
    def __init__(self, daemon=False, parent=None, name=None):
        self._setup()

        self.daemon = daemon
        self.parent = parent
        self.name = name
        self.eventloop = parent.eventloop

        self.parent.add_child(self)

    def _setup(self):
        self.children = WeakSet()
        self.daemon_children = WeakSet()
        self.exception = None
        self.tb_list = None
        self.stack_list = None
        self.except_func = None
        self.finally_func = None

    def add_child(self, child):
        if DEBUG:
            log.debug("Adding child:%r ", child)

        if child.daemon:
            self.daemon_children.add(child)
        else:
            self.children.add(child)

    def remove_child(self, child):
        if DEBUG:
            log.debug("Removing child %r %r", child, self)
            log.debug("--------------------BEFORE REMOVE---------------------")
            log_task_context(self, log)
            log.debug("------------------------------------------------------")

        if child.daemon:
            self.daemon_children.remove(child)
        else:
            self.children.remove(child)
            if self.daemon_children and not self.children:
                self.parent.cancel()

        if not self.children and not self.daemon_children:
            if self.exception is not None and self.except_func is not None:
                self._execute_except(self.exception)
            else:
                self._execute_finally()

    def handle_exception(self, exception, tb_list=None):
        if DEBUG:
            log.debug("Handling exception %r %r", self, exception)

        if self.exception is None \
           or not isinstance(exception, CancellationError):
            self.exception = exception
            self.tb_list = tb_list

        for child in self.children.union(self.daemon_children):
            child.cancel()

    def cancel(self):
        if DEBUG:
            log.debug("Cancelling %r", self)

        self.handle_exception(CancellationError(), self.tb_list)

    def update_parent(self):
        if DEBUG:
            log.debug("updating parent %r of self %r", self.parent, self)
        if self.parent is None:
            return

        if self.exception is not None:
            self.parent.handle_exception(self.exception, self.tb_list)

        self.parent.remove_child(self)
        self.parent = None  # gc

    def schedule_task(self, task, now=False):
        if DEBUG:
            log.debug("Scheduling task %r", task)

        if now:
            self.eventloop.execute_now(task)
        else:
            self.eventloop.execute(task)

    def set_stack(self, stack_list):
        stack_before, stack_after = split_stack(stack_list)
        if self.parent.stack_list is None:
            self.parent.stack_list = stack_before

        self.stack_list = stack_after

    def _execute_except(self, err):
        if DEBUG:
            log.debug("Executing except %r %r", self, err)

        if self.except_func is not None:
            with self:
                except_func = self.except_func
                self.except_func = None
                task = AsyncTask(except_func, (err, ),
                                 context=self,
                                 name=except_func.__name__)
                task.cancellable = False
                task.daemon = self.daemon
                # execute exceptions asap to have a chance to cancel any
                # pending tasks
                task.execute_now()
        else:
            self._execute_finally()

    def _execute_finally(self):
        if DEBUG:
            log.debug("Executiong finally %r with exception %r", self,
                      self.exception)

        if isinstance(self.exception, CancellationError):
            self.exception = None

        if self.finally_func is not None:
            with self:
                task = AsyncTask(self.finally_func,
                                 context=self,
                                 name=self.finally_func.__name__)
                task.daemon = self.daemon
                task.cancellable = False
                task.execute()
                self.finally_func = None
        else:
            self.update_parent()

    def __enter__(self):
        self._parent_context = get_async_context()
        set_async_context(self)
        return self

    def __exit__(self, exc_type, err, tb):
        set_async_context(self._parent_context)
        self._parent_context = None  # gc

    def __repr__(self):
        args = []
        if self.name is not None:
            args.append("name=%s" % self.name)
        if self.parent:
            args.append("parent=%s" % self.parent)
        if self.children:
            args.append("children=%d" % len(self.children))
        if self.daemon_children:
            args.append("daemon_children=%d" % len(self.daemon_children))
        if self.except_func:
            args.append("except_func=%r" % self.except_func.__name__)
        if self.finally_func:
            args.append("finally_func=%r" % self.finally_func.__name__)
        if self.exception:
            args.append("exception=%r" % self.exception)

        if args:
            args.insert(0, "")

        return "<%s at %s%s>" % (self.__class__.__name__, hex(
            id(self)), " ".join(args))

    def __str__(self):
        return "<%s at %s>" % (self.__class__.__name__, hex(id(self)))
Ejemplo n.º 18
0
class Signal(object):
    '''
    The Signal class is an approximation of Qt's signals+slot system. Each event
    that an object would like to produce requires a Signal() object. All 
    interested parties on the event must register themselves as receivers via
    connect() or the '+=' operator.

    The event source calls emit() to produce an event (or treat it as a
    callable). All registered receivers will receive it, synchronously.
    '''
    def __init__(self, description=None):
        '''
        Create a Signal() object. Pass 'True' to constructor if locking around
        emit() is required.
        '''
        self.description = description
        self._functions = WeakSet()
        self._methods = WeakKeyDictionary()
        self._forwards = WeakKeyDictionary()
        self.disabled = False

    def disable(self):
        self.disabled = True

    def enable(self):
        self.disabled = False

    def __len__(self):
        return len(self._functions) + len(self._methods)

    def __call__(self, *args, **kwargs):
        return self.emit(*args, **kwargs)

    def emit(self, *args, **kwargs):
        'Invoke the signal with |args| and |kwargs|'
        results = []

        if self.disabled:
            return results

        for f in self._functions:
            if '__predicate__' in f.__dict__:
                if not f.__dict__['__predicate__']():
                    continue

            results.append(f(*args, **kwargs))

        for obj, funcs in self._methods.items():
            for f in funcs:
                if '__predicate__' in f.__dict__:
                    if not f.__dict__['__predicate__']():
                        continue

                results.append(f(obj, *args, **kwargs))

        return results

    def connect(self, dest, predicate=None):
        '''
        Connect |dest| to the signal. If |predicate| is set, it is treated as a
        nullary callable whose return value determines if the signal is fired.

        NOTE: Passing identical values to multiple invocations of connect() with
        different values of predicate will overwrite previous predicates and
        persist the last-used value.
        
        To achieve a similar effect, wrap |dest| in a function.

        '''
        assert callable(dest)
        if inspect.ismethod(dest):
            obj, impl = dest.__self__, dest.__func__

            if predicate is not None:
                impl.__dict__['__predicate__'] = predicate

            self._methods.setdefault(obj, set()).add(impl)
        else:
            if predicate is not None:
                dest.__dict__['__predicate__'] = predicate

            self._functions.add(dest)

        for signal, methods in self._forwards.items():
            for method in methods:
                signal.connect(method)
        self._forwards.clear()

    def when(self, obj, signal, arg=False):
        ''' This forwards signal from obj '''
        #will reemit forwarded signal prepending obj to arguments
        if arg:
            method = MethodType(
                lambda *args, **kwargs: self.emit(*args, **kwargs), obj)
        else:
            method = self.emit
        if len(self):
            signal.connect(method)
        else:
            self._forwards.setdefault(signal, set()).add(method)

    def __iadd__(self, dest):
        self.connect(dest)
        return self

    def disconnect(self, dest):
        try:
            if inspect.ismethod(dest):
                obj, impl = dest.__self__, dest.__func__
                self._methods[obj].remove(impl)
            else:
                self._functions.remove(dest)
        except KeyError:
            raise SignalDisconnectedError()

    def __isub__(self, dest):
        self.disconnect(dest)
        return self

    def reset(self):
        self._functions.clear()
        self._methods.clear()
        self._forwards.clear()
Ejemplo n.º 19
0
class HealthMonitor(object):
    """
    Monitors whether a particular host is marked as up or down.
    This class is primarily intended for internal use, although
    applications may find it useful to check whether a given node
    is up or down.
    """

    is_up = True
    """
    A boolean representing the current state of the node.
    """
    def __init__(self, conviction_policy):
        self._conviction_policy = conviction_policy
        self._host = conviction_policy.host
        # self._listeners will hold, among other things, references to
        # Cluster objects.  To allow those to be GC'ed (and shutdown) even
        # though we've implemented __del__, use weak references.
        self._listeners = WeakSet()
        self._lock = RLock()

    def register(self, listener):
        with self._lock:
            self._listeners.add(listener)

    def unregister(self, listener):
        with self._lock:
            self._listeners.remove(listener)

    def set_up(self):
        if self.is_up:
            return

        self._conviction_policy.reset()
        log.info("Host %s is considered up", self._host)

        with self._lock:
            listeners = self._listeners.copy()

        for listener in listeners:
            listener.on_up(self._host)

        self.is_up = True

    def set_down(self):
        if not self.is_up:
            return

        self.is_up = False
        log.info("Host %s is considered down", self._host)

        with self._lock:
            listeners = self._listeners.copy()

        for listener in listeners:
            listener.on_down(self._host)

    def reset(self):
        return self.set_up()

    def signal_connection_failure(self, connection_exc):
        is_down = self._conviction_policy.add_failure(connection_exc)
        if is_down:
            self.set_down()
        return is_down
Ejemplo n.º 20
0
class BaseService(ABC, CancellableMixin):
    # Use a WeakSet so that we don't have to bother updating it when tasks finish.
    _child_services = None  # : 'WeakSet[BaseService]'
    _tasks = None  # : 'WeakSet[asyncio.Future[Any]]'
    _finished_callbacks = None  # : List[Callable[['BaseService'], None]]
    # Number of seconds cancel() will wait for run() to finish.
    _wait_until_finished_timeout = 5

    # the custom event loop to run in, or None if the default loop should be used
    _loop = None  # : asyncio.AbstractEventLoop

    def __init__(
        self, token: CancelToken = None, loop: asyncio.AbstractEventLoop = None
    ) -> None:
        self.events = ServiceEvents()
        self._run_lock = asyncio.Lock()
        self._child_services = WeakSet()
        self._tasks = WeakSet()
        self._finished_callbacks = []

        self._loop = loop

        base_token = CancelToken(type(self).__name__, loop=loop)

        if token is None:
            self.cancel_token = base_token
        else:
            self.cancel_token = base_token.chain(token)

        self._executor = get_asyncio_executor()

    @property
    def logger(self) -> Logger:
        return Logger

    def get_event_loop(self) -> asyncio.AbstractEventLoop:
        if self._loop is None:
            return asyncio.get_event_loop()
        else:
            return self._loop

    async def run(
        self, finished_callback: Optional[Callable[["BaseService"], None]] = None
    ) -> None:
        """Await for the service's _run() coroutine.

        Once _run() returns, triggers the cancel token, call cleanup() and
        finished_callback (if one was passed).
        """
        if self.is_running:
            raise ValidationError("Cannot start the service while it's already running")
        elif self.is_cancelled:
            raise ValidationError(
                "Cannot restart a service that has already been cancelled"
            )

        if finished_callback:
            self._finished_callbacks.append(finished_callback)

        try:
            async with self._run_lock:
                self.events.started.set()
                await self._run()
        except OperationCancelled as e:
            self.logger.debug("%s finished: %s" % (self, e))
        except Exception:
            self.logger.exception("Unexpected error in %r, exiting" % self)
        finally:
            # Trigger our cancel token to ensure all pending asyncio tasks and background
            # coroutines started by this service exit cleanly.
            self.events.cancelled.set()
            self.cancel_token.trigger()

            await self.cleanup()

            for callback in self._finished_callbacks:
                callback(self)

            self.events.finished.set()
            self.logger.debug("%s halted cleanly" % self)

    def add_finished_callback(
        self, finished_callback: Callable[["BaseService"], None]
    ) -> None:
        self._finished_callbacks.append(finished_callback)

    def run_task(self, awaitable: Awaitable[Any]) -> None:
        """Run the given awaitable in the background.

        The awaitable should return whenever this service's cancel token is triggered.

        If it raises OperationCancelled, that is caught and ignored.
        """

        @functools.wraps(awaitable)  # type: ignore
        async def _run_task_wrapper() -> None:
            self.logger.debug("Running task %s" % awaitable)
            try:
                await awaitable
            except OperationCancelled:
                pass
            except Exception as e:
                self.logger.warning("Task %s finished unexpectedly: %s" % (awaitable, e))
                self.logger.debug("Task failure traceback")
            else:
                self.logger.debug("Task %s finished with no errors" % awaitable)

        self._tasks.add(asyncio.ensure_future(_run_task_wrapper()))

    def run_daemon_task(self, awaitable: Awaitable[Any]) -> None:
        """Run the given awaitable in the background.

        Like :meth:`run_task` but if the task ends without cancelling, then this
        this service will terminate as well.
        """

        @functools.wraps(awaitable)  # type: ignore
        async def _run_daemon_task_wrapper() -> None:
            try:
                await awaitable
            finally:
                if not self.is_cancelled:
                    self.logger.debug(
                        "%s finished while %s is still running, terminating as well" %
                        (awaitable, self)
                    )
                    self.cancel_token.trigger()

        self.run_task(_run_daemon_task_wrapper())

    def run_child_service(self, child_service: "BaseService") -> None:
        """
        Run a child service and keep a reference to it to be considered during the cleanup.
        """
        if child_service.is_running:
            raise ValidationError(
                "Can't start service {}, child of {}: it's already running".format(repr(child_service), repr(self))
            )
        elif child_service.is_cancelled:
            raise ValidationError(
                "Can't restart {}, child of {}: it's already completed".format(repr(child_service), repr(self))
            )

        self._child_services.add(child_service)
        self.run_task(child_service.run())

    def run_daemon(self, service: "BaseService") -> None:
        """
        Run a service and keep a reference to it to be considered during the cleanup.

        If the service finishes while we're still running, we'll terminate as well.
        """
        if service.is_running:
            raise ValidationError(
                "Can't start daemon {}, child of {}: it's already running".format(repr(service), repr(self))
            )
        elif service.is_cancelled:
            raise ValidationError(
                "Can't restart daemon {}, child of {}: it's already completed".format(repr(service), repr(self))
            )

        self._child_services.add(service)

        @functools.wraps(service.run)
        async def _run_daemon_wrapper() -> None:
            try:
                await service.run()
            except OperationCancelled:
                pass
            except Exception as e:
                self.logger.warning(
                    "Daemon Service %s finished unexpectedly: %s" % (service, e)
                )
                self.logger.debug("Daemon Service failure traceback")
            finally:
                if not self.is_cancelled:
                    self.logger.debug(
                        "%s finished while %s is still running, terminating as well" %
                        (service, self)
                    )
                    self.cancel_token.trigger()

        self.run_task(_run_daemon_wrapper())

    def call_later(
        self, delay: float, callback: "Callable[..., None]", *args: Any
    ) -> None:
        @functools.wraps(callback)
        async def _call_later_wrapped() -> None:
            await self.sleep(delay)
            callback(*args)

        self.run_task(_call_later_wrapped())

    async def _run_in_executor(self, callback: Callable[..., Any], *args: Any) -> Any:
        loop = self.get_event_loop()
        return await self.wait(loop.run_in_executor(self._executor, callback, *args))

    async def cleanup(self) -> None:
        """
        Run the ``_cleanup()`` coroutine and set the ``cleaned_up`` event after the service as
        well as all child services finished their cleanup.

        The ``_cleanup()`` coroutine is invoked before the child services may have finished
        their cleanup.
        """
        if self._child_services:
            self.logger.debug(
                "Waiting for child services: %s" % list(self._child_services)
            )
            await asyncio.gather(
                *[
                    child_service.events.cleaned_up.wait()
                    for child_service in self._child_services
                ]
            )
            self.logger.debug("All child services finished")
        if self._tasks:
            self.logger.debug("Waiting for tasks: %s" % list(self._tasks))
            await asyncio.gather(*self._tasks)
            self.logger.debug("All tasks finished")

        await self._cleanup()
        self.events.cleaned_up.set()

    def cancel_nowait(self) -> None:
        if self.is_cancelled:
            self.logger.warning(
                "Tried to cancel %s, but it was already cancelled" % self
            )
            return
        elif not self.is_running:
            raise ValidationError("Cannot cancel a service that has not been started")

        self.logger.debug("Cancelling %s" % self)
        self.events.cancelled.set()
        self.cancel_token.trigger()

    async def cancel(self) -> None:
        """Trigger the CancelToken and wait for the cleaned_up event to be set."""
        self.cancel_nowait()

        try:
            await asyncio.wait_for(
                self.events.cleaned_up.wait(), timeout=self._wait_until_finished_timeout
            )
        except asyncio.futures.TimeoutError:
            self.logger.info(
                "Timed out waiting for %s to finish its cleanup, forcibly cancelling pending "
                "tasks and exiting anyway" %
                self,
            )
            if self._tasks:
                self.logger.debug("Pending tasks: %s" % list(self._tasks))
            if self._child_services:
                self.logger.debug(
                    "Pending child services: %s" % list(self._child_services)
                )
            self._forcibly_cancel_all_tasks()
            # Sleep a bit because the Future.cancel() method just schedules the callbacks, so we
            # need to give the event loop a chance to actually call them.
            await asyncio.sleep(0.5)
        else:
            self.logger.debug("%s finished cleanly" % self)

    def _forcibly_cancel_all_tasks(self) -> None:
        for task in self._tasks:
            task.cancel()

    @property
    def is_cancelled(self) -> bool:
        return self.cancel_token.triggered

    @property
    def is_operational(self) -> bool:
        return self.events.started.is_set() and not self.cancel_token.triggered

    @property
    def is_running(self) -> bool:
        return self._run_lock.locked()

    async def threadsafe_cancel(self) -> None:
        """
        Cancel service in another thread. Block until service is cleaned up.

        :param poll_period: how many seconds to wait in between each check for service cleanup
        """
        asyncio.run_coroutine_threadsafe(self.cancel(), loop=self.get_event_loop())
        await asyncio.wait_for(
            self.events.cleaned_up.wait(), timeout=self._wait_until_finished_timeout
        )

    async def sleep(self, delay: float) -> None:
        """Coroutine that completes after a given time (in seconds)."""
        await self.wait(asyncio.sleep(delay))

    @abstractmethod
    async def _run(self) -> None:
        """Run the service's loop.

        Should return or raise OperationCancelled when the CancelToken is triggered.
        """
        raise NotImplementedError()

    async def _cleanup(self) -> None:
        """Clean up any resources held by this service.

        Called after the service's _run() method returns.
        """
        pass

    def gc(self) -> None:
        for cs in self._child_services.copy():
            if cs.events.finished.is_set():
                self._child_services.remove(cs)
        for t in self._tasks.copy():
            if t.done():
                self._tasks.remove(t)
Ejemplo n.º 21
0
class TestWeakSet(unittest.TestCase):
    def setUp(self):
        self.items = [ustr(c) for c in ('a', 'b', 'c')]
        self.items2 = [ustr(c) for c in ('x', 'y', 'z')]
        self.ab_items = [ustr(c) for c in 'ab']
        self.abcde_items = [ustr(c) for c in 'abcde']
        self.def_items = [ustr(c) for c in 'def']
        self.ab_weakset = WeakSet(self.ab_items)
        self.abcde_weakset = WeakSet(self.abcde_items)
        self.def_weakset = WeakSet(self.def_items)
        self.letters = [ustr(c) for c in string.ascii_letters]
        self.s = WeakSet(self.items)
        self.d = dict.fromkeys(self.items)
        self.obj = ustr('F')
        self.fs = WeakSet([self.obj])

    def test_methods(self):
        weaksetmethods = dir(WeakSet)
        for method in dir(set):
            if method == 'test_c_api' or method.startswith('_'):
                continue
            self.assertIn(method, weaksetmethods,
                          'WeakSet missing method ' + method)

    def test_new_or_init(self):
        self.assertRaises(TypeError, WeakSet, [], 2)

    def test_len(self):
        self.assertEqual(len(self.s), len(self.d))
        self.assertEqual(len(self.fs), 1)
        del self.obj
        self.assertEqual(len(self.fs), 0)

    def test_contains(self):
        for c in self.letters:
            self.assertEqual(c in self.s, c in self.d)
        self.assertNotIn(1, self.s)
        self.assertIn(self.obj, self.fs)
        del self.obj
        self.assertNotIn(ustr('F'), self.fs)

    def test_union(self):
        u = self.s.union(self.items2)
        for c in self.letters:
            self.assertEqual(c in u, c in self.d or c in self.items2)
        self.assertEqual(self.s, WeakSet(self.items))
        self.assertEqual(type(u), WeakSet)
        self.assertRaises(TypeError, self.s.union, [[]])
        for C in (set, frozenset, dict.fromkeys, list, tuple):
            x = WeakSet(self.items + self.items2)
            c = C(self.items2)
            self.assertEqual(self.s.union(c), x)
            del c
        self.assertEqual(len(u), len(self.items) + len(self.items2))
        self.items2.pop()
        gc.collect()
        self.assertEqual(len(u), len(self.items) + len(self.items2))

    def test_or(self):
        i = self.s.union(self.items2)
        self.assertEqual(self.s | set(self.items2), i)
        self.assertEqual(self.s | frozenset(self.items2), i)

    def test_intersection(self):
        s = WeakSet(self.letters)
        i = s.intersection(self.items2)
        for c in self.letters:
            self.assertEqual(c in i, c in self.items2 and c in self.letters)
        self.assertEqual(s, WeakSet(self.letters))
        self.assertEqual(type(i), WeakSet)
        for C in (set, frozenset, dict.fromkeys, list, tuple):
            x = WeakSet([])
            self.assertEqual(i.intersection(C(self.items)), x)
        self.assertEqual(len(i), len(self.items2))
        self.items2.pop()
        gc.collect()
        self.assertEqual(len(i), len(self.items2))

    def test_isdisjoint(self):
        self.assertTrue(self.s.isdisjoint(WeakSet(self.items2)))
        self.assertTrue(not self.s.isdisjoint(WeakSet(self.letters)))

    def test_and(self):
        i = self.s.intersection(self.items2)
        self.assertEqual(self.s & set(self.items2), i)
        self.assertEqual(self.s & frozenset(self.items2), i)

    def test_difference(self):
        i = self.s.difference(self.items2)
        for c in self.letters:
            self.assertEqual(c in i, c in self.d and c not in self.items2)
        self.assertEqual(self.s, WeakSet(self.items))
        self.assertEqual(type(i), WeakSet)
        self.assertRaises(TypeError, self.s.difference, [[]])

    def test_sub(self):
        i = self.s.difference(self.items2)
        self.assertEqual(self.s - set(self.items2), i)
        self.assertEqual(self.s - frozenset(self.items2), i)

    def test_symmetric_difference(self):
        i = self.s.symmetric_difference(self.items2)
        for c in self.letters:
            self.assertEqual(c in i, (c in self.d) ^ (c in self.items2))
        self.assertEqual(self.s, WeakSet(self.items))
        self.assertEqual(type(i), WeakSet)
        self.assertRaises(TypeError, self.s.symmetric_difference, [[]])
        self.assertEqual(len(i), len(self.items) + len(self.items2))
        self.items2.pop()
        gc.collect()
        self.assertEqual(len(i), len(self.items) + len(self.items2))

    def test_xor(self):
        i = self.s.symmetric_difference(self.items2)
        self.assertEqual(self.s ^ set(self.items2), i)
        self.assertEqual(self.s ^ frozenset(self.items2), i)

    def test_sub_and_super(self):
        self.assertTrue(self.ab_weakset <= self.abcde_weakset)
        self.assertTrue(self.abcde_weakset <= self.abcde_weakset)
        self.assertTrue(self.abcde_weakset >= self.ab_weakset)
        self.assertFalse(self.abcde_weakset <= self.def_weakset)
        self.assertFalse(self.abcde_weakset >= self.def_weakset)
        self.assertTrue(set('a').issubset('abc'))
        self.assertTrue(set('abc').issuperset('a'))
        self.assertFalse(set('a').issubset('cbs'))
        self.assertFalse(set('cbs').issuperset('a'))

    def test_lt(self):
        self.assertTrue(self.ab_weakset < self.abcde_weakset)
        self.assertFalse(self.abcde_weakset < self.def_weakset)
        self.assertFalse(self.ab_weakset < self.ab_weakset)
        self.assertFalse(WeakSet() < WeakSet())

    def test_gt(self):
        self.assertTrue(self.abcde_weakset > self.ab_weakset)
        self.assertFalse(self.abcde_weakset > self.def_weakset)
        self.assertFalse(self.ab_weakset > self.ab_weakset)
        self.assertFalse(WeakSet() > WeakSet())

    def test_gc(self):
        s = WeakSet(Foo() for i in range(1000))
        for elem in s:
            elem.cycle = s
            elem.sub = elem
            elem.set = WeakSet([elem])

    def test_subclass_with_custom_hash(self):
        class H(WeakSet):
            def __hash__(self):
                return int(id(self) & 2147483647)

        s = H()
        f = set()
        f.add(s)
        self.assertIn(s, f)
        f.remove(s)
        f.add(s)
        f.discard(s)

    def test_init(self):
        s = WeakSet()
        s.__init__(self.items)
        self.assertEqual(s, self.s)
        s.__init__(self.items2)
        self.assertEqual(s, WeakSet(self.items2))
        self.assertRaises(TypeError, s.__init__, s, 2)
        self.assertRaises(TypeError, s.__init__, 1)

    def test_constructor_identity(self):
        s = WeakSet(self.items)
        t = WeakSet(s)
        self.assertNotEqual(id(s), id(t))

    def test_hash(self):
        self.assertRaises(TypeError, hash, self.s)

    def test_clear(self):
        self.s.clear()
        self.assertEqual(self.s, WeakSet([]))
        self.assertEqual(len(self.s), 0)

    def test_copy(self):
        dup = self.s.copy()
        self.assertEqual(self.s, dup)
        self.assertNotEqual(id(self.s), id(dup))

    def test_add(self):
        x = ustr('Q')
        self.s.add(x)
        self.assertIn(x, self.s)
        dup = self.s.copy()
        self.s.add(x)
        self.assertEqual(self.s, dup)
        self.assertRaises(TypeError, self.s.add, [])
        self.fs.add(Foo())
        self.assertTrue(len(self.fs) == 1)
        self.fs.add(self.obj)
        self.assertTrue(len(self.fs) == 1)

    def test_remove(self):
        x = ustr('a')
        self.s.remove(x)
        self.assertNotIn(x, self.s)
        self.assertRaises(KeyError, self.s.remove, x)
        self.assertRaises(TypeError, self.s.remove, [])

    def test_discard(self):
        a, q = ustr('a'), ustr('Q')
        self.s.discard(a)
        self.assertNotIn(a, self.s)
        self.s.discard(q)
        self.assertRaises(TypeError, self.s.discard, [])

    def test_pop(self):
        for i in range(len(self.s)):
            elem = self.s.pop()
            self.assertNotIn(elem, self.s)
        self.assertRaises(KeyError, self.s.pop)

    def test_update(self):
        retval = self.s.update(self.items2)
        self.assertEqual(retval, None)
        for c in (self.items + self.items2):
            self.assertIn(c, self.s)
        self.assertRaises(TypeError, self.s.update, [[]])

    def test_update_set(self):
        self.s.update(set(self.items2))
        for c in (self.items + self.items2):
            self.assertIn(c, self.s)

    def test_ior(self):
        self.s |= set(self.items2)
        for c in (self.items + self.items2):
            self.assertIn(c, self.s)

    def test_intersection_update(self):
        retval = self.s.intersection_update(self.items2)
        self.assertEqual(retval, None)
        for c in (self.items + self.items2):
            if c in self.items2 and c in self.items:
                self.assertIn(c, self.s)
            else:
                self.assertNotIn(c, self.s)
        self.assertRaises(TypeError, self.s.intersection_update, [[]])

    def test_iand(self):
        self.s &= set(self.items2)
        for c in (self.items + self.items2):
            if c in self.items2 and c in self.items:
                self.assertIn(c, self.s)
            else:
                self.assertNotIn(c, self.s)

    def test_difference_update(self):
        retval = self.s.difference_update(self.items2)
        self.assertEqual(retval, None)
        for c in (self.items + self.items2):
            if c in self.items and c not in self.items2:
                self.assertIn(c, self.s)
            else:
                self.assertNotIn(c, self.s)
        self.assertRaises(TypeError, self.s.difference_update, [[]])
        self.assertRaises(TypeError, self.s.symmetric_difference_update, [[]])

    def test_isub(self):
        self.s -= set(self.items2)
        for c in (self.items + self.items2):
            if c in self.items and c not in self.items2:
                self.assertIn(c, self.s)
            else:
                self.assertNotIn(c, self.s)

    def test_symmetric_difference_update(self):
        retval = self.s.symmetric_difference_update(self.items2)
        self.assertEqual(retval, None)
        for c in (self.items + self.items2):
            if (c in self.items) ^ (c in self.items2):
                self.assertIn(c, self.s)
            else:
                self.assertNotIn(c, self.s)
        self.assertRaises(TypeError, self.s.symmetric_difference_update, [[]])

    def test_ixor(self):
        self.s ^= set(self.items2)
        for c in (self.items + self.items2):
            if (c in self.items) ^ (c in self.items2):
                self.assertIn(c, self.s)
            else:
                self.assertNotIn(c, self.s)

    def test_inplace_on_self(self):
        t = self.s.copy()
        t |= t
        self.assertEqual(t, self.s)
        t &= t
        self.assertEqual(t, self.s)
        t -= t
        self.assertEqual(t, WeakSet())
        t = self.s.copy()
        t ^= t
        self.assertEqual(t, WeakSet())

    def test_eq(self):
        self.assertTrue(self.s == self.s)
        self.assertTrue(self.s == WeakSet(self.items))
        self.assertFalse(self.s == set(self.items))
        self.assertFalse(self.s == list(self.items))
        self.assertFalse(self.s == tuple(self.items))
        self.assertFalse(self.s == WeakSet([Foo]))
        self.assertFalse(self.s == 1)

    def test_ne(self):
        self.assertTrue(self.s != set(self.items))
        s1 = WeakSet()
        s2 = WeakSet()
        self.assertFalse(s1 != s2)

    def test_weak_destroy_while_iterating(self):
        items = [ustr(c) for c in ('a', 'b', 'c')]
        s = WeakSet(items)
        it = iter(s)
        next(it)
        del items[-1]
        gc.collect()
        self.assertIn(len(list(it)), [len(items), len(items) - 1])
        del it
        self.assertEqual(len(s), len(items))

    def test_weak_destroy_and_mutate_while_iterating(self):
        items = [ustr(c) for c in string.ascii_letters]
        s = WeakSet(items)

        @contextlib.contextmanager
        def testcontext():
            try:
                it = iter(s)
                yielded = ustr(str(next(it)))
                u = ustr(str(items.pop()))
                if yielded == u:
                    next(it)
                gc.collect()
                yield u
            finally:
                it = None

        with testcontext() as u:
            self.assertNotIn(u, s)
        with testcontext() as u:
            self.assertRaises(KeyError, s.remove, u)
        self.assertNotIn(u, s)
        with testcontext() as u:
            s.add(u)
        self.assertIn(u, s)
        t = s.copy()
        with testcontext() as u:
            s.update(t)
        self.assertEqual(len(s), len(t))
        with testcontext() as u:
            s.clear()
        self.assertEqual(len(s), 0)

    def test_len_cycles(self):
        N = 20
        items = [RefCycle() for i in range(N)]
        s = WeakSet(items)
        del items
        it = iter(s)
        try:
            next(it)
        except StopIteration:
            pass
        gc.collect()
        n1 = len(s)
        del it
        gc.collect()
        n2 = len(s)
        self.assertIn(n1, (0, 1))
        self.assertEqual(n2, 0)

    def test_len_race(self):
        self.addCleanup(gc.set_threshold, *gc.get_threshold())
        for th in range(1, 100):
            N = 20
            gc.collect(0)
            gc.set_threshold(th, th, th)
            items = [RefCycle() for i in range(N)]
            s = WeakSet(items)
            del items
            it = iter(s)
            try:
                next(it)
            except StopIteration:
                pass
            n1 = len(s)
            del it
            n2 = len(s)
            self.assertGreaterEqual(n1, 0)
            self.assertLessEqual(n1, N)
            self.assertGreaterEqual(n2, 0)
            self.assertLessEqual(n2, n1)
Ejemplo n.º 22
0
class Signal(object):
    """
    The Signalling class
    """
    def __init__(self, optimized=False):
        self._functions = WeakSet()
        self._after_functions = WeakSet()
        self._methods = WeakKeyDictionary()
        self._after_methods = WeakKeyDictionary()
        self._optimized = optimized

    def __call__(self, *args, **kargs):
        res_list = []
        # Call handler functions
        for func in self._functions:
            res = func(*args, **kargs)
            if res and self._optimized:
                return res
            res_list.append(res)

        # Call handler methods
        for obj, funcs in self._methods.items():
            for func in funcs:
                res = func(obj, *args, **kargs)
                if res and self._optimized:
                    return res
                res_list.append(res)

        for func in self._after_functions:
            res = func(*args, **kargs)
            if res and self._optimized:
                return res
            res_list.append(res)

        # Call handler methods
        for obj, funcs in self._after_methods.items():
            for func in funcs:
                res = func(obj, *args, **kargs)
                if res and self._optimized:
                    return res
                res_list.append(res)

        if self._optimized:
            return None

        return res_list

    def connect(self, slot):
        """
        @slot: The method to be called on signal emission

        Connects to @slot
        """
        if inspect.ismethod(slot):
            if slot.__self__ not in self._methods:
                self._methods[slot.__self__] = set()

            self._methods[slot.__self__].add(slot.__func__)

        else:
            self._functions.add(slot)

    def connect_after(self, slot):
        """
        @slot: The method to be called at last stage of signal emission

        Connects to the signal after the signals has been handled by other
        connect callbacks.
        """
        if inspect.ismethod(slot):
            if slot.__self__ not in self._after_methods:
                self._after_methods[slot.__self__] = set()

            self._after_methods[slot.__self__].add(slot.__func__)

        else:
            self._after_functions.add(slot)

    def disconnect(self, slot):
        """
        Disconnect @slot from the signal
        """
        if inspect.ismethod(slot):
            if slot.__self__ in self._methods:
                self._methods[slot.__self__].remove(slot.__func__)
            elif slot.__self__ in self._after_methods:
                self._after_methods[slot.__self__].remove(slot.__func__)
        else:
            if slot in self._functions:
                self._functions.remove(slot)
            elif slot in self._after_functions:
                self._after_functions.remove(slot)

    def clear(self):
        """
        Cleanup the signal
        """
        self._functions.clear()
        self._methods.clear()
        self._after_functions.clear()
        self._after_methods.clear()
Ejemplo n.º 23
0
class ElementObject:
    def __init__(self, parent, type, save_id=None):
        self.__parent = ref(parent)
        self.__type = type
        self.__data = type.ufl_type.build_default(
            ElementValueGenerator(parent, type))
        self.__connections = []
        self.__children = []
        self.__diagrams = []
        self.__visuals = WeakSet()
        self.__cache = ModelTemporaryDataCache(None)
        if save_id is None:
            self.__save_id = uuid4()
        else:
            self.__save_id = save_id

    def add_visual(self, visual):
        if visual.object is not self:
            raise Exception
        self.__visuals.add(visual)

    def remove_visual(self, visual):
        self.__visuals.remove(visual)

    @property
    def visuals(self):
        yield from self.__visuals

    @property
    def cache(self):
        return self.__cache

    @property
    def parent(self):
        return self.__parent()

    def change_parent(self, new_parent, new_index):
        if self.project is not new_parent and self.project is not new_parent.project:
            raise Exception

        self.__notify_node_change_parent(0)
        self.__parent().remove_child(self)
        self.__parent = ref(new_parent)
        self.__parent().add_child(self, new_index)
        self.__notify_node_change_children(0)

    @property
    def type(self):
        return self.__type

    @property
    def data(self):
        return self.__data

    @property
    def connections(self):
        yield from self.__connections

    def get_display_name(self):
        return self.__type.get_display_name(self)

    def create_appearance_object(self, ruler):
        return self.__type.create_appearance_object(self, ruler)

    def connect_with(self, connection_type, second_element, save_id=None):
        connection = ConnectionObject(connection_type, self, second_element,
                                      save_id)
        self.__connections.append(connection)
        if second_element is not self:
            second_element.__connections.append(connection)
        return connection

    def get_connections_to(self, element):
        for connection in self.__connections:
            if connection.is_connected_with(element):
                yield connection

    def add_connection(self, connection):
        if not connection.is_connected_with(self):
            raise Exception

        if connection in self.__connections:
            raise Exception

        self.__connections.append(connection)

    def remove_connection(self, connection):
        if not connection.is_connected_with(self):
            raise Exception

        if connection not in self.__connections:
            raise Exception

        self.__connections.remove(connection)

    def reconnect(self, connection):
        if connection in self.__connections:
            raise Exception
        if not connection.is_connected_with(self):
            raise Exception
        self.__connections.append(connection)
        other = connection.get_other_end(self)
        if other is not self:
            other.__connections.append(connection)

    def disconnect(self, connection):
        if connection not in self.__connections:
            raise Exception
        self.__connections.remove(connection)
        other = connection.get_other_end(self)
        if other is not self:
            other.__connections.remove(connection)

    @property
    def project(self):
        if isinstance(self.__parent(), ElementObject):
            return self.__parent().project
        else:
            return self.__parent()

    @property
    def children_count(self):
        return len(self.__children)

    @property
    def children(self):
        yield from self.__children

    @property
    def diagram_count(self):
        return len(self.__diagrams)

    @property
    def diagrams(self):
        yield from self.__diagrams

    @property
    def save_id(self):
        return self.__save_id

    def create_child_element(self, type, save_id=None):
        obj = ElementObject(self, type, save_id)
        self.__children.append(obj)
        self.__notify_node_change_parent(0)
        self.__notify_node_change_children(0)
        return obj

    def create_child_diagram(self, type, save_id=None):
        from ..diagram import Diagram  # circular imports

        diagram = Diagram(self, type, save_id)
        self.__diagrams.append(diagram)
        return diagram

    def get_child_index(self, obj):
        if isinstance(obj, ElementObject):
            return self.__children.index(obj)
        else:
            return self.__diagrams.index(obj)

    def add_child(self, obj, index=None):
        if obj.parent is not self:
            raise Exception
        if isinstance(obj, ElementObject):
            if obj in self.__children:
                raise Exception
            if index is None:
                self.__children.append(obj)
            else:
                self.__children.insert(index, obj)
            self.__notify_node_change_parent(0)
            self.__notify_node_change_children(0)
        else:
            if obj in self.__diagrams:
                raise Exception
            if index is None:
                self.__diagrams.append(obj)
            else:
                self.__diagrams.insert(index, obj)

    def remove_child(self, obj):
        if obj.parent is not self:
            raise Exception
        if isinstance(obj, ElementObject):
            if obj not in self.__children:
                raise Exception
            self.__children.remove(obj)
            self.__notify_node_change_parent(0)
            self.__notify_node_change_children(0)
        else:
            if obj not in self.__diagrams:
                raise Exception
            self.__diagrams.remove(obj)

    def apply_ufl_patch(self, patch):
        self.__data.apply_patch(patch)
        self.__cache.refresh()

    @property
    def has_ufl_dialog(self):
        return self.__type.ufl_type.has_attributes

    def create_ufl_dialog(self, options=UflDialogOptions.standard):
        if not self.__type.ufl_type.has_attributes:
            raise Exception
        dialog = UflDialog(self.__type.ufl_type, options)
        dialog.associate(self.__data)
        return dialog

    def __notify_node_change_parent(self, depth):
        if depth <= self.__type.node_access_depth.parent:
            self.__cache.refresh()

        parent = self.__parent()
        if isinstance(parent, ElementObject):
            parent.__notify_node_change_parent(depth + 1)

    def __notify_node_change_children(self, depth):
        if depth <= self.__type.node_access_depth.child:
            self.__cache.refresh()

        for child in self.__children:
            child.__notify_node_change_children(depth + 1)

    def invalidate_all_caches(self):
        self.__cache.invalidate()

        for element in self.__children:
            element.invalidate_all_caches()

        for connection in self.__connections:
            connection.cache.invalidate()
Ejemplo n.º 24
0
class Signal:
    ##  Signal types.
    #   These indicate the type of a signal, that is, how the signal handles calling the connected
    #   slots.
    #   - Direct connections immediately call the connected slots from the thread that called emit().
    #   - Auto connections will push the call onto the event loop if the current thread is
    #     not the main thread, but make a direct call if it is.
    #   - Queued connections will always push
    #     the call on to the event loop.
    Direct = 1
    Auto = 2
    Queued = 3

    ##  Initialize the instance.
    #
    #   \param kwargs Keyword arguments.
    #                 Possible keywords:
    #                 - type: The signal type. Defaults to Direct.
    def __init__(self, **kwargs):
        self.__functions = WeakSet()
        self.__methods = WeakKeyDictionary()
        self.__signals = WeakSet()
        self.__type = kwargs.get("type", Signal.Auto)

        self.__emitting = False
        self.__connect_queue = []
        self.__disconnect_queue = []

    ##  \exception NotImplementedError
    def __call__(self):
        raise NotImplementedError("Call emit() to emit a signal")

    ##  Get type of the signal
    #   \return \type{int} Direct(1), Auto(2) or Queued(3)
    def getType(self):
        return self.__type

    ##  Emit the signal which indirectly calls all of the connected slots.
    #
    #   \param args The positional arguments to pass along.
    #   \param kargs The keyword arguments to pass along.
    #
    #   \note If the Signal type is Queued and this is not called from the application thread
    #   the call will be posted as an event to the application main thread, which means the
    #   function will be called on the next application event loop tick.
    def emit(self, *args, **kargs):
        try:
            if self.__type == Signal.Queued:
                Signal._app.functionEvent(
                    CallFunctionEvent(self.emit, args, kargs))
                return

            if self.__type == Signal.Auto:
                if threading.current_thread() is not Signal._app.getMainThread(
                ):
                    Signal._app.functionEvent(
                        CallFunctionEvent(self.emit, args, kargs))
                    return
        except AttributeError:  # If Signal._app is not set
            return

        self.__emitting = True

        # Call handler functions
        for func in self.__functions:
            func(*args, **kargs)

        # Call handler methods
        for dest, funcs in self.__methods.items():
            for func in funcs:
                func(dest, *args, **kargs)

        # Emit connected signals
        for signal in self.__signals:
            signal.emit(*args, **kargs)

        self.__emitting = False
        for connector in self.__connect_queue:
            self.connect(connector)
        self.__connect_queue.clear()
        for connector in self.__disconnect_queue:
            self.disconnect(connector)
        self.__connect_queue.clear()

    ##  Connect to this signal.
    #   \param connector The signal or slot (function) to connect.
    def connect(self, connector):
        if self.__emitting:
            # When we try to connect to a signal we change the dictionary of connectors.
            # This will cause an Exception since we are iterating over a dictionary that changed.
            # So instead, defer the connections until after we are done emitting.
            self.__connect_queue.append(connector)
            return

        if type(connector) == Signal:
            if connector == self:
                return
            self.__signals.add(connector)
        elif inspect.ismethod(connector):
            if connector.__self__ not in self.__methods:
                self.__methods[connector.__self__] = set()

            self.__methods[connector.__self__].add(connector.__func__)
        else:
            self.__functions.add(connector)

    ##  Disconnect from this signal.
    #   \param connector The signal or slot (function) to disconnect.
    def disconnect(self, connector):
        if self.__emitting:
            # See above.
            self.__disconnect_queue.append(connector)
            return

        try:
            if connector in self.__signals:
                self.__signals.remove(connector)
            elif inspect.ismethod(
                    connector) and connector.__self__ in self.__methods:
                self.__methods[connector.__self__].remove(connector.__func__)
            else:
                if connector in self.__functions:
                    self.__functions.remove(connector)

        except KeyError:  #Ignore errors when connector is not connected to this signal.
            pass

    ##  Disconnect all connected slots.
    def disconnectAll(self):
        if self.__emitting:
            raise RuntimeError(
                "Tried to disconnect signal while signal is being emitted")

        self.__functions.clear()
        self.__methods.clear()
        self.__signals.clear()

    ##  private:

    #   To avoid circular references when importing Application, this should be
    #   set by the Application instance.
    _app = None
Ejemplo n.º 25
0
class TestWeakSet(unittest.TestCase):

    def setUp(self):
        # need to keep references to them
        self.items = [ustr(c) for c in ('a', 'b', 'c')]
        self.items2 = [ustr(c) for c in ('x', 'y', 'z')]
        self.letters = [ustr(c) for c in string.ascii_letters]
        self.s = WeakSet(self.items)
        self.d = dict.fromkeys(self.items)
        self.obj = ustr('F')
        self.fs = WeakSet([self.obj])

    def test_methods(self):
        weaksetmethods = dir(WeakSet)
        for method in dir(set):
            if method == 'test_c_api' or method.startswith('_'):
                continue
            self.assert_(method in weaksetmethods,
                         "WeakSet missing method " + method)

    def test_new_or_init(self):
        self.assertRaises(TypeError, WeakSet, [], 2)

    def test_len(self):
        self.assertEqual(len(self.s), len(self.d))
        self.assertEqual(len(self.fs), 1)
        del self.obj
        self.assertEqual(len(self.fs), 0)

    def test_contains(self):
        for c in self.letters:
            self.assertEqual(c in self.s, c in self.d)
        self.assertRaises(TypeError, self.s.__contains__, [[]])
        self.assert_(self.obj in self.fs)
        del self.obj
        self.assert_(ustr('F') not in self.fs)

    def test_union(self):
        u = self.s.union(self.items2)
        for c in self.letters:
            self.assertEqual(c in u, c in self.d or c in self.items2)
        self.assertEqual(self.s, WeakSet(self.items))
        self.assertEqual(type(u), WeakSet)
        self.assertRaises(TypeError, self.s.union, [[]])
        for C in set, frozenset, dict.fromkeys, list, tuple:
            x = WeakSet(self.items + self.items2)
            c = C(self.items2)
            self.assertEqual(self.s.union(c), x)

    def test_or(self):
        i = self.s.union(self.items2)
        self.assertEqual(self.s | set(self.items2), i)
        self.assertEqual(self.s | frozenset(self.items2), i)

    def test_intersection(self):
        i = self.s.intersection(self.items2)
        for c in self.letters:
            self.assertEqual(c in i, c in self.d and c in self.items2)
        self.assertEqual(self.s, WeakSet(self.items))
        self.assertEqual(type(i), WeakSet)
        for C in set, frozenset, dict.fromkeys, list, tuple:
            x = WeakSet([])
            self.assertEqual(self.s.intersection(C(self.items2)), x)

    def test_isdisjoint(self):
        self.assert_(self.s.isdisjoint(WeakSet(self.items2)))
        self.assert_(not self.s.isdisjoint(WeakSet(self.letters)))

    def test_and(self):
        i = self.s.intersection(self.items2)
        self.assertEqual(self.s & set(self.items2), i)
        self.assertEqual(self.s & frozenset(self.items2), i)

    def test_difference(self):
        i = self.s.difference(self.items2)
        for c in self.letters:
            self.assertEqual(c in i, c in self.d and c not in self.items2)
        self.assertEqual(self.s, WeakSet(self.items))
        self.assertEqual(type(i), WeakSet)
        self.assertRaises(TypeError, self.s.difference, [[]])

    def test_sub(self):
        i = self.s.difference(self.items2)
        self.assertEqual(self.s - set(self.items2), i)
        self.assertEqual(self.s - frozenset(self.items2), i)

    def test_symmetric_difference(self):
        i = self.s.symmetric_difference(self.items2)
        for c in self.letters:
            self.assertEqual(c in i, (c in self.d) ^ (c in self.items2))
        self.assertEqual(self.s, WeakSet(self.items))
        self.assertEqual(type(i), WeakSet)
        self.assertRaises(TypeError, self.s.symmetric_difference, [[]])

    def test_xor(self):
        i = self.s.symmetric_difference(self.items2)
        self.assertEqual(self.s ^ set(self.items2), i)
        self.assertEqual(self.s ^ frozenset(self.items2), i)

    def test_sub_and_super(self):
        pl, ql, rl = map(lambda s: [ustr(c) for c in s], ['ab', 'abcde', 'def'])
        p, q, r = map(WeakSet, (pl, ql, rl))
        self.assert_(p < q)
        self.assert_(p <= q)
        self.assert_(q <= q)
        self.assert_(q > p)
        self.assert_(q >= p)
        self.failIf(q < r)
        self.failIf(q <= r)
        self.failIf(q > r)
        self.failIf(q >= r)
        self.assert_(set('a').issubset('abc'))
        self.assert_(set('abc').issuperset('a'))
        self.failIf(set('a').issubset('cbs'))
        self.failIf(set('cbs').issuperset('a'))

    def test_gc(self):
        # Create a nest of cycles to exercise overall ref count check
        class A:
            pass
        s = set(A() for i in range(1000))
        for elem in s:
            elem.cycle = s
            elem.sub = elem
            elem.set = set([elem])

    def test_subclass_with_custom_hash(self):
        # Bug #1257731
        class H(WeakSet):
            def __hash__(self):
                return int(id(self) & 0x7fffffff)
        s=H()
        f=set()
        f.add(s)
        self.assert_(s in f)
        f.remove(s)
        f.add(s)
        f.discard(s)

    def test_init(self):
        s = WeakSet()
        s.__init__(self.items)
        self.assertEqual(s, self.s)
        s.__init__(self.items2)
        self.assertEqual(s, WeakSet(self.items2))
        self.assertRaises(TypeError, s.__init__, s, 2);
        self.assertRaises(TypeError, s.__init__, 1);

    def test_constructor_identity(self):
        s = WeakSet(self.items)
        t = WeakSet(s)
        self.assertNotEqual(id(s), id(t))

    def test_set_literal(self):
        s = set([1,2,3])
        t = {1,2,3}
        self.assertEqual(s, t)

    def test_hash(self):
        self.assertRaises(TypeError, hash, self.s)

    def test_clear(self):
        self.s.clear()
        self.assertEqual(self.s, set())
        self.assertEqual(len(self.s), 0)

    def test_copy(self):
        dup = self.s.copy()
        self.assertEqual(self.s, dup)
        self.assertNotEqual(id(self.s), id(dup))

    def test_add(self):
        x = ustr('Q')
        self.s.add(x)
        self.assert_(x in self.s)
        dup = self.s.copy()
        self.s.add(x)
        self.assertEqual(self.s, dup)
        self.assertRaises(TypeError, self.s.add, [])
        self.fs.add(Foo())
        self.assert_(len(self.fs) == 1)
        self.fs.add(self.obj)
        self.assert_(len(self.fs) == 1)

    def test_remove(self):
        x = ustr('a')
        self.s.remove(x)
        self.assert_(x not in self.s)
        self.assertRaises(KeyError, self.s.remove, x)
        self.assertRaises(TypeError, self.s.remove, [])

    def test_discard(self):
        a, q = ustr('a'), ustr('Q')
        self.s.discard(a)
        self.assert_(a not in self.s)
        self.s.discard(q)
        self.assertRaises(TypeError, self.s.discard, [])

    def test_pop(self):
        for i in range(len(self.s)):
            elem = self.s.pop()
            self.assert_(elem not in self.s)
        self.assertRaises(KeyError, self.s.pop)

    def test_update(self):
        retval = self.s.update(self.items2)
        self.assertEqual(retval, None)
        for c in (self.items + self.items2):
            self.assert_(c in self.s)
        self.assertRaises(TypeError, self.s.update, [[]])

    def test_update_set(self):
        self.s.update(set(self.items2))
        for c in (self.items + self.items2):
            self.assert_(c in self.s)

    def test_ior(self):
        self.s |= set(self.items2)
        for c in (self.items + self.items2):
            self.assert_(c in self.s)

    def test_intersection_update(self):
        retval = self.s.intersection_update(self.items2)
        self.assertEqual(retval, None)
        for c in (self.items + self.items2):
            if c in self.items2 and c in self.items:
                self.assert_(c in self.s)
            else:
                self.assert_(c not in self.s)
        self.assertRaises(TypeError, self.s.intersection_update, [[]])

    def test_iand(self):
        self.s &= set(self.items2)
        for c in (self.items + self.items2):
            if c in self.items2 and c in self.items:
                self.assert_(c in self.s)
            else:
                self.assert_(c not in self.s)

    def test_difference_update(self):
        retval = self.s.difference_update(self.items2)
        self.assertEqual(retval, None)
        for c in (self.items + self.items2):
            if c in self.items and c not in self.items2:
                self.assert_(c in self.s)
            else:
                self.assert_(c not in self.s)
        self.assertRaises(TypeError, self.s.difference_update, [[]])
        self.assertRaises(TypeError, self.s.symmetric_difference_update, [[]])

    def test_isub(self):
        self.s -= set(self.items2)
        for c in (self.items + self.items2):
            if c in self.items and c not in self.items2:
                self.assert_(c in self.s)
            else:
                self.assert_(c not in self.s)

    def test_symmetric_difference_update(self):
        retval = self.s.symmetric_difference_update(self.items2)
        self.assertEqual(retval, None)
        for c in (self.items + self.items2):
            if (c in self.items) ^ (c in self.items2):
                self.assert_(c in self.s)
            else:
                self.assert_(c not in self.s)
        self.assertRaises(TypeError, self.s.symmetric_difference_update, [[]])

    def test_ixor(self):
        self.s ^= set(self.items2)
        for c in (self.items + self.items2):
            if (c in self.items) ^ (c in self.items2):
                self.assert_(c in self.s)
            else:
                self.assert_(c not in self.s)

    def test_inplace_on_self(self):
        t = self.s.copy()
        t |= t
        self.assertEqual(t, self.s)
        t &= t
        self.assertEqual(t, self.s)
        t -= t
        self.assertEqual(t, WeakSet())
        t = self.s.copy()
        t ^= t
        self.assertEqual(t, WeakSet())
Ejemplo n.º 26
0
class Signal:
    ##  Signal types.
    #   These indicate the type of a signal, that is, how the signal handles calling the connected
    #   slots. 
    #   - Direct connections immediately call the connected slots from the thread that called emit(). 
    #   - Auto connections will push the call onto the event loop if the current thread is
    #     not the main thread, but make a direct call if it is. 
    #   - Queued connections will always push
    #     the call on to the event loop.
    Direct = 1
    Auto = 2
    Queued = 3

    ##  Initialize the instance.
    #
    #   \param kwargs Keyword arguments.
    #                 Possible keywords:
    #                 - type: The signal type. Defaults to Direct.
    def __init__(self, **kwargs):
        self.__functions = WeakSet()
        self.__methods = WeakKeyDictionary()
        self.__signals = WeakSet()
        self.__type = kwargs.get("type", Signal.Auto)
    
    ##  \exception NotImplementedError
    def __call__(self):
        raise NotImplementedError("Call emit() to emit a signal")
    
    ##  Get type of the signal
    #   \return \type{int} Direct(1), Auto(2) or Queued(3)
    def getType(self):
        return self.__type

    ##  Emit the signal which indirectly calls all of the connected slots.
    #
    #   \param args The positional arguments to pass along.
    #   \param kargs The keyword arguments to pass along.
    #
    #   \note If the Signal type is Queued and this is not called from the application thread
    #   the call will be posted as an event to the application main thread, which means the
    #   function will be called on the next application event loop tick.
    def emit(self, *args, **kargs):
        try:
            if self.__type == Signal.Queued:
                Signal._app.functionEvent(CallFunctionEvent(self.emit, args, kargs))
                return

            if self.__type == Signal.Auto:
                if threading.current_thread() is not Signal._app.getMainThread():
                    Signal._app.functionEvent(CallFunctionEvent(self.emit, args, kargs))
                    return
        except AttributeError: # If Signal._app is not set
            return

        # Call handler functions
        for func in self.__functions:
            func(*args, **kargs)

        # Call handler methods
        for dest, funcs in self.__methods.items():
            for func in funcs:
                func(dest, *args, **kargs)

        # Emit connected signals
        for signal in self.__signals:
            signal.emit(*args, **kargs)

    ##  Connect to this signal.
    #   \param connector The signal or slot (function) to connect.
    def connect(self, connector):
        if type(connector) == Signal:
            if connector == self:
                return
            self.__signals.add(connector)
        elif inspect.ismethod(connector):
            if connector.__self__ not in self.__methods:
                self.__methods[connector.__self__] = set()

            self.__methods[connector.__self__].add(connector.__func__)
        else:
            self.__functions.add(connector)

    ##  Disconnect from this signal.
    #   \param connector The signal or slot (function) to disconnect.
    def disconnect(self, connector):
        try:
            if connector in self.__signals:
                self.__signals.remove(connector)
            elif inspect.ismethod(connector) and connector.__self__ in self.__methods:
                self.__methods[connector.__self__].remove(connector.__func__)
            else:
                if connector in self.__functions:
                    self.__functions.remove(connector)

        except KeyError: #Ignore errors when connector is not connected to this signal.
            pass

    ##  Disconnect all connected slots.
    def disconnectAll(self):
        self.__functions.clear()
        self.__methods.clear()
        self.__signals.clear()

    ##  private:

    #   To avoid circular references when importing Application, this should be
    #   set by the Application instance.
    _app = None
Ejemplo n.º 27
0
class Signal(object):
    """
    The Signalling class
    """
    def __init__(self, optimized=False):
        self._functions = WeakSet()
        self._after_functions = WeakSet()
        self._methods = WeakKeyDictionary()
        self._after_methods = WeakKeyDictionary()
        self._optimized = optimized

    def __call__(self, *args, **kargs):
        res_list = []
        # Call handler functions
        for func in self._functions:
            res = func(*args, **kargs)
            if res and self._optimized:
                return res
            res_list.append(res)

        # Call handler methods
        for obj, funcs in self._methods.items():
            for func in funcs:
                res = func(obj, *args, **kargs)
                if res and self._optimized:
                    return res
                res_list.append(res)

        for func in self._after_functions:
            res = func(*args, **kargs)
            if res and self._optimized:
                return res
            res_list.append(res)

        # Call handler methods
        for obj, funcs in self._after_methods.items():
            for func in funcs:
                res = func(obj, *args, **kargs)
                if res and self._optimized:
                    return res
                res_list.append(res)

        if self._optimized:
            return None

        return res_list

    def connect(self, slot):
        """
        @slot: The method to be called on signal emission

        Connects to @slot
        """
        if inspect.ismethod(slot):
            if slot.__self__ not in self._methods:
                self._methods[slot.__self__] = set()

            self._methods[slot.__self__].add(slot.__func__)

        else:
            self._functions.add(slot)

    def connect_after(self, slot):
        """
        @slot: The method to be called at last stage of signal emission

        Connects to the signal after the signals has been handled by other
        connect callbacks.
        """
        if inspect.ismethod(slot):
            if slot.__self__ not in self._after_methods:
                self._after_methods[slot.__self__] = set()

            self._after_methods[slot.__self__].add(slot.__func__)

        else:
            self._after_functions.add(slot)

    def disconnect(self, slot):
        """
        Disconnect @slot from the signal
        """
        if inspect.ismethod(slot):
            if slot.__self__ in self._methods:
                self._methods[slot.__self__].remove(slot.__func__)
            elif slot.__self__ in self._after_methods:
                self._after_methods[slot.__self__].remove(slot.__func__)
        else:
            if slot in self._functions:
                self._functions.remove(slot)
            elif slot in self._after_functions:
                self._after_functions.remove(slot)

    def clear(self):
        """
        Cleanup the signal
        """
        self._functions.clear()
        self._methods.clear()
        self._after_functions.clear()
        self._after_methods.clear()
Ejemplo n.º 28
0
class TestWeakSet(unittest.TestCase):
    def setUp(self):
        # need to keep references to them
        self.items = [ustr(c) for c in ("a", "b", "c")]
        self.items2 = [ustr(c) for c in ("x", "y", "z")]
        self.letters = [ustr(c) for c in string.ascii_letters]
        self.s = WeakSet(self.items)
        self.d = dict.fromkeys(self.items)
        self.obj = ustr("F")
        self.fs = WeakSet([self.obj])

    def test_methods(self):
        weaksetmethods = dir(WeakSet)
        for method in dir(set):
            if method == "test_c_api" or method.startswith("_"):
                continue
            self.assert_(method in weaksetmethods, "WeakSet missing method " + method)

    def test_new_or_init(self):
        self.assertRaises(TypeError, WeakSet, [], 2)

    def test_len(self):
        self.assertEqual(len(self.s), len(self.d))
        self.assertEqual(len(self.fs), 1)
        del self.obj
        self.assertEqual(len(self.fs), 0)

    def test_contains(self):
        for c in self.letters:
            self.assertEqual(c in self.s, c in self.d)
        self.assertRaises(TypeError, self.s.__contains__, [[]])
        self.assert_(self.obj in self.fs)
        del self.obj
        self.assert_(ustr("F") not in self.fs)

    def test_union(self):
        u = self.s.union(self.items2)
        for c in self.letters:
            self.assertEqual(c in u, c in self.d or c in self.items2)
        self.assertEqual(self.s, WeakSet(self.items))
        self.assertEqual(type(u), WeakSet)
        self.assertRaises(TypeError, self.s.union, [[]])
        for C in set, frozenset, dict.fromkeys, list, tuple:
            x = WeakSet(self.items + self.items2)
            c = C(self.items2)
            self.assertEqual(self.s.union(c), x)

    def test_or(self):
        i = self.s.union(self.items2)
        self.assertEqual(self.s | set(self.items2), i)
        self.assertEqual(self.s | frozenset(self.items2), i)

    def test_intersection(self):
        i = self.s.intersection(self.items2)
        for c in self.letters:
            self.assertEqual(c in i, c in self.d and c in self.items2)
        self.assertEqual(self.s, WeakSet(self.items))
        self.assertEqual(type(i), WeakSet)
        for C in set, frozenset, dict.fromkeys, list, tuple:
            x = WeakSet([])
            self.assertEqual(self.s.intersection(C(self.items2)), x)

    def test_isdisjoint(self):
        self.assert_(self.s.isdisjoint(WeakSet(self.items2)))
        self.assert_(not self.s.isdisjoint(WeakSet(self.letters)))

    def test_and(self):
        i = self.s.intersection(self.items2)
        self.assertEqual(self.s & set(self.items2), i)
        self.assertEqual(self.s & frozenset(self.items2), i)

    def test_difference(self):
        i = self.s.difference(self.items2)
        for c in self.letters:
            self.assertEqual(c in i, c in self.d and c not in self.items2)
        self.assertEqual(self.s, WeakSet(self.items))
        self.assertEqual(type(i), WeakSet)
        self.assertRaises(TypeError, self.s.difference, [[]])

    def test_sub(self):
        i = self.s.difference(self.items2)
        self.assertEqual(self.s - set(self.items2), i)
        self.assertEqual(self.s - frozenset(self.items2), i)

    def test_symmetric_difference(self):
        i = self.s.symmetric_difference(self.items2)
        for c in self.letters:
            self.assertEqual(c in i, (c in self.d) ^ (c in self.items2))
        self.assertEqual(self.s, WeakSet(self.items))
        self.assertEqual(type(i), WeakSet)
        self.assertRaises(TypeError, self.s.symmetric_difference, [[]])

    def test_xor(self):
        i = self.s.symmetric_difference(self.items2)
        self.assertEqual(self.s ^ set(self.items2), i)
        self.assertEqual(self.s ^ frozenset(self.items2), i)

    def test_sub_and_super(self):
        pl, ql, rl = map(lambda s: [ustr(c) for c in s], ["ab", "abcde", "def"])
        p, q, r = map(WeakSet, (pl, ql, rl))
        self.assert_(p < q)
        self.assert_(p <= q)
        self.assert_(q <= q)
        self.assert_(q > p)
        self.assert_(q >= p)
        self.failIf(q < r)
        self.failIf(q <= r)
        self.failIf(q > r)
        self.failIf(q >= r)
        self.assert_(set("a").issubset("abc"))
        self.assert_(set("abc").issuperset("a"))
        self.failIf(set("a").issubset("cbs"))
        self.failIf(set("cbs").issuperset("a"))

    def test_gc(self):
        # Create a nest of cycles to exercise overall ref count check
        s = WeakSet(Foo() for i in range(1000))
        for elem in s:
            elem.cycle = s
            elem.sub = elem
            elem.set = WeakSet([elem])

    def test_subclass_with_custom_hash(self):
        # Bug #1257731
        class H(WeakSet):
            def __hash__(self):
                return int(id(self) & 0x7FFFFFFF)

        s = H()
        f = set()
        f.add(s)
        self.assert_(s in f)
        f.remove(s)
        f.add(s)
        f.discard(s)

    def test_init(self):
        s = WeakSet()
        s.__init__(self.items)
        self.assertEqual(s, self.s)
        s.__init__(self.items2)
        self.assertEqual(s, WeakSet(self.items2))
        self.assertRaises(TypeError, s.__init__, s, 2)
        self.assertRaises(TypeError, s.__init__, 1)

    def test_constructor_identity(self):
        s = WeakSet(self.items)
        t = WeakSet(s)
        self.assertNotEqual(id(s), id(t))

    def test_hash(self):
        self.assertRaises(TypeError, hash, self.s)

    def test_clear(self):
        self.s.clear()
        self.assertEqual(self.s, WeakSet([]))
        self.assertEqual(len(self.s), 0)

    def test_copy(self):
        dup = self.s.copy()
        self.assertEqual(self.s, dup)
        self.assertNotEqual(id(self.s), id(dup))

    def test_add(self):
        x = ustr("Q")
        self.s.add(x)
        self.assert_(x in self.s)
        dup = self.s.copy()
        self.s.add(x)
        self.assertEqual(self.s, dup)
        self.assertRaises(TypeError, self.s.add, [])
        self.fs.add(Foo())
        self.assert_(len(self.fs) == 1)
        self.fs.add(self.obj)
        self.assert_(len(self.fs) == 1)

    def test_remove(self):
        x = ustr("a")
        self.s.remove(x)
        self.assert_(x not in self.s)
        self.assertRaises(KeyError, self.s.remove, x)
        self.assertRaises(TypeError, self.s.remove, [])

    def test_discard(self):
        a, q = ustr("a"), ustr("Q")
        self.s.discard(a)
        self.assert_(a not in self.s)
        self.s.discard(q)
        self.assertRaises(TypeError, self.s.discard, [])

    def test_pop(self):
        for i in range(len(self.s)):
            elem = self.s.pop()
            self.assert_(elem not in self.s)
        self.assertRaises(KeyError, self.s.pop)

    def test_update(self):
        retval = self.s.update(self.items2)
        self.assertEqual(retval, None)
        for c in self.items + self.items2:
            self.assert_(c in self.s)
        self.assertRaises(TypeError, self.s.update, [[]])

    def test_update_set(self):
        self.s.update(set(self.items2))
        for c in self.items + self.items2:
            self.assert_(c in self.s)

    def test_ior(self):
        self.s |= set(self.items2)
        for c in self.items + self.items2:
            self.assert_(c in self.s)

    def test_intersection_update(self):
        retval = self.s.intersection_update(self.items2)
        self.assertEqual(retval, None)
        for c in self.items + self.items2:
            if c in self.items2 and c in self.items:
                self.assert_(c in self.s)
            else:
                self.assert_(c not in self.s)
        self.assertRaises(TypeError, self.s.intersection_update, [[]])

    def test_iand(self):
        self.s &= set(self.items2)
        for c in self.items + self.items2:
            if c in self.items2 and c in self.items:
                self.assert_(c in self.s)
            else:
                self.assert_(c not in self.s)

    def test_difference_update(self):
        retval = self.s.difference_update(self.items2)
        self.assertEqual(retval, None)
        for c in self.items + self.items2:
            if c in self.items and c not in self.items2:
                self.assert_(c in self.s)
            else:
                self.assert_(c not in self.s)
        self.assertRaises(TypeError, self.s.difference_update, [[]])
        self.assertRaises(TypeError, self.s.symmetric_difference_update, [[]])

    def test_isub(self):
        self.s -= set(self.items2)
        for c in self.items + self.items2:
            if c in self.items and c not in self.items2:
                self.assert_(c in self.s)
            else:
                self.assert_(c not in self.s)

    def test_symmetric_difference_update(self):
        retval = self.s.symmetric_difference_update(self.items2)
        self.assertEqual(retval, None)
        for c in self.items + self.items2:
            if (c in self.items) ^ (c in self.items2):
                self.assert_(c in self.s)
            else:
                self.assert_(c not in self.s)
        self.assertRaises(TypeError, self.s.symmetric_difference_update, [[]])

    def test_ixor(self):
        self.s ^= set(self.items2)
        for c in self.items + self.items2:
            if (c in self.items) ^ (c in self.items2):
                self.assert_(c in self.s)
            else:
                self.assert_(c not in self.s)

    def test_inplace_on_self(self):
        t = self.s.copy()
        t |= t
        self.assertEqual(t, self.s)
        t &= t
        self.assertEqual(t, self.s)
        t -= t
        self.assertEqual(t, WeakSet())
        t = self.s.copy()
        t ^= t
        self.assertEqual(t, WeakSet())

    def test_eq(self):
        # issue 5964
        self.assertTrue(self.s == self.s)
        self.assertTrue(self.s == WeakSet(self.items))
        self.assertFalse(self.s == set(self.items))
        self.assertFalse(self.s == list(self.items))
        self.assertFalse(self.s == tuple(self.items))
        self.assertFalse(self.s == WeakSet([Foo]))
        self.assertFalse(self.s == 1)
Ejemplo n.º 29
0
class StreamInterfaceBase(object):
    def __init__(self, kernel, endpoint=None, handler=None):
        self.kernel = proxy(kernel)
        self.handler = handler
        self.meta = Metadata()

        s = self.create_socket(endpoint)
        self.listen_w = kernel.loop.io(s, pyev.EV_READ, self.on_accept, s)
        self.listen_w.start()
        self.timer_w = kernel.loop.timer(30, 30, self.on_timer)
        self.timer_w.start()

        self.clients = WeakSet()

    @property
    def alive(self):
        return self.listen_w is not None

    def create_socket(self, endpoint):
        pass

    def create_handler(self, sock, endpoint):
        h = self.handler(self.kernel, sock, endpoint)
        return h

    def getsocket(self):
        if self.listen_w:
            return self.listen_w.data

    def on_accept(self, watcher, revent):
        sock, endpoint = watcher.data.accept()
        try:
            sock.settimeout(3)
            handler = self.create_handler(sock, endpoint)
            self.clients.add(handler)
        except Exception:
            logger.exception("Unhandle error while create connection handler")
            sock.close()

    def on_timer(self, watcher, revent):
        zombie = []
        for h in self.clients:
            if (not h.alive) or h.is_timeout:
                zombie.append(h)

        for h in zombie:
            if h.alive:
                logger.debug("%s connection timeout", h)
                h.close()
            else:
                logger.debug("Clean zombie connection %s", h)

            self.clients.remove(h)

    def close(self):
        if self.listen_w:
            self.timer_w.stop()
            self.timer_w = None
            self.listen_w.stop()
            self.listen_w.data.close()
            self.listen_w = None

            while self.clients:
                h = self.clients.pop()
                h.close()
Ejemplo n.º 30
0
class TestWeakSet(unittest.TestCase):

    def setUp(self):
        # need to keep references to them
        self.items = [ustr(c) for c in ('a', 'b', 'c')]
        self.items2 = [ustr(c) for c in ('x', 'y', 'z')]
        self.ab_items = [ustr(c) for c in 'ab']
        self.abcde_items = [ustr(c) for c in 'abcde']
        self.def_items = [ustr(c) for c in 'def']
        self.ab_weakset = WeakSet(self.ab_items)
        self.abcde_weakset = WeakSet(self.abcde_items)
        self.def_weakset = WeakSet(self.def_items)
        self.letters = [ustr(c) for c in string.ascii_letters]
        self.s = WeakSet(self.items)
        self.d = dict.fromkeys(self.items)
        self.obj = ustr('F')
        self.fs = WeakSet([self.obj])

    def test_methods(self):
        weaksetmethods = dir(WeakSet)
        for method in dir(set):
            if method == 'test_c_api' or method.startswith('_'):
                continue
            self.assertIn(method, weaksetmethods,
                         "WeakSet missing method " + method)

    def test_new_or_init(self):
        self.assertRaises(TypeError, WeakSet, [], 2)

    @support.impl_detail("finalization", graalvm=False)
    def test_len(self):
        self.assertEqual(len(self.s), len(self.d))
        self.assertEqual(len(self.fs), 1)
        del self.obj
        self.assertEqual(len(self.fs), 0)

    @support.impl_detail("finalization", graalvm=False)
    def test_contains(self):
        for c in self.letters:
            self.assertEqual(c in self.s, c in self.d)
        # 1 is not weakref'able, but that TypeError is caught by __contains__
        self.assertNotIn(1, self.s)
        self.assertIn(self.obj, self.fs)
        del self.obj
        self.assertNotIn(ustr('F'), self.fs)

    @support.impl_detail("finalization", graalvm=False)
    def test_union(self):
        u = self.s.union(self.items2)
        for c in self.letters:
            self.assertEqual(c in u, c in self.d or c in self.items2)
        self.assertEqual(self.s, WeakSet(self.items))
        self.assertEqual(type(u), WeakSet)
        self.assertRaises(TypeError, self.s.union, [[]])
        for C in set, frozenset, dict.fromkeys, list, tuple:
            x = WeakSet(self.items + self.items2)
            c = C(self.items2)
            self.assertEqual(self.s.union(c), x)
            del c
        self.assertEqual(len(u), len(self.items) + len(self.items2))
        self.items2.pop()
        gc.collect()
        self.assertEqual(len(u), len(self.items) + len(self.items2))

    def test_or(self):
        i = self.s.union(self.items2)
        self.assertEqual(self.s | set(self.items2), i)
        self.assertEqual(self.s | frozenset(self.items2), i)

    @support.impl_detail("finalization", graalvm=False)
    def test_intersection(self):
        s = WeakSet(self.letters)
        i = s.intersection(self.items2)
        for c in self.letters:
            self.assertEqual(c in i, c in self.items2 and c in self.letters)
        self.assertEqual(s, WeakSet(self.letters))
        self.assertEqual(type(i), WeakSet)
        for C in set, frozenset, dict.fromkeys, list, tuple:
            x = WeakSet([])
            self.assertEqual(i.intersection(C(self.items)), x)
        self.assertEqual(len(i), len(self.items2))
        self.items2.pop()
        gc.collect()
        self.assertEqual(len(i), len(self.items2))

    def test_isdisjoint(self):
        self.assertTrue(self.s.isdisjoint(WeakSet(self.items2)))
        self.assertTrue(not self.s.isdisjoint(WeakSet(self.letters)))

    def test_and(self):
        i = self.s.intersection(self.items2)
        self.assertEqual(self.s & set(self.items2), i)
        self.assertEqual(self.s & frozenset(self.items2), i)

    def test_difference(self):
        i = self.s.difference(self.items2)
        for c in self.letters:
            self.assertEqual(c in i, c in self.d and c not in self.items2)
        self.assertEqual(self.s, WeakSet(self.items))
        self.assertEqual(type(i), WeakSet)
        self.assertRaises(TypeError, self.s.difference, [[]])

    def test_sub(self):
        i = self.s.difference(self.items2)
        self.assertEqual(self.s - set(self.items2), i)
        self.assertEqual(self.s - frozenset(self.items2), i)

    @support.impl_detail("finalization", graalvm=False)
    def test_symmetric_difference(self):
        i = self.s.symmetric_difference(self.items2)
        for c in self.letters:
            self.assertEqual(c in i, (c in self.d) ^ (c in self.items2))
        self.assertEqual(self.s, WeakSet(self.items))
        self.assertEqual(type(i), WeakSet)
        self.assertRaises(TypeError, self.s.symmetric_difference, [[]])
        self.assertEqual(len(i), len(self.items) + len(self.items2))
        self.items2.pop()
        gc.collect()
        self.assertEqual(len(i), len(self.items) + len(self.items2))

    def test_xor(self):
        i = self.s.symmetric_difference(self.items2)
        self.assertEqual(self.s ^ set(self.items2), i)
        self.assertEqual(self.s ^ frozenset(self.items2), i)

    def test_sub_and_super(self):
        self.assertTrue(self.ab_weakset <= self.abcde_weakset)
        self.assertTrue(self.abcde_weakset <= self.abcde_weakset)
        self.assertTrue(self.abcde_weakset >= self.ab_weakset)
        self.assertFalse(self.abcde_weakset <= self.def_weakset)
        self.assertFalse(self.abcde_weakset >= self.def_weakset)
        self.assertTrue(set('a').issubset('abc'))
        self.assertTrue(set('abc').issuperset('a'))
        self.assertFalse(set('a').issubset('cbs'))
        self.assertFalse(set('cbs').issuperset('a'))

    def test_lt(self):
        self.assertTrue(self.ab_weakset < self.abcde_weakset)
        self.assertFalse(self.abcde_weakset < self.def_weakset)
        self.assertFalse(self.ab_weakset < self.ab_weakset)
        self.assertFalse(WeakSet() < WeakSet())

    def test_gt(self):
        self.assertTrue(self.abcde_weakset > self.ab_weakset)
        self.assertFalse(self.abcde_weakset > self.def_weakset)
        self.assertFalse(self.ab_weakset > self.ab_weakset)
        self.assertFalse(WeakSet() > WeakSet())

    def test_gc(self):
        # Create a nest of cycles to exercise overall ref count check
        s = WeakSet(Foo() for i in range(1000))
        for elem in s:
            elem.cycle = s
            elem.sub = elem
            elem.set = WeakSet([elem])

    def test_subclass_with_custom_hash(self):
        # Bug #1257731
        class H(WeakSet):
            def __hash__(self):
                return int(id(self) & 0x7fffffff)
        s=H()
        f=set()
        f.add(s)
        self.assertIn(s, f)
        f.remove(s)
        f.add(s)
        f.discard(s)

    def test_init(self):
        s = WeakSet()
        s.__init__(self.items)
        self.assertEqual(s, self.s)
        s.__init__(self.items2)
        self.assertEqual(s, WeakSet(self.items2))
        self.assertRaises(TypeError, s.__init__, s, 2);
        self.assertRaises(TypeError, s.__init__, 1);

    def test_constructor_identity(self):
        s = WeakSet(self.items)
        t = WeakSet(s)
        self.assertNotEqual(id(s), id(t))

    def test_hash(self):
        self.assertRaises(TypeError, hash, self.s)

    def test_clear(self):
        self.s.clear()
        self.assertEqual(self.s, WeakSet([]))
        self.assertEqual(len(self.s), 0)

    def test_copy(self):
        dup = self.s.copy()
        self.assertEqual(self.s, dup)
        self.assertNotEqual(id(self.s), id(dup))

    @support.impl_detail("refcounting", graalvm=False)
    def test_add(self):
        x = ustr('Q')
        self.s.add(x)
        self.assertIn(x, self.s)
        dup = self.s.copy()
        self.s.add(x)
        self.assertEqual(self.s, dup)
        self.assertRaises(TypeError, self.s.add, [])
        self.fs.add(Foo())
        self.assertTrue(len(self.fs) == 1)
        self.fs.add(self.obj)
        self.assertTrue(len(self.fs) == 1)

    def test_remove(self):
        x = ustr('a')
        self.s.remove(x)
        self.assertNotIn(x, self.s)
        self.assertRaises(KeyError, self.s.remove, x)
        self.assertRaises(TypeError, self.s.remove, [])

    def test_discard(self):
        a, q = ustr('a'), ustr('Q')
        self.s.discard(a)
        self.assertNotIn(a, self.s)
        self.s.discard(q)
        self.assertRaises(TypeError, self.s.discard, [])

    def test_pop(self):
        for i in range(len(self.s)):
            elem = self.s.pop()
            self.assertNotIn(elem, self.s)
        self.assertRaises(KeyError, self.s.pop)

    def test_update(self):
        retval = self.s.update(self.items2)
        self.assertEqual(retval, None)
        for c in (self.items + self.items2):
            self.assertIn(c, self.s)
        self.assertRaises(TypeError, self.s.update, [[]])

    def test_update_set(self):
        self.s.update(set(self.items2))
        for c in (self.items + self.items2):
            self.assertIn(c, self.s)

    def test_ior(self):
        self.s |= set(self.items2)
        for c in (self.items + self.items2):
            self.assertIn(c, self.s)

    def test_intersection_update(self):
        retval = self.s.intersection_update(self.items2)
        self.assertEqual(retval, None)
        for c in (self.items + self.items2):
            if c in self.items2 and c in self.items:
                self.assertIn(c, self.s)
            else:
                self.assertNotIn(c, self.s)
        self.assertRaises(TypeError, self.s.intersection_update, [[]])

    def test_iand(self):
        self.s &= set(self.items2)
        for c in (self.items + self.items2):
            if c in self.items2 and c in self.items:
                self.assertIn(c, self.s)
            else:
                self.assertNotIn(c, self.s)

    def test_difference_update(self):
        retval = self.s.difference_update(self.items2)
        self.assertEqual(retval, None)
        for c in (self.items + self.items2):
            if c in self.items and c not in self.items2:
                self.assertIn(c, self.s)
            else:
                self.assertNotIn(c, self.s)
        self.assertRaises(TypeError, self.s.difference_update, [[]])
        self.assertRaises(TypeError, self.s.symmetric_difference_update, [[]])

    def test_isub(self):
        self.s -= set(self.items2)
        for c in (self.items + self.items2):
            if c in self.items and c not in self.items2:
                self.assertIn(c, self.s)
            else:
                self.assertNotIn(c, self.s)

    def test_symmetric_difference_update(self):
        retval = self.s.symmetric_difference_update(self.items2)
        self.assertEqual(retval, None)
        for c in (self.items + self.items2):
            if (c in self.items) ^ (c in self.items2):
                self.assertIn(c, self.s)
            else:
                self.assertNotIn(c, self.s)
        self.assertRaises(TypeError, self.s.symmetric_difference_update, [[]])

    def test_ixor(self):
        self.s ^= set(self.items2)
        for c in (self.items + self.items2):
            if (c in self.items) ^ (c in self.items2):
                self.assertIn(c, self.s)
            else:
                self.assertNotIn(c, self.s)

    def test_inplace_on_self(self):
        t = self.s.copy()
        t |= t
        self.assertEqual(t, self.s)
        t &= t
        self.assertEqual(t, self.s)
        t -= t
        self.assertEqual(t, WeakSet())
        t = self.s.copy()
        t ^= t
        self.assertEqual(t, WeakSet())

    def test_eq(self):
        # issue 5964
        self.assertTrue(self.s == self.s)
        self.assertTrue(self.s == WeakSet(self.items))
        self.assertFalse(self.s == set(self.items))
        self.assertFalse(self.s == list(self.items))
        self.assertFalse(self.s == tuple(self.items))
        self.assertFalse(self.s == WeakSet([Foo]))
        self.assertFalse(self.s == 1)

    def test_ne(self):
        self.assertTrue(self.s != set(self.items))
        s1 = WeakSet()
        s2 = WeakSet()
        self.assertFalse(s1 != s2)

    @support.impl_detail("finalization", graalvm=False)
    def test_weak_destroy_while_iterating(self):
        # Issue #7105: iterators shouldn't crash when a key is implicitly removed
        # Create new items to be sure no-one else holds a reference
        items = [ustr(c) for c in ('a', 'b', 'c')]
        s = WeakSet(items)
        it = iter(s)
        next(it)             # Trigger internal iteration
        # Destroy an item
        del items[-1]
        gc.collect()    # just in case
        # We have removed either the first consumed items, or another one
        self.assertIn(len(list(it)), [len(items), len(items) - 1])
        del it
        # The removal has been committed
        self.assertEqual(len(s), len(items))

    @support.impl_detail("finalization", graalvm=False)
    def test_weak_destroy_and_mutate_while_iterating(self):
        # Issue #7105: iterators shouldn't crash when a key is implicitly removed
        items = [ustr(c) for c in string.ascii_letters]
        s = WeakSet(items)
        @contextlib.contextmanager
        def testcontext():
            try:
                it = iter(s)
                # Start iterator
                yielded = ustr(str(next(it)))
                # Schedule an item for removal and recreate it
                u = ustr(str(items.pop()))
                if yielded == u:
                    # The iterator still has a reference to the removed item,
                    # advance it (issue #20006).
                    next(it)
                gc.collect()      # just in case
                yield u
            finally:
                it = None           # should commit all removals

        with testcontext() as u:
            self.assertNotIn(u, s)
        with testcontext() as u:
            self.assertRaises(KeyError, s.remove, u)
        self.assertNotIn(u, s)
        with testcontext() as u:
            s.add(u)
        self.assertIn(u, s)
        t = s.copy()
        with testcontext() as u:
            s.update(t)
        self.assertEqual(len(s), len(t))
        with testcontext() as u:
            s.clear()
        self.assertEqual(len(s), 0)

    @support.impl_detail("finalization", graalvm=False)
    def test_len_cycles(self):
        N = 20
        items = [RefCycle() for i in range(N)]
        s = WeakSet(items)
        del items
        it = iter(s)
        try:
            next(it)
        except StopIteration:
            pass
        gc.collect()
        n1 = len(s)
        del it
        gc.collect()
        n2 = len(s)
        # one item may be kept alive inside the iterator
        self.assertIn(n1, (0, 1))
        self.assertEqual(n2, 0)

    @support.impl_detail("finalization", graalvm=False)
    def test_len_race(self):
        # Extended sanity checks for len() in the face of cyclic collection
        self.addCleanup(gc.set_threshold, *gc.get_threshold())
        for th in range(1, 100):
            N = 20
            gc.collect(0)
            gc.set_threshold(th, th, th)
            items = [RefCycle() for i in range(N)]
            s = WeakSet(items)
            del items
            # All items will be collected at next garbage collection pass
            it = iter(s)
            try:
                next(it)
            except StopIteration:
                pass
            n1 = len(s)
            del it
            n2 = len(s)
            self.assertGreaterEqual(n1, 0)
            self.assertLessEqual(n1, N)
            self.assertGreaterEqual(n2, 0)
            self.assertLessEqual(n2, n1)

    def test_repr(self):
        assert repr(self.s) == repr(self.s.data)
Ejemplo n.º 31
0
class Dataset(object):

    def __init__(self, name):
        self.name = name
        self.sources = []
        self._observers = WeakSet()

    def __repr__(self):
        return self.name

    def add(self, datasource):
        if isinstance(datasource, DataSource):
            self.sources.append(datasource)
        else:
            for source in datasource:
                self.add(source)
        for o in self._observers:
            o(self)

    def remove(self, datasource):
        self.sources.remove(datasource)
        for o in self._observers:
            o(self)

    def count(self, lookup_unknown=True):
        total = 0
        for datasource in self.sources:
            s = datasource.size(lookup=lookup_unknown)
            if s is not None:
                total += s
        return total

    def on_change(self, callback):
        self._observers.add(callback)

    def remove_on_change(self, callback):
        self._observers.remove(callback)

    def __iadd__(self, other):
        if isinstance(other, DataSource):
            self.add(other)
        if isinstance(other, Dataset):
            self.sources = self.sources + other.sources
            for o in self._observers:
                o(self)
        return self

    def __add__(self, other):
        newset = Dataset("%s + %s" % (self.name, other.name))
        if isinstance(other, DataSource):
            newset.add(other)
        if isinstance(other, Dataset):
            newset.sources = self.sources + other.sources
        return newset

    @staticmethod
    def load(directory, indices=None, name=None, max_scenes=None, assume_same_frames=True, assume_same_shapes=True):
        import os
        from .fluidformat import Scene

        if name is None:
            name = os.path.basename(directory)

        dataset = Dataset(name)

        shape_map = dict() if assume_same_shapes else None
        frames = None

        indexfilter = None if indices is None else lambda i: i in indices
        scene_iterator = Scene.list(directory, max_count=max_scenes, indexfilter=indexfilter)

        for scene in scene_iterator:
            if assume_same_frames and frames is None:
                frames = scene.frames
            dataset.add(SceneSource(scene, frames=frames, shape_map=shape_map))

        if dataset.count() == 0:
            raise ValueError("No data sets found in '%s' " % directory)

        return dataset
Ejemplo n.º 32
0
class AsyncPoolWrapper:
    def __init__(self, pool: SessionPool, loop: 'ProactorEventLoop' = None):
        if loop == None:
            loop = asyncio.get_running_loop()
        self._thread_pool = ThreadPoolExecutor(
            max_workers=max(DEFAULT_MAXIMUM_WORKER_NUM,
                            pool.max << DEFAULT_MAXIMUM_WORKER_TIMES))
        self._thread_pool.set_daemon_opts(min_workers=max(4, pool.min << 1))
        self._loop = loop
        self._pool = pool
        self._occupied = WeakSet()

    def acquire(self):
        coro = self._loop.run_in_executor(self._thread_pool, self._acquire)
        return AsyncConnectionWrapper_context(coro)

    def _acquire(self):
        wrapper = AsyncConnectionWrapper(self._pool.acquire(), self._loop,
                                         self._thread_pool, self._pool, self)
        self._occupied.add(wrapper)
        return wrapper

    def _ofree(self, obj: AsyncConnectionWrapper):
        '''
        A performance optimization tip:

        When there's no exception raised , `try` way perform
        20%-30% faster than `if` way.

        If there do have a exception , `try` way will be 
        100% slower than `if` way , it takes about 500ns
        to recover the stack.

        So in this perticular situation when there's far more
        chance no exception raised rather than exception raised,
        use `try` provides better performance.
        '''
        try:
            self._occupied.remove(obj)
        except:
            pass
        # if obj in self._occupied:
        #     self._occupied.remove(obj)

    async def release(self, conn: AsyncConnectionWrapper):
        self._ofree(conn)
        return await self._loop.run_in_executor(self._thread_pool,
                                                self._pool.release, conn._conn)

    async def drop(self, conn: Connection):
        return await self._loop.run_in_executor(self._thread_pool,
                                                self._pool.drop, conn)

    async def close(self, force: bool = False, interrupt: bool = False):
        '''
        WARNING: option `interrupt` will force cancel all running connections before close
        the pool. This may cause fetching thread no response forever in some legacy version
        of oracle database such as 11 or lower.

        Do make sure this option works fine with your working enviornment.
        '''
        while self._occupied:
            wrapper = self._occupied.pop()
            if interrupt:
                await self._loop.run_in_executor(self._thread_pool,
                                                 wrapper._conn.cancel)

        return await self._loop.run_in_executor(self._thread_pool,
                                                self._pool.close, force)
Ejemplo n.º 33
0
class Agent:
    def __init__(self, loop: AbstractEventLoop = None):
        self._loop = loop
        self._links = WeakSet()
        self._monitors = WeakSet()
        self._queue = Queue(loop=self._loop)
        self._task = asyncio.ensure_future(self._main(), loop=self._loop)

    @property
    def alive(self) -> bool:
        return self._task is not None

    @property
    def exited(self) -> bool:
        return self._task is None

    @property
    def loop(self) -> AbstractEventLoop:
        return self._loop

    @property
    def task(self) -> Task:
        return self._task

    def bidirectional_link(self, to: 'Agent'):
        self._links.add(to)
        to._links.add(self)

    def unlink(self, from_: 'Agent'):
        self._links.remove(from_)
        from_._links.remove(self)

    def monitor(self, monitored: 'Agent'):
        self._links.add(monitored)
        monitored._monitors.add(self)

    def spawn_linked_task(self, coro_or_future, unlink_on_success: bool = True) -> 'LinkedTask':
        return LinkedTask(self, coro_or_future, unlink_on_success=unlink_on_success, loop=self._loop)

    async def _main(self):
        # noinspection PyBroadException
        try:
            while self.alive:
                fun = await self._queue.get()
                await fun()
        except Exception as exc:
            self.exit(exc)
        else:
            self.exit(None)

    def exit(self, exc: Optional[Exception] = None):
        old_task = self._task
        try:
            if self.exited:
                return
            self._task = None
            if exc:
                logger.debug("%s is exiting because %s", self, exc)
            else:
                logger.debug("%s is exiting normally", self)
            for link in self._links:
                link.exit(exc)

            for monitor in self._monitors:
                method = getattr(monitor, 'on_monitored_exit', None)
                if method:
                    method(self, exc)
                else:
                    logger.warning("%s was monitoring an agent %s, but doesn't implemented on_monitored_exit",
                                   monitor, self)
        finally:
            if old_task is not None:
                old_task.cancel()
                self._links = WeakSet()
                self._monitors = WeakSet()
Ejemplo n.º 34
0
class TestWeakSet(unittest.TestCase):

    def setUp(self):
        # need to keep references to them
        self.items = [SomeClass(c) for c in ('a', 'b', 'c')]
        self.items2 = [SomeClass(c) for c in ('x', 'y', 'z')]
        self.letters = [SomeClass(c) for c in string.ascii_letters]
        self.s = WeakSet(self.items)
        self.d = dict.fromkeys(self.items)
        self.obj = SomeClass('F')
        self.fs = WeakSet([self.obj])

    def test_methods(self):
        weaksetmethods = dir(WeakSet)
        for method in dir(set):
            if method == 'test_c_api' or method.startswith('_'):
                continue
            self.assertIn(method, weaksetmethods,
                         "WeakSet missing method " + method)

    def test_new_or_init(self):
        self.assertRaises(TypeError, WeakSet, [], 2)

    def test_len(self):
        self.assertEqual(len(self.s), len(self.d))
        self.assertEqual(len(self.fs), 1)
        del self.obj
        self.assertEqual(len(self.fs), 0)

    def test_contains(self):
        for c in self.letters:
            self.assertEqual(c in self.s, c in self.d)
        # 1 is not weakref'able, but that TypeError is caught by __contains__
        self.assertNotIn(1, self.s)
        self.assertIn(self.obj, self.fs)
        del self.obj
        self.assertNotIn(SomeClass('F'), self.fs)

    def test_union(self):
        u = self.s.union(self.items2)
        for c in self.letters:
            self.assertEqual(c in u, c in self.d or c in self.items2)
        self.assertEqual(self.s, WeakSet(self.items))
        self.assertEqual(type(u), WeakSet)
        self.assertRaises(TypeError, self.s.union, [[]])
        for C in set, frozenset, dict.fromkeys, list, tuple:
            x = WeakSet(self.items + self.items2)
            c = C(self.items2)
            self.assertEqual(self.s.union(c), x)

    def test_or(self):
        i = self.s.union(self.items2)
        self.assertEqual(self.s | set(self.items2), i)
        self.assertEqual(self.s | frozenset(self.items2), i)

    def test_intersection(self):
        i = self.s.intersection(self.items2)
        for c in self.letters:
            self.assertEqual(c in i, c in self.d and c in self.items2)
        self.assertEqual(self.s, WeakSet(self.items))
        self.assertEqual(type(i), WeakSet)
        for C in set, frozenset, dict.fromkeys, list, tuple:
            x = WeakSet([])
            self.assertEqual(self.s.intersection(C(self.items2)), x)

    def test_isdisjoint(self):
        self.assertTrue(self.s.isdisjoint(WeakSet(self.items2)))
        self.assertTrue(not self.s.isdisjoint(WeakSet(self.letters)))

    def test_and(self):
        i = self.s.intersection(self.items2)
        self.assertEqual(self.s & set(self.items2), i)
        self.assertEqual(self.s & frozenset(self.items2), i)

    def test_difference(self):
        i = self.s.difference(self.items2)
        for c in self.letters:
            self.assertEqual(c in i, c in self.d and c not in self.items2)
        self.assertEqual(self.s, WeakSet(self.items))
        self.assertEqual(type(i), WeakSet)
        self.assertRaises(TypeError, self.s.difference, [[]])

    def test_sub(self):
        i = self.s.difference(self.items2)
        self.assertEqual(self.s - set(self.items2), i)
        self.assertEqual(self.s - frozenset(self.items2), i)

    def test_symmetric_difference(self):
        i = self.s.symmetric_difference(self.items2)
        for c in self.letters:
            self.assertEqual(c in i, (c in self.d) ^ (c in self.items2))
        self.assertEqual(self.s, WeakSet(self.items))
        self.assertEqual(type(i), WeakSet)
        self.assertRaises(TypeError, self.s.symmetric_difference, [[]])

    def test_xor(self):
        i = self.s.symmetric_difference(self.items2)
        self.assertEqual(self.s ^ set(self.items2), i)
        self.assertEqual(self.s ^ frozenset(self.items2), i)

    def test_sub_and_super(self):
        pl, ql, rl = map(lambda s: [SomeClass(c) for c in s], ['ab', 'abcde', 'def'])
        p, q, r = map(WeakSet, (pl, ql, rl))
        self.assertTrue(p < q)
        self.assertTrue(p <= q)
        self.assertTrue(q <= q)
        self.assertTrue(q > p)
        self.assertTrue(q >= p)
        self.assertFalse(q < r)
        self.assertFalse(q <= r)
        self.assertFalse(q > r)
        self.assertFalse(q >= r)
        self.assertTrue(set('a').issubset('abc'))
        self.assertTrue(set('abc').issuperset('a'))
        self.assertFalse(set('a').issubset('cbs'))
        self.assertFalse(set('cbs').issuperset('a'))

    def test_gc(self):
        # Create a nest of cycles to exercise overall ref count check
        s = WeakSet(Foo() for i in range(1000))
        for elem in s:
            elem.cycle = s
            elem.sub = elem
            elem.set = WeakSet([elem])

    def test_subclass_with_custom_hash(self):
        # Bug #1257731
        class H(WeakSet):
            def __hash__(self):
                return int(id(self) & 0x7fffffff)
        s=H()
        f=set()
        f.add(s)
        self.assertIn(s, f)
        f.remove(s)
        f.add(s)
        f.discard(s)

    def test_init(self):
        s = WeakSet()
        s.__init__(self.items)
        self.assertEqual(s, self.s)
        s.__init__(self.items2)
        self.assertEqual(s, WeakSet(self.items2))
        self.assertRaises(TypeError, s.__init__, s, 2);
        self.assertRaises(TypeError, s.__init__, 1);

    def test_constructor_identity(self):
        s = WeakSet(self.items)
        t = WeakSet(s)
        self.assertNotEqual(id(s), id(t))

    def test_hash(self):
        self.assertRaises(TypeError, hash, self.s)

    def test_clear(self):
        self.s.clear()
        self.assertEqual(self.s, WeakSet([]))
        self.assertEqual(len(self.s), 0)

    def test_copy(self):
        dup = self.s.copy()
        self.assertEqual(self.s, dup)
        self.assertNotEqual(id(self.s), id(dup))

    def test_add(self):
        x = SomeClass('Q')
        self.s.add(x)
        self.assertIn(x, self.s)
        dup = self.s.copy()
        self.s.add(x)
        self.assertEqual(self.s, dup)
        self.assertRaises(TypeError, self.s.add, [])
        self.fs.add(Foo())
        self.assertTrue(len(self.fs) == 1)
        self.fs.add(self.obj)
        self.assertTrue(len(self.fs) == 1)

    def test_remove(self):
        x = SomeClass('a')
        self.s.remove(x)
        self.assertNotIn(x, self.s)
        self.assertRaises(KeyError, self.s.remove, x)
        self.assertRaises(TypeError, self.s.remove, [])

    def test_discard(self):
        a, q = SomeClass('a'), SomeClass('Q')
        self.s.discard(a)
        self.assertNotIn(a, self.s)
        self.s.discard(q)
        self.assertRaises(TypeError, self.s.discard, [])

    def test_pop(self):
        for i in range(len(self.s)):
            elem = self.s.pop()
            self.assertNotIn(elem, self.s)
        self.assertRaises(KeyError, self.s.pop)

    def test_update(self):
        retval = self.s.update(self.items2)
        self.assertEqual(retval, None)
        for c in (self.items + self.items2):
            self.assertIn(c, self.s)
        self.assertRaises(TypeError, self.s.update, [[]])

    def test_update_set(self):
        self.s.update(set(self.items2))
        for c in (self.items + self.items2):
            self.assertIn(c, self.s)

    def test_ior(self):
        self.s |= set(self.items2)
        for c in (self.items + self.items2):
            self.assertIn(c, self.s)

    def test_intersection_update(self):
        retval = self.s.intersection_update(self.items2)
        self.assertEqual(retval, None)
        for c in (self.items + self.items2):
            if c in self.items2 and c in self.items:
                self.assertIn(c, self.s)
            else:
                self.assertNotIn(c, self.s)
        self.assertRaises(TypeError, self.s.intersection_update, [[]])

    def test_iand(self):
        self.s &= set(self.items2)
        for c in (self.items + self.items2):
            if c in self.items2 and c in self.items:
                self.assertIn(c, self.s)
            else:
                self.assertNotIn(c, self.s)

    def test_difference_update(self):
        retval = self.s.difference_update(self.items2)
        self.assertEqual(retval, None)
        for c in (self.items + self.items2):
            if c in self.items and c not in self.items2:
                self.assertIn(c, self.s)
            else:
                self.assertNotIn(c, self.s)
        self.assertRaises(TypeError, self.s.difference_update, [[]])
        self.assertRaises(TypeError, self.s.symmetric_difference_update, [[]])

    def test_isub(self):
        self.s -= set(self.items2)
        for c in (self.items + self.items2):
            if c in self.items and c not in self.items2:
                self.assertIn(c, self.s)
            else:
                self.assertNotIn(c, self.s)

    def test_symmetric_difference_update(self):
        retval = self.s.symmetric_difference_update(self.items2)
        self.assertEqual(retval, None)
        for c in (self.items + self.items2):
            if (c in self.items) ^ (c in self.items2):
                self.assertIn(c, self.s)
            else:
                self.assertNotIn(c, self.s)
        self.assertRaises(TypeError, self.s.symmetric_difference_update, [[]])

    def test_ixor(self):
        self.s ^= set(self.items2)
        for c in (self.items + self.items2):
            if (c in self.items) ^ (c in self.items2):
                self.assertIn(c, self.s)
            else:
                self.assertNotIn(c, self.s)

    def test_inplace_on_self(self):
        t = self.s.copy()
        t |= t
        self.assertEqual(t, self.s)
        t &= t
        self.assertEqual(t, self.s)
        t -= t
        self.assertEqual(t, WeakSet())
        t = self.s.copy()
        t ^= t
        self.assertEqual(t, WeakSet())

    def test_eq(self):
        # issue 5964
        self.assertTrue(self.s == self.s)
        self.assertTrue(self.s == WeakSet(self.items))
        self.assertFalse(self.s == set(self.items))
        self.assertFalse(self.s == list(self.items))
        self.assertFalse(self.s == tuple(self.items))
        self.assertFalse(self.s == 1)

    def test_weak_destroy_while_iterating(self):
        # Issue #7105: iterators shouldn't crash when a key is implicitly removed
        # Create new items to be sure no-one else holds a reference
        items = [SomeClass(c) for c in ('a', 'b', 'c')]
        s = WeakSet(items)
        it = iter(s)
        next(it)             # Trigger internal iteration
        # Destroy an item
        del items[-1]
        gc.collect()    # just in case
        # We have removed either the first consumed items, or another one
        self.assertIn(len(list(it)), [len(items), len(items) - 1])
        del it
        # The removal has been committed
        self.assertEqual(len(s), len(items))

    def test_weak_destroy_and_mutate_while_iterating(self):
        # Issue #7105: iterators shouldn't crash when a key is implicitly removed
        items = [SomeClass(c) for c in string.ascii_letters]
        s = WeakSet(items)
        @contextlib.contextmanager
        def testcontext():
            try:
                it = iter(s)
                next(it)
                # Schedule an item for removal and recreate it
                u = SomeClass(str(items.pop()))
                gc.collect()      # just in case
                yield u
            finally:
                it = None           # should commit all removals

        with testcontext() as u:
            self.assertNotIn(u, s)
        with testcontext() as u:
            self.assertRaises(KeyError, s.remove, u)
        self.assertNotIn(u, s)
        with testcontext() as u:
            s.add(u)
        self.assertIn(u, s)
        t = s.copy()
        with testcontext() as u:
            s.update(t)
        self.assertEqual(len(s), len(t))
        with testcontext() as u:
            s.clear()
        self.assertEqual(len(s), 0)
Ejemplo n.º 35
0
class Privacy(LineOfSight):
    _PRIVACY_SURFACE_BLOCKING_FOOTPRINT_COST = 100000
    _PRIVACY_DISCOURAGEMENT_COST = routing.get_default_discouragement_cost()
    _SHOO_CONSTRAINT_RADIUS = Tunable(description='\n        The radius of the constraint a Shooed Sim will attempt to route to.\n        ', tunable_type=float, default=2.5)
    _UNAVAILABLE_TOOLTIP = TunableLocalizedStringFactory(description='\n        Tooltip displayed when an object is not accessible due to being inside\n        a privacy region.\n        ')
    _EMBARRASSED_AFFORDANCE = TunableReference(description='\n        The affordance a Sim will play when getting embarrassed by walking in\n        on a privacy situation.\n        ', manager=services.get_instance_manager(Types.INTERACTION))

    def __init__(self, *, interaction=None, tests=None, shoo_exempt_tests=None, max_line_of_sight_radius=None, map_divisions=None, simplification_ratio=None, boundary_epsilon=None, facing_offset=None, routing_surface_only=None, shoo_constraint_radius=None, unavailable_tooltip=None, embarrassed_affordance=None, reserved_surface_space=None, vehicle_tests=None, central_object=None, post_route_affordance=None, add_to_privacy_service=True, privacy_cost_override=None, additional_exit_offsets=None, persistent_instance=False, privacy_violators=None):
        super().__init__(max_line_of_sight_radius, map_divisions, simplification_ratio, boundary_epsilon)
        logger.assert_raise(bool(interaction) != bool(central_object), 'Privacy must define either one of interaction or central object, and never both.')
        self._max_line_of_sight_radius = max_line_of_sight_radius
        self._interaction = interaction
        self._tests = tests
        self._shoo_exempt_tests = shoo_exempt_tests
        self._privacy_constraints = []
        self._allowed_sims = WeakSet()
        self._disallowed_sims = WeakSet()
        self._violators = WeakSet()
        self._late_violators = WeakSet()
        self._exempt_sims = WeakSet()
        self.is_active = False
        self.has_shooed = False
        self.central_object = central_object
        self.additional_exit_offsets = additional_exit_offsets
        self._multi_surface = True
        self.persistent_instance = persistent_instance
        self._routing_surface_only = routing_surface_only
        self._shoo_constraint_radius = shoo_constraint_radius
        self._unavailable_tooltip = unavailable_tooltip
        self._embarrassed_affordance = embarrassed_affordance
        self._reserved_surface_space = reserved_surface_space
        self._post_route_affordance = post_route_affordance
        self._privacy_cost_override = privacy_cost_override
        self.privacy_violators = privacy_violators
        self._vehicle_tests = vehicle_tests
        self._pushed_interactions = []
        if add_to_privacy_service:
            self.add_privacy()

    @property
    def shoo_constraint_radius(self):
        return self._shoo_constraint_radius or self._SHOO_CONSTRAINT_RADIUS

    @property
    def unavailable_tooltip(self):
        return self._unavailable_toolip or self._UNAVAILABLE_TOOLTIP

    @property
    def embarrassed_affordance(self):
        return self._embarrassed_affordance or self._EMBARRASSED_AFFORDANCE

    @property
    def privacy_discouragement_cost(self):
        return self._privacy_cost_override or self._PRIVACY_DISCOURAGEMENT_COST

    @property
    def interaction(self):
        return self._interaction

    @property
    def is_active(self) -> bool:
        return self._is_active

    @is_active.setter
    def is_active(self, value):
        self._is_active = value

    def _is_sim_allowed(self, sim):
        if self._tests:
            resolver = SingleSimResolver(sim.sim_info) if self._interaction is None else self._interaction.get_resolver(target=sim)
            if self._tests and self._tests.run_tests(resolver):
                return True
            elif self._interaction is not None and self._interaction.can_sim_violate_privacy(sim):
                return True
        if self._interaction is not None and self._interaction.can_sim_violate_privacy(sim):
            return True
        return False

    def evaluate_sim(self, sim):
        if self._is_sim_allowed(sim):
            self._allowed_sims.add(sim)
            return True
        self._disallowed_sims.add(sim)
        return False

    def build_privacy(self, target=None):
        self.is_active = True
        if self.central_object is None:
            target_object = self._interaction.get_participant(ParticipantType.Object)
            target_object = None if target_object.is_sim else target_object
            self.central_object = target_object or (target or self._interaction.sim)
        if self._routing_surface_only:
            allow_object_routing_surface = True
            routing_surface = self.central_object.provided_routing_surface
            if routing_surface is None:
                return False
        else:
            allow_object_routing_surface = False
            routing_surface = self.central_object.routing_surface
        self.generate(self.central_object.position, routing_surface, allow_object_routing_surface=allow_object_routing_surface)
        for poly in self.constraint.geometry.polygon:
            self._privacy_constraints.append(PolygonFootprint(poly, routing_surface=routing_surface, cost=self.privacy_discouragement_cost, footprint_type=FootprintType.FOOTPRINT_TYPE_PATH, enabled=True))
        if self._reserved_surface_space is not None and target is not None:
            reserved_space = self._reserved_surface_space.reserved_space
            try:
                polygon = _generate_single_poly_rectangle_points(target.position, target.part_owner.orientation.transform_vector(sims4.math.Vector3.Z_AXIS()), target.part_owner.orientation.transform_vector(sims4.math.Vector3.X_AXIS()), reserved_space.left, reserved_space.right, reserved_space.front, reserved_space.back)
            except AttributeError as exc:
                raise AttributeError('Interaction: {} is trying to reserve surface space with sim as target. Exception:{}'.format(self._interaction, exc))
            routing_surface = self.central_object.provided_routing_surface
            if routing_surface is None:
                routing_surface = target.routing_surface
            footprint_cost = self.privacy_discouragement_cost if self._reserved_surface_space.allow_routing else self._PRIVACY_SURFACE_BLOCKING_FOOTPRINT_COST
            self._privacy_constraints.append(PolygonFootprint(polygon, routing_surface=routing_surface, cost=footprint_cost, footprint_type=FootprintType.FOOTPRINT_TYPE_PATH, enabled=True))
        if self.privacy_violators & PrivacyViolators.SIM:
            if self._interaction is not None:
                self._allowed_sims.update(self._interaction.get_participants(ParticipantType.AllSims))
            for sim in services.sim_info_manager().instanced_sims_gen():
                if sim not in self._allowed_sims:
                    self.evaluate_sim(sim)
            violating_sims = self.find_violating_sims()
            self._exempt_sims = set([s for s in violating_sims if self.is_sim_shoo_exempt(s)])
            self._cancel_unavailable_interactions(violating_sims)
            self._add_overrides_and_constraints_if_needed(violating_sims)
        if self.privacy_violators & PrivacyViolators.VEHICLES:
            violating_vehicles = self.find_violating_vehicles()
            for vehicle in violating_vehicles:
                vehicle.objectrouting_component.handle_privacy_violation(self)
        return True

    def cleanup_privacy_instance(self):
        if self.is_active:
            self.is_active = False
            for sim in self._allowed_sims:
                self.remove_override_for_sim(sim)
            for sim in self._late_violators:
                self.remove_override_for_sim(sim)
            del self._privacy_constraints[:]
            self._allowed_sims.clear()
            self._disallowed_sims.clear()
            self._violators.clear()
            self._late_violators.clear()
            self._exempt_sims.clear()
            self._cancel_pushed_interactions()

    def add_privacy(self):
        services.privacy_service().add_instance(self)

    def remove_privacy(self):
        self.cleanup_privacy_instance()
        services.privacy_service().remove_instance(self)

    def intersects_with_object(self, obj):
        if obj.routing_surface != self.central_object.routing_surface:
            return False
        delta = obj.position - self.central_object.position
        distance = delta.magnitude_2d_squared()
        if distance > self.max_line_of_sight_radius*self.max_line_of_sight_radius:
            return False
        object_footprint = obj.footprint_polygon
        if object_footprint is None:
            object_footprint = sims4.geometry.CompoundPolygon([sims4.geometry.Polygon([obj.position])])
        return self.constraint.geometry.polygon.intersects(object_footprint)

    def vehicle_violates_privacy(self, vehicle):
        if vehicle.objectrouting_component is None:
            return False
        if self._vehicle_tests is not None:
            resolver = SingleObjectResolver(vehicle)
            if self._vehicle_tests.run_tests(resolver):
                return False
            elif not self.intersects_with_object(vehicle):
                return False
        elif not self.intersects_with_object(vehicle):
            return False
        return True

    def find_violating_vehicles(self):
        violators = []
        privacy_service = services.privacy_service()
        for vehicle in privacy_service.get_potential_vehicle_violators():
            if self.vehicle_violates_privacy(vehicle):
                violators.append(vehicle)
        return violators

    def find_violating_sims(self, consider_exempt=True):
        if not self.is_active:
            return []
        if not self.privacy_violators & PrivacyViolators.SIM:
            return []
        check_all_surfaces_on_level = not self._routing_surface_only
        nearby_sims = placement.get_nearby_sims_gen(self.central_object.position, self._routing_surface, radius=self.max_line_of_sight_radius, exclude=self._allowed_sims, only_sim_position=True, check_all_surfaces_on_level=check_all_surfaces_on_level)
        violators = []
        for sim in nearby_sims:
            if consider_exempt and sim in self._exempt_sims:
                continue
            if any(sim_primitive.is_traversing_portal() for sim_primitive in sim.primitives if isinstance(sim_primitive, FollowPath)):
                continue
            if sim not in self._disallowed_sims and self.evaluate_sim(sim):
                continue
            if sims4.geometry.test_point_in_compound_polygon(sim.position, self.constraint.geometry.polygon):
                violators.append(sim)
        return violators

    def is_sim_shoo_exempt(self, sim):
        if sim in self._exempt_sims:
            return True
        if self.central_object.provided_routing_surface == sim.location.routing_surface:
            return False
        elif self._shoo_exempt_tests:
            resolver = SingleSimResolver(sim.sim_info)
            if self._shoo_exempt_tests.run_tests(resolver):
                return True
        return False

    def add_exempt_sim(self, sim):
        self._exempt_sims.add(sim)

    def _add_overrides_and_constraints_if_needed(self, violating_sims):
        for sim in self._allowed_sims:
            self.add_override_for_sim(sim)
        for sim in violating_sims:
            self._violators.add(sim)
            if sim in self._exempt_sims:
                continue
            liabilities = ((SHOO_LIABILITY, ShooLiability(self, sim)),)
            result = self._route_sim_away(sim, liabilities=liabilities)
            if result:
                self._pushed_interactions.append(result.interaction)

    def _cancel_unavailable_interactions(self, violating_sims):
        for sim in violating_sims:
            if sim in self._exempt_sims:
                continue
            interactions_to_cancel = set()
            if sim.queue.running is not None:
                interactions_to_cancel.add(sim.queue.running)
            for interaction in sim.si_state:
                if interaction.is_super:
                    if interaction.target is not None:
                        if sim.locked_from_obj_by_privacy(interaction.target):
                            interactions_to_cancel.add(interaction)
            for interaction in sim.queue:
                if interaction.target is not None and sim.locked_from_obj_by_privacy(interaction.target):
                    interactions_to_cancel.add(interaction)
                elif interaction.target is not None:
                    break
            for interaction in interactions_to_cancel:
                interaction.cancel(FinishingType.INTERACTION_INCOMPATIBILITY, cancel_reason_msg='Canceled due to incompatibility with privacy instance.')

    def _route_sim_away(self, sim, liabilities=()):
        context = InteractionContext(sim, InteractionContext.SOURCE_SCRIPT, Priority.High, insert_strategy=QueueInsertStrategy.NEXT)
        from interactions.utils.satisfy_constraint_interaction import BuildAndForceSatisfyShooConstraintInteraction
        result = sim.push_super_affordance(BuildAndForceSatisfyShooConstraintInteraction, None, context, liabilities=liabilities, privacy_inst=self, name_override='BuildShooFromPrivacy')
        if result:
            if self._post_route_affordance is not None:

                def route_away_callback(_):
                    post_route_context = context.clone_for_continuation(result.interaction)
                    sim.push_super_affordance(self._post_route_affordance, None, post_route_context)

                result.interaction.register_on_finishing_callback(route_away_callback)
        else:
            logger.debug('Failed to push BuildAndForceSatisfyShooConstraintInteraction on Sim {} to route them out of a privacy area.  Result: {}', sim, result, owner='tastle')
            if self.interaction is not None:
                self.interaction.cancel(FinishingType.TRANSITION_FAILURE, cancel_reason_msg='Failed to shoo Sims away.')
        return result

    def _cancel_pushed_interactions(self):
        for interaction in self._pushed_interactions:
            interaction.cancel(FinishingType.AUTO_EXIT, cancel_reason_msg='Privacy finished and is cleaning up.')
        self._pushed_interactions.clear()

    def handle_late_violator(self, sim):
        self._cancel_unavailable_interactions((sim,))
        self.add_override_for_sim(sim)
        liabilities = ((LATE_SHOO_LIABILITY, LateShooLiability(self, sim)),)
        result = self._route_sim_away(sim, liabilities=liabilities)
        if not result:
            return
        if not self._violators:
            context = InteractionContext(sim, InteractionContext.SOURCE_SCRIPT, Priority.High, insert_strategy=QueueInsertStrategy.NEXT)
            if self.interaction is None:
                result = sim.push_super_affordance(self.embarrassed_affordance, sim, context)
            else:
                result = sim.push_super_affordance(self.embarrassed_affordance, self.interaction.get_participant(ParticipantType.Actor), context)
            if not result and not services.sim_spawner_service().sim_is_leaving(sim):
                logger.warn('Failed to push the embarrassed affordance on Sim {}. Interaction {}. Result {}. Context {} ', sim, self.interaction, result, context, owner='tastle')
                return
        self._late_violators.add(sim)

    def add_override_for_sim(self, sim):
        for footprint in self._privacy_constraints:
            sim.routing_context.ignore_footprint_contour(footprint.footprint_id)

    def remove_override_for_sim(self, sim):
        for footprint in self._privacy_constraints:
            sim.routing_context.remove_footprint_contour_override(footprint.footprint_id)

    @property
    def allowed_sims(self):
        return self._allowed_sims

    @property
    def disallowed_sims(self):
        return self._disallowed_sims

    def remove_sim_from_allowed_disallowed(self, sim):
        if sim in self._allowed_sims:
            self._allowed_sims.remove(sim)
        if sim in self._disallowed_sims:
            self._disallowed_sims.remove(sim)

    @property
    def violators(self):
        return self._violators

    def remove_violator(self, sim):
        self.remove_override_for_sim(sim)
        self._violators.discard(sim)

    @property
    def late_violators(self):
        return self._late_violators

    def remove_late_violator(self, sim):
        self.remove_override_for_sim(sim)
        self._late_violators.discard(sim)
Ejemplo n.º 36
0
class HealthMonitor(object):
    """
    Monitors whether a particular host is marked as up or down.
    This class is primarily intended for internal use, although
    applications may find it useful to check whether a given node
    is up or down.
    """

    is_up = True
    """
    A boolean representing the current state of the node.
    """

    def __init__(self, conviction_policy):
        self._conviction_policy = conviction_policy
        self._host = conviction_policy.host
        # self._listeners will hold, among other things, references to
        # Cluster objects.  To allow those to be GC'ed (and shutdown) even
        # though we've implemented __del__, use weak references.
        self._listeners = WeakSet()
        self._lock = RLock()

    def register(self, listener):
        with self._lock:
            self._listeners.add(listener)

    def unregister(self, listener):
        with self._lock:
            self._listeners.remove(listener)

    def set_up(self):
        if self.is_up:
            return

        self._conviction_policy.reset()
        log.info("Host %s is considered up", self._host)

        with self._lock:
            listeners = self._listeners.copy()

        for listener in listeners:
            listener.on_up(self._host)

        self.is_up = True

    def set_down(self):
        if not self.is_up:
            return

        self.is_up = False
        log.info("Host %s is considered down", self._host)

        with self._lock:
            listeners = self._listeners.copy()

        for listener in listeners:
            listener.on_down(self._host)

    def reset(self):
        return self.set_up()

    def signal_connection_failure(self, connection_exc):
        is_down = self._conviction_policy.add_failure(connection_exc)
        if is_down:
            self.set_down()
        return is_down
Ejemplo n.º 37
0
class Hub(threading.Thread, ConnectionHandler):

    def __init__(self):
        super().__init__()
        self.__running = False
        # sockets
        self.__sockets = set()
        self.__sockets_lock = threading.RLock()
        # listeners
        self.__listeners = WeakSet()
        self.__listeners_lock = threading.Lock()

    #
    #  Listeners
    #

    def add_listener(self, listener: HubListener):
        with self.__listeners_lock:
            assert listener not in self.__listeners, 'listener already added: %s' % listener
            self.__listeners.add(listener)

    def remove_listener(self, listener: HubListener):
        with self.__listeners_lock:
            assert listener in self.__listeners, 'listener not exists: %s' % listener
            self.__listeners.remove(listener)
            return True

    #
    #  Sockets
    #

    def __any_socket(self) -> Optional[Socket]:
        """ get arbitrary socket """
        with self.__sockets_lock:
            for sock in self.__sockets:
                return sock

    def __all_sockets(self) -> set:
        """ get all sockets """
        with self.__sockets_lock:
            return self.__sockets.copy()

    def __get_sockets(self, port: int) -> set:
        """ get all sockets bond to this port """
        with self.__sockets_lock:
            matched_sockets = set()
            for sock in self.__sockets:
                assert isinstance(sock, Socket), 'socket error: %s' % sock
                if port == sock.port:
                    matched_sockets.add(sock)
            return matched_sockets

    def __get_socket(self, port: int, host: str=None) -> Optional[Socket]:
        if host is None:
            # get arbitrary socket bond to this port
            with self.__sockets_lock:
                for sock in self.__sockets:
                    assert isinstance(sock, Socket), 'socket error: %s' % sock
                    if port == sock.port:
                        return sock
        else:
            # get the socket bond to this address (host, port)
            with self.__sockets_lock:
                for sock in self.__sockets:
                    assert isinstance(sock, Socket), 'socket error: %s' % sock
                    if port == sock.port and host == sock.host:
                        return sock

    def _create_socket(self, host: str, port: int) -> Socket:
        sock = Socket(host=host, port=port)
        sock.handler = self
        sock.start()
        return sock

    def open(self, port: int, host: str='0.0.0.0') -> Socket:
        """ create a socket on this port """
        with self.__sockets_lock:
            sock = self.__get_socket(host=host, port=port)
            if sock is None:
                sock = self._create_socket(host=host, port=port)
                self.__sockets.add(sock)
            return sock

    def close(self, port: int, host: str=None) -> set:
        """ remove the socket(s) on this port """
        with self.__sockets_lock:
            closed_sockets = set()
            while True:
                sock = self.__get_socket(host=host, port=port)
                if sock is None:
                    break
                sock.close()
                closed_sockets.add(sock)
                self.__sockets.remove(sock)
            return closed_sockets

    def start(self):
        if self.isAlive():
            return
        self.__running = True
        super().start()

    def stop(self):
        self.__running = False
        # close all sockets
        with self.__sockets_lock:
            for sock in self.__sockets:
                assert isinstance(sock, Socket), 'socket error: %s' % sock
                sock.stop()
            self.__sockets.clear()

    #
    #   Connections
    #

    def get_connection(self, destination: tuple, source: tuple) -> Optional[Connection]:
        sock = self.__get_socket(host=source[0], port=source[1])
        if sock is not None:
            return sock.get_connection(remote_address=destination)

    def get_connections(self, destination: tuple, source: int=0) -> set:
        if source is 0:
            sockets = self.__all_sockets()
        else:
            sockets = self.__get_sockets(port=source)
        # get connections from these sockets
        connections = set()
        for sock in sockets:
            assert isinstance(sock, Socket), 'socket error: %s' % sock
            conn = sock.get_connection(remote_address=destination)
            if conn is not None:
                connections.add(conn)
        return connections

    def connect(self, destination: tuple, source: Union[tuple, int]=None) -> Optional[Connection]:
        """
        Connect to the destination address by the socket bond to this source

        :param destination: remote address (IP and port)
        :param source:      local address or port
        :return: connection
        """
        if source is None:
            # connect from any socket
            sock = self.__any_socket()
        elif isinstance(source, int):
            # connect from the port
            sock = self.__get_socket(port=source)
        else:
            # connect from the address
            sock = self.__get_socket(host=source[0], port=source[1])
        if sock is not None:
            return sock.connect(remote_address=destination)

    @staticmethod
    def __disconnect(destination: tuple, sockets: set) -> set:
        all_removed = set()
        for sock in sockets:
            removed = sock.disconnect(remote_address=destination)
            if len(removed) > 0:
                all_removed = all_removed.union(removed)
        return all_removed

    def disconnect(self, destination: tuple, source: Union[tuple, int]=None) -> set:
        """
        Disconnect from the destination by the socket bond to this source

        :param destination: remote address (IP and port)
        :param source:      local address or port
        :return: removed connections
        """
        if source is None:
            # disconnect from all sockets
            return self.__disconnect(destination=destination, sockets=self.__all_sockets())
        elif isinstance(source, int):
            # disconnect from sockets on this port
            return self.__disconnect(destination=destination, sockets=self.__get_sockets(port=source))
        else:
            # disconnect from the address
            sock = self.__get_socket(host=source[0], port=source[1])
            if sock is not None:
                return sock.disconnect(remote_address=destination)

    def send(self, data: bytes, destination: tuple, source: Union[tuple, int]=None) -> int:
        """
        Send data from source address(port) to destination address

        :param data:        data package
        :param destination: remote address
        :param source:      local address
        :return:
        """
        if source is None:
            # connect from any socket
            sock = self.__any_socket()
        elif isinstance(source, int):
            # connect from the port
            sock = self.__get_socket(port=source)
        else:
            # connect from the address
            sock = self.__get_socket(host=source[0], port=source[1])
        if sock is not None:
            return sock.send(data=data, remote_address=destination)

    @classmethod
    def __receive_from_sockets(cls, sockets: set) -> Optional[Cargo]:
        """ Receive data from these given sockets """
        for sock in sockets:
            assert isinstance(sock, Socket), 'socket error: %s' % sock
            packet = sock.receive()
            if packet is not None:
                # got one
                return Cargo.create(packet=packet, socket=sock)

    @classmethod
    def __block_receive_from_sockets(cls, sockets: set, timeout: float) -> Optional[Cargo]:
        """ Block to receive data from these given sockets """
        while time.time() <= timeout:
            cargo = cls.__receive_from_sockets(sockets=sockets)
            if cargo is None:
                # receive nothing, have a rest for next job
                time.sleep(0.1)
            else:
                return cargo

    FOREVER = 31558150  # 3600 * 24 * 365.25636 (365d 6h 9m 10s)

    def receive(self, host: str=None, port: int=0, timeout: float=None) -> Optional[Cargo]:
        """
        Receive data; if timeout is given, block to receive data

        :return: cargo with data and addresses
        """
        if timeout is None:
            if port is 0:
                return self.__receive_from_sockets(sockets=self.__all_sockets())
            elif host is None:
                return self.__receive_from_sockets(sockets=self.__get_sockets(port=port))
            else:
                sock = self.__get_socket(host=host, port=port)
                if sock is not None:
                    return self.__receive_from_sockets(sockets={sock})
        else:
            now = time.time()
            if timeout < 0:
                timeout = now + self.FOREVER
            else:
                timeout = now + timeout
            if port is 0:
                return self.__block_receive_from_sockets(sockets=self.__all_sockets(), timeout=timeout)
            elif host is None:
                return self.__block_receive_from_sockets(sockets=self.__get_sockets(port=port), timeout=timeout)
            else:
                sock = self.__get_socket(host=host, port=port)
                if sock is not None:
                    return self.__block_receive_from_sockets(sockets={sock}, timeout=timeout)

    def run(self):
        expired = time.time() + Connection.EXPIRES
        while self.__running:
            try:
                # try to receive data
                cargo = self.__receive_from_sockets(sockets=self.__all_sockets())
                if cargo is None:
                    # received nothing, have a rest
                    time.sleep(0.1)
                else:
                    # dispatch data and got responses
                    responses = self.__dispatch(data=cargo.data, source=cargo.source, destination=cargo.destination)
                    for res in responses:
                        self.send(data=res, destination=cargo.source, source=cargo.destination)
                # check time for next heartbeat
                now = time.time()
                if now > expired:
                    expired = now + 2
                    # try heart beat for all connections in all sockets
                    self._heartbeat()
            except Exception as error:
                print('Hub.run error: %s' % error)

    def _heartbeat(self):
        with self.__sockets_lock:
            for sock in self.__sockets:
                assert isinstance(sock, Socket), 'socket error: %s' % sock
                sock.ping()  # try to keep all connections alive
                sock.purge()  # remove error connections

    def __dispatch(self, data: bytes, source: tuple, destination: tuple) -> list:
        responses = []
        with self.__listeners_lock:
            for listener in self.__listeners:
                assert isinstance(listener, HubListener), 'listener error: %s' % listener
                f = listener.filter
                if f is not None and not f.check_data(data=data, source=source, destination=destination):
                    continue
                res = listener.data_received(data=data, source=source, destination=destination)
                if res is None:
                    continue
                responses.append(res)
        return responses

    #
    #   ConnectionHandler
    #
    def connection_status_changed(self, connection: Connection,
                                  old_status: ConnectionStatus, new_status: ConnectionStatus):
        with self.__listeners_lock:
            for listener in self.__listeners:
                assert isinstance(listener, HubListener), 'listener error: %s' % listener
                f = listener.filter
                if f is not None and not f.check_connection(connection=connection):
                    continue
                listener.status_changed(connection=connection, old_status=old_status, new_status=new_status)

    def connection_received_data(self, connection: Connection):
        # if self.__running:
        #     # process by run()
        #     return True
        # address = connection.local_address
        # cargo = self.receive(host=address[0], port=address[1])
        # if cargo is None:
        #     # assert False
        #     return False
        # # dispatch data and got responses
        # responses = self.__dispatch(data=cargo.data, source=cargo.source, destination=cargo.destination)
        # for res in responses:
        #     self.send(data=res, destination=cargo.source, source=cargo.destination)
        pass
Ejemplo n.º 38
0
class UpdateModel(object):
    """Provide the object with a way to notify other objects
      that depend on it.
    """
    
    # Slots ensures we're explicit and fast
    __slots__ = ('_sources', '_listeners', '_up_to_date',
                 '_metadata', '_notify_callback',
                 '__weakref__')
    
    def __init__(self, metadata=None, notify_callback=None, *args, **kwargs):
        """Initialize the chain.
        By tracking both sources and listeners, we can make a graph of what
          gets updated by what.
        The metadata is a bucket for runtime info to be checked during notifications.
        """
        # Initialize mixins - NOPE Update is not cooperative.
        # It expects to be a base class
        #super(UpdateModel, self).__init__(*args, **kwargs)
        self._sources = tuple()
        self._listeners = WeakSet()
        self._metadata = metadata
        self._notify_callback = notify_callback
        self._up_to_date = True

        # Initialize mixins
        super(UpdateModel, self).__init__(*args, **kwargs)


    @property
    def metadata(self):
        return self._metadata


    def subscribe(self, listener):
        """Add a listener to the subscriber list.
        This isn't a set - order will likely help efficiency,
          the list will be updated infrequently, and the list
          should never get very big anyhow.
        Note that Calc objects have a source to act as their publisher list.
          (In case we want to backtrace.)
        """
        if not listener in self._listeners:
            self._listeners.add(listener)
    
    def unsubscribe(self, listener):
        """Remove a listener from the subscriber list.
        """
        while listener in self._listeners:
            self._listeners.remove(listener)
    
    def notify(self, old_selector, new_selector, source=None, depth=0):
        """Fires an update to make sure dependents are updated, if needed.
        The selectors show what happened in the update.
        """
        for dependent in self._listeners:
            try:
                # TODO: verify that for each update, only one update is marshalled and fired
                #   for example, if an update forces a Composable to clear,
                #   then we can expect that it'll fire for both the clear _and_ the pass-thru update
                if dependent.up_to_date or old_selector:
                    dependent.update(old_selector, new_selector, source or self, depth+1)
            except NotImplementedError:
                pass
            except AttributeError:
                pass
    
        if self._notify_callback:
            try:
                self._notify_callback(old_selector, new_selector, source or self, depth)
            except:
                pass # isolate event failures
            
    def update(self, old_selector, new_selector, source=None, depth=0):
        """Execute the update. Each class will have its own way to implement this."""
        # (None, None) signals that the data is out of date, 
        #  but there is nothing for dependents to do yet.
        self._up_to_date = False
        # Pass-through updates without triggering
        self.notify(old_selector, new_selector, source or self, depth)

        # NOTE: super calls in subclasses should mark up_to_date when they're brought up
    
    @property
    def listeners(self):
        return self._listeners
    
    @property
    def up_to_date(self):
        return self._up_to_date    

    @listeners.setter
    def listeners(self, new_listeners):
        self._replace_listeners(new_listeners)
    
    def _replace_listeners(self, new_listeners):        
        """If the listeners are changed en masse, break
           all the subscriptions.
           This setter makes sure the subscription methods are never skipped.
        """
        while self._listeners:
            listener = self._listeners[0]
            self.unsubscribe(listener)
            
        for listener in new_listeners:
            self.subscribe(listener)
        
    @property
    def sources(self):
        return self._sources
    
    @sources.setter
    def sources(self, new_sources):
        self._replace_sources(new_sources)
    
    def _replace_sources(self, new_sources):
        for source in set(self._sources).difference(set(new_sources)):
            source.unsubscribe(self)
        for source in new_sources:
            source.subscribe(self)
        self._sources = new_sources
Ejemplo n.º 39
0
class CallbackCollection(Set):
    __slots__ = "__sender", "__callbacks", "__weak_callbacks", "__lock"

    def __init__(self, sender):
        self.__sender = ref(sender)
        self.__callbacks = set()
        self.__weak_callbacks = WeakSet()
        self.__lock = Lock()

    def add(self, callback: Callable, weak=True):
        if self.is_frozen:
            raise RuntimeError("Collection frozen")
        if not callable(callback):
            raise ValueError("Callback is not callable")

        with self.__lock:
            if weak:
                self.__weak_callbacks.add(callback)
            else:
                self.__callbacks.add(callback)

    def remove(self, callback: Callable):
        if self.is_frozen:
            raise RuntimeError("Collection frozen")

        with self.__lock:
            try:
                self.__callbacks.remove(callback)
            except KeyError:
                self.__weak_callbacks.remove(callback)

    def clear(self):
        if self.is_frozen:
            raise RuntimeError("Collection frozen")

        with self.__lock:
            self.__callbacks.clear()
            self.__weak_callbacks.clear()

    @property
    def is_frozen(self) -> bool:
        return isinstance(self.__callbacks, frozenset)

    def freeze(self):
        if self.is_frozen:
            raise RuntimeError("Collection already frozen")

        with self.__lock:
            self.__callbacks = frozenset(self.__callbacks)
            self.__weak_callbacks = WeakSet(self.__weak_callbacks)

    def unfreeze(self):
        if not self.is_frozen:
            raise RuntimeError("Collection is not frozen")

        with self.__lock:
            self.__callbacks = set(self.__callbacks)
            self.__weak_callbacks = WeakSet(self.__weak_callbacks)

    def __contains__(self, x: object) -> bool:
        return x in self.__callbacks or x in self.__weak_callbacks

    def __len__(self) -> int:
        return len(self.__callbacks) + len(self.__weak_callbacks)

    def __iter__(self) -> Iterable[Callable]:
        return iter(chain(self.__callbacks, self.__weak_callbacks))

    def __bool__(self):
        return bool(self.__callbacks) or bool(self.__weak_callbacks)

    def __copy__(self):
        instance = self.__class__(self.__sender())

        with self.__lock:
            for cb in self.__callbacks:
                instance.add(cb, weak=False)

            for cb in self.__weak_callbacks:
                instance.add(cb, weak=True)

        if self.is_frozen:
            instance.freeze()

        return instance

    def __call__(self, *args, **kwargs):
        with self.__lock:
            for cb in self:
                try:
                    cb(self.__sender(), *args, **kwargs)
                except Exception:
                    log.exception("Callback error")
Ejemplo n.º 40
0
class MountManager:
    _running = False
    _last_run = None
    _stop = False
    _mounting = False
    def __init__(self, latency):
        self.latency = latency
        self.mounts = WeakKeyDictionary()
        self.contexts = WeakSet()
        self.lock = RLock()
        self.cell_updates = deque()
        self._tick = Event()
        self.paths = WeakKeyDictionary()

    @lockmethod
    def add_mount(self, cell, path, mode, authority, persistent, **kwargs):
        root = cell._root()
        if root not in self.paths:
            paths = set()
            self.paths[root] = paths
        else:
            paths = self.paths[root]
        assert path not in paths, path
        #print("add mount", path, cell)
        paths.add(path)
        item = MountItem(self, cell, path, mode, authority, persistent, **kwargs)
        self.mounts[cell] = item
        return item

    @lockmethod
    def add_link(self, link, path, persistent):
        paths = self.paths[link._root()]
        assert path not in paths, path
        #print("add link", path, link)
        paths.add(path)
        item = LinkItem(link, path, persistent)
        self.mounts[link] = item
        return item

    @lockmethod
    def unmount(self, cell_or_link, from_del=False):
        assert not is_dummy_mount(cell_or_link._mount), cell_or_link
        root = cell_or_link._root()
        if from_del and (cell_or_link not in self.mounts or root not in self.paths):
            return
        mountitem = self.mounts.pop(cell_or_link)
        if not mountitem._destroyed:
            paths = self.paths[root]
            path = cell_or_link._mount["path"]
            paths.discard(path)            
            mountitem.destroy()

    @lockmethod
    def unmount_context(self, context, from_del=False):
        if context in self.contexts:
            self.contexts.remove(context)
        elif not from_del:
            return
        mount = context._mount
        if context._root() is context:
            self.paths.pop(context, None)
            if mount is None:
                return
        #print("unmount context", context)
        assert not is_dummy_mount(mount), context
        try:
            paths = self.paths[context._root()]
        except KeyError:
            if not from_del:
                return
            paths = set()
        try:
            paths.remove(mount["path"])
        except KeyError:
            pass
        if mount["persistent"] == False:
            dirpath = mount["path"].replace("/", os.sep)
            try:
                #print("rmdir", dirpath)
                os.rmdir(dirpath)
            except:
                print("Error: cannot remove directory %s" % dirpath)

    @lockmethod
    def add_context(self, context, path, as_parent):
        #print("add context", path, context, as_parent, context._mount["persistent"])
        paths = self.paths[context._root()]
        if not as_parent:
            if context not in self.contexts:
                assert path not in paths, path
                paths.add(path)
                self.contexts.add(context)
        else:
            if path in paths:
                assert context in self.contexts, (path, context)        

    def _check_context(self, context, as_parent):
        mount = context._mount
        assert not is_dummy_mount(mount), context
        dirpath = mount["path"].replace("/", os.sep)
        persistent, authority = mount["persistent"], mount["authority"]
        if os.path.exists(dirpath):
            if authority == "cell" and not as_parent:
                print("Warning: Directory path '%s' already exists" % dirpath) #TODO: log warning
        else:
            if authority == "file-strict":
                raise Exception("Directory path '%s' does not exist, but authority is 'file-strict'" % dirpath)
            os.mkdir(dirpath)

    @lockmethod
    def add_cell_update(self, cell):
        if self._mounting:
            return
        assert cell in self.mounts, (cell, hex(id(cell)))
        self.cell_updates.append(cell)

    def _run(self):
        for cell, mount_item in list(self.mounts.items()):
            if isinstance(cell, Link):
                continue
            if cell in self.cell_updates:
                continue
            try:
                mount_item.conditional_read()
            except Exception:
                exc = traceback.format_exc()
                if exc != mount_item.last_exc:
                    print(exc)
                    mount_item.last_exc = exc
        while 1:
            try:
                cell = self.cell_updates.popleft()
            except IndexError:
                break
            mount_item = self.mounts.get(cell)
            if mount_item is None: #cell was deleted
                continue
            try:
                mount_item.conditional_write(with_none=True)
            except Exception:
                exc = traceback.format_exc()
                if exc != mount_item.last_exc:
                    print(exc)
                    mount_item.last_exc = exc
        self._tick.set()

    def run(self):
        try:
            self._running = True
            while not self._stop:
                t = time.time()
                self._run()
                while time.time() - t < self.latency:
                    if not self._tick.is_set():
                        break
                    time.sleep(0.01)
        finally:
            self._running = False

    def start(self):
        self._stop = False
        t = self.thread = Thread(target=self.run)
        t.setDaemon(True)
        t.start()

    def stop(self, wait=False, waiting_loop_period=0.01):
        self._stop = True
        if wait:
            while self._running:
                time.sleep(waiting_loop_period)

    def tick(self):
        """Waits until one iteration of the run() loop has finished"""
        if self._running:
            self._tick.clear()
            self._tick.wait()

    def destroy(self):
        for path in list(self.mounts.keys()):
            self.unmount(path)
        for context in sorted(self.contexts,key=lambda l:-len(l.path)):
            self.unmount_context(context)
Ejemplo n.º 41
0
class Signal(object):
    """Signal/slot implementation.

    Author:  Thiago Marcos P. Santos
    Author:  Christopher S. Case
    Author:  David H. Bronke
    Created: August 28, 2008
    Updated: December 12, 2011
    License: MIT

    Sample usage:
    \code
    class Model(object):
        def __init__(self, value):
            self.__value = value
            self.changed = Signal()

        def set_value(self, value):
            self.__value = value
            self.changed()  # Emit signal

        def get_value(self):
            return self.__value

    class View(object):
        def __init__(self, model):
            self.model = model
            model.changed.connect(self.model_changed)

        def model_changed(self):
            print("   New value:", self.model.get_value())

    print("Beginning Tests:")
    model = Model(10)
    view1 = View(model)
    view2 = View(model)
    view3 = View(model)

    print("Setting value to 20...")
    model.set_value(20)

    print("Deleting a view, and setting value to 30...")
    del view1
    model.set_value(30)

    print("Clearing all listeners, and setting value to 40...")
    model.changed.clear()
    model.set_value(40)

    print("Testing non-member function...")

    def bar():
        print("   Calling Non Class Function!")

    model.changed.connect(bar)
    model.set_value(50)
    \endcode
    """

    def __init__(self):
        """Initialize a new signal"""
        self._functions = WeakSet()
        self._methods = WeakKeyDictionary()

    def __call__(self, *args, **kargs):
        """Emits the signal and calls all connections"""
        # Call handler functions
        for func in self._functions:
            func(*args, **kargs)

        # Call handler methods
        for obj, funcs in self._methods.items():
            for func in funcs:
                func(obj, *args, **kargs)

    def connect(self, slot):
        """Connects a slot to the signal so that when the signal is emitted, the slot is called."""
        if inspect.ismethod(slot):
            if slot.__self__ not in self._methods:
                self._methods[slot.__self__] = set()

            self._methods[slot.__self__].add(slot.__func__)

        else:
            self._functions.add(slot)

    def disconnect(self, slot):
        """Disconnects a slot from the signal"""
        if inspect.ismethod(slot):
            if slot.__self__ in self._methods:
                self._methods[slot.__self__].remove(slot.__func__)
        else:
            if slot in self._functions:
                self._functions.remove(slot)

    def clear(self):
        """Removes all slots from the signal"""
        self._functions.clear()
        self._methods.clear()
Ejemplo n.º 42
0
class ElementVisual:
    def __init__(self, diagram, object):
        self.__cache = ModelTemporaryDataCache(self.__create_appearance_object)
        self.__cache.depend_on(object.cache)

        self.__diagram = ref(diagram)

        self.__object = object
        self.__cached_appearance = None
        self.__position = Point(0, 0)
        self.__size = None
        self.__connections = WeakSet()

    def add_connection(self, connection):
        if connection.source != self and connection.destination != self:
            raise Exception(
                "Cannot add connection not connected to the element")

        self.__connections.add(connection)

    def remove_connection(self, connection):
        if connection.source != self and connection.destination != self:
            raise Exception(
                "Cannot remove connection not connected to the element")

        self.__connections.remove(connection)

    @property
    def cache(self):
        return self.__cache

    @property
    def object(self):
        return self.__object

    @property
    def diagram(self):
        return self.__diagram()

    @property
    def connections(self):
        yield from self.__connections

    def get_position(self, ruler):
        self.__cache.ensure_valid(ruler=ruler)

        return self.__position

    def get_size(self, ruler):
        self.__cache.ensure_valid(ruler=ruler)

        return self.__size

    def get_minimal_size(self, ruler):
        self.__cache.ensure_valid(ruler=ruler)

        return self.__cached_appearance.get_minimal_size()

    def get_bounds(self, ruler):
        self.__cache.ensure_valid(ruler=ruler)

        return Rectangle.from_point_size(self.__position, self.__size)

    def draw(self, canvas):
        self.__cache.ensure_valid(ruler=canvas.get_ruler())

        self.__cached_appearance.draw(canvas)

    def resize(self, ruler, new_size):
        self.__size = new_size

        self.__cache.invalidate()

    def move(self, ruler, new_position):
        self.__position = new_position

        self.__cache.invalidate()

    def is_at_position(self, ruler, position):
        return self.get_bounds(ruler).contains(position)

    def is_resizable(self, ruler):
        self.__cache.ensure_valid(ruler=ruler)

        return self.__cached_appearance.is_resizable()

    def __create_appearance_object(self, ruler):
        self.__cached_appearance = self.__object.create_appearance_object(
            ruler)
        self.__cached_appearance.move(self.__position)
        min_size = self.__cached_appearance.get_minimal_size()

        if self.__size is None:
            self.__size = min_size
        else:
            undersize_width = self.__size.width < min_size.width
            undersize_height = self.__size.height < min_size.height

            resizable_x, resizable_y = self.__cached_appearance.is_resizable()

            if (undersize_width and undersize_height) or (not resizable_x
                                                          and not resizable_y):
                self.__size = min_size
            else:
                if undersize_width or not resizable_x:
                    self.__size = Size(min_size.width, self.__size.height)
                elif undersize_height or not resizable_y:
                    self.__size = Size(self.__size.width, min_size.height)

                self.__cached_appearance.resize(self.__size)
Ejemplo n.º 43
0
class TestWeakSet(unittest.TestCase):

    def setUp(self):
        # need to keep references to them
        self.items = [SomeClass(c) for c in ('a', 'b', 'c')]
        self.items2 = [SomeClass(c) for c in ('x', 'y', 'z')]
        self.letters = [SomeClass(c) for c in string.ascii_letters]
        self.s = WeakSet(self.items)
        self.d = dict.fromkeys(self.items)
        self.obj = SomeClass('F')
        self.fs = WeakSet([self.obj])

    def test_methods(self):
        weaksetmethods = dir(WeakSet)
        for method in dir(set):
            if method == 'test_c_api' or method.startswith('_'):
                continue
            self.assertIn(method, weaksetmethods,
                         "WeakSet missing method " + method)

    def test_new_or_init(self):
        self.assertRaises(TypeError, WeakSet, [], 2)

    def test_len(self):
        self.assertEqual(len(self.s), len(self.d))
        self.assertEqual(len(self.fs), 1)
        del self.obj
        self.assertEqual(len(self.fs), 0)

    def test_contains(self):
        for c in self.letters:
            self.assertEqual(c in self.s, c in self.d)
        # 1 is not weakref'able, but that TypeError is caught by __contains__
        self.assertNotIn(1, self.s)
        self.assertIn(self.obj, self.fs)
        del self.obj
        self.assertNotIn(SomeClass('F'), self.fs)

    def test_union(self):
        u = self.s.union(self.items2)
        for c in self.letters:
            self.assertEqual(c in u, c in self.d or c in self.items2)
        self.assertEqual(self.s, WeakSet(self.items))
        self.assertEqual(type(u), WeakSet)
        self.assertRaises(TypeError, self.s.union, [[]])
        for C in set, frozenset, dict.fromkeys, list, tuple:
            x = WeakSet(self.items + self.items2)
            c = C(self.items2)
            self.assertEqual(self.s.union(c), x)

    def test_or(self):
        i = self.s.union(self.items2)
        self.assertEqual(self.s | set(self.items2), i)
        self.assertEqual(self.s | frozenset(self.items2), i)

    def test_intersection(self):
        i = self.s.intersection(self.items2)
        for c in self.letters:
            self.assertEqual(c in i, c in self.d and c in self.items2)
        self.assertEqual(self.s, WeakSet(self.items))
        self.assertEqual(type(i), WeakSet)
        for C in set, frozenset, dict.fromkeys, list, tuple:
            x = WeakSet([])
            self.assertEqual(self.s.intersection(C(self.items2)), x)

    def test_isdisjoint(self):
        self.assertTrue(self.s.isdisjoint(WeakSet(self.items2)))
        self.assertTrue(not self.s.isdisjoint(WeakSet(self.letters)))

    def test_and(self):
        i = self.s.intersection(self.items2)
        self.assertEqual(self.s & set(self.items2), i)
        self.assertEqual(self.s & frozenset(self.items2), i)

    def test_difference(self):
        i = self.s.difference(self.items2)
        for c in self.letters:
            self.assertEqual(c in i, c in self.d and c not in self.items2)
        self.assertEqual(self.s, WeakSet(self.items))
        self.assertEqual(type(i), WeakSet)
        self.assertRaises(TypeError, self.s.difference, [[]])

    def test_sub(self):
        i = self.s.difference(self.items2)
        self.assertEqual(self.s - set(self.items2), i)
        self.assertEqual(self.s - frozenset(self.items2), i)

    def test_symmetric_difference(self):
        i = self.s.symmetric_difference(self.items2)
        for c in self.letters:
            self.assertEqual(c in i, (c in self.d) ^ (c in self.items2))
        self.assertEqual(self.s, WeakSet(self.items))
        self.assertEqual(type(i), WeakSet)
        self.assertRaises(TypeError, self.s.symmetric_difference, [[]])

    def test_xor(self):
        i = self.s.symmetric_difference(self.items2)
        self.assertEqual(self.s ^ set(self.items2), i)
        self.assertEqual(self.s ^ frozenset(self.items2), i)

    def test_sub_and_super(self):
        pl, ql, rl = map(lambda s: [SomeClass(c) for c in s], ['ab', 'abcde', 'def'])
        p, q, r = map(WeakSet, (pl, ql, rl))
        self.assertTrue(p < q)
        self.assertTrue(p <= q)
        self.assertTrue(q <= q)
        self.assertTrue(q > p)
        self.assertTrue(q >= p)
        self.assertFalse(q < r)
        self.assertFalse(q <= r)
        self.assertFalse(q > r)
        self.assertFalse(q >= r)
        self.assertTrue(set('a').issubset('abc'))
        self.assertTrue(set('abc').issuperset('a'))
        self.assertFalse(set('a').issubset('cbs'))
        self.assertFalse(set('cbs').issuperset('a'))

    def test_gc(self):
        # Create a nest of cycles to exercise overall ref count check
        s = WeakSet(Foo() for i in range(1000))
        for elem in s:
            elem.cycle = s
            elem.sub = elem
            elem.set = WeakSet([elem])

    def test_subclass_with_custom_hash(self):
        # Bug #1257731
        class H(WeakSet):
            def __hash__(self):
                return int(id(self) & 0x7fffffff)
        s=H()
        f=set()
        f.add(s)
        self.assertIn(s, f)
        f.remove(s)
        f.add(s)
        f.discard(s)

    def test_init(self):
        s = WeakSet()
        s.__init__(self.items)
        self.assertEqual(s, self.s)
        s.__init__(self.items2)
        self.assertEqual(s, WeakSet(self.items2))
        self.assertRaises(TypeError, s.__init__, s, 2);
        self.assertRaises(TypeError, s.__init__, 1);

    def test_constructor_identity(self):
        s = WeakSet(self.items)
        t = WeakSet(s)
        self.assertNotEqual(id(s), id(t))

    def test_hash(self):
        self.assertRaises(TypeError, hash, self.s)

    def test_clear(self):
        self.s.clear()
        self.assertEqual(self.s, WeakSet([]))
        self.assertEqual(len(self.s), 0)

    def test_copy(self):
        dup = self.s.copy()
        self.assertEqual(self.s, dup)
        self.assertNotEqual(id(self.s), id(dup))

    def test_add(self):
        x = SomeClass('Q')
        self.s.add(x)
        self.assertIn(x, self.s)
        dup = self.s.copy()
        self.s.add(x)
        self.assertEqual(self.s, dup)
        self.assertRaises(TypeError, self.s.add, [])
        self.fs.add(Foo())
        self.assertTrue(len(self.fs) == 1)
        self.fs.add(self.obj)
        self.assertTrue(len(self.fs) == 1)

    def test_remove(self):
        x = SomeClass('a')
        self.s.remove(x)
        self.assertNotIn(x, self.s)
        self.assertRaises(KeyError, self.s.remove, x)
        self.assertRaises(TypeError, self.s.remove, [])

    def test_discard(self):
        a, q = SomeClass('a'), SomeClass('Q')
        self.s.discard(a)
        self.assertNotIn(a, self.s)
        self.s.discard(q)
        self.assertRaises(TypeError, self.s.discard, [])

    def test_pop(self):
        for i in range(len(self.s)):
            elem = self.s.pop()
            self.assertNotIn(elem, self.s)
        self.assertRaises(KeyError, self.s.pop)

    def test_update(self):
        retval = self.s.update(self.items2)
        self.assertEqual(retval, None)
        for c in (self.items + self.items2):
            self.assertIn(c, self.s)
        self.assertRaises(TypeError, self.s.update, [[]])

    def test_update_set(self):
        self.s.update(set(self.items2))
        for c in (self.items + self.items2):
            self.assertIn(c, self.s)

    def test_ior(self):
        self.s |= set(self.items2)
        for c in (self.items + self.items2):
            self.assertIn(c, self.s)

    def test_intersection_update(self):
        retval = self.s.intersection_update(self.items2)
        self.assertEqual(retval, None)
        for c in (self.items + self.items2):
            if c in self.items2 and c in self.items:
                self.assertIn(c, self.s)
            else:
                self.assertNotIn(c, self.s)
        self.assertRaises(TypeError, self.s.intersection_update, [[]])

    def test_iand(self):
        self.s &= set(self.items2)
        for c in (self.items + self.items2):
            if c in self.items2 and c in self.items:
                self.assertIn(c, self.s)
            else:
                self.assertNotIn(c, self.s)

    def test_difference_update(self):
        retval = self.s.difference_update(self.items2)
        self.assertEqual(retval, None)
        for c in (self.items + self.items2):
            if c in self.items and c not in self.items2:
                self.assertIn(c, self.s)
            else:
                self.assertNotIn(c, self.s)
        self.assertRaises(TypeError, self.s.difference_update, [[]])
        self.assertRaises(TypeError, self.s.symmetric_difference_update, [[]])

    def test_isub(self):
        self.s -= set(self.items2)
        for c in (self.items + self.items2):
            if c in self.items and c not in self.items2:
                self.assertIn(c, self.s)
            else:
                self.assertNotIn(c, self.s)

    def test_symmetric_difference_update(self):
        retval = self.s.symmetric_difference_update(self.items2)
        self.assertEqual(retval, None)
        for c in (self.items + self.items2):
            if (c in self.items) ^ (c in self.items2):
                self.assertIn(c, self.s)
            else:
                self.assertNotIn(c, self.s)
        self.assertRaises(TypeError, self.s.symmetric_difference_update, [[]])

    def test_ixor(self):
        self.s ^= set(self.items2)
        for c in (self.items + self.items2):
            if (c in self.items) ^ (c in self.items2):
                self.assertIn(c, self.s)
            else:
                self.assertNotIn(c, self.s)

    def test_inplace_on_self(self):
        t = self.s.copy()
        t |= t
        self.assertEqual(t, self.s)
        t &= t
        self.assertEqual(t, self.s)
        t -= t
        self.assertEqual(t, WeakSet())
        t = self.s.copy()
        t ^= t
        self.assertEqual(t, WeakSet())

    def test_eq(self):
        # issue 5964
        self.assertTrue(self.s == self.s)
        self.assertTrue(self.s == WeakSet(self.items))
        self.assertFalse(self.s == set(self.items))
        self.assertFalse(self.s == list(self.items))
        self.assertFalse(self.s == tuple(self.items))
        self.assertFalse(self.s == 1)

    def test_weak_destroy_while_iterating(self):
        # Issue #7105: iterators shouldn't crash when a key is implicitly removed
        # Create new items to be sure no-one else holds a reference
        items = [SomeClass(c) for c in ('a', 'b', 'c')]
        s = WeakSet(items)
        it = iter(s)
        next(it)             # Trigger internal iteration
        # Destroy an item
        del items[-1]
        gc.collect()    # just in case
        # We have removed either the first consumed items, or another one
        self.assertIn(len(list(it)), [len(items), len(items) - 1])
        del it
        # The removal has been committed
        self.assertEqual(len(s), len(items))

    def test_weak_destroy_and_mutate_while_iterating(self):
        # Issue #7105: iterators shouldn't crash when a key is implicitly removed
        items = [SomeClass(c) for c in string.ascii_letters]
        s = WeakSet(items)
        @contextlib.contextmanager
        def testcontext():
            try:
                it = iter(s)
                next(it)
                # Schedule an item for removal and recreate it
                u = SomeClass(str(items.pop()))
                gc.collect()      # just in case
                yield u
            finally:
                it = None           # should commit all removals

        with testcontext() as u:
            self.assertNotIn(u, s)
        with testcontext() as u:
            self.assertRaises(KeyError, s.remove, u)
        self.assertNotIn(u, s)
        with testcontext() as u:
            s.add(u)
        self.assertIn(u, s)
        t = s.copy()
        with testcontext() as u:
            s.update(t)
        self.assertEqual(len(s), len(t))
        with testcontext() as u:
            s.clear()
        self.assertEqual(len(s), 0)
Ejemplo n.º 44
0
class Signal(object):
    """ basic signal emitter
	fired signals are added to this object's calling frame -
	if this becomes excessive, this
	also includes mode to add function calls to queue
	instead of directly firing connnected functions

	queue support not complete yet, as nothing I use needs it.
	"""

    queues = {"default": deque()}
    debugConnection = False

    def __init__(self, name="", queue="", useQueue=False):
        """:param queue : name of queue to use, or external queue object """
        self.name = name
        self._functions = WeakSet()
        self._methods = WeakKeyDictionary()

        # separate register for references to explicitly strong functions
        # they are still placed in main weak sets above,
        # little bit spaghetti
        self._strongItemRefs = set()

        # is signal active
        self._active = True

        # event queue support
        self._useQueue = useQueue
        self._queue = queue or "default"

    def __hash__(self):
        return hash(id(self))

    def __repr__(self):
        return f"Signal({self.name})"

    def __call__(self, *args, **kwargs):
        #print("emit", self.debugLog())
        if not self._active:
            return

        queue = self.getQueue()
        # Call handler functions
        for func in list(self._functions):
            if self._useQueue:
                queue.append(partial(func, *args, **kwargs))
            else:
                func(*args, **kwargs)

        # Call handler methods
        for obj, funcs in dict(self._methods).items():
            for func in funcs:
                if self._useQueue:
                    queue.append(partial(func, obj, *args, **kwargs))
                else:
                    func(obj, *args, **kwargs)

    def debugLog(self):
        return str((*self._functions, dict(self._methods)))

    def activate(self):
        self._active = True

    def mute(self):
        self._active = False

    def getQueue(self, name="default", create=True):
        """return one of the event queues attended by signal objects"""
        name = name or self._queue or "default"
        if not name in self.queues and create:
            self.queues[name] = deque()
        return self.queues[name]

    def setQueue(self, queueName):
        """ set signal to use given queue """
        self._queue = queueName

    def emit(self, *args, **kwargs):
        """ brings this object up to rough parity with qt signals """
        self(*args, **kwargs)

    def connect(self, slot, strong=False):
        """add given callable to function or method register
		flag as strong to allow local lambdas or closures"""

        if inspect.ismethod(slot):
            if self.debugConnection:
                print()
            try:
                hash(slot.__self__)
                if slot.__self__ not in self._methods:
                    self._methods[slot.__self__] = set()

                self._methods[slot.__self__].add(slot.__func__)
            except TypeError:
                self._functions.add(slot)
                pass
        else:
            self._functions.add(slot)

        if strong:
            self._strongItemRefs.add(slot)

    def disconnect(self, slot):
        if inspect.ismethod(slot):
            try:
                hash(slot.__self__)
                if slot.__self__ in self._methods:
                    self._methods[slot.__self__].remove(slot.__func__)
                    return
            except TypeError:
                # self._functions.remove(slot)
                pass

        if slot in self._functions:
            self._functions.remove(slot)

        if slot in self._strongItemRefs:
            self._strongItemRefs.remove(slot)

    def disconnectFromPool(self, pool):
        """remove any function in the pool from signal's connections
		"""
        for fn in pool:
            self.disconnect(fn)

    def clear(self):
        self._functions.clear()
        self._methods.clear()
Ejemplo n.º 45
0
class Signal(object):
    """ class for signal slot concept

    Example
    -------

    A simple example for a callback is
    >>> event = Signal()
    >>> event.connect(mfunc)
    >>> # raise the signal
    >>> event("hello")
    >>>
    >>> # functions can be disconnected
    >>> even.disconnect(myfunc)

    Since weak references are used, care has to be taken with object functions

    >>> obj = MyClass()
    >>> event.connect(obj.myfunc) # works
    >>> event.connect(MyClass().myfunc) # will not work

    The second example for member functions will not work since the Signal class
    uses weakref and therefore does not increase the reference counter. MyClass()
    only exists for the time of the function call and will be deleted afterwards
    and the weakref will become invalid.

    """
    
    def __init__(self):
        self._functions = WeakSet()
        self._methods = WeakKeyDictionary()

    def __call__(self, *args, **kargs):
        """ raise the event """
        # Call handler functions
        for func in self._functions:
            func(*args, **kargs)

        # Call handler methods
        for obj, funcs in self._methods.items():
            for func in funcs:
                func(obj, *args, **kargs)

    def connect(self, slot):
        """ connect a function / member function to the signal """
        if inspect.ismethod(slot):
            if slot.__self__ not in self._methods:
                self._methods[slot.__self__] = set()

            self._methods[slot.__self__].add(slot.__func__)

        else:
            self._functions.add(slot)

    def disconnect(self, slot):
        """ disconnect a function from the signal """
        if inspect.ismethod(slot):
            if slot.__self__ in self._methods:
                self._methods[slot.__self__].remove(slot.__func__)
        else:
            if slot in self._functions:
                self._functions.remove(slot)

    def clear(self):
        """ remove all callbacks from the signal """
        self._functions.clear()
        self._methods.clear()
Ejemplo n.º 46
0
class TestWeakSet(unittest.TestCase):

    def setUp(self):
        # need to keep references to them
        self.items = [ustr(c) for c in ('a', 'b', 'c')]
        self.items2 = [ustr(c) for c in ('x', 'y', 'z')]
        self.ab_items = [ustr(c) for c in 'ab']
        self.abcde_items = [ustr(c) for c in 'abcde']
        self.def_items = [ustr(c) for c in 'def']
        self.ab_weakset = WeakSet(self.ab_items)
        self.abcde_weakset = WeakSet(self.abcde_items)
        self.def_weakset = WeakSet(self.def_items)
        self.letters = [ustr(c) for c in string.ascii_letters]
        self.s = WeakSet(self.items)
        self.d = dict.fromkeys(self.items)
        self.obj = ustr('F')
        self.fs = WeakSet([self.obj])

    def test_methods(self):
        weaksetmethods = dir(WeakSet)
        for method in dir(set):
            if method == 'test_c_api' or method.startswith('_'):
                continue
            self.assertIn(method, weaksetmethods,
                         "WeakSet missing method " + method)

    def test_new_or_init(self):
        self.assertRaises(TypeError, WeakSet, [], 2)

    def test_len(self):
        self.assertEqual(len(self.s), len(self.d))
        self.assertEqual(len(self.fs), 1)
        del self.obj
        support.gc_collect()
        self.assertEqual(len(self.fs), 0)

    def test_contains(self):
        for c in self.letters:
            self.assertEqual(c in self.s, c in self.d)
        # 1 is not weakref'able, but that TypeError is caught by __contains__
        self.assertNotIn(1, self.s)
        self.assertIn(self.obj, self.fs)
        del self.obj
        support.gc_collect()
        self.assertNotIn(ustr('F'), self.fs)

    def test_union(self):
        u = self.s.union(self.items2)
        for c in self.letters:
            self.assertEqual(c in u, c in self.d or c in self.items2)
        self.assertEqual(self.s, WeakSet(self.items))
        self.assertEqual(type(u), WeakSet)
        self.assertRaises(TypeError, self.s.union, [[]])
        for C in set, frozenset, dict.fromkeys, list, tuple:
            x = WeakSet(self.items + self.items2)
            c = C(self.items2)
            self.assertEqual(self.s.union(c), x)
            del c
        self.assertEqual(len(u), len(self.items) + len(self.items2))
        self.items2.pop()
        gc.collect()
        self.assertEqual(len(u), len(self.items) + len(self.items2))

    def test_or(self):
        i = self.s.union(self.items2)
        self.assertEqual(self.s | set(self.items2), i)
        self.assertEqual(self.s | frozenset(self.items2), i)

    def test_intersection(self):
        s = WeakSet(self.letters)
        i = s.intersection(self.items2)
        for c in self.letters:
            self.assertEqual(c in i, c in self.items2 and c in self.letters)
        self.assertEqual(s, WeakSet(self.letters))
        self.assertEqual(type(i), WeakSet)
        for C in set, frozenset, dict.fromkeys, list, tuple:
            x = WeakSet([])
            self.assertEqual(i.intersection(C(self.items)), x)
        self.assertEqual(len(i), len(self.items2))
        self.items2.pop()
        gc.collect()
        self.assertEqual(len(i), len(self.items2))

    def test_isdisjoint(self):
        self.assertTrue(self.s.isdisjoint(WeakSet(self.items2)))
        self.assertTrue(not self.s.isdisjoint(WeakSet(self.letters)))

    def test_and(self):
        i = self.s.intersection(self.items2)
        self.assertEqual(self.s & set(self.items2), i)
        self.assertEqual(self.s & frozenset(self.items2), i)

    def test_difference(self):
        i = self.s.difference(self.items2)
        for c in self.letters:
            self.assertEqual(c in i, c in self.d and c not in self.items2)
        self.assertEqual(self.s, WeakSet(self.items))
        self.assertEqual(type(i), WeakSet)
        self.assertRaises(TypeError, self.s.difference, [[]])

    def test_sub(self):
        i = self.s.difference(self.items2)
        self.assertEqual(self.s - set(self.items2), i)
        self.assertEqual(self.s - frozenset(self.items2), i)

    def test_symmetric_difference(self):
        i = self.s.symmetric_difference(self.items2)
        for c in self.letters:
            self.assertEqual(c in i, (c in self.d) ^ (c in self.items2))
        self.assertEqual(self.s, WeakSet(self.items))
        self.assertEqual(type(i), WeakSet)
        self.assertRaises(TypeError, self.s.symmetric_difference, [[]])
        self.assertEqual(len(i), len(self.items) + len(self.items2))
        self.items2.pop()
        gc.collect()
        self.assertEqual(len(i), len(self.items) + len(self.items2))

    def test_xor(self):
        i = self.s.symmetric_difference(self.items2)
        self.assertEqual(self.s ^ set(self.items2), i)
        self.assertEqual(self.s ^ frozenset(self.items2), i)

    def test_sub_and_super(self):
        self.assertTrue(self.ab_weakset <= self.abcde_weakset)
        self.assertTrue(self.abcde_weakset <= self.abcde_weakset)
        self.assertTrue(self.abcde_weakset >= self.ab_weakset)
        self.assertFalse(self.abcde_weakset <= self.def_weakset)
        self.assertFalse(self.abcde_weakset >= self.def_weakset)
        self.assertTrue(set('a').issubset('abc'))
        self.assertTrue(set('abc').issuperset('a'))
        self.assertFalse(set('a').issubset('cbs'))
        self.assertFalse(set('cbs').issuperset('a'))

    def test_lt(self):
        self.assertTrue(self.ab_weakset < self.abcde_weakset)
        self.assertFalse(self.abcde_weakset < self.def_weakset)
        self.assertFalse(self.ab_weakset < self.ab_weakset)
        self.assertFalse(WeakSet() < WeakSet())

    def test_gt(self):
        self.assertTrue(self.abcde_weakset > self.ab_weakset)
        self.assertFalse(self.abcde_weakset > self.def_weakset)
        self.assertFalse(self.ab_weakset > self.ab_weakset)
        self.assertFalse(WeakSet() > WeakSet())

    def test_gc(self):
        # Create a nest of cycles to exercise overall ref count check
        s = WeakSet(Foo() for i in range(1000))
        for elem in s:
            elem.cycle = s
            elem.sub = elem
            elem.set = WeakSet([elem])

    def test_subclass_with_custom_hash(self):
        # Bug #1257731
        class H(WeakSet):
            def __hash__(self):
                return int(id(self) & 0x7fffffff)
        s=H()
        f=set()
        f.add(s)
        self.assertIn(s, f)
        f.remove(s)
        f.add(s)
        f.discard(s)

    def test_init(self):
        s = WeakSet()
        s.__init__(self.items)
        self.assertEqual(s, self.s)
        s.__init__(self.items2)
        self.assertEqual(s, WeakSet(self.items2))
        self.assertRaises(TypeError, s.__init__, s, 2);
        self.assertRaises(TypeError, s.__init__, 1);

    def test_constructor_identity(self):
        s = WeakSet(self.items)
        t = WeakSet(s)
        self.assertNotEqual(id(s), id(t))

    def test_hash(self):
        self.assertRaises(TypeError, hash, self.s)

    def test_clear(self):
        self.s.clear()
        self.assertEqual(self.s, WeakSet([]))
        self.assertEqual(len(self.s), 0)

    def test_copy(self):
        dup = self.s.copy()
        self.assertEqual(self.s, dup)
        self.assertNotEqual(id(self.s), id(dup))

    def test_add(self):
        x = ustr('Q')
        self.s.add(x)
        self.assertIn(x, self.s)
        dup = self.s.copy()
        self.s.add(x)
        self.assertEqual(self.s, dup)
        self.assertRaises(TypeError, self.s.add, [])
        self.fs.add(Foo())
        support.gc_collect()
        self.assertTrue(len(self.fs) == 1)
        self.fs.add(self.obj)
        self.assertTrue(len(self.fs) == 1)

    def test_remove(self):
        x = ustr('a')
        self.s.remove(x)
        self.assertNotIn(x, self.s)
        self.assertRaises(KeyError, self.s.remove, x)
        self.assertRaises(TypeError, self.s.remove, [])

    def test_discard(self):
        a, q = ustr('a'), ustr('Q')
        self.s.discard(a)
        self.assertNotIn(a, self.s)
        self.s.discard(q)
        self.assertRaises(TypeError, self.s.discard, [])

    def test_pop(self):
        for i in range(len(self.s)):
            elem = self.s.pop()
            self.assertNotIn(elem, self.s)
        self.assertRaises(KeyError, self.s.pop)

    def test_update(self):
        retval = self.s.update(self.items2)
        self.assertEqual(retval, None)
        for c in (self.items + self.items2):
            self.assertIn(c, self.s)
        self.assertRaises(TypeError, self.s.update, [[]])

    def test_update_set(self):
        self.s.update(set(self.items2))
        for c in (self.items + self.items2):
            self.assertIn(c, self.s)

    def test_ior(self):
        self.s |= set(self.items2)
        for c in (self.items + self.items2):
            self.assertIn(c, self.s)

    def test_intersection_update(self):
        retval = self.s.intersection_update(self.items2)
        self.assertEqual(retval, None)
        for c in (self.items + self.items2):
            if c in self.items2 and c in self.items:
                self.assertIn(c, self.s)
            else:
                self.assertNotIn(c, self.s)
        self.assertRaises(TypeError, self.s.intersection_update, [[]])

    def test_iand(self):
        self.s &= set(self.items2)
        for c in (self.items + self.items2):
            if c in self.items2 and c in self.items:
                self.assertIn(c, self.s)
            else:
                self.assertNotIn(c, self.s)

    def test_difference_update(self):
        retval = self.s.difference_update(self.items2)
        self.assertEqual(retval, None)
        for c in (self.items + self.items2):
            if c in self.items and c not in self.items2:
                self.assertIn(c, self.s)
            else:
                self.assertNotIn(c, self.s)
        self.assertRaises(TypeError, self.s.difference_update, [[]])
        self.assertRaises(TypeError, self.s.symmetric_difference_update, [[]])

    def test_isub(self):
        self.s -= set(self.items2)
        for c in (self.items + self.items2):
            if c in self.items and c not in self.items2:
                self.assertIn(c, self.s)
            else:
                self.assertNotIn(c, self.s)

    def test_symmetric_difference_update(self):
        retval = self.s.symmetric_difference_update(self.items2)
        self.assertEqual(retval, None)
        for c in (self.items + self.items2):
            if (c in self.items) ^ (c in self.items2):
                self.assertIn(c, self.s)
            else:
                self.assertNotIn(c, self.s)
        self.assertRaises(TypeError, self.s.symmetric_difference_update, [[]])

    def test_ixor(self):
        self.s ^= set(self.items2)
        for c in (self.items + self.items2):
            if (c in self.items) ^ (c in self.items2):
                self.assertIn(c, self.s)
            else:
                self.assertNotIn(c, self.s)

    def test_inplace_on_self(self):
        t = self.s.copy()
        t |= t
        self.assertEqual(t, self.s)
        t &= t
        self.assertEqual(t, self.s)
        t -= t
        self.assertEqual(t, WeakSet())
        t = self.s.copy()
        t ^= t
        self.assertEqual(t, WeakSet())

    def test_eq(self):
        # issue 5964
        self.assertTrue(self.s == self.s)
        self.assertTrue(self.s == WeakSet(self.items))
        self.assertFalse(self.s == set(self.items))
        self.assertFalse(self.s == list(self.items))
        self.assertFalse(self.s == tuple(self.items))
        self.assertFalse(self.s == WeakSet([Foo]))
        self.assertFalse(self.s == 1)

    def test_ne(self):
        self.assertTrue(self.s != set(self.items))
        s1 = WeakSet()
        s2 = WeakSet()
        self.assertFalse(s1 != s2)

    def test_weak_destroy_while_iterating(self):
        # Issue #7105: iterators shouldn't crash when a key is implicitly removed
        # Create new items to be sure no-one else holds a reference
        items = [ustr(c) for c in ('a', 'b', 'c')]
        s = WeakSet(items)
        it = iter(s)
        next(it)             # Trigger internal iteration
        # Destroy an item
        del items[-1]
        gc.collect()    # just in case
        # We have removed either the first consumed items, or another one
        self.assertIn(len(list(it)), [len(items), len(items) - 1])
        del it
        # The removal has been committed
        self.assertEqual(len(s), len(items))

    def test_weak_destroy_and_mutate_while_iterating(self):
        # Issue #7105: iterators shouldn't crash when a key is implicitly removed
        items = [ustr(c) for c in string.ascii_letters]
        s = WeakSet(items)
        @contextlib.contextmanager
        def testcontext():
            try:
                it = iter(s)
                # Start iterator
                yielded = ustr(str(next(it)))
                # Schedule an item for removal and recreate it
                u = ustr(str(items.pop()))
                if yielded == u:
                    # The iterator still has a reference to the removed item,
                    # advance it (issue #20006).
                    next(it)
                gc.collect()      # just in case
                yield u
            finally:
                it = None           # should commit all removals

        with testcontext() as u:
            self.assertNotIn(u, s)
        with testcontext() as u:
            self.assertRaises(KeyError, s.remove, u)
        self.assertNotIn(u, s)
        with testcontext() as u:
            s.add(u)
        self.assertIn(u, s)
        t = s.copy()
        with testcontext() as u:
            s.update(t)
        self.assertEqual(len(s), len(t))
        with testcontext() as u:
            s.clear()
        self.assertEqual(len(s), 0)

    def test_len_cycles(self):
        N = 20
        items = [RefCycle() for i in range(N)]
        s = WeakSet(items)
        del items
        it = iter(s)
        try:
            next(it)
        except StopIteration:
            pass
        gc.collect()
        n1 = len(s)
        del it
        gc.collect()
        gc.collect()
        n2 = len(s)
        # one item may be kept alive inside the iterator
        self.assertIn(n1, (0, 1))
        self.assertEqual(n2, 0)

    @support.impl_detail("PyPy has no cyclic collection", pypy=False)
    def test_len_race(self):
        # Extended sanity checks for len() in the face of cyclic collection
        self.addCleanup(gc.set_threshold, *gc.get_threshold())
        for th in range(1, 100):
            N = 20
            gc.collect(0)
            gc.set_threshold(th, th, th)
            items = [RefCycle() for i in range(N)]
            s = WeakSet(items)
            del items
            # All items will be collected at next garbage collection pass
            it = iter(s)
            try:
                next(it)
            except StopIteration:
                pass
            n1 = len(s)
            del it
            n2 = len(s)
            self.assertGreaterEqual(n1, 0)
            self.assertLessEqual(n1, N)
            self.assertGreaterEqual(n2, 0)
            self.assertLessEqual(n2, n1)
Ejemplo n.º 47
0
class AsyncTaskContext(AbstractAsyncTaskContext):

    def __init__(self, daemon=False, parent=None, name=None):
        self._setup()

        self.daemon = daemon
        self.parent = parent
        self.name = name
        self.eventloop = parent.eventloop

        self.parent.add_child(self)

    def _setup(self):
        self.children = WeakSet()
        self.daemon_children = WeakSet()
        self.exception = None
        self.tb_list = None
        self.stack_list = None
        self.except_func = None
        self.finally_func = None

    def add_child(self, child):
        if DEBUG:
            log.debug("Adding child:%r ", child)

        if child.daemon:
            self.daemon_children.add(child)
        else:
            self.children.add(child)

    def remove_child(self, child):
        if DEBUG:
            log.debug("Removing child %r %r", child, self)
            log.debug("--------------------BEFORE REMOVE---------------------")
            log_task_context(self, log)
            log.debug("------------------------------------------------------")

        if child.daemon:
            self.daemon_children.remove(child)
        else:
            self.children.remove(child)
            if self.daemon_children and not self.children:
                self.parent.cancel()

        if not self.children and not self.daemon_children:
            if self.exception is not None and self.except_func is not None:
                self._execute_except(self.exception)
            else:
                self._execute_finally()

    def handle_exception(self, exception, tb_list=None):
        if DEBUG:
            log.debug("Handling exception %r %r", self, exception)

        if self.exception is None \
           or not isinstance(exception, CancellationError):
            self.exception = exception
            self.tb_list = tb_list

        for child in self.children.union(self.daemon_children):
            child.cancel()

    def cancel(self):
        if DEBUG:
            log.debug("Cancelling %r", self)

        self.handle_exception(CancellationError(), self.tb_list)

    def update_parent(self):
        if DEBUG:
            log.debug("updating parent %r of self %r", self.parent, self)
        if self.parent is None:
            return

        if self.exception is not None:
            self.parent.handle_exception(self.exception, self.tb_list)

        self.parent.remove_child(self)
        self.parent = None  # gc

    def schedule_task(self, task, now=False):
        if DEBUG:
            log.debug("Scheduling task %r", task)

        if now:
            self.eventloop.execute_now(task)
        else:
            self.eventloop.execute(task)

    def set_stack(self, stack_list):
        stack_before, stack_after = split_stack(stack_list)
        if self.parent.stack_list is None:
            self.parent.stack_list = stack_before

        self.stack_list = stack_after

    def _execute_except(self, err):
        if DEBUG:
            log.debug("Executing except %r %r", self, err)

        if self.except_func is not None:
            with self:
                except_func = self.except_func
                self.except_func = None
                task = AsyncTask(except_func, (err,), context=self,
                                 name=except_func.__name__)
                task.cancellable = False
                task.daemon = self.daemon
                # execute exceptions asap to have a chance to cancel any
                # pending tasks
                task.execute_now()
        else:
            self._execute_finally()

    def _execute_finally(self):
        if DEBUG:
            log.debug("Executiong finally %r with exception %r", self,
                      self.exception)

        if isinstance(self.exception, CancellationError):
            self.exception = None

        if self.finally_func is not None:
            with self:
                task = AsyncTask(self.finally_func, context=self,
                                 name=self.finally_func.__name__)
                task.daemon = self.daemon
                task.cancellable = False
                task.execute()
                self.finally_func = None
        else:
            self.update_parent()

    def __enter__(self):
        self._parent_context = get_async_context()
        set_async_context(self)
        return self

    def __exit__(self, exc_type, err, tb):
        set_async_context(self._parent_context)
        self._parent_context = None  # gc

    def __repr__(self):
        args = []
        if self.name is not None:
            args.append("name=%s" % self.name)
        if self.parent:
            args.append("parent=%s" % self.parent)
        if self.children:
            args.append("children=%d" % len(self.children))
        if self.daemon_children:
            args.append("daemon_children=%d" % len(self.daemon_children))
        if self.except_func:
            args.append("except_func=%r" % self.except_func.__name__)
        if self.finally_func:
            args.append("finally_func=%r" % self.finally_func.__name__)
        if self.exception:
            args.append("exception=%r" % self.exception)

        if args:
            args.insert(0, "")

        return "<%s at %s%s>" % (
            self.__class__.__name__, hex(id(self)), " ".join(args))

    def __str__(self):
        return "<%s at %s>" % (self.__class__.__name__, hex(id(self)))