diff --git a/pyipp/__init__.py b/pyipp/__init__.py index 1926dfe22..bfc3b28eb 100644 --- a/pyipp/__init__.py +++ b/pyipp/__init__.py @@ -6,5 +6,6 @@ IPPError, IPPParseError, IPPResponseError, + IPPVersionNotSupportedError, ) from .models import Printer # noqa diff --git a/pyipp/exceptions.py b/pyipp/exceptions.py index 79e803501..053b56d91 100644 --- a/pyipp/exceptions.py +++ b/pyipp/exceptions.py @@ -29,3 +29,9 @@ class IPPResponseError(IPPError): """IPP response exception.""" pass + + +class IPPVersionNotSupportedError(IPPError): + """IPP version not supported.""" + + pass diff --git a/pyipp/ipp.py b/pyipp/ipp.py index 600221e43..66434acc2 100644 --- a/pyipp/ipp.py +++ b/pyipp/ipp.py @@ -16,13 +16,14 @@ DEFAULT_PRINTER_ATTRIBUTES, DEFAULT_PROTO_VERSION, ) -from .enums import IppOperation +from .enums import IppOperation, IppStatus from .exceptions import ( IPPConnectionError, IPPConnectionUpgradeRequired, IPPError, IPPParseError, IPPResponseError, + IPPVersionNotSupportedError, ) from .models import Printer from .parser import parse as parse_response @@ -180,7 +181,10 @@ async def execute(self, operation: IppOperation, message: dict) -> dict: except (StructError, Exception) as exc: # disable=broad-except raise IPPParseError from exc - if parsed["status-code"] != 0: + if parsed["status-code"] == IppStatus.ERROR_VERSION_NOT_SUPPORTED: + raise IPPVersionNotSupportedError("IPP version not supported by server") + + if parsed["status-code"] != IppStatus.OK: raise IPPError( "Unexpected printer status code", {"status-code": parsed["status-code"]}, diff --git a/pyipp/parser.py b/pyipp/parser.py index db7b196ca..ff9aafcd5 100644 --- a/pyipp/parser.py +++ b/pyipp/parser.py @@ -3,7 +3,7 @@ import struct from typing import Any, Dict, Tuple, cast -from .enums import IppDocumentState, IppJobState, IppPrinterState, IppTag +from .enums import IppDocumentState, IppJobState, IppPrinterState, IppStatus, IppTag _LOGGER = logging.getLogger(__name__) @@ -69,6 +69,8 @@ def parse_attribute(data: bytes, offset: int): attribute["value"] = IppPrinterState(attribute["value"]) elif attribute["name"] == "document-state": attribute["value"] = IppDocumentState(attribute["value"]) + elif attribute["name"] == "status-code": + attribute["value"] = IppStatus(attribute["value"]) offset += 4 _LOGGER.debug("Attribute Value: %s", attribute["value"]) diff --git a/tests/fixtures/get-printer-attributes-error-0x0503.bin b/tests/fixtures/get-printer-attributes-error-0x0503.bin new file mode 100644 index 000000000..c92134b9e Binary files /dev/null and b/tests/fixtures/get-printer-attributes-error-0x0503.bin differ diff --git a/tests/test_client.py b/tests/test_client.py index c6dde93da..09a81339f 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -11,6 +11,7 @@ IPPConnectionUpgradeRequired, IPPError, IPPParseError, + IPPVersionNotSupportedError, ) from . import ( @@ -255,3 +256,30 @@ async def test_unexpected_response(aresponses): }, }, ) + + +@pytest.mark.asyncio +async def test_ipp_error_0x0503(aresponses): + """Test IPP Error 0x0503 response handling.""" + 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-error-0x0503.bin"), + ), + ) + + async with ClientSession() as session: + ipp = IPP(DEFAULT_PRINTER_URI, session=session) + with pytest.raises(IPPVersionNotSupportedError): + assert await ipp.execute( + IppOperation.GET_PRINTER_ATTRIBUTES, + { + "operation-attributes-tag": { + "requested-attributes": DEFAULT_PRINTER_ATTRIBUTES, + }, + }, + )