diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000..ecf9ad20 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,14 @@ +.git/ + +**/*~ +**/.#* +**/*# +**/htmlcov +**/__pycache__ +**/*.pyc +**/.python-version +**/.env +**/.venv +**/venv +**/.coverage +**/*.egg-info/ diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..5a60f87a --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,13 @@ +version: 2 + +updates: + - package-ecosystem: "pip" + directory: "/" + schedule: + interval: "weekly" + open-pull-requests-limit: 20 + + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "monthly" diff --git a/.github/workflows/auto-merge-dependabot-prs.yml b/.github/workflows/auto-merge-dependabot-prs.yml new file mode 100644 index 00000000..7b01deac --- /dev/null +++ b/.github/workflows/auto-merge-dependabot-prs.yml @@ -0,0 +1,9 @@ +name: Auto merge Dependabot PRs + +on: pull_request + +jobs: + auto-merge-dependabot-prs: + uses: opensafely-core/.github/.github/workflows/auto-merge-dependabot-prs.yml@main + secrets: + token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 00000000..b55dce0d --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,40 @@ +--- +name: CI + +on: + push: + +jobs: + check: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - uses: "opensafely-core/setup-action@v1" + with: + python-version: "3.11" + install-just: true + - name: Check formatting, linting and import sorting + run: just check + + test: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - uses: "opensafely-core/setup-action@v1" + with: + python-version: "3.11" + install-just: true + - name: Run tests +# env: # Add environment variables required for tests + run: | + just test + + lint-dockerfile: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: hadolint/hadolint-action@54c9adbab1582c2ef04b2016b760714a4bfde3cf # v3.1.0 + with: + failure-threshold: error diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..13b2aaa4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,104 @@ +# Created by https://www.toptal.com/developers/gitignore/api/osx,macos,linux,windows +# Edit at https://www.toptal.com/developers/gitignore?templates=osx,macos,linux,windows + +### Linux ### +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +### macOS ### +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### OSX ### +# General + +# Icon must end with two \r + +# Thumbnails + +# Files that might appear in the root of a volume + +# Directories potentially created on remote AFP share + +### Windows ### +# Windows thumbnail cache files +Thumbs.db +Thumbs.db:encryptable +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +# End of https://www.toptal.com/developers/gitignore/api/osx,macos,linux,windows + +# Python +__pycache__ +.python-version +*.pyc + +# Coverage +.coverage +htmlcov + +# IDEs +.idea/ + + +# Virtual environments +.venv/ +venv/ + +.pytest-cache/ diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 00000000..a9dd67e9 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,35 @@ +default_language_version: + python: python3.11 + +repos: + - repo: local + hooks: + - id: black + name: black + entry: just black + language: system + types: [python] + require_serial: true + - id: ruff + name: ruff + entry: just ruff + language: system + types: [python] + require_serial: true + + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.1.0 + hooks: + - id: trailing-whitespace + - id: end-of-file-fixer + - id: debug-statements + - id: check-ast + - id: check-json + - id: check-toml + - id: check-yaml + - id: detect-private-key + + - repo: https://github.com/stratasan/hadolint-pre-commit + rev: cdefcb0 + hooks: + - id: hadolint diff --git a/DEVELOPERS.md b/DEVELOPERS.md new file mode 100644 index 00000000..c955e07d --- /dev/null +++ b/DEVELOPERS.md @@ -0,0 +1,34 @@ +# Notes for developers + +## System requirements + +### just + +```sh +# macOS +brew install just + +# Linux +# Install from https://github.com/casey/just/releases + +# Add completion for your shell. E.g. for bash: +source <(just --completions bash) + +# Show all available commands +just # shortcut for just --list +``` + + +## Local development environment + + +Set up a local development environment with: +``` +just dev_setup +``` + +## Tests +Run the tests with: +``` +just test +``` diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..a8888250 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,3 @@ +# All Dockerfiles should start from this base image +# Provide the TAG environment variable, or replace with the image version required +FROM ghcr.io/opensafely-core/base-docker:$TAG diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..c7901370 --- /dev/null +++ b/LICENSE @@ -0,0 +1,15 @@ +${GITHUB_REPOSITORY_NAME} +Copyright (C) University of Oxford + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . diff --git a/README.md b/README.md new file mode 100644 index 00000000..46ad3153 --- /dev/null +++ b/README.md @@ -0,0 +1,29 @@ +# metrics + +This is a template for an OpenSAFELY Core repository. + +Put your project description here. + +New repo checklist: +- [ ] Does the repo require a Dockerfile? + If not, delete: + - Dockerfile - + - .dockerignore + - hadolint pre-commit hook from `.pre-commit-config.yaml` + - `lint-dockerfile` action from `.github/workflows/main.yml` +- [ ] Is this a Django project? + If so, you probably need to add the following per-file ignores to `.flake8` + ``` + per-file-ignores = + manage.py:INP001 + gunicorn.conf.py:INP001 + ``` +- [ ] Will this project be installed with pip? + If so, delete `requirements.prod.in` and switch references in the `justfile` to `pyproject.toml` +- [ ] Update DEVELOPERS.md with any project-specific requirements and commands +- [ ] Update commands in `justfile` + + +## Developer docs + +Please see the [additional information](DEVELOPERS.md). diff --git a/justfile b/justfile new file mode 100644 index 00000000..982695ee --- /dev/null +++ b/justfile @@ -0,0 +1,168 @@ +export VIRTUAL_ENV := env_var_or_default("VIRTUAL_ENV", ".venv") + +export BIN := VIRTUAL_ENV + if os_family() == "unix" { "/bin" } else { "/Scripts" } +export PIP := BIN + if os_family() == "unix" { "/python -m pip" } else { "/python.exe -m pip" } + +export DEFAULT_PYTHON := if os_family() == "unix" { "python3.11" } else { "python" } + + +# list available commands +default: + @"{{ just_executable() }}" --list + + +# clean up temporary files +clean: + rm -rf .venv + + +# ensure valid virtualenv +virtualenv: + #!/usr/bin/env bash + set -euo pipefail + + # allow users to specify python version in .env + PYTHON_VERSION=${PYTHON_VERSION:-$DEFAULT_PYTHON} + + # create venv and upgrade pip + test -d $VIRTUAL_ENV || { $PYTHON_VERSION -m venv $VIRTUAL_ENV && $PIP install --upgrade pip; } + + # ensure we have pip-tools so we can run pip-compile + test -e $BIN/pip-compile || $PIP install pip-tools + + +_compile src dst *args: virtualenv + #!/usr/bin/env bash + set -euo pipefail + + # exit if src file is older than dst file (-nt = 'newer than', but we negate with || to avoid error exit code) + test "${FORCE:-}" = "true" -o {{ src }} -nt {{ dst }} || exit 0 + $BIN/pip-compile --allow-unsafe --generate-hashes --output-file={{ dst }} {{ src }} {{ args }} + + +# update requirements.prod.txt if requirements.prod.in has changed +requirements-prod *args: + "{{ just_executable() }}" _compile requirements.prod.in requirements.prod.txt {{ args }} + + +# update requirements.dev.txt if requirements.dev.in has changed +requirements-dev *args: requirements-prod + "{{ just_executable() }}" _compile requirements.dev.in requirements.dev.txt {{ args }} + + +# ensure prod requirements installed and up to date +prodenv: requirements-prod + #!/usr/bin/env bash + set -euo pipefail + + # exit if .txt file has not changed since we installed them (-nt == "newer than', but we negate with || to avoid error exit code) + test requirements.prod.txt -nt $VIRTUAL_ENV/.prod || exit 0 + + $PIP install -r requirements.prod.txt + touch $VIRTUAL_ENV/.prod + + +# && dependencies are run after the recipe has run. Needs just>=0.9.9. This is +# a killer feature over Makefiles. +# +# ensure dev requirements installed and up to date +devenv: prodenv requirements-dev && install-precommit + #!/usr/bin/env bash + set -euo pipefail + + # exit if .txt file has not changed since we installed them (-nt == "newer than', but we negate with || to avoid error exit code) + test requirements.dev.txt -nt $VIRTUAL_ENV/.dev || exit 0 + + $PIP install -r requirements.dev.txt + touch $VIRTUAL_ENV/.dev + + +# ensure precommit is installed +install-precommit: + #!/usr/bin/env bash + set -euo pipefail + + BASE_DIR=$(git rev-parse --show-toplevel) + test -f $BASE_DIR/.git/hooks/pre-commit || $BIN/pre-commit install + + +# upgrade dev or prod dependencies (specify package to upgrade single package, all by default) +upgrade env package="": virtualenv + #!/usr/bin/env bash + set -euo pipefail + + opts="--upgrade" + test -z "{{ package }}" || opts="--upgrade-package {{ package }}" + FORCE=true "{{ just_executable() }}" requirements-{{ env }} $opts + + +# *args is variadic, 0 or more. This allows us to do `just test -k match`, for example. +# Run the tests +test *args: devenv + $BIN/coverage run --module pytest {{ args }} + $BIN/coverage report || $BIN/coverage html + + +black *args=".": devenv + $BIN/black --check {{ args }} + +ruff *args=".": devenv + $BIN/ruff check {{ args }} + +# run the various dev checks but does not change any files +check: black ruff + + +# fix formatting and import sort ordering +fix: devenv + $BIN/black . + $BIN/ruff --fix . + + +# Run the dev project +run: devenv + echo "Not implemented yet" + + + +# Remove built assets and collected static files +assets-clean: + rm -rf assets/dist + rm -rf staticfiles + + +# Install the Node.js dependencies +assets-install: + #!/usr/bin/env bash + set -euo pipefail + + # exit if lock file has not changed since we installed them. -nt == "newer than", + # but we negate with || to avoid error exit code + test package-lock.json -nt node_modules/.written || exit 0 + + npm ci + touch node_modules/.written + + +# Build the Node.js assets +assets-build: + #!/usr/bin/env bash + set -euo pipefail + + # find files which are newer than dist/.written in the src directory. grep + # will exit with 1 if there are no files in the result. We negate this + # with || to avoid error exit code + # we wrap the find in an if in case dist/.written is missing so we don't + # trigger a failure prematurely + if test -f assets/dist/.written; then + find assets/src -type f -newer assets/dist/.written | grep -q . || exit 0 + fi + + npm run build + touch assets/dist/.written + + +assets: assets-install assets-build + + +assets-rebuild: assets-clean assets diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 00000000..02730826 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,46 @@ +[tool.coverage.run] +branch = true +dynamic_context = "test_function" +omit = [ + ".venv/*", +] + +[tool.coverage.report] +fail_under = 100 +skip_covered = true +show_missing = true + +[tool.coverage.html] +show_contexts = true + +[tool.pytest.ini_options] + +[tool.ruff] +line-length = 88 +exclude = [ + ".direnv", + ".git", + ".github", + ".ipynb_checkpoints", + ".pytest_cache", + ".venv", + "__pycache__", + "docker", + "htmlcov", + "venv", +] +extend-select = [ + "A", # flake8-builtins + "I", # isort + "INP", # flake8-no-pep420 + "ISC", # flake8-implicit-str-concat + "UP", # pyupgrade + "W", # pycodestyle warning +] +extend-ignore = [ + "E501", + "E731", +] + +[tool.ruff.isort] +lines-after-imports = 2 diff --git a/requirements.dev.in b/requirements.dev.in new file mode 100644 index 00000000..a0d01151 --- /dev/null +++ b/requirements.dev.in @@ -0,0 +1,13 @@ +--constraint requirements.prod.txt + +# Additional dev requirements +# To generate a requirements file that includes both prod and dev requirements, run: +# pip-compile --generate-hashes --output-file=requirements.dev.txt requirements.dev.in + +black +coverage +pip-tools +pre-commit +pytest +pyyaml==6.0.1 +ruff diff --git a/requirements.dev.txt b/requirements.dev.txt new file mode 100644 index 00000000..1ebdd3e5 --- /dev/null +++ b/requirements.dev.txt @@ -0,0 +1,240 @@ +# +# This file is autogenerated by pip-compile with Python 3.11 +# by the following command: +# +# pip-compile --allow-unsafe --generate-hashes --output-file=requirements.dev.txt requirements.dev.in +# +black==23.10.1 \ + --hash=sha256:037e9b4664cafda5f025a1728c50a9e9aedb99a759c89f760bd83730e76ba884 \ + --hash=sha256:1b917a2aa020ca600483a7b340c165970b26e9029067f019e3755b56e8dd5916 \ + --hash=sha256:1f8ce316753428ff68749c65a5f7844631aa18c8679dfd3ca9dc1a289979c258 \ + --hash=sha256:33d40f5b06be80c1bbce17b173cda17994fbad096ce60eb22054da021bf933d1 \ + --hash=sha256:3f157a8945a7b2d424da3335f7ace89c14a3b0625e6593d21139c2d8214d55ce \ + --hash=sha256:5ed45ac9a613fb52dad3b61c8dea2ec9510bf3108d4db88422bacc7d1ba1243d \ + --hash=sha256:6d23d7822140e3fef190734216cefb262521789367fbdc0b3f22af6744058982 \ + --hash=sha256:7670242e90dc129c539e9ca17665e39a146a761e681805c54fbd86015c7c84f7 \ + --hash=sha256:7b4d10b0f016616a0d93d24a448100adf1699712fb7a4efd0e2c32bbb219b173 \ + --hash=sha256:7cb5936e686e782fddb1c73f8aa6f459e1ad38a6a7b0e54b403f1f05a1507ee9 \ + --hash=sha256:7d56124b7a61d092cb52cce34182a5280e160e6aff3137172a68c2c2c4b76bcb \ + --hash=sha256:840015166dbdfbc47992871325799fd2dc0dcf9395e401ada6d88fe11498abad \ + --hash=sha256:9c74de4c77b849e6359c6f01987e94873c707098322b91490d24296f66d067dc \ + --hash=sha256:b15b75fc53a2fbcac8a87d3e20f69874d161beef13954747e053bca7a1ce53a0 \ + --hash=sha256:cfcce6f0a384d0da692119f2d72d79ed07c7159879d0bb1bb32d2e443382bf3a \ + --hash=sha256:d431e6739f727bb2e0495df64a6c7a5310758e87505f5f8cde9ff6c0f2d7e4fe \ + --hash=sha256:e293e4c2f4a992b980032bbd62df07c1bcff82d6964d6c9496f2cd726e246ace \ + --hash=sha256:ec3f8e6234c4e46ff9e16d9ae96f4ef69fa328bb4ad08198c8cee45bb1f08c69 + # via -r requirements.dev.in +build==0.8.0 \ + --hash=sha256:19b0ed489f92ace6947698c3ca8436cb0556a66e2aa2d34cd70e2a5d27cd0437 \ + --hash=sha256:887a6d471c901b1a6e6574ebaeeebb45e5269a79d095fe9a8f88d6614ed2e5f0 + # via pip-tools +cfgv==3.3.0 \ + --hash=sha256:9e600479b3b99e8af981ecdfc80a0296104ee610cab48a5ae4ffd0b668650eb1 \ + --hash=sha256:b449c9c6118fe8cca7fa5e00b9ec60ba08145d281d52164230a69211c5d597a1 + # via pre-commit +click==8.0.1 \ + --hash=sha256:8c04c11192119b1ef78ea049e0a6f0463e4c48ef00a30160c704337586f3ad7a \ + --hash=sha256:fba402a4a47334742d782209a7c79bc448911afe1149d07bdabdf480b3e2f4b6 + # via + # black + # pip-tools +coverage==7.3.2 \ + --hash=sha256:0cbf38419fb1a347aaf63481c00f0bdc86889d9fbf3f25109cf96c26b403fda1 \ + --hash=sha256:12d15ab5833a997716d76f2ac1e4b4d536814fc213c85ca72756c19e5a6b3d63 \ + --hash=sha256:149de1d2401ae4655c436a3dced6dd153f4c3309f599c3d4bd97ab172eaf02d9 \ + --hash=sha256:1981f785239e4e39e6444c63a98da3a1db8e971cb9ceb50a945ba6296b43f312 \ + --hash=sha256:2443cbda35df0d35dcfb9bf8f3c02c57c1d6111169e3c85fc1fcc05e0c9f39a3 \ + --hash=sha256:289fe43bf45a575e3ab10b26d7b6f2ddb9ee2dba447499f5401cfb5ecb8196bb \ + --hash=sha256:2f11cc3c967a09d3695d2a6f03fb3e6236622b93be7a4b5dc09166a861be6d25 \ + --hash=sha256:307adb8bd3abe389a471e649038a71b4eb13bfd6b7dd9a129fa856f5c695cf92 \ + --hash=sha256:310b3bb9c91ea66d59c53fa4989f57d2436e08f18fb2f421a1b0b6b8cc7fffda \ + --hash=sha256:315a989e861031334d7bee1f9113c8770472db2ac484e5b8c3173428360a9148 \ + --hash=sha256:3a4006916aa6fee7cd38db3bfc95aa9c54ebb4ffbfc47c677c8bba949ceba0a6 \ + --hash=sha256:3c7bba973ebee5e56fe9251300c00f1579652587a9f4a5ed8404b15a0471f216 \ + --hash=sha256:4175e10cc8dda0265653e8714b3174430b07c1dca8957f4966cbd6c2b1b8065a \ + --hash=sha256:43668cabd5ca8258f5954f27a3aaf78757e6acf13c17604d89648ecc0cc66640 \ + --hash=sha256:4cbae1051ab791debecc4a5dcc4a1ff45fc27b91b9aee165c8a27514dd160836 \ + --hash=sha256:5c913b556a116b8d5f6ef834038ba983834d887d82187c8f73dec21049abd65c \ + --hash=sha256:5f7363d3b6a1119ef05015959ca24a9afc0ea8a02c687fe7e2d557705375c01f \ + --hash=sha256:630b13e3036e13c7adc480ca42fa7afc2a5d938081d28e20903cf7fd687872e2 \ + --hash=sha256:72c0cfa5250f483181e677ebc97133ea1ab3eb68645e494775deb6a7f6f83901 \ + --hash=sha256:7dbc3ed60e8659bc59b6b304b43ff9c3ed858da2839c78b804973f613d3e92ed \ + --hash=sha256:88ed2c30a49ea81ea3b7f172e0269c182a44c236eb394718f976239892c0a27a \ + --hash=sha256:89a937174104339e3a3ffcf9f446c00e3a806c28b1841c63edb2b369310fd074 \ + --hash=sha256:9028a3871280110d6e1aa2df1afd5ef003bab5fb1ef421d6dc748ae1c8ef2ebc \ + --hash=sha256:99b89d9f76070237975b315b3d5f4d6956ae354a4c92ac2388a5695516e47c84 \ + --hash=sha256:9f805d62aec8eb92bab5b61c0f07329275b6f41c97d80e847b03eb894f38d083 \ + --hash=sha256:a889ae02f43aa45032afe364c8ae84ad3c54828c2faa44f3bfcafecb5c96b02f \ + --hash=sha256:aa72dbaf2c2068404b9870d93436e6d23addd8bbe9295f49cbca83f6e278179c \ + --hash=sha256:ac8c802fa29843a72d32ec56d0ca792ad15a302b28ca6203389afe21f8fa062c \ + --hash=sha256:ae97af89f0fbf373400970c0a21eef5aa941ffeed90aee43650b81f7d7f47637 \ + --hash=sha256:af3d828d2c1cbae52d34bdbb22fcd94d1ce715d95f1a012354a75e5913f1bda2 \ + --hash=sha256:b4275802d16882cf9c8b3d057a0839acb07ee9379fa2749eca54efbce1535b82 \ + --hash=sha256:b4767da59464bb593c07afceaddea61b154136300881844768037fd5e859353f \ + --hash=sha256:b631c92dfe601adf8f5ebc7fc13ced6bb6e9609b19d9a8cd59fa47c4186ad1ce \ + --hash=sha256:be32ad29341b0170e795ca590e1c07e81fc061cb5b10c74ce7203491484404ef \ + --hash=sha256:beaa5c1b4777f03fc63dfd2a6bd820f73f036bfb10e925fce067b00a340d0f3f \ + --hash=sha256:c0ba320de3fb8c6ec16e0be17ee1d3d69adcda99406c43c0409cb5c41788a611 \ + --hash=sha256:c9eacf273e885b02a0273bb3a2170f30e2d53a6d53b72dbe02d6701b5296101c \ + --hash=sha256:cb536f0dcd14149425996821a168f6e269d7dcd2c273a8bff8201e79f5104e76 \ + --hash=sha256:d1bc430677773397f64a5c88cb522ea43175ff16f8bfcc89d467d974cb2274f9 \ + --hash=sha256:d1c88ec1a7ff4ebca0219f5b1ef863451d828cccf889c173e1253aa84b1e07ce \ + --hash=sha256:d3d9df4051c4a7d13036524b66ecf7a7537d14c18a384043f30a303b146164e9 \ + --hash=sha256:d51ac2a26f71da1b57f2dc81d0e108b6ab177e7d30e774db90675467c847bbdf \ + --hash=sha256:d872145f3a3231a5f20fd48500274d7df222e291d90baa2026cc5152b7ce86bf \ + --hash=sha256:d8f17966e861ff97305e0801134e69db33b143bbfb36436efb9cfff6ec7b2fd9 \ + --hash=sha256:dbc1b46b92186cc8074fee9d9fbb97a9dd06c6cbbef391c2f59d80eabdf0faa6 \ + --hash=sha256:e10c39c0452bf6e694511c901426d6b5ac005acc0f78ff265dbe36bf81f808a2 \ + --hash=sha256:e267e9e2b574a176ddb983399dec325a80dbe161f1a32715c780b5d14b5f583a \ + --hash=sha256:f47d39359e2c3779c5331fc740cf4bce6d9d680a7b4b4ead97056a0ae07cb49a \ + --hash=sha256:f6e9589bd04d0461a417562649522575d8752904d35c12907d8c9dfeba588faf \ + --hash=sha256:f94b734214ea6a36fe16e96a70d941af80ff3bfd716c141300d95ebc85339738 \ + --hash=sha256:fa28e909776dc69efb6ed975a63691bc8172b64ff357e663a1bb06ff3c9b589a \ + --hash=sha256:fe494faa90ce6381770746077243231e0b83ff3f17069d748f645617cefe19d4 + # via -r requirements.dev.in +distlib==0.3.6 \ + --hash=sha256:14bad2d9b04d3a36127ac97f30b12a19268f211063d8f8ee4f47108896e11b46 \ + --hash=sha256:f35c4b692542ca110de7ef0bea44d73981caeb34ca0b9b6b2e6d7790dda8f80e + # via virtualenv +filelock==3.9.0 \ + --hash=sha256:7b319f24340b51f55a2bf7a12ac0755a9b03e718311dac567a0f4f7fabd2f5de \ + --hash=sha256:f58d535af89bb9ad5cd4df046f741f8553a418c01a7856bf0d173bbc9f6bd16d + # via virtualenv +identify==2.2.11 \ + --hash=sha256:7abaecbb414e385752e8ce02d8c494f4fbc780c975074b46172598a28f1ab839 \ + --hash=sha256:a0e700637abcbd1caae58e0463861250095dfe330a8371733a471af706a4a29a + # via pre-commit +iniconfig==1.1.1 \ + --hash=sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3 \ + --hash=sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32 + # via pytest +mypy-extensions==0.4.3 \ + --hash=sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d \ + --hash=sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8 + # via black +nodeenv==1.6.0 \ + --hash=sha256:3ef13ff90291ba2a4a7a4ff9a979b63ffdd00a464dbe04acf0ea6471517a4c2b \ + --hash=sha256:621e6b7076565ddcacd2db0294c0381e01fd28945ab36bcf00f41c5daf63bef7 + # via pre-commit +packaging==23.0 \ + --hash=sha256:714ac14496c3e68c99c29b00845f7a2b85f3bb6f1078fd9f72fd20f0570002b2 \ + --hash=sha256:b6ad297f8907de0fa2fe1ccbd26fdaf387f5f47c7275fedf8cce89f99446cf97 + # via + # black + # build + # pytest +pathspec==0.9.0 \ + --hash=sha256:7d15c4ddb0b5c802d161efc417ec1a2558ea2653c2e8ad9c19098201dc1c993a \ + --hash=sha256:e564499435a2673d586f6b2130bb5b95f04a3ba06f81b8f895b651a3c76aabb1 + # via black +pep517==0.11.0 \ + --hash=sha256:3fa6b85b9def7ba4de99fb7f96fe3f02e2d630df8aa2720a5cf3b183f087a738 \ + --hash=sha256:e1ba5dffa3a131387979a68ff3e391ac7d645be409216b961bc2efe6468ab0b2 + # via build +pip-tools==7.3.0 \ + --hash=sha256:8717693288720a8c6ebd07149c93ab0be1fced0b5191df9e9decd3263e20d85e \ + --hash=sha256:8e9c99127fe024c025b46a0b2d15c7bd47f18f33226cf7330d35493663fc1d1d + # via -r requirements.dev.in +platformdirs==2.6.2 \ + --hash=sha256:83c8f6d04389165de7c9b6f0c682439697887bca0aa2f1c87ef1826be3584490 \ + --hash=sha256:e1fea1fe471b9ff8332e229df3cb7de4f53eeea4998d3b6bfff542115e998bd2 + # via + # black + # virtualenv +pluggy==0.13.1 \ + --hash=sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0 \ + --hash=sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d + # via pytest +pre-commit==3.5.0 \ + --hash=sha256:5804465c675b659b0862f07907f96295d490822a450c4c40e747d0b1c6ebcb32 \ + --hash=sha256:841dc9aef25daba9a0238cd27984041fa0467b4199fc4852e27950664919f660 + # via -r requirements.dev.in +pytest==7.4.3 \ + --hash=sha256:0d009c083ea859a71b76adf7c1d502e4bc170b80a8ef002da5806527b9591fac \ + --hash=sha256:d989d136982de4e3b29dabcc838ad581c64e8ed52c11fbe86ddebd9da0818cd5 + # via -r requirements.dev.in +pyyaml==6.0.1 \ + --hash=sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc \ + --hash=sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741 \ + --hash=sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206 \ + --hash=sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27 \ + --hash=sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595 \ + --hash=sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62 \ + --hash=sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98 \ + --hash=sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696 \ + --hash=sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d \ + --hash=sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867 \ + --hash=sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47 \ + --hash=sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486 \ + --hash=sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6 \ + --hash=sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3 \ + --hash=sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007 \ + --hash=sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938 \ + --hash=sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c \ + --hash=sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735 \ + --hash=sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d \ + --hash=sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba \ + --hash=sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8 \ + --hash=sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5 \ + --hash=sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd \ + --hash=sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3 \ + --hash=sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0 \ + --hash=sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515 \ + --hash=sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c \ + --hash=sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c \ + --hash=sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924 \ + --hash=sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34 \ + --hash=sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43 \ + --hash=sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859 \ + --hash=sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673 \ + --hash=sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a \ + --hash=sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab \ + --hash=sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa \ + --hash=sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c \ + --hash=sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585 \ + --hash=sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d \ + --hash=sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f + # via + # -r requirements.dev.in + # pre-commit +ruff==0.1.3 \ + --hash=sha256:0b6c55f5ef8d9dd05b230bb6ab80bc4381ecb60ae56db0330f660ea240cb0d4a \ + --hash=sha256:0f75e670d529aa2288cd00fc0e9b9287603d95e1536d7a7e0cafe00f75e0dd9d \ + --hash=sha256:12fd53696c83a194a2db7f9a46337ce06445fb9aa7d25ea6f293cf75b21aca9f \ + --hash=sha256:1c595193881922cc0556a90f3af99b1c5681f0c552e7a2a189956141d8666fe8 \ + --hash=sha256:2e3de9ed2e39160800281848ff4670e1698037ca039bda7b9274f849258d26ce \ + --hash=sha256:3ba6145369a151401d5db79f0a47d50e470384d0d89d0d6f7fab0b589ad07c34 \ + --hash=sha256:3e7afcbdcfbe3399c34e0f6370c30f6e529193c731b885316c5a09c9e4317eef \ + --hash=sha256:4874c165f96c14a00590dcc727a04dca0cfd110334c24b039458c06cf78a672e \ + --hash=sha256:76dd49f6cd945d82d9d4a9a6622c54a994689d8d7b22fa1322983389b4892e20 \ + --hash=sha256:7a18df6638cec4a5bd75350639b2bb2a2366e01222825562c7346674bdceb7ea \ + --hash=sha256:918b454bc4f8874a616f0d725590277c42949431ceb303950e87fef7a7d94cb3 \ + --hash=sha256:b46d43d51f7061652eeadb426a9e3caa1e0002470229ab2fc19de8a7b0766901 \ + --hash=sha256:b8afeb9abd26b4029c72adc9921b8363374f4e7edb78385ffaa80278313a15f9 \ + --hash=sha256:ca3cf365bf32e9ba7e6db3f48a4d3e2c446cd19ebee04f05338bc3910114528b \ + --hash=sha256:d8859605e729cd5e53aa38275568dbbdb4fe882d2ea2714c5453b678dca83784 \ + --hash=sha256:dc3ec4edb3b73f21b4aa51337e16674c752f1d76a4a543af56d7d04e97769613 \ + --hash=sha256:eec2dd31eed114e48ea42dbffc443e9b7221976554a504767ceaee3dd38edeb8 + # via -r requirements.dev.in +tomli==1.1.0 \ + --hash=sha256:33d7984738f8bb699c9b0a816eb646a8178a69eaa792d258486776a5d21b8ca5 \ + --hash=sha256:f4a182048010e89cbec0ae4686b21f550a7f2903f665e34a6de58ec15424f919 + # via pep517 +virtualenv==20.17.1 \ + --hash=sha256:ce3b1684d6e1a20a3e5ed36795a97dfc6af29bc3970ca8dab93e11ac6094b3c4 \ + --hash=sha256:f8b927684efc6f1cc206c9db297a570ab9ad0e51c16fa9e45487d36d1905c058 + # via pre-commit +wheel==0.38.1 \ + --hash=sha256:7a95f9a8dc0924ef318bd55b616112c70903192f524d120acc614f59547a9e1f \ + --hash=sha256:ea041edf63f4ccba53ad6e035427997b3bb10ee88a4cd014ae82aeb9eea77bb9 + # via pip-tools + +# The following packages are considered to be unsafe in a requirements file: +pip==23.0.1 \ + --hash=sha256:236bcb61156d76c4b8a05821b988c7b8c35bf0da28a4b614e8d6ab5212c25c6f \ + --hash=sha256:cd015ea1bfb0fcef59d8a286c1f8bebcb983f6317719d415dc5351efb7cd7024 + # via pip-tools +setuptools==67.6.1 \ + --hash=sha256:257de92a9d50a60b8e22abfcbb771571fde0dbf3ec234463212027a4eeecbe9a \ + --hash=sha256:e728ca814a823bf7bf60162daf9db95b93d532948c4c0bea762ce62f60189078 + # via pip-tools diff --git a/requirements.prod.in b/requirements.prod.in new file mode 100644 index 00000000..06b80caa --- /dev/null +++ b/requirements.prod.in @@ -0,0 +1,4 @@ +# Main prod requirements + +# To generate requirements file, run: +# pip-compile --generate-hashes --output-file=requirements.prod.txt requirements.prod.in diff --git a/requirements.prod.txt b/requirements.prod.txt new file mode 100644 index 00000000..2a042f59 --- /dev/null +++ b/requirements.prod.txt @@ -0,0 +1,6 @@ +# +# This file is autogenerated by pip-compile with python 3.11 +# To update, run: +# +# pip-compile --allow-unsafe --generate-hashes --output-file=requirements.prod.txt requirements.prod.in +# diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 00000000..e69de29b