Skip to content
39 changes: 39 additions & 0 deletions examples/debug.py
Original file line number Diff line number Diff line change
@@ -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())
38 changes: 22 additions & 16 deletions pyipp/ipp.py
Original file line number Diff line number Diff line change
@@ -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

Expand Down Expand Up @@ -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
Expand All @@ -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"
Expand Down Expand Up @@ -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:
Expand Down
2 changes: 1 addition & 1 deletion tests/test_ipp.py → tests/test_client.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"""Tests for IPP."""
"""Tests for IPP Client."""
import asyncio

import pytest
Expand Down
32 changes: 31 additions & 1 deletion tests/test_printer.py → tests/test_interface.py
Original file line number Diff line number Diff line change
@@ -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,
Expand Down Expand Up @@ -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)