Files
houseplan-card/tests_backend/pure_imports.py
T
Matysh 8dfb0a9e36 test: put the package stub in one place, under an honest condition
Чистые тесты подменяли 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
2026-08-30 20:11:31 +03:00

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