diff --git a/.devcontainer.json b/.devcontainer.json index 941547f4..0a09ed54 100644 --- a/.devcontainer.json +++ b/.devcontainer.json @@ -1,7 +1,7 @@ { "name": "basnijholt/adaptive_lighting", - "image": "mcr.microsoft.com/vscode/devcontainers/python:3.13", - "postCreateCommand": "scripts/setup-devcontainer", + "image": "mcr.microsoft.com/devcontainers/python:1-3.13", + "postCreateCommand": "./scripts/setup-devcontainer && . .venv/bin/activate", "forwardPorts": [ 8123 ], @@ -36,7 +36,5 @@ } }, "remoteUser": "vscode", - "features": { - "ghcr.io/devcontainers/features/rust:1": {} - } + "features": {} } diff --git a/.github/workflows/pytest.yaml b/.github/workflows/pytest.yaml index 68d4ff08..411cfdd5 100644 --- a/.github/workflows/pytest.yaml +++ b/.github/workflows/pytest.yaml @@ -14,22 +14,6 @@ jobs: fail-fast: false matrix: include: - - python-version: "3.10" - core-version: "2022.11.5" - - python-version: "3.10" - core-version: "2022.12.9" - - python-version: "3.10" - core-version: "2023.1.7" - - python-version: "3.10" - core-version: "2023.2.5" - - python-version: "3.10" - core-version: "2023.3.6" - - python-version: "3.10" - core-version: "2023.4.6" - - python-version: "3.10" - core-version: "2023.5.4" - - python-version: "3.11" - core-version: "2023.6.3" - python-version: "3.11" core-version: "2023.7.3" - python-version: "3.11" @@ -66,7 +50,7 @@ jobs: core-version: "2024.11.3" - python-version: "3.12" core-version: "2024.12.0" - - python-version: "3.12" + - python-version: "3.13" core-version: "dev" steps: - name: Check out code from GitHub @@ -82,6 +66,7 @@ jobs: timeout-minutes: 60 run: | export PYTHONPATH=${PYTHONPATH}:${PWD} + source .venv/bin/activate cd core python3 -X dev -m pytest \ -vvv \ diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..e59dc709 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,20 @@ +{ + "files.associations": { + "*.yaml": "home-assistant" + }, + "python.defaultInterpreterPath": "${workspaceFolder}/.venv/bin/python", + "python.testing.pytestEnabled": true, + "python.testing.pytestArgs": [ + "-vvv", + "-qq", + "--timeout=9", + "--durations=10", + "--cov=homeassistant", + "--cov-report=xml", + "-o", + "console_output_style=count", + "-p", + "no:sugar", + "core/tests/components/adaptive_lighting" + ] +} diff --git a/hacs.json b/hacs.json index f21e6d60..9c9035ef 100644 --- a/hacs.json +++ b/hacs.json @@ -1,5 +1,5 @@ { "name": "Adaptive Lighting", "render_readme": true, - "homeassistant": "2022.11.0" + "homeassistant": "2023.7.0" } diff --git a/scripts/setup-dependencies b/scripts/setup-dependencies index ca14045d..9409ac0c 100755 --- a/scripts/setup-dependencies +++ b/scripts/setup-dependencies @@ -2,7 +2,11 @@ set -ex cd "$(dirname "$0")/.." -pip install -r core/requirements.txt +pip install uv +uv venv +source .venv/bin/activate + +uv pip install -r core/requirements.txt if grep -q 'codecov' core/requirements_test.txt; then # Older HA versions still have `codecov` in `requirements_test.txt` @@ -14,8 +18,8 @@ if grep -q 'mypy-dev==1.10.0a3' core/requirements_test.txt; then # mypy-dev==1.10.0a3 seems to not be available anymore, HA 2024.4 and 2024.5 are affected sed -i 's/mypy-dev==1.10.0a3/mypy-dev==1.10.0b1/' core/requirements_test.txt fi -pip install -r core/requirements_test.txt +uv pip install -r core/requirements_test.txt -pip install -e core/ -pip install ulid-transform # this is in Adaptive-lighting's manifest.json -pip install $(python test_dependencies.py) +uv pip install -e core/ +uv pip install ulid-transform # this is in Adaptive-lighting's manifest.json +uv pip install $(python test_dependencies.py) diff --git a/scripts/setup-devcontainer b/scripts/setup-devcontainer index 11fdd106..bdb82534 100755 --- a/scripts/setup-devcontainer +++ b/scripts/setup-devcontainer @@ -1,5 +1,5 @@ #!/usr/bin/env bash -set -e +set -ex cd "$(dirname "$0")/.." # Clone only if the folder doesn't exist @@ -8,10 +8,10 @@ if [[ ! -d "core" ]]; then fi pip install \ - colorlog==6.7.0 \ - pip>=21.0,<23.2 \ - ruff==0.0.265 + colorlog \ + pip \ + ruff ./scripts/setup-dependencies ./scripts/setup-symlinks -pre-commit install-hooks +uv run pre-commit install-hooks diff --git a/tests/test_config_flow.py b/tests/test_config_flow.py index 1a9e8fbf..af01fc11 100644 --- a/tests/test_config_flow.py +++ b/tests/test_config_flow.py @@ -1,6 +1,5 @@ """Test Adaptive Lighting config flow.""" -from homeassistant import data_entry_flow from homeassistant.components.adaptive_lighting.const import ( CONF_SUNRISE_TIME, CONF_SUNSET_TIME, @@ -11,6 +10,7 @@ from homeassistant.components.adaptive_lighting.const import ( ) from homeassistant.config_entries import SOURCE_IMPORT from homeassistant.const import CONF_NAME +from homeassistant.data_entry_flow import FlowResultType from tests.common import MockConfigEntry @@ -24,7 +24,7 @@ async def test_flow_manual_configuration(hass): context={"source": "user"}, ) - assert result["type"] == data_entry_flow.RESULT_TYPE_FORM + assert result["type"] == FlowResultType.FORM assert result["step_id"] == "user" assert result["handler"] == "adaptive_lighting" @@ -32,7 +32,7 @@ async def test_flow_manual_configuration(hass): result["flow_id"], user_input={CONF_NAME: "living room"}, ) - assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY + assert result["type"] == FlowResultType.CREATE_ENTRY assert result["title"] == "living room" @@ -46,7 +46,7 @@ async def test_import_success(hass): data=data, ) - assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY + assert result["type"] == FlowResultType.CREATE_ENTRY assert result["title"] == DEFAULT_NAME for key, value in data.items(): assert result["data"][key] == value @@ -65,7 +65,7 @@ async def test_options(hass): await hass.config_entries.async_setup(entry.entry_id) result = await hass.config_entries.options.async_init(entry.entry_id) - assert result["type"] == data_entry_flow.RESULT_TYPE_FORM + assert result["type"] == FlowResultType.FORM assert result["step_id"] == "init" data = DEFAULT_DATA.copy() @@ -75,7 +75,7 @@ async def test_options(hass): result["flow_id"], user_input=data, ) - assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY + assert result["type"] == FlowResultType.CREATE_ENTRY for key, value in data.items(): assert result["data"][key] == value @@ -114,6 +114,9 @@ async def test_import_twice(hass): ) +# TODO: Fix, broken for all supported versions +# But in ≤2024.5 it gives homeassistant.config_entries.UnknownEntry: cd69dbda65bd3f86e9a32d974cdfa23f +# and ≥2024.6 it times out async def test_changing_options_when_using_yaml(hass): """Test changing options when using YAML.""" entry = MockConfigEntry( @@ -125,6 +128,7 @@ async def test_changing_options_when_using_yaml(hass): ) entry.add_to_hass(hass) + await hass.block_till_done() await hass.config_entries.async_setup(entry.entry_id) result = await hass.config_entries.options.async_init(entry.entry_id) diff --git a/tests/test_switch.py b/tests/test_switch.py index e582a031..afc720e5 100644 --- a/tests/test_switch.py +++ b/tests/test_switch.py @@ -11,7 +11,6 @@ from random import randint from typing import Any from unittest.mock import Mock, patch -import homeassistant.config as config_util import homeassistant.util.dt as dt_util import pytest import ulid_transform @@ -362,6 +361,19 @@ async def test_adaptive_lighting_switches(hass): assert len(data.keys()) == 5 +def async_process_ha_core_config(hass, config): + """Set up the Home Assistant configuration.""" + try: + # ha >= "2023.11.0" + from homeassistant.core_config import async_process_ha_core_config + + return async_process_ha_core_config(hass, config) + except ModuleNotFoundError: + import homeassistant.config as config_util + + return config_util.async_process_ha_core_config(hass, config) + + @pytest.mark.parametrize(("lat", "long", "timezone"), LAT_LONG_TZS) async def test_adaptive_lighting_time_zones_with_default_settings( hass, @@ -371,9 +383,9 @@ async def test_adaptive_lighting_time_zones_with_default_settings( reset_time_zone, # pylint: disable=redefined-outer-name ): """Test setting up the Adaptive Lighting switches with different timezones.""" - await config_util.async_process_ha_core_config( + await async_process_ha_core_config( hass, - {"latitude": lat, "longitude": long, "time_zone": timezone}, + {"latitude": lat, "longitude": long, "time_zone": timezone, "country": "US"}, ) _, switch = await setup_switch(hass, {}) # Shouldn't raise an exception ever @@ -394,9 +406,9 @@ async def test_adaptive_lighting_time_zones_and_sun_settings( Also test the (sleep) brightness and color temperature settings. """ - await config_util.async_process_ha_core_config( + await async_process_ha_core_config( hass, - {"latitude": lat, "longitude": long, "time_zone": timezone}, + {"latitude": lat, "longitude": long, "time_zone": timezone, "country": "US"}, ) _, switch = await setup_switch( hass, @@ -1359,6 +1371,8 @@ def mock_area_registry( area_kwargs["icon"] = None if dt >= datetime.date(2024, 3, 1): area_kwargs["floor_id"] = "test-floor" + if dt >= datetime.date(2024, 11, 1): + area_kwargs.pop("normalized_name") # This mess... 🤯 if dt >= datetime.date(2024, 2, 1) and dt != datetime.date(2024, 4, 1): @@ -1588,6 +1602,7 @@ async def test_proactive_adaptation(hass): assert state.attributes[ATTR_COLOR_TEMP_KELVIN] == 3448 +# TODO: Breaks since 2024.5.0! async def test_proactive_adaptation_with_separate_commands(hass): """Validate that a split proactive adaptation yields one additional service call.""" switch, _ = await setup_lights_and_switch( @@ -1927,9 +1942,9 @@ async def test_adapt_until_sleep_and_rgb_colors(hass): Also test the (sleep) brightness and color temperature settings. """ lat, long, timezone = (32.87336, -117.22743, "US/Pacific") - await config_util.async_process_ha_core_config( + await async_process_ha_core_config( hass, - {"latitude": lat, "longitude": long, "time_zone": timezone}, + {"latitude": lat, "longitude": long, "time_zone": timezone, "country": "US"}, ) switch, lights = await setup_lights_and_switch( hass,