Metadata-Version: 2.4
Name: core-framework
Version: 1.6.0
Summary: Core framework package (import as core_framework)
Project-URL: Homepage, https://github.com/NepNepFFXIV/core-framework
Project-URL: Repository, https://github.com/NepNepFFXIV/core-framework
License-Expression: MIT
License-File: LICENSE
Requires-Python: >=3.14
Requires-Dist: aiofiles>=25.1.0
Requires-Dist: alembic>=1.18.4
Requires-Dist: arq>=0.28.0
Requires-Dist: async-lru>=2.1.0
Requires-Dist: asyncer>=0.0.14
Requires-Dist: asyncpg>=0.31.0
Requires-Dist: asyncssh>=2.23.0
Requires-Dist: brotli-asgi>=1.6.0
Requires-Dist: cashews[redis]>=7.5.0
Requires-Dist: device-detector>=6.2.0
Requires-Dist: fastapi[standard]>=0.136.1
Requires-Dist: firebase-admin>=7.4.0
Requires-Dist: httpx[http2]>=0.28.1
Requires-Dist: itsdangerous>=2.2.0
Requires-Dist: logfire[asyncpg,fastapi,httpx,redis]>=4.32.1
Requires-Dist: mashumaro[orjson]>=3.20
Requires-Dist: orjson>=3.11.7
Requires-Dist: pillow>=12.2.0
Requires-Dist: python-ulid>=3.1.0
Requires-Dist: structlog>=25.5.0
Requires-Dist: tenacity>=9.1.4
Provides-Extra: testing
Requires-Dist: asgi-lifespan>=2.1.0; extra == 'testing'
Requires-Dist: pytest-xdist>=3.6.0; extra == 'testing'
Requires-Dist: pytest>=9.0.3; extra == 'testing'
Requires-Dist: testcontainers[postgres,redis]>=4.13.2; extra == 'testing'
Description-Content-Type: text/markdown

# Core framework

Install from PyPI as **`core-framework`**, import **`core_framework`**. MIT — [LICENSE](LICENSE). [Repository](https://github.com/NepNepFFXIV/core-framework), [PyPI](https://pypi.org/project/core-framework/).

## Install

```bash
uv add core-framework
```

## Local development

Use **Python 3.14**. Install **uv** and **Docker**.

```bash
docker compose -f docker-compose.dev.yaml up -d
uv sync --locked --all-extras --dev
uv run cf-alembic
make run
```

**Firebase:** copy **`firebase_config.example.json`** to **`firebase_config.json`** at the repo root and replace with your Firebase project’s **service account** JSON from the console.

For **`make test`**, use the Firebase CLI (Auth emulator). Stop DB/Redis: **`docker compose -f docker-compose.dev.yaml down`**.

## Hosts

In your host app, load **`Settings`** or a **`Settings`** subclass from **`core_framework.core.settings`**, pass it to **`init_app`** from **`core_framework.main`**, then wire host-specific dependencies, exception handlers, and routers.

```python
from core_framework.main import init_app
from fastapi import FastAPI

from myapp.settings import HostSettings, load_default_settings


def build_app(settings: HostSettings | None = None) -> FastAPI:
    resolved = settings if settings is not None else load_default_settings()
    app = init_app(resolved)

    from myapp.bootstrap import configure_dependencies
    from myapp.exception_handlers import setup_exception_handlers

    configure_dependencies(runtime=app.state.core_runtime)
    setup_exception_handlers(app)

    from myapp.api.router import router

    app.include_router(router)
    return app
```

From the host repository root, run **`uv run cf-alembic`**. See [core-framework-migration](docs/core-framework-migration.md).

## Host pytest

In your host repository, add the **`core-framework[testing]`** extra to dev or test dependencies. In **`tests/conftest.py`**, register **`pytest_core_framework_config`** (returns **`TestConfig`**) and a session-scoped **`anyio_backend`** fixture that returns **`"asyncio"`**.

```python
import pytest

from core_framework.testing import TestConfig

from myapp.settings import load_default_settings


def pytest_core_framework_config() -> TestConfig:
    from myapp.main import build_app

    return TestConfig(
        settings_loader=load_default_settings,
        app_factory=build_app,
    )


@pytest.fixture(scope="session")
def anyio_backend() -> str:
    return "asyncio"
```

See [Package API — Testing](docs/package-api.md#testing-pytest-plugin) and [testing plugin design](docs/testing-plugin-design.md).
