Skip to content

Commit

Permalink
Bump version
Browse files Browse the repository at this point in the history
  • Loading branch information
MatthewFlamm committed Nov 28, 2024
1 parent 868eefa commit d9e44b3
Show file tree
Hide file tree
Showing 9 changed files with 248 additions and 30 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# pytest-homeassistant-custom-component

![HA core version](https://img.shields.io/static/v1?label=HA+core+version&message=2024.11.3&labelColor=blue)
![HA core version](https://img.shields.io/static/v1?label=HA+core+version&message=2024.12.0b0&labelColor=blue)

[![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/#https://github.com/MatthewFlamm/pytest-homeassistant-custom-component)

Expand Down
2 changes: 1 addition & 1 deletion ha_version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
2024.11.3
2024.12.0b0
12 changes: 6 additions & 6 deletions requirements_dev.txt
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
# This file is originally from homeassistant/core and modified by pytest-homeassistant-custom-component.
astroid==3.3.5
mypy-dev==1.13.0a1
mypy-dev==1.14.0a3
pre-commit==4.0.0
pylint==3.3.1
types-aiofiles==24.1.0.20240626
types-atomicwrites==1.4.5.1
types-croniter==2.0.0.20240423
types-beautifulsoup4==4.12.0.20240907
types-caldav==1.3.0.20240824
types-croniter==4.0.0.20241030
types-beautifulsoup4==4.12.0.20241020
types-caldav==1.3.0.20241107
types-chardet==0.1.5
types-decorator==5.1.8.20240310
types-paho-mqtt==1.6.0.20240321
types-pillow==10.2.0.20240822
types-protobuf==5.28.0.20240924
types-psutil==6.0.0.20240901
types-protobuf==5.28.3.20241030
types-psutil==6.1.0.20241102
types-python-dateutil==2.9.0.20241003
types-python-slugify==8.0.2.20240310
types-pytz==2024.2.0.20241003
Expand Down
10 changes: 5 additions & 5 deletions requirements_test.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,16 @@

-c homeassistant/package_constraints.txt
-r requirements_test_pre_commit.txt
coverage==7.6.1
coverage==7.6.8
freezegun==1.5.1
license-expression==30.4.0
mock-open==1.4.0
pydantic==1.10.18
pydantic==1.10.19
pylint-per-file-ignores==1.3.2
pipdeptree==2.23.4
pytest-asyncio==0.24.0
pytest-aiohttp==1.0.5
pytest-cov==5.0.0
pytest-cov==6.0.0
pytest-freezer==0.4.8
pytest-github-actions-annotate-failures==0.2.0
pytest-socket==0.7.0
Expand All @@ -31,10 +31,10 @@ requests-mock==1.12.1
respx==0.21.1
syrupy==4.7.2
tqdm==4.66.5
homeassistant==2024.11.3
homeassistant==2024.12.0b0
SQLAlchemy==2.0.31

paho-mqtt==1.6.1

numpy==1.26.4
numpy==2.1.3

17 changes: 17 additions & 0 deletions src/pytest_homeassistant_custom_component/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -1821,3 +1821,20 @@ async def snapshot_platform(
state = hass.states.get(entity_entry.entity_id)
assert state, f"State not found for {entity_entry.entity_id}"
assert state == snapshot(name=f"{entity_entry.entity_id}-state")


def reset_translation_cache(hass: HomeAssistant, components: list[str]) -> None:
"""Reset translation cache for specified components.
Use this if you are mocking a core component (for example via
mock_integration), to ensure that the mocked translations are not
persisted in the shared session cache.
"""
translations_cache = translation._async_get_translations_cache(hass)
for loaded_components in translations_cache.cache_data.loaded.values():
for component_to_unload in components:
loaded_components.discard(component_to_unload)
for loaded_categories in translations_cache.cache_data.cache.values():
for loaded_components in loaded_categories.values():
for component_to_unload in components:
loaded_components.pop(component_to_unload, None)
4 changes: 2 additions & 2 deletions src/pytest_homeassistant_custom_component/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"""
from typing import TYPE_CHECKING, Final
MAJOR_VERSION: Final = 2024
MINOR_VERSION: Final = 11
PATCH_VERSION: Final = "3"
MINOR_VERSION: Final = 12
PATCH_VERSION: Final = "0b0"
__short_version__: Final = f"{MAJOR_VERSION}.{MINOR_VERSION}"
__version__: Final = f"{__short_version__}.{PATCH_VERSION}"
60 changes: 46 additions & 14 deletions src/pytest_homeassistant_custom_component/plugins.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
import requests_mock
import respx
from syrupy.assertion import SnapshotAssertion
from syrupy.session import SnapshotSession

from homeassistant import block_async_io
from homeassistant.exceptions import ServiceNotFound
Expand Down Expand Up @@ -96,7 +97,7 @@
from homeassistant.util.json import json_loads

from .ignore_uncaught_exceptions import IGNORE_UNCAUGHT_EXCEPTIONS
from .syrupy import HomeAssistantSnapshotExtension
from .syrupy import HomeAssistantSnapshotExtension, override_syrupy_finish
from .typing import (
ClientSessionGenerator,
MockHAClientWebSocket,
Expand Down Expand Up @@ -153,6 +154,11 @@ def pytest_configure(config: pytest.Config) -> None:
if config.getoption("verbose") > 0:
logging.getLogger().setLevel(logging.DEBUG)

# Override default finish to detect unused snapshots despite xdist
# Temporary workaround until it is finalised inside syrupy
# See https://github.com/syrupy-project/syrupy/pull/901
SnapshotSession.finish = override_syrupy_finish


def pytest_runtest_setup() -> None:
"""Prepare pytest_socket and freezegun.
Expand Down Expand Up @@ -508,30 +514,31 @@ def aiohttp_client(
clients = []

async def go(
__param: Application | BaseTestServer,
param: Application | BaseTestServer,
/,
*args: Any,
server_kwargs: dict[str, Any] | None = None,
**kwargs: Any,
) -> TestClient:
if isinstance(__param, Callable) and not isinstance( # type: ignore[arg-type]
__param, (Application, BaseTestServer)
if isinstance(param, Callable) and not isinstance( # type: ignore[arg-type]
param, (Application, BaseTestServer)
):
__param = __param(loop, *args, **kwargs)
param = param(loop, *args, **kwargs)
kwargs = {}
else:
assert not args, "args should be empty"

client: TestClient
if isinstance(__param, Application):
if isinstance(param, Application):
server_kwargs = server_kwargs or {}
server = TestServer(__param, loop=loop, **server_kwargs)
server = TestServer(param, loop=loop, **server_kwargs)
# Registering a view after starting the server should still work.
server.app._router.freeze = lambda: None
client = CoalescingClient(server, loop=loop, **kwargs)
elif isinstance(__param, BaseTestServer):
client = TestClient(__param, loop=loop, **kwargs)
elif isinstance(param, BaseTestServer):
client = TestClient(param, loop=loop, **kwargs)
else:
raise TypeError(f"Unknown argument type: {type(__param)!r}")
raise TypeError(f"Unknown argument type: {type(param)!r}")

await client.start_server()
clients.append(client)
Expand Down Expand Up @@ -1189,7 +1196,12 @@ def mock_get_source_ip() -> Generator[_patch]:

@pytest.fixture(autouse=True, scope="session")
def translations_once() -> Generator[_patch]:
"""Only load translations once per session."""
"""Only load translations once per session.
Warning: having this as a session fixture can cause issues with tests that
create mock integrations, overriding the real integration translations
with empty ones. Translations should be reset after such tests (see #131628)
"""
cache = _TranslationsCacheData({}, {})
patcher = patch(
"homeassistant.helpers.translation._TranslationsCacheData",
Expand Down Expand Up @@ -1770,10 +1782,30 @@ def mock_bleak_scanner_start() -> Generator[MagicMock]:


@pytest.fixture
def mock_integration_frame() -> Generator[Mock]:
"""Mock as if we're calling code from inside an integration."""
def integration_frame_path() -> str:
"""Return the path to the integration frame.
Can be parametrized with
`@pytest.mark.parametrize("integration_frame_path", ["path_to_frame"])`
- "custom_components/XYZ" for a custom integration
- "homeassistant/components/XYZ" for a core integration
- "homeassistant/XYZ" for core (no integration)
Defaults to core component `hue`
"""
return "homeassistant/components/hue"


@pytest.fixture
def mock_integration_frame(integration_frame_path: str) -> Generator[Mock]:
"""Mock where we are calling code from.
Defaults to calling from `hue` core integration, and can be parametrized
with `integration_frame_path`.
"""
correct_frame = Mock(
filename="/home/paulus/homeassistant/components/hue/light.py",
filename=f"/home/paulus/{integration_frame_path}/light.py",
lineno="23",
line="self.light.is_on",
)
Expand Down
Loading

0 comments on commit d9e44b3

Please sign in to comment.