diff --git a/examples/debug.py b/examples/debug.py new file mode 100644 index 000000000..0deacd854 --- /dev/null +++ b/examples/debug.py @@ -0,0 +1,39 @@ +# pylint: disable=W0621 +"""Asynchronous Python client for IPP.""" +import asyncio + +from pyipp import IPP + + +async def main(): + """Show example of connecting to your IPP print server.""" + async with IPP("ipps://EPSON761251.local:631/ipp/print") as ipp: + response = await ipp.raw( + 0x000B, + { + "operation-attributes-tag": { + "requested-attributes": [ + "printer-name", + "printer-type", + "printer-location", + "printer-info", + "printer-make-and-model", + "printer-state", + "printer-state-message", + "printer-state-reason", + "printer-uri-supported", + "device-uri", + "printer-is-shared", + ], + }, + }, + ) + + with open("printer-attributes.bin", "wb") as f: + f.write(response) + f.close() + + +if __name__ == "__main__": + loop = asyncio.get_event_loop() + loop.run_until_complete(main()) diff --git a/pyipp/ipp.py b/pyipp/ipp.py index 1a71a4a04..c6de1616e 100644 --- a/pyipp/ipp.py +++ b/pyipp/ipp.py @@ -1,6 +1,6 @@ """Asynchronous Python client for IPP.""" import asyncio -from socket import gaierror as SocketGIAEroor +from socket import gaierror as SocketGIAError from struct import error as StructError from typing import Any, Mapping, Optional @@ -121,7 +121,7 @@ async def _request( raise IPPConnectionError( "Timeout occurred while connecting to IPP server." ) from exception - except (aiohttp.ClientError, SocketGIAEroor) as exception: + except (aiohttp.ClientError, SocketGIAError) as exception: raise IPPConnectionError( "Error occurred while communicating with IPP server." ) from exception @@ -145,20 +145,7 @@ async def _request( }, ) - content = await response.read() - - try: - parsed_content = parse_response(content) - except (StructError, Exception) as exception: # disable=broad-except - raise IPPParseError from exception - - if parsed_content["status-code"] != 0: - raise IPPError( - "Unexpected printer status code", - {"status-code": parsed_content["status-code"]}, - ) - - return parsed_content + return await response.read() def _build_printer_uri(self) -> str: scheme = "ipps" if self.tls else "ipp" @@ -189,6 +176,25 @@ def _message(self, operation: IppOperation, msg: dict) -> dict: async def execute(self, operation: IppOperation, message: dict) -> dict: """Send a request message to the server.""" message = self._message(operation, message) + response = await self._request(data=message) + + try: + parsed = parse_response(response) + except (StructError, Exception) as exception: # disable=broad-except + raise IPPParseError from exception + + if parsed["status-code"] != 0: + raise IPPError( + "Unexpected printer status code", + {"status-code": parsed["status-code"]}, + ) + + return parsed + + async def raw(self, operation: IppOperation, message: dict) -> bytes: + """Send a request message to the server and return raw response.""" + message = self._message(operation, message) + return await self._request(data=message) async def close(self) -> None: diff --git a/tests/test_ipp.py b/tests/test_client.py similarity index 99% rename from tests/test_ipp.py rename to tests/test_client.py index db2fa1eb1..c6dde93da 100644 --- a/tests/test_ipp.py +++ b/tests/test_client.py @@ -1,4 +1,4 @@ -"""Tests for IPP.""" +"""Tests for IPP Client.""" import asyncio import pytest diff --git a/tests/test_printer.py b/tests/test_interface.py similarity index 80% rename from tests/test_printer.py rename to tests/test_interface.py index bcac499d2..68f2239b6 100644 --- a/tests/test_printer.py +++ b/tests/test_interface.py @@ -1,7 +1,9 @@ -"""Tests for IPP Printer model.""" +"""Tests for IPP public interface.""" import pytest from aiohttp import ClientSession from pyipp import IPP, Printer +from pyipp.const import DEFAULT_PRINTER_ATTRIBUTES +from pyipp.enums import IppOperation from . import ( DEFAULT_PRINTER_HOST, @@ -100,3 +102,31 @@ async def test_printer(aresponses): assert printer.markers[4].level == 92 assert printer.markers[4].low_level == 15 assert printer.markers[4].high_level == 100 + + +@pytest.mark.asyncio +async def test_raw(aresponses): + """Test raw method is handled correctly.""" + aresponses.add( + MATCH_DEFAULT_HOST, + DEFAULT_PRINTER_PATH, + "POST", + aresponses.Response( + status=200, + headers={"Content-Type": "application/ipp"}, + body=load_fixture_binary("get-printer-attributes-epsonxp6000.bin"), + ), + ) + + async with ClientSession() as session: + ipp = IPP(DEFAULT_PRINTER_URI, session=session) + response = await ipp.raw( + IppOperation.GET_PRINTER_ATTRIBUTES, + { + "operation-attributes-tag": { + "requested-attributes": DEFAULT_PRINTER_ATTRIBUTES, + }, + }, + ) + + assert isinstance(response, bytes)