Skip to content

Commit 9f8dcd8

Browse files
authored
Merge pull request #2475 from cebtenzzre/only-clean-queryparams
only clean query parameters
2 parents 78dd615 + f573f4d commit 9f8dcd8

File tree

4 files changed

+23
-36
lines changed

4 files changed

+23
-36
lines changed

appdaemon/models/config/plugin.py

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
from ssl import _SSLMethod
44
from typing import Annotated, Any, Literal
55

6-
from pydantic import AnyHttpUrl, BaseModel, BeforeValidator, Field, SecretBytes, SecretStr, field_validator, model_validator
6+
from pydantic import BaseModel, BeforeValidator, ConfigDict, Field, PlainSerializer, SecretBytes, SecretStr, field_validator, model_validator
77
from typing_extensions import deprecated
8-
8+
from yarl import URL
99

1010
from .common import CoercedPath, ParsedTimedelta
1111

@@ -86,7 +86,11 @@ class StartupConditions(BaseModel):
8686

8787

8888
class HASSConfig(PluginConfig, extra="forbid"):
89-
ha_url: AnyHttpUrl = Field(default="http://supervisor/core", validate_default=True) # pyright: ignore[reportAssignmentType]
89+
ha_url: Annotated[
90+
URL,
91+
BeforeValidator(URL),
92+
PlainSerializer(str),
93+
] = Field(default="http://supervisor/core", validate_default=True) # pyright: ignore[reportAssignmentType]
9094
token: SecretStr = Field(default_factory=lambda: SecretStr(os.environ.get("SUPERVISOR_TOKEN"))) # pyright: ignore[reportArgumentType]
9195
ha_key: Annotated[SecretStr, deprecated("'ha_key' is deprecated. Please use long lived tokens instead")] | None = None
9296
appdaemon_startup_conditions: StartupConditions | None = None
@@ -108,6 +112,8 @@ class HASSConfig(PluginConfig, extra="forbid"):
108112
config_sleep_time: ParsedTimedelta = timedelta(seconds=60)
109113
"""The sleep time in the background task that updates the config metadata every once in a while"""
110114

115+
model_config = ConfigDict(arbitrary_types_allowed=True)
116+
111117
@model_validator(mode="after")
112118
def custom_validator(self):
113119
if self.token.get_secret_value() is None:
@@ -117,15 +123,8 @@ def custom_validator(self):
117123
return self
118124

119125
@property
120-
def websocket_url(self) -> str:
121-
return f"{self.ha_url!s}api/websocket"
122-
123-
@property
124-
def states_api(self) -> str:
125-
return f"{self.ha_url!s}api/states"
126-
127-
def get_entity_api(self, entity_id: str) -> str:
128-
return f"{self.states_api}/{entity_id}"
126+
def websocket_url(self) -> URL:
127+
return self.ha_url / "api/websocket"
129128

130129
@property
131130
def auth_json(self) -> dict:

appdaemon/plugins/hass/hassplugin.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
from typing import Any, Literal, Optional
1515

1616
import aiohttp
17-
from aiohttp import ClientResponse, ClientResponseError, RequestInfo, WSMsgType, WebSocketError
17+
from aiohttp import ClientResponse, ClientResponseError, RequestInfo, WebSocketError, WSMsgType
1818
from pydantic import BaseModel
1919

2020
import appdaemon.utils as utils
@@ -460,11 +460,11 @@ async def http_method(
460460
appropriate.
461461
"""
462462
kwargs = utils.clean_http_kwargs(kwargs)
463-
url = utils.make_endpoint(f"{self.config.ha_url!s}", endpoint)
463+
url = self.config.ha_url / endpoint.lstrip("/")
464464

465465
try:
466466
self.update_perf(
467-
bytes_sent=len(url) + len(json.dumps(kwargs).encode("utf-8")),
467+
bytes_sent=len(str(url)) + len(json.dumps(kwargs).encode("utf-8")),
468468
requests_sent=1,
469469
)
470470

@@ -475,7 +475,7 @@ async def http_method(
475475
case "post":
476476
http_method = functools.partial(self.session.post, json=kwargs)
477477
case "delete":
478-
http_method = functools.partial(self.session.delete, json=kwargs)
478+
http_method = functools.partial(self.session.delete, params=kwargs)
479479
case _:
480480
raise ValueError(f"Invalid method: {method}")
481481

@@ -889,8 +889,7 @@ async def set_plugin_state(
889889

890890
@utils.warning_decorator(error_text=f"Error setting state for {entity_id}")
891891
async def safe_set_state(self: "HassPlugin"):
892-
api_url = self.config.get_entity_api(entity_id)
893-
return await self.http_method("post", api_url, state=state, attributes=attributes)
892+
return await self.http_method("post", f"api/states/{entity_id}", state=state, attributes=attributes)
894893

895894
return await safe_set_state(self)
896895

appdaemon/utils.py

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -862,7 +862,12 @@ def dt_to_str(dt: datetime, tz: tzinfo | None = None, *, round: bool = False) ->
862862

863863

864864
def convert_json(data, **kwargs):
865-
return json.dumps(data, default=str, **kwargs)
865+
def fallback_serializer(obj):
866+
if isinstance(obj, datetime):
867+
return obj.isoformat()
868+
return str(obj)
869+
870+
return json.dumps(data, default=fallback_serializer, **kwargs)
866871

867872

868873
def get_object_size(obj, seen=None):
@@ -1167,15 +1172,6 @@ def clean_http_kwargs(val: Any) -> Any:
11671172
return pruned
11681173

11691174

1170-
def make_endpoint(base: str, endpoint: str) -> str:
1171-
"""Formats a URL appropriately with slashes"""
1172-
if not endpoint.startswith(base):
1173-
result = f"{base}/{endpoint.strip('/')}"
1174-
else:
1175-
result = endpoint
1176-
return result.strip("/")
1177-
1178-
11791175
def unwrapped(func: Callable) -> Callable:
11801176
while hasattr(func, "__wrapped__"):
11811177
func = func.__wrapped__

docs/HISTORY.md

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
- Added some basic test for persistent namespaces
88
- Add request context logging for failed HASS calls - contributed by [ekutner](https://github.com/ekutner)
99
- Reload modified apps on SIGUSR2 - contributed by [chatziko](https://github.com/chatziko)
10+
- Using urlib to create endpoints from URLs
1011

1112
**Fixes**
1213

@@ -16,14 +17,6 @@
1617
- Fix for connecting to Home Assistant with https
1718
- Fix for persistent namespaces in Python 3.12
1819
- Better error handling for receiving huge websocket messages in the Hass plugin
19-
- Fix production mode and scheduler race - contributed by [cebtenzzre](https://github.com/cebtenzzre)
20-
- Fix scheduler crash - contributed by [cebtenzzre](https://github.com/cebtenzzre)
21-
- Fix startup when no plugins are configured - contributed by [cebtenzzre](https://github.com/cebtenzzre)
22-
- Fix entity persistencre - contributed by [cebtenzzre](https://github.com/cebtenzzre)
23-
24-
**Features**
25-
26-
None
2720

2821
**Breaking Changes**
2922

0 commit comments

Comments
 (0)