Contributing
Contributions are welcome. This guide covers setting up the development environment, running tests, linting, and building documentation.
Development setup
Prerequisites
- Python 3.12+
- uv — fast Python package manager
Clone and install
git clone https://github.com/utsmok/aletheca.git
cd aletheca
uv sync --all-groups
This installs the package in editable mode along with all dependency groups (dev, docs, lint, test).
??? note "Dependency groups"
The pyproject.toml defines these groups:
- **dev** — pytest, pytest-asyncio, pytest-cov, pytest-httpx, python-dotenv
- **docs** — mkdocs, mkdocs-material, mkdocstrings
- **lint** — ruff
- **test** — pytest, pytest-randomly
Running tests
# Run all unit tests
uv run pytest
# Run with coverage
uv run pytest --cov=aletheca
# Run a specific test file
uv run pytest tests/test_session.py
# Run with verbose output
uv run pytest -v
Test markers
Tests that hit the live OpenAlex API are marked with @pytest.mark.live_api and are excluded by default:
# Run only live API tests (requires ALETHECA_OPENALEX_API_KEY)
uv run pytest -m live_api
??? note "asyncio mode"
The test suite uses asyncio_mode = "auto" in pytest — no need for @pytest.mark.asyncio decorators on async test functions.
Linting and formatting
Aletheca uses ruff for both linting and formatting:
# Check for lint errors
uv run ruff check .
# Auto-fix lint errors
uv run ruff check --fix .
# Format code
uv run ruff format .
# Check formatting without writing
uv run ruff format --check .
Type checking
uv run ty check .
Building documentation
Documentation uses mkdocs-material with mkdocstrings for API reference generation:
# Build static docs
uv run mkdocs build
# Live preview with auto-reload
uv run mkdocs serve
The docs source lives in docs/. The mkdocs configuration is in mkdocs.yml at the project root.
Project structure
src/aletheca/
__init__.py # Public API: AlethecaSession, AlethecaClient
client.py # AlethecaClient — async HTTP client
session.py # AlethecaSession — high-level context manager
config.py # AlethecaSettings (pydantic-settings)
constants.py # Base URL, defaults, user agent
endpoints.py # Pydantic filter models for all endpoints
queries.py # Convenience query functions
_helpers.py # DOI normalization, ID parsing, abstract reconstruction
unwrapper.py # OpenAlex response unwrapper (meta/results)
py.typed # PEP 561 marker
models/ # Pydantic v2 entity models
base.py # BaseEntity, ApiResponse, Meta
work.py # Work, Authorship, DehydratedSource
author.py # Author
source.py # Source
institution.py # Institution
topic.py # Topic
keyword.py # Keyword
publisher.py # Publisher
funder.py # Funder
award.py # Award
common.py # Shared nested types (Location, OpenAccess, etc.)
ids.py # Entity ID models (WorkIds, AuthorIds, etc.)
safe_types.py # SafeStr, SafeList wrappers
resources/ # Endpoint-specific resource clients
_standard.py # AlethecaResourceClient base class
works_client.py # WorksClient
authors_client.py # AuthorsClient
... # One client per entity
tests/
test_*.py # Unit and integration tests
Code conventions
- Use
uv runfor everything — neverpython,pip, or manual venv activation. - Ruff formatting — 88 character line length, configured in
pyproject.toml. - Pydantic v2 models — all entity models use
ConfigDict(extra="allow")for forward-compatibility with API changes. - Keyword arguments — instantiate models with keyword args, never positional.
- Async-only — all API operations are async. No synchronous client exists yet.
- Typed — the package ships
py.typed. Preserve type annotations for downstream users.
Pull request checklist
Before opening a PR:
uv run ruff check .passesuv run ruff format --check .passesuv run pytestpasses- New functionality includes tests
- Public API changes update
__all__exports