from __future__ import annotations import importlib import sys from pathlib import Path from types import ModuleType from typing import Type PROJECT_ROOT = Path(__file__).resolve().parents[1] if str(PROJECT_ROOT) not in sys.path: sys.path.append(str(PROJECT_ROOT)) if "airflow" not in sys.modules: airflow_module = ModuleType("airflow") airflow_module.__path__ = [str(PROJECT_ROOT / "airflow")] sys.modules["airflow"] = airflow_module providers_module = ModuleType("airflow.providers") providers_module.__path__ = [] sys.modules["airflow.providers"] = providers_module airflow_module.providers = providers_module postgres_module = ModuleType("airflow.providers.postgres") postgres_module.__path__ = [] sys.modules["airflow.providers.postgres"] = postgres_module providers_module.postgres = postgres_module hooks_module = ModuleType("airflow.providers.postgres.hooks") hooks_module.__path__ = [] sys.modules["airflow.providers.postgres.hooks"] = hooks_module postgres_module.hooks = hooks_module if "psycopg2" not in sys.modules: psycopg2_stub = ModuleType("psycopg2") psycopg2_stub.connect = lambda **_: None # type: ignore[assignment] sys.modules["psycopg2"] = psycopg2_stub def _ensure_stub_module(full_name: str) -> ModuleType: """ Ensure that module placeholders exist for a dotted path and return leaf module. """ parts = full_name.split(".") module: ModuleType | None = None path = "" for part in parts: path = f"{path}.{part}" if path else part if path not in sys.modules: new_module = ModuleType(path) if module is not None: setattr(module, part, new_module) sys.modules[path] = new_module module = new_module else: module = sys.modules[path] assert isinstance(module, ModuleType) return module