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, },