示例#1
0
    async def test_acquire_nowait_wouldblock(self):
        async def try_lock():
            pytest.raises(WouldBlock, condition.acquire_nowait)

        condition = Condition()
        async with condition, create_task_group() as tg:
            assert condition.locked()
            tg.start_soon(try_lock)
示例#2
0
    def _ensure_condition_exists(self) -> None:
        """Creates the condition object that the backend will use to notify
        listeners about network change events.

        This function is used to avoid having to create a condition object
        in the constructor, which may be executed outside the context of an
        event loop.
        """
        if self._condition is None:
            self._condition = Condition()
示例#3
0
    async def test_contextmanager(self):
        async def notifier():
            async with condition:
                condition.notify_all()

        condition = Condition()
        async with create_task_group() as tg:
            async with condition:
                assert condition.locked()
                tg.start_soon(notifier)
                await condition.wait()
示例#4
0
    async def test_manual_acquire(self):
        async def notifier():
            await condition.acquire()
            try:
                condition.notify_all()
            finally:
                condition.release()

        condition = Condition()
        async with create_task_group() as tg:
            await condition.acquire()
            try:
                assert condition.locked()
                tg.start_soon(notifier)
                await condition.wait()
            finally:
                condition.release()
示例#5
0
    async def test_wait_cancel(self):
        async def task():
            nonlocal task_started, notified
            task_started = True
            async with condition:
                event.set()
                await condition.wait()
                notified = True

        task_started = notified = False
        event = Event()
        condition = Condition()
        async with create_task_group() as tg:
            tg.start_soon(task)
            await event.wait()
            await wait_all_tasks_blocked()
            tg.cancel_scope.cancel()

        assert task_started
        assert not notified
示例#6
0
    async def test_statistics(self):
        async def waiter():
            async with condition:
                await condition.wait()

        condition = Condition()
        async with create_task_group() as tg:
            assert not condition.statistics().lock_statistics.locked
            assert condition.statistics().tasks_waiting == 0
            async with condition:
                assert condition.statistics().lock_statistics.locked
                assert condition.statistics().tasks_waiting == 0

            for i in range(1, 3):
                tg.start_soon(waiter)
                await wait_all_tasks_blocked()
                assert condition.statistics().tasks_waiting == i

            for i in range(1, -1, -1):
                async with condition:
                    condition.notify(1)

                await wait_all_tasks_blocked()
                assert condition.statistics().tasks_waiting == i

        assert not condition.statistics().lock_statistics.locked
        assert condition.statistics().tasks_waiting == 0
示例#7
0
 async def test_acquire_nowait(self):
     condition = Condition()
     condition.acquire_nowait()
     assert condition.locked()
示例#8
0
class SystemConfigurationBasedNetworkEventDetectorBackend(
        PortableNetworkEventDetectorBackend):
    """Specialized network event detector backend for macOS using the
    SystemConfiguration framework.

    This backend works similarly to the PortableNetworkEventDetectorBackend_,
    but it uses an SCDynamicStore instance to detect changes to network
    interfaces and addresses instead of polling the network configuration.

    This backend is preferred by the autodetection mechanism on macOS over the
    default portable backend.
    """

    _condition: Optional[Condition]

    def __init__(self) -> None:
        super().__init__()
        self._condition = None

    @asynccontextmanager
    async def use(self) -> AsyncIterator[None]:
        self._ensure_condition_exists()
        async with create_task_group() as tg:
            tg.start_soon(
                partial(to_thread.run_sync,
                        self._run_worker_thread,
                        cancellable=True))
            yield

    def _ensure_condition_exists(self) -> None:
        """Creates the condition object that the backend will use to notify
        listeners about network change events.

        This function is used to avoid having to create a condition object
        in the constructor, which may be executed outside the context of an
        event loop.
        """
        if self._condition is None:
            self._condition = Condition()

    def _on_network_changed(self, *args, **kwds):
        """Callback that is called by the SystemConfiguration framework when
        the network configuration has changed.

        This function runs in the context of the worker thread.
        """
        from_thread.run(self._on_network_changed_main)

    async def _on_network_changed_main(self):
        """Task that is scheduled on the main event loop when the network
        configuration has changed.

        This function runs in the context of the main event loop.
        """
        assert self._condition is not None
        async with self._condition:
            self._condition.notify_all()

    def _run_worker_thread(self):
        """Runs the worker thread that waits for network events."""
        from Foundation import (
            CFRunLoopAddSource,
            CFRunLoopGetCurrent,
            kCFRunLoopCommonModes,
            CFRunLoopRun,
        )
        from SystemConfiguration import (
            SCDynamicStoreCreate,
            SCDynamicStoreSetNotificationKeys,
            SCDynamicStoreCreateRunLoopSource,
        )

        store = SCDynamicStoreCreate(None, "global-network-watcher",
                                     self._on_network_changed, None)
        SCDynamicStoreSetNotificationKeys(
            store, None,
            ["State:/Network/Global/IPv4", "State:/Network/Global/IPv6"])

        CFRunLoopAddSource(
            CFRunLoopGetCurrent(),
            SCDynamicStoreCreateRunLoopSource(None, store, 0),
            kCFRunLoopCommonModes,
        )

        CFRunLoopRun()

    async def wait_until_next_scan(self) -> None:
        assert self._condition is not None

        self._ensure_condition_exists()
        async with self._condition:
            await self._condition.wait()
示例#9
0
 async def test_condition_release(self) -> None:
     condition = Condition()
     condition.acquire_nowait()
     with pytest.deprecated_call():
         await condition.release()