From e730b88d6db851843063b2152f353caa4412c526 Mon Sep 17 00:00:00 2001 From: renovate Date: Sat, 10 Oct 2026 00:31:18 +0000 Subject: [PATCH] chore(backend): update template to v0.6.0, conflicts left --- .copier/backend.yml | 2 +- backend/.env.example | 1 + backend/CLAUDE.md | 7 +++-- backend/Makefile | 20 +++--------- backend/migrations/env.py | 15 +++++++++ backend/scripts/check_imports.py | 44 +++++++++++++++++++++++++++ backend/scripts/session/create.py | 4 +++ backend/src/dependencies/container.py | 4 +++ backend/src/userbot/__init__.py | 3 ++ backend/src/utils/env.py | 20 ++++++++++++ backend/src/utils/imports.py | 6 ++++ backend/src/utils/logging.py | 4 +-- 12 files changed, 109 insertions(+), 21 deletions(-) create mode 100644 backend/scripts/check_imports.py create mode 100644 backend/src/utils/imports.py diff --git a/.copier/backend.yml b/.copier/backend.yml index d72ae20..f99b06c 100644 --- a/.copier/backend.yml +++ b/.copier/backend.yml @@ -1,4 +1,4 @@ -_commit: v0.4.0 +_commit: v0.6.0 _src_path: https://git.kotikot.com/templates/backend-python.git author_email: h@kotikot.com author_name: h diff --git a/backend/.env.example b/backend/.env.example index eafd9f2..098c87f 100644 --- a/backend/.env.example +++ b/backend/.env.example @@ -4,6 +4,7 @@ TZ=UTC LOG__LEVEL=INFO LOG__LEVEL_EXTERNAL=WARNING LOG__SHOW_TIME=false +LOG__SHOW_LOCALS=false LOG__CONSOLE_WIDTH=150 DB__HOST=postgres diff --git a/backend/CLAUDE.md b/backend/CLAUDE.md index 2cabb83..9f4b8ca 100644 --- a/backend/CLAUDE.md +++ b/backend/CLAUDE.md @@ -1,7 +1,8 @@ ## Checking commands After writing code, always run from `backend/`: ```shell -ruff format -ruff check --fix -ty check +make fmt +make check ``` + +Mind startup imports: `make check` runs `scripts/check_imports.py`. diff --git a/backend/Makefile b/backend/Makefile index cbcd6e6..99d7ec2 100644 --- a/backend/Makefile +++ b/backend/Makefile @@ -1,12 +1,15 @@ COMPOSE := cd .. && docker compose +<<<<<<< before updating IMAGE := beavergram/backend IMAGE_INPUTS := pyproject.toml uv.lock Dockerfile CODE := src scripts ../frontend SERVICES := api userbot watcher changed = ! git diff --quiet $(1) -- $(2) 2>/dev/null stamp = { git update-ref $(1) HEAD 2>/dev/null || true; } +======= +>>>>>>> after updating -.PHONY: fmt check build pre-deploy post-deploy migrate revision session +.PHONY: fmt check build migrate revision session fmt: uv run ruff format @@ -16,24 +19,11 @@ check: uv run ruff format --check uv run ruff check uv run ty check + uv run python scripts/check_imports.py build: $(COMPOSE) build api -pre-deploy: - @if $(call changed,refs/deploy/backend,$(IMAGE_INPUTS)) || ! docker image inspect $(IMAGE) >/dev/null 2>&1; then \ - $(MAKE) build && $(call stamp,refs/deploy/backend) && $(call stamp,refs/deploy/backend-code); \ - fi - @$(COMPOSE) config --services | grep -qx postgres && $(COMPOSE) up -d postgres || true - $(MAKE) migrate - -post-deploy: - @if $(call changed,refs/deploy/backend-code,$(CODE)); then \ - running=$$($(COMPOSE) ps --services --status running | grep -x $(addprefix -e ,$(SERVICES))); \ - [ -z "$$running" ] || $(COMPOSE) restart $$running; \ - $(call stamp,refs/deploy/backend-code); \ - fi - migrate: $(COMPOSE) run --rm migrator $(or $(filter-out $@,$(MAKECMDGOALS)),upgrade head) diff --git a/backend/migrations/env.py b/backend/migrations/env.py index 5dea3f2..bfe3016 100644 --- a/backend/migrations/env.py +++ b/backend/migrations/env.py @@ -16,14 +16,20 @@ if config.config_file_name is not None: target_metadata = SQLModel.metadata +<<<<<<< before updating def _async_url() -> str: return env.db.connection_url.replace("postgresql://", "postgresql+asyncpg://", 1) +======= +def include_name(name: str | None, type_: str, _parents: object) -> bool: + return not (type_ == "table" and name is not None and name.startswith("taskiq_")) +>>>>>>> after updating def run_migrations_offline() -> None: context.configure( url=_async_url(), target_metadata=target_metadata, + include_name=include_name, literal_binds=True, dialect_opts={"paramstyle": "named"}, ) @@ -31,8 +37,17 @@ def run_migrations_offline() -> None: context.run_migrations() +<<<<<<< before updating def _do_run_migrations(connection) -> None: # noqa: ANN001 context.configure(connection=connection, target_metadata=target_metadata) +======= +def do_run_migrations(connection: Connection) -> None: + context.configure( + connection=connection, + target_metadata=target_metadata, + include_name=include_name, + ) +>>>>>>> after updating with context.begin_transaction(): context.run_migrations() diff --git a/backend/scripts/check_imports.py b/backend/scripts/check_imports.py new file mode 100644 index 0000000..9878fb3 --- /dev/null +++ b/backend/scripts/check_imports.py @@ -0,0 +1,44 @@ +import os +import subprocess +import sys + +HEAVY = ["aiogram", "pyrogram", "fastapi", "google.genai"] +SERVICES = { + "api": (["api.app"], {"fastapi"}), + "userbot": (["userbot.runner", "userbot.handlers"], {"pyrogram"}), +} +PROBE = """ +import importlib, sys +for module in sys.argv[1].split(","): + importlib.import_module(module) +print(" ".join(name for name in sys.argv[2:] if name in sys.modules)) +""" +ENV = dict(os.environ) + + +def loaded(modules: list[str]) -> tuple[set[str], str]: + result = subprocess.run( # noqa: S603 + [sys.executable, "-c", PROBE, ",".join(modules), *HEAVY], + capture_output=True, + text=True, + cwd="src", + env=ENV, + check=False, + ) + error = (result.stderr.strip().splitlines() or ["exit code"])[-1] + return set(result.stdout.split()) & set(HEAVY), error if result.returncode else "" + + +def main() -> int: + failed = False + for service, (modules, allowed) in SERVICES.items(): + found, error = loaded(modules) + extra = sorted(found - allowed) + status = error or ("imports " + ", ".join(extra) if extra else "") + print(f"{service:10s} {'FAIL: ' + status if status else 'ok'}") + failed |= bool(status) + return int(failed) + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/backend/scripts/session/create.py b/backend/scripts/session/create.py index d2194e4..0847237 100644 --- a/backend/scripts/session/create.py +++ b/backend/scripts/session/create.py @@ -5,6 +5,7 @@ from userbot.modules.client import PyroClient from utils.env import env from utils.logging import logger, setup_logging +<<<<<<< before updating setup_logging() @@ -18,6 +19,9 @@ def _finalize_session(sessions_dir: Path, name: str) -> Path: target = sessions_dir / f"{name}.session" (sessions_dir / "generated.session").rename(target) return target +======= +from userbot.modules.client import PyroClient +>>>>>>> after updating async def main() -> None: diff --git a/backend/src/dependencies/container.py b/backend/src/dependencies/container.py index f2cf878..7bd29b6 100644 --- a/backend/src/dependencies/container.py +++ b/backend/src/dependencies/container.py @@ -3,4 +3,8 @@ from dishka import make_async_container from dependencies.providers.postgres import DbProvider from dependencies.providers.storage import StorageProvider +<<<<<<< before updating container = make_async_container(DbProvider(), StorageProvider()) +======= +container = make_async_container(DbProvider(), RepositoryProvider()) +>>>>>>> after updating diff --git a/backend/src/userbot/__init__.py b/backend/src/userbot/__init__.py index 64586e2..f322d9e 100644 --- a/backend/src/userbot/__init__.py +++ b/backend/src/userbot/__init__.py @@ -1,3 +1,6 @@ +<<<<<<< before updating from userbot.modules.client import DEVICE_MODEL, DEVICE_MODEL_LIMIT, PyroClient __all__ = ["DEVICE_MODEL", "DEVICE_MODEL_LIMIT", "PyroClient"] +======= +>>>>>>> after updating diff --git a/backend/src/utils/env.py b/backend/src/utils/env.py index bc7cb3f..15097c9 100644 --- a/backend/src/utils/env.py +++ b/backend/src/utils/env.py @@ -4,7 +4,27 @@ from pydantic import Field, SecretStr from pydantic_settings import BaseSettings, SettingsConfigDict +<<<<<<< before updating class DatabaseSettings(BaseSettings): +======= +def is_prod() -> bool: + return os.getenv("RUN_ENVIRONMENT") == "prod" + + +class Section(BaseSettings): + model_config = SettingsConfigDict(extra="ignore") + + +class LogSettings(Section): + level: str = "INFO" + level_external: str = "WARNING" + show_time: bool = False + show_locals: bool = False + console_width: int = 150 + + +class DatabaseSettings(Section): +>>>>>>> after updating host: str = "postgres" port: int = 5432 user: str = "beavergram" diff --git a/backend/src/utils/imports.py b/backend/src/utils/imports.py new file mode 100644 index 0000000..b267223 --- /dev/null +++ b/backend/src/utils/imports.py @@ -0,0 +1,6 @@ +import asyncio +from importlib import import_module + + +async def preload(module: str) -> None: + await asyncio.to_thread(import_module, module) diff --git a/backend/src/utils/logging.py b/backend/src/utils/logging.py index 29ef942..906fecd 100644 --- a/backend/src/utils/logging.py +++ b/backend/src/utils/logging.py @@ -20,13 +20,13 @@ def setup_logging() -> None: markup=True, rich_tracebacks=True, enable_link_path=False, - tracebacks_show_locals=True, + tracebacks_show_locals=env.log.show_locals, omit_repeated_times=False, show_time=env.log.show_time, ) ], ) - install(console=console, show_locals=True) + install(console=console, show_locals=env.log.show_locals) logger = logging.getLogger("beavergram")