Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# Git and version control
.git
.gitignore

# Virtual environments
.venv

# Python cache and bytecode
__pycache__
*.py[cod]
*$py.class
*.so
*.egg-info
*.egg

# Testing
tests
.pytest_cache
.coverage
.coverage.*
htmlcov
.tox
.nox
.hypothesis

# Development tools and docs
Makefile
.pre-commit-config.yaml
CHANGELOG.md
README.md

# IDE and editor files
.vscode
.idea
*.swp
*.swo
*~

# OS files
.DS_Store
Thumbs.db

# Build artifacts
build
dist
*.whl
*.tar.gz

# Linting and type checking caches
.ruff_cache
.mypy_cache
.dmypy.json

# Misc
*.bak
.cache

# Docker files
Dockerfile
.dockerignore
52 changes: 11 additions & 41 deletions .github/workflows/actions.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
name: All checks
on:
workflow_call:
push:
tags:
- 'v[0-9]+'
Expand All @@ -11,55 +10,26 @@
- 'v[0-9]+.[0-9]+.[0-9]+-*'
branches:
- '**'
pull_request: ~

jobs:
pre-commit-preparation:
name: Pre-commit
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v3

- name: Copy config
run: |
if [ ! -f .pre-commit-config.yaml ]; then
curl -o .pre-commit-config.yaml https://raw.githubusercontent.com/EO-DataHub/github-actions/main/.pre-commit-config-python.yaml
fi
- uses: pre-commit/action@v3.0.1
qa:
uses: EO-DataHub/github-actions/.github/workflows/qa-python.yaml@main

security-scan:

Check warning

Code scanning / CodeQL

Workflow does not contain permissions Medium

Actions job or workflow does not limit the permissions of the GITHUB_TOKEN. Consider setting an explicit permissions block, using the following as a minimal starting point: {}
name: Call Security Scan
uses: EO-DataHub/github-actions/.github/workflows/security.yaml@main

unit-tests:
name: Run unit tests
uses: EO-DataHub/github-actions/.github/workflows/unit-tests-python.yaml@main
uses: EO-DataHub/github-actions/.github/workflows/unit-tests-python-uv.yaml@main

get-tag-name:
runs-on: ubuntu-latest
outputs:
image_tag: ${{ steps.get-image-tag.outputs.IMAGE_TAG }}
steps:
- name: Get image tag
id: get-image-tag
run: |
IMAGE_TAG=$(if [[ "${GITHUB_REF##refs/tags/}" =~ ^v ]]; then echo ${GITHUB_REF##refs/tags/v}; elif [[ "${GITHUB_REF}" == "refs/heads/main" ]]; then echo "latest"; else echo "${GITHUB_REF##refs/heads/}-latest" | sed "s/[^a-zA-Z0-9]/-/g" ; fi) >> "$GITHUB_ENV"
echo $IMAGE_TAG
echo "IMAGE_TAG=$IMAGE_TAG" >> "$GITHUB_OUTPUT"
aws-ecr-build:
name: Build ECR image
needs: get-tag-name
uses: EO-DataHub/github-actions/.github/workflows/docker-image-to-aws-ecr.yaml@main
publish:
name: Build and push Docker image
uses: EO-DataHub/github-actions/.github/workflows/ecr-publish.yaml@main
with:
image_name: CHANGE-ME
image_tag: ${{ needs.get-tag-name.outputs.image_tag }}
permissions:
image_name: ${{ vars.IMAGE_NAME }}
aws_role_arn: ${{ vars.AWS_ROLE_ARN }}
aws_ecr_alias: ${{ vars.AWS_ECR_ALIAS }}s
id-token: write
contents: read
secrets:
AWS_ACCOUNT_ID: ${{ secrets.AWS_ACCOUNT_ID }}
AWS_ECR: ${{ secrets.AWS_ECR }}
AWS_REGION: ${{ secrets.AWS_REGION }}

contents: read
30 changes: 16 additions & 14 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
# syntax=docker/dockerfile:1
FROM python:3.11-slim-bullseye
FROM ghcr.io/astral-sh/uv:python3.13-trixie-slim

RUN rm -f /etc/apt/apt.conf.d/docker-clean; \
echo 'Binary::apt::APT::Keep-Downloaded-Packages "true";' > /etc/apt/apt.conf.d/keep-cache
ENV UV_NO_DEV=1

RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
--mount=type=cache,target=/var/lib/apt,sharing=locked \
apt-get update -y && apt-get upgrade -y
WORKDIR /app

WORKDIR /CHANGME-component-name
ADD LICENSE.txt requirements.txt ./
ADD CHANGEME-module-name ./CHANGEME-module-name/
ADD pyproject.toml ./
RUN --mount=type=cache,target=/root/.cache/pip pip3 install -r requirements.txt .
# Install dependencies
RUN --mount=type=cache,target=/root/.cache/uv \
--mount=type=bind,source=uv.lock,target=uv.lock \
--mount=type=bind,source=pyproject.toml,target=pyproject.toml \
uv sync --frozen --no-install-project

# Change as required, eg
# CMD ["gunicorn", "-w", "2", "-b", "0.0.0.0", "-k", "uvicorn.workers.UvicornWorker", "--log-level", "debug", "mymodule.main:app"]
CMD python -m my.module
# Copy project files
COPY . /app

# Sync the project
RUN --mount=type=cache,target=/root/.cache/uv \
uv sync --frozen

# Change as required
CMD ["uv", "run", "--no-sync", "python", "-m", "my.module"]
74 changes: 36 additions & 38 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,58 +1,56 @@
.PHONY: dockerbuild dockerpush test testonce ruff black lint isort pre-commit-check requirements-update requirements setup
VERSION ?= latest
IMAGENAME = CHANGEME
DOCKERREPO ?= public.ecr.aws/n1b3o1k2/ukeodhp
DOCKERREPO ?= public.ecr.aws/eodh
uv-run ?= uv run --no-sync

.PHONY: dockerbuild
dockerbuild:
DOCKER_BUILDKIT=1 docker build -t ${IMAGENAME}:${VERSION} .

dockerpush: dockerbuild testdocker
.PHONY: dockerpush
dockerpush: dockerbuild
docker tag ${IMAGENAME}:${VERSION} ${DOCKERREPO}/${IMAGENAME}:${VERSION}
docker push ${DOCKERREPO}/${IMAGENAME}:${VERSION}

.PHONY: test
test:
./venv/bin/ptw CHANGEME-test-package-names
${uv-run} ptw CHANGEME-test-package-names

.PHONY: testonce
testonce:
./venv/bin/pytest
${uv-run} pytest

ruff:
./venv/bin/ruff check .

black:
./venv/bin/black .

isort:
./venv/bin/isort . --profile black

validate-pyproject:
validate-pyproject pyproject.toml

lint: ruff black isort validate-pyproject

requirements.txt: venv pyproject.toml
./venv/bin/pip-compile
.git/hooks/pre-commit:
${uv-run} pre-commit install
curl -o .pre-commit-config.yaml https://raw.githubusercontent.com/EO-DataHub/github-actions/main/.pre-commit-config-python.yaml

requirements-dev.txt: venv pyproject.toml
./venv/bin/pip-compile --extra dev -o requirements-dev.txt
.PHONY: setup
setup: update .git/hooks/pre-commit

requirements: requirements.txt requirements-dev.txt
.PHONY: pre-commit
pre-commit:
${uv-run} pre-commit

requirements-update: venv
./venv/bin/pip-compile -U
./venv/bin/pip-compile --extra dev -o requirements-dev.txt -U
.PHONY: pre-commit-all
pre-commit-all:
${uv-run} pre-commit run --all-files

venv:
virtualenv -p python3.11 venv
./venv/bin/python -m ensurepip -U
./venv/bin/pip3 install pip-tools
.PHONY: check
check:
${uv-run} ruff check
${uv-run} ruff format --check --diff
${uv-run} pyright
${uv-run} validate-pyproject pyproject.toml

.make-venv-installed: venv requirements.txt requirements-dev.txt
./venv/bin/pip3 install -r requirements.txt -r requirements-dev.txt
touch .make-venv-installed
.PHONY: format
format:
${uv-run} ruff check --fix
${uv-run} ruff format

.git/hooks/pre-commit:
./venv/bin/pre-commit install
curl -o .pre-commit-config.yaml https://raw.githubusercontent.com/EO-DataHub/github-actions/main/.pre-commit-config-python.yaml
.PHONY: install
install:
uv sync --frozen

setup: venv requirements .make-venv-installed .git/hooks/pre-commit
.PHONY: update
update:
uv sync
74 changes: 17 additions & 57 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,85 +15,45 @@ When using this template remember to:

## Getting started

### Prerequisites

Install the `uv` package manager by following the [official documentation](https://docs.astral.sh/uv/getting-started/installation/).

### Install via makefile

```commandline
make setup
```

This will create a virtual environment called `venv`, build `requirements.txt` and
`requirements-dev.txt` from `pyproject.toml` if they're out of date, install the Python
and Node dependencies and install `pre-commit`.

It's safe and fast to run `make setup` repeatedly as it will only update these things if
they have changed.

After `make setup` you can run `pre-commit` to run pre-commit checks on staged changes and
`pre-commit run --all-files` to run them on all files. This replicates the linter checks that
run from GitHub actions.


### Alternative installation

You will need Python 3.11. On Debian you may need:
* `sudo add-apt-repository -y 'deb http://ppa.launchpad.net/deadsnakes/ppa/ubuntu focal main'` (or `jammy` in place of `focal` for later Debian)
* `sudo apt update`
* `sudo apt install python3.11 python3.11-venv`

and on Ubuntu you may need
* `sudo add-apt-repository -y 'ppa:deadsnakes/ppa'`
* `sudo apt update`
* `sudo apt install python3.11 python3.11-venv`

To prepare running it:
This will create a Python virtual environment, install basic testing and linting
dependencies and install `pre-commit`.

* `virtualenv venv -p python3.11`
* `. venv/bin/activate`
* `rehash`
* `python -m ensurepip -U`
* `pip3 install -r requirements.txt`
* `pip3 install -r requirements-dev.txt`

You should also configure your IDE to use black so that code is automatically reformatted on save.
After `make setup` you can run `make check` to run linting and type checking.

## Building and testing

This component uses `pytest` tests and the `ruff` and `black` linters. `black` will reformat your code in an
opinionated way.
This component uses `pytest` tests and the `ruff` linter and `pyright` type checker.

See Makefile for all available commands.

A number of `make` targets are defined:
* `make test`: run tests continuously
* `make testonce`: run tests once
* `make lint`: lint and reformat
* `make check`: run linting and type checking
* `make format`: reformat code
* `make install`: install dependencies
* `make update`: update dependencies
* `make dockerbuild`: build a `latest` Docker image (use `make dockerbuild `VERSION=1.2.3` for a release image)
* `make dockerpush`: push a `latest` Docker image (again, you can add `VERSION=1.2.3`) - normally this should be done
only via the build system and its GitHub actions.

## Managing requirements

Requirements are specified in `pyproject.toml`, with development requirements listed separately. Specify version
constraints as necessary but not specific versions. After changing them:

* Run `pip-compile` (or `pip-compile -U` to upgrade requirements within constraints) to regenerate `requirements.txt`
* Run `pip-compile --extra dev -o requirements-dev.txt` (again, add `-U` to upgrade) to regenerate
`requirements-dev.txt`.
* Run the `pip3 install -r requirements.txt` and `pip3 install -r requirements-dev.txt` commands again and test.
* Commit these files.

If you see the error

```commandline
Backend subprocess exited when trying to invoke get_requires_for_build_wheel
Failed to parse /.../template-python/pyproject.toml
```

then install and run `validate-pyproject pyproject.toml` and/or `pip3 install .` to check its syntax.
## Managing dependencies

To check for vulnerable dependencies, run `pip-audit`.
To add a new dependency, run `uv add <dependency>` or see `uv help add`.

## Releasing

Ensure that `make lint` and `make test` work correctly and produce no further changes to code formatting before
Ensure that `make check` and `make test` work correctly and produce no further changes to code formatting before
continuing.

Releases tagged `latest` and targeted at development environments can be created from the `main` branch. Releases for
Expand Down
Empty file added app/__init__.py
Empty file.
6 changes: 6 additions & 0 deletions app/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
def main() -> None:
print("Hello, World!")


if __name__ == "__main__":
main()
Loading
Loading