@@ 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
@@ 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")