From 4536e3c5db527ae2e1b879ab2240ecb32f3f6382 Mon Sep 17 00:00:00 2001 From: Klaas Schoute Date: Wed, 1 Dec 2021 21:15:22 +0100 Subject: [PATCH 1/3] Small changes --- omnikinverter/omnikinverter.py | 10 ++++++---- pyproject.toml | 2 +- tests/test_omnik.py | 2 +- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/omnikinverter/omnikinverter.py b/omnikinverter/omnikinverter.py index 2ad55688..2084aeac 100644 --- a/omnikinverter/omnikinverter.py +++ b/omnikinverter/omnikinverter.py @@ -76,9 +76,8 @@ async def request( "Accept": "text/html,application/xhtml+xml,application/xml", } - if self._session is None: - self._session = ClientSession() - self._close_session = True + # Don't reuse session as Wifi stick does not seem to support it + self._session = ClientSession() auth = None if self.username and self.password: @@ -112,7 +111,10 @@ async def request( {"Content-Type": content_type, "response": text}, ) - return await response.text() + raw_response = await response.read() + # Close the client session + await self._session.close() + return raw_response.decode("ascii", "ignore") async def inverter(self) -> Inverter: """Get values from your Omnik Inverter. diff --git a/pyproject.toml b/pyproject.toml index 2d39f57d..98f7b08d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -63,7 +63,7 @@ bandit = "^1.7.0" Changelog = "https://github.com/klaasnicolaas/python-omnikinverter/releases" [tool.black] -target-version = ['py37'] +target-version = ['py38'] [tool.coverage.paths] source = ["omnikinverter"] diff --git a/tests/test_omnik.py b/tests/test_omnik.py index 5a7a0576..72f1985f 100644 --- a/tests/test_omnik.py +++ b/tests/test_omnik.py @@ -74,7 +74,7 @@ async def response_handler(_): aresponses.add("example.com", "/js/status.js", "GET", response_handler) async with aiohttp.ClientSession() as session: - client = OmnikInverter(host="example.com", session=session) + client = OmnikInverter(host="example.com", session=session, request_timeout=0.1) with pytest.raises(OmnikInverterConnectionError): assert await client.inverter() From 22708751a5b9995dd12c2154fac8fa8ec12dcf8a Mon Sep 17 00:00:00 2001 From: Klaas Schoute Date: Fri, 17 Dec 2021 22:42:44 +0100 Subject: [PATCH 2/3] Remove init from the dataclass --- omnikinverter/omnikinverter.py | 55 +++++++++++----------------------- omnikinverter/py.typed | 0 2 files changed, 18 insertions(+), 37 deletions(-) create mode 100644 omnikinverter/py.typed diff --git a/omnikinverter/omnikinverter.py b/omnikinverter/omnikinverter.py index 2084aeac..9ed3526c 100644 --- a/omnikinverter/omnikinverter.py +++ b/omnikinverter/omnikinverter.py @@ -9,6 +9,7 @@ import aiohttp import async_timeout from aiohttp.client import ClientError, ClientResponseError, ClientSession +from aiohttp.hdrs import METH_GET from yarl import URL from .exceptions import OmnikInverterConnectionError, OmnikInverterError @@ -19,46 +20,27 @@ class OmnikInverter: """Main class for handling connections with the Omnik Inverter.""" - # pylint: disable=too-many-arguments - def __init__( - self, - host: str, - username: str | None = None, - password: str | None = None, - source_type: str = "javascript", - request_timeout: int = 10, - session: ClientSession | None = None, - ) -> None: - """Initialize connection with the Omnik Inverter. - - Args: - host: Hostname or IP address of the Omnik Inverter. - username: Username for HTTP auth, if enabled. - password: Password for HTTP auth, if enabled. - source_type: Whisch source your inverter uses - [javascript (default), html, json]. - request_timeout: An integer with the request timeout in seconds. - session: Optional, shared, aiohttp client session. - """ - self._session = session - self._close_session = False + host: str + username: str | None = None + password: str | None = None + source_type: str = "javascript" + request_timeout: int = 10 + session: ClientSession | None = None - self.host = host - self.username = username - self.password = password - self.source_type = source_type - self.request_timeout = request_timeout + _close_session: bool = False async def request( self, uri: str, *, + method: str = METH_GET, params: Mapping[str, str] | None = None, ) -> dict[str, Any]: """Handle a request to a Omnik Inverter device. Args: uri: Request URI, without '/', for example, 'status' + method: HTTP Method to use. params: Extra options to improve or limit the response. Returns: @@ -76,17 +58,18 @@ async def request( "Accept": "text/html,application/xhtml+xml,application/xml", } - # Don't reuse session as Wifi stick does not seem to support it - self._session = ClientSession() + if self.session is None: + self.session = ClientSession() + self._close_session = True auth = None if self.username and self.password: auth = aiohttp.BasicAuth(self.username, self.password) try: - with async_timeout.timeout(self.request_timeout): - response = await self._session.request( - "GET", + async with async_timeout.timeout(self.request_timeout): + response = await self.session.request( + method, url, auth=auth, params=params, @@ -112,8 +95,6 @@ async def request( ) raw_response = await response.read() - # Close the client session - await self._session.close() return raw_response.decode("ascii", "ignore") async def inverter(self) -> Inverter: @@ -148,8 +129,8 @@ async def device(self) -> Device: async def close(self) -> None: """Close open client session.""" - if self._session and self._close_session: - await self._session.close() + if self.session and self._close_session: + await self.session.close() async def __aenter__(self) -> OmnikInverter: """Async enter. diff --git a/omnikinverter/py.typed b/omnikinverter/py.typed new file mode 100644 index 00000000..e69de29b From 719aa7a8bab8ffeecf2c083c3b348c2ce8ca1512 Mon Sep 17 00:00:00 2001 From: Klaas Schoute Date: Fri, 17 Dec 2021 22:47:08 +0100 Subject: [PATCH 3/3] Add extra tests --- pyproject.toml | 2 +- tests/test_omnik.py | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 98f7b08d..3a957134 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -120,5 +120,5 @@ paths = ["omnikinverter"] verbose = true [build-system] -requires = ["poetry-core>=1.0.0"] +requires = ["setuptools","poetry-core>=1.0.0"] build-backend = "poetry.core.masonry.api" diff --git a/tests/test_omnik.py b/tests/test_omnik.py index 72f1985f..c4551fc0 100644 --- a/tests/test_omnik.py +++ b/tests/test_omnik.py @@ -15,6 +15,42 @@ from . import load_fixtures +@pytest.mark.asyncio +async def test_json_request(aresponses): + """Test JSON response is handled correctly.""" + aresponses.add( + "example.com", + "/test", + "GET", + aresponses.Response( + status=200, + headers={"Content-Type": "application/json"}, + text='{"status": "ok"}', + ), + ) + async with aiohttp.ClientSession() as session: + omnik_inverter = OmnikInverter("example.com", session=session) + await omnik_inverter.request("test") + await omnik_inverter.close() + + +@pytest.mark.asyncio +async def test_internal_session(aresponses): + """Test JSON response is handled correctly.""" + aresponses.add( + "example.com", + "/test", + "GET", + aresponses.Response( + status=200, + headers={"Content-Type": "application/json"}, + text='{"status": "ok"}', + ), + ) + async with OmnikInverter("example.com") as omnik_inverter: + await omnik_inverter.request("test") + + @pytest.mark.asyncio async def test_wrong_js_source(aresponses): """Test on wrong data source error raise."""