From fe93ea58cdf86ecc8902d760eba89bc83ea73c2b Mon Sep 17 00:00:00 2001
From: Callum Forrester <29771545+callumforrester@users.noreply.github.com>
Date: Tue, 30 May 2023 11:44:10 +0100
Subject: [PATCH] Move to python3-pip-skeleton (#21)
---
.devcontainer/devcontainer.json | 54 +
.dockerignore | 3 -
.gitattributes | 1 -
.github/CONTRIBUTING.rst | 35 +
.../actions/install_requirements/action.yml | 58 +
.github/dependabot.yml | 16 +
.github/pages/index.html | 8 +-
.github/pages/make_switcher.py | 99 ++
.github/workflows/code.yml | 230 ++--
.github/workflows/container.yml | 65 -
.github/workflows/docs.yml | 40 +-
.github/workflows/docs_clean.yml | 43 +
.github/workflows/linkcheck.yml | 22 +-
.gitignore | 14 +-
.gitlab-ci.yml | 4 -
.gitremotes | 1 -
.pre-commit-config.yaml | 13 +-
.vscode/extensions.json | 4 +-
.vscode/launch.json | 16 +-
.vscode/settings.json | 3 +-
.vscode/tasks.json | 4 +-
CONTRIBUTING.rst | 122 --
Dockerfile | 47 +-
Pipfile | 17 -
Pipfile.lock | 1120 -----------------
README.rst | 15 +-
docs/_static/theme_overrides.css | 34 -
docs/conf.py | 111 +-
docs/developer/explanations/decisions.rst | 17 +
.../0001-record-architecture-decisions.rst | 26 +
.../0002-switched-to-pip-skeleton.rst | 35 +
docs/developer/how-to/build-docs.rst | 38 +
docs/developer/how-to/contribute.rst | 1 +
docs/developer/how-to/lint.rst | 41 +
docs/developer/how-to/make-release.rst | 16 +
docs/developer/how-to/pin-requirements.rst | 74 ++
docs/developer/how-to/run-tests.rst | 12 +
docs/developer/how-to/static-analysis.rst | 8 +
docs/developer/how-to/test-container.rst | 25 +
docs/developer/how-to/update-tools.rst | 16 +
docs/developer/index.rst | 64 +
docs/developer/reference/standards.rst | 64 +
docs/developer/tutorials/dev-install.rst | 68 +
docs/explanations.rst | 11 -
docs/explanations/why-is-something-so.rst | 7 -
docs/genindex.rst | 5 +
docs/how-to.rst | 11 -
docs/how-to/accomplish-a-task.rst | 7 -
docs/index.rst | 51 +-
docs/reference.rst | 18 -
docs/reference/api.rst | 4 -
docs/reference/contributing.rst | 1 -
docs/tutorials.rst | 11 -
docs/tutorials/installation.rst | 48 -
docs/user/explanations/docs-structure.rst | 18 +
docs/user/how-to/run-container.rst | 15 +
docs/user/index.rst | 57 +
docs/user/reference/api.rst | 14 +
docs/user/tutorials/installation.rst | 38 +
pyproject.toml | 119 +-
setup.cfg | 96 --
setup.py | 13 -
src/hdf5_reader_service/__init__ copy.py | 5 +
src/hdf5_reader_service/__init__.py | 12 +-
src/hdf5_reader_service/__main__.py | 30 +
src/hdf5_reader_service/app.py | 12 +
src/hdf5_reader_service/main.py | 43 -
src/hdf5_reader_service/tasks/metadata.py | 1 -
src/hdf5_reader_service/tasks/shapes.py | 1 -
tests/test_boilerplate_removed copy.py | 97 ++
tests/test_boilerplate_removed.py | 69 +-
tests/test_cli.py | 12 +
tests/test_system.py | 16 +-
73 files changed, 1628 insertions(+), 1918 deletions(-)
create mode 100644 .devcontainer/devcontainer.json
delete mode 100644 .dockerignore
delete mode 100644 .gitattributes
create mode 100644 .github/CONTRIBUTING.rst
create mode 100644 .github/actions/install_requirements/action.yml
create mode 100644 .github/dependabot.yml
create mode 100755 .github/pages/make_switcher.py
delete mode 100644 .github/workflows/container.yml
create mode 100644 .github/workflows/docs_clean.yml
delete mode 100644 .gitlab-ci.yml
delete mode 100644 .gitremotes
delete mode 100644 CONTRIBUTING.rst
delete mode 100644 Pipfile
delete mode 100644 Pipfile.lock
delete mode 100644 docs/_static/theme_overrides.css
create mode 100644 docs/developer/explanations/decisions.rst
create mode 100644 docs/developer/explanations/decisions/0001-record-architecture-decisions.rst
create mode 100644 docs/developer/explanations/decisions/0002-switched-to-pip-skeleton.rst
create mode 100644 docs/developer/how-to/build-docs.rst
create mode 100644 docs/developer/how-to/contribute.rst
create mode 100644 docs/developer/how-to/lint.rst
create mode 100644 docs/developer/how-to/make-release.rst
create mode 100644 docs/developer/how-to/pin-requirements.rst
create mode 100644 docs/developer/how-to/run-tests.rst
create mode 100644 docs/developer/how-to/static-analysis.rst
create mode 100644 docs/developer/how-to/test-container.rst
create mode 100644 docs/developer/how-to/update-tools.rst
create mode 100644 docs/developer/index.rst
create mode 100644 docs/developer/reference/standards.rst
create mode 100644 docs/developer/tutorials/dev-install.rst
delete mode 100644 docs/explanations.rst
delete mode 100644 docs/explanations/why-is-something-so.rst
create mode 100644 docs/genindex.rst
delete mode 100644 docs/how-to.rst
delete mode 100644 docs/how-to/accomplish-a-task.rst
delete mode 100644 docs/reference.rst
delete mode 100644 docs/reference/api.rst
delete mode 100644 docs/reference/contributing.rst
delete mode 100644 docs/tutorials.rst
delete mode 100644 docs/tutorials/installation.rst
create mode 100644 docs/user/explanations/docs-structure.rst
create mode 100644 docs/user/how-to/run-container.rst
create mode 100644 docs/user/index.rst
create mode 100644 docs/user/reference/api.rst
create mode 100644 docs/user/tutorials/installation.rst
delete mode 100644 setup.cfg
delete mode 100644 setup.py
create mode 100644 src/hdf5_reader_service/__init__ copy.py
create mode 100644 src/hdf5_reader_service/__main__.py
create mode 100644 src/hdf5_reader_service/app.py
delete mode 100644 src/hdf5_reader_service/main.py
create mode 100644 tests/test_boilerplate_removed copy.py
create mode 100644 tests/test_cli.py
diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json
new file mode 100644
index 0000000..44de8d3
--- /dev/null
+++ b/.devcontainer/devcontainer.json
@@ -0,0 +1,54 @@
+// For format details, see https://containers.dev/implementors/json_reference/
+{
+ "name": "Python 3 Developer Container",
+ "build": {
+ "dockerfile": "../Dockerfile",
+ "target": "build",
+ // Only upgrade pip, we will install the project below
+ "args": {
+ "PIP_OPTIONS": "--upgrade pip"
+ }
+ },
+ "remoteEnv": {
+ "DISPLAY": "${localEnv:DISPLAY}"
+ },
+ // Add the URLs of features you want added when the container is built.
+ "features": {
+ "ghcr.io/devcontainers/features/common-utils:1": {
+ "username": "none",
+ "upgradePackages": false
+ }
+ },
+ // Set *default* container specific settings.json values on container create.
+ "settings": {
+ "python.defaultInterpreterPath": "/venv/bin/python"
+ },
+ "customizations": {
+ "vscode": {
+ // Add the IDs of extensions you want installed when the container is created.
+ "extensions": [
+ "ms-python.python",
+ "tamasfe.even-better-toml",
+ "redhat.vscode-yaml",
+ "ryanluker.vscode-coverage-gutters"
+ ]
+ }
+ },
+ // Make sure the files we are mapping into the container exist on the host
+ "initializeCommand": "bash -c 'for i in $HOME/.inputrc; do [ -f $i ] || touch $i; done'",
+ "runArgs": [
+ "--net=host",
+ "--security-opt=label=type:container_runtime_t"
+ ],
+ "mounts": [
+ "source=${localEnv:HOME}/.ssh,target=/root/.ssh,type=bind",
+ "source=${localEnv:HOME}/.inputrc,target=/root/.inputrc,type=bind",
+ // map in home directory - not strictly necessary but useful
+ "source=${localEnv:HOME},target=${localEnv:HOME},type=bind,consistency=cached"
+ ],
+ // make the workspace folder the same inside and outside of the container
+ "workspaceMount": "source=${localWorkspaceFolder},target=${localWorkspaceFolder},type=bind",
+ "workspaceFolder": "${localWorkspaceFolder}",
+ // After the container is created, install the python project in editable form
+ "postCreateCommand": "pip install -e '.[dev]'"
+}
diff --git a/.dockerignore b/.dockerignore
deleted file mode 100644
index a41848d..0000000
--- a/.dockerignore
+++ /dev/null
@@ -1,3 +0,0 @@
-**/.*
-**/*.pyc
-**/*.swp
diff --git a/.gitattributes b/.gitattributes
deleted file mode 100644
index 075748c..0000000
--- a/.gitattributes
+++ /dev/null
@@ -1 +0,0 @@
-src/*/_version_git.py export-subst
diff --git a/.github/CONTRIBUTING.rst b/.github/CONTRIBUTING.rst
new file mode 100644
index 0000000..173992d
--- /dev/null
+++ b/.github/CONTRIBUTING.rst
@@ -0,0 +1,35 @@
+Contributing to the project
+===========================
+
+Contributions and issues are most welcome! All issues and pull requests are
+handled through GitHub_. Also, please check for any existing issues before
+filing a new one. If you have a great idea but it involves big changes, please
+file a ticket before making a pull request! We want to make sure you don't spend
+your time coding something that might not fit the scope of the project.
+
+.. _GitHub: https://github.com/DiamondLightSource/hdf5-reader-service/issues
+
+Issue or Discussion?
+--------------------
+
+Github also offers discussions_ as a place to ask questions and share ideas. If
+your issue is open ended and it is not obvious when it can be "closed", please
+raise it as a discussion instead.
+
+.. _discussions: https://github.com/DiamondLightSource/hdf5-reader-service/discussions
+
+Code coverage
+-------------
+
+While 100% code coverage does not make a library bug-free, it significantly
+reduces the number of easily caught bugs! Please make sure coverage remains the
+same or is improved by a pull request!
+
+Developer guide
+---------------
+
+The `Developer Guide`_ contains information on setting up a development
+environment, running the tests and what standards the code and documentation
+should follow.
+
+.. _Developer Guide: https://diamondlightsource.github.io/hdf5-reader-service/main/developer/how-to/contribute.html
diff --git a/.github/actions/install_requirements/action.yml b/.github/actions/install_requirements/action.yml
new file mode 100644
index 0000000..25a146d
--- /dev/null
+++ b/.github/actions/install_requirements/action.yml
@@ -0,0 +1,58 @@
+name: Install requirements
+description: Run pip install with requirements and upload resulting requirements
+inputs:
+ requirements_file:
+ description: Name of requirements file to use and upload
+ required: true
+ install_options:
+ description: Parameters to pass to pip install
+ required: true
+ python_version:
+ description: Python version to install
+ default: "3.x"
+
+runs:
+ using: composite
+
+ steps:
+ - name: Setup python
+ uses: actions/setup-python@v4
+ with:
+ python-version: ${{ inputs.python_version }}
+
+ - name: Pip install
+ run: |
+ touch ${{ inputs.requirements_file }}
+ # -c uses requirements.txt as constraints, see 'Validate requirements file'
+ pip install -c ${{ inputs.requirements_file }} ${{ inputs.install_options }}
+ shell: bash
+
+ - name: Create lockfile
+ run: |
+ mkdir -p lockfiles
+ pip freeze --exclude-editable > lockfiles/${{ inputs.requirements_file }}
+ # delete the self referencing line and make sure it isn't blank
+ sed -i '/file:/d' lockfiles/${{ inputs.requirements_file }}
+ shell: bash
+
+ - name: Upload lockfiles
+ uses: actions/upload-artifact@v3
+ with:
+ name: lockfiles
+ path: lockfiles
+
+ # This eliminates the class of problems where the requirements being given no
+ # longer match what the packages themselves dictate. E.g. In the rare instance
+ # where I install some-package which used to depend on vulnerable-dependency
+ # but now uses good-dependency (despite being nominally the same version)
+ # pip will install both if given a requirements file with -r
+ - name: If requirements file exists, check it matches pip installed packages
+ run: |
+ if [ -s ${{ inputs.requirements_file }} ]; then
+ if ! diff -u ${{ inputs.requirements_file }} lockfiles/${{ inputs.requirements_file }}; then
+ echo "Error: ${{ inputs.requirements_file }} need the above changes to be exhaustive"
+ exit 1
+ fi
+ fi
+ shell: bash
+
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 0000000..fb7c6ee
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,16 @@
+# To get started with Dependabot version updates, you'll need to specify which
+# package ecosystems to update and where the package manifests are located.
+# Please see the documentation for all configuration options:
+# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
+
+version: 2
+updates:
+ - package-ecosystem: "github-actions"
+ directory: "/"
+ schedule:
+ interval: "weekly"
+
+ - package-ecosystem: "pip"
+ directory: "/"
+ schedule:
+ interval: "weekly"
diff --git a/.github/pages/index.html b/.github/pages/index.html
index 661903e..80f0a00 100644
--- a/.github/pages/index.html
+++ b/.github/pages/index.html
@@ -2,10 +2,10 @@
- Redirecting to master branch
-
-
-
+ Redirecting to main branch
+
+
+
\ No newline at end of file
diff --git a/.github/pages/make_switcher.py b/.github/pages/make_switcher.py
new file mode 100755
index 0000000..39c1277
--- /dev/null
+++ b/.github/pages/make_switcher.py
@@ -0,0 +1,99 @@
+import json
+import logging
+from argparse import ArgumentParser
+from pathlib import Path
+from subprocess import CalledProcessError, check_output
+from typing import List, Optional
+
+
+def report_output(stdout: bytes, label: str) -> List[str]:
+ ret = stdout.decode().strip().split("\n")
+ print(f"{label}: {ret}")
+ return ret
+
+
+def get_branch_contents(ref: str) -> List[str]:
+ """Get the list of directories in a branch."""
+ stdout = check_output(["git", "ls-tree", "-d", "--name-only", ref])
+ return report_output(stdout, "Branch contents")
+
+
+def get_sorted_tags_list() -> List[str]:
+ """Get a list of sorted tags in descending order from the repository."""
+ stdout = check_output(["git", "tag", "-l", "--sort=-v:refname"])
+ return report_output(stdout, "Tags list")
+
+
+def get_versions(ref: str, add: Optional[str], remove: Optional[str]) -> List[str]:
+ """Generate the file containing the list of all GitHub Pages builds."""
+ # Get the directories (i.e. builds) from the GitHub Pages branch
+ try:
+ builds = set(get_branch_contents(ref))
+ except CalledProcessError:
+ builds = set()
+ logging.warning(f"Cannot get {ref} contents")
+
+ # Add and remove from the list of builds
+ if add:
+ builds.add(add)
+ if remove:
+ assert remove in builds, f"Build '{remove}' not in {sorted(builds)}"
+ builds.remove(remove)
+
+ # Get a sorted list of tags
+ tags = get_sorted_tags_list()
+
+ # Make the sorted versions list from main branches and tags
+ versions: List[str] = []
+ for version in ["master", "main"] + tags:
+ if version in builds:
+ versions.append(version)
+ builds.remove(version)
+
+ # Add in anything that is left to the bottom
+ versions += sorted(builds)
+ print(f"Sorted versions: {versions}")
+ return versions
+
+
+def write_json(path: Path, repository: str, versions: str):
+ org, repo_name = repository.split("/")
+ struct = [
+ dict(version=version, url=f"https://{org}.github.io/{repo_name}/{version}/")
+ for version in versions
+ ]
+ text = json.dumps(struct, indent=2)
+ print(f"JSON switcher:\n{text}")
+ path.write_text(text)
+
+
+def main(args=None):
+ parser = ArgumentParser(
+ description="Make a versions.txt file from gh-pages directories"
+ )
+ parser.add_argument(
+ "--add",
+ help="Add this directory to the list of existing directories",
+ )
+ parser.add_argument(
+ "--remove",
+ help="Remove this directory from the list of existing directories",
+ )
+ parser.add_argument(
+ "repository",
+ help="The GitHub org and repository name: ORG/REPO",
+ )
+ parser.add_argument(
+ "output",
+ type=Path,
+ help="Path of write switcher.json to",
+ )
+ args = parser.parse_args(args)
+
+ # Write the versions file
+ versions = get_versions("origin/gh-pages", args.add, args.remove)
+ write_json(args.output, args.repository, versions)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/.github/workflows/code.yml b/.github/workflows/code.yml
index ed0131c..4a16984 100644
--- a/.github/workflows/code.yml
+++ b/.github/workflows/code.yml
@@ -2,80 +2,43 @@ name: Code CI
on:
push:
- branches:
- # Restricting to these branches and tags stops duplicate jobs on internal
- # PRs but stops CI running on internal branches without a PR. Delete the
- # next 5 lines to restore the original behaviour
- - master
- - main
- tags:
- - "*"
pull_request:
- schedule:
- # Run every Monday at 8am to check latest versions of dependencies
- - cron: "0 8 * * MON"
+env:
+ # The target python version, which must match the Dockerfile version
+ CONTAINER_PYTHON: "3.11"
jobs:
lint:
- runs-on: "ubuntu-latest"
- steps:
- - name: Run black, flake8, mypy
- uses: dls-controls/pipenv-run-action@v1
- with:
- pipenv-run: lint
- python-version: 3.9
-
- wheel:
- strategy:
- fail-fast: false
- matrix:
- os: ["ubuntu-latest"]
- python: ["3.9"]
+ # pull requests are a duplicate of a branch push if within the same repo.
+ if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.repository
+ runs-on: ubuntu-latest
- runs-on: ${{ matrix.os }}
steps:
- - uses: actions/checkout@v2
- with:
- fetch-depth: 0
-
- - name: Create Sdist and Wheel
- # Set SOURCE_DATE_EPOCH from git commit for reproducible build
- # https://reproducible-builds.org/
- # Set group writable and umask to do the same to match inside DLS
- run: |
- chmod -R g+w .
- umask 0002
- SOURCE_DATE_EPOCH=$(git log -1 --pretty=%ct) pipx run build --sdist --wheel
-
- - name: Upload Wheel and Sdist as artifacts
- uses: actions/upload-artifact@v2
- with:
- name: dist
- path: dist/*
+ - name: Checkout
+ uses: actions/checkout@v3
- - name: Install minimum python version
- uses: actions/setup-python@v2
+ - name: Install python packages
+ uses: ./.github/actions/install_requirements
with:
- python-version: ${{ matrix.python }}
+ requirements_file: requirements-dev-3.x.txt
+ install_options: -e .[dev]
- - name: Install wheel in a venv and check cli works
- # ${GITHUB_REPOSITORY##*/} is the repo name without org
- # Replace this with the cli command if different to the repo name
- run: pipx run --python $(which python${{ matrix.python }}) --spec dist/*.whl hdf5-reader-service --version
+ - name: Lint
+ run: tox -e pre-commit,mypy
test:
+ if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.repository
strategy:
fail-fast: false
matrix:
os: ["ubuntu-latest"] # can add windows-latest, macos-latest
- python: ["3.8", "3.9", "3.10"]
- pipenv: ["skip-lock"]
-
+ python: ["3.9", "3.10", "3.11"]
+ install: ["-e .[dev]"]
+ # Make one version be non-editable to test both paths of version code
include:
- # Add an extra Python3.9 runner to use the lockfile
- os: "ubuntu-latest"
python: "3.9"
- pipenv: "deploy"
+ install: ".[dev]"
runs-on: ${{ matrix.os }}
env:
@@ -83,43 +46,158 @@ jobs:
PY_IGNORE_IMPORTMISMATCH: "1"
steps:
- - name: Setup repo and test
- uses: dls-controls/pipenv-run-action@v1
+ - name: Checkout
+ uses: actions/checkout@v3
+ with:
+ # Need this to get version number from last tag
+ fetch-depth: 0
+
+ - name: Install python packages
+ uses: ./.github/actions/install_requirements
with:
- python-version: ${{ matrix.python }}
- pipenv-install: --dev --${{ matrix.pipenv }}
- allow-editable-installs: ${{ matrix.pipenv == 'deploy' }}
- pipenv-run: tests
+ python_version: ${{ matrix.python }}
+ requirements_file: requirements-test-${{ matrix.os }}-${{ matrix.python }}.txt
+ install_options: ${{ matrix.install }}
+
+ - name: List dependency tree
+ run: pipdeptree
+
+ - name: Run tests
+ run: pytest
- name: Upload coverage to Codecov
- uses: codecov/codecov-action@v2
+ uses: codecov/codecov-action@v3
with:
- name: ${{ matrix.python }}/${{ matrix.os }}/${{ matrix.pipenv }}
+ name: ${{ matrix.python }}/${{ matrix.os }}
files: cov.xml
- release:
- needs: [lint, wheel, test]
- runs-on: ubuntu-latest
- # upload to PyPI and make a release on every tag
- if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags')
+ dist:
+ if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.repository
+ runs-on: "ubuntu-latest"
+
steps:
- - uses: actions/download-artifact@v2
+ - name: Checkout
+ uses: actions/checkout@v3
+ with:
+ # Need this to get version number from last tag
+ fetch-depth: 0
+
+ - name: Build sdist and wheel
+ run: |
+ export SOURCE_DATE_EPOCH=$(git log -1 --pretty=%ct) && \
+ pipx run build
+
+ - name: Upload sdist and wheel as artifacts
+ uses: actions/upload-artifact@v3
with:
name: dist
path: dist
+ - name: Check for packaging errors
+ run: pipx run twine check --strict dist/*
+
+ - name: Install python packages
+ uses: ./.github/actions/install_requirements
+ with:
+ python_version: ${{env.CONTAINER_PYTHON}}
+ requirements_file: requirements.txt
+ install_options: dist/*.whl
+
+ - name: Test module --version works using the installed wheel
+ # If more than one module in src/ replace with module name to test
+ run: python -m $(ls src | head -1) --version
+
+ container:
+ needs: [lint, dist, test]
+ runs-on: ubuntu-latest
+
+ permissions:
+ contents: read
+ packages: write
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v3
+
+ # image names must be all lower case
+ - name: Generate image repo name
+ run: echo IMAGE_REPOSITORY=ghcr.io/$(tr '[:upper:]' '[:lower:]' <<< "${{ github.repository }}") >> $GITHUB_ENV
+
+ - name: Download wheel and lockfiles
+ uses: actions/download-artifact@v3
+ with:
+ path: artifacts/
+
+ - name: Log in to GitHub Docker Registry
+ if: github.event_name != 'pull_request'
+ uses: docker/login-action@v2
+ with:
+ registry: ghcr.io
+ username: ${{ github.actor }}
+ password: ${{ secrets.GITHUB_TOKEN }}
+
+ - name: Docker meta
+ id: meta
+ uses: docker/metadata-action@v4
+ with:
+ images: ${{ env.IMAGE_REPOSITORY }}
+ tags: |
+ type=ref,event=tag
+ type=raw,value=latest
+
+ - name: Set up Docker Buildx
+ id: buildx
+ uses: docker/setup-buildx-action@v2
+
+ - name: Build runtime image
+ uses: docker/build-push-action@v3
+ with:
+ build-args: |
+ PIP_OPTIONS=-r lockfiles/requirements.txt dist/*.whl
+ push: ${{ github.event_name == 'push' && startsWith(github.ref, 'refs/tags') }}
+ load: ${{ ! (github.event_name == 'push' && startsWith(github.ref, 'refs/tags')) }}
+ tags: ${{ steps.meta.outputs.tags }}
+ labels: ${{ steps.meta.outputs.labels }}
+ context: artifacts/
+ file: ./Dockerfile
+ # If you have a long docker build, uncomment the following to turn on caching
+ # For short build times this makes it a little slower
+ #cache-from: type=gha
+ #cache-to: type=gha,mode=max
+
+ - name: Test cli works in runtime image
+ run: docker run ${{ env.IMAGE_REPOSITORY }} --version
+
+ release:
+ # upload to PyPI and make a release on every tag
+ needs: [lint, dist, test]
+ if: ${{ github.event_name == 'push' && startsWith(github.ref, 'refs/tags') }}
+ runs-on: ubuntu-latest
+ env:
+ HAS_PYPI_TOKEN: ${{ secrets.PYPI_TOKEN != '' }}
+
+ steps:
+ - uses: actions/download-artifact@v3
+
+ - name: Fixup blank lockfiles
+ # Github release artifacts can't be blank
+ run: for f in lockfiles/*; do [ -s $f ] || echo '# No requirements' >> $f; done
+
- name: Github Release
# We pin to the SHA, not the tag, for security reasons.
# https://docs.github.com/en/actions/learn-github-actions/security-hardening-for-github-actions#using-third-party-actions
- uses: softprops/action-gh-release@1e07f4398721186383de40550babbdf2b84acfc5 # v0.1.14
+ uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # v0.1.15
with:
- files: dist/*
+ prerelease: ${{ contains(github.ref_name, 'a') || contains(github.ref_name, 'b') || contains(github.ref_name, 'rc') }}
+ files: |
+ dist/*
+ lockfiles/*
generate_release_notes: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Publish to PyPI
- env:
- TWINE_USERNAME: __token__
- TWINE_PASSWORD: ${{ secrets.pypi_token }}
- run: pipx run twine upload dist/*
+ if: ${{ env.HAS_PYPI_TOKEN }}
+ uses: pypa/gh-action-pypi-publish@release/v1
+ with:
+ password: ${{ secrets.PYPI_TOKEN }}
diff --git a/.github/workflows/container.yml b/.github/workflows/container.yml
deleted file mode 100644
index 1a3b0d8..0000000
--- a/.github/workflows/container.yml
+++ /dev/null
@@ -1,65 +0,0 @@
-
-
-name: Container CI
-
-on:
- push:
- branches:
- - master
- release:
- types: [published]
-
-jobs:
- build-image:
- timeout-minutes: 60
-
- runs-on: ubuntu-latest
- permissions:
- contents: read
- packages: write
-
- steps:
- - name: Checkout
- uses: actions/checkout@v2
-
- - name: Generate image tags
- id: tagger
- run: |
- # tag is branch name or tag if there is a tag
- echo ::set-output name=image_tag::${GITHUB_REF##*/}
- echo ::set-output name=do_push::true
-
- - name: Cache Docker layers
- uses: actions/cache@v2
- with:
- path: |
- ~/cache
- !~/cache/exclude
- key: ${{ runner.os }}-hdf5-reader-service-${{ github.sha }}
- restore-keys: ${{ runner.os }}-hdf5-reader-service-
-
- - name: Log in to Github Docker Registry
- uses: docker/login-action@v1
- with:
- registry: ghcr.io/hdf5-reader-service
- username: ${{ github.actor }}
- password: ${{ secrets.GITHUB_TOKEN }}
-
- - name: Set up Docker Buildx
- id: buildx
- uses: docker/setup-buildx-action@v1
-
- - id: read-docker-image-identifiers
- name: Read Docker Image Identifiers
- run: echo "IMAGE_REPOSITORY=$(echo ${{ github.repository }} | tr '[:upper:]' '[:lower:]')" >> $GITHUB_ENV
-
- - name: Run build (base container)
- uses: docker/build-push-action@v2
- with:
- builder: ${{ steps.buildx.output.name }}
- push: true
- tags: |
- ghcr.io/${{ env.IMAGE_REPOSITORY }}:${{ steps.tagger.outputs.image_tag }}
- target: base
- cache-from: type=local,src=~/cache
- cache-to: type=local,dest=~/cache
diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml
index 823ac9e..c510d57 100644
--- a/.github/workflows/docs.yml
+++ b/.github/workflows/docs.yml
@@ -2,16 +2,11 @@ name: Docs CI
on:
push:
- branches:
- # Add more branches here to publish docs from other branches
- - master
- - main
- tags:
- - "*"
pull_request:
jobs:
docs:
+ if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.repository
runs-on: ubuntu-latest
steps:
@@ -19,28 +14,39 @@ jobs:
if: startsWith(github.ref, 'refs/tags')
run: sleep 60
- - name: Install Packages
+ - name: Checkout
+ uses: actions/checkout@v3
+ with:
+ # Need this to get version number from last tag
+ fetch-depth: 0
+
+ - name: Install system packages
# Can delete this if you don't use graphviz in your docs
run: sudo apt-get install graphviz
- - name: Build docs
- uses: dls-controls/pipenv-run-action@v1
+ - name: Install python packages
+ uses: ./.github/actions/install_requirements
with:
- python-version: "3.9"
- pipenv-run: docs
+ requirements_file: requirements-dev-3.x.txt
+ install_options: -e .[dev]
+
+ - name: Build docs
+ run: tox -e docs
+
+ - name: Sanitize ref name for docs version
+ run: echo "DOCS_VERSION=${GITHUB_REF_NAME//[^A-Za-z0-9._-]/_}" >> $GITHUB_ENV
- name: Move to versioned directory
- # e.g. master or 0.1.2
- run: mv build/html ".github/pages/${GITHUB_REF##*/}"
+ run: mv build/html .github/pages/$DOCS_VERSION
- - name: Write versions.txt
- run: pipenv run sphinx_rtd_theme_github_versions .github/pages
+ - name: Write switcher.json
+ run: python .github/pages/make_switcher.py --add $DOCS_VERSION ${{ github.repository }} .github/pages/switcher.json
- name: Publish Docs to gh-pages
- if: github.event_name == 'push'
+ if: github.event_name == 'push' && github.actor != 'dependabot[bot]'
# We pin to the SHA, not the tag, for security reasons.
# https://docs.github.com/en/actions/learn-github-actions/security-hardening-for-github-actions#using-third-party-actions
- uses: peaceiris/actions-gh-pages@068dc23d9710f1ba62e86896f84735d869951305 # v3.8.0
+ uses: peaceiris/actions-gh-pages@64b46b4226a4a12da2239ba3ea5aa73e3163c75b # v3.9.1
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: .github/pages
diff --git a/.github/workflows/docs_clean.yml b/.github/workflows/docs_clean.yml
new file mode 100644
index 0000000..a67e188
--- /dev/null
+++ b/.github/workflows/docs_clean.yml
@@ -0,0 +1,43 @@
+name: Docs Cleanup CI
+
+# delete branch documentation when a branch is deleted
+# also allow manually deleting a documentation version
+on:
+ delete:
+ workflow_dispatch:
+ inputs:
+ version:
+ description: "documentation version to DELETE"
+ required: true
+ type: string
+
+jobs:
+ remove:
+ if: github.event.ref_type == 'branch' || github.event_name == 'workflow_dispatch'
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v3
+ with:
+ ref: gh-pages
+
+ - name: removing documentation for branch ${{ github.event.ref }}
+ if: ${{ github.event_name != 'workflow_dispatch' }}
+ run: echo "REF_NAME=${{ github.event.ref }}" >> $GITHUB_ENV
+
+ - name: manually removing documentation version ${{ github.event.inputs.version }}
+ if: ${{ github.event_name == 'workflow_dispatch' }}
+ run: echo "REF_NAME=${{ github.event.inputs.version }}" >> $GITHUB_ENV
+
+ - name: Sanitize ref name for docs version
+ run: echo "DOCS_VERSION=${REF_NAME//[^A-Za-z0-9._-]/_}" >> $GITHUB_ENV
+
+ - name: update index and push changes
+ run: |
+ rm -r $DOCS_VERSION
+ python make_switcher.py --remove $DOCS_VERSION ${{ github.repository }} switcher.json
+ git config --global user.name 'GitHub Actions Docs Cleanup CI'
+ git config --global user.email 'GithubActionsCleanup@noreply.github.com'
+ git commit -am "Removing redundant docs version $DOCS_VERSION"
+ git push
diff --git a/.github/workflows/linkcheck.yml b/.github/workflows/linkcheck.yml
index fce5d13..6b64fde 100644
--- a/.github/workflows/linkcheck.yml
+++ b/.github/workflows/linkcheck.yml
@@ -1,17 +1,27 @@
name: Link Check
on:
+ workflow_dispatch:
schedule:
- # Run every Monday at 8am to check URL links still resolve
- - cron: "0 8 * * MON"
+ # Run weekly to check URL links still resolve
+ - cron: "0 8 * * WED"
jobs:
docs:
runs-on: ubuntu-latest
steps:
- - name: Build docs
- uses: dls-controls/pipenv-run-action@v1
+ - name: Checkout
+ uses: actions/checkout@v3
+
+ - name: Install python packages
+ uses: ./.github/actions/install_requirements
with:
- python-version: "3.9"
- pipenv-run: docs -b linkcheck
+ requirements_file: requirements-dev-3.x.txt
+ install_options: -e .[dev]
+
+ - name: Check links
+ run: tox -e docs build -- -b linkcheck
+
+ - name: Keepalive Workflow
+ uses: gautamkrishnar/keepalive-workflow@v1
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index 0ce69d9..9fbb6bf 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,6 +8,7 @@ __pycache__/
# Distribution / packaging
.Python
env/
+.venv
build/
develop-eggs/
dist/
@@ -22,6 +23,7 @@ var/
*.egg-info/
.installed.cfg
*.egg
+**/_version.py
# PyInstaller
# Usually these files are written by a python script from a template
@@ -58,8 +60,10 @@ docs/_build/
# PyBuilder
target/
-# DLS build dir and virtual environment
-/prefix/
-/venv/
-/lightweight-venv/
-/installed.files
+# likely venv names
+.venv*
+venv*
+
+# further build artifacts
+lockfiles/
+
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
deleted file mode 100644
index 1efd502..0000000
--- a/.gitlab-ci.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-include:
- - project: 'controls/reports/ci_templates'
- ref: master
- file: 'python3/dls_py3_template.yml'
diff --git a/.gitremotes b/.gitremotes
deleted file mode 100644
index 09cb289..0000000
--- a/.gitremotes
+++ /dev/null
@@ -1 +0,0 @@
-github git@github.com:dls-controls/hdf5-reader-service.git
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index d081700..aa2a4cb 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -1,6 +1,6 @@
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
- rev: v2.3.0
+ rev: v4.4.0
hooks:
- id: check-added-large-files
- id: check-yaml
@@ -12,19 +12,12 @@ repos:
name: Run black
stages: [commit]
language: system
- entry: pipenv run black --check --diff
+ entry: black --check --diff
types: [python]
- id: flake8
name: Run flake8
stages: [commit]
language: system
- entry: pipenv run flake8
+ entry: flake8
types: [python]
-
- - id: mypy
- name: Run mypy
- stages: [commit]
- language: system
- entry: pipenv run mypy src tests
- pass_filenames: false
diff --git a/.vscode/extensions.json b/.vscode/extensions.json
index 734f215..8192299 100644
--- a/.vscode/extensions.json
+++ b/.vscode/extensions.json
@@ -1,7 +1,9 @@
{
"recommendations": [
- "ms-python.vscode-pylance",
+ "ms-vscode-remote.remote-containers",
"ms-python.python",
+ "tamasfe.even-better-toml",
+ "redhat.vscode-yaml",
"ryanluker.vscode-coverage-gutters"
]
}
\ No newline at end of file
diff --git a/.vscode/launch.json b/.vscode/launch.json
index 10a1641..f65cb37 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -9,29 +9,17 @@
"type": "python",
"request": "launch",
"justMyCode": false,
- "module": "pytest",
+ "program": "${file}",
"purpose": [
"debug-test"
],
"console": "integratedTerminal",
"env": {
- // The default config in setup.cfg's "[tool:pytest]" adds coverage.
+ // The default config in pyproject.toml's "[tool.pytest.ini_options]" adds coverage.
// Cannot have coverage and debugging at the same time.
// https://github.com/microsoft/vscode-python/issues/693
"PYTEST_ADDOPTS": "--no-cov"
},
- },
- {
- "name": "Python: FastAPI",
- "type": "python",
- "request": "launch",
- "module": "uvicorn",
- "args": [
- "hdf5_reader_service.main:app",
- "--reload",
- "--port", //these arg are optional
- "8000"
- ]
}
]
}
\ No newline at end of file
diff --git a/.vscode/settings.json b/.vscode/settings.json
index a8c6e16..2472acf 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -11,6 +11,5 @@
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.organizeImports": true
- },
- "esbonio.server.enabled": true
+ }
}
\ No newline at end of file
diff --git a/.vscode/tasks.json b/.vscode/tasks.json
index ff78a11..946e69d 100644
--- a/.vscode/tasks.json
+++ b/.vscode/tasks.json
@@ -5,8 +5,8 @@
"tasks": [
{
"type": "shell",
- "label": "Tests with coverage",
- "command": "pipenv run tests",
+ "label": "Tests, lint and docs",
+ "command": "tox -p",
"options": {
"cwd": "${workspaceRoot}"
},
diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst
deleted file mode 100644
index 3e50e8a..0000000
--- a/CONTRIBUTING.rst
+++ /dev/null
@@ -1,122 +0,0 @@
-Contributing
-============
-
-Contributions and issues are most welcome! All issues and pull requests are
-handled through GitHub_. Also, please check for any existing issues before
-filing a new one. If you have a great idea but it involves big changes, please
-file a ticket before making a pull request! We want to make sure you don't spend
-your time coding something that might not fit the scope of the project.
-
-.. _GitHub: https://github.com/DiamondLightSource/python-hdf5-reader-service/issues
-
-Running the tests
------------------
-
-To get the source source code and run the unit tests, run::
-
- $ git clone git://github.com/DiamondLightSource/python-hdf5-reader-service.git
- $ cd hdf5-reader-service
- $ pipenv install --dev
- $ pipenv run tests
-
-While 100% code coverage does not make a library bug-free, it significantly
-reduces the number of easily caught bugs! Please make sure coverage remains the
-same or is improved by a pull request!
-
-Code Styling
-------------
-
-The code in this repository conforms to standards set by the following tools:
-
-- black_ for code formatting
-- flake8_ for style checks
-- isort_ for import ordering
-- mypy_ for static type checking
-
-These checks will be run by pre-commit_. You can either choose to run these
-tests on all files tracked by git::
-
- $ pipenv run lint
-
-Or you can install a pre-commit hook that will run each time you do a ``git
-commit`` on just the files that have changed::
-
- $ pipenv run pre-commit install
-
-.. _black: https://github.com/psf/black
-.. _flake8: https://flake8.pycqa.org/en/latest/
-.. _isort: https://github.com/PyCQA/isort
-.. _mypy: https://github.com/python/mypy
-.. _pre-commit: https://pre-commit.com/
-
-Docstrings are pre-processed using the Sphinx Napoleon extension. As such,
-google-style_ is considered as standard for this repository. Please use type
-hints in the function signature for types. For example::
-
- def func(arg1: str, arg2: int) -> bool:
- """Summary line.
-
- Extended description of function.
-
- Args:
- arg1: Description of arg1
- arg2: Description of arg2
-
- Returns:
- Description of return value
- """
- return True
-
-.. _google-style: https://sphinxcontrib-napoleon.readthedocs.io/en/latest/index.html#google-vs-numpy
-
-Documentation
--------------
-
-Documentation is contained in the ``docs`` directory and extracted from
-docstrings of the API.
-
-Docs follow the underlining convention::
-
- Headling 1 (page title)
- =======================
-
- Heading 2
- ---------
-
- Heading 3
- ~~~~~~~~~
-
-You can build the docs from the project directory by running::
-
- $ pipenv run docs
- $ firefox build/html/index.html
-
-Release Process
----------------
-
-To make a new release, please follow this checklist:
-
-- Choose a new PEP440 compliant release number
-- Git tag the version
-- Push to GitHub and the actions will make a release on pypi
-- Push to internal gitlab and do a dls-release.py of the tag
-- Check and edit for clarity the autogenerated GitHub release_
-
-.. _release: https://github.com/DiamondLightSource/python-hdf5-reader-service/releases
-
-Updating the tools
-------------------
-
-This module is merged with the dls-python3-skeleton_. This is a generic
-Python project structure which provides a means to keep tools and
-techniques in sync between multiple Python projects. To update to the
-latest version of the skeleton, run::
-
- $ git pull https://github.com/dls-controls/dls-python3-skeleton skeleton
-
-Any merge conflicts will indicate an area where something has changed that
-conflicts with the setup of the current module. Check the `closed pull requests
-`_
-of the skeleton module for more details.
-
-.. _dls-python3-skeleton: https://dls-controls.github.io/dls-python3-skeleton
diff --git a/Dockerfile b/Dockerfile
index bd694ff..a184aff 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,24 +1,37 @@
-##### Shared Environment stage #########################################################
-FROM registry.hub.docker.com/library/python:3.9-slim AS base
+# This file is for use as a devcontainer and a runtime container
+#
+# The devcontainer should use the build target and run as root with podman
+# or docker with user namespaces.
+#
+FROM python:3.11 as build
-ENV PIP_DEPENDENCIES wheel pip
-ENV ENV_DIR /hdf5_reader_service
+ARG PIP_OPTIONS=.
-ENV VIRTUAL_ENV=/opt/venv
-RUN python3 -m venv $VIRTUAL_ENV
-ENV PATH="$VIRTUAL_ENV/bin:$PATH"
+# Add any system dependencies for the developer/build environment here e.g.
+# RUN apt-get update && apt-get upgrade -y && \
+# apt-get install -y --no-install-recommends \
+# desired-packages \
+# && rm -rf /var/lib/apt/lists/*
-# Install pip dependencies
-COPY requirements.txt .
-RUN python3.9 -m pip install --upgrade pip
-RUN python3.9 -m pip install -r requirements.txt
+# set up a virtual environment and put it in PATH
+RUN python -m venv /venv
+ENV PATH=/venv/bin:$PATH
-# Copy hdf5-reader-service code into container
-COPY . ${ENV_DIR}
+# Copy any required context for the pip install over
+COPY . /context
+WORKDIR /context
-ENV ENV_DIR /hdf5_reader_service
-WORKDIR ${ENV_DIR}
+# install python package into /venv
+RUN pip install ${PIP_OPTIONS}
-ENV PYTHON_SITE_PACKAGES /usr/local/lib/python3.9/site-packages
+FROM python:3.11-slim as runtime
-CMD ["hdf5-reader-service"]
+# Add apt-get system dependecies for runtime here if needed
+
+# copy the virtual environment from the build stage and put it in PATH
+COPY --from=build /venv/ /venv/
+ENV PATH=/venv/bin:$PATH
+
+# change this entrypoint if it is not the same as the repo
+ENTRYPOINT ["hdf5-reader-service"]
+CMD ["--version"]
diff --git a/Pipfile b/Pipfile
deleted file mode 100644
index d839649..0000000
--- a/Pipfile
+++ /dev/null
@@ -1,17 +0,0 @@
-[[source]]
-name = "pypi"
-url = "https://pypi.org/simple"
-verify_ssl = true
-
-[dev-packages]
-hdf5-reader-service = {editable = true, extras = ["dev"], path = "."}
-
-[packages]
-hdf5-reader-service = {editable = true, path = "."}
-
-[scripts]
-lint = "pre-commit run --all-files --show-diff-on-failure --color=always -v"
-tests = "pytest"
-docs = "sphinx-build -EWT --keep-going docs build/html"
-# Delete any files that git ignore hides from us
-gitclean = "git clean -fdX"
diff --git a/Pipfile.lock b/Pipfile.lock
deleted file mode 100644
index 624ff45..0000000
--- a/Pipfile.lock
+++ /dev/null
@@ -1,1120 +0,0 @@
-{
- "_meta": {
- "hash": {
- "sha256": "195dd5071397527423c4c78ae8fe9ebd8f91f2f98df3368fbb61b6ada651f926"
- },
- "pipfile-spec": 6,
- "requires": {},
- "sources": [
- {
- "name": "pypi",
- "url": "https://pypi.org/simple",
- "verify_ssl": true
- }
- ]
- },
- "default": {
- "anyio": {
- "hashes": [
- "sha256:a0aeffe2fb1fdf374a8e4b471444f0f3ac4fb9f5a5b542b48824475e0042a5a6",
- "sha256:b5fa16c5ff93fa1046f2eeb5bbff2dad4d3514d6cda61d02816dba34fa8c3c2e"
- ],
- "markers": "python_full_version >= '3.6.2'",
- "version": "==3.5.0"
- },
- "asgiref": {
- "hashes": [
- "sha256:2f8abc20f7248433085eda803936d98992f1343ddb022065779f37c5da0181d0",
- "sha256:88d59c13d634dcffe0510be048210188edd79aeccb6a6c9028cdad6f31d730a9"
- ],
- "markers": "python_version >= '3.7'",
- "version": "==3.5.0"
- },
- "click": {
- "hashes": [
- "sha256:6a7a62563bbfabfda3a38f3023a1db4a35978c0abd76f6c9605ecd6554d6d9b1",
- "sha256:8458d7b1287c5fb128c90e23381cf99dcde74beaf6c7ff6384ce84d6fe090adb"
- ],
- "markers": "python_version >= '3.6'",
- "version": "==8.0.4"
- },
- "fastapi": {
- "hashes": [
- "sha256:124774ce4cb3322841965f559669b233a0b8d343ea24fdd8b293253c077220d7",
- "sha256:43d12891b78fc497a50623e9c7c24640c569489f060acd9ce2c4902080487a93"
- ],
- "markers": "python_full_version >= '3.6.1'",
- "version": "==0.75.0"
- },
- "h11": {
- "hashes": [
- "sha256:70813c1135087a248a4d38cc0e1a0181ffab2188141a93eaf567940c3957ff06",
- "sha256:8ddd78563b633ca55346c8cd41ec0af27d3c79931828beffb46ce70a379e7442"
- ],
- "markers": "python_version >= '3.6'",
- "version": "==0.13.0"
- },
- "h5py": {
- "hashes": [
- "sha256:1c5acc660c458421e88c4c5fe092ce15923adfac4c732af1ac4fced683a5ea97",
- "sha256:35ab552c6f0a93365b3cb5664a5305f3920daa0a43deb5b2c547c52815ec46b9",
- "sha256:542781d50e1182b8fb619b1265dfe1c765e18215f818b0ab28b2983c28471325",
- "sha256:5996ff5adefd2d68c330a4265b6ef92e51b2fc674834a5990add5033bf109e20",
- "sha256:8752d2814a92aba4e2b2a5922d2782d0029102d99caaf3c201a566bc0b40db29",
- "sha256:8ecedf16c613973622a334701f67edcc0249469f9daa0576e994fb20ac0405db",
- "sha256:954c5c39a09b5302f69f752c3bbf165d368a65c8d200f7d5655e0fa6368a75e6",
- "sha256:98646e659bf8591a2177e12a4461dced2cad72da0ba4247643fd118db88880d2",
- "sha256:9f39242960b8d7f86f3056cc2546aa3047ff4835985f6483229af8f029e9c8db",
- "sha256:9fd8a14236fdd092a20c0bdf25c3aba3777718d266fabb0fdded4fcf252d1630",
- "sha256:a5320837c60870911645e9a935099bdb2be6a786fcf0dac5c860f3b679e2de55",
- "sha256:c9a5529343a619fea777b7caa27d493595b28b5af8b005e8d1817559fcccf493",
- "sha256:cd9447633b0bafaf82190d9a8d56f3cb2e8d30169483aee67d800816e028190a",
- "sha256:d8cacad89aa7daf3626fce106f7f2662ac35b14849df22d252d0d8fab9dc1c0b",
- "sha256:dbaa1ed9768bf9ff04af0919acc55746e62b28333644f0251f38768313f31745",
- "sha256:e2b49c48df05e19bb20b400b7ff7dc6f1ee36b84dc717c3771c468b33697b466"
- ],
- "markers": "python_version >= '3.7'",
- "version": "==3.6.0"
- },
- "hdf5-reader-service": {
- "editable": true,
- "path": "."
- },
- "idna": {
- "hashes": [
- "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff",
- "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d"
- ],
- "markers": "python_version >= '3.5'",
- "version": "==3.3"
- },
- "numpy": {
- "hashes": [
- "sha256:07a8c89a04997625236c5ecb7afe35a02af3896c8aa01890a849913a2309c676",
- "sha256:08d9b008d0156c70dc392bb3ab3abb6e7a711383c3247b410b39962263576cd4",
- "sha256:201b4d0552831f7250a08d3b38de0d989d6f6e4658b709a02a73c524ccc6ffce",
- "sha256:2c10a93606e0b4b95c9b04b77dc349b398fdfbda382d2a39ba5a822f669a0123",
- "sha256:3ca688e1b9b95d80250bca34b11a05e389b1420d00e87a0d12dc45f131f704a1",
- "sha256:48a3aecd3b997bf452a2dedb11f4e79bc5bfd21a1d4cc760e703c31d57c84b3e",
- "sha256:568dfd16224abddafb1cbcce2ff14f522abe037268514dd7e42c6776a1c3f8e5",
- "sha256:5bfb1bb598e8229c2d5d48db1860bcf4311337864ea3efdbe1171fb0c5da515d",
- "sha256:639b54cdf6aa4f82fe37ebf70401bbb74b8508fddcf4797f9fe59615b8c5813a",
- "sha256:8251ed96f38b47b4295b1ae51631de7ffa8260b5b087808ef09a39a9d66c97ab",
- "sha256:92bfa69cfbdf7dfc3040978ad09a48091143cffb778ec3b03fa170c494118d75",
- "sha256:97098b95aa4e418529099c26558eeb8486e66bd1e53a6b606d684d0c3616b168",
- "sha256:a3bae1a2ed00e90b3ba5f7bd0a7c7999b55d609e0c54ceb2b076a25e345fa9f4",
- "sha256:c34ea7e9d13a70bf2ab64a2532fe149a9aced424cd05a2c4ba662fd989e3e45f",
- "sha256:dbc7601a3b7472d559dc7b933b18b4b66f9aa7452c120e87dfb33d02008c8a18",
- "sha256:e7927a589df200c5e23c57970bafbd0cd322459aa7b1ff73b7c2e84d6e3eae62",
- "sha256:f8c1f39caad2c896bc0018f699882b345b2a63708008be29b1f355ebf6f933fe",
- "sha256:f950f8845b480cffe522913d35567e29dd381b0dc7e4ce6a4a9f9156417d2430",
- "sha256:fade0d4f4d292b6f39951b6836d7a3c7ef5b2347f3c420cd9820a1d90d794802",
- "sha256:fdf3c08bce27132395d3c3ba1503cac12e17282358cb4bddc25cc46b0aca07aa"
- ],
- "markers": "python_version >= '3.8'",
- "version": "==1.22.3"
- },
- "orjson": {
- "hashes": [
- "sha256:0a65f3c403f38b0117c6dd8e76e85a7bd51fcd92f06c5598dfeddbc44697d3e5",
- "sha256:2d5f45c6b85e5f14646df2d32ecd7ff20fcccc71c0ea1155f4d3df8c5299bbb7",
- "sha256:3af57ffab7848aaec6ba6b9e9b41331250b57bf696f9d502bacdc71a0ebab0ba",
- "sha256:3be045ca3b96119f592904cf34b962969ce97bd7843cbfca084009f6c8d2f268",
- "sha256:48c5831ec388b4e2682d4ff56d6bfa4a2ef76c963f5e75f4ff4785f9cf338a80",
- "sha256:4a2c7d0a236aaeab7f69c17b7ab4c078874e817da1bfbb9827cb8c73058b3050",
- "sha256:539cdc5067db38db27985e257772d073cd2eb9462d0a41bde96da4e4e60bd99b",
- "sha256:58f244775f20476e5851e7546df109f75160a5178d44257d437ba6d7e562bfe8",
- "sha256:5a50cde0dbbde255ce751fd1bca39d00ecd878ba0903c0480961b31984f2fab7",
- "sha256:612d242493afeeb2068bc72ff2544aa3b1e627578fcf92edee9daebb5893ffea",
- "sha256:63185af814c243fad7a72441e5f98120c9ecddf2675befa486d669fb65539e9b",
- "sha256:6c47cfca18e41f7f37b08ff3e7abf5ada2d0f27b5ade934f05be5fc5bb956e9d",
- "sha256:6d103b721bbc4f5703f62b3882e638c0b65fcdd48622531c7ffd45047ef8e87c",
- "sha256:70d0386abe02879ebaead2f9632dd2acb71000b4721fd8c1a2fb8c031a38d4d5",
- "sha256:7107a5673fd0b05adbb58bf71c1578fc84d662d29c096eb6d998982c8635c221",
- "sha256:7dd9e1e46c0776eee9e0649e3ae9584ea368d96851bcaeba18e217fa5d755283",
- "sha256:82515226ecb77689a029061552b5df1802b75d861780c401e96ca6bc8495f775",
- "sha256:913fac5d594ccabf5e8fbac15b9b3bb9c576d537d49eeec9f664e7a64dde4c4b",
- "sha256:93188a9d6eb566419ad48befa202dfe7cd7a161756444b99c4ec77faea9352a4",
- "sha256:a08b6940dd9a98ccf09785890112a0f81eadb4f35b51b9a80736d1725437e22c",
- "sha256:a4bb62b11289b7620eead2f25695212e9ac77fcfba76f050fa8a540fb5c32401",
- "sha256:a7297504d1142e7efa236ffc53f056d73934a993a08646dbcee89fc4308a8fcf",
- "sha256:b2da6fde42182b80b40df2e6ab855c55090ebfa3fcc21c182b7ad1762b61d55c",
- "sha256:bb68d0da349cf8a68971a48ad179434f75256159fe8b0715275d9b49fa23b7a3",
- "sha256:bd765c06c359d8a814b90f948538f957fa8a1f55ad1aaffcdc5771996aaea061",
- "sha256:c4b4f20a1e3df7e7c83717aff0ef4ab69e42ce2fb1f5234682f618153c458406",
- "sha256:cb10a20f80e95102dd35dfbc3a22531661b44a09b55236b012a446955846b023",
- "sha256:d21f9a2d1c30e58070f93988db4cad154b9009fafbde238b52c1c760e3607fbe",
- "sha256:d9a3288861bfd26f3511fb4081561ca768674612bac59513cb9081bb61fcc87f",
- "sha256:e152464c4606b49398afd911777decebcf9749cc8810c5b4199039e1afb0991e",
- "sha256:e6201494e8dff2ce7fd21da4e3f6dfca1a3fed38f9dcefc972f552f6596a7621",
- "sha256:f5d1648e5a9d1070f3628a69a7c6c17634dbb0caf22f2085eca6910f7427bf1f"
- ],
- "markers": "python_version >= '3.7'",
- "version": "==3.6.7"
- },
- "pydantic": {
- "hashes": [
- "sha256:085ca1de245782e9b46cefcf99deecc67d418737a1fd3f6a4f511344b613a5b3",
- "sha256:086254884d10d3ba16da0588604ffdc5aab3f7f09557b998373e885c690dd398",
- "sha256:0b6037175234850ffd094ca77bf60fb54b08b5b22bc85865331dd3bda7a02fa1",
- "sha256:0fe476769acaa7fcddd17cadd172b156b53546ec3614a4d880e5d29ea5fbce65",
- "sha256:1d5278bd9f0eee04a44c712982343103bba63507480bfd2fc2790fa70cd64cf4",
- "sha256:2cc6a4cb8a118ffec2ca5fcb47afbacb4f16d0ab8b7350ddea5e8ef7bcc53a16",
- "sha256:2ee7e3209db1e468341ef41fe263eb655f67f5c5a76c924044314e139a1103a2",
- "sha256:3011b975c973819883842c5ab925a4e4298dffccf7782c55ec3580ed17dc464c",
- "sha256:3c3b035103bd4e2e4a28da9da7ef2fa47b00ee4a9cf4f1a735214c1bcd05e0f6",
- "sha256:4c68c3bc88dbda2a6805e9a142ce84782d3930f8fdd9655430d8576315ad97ce",
- "sha256:574936363cd4b9eed8acdd6b80d0143162f2eb654d96cb3a8ee91d3e64bf4cf9",
- "sha256:5a79330f8571faf71bf93667d3ee054609816f10a259a109a0738dac983b23c3",
- "sha256:5e48ef4a8b8c066c4a31409d91d7ca372a774d0212da2787c0d32f8045b1e034",
- "sha256:6c5b77947b9e85a54848343928b597b4f74fc364b70926b3c4441ff52620640c",
- "sha256:742645059757a56ecd886faf4ed2441b9c0cd406079c2b4bee51bcc3fbcd510a",
- "sha256:7bdfdadb5994b44bd5579cfa7c9b0e1b0e540c952d56f627eb227851cda9db77",
- "sha256:815ddebb2792efd4bba5488bc8fde09c29e8ca3227d27cf1c6990fc830fd292b",
- "sha256:8b5ac0f1c83d31b324e57a273da59197c83d1bb18171e512908fe5dc7278a1d6",
- "sha256:96f240bce182ca7fe045c76bcebfa0b0534a1bf402ed05914a6f1dadff91877f",
- "sha256:a733965f1a2b4090a5238d40d983dcd78f3ecea221c7af1497b845a9709c1721",
- "sha256:ab624700dc145aa809e6f3ec93fb8e7d0f99d9023b713f6a953637429b437d37",
- "sha256:b2571db88c636d862b35090ccf92bf24004393f85c8870a37f42d9f23d13e032",
- "sha256:bbbc94d0c94dd80b3340fc4f04fd4d701f4b038ebad72c39693c794fd3bc2d9d",
- "sha256:c0727bda6e38144d464daec31dff936a82917f431d9c39c39c60a26567eae3ed",
- "sha256:c556695b699f648c58373b542534308922c46a1cda06ea47bc9ca45ef5b39ae6",
- "sha256:c86229333cabaaa8c51cf971496f10318c4734cf7b641f08af0a6fbf17ca3054",
- "sha256:c8d7da6f1c1049eefb718d43d99ad73100c958a5367d30b9321b092771e96c25",
- "sha256:c8e9dcf1ac499679aceedac7e7ca6d8641f0193c591a2d090282aaf8e9445a46",
- "sha256:cb23bcc093697cdea2708baae4f9ba0e972960a835af22560f6ae4e7e47d33f5",
- "sha256:d1e4c28f30e767fd07f2ddc6f74f41f034d1dd6bc526cd59e63a82fe8bb9ef4c",
- "sha256:d9c9bdb3af48e242838f9f6e6127de9be7063aad17b32215ccc36a09c5cf1070",
- "sha256:dee5ef83a76ac31ab0c78c10bd7d5437bfdb6358c95b91f1ba7ff7b76f9996a1",
- "sha256:e0896200b6a40197405af18828da49f067c2fa1f821491bc8f5bde241ef3f7d7",
- "sha256:f5a64b64ddf4c99fe201ac2724daada8595ada0d102ab96d019c1555c2d6441d",
- "sha256:f947352c3434e8b937e3aa8f96f47bdfe6d92779e44bb3f41e4c213ba6a32145"
- ],
- "markers": "python_full_version >= '3.6.1'",
- "version": "==1.9.0"
- },
- "sniffio": {
- "hashes": [
- "sha256:471b71698eac1c2112a40ce2752bb2f4a4814c22a54a3eed3676bc0f5ca9f663",
- "sha256:c4666eecec1d3f50960c6bdf61ab7bc350648da6c126e3cf6898d8cd4ddcd3de"
- ],
- "markers": "python_version >= '3.5'",
- "version": "==1.2.0"
- },
- "starlette": {
- "hashes": [
- "sha256:26a18cbda5e6b651c964c12c88b36d9898481cd428ed6e063f5f29c418f73050",
- "sha256:57eab3cc975a28af62f6faec94d355a410634940f10b30d68d31cb5ec1b44ae8"
- ],
- "markers": "python_version >= '3.6'",
- "version": "==0.17.1"
- },
- "typing-extensions": {
- "hashes": [
- "sha256:1a9462dcc3347a79b1f1c0271fbe79e844580bb598bafa1ed208b94da3cdcd42",
- "sha256:21c85e0fe4b9a155d0799430b0ad741cdce7e359660ccbd8b530613e8df88ce2"
- ],
- "markers": "python_version >= '3.6'",
- "version": "==4.1.1"
- },
- "uvicorn": {
- "hashes": [
- "sha256:19e2a0e96c9ac5581c01eb1a79a7d2f72bb479691acd2b8921fce48ed5b961a6",
- "sha256:5180f9d059611747d841a4a4c4ab675edf54c8489e97f96d0583ee90ac3bfc23"
- ],
- "markers": "python_version >= '3.7'",
- "version": "==0.17.6"
- }
- },
- "develop": {
- "alabaster": {
- "hashes": [
- "sha256:446438bdcca0e05bd45ea2de1668c1d9b032e1a9154c2c259092d77031ddd359",
- "sha256:a661d72d58e6ea8a57f7a86e37d86716863ee5e92788398526d58b26a4e4dc02"
- ],
- "version": "==0.7.12"
- },
- "anyio": {
- "hashes": [
- "sha256:a0aeffe2fb1fdf374a8e4b471444f0f3ac4fb9f5a5b542b48824475e0042a5a6",
- "sha256:b5fa16c5ff93fa1046f2eeb5bbff2dad4d3514d6cda61d02816dba34fa8c3c2e"
- ],
- "markers": "python_full_version >= '3.6.2'",
- "version": "==3.5.0"
- },
- "asgiref": {
- "hashes": [
- "sha256:2f8abc20f7248433085eda803936d98992f1343ddb022065779f37c5da0181d0",
- "sha256:88d59c13d634dcffe0510be048210188edd79aeccb6a6c9028cdad6f31d730a9"
- ],
- "markers": "python_version >= '3.7'",
- "version": "==3.5.0"
- },
- "attrs": {
- "hashes": [
- "sha256:2d27e3784d7a565d36ab851fe94887c5eccd6a463168875832a1be79c82828b4",
- "sha256:626ba8234211db98e869df76230a137c4c40a12d72445c45d5f5b716f076e2fd"
- ],
- "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
- "version": "==21.4.0"
- },
- "babel": {
- "hashes": [
- "sha256:ab49e12b91d937cd11f0b67cb259a57ab4ad2b59ac7a3b41d6c06c0ac5b0def9",
- "sha256:bc0c176f9f6a994582230df350aa6e05ba2ebe4b3ac317eab29d9be5d2768da0"
- ],
- "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
- "version": "==2.9.1"
- },
- "black": {
- "hashes": [
- "sha256:380f1b5da05e5a1429225676655dddb96f5ae8c75bdf91e53d798871b902a115",
- "sha256:7de4cfc7eb6b710de325712d40125689101d21d25283eed7e9998722cf10eb91"
- ],
- "markers": "python_full_version >= '3.6.2'",
- "version": "==21.9b0"
- },
- "certifi": {
- "hashes": [
- "sha256:78884e7c1d4b00ce3cea67b44566851c4343c120abd683433ce934a68ea58872",
- "sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569"
- ],
- "version": "==2021.10.8"
- },
- "cfgv": {
- "hashes": [
- "sha256:c6a0883f3917a037485059700b9e75da2464e6c27051014ad85ba6aaa5884426",
- "sha256:f5a830efb9ce7a445376bb66ec94c638a9787422f96264c98edc6bdeed8ab736"
- ],
- "markers": "python_full_version >= '3.6.1'",
- "version": "==3.3.1"
- },
- "charset-normalizer": {
- "hashes": [
- "sha256:2857e29ff0d34db842cd7ca3230549d1a697f96ee6d3fb071cfa6c7393832597",
- "sha256:6881edbebdb17b39b4eaaa821b438bf6eddffb4468cf344f09f89def34a8b1df"
- ],
- "markers": "python_version >= '3'",
- "version": "==2.0.12"
- },
- "click": {
- "hashes": [
- "sha256:6a7a62563bbfabfda3a38f3023a1db4a35978c0abd76f6c9605ecd6554d6d9b1",
- "sha256:8458d7b1287c5fb128c90e23381cf99dcde74beaf6c7ff6384ce84d6fe090adb"
- ],
- "markers": "python_version >= '3.6'",
- "version": "==8.0.4"
- },
- "coverage": {
- "extras": [
- "toml"
- ],
- "hashes": [
- "sha256:03e2a7826086b91ef345ff18742ee9fc47a6839ccd517061ef8fa1976e652ce9",
- "sha256:07e6db90cd9686c767dcc593dff16c8c09f9814f5e9c51034066cad3373b914d",
- "sha256:18d520c6860515a771708937d2f78f63cc47ab3b80cb78e86573b0a760161faf",
- "sha256:1ebf730d2381158ecf3dfd4453fbca0613e16eaa547b4170e2450c9707665ce7",
- "sha256:21b7745788866028adeb1e0eca3bf1101109e2dc58456cb49d2d9b99a8c516e6",
- "sha256:26e2deacd414fc2f97dd9f7676ee3eaecd299ca751412d89f40bc01557a6b1b4",
- "sha256:2c6dbb42f3ad25760010c45191e9757e7dce981cbfb90e42feef301d71540059",
- "sha256:2fea046bfb455510e05be95e879f0e768d45c10c11509e20e06d8fcaa31d9e39",
- "sha256:34626a7eee2a3da12af0507780bb51eb52dca0e1751fd1471d0810539cefb536",
- "sha256:37d1141ad6b2466a7b53a22e08fe76994c2d35a5b6b469590424a9953155afac",
- "sha256:46191097ebc381fbf89bdce207a6c107ac4ec0890d8d20f3360345ff5976155c",
- "sha256:4dd8bafa458b5c7d061540f1ee9f18025a68e2d8471b3e858a9dad47c8d41903",
- "sha256:4e21876082ed887baed0146fe222f861b5815455ada3b33b890f4105d806128d",
- "sha256:58303469e9a272b4abdb9e302a780072c0633cdcc0165db7eec0f9e32f901e05",
- "sha256:5ca5aeb4344b30d0bec47481536b8ba1181d50dbe783b0e4ad03c95dc1296684",
- "sha256:68353fe7cdf91f109fc7d474461b46e7f1f14e533e911a2a2cbb8b0fc8613cf1",
- "sha256:6f89d05e028d274ce4fa1a86887b071ae1755082ef94a6740238cd7a8178804f",
- "sha256:7a15dc0a14008f1da3d1ebd44bdda3e357dbabdf5a0b5034d38fcde0b5c234b7",
- "sha256:8bdde1177f2311ee552f47ae6e5aa7750c0e3291ca6b75f71f7ffe1f1dab3dca",
- "sha256:8ce257cac556cb03be4a248d92ed36904a59a4a5ff55a994e92214cde15c5bad",
- "sha256:8cf5cfcb1521dc3255d845d9dca3ff204b3229401994ef8d1984b32746bb45ca",
- "sha256:8fbbdc8d55990eac1b0919ca69eb5a988a802b854488c34b8f37f3e2025fa90d",
- "sha256:9548f10d8be799551eb3a9c74bbf2b4934ddb330e08a73320123c07f95cc2d92",
- "sha256:96f8a1cb43ca1422f36492bebe63312d396491a9165ed3b9231e778d43a7fca4",
- "sha256:9b27d894748475fa858f9597c0ee1d4829f44683f3813633aaf94b19cb5453cf",
- "sha256:9baff2a45ae1f17c8078452e9e5962e518eab705e50a0aa8083733ea7d45f3a6",
- "sha256:a2a8b8bcc399edb4347a5ca8b9b87e7524c0967b335fbb08a83c8421489ddee1",
- "sha256:acf53bc2cf7282ab9b8ba346746afe703474004d9e566ad164c91a7a59f188a4",
- "sha256:b0be84e5a6209858a1d3e8d1806c46214e867ce1b0fd32e4ea03f4bd8b2e3359",
- "sha256:b31651d018b23ec463e95cf10070d0b2c548aa950a03d0b559eaa11c7e5a6fa3",
- "sha256:b78e5afb39941572209f71866aa0b206c12f0109835aa0d601e41552f9b3e620",
- "sha256:c76aeef1b95aff3905fb2ae2d96e319caca5b76fa41d3470b19d4e4a3a313512",
- "sha256:dd035edafefee4d573140a76fdc785dc38829fe5a455c4bb12bac8c20cfc3d69",
- "sha256:dd6fe30bd519694b356cbfcaca9bd5c1737cddd20778c6a581ae20dc8c04def2",
- "sha256:e5f4e1edcf57ce94e5475fe09e5afa3e3145081318e5fd1a43a6b4539a97e518",
- "sha256:ec6bc7fe73a938933d4178c9b23c4e0568e43e220aef9472c4f6044bfc6dd0f0",
- "sha256:f1555ea6d6da108e1999b2463ea1003fe03f29213e459145e70edbaf3e004aaa",
- "sha256:f5fa5803f47e095d7ad8443d28b01d48c0359484fec1b9d8606d0e3282084bc4",
- "sha256:f7331dbf301b7289013175087636bbaf5b2405e57259dd2c42fdcc9fcc47325e",
- "sha256:f9987b0354b06d4df0f4d3e0ec1ae76d7ce7cbca9a2f98c25041eb79eec766f1",
- "sha256:fd9e830e9d8d89b20ab1e5af09b32d33e1a08ef4c4e14411e559556fd788e6b2"
- ],
- "markers": "python_version >= '3.7'",
- "version": "==6.3.2"
- },
- "distlib": {
- "hashes": [
- "sha256:6564fe0a8f51e734df6333d08b8b94d4ea8ee6b99b5ed50613f731fd4089f34b",
- "sha256:e4b58818180336dc9c529bfb9a0b58728ffc09ad92027a3f30b7cd91e3458579"
- ],
- "version": "==0.3.4"
- },
- "docutils": {
- "hashes": [
- "sha256:686577d2e4c32380bb50cbb22f575ed742d58168cee37e99117a854bcd88f125",
- "sha256:cf316c8370a737a022b72b56874f6602acf974a37a9fba42ec2876387549fc61"
- ],
- "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
- "version": "==0.17.1"
- },
- "fastapi": {
- "hashes": [
- "sha256:124774ce4cb3322841965f559669b233a0b8d343ea24fdd8b293253c077220d7",
- "sha256:43d12891b78fc497a50623e9c7c24640c569489f060acd9ce2c4902080487a93"
- ],
- "markers": "python_full_version >= '3.6.1'",
- "version": "==0.75.0"
- },
- "filelock": {
- "hashes": [
- "sha256:9cd540a9352e432c7246a48fe4e8712b10acb1df2ad1f30e8c070b82ae1fed85",
- "sha256:f8314284bfffbdcfa0ff3d7992b023d4c628ced6feb957351d4c48d059f56bc0"
- ],
- "markers": "python_version >= '3.7'",
- "version": "==3.6.0"
- },
- "flake8": {
- "hashes": [
- "sha256:479b1304f72536a55948cb40a32dce8bb0ffe3501e26eaf292c7e60eb5e0428d",
- "sha256:806e034dda44114815e23c16ef92f95c91e4c71100ff52813adf7132a6ad870d"
- ],
- "markers": "python_version >= '3.6'",
- "version": "==4.0.1"
- },
- "flake8-isort": {
- "hashes": [
- "sha256:c4e8b6dcb7be9b71a02e6e5d4196cefcef0f3447be51e82730fb336fff164949",
- "sha256:d814304ab70e6e58859bc5c3e221e2e6e71c958e7005239202fee19c24f82717"
- ],
- "version": "==4.1.1"
- },
- "h11": {
- "hashes": [
- "sha256:70813c1135087a248a4d38cc0e1a0181ffab2188141a93eaf567940c3957ff06",
- "sha256:8ddd78563b633ca55346c8cd41ec0af27d3c79931828beffb46ce70a379e7442"
- ],
- "markers": "python_version >= '3.6'",
- "version": "==0.13.0"
- },
- "h5py": {
- "hashes": [
- "sha256:1c5acc660c458421e88c4c5fe092ce15923adfac4c732af1ac4fced683a5ea97",
- "sha256:35ab552c6f0a93365b3cb5664a5305f3920daa0a43deb5b2c547c52815ec46b9",
- "sha256:542781d50e1182b8fb619b1265dfe1c765e18215f818b0ab28b2983c28471325",
- "sha256:5996ff5adefd2d68c330a4265b6ef92e51b2fc674834a5990add5033bf109e20",
- "sha256:8752d2814a92aba4e2b2a5922d2782d0029102d99caaf3c201a566bc0b40db29",
- "sha256:8ecedf16c613973622a334701f67edcc0249469f9daa0576e994fb20ac0405db",
- "sha256:954c5c39a09b5302f69f752c3bbf165d368a65c8d200f7d5655e0fa6368a75e6",
- "sha256:98646e659bf8591a2177e12a4461dced2cad72da0ba4247643fd118db88880d2",
- "sha256:9f39242960b8d7f86f3056cc2546aa3047ff4835985f6483229af8f029e9c8db",
- "sha256:9fd8a14236fdd092a20c0bdf25c3aba3777718d266fabb0fdded4fcf252d1630",
- "sha256:a5320837c60870911645e9a935099bdb2be6a786fcf0dac5c860f3b679e2de55",
- "sha256:c9a5529343a619fea777b7caa27d493595b28b5af8b005e8d1817559fcccf493",
- "sha256:cd9447633b0bafaf82190d9a8d56f3cb2e8d30169483aee67d800816e028190a",
- "sha256:d8cacad89aa7daf3626fce106f7f2662ac35b14849df22d252d0d8fab9dc1c0b",
- "sha256:dbaa1ed9768bf9ff04af0919acc55746e62b28333644f0251f38768313f31745",
- "sha256:e2b49c48df05e19bb20b400b7ff7dc6f1ee36b84dc717c3771c468b33697b466"
- ],
- "markers": "python_version >= '3.7'",
- "version": "==3.6.0"
- },
- "hdf5-reader-service": {
- "editable": true,
- "path": "."
- },
- "identify": {
- "hashes": [
- "sha256:3f3244a559290e7d3deb9e9adc7b33594c1bc85a9dd82e0f1be519bf12a1ec17",
- "sha256:5f06b14366bd1facb88b00540a1de05b69b310cbc2654db3c7e07fa3a4339323"
- ],
- "markers": "python_version >= '3.7'",
- "version": "==2.4.12"
- },
- "idna": {
- "hashes": [
- "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff",
- "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d"
- ],
- "markers": "python_version >= '3.5'",
- "version": "==3.3"
- },
- "imagesize": {
- "hashes": [
- "sha256:1db2f82529e53c3e929e8926a1fa9235aa82d0bd0c580359c67ec31b2fddaa8c",
- "sha256:cd1750d452385ca327479d45b64d9c7729ecf0b3969a58148298c77092261f9d"
- ],
- "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
- "version": "==1.3.0"
- },
- "importlib-metadata": {
- "hashes": [
- "sha256:1208431ca90a8cca1a6b8af391bb53c1a2db74e5d1cef6ddced95d4b2062edc6",
- "sha256:ea4c597ebf37142f827b8f39299579e31685c31d3a438b59f469406afd0f2539"
- ],
- "markers": "python_version < '3.10'",
- "version": "==4.11.3"
- },
- "iniconfig": {
- "hashes": [
- "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3",
- "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"
- ],
- "version": "==1.1.1"
- },
- "isort": {
- "hashes": [
- "sha256:6f62d78e2f89b4500b080fe3a81690850cd254227f27f75c3a0c491a1f351ba7",
- "sha256:e8443a5e7a020e9d7f97f1d7d9cd17c88bcb3bc7e218bf9cf5095fe550be2951"
- ],
- "markers": "python_full_version >= '3.6.1' and python_version < '4.0'",
- "version": "==5.10.1"
- },
- "jinja2": {
- "hashes": [
- "sha256:077ce6014f7b40d03b47d1f1ca4b0fc8328a692bd284016f806ed0eaca390ad8",
- "sha256:611bb273cd68f3b993fabdc4064fc858c5b47a973cb5aa7999ec1ba405c87cd7"
- ],
- "markers": "python_version >= '3.6'",
- "version": "==3.0.3"
- },
- "markupsafe": {
- "hashes": [
- "sha256:0212a68688482dc52b2d45013df70d169f542b7394fc744c02a57374a4207003",
- "sha256:089cf3dbf0cd6c100f02945abeb18484bd1ee57a079aefd52cffd17fba910b88",
- "sha256:10c1bfff05d95783da83491be968e8fe789263689c02724e0c691933c52994f5",
- "sha256:33b74d289bd2f5e527beadcaa3f401e0df0a89927c1559c8566c066fa4248ab7",
- "sha256:3799351e2336dc91ea70b034983ee71cf2f9533cdff7c14c90ea126bfd95d65a",
- "sha256:3ce11ee3f23f79dbd06fb3d63e2f6af7b12db1d46932fe7bd8afa259a5996603",
- "sha256:421be9fbf0ffe9ffd7a378aafebbf6f4602d564d34be190fc19a193232fd12b1",
- "sha256:43093fb83d8343aac0b1baa75516da6092f58f41200907ef92448ecab8825135",
- "sha256:46d00d6cfecdde84d40e572d63735ef81423ad31184100411e6e3388d405e247",
- "sha256:4a33dea2b688b3190ee12bd7cfa29d39c9ed176bda40bfa11099a3ce5d3a7ac6",
- "sha256:4b9fe39a2ccc108a4accc2676e77da025ce383c108593d65cc909add5c3bd601",
- "sha256:56442863ed2b06d19c37f94d999035e15ee982988920e12a5b4ba29b62ad1f77",
- "sha256:671cd1187ed5e62818414afe79ed29da836dde67166a9fac6d435873c44fdd02",
- "sha256:694deca8d702d5db21ec83983ce0bb4b26a578e71fbdbd4fdcd387daa90e4d5e",
- "sha256:6a074d34ee7a5ce3effbc526b7083ec9731bb3cbf921bbe1d3005d4d2bdb3a63",
- "sha256:6d0072fea50feec76a4c418096652f2c3238eaa014b2f94aeb1d56a66b41403f",
- "sha256:6fbf47b5d3728c6aea2abb0589b5d30459e369baa772e0f37a0320185e87c980",
- "sha256:7f91197cc9e48f989d12e4e6fbc46495c446636dfc81b9ccf50bb0ec74b91d4b",
- "sha256:86b1f75c4e7c2ac2ccdaec2b9022845dbb81880ca318bb7a0a01fbf7813e3812",
- "sha256:8dc1c72a69aa7e082593c4a203dcf94ddb74bb5c8a731e4e1eb68d031e8498ff",
- "sha256:8e3dcf21f367459434c18e71b2a9532d96547aef8a871872a5bd69a715c15f96",
- "sha256:8e576a51ad59e4bfaac456023a78f6b5e6e7651dcd383bcc3e18d06f9b55d6d1",
- "sha256:96e37a3dc86e80bf81758c152fe66dbf60ed5eca3d26305edf01892257049925",
- "sha256:97a68e6ada378df82bc9f16b800ab77cbf4b2fada0081794318520138c088e4a",
- "sha256:99a2a507ed3ac881b975a2976d59f38c19386d128e7a9a18b7df6fff1fd4c1d6",
- "sha256:a49907dd8420c5685cfa064a1335b6754b74541bbb3706c259c02ed65b644b3e",
- "sha256:b09bf97215625a311f669476f44b8b318b075847b49316d3e28c08e41a7a573f",
- "sha256:b7bd98b796e2b6553da7225aeb61f447f80a1ca64f41d83612e6139ca5213aa4",
- "sha256:b87db4360013327109564f0e591bd2a3b318547bcef31b468a92ee504d07ae4f",
- "sha256:bcb3ed405ed3222f9904899563d6fc492ff75cce56cba05e32eff40e6acbeaa3",
- "sha256:d4306c36ca495956b6d568d276ac11fdd9c30a36f1b6eb928070dc5360b22e1c",
- "sha256:d5ee4f386140395a2c818d149221149c54849dfcfcb9f1debfe07a8b8bd63f9a",
- "sha256:dda30ba7e87fbbb7eab1ec9f58678558fd9a6b8b853530e176eabd064da81417",
- "sha256:e04e26803c9c3851c931eac40c695602c6295b8d432cbe78609649ad9bd2da8a",
- "sha256:e1c0b87e09fa55a220f058d1d49d3fb8df88fbfab58558f1198e08c1e1de842a",
- "sha256:e72591e9ecd94d7feb70c1cbd7be7b3ebea3f548870aa91e2732960fa4d57a37",
- "sha256:e8c843bbcda3a2f1e3c2ab25913c80a3c5376cd00c6e8c4a86a89a28c8dc5452",
- "sha256:efc1913fd2ca4f334418481c7e595c00aad186563bbc1ec76067848c7ca0a933",
- "sha256:f121a1420d4e173a5d96e47e9a0c0dcff965afdf1626d28de1460815f7c4ee7a",
- "sha256:fc7b548b17d238737688817ab67deebb30e8073c95749d55538ed473130ec0c7"
- ],
- "markers": "python_version >= '3.7'",
- "version": "==2.1.1"
- },
- "mccabe": {
- "hashes": [
- "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42",
- "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"
- ],
- "version": "==0.6.1"
- },
- "mypy": {
- "hashes": [
- "sha256:080097eee5393fd740f32c63f9343580aaa0fb1cda0128fd859dfcf081321c3d",
- "sha256:0d3bcbe146247997e03bf030122000998b076b3ac6925b0b6563f46d1ce39b50",
- "sha256:0dd441fbacf48e19dc0c5c42fafa72b8e1a0ba0a39309c1af9c84b9397d9b15a",
- "sha256:108f3c7e14a038cf097d2444fa0155462362c6316e3ecb2d70f6dd99cd36084d",
- "sha256:3bada0cf7b6965627954b3a128903a87cac79a79ccd83b6104912e723ef16c7b",
- "sha256:3cf77f138efb31727ee7197bc824c9d6d7039204ed96756cc0f9ca7d8e8fc2a4",
- "sha256:42c216a33d2bdba08098acaf5bae65b0c8196afeb535ef4b870919a788a27259",
- "sha256:465a6ce9ca6268cadfbc27a2a94ddf0412568a6b27640ced229270be4f5d394d",
- "sha256:6a8e1f63357851444940351e98fb3252956a15f2cabe3d698316d7a2d1f1f896",
- "sha256:745071762f32f65e77de6df699366d707fad6c132a660d1342077cbf671ef589",
- "sha256:818cfc51c25a5dbfd0705f3ac1919fff6971eb0c02e6f1a1f6a017a42405a7c0",
- "sha256:8e5974583a77d630a5868eee18f85ac3093caf76e018c510aeb802b9973304ce",
- "sha256:8eaf55fdf99242a1c8c792247c455565447353914023878beadb79600aac4a2a",
- "sha256:98f61aad0bb54f797b17da5b82f419e6ce214de0aa7e92211ebee9e40eb04276",
- "sha256:b2ce2788df0c066c2ff4ba7190fa84f18937527c477247e926abeb9b1168b8cc",
- "sha256:b30d29251dff4c59b2e5a1fa1bab91ff3e117b4658cb90f76d97702b7a2ae699",
- "sha256:bf446223b2e0e4f0a4792938e8d885e8a896834aded5f51be5c3c69566495540",
- "sha256:cbcc691d8b507d54cb2b8521f0a2a3d4daa477f62fe77f0abba41e5febb377b7",
- "sha256:d051ce0946521eba48e19b25f27f98e5ce4dbc91fff296de76240c46b4464df0",
- "sha256:d61b73c01fc1de799226963f2639af831307fe1556b04b7c25e2b6c267a3bc76",
- "sha256:eea10982b798ff0ccc3b9e7e42628f932f552c5845066970e67cd6858655d52c",
- "sha256:f79137d012ff3227866222049af534f25354c07a0d6b9a171dba9f1d6a1fdef4",
- "sha256:fc5ecff5a3bbfbe20091b1cad82815507f5ae9c380a3a9bf40f740c70ce30a9b"
- ],
- "markers": "python_version >= '3.6'",
- "version": "==0.941"
- },
- "mypy-extensions": {
- "hashes": [
- "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d",
- "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"
- ],
- "version": "==0.4.3"
- },
- "nodeenv": {
- "hashes": [
- "sha256:3ef13ff90291ba2a4a7a4ff9a979b63ffdd00a464dbe04acf0ea6471517a4c2b",
- "sha256:621e6b7076565ddcacd2db0294c0381e01fd28945ab36bcf00f41c5daf63bef7"
- ],
- "version": "==1.6.0"
- },
- "numpy": {
- "hashes": [
- "sha256:07a8c89a04997625236c5ecb7afe35a02af3896c8aa01890a849913a2309c676",
- "sha256:08d9b008d0156c70dc392bb3ab3abb6e7a711383c3247b410b39962263576cd4",
- "sha256:201b4d0552831f7250a08d3b38de0d989d6f6e4658b709a02a73c524ccc6ffce",
- "sha256:2c10a93606e0b4b95c9b04b77dc349b398fdfbda382d2a39ba5a822f669a0123",
- "sha256:3ca688e1b9b95d80250bca34b11a05e389b1420d00e87a0d12dc45f131f704a1",
- "sha256:48a3aecd3b997bf452a2dedb11f4e79bc5bfd21a1d4cc760e703c31d57c84b3e",
- "sha256:568dfd16224abddafb1cbcce2ff14f522abe037268514dd7e42c6776a1c3f8e5",
- "sha256:5bfb1bb598e8229c2d5d48db1860bcf4311337864ea3efdbe1171fb0c5da515d",
- "sha256:639b54cdf6aa4f82fe37ebf70401bbb74b8508fddcf4797f9fe59615b8c5813a",
- "sha256:8251ed96f38b47b4295b1ae51631de7ffa8260b5b087808ef09a39a9d66c97ab",
- "sha256:92bfa69cfbdf7dfc3040978ad09a48091143cffb778ec3b03fa170c494118d75",
- "sha256:97098b95aa4e418529099c26558eeb8486e66bd1e53a6b606d684d0c3616b168",
- "sha256:a3bae1a2ed00e90b3ba5f7bd0a7c7999b55d609e0c54ceb2b076a25e345fa9f4",
- "sha256:c34ea7e9d13a70bf2ab64a2532fe149a9aced424cd05a2c4ba662fd989e3e45f",
- "sha256:dbc7601a3b7472d559dc7b933b18b4b66f9aa7452c120e87dfb33d02008c8a18",
- "sha256:e7927a589df200c5e23c57970bafbd0cd322459aa7b1ff73b7c2e84d6e3eae62",
- "sha256:f8c1f39caad2c896bc0018f699882b345b2a63708008be29b1f355ebf6f933fe",
- "sha256:f950f8845b480cffe522913d35567e29dd381b0dc7e4ce6a4a9f9156417d2430",
- "sha256:fade0d4f4d292b6f39951b6836d7a3c7ef5b2347f3c420cd9820a1d90d794802",
- "sha256:fdf3c08bce27132395d3c3ba1503cac12e17282358cb4bddc25cc46b0aca07aa"
- ],
- "markers": "python_version >= '3.8'",
- "version": "==1.22.3"
- },
- "orjson": {
- "hashes": [
- "sha256:0a65f3c403f38b0117c6dd8e76e85a7bd51fcd92f06c5598dfeddbc44697d3e5",
- "sha256:2d5f45c6b85e5f14646df2d32ecd7ff20fcccc71c0ea1155f4d3df8c5299bbb7",
- "sha256:3af57ffab7848aaec6ba6b9e9b41331250b57bf696f9d502bacdc71a0ebab0ba",
- "sha256:3be045ca3b96119f592904cf34b962969ce97bd7843cbfca084009f6c8d2f268",
- "sha256:48c5831ec388b4e2682d4ff56d6bfa4a2ef76c963f5e75f4ff4785f9cf338a80",
- "sha256:4a2c7d0a236aaeab7f69c17b7ab4c078874e817da1bfbb9827cb8c73058b3050",
- "sha256:539cdc5067db38db27985e257772d073cd2eb9462d0a41bde96da4e4e60bd99b",
- "sha256:58f244775f20476e5851e7546df109f75160a5178d44257d437ba6d7e562bfe8",
- "sha256:5a50cde0dbbde255ce751fd1bca39d00ecd878ba0903c0480961b31984f2fab7",
- "sha256:612d242493afeeb2068bc72ff2544aa3b1e627578fcf92edee9daebb5893ffea",
- "sha256:63185af814c243fad7a72441e5f98120c9ecddf2675befa486d669fb65539e9b",
- "sha256:6c47cfca18e41f7f37b08ff3e7abf5ada2d0f27b5ade934f05be5fc5bb956e9d",
- "sha256:6d103b721bbc4f5703f62b3882e638c0b65fcdd48622531c7ffd45047ef8e87c",
- "sha256:70d0386abe02879ebaead2f9632dd2acb71000b4721fd8c1a2fb8c031a38d4d5",
- "sha256:7107a5673fd0b05adbb58bf71c1578fc84d662d29c096eb6d998982c8635c221",
- "sha256:7dd9e1e46c0776eee9e0649e3ae9584ea368d96851bcaeba18e217fa5d755283",
- "sha256:82515226ecb77689a029061552b5df1802b75d861780c401e96ca6bc8495f775",
- "sha256:913fac5d594ccabf5e8fbac15b9b3bb9c576d537d49eeec9f664e7a64dde4c4b",
- "sha256:93188a9d6eb566419ad48befa202dfe7cd7a161756444b99c4ec77faea9352a4",
- "sha256:a08b6940dd9a98ccf09785890112a0f81eadb4f35b51b9a80736d1725437e22c",
- "sha256:a4bb62b11289b7620eead2f25695212e9ac77fcfba76f050fa8a540fb5c32401",
- "sha256:a7297504d1142e7efa236ffc53f056d73934a993a08646dbcee89fc4308a8fcf",
- "sha256:b2da6fde42182b80b40df2e6ab855c55090ebfa3fcc21c182b7ad1762b61d55c",
- "sha256:bb68d0da349cf8a68971a48ad179434f75256159fe8b0715275d9b49fa23b7a3",
- "sha256:bd765c06c359d8a814b90f948538f957fa8a1f55ad1aaffcdc5771996aaea061",
- "sha256:c4b4f20a1e3df7e7c83717aff0ef4ab69e42ce2fb1f5234682f618153c458406",
- "sha256:cb10a20f80e95102dd35dfbc3a22531661b44a09b55236b012a446955846b023",
- "sha256:d21f9a2d1c30e58070f93988db4cad154b9009fafbde238b52c1c760e3607fbe",
- "sha256:d9a3288861bfd26f3511fb4081561ca768674612bac59513cb9081bb61fcc87f",
- "sha256:e152464c4606b49398afd911777decebcf9749cc8810c5b4199039e1afb0991e",
- "sha256:e6201494e8dff2ce7fd21da4e3f6dfca1a3fed38f9dcefc972f552f6596a7621",
- "sha256:f5d1648e5a9d1070f3628a69a7c6c17634dbb0caf22f2085eca6910f7427bf1f"
- ],
- "markers": "python_version >= '3.7'",
- "version": "==3.6.7"
- },
- "packaging": {
- "hashes": [
- "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb",
- "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"
- ],
- "markers": "python_version >= '3.6'",
- "version": "==21.3"
- },
- "pathspec": {
- "hashes": [
- "sha256:7d15c4ddb0b5c802d161efc417ec1a2558ea2653c2e8ad9c19098201dc1c993a",
- "sha256:e564499435a2673d586f6b2130bb5b95f04a3ba06f81b8f895b651a3c76aabb1"
- ],
- "version": "==0.9.0"
- },
- "platformdirs": {
- "hashes": [
- "sha256:7535e70dfa32e84d4b34996ea99c5e432fa29a708d0f4e394bbcb2a8faa4f16d",
- "sha256:bcae7cab893c2d310a711b70b24efb93334febe65f8de776ee320b517471e227"
- ],
- "markers": "python_version >= '3.7'",
- "version": "==2.5.1"
- },
- "pluggy": {
- "hashes": [
- "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159",
- "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"
- ],
- "markers": "python_version >= '3.6'",
- "version": "==1.0.0"
- },
- "pre-commit": {
- "hashes": [
- "sha256:725fa7459782d7bec5ead072810e47351de01709be838c2ce1726b9591dad616",
- "sha256:c1a8040ff15ad3d648c70cc3e55b93e4d2d5b687320955505587fd79bbaed06a"
- ],
- "markers": "python_full_version >= '3.6.1'",
- "version": "==2.17.0"
- },
- "py": {
- "hashes": [
- "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719",
- "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"
- ],
- "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
- "version": "==1.11.0"
- },
- "pycodestyle": {
- "hashes": [
- "sha256:720f8b39dde8b293825e7ff02c475f3077124006db4f440dcbc9a20b76548a20",
- "sha256:eddd5847ef438ea1c7870ca7eb78a9d47ce0cdb4851a5523949f2601d0cbbe7f"
- ],
- "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
- "version": "==2.8.0"
- },
- "pydantic": {
- "hashes": [
- "sha256:085ca1de245782e9b46cefcf99deecc67d418737a1fd3f6a4f511344b613a5b3",
- "sha256:086254884d10d3ba16da0588604ffdc5aab3f7f09557b998373e885c690dd398",
- "sha256:0b6037175234850ffd094ca77bf60fb54b08b5b22bc85865331dd3bda7a02fa1",
- "sha256:0fe476769acaa7fcddd17cadd172b156b53546ec3614a4d880e5d29ea5fbce65",
- "sha256:1d5278bd9f0eee04a44c712982343103bba63507480bfd2fc2790fa70cd64cf4",
- "sha256:2cc6a4cb8a118ffec2ca5fcb47afbacb4f16d0ab8b7350ddea5e8ef7bcc53a16",
- "sha256:2ee7e3209db1e468341ef41fe263eb655f67f5c5a76c924044314e139a1103a2",
- "sha256:3011b975c973819883842c5ab925a4e4298dffccf7782c55ec3580ed17dc464c",
- "sha256:3c3b035103bd4e2e4a28da9da7ef2fa47b00ee4a9cf4f1a735214c1bcd05e0f6",
- "sha256:4c68c3bc88dbda2a6805e9a142ce84782d3930f8fdd9655430d8576315ad97ce",
- "sha256:574936363cd4b9eed8acdd6b80d0143162f2eb654d96cb3a8ee91d3e64bf4cf9",
- "sha256:5a79330f8571faf71bf93667d3ee054609816f10a259a109a0738dac983b23c3",
- "sha256:5e48ef4a8b8c066c4a31409d91d7ca372a774d0212da2787c0d32f8045b1e034",
- "sha256:6c5b77947b9e85a54848343928b597b4f74fc364b70926b3c4441ff52620640c",
- "sha256:742645059757a56ecd886faf4ed2441b9c0cd406079c2b4bee51bcc3fbcd510a",
- "sha256:7bdfdadb5994b44bd5579cfa7c9b0e1b0e540c952d56f627eb227851cda9db77",
- "sha256:815ddebb2792efd4bba5488bc8fde09c29e8ca3227d27cf1c6990fc830fd292b",
- "sha256:8b5ac0f1c83d31b324e57a273da59197c83d1bb18171e512908fe5dc7278a1d6",
- "sha256:96f240bce182ca7fe045c76bcebfa0b0534a1bf402ed05914a6f1dadff91877f",
- "sha256:a733965f1a2b4090a5238d40d983dcd78f3ecea221c7af1497b845a9709c1721",
- "sha256:ab624700dc145aa809e6f3ec93fb8e7d0f99d9023b713f6a953637429b437d37",
- "sha256:b2571db88c636d862b35090ccf92bf24004393f85c8870a37f42d9f23d13e032",
- "sha256:bbbc94d0c94dd80b3340fc4f04fd4d701f4b038ebad72c39693c794fd3bc2d9d",
- "sha256:c0727bda6e38144d464daec31dff936a82917f431d9c39c39c60a26567eae3ed",
- "sha256:c556695b699f648c58373b542534308922c46a1cda06ea47bc9ca45ef5b39ae6",
- "sha256:c86229333cabaaa8c51cf971496f10318c4734cf7b641f08af0a6fbf17ca3054",
- "sha256:c8d7da6f1c1049eefb718d43d99ad73100c958a5367d30b9321b092771e96c25",
- "sha256:c8e9dcf1ac499679aceedac7e7ca6d8641f0193c591a2d090282aaf8e9445a46",
- "sha256:cb23bcc093697cdea2708baae4f9ba0e972960a835af22560f6ae4e7e47d33f5",
- "sha256:d1e4c28f30e767fd07f2ddc6f74f41f034d1dd6bc526cd59e63a82fe8bb9ef4c",
- "sha256:d9c9bdb3af48e242838f9f6e6127de9be7063aad17b32215ccc36a09c5cf1070",
- "sha256:dee5ef83a76ac31ab0c78c10bd7d5437bfdb6358c95b91f1ba7ff7b76f9996a1",
- "sha256:e0896200b6a40197405af18828da49f067c2fa1f821491bc8f5bde241ef3f7d7",
- "sha256:f5a64b64ddf4c99fe201ac2724daada8595ada0d102ab96d019c1555c2d6441d",
- "sha256:f947352c3434e8b937e3aa8f96f47bdfe6d92779e44bb3f41e4c213ba6a32145"
- ],
- "markers": "python_full_version >= '3.6.1'",
- "version": "==1.9.0"
- },
- "pyflakes": {
- "hashes": [
- "sha256:05a85c2872edf37a4ed30b0cce2f6093e1d0581f8c19d7393122da7e25b2b24c",
- "sha256:3bb3a3f256f4b7968c9c788781e4ff07dce46bdf12339dcda61053375426ee2e"
- ],
- "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
- "version": "==2.4.0"
- },
- "pygments": {
- "hashes": [
- "sha256:44238f1b60a76d78fc8ca0528ee429702aae011c265fe6a8dd8b63049ae41c65",
- "sha256:4e426f72023d88d03b2fa258de560726ce890ff3b630f88c21cbb8b2503b8c6a"
- ],
- "markers": "python_version >= '3.5'",
- "version": "==2.11.2"
- },
- "pyparsing": {
- "hashes": [
- "sha256:18ee9022775d270c55187733956460083db60b37d0d0fb357445f3094eed3eea",
- "sha256:a6c06a88f252e6c322f65faf8f418b16213b51bdfaece0524c1c1bc30c63c484"
- ],
- "markers": "python_version >= '3.6'",
- "version": "==3.0.7"
- },
- "pytest": {
- "hashes": [
- "sha256:841132caef6b1ad17a9afde46dc4f6cfa59a05f9555aae5151f73bdf2820ca63",
- "sha256:92f723789a8fdd7180b6b06483874feca4c48a5c76968e03bb3e7f806a1869ea"
- ],
- "markers": "python_version >= '3.7'",
- "version": "==7.1.1"
- },
- "pytest-cov": {
- "hashes": [
- "sha256:578d5d15ac4a25e5f961c938b85a05b09fdaae9deef3bb6de9a6e766622ca7a6",
- "sha256:e7f0f5b1617d2210a2cabc266dfe2f4c75a8d32fb89eafb7ad9d06f6d076d470"
- ],
- "markers": "python_version >= '3.6'",
- "version": "==3.0.0"
- },
- "pytz": {
- "hashes": [
- "sha256:1e760e2fe6a8163bc0b3d9a19c4f84342afa0a2affebfaa84b01b978a02ecaa7",
- "sha256:e68985985296d9a66a881eb3193b0906246245294a881e7c8afe623866ac6a5c"
- ],
- "version": "==2022.1"
- },
- "pyyaml": {
- "hashes": [
- "sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293",
- "sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b",
- "sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57",
- "sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b",
- "sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4",
- "sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07",
- "sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba",
- "sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9",
- "sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287",
- "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513",
- "sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0",
- "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0",
- "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92",
- "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f",
- "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2",
- "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc",
- "sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c",
- "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86",
- "sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4",
- "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c",
- "sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34",
- "sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b",
- "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c",
- "sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb",
- "sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737",
- "sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3",
- "sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d",
- "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53",
- "sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78",
- "sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803",
- "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a",
- "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174",
- "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5"
- ],
- "markers": "python_version >= '3.6'",
- "version": "==6.0"
- },
- "regex": {
- "hashes": [
- "sha256:0066a6631c92774391f2ea0f90268f0d82fffe39cb946f0f9c6b382a1c61a5e5",
- "sha256:0100f0ded953b6b17f18207907159ba9be3159649ad2d9b15535a74de70359d3",
- "sha256:01c913cf573d1da0b34c9001a94977273b5ee2fe4cb222a5d5b320f3a9d1a835",
- "sha256:0214ff6dff1b5a4b4740cfe6e47f2c4c92ba2938fca7abbea1359036305c132f",
- "sha256:029e9e7e0d4d7c3446aa92474cbb07dafb0b2ef1d5ca8365f059998c010600e6",
- "sha256:0317eb6331146c524751354ebef76a7a531853d7207a4d760dfb5f553137a2a4",
- "sha256:04b5ee2b6d29b4a99d38a6469aa1db65bb79d283186e8460542c517da195a8f6",
- "sha256:04c09b9651fa814eeeb38e029dc1ae83149203e4eeb94e52bb868fadf64852bc",
- "sha256:058054c7a54428d5c3e3739ac1e363dc9347d15e64833817797dc4f01fb94bb8",
- "sha256:060f9066d2177905203516c62c8ea0066c16c7342971d54204d4e51b13dfbe2e",
- "sha256:0a7b75cc7bb4cc0334380053e4671c560e31272c9d2d5a6c4b8e9ae2c9bd0f82",
- "sha256:0e2630ae470d6a9f8e4967388c1eda4762706f5750ecf387785e0df63a4cc5af",
- "sha256:174d964bc683b1e8b0970e1325f75e6242786a92a22cedb2a6ec3e4ae25358bd",
- "sha256:25ecb1dffc5e409ca42f01a2b2437f93024ff1612c1e7983bad9ee191a5e8828",
- "sha256:286908cbe86b1a0240a867aecfe26a439b16a1f585d2de133540549831f8e774",
- "sha256:303b15a3d32bf5fe5a73288c316bac5807587f193ceee4eb6d96ee38663789fa",
- "sha256:34bb30c095342797608727baf5c8aa122406aa5edfa12107b8e08eb432d4c5d7",
- "sha256:3e265b388cc80c7c9c01bb4f26c9e536c40b2c05b7231fbb347381a2e1c8bf43",
- "sha256:3e4d710ff6539026e49f15a3797c6b1053573c2b65210373ef0eec24480b900b",
- "sha256:42eb13b93765c6698a5ab3bcd318d8c39bb42e5fa8a7fcf7d8d98923f3babdb1",
- "sha256:48081b6bff550fe10bcc20c01cf6c83dbca2ccf74eeacbfac240264775fd7ecf",
- "sha256:491fc754428514750ab21c2d294486223ce7385446f2c2f5df87ddbed32979ae",
- "sha256:4d1445824944e642ffa54c4f512da17a953699c563a356d8b8cbdad26d3b7598",
- "sha256:530a3a16e57bd3ea0dff5ec2695c09632c9d6c549f5869d6cf639f5f7153fb9c",
- "sha256:591d4fba554f24bfa0421ba040cd199210a24301f923ed4b628e1e15a1001ff4",
- "sha256:5a86cac984da35377ca9ac5e2e0589bd11b3aebb61801204bd99c41fac516f0d",
- "sha256:5b1ceede92400b3acfebc1425937454aaf2c62cd5261a3fabd560c61e74f6da3",
- "sha256:5b2e24f3ae03af3d8e8e6d824c891fea0ca9035c5d06ac194a2700373861a15c",
- "sha256:6504c22c173bb74075d7479852356bb7ca80e28c8e548d4d630a104f231e04fb",
- "sha256:673f5a393d603c34477dbad70db30025ccd23996a2d0916e942aac91cc42b31a",
- "sha256:6ca6dcd17f537e9f3793cdde20ac6076af51b2bd8ad5fe69fa54373b17b48d3c",
- "sha256:6e1d8ed9e61f37881c8db383a124829a6e8114a69bd3377a25aecaeb9b3538f8",
- "sha256:75a5e6ce18982f0713c4bac0704bf3f65eed9b277edd3fb9d2b0ff1815943327",
- "sha256:76435a92e444e5b8f346aed76801db1c1e5176c4c7e17daba074fbb46cb8d783",
- "sha256:764e66a0e382829f6ad3bbce0987153080a511c19eb3d2f8ead3f766d14433ac",
- "sha256:78ce90c50d0ec970bd0002462430e00d1ecfd1255218d52d08b3a143fe4bde18",
- "sha256:794a6bc66c43db8ed06698fc32aaeaac5c4812d9f825e9589e56f311da7becd9",
- "sha256:797437e6024dc1589163675ae82f303103063a0a580c6fd8d0b9a0a6708da29e",
- "sha256:7b7494df3fdcc95a1f76cf134d00b54962dd83189520fd35b8fcd474c0aa616d",
- "sha256:7d1a6e403ac8f1d91d8f51c441c3f99367488ed822bda2b40836690d5d0059f5",
- "sha256:7f63877c87552992894ea1444378b9c3a1d80819880ae226bb30b04789c0828c",
- "sha256:8923e1c5231549fee78ff9b2914fad25f2e3517572bb34bfaa3aea682a758683",
- "sha256:8afcd1c2297bc989dceaa0379ba15a6df16da69493635e53431d2d0c30356086",
- "sha256:8b1cc70e31aacc152a12b39245974c8fccf313187eead559ee5966d50e1b5817",
- "sha256:8d1f3ea0d1924feb4cf6afb2699259f658a08ac6f8f3a4a806661c2dfcd66db1",
- "sha256:940570c1a305bac10e8b2bc934b85a7709c649317dd16520471e85660275083a",
- "sha256:947a8525c0a95ba8dc873191f9017d1b1e3024d4dc757f694e0af3026e34044a",
- "sha256:9beb03ff6fe509d6455971c2489dceb31687b38781206bcec8e68bdfcf5f1db2",
- "sha256:9c144405220c5ad3f5deab4c77f3e80d52e83804a6b48b6bed3d81a9a0238e4c",
- "sha256:a98ae493e4e80b3ded6503ff087a8492db058e9c68de371ac3df78e88360b374",
- "sha256:aa2ce79f3889720b46e0aaba338148a1069aea55fda2c29e0626b4db20d9fcb7",
- "sha256:aa5eedfc2461c16a092a2fabc5895f159915f25731740c9152a1b00f4bcf629a",
- "sha256:ab5d89cfaf71807da93c131bb7a19c3e19eaefd613d14f3bce4e97de830b15df",
- "sha256:b4829db3737480a9d5bfb1c0320c4ee13736f555f53a056aacc874f140e98f64",
- "sha256:b52771f05cff7517f7067fef19ffe545b1f05959e440d42247a17cd9bddae11b",
- "sha256:b8248f19a878c72d8c0a785a2cd45d69432e443c9f10ab924c29adda77b324ae",
- "sha256:b9809404528a999cf02a400ee5677c81959bc5cb938fdc696b62eb40214e3632",
- "sha256:c155a1a80c5e7a8fa1d9bb1bf3c8a953532b53ab1196092749bafb9d3a7cbb60",
- "sha256:c33ce0c665dd325200209340a88438ba7a470bd5f09f7424e520e1a3ff835b52",
- "sha256:c5adc854764732dbd95a713f2e6c3e914e17f2ccdc331b9ecb777484c31f73b6",
- "sha256:cb374a2a4dba7c4be0b19dc7b1adc50e6c2c26c3369ac629f50f3c198f3743a4",
- "sha256:cd00859291658fe1fda48a99559fb34da891c50385b0bfb35b808f98956ef1e7",
- "sha256:ce3057777a14a9a1399b81eca6a6bfc9612047811234398b84c54aeff6d536ea",
- "sha256:d0a5a1fdc9f148a8827d55b05425801acebeeefc9e86065c7ac8b8cc740a91ff",
- "sha256:dad3991f0678facca1a0831ec1ddece2eb4d1dd0f5150acb9440f73a3b863907",
- "sha256:dc7b7c16a519d924c50876fb152af661a20749dcbf653c8759e715c1a7a95b18",
- "sha256:dcbb7665a9db9f8d7642171152c45da60e16c4f706191d66a1dc47ec9f820aed",
- "sha256:df037c01d68d1958dad3463e2881d3638a0d6693483f58ad41001aa53a83fcea",
- "sha256:f08a7e4d62ea2a45557f561eea87c907222575ca2134180b6974f8ac81e24f06",
- "sha256:f16cf7e4e1bf88fecf7f41da4061f181a6170e179d956420f84e700fb8a3fd6b",
- "sha256:f2c53f3af011393ab5ed9ab640fa0876757498aac188f782a0c620e33faa2a3d",
- "sha256:f320c070dea3f20c11213e56dbbd7294c05743417cde01392148964b7bc2d31a",
- "sha256:f553a1190ae6cd26e553a79f6b6cfba7b8f304da2071052fa33469da075ea625",
- "sha256:fc8c7958d14e8270171b3d72792b609c057ec0fa17d507729835b5cff6b7f69a"
- ],
- "markers": "python_version >= '3.6'",
- "version": "==2022.3.15"
- },
- "requests": {
- "hashes": [
- "sha256:68d7c56fd5a8999887728ef304a6d12edc7be74f1cfa47714fc8b414525c9a61",
- "sha256:f22fa1e554c9ddfd16e6e41ac79759e17be9e492b3587efa038054674760e72d"
- ],
- "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'",
- "version": "==2.27.1"
- },
- "six": {
- "hashes": [
- "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926",
- "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"
- ],
- "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'",
- "version": "==1.16.0"
- },
- "sniffio": {
- "hashes": [
- "sha256:471b71698eac1c2112a40ce2752bb2f4a4814c22a54a3eed3676bc0f5ca9f663",
- "sha256:c4666eecec1d3f50960c6bdf61ab7bc350648da6c126e3cf6898d8cd4ddcd3de"
- ],
- "markers": "python_version >= '3.5'",
- "version": "==1.2.0"
- },
- "snowballstemmer": {
- "hashes": [
- "sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1",
- "sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a"
- ],
- "version": "==2.2.0"
- },
- "sphinx": {
- "hashes": [
- "sha256:5da895959511473857b6d0200f56865ed62c31e8f82dd338063b84ec022701fe",
- "sha256:6caad9786055cb1fa22b4a365c1775816b876f91966481765d7d50e9f0dd35cc"
- ],
- "markers": "python_version >= '3.6'",
- "version": "==4.4.0"
- },
- "sphinx-rtd-theme": {
- "hashes": [
- "sha256:4d35a56f4508cfee4c4fb604373ede6feae2a306731d533f409ef5c3496fdbd8",
- "sha256:eec6d497e4c2195fa0e8b2016b337532b8a699a68bcb22a512870e16925c6a5c"
- ],
- "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
- "version": "==1.0.0"
- },
- "sphinx-rtd-theme-github-versions": {
- "hashes": [
- "sha256:23018e51a5d27ef4f69dd86314f73b19088f2cfd91c74a24db1517832233dc07",
- "sha256:7f67ba75cac8ddd51326f0b2f314bf653e72b4c96a5adc6e779acc8c01da81ab"
- ],
- "markers": "python_version >= '3.7'",
- "version": "==1.1"
- },
- "sphinxcontrib-applehelp": {
- "hashes": [
- "sha256:806111e5e962be97c29ec4c1e7fe277bfd19e9652fb1a4392105b43e01af885a",
- "sha256:a072735ec80e7675e3f432fcae8610ecf509c5f1869d17e2eecff44389cdbc58"
- ],
- "markers": "python_version >= '3.5'",
- "version": "==1.0.2"
- },
- "sphinxcontrib-devhelp": {
- "hashes": [
- "sha256:8165223f9a335cc1af7ffe1ed31d2871f325254c0423bc0c4c7cd1c1e4734a2e",
- "sha256:ff7f1afa7b9642e7060379360a67e9c41e8f3121f2ce9164266f61b9f4b338e4"
- ],
- "markers": "python_version >= '3.5'",
- "version": "==1.0.2"
- },
- "sphinxcontrib-htmlhelp": {
- "hashes": [
- "sha256:d412243dfb797ae3ec2b59eca0e52dac12e75a241bf0e4eb861e450d06c6ed07",
- "sha256:f5f8bb2d0d629f398bf47d0d69c07bc13b65f75a81ad9e2f71a63d4b7a2f6db2"
- ],
- "markers": "python_version >= '3.6'",
- "version": "==2.0.0"
- },
- "sphinxcontrib-jsmath": {
- "hashes": [
- "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178",
- "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8"
- ],
- "markers": "python_version >= '3.5'",
- "version": "==1.0.1"
- },
- "sphinxcontrib-qthelp": {
- "hashes": [
- "sha256:4c33767ee058b70dba89a6fc5c1892c0d57a54be67ddd3e7875a18d14cba5a72",
- "sha256:bd9fc24bcb748a8d51fd4ecaade681350aa63009a347a8c14e637895444dfab6"
- ],
- "markers": "python_version >= '3.5'",
- "version": "==1.0.3"
- },
- "sphinxcontrib-serializinghtml": {
- "hashes": [
- "sha256:352a9a00ae864471d3a7ead8d7d79f5fc0b57e8b3f95e9867eb9eb28999b92fd",
- "sha256:aa5f6de5dfdf809ef505c4895e51ef5c9eac17d0f287933eb49ec495280b6952"
- ],
- "markers": "python_version >= '3.5'",
- "version": "==1.1.5"
- },
- "starlette": {
- "hashes": [
- "sha256:26a18cbda5e6b651c964c12c88b36d9898481cd428ed6e063f5f29c418f73050",
- "sha256:57eab3cc975a28af62f6faec94d355a410634940f10b30d68d31cb5ec1b44ae8"
- ],
- "markers": "python_version >= '3.6'",
- "version": "==0.17.1"
- },
- "testfixtures": {
- "hashes": [
- "sha256:02dae883f567f5b70fd3ad3c9eefb95912e78ac90be6c7444b5e2f46bf572c84",
- "sha256:7de200e24f50a4a5d6da7019fb1197aaf5abd475efb2ec2422fdcf2f2eb98c1d"
- ],
- "version": "==6.18.5"
- },
- "toml": {
- "hashes": [
- "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b",
- "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"
- ],
- "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2'",
- "version": "==0.10.2"
- },
- "tomli": {
- "hashes": [
- "sha256:05b6166bff487dc068d322585c7ea4ef78deed501cc124060e0f238e89a9231f",
- "sha256:e3069e4be3ead9668e21cb9b074cd948f7b3113fd9c8bba083f48247aab8b11c"
- ],
- "markers": "python_version >= '3.6'",
- "version": "==1.2.3"
- },
- "typed-ast": {
- "hashes": [
- "sha256:0eb77764ea470f14fcbb89d51bc6bbf5e7623446ac4ed06cbd9ca9495b62e36e",
- "sha256:1098df9a0592dd4c8c0ccfc2e98931278a6c6c53cb3a3e2cf7e9ee3b06153344",
- "sha256:183b183b7771a508395d2cbffd6db67d6ad52958a5fdc99f450d954003900266",
- "sha256:18fe320f354d6f9ad3147859b6e16649a0781425268c4dde596093177660e71a",
- "sha256:26a432dc219c6b6f38be20a958cbe1abffcc5492821d7e27f08606ef99e0dffd",
- "sha256:294a6903a4d087db805a7656989f613371915fc45c8cc0ddc5c5a0a8ad9bea4d",
- "sha256:31d8c6b2df19a777bc8826770b872a45a1f30cfefcfd729491baa5237faae837",
- "sha256:33b4a19ddc9fc551ebabca9765d54d04600c4a50eda13893dadf67ed81d9a098",
- "sha256:42c47c3b43fe3a39ddf8de1d40dbbfca60ac8530a36c9b198ea5b9efac75c09e",
- "sha256:525a2d4088e70a9f75b08b3f87a51acc9cde640e19cc523c7e41aa355564ae27",
- "sha256:58ae097a325e9bb7a684572d20eb3e1809802c5c9ec7108e85da1eb6c1a3331b",
- "sha256:676d051b1da67a852c0447621fdd11c4e104827417bf216092ec3e286f7da596",
- "sha256:74cac86cc586db8dfda0ce65d8bcd2bf17b58668dfcc3652762f3ef0e6677e76",
- "sha256:8c08d6625bb258179b6e512f55ad20f9dfef019bbfbe3095247401e053a3ea30",
- "sha256:90904d889ab8e81a956f2c0935a523cc4e077c7847a836abee832f868d5c26a4",
- "sha256:963a0ccc9a4188524e6e6d39b12c9ca24cc2d45a71cfdd04a26d883c922b4b78",
- "sha256:bbebc31bf11762b63bf61aaae232becb41c5bf6b3461b80a4df7e791fabb3aca",
- "sha256:bc2542e83ac8399752bc16e0b35e038bdb659ba237f4222616b4e83fb9654985",
- "sha256:c29dd9a3a9d259c9fa19d19738d021632d673f6ed9b35a739f48e5f807f264fb",
- "sha256:c7407cfcad702f0b6c0e0f3e7ab876cd1d2c13b14ce770e412c0c4b9728a0f88",
- "sha256:da0a98d458010bf4fe535f2d1e367a2e2060e105978873c04c04212fb20543f7",
- "sha256:df05aa5b241e2e8045f5f4367a9f6187b09c4cdf8578bb219861c4e27c443db5",
- "sha256:f290617f74a610849bd8f5514e34ae3d09eafd521dceaa6cf68b3f4414266d4e",
- "sha256:f30ddd110634c2d7534b2d4e0e22967e88366b0d356b24de87419cc4410c41b7"
- ],
- "markers": "python_version >= '3.6'",
- "version": "==1.5.2"
- },
- "typing-extensions": {
- "hashes": [
- "sha256:1a9462dcc3347a79b1f1c0271fbe79e844580bb598bafa1ed208b94da3cdcd42",
- "sha256:21c85e0fe4b9a155d0799430b0ad741cdce7e359660ccbd8b530613e8df88ce2"
- ],
- "markers": "python_version >= '3.6'",
- "version": "==4.1.1"
- },
- "urllib3": {
- "hashes": [
- "sha256:44ece4d53fb1706f667c9bd1c648f5469a2ec925fcf3a776667042d645472c14",
- "sha256:aabaf16477806a5e1dd19aa41f8c2b7950dd3c746362d7e3223dbe6de6ac448e"
- ],
- "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4.0'",
- "version": "==1.26.9"
- },
- "uvicorn": {
- "hashes": [
- "sha256:19e2a0e96c9ac5581c01eb1a79a7d2f72bb479691acd2b8921fce48ed5b961a6",
- "sha256:5180f9d059611747d841a4a4c4ab675edf54c8489e97f96d0583ee90ac3bfc23"
- ],
- "markers": "python_version >= '3.7'",
- "version": "==0.17.6"
- },
- "virtualenv": {
- "hashes": [
- "sha256:c3e01300fb8495bc00ed70741f5271fc95fed067eb7106297be73d30879af60c",
- "sha256:ce8901d3bbf3b90393498187f2d56797a8a452fb2d0d7efc6fd837554d6f679c"
- ],
- "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
- "version": "==20.13.4"
- },
- "zipp": {
- "hashes": [
- "sha256:9f50f446828eb9d45b267433fd3e9da8d801f614129124863f9c51ebceafb87d",
- "sha256:b47250dd24f92b7dd6a0a8fc5244da14608f3ca90a5efcd37a3b1642fac9a375"
- ],
- "markers": "python_version >= '3.7'",
- "version": "==3.7.0"
- }
- }
-}
diff --git a/README.rst b/README.rst
index d519e8d..ad880f5 100644
--- a/README.rst
+++ b/README.rst
@@ -7,25 +7,24 @@ Microservice for reading HDF5 data and serving it via REST, aimed at performance
============== ==============================================================
PyPI ``pip install hdf5-reader-service``
-Source code https://github.com/DiamondLightSource/python-hdf5-reader-service
+Source code https://github.com/DiamondLightSource/hdf5-reader-service
Documentation https://DiamondLightSource.github.io/hdf5-reader-service
-Releases https://github.com/DiamondLightSource/python-hdf5-reader-service/releases
+Releases https://github.com/DiamondLightSource/hdf5-reader-service/releases
============== ==============================================================
-
To run a basic server::
hdf5-reader-service --host --port
-.. |code_ci| image:: https://github.com/DiamondLightSource/python-hdf5-reader-service/workflows/Code%20CI/badge.svg?branch=master
- :target: https://github.com/DiamondLightSource/python-hdf5-reader-service/actions?query=workflow%3A%22Code+CI%22
+.. |code_ci| image:: https://github.com/DiamondLightSource/hdf5-reader-service/actions/workflows/code.yml/badge.svg?branch=main
+ :target: https://github.com/DiamondLightSource/hdf5-reader-service/actions/workflows/code.yml
:alt: Code CI
-.. |docs_ci| image:: https://github.com/DiamondLightSource/python-hdf5-reader-service/workflows/Docs%20CI/badge.svg?branch=master
- :target: https://github.com/DiamondLightSource/python-hdf5-reader-service/actions?query=workflow%3A%22Docs+CI%22
+.. |docs_ci| image:: https://github.com/DiamondLightSource/hdf5-reader-service/actions/workflows/docs.yml/badge.svg?branch=main
+ :target: https://github.com/DiamondLightSource/hdf5-reader-service/actions/workflows/docs.yml
:alt: Docs CI
-.. |coverage| image:: https://codecov.io/gh/DiamondLightSource/hdf5-reader-service/branch/master/graph/badge.svg
+.. |coverage| image:: https://codecov.io/gh/DiamondLightSource/hdf5-reader-service/branch/main/graph/badge.svg
:target: https://codecov.io/gh/DiamondLightSource/hdf5-reader-service
:alt: Test Coverage
diff --git a/docs/_static/theme_overrides.css b/docs/_static/theme_overrides.css
deleted file mode 100644
index 5fd9b72..0000000
--- a/docs/_static/theme_overrides.css
+++ /dev/null
@@ -1,34 +0,0 @@
-/* override table width restrictions */
-@media screen and (min-width: 639px) {
- .wy-table-responsive table td {
- /* !important prevents the common CSS stylesheets from
- overriding this as on RTD they are loaded after this stylesheet */
- white-space: normal !important;
- }
-}
-
-/* override table padding */
-.rst-content table.docutils th, .rst-content table.docutils td {
- padding: 4px 6px;
-}
-
-/* Add two-column option */
-@media only screen and (min-width: 1000px) {
- .columns {
- padding-left: 10px;
- padding-right: 10px;
- float: left;
- width: 50%;
- min-height: 145px;
- }
-}
-
-.endcolumns {
- clear: both
-}
-
-/* Hide toctrees within columns and captions from all toctrees.
- This is what makes the include trick in index.rst work */
-.columns .toctree-wrapper, .toctree-wrapper .caption-text {
- display: none;
-}
diff --git a/docs/conf.py b/docs/conf.py
index 8e1dc70..04ab160 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -4,6 +4,12 @@
# list see the documentation:
# https://www.sphinx-doc.org/en/master/usage/configuration.html
+import sys
+from pathlib import Path
+from subprocess import check_output
+
+import requests
+
import hdf5_reader_service
# -- General configuration ------------------------------------------------
@@ -16,8 +22,10 @@
# The short X.Y version.
if "+" in release:
- # Not on a tag
- version = "master"
+ # Not on a tag, use branch name
+ root = Path(__file__).absolute().parent.parent
+ git_branch = check_output("git branch --show-current".split(), cwd=root)
+ version = git_branch.decode().strip()
else:
version = release
@@ -32,6 +40,10 @@
"sphinx.ext.viewcode",
# Adds the inheritance-diagram generation directive
"sphinx.ext.inheritance_diagram",
+ # Add a copy button to each code block
+ "sphinx_copybutton",
+ # For the card element
+ "sphinx_design",
]
# If true, Sphinx will warn about all references where the target cannot
@@ -42,7 +54,16 @@
# generating warnings in "nitpicky mode". Note that type should include the
# domain name if present. Example entries would be ('py:func', 'int') or
# ('envvar', 'LD_LIBRARY_PATH').
-nitpick_ignore = [("py:func", "int")]
+nitpick_ignore = [
+ ("py:class", "NoneType"),
+ ("py:class", "'str'"),
+ ("py:class", "'float'"),
+ ("py:class", "'int'"),
+ ("py:class", "'bool'"),
+ ("py:class", "'object'"),
+ ("py:class", "'id'"),
+ ("py:class", "typing_extensions.Literal"),
+]
# Both the class’ and the __init__ method’s docstring are concatenated and
# inserted into the main body of the autoclass directive
@@ -84,27 +105,84 @@
# Common links that should be available on every page
rst_epilog = """
-.. _Diamond Light Source:
- http://www.diamond.ac.uk
+.. _Diamond Light Source: http://www.diamond.ac.uk
+.. _black: https://github.com/psf/black
+.. _flake8: https://flake8.pycqa.org/en/latest/
+.. _isort: https://github.com/PyCQA/isort
+.. _mypy: http://mypy-lang.org/
+.. _pre-commit: https://pre-commit.com/
"""
-# Ignore localhost links for period check that links in docs are valid
+# Ignore localhost links for periodic check that links in docs are valid
linkcheck_ignore = [r"http://localhost:\d+/"]
+# Set copy-button to ignore python and bash prompts
+# https://sphinx-copybutton.readthedocs.io/en/latest/use.html#using-regexp-prompt-identifiers
+copybutton_prompt_text = r">>> |\.\.\. |\$ |In \[\d*\]: | {2,5}\.\.\.: | {5,8}: "
+copybutton_prompt_is_regexp = True
+
# -- Options for HTML output -------------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#
-html_theme = "sphinx_rtd_theme_github_versions"
-
-# Options for the sphinx rtd theme, use DLS blue
-html_theme_options = dict(style_nav_header_background="rgb(7, 43, 93)")
-
-# Add any paths that contain custom static files (such as style sheets) here,
-# relative to this directory. They are copied after the builtin static files,
-# so a file named "default.css" will overwrite the builtin "default.css".
-html_static_path = ["_static"]
+html_theme = "pydata_sphinx_theme"
+github_repo = project
+github_user = "DiamondLightSource"
+switcher_json = f"https://{github_user}.github.io/{github_repo}/switcher.json"
+switcher_exists = requests.get(switcher_json).ok
+if not switcher_exists:
+ print(
+ "*** Can't read version switcher, is GitHub pages enabled? \n"
+ " Once Docs CI job has successfully run once, set the "
+ "Github pages source branch to be 'gh-pages' at:\n"
+ f" https://github.com/{github_user}/{github_repo}/settings/pages",
+ file=sys.stderr,
+ )
+
+# Theme options for pydata_sphinx_theme
+# We don't check switcher because there are 3 possible states for a repo:
+# 1. New project, docs are not published so there is no switcher
+# 2. Existing project with latest skeleton, switcher exists and works
+# 3. Existing project with old skeleton that makes broken switcher,
+# switcher exists but is broken
+# Point 3 makes checking switcher difficult, because the updated skeleton
+# will fix the switcher at the end of the docs workflow, but never gets a chance
+# to complete as the docs build warns and fails.
+html_theme_options = dict(
+ logo=dict(
+ text=project,
+ ),
+ use_edit_page_button=True,
+ github_url=f"https://github.com/{github_user}/{github_repo}",
+ icon_links=[
+ dict(
+ name="PyPI",
+ url=f"https://pypi.org/project/{project}",
+ icon="fas fa-cube",
+ )
+ ],
+ switcher=dict(
+ json_url=switcher_json,
+ version_match=version,
+ ),
+ check_switcher=False,
+ navbar_end=["theme-switcher", "icon-links", "version-switcher"],
+ external_links=[
+ dict(
+ name="Release Notes",
+ url=f"https://github.com/{github_user}/{github_repo}/releases",
+ )
+ ],
+)
+
+# A dictionary of values to pass into the template engine’s context for all pages
+html_context = dict(
+ github_user=github_user,
+ github_repo=project,
+ github_version=version,
+ doc_path="docs",
+)
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
html_show_sphinx = False
@@ -112,9 +190,6 @@
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
html_show_copyright = False
-# Add some CSS classes for columns and other tweaks in a custom css file
-html_css_files = ["theme_overrides.css"]
-
# Logo
html_logo = "images/dls-logo.svg"
html_favicon = "images/dls-favicon.ico"
diff --git a/docs/developer/explanations/decisions.rst b/docs/developer/explanations/decisions.rst
new file mode 100644
index 0000000..5841e6e
--- /dev/null
+++ b/docs/developer/explanations/decisions.rst
@@ -0,0 +1,17 @@
+.. This Source Code Form is subject to the terms of the Mozilla Public
+.. License, v. 2.0. If a copy of the MPL was not distributed with this
+.. file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+Architectural Decision Records
+==============================
+
+We record major architectural decisions in Architecture Decision Records (ADRs),
+as `described by Michael Nygard
+`_.
+Below is the list of our current ADRs.
+
+.. toctree::
+ :maxdepth: 1
+ :glob:
+
+ decisions/*
\ No newline at end of file
diff --git a/docs/developer/explanations/decisions/0001-record-architecture-decisions.rst b/docs/developer/explanations/decisions/0001-record-architecture-decisions.rst
new file mode 100644
index 0000000..b2d3d0f
--- /dev/null
+++ b/docs/developer/explanations/decisions/0001-record-architecture-decisions.rst
@@ -0,0 +1,26 @@
+1. Record architecture decisions
+================================
+
+Date: 2022-02-18
+
+Status
+------
+
+Accepted
+
+Context
+-------
+
+We need to record the architectural decisions made on this project.
+
+Decision
+--------
+
+We will use Architecture Decision Records, as `described by Michael Nygard
+`_.
+
+Consequences
+------------
+
+See Michael Nygard's article, linked above. To create new ADRs we will copy and
+paste from existing ones.
diff --git a/docs/developer/explanations/decisions/0002-switched-to-pip-skeleton.rst b/docs/developer/explanations/decisions/0002-switched-to-pip-skeleton.rst
new file mode 100644
index 0000000..a7f175a
--- /dev/null
+++ b/docs/developer/explanations/decisions/0002-switched-to-pip-skeleton.rst
@@ -0,0 +1,35 @@
+2. Adopt hdf5-reader-service for project structure
+===================================================
+
+Date: 2022-02-18
+
+Status
+------
+
+Accepted
+
+Context
+-------
+
+We should use the following `pip-skeleton `_.
+The skeleton will ensure consistency in developer
+environments and package management.
+
+Decision
+--------
+
+We have switched to using the skeleton.
+
+Consequences
+------------
+
+This module will use a fixed set of tools as developed in hdf5-reader-service
+and can pull from this skeleton to update the packaging to the latest techniques.
+
+As such, the developer environment may have changed, the following could be
+different:
+
+- linting
+- formatting
+- pip venv setup
+- CI/CD
diff --git a/docs/developer/how-to/build-docs.rst b/docs/developer/how-to/build-docs.rst
new file mode 100644
index 0000000..0174fc8
--- /dev/null
+++ b/docs/developer/how-to/build-docs.rst
@@ -0,0 +1,38 @@
+Build the docs using sphinx
+===========================
+
+You can build the `sphinx`_ based docs from the project directory by running::
+
+ $ tox -e docs
+
+This will build the static docs on the ``docs`` directory, which includes API
+docs that pull in docstrings from the code.
+
+.. seealso::
+
+ `documentation_standards`
+
+The docs will be built into the ``build/html`` directory, and can be opened
+locally with a web browser::
+
+ $ firefox build/html/index.html
+
+Autobuild
+---------
+
+You can also run an autobuild process, which will watch your ``docs``
+directory for changes and rebuild whenever it sees changes, reloading any
+browsers watching the pages::
+
+ $ tox -e docs autobuild
+
+You can view the pages at localhost::
+
+ $ firefox http://localhost:8000
+
+If you are making changes to source code too, you can tell it to watch
+changes in this directory too::
+
+ $ tox -e docs autobuild -- --watch src
+
+.. _sphinx: https://www.sphinx-doc.org/
\ No newline at end of file
diff --git a/docs/developer/how-to/contribute.rst b/docs/developer/how-to/contribute.rst
new file mode 100644
index 0000000..65b992f
--- /dev/null
+++ b/docs/developer/how-to/contribute.rst
@@ -0,0 +1 @@
+.. include:: ../../../.github/CONTRIBUTING.rst
diff --git a/docs/developer/how-to/lint.rst b/docs/developer/how-to/lint.rst
new file mode 100644
index 0000000..8f4e92d
--- /dev/null
+++ b/docs/developer/how-to/lint.rst
@@ -0,0 +1,41 @@
+Run linting using pre-commit
+============================
+
+Code linting is handled by black_, flake8_ and isort_ run under pre-commit_.
+
+Running pre-commit
+------------------
+
+You can run the above checks on all files with this command::
+
+ $ tox -e pre-commit
+
+Or you can install a pre-commit hook that will run each time you do a ``git
+commit`` on just the files that have changed::
+
+ $ pre-commit install
+
+It is also possible to `automatically enable pre-commit on cloned repositories `_.
+This will result in pre-commits being enabled on every repo your user clones from now on.
+
+Fixing issues
+-------------
+
+If black reports an issue you can tell it to reformat all the files in the
+repository::
+
+ $ black .
+
+Likewise with isort::
+
+ $ isort .
+
+If you get any flake8 issues you will have to fix those manually.
+
+VSCode support
+--------------
+
+The ``.vscode/settings.json`` will run black and isort formatters as well as
+flake8 checking on save. Issues will be highlighted in the editor window.
+
+
diff --git a/docs/developer/how-to/make-release.rst b/docs/developer/how-to/make-release.rst
new file mode 100644
index 0000000..6a9a22e
--- /dev/null
+++ b/docs/developer/how-to/make-release.rst
@@ -0,0 +1,16 @@
+Make a release
+==============
+
+To make a new release, please follow this checklist:
+
+- Choose a new PEP440 compliant release number (see https://peps.python.org/pep-0440/)
+- Go to the GitHub release_ page
+- Choose ``Draft New Release``
+- Click ``Choose Tag`` and supply the new tag you chose (click create new tag)
+- Click ``Generate release notes``, review and edit these notes
+- Choose a title and click ``Publish Release``
+
+Note that tagging and pushing to the main branch has the same effect except that
+you will not get the option to edit the release notes.
+
+.. _release: https://github.com/DiamondLightSource/hdf5-reader-service/releases
\ No newline at end of file
diff --git a/docs/developer/how-to/pin-requirements.rst b/docs/developer/how-to/pin-requirements.rst
new file mode 100644
index 0000000..6791659
--- /dev/null
+++ b/docs/developer/how-to/pin-requirements.rst
@@ -0,0 +1,74 @@
+Pinning Requirements
+====================
+
+Introduction
+------------
+
+By design this project only defines dependencies in one place, i.e. in
+the ``requires`` table in ``pyproject.toml``.
+
+In the ``requires`` table it is possible to pin versions of some dependencies
+as needed. For library projects it is best to leave pinning to a minimum so
+that your library can be used by the widest range of applications.
+
+When CI builds the project it will use the latest compatible set of
+dependencies available (after applying your pins and any dependencies' pins).
+
+This approach means that there is a possibility that a future build may
+break because an updated release of a dependency has made a breaking change.
+
+The correct way to fix such an issue is to work out the minimum pinning in
+``requires`` that will resolve the problem. However this can be quite hard to
+do and may be time consuming when simply trying to release a minor update.
+
+For this reason we provide a mechanism for locking all dependencies to
+the same version as a previous successful release. This is a quick fix that
+should guarantee a successful CI build.
+
+Finding the lock files
+----------------------
+
+Every release of the project will have a set of requirements files published
+as release assets.
+
+For example take a look at the release page for python3-pip-skeleton-cli here:
+https://github.com/DiamondLightSource/python3-pip-skeleton-cli/releases/tag/3.3.0
+
+There is a list of requirements*.txt files showing as assets on the release.
+
+There is one file for each time the CI installed the project into a virtual
+environment. There are multiple of these as the CI creates a number of
+different environments.
+
+The files are created using ``pip freeze`` and will contain a full list
+of the dependencies and sub-dependencies with pinned versions.
+
+You can download any of these files by clicking on them. It is best to use
+the one that ran with the lowest Python version as this is more likely to
+be compatible with all the versions of Python in the test matrix.
+i.e. ``requirements-test-ubuntu-latest-3.9.txt`` in this example.
+
+Applying the lock file
+----------------------
+
+To apply a lockfile:
+
+- copy the requirements file you have downloaded to the root of your
+ repository
+- rename it to requirements.txt
+- commit it into the repo
+- push the changes
+
+The CI looks for a requirements.txt in the root and will pass it to pip
+when installing each of the test environments. pip will then install exactly
+the same set of packages as the previous release.
+
+Removing dependency locking from CI
+-----------------------------------
+
+Once the reasons for locking the build have been resolved it is a good idea
+to go back to an unlocked build. This is because you get an early indication
+of any incoming problems.
+
+To restore unlocked builds in CI simply remove requirements.txt from the root
+of the repo and push.
diff --git a/docs/developer/how-to/run-tests.rst b/docs/developer/how-to/run-tests.rst
new file mode 100644
index 0000000..d2e0364
--- /dev/null
+++ b/docs/developer/how-to/run-tests.rst
@@ -0,0 +1,12 @@
+Run the tests using pytest
+==========================
+
+Testing is done with pytest_. It will find functions in the project that `look
+like tests`_, and run them to check for errors. You can run it with::
+
+ $ tox -e pytest
+
+It will also report coverage to the commandline and to ``cov.xml``.
+
+.. _pytest: https://pytest.org/
+.. _look like tests: https://docs.pytest.org/explanation/goodpractices.html#test-discovery
diff --git a/docs/developer/how-to/static-analysis.rst b/docs/developer/how-to/static-analysis.rst
new file mode 100644
index 0000000..065920e
--- /dev/null
+++ b/docs/developer/how-to/static-analysis.rst
@@ -0,0 +1,8 @@
+Run static analysis using mypy
+==============================
+
+Static type analysis is done with mypy_. It checks type definition in source
+files without running them, and highlights potential issues where types do not
+match. You can run it with::
+
+ $ tox -e mypy
diff --git a/docs/developer/how-to/test-container.rst b/docs/developer/how-to/test-container.rst
new file mode 100644
index 0000000..a4a43a6
--- /dev/null
+++ b/docs/developer/how-to/test-container.rst
@@ -0,0 +1,25 @@
+Container Local Build and Test
+==============================
+
+CI builds a runtime container for the project. The local tests
+checks available via ``tox -p`` do not verify this because not
+all developers will have docker installed locally.
+
+If CI is failing to build the container, then it is best to fix and
+test the problem locally. This would require that you have docker
+or podman installed on your local workstation.
+
+In the following examples the command ``docker`` is interchangeable with
+``podman`` depending on which container cli you have installed.
+
+To build the container and call it ``test``::
+
+ cd
+ docker build -t test .
+
+To verify that the container runs::
+
+ docker run -it test --help
+
+You can pass any other command line parameters to your application
+instead of --help.
diff --git a/docs/developer/how-to/update-tools.rst b/docs/developer/how-to/update-tools.rst
new file mode 100644
index 0000000..c1075ee
--- /dev/null
+++ b/docs/developer/how-to/update-tools.rst
@@ -0,0 +1,16 @@
+Update the tools
+================
+
+This module is merged with the python3-pip-skeleton_. This is a generic
+Python project structure which provides a means to keep tools and
+techniques in sync between multiple Python projects. To update to the
+latest version of the skeleton, run::
+
+ $ git pull --rebase=false https://github.com/DiamondLightSource/python3-pip-skeleton
+
+Any merge conflicts will indicate an area where something has changed that
+conflicts with the setup of the current module. Check the `closed pull requests
+`_
+of the skeleton module for more details.
+
+.. _python3-pip-skeleton: https://DiamondLightSource.github.io/python3-pip-skeleton
diff --git a/docs/developer/index.rst b/docs/developer/index.rst
new file mode 100644
index 0000000..8a6369b
--- /dev/null
+++ b/docs/developer/index.rst
@@ -0,0 +1,64 @@
+Developer Guide
+===============
+
+Documentation is split into four categories, also accessible from links in the
+side-bar.
+
+.. grid:: 2
+ :gutter: 4
+
+ .. grid-item-card:: :material-regular:`directions_run;3em`
+
+ .. toctree::
+ :caption: Tutorials
+ :maxdepth: 1
+
+ tutorials/dev-install
+
+ +++
+
+ Tutorials for getting up and running as a developer.
+
+ .. grid-item-card:: :material-regular:`task;3em`
+
+ .. toctree::
+ :caption: How-to Guides
+ :maxdepth: 1
+
+ how-to/contribute
+ how-to/build-docs
+ how-to/run-tests
+ how-to/static-analysis
+ how-to/lint
+ how-to/update-tools
+ how-to/make-release
+ how-to/pin-requirements
+ how-to/test-container
+
+ +++
+
+ Practical step-by-step guides for day-to-day dev tasks.
+
+ .. grid-item-card:: :material-regular:`apartment;3em`
+
+ .. toctree::
+ :caption: Explanations
+ :maxdepth: 1
+
+ explanations/decisions
+
+ +++
+
+ Explanations of how and why the architecture is why it is.
+
+ .. grid-item-card:: :material-regular:`description;3em`
+
+ .. toctree::
+ :caption: Reference
+ :maxdepth: 1
+
+ reference/standards
+
+ +++
+
+ Technical reference material on standards in use.
diff --git a/docs/developer/reference/standards.rst b/docs/developer/reference/standards.rst
new file mode 100644
index 0000000..b78a719
--- /dev/null
+++ b/docs/developer/reference/standards.rst
@@ -0,0 +1,64 @@
+Standards
+=========
+
+This document defines the code and documentation standards used in this
+repository.
+
+Code Standards
+--------------
+
+The code in this repository conforms to standards set by the following tools:
+
+- black_ for code formatting
+- flake8_ for style checks
+- isort_ for import ordering
+- mypy_ for static type checking
+
+.. seealso::
+
+ How-to guides `../how-to/lint` and `../how-to/static-analysis`
+
+.. _documentation_standards:
+
+Documentation Standards
+-----------------------
+
+Docstrings are pre-processed using the Sphinx Napoleon extension. As such,
+google-style_ is considered as standard for this repository. Please use type
+hints in the function signature for types. For example:
+
+.. code:: python
+
+ def func(arg1: str, arg2: int) -> bool:
+ """Summary line.
+
+ Extended description of function.
+
+ Args:
+ arg1: Description of arg1
+ arg2: Description of arg2
+
+ Returns:
+ Description of return value
+ """
+ return True
+
+.. _google-style: https://sphinxcontrib-napoleon.readthedocs.io/en/latest/index.html#google-vs-numpy
+
+Documentation is contained in the ``docs`` directory and extracted from
+docstrings of the API.
+
+Docs follow the underlining convention::
+
+ Headling 1 (page title)
+ =======================
+
+ Heading 2
+ ---------
+
+ Heading 3
+ ~~~~~~~~~
+
+.. seealso::
+
+ How-to guide `../how-to/build-docs`
\ No newline at end of file
diff --git a/docs/developer/tutorials/dev-install.rst b/docs/developer/tutorials/dev-install.rst
new file mode 100644
index 0000000..834efc9
--- /dev/null
+++ b/docs/developer/tutorials/dev-install.rst
@@ -0,0 +1,68 @@
+Developer install
+=================
+
+These instructions will take you through the minimal steps required to get a dev
+environment setup, so you can run the tests locally.
+
+Clone the repository
+--------------------
+
+First clone the repository locally using `Git
+`_::
+
+ $ git clone git://github.com/DiamondLightSource/hdf5-reader-service.git
+
+Install dependencies
+--------------------
+
+You can choose to either develop on the host machine using a `venv` (which
+requires python 3.9 or later) or to run in a container under `VSCode
+`_
+
+.. tab-set::
+
+ .. tab-item:: Local virtualenv
+
+ .. code::
+
+ $ cd hdf5-reader-service
+ $ python3 -m venv venv
+ $ source venv/bin/activate
+ $ pip install -e '.[dev]'
+
+ .. tab-item:: VSCode devcontainer
+
+ .. code::
+
+ $ code hdf5-reader-service
+ # Click on 'Reopen in Container' when prompted
+ # Open a new terminal
+
+ .. note::
+
+ See the epics-containers_ documentation for more complex
+ use cases, such as integration with podman.
+
+See what was installed
+----------------------
+
+To see a graph of the python package dependency tree type::
+
+ $ pipdeptree
+
+Build and test
+--------------
+
+Now you have a development environment you can run the tests in a terminal::
+
+ $ tox -p
+
+This will run in parallel the following checks:
+
+- `../how-to/build-docs`
+- `../how-to/run-tests`
+- `../how-to/static-analysis`
+- `../how-to/lint`
+
+
+.. _epics-containers: https://epics-containers.github.io/main/user/tutorials/devcontainer.html
\ No newline at end of file
diff --git a/docs/explanations.rst b/docs/explanations.rst
deleted file mode 100644
index 39de4e6..0000000
--- a/docs/explanations.rst
+++ /dev/null
@@ -1,11 +0,0 @@
-:orphan:
-
-Explanations
-============
-
-Explanation of how the library works and why it works that way.
-
-.. toctree::
- :caption: Explanations
-
- explanations/why-is-something-so
diff --git a/docs/explanations/why-is-something-so.rst b/docs/explanations/why-is-something-so.rst
deleted file mode 100644
index 421cfa9..0000000
--- a/docs/explanations/why-is-something-so.rst
+++ /dev/null
@@ -1,7 +0,0 @@
-Why is something the way it is
-==============================
-
-Often, reading the code will not explain *why* it is written that way. These
-explanations should be grouped together in articles here. They might include
-history of hdf5-reader-service, architectural decisions, or the
-real world tests that influenced the design of hdf5-reader-service.
diff --git a/docs/genindex.rst b/docs/genindex.rst
new file mode 100644
index 0000000..93eb8b2
--- /dev/null
+++ b/docs/genindex.rst
@@ -0,0 +1,5 @@
+API Index
+=========
+
+..
+ https://stackoverflow.com/a/42310803
diff --git a/docs/how-to.rst b/docs/how-to.rst
deleted file mode 100644
index 86b2ddb..0000000
--- a/docs/how-to.rst
+++ /dev/null
@@ -1,11 +0,0 @@
-:orphan:
-
-How-to Guides
-=============
-
-Practical step-by-step guides for the more experienced user.
-
-.. toctree::
- :caption: How-to Guides
-
- how-to/accomplish-a-task
diff --git a/docs/how-to/accomplish-a-task.rst b/docs/how-to/accomplish-a-task.rst
deleted file mode 100644
index 959ecf7..0000000
--- a/docs/how-to/accomplish-a-task.rst
+++ /dev/null
@@ -1,7 +0,0 @@
-How to accomplish a task
-========================
-
-Here you would explain how to use hdf5-reader-service to accomplish
-a particular task. It doesn't have to be an exhaustive guide like the tutorials,
-just enough information to show someone who knows what they want to do, how to
-accomplish that task.
diff --git a/docs/index.rst b/docs/index.rst
index 9bde8ad..b196242 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -1,48 +1,29 @@
+:html_theme.sidebar_secondary.remove:
+
.. include:: ../README.rst
:end-before: when included in index.rst
-
How the documentation is structured
-----------------------------------
-Documentation is split into four categories, also accessible from links in the
-side-bar.
-
-.. rst-class:: columns
-
-`tutorials`
-~~~~~~~~~~~
-
-.. include:: tutorials.rst
- :start-after: =========
-
-.. rst-class:: columns
-
-`how-to`
-~~~~~~~~
-
-.. include:: how-to.rst
- :start-after: =============
-
-.. rst-class:: columns
-
-`explanations`
-~~~~~~~~~~~~~~
+The documentation is split into 2 sections:
-.. include:: explanations.rst
- :start-after: ============
+.. grid:: 2
-.. rst-class:: columns
+ .. grid-item-card:: :material-regular:`person;4em`
+ :link: user/index
+ :link-type: doc
-`reference`
-~~~~~~~~~~~
+ The User Guide contains documentation on how to install and use hdf5-reader-service.
-.. include:: reference.rst
- :start-after: =========
+ .. grid-item-card:: :material-regular:`code;4em`
+ :link: developer/index
+ :link-type: doc
-.. rst-class:: endcolumns
+ The Developer Guide contains documentation on how to develop and contribute changes back to hdf5-reader-service.
-About the documentation
-~~~~~~~~~~~~~~~~~~~~~~~
+.. toctree::
+ :hidden:
-`Why is the documentation structured this way? `_
+ user/index
+ developer/index
diff --git a/docs/reference.rst b/docs/reference.rst
deleted file mode 100644
index 7b62159..0000000
--- a/docs/reference.rst
+++ /dev/null
@@ -1,18 +0,0 @@
-:orphan:
-
-Reference
-=========
-
-Practical step-by-step guides for the more experienced user.
-
-.. toctree::
- :caption: Reference
-
- reference/api
- reference/contributing
- Releases
- Index
-
-..
- Index link above is a hack to make genindex.html a relative link
- https://stackoverflow.com/a/31820846
diff --git a/docs/reference/api.rst b/docs/reference/api.rst
deleted file mode 100644
index 2a1742e..0000000
--- a/docs/reference/api.rst
+++ /dev/null
@@ -1,4 +0,0 @@
-API
-===
-
-TODO
diff --git a/docs/reference/contributing.rst b/docs/reference/contributing.rst
deleted file mode 100644
index ac7b6bc..0000000
--- a/docs/reference/contributing.rst
+++ /dev/null
@@ -1 +0,0 @@
-.. include:: ../../CONTRIBUTING.rst
diff --git a/docs/tutorials.rst b/docs/tutorials.rst
deleted file mode 100644
index dfdef50..0000000
--- a/docs/tutorials.rst
+++ /dev/null
@@ -1,11 +0,0 @@
-:orphan:
-
-Tutorials
-=========
-
-Tutorials for installation, library and commandline usage. New users start here.
-
-.. toctree::
- :caption: Tutorials
-
- tutorials/installation
diff --git a/docs/tutorials/installation.rst b/docs/tutorials/installation.rst
deleted file mode 100644
index f351a7c..0000000
--- a/docs/tutorials/installation.rst
+++ /dev/null
@@ -1,48 +0,0 @@
-Installation
-============
-
-.. note::
-
- For installation inside DLS, please see the internal documentation on
- ``dls-python3`` and ``pipenv``. Although these instructions will work
- inside DLS, they are intended for external use.
-
- If you want to contribute to the library itself, please follow
- the `../reference/contributing` instructions.
-
-
-Check your version of python
-----------------------------
-
-You will need python 3.7 or later. You can check your version of python by
-typing into a terminal::
-
- python3 --version
-
-
-Create a virtual environment
-----------------------------
-
-It is recommended that you install into a “virtual environment” so this
-installation will not interfere with any existing Python software::
-
- python3 -m venv /path/to/venv
- source /path/to/venv/bin/activate
-
-
-Installing the library
-----------------------
-
-You can now use ``pip`` to install the library::
-
- python3 -m pip install hdf5-reader-service
-
-If you require a feature that is not currently released you can also install
-from github::
-
- python3 -m pip install git+git://github.com/dls-controls/hdf5-reader-service.git
-
-The library should now be installed and the commandline interface on your path.
-You can check the version that has been installed by typing::
-
- hdf5-reader-service --version
diff --git a/docs/user/explanations/docs-structure.rst b/docs/user/explanations/docs-structure.rst
new file mode 100644
index 0000000..f25a09b
--- /dev/null
+++ b/docs/user/explanations/docs-structure.rst
@@ -0,0 +1,18 @@
+About the documentation
+-----------------------
+
+ :material-regular:`format_quote;2em`
+
+ The Grand Unified Theory of Documentation
+
+ -- David Laing
+
+There is a secret that needs to be understood in order to write good software
+documentation: there isn't one thing called *documentation*, there are four.
+
+They are: *tutorials*, *how-to guides*, *technical reference* and *explanation*.
+They represent four different purposes or functions, and require four different
+approaches to their creation. Understanding the implications of this will help
+improve most documentation - often immensely.
+
+`More information on this topic. `_
diff --git a/docs/user/how-to/run-container.rst b/docs/user/how-to/run-container.rst
new file mode 100644
index 0000000..46a5e43
--- /dev/null
+++ b/docs/user/how-to/run-container.rst
@@ -0,0 +1,15 @@
+Run in a container
+==================
+
+Pre-built containers with hdf5-reader-service and its dependencies already
+installed are available on `Github Container Registry
+`_.
+
+Starting the container
+----------------------
+
+To pull the container from github container registry and run::
+
+ $ docker run ghcr.io/DiamondLightSource/hdf5-reader-service:main --version
+
+To get a released version, use a numbered release instead of ``main``.
diff --git a/docs/user/index.rst b/docs/user/index.rst
new file mode 100644
index 0000000..2c94a0c
--- /dev/null
+++ b/docs/user/index.rst
@@ -0,0 +1,57 @@
+User Guide
+==========
+
+Documentation is split into four categories, also accessible from links in the
+side-bar.
+
+.. grid:: 2
+ :gutter: 4
+
+ .. grid-item-card:: :material-regular:`directions_walk;3em`
+
+ .. toctree::
+ :caption: Tutorials
+ :maxdepth: 1
+
+ tutorials/installation
+
+ +++
+
+ Tutorials for installation and typical usage. New users start here.
+
+ .. grid-item-card:: :material-regular:`directions;3em`
+
+ .. toctree::
+ :caption: How-to Guides
+ :maxdepth: 1
+
+ how-to/run-container
+
+ +++
+
+ Practical step-by-step guides for the more experienced user.
+
+ .. grid-item-card:: :material-regular:`info;3em`
+
+ .. toctree::
+ :caption: Explanations
+ :maxdepth: 1
+
+ explanations/docs-structure
+
+ +++
+
+ Explanations of how the library works and why it works that way.
+
+ .. grid-item-card:: :material-regular:`menu_book;3em`
+
+ .. toctree::
+ :caption: Reference
+ :maxdepth: 1
+
+ reference/api
+ ../genindex
+
+ +++
+
+ Technical reference material including APIs and release notes.
diff --git a/docs/user/reference/api.rst b/docs/user/reference/api.rst
new file mode 100644
index 0000000..6317dd9
--- /dev/null
+++ b/docs/user/reference/api.rst
@@ -0,0 +1,14 @@
+API
+===
+
+.. automodule:: hdf5_reader_service
+
+ ``hdf5_reader_service``
+ -----------------------------------
+
+This is the internal API reference for hdf5_reader_service
+
+.. data:: hdf5_reader_service.__version__
+ :type: str
+
+ Version number as calculated by https://github.com/pypa/setuptools_scm
diff --git a/docs/user/tutorials/installation.rst b/docs/user/tutorials/installation.rst
new file mode 100644
index 0000000..db7781d
--- /dev/null
+++ b/docs/user/tutorials/installation.rst
@@ -0,0 +1,38 @@
+Installation
+============
+
+Check your version of python
+----------------------------
+
+You will need python 3.9 or later. You can check your version of python by
+typing into a terminal::
+
+ $ python3 --version
+
+
+Create a virtual environment
+----------------------------
+
+It is recommended that you install into a “virtual environment” so this
+installation will not interfere with any existing Python software::
+
+ $ python3 -m venv /path/to/venv
+ $ source /path/to/venv/bin/activate
+
+
+Installing the library
+----------------------
+
+You can now use ``pip`` to install the library and its dependencies::
+
+ $ python3 -m pip install hdf5-reader-service
+
+If you require a feature that is not currently released you can also install
+from github::
+
+ $ python3 -m pip install git+https://github.com/DiamondLightSource/hdf5-reader-service.git
+
+The library should now be installed and the commandline interface on your path.
+You can check the version that has been installed by typing::
+
+ $ hdf5-reader-service --version
diff --git a/pyproject.toml b/pyproject.toml
index ccd70c7..f63babe 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,117 @@
[build-system]
-# To get a reproducible wheel, wheel must be pinned to the same version as in
-# dls-python3, and setuptools must produce the same dist-info. Cap setuptools
-# to the last version that didn't add License-File to METADATA
-requires = ["setuptools<57", "wheel==0.33.1"]
+requires = ["setuptools>=64", "setuptools_scm[toml]>=6.2", "wheel"]
build-backend = "setuptools.build_meta"
+
+[project]
+name = "hdf5-reader-service"
+classifiers = [
+ "Development Status :: 3 - Alpha",
+ "License :: OSI Approved :: Apache Software License",
+ "Programming Language :: Python :: 3.9",
+ "Programming Language :: Python :: 3.10",
+ "Programming Language :: Python :: 3.11",
+]
+description = "Microservice for reading HDF5 data and serving it via REST, aimed at performance and concurrency"
+dependencies = [
+ "h5py",
+ "fastapi",
+ "uvicorn",
+ "orjson",
+ "click",
+] # Add project dependencies here, e.g. ["click", "numpy"]
+dynamic = ["version"]
+license.file = "LICENSE"
+readme = "README.rst"
+requires-python = ">=3.9"
+
+[project.optional-dependencies]
+dev = [
+ "black",
+ "mypy",
+ "flake8-isort",
+ "Flake8-pyproject",
+ "pipdeptree",
+ "pre-commit",
+ "pydata-sphinx-theme>=0.12",
+ "pytest",
+ "pytest-cov",
+ "sphinx-autobuild",
+ "sphinx-copybutton",
+ "sphinx-design",
+ "tox-direct",
+ "types-mock",
+ "httpx",
+]
+
+[project.scripts]
+hdf5-reader-service = "hdf5_reader_service.__main__:main"
+
+[project.urls]
+GitHub = "https://github.com/DiamondLightSource/hdf5-reader-service"
+
+[[project.authors]] # Further authors may be added by duplicating this section
+email = "callum.forrester@diamond.ac.uk"
+name = "Callum Forrester"
+
+
+[tool.setuptools_scm]
+write_to = "src/hdf5_reader_service/_version.py"
+
+[tool.mypy]
+ignore_missing_imports = true # Ignore missing stubs in imported modules
+
+[tool.isort]
+float_to_top = true
+profile = "black"
+
+[tool.flake8]
+extend-ignore = [
+ "E203", # See https://github.com/PyCQA/pycodestyle/issues/373
+ "F811", # support typing.overload decorator
+ "F722", # allow Annotated[typ, some_func("some string")]
+]
+max-line-length = 88 # Respect black's line length (default 88),
+exclude = [".tox", "venv"]
+
+
+[tool.pytest.ini_options]
+# Run pytest with all our checkers, and don't spam us with massive tracebacks on error
+addopts = """
+ --tb=native -vv --doctest-modules --doctest-glob="*.rst"
+ --cov=hdf5_reader_service --cov-report term --cov-report xml:cov.xml
+ """
+# https://iscinumpy.gitlab.io/post/bound-version-constraints/#watch-for-warnings
+filterwarnings = "error"
+# Doctest python code in docs, python code in src docstrings, test functions in tests
+testpaths = "docs src tests"
+
+[tool.coverage.run]
+data_file = "/tmp/hdf5_reader_service.coverage"
+
+[tool.coverage.paths]
+# Tests are run from installed location, map back to the src directory
+source = ["src", "**/site-packages/"]
+
+# tox must currently be configured via an embedded ini string
+# See: https://github.com/tox-dev/tox/issues/999
+[tool.tox]
+legacy_tox_ini = """
+[tox]
+skipsdist=True
+
+[testenv:{pre-commit,mypy,pytest,docs}]
+# Don't create a virtualenv for the command, requires tox-direct plugin
+direct = True
+passenv = *
+allowlist_externals =
+ pytest
+ pre-commit
+ mypy
+ sphinx-build
+ sphinx-autobuild
+commands =
+ pytest: pytest {posargs}
+ mypy: mypy src tests {posargs}
+ pre-commit: pre-commit run --all-files {posargs}
+ docs: sphinx-{posargs:build -EW --keep-going} -T docs build/html
+"""
diff --git a/setup.cfg b/setup.cfg
deleted file mode 100644
index 2a71d31..0000000
--- a/setup.cfg
+++ /dev/null
@@ -1,96 +0,0 @@
-[metadata]
-name = hdf5-reader-service
-description = Microservice for reading HDF5 data and serving it via REST, aimed at performance and concurrency
-url = https://github.com/dls-controls/hdf5-reader-service
-author = Oliver Copping
-author_email = oliver.copping@diamond.ac.uk
-license = Apache License 2.0
-long_description = file: README.rst
-long_description_content_type = text/x-rst
-classifiers =
- Development Status :: 4 - Beta
- License :: OSI Approved :: Apache Software License
- Programming Language :: Python :: 3.8
- Programming Language :: Python :: 3.9
- Programming Language :: Python :: 3.10
-
-[options]
-python_requires = >=3.8
-packages = find:
-# =src is interpreted as {"": "src"}
-# as per recommendation here https://hynek.me/articles/testing-packaging/
-package_dir =
- =src
-
-# Specify any package dependencies below.
-install_requires =
- h5py
- fastapi
- uvicorn
- orjson
- click
-
-[options.extras_require]
-# For development tests/docs
-dev =
- black==22.3.0
- isort>5.0
- pytest-cov
- mypy
- # remove this dependency once flake8 has dropped "importlib-metadata <=4.3"
- # https://github.com/PyCQA/flake8/pull/1438
- flake8 <= 3.9.2
- flake8-isort
- sphinx-rtd-theme-github-versions
- pre-commit
- typed-ast
-
-[options.packages.find]
-where = src
-
-# Specify any package data to be included in the wheel below.
-# [options.package_data]
-# hdf5_reader_service =
-# subpackage/*.yaml
-
-[options.entry_points]
-# Include a command line script
-console_scripts =
- hdf5-reader-service = hdf5_reader_service.main:main
-
-[mypy]
-# Ignore missing stubs for modules we use
-ignore_missing_imports = True
-
-[isort]
-profile=black
-float_to_top=true
-
-[flake8]
-# Make flake8 respect black's line length (default 88),
-max-line-length = 88
-extend-ignore =
- E203, # See https://github.com/PyCQA/pycodestyle/issues/373
- F811, # support typing.overload decorator
-
-[tool:pytest]
-# Run pytest with all our checkers, and don't spam us with massive tracebacks on error
-addopts =
- --tb=native -vv --doctest-modules --doctest-glob="*.rst"
- --cov=hdf5_reader_service --cov-report term --cov-report xml:cov.xml
-# https://iscinumpy.gitlab.io/post/bound-version-constraints/#watch-for-warnings
-filterwarnings = error
-# Doctest python code in docs, python code in src docstrings, test functions in tests
-testpaths =
- docs src tests
-
-[coverage:run]
-# This is covered in the versiongit test suite so exclude it here
-omit = */_version_git.py
-data_file = /tmp/hdf5_reader_service.coverage
-
-[coverage:paths]
-# Tests are run from installed location, map back to the src directory
-source =
- src
- **/site-packages/
diff --git a/setup.py b/setup.py
deleted file mode 100644
index 39de827..0000000
--- a/setup.py
+++ /dev/null
@@ -1,13 +0,0 @@
-# type: ignore
-import glob
-import importlib.util
-
-from setuptools import setup
-
-# Import ._version_git.py without importing
-path = glob.glob(__file__.replace("setup.py", "src/*/_version_git.py"))[0]
-spec = importlib.util.spec_from_file_location("_version_git", path)
-vg = importlib.util.module_from_spec(spec)
-spec.loader.exec_module(vg)
-
-setup(cmdclass=vg.get_cmdclass(), version=vg.__version__)
diff --git a/src/hdf5_reader_service/__init__ copy.py b/src/hdf5_reader_service/__init__ copy.py
new file mode 100644
index 0000000..fb7d9ae
--- /dev/null
+++ b/src/hdf5_reader_service/__init__ copy.py
@@ -0,0 +1,5 @@
+from ._version_git import __version__
+
+# __all__ defines the public API for the package.
+# Each module also defines its own __all__.
+__all__ = ["__version__"]
diff --git a/src/hdf5_reader_service/__init__.py b/src/hdf5_reader_service/__init__.py
index fb7d9ae..40f6f34 100644
--- a/src/hdf5_reader_service/__init__.py
+++ b/src/hdf5_reader_service/__init__.py
@@ -1,5 +1,11 @@
-from ._version_git import __version__
+import sys
+
+if sys.version_info < (3, 8):
+ from importlib_metadata import version # noqa
+else:
+ from importlib.metadata import version # noqa
+
+__version__ = version("hdf5-reader-service")
+del version
-# __all__ defines the public API for the package.
-# Each module also defines its own __all__.
__all__ = ["__version__"]
diff --git a/src/hdf5_reader_service/__main__.py b/src/hdf5_reader_service/__main__.py
new file mode 100644
index 0000000..9684740
--- /dev/null
+++ b/src/hdf5_reader_service/__main__.py
@@ -0,0 +1,30 @@
+import click
+
+from . import __version__
+from .app import app
+
+
+@click.group(invoke_without_command=True)
+@click.option(
+ "-h",
+ "--host",
+ type=str,
+ help="host IP",
+ default="0.0.0.0",
+)
+@click.option(
+ "-p",
+ "--port",
+ type=int,
+ help="host port",
+ default="8000",
+)
+@click.version_option(version=__version__, prog_name="hdf5-reader-service")
+def main(host: str, port: int) -> None:
+ import uvicorn
+
+ uvicorn.run(app, host=host, port=port)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/src/hdf5_reader_service/app.py b/src/hdf5_reader_service/app.py
new file mode 100644
index 0000000..f14aa3c
--- /dev/null
+++ b/src/hdf5_reader_service/app.py
@@ -0,0 +1,12 @@
+from fastapi import FastAPI
+
+from .api import router
+
+# Setup the app
+app = FastAPI()
+app.include_router(router)
+
+
+@app.get("/")
+def index():
+ return {"INFO": "Please provide a path to the HDF5 file, e.g. '/file/'."}
diff --git a/src/hdf5_reader_service/main.py b/src/hdf5_reader_service/main.py
deleted file mode 100644
index fad7b42..0000000
--- a/src/hdf5_reader_service/main.py
+++ /dev/null
@@ -1,43 +0,0 @@
-import click
-from fastapi import FastAPI # , Response, status
-
-from ._version_git import __version__
-from .api import router
-
-# Setup the app
-app = FastAPI()
-app.include_router(router)
-
-
-@app.get("/")
-def index():
- return {"INFO": "Please provide a path to the HDF5 file, e.g. '/file/'."}
-
-
-# @app.get("/busy")
-# def busy(response: Response):
-# if LOCK.locked():
-# response.status_code = status.HTTP_423_LOCKED
-# return {"busy": LOCK.locked()}
-
-
-@click.group(invoke_without_command=True)
-@click.option(
- "-h",
- "--host",
- type=str,
- help="host IP",
- default="0.0.0.0",
-)
-@click.option(
- "-p",
- "--port",
- type=int,
- help="host port",
- default="8000",
-)
-@click.version_option(version=__version__)
-def main(host: str, port: int) -> None:
- import uvicorn
-
- uvicorn.run(app, host=host, port=port)
diff --git a/src/hdf5_reader_service/tasks/metadata.py b/src/hdf5_reader_service/tasks/metadata.py
index 3de6d07..e8196dc 100644
--- a/src/hdf5_reader_service/tasks/metadata.py
+++ b/src/hdf5_reader_service/tasks/metadata.py
@@ -13,7 +13,6 @@
def fetch_metadata(path: str, subpath: str, swmr: bool) -> MetadataNode:
-
path = "/" + path
with h5py.File(path, "r", swmr=swmr, libver="latest") as f:
diff --git a/src/hdf5_reader_service/tasks/shapes.py b/src/hdf5_reader_service/tasks/shapes.py
index be9d88b..070c5ff 100644
--- a/src/hdf5_reader_service/tasks/shapes.py
+++ b/src/hdf5_reader_service/tasks/shapes.py
@@ -5,7 +5,6 @@
def fetch_shapes(path: str, subpath: str, swmr: bool) -> DataTree[ShapeMetadata]:
-
path = "/" + path
def get_shape(name: str, obj: h5py.HLObject) -> ShapeMetadata:
diff --git a/tests/test_boilerplate_removed copy.py b/tests/test_boilerplate_removed copy.py
new file mode 100644
index 0000000..59fafed
--- /dev/null
+++ b/tests/test_boilerplate_removed copy.py
@@ -0,0 +1,97 @@
+"""
+This file checks that all the example boilerplate text has been removed.
+It can be deleted when all the contained tests pass
+"""
+import configparser
+from pathlib import Path
+
+import pytest
+
+ROOT = Path(__file__).parent.parent
+
+
+def skeleton_check(check: bool, text: str):
+ if ROOT.name == "dls-python3-skeleton":
+ # In the skeleton module the check should fail
+ check = not check
+ text = f"Skeleton didn't raise: {text}"
+ if check:
+ raise AssertionError(text)
+
+
+def assert_not_contains_text(path: str, text: str, explanation: str):
+ full_path = ROOT / path
+ if full_path.exists():
+ contents = full_path.read_text().replace("\n", " ")
+ skeleton_check(text in contents, f"Please change ./{path} {explanation}")
+
+
+def assert_not_exists(path: str, explanation: str):
+ exists = (ROOT / path).exists()
+ skeleton_check(exists, f"Please delete ./{path} {explanation}")
+
+
+# setup.cfg
+
+
+@pytest.mark.skip("development needed")
+def test_module_description():
+ conf = configparser.ConfigParser()
+ conf.read("setup.cfg")
+ description = conf["metadata"]["description"]
+ skeleton_check(
+ "One line description of your module" in description,
+ "Please change description in ./setup.cfg "
+ "to be a one line description of your module",
+ )
+
+
+# README
+
+
+@pytest.mark.skip("development needed")
+def test_changed_README_intro():
+ assert_not_contains_text(
+ "README.rst",
+ "This is where you should write a short paragraph",
+ "to include an intro on what your module does",
+ )
+
+
+@pytest.mark.skip("development needed")
+def test_changed_README_body():
+ assert_not_contains_text(
+ "README.rst",
+ "This is where you should put some images or code snippets",
+ "to include some features and why people should use it",
+ )
+
+
+# Docs
+@pytest.mark.skip(
+ "pending https://github.com/DiamondLightSource/python-hdf5-reader-service/issues/3"
+)
+def test_docs_ref_api_changed():
+ assert_not_contains_text(
+ "docs/reference/api.rst",
+ "You can mix verbose text with docstring and signature",
+ "to introduce the API for your module",
+ )
+
+
+@pytest.mark.skip(
+ "pending https://github.com/DiamondLightSource/python-hdf5-reader-service/issues/3"
+)
+def test_how_tos_written():
+ assert_not_exists(
+ "docs/how-to/accomplish-a-task.rst", "and write some docs/how-tos"
+ )
+
+
+@pytest.mark.skip(
+ "pending https://github.com/DiamondLightSource/python-hdf5-reader-service/issues/3"
+)
+def test_explanations_written():
+ assert_not_exists(
+ "docs/explanations/why-is-something-so.rst", "and write some docs/explanations"
+ )
diff --git a/tests/test_boilerplate_removed.py b/tests/test_boilerplate_removed.py
index 59fafed..931a44f 100644
--- a/tests/test_boilerplate_removed.py
+++ b/tests/test_boilerplate_removed.py
@@ -2,16 +2,19 @@
This file checks that all the example boilerplate text has been removed.
It can be deleted when all the contained tests pass
"""
-import configparser
+import sys
from pathlib import Path
-import pytest
+if sys.version_info < (3, 8):
+ from importlib_metadata import metadata # noqa
+else:
+ from importlib.metadata import metadata # noqa
ROOT = Path(__file__).parent.parent
def skeleton_check(check: bool, text: str):
- if ROOT.name == "dls-python3-skeleton":
+ if ROOT.name == "python3-pip-skeleton" or str(ROOT) == "/project":
# In the skeleton module the check should fail
check = not check
text = f"Skeleton didn't raise: {text}"
@@ -26,30 +29,17 @@ def assert_not_contains_text(path: str, text: str, explanation: str):
skeleton_check(text in contents, f"Please change ./{path} {explanation}")
-def assert_not_exists(path: str, explanation: str):
- exists = (ROOT / path).exists()
- skeleton_check(exists, f"Please delete ./{path} {explanation}")
-
-
-# setup.cfg
-
-
-@pytest.mark.skip("development needed")
-def test_module_description():
- conf = configparser.ConfigParser()
- conf.read("setup.cfg")
- description = conf["metadata"]["description"]
+# pyproject.toml
+def test_module_summary():
+ summary = metadata("hdf5-reader-service")["summary"]
skeleton_check(
- "One line description of your module" in description,
- "Please change description in ./setup.cfg "
+ "One line description of your module" in summary,
+ "Please change project.description in ./pyproject.toml "
"to be a one line description of your module",
)
# README
-
-
-@pytest.mark.skip("development needed")
def test_changed_README_intro():
assert_not_contains_text(
"README.rst",
@@ -58,40 +48,17 @@ def test_changed_README_intro():
)
-@pytest.mark.skip("development needed")
-def test_changed_README_body():
+def test_removed_adopt_skeleton():
assert_not_contains_text(
"README.rst",
- "This is where you should put some images or code snippets",
- "to include some features and why people should use it",
+ "This project contains template code only",
+ "remove the note at the start",
)
-# Docs
-@pytest.mark.skip(
- "pending https://github.com/DiamondLightSource/python-hdf5-reader-service/issues/3"
-)
-def test_docs_ref_api_changed():
+def test_changed_README_body():
assert_not_contains_text(
- "docs/reference/api.rst",
- "You can mix verbose text with docstring and signature",
- "to introduce the API for your module",
- )
-
-
-@pytest.mark.skip(
- "pending https://github.com/DiamondLightSource/python-hdf5-reader-service/issues/3"
-)
-def test_how_tos_written():
- assert_not_exists(
- "docs/how-to/accomplish-a-task.rst", "and write some docs/how-tos"
- )
-
-
-@pytest.mark.skip(
- "pending https://github.com/DiamondLightSource/python-hdf5-reader-service/issues/3"
-)
-def test_explanations_written():
- assert_not_exists(
- "docs/explanations/why-is-something-so.rst", "and write some docs/explanations"
+ "README.rst",
+ "This is where you should put some images or code snippets",
+ "to include some features and why people should use it",
)
diff --git a/tests/test_cli.py b/tests/test_cli.py
new file mode 100644
index 0000000..fcf5c7c
--- /dev/null
+++ b/tests/test_cli.py
@@ -0,0 +1,12 @@
+import subprocess
+import sys
+
+from hdf5_reader_service import __version__
+
+
+def test_cli_version():
+ cmd = [sys.executable, "-m", "hdf5_reader_service", "--version"]
+ assert (
+ subprocess.check_output(cmd).decode().strip()
+ == f"hdf5-reader-service, version {__version__}"
+ )
diff --git a/tests/test_system.py b/tests/test_system.py
index e74ef1f..d1a08c8 100644
--- a/tests/test_system.py
+++ b/tests/test_system.py
@@ -4,7 +4,7 @@
import pytest
from fastapi.testclient import TestClient
-from hdf5_reader_service.main import app
+from hdf5_reader_service.app import app
from hdf5_reader_service.model import (
DataTree,
MetadataNode,
@@ -41,7 +41,7 @@ def test_read_shapes(
shape: DataTree[ShapeMetadata],
):
response = client.get(
- "/shapes/", params={"path": test_data_path, "subpath": subpath}
+ "/shapes/", params={"path": str(test_data_path), "subpath": subpath}
)
assert response.status_code == 200
actual_shape = DataTree[ShapeMetadata].parse_obj(response.json())
@@ -52,7 +52,9 @@ def test_read_shapes(
def test_read_tree(
client: TestClient, test_data_path: Path, subpath: str, tree: DataTree[MetadataNode]
):
- response = client.get("/tree/", params={"path": test_data_path, "subpath": subpath})
+ response = client.get(
+ "/tree/", params={"path": str(test_data_path), "subpath": subpath}
+ )
assert response.status_code == 200
actual_tree = DataTree[MetadataNode].parse_obj(response.json())
assert actual_tree == tree
@@ -62,7 +64,9 @@ def test_read_tree(
def test_read_info(
client: TestClient, test_data_path: Path, subpath: str, metadata: MetadataNode
):
- response = client.get("/info/", params={"path": test_data_path, "subpath": subpath})
+ response = client.get(
+ "/info/", params={"path": str(test_data_path), "subpath": subpath}
+ )
assert response.status_code == 200
actual_metadata = MetadataNode.parse_obj(response.json())
assert actual_metadata == metadata
@@ -73,7 +77,7 @@ def test_read_search(
client: TestClient, test_data_path: Path, subpath: str, children: NodeChildren
):
response = client.get(
- "/search/", params={"path": test_data_path, "subpath": subpath}
+ "/search/", params={"path": str(test_data_path), "subpath": subpath}
)
assert response.status_code == 200
actual_children = NodeChildren.parse_obj(response.json())
@@ -90,7 +94,7 @@ def test_read_slice(
response = client.get(
"/slice/",
params={
- "path": test_data_path,
+ "path": str(test_data_path),
"subpath": "/entry/DIFFRACTION/data",
"slice_info": slice_info,
},