From 8f6ea0fe8ffc07209911ffa2557ebd80c634fd9e Mon Sep 17 00:00:00 2001 From: d-eigo-hara Date: Thu, 8 Oct 2026 17:45:48 +0900 Subject: [PATCH 1/7] fix: gha --- .github/labeler.yml | 3 - .github/protection.json | 15 --- .github/workflows/publish-app.yml | 73 --------------- .github/workflows/publish-devcontainer.yml | 73 --------------- .github/workflows/release.yml | 102 +++++++++++++++------ .github/workflows/setting.yml | 18 ++-- .github/workflows/test.yml | 1 - 7 files changed, 85 insertions(+), 200 deletions(-) delete mode 100644 .github/workflows/publish-app.yml delete mode 100644 .github/workflows/publish-devcontainer.yml diff --git a/.github/labeler.yml b/.github/labeler.yml index 9df15089..dc108299 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -13,6 +13,3 @@ hotfix: refactor: - head-branch: ["^refactor/"] - -release: - - head-branch: ["^release/"] diff --git a/.github/protection.json b/.github/protection.json index 987fa795..ba49d1ca 100644 --- a/.github/protection.json +++ b/.github/protection.json @@ -1,19 +1,4 @@ { - "develop": { - "allow_deletions": false, - "allow_force_pushes": false, - "enforce_admins": false, - "required_pull_request_reviews": { - "dismiss_stale_reviews": false, - "require_code_owner_reviews": false, - "required_approving_review_count": 1 - }, - "required_status_checks": { - "contexts": [], - "strict": true - }, - "restrictions": null - }, "main": { "allow_deletions": false, "allow_force_pushes": false, diff --git a/.github/workflows/publish-app.yml b/.github/workflows/publish-app.yml deleted file mode 100644 index 5cd4b796..00000000 --- a/.github/workflows/publish-app.yml +++ /dev/null @@ -1,73 +0,0 @@ -name: Publish App to GHCR - -on: - push: - branches: - - develop - paths: - - ".github/workflows/publish-app.yml" - - ".python-version" - - "Dockerfile" - tags: - - "v*" - - workflow_dispatch: - -env: - IMAGE_NAME: ${{ github.repository }}/app - REGISTRY: ghcr.io - -jobs: - publish: - runs-on: ubuntu-latest - - permissions: - contents: read - packages: write - - steps: - - name: Checkout Repository - uses: actions/checkout@v7 - - - name: Setup Docker Buildx - uses: docker/setup-buildx-action@v4 - - - name: Log in to Container Registry - uses: docker/login-action@v4.6.0 - with: - registry: ${{ env.REGISTRY }} - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Extract Metadata - id: meta - uses: docker/metadata-action@v6 - with: - images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} - tags: | - type=ref,event=branch - type=semver,pattern={{version}} - type=sha,prefix={{branch}}- - type=raw,value=latest,enable={{is_default_branch}} - labels: | - maintainer=a5chin - org.opencontainers.image.url=https://github.com/${{ github.repository }} - org.opencontainers.image.source=https://github.com/${{ github.repository }} - org.opencontainers.image.vendor=a5chin - org.opencontainers.image.title=python-uv - org.opencontainers.image.description=App for Python development with uv-based dependency management and environment configuration. - org.opencontainers.image.documentation=https://a5chin.github.io/python-uv/ - org.opencontainers.image.authors=a5chin - org.opencontainers.image.licenses=MIT - - - name: Build and Push App Image - uses: docker/build-push-action@v7 - with: - context: . - file: Dockerfile - push: true - provenance: false - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} - cache-from: type=gha - cache-to: type=gha,mode=max diff --git a/.github/workflows/publish-devcontainer.yml b/.github/workflows/publish-devcontainer.yml deleted file mode 100644 index a7611ee5..00000000 --- a/.github/workflows/publish-devcontainer.yml +++ /dev/null @@ -1,73 +0,0 @@ -name: Publish Devcontainer to GHCR - -on: - push: - branches: - - develop - paths: - - ".devcontainer/Dockerfile" - - ".github/workflows/publish-devcontainer.yml" - - ".python-version" - tags: - - "v*" - - workflow_dispatch: - -env: - IMAGE_NAME: ${{ github.repository }}/devcontainer - REGISTRY: ghcr.io - -jobs: - publish: - runs-on: ubuntu-latest - - permissions: - contents: read - packages: write - - steps: - - name: Checkout Repository - uses: actions/checkout@v7 - - - name: Setup Docker Buildx - uses: docker/setup-buildx-action@v4 - - - name: Login to Container Registry - uses: docker/login-action@v4.6.0 - with: - password: ${{ secrets.GITHUB_TOKEN }} - registry: ${{ env.REGISTRY }} - username: ${{ github.actor }} - - - name: Extract Metadata - id: meta - uses: docker/metadata-action@v6 - with: - images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} - tags: | - type=ref,event=branch - type=semver,pattern={{version}} - type=sha,prefix={{branch}}- - type=raw,value=latest,enable={{is_default_branch}} - labels: | - maintainer=a5chin - org.opencontainers.image.authors=a5chin - org.opencontainers.image.description=Dev Container for Python development with uv-based dependency management and environment configuration. - org.opencontainers.image.documentation=https://a5chin.github.io/python-uv/ - org.opencontainers.image.licenses=MIT - org.opencontainers.image.source=https://github.com/${{ github.repository }} - org.opencontainers.image.title=python-uv - org.opencontainers.image.url=https://github.com/${{ github.repository }} - org.opencontainers.image.vendor=a5chin - - - name: Build and Push Devcontainer Image - uses: docker/build-push-action@v7 - with: - context: . - file: .devcontainer/Dockerfile - push: true - provenance: false - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} - cache-from: type=gha - cache-to: type=gha,mode=max diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6c5deb0b..56c1b387 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -3,60 +3,106 @@ name: Release on: push: branches: - - develop - main + release: + types: + - released + +concurrency: + group: release-${{ github.ref }} + cancel-in-progress: ${{ github.event_name == 'push' }} permissions: contents: write + packages: write pull-requests: read -jobs: - develop: - if: github.ref_name == 'develop' +env: + REGISTRY: ghcr.io +jobs: + publish: runs-on: ubuntu-latest - environment: Develop + environment: ${{ github.event_name == 'release' && 'Production' || 'Develop' }} + + strategy: + fail-fast: false + matrix: + include: + - image: app + dockerfile: Dockerfile + description: App for Python development with uv-based dependency management and environment configuration. + - image: devcontainer + dockerfile: .devcontainer/Dockerfile + description: Dev Container for Python development with uv-based dependency management and environment configuration. steps: - name: Checkout uses: actions/checkout@v7 - - name: Update Draft Release - uses: release-drafter/release-drafter@v7.10.0 + - name: Setup Docker Buildx + uses: docker/setup-buildx-action@v4 + + - name: Log in to Container Registry + uses: docker/login-action@v4.6.0 with: - config-name: release-drafter.yml - publish: false - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} - production: - if: github.ref_name == 'main' + - name: Extract Metadata + id: meta + uses: docker/metadata-action@v6 + with: + images: ${{ env.REGISTRY }}/${{ github.repository }}/${{ matrix.image }} + tags: | + type=ref,event=branch + type=sha,format=long,enable=${{ github.event_name == 'push' }} + type=raw,value=${{ github.event.release.tag_name }},enable=${{ github.event_name == 'release' }} + type=raw,value=latest,enable=${{ github.event_name == 'release' }} + labels: | + maintainer=a5chin + org.opencontainers.image.authors=a5chin + org.opencontainers.image.description=${{ matrix.description }} + org.opencontainers.image.documentation=https://a5chin.github.io/python-uv/ + org.opencontainers.image.licenses=MIT + org.opencontainers.image.source=https://github.com/${{ github.repository }} + org.opencontainers.image.title=python-uv + org.opencontainers.image.url=https://github.com/${{ github.repository }} + org.opencontainers.image.vendor=a5chin + org.opencontainers.image.version=${{ github.event.release.tag_name || github.ref_name }} + + - name: Build and Push Image + uses: docker/build-push-action@v7 + with: + context: . + file: ${{ matrix.dockerfile }} + push: true + provenance: false + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=gha,scope=${{ matrix.image }} + cache-to: type=gha,mode=max,scope=${{ matrix.image }} + + draft: + needs: publish + + if: github.event_name == 'push' runs-on: ubuntu-latest - environment: Production + environment: Develop steps: - name: Checkout uses: actions/checkout@v7 - - name: Get PR Title for Version - id: pr - run: | - PR_TITLE=$(gh pr list --search "${{ github.sha }}" --state merged --json title --jq '.[0].title') - echo "TITLE=$PR_TITLE" >> "$GITHUB_OUTPUT" - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - name: Publish Release + - name: Update Draft Release uses: release-drafter/release-drafter@v7.10.0 with: config-name: release-drafter.yml - name: ${{ env.VERSION }} - publish: true - tag: ${{ env.VERSION }} - version: ${{ env.VERSION }} + commitish: ${{ github.sha }} + publish: false env: - VERSION: ${{ steps.pr.outputs.TITLE }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/setting.yml b/.github/workflows/setting.yml index a92e3acb..df27a4ac 100644 --- a/.github/workflows/setting.yml +++ b/.github/workflows/setting.yml @@ -25,7 +25,7 @@ jobs: - name: Enable auto-delete head branches run: | gh repo edit ${{ github.repository }} \ - --default-branch develop \ + --default-branch main \ --delete-branch-on-merge env: GH_TOKEN: ${{ steps.generate-token.outputs.token }} @@ -37,11 +37,14 @@ jobs: matrix: include: - environment: Develop - branch: develop + pattern: main + type: branch - environment: Production - branch: main + pattern: v* + type: tag - environment: github-pages - branch: gh-pages + pattern: gh-pages + type: branch steps: - name: Checkout @@ -74,11 +77,12 @@ jobs: fi gh api -X POST "${{ env.ENDPOINT }}/${{ env.ENVIRONMENT_NAME }}/deployment-branch-policies" \ - -f "name=${{ env.BRANCH_NAME }}" \ - -f "type=branch" + -f "name=${{ env.POLICY_PATTERN }}" \ + -f "type=${{ env.POLICY_TYPE }}" env: CONFIG_FILE: .github/environments.json - BRANCH_NAME: ${{ matrix.branch }} + POLICY_PATTERN: ${{ matrix.pattern }} + POLICY_TYPE: ${{ matrix.type }} ENDPOINT: repos/${{ github.repository }}/environments ENVIRONMENT_NAME: ${{ matrix.environment }} GH_TOKEN: ${{ steps.generate-token.outputs.token }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 37d1ba62..52299302 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -16,7 +16,6 @@ on: - "uv.lock" push: branches: - - develop - main paths: - ".github/actions/setup-python-with-uv/action.yml" From 8bf1e2eac3c4f9162b68253e10f03b911c00adfe Mon Sep 17 00:00:00 2001 From: d-eigo-hara Date: Thu, 8 Oct 2026 17:46:04 +0900 Subject: [PATCH 2/7] fix: settings --- .vscode/settings.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.vscode/settings.json b/.vscode/settings.json index c653022a..82b6089f 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -23,6 +23,9 @@ "path": "/bin/zsh" } }, + "yaml.customTags": [ + "tag:yaml.org,2002:python/name:pymdownx.superfences.fence_code_format" + ], "[dockercompose]": { "editor.defaultFormatter": "redhat.vscode-yaml", "editor.tabSize": 4 From 39215118ae84e1dc0f68c7c8110695bcaa2f14ed Mon Sep 17 00:00:00 2001 From: d-eigo-hara Date: Thu, 8 Oct 2026 17:46:34 +0900 Subject: [PATCH 3/7] fix: docs --- CLAUDE.md | 317 ++++------------------- CONTRIBUTING.md | 405 ++---------------------------- README.md | 375 ++------------------------- docs/configurations/index.md | 203 +-------------- docs/configurations/pre-commit.md | 113 ++------- docs/configurations/ruff.md | 109 +------- docs/configurations/sqruff.md | 31 +++ docs/configurations/test.md | 30 +-- docs/configurations/ty.md | 4 +- docs/getting-started/index.md | 23 +- docs/guides/branch-strategy.md | 81 ++++++ docs/guides/ci-cd.md | 36 +++ docs/guides/code-standards.md | 166 ++++++++++++ docs/guides/index.md | 234 ++--------------- docs/guides/tools/config.md | 35 +-- docs/guides/tools/logger.md | 26 +- docs/guides/tools/tracer.md | 22 +- docs/guides/ty.md | 2 +- docs/guides/uv.md | 2 +- docs/index.md | 62 +++-- docs/usecases/jupyter.md | 3 + mkdocs.yml | 15 +- 22 files changed, 582 insertions(+), 1712 deletions(-) create mode 100644 docs/configurations/sqruff.md create mode 100644 docs/guides/branch-strategy.md create mode 100644 docs/guides/ci-cd.md create mode 100644 docs/guides/code-standards.md diff --git a/CLAUDE.md b/CLAUDE.md index 118ed7a5..2e7fe55c 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,293 +1,84 @@ # CLAUDE.md -This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. It only holds agent-specific rules and the minimum commands; everything else is in `docs/` (see [Documentation Map](#documentation-map)). ## Project Overview -This is a Python development environment template using **uv** (fast Python package manager) and **Ruff** (linter/formatter). The repository serves dual purposes: -1. A template for starting new Python projects -2. A reusable `tools/` package with production-ready utilities (Logger, Config, Timer) +A Python development environment template using **uv** (package manager), **Ruff** (linter/formatter), and **ty** (type checker). It also ships a reusable `tools/` package (`Logger`, `Settings`, `Timer`). -## Development Commands +## Essential Commands -### Package Management ```bash -# Install dependencies -uv sync - -# Add new dependency -uv add - -# Add dev dependency -uv add --dev - -# Remove dependency -uv remove +uv sync # Install dependencies +uv add # Add a dependency (--dev for dev dependencies); never use pip +uv run nox -s fmt -- --ruff --sqruff # Format (without flags, nothing runs) +uv run nox -s lint -- --ruff --sqruff --ty # Lint and type check (without flags, nothing runs) +uv run nox -s test # Tests with coverage (75% minimum) +uv run pre-commit run --all-files # All pre-commit hooks ``` -### Testing -```bash -# Run all tests with coverage (75% minimum required) -uv run nox -s test - -# Run specific test file -uv run pytest tests/tools/test__logger.py +Run all of the above before opening a PR. Other options: [Task Automation with nox](docs/guides/index.md#task-automation-with-nox). -# Run with JUnit XML output for CI -uv run nox -s test -- --cov_report xml --junitxml junit.xml - -# Run pytest directly (bypasses nox) -uv run pytest -``` - -### Linting & Formatting -```bash -# Format code with Ruff -uv run nox -s fmt -- --ruff +## Rules for Claude Code -# Format SQL files with sqruff -uv run nox -s fmt -- --sqruff +### Code and tests -# Format both Python and SQL -uv run nox -s fmt -- --ruff --sqruff - -# Lint with all tools (Ruff, sqruff, ty) -uv run nox -s lint -- --ruff --sqruff --ty - -# Lint with Ruff only -uv run nox -s lint -- --ruff - -# Lint SQL files only -uv run nox -s lint -- --sqruff - -# Lint with ty only -uv run nox -s lint -- --ty - -# Run Ruff directly -uv run ruff check . --fix -uv run ruff format . - -# Run sqruff directly -uv run sqruff lint -uv run sqruff fix - -# Run ty directly -uv run ty check -``` - -### Pre-commit Hooks -```bash -# Install hooks -uv run pre-commit install - -# Run all hooks manually -uv run pre-commit run --all-files - -# Run specific hook -uv run pre-commit run ruff-format -``` +- Follow [Code Standards](docs/guides/code-standards.md): type hints and docstrings on public APIs, line length 88. +- Name test files `test__*.py` (double underscore) and mirror `tools/` in `tests/`. Coverage must stay at 75% or above (branch coverage included). +- When adding a utility to `tools/`, add or update its page in `docs/guides/tools/`. ### Documentation -```bash -# Serve docs locally at http://127.0.0.1:8000 -uv run mkdocs serve - -# Build documentation -uv run mkdocs build - -# Deploy to GitHub Pages -uv run mkdocs gh-deploy -``` - -## Architecture - -### Core Modules - -The `tools/` package provides three main utility modules: -#### **tools/logger/** - Dual-Mode Logging System -- `Logger` class extends `logging.Logger` with environment-aware formatting -- **LogType.LOCAL**: Colored console output via `LocalFormatter` for development -- **LogType.GOOGLE_CLOUD**: Structured JSON via `GoogleCloudFormatter` for production -- Key pattern: Use `Settings.IS_LOCAL` to switch between modes automatically +- Each topic has exactly one source of truth under `docs/` (see [Documentation Map](#documentation-map)). Edit only that page. +- Never copy documentation content into `README.md`, `CONTRIBUTING.md`, or this file; link to the `docs/` page instead. +- Configuration pages include the real config files with `--8<--` snippets; do not paste config contents into docs. +- After changing docs, run `uv run mkdocs build --strict`. Register new pages in the `nav` of `mkdocs.yml`. -```python -from tools.config import Settings -from tools.logger import Logger, LogType +### Branches and pull requests -settings = Settings() -logger = Logger( - __name__, - log_type=LogType.LOCAL if settings.IS_LOCAL else LogType.GOOGLE_CLOUD -) -``` - -#### **tools/config/** - Environment-Based Configuration -- `Settings` class uses Pydantic for type-safe configuration -- Loads from `.env` (version controlled) and `.env.local` (local overrides, in .gitignore) -- `FastAPIKwArgs` provides ready-to-use FastAPI initialization parameters -- Pattern: Extend `Settings` to add project-specific configuration fields +The flow is described in [Branch Strategy & Release Flow](docs/guides/branch-strategy.md) (GitHub Flow, no `develop` branch). -```python -from tools.config import Settings +- Always open PRs against `main`; never push directly to `main`. +- Use a branch prefix from [Branches](docs/guides/branch-strategy.md#branches) (`feature/`, `fix/`, `hotfix/`, `refactor/`). +- Commit or push only when the user asks. -settings = Settings() -api_url = settings.api_prefix_v1 # Loaded from environment -``` +### Releases -#### **tools/tracer/** - Performance Monitoring -- `Timer` class works as both decorator and context manager -- Automatically logs execution time in milliseconds at DEBUG level -- Uses the `Logger` module for output (inherits logging configuration) -- Pattern: Nest timers to measure both overall and component performance +- To release, edit the **existing** Draft Release; never create a new release or tag (`gh release create`, `git tag`). +- The tag must start with `v` (e.g. `v1.3.0`); changing the proposed tag is allowed. +- Publishing deploys to Production: always confirm with the user before publishing. -```python -from tools.tracer import Timer +Release procedure (e.g. the user asks "release v1.3.0" and the Draft proposes `v1.2.4`): -@Timer("full_operation") -def process(): - with Timer("step1"): - do_step1() - with Timer("step2"): - do_step2() -``` - -### Test Structure - -Tests in `tests/tools/` mirror the package structure: -- **Naming convention**: `test__*.py` (double underscore) -- **Coverage requirement**: 75% minimum (including branch coverage) -- **Test files exempt from**: `INP001` (namespace packages), `S101` (assert usage) - -### Configuration Philosophy - -**Ruff (ruff.toml)**: -- ALL rules enabled by default with specific exclusions -- Line length: 88 (Black-compatible) -- Target Python: 3.14 -- Per-file ignores for test files - -**ty (ty.toml)**: -- Includes `tools/`, `tests/` packages, and `noxfile.py` -- Excludes cache directories (`__pycache__`, `.pytest_cache`, `.ruff_cache`, `.venv`) - -**pytest (pytest.ini)**: -- Coverage: 75% minimum with branch coverage -- Reports: HTML + terminal -- Import mode: importlib - -**sqruff (.sqruff)**: -- Dialect: BigQuery -- Max line length: 80 -- Tab space size: 2 - -### Nox Task Automation - -The `noxfile.py` uses a custom `CLIArgs` parser (Pydantic-based): -- All sessions use `python=False` (rely on `uv run`) -- Arguments passed via `-- --flag value` syntax -- Sessions: `fmt`, `lint`, `test` - -Example of the argument parsing pattern: -```python -# noxfile.py -@nox.session(python=False) -def lint(session: nox.Session) -> None: - args = CLIArgs.parse(session.posargs) - if args.ty: - session.run("uv", "run", "ty", "check") - if args.ruff: - session.run("uv", "run", "ruff", "check", ".", "--fix") - if args.sqruff: - session.run("uv", "run", "sqruff", "lint") -``` - -## Key Patterns for Development - -### Adding New Configuration Fields - -Extend the `Settings` class in `tools/config/settings.py`: - -```python -class Settings(BaseSettings): - # Existing fields... - - # Add your new fields - NEW_SETTING: str = "default_value" - ANOTHER_SETTING: int = 42 -``` - -Then add to `.env.local`: ```bash -NEW_SETTING=custom_value -ANOTHER_SETTING=100 -``` - -### Adding New Logger Formatters - -Create a new formatter in `tools/logger/`: -1. Extend `logging.Formatter` -2. Export from `tools/logger/__init__.py` -3. Update `Logger.__init__()` to support the new type - -### Testing Utilities - -When testing the utilities themselves: -- Logger: Capture logs using `assertLogs` context manager -- Config: Use Pydantic's model instantiation with kwargs to override values -- Timer: Check debug logs for execution time messages - -## Documentation Structure +# 1. Find the Draft: the row marked "Draft"; its proposed tag (here v1.2.4) identifies it +gh release list +gh release view v1.2.4 # check the change list and the target commit -The `docs/` directory is organized for MkDocs: -- **docs/index.md**: Main landing page -- **docs/getting-started/**: Setup guides (Docker, VSCode, Dev Container) -- **docs/guides/**: Tool usage guides (uv, Ruff, ty, pre-commit, tools package) -- **docs/configurations/**: Detailed configuration references -- **docs/usecases/**: Real-world examples (Jupyter, FastAPI, OpenCV) +# 2. Ask the user for confirmation, showing the new tag (v1.3.0) and the change list. +# Do not edit anything until the user approves. -When adding new utilities to `tools/`, add corresponding documentation to `docs/guides/tools/`. - -## CI/CD Workflows - -GitHub Actions workflows in `.github/workflows/`: -- **actionlint.yml**: Lint GitHub Actions workflows -- **docker.yml**: Validate Docker build -- **devcontainer.yml**: Validate Dev Container configuration -- **format.yml**: Check Ruff formatting -- **labeler.yml**: Add label in GitHub -- **lint.yml**: Run Ruff + ty linting -- **test.yml**: Run pytest with coverage -- **gh-deploy.yml**: Deploy documentation to GitHub Pages - -All workflows use the same nox commands as local development. - -## Pull Request Process - -For comprehensive contribution guidelines, including detailed steps for creating and reviewing Pull Requests, please refer to [CONTRIBUTING.md](CONTRIBUTING.md) in the repository root. - -**Code of Conduct**: All contributors must follow our [Code of Conduct](CODE_OF_CONDUCT.md). We maintain a welcoming, inclusive, and harassment-free environment for everyone. -## Environment Variables - -Critical environment variables (set in `.env.local`): -- `IS_LOCAL`: Boolean flag for local vs production (affects logging, configuration) -- `DEBUG`: Boolean for debug mode -- FastAPI settings: `TITLE`, `VERSION`, `API_PREFIX_V1`, etc. +# 3. After approval, change the tag and publish immediately, without waiting in between +# (a merge into main in between makes release-drafter overwrite the tag again) +gh release edit v1.2.4 --tag v1.3.0 --title v1.3.0 --prerelease=false +gh release edit v1.3.0 --draft=false # from here on, the release is addressed by the new tag +``` -## Important Notes +`gh` runs with the user's own credentials, so publishing with it triggers the Production deployment. The "`GITHUB_TOKEN` does not trigger workflows" caveat only applies to releases published from inside a GitHub Actions workflow. -- **Coverage is enforced**: Tests must maintain 75% coverage (configured in pytest.ini) -- **uv replaces pip/poetry**: Use `uv add` not `pip install`, use `uv.lock` not `requirements.txt` -- **Ruff replaces multiple tools**: No need for Black, isort, Flake8, etc. -- **nox is the task runner**: Prefer `uv run nox -s ` over direct tool calls -- **Test naming**: Use `test__*.py` pattern (double underscore) -- **Type checking**: ty checks both the `tools/` and `tests/` packages +## Documentation Map -## Template Usage Pattern +| Topic | Source of truth | +|---|---| +| Setup, using this repository as a template | [docs/getting-started/index.md](docs/getting-started/index.md) | +| nox sessions and flags | [docs/guides/index.md](docs/guides/index.md#task-automation-with-nox) | +| uv / Ruff / ty / pre-commit / pytest usage | [docs/guides/](docs/guides/index.md) | +| Configuration files (`ruff.toml`, `ty.toml`, `pytest.ini`, `.sqruff`, `.pre-commit-config.yaml`, ...) | [docs/configurations/](docs/configurations/index.md) | +| `tools/` package (`Logger`, `Settings`, `Timer`) and environment variables | [docs/guides/tools/](docs/guides/tools/index.md) | +| Code standards, writing tests, common issues | [docs/guides/code-standards.md](docs/guides/code-standards.md) | +| Branch strategy and release flow | [docs/guides/branch-strategy.md](docs/guides/branch-strategy.md) | +| GitHub Actions workflows | [docs/guides/ci-cd.md](docs/guides/ci-cd.md) | +| Project structure | [docs/index.md](docs/index.md) | +| Pull request process | [CONTRIBUTING.md](CONTRIBUTING.md) | -When using this as a template for a new project: -1. Update `pyproject.toml` with new project name/description -2. Modify or extend `tools/config/settings.py` for project-specific configuration -3. Use the utilities from `tools/` or remove if not needed -4. Update `.env` with base configuration, `.env.local` with local overrides -5. Customize Ruff rules in `ruff.toml` if needed (but start with defaults) +All contributors must follow the [Code of Conduct](CODE_OF_CONDUCT.md). diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c999cc66..29b65148 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,106 +1,39 @@ # Contributing to python-uv -Thank you for your interest in contributing to python-uv! This document provides guidelines and instructions for contributing to this project. +Thank you for your interest in contributing to python-uv! This document describes how to propose changes. Development details live in the [documentation](docs/index.md), which this page links to. + +All contributors must follow our [Code of Conduct](CODE_OF_CONDUCT.md). ## Table of Contents - [Quick Start for Contributors](#quick-start-for-contributors) -- [Development Setup](#development-setup) - [Making Changes](#making-changes) - [Pull Request Process](#pull-request-process) -- [Code Standards](#code-standards) -- [Testing Requirements](#testing-requirements) -- [Documentation Guidelines](#documentation-guidelines) -- [Common Issues](#common-issues) - [Getting Help](#getting-help) ## Quick Start for Contributors -1. **Fork and clone** the repository -2. **Set up** your development environment -3. **Create a branch** for your changes -4. **Make changes** following our code standards -5. **Run tests** and quality checks -6. **Submit a pull request** using our template - -## Development Setup - -### Prerequisites - -- Python 3.11 or higher -- [uv](https://github.com/astral-sh/uv) package manager -- Git -- (Optional) Docker and VSCode with Dev Containers extension - -### Setup Steps - -#### Option 1: Using Dev Container (Recommended) - -```bash -# Clone the repository -git clone https://github.com/a5chin/python-uv.git -cd python-uv - -# Open in VSCode -code . - -# When prompted, click "Reopen in Container" -``` - -#### Option 2: Local Setup - -```bash -# Install uv -curl -LsSf https://astral.sh/uv/install.sh | sh - -# Clone the repository -git clone https://github.com/a5chin/python-uv.git -cd python-uv - -# Install dependencies -uv sync - -# Install pre-commit hooks -uv run pre-commit install -``` - -### Verify Your Setup - -```bash -# Run tests -uv run nox -s test - -# Run linters -uv run nox -s lint -- --ruff --ty - -# Format code -uv run nox -s fmt -``` - -If all commands complete successfully, you're ready to contribute! +1. **Set up** your development environment: [Getting Started](docs/getting-started/index.md) +2. **Create a branch** from `main`: [Branch Strategy & Release Flow](docs/guides/branch-strategy.md#branches) +3. **Make changes** following the [Code Standards](docs/guides/code-standards.md) +4. **Run the quality checks**: [Before Submitting](#before-submitting) +5. **Submit a pull request** to `main` using our template ## Making Changes -### 1. Create a Feature Branch +### 1. Create a Branch ```bash git checkout -b feature/your-feature-name ``` -Branch naming conventions: -- `feature/` - New features -- `fix/` - Bug fixes -- `hotfix/` - Hotfix -- `release/` - Release changes +Use a prefix from [Branches](docs/guides/branch-strategy.md#branches) (`feature/`, `fix/`, `hotfix/`, `refactor/`). What happens after your PR is merged into `main` is described in [Branch Strategy & Release Flow](docs/guides/branch-strategy.md). ### 2. Make Your Changes -Follow these guidelines while making changes: - - **Write clear, focused commits** - Each commit should represent a single logical change -- **Follow code standards** - See [Code Standards](#code-standards) section -- **Add tests** - All new code should have corresponding tests -- **Update documentation** - Keep docs in sync with code changes +- **Follow the [Code Standards](docs/guides/code-standards.md)** - including type hints, docstrings, and tests +- **Update documentation** - Edit the page under `docs/` that owns the topic (see [Documentation](docs/guides/code-standards.md#documentation)) ### 3. Commit Your Changes @@ -125,23 +58,18 @@ git commit -m "changes" ### Before Submitting -**You MUST run all quality checks before submitting your PR:** - -```bash -# 1. Format code -uv run nox -s fmt - -# 2. Run linters -uv run nox -s lint -- --ruff --ty +**You MUST pass all quality checks before submitting your PR.** The commands and their flags are listed in [Task Automation with nox](docs/guides/index.md#task-automation-with-nox): -# 3. Run tests with coverage -uv run nox -s test - -# 4. Run pre-commit hooks -uv run pre-commit run --all-files -``` +- [ ] Code is formatted: `uv run nox -s fmt -- --ruff --sqruff` +- [ ] Linting passes: `uv run nox -s lint -- --ruff --sqruff --ty` +- [ ] All tests pass: `uv run nox -s test` (coverage โ‰ฅ 75%) +- [ ] Pre-commit hooks pass: `uv run pre-commit run --all-files` +- [ ] New test files follow the `test__*.py` naming convention +- [ ] Dependencies are added via `uv add`, and `uv.lock` is committed +- [ ] Documentation is updated under `docs/` +- [ ] Breaking changes are documented (if applicable) -All checks must pass. PRs with failing checks will not be reviewed. +PRs with failing checks will not be reviewed. If a check fails, see [Common Issues](docs/guides/code-standards.md#common-issues). ### Submitting Your PR @@ -150,7 +78,7 @@ All checks must pass. PRs with failing checks will not be reviewed. git push origin feature/your-feature-name ``` -2. **Create a Pull Request** on GitHub +2. **Create a Pull Request** against `main` on GitHub - The PR template will be auto-populated - Fill out all sections completely - Link related issues using `Fixes #123` or `Relates to #456` @@ -168,7 +96,7 @@ All checks must pass. PRs with failing checks will not be reviewed. ### PR Review Process -1. **Automated checks** run on your PR (CI/CD workflows) +1. **Automated checks** run on your PR (see [CI/CD Workflows](docs/guides/ci-cd.md)) 2. **Maintainers review** your code using the review checklist 3. **Address feedback** if changes are requested 4. **PR is merged** once approved @@ -177,274 +105,12 @@ All checks must pass. PRs with failing checks will not be reviewed. - Initial review: Within 2-3 business days - Follow-up reviews: Within 1-2 business days -## Code Standards - -### General Guidelines - -- **Line length**: Maximum 88 characters (Black-compatible) -- **Python version**: Target Python 3.11+ (or a specific stable version) -- **Import order**: Automatically handled by Ruff -- **Naming conventions**: - - Classes: `PascalCase` - - Functions/variables: `snake_case` - - Constants: `UPPER_SNAKE_CASE` - - Private members: `_leading_underscore` - -### Type Hints - -All functions and methods must have type hints: - -```python -# Good -def process_data(items: list[str], max_count: int = 10) -> dict[str, int]: - """Process items and return statistics.""" - ... - -# Avoid -def process_data(items, max_count=10): - ... -``` - -### Docstring - -All public functions, classes, and modules must have docstring: - -```python -def calculate_total(items: list[float], tax_rate: float) -> float: - """Calculate the total price including tax. - - Args: - items: List of item prices. - tax_rate: Tax rate as a decimal (e.g., 0.1 for 10%). - - Returns: - Total price including tax. - - Raises: - ValueError: If tax_rate is negative. - """ - if tax_rate < 0: - raise ValueError("Tax rate cannot be negative") - subtotal = sum(items) - return subtotal * (1 + tax_rate) -``` - -### Code Organization - -- **One class per file** (unless closely related) -- **Group related functions** in modules -- **Keep functions focused** - Single Responsibility Principle -- **Avoid deep nesting** - Maximum 3-4 levels -- **Extract complex logic** into named functions - -### Ruff Rules -Run `uv run ruff check .` to see all violations. - -## Testing Requirements - -### Coverage Requirements - -- **Minimum coverage**: 75% (including branch coverage) -- **Target coverage**: 100% for new code -- **Coverage report**: Generated automatically when running tests - -### Writing Tests - -1. **Location**: Mirror the structure of `tools/` in `tests/` -2. **Naming**: Use `test__*.py` pattern (double underscore) -3. **Structure**: One test file per module - -Example test structure: - -```python -# tests/tools/test__logger.py -import logging -from tools.logger import Logger, LogType - -def test_logger_local_format(): - """Test local logger formatting.""" - logger = Logger(__name__, log_type=LogType.LOCAL) - assert logger.level == logging.INFO - -def test_logger_handles_none(): - """Test logger handles None values correctly.""" - logger = Logger(__name__) - # Test implementation - ... -``` - -### Running Tests - -```bash -# Run all tests with coverage -uv run nox -s test - -# Run specific test file -uv run pytest tests/tools/test__logger.py - -# Run specific test function -uv run pytest tests/tools/test__logger.py::test_logger_local_format - -# View coverage report -open htmlcov/index.html -``` - -### Test Best Practices - -- **Test one thing** per test function -- **Use descriptive names** - `test_logger_handles_none_values` -- **Arrange-Act-Assert** pattern -- **Cover edge cases** - empty inputs, None, boundary values -- **Test error conditions** - expected exceptions -- **Minimize mocking** - Use real objects when possible -- **Independent tests** - No dependencies between tests - -## Documentation Guidelines - -### When to Update Documentation - -Update documentation when you: -- Add new features or utilities -- Change public APIs -- Modify configuration options -- Add environment variables -- Change development workflow -- Fix bugs that were caused by unclear documentation - -### Documentation Files - -- **README.md** - High-level overview, quick start, features -- **CLAUDE.md** - Development workflow for Claude Code users -- **CONTRIBUTING.md** - This file (contribution guidelines) -- **docs/** - Detailed guides and references - - `docs/guides/` - Usage guides and tutorials - - `docs/configurations/` - Configuration references - - `docs/usecases/` - Real-world examples - -### Documentation Standards - -- Use clear, concise language -- Provide code examples for new features -- Include both "how" and "why" explanations -- Keep examples up-to-date with code changes -- Use proper markdown formatting -- Test all code examples before committing - -## Common Issues - -### Test Coverage Below 75% - -**Problem**: Coverage is 72%, below the required 75% - -**Solution**: -```bash -# Check coverage report -uv run nox -s test - -# View detailed HTML report to see uncovered lines -open htmlcov/index.html - -# Add tests for uncovered lines -``` - -### Linting Errors - -**Problem**: `uv run nox -s lint` fails - -**Solution**: -```bash -# Auto-fix Ruff issues -uv run ruff check . --fix - -# Format code -uv run ruff format . - -# Check type errors -uv run ty check - -# If type errors persist, add type hints or use type: ignore with justification -``` - -### Pre-commit Hook Failures - -**Problem**: Git commit is blocked by pre-commit hooks - -**Solution**: -```bash -# See what failed -uv run pre-commit run --all-files - -# Common fixes: -# - Ruff formatting: Auto-fixed by the hook -# - Trailing whitespace: Auto-fixed by the hook -# - JSON/YAML/TOML: Fix syntax errors manually - -# Retry commit after fixes -git add . -git commit -m "Your message" -``` - -### Merge Conflicts - -**Problem**: Your branch has conflicts with main - -**Solution**: -```bash -# Update main branch -git checkout main -git pull origin main - -# Go back to your branch -git checkout your-branch - -# Merge main into your branch -git merge main - -# Resolve conflicts in your editor -# After resolving, stage the files -git add . - -# Complete the merge -git commit -m "Resolve merge conflicts with main" - -# Push updated branch -git push origin your-branch -``` - -### `uv.lock` Out of Sync - -**Problem**: CI fails with dependency resolution errors - -**Solution**: -```bash -# Regenerate lock file -uv lock - -# Commit the updated lock file -git add uv.lock -git commit -m "Update: Regenerate uv.lock" -``` - -### Import Errors in Tests - -**Problem**: Tests fail with `ModuleNotFoundError` - -**Solution**: -```bash -# Ensure dependencies are installed -uv sync - -# If issue persists, check that you're using the correct import paths -# Example: Use `from tools.logger import Logger` not `from logger import Logger` -``` - ## Getting Help ### Resources -- **Documentation**: https://a5chin.github.io/python-uv -- **Detailed Contributing Guide**: [CONTRIBUTING.md](CONTRIBUTINGmd) -- **PR Template**: [.github/pull_request_template.md](.github/pull_request_template.md) +- **Documentation**: https://a5chin.github.io/python-uv (source: [`docs/`](docs/index.md)) +- **PR Template**: [.github/PULL_REQUEST_TEMPLATE.md](.github/PULL_REQUEST_TEMPLATE.md) ### Questions and Discussions @@ -452,23 +118,4 @@ uv sync - **GitHub Discussions**: For questions and general discussions - **Pull Request Comments**: For questions about specific code changes ---- - -## Summary Checklist - -Before submitting your PR, verify: - -- [ ] Code follows project standards (Ruff, ty, type hints, docstring) -- [ ] All tests pass: `uv run nox -s test` (coverage โ‰ฅ 75%) -- [ ] Linting passes: `uv run nox -s lint -- --ruff --ty` -- [ ] Code is formatted: `uv run nox -s fmt` -- [ ] Pre-commit hooks pass: `uv run pre-commit run --all-files` -- [ ] Documentation updated (README, CLAUDE.md, or docs/) -- [ ] New test files follow `test__*.py` naming convention -- [ ] Dependencies added via `uv add` (not manual edits) -- [ ] `uv.lock` is updated and committed -- [ ] PR template is completely filled out -- [ ] Breaking changes are documented (if applicable) -- [ ] Related issues are linked in PR description - **Thank you for contributing to python-uv! ๐ŸŽ‰** diff --git a/README.md b/README.md index d7def6c3..5f9f9bcd 100644 --- a/README.md +++ b/README.md @@ -29,28 +29,8 @@ A production-ready Python development environment template using modern tools: * - [๐Ÿ“‹ Table of Contents](#-table-of-contents) - [โœจ Features](#-features) - [๐Ÿš€ Quick Start](#-quick-start) - - [Using Dev Container (Recommended)](#using-dev-container-recommended) - - [Using Docker Only](#using-docker-only) - - [Local Setup (Without Docker)](#local-setup-without-docker) - - [๐Ÿ“š Development Workflow](#-development-workflow) - - [Installing Dependencies](#installing-dependencies) - - [Running Tasks](#running-tasks) - - [Pre-commit Hooks](#pre-commit-hooks) - - [Documentation](#documentation) - - [๐Ÿ—๏ธ Project Structure](#๏ธ-project-structure) - - [Built-in Utility Modules](#built-in-utility-modules) - - [**Logger** - Dual-mode logging system](#logger---dual-mode-logging-system) - - [**Configuration** - Environment-based settings](#configuration---environment-based-settings) - - [**Timer** - Performance monitoring](#timer---performance-monitoring) - - [โš™๏ธ Configuration](#๏ธ-configuration) - - [Ruff Configuration](#ruff-configuration) - - [ty Configuration](#ty-configuration) - - [Pytest Configuration](#pytest-configuration) - - [๐Ÿ”„ CI/CD](#-cicd) - - [๐ŸŽจ VSCode Configuration](#-vscode-configuration) - - [๐Ÿช Cookiecutter Templates](#-cookiecutter-templates) - [๐Ÿ“– Documentation](#-documentation) - - [๐ŸŒฟ Branches](#-branches) + - [๐Ÿ—„๏ธ Archived Branches](#๏ธ-archived-branches) - [๐Ÿ“„ License](#-license) - [๐Ÿ™ Acknowledgments](#-acknowledgments) @@ -70,352 +50,45 @@ A production-ready Python development environment template using modern tools: * ## ๐Ÿš€ Quick Start -### Using Dev Container (Recommended) - -1. **Prerequisites**: Install [Docker](https://www.docker.com/) and [VSCode](https://code.visualstudio.com/) with the [Dev Containers extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) - -2. **Open in container**: +1. Install [Docker](https://www.docker.com/) and [VSCode](https://code.visualstudio.com/) with the [Dev Containers extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers). +2. Clone the repository and open it in VSCode, then click **Reopen in Container** when prompted: ```bash git clone https://github.com/a5chin/python-uv.git cd python-uv code . ``` - When prompted, click "Reopen in Container" - -3. **Start developing**: +3. Check that everything works: ```bash - # Install dependencies - uv sync - - # Run tests uv run nox -s test - - # Format and lint - uv run nox -s fmt - uv run nox -s lint -- --ruff --ty ``` -### Using Docker Only - -```bash -# Build the image -docker build -t python-uv . - -# Run container -docker run -it --rm -v $(pwd):/workspace python-uv -``` - -### Local Setup (Without Docker) - -**Prerequisites**: Python 3.11+ and [uv](https://github.com/astral-sh/uv) - -```bash -# Install uv (if not already installed) -curl -LsSf https://astral.sh/uv/install.sh | sh - -# Clone and setup -git clone https://github.com/a5chin/python-uv.git -cd python-uv - -# Install dependencies -uv sync - -# Install pre-commit hooks (optional) -uv run pre-commit install -``` - -## ๐Ÿ“š Development Workflow - -### Installing Dependencies - -```bash -# Install all dependencies (including dev dependencies) -uv sync - -# Install without dev dependencies -uv sync --no-dev - -# Add new dependencies -uv add requests pandas - -# Add dev dependencies -uv add --dev pytest-mock -``` - -### Running Tasks - -This project uses **nox** for task automation. All common development tasks are available as nox sessions: - -```bash -# Format code with Ruff -uv run nox -s fmt - -# Run linters (Ruff + ty) -uv run nox -s lint -- --ruff --ty - -# Run only ty -uv run nox -s lint -- --ty - -# Run only Ruff linter -uv run nox -s lint -- --ruff - -# Run tests with coverage (75% minimum required) -uv run nox -s test - -# Run tests with JUnit XML output (for CI) -uv run nox -s test -- --cov_report xml --junitxml junit.xml -``` - -You can also run tools directly: - -```bash -# Run pytest directly -uv run pytest - -# Run specific test file -uv run pytest tests/tools/test__logger.py - -# Format with Ruff -uv run ruff format . - -# Lint with Ruff -uv run ruff check . --fix - -# Type check with ty -uv run ty check -``` - -### Pre-commit Hooks - -Pre-commit hooks automatically run code quality checks before each commit: - -```bash -# Install hooks -uv run pre-commit install - -# Run manually on all files -uv run pre-commit run --all-files -``` - -Configured hooks: -- Ruff formatting and linting -- JSON, YAML, TOML validation -- Trailing whitespace removal -- End-of-file fixer -- Private key detection -- Dockerfile linting with hadolint - -### Documentation - -Generate and serve documentation with MkDocs: - -```bash -# Serve locally at http://127.0.0.1:8000 -uv run mkdocs serve - -# Build static site -uv run mkdocs build - -# Deploy to GitHub Pages -uv run mkdocs gh-deploy -``` - -## ๐Ÿ—๏ธ Project Structure - -``` -. -โ”œโ”€โ”€ tools/ # Reusable utility modules -โ”‚ โ”œโ”€โ”€ config/ # Configuration management (Settings, FastAPI config) -โ”‚ โ”œโ”€โ”€ logger/ # Logging utilities (Local & Google Cloud formatters) -โ”‚ โ””โ”€โ”€ tracer/ # Performance tracing (Timer decorator/context manager) -โ”œโ”€โ”€ tests/ # Test suite (mirrors tools/ structure) -โ”‚ โ””โ”€โ”€ tools/ # Unit tests for utility modules -โ”œโ”€โ”€ docs/ # MkDocs documentation -โ”‚ โ”œโ”€โ”€ getting-started/ # Setup guides -โ”‚ โ”œโ”€โ”€ guides/ # Tool usage guides -โ”‚ โ”œโ”€โ”€ configurations/ # Configuration references -โ”‚ โ””โ”€โ”€ usecases/ # Real-world examples -โ”œโ”€โ”€ .devcontainer/ # Dev Container configuration -โ”œโ”€โ”€ .github/ # GitHub Actions workflows, PR templates, and review checklists -โ”œโ”€โ”€ CODE_OF_CONDUCT.md # Community Code of Conduct -โ”œโ”€โ”€ CONTRIBUTING.md # Contribution guidelines -โ”œโ”€โ”€ CLAUDE.md # Claude Code development guidance -โ”œโ”€โ”€ noxfile.py # Task automation configuration (test, lint, fmt) -โ”œโ”€โ”€ pyproject.toml # Project metadata and dependencies (uv) -โ”œโ”€โ”€ ruff.toml # Ruff linter/formatter configuration -โ””โ”€โ”€ pytest.ini # Pytest configuration (75% coverage requirement) -``` - -### Built-in Utility Modules - -The `tools/` package provides production-ready utilities that can be used in your projects: - -#### **Logger** - Dual-mode logging system - -Environment-aware logging with support for local development and cloud environments: - -```python -from tools.logger import Logger, LogType - -# Local development (colored console output) -logger = Logger(__name__, log_type=LogType.LOCAL) - -# Google Cloud (structured JSON logging) -logger = Logger(__name__, log_type=LogType.GOOGLE_CLOUD, project="my-project") - -logger.info("Application started") -``` - -#### **Configuration** - Environment-based settings - -Type-safe configuration management using Pydantic: - -```python -from tools.config import Settings - -settings = Settings() # Loads from .env and .env.local -api_url = settings.api_prefix_v1 -is_debug = settings.DEBUG -``` - -#### **Timer** - Performance monitoring - -Automatic execution time logging for functions and code blocks: - -```python -from tools.tracer import Timer - -# As context manager -with Timer("database_query"): - result = db.query() # Logs execution time automatically - -# As decorator -@Timer("process_data") -def process_data(data): - return transform(data) # Logs execution time when function completes -``` - -## โš™๏ธ Configuration - -### Ruff Configuration - -Ruff replaces multiple tools (Black, isort, Flake8, pydocstyle, pyupgrade, autoflake) with a single, fast tool. - -**Key settings in `ruff.toml`:** -- **Line length**: 88 (Black-compatible) -- **Target Python**: 3.14 -- **Rules**: ALL enabled by default with specific exclusions -- **Test files**: Exempt from `INP001` (namespace packages) and `S101` (assert usage) - -> See [Ruff documentation](https://docs.astral.sh/ruff/) for customization options. - -### ty Configuration - -Static type checking for Python code. - -**Key settings in `ty.toml`:** -- **Include**: `tools/` and `tests/` packages -- **Exclude**: Cache directories (`__pycache__`, `.pytest_cache`, `.ruff_cache`, `.venv`) - -> See [ty documentation](https://github.com/astral-sh/ty) for advanced configuration. - -### Pytest Configuration - -Testing framework with coverage enforcement. - -**Key settings in `pytest.ini`:** -- **Coverage requirement**: 75% minimum (including branch coverage) -- **Test file pattern**: `test__*.py` (double underscore) -- **Coverage reports**: HTML and terminal -- **Import mode**: importlib - -> See [pytest documentation](https://docs.pytest.org/) for additional options. - -## ๐Ÿ”„ CI/CD - -Automated workflows ensure code quality and consistency. All workflows run on push and pull requests. - -**Available workflows in `.github/workflows/`:** - -| Workflow | Purpose | Tools Used | -| -------------------------- | ------------------------------------ | ---------------- | -| `docker.yml` | Validate Docker build | Docker | -| `devcontainer.yml` | Validate Dev Container configuration | devcontainer CLI | -| `format.yml` | Check code formatting | Ruff | -| `labeler.yml` | Add label in GitHub | GitHub | -| `lint.yml` | Run static analysis | Ruff, ty | -| `test.yml` | Run test suite with coverage | pytest, coverage | -| `gh-deploy.yml` | Deploy documentation to GitHub Pages | MkDocs | -| `pr-agent.yml` | Automated PR reviews | Qodo AI PR Agent | -| `publish-devcontainer.yml` | Publish Dev Container image | Docker, GHCR | - -## ๐ŸŽจ VSCode Configuration - -The Dev Container includes pre-configured extensions and settings for optimal Python development. - -**Python Development:** -- **Ruff** - Fast linting and formatting -- **ty** - Static type checking -- **Python** - Core Python support -- **autodocstring** - Automatic docstring generation -- **python-indent** - Correct Python indentation - -**Code Quality:** -- **GitLens** - Enhanced Git integration -- **Error Lens** - Inline error highlighting -- **indent-rainbow** - Visual indentation guide -- **trailing-spaces** - Highlight trailing whitespace - -**File Support:** -- **YAML**, **TOML**, **Markdown** - Configuration file support -- **Docker** - Dockerfile and docker-compose support -- **Material Icon Theme** - File icons - -**Editor Settings:** -- โœ… Format on save (Python, JSON, YAML, TOML, Dockerfile) -- โœ… Auto-trim trailing whitespace -- โœ… Auto-insert final newline -- โœ… Organize imports on save - -> **Troubleshooting**: If Ruff formatting doesn't work, reload the window: `Cmd+Shift+P` โ†’ "Developer: Reload Window" - -## ๐Ÿช Cookiecutter Templates - -This repository can be used as a base template for various Python projects. Combine it with Cookiecutter to bootstrap project-specific setups: - -```bash -# Install cookiecutter -uv add --dev cookiecutter - -# Use a template -uv run cookiecutter -``` - -**Recommended templates:** - -- **Data Science**: [cookiecutter-data-science](https://github.com/drivendataorg/cookiecutter-data-science) - Standardized data science project structure -- **FastAPI**: [full-stack-fastapi-template](https://github.com/fastapi/full-stack-fastapi-template) - Full-stack web applications -- **Django**: [cookiecutter-django](https://github.com/cookiecutter/cookiecutter-django) - Production-ready Django projects -- **Flask**: [cookiecutter-flask](https://github.com/cookiecutter-flask/cookiecutter-flask) - Flask web applications +For Docker-only or local setup (without Docker), see [Getting Started](docs/getting-started/index.md). ## ๐Ÿ“– Documentation -Comprehensive documentation is available at **[https://a5chin.github.io/python-uv](https://a5chin.github.io/python-uv)** +The full documentation is published at **[https://a5chin.github.io/python-uv](https://a5chin.github.io/python-uv)**. Its source lives in [`docs/`](docs/index.md), which is the single source of truth for every topic below. + +| Topic | Document | +|---|---| +| Setup (Dev Container, Docker, local) | [Getting Started](docs/getting-started/index.md) | +| Development commands (`fmt` / `lint` / `test`) | [Task Automation with nox](docs/guides/index.md#task-automation-with-nox) | +| uv, Ruff, ty, pre-commit, pytest | [Guides](docs/guides/index.md) | +| Configuration files | [Configuration Reference](docs/configurations/index.md) | +| Built-in utilities (`Logger`, `Settings`, `Timer`) | [Tools Package](docs/guides/tools/index.md) | +| Coding rules and writing tests | [Code Standards](docs/guides/code-standards.md) | +| Branches, releases, and deployment | [Branch Strategy & Release Flow](docs/guides/branch-strategy.md) | +| GitHub Actions workflows | [CI/CD Workflows](docs/guides/ci-cd.md) | +| Project templates | [cookiecutter](docs/guides/cookiecutter.md) | +| Examples (Jupyter, FastAPI, OpenCV) | [Use Cases](docs/usecases/index.md) | -**Topics covered:** -- ๐Ÿš€ **Getting Started** - Docker, VSCode, Dev Containers setup -- โš™๏ธ **Tool Configurations** - uv, Ruff, ty, pre-commit -- ๐Ÿงช **Testing Strategies** - pytest, coverage, and best practices -- ๐Ÿ› ๏ธ **Utility Modules** - Config, logger, and tracer guides -- ๐Ÿ’ก **Use Cases** - Jupyter, FastAPI, OpenCV examples +To contribute, see [CONTRIBUTING.md](CONTRIBUTING.md). -## ๐ŸŒฟ Branches +## ๐Ÿ—„๏ธ Archived Branches -This repository maintains multiple branches for different use cases: +These branches are no longer maintained; use `main` for new projects. -- **[main](https://github.com/a5chin/python-uv/tree/main)** - Current production-ready template (recommended) -- **[jupyter](https://github.com/a5chin/python-uv/tree/jupyter)** - Archived: Jupyter-specific configuration -- **[rye](https://github.com/a5chin/python-uv/tree/rye)** - Archived: Rye package manager version (replaced by uv) +- **[jupyter](https://github.com/a5chin/python-uv/tree/jupyter)** - Jupyter-specific configuration +- **[rye](https://github.com/a5chin/python-uv/tree/rye)** - Rye package manager version (replaced by uv) ## ๐Ÿ“„ License diff --git a/docs/configurations/index.md b/docs/configurations/index.md index 7044f38e..061411bf 100644 --- a/docs/configurations/index.md +++ b/docs/configurations/index.md @@ -2,152 +2,20 @@ This section provides detailed information about how each tool in this template is configured. Understanding these configurations will help you customize the environment to match your project's specific needs. -## Overview - -The development environment includes configuration files for: - -- **uv** - Package management and Python version -- **Ruff** - Linting and formatting rules -- **sqruff** - Linting and formatting rules for SQL -- **ty** - Type checking strictness -- **pytest** - Testing and coverage -- **pre-commit** - Automated quality checks - -Each tool is configured through dedicated configuration files in the repository root. - ## Configuration Files -| File | Tool | Purpose | -| ------------------------- | ----------- | --------------------------------- | -| `pyproject.toml` | uv, Project | Dependencies and project metadata | -| `ruff.toml` | Ruff | Linting and formatting rules | -| `ty.toml` | ty | Type checking configuration | -| `.sqruff` | sqruff | SQL linting and formatting rules | -| `pytest.ini` | pytest | Testing and coverage settings | -| `.pre-commit-config.yaml` | pre-commit | Hook definitions | -| `noxfile.py` | nox | Task automation | - -## Quick Links - -Jump to detailed configuration guides: - -### [uv Configuration](uv.md) -Learn how uv manages dependencies and Python versions: -- Dependency groups (production vs development) -- Lock file management -- Python version pinning -- Virtual environment handling - -**Key file**: `pyproject.toml` - -[โ†’ Read full uv configuration guide](uv.md) +| File | Tool | Purpose | Reference | +| --- | --- | --- | --- | +| `pyproject.toml`, `.devcontainer/devcontainer.json` | uv, Project | Dependencies, project metadata, Dev Container and VS Code settings | [uv](uv.md) | +| `ruff.toml` | Ruff | Linting and formatting rules | [Ruff](ruff.md) | +| `ty.toml` | ty | Type checking configuration | [ty](ty.md) | +| `.sqruff` | sqruff | SQL linting and formatting rules | [sqruff](sqruff.md) | +| `pytest.ini` | pytest | Testing and coverage settings | [Test](test.md) | +| `.pre-commit-config.yaml` | pre-commit | Hook definitions | [pre-commit](pre-commit.md) | +| `noxfile.py` | nox | Task automation | [Task Automation with nox](../guides/index.md#task-automation-with-nox) | +| `.env`, `.env.local` | `Settings` | Environment variables | [Configuration Management](../guides/tools/config.md) | -### [Ruff Configuration](ruff.md) -Understand Ruff's linting and formatting rules: -- Rule selection (ALL enabled by default) -- Specific rule exclusions -- Per-file rule overrides -- Line length and formatting style - -**Key file**: `ruff.toml` - -[โ†’ Read full Ruff configuration guide](ruff.md) - -### sqruff Configuration -Configure SQL linting and formatting: -- SQL dialect (BigQuery) -- Line length (80 characters) -- Indentation (2 spaces) -- Custom rules for SQL best practices - -**Key file**: `.sqruff` - -**Quick reference:** -```bash -# Lint SQL files -uv run sqruff lint - -# Fix SQL files -uv run sqruff fix - -# Use via nox -uv run nox -s lint -- --sqruff -``` - -### [ty Configuration](ty.md) -Configure type checking behavior: -- Include/exclude patterns -- Source directories -- Cache exclusions - -**Key file**: `ty.toml` - -[โ†’ Read full ty configuration guide](ty.md) - -### [pytest Configuration](test.md) -Set up testing and coverage: -- Coverage requirements (75% minimum) -- Test discovery patterns -- Coverage reports (HTML + terminal) -- pytest plugins and options - -**Key file**: `pytest.ini` - -[โ†’ Read full pytest configuration guide](test.md) - -### [pre-commit Configuration](pre-commit.md) -Configure automated hooks: -- Ruff formatting and linting hooks -- File validation hooks -- Dockerfile linting -- Hook execution order - -**Key file**: `.pre-commit-config.yaml` - -[โ†’ Read full pre-commit configuration guide](pre-commit.md) - -## Common Configuration Tasks - -### Adjusting Code Quality Standards - -**Make linting more strict:** -```toml -# ruff.toml -[lint] -select = ["ALL"] -ignore = [] # Remove exclusions to enable all rules -``` - -**Increase coverage requirements:** -```ini -# pytest.ini -[pytest] -addopts = --cov-fail-under=90 # Increase from 75% to 90% -``` - -**Configure type checking:** -```toml -# ty.toml -[src] -include = ["tools", "tests", "your_package"] -exclude = ["**/__pycache__", ".pytest_cache", ".ruff_cache", ".venv"] -``` - -### Adding New Dependencies - -**Add production dependency:** -```bash -uv add requests -``` - -**Add development dependency:** -```bash -uv add --dev pytest-mock -``` - -Both commands automatically update `pyproject.toml` and `uv.lock`. - -### Customizing for Your Project +## Customizing for Your Project **Update project metadata:** ```toml @@ -159,14 +27,7 @@ description = "Your project description" requires-python = ">=3.11" ``` -**Configure FastAPI settings:** -```bash -# .env.local -DEBUG=true -TITLE=Your API Name -VERSION=1.0.0 -API_PREFIX_V1=/api/v1 -``` +To change linting rules, coverage requirements, or type checking targets, edit the file listed above; each reference page explains its options. ## Configuration Best Practices @@ -195,13 +56,7 @@ Ensure configurations work together: ### 4. Version Control -Commit configuration files to git: -```bash -git add pyproject.toml ruff.toml ty.toml pytest.ini .pre-commit-config.yaml -git commit -m "Update project configurations" -``` - -**Exception**: Never commit `.env.local` (contains local secrets) +Commit configuration files to git. `.env` is ignored by git, so put secrets there; `.env.local` is committed (see [Configuration Management](../guides/tools/config.md)). ### 5. Team Alignment @@ -239,38 +94,6 @@ uv run pre-commit uninstall uv run pre-commit install ``` -## Advanced Configuration - -### Multi-Environment Setup - -Use different configurations for different environments: - -```python -# Load config based on environment -from tools.config import Settings - -settings = Settings() - -if settings.IS_LOCAL: - # Use local database - DATABASE_URL = "sqlite:///./dev.db" -else: - # Use production database - DATABASE_URL = settings.PRODUCTION_DATABASE_URL -``` - -### CI/CD Configuration - -GitHub Actions workflows use the same configurations: - -```yaml -# .github/workflows/test.yml -- name: Run tests - run: uv run nox -s test -``` - -Ensure CI and local environments use identical configurations. - ## Migration Guide ### From pip to uv diff --git a/docs/configurations/pre-commit.md b/docs/configurations/pre-commit.md index db314887..152c77ea 100644 --- a/docs/configurations/pre-commit.md +++ b/docs/configurations/pre-commit.md @@ -3,111 +3,28 @@ !!! TIP If you do not want to use the pre-commit hook, run this command: ```sh - pre-commit uninstall + uv run pre-commit uninstall ``` ## Hook List +- [https://github.com/pre-commit/pre-commit-hooks](https://github.com/pre-commit/pre-commit-hooks) + - End of file fixer, Trailing whitespace + - Check JSON / TOML / XML / YAML + - Detect private key - [https://github.com/astral-sh/ruff-pre-commit](https://github.com/astral-sh/ruff-pre-commit) - - Ruff Lint - - Ruff Format -- [https://github.com/quarylabs/sqruff](https://github.com/quarylabs/sqruff) - - sqruff Lint - - sqruff Fix + - Python Format (`ruff format`) + - Python Lint (`ruff check --fix`) +- ty (local hook: `uv run ty check`) + - Python Type Check - [https://github.com/rhysd/actionlint](https://github.com/rhysd/actionlint) - - actionlint + - GitHub Actions Lint - [https://github.com/hadolint/hadolint](https://github.com/hadolint/hadolint) - - Hadolint + - Dockerfile Lint (requires `hadolint` on your `PATH`) +- [sqruff](https://github.com/quarylabs/sqruff) (local hooks: `uv run sqruff fix` / `uv run sqruff lint`) + - SQL Format + - SQL Lint ## Overview ```{.yaml title=".pre-commit-config.yaml"} -default_stages: [pre-commit] - -repos: - - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v5.0.0 - hooks: - - id: end-of-file-fixer - name: End of file fixer - description: Ensure files end with a newline - - - id: check-json - name: Check JSON - description: Check that JSON files are valid - - - id: check-toml - name: Check TOML - description: Check that TOML files are valid - - - id: check-xml - name: Check XML - description: Check that XML files are valid - - - id: check-yaml - name: Check YAML - description: Check that YAML files are valid - - - id: detect-private-key - name: Detect private key - description: Detect private keys in files - - - id: trailing-whitespace - name: Trailing whitespace - description: Remove trailing whitespace from files - - - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.12.8 - hooks: - - id: ruff-format - name: Python Format - description: Run 'ruff format' for extremely fast Python formatting - - - id: ruff-lint - name: Python Lint - description: Run 'ruff check' for extremely fast Python linting - args: [--fix] - - - repo: local - hooks: - - id: ty - name: Python Type Check - description: Run 'ty check' for Python type checking - entry: uv run ty check - language: python - types: [python] - - - repo: https://github.com/rhysd/actionlint - rev: v1.7.10 - hooks: - - id: actionlint - name: GitHub Actions Lint - description: Lint GitHub Actions workflows - - - repo: https://github.com/hadolint/hadolint - rev: v2.12.0 - hooks: - - id: hadolint - name: Dockerfile Lint - description: Runs hadolint to lint Dockerfiles - language: system - types: ["dockerfile"] - entry: hadolint - - - repo: local - hooks: - - id: sqruff-fix - name: SQL Format - description: Run 'sqruff fix' for SQL formatting - entry: uv run sqruff fix - language: python - types: [python] - - - id: sqruff-lint - name: SQL Lint - description: Run 'sqruff lint' for SQL linting - entry: uv run sqruff lint - language: python - types: [python] - -ci: - autoupdate_schedule: weekly +--8<-- ".pre-commit-config.yaml" ``` diff --git a/docs/configurations/ruff.md b/docs/configurations/ruff.md index 8a747706..154b1760 100644 --- a/docs/configurations/ruff.md +++ b/docs/configurations/ruff.md @@ -20,95 +20,13 @@ The Ruff formatter is an extremely fast Python code formatter designed as a drop They are set as default in this repository. === "ruff.toml" - ```{.toml hl_lines=42-58 81-83} - # Exclude a variety of commonly ignored directories. - exclude = [ - ".bzr", - ".direnv", - ".eggs", - ".git", - ".git-rewrite", - ".hg", - ".ipynb_checkpoints", - ".mypy_cache", - ".nox", - ".pants.d", - ".pyenv", - ".pytest_cache", - ".pytype", - ".ruff_cache", - ".svn", - ".tox", - ".venv", - ".vscode", - "__pypackages__", - "_build", - "buck-out", - "build", - "dist", - "node_modules", - "site-packages", - "venv", - ] - - # Same as Black. - line-length = 88 - indent-width = 4 - - # Assume Python 3.14 - target-version = "py314" - - [lint] - # Enable Pyflakes (`F`) and a subset of the pycodestyle (`E`) codes by default. - select = ["ALL"] - ignore = [ - "COM812", - "COM819", - "D100", - "D203", - "D213", - "D300", - "E111", - "E114", - "E117", - "ISC001", - "ISC002", - "PLC0415", - "Q000", - "Q001", - "Q002", - "Q003", - "W191", - ] - - # Allow fix for all enabled rules (when `--fix`) is provided. - fixable = ["ALL"] - unfixable = [] - - # Allow unused variables when underscore-prefixed. - dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$" - - [format] - # Like Black, use double quotes for strings. - quote-style = "double" - - # Like Black, indent with spaces, rather than tabs. - indent-style = "space" - - # Like Black, respect magic trailing commas. - skip-magic-trailing-comma = false - - # Like Black, automatically detect the appropriate line ending. - line-ending = "auto" - - [lint.per-file-ignores] - # Ignore all directories named `tests`. - "tests/**" = ["INP001", "S101"] + ```{.toml hl_lines="42-59 82-84"} + --8<-- "ruff.toml" ``` === "pyproject.toml" - ```{.toml hl_lines=43-59 82-84} + ```{.toml hl_lines="43-60 83-85"} [tool.ruff] # Exclude a variety of commonly ignored directories. exclude = [ @@ -153,6 +71,7 @@ The Ruff formatter is an extremely fast Python code formatter designed as a drop ignore = [ "COM812", "COM819", + "CPY001", "D100", "D203", "D213", @@ -195,19 +114,9 @@ The Ruff formatter is an extremely fast Python code formatter designed as a drop "tests/**" = ["INP001", "S101"] ``` -## extensions.json -The following settings are required for automatic formatting on VSCode. -```{.json title=".vscode/extensions.json" } -{ - "python.defaultInterpreterPath": ".venv/bin/python", - "[python]": { - "editor.codeActionsOnSave": { - "source.fixAll": "explicit", - "source.organizeImports": "explicit" - }, - "editor.defaultFormatter": "charliermarsh.ruff", - "editor.formatOnSave": true, - "editor.tabSize": 4 - } -} +## VS Code Settings +The `[python]` section of `.vscode/settings.json` formats Python with Ruff on save (`editor.formatOnSave`), and fixes lint errors and sorts imports (`source.fixAll`, `source.organizeImports`). + +```{.json title=".vscode/settings.json"} +--8<-- ".vscode/settings.json" ``` diff --git a/docs/configurations/sqruff.md b/docs/configurations/sqruff.md new file mode 100644 index 00000000..916743a3 --- /dev/null +++ b/docs/configurations/sqruff.md @@ -0,0 +1,31 @@ +# sqruff Configurations + +!!! TIP + Official documentation for sqruff is available at [https://github.com/quarylabs/sqruff](https://github.com/quarylabs/sqruff) + +```{.ini title=".sqruff"} +--8<-- ".sqruff" +``` + +## Configuration Options + +- **`dialect`**: SQL dialect (BigQuery) +- **`templater`**: Jinja templates in SQL files are rendered before linting +- **`max_line_length`**: 80 characters +- **`rules`**: All rules are enabled; list rules to skip in `exclude_rules` +- **Indentation**: 2 spaces, and `JOIN` clauses are indented +- **`ambiguous.join`**: Join types must be written explicitly (e.g. `INNER JOIN`, not `JOIN`) + +Files listed in `.sqruffignore` are skipped. + +## Usage + +```bash +# Lint / format SQL files via nox +uv run nox -s lint -- --sqruff +uv run nox -s fmt -- --sqruff + +# Run sqruff directly +uv run sqruff lint +uv run sqruff fix +``` diff --git a/docs/configurations/test.md b/docs/configurations/test.md index 16470bfa..174efa10 100644 --- a/docs/configurations/test.md +++ b/docs/configurations/test.md @@ -2,23 +2,7 @@ ## `pytest.ini` ```{.ini title="pytest.ini"} -[pytest] -addopts = - --cov=. - --cov-branch - --cov-fail-under=75 - --cov-report=html - --cov-report=term-missing - --import-mode=importlib - -norecursedirs = - .* - __pycache__ - htmlcov - -pythonpath = "." -python_files = test__*.py -testpaths = tests +--8<-- "pytest.ini" ``` ## Options Details @@ -56,14 +40,4 @@ Only the `tests` directory will be considered for running the tests. It is recommended to reduce the number of directories that pytest has to scan. ## `settings.json` - -```{.json title=".vscode/settings.json"} -{ - "python.testing.autoTestDiscoverOnSaveEnabled": false, - "python.testing.pytestEnabled": true, - "python.testing.pytestArgs": [ - "tests" - ], - "python.testing.unittestEnabled": false, -} -``` +VS Code discovers tests in `tests/` with pytest through the `python.testing.*` keys in `.vscode/settings.json` (see [VS Code Settings](ruff.md#vs-code-settings) for the full file). diff --git a/docs/configurations/ty.md b/docs/configurations/ty.md index 2302d313..2403eed6 100644 --- a/docs/configurations/ty.md +++ b/docs/configurations/ty.md @@ -7,9 +7,7 @@ ty is a fast type checker for Python built by Astral (the creators of uv and Ruff). ```{.toml title="ty.toml"} -[src] -include = ["tools", "tests", "noxfile.py"] -exclude = ["**/__pycache__", ".pytest_cache", ".ruff_cache", ".venv"] +--8<-- "ty.toml" ``` ## Configuration Options diff --git a/docs/getting-started/index.md b/docs/getting-started/index.md index c791d638..e24a07fd 100644 --- a/docs/getting-started/index.md +++ b/docs/getting-started/index.md @@ -56,11 +56,12 @@ cd python-uv # Build the Docker image docker build -t python-uv . -# Run the container -docker run -it --rm -v $(pwd):/workspace python-uv +# Run the container with the source mounted at /app (the image's WORKDIR). +# The extra volume keeps the virtual environment that was installed in the image. +docker run -it --rm -v "$(pwd)":/app -v /app/.venv python-uv bash -# Inside the container, install dependencies -uv sync +# Inside the container, dependencies are already installed +uv run nox -s test ``` ### Option 3: Local Installation @@ -110,13 +111,13 @@ uv sync uv run nox -s test # Format code -uv run nox -s fmt +uv run nox -s fmt -- --ruff # Run linters uv run nox -s lint -- --ruff --ty ``` -If all commands complete successfully, you're ready to start developing! ๐ŸŽ‰ +If all commands complete successfully, you're ready to start developing! ๐ŸŽ‰ See [Task Automation with nox](../guides/index.md#task-automation-with-nox) for all sessions and flags. ## Detailed Setup Guides @@ -156,6 +157,16 @@ sudo usermod -aG docker $USER Log out and log back in for the changes to take effect. +## Using as a Template + +When you start a new project from this template: + +1. Update the project name and description in `pyproject.toml` (see [Customizing for Your Project](../configurations/index.md#customizing-for-your-project)). +2. Add project-specific configuration by extending `Settings` (see [Extending Settings](../guides/tools/config.md#extending-settings)). +3. Use the utilities in `tools/`, or remove them if you do not need them. If you remove or add packages, update `include` in `ty.toml` (see [ty Configurations](../configurations/ty.md)). +4. Put shared defaults in `.env.local` (committed) and secrets in `.env` (not committed) (see [Environment Files](../guides/tools/config.md#environment-files)). +5. Customize Ruff rules in `ruff.toml` only when needed (see [Ruff Configurations](../configurations/ruff.md)). + ## Next Steps Now that your environment is set up, explore the guides to learn how to use the tools: diff --git a/docs/guides/branch-strategy.md b/docs/guides/branch-strategy.md new file mode 100644 index 00000000..cb3cd852 --- /dev/null +++ b/docs/guides/branch-strategy.md @@ -0,0 +1,81 @@ +# Branch Strategy & Release Flow + +This repository follows **GitHub Flow**: `main` is the only long-lived branch. There is no `develop` branch. + +**Develop** and **Production** are GitHub Environments, not branches. "Deploying" to them means pushing the `app` and `devcontainer` container images to GHCR (`ghcr.io/a5chin/python-uv/{app,devcontainer}`). + +```mermaid +gitGraph + commit id: "initial commit" + + branch feature/xxx + commit id: "add feature" + checkout main + merge feature/xxx id: "merge feature [Develop + Draft]" + + branch fix/xxx + commit id: "fix bug" + checkout main + merge fix/xxx id: "merge fix [Develop + Draft]" tag: "v1.0.0" + + branch hotfix/xxx + commit id: "urgent fix" + checkout main + merge hotfix/xxx id: "merge hotfix [Develop + Draft]" tag: "v1.0.1" +``` + +- **[Develop + Draft]**: every merge into `main` pushes the images to Develop and, if the builds succeed, updates the Draft Release. +- **Tags (`v1.0.0`, `v1.0.1`)**: publishing the Draft adds the tag to the commit it points to and deploys that tag to Production. No commit is made for the tag; check the Develop images before publishing. + +## Branches + +Create every branch from `main` and merge it back into `main` with a pull request. Never push directly to `main`. + +| Prefix | Use | Label added automatically | +|---|---|---| +| `feature/` | New features | `feature` | +| `fix/` | Bug fixes | `fix` | +| `hotfix/` | Urgent fix for a problem in Production | `hotfix` | +| `refactor/` | Refactoring | `refactor` | + +Labels are added by [`labeler.yml`](https://github.com/a5chin/python-uv/blob/main/.github/labeler.yml) from the branch prefix; PRs that change `*.md` files also get `documentation`. These labels decide the section of the release notes. + +## 1. Merge into `main` โ†’ Develop + +Every merge into `main` runs [`release.yml`](https://github.com/a5chin/python-uv/blob/main/.github/workflows/release.yml): + +1. The `publish` job builds the `app` and `devcontainer` images and pushes them to GHCR with the tags `main` and `sha-` (environment: **Develop**). +2. Only if **both** builds succeed, the `draft` job updates the Draft Release with release-drafter. The Draft points to the exact commit that was just built. + +If several PRs are merged in quick succession, older runs are cancelled and only the latest commit is built and drafted. + +## 2. Review the Draft Release โ†’ Publish โ†’ Production + +Publishing is done by a **maintainer with write access** to the repository. Contributors only need to get their PR merged into `main`. + +1. Open **Releases** on GitHub and edit the existing Draft. Do **not** create a new release or push a tag yourself. +2. Check the tag. release-drafter proposes it from the version labels on the merged PRs (`major` / `minor` / `patch`; the highest wins, default `patch`). Maintainers add version labels manually. You may change the tag; change it right before publishing, because any merge into `main` in between makes release-drafter overwrite it with its proposed value. +3. Edit the release notes if needed, then click **Publish release**. Publishing from the GitHub UI or with `gh release edit --draft=false` (your own credentials) is fine. Only releases published from inside a GitHub Actions workflow with `GITHUB_TOKEN` fail to trigger the deployment. +4. The `publish` job runs again (environment: **Production**), rebuilds the images from the tag, and pushes them with the tags `` (e.g. `v1.3.0`) and `latest`. The `org.opencontainers.image.version` label is set to the release tag. + +!!! WARNING + The tag **must start with `v`** (e.g. `v1.3.0`). The Production environment only allows deployments from tags matching `v*` (a tag policy; no `v*` branch is created), so any other tag is rejected. + +Pre-releases are **not** deployed: only a full release (or converting a pre-release to a full release) triggers Production. + +## Hotfixes + +Hotfixes follow the same flow: create `hotfix/*` from `main`, open a PR to `main`, merge, then publish the Draft. + +Note that **everything already merged into `main` but not yet released ships together with the hotfix**. Check the Draft's change list before publishing. + +- If some of those changes must not ship yet, revert them with a PR to `main` first, then publish. +- The proposed tag follows the PR labels (the highest of `major` / `minor` / `patch` wins), so it may be a minor version even for a hotfix. Change it if it does not match what you are releasing (e.g. `v1.2.4` for a patch); it must still start with `v`. + +## When Something Fails + +| Symptom | Cause | Action | +|---|---|---| +| The Draft Release was not updated after a merge | The `publish` job (image build) failed, so `draft` was skipped | Open the `Release` workflow run in the Actions tab, fix the failure, then re-run the failed jobs or merge the fix into `main` | +| Production succeeded for only one image | Image builds run independently (`fail-fast: false`) | Re-run the failed job in the same workflow run | +| Production deployment was rejected | The tag does not start with `v` | Edit the release, set it back to a draft, change the tag to start with `v`, and publish again | diff --git a/docs/guides/ci-cd.md b/docs/guides/ci-cd.md new file mode 100644 index 00000000..73a632cd --- /dev/null +++ b/docs/guides/ci-cd.md @@ -0,0 +1,36 @@ +# CI/CD Workflows + +All workflows live in [`.github/workflows/`](https://github.com/a5chin/python-uv/tree/main/.github/workflows). Quality checks run on pull requests, using the same nox sessions as local development (see [Task Automation with nox](index.md#task-automation-with-nox)). + +## Quality Checks + +| Workflow | Runs on | What it does | +|---|---|---| +| `format.yml` | PRs changing Python / SQL files or their configs | `nox -s fmt -- --ruff` and `nox -s fmt -- --sqruff` | +| `lint.yml` | PRs changing Python / SQL files or their configs | `nox -s lint -- --ruff`, `-- --sqruff`, and `-- --ty` | +| `test.yml` | PRs and pushes to `main` changing Python files or test configs | `nox -s test -- --cov_report xml --junitxml junit.xml`, then uploads results to Codecov | +| `actionlint.yml` | PRs changing `.github/workflows/*.yml` | Lints workflows with actionlint (reviewdog) | +| `docker.yml` | PRs changing Python files, `pyproject.toml`, `uv.lock`, ... | Validates the `Dockerfile` build | +| `devcontainer.yml` | PRs changing `.devcontainer/` or `.python-version` | Validates the Dev Container build | + +## Pull Request Automation + +| Workflow | Runs on | What it does | +|---|---|---| +| `labeler.yml` | PRs opened / updated | Adds labels from the branch prefix (see [Branches](branch-strategy.md#branches)) | +| `assign.yml` | PRs opened by humans without an assignee | Assigns the PR author | +| `approve.yml` | PRs opened by bots (e.g. Renovate) | Approves the PR | +| `pr-agent.yml` | PRs opened / updated and PR comments (non-bot) | Automated review with Qodo PR Agent | + +## Release & Deployment + +| Workflow | Runs on | What it does | +|---|---|---| +| `release.yml` | Pushes to `main` and published releases | Builds and pushes the `app` / `devcontainer` images to GHCR and updates the Draft Release. See [Branch Strategy & Release Flow](branch-strategy.md) | +| `gh-deploy.yml` | PRs changing `docs/` or `mkdocs.yml`, and manual runs | Deploys this documentation site to GitHub Pages (`mkdocs gh-deploy`) | + +## Repository Settings + +| Workflow | Runs on | What it does | +|---|---|---| +| `setting.yml` | Daily, manual runs, and PRs changing it or `.github/{environments,protection}.json` | Applies the default branch, environments and their deployment policies, GitHub Pages source, workflow permissions, and branch protection | diff --git a/docs/guides/code-standards.md b/docs/guides/code-standards.md new file mode 100644 index 00000000..d4cc434c --- /dev/null +++ b/docs/guides/code-standards.md @@ -0,0 +1,166 @@ +# Code Standards + +Ruff and ty enforce most of these rules automatically; run the checks in [Task Automation with nox](index.md#task-automation-with-nox) before opening a pull request. + +## General Guidelines + +- **Line length**: Maximum 88 characters (see [Ruff Configurations](../configurations/ruff.md)) +- **Python version**: The project supports Python 3.11+ (`requires-python`); Ruff targets Python 3.14 +- **Import order**: Automatically handled by Ruff +- **Naming conventions**: + - Classes: `PascalCase` + - Functions/variables: `snake_case` + - Constants: `UPPER_SNAKE_CASE` + - Private members: `_leading_underscore` + +## Type Hints + +All functions and methods must have type hints: + +```python +# Good +def process_data(items: list[str], max_count: int = 10) -> dict[str, int]: + """Process items and return statistics.""" + ... + +# Avoid +def process_data(items, max_count=10): + ... +``` + +## Docstring + +All public functions, classes, and modules must have docstring: + +```python +def calculate_total(items: list[float], tax_rate: float) -> float: + """Calculate the total price including tax. + + Args: + items: List of item prices. + tax_rate: Tax rate as a decimal (e.g., 0.1 for 10%). + + Returns: + Total price including tax. + + Raises: + ValueError: If tax_rate is negative. + """ + if tax_rate < 0: + raise ValueError("Tax rate cannot be negative") + subtotal = sum(items) + return subtotal * (1 + tax_rate) +``` + +## Code Organization + +- **One class per file** (unless closely related) +- **Group related functions** in modules +- **Keep functions focused** - Single Responsibility Principle +- **Avoid deep nesting** - Maximum 3-4 levels +- **Extract complex logic** into named functions + +## Testing + +### Coverage + +- **Minimum coverage**: 75% (including branch coverage), enforced by `pytest.ini` (see [Test Configurations](../configurations/test.md)) +- **Target coverage**: 100% for new code + +### Writing Tests + +1. **Location**: Put tests for `tools//` in `tests/tools/test__.py` (e.g. `tools/logger/` โ†’ `tests/tools/test__logger.py`) +2. **Naming**: Use the `test__*.py` pattern (double underscore); other files are not collected +3. **Structure**: One test file per module + +```python +# tests/tools/test__logger.py +from tools.logger import Logger, LogType + + +class TestLocalLogger: + """Test class for local logger.""" + + def setup_method(self) -> None: + """Set up logger.""" + self.logger = Logger(name=__name__, log_type=LogType.LOCAL) + + def test_name(self) -> None: + """Test correct name of logger.""" + assert self.logger.name == __name__ +``` + +### Running Tests + +```bash +# Run all tests with coverage +uv run nox -s test + +# Run a specific test file / test +uv run pytest tests/tools/test__logger.py +uv run pytest tests/tools/test__logger.py::TestLocalLogger::test_name + +# View the coverage report +open htmlcov/index.html +``` + +### Best Practices + +- **Test one thing** per test function +- **Use descriptive names** - `test_logger_handles_none_values` +- **Arrange-Act-Assert** pattern +- **Cover edge cases** - empty inputs, None, boundary values +- **Test error conditions** - expected exceptions +- **Minimize mocking** - Use real objects when possible +- **Independent tests** - No dependencies between tests + +## Documentation + +Update the documentation when you add features or utilities, change public APIs or configuration, add environment variables, or change the development workflow. + +- **Each topic has exactly one source of truth under `docs/`.** Edit that page; `README.md`, `CONTRIBUTING.md`, and `CLAUDE.md` only link to it and must not copy its content. +- Configuration pages include the real config files with `--8<-- ""` ([snippets](https://facelessuser.github.io/pymdown-extensions/extensions/snippets/)); do not paste config contents into a page. +- When adding a utility to `tools/`, add a page to `docs/guides/tools/` and list it under Available Modules and Package Structure in [`docs/guides/tools/index.md`](tools/index.md). +- When adding a page, register it in the `nav` of `mkdocs.yml` and check it with `uv run mkdocs build --strict`. +- Provide code examples and test them before committing. + +## Common Issues + +### Test Coverage Below 75% + +Run `uv run nox -s test`, open `htmlcov/index.html` to find uncovered lines, and add tests for them. + +### Lint Errors + +```bash +uv run ruff check . --fix # Auto-fix Ruff issues +uv run ruff format . # Format code +uv run ty check # Check type errors +``` + +If type errors persist, add type hints or use `# type: ignore` with a justification. + +### Pre-commit Hook Failures + +Run `uv run pre-commit run --all-files` to see what failed. Formatting and trailing whitespace are fixed by the hooks; fix JSON / YAML / TOML syntax errors manually, then `git add` and commit again. + +### Merge Conflicts + +```bash +git checkout main +git pull origin main +git checkout your-branch +git merge main +# Resolve conflicts, then: +git add . +git commit -m "fix: Resolve merge conflicts with main" +git push origin your-branch +``` + +### `uv.lock` Out of Sync + +If CI fails with dependency resolution errors, run `uv lock` and commit the updated `uv.lock`. + +### Import Errors in Tests + +If tests fail with `ModuleNotFoundError`, run `uv sync` and import from the package root (e.g. `from tools.logger import Logger`, not `from logger import Logger`). diff --git a/docs/guides/index.md b/docs/guides/index.md index 321b8788..8d19deb2 100644 --- a/docs/guides/index.md +++ b/docs/guides/index.md @@ -1,24 +1,10 @@ # Development Guides -This section provides comprehensive guides for using the tools and utilities included in this template. Whether you're managing dependencies, formatting code, or building production applications, these guides will help you work efficiently. - -## Overview - -This template includes several modern Python development tools, each serving a specific purpose: - -- **uv** - Ultra-fast package management (10-100x faster than pip) -- **Ruff** - Lightning-fast linting and formatting -- **ty** - Advanced type checking -- **sqruff** - SQL linting and formatting -- **actionlint** - GitHub Actions workflow linting -- **pytest** - Comprehensive testing framework -- **nox** - Task automation and workflow management -- **pre-commit** - Automated code quality checks -- **Built-in utilities** - Production-ready modules for logging, configuration, and monitoring +This section provides guides for using the tools and utilities included in this template, and for contributing to it. ## Task Automation with nox -**nox** is the primary way to run development tasks in this repository. It provides a consistent interface for common operations and handles dependency management automatically. +**nox** is the primary way to run development tasks in this repository. Every session runs with `python=False` (it relies on `uv run`), and `fmt` / `lint` only run the tools whose flags you pass: `uv run nox -s fmt` without flags does nothing. ### Available Sessions @@ -42,206 +28,26 @@ uv run nox -s test uv run nox -s test -- --cov_report xml --junitxml junit.xml ``` -### Why nox? - -- **Consistent workflow** - Same commands work for all developers -- **Isolated environments** - Each session runs in isolation -- **Customizable** - Easy to add new sessions for your needs -- **CI/CD friendly** - Integrates seamlessly with GitHub Actions - -## Package Management - -### [uv Guide](uv.md) - -Learn how to manage Python packages with uv, the blazing-fast package manager: - -- Adding and removing dependencies -- Managing development dependencies -- Pinning Python versions -- Understanding the lock file - -**Quick reference:** - -```bash -# Add a package -uv add requests - -# Add a dev dependency -uv add --dev pytest-mock - -# Install all dependencies -uv sync - -# Remove a package -uv remove requests -``` - -[โ†’ Read the full uv guide](uv.md) - -## Code Quality - -### [Ruff Guide](ruff.md) - -Master Ruff, the all-in-one linter and formatter that replaces Black, isort, Flake8, and more: - -- Formatting code automatically -- Running linting checks -- Understanding Ruff rules -- Customizing for your project - -**Quick reference:** - -```bash -# Format code -uv run ruff format . - -# Lint code -uv run ruff check . - -# Auto-fix issues -uv run ruff check . --fix -``` - -[โ†’ Read the full Ruff guide](ruff.md) - -### [ty Guide](ty.md) - -Use ty for comprehensive type checking: - -- Running type checks -- Understanding type errors -- Configuring type checking -- Integrating with your editor - -**Quick reference:** - -```bash -# Run type checker -uv run ty check - -# Check via nox -uv run nox -s lint -- --ty -``` - -[โ†’ Read the full ty guide](ty.md) - -## Testing - -### [Testing Guide](test.md) - -Learn how to write and run tests with pytest: - -- Writing test cases -- Running tests with coverage -- Understanding coverage reports -- Testing best practices - -**Quick reference:** - -```bash -# Run all tests -uv run pytest - -# Run specific test file -uv run pytest tests/tools/test__logger.py - -# Run with coverage report -uv run pytest --cov=tools --cov-report=html -``` - -[โ†’ Read the full testing guide](test.md) - -## Automation - -### [Pre-commit Guide](pre-commit.md) - -Set up automated code quality checks that run before every commit: - -- Installing pre-commit hooks -- Running hooks manually -- Understanding hook failures -- Customizing hooks - -**Quick reference:** - -```bash -# Install hooks -uv run pre-commit install - -# Run all hooks manually -uv run pre-commit run --all-files - -# Run specific hook -uv run pre-commit run ruff-format -``` - -[โ†’ Read the full pre-commit guide](pre-commit.md) - -## Built-in Utilities - -### [Tools Package](tools/index.md) - -Explore the production-ready utility modules included in this template: - -#### [Logger](tools/logger.md) -Flexible logging system with support for both local development and Google Cloud: - -```python -from tools.logger import Logger, LogType - -logger = Logger(__name__, log_type=LogType.LOCAL) -logger.info("Application started") -``` - -#### [Configuration](tools/config.md) -Environment-based configuration management: - -```python -from tools.config import Settings - -settings = Settings() # Loads from .env and .env.local -api_url = settings.api_prefix_v1 -``` - -#### [Performance Tracer](tools/tracer.md) -Timer decorator and context manager for performance monitoring: - -```python -from tools.tracer import Timer - -with Timer("database_query"): - result = db.query() # Logs execution time -``` - -[โ†’ Explore all built-in utilities](tools/index.md) - -## Project Templates - -### [Cookiecutter Guide](cookiecutter.md) - -Learn how to use cookiecutter templates to bootstrap new projects: - -- Data Science projects -- FastAPI applications -- Django web apps -- Flask microservices - -**Quick reference:** - -```bash -# Use a template -uv run cookiecutter https://github.com/fastapi/full-stack-fastapi-template -``` +Before opening a pull request, run `fmt`, `lint`, and `test` above, then `uv run pre-commit run --all-files`. -[โ†’ Read the full cookiecutter guide](cookiecutter.md) +## Tools -## Next Steps +| Guide | What it covers | +|---|---| +| [uv](uv.md) | Adding / removing dependencies, development dependencies, pinning the Python version | +| [Ruff](ruff.md) | Formatting and linting Python code | +| [ty](ty.md) | Type checking | +| [pre-commit](pre-commit.md) | Hooks that run before every commit | +| [Test](test.md) | Running pytest with coverage | +| [cookiecutter](cookiecutter.md) | Bootstrapping new projects from templates | +| [Tools Package](tools/index.md) | Built-in `Logger`, `Settings`, and `Timer` utilities | -1. **Start with basics**: Read the [uv guide](uv.md) to understand package management -2. **Ensure quality**: Set up [pre-commit hooks](pre-commit.md) for automatic checks -3. **Explore utilities**: Check out the [built-in tools](tools/index.md) for common tasks -4. **See examples**: Browse [use cases](../usecases/index.md) for real-world applications +## Contributing -## Need More Details? +| Guide | What it covers | +|---|---| +| [Code Standards](code-standards.md) | Coding rules, writing tests, documentation rules, common issues | +| [Branch Strategy & Release Flow](branch-strategy.md) | GitHub Flow, branch naming, Draft Release โ†’ Publish โ†’ Production | +| [CI/CD Workflows](ci-cd.md) | What each GitHub Actions workflow does and when it runs | -For in-depth configuration information, see the [Configuration Reference](../configurations/index.md) section. +For configuration details, see the [Configuration Reference](../configurations/index.md). diff --git a/docs/guides/tools/config.md b/docs/guides/tools/config.md index b38689f3..b2d08ce3 100644 --- a/docs/guides/tools/config.md +++ b/docs/guides/tools/config.md @@ -30,22 +30,22 @@ is_local = settings.IS_LOCAL ### Environment Files -The module loads configuration from two files in order: +The module loads configuration from two files in order; values in a later file override earlier ones, and real environment variables override both: -1. `.env` - Base configuration (committed to git) -2. `.env.local` - Local overrides (not committed, in `.gitignore`) +1. `.env` - Not committed (listed in `.gitignore`). Put secrets and personal settings here. +2. `.env.local` - Committed to git. The template ships it with `IS_LOCAL=True`. -**`.env`** (shared configuration): +Variable names are case-insensitive (`DEBUG=true` sets the `debug` field). + +**`.env.local`** (committed): ```bash -DEBUG=false -TITLE=My Application -API_PREFIX_V1=/api/v1 +IS_LOCAL=True ``` -**`.env.local`** (local overrides): +**`.env`** (not committed): ```bash -IS_LOCAL=true DEBUG=true +TITLE=My Application ``` ## Available Settings @@ -269,12 +269,7 @@ async def health_check(): ### 1. Never Commit Secrets -Always keep sensitive data in `.env.local`: - -```bash -# .gitignore (should already include this) -.env.local -``` +Always keep sensitive data in `.env`, which is listed in `.gitignore`. `.env.local` is committed, so never put secrets there. ### 2. Provide Defaults @@ -312,7 +307,7 @@ class Settings(BaseSettings): """Database connection string.""" SECRET_KEY: str - """Secret key for JWT tokens. Must be set in .env.local.""" + """Secret key for JWT tokens. Must be set in .env.""" ``` ### 5. Validate Related Settings @@ -345,13 +340,9 @@ import pytest from tools.config import Settings def test_with_custom_settings(): - settings = Settings( - DEBUG=True, - IS_LOCAL=True, - DATABASE_URL="sqlite:///:memory:" - ) + settings = Settings(debug=True, IS_LOCAL=True) - assert settings.DEBUG is True + assert settings.debug is True assert settings.IS_LOCAL is True ``` diff --git a/docs/guides/tools/logger.md b/docs/guides/tools/logger.md index fd15d00d..2362cb5f 100644 --- a/docs/guides/tools/logger.md +++ b/docs/guides/tools/logger.md @@ -270,22 +270,30 @@ class CustomFormatter(LocalFormatter): return f"[CUSTOM] {formatted}" ``` +### Adding a New Log Type + +To add an output format selectable with `log_type`: + +1. Create a formatter in `tools/logger/` that extends `logging.Formatter` (see `local.py` and `googlecloud.py`). +2. Export it from `tools/logger/__init__.py` and add it to `__all__`. +3. Add a member to `LogType` in `tools/logger/type.py`. +4. Handle the new member in `Logger.__init__()` in `tools/logger/logger.py`, and add tests in `tests/tools/`. + ## Testing -Test your logging by checking log output: +`Logger` does not propagate to the root logger, so attach pytest's `caplog` handler to it: + +```python +from tools.logger import Logger, LogType + def test_logger(caplog): - logger = Logger("test") + logger = Logger("test", log_type=LogType.LOCAL) + logger.addHandler(caplog.handler) - # Capture log output - with caplog.at_level(logging.INFO): - logger.info("Test message") + logger.info("Test message") assert "Test message" in caplog.text - with self.assertLogs(logger, level=logging.INFO) as cm: - logger.info("Test message") - - assert "Test message" in cm.output[0] ``` ## Related Documentation diff --git a/docs/guides/tools/tracer.md b/docs/guides/tools/tracer.md index e950c1d9..33b5631d 100644 --- a/docs/guides/tools/tracer.md +++ b/docs/guides/tools/tracer.md @@ -363,20 +363,20 @@ with maybe_timer("optional_timing"): ## Testing -Test code with timers by checking log output: +`Timer` writes its DEBUG log to standard output through a new `Logger`, so check it with pytest's `capsys`: + +```python +from tools.tracer import Timer -def test_timer_logging(caplog): - with caplog.at_level(logging.DEBUG): - with Timer("test_operation"): - pass # Instant operation - assert "test_operation" in caplog.text - assert "executed in" in caplog.text - assert "ms" in caplog.text +def test_timer_logging(capsys): + with Timer("test_operation"): + pass # Instant operation - assert "test_operation" in cm.output[0] - assert "executed in" in cm.output[0] - assert "ms" in cm.output[0] + out = capsys.readouterr().out + assert "test_operation" in out + assert "executed in" in out + assert "ms" in out ``` ## Related Documentation diff --git a/docs/guides/ty.md b/docs/guides/ty.md index f1c01cd7..4c5b4482 100644 --- a/docs/guides/ty.md +++ b/docs/guides/ty.md @@ -40,7 +40,7 @@ uv run pre-commit install ``` ### CI/CD -GitHub Actions runs ty on every push and pull request to the main branch. See the workflow configuration in `.github/workflows/lint.yml`. +GitHub Actions runs ty on pull requests that change Python files or their configuration. See [CI/CD Workflows](ci-cd.md). ### VSCode Integration VSCode uses ty for type checking when `python.languageServer` is set to `"None"` in `.vscode/settings.json`. diff --git a/docs/guides/uv.md b/docs/guides/uv.md index 397b4abd..de48ac6e 100644 --- a/docs/guides/uv.md +++ b/docs/guides/uv.md @@ -29,7 +29,7 @@ uv remove ruff ## Pin Python Version If you want to pin the Python version, run the following command: ```sh -uv pin python 3.14 +uv python pin 3.14 ``` ## Configuration for uv diff --git a/docs/index.md b/docs/index.md index ce74965c..e2e6cb48 100644 --- a/docs/index.md +++ b/docs/index.md @@ -74,6 +74,14 @@ Learn how to use the tools and utilities: - [Pre-commit Guide](guides/pre-commit.md) - Automated quality checks - [Built-in Utilities](guides/tools/index.md) - Logger, Config, Timer +### Contributing + +How changes are written, checked, and released: + +- [Code Standards](guides/code-standards.md) - Coding rules, tests, and documentation rules +- [Branch Strategy & Release Flow](guides/branch-strategy.md) - GitHub Flow, Draft Release, Develop / Production +- [CI/CD Workflows](guides/ci-cd.md) - What each GitHub Actions workflow does + ### Configuration Reference Deep dive into tool configurations: @@ -81,6 +89,7 @@ Deep dive into tool configurations: - [uv Configuration](configurations/uv.md) - Package manager settings - [Ruff Configuration](configurations/ruff.md) - Linter and formatter rules - [ty Configuration](configurations/ty.md) - Type checker settings +- [sqruff Configuration](configurations/sqruff.md) - SQL linter and formatter rules - [pytest Configuration](configurations/test.md) - Testing framework setup - [Pre-commit Configuration](configurations/pre-commit.md) - Hook definitions @@ -96,45 +105,30 @@ See practical examples: ``` . -โ”œโ”€โ”€ tools/ # Reusable utility modules -โ”‚ โ”œโ”€โ”€ config/ # Configuration management -โ”‚ โ”œโ”€โ”€ logger/ # Logging utilities -โ”‚ โ””โ”€โ”€ tracer/ # Performance monitoring -โ”œโ”€โ”€ tests/ # Test suite -โ”œโ”€โ”€ docs/ # This documentation -โ”œโ”€โ”€ .devcontainer/ # Dev Container configuration -โ”œโ”€โ”€ .github/ # GitHub Actions workflows -โ”œโ”€โ”€ noxfile.py # Task automation -โ”œโ”€โ”€ pyproject.toml # Project metadata +โ”œโ”€โ”€ tools/ # Reusable utility modules +โ”‚ โ”œโ”€โ”€ config/ # Configuration management (Settings, FastAPI config) +โ”‚ โ”œโ”€โ”€ logger/ # Logging utilities (Local & Google Cloud formatters) +โ”‚ โ””โ”€โ”€ tracer/ # Performance tracing (Timer decorator/context manager) +โ”œโ”€โ”€ tests/ # Test suite (mirrors tools/ structure) +โ”œโ”€โ”€ docs/ # This documentation (MkDocs) +โ”œโ”€โ”€ .devcontainer/ # Dev Container configuration +โ”œโ”€โ”€ .github/ # GitHub Actions workflows, PR template, repository settings +โ”œโ”€โ”€ CLAUDE.md # Guidance for Claude Code +โ”œโ”€โ”€ CODE_OF_CONDUCT.md # Community Code of Conduct +โ”œโ”€โ”€ CONTRIBUTING.md # Contribution guidelines +โ”œโ”€โ”€ Dockerfile # App image +โ”œโ”€โ”€ mkdocs.yml # Documentation site configuration +โ”œโ”€โ”€ noxfile.py # Task automation (fmt, lint, test) +โ”œโ”€โ”€ pyproject.toml # Project metadata and dependencies (uv) +โ”œโ”€โ”€ pytest.ini # pytest configuration (75% coverage requirement) โ”œโ”€โ”€ ruff.toml # Ruff configuration -โ”œโ”€โ”€ ty.toml # Type checking config -โ””โ”€โ”€ pytest.ini # Testing configuration +โ”œโ”€โ”€ ty.toml # ty configuration +โ””โ”€โ”€ .sqruff # sqruff configuration ``` ## Common Commands -```bash -# Install dependencies -uv sync - -# Format Python code -uv run nox -s fmt -- --ruff - -# Format SQL code -uv run nox -s fmt -- --sqruff - -# Run linters -uv run nox -s lint -- --ruff --sqruff --ty - -# Run tests -uv run nox -s test - -# Serve documentation -uv run mkdocs serve - -# Add dependencies -uv add requests pandas -``` +Install dependencies with `uv sync`, then use the nox sessions in [Task Automation with nox](guides/index.md#task-automation-with-nox) to format, lint, and test. Serve this documentation locally with `uv run mkdocs serve`. ## Next Steps diff --git a/docs/usecases/jupyter.md b/docs/usecases/jupyter.md index b569cd3d..867e9f30 100644 --- a/docs/usecases/jupyter.md +++ b/docs/usecases/jupyter.md @@ -1,3 +1,6 @@ +!!! WARNING + The [jupyter](https://github.com/a5chin/python-uv/tree/jupyter) branch is **archived** and no longer maintained, so its configuration may be outdated. For new projects, start from `main`. + This repository provides jupyter branch for Jupyter Notebook. What a surprise! You can use it with just the following commands! ```sh diff --git a/mkdocs.yml b/mkdocs.yml index fb359718..1c111468 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -1,7 +1,7 @@ repo_name: a5chin/python-uv repo_url: https://github.com/a5chin/python-uv site_name: python-uv -site_url: https://a5chin.github.io/a5chin +site_url: https://a5chin.github.io/python-uv theme: name: material @@ -39,7 +39,14 @@ markdown_extensions: - pymdownx.highlight: linenums: true - pymdownx.keys - - pymdownx.superfences + - pymdownx.snippets: + base_path: [.] + check_paths: true + - pymdownx.superfences: + custom_fences: + - name: mermaid + class: mermaid + format: !!python/name:pymdownx.superfences.fence_code_format - pymdownx.tabbed: alternate_style: true @@ -58,6 +65,9 @@ nav: - pre-commit: guides/pre-commit.md - Test: guides/test.md - cookiecutter: guides/cookiecutter.md + - Code Standards: guides/code-standards.md + - Branch Strategy: guides/branch-strategy.md + - CI/CD: guides/ci-cd.md - tools: - guides/tools/index.md - config: guides/tools/config.md @@ -68,6 +78,7 @@ nav: - uv: configurations/uv.md - Ruff: configurations/ruff.md - ty: configurations/ty.md + - sqruff: configurations/sqruff.md - pre-commit: configurations/pre-commit.md - Test: configurations/test.md - Usecases: From 19e9c6afbdb447e50c32d50ff85170449c3863b7 Mon Sep 17 00:00:00 2001 From: d-eigo-hara Date: Thu, 8 Oct 2026 17:46:43 +0900 Subject: [PATCH 4/7] fix: pre-commit --- .pre-commit-config.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index b85d4bab..aeef0fd1 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -23,6 +23,7 @@ repos: - id: check-yaml name: Check YAML description: Check that YAML files are valid + args: [--unsafe] - id: detect-private-key name: Detect private key From 2f28cdfef5e01edc28cf14565f9b970a027e6305 Mon Sep 17 00:00:00 2001 From: d-eigo-hara Date: Thu, 8 Oct 2026 17:56:16 +0900 Subject: [PATCH 5/7] fix: bot --- .github/workflows/approve.yml | 2 +- .github/workflows/assign.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/approve.yml b/.github/workflows/approve.yml index 0c3576dd..c6899201 100644 --- a/.github/workflows/approve.yml +++ b/.github/workflows/approve.yml @@ -12,7 +12,7 @@ jobs: approve: runs-on: ubuntu-latest - if: endsWith(github.actor, '[bot]') + if: github.event.pull_request.user.type != 'Bot' steps: - name: Checkout diff --git a/.github/workflows/assign.yml b/.github/workflows/assign.yml index 4ea63f05..a6d99064 100644 --- a/.github/workflows/assign.yml +++ b/.github/workflows/assign.yml @@ -13,7 +13,7 @@ jobs: assign: runs-on: ubuntu-latest - if: endsWith(github.actor, '[bot]') == false && github.event.pull_request.assignee == null + if: github.event.pull_request.user.type != 'Bot' && github.event.pull_request.assignee == null steps: - name: Add assignees From 36a0e5eee45d175e84b43e8f43e698780c72edff Mon Sep 17 00:00:00 2001 From: d-eigo-hara Date: Thu, 8 Oct 2026 18:40:22 +0900 Subject: [PATCH 6/7] fix: approve --- .github/workflows/approve.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/approve.yml b/.github/workflows/approve.yml index c6899201..eb91f666 100644 --- a/.github/workflows/approve.yml +++ b/.github/workflows/approve.yml @@ -12,7 +12,7 @@ jobs: approve: runs-on: ubuntu-latest - if: github.event.pull_request.user.type != 'Bot' + if: github.event.pull_request.user.type == 'Bot' steps: - name: Checkout From 741ecdabb00fe2621b48a13cc23f9e942028dbbf Mon Sep 17 00:00:00 2001 From: d-eigo-hara Date: Thu, 8 Oct 2026 19:19:26 +0900 Subject: [PATCH 7/7] fix: env --- .github/workflows/release.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 56c1b387..c1d5935d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -92,8 +92,6 @@ jobs: runs-on: ubuntu-latest - environment: Develop - steps: - name: Checkout uses: actions/checkout@v7