~naglis/aio_mpv_ipc

8b92d380116c60e1245280da49f88923b5557e3a — Naglis Jonaitis 10 months ago 6175665
Small changes
2 files changed, 76 insertions(+), 27 deletions(-)

M aio_mpv_ipc/_client.py
M tests/test_client.py
M aio_mpv_ipc/_client.py => aio_mpv_ipc/_client.py +11 -5
@@ 110,7 110,7 @@ class MpvClient:
            attempt += 1
            try:
                self._reader, self._writer = await asyncio.open_unix_connection(
                    self._socket_path
                    self.socket_path
                )
                break
            except (ConnectionRefusedError, FileNotFoundError) as exc:


@@ 123,13 123,15 @@ class MpvClient:
                )
                await asyncio.sleep(self._connect_sleep_timeout)

        self._poll_task = asyncio.create_task(self._poll(), name="Poll mpv IPC socket")
        self._poll_task = asyncio.create_task(
            self._poll(), name="Poll mpv JSON IPC socket"
        )

        return self

    async def __aexit__(self, _, __, ___):
        if self._writer is not None:
            logger.debug("Closing mpv IPC socket writer")
            logger.debug("Closing mpv JSON IPC socket writer")
            self._writer.close()

        if self._poll_task is not None:


@@ 183,7 185,7 @@ class MpvClient:
        self, command_name: str, *params, nowait: bool = False
    ) -> typing.Optional[typing.Any]:
        if self._writer is None:
            raise AioMpvIPCException("mpv IPC socket writer was not initialized")
            raise AioMpvIPCException("mpv JSON IPC socket writer was not initialized")

        self._request_counter += 1



@@ 201,7 203,11 @@ class MpvClient:
        data = self._json_dumps(payload)
        self._writer.write(data.encode(encoding=IPC_ENCODING))
        self._writer.write(NEWLINE)
        await self._writer.drain()

        try:
            await self._writer.drain()
        except ConnectionError as exc:
            raise IPCConnectionException("IPC connection to mpv failed") from exc

        if not nowait:
            return await fut

M tests/test_client.py => tests/test_client.py +65 -22
@@ 1,5 1,6 @@
import asyncio
import contextlib
import functools
import pathlib
import shutil
import tempfile


@@ 9,6 10,7 @@ import pytest
import aio_mpv_ipc

TEST_FILE_SILENCE = pathlib.Path(__file__).parent / "test_data" / "silence.ogg"
TMP_FILE_PREFIX = "aio_mpv_ipc.test."

MPV_PATH = shutil.which("mpv")



@@ 25,11 27,12 @@ MPV_ARGS = [
]


@contextlib.asynccontextmanager
async def temp_file(*args, **kwargs):
    """Awaitable version of :class:`tempfile.NamedTemporaryFile`."""
    with tempfile.NamedTemporaryFile(*args, **kwargs) as tmp:
        yield tmp
tmp_socket = functools.partial(
    tempfile.NamedTemporaryFile,
    prefix="aio_mpv_ipc.test.",
    suffix=".socket",
    delete=True,
)


@pytest.fixture


@@ 41,9 44,7 @@ def queue():
@pytest.mark.asyncio
async def mpv_client():
    async with contextlib.AsyncExitStack() as exit_stack:
        tmp_file = await exit_stack.enter_async_context(
            temp_file(prefix=f"veil.test.", suffix=".socket", delete=True)
        )
        tmp_file = exit_stack.enter_context(tmp_socket())
        socket_path = tmp_file.name

        mpv_ctx_mgr = aio_mpv_ipc.start_mpv(


@@ 103,23 104,40 @@ async def test_event_subscription(event_loop, mpv_client, queue):

    mpv_client.subscribe("file-loaded", queue)
    await mpv_client.ipc("loadfile", TEST_FILE_SILENCE)
    result = await asyncio.wait_for(event_handler(), timeout=1.0)
    result = await asyncio.wait_for(event_handler(), timeout=10)
    assert result["event"] == "file-loaded"


@pytest.mark.mpv
@pytest.mark.asyncio
async def test_event_unsubscription(event_loop, mpv_client, queue):
    async def event_handler():
        event_data = await queue.get()
        queue.task_done()
        return event_data

    mpv_client.subscribe("file-loaded", queue)
    await mpv_client.ipc("loadfile", TEST_FILE_SILENCE)
    result = await asyncio.wait_for(event_handler(), timeout=10)
    assert result["event"] == "file-loaded"
    await mpv_client.ipc("playlist-clear")
    mpv_client.unsubscribe("file-loaded", queue)
    await mpv_client.ipc("loadfile", TEST_FILE_SILENCE)
    await asyncio.sleep(1)
    assert queue.empty()


@pytest.mark.mpv
@pytest.mark.asyncio
async def test_mpv_started_with_unknown_flag_exception_is_raised():
    async with temp_file(
        prefix=f"veil.test.", suffix=".socket", delete=True
    ) as socket_file:
    with tmp_socket() as socket_file:
        mpv = aio_mpv_ipc.start_mpv(
            socket_file.name,
            *[*MPV_ARGS, "--foo-bar"],
            terminate=True,
            mpv_path=MPV_PATH,
        )
        client = aio_mpv_ipc.MpvClient(socket_file.name, max_connect_attempts=3)
        client = aio_mpv_ipc.MpvClient(socket_file.name)
        with pytest.raises(
            aio_mpv_ipc.MpvStartException, match=r"mpv exited with status code: 1"
        ):


@@ 129,10 147,8 @@ async def test_mpv_started_with_unknown_flag_exception_is_raised():

@pytest.mark.asyncio
async def test_mpv_not_started_client_raises_error():
    async with temp_file(
        prefix=f"veil.test.", suffix=".socket", delete=True
    ) as socket_file:
        client = aio_mpv_ipc.MpvClient(socket_file.name, max_connect_attempts=3)
    with tmp_socket() as socket_file:
        client = aio_mpv_ipc.MpvClient(socket_file.name)
        with pytest.raises(
            aio_mpv_ipc.IPCConnectionException, match=r"Failed to connect to mpv"
        ):


@@ 141,12 157,39 @@ async def test_mpv_not_started_client_raises_error():

@pytest.mark.asyncio
async def test_client_not_used_as_context_manager_ipc_raises_error():
    async with temp_file(
        prefix=f"veil.test.", suffix=".socket", delete=True
    ) as socket_file:
        client = aio_mpv_ipc.MpvClient(socket_file.name, max_connect_attempts=3)
    with tmp_socket() as socket_file:
        client = aio_mpv_ipc.MpvClient(socket_file.name)
        with pytest.raises(
            aio_mpv_ipc.AioMpvIPCException,
            match=r"mpv IPC socket writer was not initialized",
            match=r"mpv JSON IPC socket writer was not initialized",
        ):
            await client.ipc("client_name")


@pytest.mark.mpv
@pytest.mark.asyncio
async def test_exit_mpv_from_client():
    with tmp_socket() as socket_file:
        mpv = aio_mpv_ipc.start_mpv(socket_file.name, *MPV_ARGS, mpv_path=MPV_PATH)
        client = aio_mpv_ipc.MpvClient(socket_file.name)
        async with mpv as mpv, client:
            await client.ipc("quit")
            await mpv.wait()

        assert mpv.returncode == 0


@pytest.mark.mpv
@pytest.mark.asyncio
async def test_ipc_after_mpv_exit():
    with tmp_socket() as socket_file:
        mpv = aio_mpv_ipc.start_mpv(socket_file.name, *MPV_ARGS, mpv_path=MPV_PATH)
        client = aio_mpv_ipc.MpvClient(socket_file.name)
        async with mpv as mpv, client:
            await client.ipc("quit")
            await mpv.wait()
            with pytest.raises(
                aio_mpv_ipc.exceptions.IPCConnectionException,
                match=r"IPC connection to mpv failed",
            ):
                await client.ipc("client_name")