Skip to content

Commit

Permalink
Update URL handling to use yarl (#62)
Browse files Browse the repository at this point in the history
* Update URL handling to use yarl
* remove insecure warnings
  • Loading branch information
bdraco authored Feb 8, 2024
1 parent 7c921ef commit 2e95490
Show file tree
Hide file tree
Showing 4 changed files with 15 additions and 38 deletions.
4 changes: 1 addition & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,14 +80,12 @@ powerwall = Powerwall(
# Provide a requests.Session or None. If None is provided, a Session will be created.
http_session=None,
# Whether to verify the SSL certificate or not
verify_ssl=False,
disable_insecure_warning=True
verify_ssl=False
)
#=> <Powerwall ...>
```

> Note: By default the API client does not verify the SSL certificate of the Powerwall. If you want to verify the SSL certificate you can set `verify_ssl` to `True`.
> The API client suppresses warnings about an inseucre request (because we aren't verifing the certificate). If you want to enable those warnings you can set `disable_insecure_warning` to `False`.
### Authentication

Expand Down
35 changes: 6 additions & 29 deletions tesla_powerwall/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,10 @@
from json.decoder import JSONDecodeError
from types import TracebackType
from typing import Any, List, Optional, Type
from urllib.parse import urljoin

import aiohttp
import orjson
from urllib3 import disable_warnings
from urllib3.exceptions import InsecureRequestWarning
from yarl import URL

from .error import AccessDeniedError, ApiError, PowerwallUnreachableError

Expand All @@ -19,12 +17,10 @@ def __init__(
timeout: int = 10,
http_session: Optional[aiohttp.ClientSession] = None,
verify_ssl: bool = False,
disable_insecure_warning: bool = True,
) -> None:
if disable_insecure_warning:
disable_warnings(InsecureRequestWarning)

self._endpoint = self._parse_endpoint(endpoint)
if not endpoint.startswith("http"):
endpoint = f"https://{endpoint}"
self._endpoint = URL(endpoint).with_path("api").with_scheme("https")
self._timeout = aiohttp.ClientTimeout(total=timeout)
self._owns_http_session = False if http_session else True
self._ssl = None if verify_ssl else False
Expand All @@ -40,25 +36,6 @@ def __init__(
jar = aiohttp.CookieJar(unsafe=True)
self._http_session = aiohttp.ClientSession(cookie_jar=jar)

@staticmethod
def _parse_endpoint(endpoint: str) -> str:
if endpoint.startswith("https"):
endpoint = endpoint
elif endpoint.startswith("http"):
endpoint = endpoint.replace("http", "https")
else:
# Use str.format instead of f'strings to be backwards compatible
endpoint = "https://{}".format(endpoint)

if not endpoint.endswith("api") and not endpoint.endswith("/"):
endpoint += "/api/"
elif endpoint.endswith("api"):
endpoint += "/"
elif endpoint.endswith("/") and not endpoint.endswith("api/"):
endpoint += "api/"

return endpoint

@staticmethod
async def _handle_error(response: aiohttp.ClientResponse) -> None:
if response.status == 404:
Expand Down Expand Up @@ -121,8 +98,8 @@ async def _process_response(self, response: aiohttp.ClientResponse) -> dict:

return response_json

def url(self, path: str):
return urljoin(self._endpoint, path)
def url(self, path: str) -> URL:
return self._endpoint.joinpath(path)

async def get(self, path: str, headers: dict = {}) -> Any:
try:
Expand Down
4 changes: 1 addition & 3 deletions tesla_powerwall/powerwall.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,12 @@ def __init__(
timeout: int = 10,
http_session: Union[aiohttp.ClientSession, None] = None,
verify_ssl: bool = False,
disable_insecure_warning: bool = True,
):
) -> None:
self._api = API(
endpoint=endpoint,
timeout=timeout,
http_session=http_session,
verify_ssl=verify_ssl,
disable_insecure_warning=disable_insecure_warning,
)

async def login_as(
Expand Down
10 changes: 7 additions & 3 deletions tests/unit/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

import aiohttp
import aresponses
from yarl import URL

from tesla_powerwall import API, AccessDeniedError, ApiError
from tesla_powerwall.const import User
Expand All @@ -22,16 +23,19 @@ async def asyncTearDown(self):
await self.session.close()
await self.aresponses.__aexit__(None, None, None)

def test_parse_endpoint(self):
async def test_parse_endpoint(self):
test_endpoints = [
"1.1.1.1",
"http://1.1.1.1",
"https://1.1.1.1/api/",
"https://1.1.1.1/api",
"https://1.1.1.1/",
]

for test_endpoint in test_endpoints:
self.assertEqual(self.api._parse_endpoint(test_endpoint), ENDPOINT)
api = API(test_endpoint)
await api.close()
self.assertEqual(api.url(""), URL(ENDPOINT.rstrip("/")))

async def test_process_response(self):
status = 0
Expand Down Expand Up @@ -122,7 +126,7 @@ async def test_is_authenticated(self):
self.assertEqual(self.api.is_authenticated(), True)

def test_url(self):
self.assertEqual(self.api.url("test"), ENDPOINT + "test")
self.assertEqual(self.api.url("test"), URL(ENDPOINT + "test"))

async def test_login(self):
jar = aiohttp.CookieJar(unsafe=True)
Expand Down

0 comments on commit 2e95490

Please sign in to comment.