mirror of
https://github.com/Matysh/houseplan-card
synced 2026-10-04 05:41:34 +00:00
Чистые тесты подменяли custom_components и custom_components.houseplan пустышками и не убирали их никогда. В CI это не стреляло только потому, что настоящий пакет успевал импортироваться из файла, который идёт раньше по алфавиту: условие «если ещё не импортирован» оказывалось ложным. То есть корректность HA-харнесса держалась на именах файлов в каталоге, и хватило бы переименования, чтобы получить #389 заново. Подмена переехала в conftest и стала условной по единственному честному признаку: есть Home Assistant — работаем с настоящим пакетом и не подменяем ничего; нет — HA-тесты и так пропущены, ломать нечего. Первым заходом я делал подмену обратимой прямо в тестах, контекстным менеджером. Замер показал, что так теряется работоспособность test_wall_segment_model в песочнице: он импортирует пакет обычным способом и жил как раз за счёт чужой пустышки. Развилка в conftest сохраняет оба окружения и убирает зависимость от порядка файлов. Проверено в обе стороны: в песочнице 240 passed, а в эмуляции «HA есть» объект пакета после прогона тот же, что был до. Issue: #394 User-Visible: no
34 lines
1.8 KiB
Python
34 lines
1.8 KiB
Python
"""Загрузка модуля интеграции по пути, без Home Assistant (issue #394).
|
|
|
|
Зачем не обычный импорт: часть чистых тестов читает модуль под своим именем
|
|
(`hp_validation`) либо под каноническим, чтобы работали относительные импорты
|
|
внутри него. Родительские пакеты при этом должны существовать — в окружении с
|
|
Home Assistant это настоящий пакет, без него пустышки ставит `conftest.py`.
|
|
|
|
Ставить пустышки здесь, в момент загрузки, было бы ошибкой: именно так они
|
|
переживали свой тест и доставались всей сессии. В #389 это стоило пяти часов
|
|
красного `dev` — HA получал пустышку вместо интеграции и не мог её поднять.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import importlib.util
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
REPO = Path(__file__).resolve().parent.parent
|
|
PACKAGE_ROOT = REPO / "custom_components"
|
|
HOUSEPLAN_ROOT = PACKAGE_ROOT / "houseplan"
|
|
|
|
|
|
def load_pure(name: str, file: Path):
|
|
"""Загрузить модуль по пути под указанным именем.
|
|
|
|
Имя значимо: относительные импорты внутри модуля резолвятся только тогда,
|
|
когда модуль знает, какому пакету принадлежит.
|
|
"""
|
|
spec = importlib.util.spec_from_file_location(name, file)
|
|
module = importlib.util.module_from_spec(spec)
|
|
sys.modules[name] = module
|
|
spec.loader.exec_module(module)
|
|
return module
|