Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update the python package #90

Merged
merged 3 commits into from
Dec 18, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 19 additions & 36 deletions omnikinverter/omnikinverter.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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:
Expand All @@ -76,18 +58,18 @@ async def request(
"Accept": "text/html,application/xhtml+xml,application/xml",
}

if self._session is None:
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,
Expand All @@ -112,7 +94,8 @@ async def request(
{"Content-Type": content_type, "response": text},
)

return await response.text()
raw_response = await response.read()
return raw_response.decode("ascii", "ignore")

async def inverter(self) -> Inverter:
"""Get values from your Omnik Inverter.
Expand Down Expand Up @@ -146,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.
Expand Down
Empty file added omnikinverter/py.typed
Empty file.
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"]
Expand Down Expand Up @@ -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"
38 changes: 37 additions & 1 deletion tests/test_omnik.py
Original file line number Diff line number Diff line change
Expand Up @@ -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."""
Expand Down Expand Up @@ -74,7 +110,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()

Expand Down