From e12fba4aa691941f421e5c190d72b2c23acc60d9 Mon Sep 17 00:00:00 2001 From: Jelmer Date: Sun, 10 Sep 2023 23:43:00 +0200 Subject: [PATCH] Release camelot-fork 0.20.1 (#353) This PR contains a ton of improvements. They are merged via a squash-commit, but the individual changes are visible in the PR: * Add hypermodern python to the original repo * Add conftest.py and skip tests that depend on poppler * Align the type of PDFHandler.filepath with PdfReader.stream so Path and IO objects are accepted * Pre-commit * Initialized Table.df as empty DataFrame * Fixed: ValueError: min() arg is an empty sequence * Fix: unwanted data leaks into the last cell * added test case for method bbox_no_intersection method * Update test fixtures and remove unused imports * Fixed ZeroDivisionError in text_in_bbox * camelot-fork 0.20.1 * chore: revert changes to README.md * Remove references from pyproject to the fork * Fix install ghostscript * Poetry update * Removed references to me as person or to the camelot-fork repo --------- Co-authored-by: Jinjun Liang Co-authored-by: Manish Patwari Co-authored-by: zhy Co-authored-by: Rahul.Bhave Co-authored-by: Constantine Parkhimovich --- .coveragerc | 2 - .flake8 | 9 + .gitattributes | 1 + .github/ISSUE_TEMPLATE/bug_report.md | 5 +- .github/dependabot.yml | 21 + .github/labels.yml | 66 + .github/release-drafter.yml | 29 + .github/workflows/constraints.txt | 6 + .github/workflows/labeler.yml | 19 + .github/workflows/release.yml | 79 + .github/workflows/tests.yml | 173 +- .gitignore | 29 +- .pre-commit-config.yaml | 59 + .readthedocs.yml | 29 +- CODE_OF_CONDUCT.md | 135 +- CONTRIBUTING.md | 166 +- HISTORY.md | 275 +- MANIFEST.in | 1 - Makefile | 28 - README.md | 6 +- camelot/__init__.py | 2 - camelot/__main__.py | 3 - camelot/__version__.py | 2 - camelot/backends/__init__.py | 2 - camelot/backends/ghostscript_backend.py | 6 +- camelot/backends/image_conversion.py | 7 +- camelot/backends/poppler_backend.py | 4 +- camelot/cli.py | 9 +- camelot/core.py | 17 +- camelot/handlers.py | 146 +- camelot/image_processing.py | 2 - camelot/io.py | 29 +- camelot/parsers/__init__.py | 4 +- camelot/parsers/base.py | 7 +- camelot/parsers/lattice.py | 48 +- camelot/parsers/stream.py | 25 +- camelot/plotting.py | 6 +- camelot/py.typed | 0 camelot/utils.py | 43 +- codecov.yml | 9 + docs/_static/csv/foo.csv | 2 +- docs/_templates/hacks.html | 30 +- docs/_templates/sidebarintro.html | 16 +- docs/_templates/sidebarlogo.html | 12 +- docs/_themes/.gitignore | 2 +- docs/_themes/LICENSE | 2 +- docs/_themes/flask_theme_support.py | 26 +- docs/api.rst | 2 +- .../lattice/agstat/agstat-data-pdfplumber.csv | 2 +- .../column_span_1-data-pdfplumber.csv | 8 +- .../rotated/rotated-data-pdfplumber.csv | 6 +- .../district_health-data-pdfplumber.csv | 50 +- .../stream/health/health-data-pdfplumber.csv | 4 +- .../missing_values-data-pdfplumber.csv | 56 +- docs/conf.py | 20 +- docs/dev/contributing.rst | 2 +- docs/requirements.txt | 7 + docs/user/intro.rst | 2 +- noxfile.py | 254 ++ poetry.lock | 2483 +++++++++++++++++ pyproject.toml | 94 + setup.cfg | 6 - setup.py | 91 - tests/__init__.py | 1 + tests/conftest.py | 24 + tests/data.py | 3 +- .../competition-dataset-eu/eu-001.json | 7 +- .../competition-dataset-eu/eu-002.json | 7 +- .../competition-dataset-eu/eu-003.json | 7 +- .../competition-dataset-eu/eu-004.json | 7 +- .../competition-dataset-eu/eu-005.json | 7 +- .../competition-dataset-eu/eu-006.json | 7 +- .../competition-dataset-eu/eu-007.json | 7 +- .../competition-dataset-eu/eu-008.json | 7 +- .../competition-dataset-eu/eu-009a-str.xml | 2 +- .../competition-dataset-eu/eu-009a.json | 7 +- .../competition-dataset-eu/eu-009b-str.xml | 2 +- .../competition-dataset-eu/eu-010.json | 7 +- .../competition-dataset-eu/eu-011.json | 7 +- .../competition-dataset-eu/eu-012.json | 7 +- .../competition-dataset-eu/eu-013.json | 7 +- .../competition-dataset-eu/eu-014.json | 7 +- .../competition-dataset-eu/eu-015.json | 7 +- .../competition-dataset-eu/eu-016.json | 7 +- .../competition-dataset-eu/eu-017.json | 7 +- .../competition-dataset-eu/eu-018.json | 7 +- .../competition-dataset-eu/eu-019.json | 7 +- .../competition-dataset-eu/eu-020.json | 7 +- .../competition-dataset-eu/eu-021.json | 7 +- .../competition-dataset-eu/eu-022.json | 7 +- .../competition-dataset-eu/eu-023.json | 7 +- .../competition-dataset-eu/eu-024.json | 7 +- .../competition-dataset-eu/eu-025.json | 7 +- .../competition-dataset-eu/eu-026.json | 7 +- .../competition-dataset-eu/eu-027.json | 7 +- .../competition-dataset-us/us-001.json | 7 +- .../competition-dataset-us/us-002.json | 7 +- .../competition-dataset-us/us-003.json | 7 +- .../competition-dataset-us/us-004.json | 7 +- .../competition-dataset-us/us-005.json | 7 +- .../competition-dataset-us/us-006.json | 7 +- .../competition-dataset-us/us-007.json | 7 +- .../competition-dataset-us/us-008.json | 7 +- .../competition-dataset-us/us-009.json | 7 +- .../competition-dataset-us/us-010.json | 7 +- .../competition-dataset-us/us-011a.json | 7 +- .../competition-dataset-us/us-012.json | 7 +- .../competition-dataset-us/us-013.json | 7 +- .../competition-dataset-us/us-014-str.xml | 2 +- .../competition-dataset-us/us-014.json | 7 +- .../competition-dataset-us/us-015.json | 7 +- .../competition-dataset-us/us-016.json | 7 +- .../competition-dataset-us/us-017.json | 7 +- .../competition-dataset-us/us-018.json | 7 +- .../competition-dataset-us/us-019.json | 7 +- .../competition-dataset-us/us-020.json | 7 +- .../competition-dataset-us/us-021.json | 7 +- .../competition-dataset-us/us-022.json | 7 +- .../competition-dataset-us/us-023.json | 7 +- .../competition-dataset-us/us-024.json | 7 +- .../competition-dataset-us/us-025-str.xml | 12 +- .../competition-dataset-us/us-025.json | 7 +- .../competition-dataset-us/us-026.json | 7 +- .../competition-dataset-us/us-027.json | 7 +- .../competition-dataset-us/us-028.json | 7 +- .../competition-dataset-us/us-029.json | 7 +- .../competition-dataset-us/us-030.json | 7 +- .../competition-dataset-us/us-031a.json | 7 +- .../competition-dataset-us/us-032.json | 7 +- .../competition-dataset-us/us-033.json | 7 +- .../competition-dataset-us/us-034.json | 7 +- .../competition-dataset-us/us-035a.json | 7 +- .../competition-dataset-us/us-036.json | 7 +- .../competition-dataset-us/us-037.json | 7 +- .../competition-dataset-us/us-038.json | 7 +- .../competition-dataset-us/us-039.json | 7 +- .../competition-dataset-us/us-040.json | 7 +- tests/test_cli.py | 24 +- tests/test_common.py | 58 +- tests/test_errors.py | 74 +- tests/test_image_conversion_backend.py | 44 +- tests/test_lattice.py | 33 +- tests/test_plotting.py | 47 +- tests/test_stream.py | 32 +- tests/test_utils.py | 45 + 145 files changed, 4583 insertions(+), 975 deletions(-) delete mode 100644 .coveragerc create mode 100644 .flake8 create mode 100644 .gitattributes create mode 100644 .github/dependabot.yml create mode 100644 .github/labels.yml create mode 100644 .github/release-drafter.yml create mode 100644 .github/workflows/constraints.txt create mode 100644 .github/workflows/labeler.yml create mode 100644 .github/workflows/release.yml create mode 100644 .pre-commit-config.yaml delete mode 100644 MANIFEST.in delete mode 100644 Makefile mode change 100755 => 100644 camelot/__main__.py create mode 100644 camelot/py.typed create mode 100644 codecov.yml create mode 100644 docs/requirements.txt create mode 100644 noxfile.py create mode 100644 poetry.lock create mode 100644 pyproject.toml delete mode 100644 setup.cfg delete mode 100644 setup.py create mode 100644 tests/conftest.py mode change 100755 => 100644 tests/data.py mode change 100755 => 100644 tests/test_cli.py mode change 100755 => 100644 tests/test_errors.py create mode 100644 tests/test_utils.py diff --git a/.coveragerc b/.coveragerc deleted file mode 100644 index 398ff08a..00000000 --- a/.coveragerc +++ /dev/null @@ -1,2 +0,0 @@ -[run] -branch = True diff --git a/.flake8 b/.flake8 new file mode 100644 index 00000000..a2b5078b --- /dev/null +++ b/.flake8 @@ -0,0 +1,9 @@ +[flake8] +select = B,B9,C,D,DAR,E,F,N,RST,S,W +ignore = E203,E501,RST201,RST203,RST301,W503 +max-line-length = 120 +max-complexity = 10 +docstring-convention = google +per-file-ignores = tests/*:S101 +rst-roles = class,const,func,meth,mod,ref +rst-directives = deprecated diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..6313b56c --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +* text=auto eol=lf diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 1d39ef13..b86ee533 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -1,10 +1,9 @@ --- name: Bug report about: Please follow this template to submit bug reports. -title: '' +title: "" labels: bug -assignees: '' - +assignees: "" --- diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..2beb2698 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,21 @@ +version: 2 +updates: + - package-ecosystem: github-actions + directory: "/" + schedule: + interval: daily + - package-ecosystem: pip + directory: "/.github/workflows" + schedule: + interval: daily + - package-ecosystem: pip + directory: "/docs" + schedule: + interval: daily + - package-ecosystem: pip + directory: "/" + schedule: + interval: daily + versioning-strategy: lockfile-only + allow: + - dependency-type: "all" diff --git a/.github/labels.yml b/.github/labels.yml new file mode 100644 index 00000000..21a15056 --- /dev/null +++ b/.github/labels.yml @@ -0,0 +1,66 @@ +--- +# Labels names are important as they are used by Release Drafter to decide +# regarding where to record them in changelog or if to skip them. +# +# The repository labels will be automatically configured using this file and +# the GitHub Action https://github.com/marketplace/actions/github-labeler. +- name: breaking + description: Breaking Changes + color: bfd4f2 +- name: bug + description: Something isn't working + color: d73a4a +- name: build + description: Build System and Dependencies + color: bfdadc +- name: ci + description: Continuous Integration + color: 4a97d6 +- name: dependencies + description: Pull requests that update a dependency file + color: 0366d6 +- name: documentation + description: Improvements or additions to documentation + color: 0075ca +- name: duplicate + description: This issue or pull request already exists + color: cfd3d7 +- name: enhancement + description: New feature or request + color: a2eeef +- name: github_actions + description: Pull requests that update Github_actions code + color: "000000" +- name: good first issue + description: Good for newcomers + color: 7057ff +- name: help wanted + description: Extra attention is needed + color: "008672" +- name: invalid + description: This doesn't seem right + color: e4e669 +- name: performance + description: Performance + color: "016175" +- name: python + description: Pull requests that update Python code + color: 2b67c6 +- name: question + description: Further information is requested + color: d876e3 +- name: refactoring + description: Refactoring + color: ef67c4 +- name: removal + description: Removals and Deprecations + color: 9ae7ea +- name: style + description: Style + color: c120e5 +- name: testing + description: Testing + color: b1fc6f +- name: wontfix + description: This will not be worked on + color: ffffff diff --git a/.github/release-drafter.yml b/.github/release-drafter.yml new file mode 100644 index 00000000..7a04410f --- /dev/null +++ b/.github/release-drafter.yml @@ -0,0 +1,29 @@ +categories: + - title: ":boom: Breaking Changes" + label: "breaking" + - title: ":rocket: Features" + label: "enhancement" + - title: ":fire: Removals and Deprecations" + label: "removal" + - title: ":beetle: Fixes" + label: "bug" + - title: ":racehorse: Performance" + label: "performance" + - title: ":rotating_light: Testing" + label: "testing" + - title: ":construction_worker: Continuous Integration" + label: "ci" + - title: ":books: Documentation" + label: "documentation" + - title: ":hammer: Refactoring" + label: "refactoring" + - title: ":lipstick: Style" + label: "style" + - title: ":package: Dependencies" + labels: + - "dependencies" + - "build" +template: | + ## Changes + + $CHANGES diff --git a/.github/workflows/constraints.txt b/.github/workflows/constraints.txt new file mode 100644 index 00000000..55b382dc --- /dev/null +++ b/.github/workflows/constraints.txt @@ -0,0 +1,6 @@ +lockfile<0.13.0,>=0.12.2 +pip==23.0 +nox==2022.11.21 +nox-poetry==1.0.2 +poetry>=1.2.0 +virtualenv==20.19.0 diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml new file mode 100644 index 00000000..9da4ff43 --- /dev/null +++ b/.github/workflows/labeler.yml @@ -0,0 +1,19 @@ +name: Labeler + +on: + push: + branches: + - main + - master + +jobs: + labeler: + runs-on: ubuntu-latest + steps: + - name: Check out the repository + uses: actions/checkout@v3 + + - name: Run Labeler + uses: crazy-max/ghaction-github-labeler@v4.0.0 + with: + skip-delete: true diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..fb467ab7 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,79 @@ +name: Release + +on: + push: + branches: + - main + - master + +jobs: + release: + name: Release + runs-on: ubuntu-latest + steps: + - name: Check out the repository + uses: actions/checkout@v3 + with: + fetch-depth: 2 + + - name: Set up Python + uses: actions/setup-python@v3 + with: + python-version: "3.10" + + - name: Upgrade pip + run: | + pip install --constraint=.github/workflows/constraints.txt pip + pip --version + + - name: Install Poetry + run: | + pip install --constraint=.github/workflows/constraints.txt poetry + poetry --version + + - name: Check if there is a parent commit + id: check-parent-commit + run: | + echo "::set-output name=sha::$(git rev-parse --verify --quiet HEAD^)" + + - name: Detect and tag new version + id: check-version + if: steps.check-parent-commit.outputs.sha + uses: salsify/action-detect-and-tag-new-version@v2.0.1 + with: + version-command: | + bash -o pipefail -c "poetry version | awk '{ print \$2 }'" + + - name: Bump version for developmental release + if: "! steps.check-version.outputs.tag" + run: | + poetry version patch && + version=$(poetry version | awk '{ print $2 }') && + poetry version $version.dev.$(date +%s) + + - name: Build package + run: | + poetry build --ansi + + - name: Publish package on PyPI + if: steps.check-version.outputs.tag + uses: pypa/gh-action-pypi-publish@v1.5.0 + with: + user: __token__ + password: ${{ secrets.PYPI_TOKEN }} + + - name: Publish package on TestPyPI + if: "! steps.check-version.outputs.tag" + uses: pypa/gh-action-pypi-publish@v1.5.0 + with: + user: __token__ + password: ${{ secrets.TEST_PYPI_TOKEN }} + repository_url: https://test.pypi.org/legacy/ + + - name: Publish the release notes + uses: release-drafter/release-drafter@v5.20.0 + with: + publish: ${{ steps.check-version.outputs.tag != '' }} + tag: ${{ steps.check-version.outputs.tag }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index c63850bf..9bff42ee 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -1,44 +1,161 @@ -name: tests +name: Tests -on: [pull_request] +on: + - push + - pull_request jobs: - test: - runs-on: ubuntu-latest + tests: + name: ${{ matrix.session }} ${{ matrix.python }} / ${{ matrix.os }} + runs-on: ${{ matrix.os }} strategy: + fail-fast: false matrix: - python-version: ["3.7", "3.8"] + include: + # - { python: "3.10", os: "ubuntu-latest", session: "pre-commit" } + - { python: "3.10", os: "ubuntu-latest", session: "safety" } + # - { python: "3.11", os: "ubuntu-latest", session: "mypy" } + # - { python: "3.10", os: "ubuntu-latest", session: "mypy" } + # - { python: "3.9", os: "ubuntu-latest", session: "mypy" } + # - { python: "3.8", os: "ubuntu-latest", session: "mypy" } + # - { python: "3.7", os: "ubuntu-latest", session: "mypy" } + - { python: "3.11", os: "ubuntu-latest", session: "tests" } + - { python: "3.10", os: "ubuntu-latest", session: "tests" } + - { python: "3.9", os: "ubuntu-latest", session: "tests" } + - { python: "3.8", os: "ubuntu-latest", session: "tests" } + - { python: "3.10", os: "windows-latest", session: "tests" } + - { python: "3.10", os: "macos-latest", session: "tests" } + - { python: "3.10", os: "ubuntu-latest", session: "typeguard" } + - { python: "3.10", os: "ubuntu-latest", session: "xdoctest" } + - { python: "3.10", os: "ubuntu-latest", session: "docs-build" } + + env: + NOXSESSION: ${{ matrix.session }} + FORCE_COLOR: "1" + PRE_COMMIT_COLOR: "always" steps: - - uses: actions/checkout@v3 - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v4 + - name: Check out the repository + uses: actions/checkout@v3 + + - name: Set up Python ${{ matrix.python }} + uses: actions/setup-python@v3 with: - python-version: ${{ matrix.python-version }} - - name: Install camelot with dependencies + python-version: ${{ matrix.python }} + + - name: Upgrade pip run: | - make install - - name: Test with pytest + pip install --constraint=.github/workflows/constraints.txt pip + pip --version + + - name: Upgrade pip in virtual environments + shell: python run: | - make test + import os + import pip - test_latest: - name: Test on ${{ matrix.os }} with Python 3.9 - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [ubuntu-latest, macos-latest, windows-latest] - python-version: ["3.9"] + with open(os.environ["GITHUB_ENV"], mode="a") as io: + print(f"VIRTUALENV_PIP={pip.__version__}", file=io) + + - name: Install Poetry + run: | + pipx install --pip-args=--constraint=.github/workflows/constraints.txt poetry + poetry --version + + - name: Install Nox + run: | + pipx install --pip-args=--constraint=.github/workflows/constraints.txt nox + pipx inject --pip-args=--constraint=.github/workflows/constraints.txt nox nox-poetry + nox --version + + - name: Install ghostscript + if: matrix.os == 'ubuntu-latest' + run: | + sudo apt update + sudo apt install ghostscript + + - name: Compute pre-commit cache key + if: matrix.session == 'pre-commit' + id: pre-commit-cache + shell: python + run: | + import hashlib + import sys + + python = "py{}.{}".format(*sys.version_info[:2]) + payload = sys.version.encode() + sys.executable.encode() + digest = hashlib.sha256(payload).hexdigest() + result = "${{ runner.os }}-{}-{}-pre-commit".format(python, digest[:8]) + + print("::set-output name=result::{}".format(result)) + + - name: Restore pre-commit cache + uses: actions/cache@v3 + if: matrix.session == 'pre-commit' + with: + path: ~/.cache/pre-commit + key: ${{ steps.pre-commit-cache.outputs.result }}-${{ hashFiles('.pre-commit-config.yaml') }} + restore-keys: | + ${{ steps.pre-commit-cache.outputs.result }}- + + - name: Run Nox + run: | + nox --python=${{ matrix.python }} + + - name: Upload coverage data + if: always() && matrix.session == 'tests' + uses: "actions/upload-artifact@v3" + with: + name: coverage-data + path: ".coverage.*" + - name: Upload documentation + if: matrix.session == 'docs-build' + uses: actions/upload-artifact@v3 + with: + name: docs + path: docs/_build + + coverage: + runs-on: ubuntu-latest + needs: tests steps: - - uses: actions/checkout@v3 - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v4 + - name: Check out the repository + uses: actions/checkout@v3 + + - name: Set up Python + uses: actions/setup-python@v3 + with: + python-version: "3.10" + + - name: Upgrade pip + run: | + pip install --constraint=.github/workflows/constraints.txt pip + pip --version + + - name: Install Poetry + run: | + pipx install --pip-args=--constraint=.github/workflows/constraints.txt poetry + poetry --version + + - name: Install Nox + run: | + pipx install --pip-args=--constraint=.github/workflows/constraints.txt nox + pipx inject --pip-args=--constraint=.github/workflows/constraints.txt nox nox-poetry + nox --version + + - name: Download coverage data + uses: actions/download-artifact@v3 with: - python-version: ${{ matrix.python-version }} - - name: Install camelot with dependencies + name: coverage-data + + - name: Combine coverage data and display human readable report run: | - make install - - name: Test with pytest + nox --session=coverage + + - name: Create coverage report run: | - make test + nox --session=coverage -- xml -i + + - name: Upload coverage report + uses: codecov/codecov-action@v3.1.0 diff --git a/.gitignore b/.gitignore index aaeac147..3c9e8e43 100644 --- a/.gitignore +++ b/.gitignore @@ -1,20 +1,11 @@ -fontconfig/ +.mypy_cache/ +/.coverage +/.coverage.* +/.nox/ +/.python-version +/.pytype/ +/dist/ +/docs/_build/ +/src/*.egg-info/ __pycache__/ -*.py[cod] -*.so - -build/ -dist/ -*.egg-info/ -.eggs/ -.coverage -coverage.xml - -.pytest_cache/ -_build/ - -.venv/ -htmlcov/ - -# vscode -.vscode +.idea/ diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 00000000..838b6ba6 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,59 @@ +repos: + - repo: local + hooks: + - id: black + name: black + entry: black + language: system + types: [python] + require_serial: true + - id: check-added-large-files + name: Check for added large files + entry: check-added-large-files + language: system + - id: check-toml + name: Check Toml + entry: check-toml + language: system + types: [toml] + - id: check-yaml + name: Check Yaml + entry: check-yaml + language: system + types: [yaml] + - id: end-of-file-fixer + name: Fix End of Files + entry: end-of-file-fixer + language: system + types: [text] + stages: [commit, push, manual] + - id: flake8 + name: flake8 + entry: flake8 + language: system + types: [python] + require_serial: true + - id: isort + name: isort + entry: isort + require_serial: true + language: system + types_or: [cython, pyi, python] + args: ["--filter-files"] + - id: pyupgrade + name: pyupgrade + description: Automatically upgrade syntax for newer versions. + entry: pyupgrade + language: system + types: [python] + args: [--py37-plus] + - id: trailing-whitespace + name: Trim Trailing Whitespace + entry: trailing-whitespace-fixer + language: system + types: [text] + stages: [commit, push, manual] + - repo: https://github.com/pre-commit/mirrors-prettier + rev: v2.6.0 + hooks: + - id: prettier diff --git a/.readthedocs.yml b/.readthedocs.yml index b5a05bd6..66f2a214 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -1,27 +1,12 @@ -# .readthedocs.yml -# Read the Docs configuration file -# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details - -# Required version: 2 - -# Build documentation in the docs/ directory with Sphinx +build: + os: ubuntu-20.04 + tools: + python: "3.10" sphinx: configuration: docs/conf.py - -# Build documentation with MkDocs -#mkdocs: -# configuration: mkdocs.yml - -# Optionally build your docs in additional formats such as PDF -formats: - - pdf - -# Optionally set the version of Python and requirements required to build your docs +formats: all python: - version: 3.8 install: - - method: pip - path: . - extra_requirements: - - dev + - requirements: docs/requirements.txt + - path: . diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 0a0e0807..1b5cd58f 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -1,3 +1,136 @@ Be cordial or be on your way. --Kenneth Reitz -https://www.kennethreitz.org/essays/2013/01/27/be-cordial-or-be-on-your-way \ No newline at end of file +https://www.kennethreitz.org/essays/2013/01/27/be-cordial-or-be-on-your-way + +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our +community a harassment-free experience for everyone, regardless of age, body +size, visible or invisible disability, ethnicity, sex characteristics, gender +identity and expression, level of experience, education, socio-economic status, +nationality, personal appearance, race, caste, color, religion, or sexual +identity and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our +community include: + +- Demonstrating empathy and kindness toward other people +- Being respectful of differing opinions, viewpoints, and experiences +- Giving and gracefully accepting constructive feedback +- Accepting responsibility and apologizing to those affected by our mistakes, + and learning from the experience +- Focusing on what is best not just for us as individuals, but for the overall + community + +Examples of unacceptable behavior include: + +- The use of sexualized language or imagery, and sexual attention or advances of + any kind +- Trolling, insulting or derogatory comments, and personal or political attacks +- Public or private harassment +- Publishing others' private information, such as a physical or email address, + without their explicit permission +- Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, and will communicate reasons for moderation +decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. +Examples of representing our community include using an official e-mail address, +posting via an official social media account, or acting as an appointed +representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported to the community leaders responsible for enforcement at +https://github.com/camelot-dev/camelot/issues. +All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining +the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed +unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing +clarity around the nature of the violation and an explanation of why the +behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series of +actions. + +**Consequence**: A warning with consequences for continued behavior. No +interaction with the people involved, including unsolicited interaction with +those enforcing the Code of Conduct, for a specified period of time. This +includes avoiding interactions in community spaces as well as external channels +like social media. Violating these terms may lead to a temporary or permanent +ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including +sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public +communication with the community for a specified period of time. No public or +private interaction with the people involved, including unsolicited interaction +with those enforcing the Code of Conduct, is allowed during this period. +Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community +standards, including sustained inappropriate behavior, harassment of an +individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within the +community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 2.1, available at +[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1]. + +Community Impact Guidelines were inspired by +[Mozilla's code of conduct enforcement ladder][mozilla coc]. + +For answers to common questions about this code of conduct, see the FAQ at +[https://www.contributor-covenant.org/faq][faq]. Translations are available at +[https://www.contributor-covenant.org/translations][translations]. + +[homepage]: https://www.contributor-covenant.org +[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html +[mozilla coc]: https://github.com/mozilla/diversity +[faq]: https://www.contributor-covenant.org/faq +[translations]: https://www.contributor-covenant.org/translations diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ae2023fe..364a5aee 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,131 +1,117 @@ -# Contributor's Guide +# Contributor Guide -If you're reading this, you're probably looking to contributing to Camelot. *Time is the only real currency*, and the fact that you're considering spending some here is *very* generous of you. Thank you very much! - -This document will help you get started with contributing documentation, code, testing and filing issues. If you have any questions, feel free to reach out to [Vinayak Mehta](https://vinayak-mehta.github.io), the author and maintainer. - -## Code Of Conduct - -The following quote sums up the **Code Of Conduct**. - - > Be cordial or be on your way. --Kenneth Reitz +Thank you for your interest in improving this project. +This project is open-source under the [MIT license] and +welcomes contributions in the form of bug reports, feature requests, and pull requests. Kenneth Reitz has also written an [essay](https://www.kennethreitz.org/essays/2013/01/27/be-cordial-or-be-on-your-way) on this topic, which you should read. -As the [Requests Code Of Conduct](http://docs.python-requests.org/en/master/dev/contributing/#be-cordial) states, **all contributions are welcome**, as long as everyone involved is treated with respect. - -## Your first contribution - -A great way to start contributing to Camelot is to pick an issue tagged with the [help wanted](https://github.com/camelot-dev/camelot/labels/help%20wanted) tag or the [good first issue](https://github.com/camelot-dev/camelot/labels/good%20first%20issue) tag. If you're unable to find a good first issue, feel free to contact the maintainer. - -## Setting up a development environment - -To install the dependencies needed for development, you can use pip: - -
-$ pip install "camelot-py[dev]"
-
- -Alternatively, you can clone the project repository, and install using pip: +Here is a list of important resources for contributors: -
-$ pip install ".[dev]"
-
+- [Source Code] +- [Documentation] +- [Issue Tracker] +- [Code of Conduct] -## Pull Requests +[mit license]: https://opensource.org/licenses/MIT +[source code]: https://github.com/camelot-dev/camelot +[documentation]: https://camelot-py.readthedocs.io/ +[issue tracker]: https://github.com/camelot-dev/camelot/issues -### Submit a pull request +## How to report a bug -The preferred workflow for contributing to Camelot is to fork the [project repository](https://github.com/camelot-dev/camelot) on GitHub, clone, develop on a branch and then finally submit a pull request. Here are the steps: +Report bugs on the [Issue Tracker]. -1. Fork the project repository. Click on the ‘Fork’ button near the top of the page. This creates a copy of the code under your account on the GitHub. +When filing an issue, make sure to answer these questions: -2. Clone your fork of Camelot from your GitHub account: +- Which operating system and Python version are you using? +- Which version of this project are you using? +- What did you do? +- What did you expect to see? +- What did you see instead? -
-$ git clone https://www.github.com/[username]/camelot
-
+The best way to get your bug fixed is to provide a test case, +and/or steps to reproduce the issue. -3. Create a branch to hold your changes: +## How to request a feature -
-$ git checkout -b my-feature
-
+Request features on the [Issue Tracker]. -Always branch out from `master` to work on your contribution. It's good practice to never work on the `master` branch! +## How to set up your development environment -**Protip: `git stash` is a great way to save the work that you haven't committed yet, to move between branches.** +You need Python 3.7+ and the following tools: -4. Work on your contribution. Add changed files using `git add` and then `git commit` them: +- [Poetry] +- [Nox] +- [nox-poetry] -
-$ git add modified_files
-$ git commit
-
+Install the package with development requirements: -5. Finally, push them to your GitHub fork: +```console +$ poetry install +``` -
-$ git push -u origin my-feature
-
+You can now run an interactive Python session, +or the command-line interface: -Now it's time to go to the your fork of Camelot and create a pull request! You can [follow these instructions](https://help.github.com/articles/creating-a-pull-request-from-a-fork/) to do this. +```console +$ poetry run python +$ poetry run camelot +``` -### Work on your pull request +[poetry]: https://python-poetry.org/ +[nox]: https://nox.thea.codes/ +[nox-poetry]: https://nox-poetry.readthedocs.io/ -We recommend that your pull request complies with the following rules: +## How to test the project -- Make sure your code follows [pep8](http://pep8.org). +Run the full test suite: -- In case your pull request contains function docstrings, make sure you follow the [numpydoc](https://numpydoc.readthedocs.io/en/latest/format.html) format. All function docstrings in Camelot follow this format. Moreover, following the format will make sure that the API documentation is generated flawlessly. +```console +$ nox +``` -- Make sure your commit messages follow [the seven rules of a great git commit message](https://chris.beams.io/posts/git-commit/): - - Separate subject from body with a blank line - - Limit the subject line to 50 characters - - Capitalize the subject line - - Do not end the subject line with a period - - Use the imperative mood in the subject line - - Wrap the body at 72 characters - - Use the body to explain what and why vs. how +List the available Nox sessions: -- Please prefix the title of your pull request with [MRG] (Ready for Merge), if the contribution is complete and ready for a detailed review. An incomplete pull request's title should be prefixed with [WIP] (to indicate a work in progress), and changed to [MRG] when it's complete. A good [task list](https://blog.github.com/2013-01-09-task-lists-in-gfm-issues-pulls-comments/) in the PR description will ensure that other people get a better idea of what it proposes to do, which will also increase collaboration. +```console +$ nox --list-sessions +``` -- If contributing new functionality, make sure that you add a unit test for it, while making sure that all previous tests pass. Camelot uses [pytest](https://docs.pytest.org/en/latest/) for testing. Tests can be run using: +You can also run a specific Nox session. +For example, invoke the unit test suite like this: -
-$ python setup.py test
-
+```console +$ nox --session=tests +``` -## Writing Documentation +Unit tests are located in the _tests_ directory, +and are written using the [pytest] testing framework. -Writing documentation, function docstrings, examples and tutorials is a great way to start contributing to open-source software! The documentation is present inside the `docs/` directory of the project repository. +[pytest]: https://pytest.readthedocs.io/ -It is written in [reStructuredText](https://en.wikipedia.org/wiki/ReStructuredText), with [Sphinx](http://www.sphinx-doc.org/en/master/) used to generate these lovely HTML files that you're currently reading (unless you're reading this on GitHub). You can edit the documentation using any text editor and then generate the HTML output by running `make html` in the `docs/` directory. +## How to submit changes -The function docstrings are written using the [numpydoc](https://numpydoc.readthedocs.io/en/latest/format.html) extension for Sphinx. Make sure you check out its format guidelines before you start writing one. +Open a [pull request] to submit changes to this project. -## Filing Issues +Your pull request needs to meet the following guidelines for acceptance: -We use [GitHub issues](https://github.com/camelot-dev/camelot/issues) to keep track of all issues and pull requests. Before opening an issue (which asks a question or reports a bug), please use GitHub search to look for existing issues (both open and closed) that may be similar. +- The Nox test suite must pass without errors and warnings. +- Include unit tests. This project maintains 100% code coverage. +- If your changes add functionality, update the documentation accordingly. -### Questions +Feel free to submit early, though—we can always iterate on this. -Please don't use GitHub issues for support questions. A better place for them would be [Stack Overflow](http://stackoverflow.com). Make sure you tag them using the `python-camelot` tag. +To run linting and code formatting checks before committing your change, you can install pre-commit as a Git hook by running the following command: -### Bug Reports +```console +$ nox --session=pre-commit -- install +``` -In bug reports, make sure you include: +It is recommended to open an issue before starting work on anything. +This will allow a chance to talk it over with the owners and validate your approach. -- Your operating system type and Python version number, along with the version numbers of NumPy, OpenCV and Camelot. You can use the following code snippet to find this information: +[pull request]: https://github.com/camelot-dev/camelot/pulls -
-import platform; print(platform.platform())
-import sys; print('Python', sys.version)
-import numpy; print('NumPy', numpy.__version__)
-import cv2; print('OpenCV', cv2.__version__)
-import camelot; print('Camelot', camelot.__version__)
-
+ -- The complete traceback. Just adding the exception message or a part of the traceback won't help us fix your issue sooner. -- Steps to reproduce the bug, using code snippets. See [Creating and highlighting code blocks](https://help.github.com/articles/creating-and-highlighting-code-blocks/). -- A link to the PDF document that you were trying to extract tables from, telling us what you expected the code to do and what actually happened. +[code of conduct]: CODE_OF_CONDUCT.md diff --git a/HISTORY.md b/HISTORY.md index ae5ca755..04e5abd9 100755 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,8 +1,6 @@ -Release History -=============== +# Release History -master ------- +## master 0.11.0 (2023-02-26) ------------------ @@ -15,8 +13,9 @@ master - Change extra requirements from `cv` to `base`. You can use `pip install "camelot-py[base]"` to install everything required to run camelot. -0.10.0 (2021-07-11) ------------------- + 0.10.0 (2021-07-11) + +--- **Improvements** @@ -27,8 +26,9 @@ master - Add faq section. [#216](https://github.com/camelot-dev/camelot/pull/216) by [Stefano Fiorucci](https://github.com/anakin87). -0.9.0 (2021-06-15) ------------------- + 0.9.0 (2021-06-15) + +--- **Bugfixes** @@ -52,236 +52,251 @@ master - [#193](https://github.com/camelot-dev/camelot/issues/193) Add better checks to confirm proper installation of ghostscript. [#196](https://github.com/camelot-dev/camelot/pull/196) by [jimhall](https://github.com/jimhall). - Update `advanced.rst` plotting examples. [#119](https://github.com/camelot-dev/camelot/pull/119) by [Jens Diemer](https://github.com/jedie). -0.8.2 (2020-07-27) ------------------- + 0.8.2 (2020-07-27) -* Revert the changes in `0.8.1`. +--- -0.8.1 (2020-07-21) ------------------- +- Revert the changes in `0.8.1`. + + 0.8.1 (2020-07-21) + +--- **Bugfixes** -* [#169](https://github.com/camelot-dev/camelot/issues/169) Fix import error caused by `pdfminer.six==20200720`. [#171](https://github.com/camelot-dev/camelot/pull/171) by Vinayak Mehta. +- [#169](https://github.com/camelot-dev/camelot/issues/169) Fix import error caused by `pdfminer.six==20200720`. [#171](https://github.com/camelot-dev/camelot/pull/171) by Vinayak Mehta. -0.8.0 (2020-05-24) ------------------- + 0.8.0 (2020-05-24) + +--- **Improvements** -* Drop Python 2 support! - * Remove Python 2.7 and 3.5 support. - * Replace all instances of `.format` with f-strings. - * Remove all `__future__` imports. - * Fix HTTP 403 forbidden exception in read_pdf(url) and remove Python 2 urllib support. - * Fix test data. +- Drop Python 2 support! + - Remove Python 2.7 and 3.5 support. + - Replace all instances of `.format` with f-strings. + - Remove all `__future__` imports. + - Fix HTTP 403 forbidden exception in read_pdf(url) and remove Python 2 urllib support. + - Fix test data. **Bugfixes** -* Fix library discovery on Windows. [#32](https://github.com/camelot-dev/camelot/pull/32) by [KOLANICH](https://github.com/KOLANICH). -* Fix calling convention of callback functions. [#34](https://github.com/camelot-dev/camelot/pull/34) by [KOLANICH](https://github.com/KOLANICH). +- Fix library discovery on Windows. [#32](https://github.com/camelot-dev/camelot/pull/32) by [KOLANICH](https://github.com/KOLANICH). +- Fix calling convention of callback functions. [#34](https://github.com/camelot-dev/camelot/pull/34) by [KOLANICH](https://github.com/KOLANICH). -0.7.3 (2019-07-07) ------------------- + 0.7.3 (2019-07-07) + +--- **Improvements** -* Camelot now follows the Black code style! [#1](https://github.com/camelot-dev/camelot/pull/1) and [#3](https://github.com/camelot-dev/camelot/pull/3). +- Camelot now follows the Black code style! [#1](https://github.com/camelot-dev/camelot/pull/1) and [#3](https://github.com/camelot-dev/camelot/pull/3). **Bugfixes** -* Fix Click.HelpFormatter monkey-patch. [#5](https://github.com/camelot-dev/camelot/pull/5) by [Dimiter Naydenov](https://github.com/dimitern). -* Fix strip_text argument getting ignored. [#4](https://github.com/camelot-dev/camelot/pull/4) by [Dimiter Naydenov](https://github.com/dimitern). -* [#25](https://github.com/camelot-dev/camelot/issues/25) edge_tol skipped in read_pdf. [#26](https://github.com/camelot-dev/camelot/pull/26) by Vinayak Mehta. -* Fix pytest deprecation warning. [#2](https://github.com/camelot-dev/camelot/pull/2) by Vinayak Mehta. -* [#293](https://github.com/socialcopsdev/camelot/issues/293) Split text ignores all text to the right of last cut. [#294](https://github.com/socialcopsdev/camelot/pull/294) by Vinayak Mehta. -* [#277](https://github.com/socialcopsdev/camelot/issues/277) Sort TableList by order of tables in PDF. [#283](https://github.com/socialcopsdev/camelot/pull/283) by [Sym Roe](https://github.com/symroe). -* [#312](https://github.com/socialcopsdev/camelot/issues/312) `table_regions` throws `ValueError` when `flavor='stream'`. [#332](https://github.com/socialcopsdev/camelot/pull/332) by Vinayak Mehta. +- Fix Click.HelpFormatter monkey-patch. [#5](https://github.com/camelot-dev/camelot/pull/5) by [Dimiter Naydenov](https://github.com/dimitern). +- Fix strip_text argument getting ignored. [#4](https://github.com/camelot-dev/camelot/pull/4) by [Dimiter Naydenov](https://github.com/dimitern). +- [#25](https://github.com/camelot-dev/camelot/issues/25) edge_tol skipped in read_pdf. [#26](https://github.com/camelot-dev/camelot/pull/26) by Vinayak Mehta. +- Fix pytest deprecation warning. [#2](https://github.com/camelot-dev/camelot/pull/2) by Vinayak Mehta. +- [#293](https://github.com/socialcopsdev/camelot/issues/293) Split text ignores all text to the right of last cut. [#294](https://github.com/socialcopsdev/camelot/pull/294) by Vinayak Mehta. +- [#277](https://github.com/socialcopsdev/camelot/issues/277) Sort TableList by order of tables in PDF. [#283](https://github.com/socialcopsdev/camelot/pull/283) by [Sym Roe](https://github.com/symroe). +- [#312](https://github.com/socialcopsdev/camelot/issues/312) `table_regions` throws `ValueError` when `flavor='stream'`. [#332](https://github.com/socialcopsdev/camelot/pull/332) by Vinayak Mehta. -0.7.2 (2019-01-10) ------------------- + 0.7.2 (2019-01-10) + +--- **Bugfixes** -* [#245](https://github.com/socialcopsdev/camelot/issues/245) Fix AttributeError for encrypted files. [#251](https://github.com/socialcopsdev/camelot/pull/251) by Yatin Taluja. +- [#245](https://github.com/socialcopsdev/camelot/issues/245) Fix AttributeError for encrypted files. [#251](https://github.com/socialcopsdev/camelot/pull/251) by Yatin Taluja. + 0.7.1 (2019-01-06) -0.7.1 (2019-01-06) ------------------- +--- **Bugfixes** -* Move ghostscript import to inside the function so Anaconda builds don't fail. +- Move ghostscript import to inside the function so Anaconda builds don't fail. -0.7.0 (2019-01-05) ------------------- + 0.7.0 (2019-01-05) + +--- **Improvements** -* [#240](https://github.com/socialcopsdev/camelot/issues/209) Add support to analyze only certain page regions to look for tables. [#243](https://github.com/socialcopsdev/camelot/pull/243) by Vinayak Mehta. - * You can use `table_regions` in `read_pdf()` to specify approximate page regions which may contain tables. - * Kwarg `line_size_scaling` is now called `line_scale`. -* [#212](https://github.com/socialcopsdev/camelot/issues/212) Add support to export as sqlite database. [#244](https://github.com/socialcopsdev/camelot/pull/244) by Vinayak Mehta. -* [#239](https://github.com/socialcopsdev/camelot/issues/239) Raise warning if PDF is image-based. [#240](https://github.com/socialcopsdev/camelot/pull/240) by Vinayak Mehta. +- [#240](https://github.com/socialcopsdev/camelot/issues/209) Add support to analyze only certain page regions to look for tables. [#243](https://github.com/socialcopsdev/camelot/pull/243) by Vinayak Mehta. + - You can use `table_regions` in `read_pdf()` to specify approximate page regions which may contain tables. + - Kwarg `line_size_scaling` is now called `line_scale`. +- [#212](https://github.com/socialcopsdev/camelot/issues/212) Add support to export as sqlite database. [#244](https://github.com/socialcopsdev/camelot/pull/244) by Vinayak Mehta. +- [#239](https://github.com/socialcopsdev/camelot/issues/239) Raise warning if PDF is image-based. [#240](https://github.com/socialcopsdev/camelot/pull/240) by Vinayak Mehta. **Documentation** -* Remove mention of old mesh kwarg from docs. [#241](https://github.com/socialcopsdev/camelot/pull/241) by [fte10kso](https://github.com/fte10kso). +- Remove mention of old mesh kwarg from docs. [#241](https://github.com/socialcopsdev/camelot/pull/241) by [fte10kso](https://github.com/fte10kso). **Note**: The python wrapper to Ghostscript's C API is now vendorized under the `ext` module. This was done due to unavailability of the [ghostscript](https://pypi.org/project/ghostscript/) package on Anaconda. The code should be removed after we submit a recipe for it to conda-forge. With this release, the user doesn't need to ensure that the Ghostscript executable is available on the PATH variable. -0.6.0 (2018-12-24) ------------------- +## 0.6.0 (2018-12-24) **Improvements** -* [#91](https://github.com/socialcopsdev/camelot/issues/91) Add support to read from url. [#236](https://github.com/socialcopsdev/camelot/pull/236) by Vinayak Mehta. -* [#229](https://github.com/socialcopsdev/camelot/issues/229), [#230](https://github.com/socialcopsdev/camelot/issues/230) and [#233](https://github.com/socialcopsdev/camelot/issues/233) New configuration parameters. [#234](https://github.com/socialcopsdev/camelot/pull/234) by Vinayak Mehta. - * `strip_text`: To define characters that should be stripped from each string. - * `edge_tol`: Tolerance parameter for extending textedges vertically. - * `resolution`: Resolution used for PDF to PNG conversion. - * Check out the [advanced docs](https://camelot-py.readthedocs.io/en/master/user/advanced.html#strip-characters-from-text) for usage details. -* [#170](https://github.com/socialcopsdev/camelot/issues/170) Add option to pass pdfminer layout kwargs. [#232](https://github.com/socialcopsdev/camelot/pull/232) by Vinayak Mehta. - * Keyword arguments for [pdfminer.layout.LAParams](https://github.com/euske/pdfminer/blob/master/pdfminer/layout.py#L33) can now be passed using `layout_kwargs` in `read_pdf()`. - * The `margins` keyword argument in `read_pdf()` is now deprecated. - -0.5.0 (2018-12-13) ------------------- +- [#91](https://github.com/socialcopsdev/camelot/issues/91) Add support to read from url. [#236](https://github.com/socialcopsdev/camelot/pull/236) by Vinayak Mehta. +- [#229](https://github.com/socialcopsdev/camelot/issues/229), [#230](https://github.com/socialcopsdev/camelot/issues/230) and [#233](https://github.com/socialcopsdev/camelot/issues/233) New configuration parameters. [#234](https://github.com/socialcopsdev/camelot/pull/234) by Vinayak Mehta. + - `strip_text`: To define characters that should be stripped from each string. + - `edge_tol`: Tolerance parameter for extending textedges vertically. + - `resolution`: Resolution used for PDF to PNG conversion. + - Check out the [advanced docs](https://camelot-py.readthedocs.io/en/master/user/advanced.html#strip-characters-from-text) for usage details. +- [#170](https://github.com/socialcopsdev/camelot/issues/170) Add option to pass pdfminer layout kwargs. [#232](https://github.com/socialcopsdev/camelot/pull/232) by Vinayak Mehta. + _ Keyword arguments for [pdfminer.layout.LAParams](https://github.com/euske/pdfminer/blob/master/pdfminer/layout.py#L33) can now be passed using `layout_kwargs` in `read_pdf()`. + _ The `margins` keyword argument in `read_pdf()` is now deprecated. + + 0.5.0 (2018-12-13) + +--- **Improvements** -* [#207](https://github.com/socialcopsdev/camelot/issues/207) Add a plot type for Stream text edges and detected table areas. [#224](https://github.com/socialcopsdev/camelot/pull/224) by Vinayak Mehta. -* [#204](https://github.com/socialcopsdev/camelot/issues/204) `suppress_warnings` is now called `suppress_stdout`. [#225](https://github.com/socialcopsdev/camelot/pull/225) by Vinayak Mehta. +- [#207](https://github.com/socialcopsdev/camelot/issues/207) Add a plot type for Stream text edges and detected table areas. [#224](https://github.com/socialcopsdev/camelot/pull/224) by Vinayak Mehta. +- [#204](https://github.com/socialcopsdev/camelot/issues/204) `suppress_warnings` is now called `suppress_stdout`. [#225](https://github.com/socialcopsdev/camelot/pull/225) by Vinayak Mehta. **Bugfixes** -* [#217](https://github.com/socialcopsdev/camelot/issues/217) Fix IndexError when scale is large. -* [#105](https://github.com/socialcopsdev/camelot/issues/105), [#192](https://github.com/socialcopsdev/camelot/issues/192) and [#215](https://github.com/socialcopsdev/camelot/issues/215) in [#227](https://github.com/socialcopsdev/camelot/pull/227) by Vinayak Mehta. +- [#217](https://github.com/socialcopsdev/camelot/issues/217) Fix IndexError when scale is large. +- [#105](https://github.com/socialcopsdev/camelot/issues/105), [#192](https://github.com/socialcopsdev/camelot/issues/192) and [#215](https://github.com/socialcopsdev/camelot/issues/215) in [#227](https://github.com/socialcopsdev/camelot/pull/227) by Vinayak Mehta. **Documentation** -* Add pdfplumber comparison and update Tabula (stream) comparison. Check out the [wiki page](https://github.com/socialcopsdev/camelot/wiki/Comparison-with-other-PDF-Table-Extraction-libraries-and-tools). +- Add pdfplumber comparison and update Tabula (stream) comparison. Check out the [wiki page](https://github.com/socialcopsdev/camelot/wiki/Comparison-with-other-PDF-Table-Extraction-libraries-and-tools). -0.4.1 (2018-12-05) ------------------- + 0.4.1 (2018-12-05) + +--- **Bugfixes** -* Add chardet to `install_requires` to fix [#210](https://github.com/socialcopsdev/camelot/issues/210). More details in [pdfminer.six#213](https://github.com/pdfminer/pdfminer.six/issues/213). +- Add chardet to `install_requires` to fix [#210](https://github.com/socialcopsdev/camelot/issues/210). More details in [pdfminer.six#213](https://github.com/pdfminer/pdfminer.six/issues/213). -0.4.0 (2018-11-23) ------------------- + 0.4.0 (2018-11-23) + +--- **Improvements** -* [#102](https://github.com/socialcopsdev/camelot/issues/102) Detect tables automatically when Stream is used. [#206](https://github.com/socialcopsdev/camelot/pull/206) Add implementation of Anssi Nurminen's table detection algorithm by Vinayak Mehta. +- [#102](https://github.com/socialcopsdev/camelot/issues/102) Detect tables automatically when Stream is used. [#206](https://github.com/socialcopsdev/camelot/pull/206) Add implementation of Anssi Nurminen's table detection algorithm by Vinayak Mehta. -0.3.2 (2018-11-04) ------------------- + 0.3.2 (2018-11-04) + +--- **Improvements** -* [#186](https://github.com/socialcopsdev/camelot/issues/186) Add `_bbox` attribute to table. [#193](https://github.com/socialcopsdev/camelot/pull/193) by Vinayak Mehta. - * You can use `table._bbox` to get coordinates of the detected table. +- [#186](https://github.com/socialcopsdev/camelot/issues/186) Add `_bbox` attribute to table. [#193](https://github.com/socialcopsdev/camelot/pull/193) by Vinayak Mehta. \* You can use `table._bbox` to get coordinates of the detected table. -0.3.1 (2018-11-02) ------------------- + 0.3.1 (2018-11-02) + +--- **Improvements** -* Matplotlib is now an optional requirement. [#190](https://github.com/socialcopsdev/camelot/pull/190) by Vinayak Mehta. - * You can install it using `$ pip install camelot-py[plot]`. -* [#127](https://github.com/socialcopsdev/camelot/issues/127) Add tests for plotting. Coverage is now at 87%! [#179](https://github.com/socialcopsdev/camelot/pull/179) by [Suyash Behera](https://github.com/Suyash458). +- Matplotlib is now an optional requirement. [#190](https://github.com/socialcopsdev/camelot/pull/190) by Vinayak Mehta. + - You can install it using `$ pip install camelot-py[plot]`. +- [#127](https://github.com/socialcopsdev/camelot/issues/127) Add tests for plotting. Coverage is now at 87%! [#179](https://github.com/socialcopsdev/camelot/pull/179) by [Suyash Behera](https://github.com/Suyash458). -0.3.0 (2018-10-28) ------------------- + 0.3.0 (2018-10-28) + +--- **Improvements** -* [#162](https://github.com/socialcopsdev/camelot/issues/162) Add password keyword argument. [#180](https://github.com/socialcopsdev/camelot/pull/180) by [rbares](https://github.com/rbares). - * An encrypted PDF can now be decrypted by passing `password=''` to `read_pdf` or `--password ` to the command-line interface. (Limited encryption algorithm support from PyPDF2.) -* [#139](https://github.com/socialcopsdev/camelot/issues/139) Add suppress_warnings keyword argument. [#155](https://github.com/socialcopsdev/camelot/pull/155) by [Jonathan Lloyd](https://github.com/jonathanlloyd). - * Warnings raised by Camelot can now be suppressed by passing `suppress_warnings=True` to `read_pdf` or `--quiet` to the command-line interface. -* [#154](https://github.com/socialcopsdev/camelot/issues/154) The CLI can now be run using `python -m`. Try `python -m camelot --help`. [#159](https://github.com/socialcopsdev/camelot/pull/159) by [Parth P Panchal](https://github.com/pqrth). -* [#165](https://github.com/socialcopsdev/camelot/issues/165) Rename `table_area` to `table_areas`. [#171](https://github.com/socialcopsdev/camelot/pull/171) by [Parth P Panchal](https://github.com/pqrth). +- [#162](https://github.com/socialcopsdev/camelot/issues/162) Add password keyword argument. [#180](https://github.com/socialcopsdev/camelot/pull/180) by [rbares](https://github.com/rbares). + - An encrypted PDF can now be decrypted by passing `password=''` to `read_pdf` or `--password ` to the command-line interface. (Limited encryption algorithm support from PyPDF2.) +- [#139](https://github.com/socialcopsdev/camelot/issues/139) Add suppress_warnings keyword argument. [#155](https://github.com/socialcopsdev/camelot/pull/155) by [Jonathan Lloyd](https://github.com/jonathanlloyd). + - Warnings raised by Camelot can now be suppressed by passing `suppress_warnings=True` to `read_pdf` or `--quiet` to the command-line interface. +- [#154](https://github.com/socialcopsdev/camelot/issues/154) The CLI can now be run using `python -m`. Try `python -m camelot --help`. [#159](https://github.com/socialcopsdev/camelot/pull/159) by [Parth P Panchal](https://github.com/pqrth). +- [#165](https://github.com/socialcopsdev/camelot/issues/165) Rename `table_area` to `table_areas`. [#171](https://github.com/socialcopsdev/camelot/pull/171) by [Parth P Panchal](https://github.com/pqrth). **Bugfixes** -* Raise error if the ghostscript executable is not on the PATH variable. [#166](https://github.com/socialcopsdev/camelot/pull/166) by Vinayak Mehta. -* Convert filename to lowercase to check for PDF extension. [#169](https://github.com/socialcopsdev/camelot/pull/169) by [Vinicius Mesel](https://github.com/vmesel). +- Raise error if the ghostscript executable is not on the PATH variable. [#166](https://github.com/socialcopsdev/camelot/pull/166) by Vinayak Mehta. +- Convert filename to lowercase to check for PDF extension. [#169](https://github.com/socialcopsdev/camelot/pull/169) by [Vinicius Mesel](https://github.com/vmesel). **Files** -* [#114](https://github.com/socialcopsdev/camelot/issues/114) Add Makefile and make codecov run only once. [#132](https://github.com/socialcopsdev/camelot/pull/132) by [Vaibhav Mule](https://github.com/vaibhavmule). -* Add .editorconfig. [#151](https://github.com/socialcopsdev/camelot/pull/151) by [KOLANICH](https://github.com/KOLANICH). -* Downgrade numpy version from 1.15.2 to 1.13.3. -* Add requirements.txt for readthedocs. +- [#114](https://github.com/socialcopsdev/camelot/issues/114) Add Makefile and make codecov run only once. [#132](https://github.com/socialcopsdev/camelot/pull/132) by [Vaibhav Mule](https://github.com/vaibhavmule). +- Add .editorconfig. [#151](https://github.com/socialcopsdev/camelot/pull/151) by [KOLANICH](https://github.com/KOLANICH). +- Downgrade numpy version from 1.15.2 to 1.13.3. +- Add requirements.txt for readthedocs. **Documentation** -* Add "Using conda" section to installation instructions. -* Add readthedocs badge. +- Add "Using conda" section to installation instructions. +- Add readthedocs badge. -0.2.3 (2018-10-08) ------------------- + 0.2.3 (2018-10-08) -* Remove hard dependencies on requirements versions. +--- -0.2.2 (2018-10-08) ------------------- +- Remove hard dependencies on requirements versions. + + 0.2.2 (2018-10-08) + +--- **Bugfixes** -* Move opencv-python to extra\_requires. [#134](https://github.com/socialcopsdev/camelot/pull/134) by Vinayak Mehta. +- Move opencv-python to extra_requires. [#134](https://github.com/socialcopsdev/camelot/pull/134) by Vinayak Mehta. -0.2.1 (2018-10-05) ------------------- + 0.2.1 (2018-10-05) + +--- **Bugfixes** -* [#121](https://github.com/socialcopsdev/camelot/issues/121) Fix ghostscript subprocess call for Windows. [#124](https://github.com/socialcopsdev/camelot/pull/124) by Vinayak Mehta. +- [#121](https://github.com/socialcopsdev/camelot/issues/121) Fix ghostscript subprocess call for Windows. [#124](https://github.com/socialcopsdev/camelot/pull/124) by Vinayak Mehta. **Improvements** -* [#123](https://github.com/socialcopsdev/camelot/issues/123) Make PEP8 compatible. [#125](https://github.com/socialcopsdev/camelot/pull/125) by [Oshawk](https://github.com/Oshawk). -* [#110](https://github.com/socialcopsdev/camelot/issues/110) Add more tests. Coverage is now at 84%! - * Add tests for `__repr__`. [#128](https://github.com/socialcopsdev/camelot/pull/128) by [Vaibhav Mule](https://github.com/vaibhavmule). - * Add tests for CLI. [#122](https://github.com/socialcopsdev/camelot/pull/122) by [Vaibhav Mule](https://github.com/vaibhavmule) and [#117](https://github.com/socialcopsdev/camelot/pull/117) by Vinayak Mehta. - * Add tests for errors/warnings. [#113](https://github.com/socialcopsdev/camelot/pull/113) by Vinayak Mehta. - * Add tests for output formats and parser kwargs. [#126](https://github.com/socialcopsdev/camelot/pull/126) by Vinayak Mehta. -* Add Python 3.5 and 3.7 support. [#119](https://github.com/socialcopsdev/camelot/pull/119) by Vinayak Mehta. -* Add logging and warnings. +- [#123](https://github.com/socialcopsdev/camelot/issues/123) Make PEP8 compatible. [#125](https://github.com/socialcopsdev/camelot/pull/125) by [Oshawk](https://github.com/Oshawk). +- [#110](https://github.com/socialcopsdev/camelot/issues/110) Add more tests. Coverage is now at 84%! + - Add tests for `__repr__`. [#128](https://github.com/socialcopsdev/camelot/pull/128) by [Vaibhav Mule](https://github.com/vaibhavmule). + - Add tests for CLI. [#122](https://github.com/socialcopsdev/camelot/pull/122) by [Vaibhav Mule](https://github.com/vaibhavmule) and [#117](https://github.com/socialcopsdev/camelot/pull/117) by Vinayak Mehta. + - Add tests for errors/warnings. [#113](https://github.com/socialcopsdev/camelot/pull/113) by Vinayak Mehta. + - Add tests for output formats and parser kwargs. [#126](https://github.com/socialcopsdev/camelot/pull/126) by Vinayak Mehta. +- Add Python 3.5 and 3.7 support. [#119](https://github.com/socialcopsdev/camelot/pull/119) by Vinayak Mehta. +- Add logging and warnings. **Documentation** -* Copyedit all documentation. [#112](https://github.com/socialcopsdev/camelot/pull/112) by [Christine Garcia](https://github.com/christinegarcia). -* [#115](https://github.com/socialcopsdev/camelot/issues/115) Update issue labels in contributor's guide. [#116](https://github.com/socialcopsdev/camelot/pull/116) by [Johnny Metz](https://github.com/johnnymetz). -* Update installation instructions for Windows. [#124](https://github.com/socialcopsdev/camelot/pull/124) by Vinayak Mehta. +- Copyedit all documentation. [#112](https://github.com/socialcopsdev/camelot/pull/112) by [Christine Garcia](https://github.com/christinegarcia). +- [#115](https://github.com/socialcopsdev/camelot/issues/115) Update issue labels in contributor's guide. [#116](https://github.com/socialcopsdev/camelot/pull/116) by [Johnny Metz](https://github.com/johnnymetz). +- Update installation instructions for Windows. [#124](https://github.com/socialcopsdev/camelot/pull/124) by Vinayak Mehta. **Note**: This release also bumps the version for numpy from 1.13.3 to 1.15.2 and adds a MANIFEST.in. Also, openpyxl==2.5.8 is a new requirement and pytest-cov==2.6.0 is a new dev requirement. -0.2.0 (2018-09-28) ------------------- +## 0.2.0 (2018-09-28) **Improvements** -* [#81](https://github.com/socialcopsdev/camelot/issues/81) Add Python 3.6 support. [#109](https://github.com/socialcopsdev/camelot/pull/109) by Vinayak Mehta. +- [#81](https://github.com/socialcopsdev/camelot/issues/81) Add Python 3.6 support. [#109](https://github.com/socialcopsdev/camelot/pull/109) by Vinayak Mehta. -0.1.2 (2018-09-25) ------------------- + 0.1.2 (2018-09-25) + +--- **Improvements** -* [#85](https://github.com/socialcopsdev/camelot/issues/85) Add Travis and Codecov. +- [#85](https://github.com/socialcopsdev/camelot/issues/85) Add Travis and Codecov. -0.1.1 (2018-09-24) ------------------- + 0.1.1 (2018-09-24) + +--- **Documentation** -* Add documentation fixes. +- Add documentation fixes. -0.1.0 (2018-09-24) ------------------- + 0.1.0 (2018-09-24) + +--- -* Rebirth! +- Rebirth! diff --git a/MANIFEST.in b/MANIFEST.in deleted file mode 100644 index 19d196dd..00000000 --- a/MANIFEST.in +++ /dev/null @@ -1 +0,0 @@ -include MANIFEST.in README.md HISTORY.md LICENSE setup.py setup.cfg diff --git a/Makefile b/Makefile deleted file mode 100644 index 383c8018..00000000 --- a/Makefile +++ /dev/null @@ -1,28 +0,0 @@ -.PHONY: docs -INSTALL := -UNAME_S := $(shell uname -s) -ifeq ($(UNAME_S),Linux) - INSTALL := @sudo apt install python-tk python3-tk ghostscript -else ifeq ($(UNAME_S),Darwin) - INSTALL := @brew install tcl-tk ghostscript -else - INSTALL := @echo "Please install tk and ghostscript" -endif - -install: - $(INSTALL) - pip install --upgrade pip - pip install ".[dev]" - -test: - pytest --verbose --cov-config .coveragerc --cov-report term --cov-report xml --cov=camelot --mpl - -docs: - cd docs && make html - @echo "\033[95m\n\nBuild successful! View the docs homepage at docs/_build/html/index.html.\n\033[0m" - -publish: - pip install twine - python setup.py sdist - twine upload dist/* - rm -fr build dist .egg camelot_py.egg-info diff --git a/README.md b/README.md index 9876bb79..04131d57 100644 --- a/README.md +++ b/README.md @@ -5,8 +5,8 @@ # Camelot: PDF Table Extraction for Humans [![tests](https://github.com/camelot-dev/camelot/actions/workflows/tests.yml/badge.svg)](https://github.com/camelot-dev/camelot/actions/workflows/tests.yml) [![Documentation Status](https://readthedocs.org/projects/camelot-py/badge/?version=master)](https://camelot-py.readthedocs.io/en/master/) - [![codecov.io](https://codecov.io/github/camelot-dev/camelot/badge.svg?branch=master&service=github)](https://codecov.io/github/camelot-dev/camelot?branch=master) - [![image](https://img.shields.io/pypi/v/camelot-py.svg)](https://pypi.org/project/camelot-py/) [![image](https://img.shields.io/pypi/l/camelot-py.svg)](https://pypi.org/project/camelot-py/) [![image](https://img.shields.io/pypi/pyversions/camelot-py.svg)](https://pypi.org/project/camelot-py/) [![Gitter chat](https://badges.gitter.im/camelot-dev/Lobby.png)](https://gitter.im/camelot-dev/Lobby) +[![codecov.io](https://codecov.io/github/camelot-dev/camelot/badge.svg?branch=master&service=github)](https://codecov.io/github/camelot-dev/camelot?branch=master) +[![image](https://img.shields.io/pypi/v/camelot-py.svg)](https://pypi.org/project/camelot-py/) [![image](https://img.shields.io/pypi/l/camelot-py.svg)](https://pypi.org/project/camelot-py/) [![image](https://img.shields.io/pypi/pyversions/camelot-py.svg)](https://pypi.org/project/camelot-py/) [![Gitter chat](https://badges.gitter.im/camelot-dev/Lobby.png)](https://gitter.im/camelot-dev/Lobby) [![image](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/ambv/black) **Camelot** is a Python library that can help you extract tables from PDFs! @@ -37,7 +37,7 @@ | Cycle Name | KI (1/km) | Distance (mi) | Percent Fuel Savings | | | | -|------------|-----------|---------------|----------------------|-----------------|-----------------|----------------| +| ---------- | --------- | ------------- | -------------------- | --------------- | --------------- | -------------- | | | | | Improved Speed | Decreased Accel | Eliminate Stops | Decreased Idle | | 2012_2 | 3.30 | 1.3 | 5.9% | 9.5% | 29.2% | 17.4% | | 2145_1 | 0.68 | 11.2 | 2.4% | 0.1% | 9.5% | 2.7% | diff --git a/camelot/__init__.py b/camelot/__init__.py index bc4beb62..79c5331a 100644 --- a/camelot/__init__.py +++ b/camelot/__init__.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - import logging from .__version__ import __version__ diff --git a/camelot/__main__.py b/camelot/__main__.py old mode 100755 new mode 100644 index a0b82a6b..2dc79401 --- a/camelot/__main__.py +++ b/camelot/__main__.py @@ -1,6 +1,3 @@ -# -*- coding: utf-8 -*- - - __all__ = ("main",) diff --git a/camelot/__version__.py b/camelot/__version__.py index 72364b92..9395847c 100644 --- a/camelot/__version__.py +++ b/camelot/__version__.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - VERSION = (0, 11, 0) PRERELEASE = None # alpha, beta or rc REVISION = None diff --git a/camelot/backends/__init__.py b/camelot/backends/__init__.py index 8d0b91e9..3bc50d3a 100644 --- a/camelot/backends/__init__.py +++ b/camelot/backends/__init__.py @@ -1,3 +1 @@ -# -*- coding: utf-8 -*- - from .image_conversion import ImageConversionBackend diff --git a/camelot/backends/ghostscript_backend.py b/camelot/backends/ghostscript_backend.py index 1de7da19..7d4fce3c 100644 --- a/camelot/backends/ghostscript_backend.py +++ b/camelot/backends/ghostscript_backend.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- - -import sys import ctypes +import sys from ctypes.util import find_library @@ -17,7 +15,7 @@ def installed_windows(): return library is not None -class GhostscriptBackend(object): +class GhostscriptBackend: def installed(self): if sys.platform in ["linux", "darwin"]: return installed_posix() diff --git a/camelot/backends/image_conversion.py b/camelot/backends/image_conversion.py index 7d2c4d7a..7ab2f19c 100644 --- a/camelot/backends/image_conversion.py +++ b/camelot/backends/image_conversion.py @@ -1,12 +1,11 @@ -# -*- coding: utf-8 -*- - -from .poppler_backend import PopplerBackend from .ghostscript_backend import GhostscriptBackend +from .poppler_backend import PopplerBackend + BACKENDS = {"poppler": PopplerBackend, "ghostscript": GhostscriptBackend} -class ImageConversionBackend(object): +class ImageConversionBackend: def __init__(self, backend="poppler", use_fallback=True): if backend not in BACKENDS.keys(): raise ValueError(f"Image conversion backend '{backend}' not supported") diff --git a/camelot/backends/poppler_backend.py b/camelot/backends/poppler_backend.py index 41033729..90d37a97 100644 --- a/camelot/backends/poppler_backend.py +++ b/camelot/backends/poppler_backend.py @@ -1,10 +1,8 @@ -# -*- coding: utf-8 -*- - import shutil import subprocess -class PopplerBackend(object): +class PopplerBackend: def convert(self, pdf_path, png_path): pdftopng_executable = shutil.which("pdftopng") if pdftopng_executable is None: diff --git a/camelot/cli.py b/camelot/cli.py index 546a32d8..e45664c1 100644 --- a/camelot/cli.py +++ b/camelot/cli.py @@ -1,9 +1,8 @@ -# -*- coding: utf-8 -*- - import logging import click + try: import matplotlib.pyplot as plt except ImportError: @@ -11,14 +10,16 @@ else: _HAS_MPL = True -from . import __version__, read_pdf, plot +from . import __version__ +from . import plot +from . import read_pdf logger = logging.getLogger("camelot") logger.setLevel(logging.INFO) -class Config(object): +class Config: def __init__(self): self.config = {} diff --git a/camelot/core.py b/camelot/core.py index 15eb2615..4448cabe 100644 --- a/camelot/core.py +++ b/camelot/core.py @@ -1,10 +1,7 @@ -# -*- coding: utf-8 -*- - import os import sqlite3 -import zipfile import tempfile -from itertools import chain +import zipfile from operator import itemgetter import numpy as np @@ -18,7 +15,7 @@ TABLE_AREA_PADDING = 10 -class TextEdge(object): +class TextEdge: """Defines a text edge coordinates relative to a left-bottom origin. (PDF coordinate space) @@ -73,7 +70,7 @@ def update_coords(self, x, y0, edge_tol=50): self.is_valid = True -class TextEdges(object): +class TextEdges: """Defines a dict of left, right and middle text edges found on the PDF page. The dict has three keys based on the alignments, and each key's value is a list of camelot.core.TextEdge objects. @@ -228,7 +225,7 @@ def pad(area, average_row_height): return table_areas_padded -class Cell(object): +class Cell: """Defines a cell in a table with coordinates relative to a left-bottom origin. (PDF coordinate space) @@ -308,7 +305,7 @@ def bound(self): return self.top + self.bottom + self.left + self.right -class Table(object): +class Table: """Defines a table with coordinates relative to a left-bottom origin. (PDF coordinate space) @@ -341,7 +338,7 @@ def __init__(self, cols, rows): self.cols = cols self.rows = rows self.cells = [[Cell(c[0], r[1], c[1], r[0]) for c in cols] for r in rows] - self.df = None + self.df = pd.DataFrame() self.shape = (0, 0) self.accuracy = 0 self.whitespace = 0 @@ -665,7 +662,7 @@ def to_sqlite(self, path, **kwargs): conn.close() -class TableList(object): +class TableList: """Defines a list of camelot.core.Table objects. Each table can be accessed using its index. diff --git a/camelot/handlers.py b/camelot/handlers.py index 5f07e5d0..66ee1697 100644 --- a/camelot/handlers.py +++ b/camelot/handlers.py @@ -1,23 +1,24 @@ -# -*- coding: utf-8 -*- - import os import sys +from pathlib import Path +from typing import Union -from pypdf import PdfReader, PdfWriter +from pypdf import PdfReader +from pypdf import PdfWriter +from pypdf._utils import StrByteType from .core import TableList -from .parsers import Stream, Lattice -from .utils import ( - TemporaryDirectory, - get_page_layout, - get_text_objects, - get_rotation, - is_url, - download_url, -) - - -class PDFHandler(object): +from .parsers import Lattice +from .parsers import Stream +from .utils import TemporaryDirectory +from .utils import download_url +from .utils import get_page_layout +from .utils import get_rotation +from .utils import get_text_objects +from .utils import is_url + + +class PDFHandler: """Handles all operations like temp directory creation, splitting file into single page PDFs, parsing each PDF and then removing the temp directory. @@ -34,15 +35,16 @@ class PDFHandler(object): """ - def __init__(self, filepath, pages="1", password=None): + def __init__(self, filepath: Union[StrByteType, Path], pages="1", password=None): if is_url(filepath): filepath = download_url(filepath) - self.filepath = filepath - if not filepath.lower().endswith(".pdf"): + self.filepath: Union[StrByteType, Path] = filepath + + if isinstance(filepath, str) and not filepath.lower().endswith(".pdf"): raise NotImplementedError("File format not supported") if password is None: - self.password = "" + self.password = "" # noqa: S105 else: self.password = password if sys.version_info[0] < 3: @@ -71,30 +73,29 @@ def _get_pages(self, pages): if pages == "1": page_numbers.append({"start": 1, "end": 1}) else: - with open(self.filepath, "rb") as f: - infile = PdfReader(f, strict=False) - - if infile.is_encrypted: - infile.decrypt(self.password) - - if pages == "all": - page_numbers.append({"start": 1, "end": len(infile.pages)}) - else: - for r in pages.split(","): - if "-" in r: - a, b = r.split("-") - if b == "end": - b = len(infile.pages) - page_numbers.append({"start": int(a), "end": int(b)}) - else: - page_numbers.append({"start": int(r), "end": int(r)}) - - P = [] + infile = PdfReader(self.filepath, strict=False) + + if infile.is_encrypted: + infile.decrypt(self.password) + + if pages == "all": + page_numbers.append({"start": 1, "end": len(infile.pages)}) + else: + for r in pages.split(","): + if "-" in r: + a, b = r.split("-") + if b == "end": + b = len(infile.pages) + page_numbers.append({"start": int(a), "end": int(b)}) + else: + page_numbers.append({"start": int(r), "end": int(r)}) + + result = [] for p in page_numbers: - P.extend(range(p["start"], p["end"] + 1)) - return sorted(set(P)) + result.extend(range(p["start"], p["end"] + 1)) + return sorted(set(result)) - def _save_page(self, filepath, page, temp): + def _save_page(self, filepath: Union[StrByteType, Path], page, temp): """Saves specified page from PDF into a temporary directory. Parameters @@ -107,43 +108,42 @@ def _save_page(self, filepath, page, temp): Tmp directory. """ - with open(filepath, "rb") as fileobj: - infile = PdfReader(fileobj, strict=False) + infile = PdfReader(filepath, strict=False) + if infile.is_encrypted: + infile.decrypt(self.password) + fpath = os.path.join(temp, f"page-{page}.pdf") + froot, fext = os.path.splitext(fpath) + p = infile.pages[page - 1] + outfile = PdfWriter() + outfile.add_page(p) + with open(fpath, "wb") as f: + outfile.write(f) + layout, dim = get_page_layout(fpath) + # fix rotated PDF + chars = get_text_objects(layout, ltype="char") + horizontal_text = get_text_objects(layout, ltype="horizontal_text") + vertical_text = get_text_objects(layout, ltype="vertical_text") + rotation = get_rotation(chars, horizontal_text, vertical_text) + if rotation != "": + fpath_new = "".join([froot.replace("page", "p"), "_rotated", fext]) + os.rename(fpath, fpath_new) + instream = open(fpath_new, "rb") + infile = PdfReader(instream, strict=False) if infile.is_encrypted: infile.decrypt(self.password) - fpath = os.path.join(temp, f"page-{page}.pdf") - froot, fext = os.path.splitext(fpath) - p = infile.pages[page - 1] outfile = PdfWriter() + p = infile.pages[0] + if rotation == "anticlockwise": + p.rotate(90) + elif rotation == "clockwise": + p.rotate(-90) outfile.add_page(p) with open(fpath, "wb") as f: outfile.write(f) - layout, dim = get_page_layout(fpath) - # fix rotated PDF - chars = get_text_objects(layout, ltype="char") - horizontal_text = get_text_objects(layout, ltype="horizontal_text") - vertical_text = get_text_objects(layout, ltype="vertical_text") - rotation = get_rotation(chars, horizontal_text, vertical_text) - if rotation != "": - fpath_new = "".join([froot.replace("page", "p"), "_rotated", fext]) - os.rename(fpath, fpath_new) - instream = open(fpath_new, "rb") - infile = PdfReader(instream, strict=False) - if infile.is_encrypted: - infile.decrypt(self.password) - outfile = PdfWriter() - p = infile.pages[0] - if rotation == "anticlockwise": - p.rotate(90) - elif rotation == "clockwise": - p.rotate(-90) - outfile.add_page(p) - with open(fpath, "wb") as f: - outfile.write(f) - instream.close() + instream.close() def parse( - self, flavor="lattice", suppress_stdout=False, layout_kwargs={}, **kwargs + self, flavor="lattice", suppress_stdout=False, layout_kwargs=None, **kwargs ): """Extracts tables by calling parser.get_tables on all single page PDFs. @@ -156,7 +156,8 @@ def parse( suppress_stdout : str (default: False) Suppress logs and warnings. layout_kwargs : dict, optional (default: {}) - A dict of `pdfminer.layout.LAParams `_ kwargs. + A dict of `pdfminer.layout.LAParams + `_ kwargs. kwargs : dict See camelot.read_pdf kwargs. @@ -166,6 +167,9 @@ def parse( List of tables found in PDF. """ + if layout_kwargs is None: + layout_kwargs = {} + tables = [] with TemporaryDirectory() as tempdir: for p in self.pages: diff --git a/camelot/image_processing.py b/camelot/image_processing.py index 08acb23e..a1fe8034 100644 --- a/camelot/image_processing.py +++ b/camelot/image_processing.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - import cv2 import numpy as np diff --git a/camelot/io.py b/camelot/io.py index a27a7c66..78319bc9 100644 --- a/camelot/io.py +++ b/camelot/io.py @@ -1,18 +1,21 @@ -# -*- coding: utf-8 -*- - import warnings +from pathlib import Path +from typing import Union + +from pypdf._utils import StrByteType from .handlers import PDFHandler -from .utils import validate_input, remove_extra +from .utils import remove_extra +from .utils import validate_input def read_pdf( - filepath, + filepath: Union[StrByteType, Path], pages="1", password=None, flavor="lattice", suppress_stdout=False, - layout_kwargs={}, + layout_kwargs=None, **kwargs ): """Read PDF and return extracted tables. @@ -22,7 +25,7 @@ def read_pdf( Parameters ---------- - filepath : str + filepath : str, Path, IO Filepath or URL of the PDF file. pages : str, optional (default: '1') Comma-separated page numbers. @@ -35,7 +38,8 @@ def read_pdf( suppress_stdout : bool, optional (default: True) Print all logs and warnings. layout_kwargs : dict, optional (default: {}) - A dict of `pdfminer.layout.LAParams `_ kwargs. + A dict of `pdfminer.layout.LAParams + `_ kwargs. table_areas : list, optional (default: None) List of table area strings of the form x1,y1,x2,y2 where (x1, y1) -> left-top and (x2, y2) -> right-bottom @@ -80,16 +84,19 @@ def read_pdf( Size of a pixel neighborhood that is used to calculate a threshold value for the pixel: 3, 5, 7, and so on. - For more information, refer `OpenCV's adaptiveThreshold `_. + For more information, refer `OpenCV's adaptiveThreshold + `_. threshold_constant* : int, optional (default: -2) Constant subtracted from the mean or weighted mean. Normally, it is positive but may be zero or negative as well. - For more information, refer `OpenCV's adaptiveThreshold `_. + For more information, refer `OpenCV's adaptiveThreshold + `_. iterations* : int, optional (default: 0) Number of times for erosion/dilation is applied. - For more information, refer `OpenCV's dilate `_. + For more information, refer `OpenCV's dilate + `_. resolution* : int, optional (default: 300) Resolution used for PDF to PNG conversion. @@ -98,6 +105,8 @@ def read_pdf( tables : camelot.core.TableList """ + if layout_kwargs is None: + layout_kwargs = {} if flavor not in ["lattice", "stream"]: raise NotImplementedError( "Unknown flavor specified." " Use either 'lattice' or 'stream'" diff --git a/camelot/parsers/__init__.py b/camelot/parsers/__init__.py index 5cc66051..9019058f 100644 --- a/camelot/parsers/__init__.py +++ b/camelot/parsers/__init__.py @@ -1,4 +1,2 @@ -# -*- coding: utf-8 -*- - -from .stream import Stream from .lattice import Lattice +from .stream import Stream diff --git a/camelot/parsers/base.py b/camelot/parsers/base.py index aeba056f..5e4b35f8 100644 --- a/camelot/parsers/base.py +++ b/camelot/parsers/base.py @@ -1,11 +1,10 @@ -# -*- coding: utf-8 -*- - import os -from ..utils import get_page_layout, get_text_objects +from ..utils import get_page_layout +from ..utils import get_text_objects -class BaseParser(object): +class BaseParser: """Defines a base parser.""" def _generate_layout(self, filename, layout_kwargs): diff --git a/camelot/parsers/lattice.py b/camelot/parsers/lattice.py index a1752272..01d17d96 100644 --- a/camelot/parsers/lattice.py +++ b/camelot/parsers/lattice.py @@ -1,34 +1,28 @@ -# -*- coding: utf-8 -*- - -import os -import sys import copy import locale import logging +import os +import sys import warnings import numpy as np import pandas as pd -from .base import BaseParser -from ..core import Table -from ..utils import ( - scale_image, - scale_pdf, - segments_in_bbox, - text_in_bbox, - merge_close_lines, - get_table_index, - compute_accuracy, - compute_whitespace, -) -from ..image_processing import ( - adaptive_threshold, - find_lines, - find_contours, - find_joints, -) from ..backends.image_conversion import BACKENDS +from ..core import Table +from ..image_processing import adaptive_threshold +from ..image_processing import find_contours +from ..image_processing import find_joints +from ..image_processing import find_lines +from ..utils import compute_accuracy +from ..utils import compute_whitespace +from ..utils import get_table_index +from ..utils import merge_close_lines +from ..utils import scale_image +from ..utils import scale_pdf +from ..utils import segments_in_bbox +from ..utils import text_in_bbox +from .base import BaseParser logger = logging.getLogger("camelot") @@ -344,7 +338,7 @@ def _generate_table(self, table_idx, cols, rows, **kwargs): v_s = kwargs.get("v_s") h_s = kwargs.get("h_s") if v_s is None or h_s is None: - raise ValueError("No segments found on {}".format(self.rootname)) + raise ValueError(f"No segments found on {self.rootname}") table = Table(cols, rows) # set table edges to True using ver+hor lines @@ -367,7 +361,7 @@ def _generate_table(self, table_idx, cols, rows, **kwargs): flag_size=self.flag_size, strip_text=self.strip_text, ) - if indices[:2] != (-1, -1): + if indices[0][:2] != (-1, -1): pos_errors.append(error) indices = Lattice._reduce_index( table, indices, shift_text=self.shift_text @@ -404,7 +398,7 @@ def _generate_table(self, table_idx, cols, rows, **kwargs): def extract_tables(self, filename, suppress_stdout=False, layout_kwargs={}): self._generate_layout(filename, layout_kwargs) if not suppress_stdout: - logger.info("Processing {}".format(os.path.basename(self.rootname))) + logger.info(f"Processing {os.path.basename(self.rootname)}") if not self.horizontal_text: if self.images: @@ -413,9 +407,7 @@ def extract_tables(self, filename, suppress_stdout=False, layout_kwargs={}): " text-based pages.".format(os.path.basename(self.rootname)) ) else: - warnings.warn( - "No tables found on {}".format(os.path.basename(self.rootname)) - ) + warnings.warn(f"No tables found on {os.path.basename(self.rootname)}") return [] self.backend.convert(self.filename, self.imagename) diff --git a/camelot/parsers/stream.py b/camelot/parsers/stream.py index c7b21daf..266a0e95 100644 --- a/camelot/parsers/stream.py +++ b/camelot/parsers/stream.py @@ -1,15 +1,17 @@ -# -*- coding: utf-8 -*- - -import os import logging +import os import warnings import numpy as np import pandas as pd +from ..core import Table +from ..core import TextEdges +from ..utils import compute_accuracy +from ..utils import compute_whitespace +from ..utils import get_table_index +from ..utils import text_in_bbox from .base import BaseParser -from ..core import TextEdges, Table -from ..utils import text_in_bbox, get_table_index, compute_accuracy, compute_whitespace logger = logging.getLogger("camelot") @@ -94,10 +96,15 @@ def _text_bbox(t_bbox): Tuple (x0, y0, x1, y1) in pdf coordinate space. """ - xmin = min([t.x0 for direction in t_bbox for t in t_bbox[direction]]) - ymin = min([t.y0 for direction in t_bbox for t in t_bbox[direction]]) - xmax = max([t.x1 for direction in t_bbox for t in t_bbox[direction]]) - ymax = max([t.y1 for direction in t_bbox for t in t_bbox[direction]]) + xmin = 0 + ymin = 0 + xmax = 0 + ymax = 0 + if len([t.x0 for direction in t_bbox for t in t_bbox[direction]]) > 0: + xmin = min([t.x0 for direction in t_bbox for t in t_bbox[direction]]) + ymin = min([t.y0 for direction in t_bbox for t in t_bbox[direction]]) + xmax = max([t.x1 for direction in t_bbox for t in t_bbox[direction]]) + ymax = max([t.y1 for direction in t_bbox for t in t_bbox[direction]]) text_bbox = (xmin, ymin, xmax, ymax) return text_bbox diff --git a/camelot/plotting.py b/camelot/plotting.py index f5b6afe9..b602cef6 100644 --- a/camelot/plotting.py +++ b/camelot/plotting.py @@ -1,15 +1,13 @@ -# -*- coding: utf-8 -*- - try: - import matplotlib.pyplot as plt import matplotlib.patches as patches + import matplotlib.pyplot as plt except ImportError: _HAS_MPL = False else: _HAS_MPL = True -class PlotMethods(object): +class PlotMethods: def __call__(self, table, kind="text", filename=None): """Plot elements found on PDF page based on kind specified, useful for debugging and playing with different diff --git a/camelot/py.typed b/camelot/py.typed new file mode 100644 index 00000000..e69de29b diff --git a/camelot/utils.py b/camelot/utils.py index 404c00b2..90ed400e 100644 --- a/camelot/utils.py +++ b/camelot/utils.py @@ -1,35 +1,33 @@ -# -*- coding: utf-8 -*- - import os -import re import random +import re import shutil import string import tempfile import warnings from itertools import groupby from operator import itemgetter +from urllib.parse import urlparse as parse_url +from urllib.parse import uses_netloc +from urllib.parse import uses_params +from urllib.parse import uses_relative +from urllib.request import Request +from urllib.request import urlopen import numpy as np -from pdfminer.pdfparser import PDFParser +from pdfminer.converter import PDFPageAggregator +from pdfminer.layout import LAParams +from pdfminer.layout import LTAnno +from pdfminer.layout import LTChar +from pdfminer.layout import LTImage +from pdfminer.layout import LTTextLineHorizontal +from pdfminer.layout import LTTextLineVertical from pdfminer.pdfdocument import PDFDocument +from pdfminer.pdfinterp import PDFPageInterpreter +from pdfminer.pdfinterp import PDFResourceManager from pdfminer.pdfpage import PDFPage from pdfminer.pdfpage import PDFTextExtractionNotAllowed -from pdfminer.pdfinterp import PDFResourceManager -from pdfminer.pdfinterp import PDFPageInterpreter -from pdfminer.converter import PDFPageAggregator -from pdfminer.layout import ( - LAParams, - LTAnno, - LTChar, - LTTextLineHorizontal, - LTTextLineVertical, - LTImage, -) - -from urllib.request import Request, urlopen -from urllib.parse import urlparse as parse_url -from urllib.parse import uses_relative, uses_netloc, uses_params +from pdfminer.pdfparser import PDFParser _VALID_URLS = set(uses_relative + uses_netloc + uses_params) @@ -135,7 +133,7 @@ def remove_extra(kwargs, flavor="lattice"): # https://stackoverflow.com/a/22726782 -class TemporaryDirectory(object): +class TemporaryDirectory: def __enter__(self): self.name = tempfile.mkdtemp() return self.name @@ -372,8 +370,9 @@ def text_in_bbox(bbox, text): if ba == bb: continue if bbox_intersect(ba, bb): + ba_area = bbox_area(ba) # if the intersection is larger than 80% of ba's size, we keep the longest - if (bbox_intersection_area(ba, bb) / bbox_area(ba)) > 0.8: + if ba_area == 0 or (bbox_intersection_area(ba, bb) / ba_area) > 0.8: if bbox_longer(bb, ba): rest.discard(ba) unique_boxes = list(rest) @@ -501,7 +500,7 @@ def text_strip(text, strip=""): return text stripped = re.sub( - fr"[{''.join(map(re.escape, strip))}]", "", text, flags=re.UNICODE + rf"[{''.join(map(re.escape, strip))}]", "", text, flags=re.UNICODE ) return stripped diff --git a/codecov.yml b/codecov.yml new file mode 100644 index 00000000..9ac26504 --- /dev/null +++ b/codecov.yml @@ -0,0 +1,9 @@ +comment: false +coverage: + status: + project: + default: + target: "100" + patch: + default: + target: "100" diff --git a/docs/_static/csv/foo.csv b/docs/_static/csv/foo.csv index 8e956a3a..b8a245c1 100644 --- a/docs/_static/csv/foo.csv +++ b/docs/_static/csv/foo.csv @@ -4,4 +4,4 @@ "2145_1","0.68","11.2","2.4%","0.1%","9.5%","2.7%" "4234_1","0.59","58.7","8.5%","1.3%","8.5%","3.3%" "2032_2","0.17","57.8","21.7%","0.3%","2.7%","1.2%" -"4171_1","0.07","173.9","58.1%","1.6%","2.1%","0.5%" \ No newline at end of file +"4171_1","0.07","173.9","58.1%","1.6%","2.1%","0.5%" diff --git a/docs/_templates/hacks.html b/docs/_templates/hacks.html index d2253041..960e1725 100644 --- a/docs/_templates/hacks.html +++ b/docs/_templates/hacks.html @@ -1,16 +1,30 @@ \ No newline at end of file + diff --git a/docs/_templates/sidebarintro.html b/docs/_templates/sidebarintro.html index e1211001..f4050061 100644 --- a/docs/_templates/sidebarintro.html +++ b/docs/_templates/sidebarintro.html @@ -1,16 +1,24 @@

- +

Useful Links

diff --git a/docs/_templates/sidebarlogo.html b/docs/_templates/sidebarlogo.html index b68edea1..43cca367 100644 --- a/docs/_templates/sidebarlogo.html +++ b/docs/_templates/sidebarlogo.html @@ -1,9 +1,15 @@

- +

diff --git a/docs/_themes/.gitignore b/docs/_themes/.gitignore index 3072e6ff..52e4e611 100644 --- a/docs/_themes/.gitignore +++ b/docs/_themes/.gitignore @@ -1,2 +1,2 @@ *.pyc -*.pyo \ No newline at end of file +*.pyo diff --git a/docs/_themes/LICENSE b/docs/_themes/LICENSE index 8756c7a6..8daab7ee 100644 --- a/docs/_themes/LICENSE +++ b/docs/_themes/LICENSE @@ -34,4 +34,4 @@ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS THEME, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file +POSSIBILITY OF SUCH DAMAGE. diff --git a/docs/_themes/flask_theme_support.py b/docs/_themes/flask_theme_support.py index 90005c68..05af9a9b 100644 --- a/docs/_themes/flask_theme_support.py +++ b/docs/_themes/flask_theme_support.py @@ -1,19 +1,17 @@ # flasky pygments style based on tango style from pygments.style import Style -from pygments.token import ( - Keyword, - Name, - Comment, - String, - Error, - Number, - Operator, - Generic, - Whitespace, - Punctuation, - Other, - Literal, -) +from pygments.token import Comment +from pygments.token import Error +from pygments.token import Generic +from pygments.token import Keyword +from pygments.token import Literal +from pygments.token import Name +from pygments.token import Number +from pygments.token import Operator +from pygments.token import Other +from pygments.token import Punctuation +from pygments.token import String +from pygments.token import Whitespace class FlaskyStyle(Style): diff --git a/docs/api.rst b/docs/api.rst index a1776ee0..93c2ffa8 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -30,4 +30,4 @@ Lower-Lower-Level Classes .. autoclass:: camelot.core.Table :inherited-members: -.. autoclass:: camelot.core.Cell \ No newline at end of file +.. autoclass:: camelot.core.Cell diff --git a/docs/benchmark/lattice/agstat/agstat-data-pdfplumber.csv b/docs/benchmark/lattice/agstat/agstat-data-pdfplumber.csv index 7733ba8e..2f5fd7c1 100644 --- a/docs/benchmark/lattice/agstat/agstat-data-pdfplumber.csv +++ b/docs/benchmark/lattice/agstat/agstat-data-pdfplumber.csv @@ -39,7 +39,7 @@ ot 4(I T @ (","menteds, age)nes) uireg sewastton -qn h +qn h Reudis &ak al cld L tnen diff --git a/docs/benchmark/lattice/column_span_1/column_span_1-data-pdfplumber.csv b/docs/benchmark/lattice/column_span_1/column_span_1-data-pdfplumber.csv index 040edc53..3a2334a9 100644 --- a/docs/benchmark/lattice/column_span_1/column_span_1-data-pdfplumber.csv +++ b/docs/benchmark/lattice/column_span_1/column_span_1-data-pdfplumber.csv @@ -1,9 +1,9 @@ "0","1","2","3","4","5","6","7" "Rate of Accidental Deaths & Suicides and Population Growth During 1967 to 2013","","","","","","","" -"Sl. -No.","Year","Population -(in Lakh)","Accidental Deaths","","Suicides","","Percentage -Population +"Sl. +No.","Year","Population +(in Lakh)","Accidental Deaths","","Suicides","","Percentage +Population growth" "","","","Incidence","Rate","Incidence","Rate","" "(1)","(2)","(3)","(4)","(5)","(6)","(7)","(8)" diff --git a/docs/benchmark/lattice/rotated/rotated-data-pdfplumber.csv b/docs/benchmark/lattice/rotated/rotated-data-pdfplumber.csv index e274cc59..5142c439 100644 --- a/docs/benchmark/lattice/rotated/rotated-data-pdfplumber.csv +++ b/docs/benchmark/lattice/rotated/rotated-data-pdfplumber.csv @@ -5,14 +5,14 @@ a ail v a - + t o n - + a t a D - + *","" diff --git a/docs/benchmark/stream/district_health/district_health-data-pdfplumber.csv b/docs/benchmark/stream/district_health/district_health-data-pdfplumber.csv index cc079c09..28e2b155 100644 --- a/docs/benchmark/stream/district_health/district_health-data-pdfplumber.csv +++ b/docs/benchmark/stream/district_health/district_health-data-pdfplumber.csv @@ -2,17 +2,17 @@ "","DLHS-4 (2012-13)","","DLHS-3 (2007-08)","" "Indicators","TOTAL","RURAL","TOTAL","RURAL" "Child feeding practices (based on last-born child in the reference period) (%)","","","","" -"Children age 0-5 months exclusively breastfed9 .......................................................................... 76.9 80.0 -Children age 6-9 months receiving solid/semi-solid food and breast milk .................................... 78.6 75.0 -Children age 12-23 months receiving breast feeding along with complementary feeding ........... 31.8 24.2 -Children age 6-35 months exclusively breastfed for at least 6 months ........................................ 4.7 3.4 +"Children age 0-5 months exclusively breastfed9 .......................................................................... 76.9 80.0 +Children age 6-9 months receiving solid/semi-solid food and breast milk .................................... 78.6 75.0 +Children age 12-23 months receiving breast feeding along with complementary feeding ........... 31.8 24.2 +Children age 6-35 months exclusively breastfed for at least 6 months ........................................ 4.7 3.4 Children under 3 years breastfed within one hour of birth ............................................................ 42.9 46.5","","","NA","NA" "","","","85.9","89.3" "","","","NA","NA" "","","","30.0","27.7" "","","","50.6","52.9" "Birth Weight (%) (age below 36 months)","","","","" -"Percentage of Children weighed at birth ...................................................................................... 38.8 41.0 NA NA +"Percentage of Children weighed at birth ...................................................................................... 38.8 41.0 NA NA Percentage of Children with low birth weight (out of those who weighted) ( below 2.5 kg) ......... 12.8 14.6 NA NA","","","","" "Awareness about Diarrhoea (%)","","","","" "Women know about what to do when a child gets diarrhoea ..................................................... 96.3 96.2","","","94.4","94.2" @@ -22,45 +22,45 @@ Percentage of Children with low birth weight (out of those who weighted) ( below "","","","","" "reference period) (%)","","","","" "","","","","" -"Prevalence of diarrhoea in last 2 weeks for under 5 years old children ....................................... 1.6 1.3 6.5 7.0 -Children with diarrhoea in the last 2 weeks and received ORS11 ................................................. 100.0 100.0 54.8 53.3 -Children with diarrhoea in the last 2 weeks and sought advice/treatment ................................... 100.0 50.0 72.9 73.3 -Prevalence of ARI in last 2 weeks for under 5 years old children ............................................ 4.3 3.9 3.9 4.2 -Children with acute respiratory infection or fever in last 2 weeks and sought advice/treatment 37.5 33.3 69.8 68.0 +"Prevalence of diarrhoea in last 2 weeks for under 5 years old children ....................................... 1.6 1.3 6.5 7.0 +Children with diarrhoea in the last 2 weeks and received ORS11 ................................................. 100.0 100.0 54.8 53.3 +Children with diarrhoea in the last 2 weeks and sought advice/treatment ................................... 100.0 50.0 72.9 73.3 +Prevalence of ARI in last 2 weeks for under 5 years old children ............................................ 4.3 3.9 3.9 4.2 +Children with acute respiratory infection or fever in last 2 weeks and sought advice/treatment 37.5 33.3 69.8 68.0 Children with diarrhoea in the last 2 weeks given Zinc along with ORS ...................................... 66.6 50.0 NA NA","","","6.5","7.0" "","","","54.8","53.3" "","","","72.9","73.3" "","","","3.9","4.2" "","","","69.8","68.0" "Awareness of RTI/STI and HIV/AIDS (%)","","","","" -"Women who have heard of RTI/STI ............................................................................................. 55.8 57.1 -Women who have heard of HIV/AIDS .......................................................................................... 98.9 99.0 -Women who have any symptoms of RTI/STI .............................................................................. 13.9 13.5 -Women who know the place to go for testing of HIV/AIDS12 ....................................................... 59.9 57.1 +"Women who have heard of RTI/STI ............................................................................................. 55.8 57.1 +Women who have heard of HIV/AIDS .......................................................................................... 98.9 99.0 +Women who have any symptoms of RTI/STI .............................................................................. 13.9 13.5 +Women who know the place to go for testing of HIV/AIDS12 ....................................................... 59.9 57.1 Women underwent test for detecting HIV/AIDS12 ........................................................................ 37.3 36.8","","","34.8","38.2" "","","","98.3","98.1" "","","","15.6","16.1" "","","","48.6","46.3" "","","","14.1","12.3" "Utilization of Government Health Services (%)","","","","" -"Antenatal care .............................................................................................................................. 69.7 66.7 79.0 81.0 -Treatment for pregnancy complications ....................................................................................... 57.1 59.3 88.0 87.8 -Treatment for post-delivery complications ................................................................................... 33.3 33.3 68.4 68.4 -Treatment for vaginal discharge ................................................................................................... 20.0 25.0 73.9 71.4 -Treatment for children with diarrhoea13 ........................................................................................ 50.0 100.0 NA NA +"Antenatal care .............................................................................................................................. 69.7 66.7 79.0 81.0 +Treatment for pregnancy complications ....................................................................................... 57.1 59.3 88.0 87.8 +Treatment for post-delivery complications ................................................................................... 33.3 33.3 68.4 68.4 +Treatment for vaginal discharge ................................................................................................... 20.0 25.0 73.9 71.4 +Treatment for children with diarrhoea13 ........................................................................................ 50.0 100.0 NA NA Treatment for children with ARI13 ................................................................................................. NA NA NA NA","","","79.0","81.0" "","","","88.0","87.8" "","","","68.4","68.4" "","","","73.9","71.4" "Birth Registration (%)","","","","" -"Children below age 5 years having birth registration done .......................................................... 40.6 44.3 NA NA +"Children below age 5 years having birth registration done .......................................................... 40.6 44.3 NA NA Children below age 5 years who received birth certificate (out of those registered) .................... 65.9 63.6 NA NA","","","","" "Personal Habits (age 15 years and above) (%)","","","","" -"Men who use any kind of smokeless tobacco ............................................................................. 74.6 74.2 NA NA -Women who use any kind of smokeless tobacco ........................................................................ 59.5 58.9 NA NA -Men who smoke ........................................................................................................................... 56.0 56.4 NA NA -Women who smoke ...................................................................................................................... 18.4 18.0 NA NA -Men who consume alcohol ........................................................................................................... 58.4 58.2 NA NA +"Men who use any kind of smokeless tobacco ............................................................................. 74.6 74.2 NA NA +Women who use any kind of smokeless tobacco ........................................................................ 59.5 58.9 NA NA +Men who smoke ........................................................................................................................... 56.0 56.4 NA NA +Women who smoke ...................................................................................................................... 18.4 18.0 NA NA +Men who consume alcohol ........................................................................................................... 58.4 58.2 NA NA Women who consume alcohol ..................................................................................................... 10.9 9.3 NA NA","","","","" "9 Children Who were given nothing but breast milk till the survey date 10Acute Respiratory Infections11Oral Rehydration Solutions/Salts.12Based on","","","","" "the women who have heard of HIV/AIDS.13 Last two weeks","","","","" diff --git a/docs/benchmark/stream/health/health-data-pdfplumber.csv b/docs/benchmark/stream/health/health-data-pdfplumber.csv index 36c67b0c..ffe14768 100644 --- a/docs/benchmark/stream/health/health-data-pdfplumber.csv +++ b/docs/benchmark/stream/health/health-data-pdfplumber.csv @@ -2,8 +2,8 @@ "","Table: 5 Public Health Outlay 2012-13 (Budget Estimates) (Rs. in 000)","","","","","","","","","","","","","","","","","","","","","","" "","States-A","","","Revenue","","","","","","Capital","","","","","","Total","","","Others(1)","","","Total","" "","","","","","","","","","","","","","","","","Revenue &","","","","","","","" -"","","","Medical & Family Medical & Family -Public Welfare Public Welfare +"","","","Medical & Family Medical & Family +Public Welfare Public Welfare Health Health","","","","","","","","","","","","","","","","","","","","" "","","","","","","","","","","","","","","","","Capital","","","","","","","" "","","","","","","","","","","","","","","","","","","","","","","","" diff --git a/docs/benchmark/stream/missing_values/missing_values-data-pdfplumber.csv b/docs/benchmark/stream/missing_values/missing_values-data-pdfplumber.csv index e8c5eff6..52fec204 100644 --- a/docs/benchmark/stream/missing_values/missing_values-data-pdfplumber.csv +++ b/docs/benchmark/stream/missing_values/missing_values-data-pdfplumber.csv @@ -2,39 +2,39 @@ "","DLHS-4 (2012-13)","","DLHS-3 (2007-08)","" "Indicators","TOTAL","RURAL","TOTAL","RURAL" "Reported Prevalence of Morbidity","","","","" -"Any Injury ..................................................................................................................................... 1.9 2.1 -Acute Illness ................................................................................................................................. 4.5 5.6 +"Any Injury ..................................................................................................................................... 1.9 2.1 +Acute Illness ................................................................................................................................. 4.5 5.6 Chronic Illness .............................................................................................................................. 5.1 4.1","","","","" "","","","","" "","","","","" "Reported Prevalence of Chronic Illness during last one year (%)","","","","" -"Disease of respiratory system ...................................................................................................... 11.7 15.0 -Disease of cardiovascular system ................................................................................................ 8.9 9.3 +"Disease of respiratory system ...................................................................................................... 11.7 15.0 +Disease of cardiovascular system ................................................................................................ 8.9 9.3 Persons suffering from tuberculosis ............................................................................................. 2.2 1.5","","","","" "","","","","" "","","","","" "Anaemia Status by Haemoglobin Level14 (%)","","","","" -"Children (6-59 months) having anaemia ...................................................................................... 68.5 71.9 -Children (6-59 months) having severe anaemia .......................................................................... 6.7 9.4 -Children (6-9 Years) having anaemia - Male ................................................................................ 67.1 71.4 -Children (6-9 Years) having severe anaemia - Male .................................................................... 4.4 2.4 -Children (6-9 Years) having anaemia - Female ........................................................................... 52.4 48.8 -Children (6-9 Years) having severe anaemia - Female ................................................................ 1.2 0.0 -Children (6-14 years) having anaemia - Male ............................................................................. 50.8 62.5 -Children (6-14 years) having severe anaemia - Male .................................................................. 3.7 3.6 -Children (6-14 years) having anaemia - Female ......................................................................... 48.3 50.0 -Children (6-14 years) having severe anaemia - Female .............................................................. 4.3 6.1 -Children (10-19 Years15) having anaemia - Male ......................................................................... 37.9 51.2 -Children (10-19 Years15) having severe anaemia - Male ............................................................. 3.5 4.0 -Children (10-19 Years15) having anaemia - Female ..................................................................... 46.6 52.1 -Children (10-19 Years15) having severe anaemia - Female ......................................................... 6.4 6.5 -Adolescents (15-19 years) having anaemia ................................................................................ 39.4 46.5 -Adolescents (15-19 years) having severe anaemia ..................................................................... 5.4 5.1 -Pregnant women (15-49 aged) having anaemia .......................................................................... 48.8 51.5 -Pregnant women (15-49 aged) having severe anaemia .............................................................. 7.1 8.8 -Women (15-49 aged) having anaemia ......................................................................................... 45.2 51.7 -Women (15-49 aged) having severe anaemia ............................................................................. 4.8 5.9 -Persons (20 years and above) having anaemia ........................................................................... 37.8 42.1 +"Children (6-59 months) having anaemia ...................................................................................... 68.5 71.9 +Children (6-59 months) having severe anaemia .......................................................................... 6.7 9.4 +Children (6-9 Years) having anaemia - Male ................................................................................ 67.1 71.4 +Children (6-9 Years) having severe anaemia - Male .................................................................... 4.4 2.4 +Children (6-9 Years) having anaemia - Female ........................................................................... 52.4 48.8 +Children (6-9 Years) having severe anaemia - Female ................................................................ 1.2 0.0 +Children (6-14 years) having anaemia - Male ............................................................................. 50.8 62.5 +Children (6-14 years) having severe anaemia - Male .................................................................. 3.7 3.6 +Children (6-14 years) having anaemia - Female ......................................................................... 48.3 50.0 +Children (6-14 years) having severe anaemia - Female .............................................................. 4.3 6.1 +Children (10-19 Years15) having anaemia - Male ......................................................................... 37.9 51.2 +Children (10-19 Years15) having severe anaemia - Male ............................................................. 3.5 4.0 +Children (10-19 Years15) having anaemia - Female ..................................................................... 46.6 52.1 +Children (10-19 Years15) having severe anaemia - Female ......................................................... 6.4 6.5 +Adolescents (15-19 years) having anaemia ................................................................................ 39.4 46.5 +Adolescents (15-19 years) having severe anaemia ..................................................................... 5.4 5.1 +Pregnant women (15-49 aged) having anaemia .......................................................................... 48.8 51.5 +Pregnant women (15-49 aged) having severe anaemia .............................................................. 7.1 8.8 +Women (15-49 aged) having anaemia ......................................................................................... 45.2 51.7 +Women (15-49 aged) having severe anaemia ............................................................................. 4.8 5.9 +Persons (20 years and above) having anaemia ........................................................................... 37.8 42.1 Persons (20 years and above) having Severe anaemia .............................................................. 4.6 4.8","","","","" "","","","","" "","","","","" @@ -58,12 +58,12 @@ Persons (20 years and above) having Severe anaemia ............................. "","","","","" "","","","","" "Blood Sugar Level (age 18 years and above) (%)","","","","" -"Blood Sugar Level >140 mg/dl (high) ........................................................................................... 12.9 11.1 +"Blood Sugar Level >140 mg/dl (high) ........................................................................................... 12.9 11.1 Blood Sugar Level >160 mg/dl (very high) ................................................................................... 7.0 5.1","","","","" "","","","","" "Hypertension (age 18 years and above) (%)","","","","" -"Above Normal Range (Systolic >140 mm of Hg & Diastolic >90 mm of Hg ) .............................. 23.8 22.8 -Moderately High (Systolic >160 mm of Hg & Diastolic >100 mm of Hg ) ..................................... 8.2 7.1 +"Above Normal Range (Systolic >140 mm of Hg & Diastolic >90 mm of Hg ) .............................. 23.8 22.8 +Moderately High (Systolic >160 mm of Hg & Diastolic >100 mm of Hg ) ..................................... 8.2 7.1 Very High (Systolic >180 mm of Hg & Diastolic >110 mm of Hg ) ............................................... 3.7 3.1","","","","" "","","","","" "","","","","" diff --git a/docs/conf.py b/docs/conf.py index e3384126..368e0187 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # # camelot documentation build configuration file, created by # sphinx-quickstart on Tue Jul 19 13:44:18 2016. @@ -15,6 +14,9 @@ import os import sys +import camelot + + # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. @@ -25,8 +27,6 @@ sys.path.insert(0, os.path.abspath("..")) sys.path.insert(0, os.path.abspath("_themes")) -import camelot - # -- General configuration ------------------------------------------------ @@ -43,6 +43,8 @@ "sphinx.ext.intersphinx", "sphinx.ext.todo", "sphinx.ext.viewcode", + "sphinx_click", + "myst_parser", ] # Add any paths that contain templates here, relative to this directory. @@ -62,9 +64,9 @@ master_doc = "index" # General information about the project. -project = u"Camelot" -copyright = u"2021, Camelot Developers" -author = u"Vinayak Mehta" +project = "Camelot" +copyright = "2021, Camelot Developers" +author = "Vinayak Mehta" # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the @@ -283,7 +285,7 @@ # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ - (master_doc, "Camelot.tex", u"Camelot Documentation", u"Vinayak Mehta", "manual"), + (master_doc, "Camelot.tex", "Camelot Documentation", "Vinayak Mehta", "manual"), ] # The name of an image file (relative to this directory) to place at the top of @@ -323,7 +325,7 @@ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). -man_pages = [(master_doc, "Camelot", u"Camelot Documentation", [author], 1)] +man_pages = [(master_doc, "Camelot", "Camelot Documentation", [author], 1)] # If true, show URL addresses after external links. # @@ -339,7 +341,7 @@ ( master_doc, "Camelot", - u"Camelot Documentation", + "Camelot Documentation", author, "Camelot", "One line description of project.", diff --git a/docs/dev/contributing.rst b/docs/dev/contributing.rst index 9aa5b46d..fa8778c4 100644 --- a/docs/dev/contributing.rst +++ b/docs/dev/contributing.rst @@ -162,4 +162,4 @@ In bug reports, make sure you include: .. _Creating and highlighting code blocks: https://help.github.com/articles/creating-and-highlighting-code-blocks/ -- A link to the PDF document that you were trying to extract tables from, telling us what you expected the code to do and what actually happened. \ No newline at end of file +- A link to the PDF document that you were trying to extract tables from, telling us what you expected the code to do and what actually happened. diff --git a/docs/requirements.txt b/docs/requirements.txt new file mode 100644 index 00000000..740d0e18 --- /dev/null +++ b/docs/requirements.txt @@ -0,0 +1,7 @@ +furo==2022.4.7 +sphinx==4.5.0 +sphinx-click==4.1.0 +myst_parser==0.17.2 +ghostscript==0.7 +opencv-python==4.7.0.68 +matplotlib==3.6.3 diff --git a/docs/user/intro.rst b/docs/user/intro.rst index 056984f5..bdd1b5a8 100644 --- a/docs/user/intro.rst +++ b/docs/user/intro.rst @@ -43,4 +43,4 @@ Fun fact: In the British comedy film `Monty Python and the Holy Grail`_ (and in Camelot License --------------- - .. include:: ../../LICENSE \ No newline at end of file + .. include:: ../../LICENSE diff --git a/noxfile.py b/noxfile.py new file mode 100644 index 00000000..0f02b6e1 --- /dev/null +++ b/noxfile.py @@ -0,0 +1,254 @@ +"""Nox sessions.""" +import os +import shlex +import shutil +import sys +from pathlib import Path +from textwrap import dedent + +import nox + + +try: + from nox_poetry import Session + from nox_poetry import session +except ImportError: + message = f"""\ + Nox failed to import the 'nox-poetry' package. + + Please install it using the following command: + + {sys.executable} -m pip install nox-poetry""" + raise SystemExit(dedent(message)) from None + +package = "camelot" +python_versions = ["3.10", "3.9", "3.8", "3.11"] +nox.needs_version = ">= 2021.6.6" +nox.options.sessions = ( + "pre-commit", + "safety", + "mypy", + "tests", + "typeguard", + "xdoctest", + "docs-build", +) + + +def activate_virtualenv_in_precommit_hooks(session: Session) -> None: + """Activate virtualenv in hooks installed by pre-commit. + + This function patches git hooks installed by pre-commit to activate the + session's virtual environment. This allows pre-commit to locate hooks in + that environment when invoked from git. + + Args: + session: The Session object. + """ + assert session.bin is not None # noqa: S101 + + # Only patch hooks containing a reference to this session's bindir. Support + # quoting rules for Python and bash, but strip the outermost quotes so we + # can detect paths within the bindir, like /python. + bindirs = [ + bindir[1:-1] if bindir[0] in "'\"" else bindir + for bindir in (repr(session.bin), shlex.quote(session.bin)) + ] + + virtualenv = session.env.get("VIRTUAL_ENV") + if virtualenv is None: + return + + headers = { + # pre-commit < 2.16.0 + "python": f"""\ + import os + os.environ["VIRTUAL_ENV"] = {virtualenv!r} + os.environ["PATH"] = os.pathsep.join(( + {session.bin!r}, + os.environ.get("PATH", ""), + )) + """, + # pre-commit >= 2.16.0 + "bash": f"""\ + VIRTUAL_ENV={shlex.quote(virtualenv)} + PATH={shlex.quote(session.bin)}"{os.pathsep}$PATH" + """, + # pre-commit >= 2.17.0 on Windows forces sh shebang + "/bin/sh": f"""\ + VIRTUAL_ENV={shlex.quote(virtualenv)} + PATH={shlex.quote(session.bin)}"{os.pathsep}$PATH" + """, + } + + hookdir = Path(".git") / "hooks" + if not hookdir.is_dir(): + return + + for hook in hookdir.iterdir(): + if hook.name.endswith(".sample") or not hook.is_file(): + continue + + if not hook.read_bytes().startswith(b"#!"): + continue + + text = hook.read_text() + + if not any( + Path("A") == Path("a") and bindir.lower() in text.lower() or bindir in text + for bindir in bindirs + ): + continue + + lines = text.splitlines() + + for executable, header in headers.items(): + if executable in lines[0].lower(): + lines.insert(1, dedent(header)) + hook.write_text("\n".join(lines)) + break + + +@session(name="pre-commit", python=python_versions[0]) +def precommit(session: Session) -> None: + """Lint using pre-commit.""" + args = session.posargs or [ + "run", + "--all-files", + "--hook-stage=manual", + "--show-diff-on-failure", + ] + session.install( + "black", + "flake8", + "flake8-bandit", + "flake8-bugbear", + "flake8-docstrings", + "flake8-rst-docstrings", + "isort", + "pep8-naming", + "pre-commit", + "pre-commit-hooks", + "pyupgrade", + ) + session.run("pre-commit", *args) + if args and args[0] == "install": + activate_virtualenv_in_precommit_hooks(session) + + +@session(python=python_versions[0]) +def safety(session: Session) -> None: + """Scan dependencies for insecure packages.""" + requirements = session.poetry.export_requirements() + session.install("safety") + session.run("safety", "check", "--full-report", f"--file={requirements}") + + +@session(python=python_versions) +def mypy(session: Session) -> None: + """Type-check using mypy.""" + args = session.posargs or ["camelot", "tests", "docs/conf.py"] + session.install(".") + session.install("mypy", "pytest") + session.run("mypy", *args) + if not session.posargs: + session.run("mypy", f"--python-executable={sys.executable}", "noxfile.py") + + +base_requires = ["ghostscript>=0.7", "opencv-python>=3.4.2.17"] + +plot_requires = [ + "matplotlib>=2.2.3", +] + + +@session(python=python_versions) +def tests(session: Session) -> None: + """Run the test suite.""" + session.install(".") + + session.install( + "coverage[toml]", "pytest", "pygments", *base_requires, *plot_requires + ) + try: + session.run("coverage", "run", "--parallel", "-m", "pytest", *session.posargs) + finally: + if session.interactive: + session.notify("coverage", posargs=[]) + + +@session(python=python_versions[0]) +def coverage(session: Session) -> None: + """Produce the coverage report.""" + args = session.posargs or ["report", "-i"] + + session.install("coverage[toml]") + + if not session.posargs and any(Path().glob(".coverage.*")): + session.run("coverage", "combine") + + session.run("coverage", *args) + + +@session(python=python_versions[0]) +def typeguard(session: Session) -> None: + """Runtime type checking using Typeguard.""" + session.install(".") + session.install("pytest", "typeguard", "pygments", *base_requires, *plot_requires) + session.run("pytest", f"--typeguard-packages={package}", *session.posargs) + + +@session(python=python_versions) +def xdoctest(session: Session) -> None: + """Run examples with xdoctest.""" + if session.posargs: + args = [package, *session.posargs] + else: + args = [f"--modname={package}", "--command=all"] + if "FORCE_COLOR" in os.environ: + args.append("--colored=1") + + session.install(".") + session.install("xdoctest[colors]") + session.run("python", "-m", "xdoctest", *args) + + +@session(name="docs-build", python=python_versions[0]) +def docs_build(session: Session) -> None: + """Build the documentation.""" + args = session.posargs or ["docs", "docs/_build"] + if not session.posargs and "FORCE_COLOR" in os.environ: + args.insert(0, "--color") + + session.install(".") + session.install( + "sphinx", "sphinx-click", "furo", "myst-parser", *base_requires, *plot_requires + ) + + build_dir = Path("docs", "_build") + if build_dir.exists(): + shutil.rmtree(build_dir) + + session.run("sphinx-build", *args) + + +@session(python=python_versions[0]) +def docs(session: Session) -> None: + """Build and serve the documentation with live reloading on file changes.""" + args = session.posargs or ["--open-browser", "docs", "docs/_build"] + session.install(".") + session.install( + "sphinx", + "sphinx-autobuild", + "sphinx-click", + "furo", + "myst-parser", + *base_requires, + *plot_requires, + ) + + build_dir = Path("docs", "_build") + if build_dir.exists(): + shutil.rmtree(build_dir) + + session.run("sphinx-autobuild", *args) diff --git a/poetry.lock b/poetry.lock new file mode 100644 index 00000000..5a10522c --- /dev/null +++ b/poetry.lock @@ -0,0 +1,2483 @@ +# This file is automatically @generated by Poetry 1.4.2 and should not be changed by hand. + +[[package]] +name = "alabaster" +version = "0.7.13" +description = "A configurable sidebar-enabled Sphinx theme" +category = "dev" +optional = false +python-versions = ">=3.6" +files = [ + {file = "alabaster-0.7.13-py3-none-any.whl", hash = "sha256:1ee19aca801bbabb5ba3f5f258e4422dfa86f82f3e9cefb0859b283cdd7f62a3"}, + {file = "alabaster-0.7.13.tar.gz", hash = "sha256:a27a4a084d5e690e16e01e03ad2b2e552c61a65469419b907243193de1a84ae2"}, +] + +[[package]] +name = "attrs" +version = "23.1.0" +description = "Classes Without Boilerplate" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "attrs-23.1.0-py3-none-any.whl", hash = "sha256:1f28b4522cdc2fb4256ac1a020c78acf9cba2c6b461ccd2c126f3aa8e8335d04"}, + {file = "attrs-23.1.0.tar.gz", hash = "sha256:6279836d581513a26f1bf235f9acd333bc9115683f14f7e8fae46c98fc50e015"}, +] + +[package.extras] +cov = ["attrs[tests]", "coverage[toml] (>=5.3)"] +dev = ["attrs[docs,tests]", "pre-commit"] +docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope-interface"] +tests = ["attrs[tests-no-zope]", "zope-interface"] +tests-no-zope = ["cloudpickle", "hypothesis", "mypy (>=1.1.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] + +[[package]] +name = "babel" +version = "2.12.1" +description = "Internationalization utilities" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "Babel-2.12.1-py3-none-any.whl", hash = "sha256:b4246fb7677d3b98f501a39d43396d3cafdc8eadb045f4a31be01863f655c610"}, + {file = "Babel-2.12.1.tar.gz", hash = "sha256:cc2d99999cd01d44420ae725a21c9e3711b3aadc7976d6147f622d8581963455"}, +] + +[package.dependencies] +pytz = {version = ">=2015.7", markers = "python_version < \"3.9\""} + +[[package]] +name = "bandit" +version = "1.7.5" +description = "Security oriented static analyser for python code." +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "bandit-1.7.5-py3-none-any.whl", hash = "sha256:75665181dc1e0096369112541a056c59d1c5f66f9bb74a8d686c3c362b83f549"}, + {file = "bandit-1.7.5.tar.gz", hash = "sha256:bdfc739baa03b880c2d15d0431b31c658ffc348e907fe197e54e0389dd59e11e"}, +] + +[package.dependencies] +colorama = {version = ">=0.3.9", markers = "platform_system == \"Windows\""} +GitPython = ">=1.0.1" +PyYAML = ">=5.3.1" +rich = "*" +stevedore = ">=1.20.0" + +[package.extras] +test = ["beautifulsoup4 (>=4.8.0)", "coverage (>=4.5.4)", "fixtures (>=3.0.0)", "flake8 (>=4.0.0)", "pylint (==1.9.4)", "stestr (>=2.5.0)", "testscenarios (>=0.5.0)", "testtools (>=2.3.0)", "tomli (>=1.1.0)"] +toml = ["tomli (>=1.1.0)"] +yaml = ["PyYAML"] + +[[package]] +name = "beautifulsoup4" +version = "4.12.2" +description = "Screen-scraping library" +category = "dev" +optional = false +python-versions = ">=3.6.0" +files = [ + {file = "beautifulsoup4-4.12.2-py3-none-any.whl", hash = "sha256:bd2520ca0d9d7d12694a53d44ac482d181b4ec1888909b035a3dbf40d0f57d4a"}, + {file = "beautifulsoup4-4.12.2.tar.gz", hash = "sha256:492bbc69dca35d12daac71c4db1bfff0c876c00ef4a2ffacce226d4638eb72da"}, +] + +[package.dependencies] +soupsieve = ">1.2" + +[package.extras] +html5lib = ["html5lib"] +lxml = ["lxml"] + +[[package]] +name = "black" +version = "23.7.0" +description = "The uncompromising code formatter." +category = "dev" +optional = false +python-versions = ">=3.8" +files = [ + {file = "black-23.7.0-cp310-cp310-macosx_10_16_arm64.whl", hash = "sha256:5c4bc552ab52f6c1c506ccae05681fab58c3f72d59ae6e6639e8885e94fe2587"}, + {file = "black-23.7.0-cp310-cp310-macosx_10_16_universal2.whl", hash = "sha256:552513d5cd5694590d7ef6f46e1767a4df9af168d449ff767b13b084c020e63f"}, + {file = "black-23.7.0-cp310-cp310-macosx_10_16_x86_64.whl", hash = "sha256:86cee259349b4448adb4ef9b204bb4467aae74a386bce85d56ba4f5dc0da27be"}, + {file = "black-23.7.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:501387a9edcb75d7ae8a4412bb8749900386eaef258f1aefab18adddea1936bc"}, + {file = "black-23.7.0-cp310-cp310-win_amd64.whl", hash = "sha256:fb074d8b213749fa1d077d630db0d5f8cc3b2ae63587ad4116e8a436e9bbe995"}, + {file = "black-23.7.0-cp311-cp311-macosx_10_16_arm64.whl", hash = "sha256:b5b0ee6d96b345a8b420100b7d71ebfdd19fab5e8301aff48ec270042cd40ac2"}, + {file = "black-23.7.0-cp311-cp311-macosx_10_16_universal2.whl", hash = "sha256:893695a76b140881531062d48476ebe4a48f5d1e9388177e175d76234ca247cd"}, + {file = "black-23.7.0-cp311-cp311-macosx_10_16_x86_64.whl", hash = "sha256:c333286dc3ddca6fdff74670b911cccedacb4ef0a60b34e491b8a67c833b343a"}, + {file = "black-23.7.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:831d8f54c3a8c8cf55f64d0422ee875eecac26f5f649fb6c1df65316b67c8926"}, + {file = "black-23.7.0-cp311-cp311-win_amd64.whl", hash = "sha256:7f3bf2dec7d541b4619b8ce526bda74a6b0bffc480a163fed32eb8b3c9aed8ad"}, + {file = "black-23.7.0-cp38-cp38-macosx_10_16_arm64.whl", hash = "sha256:f9062af71c59c004cd519e2fb8f5d25d39e46d3af011b41ab43b9c74e27e236f"}, + {file = "black-23.7.0-cp38-cp38-macosx_10_16_universal2.whl", hash = "sha256:01ede61aac8c154b55f35301fac3e730baf0c9cf8120f65a9cd61a81cfb4a0c3"}, + {file = "black-23.7.0-cp38-cp38-macosx_10_16_x86_64.whl", hash = "sha256:327a8c2550ddc573b51e2c352adb88143464bb9d92c10416feb86b0f5aee5ff6"}, + {file = "black-23.7.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d1c6022b86f83b632d06f2b02774134def5d4d4f1dac8bef16d90cda18ba28a"}, + {file = "black-23.7.0-cp38-cp38-win_amd64.whl", hash = "sha256:27eb7a0c71604d5de083757fbdb245b1a4fae60e9596514c6ec497eb63f95320"}, + {file = "black-23.7.0-cp39-cp39-macosx_10_16_arm64.whl", hash = "sha256:8417dbd2f57b5701492cd46edcecc4f9208dc75529bcf76c514864e48da867d9"}, + {file = "black-23.7.0-cp39-cp39-macosx_10_16_universal2.whl", hash = "sha256:47e56d83aad53ca140da0af87678fb38e44fd6bc0af71eebab2d1f59b1acf1d3"}, + {file = "black-23.7.0-cp39-cp39-macosx_10_16_x86_64.whl", hash = "sha256:25cc308838fe71f7065df53aedd20327969d05671bac95b38fdf37ebe70ac087"}, + {file = "black-23.7.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:642496b675095d423f9b8448243336f8ec71c9d4d57ec17bf795b67f08132a91"}, + {file = "black-23.7.0-cp39-cp39-win_amd64.whl", hash = "sha256:ad0014efc7acf0bd745792bd0d8857413652979200ab924fbf239062adc12491"}, + {file = "black-23.7.0-py3-none-any.whl", hash = "sha256:9fd59d418c60c0348505f2ddf9609c1e1de8e7493eab96198fc89d9f865e7a96"}, + {file = "black-23.7.0.tar.gz", hash = "sha256:022a582720b0d9480ed82576c920a8c1dde97cc38ff11d8d8859b3bd6ca9eedb"}, +] + +[package.dependencies] +click = ">=8.0.0" +mypy-extensions = ">=0.4.3" +packaging = ">=22.0" +pathspec = ">=0.9.0" +platformdirs = ">=2" +tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} +typing-extensions = {version = ">=3.10.0.0", markers = "python_version < \"3.10\""} + +[package.extras] +colorama = ["colorama (>=0.4.3)"] +d = ["aiohttp (>=3.7.4)"] +jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] +uvloop = ["uvloop (>=0.15.2)"] + +[[package]] +name = "certifi" +version = "2023.5.7" +description = "Python package for providing Mozilla's CA Bundle." +category = "dev" +optional = false +python-versions = ">=3.6" +files = [ + {file = "certifi-2023.5.7-py3-none-any.whl", hash = "sha256:c6c2e98f5c7869efca1f8916fed228dd91539f9f1b444c314c06eef02980c716"}, + {file = "certifi-2023.5.7.tar.gz", hash = "sha256:0f0d56dc5a6ad56fd4ba36484d6cc34451e1c6548c61daad8c320169f91eddc7"}, +] + +[[package]] +name = "cffi" +version = "1.15.1" +description = "Foreign Function Interface for Python calling C code." +category = "main" +optional = false +python-versions = "*" +files = [ + {file = "cffi-1.15.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:a66d3508133af6e8548451b25058d5812812ec3798c886bf38ed24a98216fab2"}, + {file = "cffi-1.15.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:470c103ae716238bbe698d67ad020e1db9d9dba34fa5a899b5e21577e6d52ed2"}, + {file = "cffi-1.15.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:9ad5db27f9cabae298d151c85cf2bad1d359a1b9c686a275df03385758e2f914"}, + {file = "cffi-1.15.1-cp27-cp27m-win32.whl", hash = "sha256:b3bbeb01c2b273cca1e1e0c5df57f12dce9a4dd331b4fa1635b8bec26350bde3"}, + {file = "cffi-1.15.1-cp27-cp27m-win_amd64.whl", hash = "sha256:e00b098126fd45523dd056d2efba6c5a63b71ffe9f2bbe1a4fe1716e1d0c331e"}, + {file = "cffi-1.15.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:d61f4695e6c866a23a21acab0509af1cdfd2c013cf256bbf5b6b5e2695827162"}, + {file = "cffi-1.15.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:ed9cb427ba5504c1dc15ede7d516b84757c3e3d7868ccc85121d9310d27eed0b"}, + {file = "cffi-1.15.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:39d39875251ca8f612b6f33e6b1195af86d1b3e60086068be9cc053aa4376e21"}, + {file = "cffi-1.15.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:285d29981935eb726a4399badae8f0ffdff4f5050eaa6d0cfc3f64b857b77185"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3eb6971dcff08619f8d91607cfc726518b6fa2a9eba42856be181c6d0d9515fd"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:21157295583fe8943475029ed5abdcf71eb3911894724e360acff1d61c1d54bc"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5635bd9cb9731e6d4a1132a498dd34f764034a8ce60cef4f5319c0541159392f"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2012c72d854c2d03e45d06ae57f40d78e5770d252f195b93f581acf3ba44496e"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd86c085fae2efd48ac91dd7ccffcfc0571387fe1193d33b6394db7ef31fe2a4"}, + {file = "cffi-1.15.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:fa6693661a4c91757f4412306191b6dc88c1703f780c8234035eac011922bc01"}, + {file = "cffi-1.15.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:59c0b02d0a6c384d453fece7566d1c7e6b7bae4fc5874ef2ef46d56776d61c9e"}, + {file = "cffi-1.15.1-cp310-cp310-win32.whl", hash = "sha256:cba9d6b9a7d64d4bd46167096fc9d2f835e25d7e4c121fb2ddfc6528fb0413b2"}, + {file = "cffi-1.15.1-cp310-cp310-win_amd64.whl", hash = "sha256:ce4bcc037df4fc5e3d184794f27bdaab018943698f4ca31630bc7f84a7b69c6d"}, + {file = "cffi-1.15.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3d08afd128ddaa624a48cf2b859afef385b720bb4b43df214f85616922e6a5ac"}, + {file = "cffi-1.15.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3799aecf2e17cf585d977b780ce79ff0dc9b78d799fc694221ce814c2c19db83"}, + {file = "cffi-1.15.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a591fe9e525846e4d154205572a029f653ada1a78b93697f3b5a8f1f2bc055b9"}, + {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3548db281cd7d2561c9ad9984681c95f7b0e38881201e157833a2342c30d5e8c"}, + {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:91fc98adde3d7881af9b59ed0294046f3806221863722ba7d8d120c575314325"}, + {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94411f22c3985acaec6f83c6df553f2dbe17b698cc7f8ae751ff2237d96b9e3c"}, + {file = "cffi-1.15.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:03425bdae262c76aad70202debd780501fabeaca237cdfddc008987c0e0f59ef"}, + {file = "cffi-1.15.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:cc4d65aeeaa04136a12677d3dd0b1c0c94dc43abac5860ab33cceb42b801c1e8"}, + {file = "cffi-1.15.1-cp311-cp311-win32.whl", hash = "sha256:a0f100c8912c114ff53e1202d0078b425bee3649ae34d7b070e9697f93c5d52d"}, + {file = "cffi-1.15.1-cp311-cp311-win_amd64.whl", hash = "sha256:04ed324bda3cda42b9b695d51bb7d54b680b9719cfab04227cdd1e04e5de3104"}, + {file = "cffi-1.15.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50a74364d85fd319352182ef59c5c790484a336f6db772c1a9231f1c3ed0cbd7"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e263d77ee3dd201c3a142934a086a4450861778baaeeb45db4591ef65550b0a6"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cec7d9412a9102bdc577382c3929b337320c4c4c4849f2c5cdd14d7368c5562d"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4289fc34b2f5316fbb762d75362931e351941fa95fa18789191b33fc4cf9504a"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:173379135477dc8cac4bc58f45db08ab45d228b3363adb7af79436135d028405"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6975a3fac6bc83c4a65c9f9fcab9e47019a11d3d2cf7f3c0d03431bf145a941e"}, + {file = "cffi-1.15.1-cp36-cp36m-win32.whl", hash = "sha256:2470043b93ff09bf8fb1d46d1cb756ce6132c54826661a32d4e4d132e1977adf"}, + {file = "cffi-1.15.1-cp36-cp36m-win_amd64.whl", hash = "sha256:30d78fbc8ebf9c92c9b7823ee18eb92f2e6ef79b45ac84db507f52fbe3ec4497"}, + {file = "cffi-1.15.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:198caafb44239b60e252492445da556afafc7d1e3ab7a1fb3f0584ef6d742375"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5ef34d190326c3b1f822a5b7a45f6c4535e2f47ed06fec77d3d799c450b2651e"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8102eaf27e1e448db915d08afa8b41d6c7ca7a04b7d73af6514df10a3e74bd82"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5df2768244d19ab7f60546d0c7c63ce1581f7af8b5de3eb3004b9b6fc8a9f84b"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a8c4917bd7ad33e8eb21e9a5bbba979b49d9a97acb3a803092cbc1133e20343c"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2642fe3142e4cc4af0799748233ad6da94c62a8bec3a6648bf8ee68b1c7426"}, + {file = "cffi-1.15.1-cp37-cp37m-win32.whl", hash = "sha256:e229a521186c75c8ad9490854fd8bbdd9a0c9aa3a524326b55be83b54d4e0ad9"}, + {file = "cffi-1.15.1-cp37-cp37m-win_amd64.whl", hash = "sha256:a0b71b1b8fbf2b96e41c4d990244165e2c9be83d54962a9a1d118fd8657d2045"}, + {file = "cffi-1.15.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:320dab6e7cb2eacdf0e658569d2575c4dad258c0fcc794f46215e1e39f90f2c3"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e74c6b51a9ed6589199c787bf5f9875612ca4a8a0785fb2d4a84429badaf22a"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5c84c68147988265e60416b57fc83425a78058853509c1b0629c180094904a5"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b926aa83d1edb5aa5b427b4053dc420ec295a08e40911296b9eb1b6170f6cca"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:87c450779d0914f2861b8526e035c5e6da0a3199d8f1add1a665e1cbc6fc6d02"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f2c9f67e9821cad2e5f480bc8d83b8742896f1242dba247911072d4fa94c192"}, + {file = "cffi-1.15.1-cp38-cp38-win32.whl", hash = "sha256:8b7ee99e510d7b66cdb6c593f21c043c248537a32e0bedf02e01e9553a172314"}, + {file = "cffi-1.15.1-cp38-cp38-win_amd64.whl", hash = "sha256:00a9ed42e88df81ffae7a8ab6d9356b371399b91dbdf0c3cb1e84c03a13aceb5"}, + {file = "cffi-1.15.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:54a2db7b78338edd780e7ef7f9f6c442500fb0d41a5a4ea24fff1c929d5af585"}, + {file = "cffi-1.15.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:fcd131dd944808b5bdb38e6f5b53013c5aa4f334c5cad0c72742f6eba4b73db0"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7473e861101c9e72452f9bf8acb984947aa1661a7704553a9f6e4baa5ba64415"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c9a799e985904922a4d207a94eae35c78ebae90e128f0c4e521ce339396be9d"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3bcde07039e586f91b45c88f8583ea7cf7a0770df3a1649627bf598332cb6984"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:33ab79603146aace82c2427da5ca6e58f2b3f2fb5da893ceac0c42218a40be35"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d598b938678ebf3c67377cdd45e09d431369c3b1a5b331058c338e201f12b27"}, + {file = "cffi-1.15.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:db0fbb9c62743ce59a9ff687eb5f4afbe77e5e8403d6697f7446e5f609976f76"}, + {file = "cffi-1.15.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:98d85c6a2bef81588d9227dde12db8a7f47f639f4a17c9ae08e773aa9c697bf3"}, + {file = "cffi-1.15.1-cp39-cp39-win32.whl", hash = "sha256:40f4774f5a9d4f5e344f31a32b5096977b5d48560c5592e2f3d2c4374bd543ee"}, + {file = "cffi-1.15.1-cp39-cp39-win_amd64.whl", hash = "sha256:70df4e3b545a17496c9b3f41f5115e69a4f2e77e94e1d2a8e1070bc0c38c8a3c"}, + {file = "cffi-1.15.1.tar.gz", hash = "sha256:d400bfb9a37b1351253cb402671cea7e89bdecc294e8016a707f6d1d8ac934f9"}, +] + +[package.dependencies] +pycparser = "*" + +[[package]] +name = "cfgv" +version = "3.3.1" +description = "Validate configuration and produce human readable error messages." +category = "dev" +optional = false +python-versions = ">=3.6.1" +files = [ + {file = "cfgv-3.3.1-py2.py3-none-any.whl", hash = "sha256:c6a0883f3917a037485059700b9e75da2464e6c27051014ad85ba6aaa5884426"}, + {file = "cfgv-3.3.1.tar.gz", hash = "sha256:f5a830efb9ce7a445376bb66ec94c638a9787422f96264c98edc6bdeed8ab736"}, +] + +[[package]] +name = "chardet" +version = "5.1.0" +description = "Universal encoding detector for Python 3" +category = "main" +optional = false +python-versions = ">=3.7" +files = [ + {file = "chardet-5.1.0-py3-none-any.whl", hash = "sha256:362777fb014af596ad31334fde1e8c327dfdb076e1960d1694662d46a6917ab9"}, + {file = "chardet-5.1.0.tar.gz", hash = "sha256:0d62712b956bc154f85fb0a266e2a3c5913c2967e00348701b32411d6def31e5"}, +] + +[[package]] +name = "charset-normalizer" +version = "3.2.0" +description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." +category = "main" +optional = false +python-versions = ">=3.7.0" +files = [ + {file = "charset-normalizer-3.2.0.tar.gz", hash = "sha256:3bb3d25a8e6c0aedd251753a79ae98a093c7e7b471faa3aa9a93a81431987ace"}, + {file = "charset_normalizer-3.2.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0b87549028f680ca955556e3bd57013ab47474c3124dc069faa0b6545b6c9710"}, + {file = "charset_normalizer-3.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7c70087bfee18a42b4040bb9ec1ca15a08242cf5867c58726530bdf3945672ed"}, + {file = "charset_normalizer-3.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a103b3a7069b62f5d4890ae1b8f0597618f628b286b03d4bc9195230b154bfa9"}, + {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:94aea8eff76ee6d1cdacb07dd2123a68283cb5569e0250feab1240058f53b623"}, + {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:db901e2ac34c931d73054d9797383d0f8009991e723dab15109740a63e7f902a"}, + {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b0dac0ff919ba34d4df1b6131f59ce95b08b9065233446be7e459f95554c0dc8"}, + {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:193cbc708ea3aca45e7221ae58f0fd63f933753a9bfb498a3b474878f12caaad"}, + {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:09393e1b2a9461950b1c9a45d5fd251dc7c6f228acab64da1c9c0165d9c7765c"}, + {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:baacc6aee0b2ef6f3d308e197b5d7a81c0e70b06beae1f1fcacffdbd124fe0e3"}, + {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:bf420121d4c8dce6b889f0e8e4ec0ca34b7f40186203f06a946fa0276ba54029"}, + {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:c04a46716adde8d927adb9457bbe39cf473e1e2c2f5d0a16ceb837e5d841ad4f"}, + {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:aaf63899c94de41fe3cf934601b0f7ccb6b428c6e4eeb80da72c58eab077b19a"}, + {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d62e51710986674142526ab9f78663ca2b0726066ae26b78b22e0f5e571238dd"}, + {file = "charset_normalizer-3.2.0-cp310-cp310-win32.whl", hash = "sha256:04e57ab9fbf9607b77f7d057974694b4f6b142da9ed4a199859d9d4d5c63fe96"}, + {file = "charset_normalizer-3.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:48021783bdf96e3d6de03a6e39a1171ed5bd7e8bb93fc84cc649d11490f87cea"}, + {file = "charset_normalizer-3.2.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:4957669ef390f0e6719db3613ab3a7631e68424604a7b448f079bee145da6e09"}, + {file = "charset_normalizer-3.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:46fb8c61d794b78ec7134a715a3e564aafc8f6b5e338417cb19fe9f57a5a9bf2"}, + {file = "charset_normalizer-3.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f779d3ad205f108d14e99bb3859aa7dd8e9c68874617c72354d7ecaec2a054ac"}, + {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f25c229a6ba38a35ae6e25ca1264621cc25d4d38dca2942a7fce0b67a4efe918"}, + {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2efb1bd13885392adfda4614c33d3b68dee4921fd0ac1d3988f8cbb7d589e72a"}, + {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f30b48dd7fa1474554b0b0f3fdfdd4c13b5c737a3c6284d3cdc424ec0ffff3a"}, + {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:246de67b99b6851627d945db38147d1b209a899311b1305dd84916f2b88526c6"}, + {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9bd9b3b31adcb054116447ea22caa61a285d92e94d710aa5ec97992ff5eb7cf3"}, + {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:8c2f5e83493748286002f9369f3e6607c565a6a90425a3a1fef5ae32a36d749d"}, + {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:3170c9399da12c9dc66366e9d14da8bf7147e1e9d9ea566067bbce7bb74bd9c2"}, + {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:7a4826ad2bd6b07ca615c74ab91f32f6c96d08f6fcc3902ceeedaec8cdc3bcd6"}, + {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:3b1613dd5aee995ec6d4c69f00378bbd07614702a315a2cf6c1d21461fe17c23"}, + {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9e608aafdb55eb9f255034709e20d5a83b6d60c054df0802fa9c9883d0a937aa"}, + {file = "charset_normalizer-3.2.0-cp311-cp311-win32.whl", hash = "sha256:f2a1d0fd4242bd8643ce6f98927cf9c04540af6efa92323e9d3124f57727bfc1"}, + {file = "charset_normalizer-3.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:681eb3d7e02e3c3655d1b16059fbfb605ac464c834a0c629048a30fad2b27489"}, + {file = "charset_normalizer-3.2.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c57921cda3a80d0f2b8aec7e25c8aa14479ea92b5b51b6876d975d925a2ea346"}, + {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:41b25eaa7d15909cf3ac4c96088c1f266a9a93ec44f87f1d13d4a0e86c81b982"}, + {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f058f6963fd82eb143c692cecdc89e075fa0828db2e5b291070485390b2f1c9c"}, + {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a7647ebdfb9682b7bb97e2a5e7cb6ae735b1c25008a70b906aecca294ee96cf4"}, + {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eef9df1eefada2c09a5e7a40991b9fc6ac6ef20b1372abd48d2794a316dc0449"}, + {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e03b8895a6990c9ab2cdcd0f2fe44088ca1c65ae592b8f795c3294af00a461c3"}, + {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:ee4006268ed33370957f55bf2e6f4d263eaf4dc3cfc473d1d90baff6ed36ce4a"}, + {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c4983bf937209c57240cff65906b18bb35e64ae872da6a0db937d7b4af845dd7"}, + {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:3bb7fda7260735efe66d5107fb7e6af6a7c04c7fce9b2514e04b7a74b06bf5dd"}, + {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:72814c01533f51d68702802d74f77ea026b5ec52793c791e2da806a3844a46c3"}, + {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:70c610f6cbe4b9fce272c407dd9d07e33e6bf7b4aa1b7ffb6f6ded8e634e3592"}, + {file = "charset_normalizer-3.2.0-cp37-cp37m-win32.whl", hash = "sha256:a401b4598e5d3f4a9a811f3daf42ee2291790c7f9d74b18d75d6e21dda98a1a1"}, + {file = "charset_normalizer-3.2.0-cp37-cp37m-win_amd64.whl", hash = "sha256:c0b21078a4b56965e2b12f247467b234734491897e99c1d51cee628da9786959"}, + {file = "charset_normalizer-3.2.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:95eb302ff792e12aba9a8b8f8474ab229a83c103d74a750ec0bd1c1eea32e669"}, + {file = "charset_normalizer-3.2.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1a100c6d595a7f316f1b6f01d20815d916e75ff98c27a01ae817439ea7726329"}, + {file = "charset_normalizer-3.2.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:6339d047dab2780cc6220f46306628e04d9750f02f983ddb37439ca47ced7149"}, + {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e4b749b9cc6ee664a3300bb3a273c1ca8068c46be705b6c31cf5d276f8628a94"}, + {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a38856a971c602f98472050165cea2cdc97709240373041b69030be15047691f"}, + {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f87f746ee241d30d6ed93969de31e5ffd09a2961a051e60ae6bddde9ec3583aa"}, + {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:89f1b185a01fe560bc8ae5f619e924407efca2191b56ce749ec84982fc59a32a"}, + {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e1c8a2f4c69e08e89632defbfabec2feb8a8d99edc9f89ce33c4b9e36ab63037"}, + {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2f4ac36d8e2b4cc1aa71df3dd84ff8efbe3bfb97ac41242fbcfc053c67434f46"}, + {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a386ebe437176aab38c041de1260cd3ea459c6ce5263594399880bbc398225b2"}, + {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:ccd16eb18a849fd8dcb23e23380e2f0a354e8daa0c984b8a732d9cfaba3a776d"}, + {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:e6a5bf2cba5ae1bb80b154ed68a3cfa2fa00fde979a7f50d6598d3e17d9ac20c"}, + {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:45de3f87179c1823e6d9e32156fb14c1927fcc9aba21433f088fdfb555b77c10"}, + {file = "charset_normalizer-3.2.0-cp38-cp38-win32.whl", hash = "sha256:1000fba1057b92a65daec275aec30586c3de2401ccdcd41f8a5c1e2c87078706"}, + {file = "charset_normalizer-3.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:8b2c760cfc7042b27ebdb4a43a4453bd829a5742503599144d54a032c5dc7e9e"}, + {file = "charset_normalizer-3.2.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:855eafa5d5a2034b4621c74925d89c5efef61418570e5ef9b37717d9c796419c"}, + {file = "charset_normalizer-3.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:203f0c8871d5a7987be20c72442488a0b8cfd0f43b7973771640fc593f56321f"}, + {file = "charset_normalizer-3.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e857a2232ba53ae940d3456f7533ce6ca98b81917d47adc3c7fd55dad8fab858"}, + {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5e86d77b090dbddbe78867a0275cb4df08ea195e660f1f7f13435a4649e954e5"}, + {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c4fb39a81950ec280984b3a44f5bd12819953dc5fa3a7e6fa7a80db5ee853952"}, + {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2dee8e57f052ef5353cf608e0b4c871aee320dd1b87d351c28764fc0ca55f9f4"}, + {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8700f06d0ce6f128de3ccdbc1acaea1ee264d2caa9ca05daaf492fde7c2a7200"}, + {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1920d4ff15ce893210c1f0c0e9d19bfbecb7983c76b33f046c13a8ffbd570252"}, + {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:c1c76a1743432b4b60ab3358c937a3fe1341c828ae6194108a94c69028247f22"}, + {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f7560358a6811e52e9c4d142d497f1a6e10103d3a6881f18d04dbce3729c0e2c"}, + {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:c8063cf17b19661471ecbdb3df1c84f24ad2e389e326ccaf89e3fb2484d8dd7e"}, + {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:cd6dbe0238f7743d0efe563ab46294f54f9bc8f4b9bcf57c3c666cc5bc9d1299"}, + {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:1249cbbf3d3b04902ff081ffbb33ce3377fa6e4c7356f759f3cd076cc138d020"}, + {file = "charset_normalizer-3.2.0-cp39-cp39-win32.whl", hash = "sha256:6c409c0deba34f147f77efaa67b8e4bb83d2f11c8806405f76397ae5b8c0d1c9"}, + {file = "charset_normalizer-3.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:7095f6fbfaa55defb6b733cfeb14efaae7a29f0b59d8cf213be4e7ca0b857b80"}, + {file = "charset_normalizer-3.2.0-py3-none-any.whl", hash = "sha256:8e098148dd37b4ce3baca71fb394c81dc5d9c7728c95df695d2dca218edf40e6"}, +] + +[[package]] +name = "click" +version = "8.1.5" +description = "Composable command line interface toolkit" +category = "main" +optional = false +python-versions = ">=3.7" +files = [ + {file = "click-8.1.5-py3-none-any.whl", hash = "sha256:e576aa487d679441d7d30abb87e1b43d24fc53bffb8758443b1a9e1cee504548"}, + {file = "click-8.1.5.tar.gz", hash = "sha256:4be4b1af8d665c6d942909916d31a213a106800c47d0eeba73d34da3cbc11367"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} + +[[package]] +name = "colorama" +version = "0.4.6" +description = "Cross-platform colored terminal text." +category = "main" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +files = [ + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, +] + +[[package]] +name = "contourpy" +version = "1.1.0" +description = "Python library for calculating contours of 2D quadrilateral grids" +category = "dev" +optional = false +python-versions = ">=3.8" +files = [ + {file = "contourpy-1.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:89f06eff3ce2f4b3eb24c1055a26981bffe4e7264acd86f15b97e40530b794bc"}, + {file = "contourpy-1.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:dffcc2ddec1782dd2f2ce1ef16f070861af4fb78c69862ce0aab801495dda6a3"}, + {file = "contourpy-1.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25ae46595e22f93592d39a7eac3d638cda552c3e1160255258b695f7b58e5655"}, + {file = "contourpy-1.1.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:17cfaf5ec9862bc93af1ec1f302457371c34e688fbd381f4035a06cd47324f48"}, + {file = "contourpy-1.1.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:18a64814ae7bce73925131381603fff0116e2df25230dfc80d6d690aa6e20b37"}, + {file = "contourpy-1.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90c81f22b4f572f8a2110b0b741bb64e5a6427e0a198b2cdc1fbaf85f352a3aa"}, + {file = "contourpy-1.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:53cc3a40635abedbec7f1bde60f8c189c49e84ac180c665f2cd7c162cc454baa"}, + {file = "contourpy-1.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:1f795597073b09d631782e7245016a4323cf1cf0b4e06eef7ea6627e06a37ff2"}, + {file = "contourpy-1.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0b7b04ed0961647691cfe5d82115dd072af7ce8846d31a5fac6c142dcce8b882"}, + {file = "contourpy-1.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:27bc79200c742f9746d7dd51a734ee326a292d77e7d94c8af6e08d1e6c15d545"}, + {file = "contourpy-1.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:052cc634bf903c604ef1a00a5aa093c54f81a2612faedaa43295809ffdde885e"}, + {file = "contourpy-1.1.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9382a1c0bc46230fb881c36229bfa23d8c303b889b788b939365578d762b5c18"}, + {file = "contourpy-1.1.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e5cec36c5090e75a9ac9dbd0ff4a8cf7cecd60f1b6dc23a374c7d980a1cd710e"}, + {file = "contourpy-1.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f0cbd657e9bde94cd0e33aa7df94fb73c1ab7799378d3b3f902eb8eb2e04a3a"}, + {file = "contourpy-1.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:181cbace49874f4358e2929aaf7ba84006acb76694102e88dd15af861996c16e"}, + {file = "contourpy-1.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:fb3b7d9e6243bfa1efb93ccfe64ec610d85cfe5aec2c25f97fbbd2e58b531256"}, + {file = "contourpy-1.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bcb41692aa09aeb19c7c213411854402f29f6613845ad2453d30bf421fe68fed"}, + {file = "contourpy-1.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:5d123a5bc63cd34c27ff9c7ac1cd978909e9c71da12e05be0231c608048bb2ae"}, + {file = "contourpy-1.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:62013a2cf68abc80dadfd2307299bfa8f5aa0dcaec5b2954caeb5fa094171103"}, + {file = "contourpy-1.1.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0b6616375d7de55797d7a66ee7d087efe27f03d336c27cf1f32c02b8c1a5ac70"}, + {file = "contourpy-1.1.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:317267d915490d1e84577924bd61ba71bf8681a30e0d6c545f577363157e5e94"}, + {file = "contourpy-1.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d551f3a442655f3dcc1285723f9acd646ca5858834efeab4598d706206b09c9f"}, + {file = "contourpy-1.1.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:e7a117ce7df5a938fe035cad481b0189049e8d92433b4b33aa7fc609344aafa1"}, + {file = "contourpy-1.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:d4f26b25b4f86087e7d75e63212756c38546e70f2a92d2be44f80114826e1cd4"}, + {file = "contourpy-1.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:bc00bb4225d57bff7ebb634646c0ee2a1298402ec10a5fe7af79df9a51c1bfd9"}, + {file = "contourpy-1.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:189ceb1525eb0655ab8487a9a9c41f42a73ba52d6789754788d1883fb06b2d8a"}, + {file = "contourpy-1.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9f2931ed4741f98f74b410b16e5213f71dcccee67518970c42f64153ea9313b9"}, + {file = "contourpy-1.1.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:30f511c05fab7f12e0b1b7730ebdc2ec8deedcfb505bc27eb570ff47c51a8f15"}, + {file = "contourpy-1.1.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:143dde50520a9f90e4a2703f367cf8ec96a73042b72e68fcd184e1279962eb6f"}, + {file = "contourpy-1.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e94bef2580e25b5fdb183bf98a2faa2adc5b638736b2c0a4da98691da641316a"}, + {file = "contourpy-1.1.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ed614aea8462735e7d70141374bd7650afd1c3f3cb0c2dbbcbe44e14331bf002"}, + {file = "contourpy-1.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:438ba416d02f82b692e371858143970ed2eb6337d9cdbbede0d8ad9f3d7dd17d"}, + {file = "contourpy-1.1.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a698c6a7a432789e587168573a864a7ea374c6be8d4f31f9d87c001d5a843493"}, + {file = "contourpy-1.1.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:397b0ac8a12880412da3551a8cb5a187d3298a72802b45a3bd1805e204ad8439"}, + {file = "contourpy-1.1.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:a67259c2b493b00e5a4d0f7bfae51fb4b3371395e47d079a4446e9b0f4d70e76"}, + {file = "contourpy-1.1.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:2b836d22bd2c7bb2700348e4521b25e077255ebb6ab68e351ab5aa91ca27e027"}, + {file = "contourpy-1.1.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:084eaa568400cfaf7179b847ac871582199b1b44d5699198e9602ecbbb5f6104"}, + {file = "contourpy-1.1.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:911ff4fd53e26b019f898f32db0d4956c9d227d51338fb3b03ec72ff0084ee5f"}, + {file = "contourpy-1.1.0.tar.gz", hash = "sha256:e53046c3863828d21d531cc3b53786e6580eb1ba02477e8681009b6aa0870b21"}, +] + +[package.dependencies] +numpy = ">=1.16" + +[package.extras] +bokeh = ["bokeh", "selenium"] +docs = ["furo", "sphinx-copybutton"] +mypy = ["contourpy[bokeh,docs]", "docutils-stubs", "mypy (==1.2.0)", "types-Pillow"] +test = ["Pillow", "contourpy[test-no-images]", "matplotlib"] +test-no-images = ["pytest", "pytest-cov", "wurlitzer"] + +[[package]] +name = "coverage" +version = "7.2.7" +description = "Code coverage measurement for Python" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "coverage-7.2.7-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d39b5b4f2a66ccae8b7263ac3c8170994b65266797fb96cbbfd3fb5b23921db8"}, + {file = "coverage-7.2.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6d040ef7c9859bb11dfeb056ff5b3872436e3b5e401817d87a31e1750b9ae2fb"}, + {file = "coverage-7.2.7-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ba90a9563ba44a72fda2e85302c3abc71c5589cea608ca16c22b9804262aaeb6"}, + {file = "coverage-7.2.7-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e7d9405291c6928619403db1d10bd07888888ec1abcbd9748fdaa971d7d661b2"}, + {file = "coverage-7.2.7-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:31563e97dae5598556600466ad9beea39fb04e0229e61c12eaa206e0aa202063"}, + {file = "coverage-7.2.7-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:ebba1cd308ef115925421d3e6a586e655ca5a77b5bf41e02eb0e4562a111f2d1"}, + {file = "coverage-7.2.7-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:cb017fd1b2603ef59e374ba2063f593abe0fc45f2ad9abdde5b4d83bd922a353"}, + {file = "coverage-7.2.7-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d62a5c7dad11015c66fbb9d881bc4caa5b12f16292f857842d9d1871595f4495"}, + {file = "coverage-7.2.7-cp310-cp310-win32.whl", hash = "sha256:ee57190f24fba796e36bb6d3aa8a8783c643d8fa9760c89f7a98ab5455fbf818"}, + {file = "coverage-7.2.7-cp310-cp310-win_amd64.whl", hash = "sha256:f75f7168ab25dd93110c8a8117a22450c19976afbc44234cbf71481094c1b850"}, + {file = "coverage-7.2.7-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:06a9a2be0b5b576c3f18f1a241f0473575c4a26021b52b2a85263a00f034d51f"}, + {file = "coverage-7.2.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5baa06420f837184130752b7c5ea0808762083bf3487b5038d68b012e5937dbe"}, + {file = "coverage-7.2.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fdec9e8cbf13a5bf63290fc6013d216a4c7232efb51548594ca3631a7f13c3a3"}, + {file = "coverage-7.2.7-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:52edc1a60c0d34afa421c9c37078817b2e67a392cab17d97283b64c5833f427f"}, + {file = "coverage-7.2.7-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:63426706118b7f5cf6bb6c895dc215d8a418d5952544042c8a2d9fe87fcf09cb"}, + {file = "coverage-7.2.7-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:afb17f84d56068a7c29f5fa37bfd38d5aba69e3304af08ee94da8ed5b0865833"}, + {file = "coverage-7.2.7-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:48c19d2159d433ccc99e729ceae7d5293fbffa0bdb94952d3579983d1c8c9d97"}, + {file = "coverage-7.2.7-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:0e1f928eaf5469c11e886fe0885ad2bf1ec606434e79842a879277895a50942a"}, + {file = "coverage-7.2.7-cp311-cp311-win32.whl", hash = "sha256:33d6d3ea29d5b3a1a632b3c4e4f4ecae24ef170b0b9ee493883f2df10039959a"}, + {file = "coverage-7.2.7-cp311-cp311-win_amd64.whl", hash = "sha256:5b7540161790b2f28143191f5f8ec02fb132660ff175b7747b95dcb77ac26562"}, + {file = "coverage-7.2.7-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f2f67fe12b22cd130d34d0ef79206061bfb5eda52feb6ce0dba0644e20a03cf4"}, + {file = "coverage-7.2.7-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a342242fe22407f3c17f4b499276a02b01e80f861f1682ad1d95b04018e0c0d4"}, + {file = "coverage-7.2.7-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:171717c7cb6b453aebac9a2ef603699da237f341b38eebfee9be75d27dc38e01"}, + {file = "coverage-7.2.7-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:49969a9f7ffa086d973d91cec8d2e31080436ef0fb4a359cae927e742abfaaa6"}, + {file = "coverage-7.2.7-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b46517c02ccd08092f4fa99f24c3b83d8f92f739b4657b0f146246a0ca6a831d"}, + {file = "coverage-7.2.7-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:a3d33a6b3eae87ceaefa91ffdc130b5e8536182cd6dfdbfc1aa56b46ff8c86de"}, + {file = "coverage-7.2.7-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:976b9c42fb2a43ebf304fa7d4a310e5f16cc99992f33eced91ef6f908bd8f33d"}, + {file = "coverage-7.2.7-cp312-cp312-win32.whl", hash = "sha256:8de8bb0e5ad103888d65abef8bca41ab93721647590a3f740100cd65c3b00511"}, + {file = "coverage-7.2.7-cp312-cp312-win_amd64.whl", hash = "sha256:9e31cb64d7de6b6f09702bb27c02d1904b3aebfca610c12772452c4e6c21a0d3"}, + {file = "coverage-7.2.7-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:58c2ccc2f00ecb51253cbe5d8d7122a34590fac9646a960d1430d5b15321d95f"}, + {file = "coverage-7.2.7-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d22656368f0e6189e24722214ed8d66b8022db19d182927b9a248a2a8a2f67eb"}, + {file = "coverage-7.2.7-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a895fcc7b15c3fc72beb43cdcbdf0ddb7d2ebc959edac9cef390b0d14f39f8a9"}, + {file = "coverage-7.2.7-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e84606b74eb7de6ff581a7915e2dab7a28a0517fbe1c9239eb227e1354064dcd"}, + {file = "coverage-7.2.7-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:0a5f9e1dbd7fbe30196578ca36f3fba75376fb99888c395c5880b355e2875f8a"}, + {file = "coverage-7.2.7-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:419bfd2caae268623dd469eff96d510a920c90928b60f2073d79f8fe2bbc5959"}, + {file = "coverage-7.2.7-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:2aee274c46590717f38ae5e4650988d1af340fe06167546cc32fe2f58ed05b02"}, + {file = "coverage-7.2.7-cp37-cp37m-win32.whl", hash = "sha256:61b9a528fb348373c433e8966535074b802c7a5d7f23c4f421e6c6e2f1697a6f"}, + {file = "coverage-7.2.7-cp37-cp37m-win_amd64.whl", hash = "sha256:b1c546aca0ca4d028901d825015dc8e4d56aac4b541877690eb76490f1dc8ed0"}, + {file = "coverage-7.2.7-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:54b896376ab563bd38453cecb813c295cf347cf5906e8b41d340b0321a5433e5"}, + {file = "coverage-7.2.7-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:3d376df58cc111dc8e21e3b6e24606b5bb5dee6024f46a5abca99124b2229ef5"}, + {file = "coverage-7.2.7-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5e330fc79bd7207e46c7d7fd2bb4af2963f5f635703925543a70b99574b0fea9"}, + {file = "coverage-7.2.7-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e9d683426464e4a252bf70c3498756055016f99ddaec3774bf368e76bbe02b6"}, + {file = "coverage-7.2.7-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d13c64ee2d33eccf7437961b6ea7ad8673e2be040b4f7fd4fd4d4d28d9ccb1e"}, + {file = "coverage-7.2.7-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b7aa5f8a41217360e600da646004f878250a0d6738bcdc11a0a39928d7dc2050"}, + {file = "coverage-7.2.7-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:8fa03bce9bfbeeef9f3b160a8bed39a221d82308b4152b27d82d8daa7041fee5"}, + {file = "coverage-7.2.7-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:245167dd26180ab4c91d5e1496a30be4cd721a5cf2abf52974f965f10f11419f"}, + {file = "coverage-7.2.7-cp38-cp38-win32.whl", hash = "sha256:d2c2db7fd82e9b72937969bceac4d6ca89660db0a0967614ce2481e81a0b771e"}, + {file = "coverage-7.2.7-cp38-cp38-win_amd64.whl", hash = "sha256:2e07b54284e381531c87f785f613b833569c14ecacdcb85d56b25c4622c16c3c"}, + {file = "coverage-7.2.7-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:537891ae8ce59ef63d0123f7ac9e2ae0fc8b72c7ccbe5296fec45fd68967b6c9"}, + {file = "coverage-7.2.7-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:06fb182e69f33f6cd1d39a6c597294cff3143554b64b9825d1dc69d18cc2fff2"}, + {file = "coverage-7.2.7-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:201e7389591af40950a6480bd9edfa8ed04346ff80002cec1a66cac4549c1ad7"}, + {file = "coverage-7.2.7-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f6951407391b639504e3b3be51b7ba5f3528adbf1a8ac3302b687ecababf929e"}, + {file = "coverage-7.2.7-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f48351d66575f535669306aa7d6d6f71bc43372473b54a832222803eb956fd1"}, + {file = "coverage-7.2.7-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b29019c76039dc3c0fd815c41392a044ce555d9bcdd38b0fb60fb4cd8e475ba9"}, + {file = "coverage-7.2.7-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:81c13a1fc7468c40f13420732805a4c38a105d89848b7c10af65a90beff25250"}, + {file = "coverage-7.2.7-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:975d70ab7e3c80a3fe86001d8751f6778905ec723f5b110aed1e450da9d4b7f2"}, + {file = "coverage-7.2.7-cp39-cp39-win32.whl", hash = "sha256:7ee7d9d4822c8acc74a5e26c50604dff824710bc8de424904c0982e25c39c6cb"}, + {file = "coverage-7.2.7-cp39-cp39-win_amd64.whl", hash = "sha256:eb393e5ebc85245347950143969b241d08b52b88a3dc39479822e073a1a8eb27"}, + {file = "coverage-7.2.7-pp37.pp38.pp39-none-any.whl", hash = "sha256:b7b4c971f05e6ae490fef852c218b0e79d4e52f79ef0c8475566584a8fb3e01d"}, + {file = "coverage-7.2.7.tar.gz", hash = "sha256:924d94291ca674905fe9481f12294eb11f2d3d3fd1adb20314ba89e94f44ed59"}, +] + +[package.dependencies] +tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.11.0a6\" and extra == \"toml\""} + +[package.extras] +toml = ["tomli"] + +[[package]] +name = "cryptography" +version = "41.0.2" +description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." +category = "main" +optional = false +python-versions = ">=3.7" +files = [ + {file = "cryptography-41.0.2-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:01f1d9e537f9a15b037d5d9ee442b8c22e3ae11ce65ea1f3316a41c78756b711"}, + {file = "cryptography-41.0.2-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:079347de771f9282fbfe0e0236c716686950c19dee1b76240ab09ce1624d76d7"}, + {file = "cryptography-41.0.2-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:439c3cc4c0d42fa999b83ded80a9a1fb54d53c58d6e59234cfe97f241e6c781d"}, + {file = "cryptography-41.0.2-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f14ad275364c8b4e525d018f6716537ae7b6d369c094805cae45300847e0894f"}, + {file = "cryptography-41.0.2-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:84609ade00a6ec59a89729e87a503c6e36af98ddcd566d5f3be52e29ba993182"}, + {file = "cryptography-41.0.2-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:49c3222bb8f8e800aead2e376cbef687bc9e3cb9b58b29a261210456a7783d83"}, + {file = "cryptography-41.0.2-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:d73f419a56d74fef257955f51b18d046f3506270a5fd2ac5febbfa259d6c0fa5"}, + {file = "cryptography-41.0.2-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:2a034bf7d9ca894720f2ec1d8b7b5832d7e363571828037f9e0c4f18c1b58a58"}, + {file = "cryptography-41.0.2-cp37-abi3-win32.whl", hash = "sha256:d124682c7a23c9764e54ca9ab5b308b14b18eba02722b8659fb238546de83a76"}, + {file = "cryptography-41.0.2-cp37-abi3-win_amd64.whl", hash = "sha256:9c3fe6534d59d071ee82081ca3d71eed3210f76ebd0361798c74abc2bcf347d4"}, + {file = "cryptography-41.0.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:a719399b99377b218dac6cf547b6ec54e6ef20207b6165126a280b0ce97e0d2a"}, + {file = "cryptography-41.0.2-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:182be4171f9332b6741ee818ec27daff9fb00349f706629f5cbf417bd50e66fd"}, + {file = "cryptography-41.0.2-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:7a9a3bced53b7f09da251685224d6a260c3cb291768f54954e28f03ef14e3766"}, + {file = "cryptography-41.0.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:f0dc40e6f7aa37af01aba07277d3d64d5a03dc66d682097541ec4da03cc140ee"}, + {file = "cryptography-41.0.2-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:674b669d5daa64206c38e507808aae49904c988fa0a71c935e7006a3e1e83831"}, + {file = "cryptography-41.0.2-pp38-pypy38_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:7af244b012711a26196450d34f483357e42aeddb04128885d95a69bd8b14b69b"}, + {file = "cryptography-41.0.2-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:9b6d717393dbae53d4e52684ef4f022444fc1cce3c48c38cb74fca29e1f08eaa"}, + {file = "cryptography-41.0.2-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:192255f539d7a89f2102d07d7375b1e0a81f7478925b3bc2e0549ebf739dae0e"}, + {file = "cryptography-41.0.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:f772610fe364372de33d76edcd313636a25684edb94cee53fd790195f5989d14"}, + {file = "cryptography-41.0.2-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:b332cba64d99a70c1e0836902720887fb4529ea49ea7f5462cf6640e095e11d2"}, + {file = "cryptography-41.0.2-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:9a6673c1828db6270b76b22cc696f40cde9043eb90373da5c2f8f2158957f42f"}, + {file = "cryptography-41.0.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:342f3767e25876751e14f8459ad85e77e660537ca0a066e10e75df9c9e9099f0"}, + {file = "cryptography-41.0.2.tar.gz", hash = "sha256:7d230bf856164de164ecb615ccc14c7fc6de6906ddd5b491f3af90d3514c925c"}, +] + +[package.dependencies] +cffi = ">=1.12" + +[package.extras] +docs = ["sphinx (>=5.3.0)", "sphinx-rtd-theme (>=1.1.1)"] +docstest = ["pyenchant (>=1.6.11)", "sphinxcontrib-spelling (>=4.0.1)", "twine (>=1.12.0)"] +nox = ["nox"] +pep8test = ["black", "check-sdist", "mypy", "ruff"] +sdist = ["build"] +ssh = ["bcrypt (>=3.1.5)"] +test = ["pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"] +test-randomorder = ["pytest-randomly"] + +[[package]] +name = "cycler" +version = "0.11.0" +description = "Composable style cycles" +category = "dev" +optional = false +python-versions = ">=3.6" +files = [ + {file = "cycler-0.11.0-py3-none-any.whl", hash = "sha256:3a27e95f763a428a739d2add979fa7494c912a32c17c4c38c4d5f082cad165a3"}, + {file = "cycler-0.11.0.tar.gz", hash = "sha256:9c87405839a19696e837b3b818fed3f5f69f16f1eec1a1ad77e043dcea9c772f"}, +] + +[[package]] +name = "distlib" +version = "0.3.6" +description = "Distribution utilities" +category = "dev" +optional = false +python-versions = "*" +files = [ + {file = "distlib-0.3.6-py2.py3-none-any.whl", hash = "sha256:f35c4b692542ca110de7ef0bea44d73981caeb34ca0b9b6b2e6d7790dda8f80e"}, + {file = "distlib-0.3.6.tar.gz", hash = "sha256:14bad2d9b04d3a36127ac97f30b12a19268f211063d8f8ee4f47108896e11b46"}, +] + +[[package]] +name = "docutils" +version = "0.20.1" +description = "Docutils -- Python Documentation Utilities" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "docutils-0.20.1-py3-none-any.whl", hash = "sha256:96f387a2c5562db4476f09f13bbab2192e764cac08ebbf3a34a95d9b1e4a59d6"}, + {file = "docutils-0.20.1.tar.gz", hash = "sha256:f08a4e276c3a1583a86dce3e34aba3fe04d02bba2dd51ed16106244e8a923e3b"}, +] + +[[package]] +name = "dparse" +version = "0.6.3" +description = "A parser for Python dependency files" +category = "dev" +optional = false +python-versions = ">=3.6" +files = [ + {file = "dparse-0.6.3-py3-none-any.whl", hash = "sha256:0d8fe18714056ca632d98b24fbfc4e9791d4e47065285ab486182288813a5318"}, + {file = "dparse-0.6.3.tar.gz", hash = "sha256:27bb8b4bcaefec3997697ba3f6e06b2447200ba273c0b085c3d012a04571b528"}, +] + +[package.dependencies] +packaging = "*" +tomli = {version = "*", markers = "python_version < \"3.11\""} + +[package.extras] +conda = ["pyyaml"] +pipenv = ["pipenv (<=2022.12.19)"] + +[[package]] +name = "et-xmlfile" +version = "1.1.0" +description = "An implementation of lxml.xmlfile for the standard library" +category = "main" +optional = false +python-versions = ">=3.6" +files = [ + {file = "et_xmlfile-1.1.0-py3-none-any.whl", hash = "sha256:a2ba85d1d6a74ef63837eed693bcb89c3f752169b0e3e7ae5b16ca5e1b3deada"}, + {file = "et_xmlfile-1.1.0.tar.gz", hash = "sha256:8eb9e2bc2f8c97e37a2dc85a09ecdcdec9d8a396530a6d5a33b30b9a92da0c5c"}, +] + +[[package]] +name = "exceptiongroup" +version = "1.1.2" +description = "Backport of PEP 654 (exception groups)" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "exceptiongroup-1.1.2-py3-none-any.whl", hash = "sha256:e346e69d186172ca7cf029c8c1d16235aa0e04035e5750b4b95039e65204328f"}, + {file = "exceptiongroup-1.1.2.tar.gz", hash = "sha256:12c3e887d6485d16943a309616de20ae5582633e0a2eda17f4e10fd61c1e8af5"}, +] + +[package.extras] +test = ["pytest (>=6)"] + +[[package]] +name = "filelock" +version = "3.12.2" +description = "A platform independent file lock." +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "filelock-3.12.2-py3-none-any.whl", hash = "sha256:cbb791cdea2a72f23da6ac5b5269ab0a0d161e9ef0100e653b69049a7706d1ec"}, + {file = "filelock-3.12.2.tar.gz", hash = "sha256:002740518d8aa59a26b0c76e10fb8c6e15eae825d34b6fdf670333fd7b938d81"}, +] + +[package.extras] +docs = ["furo (>=2023.5.20)", "sphinx (>=7.0.1)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)"] +testing = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "diff-cover (>=7.5)", "pytest (>=7.3.1)", "pytest-cov (>=4.1)", "pytest-mock (>=3.10)", "pytest-timeout (>=2.1)"] + +[[package]] +name = "flake8" +version = "5.0.4" +description = "the modular source code checker: pep8 pyflakes and co" +category = "dev" +optional = false +python-versions = ">=3.6.1" +files = [ + {file = "flake8-5.0.4-py2.py3-none-any.whl", hash = "sha256:7a1cf6b73744f5806ab95e526f6f0d8c01c66d7bbe349562d22dfca20610b248"}, + {file = "flake8-5.0.4.tar.gz", hash = "sha256:6fbe320aad8d6b95cec8b8e47bc933004678dc63095be98528b7bdd2a9f510db"}, +] + +[package.dependencies] +mccabe = ">=0.7.0,<0.8.0" +pycodestyle = ">=2.9.0,<2.10.0" +pyflakes = ">=2.5.0,<2.6.0" + +[[package]] +name = "flake8-bandit" +version = "4.1.1" +description = "Automated security testing with bandit and flake8." +category = "dev" +optional = false +python-versions = ">=3.6" +files = [ + {file = "flake8_bandit-4.1.1-py3-none-any.whl", hash = "sha256:4c8a53eb48f23d4ef1e59293657181a3c989d0077c9952717e98a0eace43e06d"}, + {file = "flake8_bandit-4.1.1.tar.gz", hash = "sha256:068e09287189cbfd7f986e92605adea2067630b75380c6b5733dab7d87f9a84e"}, +] + +[package.dependencies] +bandit = ">=1.7.3" +flake8 = ">=5.0.0" + +[[package]] +name = "flake8-bugbear" +version = "23.3.12" +description = "A plugin for flake8 finding likely bugs and design problems in your program. Contains warnings that don't belong in pyflakes and pycodestyle." +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "flake8-bugbear-23.3.12.tar.gz", hash = "sha256:e3e7f74c8a49ad3794a7183353026dabd68c74030d5f46571f84c1fb0eb79363"}, + {file = "flake8_bugbear-23.3.12-py3-none-any.whl", hash = "sha256:beb5c7efcd7ccc2039ef66a77bb8db925e7be3531ff1cb4d0b7030d0e2113d72"}, +] + +[package.dependencies] +attrs = ">=19.2.0" +flake8 = ">=3.0.0" + +[package.extras] +dev = ["coverage", "hypothesis", "hypothesmith (>=0.2)", "pre-commit", "pytest", "tox"] + +[[package]] +name = "flake8-rst-docstrings" +version = "0.3.0" +description = "Python docstring reStructuredText (RST) validator for flake8" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "flake8-rst-docstrings-0.3.0.tar.gz", hash = "sha256:d1ce22b4bd37b73cd86b8d980e946ef198cfcc18ed82fedb674ceaa2f8d1afa4"}, + {file = "flake8_rst_docstrings-0.3.0-py3-none-any.whl", hash = "sha256:f8c3c6892ff402292651c31983a38da082480ad3ba253743de52989bdc84ca1c"}, +] + +[package.dependencies] +flake8 = ">=3" +pygments = "*" +restructuredtext-lint = "*" + +[package.extras] +develop = ["build", "twine"] + +[[package]] +name = "fonttools" +version = "4.41.0" +description = "Tools to manipulate font files" +category = "dev" +optional = false +python-versions = ">=3.8" +files = [ + {file = "fonttools-4.41.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ba2a367ff478cd108d5319c0dc4fd4eb4ea3476dbfc45b00c45718e889cd9463"}, + {file = "fonttools-4.41.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:69178674505ec81adf4af2a3bbacd0cb9a37ba7831bc3fca307f80e48ab2767b"}, + {file = "fonttools-4.41.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:86edb95c4d1fe4fae2111d7e0c10c6e42b7790b377bcf1952303469eee5b52bb"}, + {file = "fonttools-4.41.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:50f8bdb421270f71b54695c62785e300fab4bb6127be40bf9f3084962a0c3adb"}, + {file = "fonttools-4.41.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:c890061915e95b619c1d3cc3c107c6fb021406b701c0c24b03e74830d522f210"}, + {file = "fonttools-4.41.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b329ae7ce971b5c4148d6cdb8119c0ce4587265b2330d4f2f3776ef851bee020"}, + {file = "fonttools-4.41.0-cp310-cp310-win32.whl", hash = "sha256:bc9e7b1e268be7a23fc66471b615c324e99c5db39ce8c49dd6dd8e962c7bc1b8"}, + {file = "fonttools-4.41.0-cp310-cp310-win_amd64.whl", hash = "sha256:f3fe90dfb297bd8265238c06787911cd81c2cb89ac5b13e1c911928bdabfce0f"}, + {file = "fonttools-4.41.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e38bd91eae257f36c2b7245c0278e9cd9d754f3a66b8d2b548c623ba66e387b6"}, + {file = "fonttools-4.41.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:415cf7c806a3f56fb280dadcf3c92c85c0415e75665ca957b4a2a2e39c17a5c9"}, + {file = "fonttools-4.41.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:381558eafffc1432d08ca58063e71c7376ecaae48e9318354a90a1049a644845"}, + {file = "fonttools-4.41.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ee75b8ca48f6c48af25e967dce995ef94e46872b35c7d454b983c62c9c7006d"}, + {file = "fonttools-4.41.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d45f28c20bb67dee0f4a4caae709f40b0693d764b7b2bf2d58890f36b1bfcef0"}, + {file = "fonttools-4.41.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5448a87f6ed57ed844b64a05d3792827af584a8584613f6289867f4e77eb603b"}, + {file = "fonttools-4.41.0-cp311-cp311-win32.whl", hash = "sha256:69dbe0154e15b68dd671441ea8f23dad87488b24a6e650d45958f4722819a443"}, + {file = "fonttools-4.41.0-cp311-cp311-win_amd64.whl", hash = "sha256:ea879afd1d6189fca02a85a7868560c9bb8415dccff6b7ae6d81e4f06b3ab30d"}, + {file = "fonttools-4.41.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:8f602dd5bcde7e4241419924f23c6f0d66723dd5408a58c3a2f781745c693f45"}, + {file = "fonttools-4.41.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:06eac087ea55b3ebb2207d93b5ac56c847163899f05f5a77e1910f688fe10030"}, + {file = "fonttools-4.41.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7e22d0144d735f6c7df770509b8c0c33414bf460df0d5dddc98a159e5dbb10eb"}, + {file = "fonttools-4.41.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:19d461c801b8904d201c6c38a99bfcfef673bfdfe0c7f026f582ef78896434e0"}, + {file = "fonttools-4.41.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:72d40a32d6443871ea0d147813caad58394b48729dfa4fbc45dcaac54f9506f2"}, + {file = "fonttools-4.41.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:0614b6348866092d00df3dfb37e037fc06412ca67087de361a2777ea5ed62c16"}, + {file = "fonttools-4.41.0-cp38-cp38-win32.whl", hash = "sha256:e43f6c7f9ba4f9d29edee530e45f9aa162872ec9549398b85971477a99f2a806"}, + {file = "fonttools-4.41.0-cp38-cp38-win_amd64.whl", hash = "sha256:eb9dfa87152bd97019adc387b2f29ef6af601de4386f36570ca537ace96d96ed"}, + {file = "fonttools-4.41.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:d2dae84a3d0f76884a6102c62f2795b2d6602c2c95cfcce74c8a590b6200e533"}, + {file = "fonttools-4.41.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:cc3324e4159e6d1f55c3615b4c1c211f87cc96cc0cc7c946c8447dc1319f2e9d"}, + {file = "fonttools-4.41.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4c654b1facf1f3b742e4d9b2dcdf0fa867b1f007b1b4981cc58a75ef5dca2a3c"}, + {file = "fonttools-4.41.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:560ea1a604c927399f36742abf342a4c5f3fee8e8e8a484b774dfe9630bd9a91"}, + {file = "fonttools-4.41.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9387b09694fbf8ac7dcf887069068f81fb4124d05e09557ac7daabfbec1744bd"}, + {file = "fonttools-4.41.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:465d0f24bf4f75160f441793b55076b7a080a57d3a1f738390af2c20bee24fbb"}, + {file = "fonttools-4.41.0-cp39-cp39-win32.whl", hash = "sha256:841c491fa3e9c54e8f9cd5dae059e88f45e086aea090c28be9d42f59c8b99e01"}, + {file = "fonttools-4.41.0-cp39-cp39-win_amd64.whl", hash = "sha256:efd59e83223cb77952997fb850c7a7c2a958c9af0642060f536722c2a9e9d53b"}, + {file = "fonttools-4.41.0-py3-none-any.whl", hash = "sha256:5b1c2b21b40229166a864f2b0aec06d37f0a204066deb1734c93370e0c76339d"}, + {file = "fonttools-4.41.0.tar.gz", hash = "sha256:6faff25991dec48f8cac882055a09ae1a29fd15bc160bc3d663e789e994664c2"}, +] + +[package.extras] +all = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "fs (>=2.2.0,<3)", "lxml (>=4.0,<5)", "lz4 (>=1.7.4.2)", "matplotlib", "munkres", "scipy", "skia-pathops (>=0.5.0)", "sympy", "uharfbuzz (>=0.23.0)", "unicodedata2 (>=15.0.0)", "xattr", "zopfli (>=0.1.4)"] +graphite = ["lz4 (>=1.7.4.2)"] +interpolatable = ["munkres", "scipy"] +lxml = ["lxml (>=4.0,<5)"] +pathops = ["skia-pathops (>=0.5.0)"] +plot = ["matplotlib"] +repacker = ["uharfbuzz (>=0.23.0)"] +symfont = ["sympy"] +type1 = ["xattr"] +ufo = ["fs (>=2.2.0,<3)"] +unicode = ["unicodedata2 (>=15.0.0)"] +woff = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "zopfli (>=0.1.4)"] + +[[package]] +name = "furo" +version = "2023.5.20" +description = "A clean customisable Sphinx documentation theme." +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "furo-2023.5.20-py3-none-any.whl", hash = "sha256:594a8436ddfe0c071f3a9e9a209c314a219d8341f3f1af33fdf7c69544fab9e6"}, + {file = "furo-2023.5.20.tar.gz", hash = "sha256:40e09fa17c6f4b22419d122e933089226dcdb59747b5b6c79363089827dea16f"}, +] + +[package.dependencies] +beautifulsoup4 = "*" +pygments = ">=2.7" +sphinx = ">=6.0,<8.0" +sphinx-basic-ng = "*" + +[[package]] +name = "ghostscript" +version = "0.7" +description = "Interface to the Ghostscript C-API, both high- and low-level, based on ctypes" +category = "dev" +optional = false +python-versions = "*" +files = [ + {file = "ghostscript-0.7-py2.py3-none-any.whl", hash = "sha256:97c70e27ba6b1cab4ab1d9b4cc82d89b8b53e57971f608ded4950b8aa20c78a7"}, + {file = "ghostscript-0.7.tar.gz", hash = "sha256:b7875a87098740eb0be3de2d9662d15db727305ca9a6d4b7534a3cc33a4b965a"}, +] + +[package.dependencies] +setuptools = ">=38.6.0" + +[[package]] +name = "gitdb" +version = "4.0.10" +description = "Git Object Database" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "gitdb-4.0.10-py3-none-any.whl", hash = "sha256:c286cf298426064079ed96a9e4a9d39e7f3e9bf15ba60701e95f5492f28415c7"}, + {file = "gitdb-4.0.10.tar.gz", hash = "sha256:6eb990b69df4e15bad899ea868dc46572c3f75339735663b81de79b06f17eb9a"}, +] + +[package.dependencies] +smmap = ">=3.0.1,<6" + +[[package]] +name = "gitpython" +version = "3.1.32" +description = "GitPython is a Python library used to interact with Git repositories" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "GitPython-3.1.32-py3-none-any.whl", hash = "sha256:e3d59b1c2c6ebb9dfa7a184daf3b6dd4914237e7488a1730a6d8f6f5d0b4187f"}, + {file = "GitPython-3.1.32.tar.gz", hash = "sha256:8d9b8cb1e80b9735e8717c9362079d3ce4c6e5ddeebedd0361b228c3a67a62f6"}, +] + +[package.dependencies] +gitdb = ">=4.0.1,<5" + +[[package]] +name = "identify" +version = "2.5.24" +description = "File identification library for Python" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "identify-2.5.24-py2.py3-none-any.whl", hash = "sha256:986dbfb38b1140e763e413e6feb44cd731faf72d1909543178aa79b0e258265d"}, + {file = "identify-2.5.24.tar.gz", hash = "sha256:0aac67d5b4812498056d28a9a512a483f5085cc28640b02b258a59dac34301d4"}, +] + +[package.extras] +license = ["ukkonen"] + +[[package]] +name = "idna" +version = "3.4" +description = "Internationalized Domain Names in Applications (IDNA)" +category = "dev" +optional = false +python-versions = ">=3.5" +files = [ + {file = "idna-3.4-py3-none-any.whl", hash = "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"}, + {file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"}, +] + +[[package]] +name = "imagesize" +version = "1.4.1" +description = "Getting image size from png/jpeg/jpeg2000/gif file" +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +files = [ + {file = "imagesize-1.4.1-py2.py3-none-any.whl", hash = "sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b"}, + {file = "imagesize-1.4.1.tar.gz", hash = "sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a"}, +] + +[[package]] +name = "importlib-metadata" +version = "6.8.0" +description = "Read metadata from Python packages" +category = "dev" +optional = false +python-versions = ">=3.8" +files = [ + {file = "importlib_metadata-6.8.0-py3-none-any.whl", hash = "sha256:3ebb78df84a805d7698245025b975d9d67053cd94c79245ba4b3eb694abe68bb"}, + {file = "importlib_metadata-6.8.0.tar.gz", hash = "sha256:dbace7892d8c0c4ac1ad096662232f831d4e64f4c4545bd53016a3e9d4654743"}, +] + +[package.dependencies] +zipp = ">=0.5" + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +perf = ["ipython"] +testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)", "pytest-ruff"] + +[[package]] +name = "importlib-resources" +version = "6.0.0" +description = "Read resources from Python packages" +category = "dev" +optional = false +python-versions = ">=3.8" +files = [ + {file = "importlib_resources-6.0.0-py3-none-any.whl", hash = "sha256:d952faee11004c045f785bb5636e8f885bed30dc3c940d5d42798a2a4541c185"}, + {file = "importlib_resources-6.0.0.tar.gz", hash = "sha256:4cf94875a8368bd89531a756df9a9ebe1f150e0f885030b461237bc7f2d905f2"}, +] + +[package.dependencies] +zipp = {version = ">=3.1.0", markers = "python_version < \"3.10\""} + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +testing = ["pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-ruff"] + +[[package]] +name = "iniconfig" +version = "2.0.0" +description = "brain-dead simple config-ini parsing" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, + {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, +] + +[[package]] +name = "isort" +version = "5.12.0" +description = "A Python utility / library to sort Python imports." +category = "dev" +optional = false +python-versions = ">=3.8.0" +files = [ + {file = "isort-5.12.0-py3-none-any.whl", hash = "sha256:f84c2818376e66cf843d497486ea8fed8700b340f308f076c6fb1229dff318b6"}, + {file = "isort-5.12.0.tar.gz", hash = "sha256:8bef7dde241278824a6d83f44a544709b065191b95b6e50894bdc722fcba0504"}, +] + +[package.extras] +colors = ["colorama (>=0.4.3)"] +pipfile-deprecated-finder = ["pip-shims (>=0.5.2)", "pipreqs", "requirementslib"] +plugins = ["setuptools"] +requirements-deprecated-finder = ["pip-api", "pipreqs"] + +[[package]] +name = "jinja2" +version = "3.1.2" +description = "A very fast and expressive template engine." +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "Jinja2-3.1.2-py3-none-any.whl", hash = "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61"}, + {file = "Jinja2-3.1.2.tar.gz", hash = "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852"}, +] + +[package.dependencies] +MarkupSafe = ">=2.0" + +[package.extras] +i18n = ["Babel (>=2.7)"] + +[[package]] +name = "kiwisolver" +version = "1.4.4" +description = "A fast implementation of the Cassowary constraint solver" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "kiwisolver-1.4.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:2f5e60fabb7343a836360c4f0919b8cd0d6dbf08ad2ca6b9cf90bf0c76a3c4f6"}, + {file = "kiwisolver-1.4.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:10ee06759482c78bdb864f4109886dff7b8a56529bc1609d4f1112b93fe6423c"}, + {file = "kiwisolver-1.4.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c79ebe8f3676a4c6630fd3f777f3cfecf9289666c84e775a67d1d358578dc2e3"}, + {file = "kiwisolver-1.4.4-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:abbe9fa13da955feb8202e215c4018f4bb57469b1b78c7a4c5c7b93001699938"}, + {file = "kiwisolver-1.4.4-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:7577c1987baa3adc4b3c62c33bd1118c3ef5c8ddef36f0f2c950ae0b199e100d"}, + {file = "kiwisolver-1.4.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f8ad8285b01b0d4695102546b342b493b3ccc6781fc28c8c6a1bb63e95d22f09"}, + {file = "kiwisolver-1.4.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8ed58b8acf29798b036d347791141767ccf65eee7f26bde03a71c944449e53de"}, + {file = "kiwisolver-1.4.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a68b62a02953b9841730db7797422f983935aeefceb1679f0fc85cbfbd311c32"}, + {file = "kiwisolver-1.4.4-cp310-cp310-win32.whl", hash = "sha256:e92a513161077b53447160b9bd8f522edfbed4bd9759e4c18ab05d7ef7e49408"}, + {file = "kiwisolver-1.4.4-cp310-cp310-win_amd64.whl", hash = "sha256:3fe20f63c9ecee44560d0e7f116b3a747a5d7203376abeea292ab3152334d004"}, + {file = "kiwisolver-1.4.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e0ea21f66820452a3f5d1655f8704a60d66ba1191359b96541eaf457710a5fc6"}, + {file = "kiwisolver-1.4.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:bc9db8a3efb3e403e4ecc6cd9489ea2bac94244f80c78e27c31dcc00d2790ac2"}, + {file = "kiwisolver-1.4.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d5b61785a9ce44e5a4b880272baa7cf6c8f48a5180c3e81c59553ba0cb0821ca"}, + {file = "kiwisolver-1.4.4-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c2dbb44c3f7e6c4d3487b31037b1bdbf424d97687c1747ce4ff2895795c9bf69"}, + {file = "kiwisolver-1.4.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6295ecd49304dcf3bfbfa45d9a081c96509e95f4b9d0eb7ee4ec0530c4a96514"}, + {file = "kiwisolver-1.4.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4bd472dbe5e136f96a4b18f295d159d7f26fd399136f5b17b08c4e5f498cd494"}, + {file = "kiwisolver-1.4.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bf7d9fce9bcc4752ca4a1b80aabd38f6d19009ea5cbda0e0856983cf6d0023f5"}, + {file = "kiwisolver-1.4.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78d6601aed50c74e0ef02f4204da1816147a6d3fbdc8b3872d263338a9052c51"}, + {file = "kiwisolver-1.4.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:877272cf6b4b7e94c9614f9b10140e198d2186363728ed0f701c6eee1baec1da"}, + {file = "kiwisolver-1.4.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:db608a6757adabb32f1cfe6066e39b3706d8c3aa69bbc353a5b61edad36a5cb4"}, + {file = "kiwisolver-1.4.4-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:5853eb494c71e267912275e5586fe281444eb5e722de4e131cddf9d442615626"}, + {file = "kiwisolver-1.4.4-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:f0a1dbdb5ecbef0d34eb77e56fcb3e95bbd7e50835d9782a45df81cc46949750"}, + {file = "kiwisolver-1.4.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:283dffbf061a4ec60391d51e6155e372a1f7a4f5b15d59c8505339454f8989e4"}, + {file = "kiwisolver-1.4.4-cp311-cp311-win32.whl", hash = "sha256:d06adcfa62a4431d404c31216f0f8ac97397d799cd53800e9d3efc2fbb3cf14e"}, + {file = "kiwisolver-1.4.4-cp311-cp311-win_amd64.whl", hash = "sha256:e7da3fec7408813a7cebc9e4ec55afed2d0fd65c4754bc376bf03498d4e92686"}, + {file = "kiwisolver-1.4.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:62ac9cc684da4cf1778d07a89bf5f81b35834cb96ca523d3a7fb32509380cbf6"}, + {file = "kiwisolver-1.4.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:41dae968a94b1ef1897cb322b39360a0812661dba7c682aa45098eb8e193dbdf"}, + {file = "kiwisolver-1.4.4-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:02f79693ec433cb4b5f51694e8477ae83b3205768a6fb48ffba60549080e295b"}, + {file = "kiwisolver-1.4.4-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d0611a0a2a518464c05ddd5a3a1a0e856ccc10e67079bb17f265ad19ab3c7597"}, + {file = "kiwisolver-1.4.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:db5283d90da4174865d520e7366801a93777201e91e79bacbac6e6927cbceede"}, + {file = "kiwisolver-1.4.4-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:1041feb4cda8708ce73bb4dcb9ce1ccf49d553bf87c3954bdfa46f0c3f77252c"}, + {file = "kiwisolver-1.4.4-cp37-cp37m-win32.whl", hash = "sha256:a553dadda40fef6bfa1456dc4be49b113aa92c2a9a9e8711e955618cd69622e3"}, + {file = "kiwisolver-1.4.4-cp37-cp37m-win_amd64.whl", hash = "sha256:03baab2d6b4a54ddbb43bba1a3a2d1627e82d205c5cf8f4c924dc49284b87166"}, + {file = "kiwisolver-1.4.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:841293b17ad704d70c578f1f0013c890e219952169ce8a24ebc063eecf775454"}, + {file = "kiwisolver-1.4.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f4f270de01dd3e129a72efad823da90cc4d6aafb64c410c9033aba70db9f1ff0"}, + {file = "kiwisolver-1.4.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f9f39e2f049db33a908319cf46624a569b36983c7c78318e9726a4cb8923b26c"}, + {file = "kiwisolver-1.4.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c97528e64cb9ebeff9701e7938653a9951922f2a38bd847787d4a8e498cc83ae"}, + {file = "kiwisolver-1.4.4-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d1573129aa0fd901076e2bfb4275a35f5b7aa60fbfb984499d661ec950320b0"}, + {file = "kiwisolver-1.4.4-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ad881edc7ccb9d65b0224f4e4d05a1e85cf62d73aab798943df6d48ab0cd79a1"}, + {file = "kiwisolver-1.4.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b428ef021242344340460fa4c9185d0b1f66fbdbfecc6c63eff4b7c29fad429d"}, + {file = "kiwisolver-1.4.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:2e407cb4bd5a13984a6c2c0fe1845e4e41e96f183e5e5cd4d77a857d9693494c"}, + {file = "kiwisolver-1.4.4-cp38-cp38-win32.whl", hash = "sha256:75facbe9606748f43428fc91a43edb46c7ff68889b91fa31f53b58894503a191"}, + {file = "kiwisolver-1.4.4-cp38-cp38-win_amd64.whl", hash = "sha256:5bce61af018b0cb2055e0e72e7d65290d822d3feee430b7b8203d8a855e78766"}, + {file = "kiwisolver-1.4.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8c808594c88a025d4e322d5bb549282c93c8e1ba71b790f539567932722d7bd8"}, + {file = "kiwisolver-1.4.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f0a71d85ecdd570ded8ac3d1c0f480842f49a40beb423bb8014539a9f32a5897"}, + {file = "kiwisolver-1.4.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b533558eae785e33e8c148a8d9921692a9fe5aa516efbdff8606e7d87b9d5824"}, + {file = "kiwisolver-1.4.4-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:efda5fc8cc1c61e4f639b8067d118e742b812c930f708e6667a5ce0d13499e29"}, + {file = "kiwisolver-1.4.4-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:7c43e1e1206cd421cd92e6b3280d4385d41d7166b3ed577ac20444b6995a445f"}, + {file = "kiwisolver-1.4.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bc8d3bd6c72b2dd9decf16ce70e20abcb3274ba01b4e1c96031e0c4067d1e7cd"}, + {file = "kiwisolver-1.4.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4ea39b0ccc4f5d803e3337dd46bcce60b702be4d86fd0b3d7531ef10fd99a1ac"}, + {file = "kiwisolver-1.4.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:968f44fdbf6dd757d12920d63b566eeb4d5b395fd2d00d29d7ef00a00582aac9"}, + {file = "kiwisolver-1.4.4-cp39-cp39-win32.whl", hash = "sha256:da7e547706e69e45d95e116e6939488d62174e033b763ab1496b4c29b76fabea"}, + {file = "kiwisolver-1.4.4-cp39-cp39-win_amd64.whl", hash = "sha256:ba59c92039ec0a66103b1d5fe588fa546373587a7d68f5c96f743c3396afc04b"}, + {file = "kiwisolver-1.4.4-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:91672bacaa030f92fc2f43b620d7b337fd9a5af28b0d6ed3f77afc43c4a64b5a"}, + {file = "kiwisolver-1.4.4-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:787518a6789009c159453da4d6b683f468ef7a65bbde796bcea803ccf191058d"}, + {file = "kiwisolver-1.4.4-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da152d8cdcab0e56e4f45eb08b9aea6455845ec83172092f09b0e077ece2cf7a"}, + {file = "kiwisolver-1.4.4-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:ecb1fa0db7bf4cff9dac752abb19505a233c7f16684c5826d1f11ebd9472b871"}, + {file = "kiwisolver-1.4.4-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:28bc5b299f48150b5f822ce68624e445040595a4ac3d59251703779836eceff9"}, + {file = "kiwisolver-1.4.4-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:81e38381b782cc7e1e46c4e14cd997ee6040768101aefc8fa3c24a4cc58e98f8"}, + {file = "kiwisolver-1.4.4-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:2a66fdfb34e05b705620dd567f5a03f239a088d5a3f321e7b6ac3239d22aa286"}, + {file = "kiwisolver-1.4.4-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:872b8ca05c40d309ed13eb2e582cab0c5a05e81e987ab9c521bf05ad1d5cf5cb"}, + {file = "kiwisolver-1.4.4-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:70e7c2e7b750585569564e2e5ca9845acfaa5da56ac46df68414f29fea97be9f"}, + {file = "kiwisolver-1.4.4-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:9f85003f5dfa867e86d53fac6f7e6f30c045673fa27b603c397753bebadc3008"}, + {file = "kiwisolver-1.4.4-pp39-pypy39_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2e307eb9bd99801f82789b44bb45e9f541961831c7311521b13a6c85afc09767"}, + {file = "kiwisolver-1.4.4-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b1792d939ec70abe76f5054d3f36ed5656021dcad1322d1cc996d4e54165cef9"}, + {file = "kiwisolver-1.4.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6cb459eea32a4e2cf18ba5fcece2dbdf496384413bc1bae15583f19e567f3b2"}, + {file = "kiwisolver-1.4.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:36dafec3d6d6088d34e2de6b85f9d8e2324eb734162fba59d2ba9ed7a2043d5b"}, + {file = "kiwisolver-1.4.4.tar.gz", hash = "sha256:d41997519fcba4a1e46eb4a2fe31bc12f0ff957b2b81bac28db24744f333e955"}, +] + +[[package]] +name = "livereload" +version = "2.6.3" +description = "Python LiveReload is an awesome tool for web developers" +category = "dev" +optional = false +python-versions = "*" +files = [ + {file = "livereload-2.6.3-py2.py3-none-any.whl", hash = "sha256:ad4ac6f53b2d62bb6ce1a5e6e96f1f00976a32348afedcb4b6d68df2a1d346e4"}, + {file = "livereload-2.6.3.tar.gz", hash = "sha256:776f2f865e59fde56490a56bcc6773b6917366bce0c267c60ee8aaf1a0959869"}, +] + +[package.dependencies] +six = "*" +tornado = {version = "*", markers = "python_version > \"2.7\""} + +[[package]] +name = "markdown-it-py" +version = "3.0.0" +description = "Python port of markdown-it. Markdown parsing, done right!" +category = "dev" +optional = false +python-versions = ">=3.8" +files = [ + {file = "markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb"}, + {file = "markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1"}, +] + +[package.dependencies] +mdurl = ">=0.1,<1.0" + +[package.extras] +benchmarking = ["psutil", "pytest", "pytest-benchmark"] +code-style = ["pre-commit (>=3.0,<4.0)"] +compare = ["commonmark (>=0.9,<1.0)", "markdown (>=3.4,<4.0)", "mistletoe (>=1.0,<2.0)", "mistune (>=2.0,<3.0)", "panflute (>=2.3,<3.0)"] +linkify = ["linkify-it-py (>=1,<3)"] +plugins = ["mdit-py-plugins"] +profiling = ["gprof2dot"] +rtd = ["jupyter_sphinx", "mdit-py-plugins", "myst-parser", "pyyaml", "sphinx", "sphinx-copybutton", "sphinx-design", "sphinx_book_theme"] +testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"] + +[[package]] +name = "markupsafe" +version = "2.1.3" +description = "Safely add untrusted strings to HTML/XML markup." +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "MarkupSafe-2.1.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cd0f502fe016460680cd20aaa5a76d241d6f35a1c3350c474bac1273803893fa"}, + {file = "MarkupSafe-2.1.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e09031c87a1e51556fdcb46e5bd4f59dfb743061cf93c4d6831bf894f125eb57"}, + {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:68e78619a61ecf91e76aa3e6e8e33fc4894a2bebe93410754bd28fce0a8a4f9f"}, + {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:65c1a9bcdadc6c28eecee2c119465aebff8f7a584dd719facdd9e825ec61ab52"}, + {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:525808b8019e36eb524b8c68acdd63a37e75714eac50e988180b169d64480a00"}, + {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:962f82a3086483f5e5f64dbad880d31038b698494799b097bc59c2edf392fce6"}, + {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:aa7bd130efab1c280bed0f45501b7c8795f9fdbeb02e965371bbef3523627779"}, + {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c9c804664ebe8f83a211cace637506669e7890fec1b4195b505c214e50dd4eb7"}, + {file = "MarkupSafe-2.1.3-cp310-cp310-win32.whl", hash = "sha256:10bbfe99883db80bdbaff2dcf681dfc6533a614f700da1287707e8a5d78a8431"}, + {file = "MarkupSafe-2.1.3-cp310-cp310-win_amd64.whl", hash = "sha256:1577735524cdad32f9f694208aa75e422adba74f1baee7551620e43a3141f559"}, + {file = "MarkupSafe-2.1.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ad9e82fb8f09ade1c3e1b996a6337afac2b8b9e365f926f5a61aacc71adc5b3c"}, + {file = "MarkupSafe-2.1.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3c0fae6c3be832a0a0473ac912810b2877c8cb9d76ca48de1ed31e1c68386575"}, + {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b076b6226fb84157e3f7c971a47ff3a679d837cf338547532ab866c57930dbee"}, + {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bfce63a9e7834b12b87c64d6b155fdd9b3b96191b6bd334bf37db7ff1fe457f2"}, + {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:338ae27d6b8745585f87218a3f23f1512dbf52c26c28e322dbe54bcede54ccb9"}, + {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e4dd52d80b8c83fdce44e12478ad2e85c64ea965e75d66dbeafb0a3e77308fcc"}, + {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:df0be2b576a7abbf737b1575f048c23fb1d769f267ec4358296f31c2479db8f9"}, + {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac"}, + {file = "MarkupSafe-2.1.3-cp311-cp311-win32.whl", hash = "sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb"}, + {file = "MarkupSafe-2.1.3-cp311-cp311-win_amd64.whl", hash = "sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686"}, + {file = "MarkupSafe-2.1.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2"}, + {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b"}, + {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707"}, + {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ca379055a47383d02a5400cb0d110cef0a776fc644cda797db0c5696cfd7e18e"}, + {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:b7ff0f54cb4ff66dd38bebd335a38e2c22c41a8ee45aa608efc890ac3e3931bc"}, + {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c011a4149cfbcf9f03994ec2edffcb8b1dc2d2aede7ca243746df97a5d41ce48"}, + {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:56d9f2ecac662ca1611d183feb03a3fa4406469dafe241673d521dd5ae92a155"}, + {file = "MarkupSafe-2.1.3-cp37-cp37m-win32.whl", hash = "sha256:8758846a7e80910096950b67071243da3e5a20ed2546e6392603c096778d48e0"}, + {file = "MarkupSafe-2.1.3-cp37-cp37m-win_amd64.whl", hash = "sha256:787003c0ddb00500e49a10f2844fac87aa6ce977b90b0feaaf9de23c22508b24"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:2ef12179d3a291be237280175b542c07a36e7f60718296278d8593d21ca937d4"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2c1b19b3aaacc6e57b7e25710ff571c24d6c3613a45e905b1fde04d691b98ee0"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8afafd99945ead6e075b973fefa56379c5b5c53fd8937dad92c662da5d8fd5ee"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8c41976a29d078bb235fea9b2ecd3da465df42a562910f9022f1a03107bd02be"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d080e0a5eb2529460b30190fcfcc4199bd7f827663f858a226a81bc27beaa97e"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:69c0f17e9f5a7afdf2cc9fb2d1ce6aabdb3bafb7f38017c0b77862bcec2bbad8"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:504b320cd4b7eff6f968eddf81127112db685e81f7e36e75f9f84f0df46041c3"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:42de32b22b6b804f42c5d98be4f7e5e977ecdd9ee9b660fda1a3edf03b11792d"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-win32.whl", hash = "sha256:ceb01949af7121f9fc39f7d27f91be8546f3fb112c608bc4029aef0bab86a2a5"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-win_amd64.whl", hash = "sha256:1b40069d487e7edb2676d3fbdb2b0829ffa2cd63a2ec26c4938b2d34391b4ecc"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8023faf4e01efadfa183e863fefde0046de576c6f14659e8782065bcece22198"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6b2b56950d93e41f33b4223ead100ea0fe11f8e6ee5f641eb753ce4b77a7042b"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9dcdfd0eaf283af041973bff14a2e143b8bd64e069f4c383416ecd79a81aab58"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:05fb21170423db021895e1ea1e1f3ab3adb85d1c2333cbc2310f2a26bc77272e"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:282c2cb35b5b673bbcadb33a585408104df04f14b2d9b01d4c345a3b92861c2c"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ab4a0df41e7c16a1392727727e7998a467472d0ad65f3ad5e6e765015df08636"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7ef3cb2ebbf91e330e3bb937efada0edd9003683db6b57bb108c4001f37a02ea"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0a4e4a1aff6c7ac4cd55792abf96c915634c2b97e3cc1c7129578aa68ebd754e"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-win32.whl", hash = "sha256:fec21693218efe39aa7f8599346e90c705afa52c5b31ae019b2e57e8f6542bb2"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-win_amd64.whl", hash = "sha256:3fd4abcb888d15a94f32b75d8fd18ee162ca0c064f35b11134be77050296d6ba"}, + {file = "MarkupSafe-2.1.3.tar.gz", hash = "sha256:af598ed32d6ae86f1b747b82783958b1a4ab8f617b06fe68795c7f026abbdcad"}, +] + +[[package]] +name = "matplotlib" +version = "3.7.2" +description = "Python plotting package" +category = "dev" +optional = false +python-versions = ">=3.8" +files = [ + {file = "matplotlib-3.7.2-cp310-cp310-macosx_10_12_universal2.whl", hash = "sha256:2699f7e73a76d4c110f4f25be9d2496d6ab4f17345307738557d345f099e07de"}, + {file = "matplotlib-3.7.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:a8035ba590658bae7562786c9cc6ea1a84aa49d3afab157e414c9e2ea74f496d"}, + {file = "matplotlib-3.7.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2f8e4a49493add46ad4a8c92f63e19d548b2b6ebbed75c6b4c7f46f57d36cdd1"}, + {file = "matplotlib-3.7.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71667eb2ccca4c3537d9414b1bc00554cb7f91527c17ee4ec38027201f8f1603"}, + {file = "matplotlib-3.7.2-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:152ee0b569a37630d8628534c628456b28686e085d51394da6b71ef84c4da201"}, + {file = "matplotlib-3.7.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:070f8dddd1f5939e60aacb8fa08f19551f4b0140fab16a3669d5cd6e9cb28fc8"}, + {file = "matplotlib-3.7.2-cp310-cp310-win32.whl", hash = "sha256:fdbb46fad4fb47443b5b8ac76904b2e7a66556844f33370861b4788db0f8816a"}, + {file = "matplotlib-3.7.2-cp310-cp310-win_amd64.whl", hash = "sha256:23fb1750934e5f0128f9423db27c474aa32534cec21f7b2153262b066a581fd1"}, + {file = "matplotlib-3.7.2-cp311-cp311-macosx_10_12_universal2.whl", hash = "sha256:30e1409b857aa8a747c5d4f85f63a79e479835f8dffc52992ac1f3f25837b544"}, + {file = "matplotlib-3.7.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:50e0a55ec74bf2d7a0ebf50ac580a209582c2dd0f7ab51bc270f1b4a0027454e"}, + {file = "matplotlib-3.7.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ac60daa1dc83e8821eed155796b0f7888b6b916cf61d620a4ddd8200ac70cd64"}, + {file = "matplotlib-3.7.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:305e3da477dc8607336ba10bac96986d6308d614706cae2efe7d3ffa60465b24"}, + {file = "matplotlib-3.7.2-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1c308b255efb9b06b23874236ec0f10f026673ad6515f602027cc8ac7805352d"}, + {file = "matplotlib-3.7.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:60c521e21031632aa0d87ca5ba0c1c05f3daacadb34c093585a0be6780f698e4"}, + {file = "matplotlib-3.7.2-cp311-cp311-win32.whl", hash = "sha256:26bede320d77e469fdf1bde212de0ec889169b04f7f1179b8930d66f82b30cbc"}, + {file = "matplotlib-3.7.2-cp311-cp311-win_amd64.whl", hash = "sha256:af4860132c8c05261a5f5f8467f1b269bf1c7c23902d75f2be57c4a7f2394b3e"}, + {file = "matplotlib-3.7.2-cp38-cp38-macosx_10_12_universal2.whl", hash = "sha256:a1733b8e84e7e40a9853e505fe68cc54339f97273bdfe6f3ed980095f769ddc7"}, + {file = "matplotlib-3.7.2-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:d9881356dc48e58910c53af82b57183879129fa30492be69058c5b0d9fddf391"}, + {file = "matplotlib-3.7.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f081c03f413f59390a80b3e351cc2b2ea0205839714dbc364519bcf51f4b56ca"}, + {file = "matplotlib-3.7.2-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:1cd120fca3407a225168238b790bd5c528f0fafde6172b140a2f3ab7a4ea63e9"}, + {file = "matplotlib-3.7.2-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a2c1590b90aa7bd741b54c62b78de05d4186271e34e2377e0289d943b3522273"}, + {file = "matplotlib-3.7.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6d2ff3c984b8a569bc1383cd468fc06b70d7b59d5c2854ca39f1436ae8394117"}, + {file = "matplotlib-3.7.2-cp38-cp38-win32.whl", hash = "sha256:5dea00b62d28654b71ca92463656d80646675628d0828e08a5f3b57e12869e13"}, + {file = "matplotlib-3.7.2-cp38-cp38-win_amd64.whl", hash = "sha256:0f506a1776ee94f9e131af1ac6efa6e5bc7cb606a3e389b0ccb6e657f60bb676"}, + {file = "matplotlib-3.7.2-cp39-cp39-macosx_10_12_universal2.whl", hash = "sha256:6515e878f91894c2e4340d81f0911857998ccaf04dbc1bba781e3d89cbf70608"}, + {file = "matplotlib-3.7.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:71f7a8c6b124e904db550f5b9fe483d28b896d4135e45c4ea381ad3b8a0e3256"}, + {file = "matplotlib-3.7.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:12f01b92ecd518e0697da4d97d163b2b3aa55eb3eb4e2c98235b3396d7dad55f"}, + {file = "matplotlib-3.7.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a7e28d6396563955f7af437894a36bf2b279462239a41028323e04b85179058b"}, + {file = "matplotlib-3.7.2-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dbcf59334ff645e6a67cd5f78b4b2cdb76384cdf587fa0d2dc85f634a72e1a3e"}, + {file = "matplotlib-3.7.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:318c89edde72ff95d8df67d82aca03861240512994a597a435a1011ba18dbc7f"}, + {file = "matplotlib-3.7.2-cp39-cp39-win32.whl", hash = "sha256:ce55289d5659b5b12b3db4dc9b7075b70cef5631e56530f14b2945e8836f2d20"}, + {file = "matplotlib-3.7.2-cp39-cp39-win_amd64.whl", hash = "sha256:2ecb5be2b2815431c81dc115667e33da0f5a1bcf6143980d180d09a717c4a12e"}, + {file = "matplotlib-3.7.2-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:fdcd28360dbb6203fb5219b1a5658df226ac9bebc2542a9e8f457de959d713d0"}, + {file = "matplotlib-3.7.2-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0c3cca3e842b11b55b52c6fb8bd6a4088693829acbfcdb3e815fa9b7d5c92c1b"}, + {file = "matplotlib-3.7.2-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ebf577c7a6744e9e1bd3fee45fc74a02710b214f94e2bde344912d85e0c9af7c"}, + {file = "matplotlib-3.7.2-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:936bba394682049919dda062d33435b3be211dc3dcaa011e09634f060ec878b2"}, + {file = "matplotlib-3.7.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:bc221ffbc2150458b1cd71cdd9ddd5bb37962b036e41b8be258280b5b01da1dd"}, + {file = "matplotlib-3.7.2-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:35d74ebdb3f71f112b36c2629cf32323adfbf42679e2751252acd468f5001c07"}, + {file = "matplotlib-3.7.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:717157e61b3a71d3d26ad4e1770dc85156c9af435659a25ee6407dc866cb258d"}, + {file = "matplotlib-3.7.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:20f844d6be031948148ba49605c8b96dfe7d3711d1b63592830d650622458c11"}, + {file = "matplotlib-3.7.2.tar.gz", hash = "sha256:a8cdb91dddb04436bd2f098b8fdf4b81352e68cf4d2c6756fcc414791076569b"}, +] + +[package.dependencies] +contourpy = ">=1.0.1" +cycler = ">=0.10" +fonttools = ">=4.22.0" +importlib-resources = {version = ">=3.2.0", markers = "python_version < \"3.10\""} +kiwisolver = ">=1.0.1" +numpy = ">=1.20" +packaging = ">=20.0" +pillow = ">=6.2.0" +pyparsing = ">=2.3.1,<3.1" +python-dateutil = ">=2.7" + +[[package]] +name = "mccabe" +version = "0.7.0" +description = "McCabe checker, plugin for flake8" +category = "dev" +optional = false +python-versions = ">=3.6" +files = [ + {file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"}, + {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"}, +] + +[[package]] +name = "mdit-py-plugins" +version = "0.4.0" +description = "Collection of plugins for markdown-it-py" +category = "dev" +optional = false +python-versions = ">=3.8" +files = [ + {file = "mdit_py_plugins-0.4.0-py3-none-any.whl", hash = "sha256:b51b3bb70691f57f974e257e367107857a93b36f322a9e6d44ca5bf28ec2def9"}, + {file = "mdit_py_plugins-0.4.0.tar.gz", hash = "sha256:d8ab27e9aed6c38aa716819fedfde15ca275715955f8a185a8e1cf90fb1d2c1b"}, +] + +[package.dependencies] +markdown-it-py = ">=1.0.0,<4.0.0" + +[package.extras] +code-style = ["pre-commit"] +rtd = ["myst-parser", "sphinx-book-theme"] +testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"] + +[[package]] +name = "mdurl" +version = "0.1.2" +description = "Markdown URL utilities" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"}, + {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"}, +] + +[[package]] +name = "mypy" +version = "1.4.1" +description = "Optional static typing for Python" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "mypy-1.4.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:566e72b0cd6598503e48ea610e0052d1b8168e60a46e0bfd34b3acf2d57f96a8"}, + {file = "mypy-1.4.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ca637024ca67ab24a7fd6f65d280572c3794665eaf5edcc7e90a866544076878"}, + {file = "mypy-1.4.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0dde1d180cd84f0624c5dcaaa89c89775550a675aff96b5848de78fb11adabcd"}, + {file = "mypy-1.4.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8c4d8e89aa7de683e2056a581ce63c46a0c41e31bd2b6d34144e2c80f5ea53dc"}, + {file = "mypy-1.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:bfdca17c36ae01a21274a3c387a63aa1aafe72bff976522886869ef131b937f1"}, + {file = "mypy-1.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7549fbf655e5825d787bbc9ecf6028731973f78088fbca3a1f4145c39ef09462"}, + {file = "mypy-1.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:98324ec3ecf12296e6422939e54763faedbfcc502ea4a4c38502082711867258"}, + {file = "mypy-1.4.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:141dedfdbfe8a04142881ff30ce6e6653c9685b354876b12e4fe6c78598b45e2"}, + {file = "mypy-1.4.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:8207b7105829eca6f3d774f64a904190bb2231de91b8b186d21ffd98005f14a7"}, + {file = "mypy-1.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:16f0db5b641ba159eff72cff08edc3875f2b62b2fa2bc24f68c1e7a4e8232d01"}, + {file = "mypy-1.4.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:470c969bb3f9a9efcedbadcd19a74ffb34a25f8e6b0e02dae7c0e71f8372f97b"}, + {file = "mypy-1.4.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e5952d2d18b79f7dc25e62e014fe5a23eb1a3d2bc66318df8988a01b1a037c5b"}, + {file = "mypy-1.4.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:190b6bab0302cec4e9e6767d3eb66085aef2a1cc98fe04936d8a42ed2ba77bb7"}, + {file = "mypy-1.4.1-cp37-cp37m-win_amd64.whl", hash = "sha256:9d40652cc4fe33871ad3338581dca3297ff5f2213d0df345bcfbde5162abf0c9"}, + {file = "mypy-1.4.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:01fd2e9f85622d981fd9063bfaef1aed6e336eaacca00892cd2d82801ab7c042"}, + {file = "mypy-1.4.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2460a58faeea905aeb1b9b36f5065f2dc9a9c6e4c992a6499a2360c6c74ceca3"}, + {file = "mypy-1.4.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a2746d69a8196698146a3dbe29104f9eb6a2a4d8a27878d92169a6c0b74435b6"}, + {file = "mypy-1.4.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:ae704dcfaa180ff7c4cfbad23e74321a2b774f92ca77fd94ce1049175a21c97f"}, + {file = "mypy-1.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:43d24f6437925ce50139a310a64b2ab048cb2d3694c84c71c3f2a1626d8101dc"}, + {file = "mypy-1.4.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c482e1246726616088532b5e964e39765b6d1520791348e6c9dc3af25b233828"}, + {file = "mypy-1.4.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:43b592511672017f5b1a483527fd2684347fdffc041c9ef53428c8dc530f79a3"}, + {file = "mypy-1.4.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:34a9239d5b3502c17f07fd7c0b2ae6b7dd7d7f6af35fbb5072c6208e76295816"}, + {file = "mypy-1.4.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5703097c4936bbb9e9bce41478c8d08edd2865e177dc4c52be759f81ee4dd26c"}, + {file = "mypy-1.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:e02d700ec8d9b1859790c0475df4e4092c7bf3272a4fd2c9f33d87fac4427b8f"}, + {file = "mypy-1.4.1-py3-none-any.whl", hash = "sha256:45d32cec14e7b97af848bddd97d85ea4f0db4d5a149ed9676caa4eb2f7402bb4"}, + {file = "mypy-1.4.1.tar.gz", hash = "sha256:9bbcd9ab8ea1f2e1c8031c21445b511442cc45c89951e49bbf852cbb70755b1b"}, +] + +[package.dependencies] +mypy-extensions = ">=1.0.0" +tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} +typing-extensions = ">=4.1.0" + +[package.extras] +dmypy = ["psutil (>=4.0)"] +install-types = ["pip"] +python2 = ["typed-ast (>=1.4.0,<2)"] +reports = ["lxml"] + +[[package]] +name = "mypy-extensions" +version = "1.0.0" +description = "Type system extensions for programs checked with the mypy type checker." +category = "dev" +optional = false +python-versions = ">=3.5" +files = [ + {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, + {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, +] + +[[package]] +name = "myst-parser" +version = "2.0.0" +description = "An extended [CommonMark](https://spec.commonmark.org/) compliant parser," +category = "dev" +optional = false +python-versions = ">=3.8" +files = [ + {file = "myst_parser-2.0.0-py3-none-any.whl", hash = "sha256:7c36344ae39c8e740dad7fdabf5aa6fc4897a813083c6cc9990044eb93656b14"}, + {file = "myst_parser-2.0.0.tar.gz", hash = "sha256:ea929a67a6a0b1683cdbe19b8d2e724cd7643f8aa3e7bb18dd65beac3483bead"}, +] + +[package.dependencies] +docutils = ">=0.16,<0.21" +jinja2 = "*" +markdown-it-py = ">=3.0,<4.0" +mdit-py-plugins = ">=0.4,<1.0" +pyyaml = "*" +sphinx = ">=6,<8" + +[package.extras] +code-style = ["pre-commit (>=3.0,<4.0)"] +linkify = ["linkify-it-py (>=2.0,<3.0)"] +rtd = ["ipython", "pydata-sphinx-theme (==v0.13.0rc4)", "sphinx-autodoc2 (>=0.4.2,<0.5.0)", "sphinx-book-theme (==1.0.0rc2)", "sphinx-copybutton", "sphinx-design2", "sphinx-pyscript", "sphinx-tippy (>=0.3.1)", "sphinx-togglebutton", "sphinxext-opengraph (>=0.8.2,<0.9.0)", "sphinxext-rediraffe (>=0.2.7,<0.3.0)"] +testing = ["beautifulsoup4", "coverage[toml]", "pytest (>=7,<8)", "pytest-cov", "pytest-param-files (>=0.3.4,<0.4.0)", "pytest-regressions", "sphinx-pytest"] +testing-docutils = ["pygments", "pytest (>=7,<8)", "pytest-param-files (>=0.3.4,<0.4.0)"] + +[[package]] +name = "nodeenv" +version = "1.8.0" +description = "Node.js virtual environment builder" +category = "dev" +optional = false +python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*" +files = [ + {file = "nodeenv-1.8.0-py2.py3-none-any.whl", hash = "sha256:df865724bb3c3adc86b3876fa209771517b0cfe596beff01a92700e0e8be4cec"}, + {file = "nodeenv-1.8.0.tar.gz", hash = "sha256:d51e0c37e64fbf47d017feac3145cdbb58836d7eee8c6f6d3b6880c5456227d2"}, +] + +[package.dependencies] +setuptools = "*" + +[[package]] +name = "numpy" +version = "1.24.4" +description = "Fundamental package for array computing in Python" +category = "main" +optional = false +python-versions = ">=3.8" +files = [ + {file = "numpy-1.24.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c0bfb52d2169d58c1cdb8cc1f16989101639b34c7d3ce60ed70b19c63eba0b64"}, + {file = "numpy-1.24.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ed094d4f0c177b1b8e7aa9cba7d6ceed51c0e569a5318ac0ca9a090680a6a1b1"}, + {file = "numpy-1.24.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:79fc682a374c4a8ed08b331bef9c5f582585d1048fa6d80bc6c35bc384eee9b4"}, + {file = "numpy-1.24.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ffe43c74893dbf38c2b0a1f5428760a1a9c98285553c89e12d70a96a7f3a4d6"}, + {file = "numpy-1.24.4-cp310-cp310-win32.whl", hash = "sha256:4c21decb6ea94057331e111a5bed9a79d335658c27ce2adb580fb4d54f2ad9bc"}, + {file = "numpy-1.24.4-cp310-cp310-win_amd64.whl", hash = "sha256:b4bea75e47d9586d31e892a7401f76e909712a0fd510f58f5337bea9572c571e"}, + {file = "numpy-1.24.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f136bab9c2cfd8da131132c2cf6cc27331dd6fae65f95f69dcd4ae3c3639c810"}, + {file = "numpy-1.24.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e2926dac25b313635e4d6cf4dc4e51c8c0ebfed60b801c799ffc4c32bf3d1254"}, + {file = "numpy-1.24.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:222e40d0e2548690405b0b3c7b21d1169117391c2e82c378467ef9ab4c8f0da7"}, + {file = "numpy-1.24.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7215847ce88a85ce39baf9e89070cb860c98fdddacbaa6c0da3ffb31b3350bd5"}, + {file = "numpy-1.24.4-cp311-cp311-win32.whl", hash = "sha256:4979217d7de511a8d57f4b4b5b2b965f707768440c17cb70fbf254c4b225238d"}, + {file = "numpy-1.24.4-cp311-cp311-win_amd64.whl", hash = "sha256:b7b1fc9864d7d39e28f41d089bfd6353cb5f27ecd9905348c24187a768c79694"}, + {file = "numpy-1.24.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1452241c290f3e2a312c137a9999cdbf63f78864d63c79039bda65ee86943f61"}, + {file = "numpy-1.24.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:04640dab83f7c6c85abf9cd729c5b65f1ebd0ccf9de90b270cd61935eef0197f"}, + {file = "numpy-1.24.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5425b114831d1e77e4b5d812b69d11d962e104095a5b9c3b641a218abcc050e"}, + {file = "numpy-1.24.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd80e219fd4c71fc3699fc1dadac5dcf4fd882bfc6f7ec53d30fa197b8ee22dc"}, + {file = "numpy-1.24.4-cp38-cp38-win32.whl", hash = "sha256:4602244f345453db537be5314d3983dbf5834a9701b7723ec28923e2889e0bb2"}, + {file = "numpy-1.24.4-cp38-cp38-win_amd64.whl", hash = "sha256:692f2e0f55794943c5bfff12b3f56f99af76f902fc47487bdfe97856de51a706"}, + {file = "numpy-1.24.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2541312fbf09977f3b3ad449c4e5f4bb55d0dbf79226d7724211acc905049400"}, + {file = "numpy-1.24.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9667575fb6d13c95f1b36aca12c5ee3356bf001b714fc354eb5465ce1609e62f"}, + {file = "numpy-1.24.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f3a86ed21e4f87050382c7bc96571755193c4c1392490744ac73d660e8f564a9"}, + {file = "numpy-1.24.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d11efb4dbecbdf22508d55e48d9c8384db795e1b7b51ea735289ff96613ff74d"}, + {file = "numpy-1.24.4-cp39-cp39-win32.whl", hash = "sha256:6620c0acd41dbcb368610bb2f4d83145674040025e5536954782467100aa8835"}, + {file = "numpy-1.24.4-cp39-cp39-win_amd64.whl", hash = "sha256:befe2bf740fd8373cf56149a5c23a0f601e82869598d41f8e188a0e9869926f8"}, + {file = "numpy-1.24.4-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:31f13e25b4e304632a4619d0e0777662c2ffea99fcae2029556b17d8ff958aef"}, + {file = "numpy-1.24.4-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95f7ac6540e95bc440ad77f56e520da5bf877f87dca58bd095288dce8940532a"}, + {file = "numpy-1.24.4-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:e98f220aa76ca2a977fe435f5b04d7b3470c0a2e6312907b37ba6068f26787f2"}, + {file = "numpy-1.24.4.tar.gz", hash = "sha256:80f5e3a4e498641401868df4208b74581206afbee7cf7b8329daae82676d9463"}, +] + +[[package]] +name = "opencv-python" +version = "4.8.0.74" +description = "Wrapper package for OpenCV python bindings." +category = "dev" +optional = false +python-versions = ">=3.6" +files = [ + {file = "opencv-python-4.8.0.74.tar.gz", hash = "sha256:009e3ce356a0cd2d7423723e00a32fd3d3cc5bb5970ed27a9a1f8a8f221d1db5"}, + {file = "opencv_python-4.8.0.74-cp37-abi3-macosx_10_16_x86_64.whl", hash = "sha256:31d0d59fc8fdf703de4cec46c79b9f8d026fdde9d23d6e2e6a66809feeebbda9"}, + {file = "opencv_python-4.8.0.74-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:66eadb5882ee56848b67f9fb57aadcaca2f4c9d9d00a0ef11043041925b51291"}, + {file = "opencv_python-4.8.0.74-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:038ba7075e55cb8e2846663ae970f0fb776a45b48ee69a887bf4ee15e2570083"}, + {file = "opencv_python-4.8.0.74-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:43dd0dfe331fb95767af581bf3b2781d7a72cf6560ddf2f55949fe547f3e5c9f"}, + {file = "opencv_python-4.8.0.74-cp37-abi3-win32.whl", hash = "sha256:458e5dc377f15fcf769d80314f3d885bd95457b1a2891bee67df2eb24a1d3a52"}, + {file = "opencv_python-4.8.0.74-cp37-abi3-win_amd64.whl", hash = "sha256:8fe0018d0056a5187c57120b6b3f6c3e706c13b45c48e54e86d245a9a16fac84"}, +] + +[package.dependencies] +numpy = [ + {version = ">=1.21.0", markers = "python_version <= \"3.9\" and platform_system == \"Darwin\" and platform_machine == \"arm64\""}, + {version = ">=1.19.3", markers = "python_version >= \"3.6\" and platform_system == \"Linux\" and platform_machine == \"aarch64\" or python_version >= \"3.9\""}, + {version = ">=1.17.0", markers = "python_version >= \"3.7\""}, + {version = ">=1.17.3", markers = "python_version >= \"3.8\""}, + {version = ">=1.21.2", markers = "python_version >= \"3.10\""}, + {version = ">=1.21.4", markers = "python_version >= \"3.10\" and platform_system == \"Darwin\""}, + {version = ">=1.23.5", markers = "python_version >= \"3.11\""}, +] + +[[package]] +name = "openpyxl" +version = "3.1.2" +description = "A Python library to read/write Excel 2010 xlsx/xlsm files" +category = "main" +optional = false +python-versions = ">=3.6" +files = [ + {file = "openpyxl-3.1.2-py2.py3-none-any.whl", hash = "sha256:f91456ead12ab3c6c2e9491cf33ba6d08357d802192379bb482f1033ade496f5"}, + {file = "openpyxl-3.1.2.tar.gz", hash = "sha256:a6f5977418eff3b2d5500d54d9db50c8277a368436f4e4f8ddb1be3422870184"}, +] + +[package.dependencies] +et-xmlfile = "*" + +[[package]] +name = "packaging" +version = "23.1" +description = "Core utilities for Python packages" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "packaging-23.1-py3-none-any.whl", hash = "sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61"}, + {file = "packaging-23.1.tar.gz", hash = "sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f"}, +] + +[[package]] +name = "pandas" +version = "1.5.3" +description = "Powerful data structures for data analysis, time series, and statistics" +category = "main" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pandas-1.5.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3749077d86e3a2f0ed51367f30bf5b82e131cc0f14260c4d3e499186fccc4406"}, + {file = "pandas-1.5.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:972d8a45395f2a2d26733eb8d0f629b2f90bebe8e8eddbb8829b180c09639572"}, + {file = "pandas-1.5.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:50869a35cbb0f2e0cd5ec04b191e7b12ed688874bd05dd777c19b28cbea90996"}, + {file = "pandas-1.5.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c3ac844a0fe00bfaeb2c9b51ab1424e5c8744f89860b138434a363b1f620f354"}, + {file = "pandas-1.5.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a0a56cef15fd1586726dace5616db75ebcfec9179a3a55e78f72c5639fa2a23"}, + {file = "pandas-1.5.3-cp310-cp310-win_amd64.whl", hash = "sha256:478ff646ca42b20376e4ed3fa2e8d7341e8a63105586efe54fa2508ee087f328"}, + {file = "pandas-1.5.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6973549c01ca91ec96199e940495219c887ea815b2083722821f1d7abfa2b4dc"}, + {file = "pandas-1.5.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c39a8da13cede5adcd3be1182883aea1c925476f4e84b2807a46e2775306305d"}, + {file = "pandas-1.5.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f76d097d12c82a535fda9dfe5e8dd4127952b45fea9b0276cb30cca5ea313fbc"}, + {file = "pandas-1.5.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e474390e60ed609cec869b0da796ad94f420bb057d86784191eefc62b65819ae"}, + {file = "pandas-1.5.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5f2b952406a1588ad4cad5b3f55f520e82e902388a6d5a4a91baa8d38d23c7f6"}, + {file = "pandas-1.5.3-cp311-cp311-win_amd64.whl", hash = "sha256:bc4c368f42b551bf72fac35c5128963a171b40dce866fb066540eeaf46faa003"}, + {file = "pandas-1.5.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:14e45300521902689a81f3f41386dc86f19b8ba8dd5ac5a3c7010ef8d2932813"}, + {file = "pandas-1.5.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9842b6f4b8479e41968eced654487258ed81df7d1c9b7b870ceea24ed9459b31"}, + {file = "pandas-1.5.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:26d9c71772c7afb9d5046e6e9cf42d83dd147b5cf5bcb9d97252077118543792"}, + {file = "pandas-1.5.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5fbcb19d6fceb9e946b3e23258757c7b225ba450990d9ed63ccceeb8cae609f7"}, + {file = "pandas-1.5.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:565fa34a5434d38e9d250af3c12ff931abaf88050551d9fbcdfafca50d62babf"}, + {file = "pandas-1.5.3-cp38-cp38-win32.whl", hash = "sha256:87bd9c03da1ac870a6d2c8902a0e1fd4267ca00f13bc494c9e5a9020920e1d51"}, + {file = "pandas-1.5.3-cp38-cp38-win_amd64.whl", hash = "sha256:41179ce559943d83a9b4bbacb736b04c928b095b5f25dd2b7389eda08f46f373"}, + {file = "pandas-1.5.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c74a62747864ed568f5a82a49a23a8d7fe171d0c69038b38cedf0976831296fa"}, + {file = "pandas-1.5.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c4c00e0b0597c8e4f59e8d461f797e5d70b4d025880516a8261b2817c47759ee"}, + {file = "pandas-1.5.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a50d9a4336a9621cab7b8eb3fb11adb82de58f9b91d84c2cd526576b881a0c5a"}, + {file = "pandas-1.5.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd05f7783b3274aa206a1af06f0ceed3f9b412cf665b7247eacd83be41cf7bf0"}, + {file = "pandas-1.5.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9f69c4029613de47816b1bb30ff5ac778686688751a5e9c99ad8c7031f6508e5"}, + {file = "pandas-1.5.3-cp39-cp39-win32.whl", hash = "sha256:7cec0bee9f294e5de5bbfc14d0573f65526071029d036b753ee6507d2a21480a"}, + {file = "pandas-1.5.3-cp39-cp39-win_amd64.whl", hash = "sha256:dfd681c5dc216037e0b0a2c821f5ed99ba9f03ebcf119c7dac0e9a7b960b9ec9"}, + {file = "pandas-1.5.3.tar.gz", hash = "sha256:74a3fd7e5a7ec052f183273dc7b0acd3a863edf7520f5d3a1765c04ffdb3b0b1"}, +] + +[package.dependencies] +numpy = [ + {version = ">=1.20.3", markers = "python_version < \"3.10\""}, + {version = ">=1.21.0", markers = "python_version >= \"3.10\""}, + {version = ">=1.23.2", markers = "python_version >= \"3.11\""}, +] +python-dateutil = ">=2.8.1" +pytz = ">=2020.1" + +[package.extras] +test = ["hypothesis (>=5.5.3)", "pytest (>=6.0)", "pytest-xdist (>=1.31)"] + +[[package]] +name = "pathspec" +version = "0.11.1" +description = "Utility library for gitignore style pattern matching of file paths." +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pathspec-0.11.1-py3-none-any.whl", hash = "sha256:d8af70af76652554bd134c22b3e8a1cc46ed7d91edcdd721ef1a0c51a84a5293"}, + {file = "pathspec-0.11.1.tar.gz", hash = "sha256:2798de800fa92780e33acca925945e9a19a133b715067cf165b8866c15a31687"}, +] + +[[package]] +name = "pbr" +version = "5.11.1" +description = "Python Build Reasonableness" +category = "dev" +optional = false +python-versions = ">=2.6" +files = [ + {file = "pbr-5.11.1-py2.py3-none-any.whl", hash = "sha256:567f09558bae2b3ab53cb3c1e2e33e726ff3338e7bae3db5dc954b3a44eef12b"}, + {file = "pbr-5.11.1.tar.gz", hash = "sha256:aefc51675b0b533d56bb5fd1c8c6c0522fe31896679882e1c4c63d5e4a0fccb3"}, +] + +[[package]] +name = "pdfminer-six" +version = "20221105" +description = "PDF parser and analyzer" +category = "main" +optional = false +python-versions = ">=3.6" +files = [ + {file = "pdfminer.six-20221105-py3-none-any.whl", hash = "sha256:1eaddd712d5b2732f8ac8486824533514f8ba12a0787b3d5fe1e686cd826532d"}, + {file = "pdfminer.six-20221105.tar.gz", hash = "sha256:8448ab7b939d18b64820478ecac5394f482d7a79f5f7eaa7703c6c959c175e1d"}, +] + +[package.dependencies] +charset-normalizer = ">=2.0.0" +cryptography = ">=36.0.0" + +[package.extras] +dev = ["black", "mypy (==0.931)", "nox", "pytest"] +docs = ["sphinx", "sphinx-argparse"] +image = ["Pillow"] + +[[package]] +name = "pep8-naming" +version = "0.13.3" +description = "Check PEP-8 naming conventions, plugin for flake8" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pep8-naming-0.13.3.tar.gz", hash = "sha256:1705f046dfcd851378aac3be1cd1551c7c1e5ff363bacad707d43007877fa971"}, + {file = "pep8_naming-0.13.3-py3-none-any.whl", hash = "sha256:1a86b8c71a03337c97181917e2b472f0f5e4ccb06844a0d6f0a33522549e7a80"}, +] + +[package.dependencies] +flake8 = ">=5.0.0" + +[[package]] +name = "pillow" +version = "10.0.0" +description = "Python Imaging Library (Fork)" +category = "dev" +optional = false +python-versions = ">=3.8" +files = [ + {file = "Pillow-10.0.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:1f62406a884ae75fb2f818694469519fb685cc7eaff05d3451a9ebe55c646891"}, + {file = "Pillow-10.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d5db32e2a6ccbb3d34d87c87b432959e0db29755727afb37290e10f6e8e62614"}, + {file = "Pillow-10.0.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:edf4392b77bdc81f36e92d3a07a5cd072f90253197f4a52a55a8cec48a12483b"}, + {file = "Pillow-10.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:520f2a520dc040512699f20fa1c363eed506e94248d71f85412b625026f6142c"}, + {file = "Pillow-10.0.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:8c11160913e3dd06c8ffdb5f233a4f254cb449f4dfc0f8f4549eda9e542c93d1"}, + {file = "Pillow-10.0.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:a74ba0c356aaa3bb8e3eb79606a87669e7ec6444be352870623025d75a14a2bf"}, + {file = "Pillow-10.0.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d5d0dae4cfd56969d23d94dc8e89fb6a217be461c69090768227beb8ed28c0a3"}, + {file = "Pillow-10.0.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:22c10cc517668d44b211717fd9775799ccec4124b9a7f7b3635fc5386e584992"}, + {file = "Pillow-10.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:dffe31a7f47b603318c609f378ebcd57f1554a3a6a8effbc59c3c69f804296de"}, + {file = "Pillow-10.0.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:9fb218c8a12e51d7ead2a7c9e101a04982237d4855716af2e9499306728fb485"}, + {file = "Pillow-10.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d35e3c8d9b1268cbf5d3670285feb3528f6680420eafe35cccc686b73c1e330f"}, + {file = "Pillow-10.0.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3ed64f9ca2f0a95411e88a4efbd7a29e5ce2cea36072c53dd9d26d9c76f753b3"}, + {file = "Pillow-10.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b6eb5502f45a60a3f411c63187db83a3d3107887ad0d036c13ce836f8a36f1d"}, + {file = "Pillow-10.0.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:c1fbe7621c167ecaa38ad29643d77a9ce7311583761abf7836e1510c580bf3dd"}, + {file = "Pillow-10.0.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:cd25d2a9d2b36fcb318882481367956d2cf91329f6892fe5d385c346c0649629"}, + {file = "Pillow-10.0.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:3b08d4cc24f471b2c8ca24ec060abf4bebc6b144cb89cba638c720546b1cf538"}, + {file = "Pillow-10.0.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d737a602fbd82afd892ca746392401b634e278cb65d55c4b7a8f48e9ef8d008d"}, + {file = "Pillow-10.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:3a82c40d706d9aa9734289740ce26460a11aeec2d9c79b7af87bb35f0073c12f"}, + {file = "Pillow-10.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:bc2ec7c7b5d66b8ec9ce9f720dbb5fa4bace0f545acd34870eff4a369b44bf37"}, + {file = "Pillow-10.0.0-cp312-cp312-macosx_10_10_x86_64.whl", hash = "sha256:d80cf684b541685fccdd84c485b31ce73fc5c9b5d7523bf1394ce134a60c6883"}, + {file = "Pillow-10.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:76de421f9c326da8f43d690110f0e79fe3ad1e54be811545d7d91898b4c8493e"}, + {file = "Pillow-10.0.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:81ff539a12457809666fef6624684c008e00ff6bf455b4b89fd00a140eecd640"}, + {file = "Pillow-10.0.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce543ed15570eedbb85df19b0a1a7314a9c8141a36ce089c0a894adbfccb4568"}, + {file = "Pillow-10.0.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:685ac03cc4ed5ebc15ad5c23bc555d68a87777586d970c2c3e216619a5476223"}, + {file = "Pillow-10.0.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:d72e2ecc68a942e8cf9739619b7f408cc7b272b279b56b2c83c6123fcfa5cdff"}, + {file = "Pillow-10.0.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d50b6aec14bc737742ca96e85d6d0a5f9bfbded018264b3b70ff9d8c33485551"}, + {file = "Pillow-10.0.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:00e65f5e822decd501e374b0650146063fbb30a7264b4d2744bdd7b913e0cab5"}, + {file = "Pillow-10.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:f31f9fdbfecb042d046f9d91270a0ba28368a723302786c0009ee9b9f1f60199"}, + {file = "Pillow-10.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:1ce91b6ec08d866b14413d3f0bbdea7e24dfdc8e59f562bb77bc3fe60b6144ca"}, + {file = "Pillow-10.0.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:349930d6e9c685c089284b013478d6f76e3a534e36ddfa912cde493f235372f3"}, + {file = "Pillow-10.0.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:3a684105f7c32488f7153905a4e3015a3b6c7182e106fe3c37fbb5ef3e6994c3"}, + {file = "Pillow-10.0.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b4f69b3700201b80bb82c3a97d5e9254084f6dd5fb5b16fc1a7b974260f89f43"}, + {file = "Pillow-10.0.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3f07ea8d2f827d7d2a49ecf1639ec02d75ffd1b88dcc5b3a61bbb37a8759ad8d"}, + {file = "Pillow-10.0.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:040586f7d37b34547153fa383f7f9aed68b738992380ac911447bb78f2abe530"}, + {file = "Pillow-10.0.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:f88a0b92277de8e3ca715a0d79d68dc82807457dae3ab8699c758f07c20b3c51"}, + {file = "Pillow-10.0.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:c7cf14a27b0d6adfaebb3ae4153f1e516df54e47e42dcc073d7b3d76111a8d86"}, + {file = "Pillow-10.0.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:3400aae60685b06bb96f99a21e1ada7bc7a413d5f49bce739828ecd9391bb8f7"}, + {file = "Pillow-10.0.0-cp38-cp38-win_amd64.whl", hash = "sha256:dbc02381779d412145331789b40cc7b11fdf449e5d94f6bc0b080db0a56ea3f0"}, + {file = "Pillow-10.0.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:9211e7ad69d7c9401cfc0e23d49b69ca65ddd898976d660a2fa5904e3d7a9baa"}, + {file = "Pillow-10.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:faaf07ea35355b01a35cb442dd950d8f1bb5b040a7787791a535de13db15ed90"}, + {file = "Pillow-10.0.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c9f72a021fbb792ce98306ffb0c348b3c9cb967dce0f12a49aa4c3d3fdefa967"}, + {file = "Pillow-10.0.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9f7c16705f44e0504a3a2a14197c1f0b32a95731d251777dcb060aa83022cb2d"}, + {file = "Pillow-10.0.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:76edb0a1fa2b4745fb0c99fb9fb98f8b180a1bbceb8be49b087e0b21867e77d3"}, + {file = "Pillow-10.0.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:368ab3dfb5f49e312231b6f27b8820c823652b7cd29cfbd34090565a015e99ba"}, + {file = "Pillow-10.0.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:608bfdee0d57cf297d32bcbb3c728dc1da0907519d1784962c5f0c68bb93e5a3"}, + {file = "Pillow-10.0.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5c6e3df6bdd396749bafd45314871b3d0af81ff935b2d188385e970052091017"}, + {file = "Pillow-10.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:7be600823e4c8631b74e4a0d38384c73f680e6105a7d3c6824fcf226c178c7e6"}, + {file = "Pillow-10.0.0-pp310-pypy310_pp73-macosx_10_10_x86_64.whl", hash = "sha256:92be919bbc9f7d09f7ae343c38f5bb21c973d2576c1d45600fce4b74bafa7ac0"}, + {file = "Pillow-10.0.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f8182b523b2289f7c415f589118228d30ac8c355baa2f3194ced084dac2dbba"}, + {file = "Pillow-10.0.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:38250a349b6b390ee6047a62c086d3817ac69022c127f8a5dc058c31ccef17f3"}, + {file = "Pillow-10.0.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:88af2003543cc40c80f6fca01411892ec52b11021b3dc22ec3bc9d5afd1c5334"}, + {file = "Pillow-10.0.0-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:c189af0545965fa8d3b9613cfdb0cd37f9d71349e0f7750e1fd704648d475ed2"}, + {file = "Pillow-10.0.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce7b031a6fc11365970e6a5686d7ba8c63e4c1cf1ea143811acbb524295eabed"}, + {file = "Pillow-10.0.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:db24668940f82321e746773a4bc617bfac06ec831e5c88b643f91f122a785684"}, + {file = "Pillow-10.0.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:efe8c0681042536e0d06c11f48cebe759707c9e9abf880ee213541c5b46c5bf3"}, + {file = "Pillow-10.0.0.tar.gz", hash = "sha256:9c82b5b3e043c7af0d95792d0d20ccf68f61a1fec6b3530e718b688422727396"}, +] + +[package.extras] +docs = ["furo", "olefile", "sphinx (>=2.4)", "sphinx-copybutton", "sphinx-inline-tabs", "sphinx-removed-in", "sphinxext-opengraph"] +tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout"] + +[[package]] +name = "platformdirs" +version = "3.8.1" +description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "platformdirs-3.8.1-py3-none-any.whl", hash = "sha256:cec7b889196b9144d088e4c57d9ceef7374f6c39694ad1577a0aab50d27ea28c"}, + {file = "platformdirs-3.8.1.tar.gz", hash = "sha256:f87ca4fcff7d2b0f81c6a748a77973d7af0f4d526f98f308477c3c436c74d528"}, +] + +[package.extras] +docs = ["furo (>=2023.5.20)", "proselint (>=0.13)", "sphinx (>=7.0.1)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.3.1)", "pytest-cov (>=4.1)", "pytest-mock (>=3.10)"] + +[[package]] +name = "pluggy" +version = "1.2.0" +description = "plugin and hook calling mechanisms for python" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pluggy-1.2.0-py3-none-any.whl", hash = "sha256:c2fd55a7d7a3863cba1a013e4e2414658b1d07b6bc57b3919e0c63c9abb99849"}, + {file = "pluggy-1.2.0.tar.gz", hash = "sha256:d12f0c4b579b15f5e054301bb226ee85eeeba08ffec228092f8defbaa3a4c4b3"}, +] + +[package.extras] +dev = ["pre-commit", "tox"] +testing = ["pytest", "pytest-benchmark"] + +[[package]] +name = "pre-commit" +version = "3.3.3" +description = "A framework for managing and maintaining multi-language pre-commit hooks." +category = "dev" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pre_commit-3.3.3-py2.py3-none-any.whl", hash = "sha256:10badb65d6a38caff29703362271d7dca483d01da88f9d7e05d0b97171c136cb"}, + {file = "pre_commit-3.3.3.tar.gz", hash = "sha256:a2256f489cd913d575c145132ae196fe335da32d91a8294b7afe6622335dd023"}, +] + +[package.dependencies] +cfgv = ">=2.0.0" +identify = ">=1.0.0" +nodeenv = ">=0.11.1" +pyyaml = ">=5.1" +virtualenv = ">=20.10.0" + +[[package]] +name = "pre-commit-hooks" +version = "4.4.0" +description = "Some out-of-the-box hooks for pre-commit." +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pre_commit_hooks-4.4.0-py2.py3-none-any.whl", hash = "sha256:fc8837335476221ccccda3d176ed6ae29fe58753ce7e8b7863f5d0f987328fc6"}, + {file = "pre_commit_hooks-4.4.0.tar.gz", hash = "sha256:7011eed8e1a25cde94693da009cba76392194cecc2f3f06c51a44ea6ad6c2af9"}, +] + +[package.dependencies] +"ruamel.yaml" = ">=0.15" +tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} + +[[package]] +name = "pycodestyle" +version = "2.9.1" +description = "Python style guide checker" +category = "dev" +optional = false +python-versions = ">=3.6" +files = [ + {file = "pycodestyle-2.9.1-py2.py3-none-any.whl", hash = "sha256:d1735fc58b418fd7c5f658d28d943854f8a849b01a5d0a1e6f3f3fdd0166804b"}, + {file = "pycodestyle-2.9.1.tar.gz", hash = "sha256:2c9607871d58c76354b697b42f5d57e1ada7d261c261efac224b664affdc5785"}, +] + +[[package]] +name = "pycparser" +version = "2.21" +description = "C parser in Python" +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +files = [ + {file = "pycparser-2.21-py2.py3-none-any.whl", hash = "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9"}, + {file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"}, +] + +[[package]] +name = "pyflakes" +version = "2.5.0" +description = "passive checker of Python programs" +category = "dev" +optional = false +python-versions = ">=3.6" +files = [ + {file = "pyflakes-2.5.0-py2.py3-none-any.whl", hash = "sha256:4579f67d887f804e67edb544428f264b7b24f435b263c4614f384135cea553d2"}, + {file = "pyflakes-2.5.0.tar.gz", hash = "sha256:491feb020dca48ccc562a8c0cbe8df07ee13078df59813b83959cbdada312ea3"}, +] + +[[package]] +name = "pygments" +version = "2.15.1" +description = "Pygments is a syntax highlighting package written in Python." +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "Pygments-2.15.1-py3-none-any.whl", hash = "sha256:db2db3deb4b4179f399a09054b023b6a586b76499d36965813c71aa8ed7b5fd1"}, + {file = "Pygments-2.15.1.tar.gz", hash = "sha256:8ace4d3c1dd481894b2005f560ead0f9f19ee64fe983366be1a21e171d12775c"}, +] + +[package.extras] +plugins = ["importlib-metadata"] + +[[package]] +name = "pyparsing" +version = "3.0.9" +description = "pyparsing module - Classes and methods to define and execute parsing grammars" +category = "dev" +optional = false +python-versions = ">=3.6.8" +files = [ + {file = "pyparsing-3.0.9-py3-none-any.whl", hash = "sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc"}, + {file = "pyparsing-3.0.9.tar.gz", hash = "sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb"}, +] + +[package.extras] +diagrams = ["jinja2", "railroad-diagrams"] + +[[package]] +name = "pypdf" +version = "3.12.1" +description = "A pure-python PDF library capable of splitting, merging, cropping, and transforming PDF files" +category = "main" +optional = false +python-versions = ">=3.6" +files = [ + {file = "pypdf-3.12.1-py3-none-any.whl", hash = "sha256:74aa287c83e9aad2ce4a3627458dad729e39b5deae52175fe9f97bfffdde41bc"}, + {file = "pypdf-3.12.1.tar.gz", hash = "sha256:68bf9e089caaab356518410168df9ed90f0a6109e29adac168449d4054fa0094"}, +] + +[package.dependencies] +typing_extensions = {version = ">=3.10.0.0", markers = "python_version < \"3.10\""} + +[package.extras] +crypto = ["PyCryptodome"] +dev = ["black", "flit", "pip-tools", "pre-commit (<2.18.0)", "pytest-cov", "pytest-socket", "wheel"] +docs = ["myst_parser", "sphinx", "sphinx_rtd_theme"] +full = ["Pillow", "PyCryptodome"] +image = ["Pillow"] + +[[package]] +name = "pytest" +version = "7.4.0" +description = "pytest: simple powerful testing with Python" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pytest-7.4.0-py3-none-any.whl", hash = "sha256:78bf16451a2eb8c7a2ea98e32dc119fd2aa758f1d5d66dbf0a59d69a3969df32"}, + {file = "pytest-7.4.0.tar.gz", hash = "sha256:b4bf8c45bd59934ed84001ad51e11b4ee40d40a1229d2c79f9c592b0a3f6bd8a"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "sys_platform == \"win32\""} +exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} +iniconfig = "*" +packaging = "*" +pluggy = ">=0.12,<2.0" +tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} + +[package.extras] +testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] + +[[package]] +name = "python-dateutil" +version = "2.8.2" +description = "Extensions to the standard Python datetime module" +category = "main" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +files = [ + {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, + {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, +] + +[package.dependencies] +six = ">=1.5" + +[[package]] +name = "pytz" +version = "2023.3" +description = "World timezone definitions, modern and historical" +category = "main" +optional = false +python-versions = "*" +files = [ + {file = "pytz-2023.3-py2.py3-none-any.whl", hash = "sha256:a151b3abb88eda1d4e34a9814df37de2a80e301e68ba0fd856fb9b46bfbbbffb"}, + {file = "pytz-2023.3.tar.gz", hash = "sha256:1d8ce29db189191fb55338ee6d0387d82ab59f3d00eac103412d64e0ebd0c588"}, +] + +[[package]] +name = "pyupgrade" +version = "3.8.0" +description = "A tool to automatically upgrade syntax for newer versions." +category = "dev" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pyupgrade-3.8.0-py2.py3-none-any.whl", hash = "sha256:08d0e6129f5e9da7e7a581bdbea689e0d49c3c93eeaf156a07ae2fd794f52660"}, + {file = "pyupgrade-3.8.0.tar.gz", hash = "sha256:1facb0b8407cca468dfcc1d13717e3a85aa37b9e6e7338664ad5bfe5ef50c867"}, +] + +[package.dependencies] +tokenize-rt = ">=3.2.0" + +[[package]] +name = "pyyaml" +version = "6.0" +description = "YAML parser and emitter for Python" +category = "dev" +optional = false +python-versions = ">=3.6" +files = [ + {file = "PyYAML-6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53"}, + {file = "PyYAML-6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c"}, + {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc"}, + {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b"}, + {file = "PyYAML-6.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5"}, + {file = "PyYAML-6.0-cp310-cp310-win32.whl", hash = "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513"}, + {file = "PyYAML-6.0-cp310-cp310-win_amd64.whl", hash = "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a"}, + {file = "PyYAML-6.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d4b0ba9512519522b118090257be113b9468d804b19d63c71dbcf4a48fa32358"}, + {file = "PyYAML-6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:81957921f441d50af23654aa6c5e5eaf9b06aba7f0a19c18a538dc7ef291c5a1"}, + {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:afa17f5bc4d1b10afd4466fd3a44dc0e245382deca5b3c353d8b757f9e3ecb8d"}, + {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dbad0e9d368bb989f4515da330b88a057617d16b6a8245084f1b05400f24609f"}, + {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:432557aa2c09802be39460360ddffd48156e30721f5e8d917f01d31694216782"}, + {file = "PyYAML-6.0-cp311-cp311-win32.whl", hash = "sha256:bfaef573a63ba8923503d27530362590ff4f576c626d86a9fed95822a8255fd7"}, + {file = "PyYAML-6.0-cp311-cp311-win_amd64.whl", hash = "sha256:01b45c0191e6d66c470b6cf1b9531a771a83c1c4208272ead47a3ae4f2f603bf"}, + {file = "PyYAML-6.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86"}, + {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f"}, + {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92"}, + {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4"}, + {file = "PyYAML-6.0-cp36-cp36m-win32.whl", hash = "sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293"}, + {file = "PyYAML-6.0-cp36-cp36m-win_amd64.whl", hash = "sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57"}, + {file = "PyYAML-6.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c"}, + {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0"}, + {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4"}, + {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9"}, + {file = "PyYAML-6.0-cp37-cp37m-win32.whl", hash = "sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737"}, + {file = "PyYAML-6.0-cp37-cp37m-win_amd64.whl", hash = "sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d"}, + {file = "PyYAML-6.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b"}, + {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba"}, + {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34"}, + {file = "PyYAML-6.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287"}, + {file = "PyYAML-6.0-cp38-cp38-win32.whl", hash = "sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78"}, + {file = "PyYAML-6.0-cp38-cp38-win_amd64.whl", hash = "sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07"}, + {file = "PyYAML-6.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b"}, + {file = "PyYAML-6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174"}, + {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803"}, + {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3"}, + {file = "PyYAML-6.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0"}, + {file = "PyYAML-6.0-cp39-cp39-win32.whl", hash = "sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb"}, + {file = "PyYAML-6.0-cp39-cp39-win_amd64.whl", hash = "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c"}, + {file = "PyYAML-6.0.tar.gz", hash = "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2"}, +] + +[[package]] +name = "requests" +version = "2.31.0" +description = "Python HTTP for Humans." +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "requests-2.31.0-py3-none-any.whl", hash = "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f"}, + {file = "requests-2.31.0.tar.gz", hash = "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"}, +] + +[package.dependencies] +certifi = ">=2017.4.17" +charset-normalizer = ">=2,<4" +idna = ">=2.5,<4" +urllib3 = ">=1.21.1,<3" + +[package.extras] +socks = ["PySocks (>=1.5.6,!=1.5.7)"] +use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] + +[[package]] +name = "restructuredtext-lint" +version = "1.4.0" +description = "reStructuredText linter" +category = "dev" +optional = false +python-versions = "*" +files = [ + {file = "restructuredtext_lint-1.4.0.tar.gz", hash = "sha256:1b235c0c922341ab6c530390892eb9e92f90b9b75046063e047cacfb0f050c45"}, +] + +[package.dependencies] +docutils = ">=0.11,<1.0" + +[[package]] +name = "rich" +version = "13.4.2" +description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" +category = "dev" +optional = false +python-versions = ">=3.7.0" +files = [ + {file = "rich-13.4.2-py3-none-any.whl", hash = "sha256:8f87bc7ee54675732fa66a05ebfe489e27264caeeff3728c945d25971b6485ec"}, + {file = "rich-13.4.2.tar.gz", hash = "sha256:d653d6bccede5844304c605d5aac802c7cf9621efd700b46c7ec2b51ea914898"}, +] + +[package.dependencies] +markdown-it-py = ">=2.2.0" +pygments = ">=2.13.0,<3.0.0" +typing-extensions = {version = ">=4.0.0,<5.0", markers = "python_version < \"3.9\""} + +[package.extras] +jupyter = ["ipywidgets (>=7.5.1,<9)"] + +[[package]] +name = "ruamel-yaml" +version = "0.17.32" +description = "ruamel.yaml is a YAML parser/emitter that supports roundtrip preservation of comments, seq/map flow style, and map key order" +category = "dev" +optional = false +python-versions = ">=3" +files = [ + {file = "ruamel.yaml-0.17.32-py3-none-any.whl", hash = "sha256:23cd2ed620231677564646b0c6a89d138b6822a0d78656df7abda5879ec4f447"}, + {file = "ruamel.yaml-0.17.32.tar.gz", hash = "sha256:ec939063761914e14542972a5cba6d33c23b0859ab6342f61cf070cfc600efc2"}, +] + +[package.dependencies] +"ruamel.yaml.clib" = {version = ">=0.2.7", markers = "platform_python_implementation == \"CPython\" and python_version < \"3.12\""} + +[package.extras] +docs = ["ryd"] +jinja2 = ["ruamel.yaml.jinja2 (>=0.2)"] + +[[package]] +name = "ruamel-yaml-clib" +version = "0.2.7" +description = "C version of reader, parser and emitter for ruamel.yaml derived from libyaml" +category = "dev" +optional = false +python-versions = ">=3.5" +files = [ + {file = "ruamel.yaml.clib-0.2.7-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d5859983f26d8cd7bb5c287ef452e8aacc86501487634573d260968f753e1d71"}, + {file = "ruamel.yaml.clib-0.2.7-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:debc87a9516b237d0466a711b18b6ebeb17ba9f391eb7f91c649c5c4ec5006c7"}, + {file = "ruamel.yaml.clib-0.2.7-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:df5828871e6648db72d1c19b4bd24819b80a755c4541d3409f0f7acd0f335c80"}, + {file = "ruamel.yaml.clib-0.2.7-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:efa08d63ef03d079dcae1dfe334f6c8847ba8b645d08df286358b1f5293d24ab"}, + {file = "ruamel.yaml.clib-0.2.7-cp310-cp310-win32.whl", hash = "sha256:763d65baa3b952479c4e972669f679fe490eee058d5aa85da483ebae2009d231"}, + {file = "ruamel.yaml.clib-0.2.7-cp310-cp310-win_amd64.whl", hash = "sha256:d000f258cf42fec2b1bbf2863c61d7b8918d31ffee905da62dede869254d3b8a"}, + {file = "ruamel.yaml.clib-0.2.7-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:045e0626baf1c52e5527bd5db361bc83180faaba2ff586e763d3d5982a876a9e"}, + {file = "ruamel.yaml.clib-0.2.7-cp311-cp311-macosx_12_6_arm64.whl", hash = "sha256:721bc4ba4525f53f6a611ec0967bdcee61b31df5a56801281027a3a6d1c2daf5"}, + {file = "ruamel.yaml.clib-0.2.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:41d0f1fa4c6830176eef5b276af04c89320ea616655d01327d5ce65e50575c94"}, + {file = "ruamel.yaml.clib-0.2.7-cp311-cp311-win32.whl", hash = "sha256:f6d3d39611ac2e4f62c3128a9eed45f19a6608670c5a2f4f07f24e8de3441d38"}, + {file = "ruamel.yaml.clib-0.2.7-cp311-cp311-win_amd64.whl", hash = "sha256:da538167284de58a52109a9b89b8f6a53ff8437dd6dc26d33b57bf6699153122"}, + {file = "ruamel.yaml.clib-0.2.7-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:4b3a93bb9bc662fc1f99c5c3ea8e623d8b23ad22f861eb6fce9377ac07ad6072"}, + {file = "ruamel.yaml.clib-0.2.7-cp36-cp36m-macosx_12_0_arm64.whl", hash = "sha256:a234a20ae07e8469da311e182e70ef6b199d0fbeb6c6cc2901204dd87fb867e8"}, + {file = "ruamel.yaml.clib-0.2.7-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:15910ef4f3e537eea7fe45f8a5d19997479940d9196f357152a09031c5be59f3"}, + {file = "ruamel.yaml.clib-0.2.7-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:370445fd795706fd291ab00c9df38a0caed0f17a6fb46b0f607668ecb16ce763"}, + {file = "ruamel.yaml.clib-0.2.7-cp36-cp36m-win32.whl", hash = "sha256:ecdf1a604009bd35c674b9225a8fa609e0282d9b896c03dd441a91e5f53b534e"}, + {file = "ruamel.yaml.clib-0.2.7-cp36-cp36m-win_amd64.whl", hash = "sha256:f34019dced51047d6f70cb9383b2ae2853b7fc4dce65129a5acd49f4f9256646"}, + {file = "ruamel.yaml.clib-0.2.7-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:2aa261c29a5545adfef9296b7e33941f46aa5bbd21164228e833412af4c9c75f"}, + {file = "ruamel.yaml.clib-0.2.7-cp37-cp37m-macosx_12_0_arm64.whl", hash = "sha256:f01da5790e95815eb5a8a138508c01c758e5f5bc0ce4286c4f7028b8dd7ac3d0"}, + {file = "ruamel.yaml.clib-0.2.7-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:40d030e2329ce5286d6b231b8726959ebbe0404c92f0a578c0e2482182e38282"}, + {file = "ruamel.yaml.clib-0.2.7-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:c3ca1fbba4ae962521e5eb66d72998b51f0f4d0f608d3c0347a48e1af262efa7"}, + {file = "ruamel.yaml.clib-0.2.7-cp37-cp37m-win32.whl", hash = "sha256:7bdb4c06b063f6fd55e472e201317a3bb6cdeeee5d5a38512ea5c01e1acbdd93"}, + {file = "ruamel.yaml.clib-0.2.7-cp37-cp37m-win_amd64.whl", hash = "sha256:be2a7ad8fd8f7442b24323d24ba0b56c51219513cfa45b9ada3b87b76c374d4b"}, + {file = "ruamel.yaml.clib-0.2.7-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:91a789b4aa0097b78c93e3dc4b40040ba55bef518f84a40d4442f713b4094acb"}, + {file = "ruamel.yaml.clib-0.2.7-cp38-cp38-macosx_12_0_arm64.whl", hash = "sha256:99e77daab5d13a48a4054803d052ff40780278240a902b880dd37a51ba01a307"}, + {file = "ruamel.yaml.clib-0.2.7-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:3243f48ecd450eddadc2d11b5feb08aca941b5cd98c9b1db14b2fd128be8c697"}, + {file = "ruamel.yaml.clib-0.2.7-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:8831a2cedcd0f0927f788c5bdf6567d9dc9cc235646a434986a852af1cb54b4b"}, + {file = "ruamel.yaml.clib-0.2.7-cp38-cp38-win32.whl", hash = "sha256:3110a99e0f94a4a3470ff67fc20d3f96c25b13d24c6980ff841e82bafe827cac"}, + {file = "ruamel.yaml.clib-0.2.7-cp38-cp38-win_amd64.whl", hash = "sha256:92460ce908546ab69770b2e576e4f99fbb4ce6ab4b245345a3869a0a0410488f"}, + {file = "ruamel.yaml.clib-0.2.7-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5bc0667c1eb8f83a3752b71b9c4ba55ef7c7058ae57022dd9b29065186a113d9"}, + {file = "ruamel.yaml.clib-0.2.7-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:4a4d8d417868d68b979076a9be6a38c676eca060785abaa6709c7b31593c35d1"}, + {file = "ruamel.yaml.clib-0.2.7-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:bf9a6bc4a0221538b1a7de3ed7bca4c93c02346853f44e1cd764be0023cd3640"}, + {file = "ruamel.yaml.clib-0.2.7-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:a7b301ff08055d73223058b5c46c55638917f04d21577c95e00e0c4d79201a6b"}, + {file = "ruamel.yaml.clib-0.2.7-cp39-cp39-win32.whl", hash = "sha256:d5e51e2901ec2366b79f16c2299a03e74ba4531ddcfacc1416639c557aef0ad8"}, + {file = "ruamel.yaml.clib-0.2.7-cp39-cp39-win_amd64.whl", hash = "sha256:184faeaec61dbaa3cace407cffc5819f7b977e75360e8d5ca19461cd851a5fc5"}, + {file = "ruamel.yaml.clib-0.2.7.tar.gz", hash = "sha256:1f08fd5a2bea9c4180db71678e850b995d2a5f4537be0e94557668cf0f5f9497"}, +] + +[[package]] +name = "safety" +version = "2.3.4" +description = "Checks installed dependencies for known vulnerabilities and licenses." +category = "dev" +optional = false +python-versions = "*" +files = [ + {file = "safety-2.3.4-py3-none-any.whl", hash = "sha256:6224dcd9b20986a2b2c5e7acfdfba6bca42bb11b2783b24ed04f32317e5167ea"}, + {file = "safety-2.3.4.tar.gz", hash = "sha256:b9e74e794e82f54d11f4091c5d820c4d2d81de9f953bf0b4f33ac8bc402ae72c"}, +] + +[package.dependencies] +Click = ">=8.0.2" +dparse = ">=0.6.2" +packaging = ">=21.0" +requests = "*" +"ruamel.yaml" = ">=0.17.21" +setuptools = ">=19.3" + +[package.extras] +github = ["jinja2 (>=3.1.0)", "pygithub (>=1.43.3)"] +gitlab = ["python-gitlab (>=1.3.0)"] + +[[package]] +name = "setuptools" +version = "68.0.0" +description = "Easily download, build, install, upgrade, and uninstall Python packages" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "setuptools-68.0.0-py3-none-any.whl", hash = "sha256:11e52c67415a381d10d6b462ced9cfb97066179f0e871399e006c4ab101fc85f"}, + {file = "setuptools-68.0.0.tar.gz", hash = "sha256:baf1fdb41c6da4cd2eae722e135500da913332ab3f2f5c7d33af9b492acb5235"}, +] + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"] +testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pip-run (>=8.8)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] +testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] + +[[package]] +name = "six" +version = "1.16.0" +description = "Python 2 and 3 compatibility utilities" +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" +files = [ + {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, + {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, +] + +[[package]] +name = "smmap" +version = "5.0.0" +description = "A pure Python implementation of a sliding window memory map manager" +category = "dev" +optional = false +python-versions = ">=3.6" +files = [ + {file = "smmap-5.0.0-py3-none-any.whl", hash = "sha256:2aba19d6a040e78d8b09de5c57e96207b09ed71d8e55ce0959eeee6c8e190d94"}, + {file = "smmap-5.0.0.tar.gz", hash = "sha256:c840e62059cd3be204b0c9c9f74be2c09d5648eddd4580d9314c3ecde0b30936"}, +] + +[[package]] +name = "snowballstemmer" +version = "2.2.0" +description = "This package provides 29 stemmers for 28 languages generated from Snowball algorithms." +category = "dev" +optional = false +python-versions = "*" +files = [ + {file = "snowballstemmer-2.2.0-py2.py3-none-any.whl", hash = "sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a"}, + {file = "snowballstemmer-2.2.0.tar.gz", hash = "sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1"}, +] + +[[package]] +name = "soupsieve" +version = "2.4.1" +description = "A modern CSS selector implementation for Beautiful Soup." +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "soupsieve-2.4.1-py3-none-any.whl", hash = "sha256:1c1bfee6819544a3447586c889157365a27e10d88cde3ad3da0cf0ddf646feb8"}, + {file = "soupsieve-2.4.1.tar.gz", hash = "sha256:89d12b2d5dfcd2c9e8c22326da9d9aa9cb3dfab0a83a024f05704076ee8d35ea"}, +] + +[[package]] +name = "sphinx" +version = "7.0.1" +description = "Python documentation generator" +category = "dev" +optional = false +python-versions = ">=3.8" +files = [ + {file = "Sphinx-7.0.1.tar.gz", hash = "sha256:61e025f788c5977d9412587e733733a289e2b9fdc2fef8868ddfbfc4ccfe881d"}, + {file = "sphinx-7.0.1-py3-none-any.whl", hash = "sha256:60c5e04756c1709a98845ed27a2eed7a556af3993afb66e77fec48189f742616"}, +] + +[package.dependencies] +alabaster = ">=0.7,<0.8" +babel = ">=2.9" +colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""} +docutils = ">=0.18.1,<0.21" +imagesize = ">=1.3" +importlib-metadata = {version = ">=4.8", markers = "python_version < \"3.10\""} +Jinja2 = ">=3.0" +packaging = ">=21.0" +Pygments = ">=2.13" +requests = ">=2.25.0" +snowballstemmer = ">=2.0" +sphinxcontrib-applehelp = "*" +sphinxcontrib-devhelp = "*" +sphinxcontrib-htmlhelp = ">=2.0.0" +sphinxcontrib-jsmath = "*" +sphinxcontrib-qthelp = "*" +sphinxcontrib-serializinghtml = ">=1.1.5" + +[package.extras] +docs = ["sphinxcontrib-websupport"] +lint = ["docutils-stubs", "flake8 (>=3.5.0)", "flake8-simplify", "isort", "mypy (>=0.990)", "ruff", "sphinx-lint", "types-requests"] +test = ["cython", "filelock", "html5lib", "pytest (>=4.6)"] + +[[package]] +name = "sphinx-autobuild" +version = "2021.3.14" +description = "Rebuild Sphinx documentation on changes, with live-reload in the browser." +category = "dev" +optional = false +python-versions = ">=3.6" +files = [ + {file = "sphinx-autobuild-2021.3.14.tar.gz", hash = "sha256:de1ca3b66e271d2b5b5140c35034c89e47f263f2cd5db302c9217065f7443f05"}, + {file = "sphinx_autobuild-2021.3.14-py3-none-any.whl", hash = "sha256:8fe8cbfdb75db04475232f05187c776f46f6e9e04cacf1e49ce81bdac649ccac"}, +] + +[package.dependencies] +colorama = "*" +livereload = "*" +sphinx = "*" + +[package.extras] +test = ["pytest", "pytest-cov"] + +[[package]] +name = "sphinx-basic-ng" +version = "1.0.0b2" +description = "A modern skeleton for Sphinx themes." +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "sphinx_basic_ng-1.0.0b2-py3-none-any.whl", hash = "sha256:eb09aedbabfb650607e9b4b68c9d240b90b1e1be221d6ad71d61c52e29f7932b"}, + {file = "sphinx_basic_ng-1.0.0b2.tar.gz", hash = "sha256:9ec55a47c90c8c002b5960c57492ec3021f5193cb26cebc2dc4ea226848651c9"}, +] + +[package.dependencies] +sphinx = ">=4.0" + +[package.extras] +docs = ["furo", "ipython", "myst-parser", "sphinx-copybutton", "sphinx-inline-tabs"] + +[[package]] +name = "sphinx-click" +version = "4.4.0" +description = "Sphinx extension that automatically documents click applications" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "sphinx-click-4.4.0.tar.gz", hash = "sha256:cc67692bd28f482c7f01531c61b64e9d2f069bfcf3d24cbbb51d4a84a749fa48"}, + {file = "sphinx_click-4.4.0-py3-none-any.whl", hash = "sha256:2821c10a68fc9ee6ce7c92fad26540d8d8c8f45e6d7258f0e4fb7529ae8fab49"}, +] + +[package.dependencies] +click = ">=7.0" +docutils = "*" +sphinx = ">=2.0" + +[[package]] +name = "sphinxcontrib-applehelp" +version = "1.0.4" +description = "sphinxcontrib-applehelp is a Sphinx extension which outputs Apple help books" +category = "dev" +optional = false +python-versions = ">=3.8" +files = [ + {file = "sphinxcontrib-applehelp-1.0.4.tar.gz", hash = "sha256:828f867945bbe39817c210a1abfd1bc4895c8b73fcaade56d45357a348a07d7e"}, + {file = "sphinxcontrib_applehelp-1.0.4-py3-none-any.whl", hash = "sha256:29d341f67fb0f6f586b23ad80e072c8e6ad0b48417db2bde114a4c9746feb228"}, +] + +[package.extras] +lint = ["docutils-stubs", "flake8", "mypy"] +test = ["pytest"] + +[[package]] +name = "sphinxcontrib-devhelp" +version = "1.0.2" +description = "sphinxcontrib-devhelp is a sphinx extension which outputs Devhelp document." +category = "dev" +optional = false +python-versions = ">=3.5" +files = [ + {file = "sphinxcontrib-devhelp-1.0.2.tar.gz", hash = "sha256:ff7f1afa7b9642e7060379360a67e9c41e8f3121f2ce9164266f61b9f4b338e4"}, + {file = "sphinxcontrib_devhelp-1.0.2-py2.py3-none-any.whl", hash = "sha256:8165223f9a335cc1af7ffe1ed31d2871f325254c0423bc0c4c7cd1c1e4734a2e"}, +] + +[package.extras] +lint = ["docutils-stubs", "flake8", "mypy"] +test = ["pytest"] + +[[package]] +name = "sphinxcontrib-htmlhelp" +version = "2.0.1" +description = "sphinxcontrib-htmlhelp is a sphinx extension which renders HTML help files" +category = "dev" +optional = false +python-versions = ">=3.8" +files = [ + {file = "sphinxcontrib-htmlhelp-2.0.1.tar.gz", hash = "sha256:0cbdd302815330058422b98a113195c9249825d681e18f11e8b1f78a2f11efff"}, + {file = "sphinxcontrib_htmlhelp-2.0.1-py3-none-any.whl", hash = "sha256:c38cb46dccf316c79de6e5515e1770414b797162b23cd3d06e67020e1d2a6903"}, +] + +[package.extras] +lint = ["docutils-stubs", "flake8", "mypy"] +test = ["html5lib", "pytest"] + +[[package]] +name = "sphinxcontrib-jsmath" +version = "1.0.1" +description = "A sphinx extension which renders display math in HTML via JavaScript" +category = "dev" +optional = false +python-versions = ">=3.5" +files = [ + {file = "sphinxcontrib-jsmath-1.0.1.tar.gz", hash = "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8"}, + {file = "sphinxcontrib_jsmath-1.0.1-py2.py3-none-any.whl", hash = "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178"}, +] + +[package.extras] +test = ["flake8", "mypy", "pytest"] + +[[package]] +name = "sphinxcontrib-qthelp" +version = "1.0.3" +description = "sphinxcontrib-qthelp is a sphinx extension which outputs QtHelp document." +category = "dev" +optional = false +python-versions = ">=3.5" +files = [ + {file = "sphinxcontrib-qthelp-1.0.3.tar.gz", hash = "sha256:4c33767ee058b70dba89a6fc5c1892c0d57a54be67ddd3e7875a18d14cba5a72"}, + {file = "sphinxcontrib_qthelp-1.0.3-py2.py3-none-any.whl", hash = "sha256:bd9fc24bcb748a8d51fd4ecaade681350aa63009a347a8c14e637895444dfab6"}, +] + +[package.extras] +lint = ["docutils-stubs", "flake8", "mypy"] +test = ["pytest"] + +[[package]] +name = "sphinxcontrib-serializinghtml" +version = "1.1.5" +description = "sphinxcontrib-serializinghtml is a sphinx extension which outputs \"serialized\" HTML files (json and pickle)." +category = "dev" +optional = false +python-versions = ">=3.5" +files = [ + {file = "sphinxcontrib-serializinghtml-1.1.5.tar.gz", hash = "sha256:aa5f6de5dfdf809ef505c4895e51ef5c9eac17d0f287933eb49ec495280b6952"}, + {file = "sphinxcontrib_serializinghtml-1.1.5-py2.py3-none-any.whl", hash = "sha256:352a9a00ae864471d3a7ead8d7d79f5fc0b57e8b3f95e9867eb9eb28999b92fd"}, +] + +[package.extras] +lint = ["docutils-stubs", "flake8", "mypy"] +test = ["pytest"] + +[[package]] +name = "stevedore" +version = "5.1.0" +description = "Manage dynamic plugins for Python applications" +category = "dev" +optional = false +python-versions = ">=3.8" +files = [ + {file = "stevedore-5.1.0-py3-none-any.whl", hash = "sha256:8cc040628f3cea5d7128f2e76cf486b2251a4e543c7b938f58d9a377f6694a2d"}, + {file = "stevedore-5.1.0.tar.gz", hash = "sha256:a54534acf9b89bc7ed264807013b505bf07f74dbe4bcfa37d32bd063870b087c"}, +] + +[package.dependencies] +pbr = ">=2.0.0,<2.1.0 || >2.1.0" + +[[package]] +name = "tabulate" +version = "0.9.0" +description = "Pretty-print tabular data" +category = "main" +optional = false +python-versions = ">=3.7" +files = [ + {file = "tabulate-0.9.0-py3-none-any.whl", hash = "sha256:024ca478df22e9340661486f85298cff5f6dcdba14f3813e8830015b9ed1948f"}, + {file = "tabulate-0.9.0.tar.gz", hash = "sha256:0095b12bf5966de529c0feb1fa08671671b3368eec77d7ef7ab114be2c068b3c"}, +] + +[package.extras] +widechars = ["wcwidth"] + +[[package]] +name = "tokenize-rt" +version = "5.1.0" +description = "A wrapper around the stdlib `tokenize` which roundtrips." +category = "dev" +optional = false +python-versions = ">=3.8" +files = [ + {file = "tokenize_rt-5.1.0-py2.py3-none-any.whl", hash = "sha256:9b7bb843e77dd6ed0be5564bfaaba200083911e0497841cd3e9235a6a9794d74"}, + {file = "tokenize_rt-5.1.0.tar.gz", hash = "sha256:08f0c2daa94c4052e53c2fcaa8e32585e6ae9bdfc800974092d031401694e002"}, +] + +[[package]] +name = "tomli" +version = "2.0.1" +description = "A lil' TOML parser" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, + {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, +] + +[[package]] +name = "tornado" +version = "6.3.2" +description = "Tornado is a Python web framework and asynchronous networking library, originally developed at FriendFeed." +category = "dev" +optional = false +python-versions = ">= 3.8" +files = [ + {file = "tornado-6.3.2-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:c367ab6c0393d71171123ca5515c61ff62fe09024fa6bf299cd1339dc9456829"}, + {file = "tornado-6.3.2-cp38-abi3-macosx_10_9_x86_64.whl", hash = "sha256:b46a6ab20f5c7c1cb949c72c1994a4585d2eaa0be4853f50a03b5031e964fc7c"}, + {file = "tornado-6.3.2-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c2de14066c4a38b4ecbbcd55c5cc4b5340eb04f1c5e81da7451ef555859c833f"}, + {file = "tornado-6.3.2-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:05615096845cf50a895026f749195bf0b10b8909f9be672f50b0fe69cba368e4"}, + {file = "tornado-6.3.2-cp38-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5b17b1cf5f8354efa3d37c6e28fdfd9c1c1e5122f2cb56dac121ac61baa47cbe"}, + {file = "tornado-6.3.2-cp38-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:29e71c847a35f6e10ca3b5c2990a52ce38b233019d8e858b755ea6ce4dcdd19d"}, + {file = "tornado-6.3.2-cp38-abi3-musllinux_1_1_i686.whl", hash = "sha256:834ae7540ad3a83199a8da8f9f2d383e3c3d5130a328889e4cc991acc81e87a0"}, + {file = "tornado-6.3.2-cp38-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:6a0848f1aea0d196a7c4f6772197cbe2abc4266f836b0aac76947872cd29b411"}, + {file = "tornado-6.3.2-cp38-abi3-win32.whl", hash = "sha256:7efcbcc30b7c654eb6a8c9c9da787a851c18f8ccd4a5a3a95b05c7accfa068d2"}, + {file = "tornado-6.3.2-cp38-abi3-win_amd64.whl", hash = "sha256:0c325e66c8123c606eea33084976c832aa4e766b7dff8aedd7587ea44a604cdf"}, + {file = "tornado-6.3.2.tar.gz", hash = "sha256:4b927c4f19b71e627b13f3db2324e4ae660527143f9e1f2e2fb404f3a187e2ba"}, +] + +[[package]] +name = "typeguard" +version = "4.0.0" +description = "Run-time type checker for Python" +category = "dev" +optional = false +python-versions = ">=3.7.4" +files = [ + {file = "typeguard-4.0.0-py3-none-any.whl", hash = "sha256:c4a40af0ba8a41077221271b46d0a6d8d46045443e4d887887c69254ca861952"}, + {file = "typeguard-4.0.0.tar.gz", hash = "sha256:194fb3dbcb06ea9caf7088f3befee014de57961689f9c859ac5239b1ef61d987"}, +] + +[package.dependencies] +importlib-metadata = {version = ">=3.6", markers = "python_version < \"3.10\""} +typing-extensions = {version = ">=4.4.0", markers = "python_version < \"3.11\""} + +[package.extras] +doc = ["packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"] +test = ["mypy (>=1.2.0)", "pytest (>=7)"] + +[[package]] +name = "typing-extensions" +version = "4.7.1" +description = "Backported and Experimental Type Hints for Python 3.7+" +category = "main" +optional = false +python-versions = ">=3.7" +files = [ + {file = "typing_extensions-4.7.1-py3-none-any.whl", hash = "sha256:440d5dd3af93b060174bf433bccd69b0babc3b15b1a8dca43789fd7f61514b36"}, + {file = "typing_extensions-4.7.1.tar.gz", hash = "sha256:b75ddc264f0ba5615db7ba217daeb99701ad295353c45f9e95963337ceeeffb2"}, +] + +[[package]] +name = "urllib3" +version = "2.0.3" +description = "HTTP library with thread-safe connection pooling, file post, and more." +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "urllib3-2.0.3-py3-none-any.whl", hash = "sha256:48e7fafa40319d358848e1bc6809b208340fafe2096f1725d05d67443d0483d1"}, + {file = "urllib3-2.0.3.tar.gz", hash = "sha256:bee28b5e56addb8226c96f7f13ac28cb4c301dd5ea8a6ca179c0b9835e032825"}, +] + +[package.extras] +brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] +secure = ["certifi", "cryptography (>=1.9)", "idna (>=2.0.0)", "pyopenssl (>=17.1.0)", "urllib3-secure-extra"] +socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] +zstd = ["zstandard (>=0.18.0)"] + +[[package]] +name = "virtualenv" +version = "20.24.0" +description = "Virtual Python Environment builder" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "virtualenv-20.24.0-py3-none-any.whl", hash = "sha256:18d1b37fc75cc2670625702d76849a91ebd383768b4e91382a8d51be3246049e"}, + {file = "virtualenv-20.24.0.tar.gz", hash = "sha256:e2a7cef9da880d693b933db7654367754f14e20650dc60e8ee7385571f8593a3"}, +] + +[package.dependencies] +distlib = ">=0.3.6,<1" +filelock = ">=3.12,<4" +platformdirs = ">=3.5.1,<4" + +[package.extras] +docs = ["furo (>=2023.5.20)", "proselint (>=0.13)", "sphinx (>=7.0.1)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] +test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.3.1)", "pytest-env (>=0.8.1)", "pytest-freezer (>=0.4.6)", "pytest-mock (>=3.10)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=67.8)", "time-machine (>=2.9)"] + +[[package]] +name = "xdoctest" +version = "1.1.1" +description = "A rewrite of the builtin doctest module" +category = "dev" +optional = false +python-versions = ">=3.6" +files = [ + {file = "xdoctest-1.1.1-py3-none-any.whl", hash = "sha256:d59d4ed91cb92e4430ef0ad1b134a2bef02adff7d2fb9c9f057547bee44081a2"}, + {file = "xdoctest-1.1.1.tar.gz", hash = "sha256:2eac8131bdcdf2781b4e5a62d6de87f044b730cc8db8af142a51bb29c245e779"}, +] + +[package.dependencies] +colorama = {version = "*", optional = true, markers = "platform_system == \"Windows\" and extra == \"colors\""} +Pygments = {version = "*", optional = true, markers = "python_version >= \"3.5.0\" and extra == \"colors\""} +six = "*" + +[package.extras] +all = ["IPython", "IPython", "Pygments", "Pygments", "attrs", "codecov", "colorama", "debugpy", "debugpy", "debugpy", "debugpy", "debugpy", "ipykernel", "ipykernel", "ipython-genutils", "jedi", "jinja2", "jupyter-client", "jupyter-client", "jupyter-core", "nbconvert", "pyflakes", "pytest", "pytest", "pytest", "pytest-cov", "six", "tomli", "typing"] +all-strict = ["IPython (==7.10.0)", "IPython (==7.23.1)", "Pygments (==2.0.0)", "Pygments (==2.4.1)", "attrs (==19.2.0)", "codecov (==2.0.15)", "colorama (==0.4.1)", "debugpy (==1.0.0)", "debugpy (==1.0.0)", "debugpy (==1.0.0)", "debugpy (==1.3.0)", "debugpy (==1.6.0)", "ipykernel (==5.2.0)", "ipykernel (==6.0.0)", "ipython-genutils (==0.2.0)", "jedi (==0.16)", "jinja2 (==3.0.0)", "jupyter-client (==6.1.5)", "jupyter-client (==7.0.0)", "jupyter-core (==4.7.0)", "nbconvert (==6.0.0)", "pyflakes (==2.2.0)", "pytest (==4.6.0)", "pytest (==4.6.0)", "pytest (==6.2.5)", "pytest-cov (==3.0.0)", "six (==1.11.0)", "tomli (==0.2.0)", "typing (==3.7.4)"] +colors = ["Pygments", "Pygments", "colorama"] +jupyter = ["IPython", "IPython", "attrs", "debugpy", "debugpy", "debugpy", "debugpy", "debugpy", "ipykernel", "ipykernel", "ipython-genutils", "jedi", "jinja2", "jupyter-client", "jupyter-client", "jupyter-core", "nbconvert"] +optional = ["IPython", "IPython", "Pygments", "Pygments", "attrs", "colorama", "debugpy", "debugpy", "debugpy", "debugpy", "debugpy", "ipykernel", "ipykernel", "ipython-genutils", "jedi", "jinja2", "jupyter-client", "jupyter-client", "jupyter-core", "nbconvert", "pyflakes", "tomli"] +optional-strict = ["IPython (==7.10.0)", "IPython (==7.23.1)", "Pygments (==2.0.0)", "Pygments (==2.4.1)", "attrs (==19.2.0)", "colorama (==0.4.1)", "debugpy (==1.0.0)", "debugpy (==1.0.0)", "debugpy (==1.0.0)", "debugpy (==1.3.0)", "debugpy (==1.6.0)", "ipykernel (==5.2.0)", "ipykernel (==6.0.0)", "ipython-genutils (==0.2.0)", "jedi (==0.16)", "jinja2 (==3.0.0)", "jupyter-client (==6.1.5)", "jupyter-client (==7.0.0)", "jupyter-core (==4.7.0)", "nbconvert (==6.0.0)", "pyflakes (==2.2.0)", "tomli (==0.2.0)"] +runtime-strict = ["six (==1.11.0)"] +tests = ["codecov", "pytest", "pytest", "pytest", "pytest-cov", "typing"] +tests-binary = ["cmake", "cmake", "ninja", "ninja", "pybind11", "pybind11", "scikit-build", "scikit-build"] +tests-binary-strict = ["cmake (==3.21.2)", "cmake (==3.25.0)", "ninja (==1.10.2)", "ninja (==1.11.1)", "pybind11 (==2.10.3)", "pybind11 (==2.7.1)", "scikit-build (==0.11.1)", "scikit-build (==0.16.1)"] +tests-strict = ["codecov (==2.0.15)", "pytest (==4.6.0)", "pytest (==4.6.0)", "pytest (==6.2.5)", "pytest-cov (==3.0.0)", "typing (==3.7.4)"] + +[[package]] +name = "zipp" +version = "3.16.2" +description = "Backport of pathlib-compatible object wrapper for zip files" +category = "dev" +optional = false +python-versions = ">=3.8" +files = [ + {file = "zipp-3.16.2-py3-none-any.whl", hash = "sha256:679e51dd4403591b2d6838a48de3d283f3d188412a9782faadf845f298736ba0"}, + {file = "zipp-3.16.2.tar.gz", hash = "sha256:ebc15946aa78bd63458992fc81ec3b6f7b1e92d51c35e6de1c3804e73b799147"}, +] + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy (>=0.9.1)", "pytest-ruff"] + +[metadata] +lock-version = "2.0" +python-versions = "^3.8" +content-hash = "b48ff439b61279c7de2ac4e0c906c060a39bd009f417dc6c47302bbe513b3f18" diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 00000000..156cd8dd --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,94 @@ +[tool.poetry] +name = "camelot" +version = "0.20.1" +description = "PDF Table Extraction for Humans." +authors = ["Vinayak Mehta "] +license = "MIT" +readme = "README.md" +homepage = "https://github.com/camelot-dev/camelot" +repository = "https://github.com/camelot-dev/camelot" +documentation = "https://camelot-py.readthedocs.io" +packages = [ + { include = "camelot", from = "." }, +] +classifiers = [ + "Development Status :: 5 - Production/Stable", +] + +[tool.poetry.urls] +Changelog = "https://github.com/camelot-dev/camelot/blob/master/HISTORY.md" + +[tool.poetry.dependencies] +python = "^3.8" +click = ">=8.0.1" +chardet = "^5.1.0" +numpy = "^1.24.2" +openpyxl = "^3.1.0" +pandas = "^1.5.3" +pdfminer-six = "^20221105" +pypdf = "^3.4.0" +tabulate = "^0.9.0" + +[tool.poetry.dev-dependencies] +Pygments = ">=2.10.0" +black = ">=23.1.0" +coverage = {extras = ["toml"], version = ">=6.2"} +flake8 = ">=4.0.1" +flake8-bandit = ">=2.1.2" +flake8-bugbear = ">=21.9.2" +flake8-rst-docstrings = ">=0.2.5" +furo = ">=2021.11.12" +isort = ">=5.10.1" +mypy = ">=0.930" +pep8-naming = ">=0.12.1" +pre-commit = ">=2.16.0" +pre-commit-hooks = ">=4.1.0" +pytest = ">=6.2.5" +pyupgrade = ">=2.29.1" +safety = ">=2.2.3" +sphinx = ">=4.3.2" +sphinx-autobuild = ">=2021.3.14" +sphinx-click = ">=3.0.2" +typeguard = ">=2.13.3" +xdoctest = {extras = ["colors"], version = ">=0.15.10"} +myst-parser = {version = ">=0.16.1"} + +[tool.poetry.scripts] +camelot = "camelot.__main__:main" + +[tool.poetry.group.base.dependencies] +ghostscript = "^0.7" +opencv-python = "^4.7.0.68" + + +[tool.poetry.group.plot.dependencies] +matplotlib = "^3.6.3" + +[tool.coverage.paths] +source = ["camelot", "*/site-packages"] +tests = ["tests", "*/tests"] + +[tool.coverage.run] +branch = true +source = ["camelot", "tests"] + +[tool.coverage.report] +show_missing = true +fail_under = 90 + +[tool.isort] +profile = "black" +force_single_line = true +lines_after_imports = 2 + +[tool.mypy] +strict = true +warn_unreachable = true +pretty = true +show_column_numbers = true +show_error_codes = true +show_error_context = true + +[build-system] +requires = ["poetry-core>=1.0.0"] +build-backend = "poetry.core.masonry.api" diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 2c56c090..00000000 --- a/setup.cfg +++ /dev/null @@ -1,6 +0,0 @@ -[aliases] -test=pytest - -[tool:pytest] -addopts = --verbose --cov-config .coveragerc --cov-report term --cov-report xml --cov=camelot --mpl -python_files = tests/test_*.py diff --git a/setup.py b/setup.py deleted file mode 100644 index b0274d6d..00000000 --- a/setup.py +++ /dev/null @@ -1,91 +0,0 @@ -# -*- coding: utf-8 -*- - -import os -from setuptools import find_packages - - -here = os.path.abspath(os.path.dirname(__file__)) -about = {} -with open(os.path.join(here, "camelot", "__version__.py"), "r") as f: - exec(f.read(), about) - -with open("README.md", "r") as f: - readme = f.read() - - -requires = [ - "chardet>=3.0.4", - "click>=6.7", - "numpy>=1.13.3", - "openpyxl>=2.5.8", - "pandas>=0.23.4", - "pdfminer.six>=20200726", - "pypdf>=3.0.0", - "tabulate>=0.8.9", -] - -base_requires = ["ghostscript>=0.7", "opencv-python>=3.4.2.17", "pdftopng>=0.2.3"] - -plot_requires = [ - "matplotlib>=2.2.3", -] - -dev_requires = [ - "codecov>=2.0.15", - "pytest>=5.4.3", - "pytest-cov>=2.10.0", - "pytest-mpl>=0.11", - "pytest-runner>=5.2", - "Sphinx>=3.1.2", - "sphinx-autobuild>=2021.3.14", -] - -all_requires = base_requires + plot_requires -dev_requires = dev_requires + all_requires - - -def setup_package(): - metadata = dict( - name=about["__title__"], - version=about["__version__"], - description=about["__description__"], - long_description=readme, - long_description_content_type="text/markdown", - url=about["__url__"], - author=about["__author__"], - author_email=about["__author_email__"], - license=about["__license__"], - packages=find_packages(exclude=("tests",)), - install_requires=requires, - extras_require={ - "all": all_requires, - "base": base_requires, - "cv": base_requires, # deprecate - "dev": dev_requires, - "plot": plot_requires, - }, - entry_points={ - "console_scripts": [ - "camelot = camelot.cli:cli", - ], - }, - classifiers=[ - # Trove classifiers - # Full list: https://pypi.python.org/pypi?%3Aaction=list_classifiers - "License :: OSI Approved :: MIT License", - "Programming Language :: Python :: 3.7", - "Programming Language :: Python :: 3.8", - "Programming Language :: Python :: 3.9", - ], - ) - - try: - from setuptools import setup - except ImportError: - from distutils.core import setup - - setup(**metadata) - - -if __name__ == "__main__": - setup_package() diff --git a/tests/__init__.py b/tests/__init__.py index 96c475ed..461ed5b5 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -1,3 +1,4 @@ import matplotlib + matplotlib.use("agg") diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 00000000..17df8c24 --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,24 @@ +import os +import sys + +import pytest + + +skip_on_windows = pytest.mark.skipif( + sys.platform.startswith("win"), + reason="Ghostscript not installed in Windows test environment", +) + +skip_pdftopng = pytest.mark.skip( + reason="Ghostscript not installed in Windows test environment", +) + + +@pytest.fixture +def testdir(): + return os.path.join(os.path.dirname(os.path.abspath(__file__)), "files") + + +@pytest.fixture +def foo_pdf(testdir): + return os.path.join(testdir, "foo.pdf") diff --git a/tests/data.py b/tests/data.py old mode 100755 new mode 100644 index 835fbb41..6d743183 --- a/tests/data.py +++ b/tests/data.py @@ -1,5 +1,4 @@ -# -*- coding: utf-8 -*- - +# noqa data_stream = [ ["States-A", "Revenue", "", "Capital", "", "Total", "Others(1)", "Total"], diff --git a/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-001.json b/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-001.json index a801a86e..b71f0def 100644 --- a/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-001.json +++ b/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-001.json @@ -1 +1,6 @@ -{"numExpectedTables":7,"numCorrectlyDetectedTables":7,"numErroneouslyDetectedTables":0,"expectedFailure":false} \ No newline at end of file +{ + "numExpectedTables": 7, + "numCorrectlyDetectedTables": 7, + "numErroneouslyDetectedTables": 0, + "expectedFailure": false +} diff --git a/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-002.json b/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-002.json index a55497df..db417b53 100644 --- a/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-002.json +++ b/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-002.json @@ -1 +1,6 @@ -{"numExpectedTables":1,"numCorrectlyDetectedTables":1,"numErroneouslyDetectedTables":0,"expectedFailure":false} \ No newline at end of file +{ + "numExpectedTables": 1, + "numCorrectlyDetectedTables": 1, + "numErroneouslyDetectedTables": 0, + "expectedFailure": false +} diff --git a/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-003.json b/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-003.json index 71ae6a77..77371fe9 100644 --- a/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-003.json +++ b/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-003.json @@ -1 +1,6 @@ -{"numExpectedTables":3,"numCorrectlyDetectedTables":3,"numErroneouslyDetectedTables":0,"expectedFailure":false} \ No newline at end of file +{ + "numExpectedTables": 3, + "numCorrectlyDetectedTables": 3, + "numErroneouslyDetectedTables": 0, + "expectedFailure": false +} diff --git a/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-004.json b/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-004.json index 755a6e46..935ba38a 100644 --- a/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-004.json +++ b/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-004.json @@ -1 +1,6 @@ -{"numExpectedTables":12,"numCorrectlyDetectedTables":12,"numErroneouslyDetectedTables":0,"expectedFailure":false} \ No newline at end of file +{ + "numExpectedTables": 12, + "numCorrectlyDetectedTables": 12, + "numErroneouslyDetectedTables": 0, + "expectedFailure": false +} diff --git a/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-005.json b/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-005.json index 1bf5fd29..69f0b666 100644 --- a/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-005.json +++ b/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-005.json @@ -1 +1,6 @@ -{"numExpectedTables":2,"numCorrectlyDetectedTables":2,"numErroneouslyDetectedTables":0,"expectedFailure":false} \ No newline at end of file +{ + "numExpectedTables": 2, + "numCorrectlyDetectedTables": 2, + "numErroneouslyDetectedTables": 0, + "expectedFailure": false +} diff --git a/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-006.json b/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-006.json index 11be9878..261d6f3c 100644 --- a/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-006.json +++ b/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-006.json @@ -1 +1,6 @@ -{"numExpectedTables":4,"numCorrectlyDetectedTables":4,"numErroneouslyDetectedTables":0,"expectedFailure":false} \ No newline at end of file +{ + "numExpectedTables": 4, + "numCorrectlyDetectedTables": 4, + "numErroneouslyDetectedTables": 0, + "expectedFailure": false +} diff --git a/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-007.json b/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-007.json index 4bed3d03..7bc7116c 100644 --- a/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-007.json +++ b/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-007.json @@ -1 +1,6 @@ -{"numExpectedTables":6,"numCorrectlyDetectedTables":6,"numErroneouslyDetectedTables":0,"expectedFailure":false} \ No newline at end of file +{ + "numExpectedTables": 6, + "numCorrectlyDetectedTables": 6, + "numErroneouslyDetectedTables": 0, + "expectedFailure": false +} diff --git a/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-008.json b/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-008.json index a55497df..db417b53 100644 --- a/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-008.json +++ b/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-008.json @@ -1 +1,6 @@ -{"numExpectedTables":1,"numCorrectlyDetectedTables":1,"numErroneouslyDetectedTables":0,"expectedFailure":false} \ No newline at end of file +{ + "numExpectedTables": 1, + "numCorrectlyDetectedTables": 1, + "numErroneouslyDetectedTables": 0, + "expectedFailure": false +} diff --git a/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-009a-str.xml b/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-009a-str.xml index 6bb1f8c0..9a21fab5 100644 --- a/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-009a-str.xml +++ b/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-009a-str.xml @@ -185,7 +185,7 @@ prepared” 3a - + Influence on project diff --git a/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-009a.json b/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-009a.json index a55497df..db417b53 100644 --- a/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-009a.json +++ b/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-009a.json @@ -1 +1,6 @@ -{"numExpectedTables":1,"numCorrectlyDetectedTables":1,"numErroneouslyDetectedTables":0,"expectedFailure":false} \ No newline at end of file +{ + "numExpectedTables": 1, + "numCorrectlyDetectedTables": 1, + "numErroneouslyDetectedTables": 0, + "expectedFailure": false +} diff --git a/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-009b-str.xml b/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-009b-str.xml index 83dc7a29..83555652 100644 --- a/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-009b-str.xml +++ b/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-009b-str.xml @@ -178,7 +178,7 @@ prepared” 3a - + Influence on project diff --git a/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-010.json b/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-010.json index a55497df..db417b53 100644 --- a/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-010.json +++ b/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-010.json @@ -1 +1,6 @@ -{"numExpectedTables":1,"numCorrectlyDetectedTables":1,"numErroneouslyDetectedTables":0,"expectedFailure":false} \ No newline at end of file +{ + "numExpectedTables": 1, + "numCorrectlyDetectedTables": 1, + "numErroneouslyDetectedTables": 0, + "expectedFailure": false +} diff --git a/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-011.json b/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-011.json index 492239e1..8cea7c3e 100644 --- a/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-011.json +++ b/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-011.json @@ -1 +1,6 @@ -{"numExpectedTables":1,"numCorrectlyDetectedTables":1,"numErroneouslyDetectedTables":3,"expectedFailure":true} \ No newline at end of file +{ + "numExpectedTables": 1, + "numCorrectlyDetectedTables": 1, + "numErroneouslyDetectedTables": 3, + "expectedFailure": true +} diff --git a/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-012.json b/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-012.json index b1fa6930..850ac646 100644 --- a/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-012.json +++ b/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-012.json @@ -1 +1,6 @@ -{"numExpectedTables":5,"numCorrectlyDetectedTables":5,"numErroneouslyDetectedTables":1,"expectedFailure":true} \ No newline at end of file +{ + "numExpectedTables": 5, + "numCorrectlyDetectedTables": 5, + "numErroneouslyDetectedTables": 1, + "expectedFailure": true +} diff --git a/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-013.json b/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-013.json index 074b6f59..0e0ada23 100644 --- a/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-013.json +++ b/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-013.json @@ -1 +1,6 @@ -{"numExpectedTables":4,"numCorrectlyDetectedTables":4,"numErroneouslyDetectedTables":1,"expectedFailure":true} \ No newline at end of file +{ + "numExpectedTables": 4, + "numCorrectlyDetectedTables": 4, + "numErroneouslyDetectedTables": 1, + "expectedFailure": true +} diff --git a/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-014.json b/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-014.json index e0d0b7bd..b8465b94 100644 --- a/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-014.json +++ b/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-014.json @@ -1 +1,6 @@ -{"numExpectedTables":1,"numCorrectlyDetectedTables":0,"numErroneouslyDetectedTables":1,"expectedFailure":true} \ No newline at end of file +{ + "numExpectedTables": 1, + "numCorrectlyDetectedTables": 0, + "numErroneouslyDetectedTables": 1, + "expectedFailure": true +} diff --git a/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-015.json b/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-015.json index fc890104..90012dd3 100644 --- a/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-015.json +++ b/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-015.json @@ -1 +1,6 @@ -{"numExpectedTables":5,"numCorrectlyDetectedTables":2,"numErroneouslyDetectedTables":2,"expectedFailure":true} \ No newline at end of file +{ + "numExpectedTables": 5, + "numCorrectlyDetectedTables": 2, + "numErroneouslyDetectedTables": 2, + "expectedFailure": true +} diff --git a/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-016.json b/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-016.json index a55497df..db417b53 100644 --- a/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-016.json +++ b/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-016.json @@ -1 +1,6 @@ -{"numExpectedTables":1,"numCorrectlyDetectedTables":1,"numErroneouslyDetectedTables":0,"expectedFailure":false} \ No newline at end of file +{ + "numExpectedTables": 1, + "numCorrectlyDetectedTables": 1, + "numErroneouslyDetectedTables": 0, + "expectedFailure": false +} diff --git a/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-017.json b/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-017.json index 16d936d5..17bd403b 100644 --- a/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-017.json +++ b/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-017.json @@ -1 +1,6 @@ -{"numExpectedTables":1,"numCorrectlyDetectedTables":1,"numErroneouslyDetectedTables":1,"expectedFailure":true} \ No newline at end of file +{ + "numExpectedTables": 1, + "numCorrectlyDetectedTables": 1, + "numErroneouslyDetectedTables": 1, + "expectedFailure": true +} diff --git a/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-018.json b/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-018.json index 1bf5fd29..69f0b666 100644 --- a/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-018.json +++ b/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-018.json @@ -1 +1,6 @@ -{"numExpectedTables":2,"numCorrectlyDetectedTables":2,"numErroneouslyDetectedTables":0,"expectedFailure":false} \ No newline at end of file +{ + "numExpectedTables": 2, + "numCorrectlyDetectedTables": 2, + "numErroneouslyDetectedTables": 0, + "expectedFailure": false +} diff --git a/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-019.json b/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-019.json index a55497df..db417b53 100644 --- a/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-019.json +++ b/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-019.json @@ -1 +1,6 @@ -{"numExpectedTables":1,"numCorrectlyDetectedTables":1,"numErroneouslyDetectedTables":0,"expectedFailure":false} \ No newline at end of file +{ + "numExpectedTables": 1, + "numCorrectlyDetectedTables": 1, + "numErroneouslyDetectedTables": 0, + "expectedFailure": false +} diff --git a/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-020.json b/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-020.json index 71ae6a77..77371fe9 100644 --- a/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-020.json +++ b/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-020.json @@ -1 +1,6 @@ -{"numExpectedTables":3,"numCorrectlyDetectedTables":3,"numErroneouslyDetectedTables":0,"expectedFailure":false} \ No newline at end of file +{ + "numExpectedTables": 3, + "numCorrectlyDetectedTables": 3, + "numErroneouslyDetectedTables": 0, + "expectedFailure": false +} diff --git a/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-021.json b/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-021.json index 1bf5fd29..69f0b666 100644 --- a/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-021.json +++ b/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-021.json @@ -1 +1,6 @@ -{"numExpectedTables":2,"numCorrectlyDetectedTables":2,"numErroneouslyDetectedTables":0,"expectedFailure":false} \ No newline at end of file +{ + "numExpectedTables": 2, + "numCorrectlyDetectedTables": 2, + "numErroneouslyDetectedTables": 0, + "expectedFailure": false +} diff --git a/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-022.json b/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-022.json index a55497df..db417b53 100644 --- a/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-022.json +++ b/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-022.json @@ -1 +1,6 @@ -{"numExpectedTables":1,"numCorrectlyDetectedTables":1,"numErroneouslyDetectedTables":0,"expectedFailure":false} \ No newline at end of file +{ + "numExpectedTables": 1, + "numCorrectlyDetectedTables": 1, + "numErroneouslyDetectedTables": 0, + "expectedFailure": false +} diff --git a/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-023.json b/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-023.json index a55497df..db417b53 100644 --- a/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-023.json +++ b/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-023.json @@ -1 +1,6 @@ -{"numExpectedTables":1,"numCorrectlyDetectedTables":1,"numErroneouslyDetectedTables":0,"expectedFailure":false} \ No newline at end of file +{ + "numExpectedTables": 1, + "numCorrectlyDetectedTables": 1, + "numErroneouslyDetectedTables": 0, + "expectedFailure": false +} diff --git a/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-024.json b/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-024.json index a55497df..db417b53 100644 --- a/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-024.json +++ b/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-024.json @@ -1 +1,6 @@ -{"numExpectedTables":1,"numCorrectlyDetectedTables":1,"numErroneouslyDetectedTables":0,"expectedFailure":false} \ No newline at end of file +{ + "numExpectedTables": 1, + "numCorrectlyDetectedTables": 1, + "numErroneouslyDetectedTables": 0, + "expectedFailure": false +} diff --git a/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-025.json b/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-025.json index 4d74e0e7..5df8c076 100644 --- a/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-025.json +++ b/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-025.json @@ -1 +1,6 @@ -{"numExpectedTables":5,"numCorrectlyDetectedTables":5,"numErroneouslyDetectedTables":0,"expectedFailure":false} \ No newline at end of file +{ + "numExpectedTables": 5, + "numCorrectlyDetectedTables": 5, + "numErroneouslyDetectedTables": 0, + "expectedFailure": false +} diff --git a/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-026.json b/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-026.json index 71ae6a77..77371fe9 100644 --- a/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-026.json +++ b/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-026.json @@ -1 +1,6 @@ -{"numExpectedTables":3,"numCorrectlyDetectedTables":3,"numErroneouslyDetectedTables":0,"expectedFailure":false} \ No newline at end of file +{ + "numExpectedTables": 3, + "numCorrectlyDetectedTables": 3, + "numErroneouslyDetectedTables": 0, + "expectedFailure": false +} diff --git a/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-027.json b/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-027.json index a55497df..db417b53 100644 --- a/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-027.json +++ b/tests/files/tabula/icdar2013-dataset/competition-dataset-eu/eu-027.json @@ -1 +1,6 @@ -{"numExpectedTables":1,"numCorrectlyDetectedTables":1,"numErroneouslyDetectedTables":0,"expectedFailure":false} \ No newline at end of file +{ + "numExpectedTables": 1, + "numCorrectlyDetectedTables": 1, + "numErroneouslyDetectedTables": 0, + "expectedFailure": false +} diff --git a/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-001.json b/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-001.json index a2697933..b424a76f 100644 --- a/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-001.json +++ b/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-001.json @@ -1 +1,6 @@ -{"numExpectedTables":2,"numCorrectlyDetectedTables":2,"numErroneouslyDetectedTables":2,"expectedFailure":true} \ No newline at end of file +{ + "numExpectedTables": 2, + "numCorrectlyDetectedTables": 2, + "numErroneouslyDetectedTables": 2, + "expectedFailure": true +} diff --git a/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-002.json b/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-002.json index 1bf5fd29..69f0b666 100644 --- a/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-002.json +++ b/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-002.json @@ -1 +1,6 @@ -{"numExpectedTables":2,"numCorrectlyDetectedTables":2,"numErroneouslyDetectedTables":0,"expectedFailure":false} \ No newline at end of file +{ + "numExpectedTables": 2, + "numCorrectlyDetectedTables": 2, + "numErroneouslyDetectedTables": 0, + "expectedFailure": false +} diff --git a/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-003.json b/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-003.json index a55497df..db417b53 100644 --- a/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-003.json +++ b/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-003.json @@ -1 +1,6 @@ -{"numExpectedTables":1,"numCorrectlyDetectedTables":1,"numErroneouslyDetectedTables":0,"expectedFailure":false} \ No newline at end of file +{ + "numExpectedTables": 1, + "numCorrectlyDetectedTables": 1, + "numErroneouslyDetectedTables": 0, + "expectedFailure": false +} diff --git a/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-004.json b/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-004.json index a55497df..db417b53 100644 --- a/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-004.json +++ b/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-004.json @@ -1 +1,6 @@ -{"numExpectedTables":1,"numCorrectlyDetectedTables":1,"numErroneouslyDetectedTables":0,"expectedFailure":false} \ No newline at end of file +{ + "numExpectedTables": 1, + "numCorrectlyDetectedTables": 1, + "numErroneouslyDetectedTables": 0, + "expectedFailure": false +} diff --git a/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-005.json b/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-005.json index a55497df..db417b53 100644 --- a/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-005.json +++ b/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-005.json @@ -1 +1,6 @@ -{"numExpectedTables":1,"numCorrectlyDetectedTables":1,"numErroneouslyDetectedTables":0,"expectedFailure":false} \ No newline at end of file +{ + "numExpectedTables": 1, + "numCorrectlyDetectedTables": 1, + "numErroneouslyDetectedTables": 0, + "expectedFailure": false +} diff --git a/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-006.json b/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-006.json index a55497df..db417b53 100644 --- a/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-006.json +++ b/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-006.json @@ -1 +1,6 @@ -{"numExpectedTables":1,"numCorrectlyDetectedTables":1,"numErroneouslyDetectedTables":0,"expectedFailure":false} \ No newline at end of file +{ + "numExpectedTables": 1, + "numCorrectlyDetectedTables": 1, + "numErroneouslyDetectedTables": 0, + "expectedFailure": false +} diff --git a/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-007.json b/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-007.json index 1bf5fd29..69f0b666 100644 --- a/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-007.json +++ b/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-007.json @@ -1 +1,6 @@ -{"numExpectedTables":2,"numCorrectlyDetectedTables":2,"numErroneouslyDetectedTables":0,"expectedFailure":false} \ No newline at end of file +{ + "numExpectedTables": 2, + "numCorrectlyDetectedTables": 2, + "numErroneouslyDetectedTables": 0, + "expectedFailure": false +} diff --git a/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-008.json b/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-008.json index 1bf5fd29..69f0b666 100644 --- a/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-008.json +++ b/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-008.json @@ -1 +1,6 @@ -{"numExpectedTables":2,"numCorrectlyDetectedTables":2,"numErroneouslyDetectedTables":0,"expectedFailure":false} \ No newline at end of file +{ + "numExpectedTables": 2, + "numCorrectlyDetectedTables": 2, + "numErroneouslyDetectedTables": 0, + "expectedFailure": false +} diff --git a/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-009.json b/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-009.json index a55497df..db417b53 100644 --- a/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-009.json +++ b/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-009.json @@ -1 +1,6 @@ -{"numExpectedTables":1,"numCorrectlyDetectedTables":1,"numErroneouslyDetectedTables":0,"expectedFailure":false} \ No newline at end of file +{ + "numExpectedTables": 1, + "numCorrectlyDetectedTables": 1, + "numErroneouslyDetectedTables": 0, + "expectedFailure": false +} diff --git a/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-010.json b/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-010.json index a55497df..db417b53 100644 --- a/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-010.json +++ b/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-010.json @@ -1 +1,6 @@ -{"numExpectedTables":1,"numCorrectlyDetectedTables":1,"numErroneouslyDetectedTables":0,"expectedFailure":false} \ No newline at end of file +{ + "numExpectedTables": 1, + "numCorrectlyDetectedTables": 1, + "numErroneouslyDetectedTables": 0, + "expectedFailure": false +} diff --git a/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-011a.json b/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-011a.json index 1bf5fd29..69f0b666 100644 --- a/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-011a.json +++ b/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-011a.json @@ -1 +1,6 @@ -{"numExpectedTables":2,"numCorrectlyDetectedTables":2,"numErroneouslyDetectedTables":0,"expectedFailure":false} \ No newline at end of file +{ + "numExpectedTables": 2, + "numCorrectlyDetectedTables": 2, + "numErroneouslyDetectedTables": 0, + "expectedFailure": false +} diff --git a/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-012.json b/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-012.json index a55497df..db417b53 100644 --- a/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-012.json +++ b/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-012.json @@ -1 +1,6 @@ -{"numExpectedTables":1,"numCorrectlyDetectedTables":1,"numErroneouslyDetectedTables":0,"expectedFailure":false} \ No newline at end of file +{ + "numExpectedTables": 1, + "numCorrectlyDetectedTables": 1, + "numErroneouslyDetectedTables": 0, + "expectedFailure": false +} diff --git a/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-013.json b/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-013.json index a55497df..db417b53 100644 --- a/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-013.json +++ b/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-013.json @@ -1 +1,6 @@ -{"numExpectedTables":1,"numCorrectlyDetectedTables":1,"numErroneouslyDetectedTables":0,"expectedFailure":false} \ No newline at end of file +{ + "numExpectedTables": 1, + "numCorrectlyDetectedTables": 1, + "numErroneouslyDetectedTables": 0, + "expectedFailure": false +} diff --git a/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-014-str.xml b/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-014-str.xml index b64c9130..326f39ec 100644 --- a/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-014-str.xml +++ b/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-014-str.xml @@ -351,4 +351,4 @@ Agreeing - + diff --git a/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-014.json b/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-014.json index 1bf5fd29..69f0b666 100644 --- a/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-014.json +++ b/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-014.json @@ -1 +1,6 @@ -{"numExpectedTables":2,"numCorrectlyDetectedTables":2,"numErroneouslyDetectedTables":0,"expectedFailure":false} \ No newline at end of file +{ + "numExpectedTables": 2, + "numCorrectlyDetectedTables": 2, + "numErroneouslyDetectedTables": 0, + "expectedFailure": false +} diff --git a/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-015.json b/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-015.json index 1bf5fd29..69f0b666 100644 --- a/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-015.json +++ b/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-015.json @@ -1 +1,6 @@ -{"numExpectedTables":2,"numCorrectlyDetectedTables":2,"numErroneouslyDetectedTables":0,"expectedFailure":false} \ No newline at end of file +{ + "numExpectedTables": 2, + "numCorrectlyDetectedTables": 2, + "numErroneouslyDetectedTables": 0, + "expectedFailure": false +} diff --git a/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-016.json b/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-016.json index a55497df..db417b53 100644 --- a/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-016.json +++ b/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-016.json @@ -1 +1,6 @@ -{"numExpectedTables":1,"numCorrectlyDetectedTables":1,"numErroneouslyDetectedTables":0,"expectedFailure":false} \ No newline at end of file +{ + "numExpectedTables": 1, + "numCorrectlyDetectedTables": 1, + "numErroneouslyDetectedTables": 0, + "expectedFailure": false +} diff --git a/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-017.json b/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-017.json index 4bed3d03..7bc7116c 100644 --- a/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-017.json +++ b/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-017.json @@ -1 +1,6 @@ -{"numExpectedTables":6,"numCorrectlyDetectedTables":6,"numErroneouslyDetectedTables":0,"expectedFailure":false} \ No newline at end of file +{ + "numExpectedTables": 6, + "numCorrectlyDetectedTables": 6, + "numErroneouslyDetectedTables": 0, + "expectedFailure": false +} diff --git a/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-018.json b/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-018.json index ed2b5b39..0de01ef8 100644 --- a/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-018.json +++ b/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-018.json @@ -1 +1,6 @@ -{"numExpectedTables":7,"numCorrectlyDetectedTables":6,"numErroneouslyDetectedTables":1,"expectedFailure":true} \ No newline at end of file +{ + "numExpectedTables": 7, + "numCorrectlyDetectedTables": 6, + "numErroneouslyDetectedTables": 1, + "expectedFailure": true +} diff --git a/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-019.json b/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-019.json index 4279ae6b..b6eaa91d 100644 --- a/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-019.json +++ b/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-019.json @@ -1 +1,6 @@ -{"numExpectedTables":4,"numCorrectlyDetectedTables":2,"numErroneouslyDetectedTables":2,"expectedFailure":true} \ No newline at end of file +{ + "numExpectedTables": 4, + "numCorrectlyDetectedTables": 2, + "numErroneouslyDetectedTables": 2, + "expectedFailure": true +} diff --git a/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-020.json b/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-020.json index 11be9878..261d6f3c 100644 --- a/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-020.json +++ b/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-020.json @@ -1 +1,6 @@ -{"numExpectedTables":4,"numCorrectlyDetectedTables":4,"numErroneouslyDetectedTables":0,"expectedFailure":false} \ No newline at end of file +{ + "numExpectedTables": 4, + "numCorrectlyDetectedTables": 4, + "numErroneouslyDetectedTables": 0, + "expectedFailure": false +} diff --git a/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-021.json b/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-021.json index 1bf5fd29..69f0b666 100644 --- a/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-021.json +++ b/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-021.json @@ -1 +1,6 @@ -{"numExpectedTables":2,"numCorrectlyDetectedTables":2,"numErroneouslyDetectedTables":0,"expectedFailure":false} \ No newline at end of file +{ + "numExpectedTables": 2, + "numCorrectlyDetectedTables": 2, + "numErroneouslyDetectedTables": 0, + "expectedFailure": false +} diff --git a/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-022.json b/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-022.json index a55497df..db417b53 100644 --- a/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-022.json +++ b/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-022.json @@ -1 +1,6 @@ -{"numExpectedTables":1,"numCorrectlyDetectedTables":1,"numErroneouslyDetectedTables":0,"expectedFailure":false} \ No newline at end of file +{ + "numExpectedTables": 1, + "numCorrectlyDetectedTables": 1, + "numErroneouslyDetectedTables": 0, + "expectedFailure": false +} diff --git a/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-023.json b/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-023.json index 79301b7d..feb114b1 100644 --- a/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-023.json +++ b/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-023.json @@ -1 +1,6 @@ -{"numExpectedTables":1,"numCorrectlyDetectedTables":1,"numErroneouslyDetectedTables":4,"expectedFailure":true} \ No newline at end of file +{ + "numExpectedTables": 1, + "numCorrectlyDetectedTables": 1, + "numErroneouslyDetectedTables": 4, + "expectedFailure": true +} diff --git a/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-024.json b/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-024.json index e700926c..dab08e97 100644 --- a/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-024.json +++ b/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-024.json @@ -1 +1,6 @@ -{"numExpectedTables":4,"numCorrectlyDetectedTables":4,"numErroneouslyDetectedTables":2,"expectedFailure":true} \ No newline at end of file +{ + "numExpectedTables": 4, + "numCorrectlyDetectedTables": 4, + "numErroneouslyDetectedTables": 2, + "expectedFailure": true +} diff --git a/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-025-str.xml b/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-025-str.xml index 6fdb985e..7adaf9a0 100644 --- a/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-025-str.xml +++ b/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-025-str.xml @@ -1,7 +1,7 @@ - + @@ -417,7 +417,7 @@
- + @@ -1331,7 +1331,7 @@
- + @@ -1843,7 +1843,7 @@ group
- + @@ -2759,7 +2759,7 @@ group
- + @@ -3271,7 +3271,7 @@ group
- + diff --git a/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-025.json b/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-025.json index f783d0e7..c8351c71 100644 --- a/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-025.json +++ b/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-025.json @@ -1 +1,6 @@ -{"numExpectedTables":6,"numCorrectlyDetectedTables":2,"numErroneouslyDetectedTables":3,"expectedFailure":true} \ No newline at end of file +{ + "numExpectedTables": 6, + "numCorrectlyDetectedTables": 2, + "numErroneouslyDetectedTables": 3, + "expectedFailure": true +} diff --git a/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-026.json b/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-026.json index a55497df..db417b53 100644 --- a/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-026.json +++ b/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-026.json @@ -1 +1,6 @@ -{"numExpectedTables":1,"numCorrectlyDetectedTables":1,"numErroneouslyDetectedTables":0,"expectedFailure":false} \ No newline at end of file +{ + "numExpectedTables": 1, + "numCorrectlyDetectedTables": 1, + "numErroneouslyDetectedTables": 0, + "expectedFailure": false +} diff --git a/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-027.json b/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-027.json index 1bf5fd29..69f0b666 100644 --- a/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-027.json +++ b/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-027.json @@ -1 +1,6 @@ -{"numExpectedTables":2,"numCorrectlyDetectedTables":2,"numErroneouslyDetectedTables":0,"expectedFailure":false} \ No newline at end of file +{ + "numExpectedTables": 2, + "numCorrectlyDetectedTables": 2, + "numErroneouslyDetectedTables": 0, + "expectedFailure": false +} diff --git a/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-028.json b/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-028.json index a2697933..b424a76f 100644 --- a/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-028.json +++ b/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-028.json @@ -1 +1,6 @@ -{"numExpectedTables":2,"numCorrectlyDetectedTables":2,"numErroneouslyDetectedTables":2,"expectedFailure":true} \ No newline at end of file +{ + "numExpectedTables": 2, + "numCorrectlyDetectedTables": 2, + "numErroneouslyDetectedTables": 2, + "expectedFailure": true +} diff --git a/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-029.json b/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-029.json index a55497df..db417b53 100644 --- a/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-029.json +++ b/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-029.json @@ -1 +1,6 @@ -{"numExpectedTables":1,"numCorrectlyDetectedTables":1,"numErroneouslyDetectedTables":0,"expectedFailure":false} \ No newline at end of file +{ + "numExpectedTables": 1, + "numCorrectlyDetectedTables": 1, + "numErroneouslyDetectedTables": 0, + "expectedFailure": false +} diff --git a/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-030.json b/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-030.json index a55497df..db417b53 100644 --- a/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-030.json +++ b/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-030.json @@ -1 +1,6 @@ -{"numExpectedTables":1,"numCorrectlyDetectedTables":1,"numErroneouslyDetectedTables":0,"expectedFailure":false} \ No newline at end of file +{ + "numExpectedTables": 1, + "numCorrectlyDetectedTables": 1, + "numErroneouslyDetectedTables": 0, + "expectedFailure": false +} diff --git a/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-031a.json b/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-031a.json index a55497df..db417b53 100644 --- a/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-031a.json +++ b/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-031a.json @@ -1 +1,6 @@ -{"numExpectedTables":1,"numCorrectlyDetectedTables":1,"numErroneouslyDetectedTables":0,"expectedFailure":false} \ No newline at end of file +{ + "numExpectedTables": 1, + "numCorrectlyDetectedTables": 1, + "numErroneouslyDetectedTables": 0, + "expectedFailure": false +} diff --git a/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-032.json b/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-032.json index a55497df..db417b53 100644 --- a/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-032.json +++ b/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-032.json @@ -1 +1,6 @@ -{"numExpectedTables":1,"numCorrectlyDetectedTables":1,"numErroneouslyDetectedTables":0,"expectedFailure":false} \ No newline at end of file +{ + "numExpectedTables": 1, + "numCorrectlyDetectedTables": 1, + "numErroneouslyDetectedTables": 0, + "expectedFailure": false +} diff --git a/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-033.json b/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-033.json index 8bca2b65..6dc747e6 100644 --- a/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-033.json +++ b/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-033.json @@ -1 +1,6 @@ -{"numExpectedTables":3,"numCorrectlyDetectedTables":1,"numErroneouslyDetectedTables":2,"expectedFailure":true} \ No newline at end of file +{ + "numExpectedTables": 3, + "numCorrectlyDetectedTables": 1, + "numErroneouslyDetectedTables": 2, + "expectedFailure": true +} diff --git a/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-034.json b/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-034.json index eb903a1d..50c30d65 100644 --- a/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-034.json +++ b/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-034.json @@ -1 +1,6 @@ -{"numExpectedTables":2,"numCorrectlyDetectedTables":0,"numErroneouslyDetectedTables":1,"expectedFailure":true} \ No newline at end of file +{ + "numExpectedTables": 2, + "numCorrectlyDetectedTables": 0, + "numErroneouslyDetectedTables": 1, + "expectedFailure": true +} diff --git a/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-035a.json b/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-035a.json index 71ae6a77..77371fe9 100644 --- a/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-035a.json +++ b/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-035a.json @@ -1 +1,6 @@ -{"numExpectedTables":3,"numCorrectlyDetectedTables":3,"numErroneouslyDetectedTables":0,"expectedFailure":false} \ No newline at end of file +{ + "numExpectedTables": 3, + "numCorrectlyDetectedTables": 3, + "numErroneouslyDetectedTables": 0, + "expectedFailure": false +} diff --git a/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-036.json b/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-036.json index a55497df..db417b53 100644 --- a/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-036.json +++ b/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-036.json @@ -1 +1,6 @@ -{"numExpectedTables":1,"numCorrectlyDetectedTables":1,"numErroneouslyDetectedTables":0,"expectedFailure":false} \ No newline at end of file +{ + "numExpectedTables": 1, + "numCorrectlyDetectedTables": 1, + "numErroneouslyDetectedTables": 0, + "expectedFailure": false +} diff --git a/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-037.json b/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-037.json index 8dd87c33..8047a2c2 100644 --- a/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-037.json +++ b/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-037.json @@ -1 +1,6 @@ -{"numExpectedTables":1,"numCorrectlyDetectedTables":0,"numErroneouslyDetectedTables":3,"expectedFailure":true} \ No newline at end of file +{ + "numExpectedTables": 1, + "numCorrectlyDetectedTables": 0, + "numErroneouslyDetectedTables": 3, + "expectedFailure": true +} diff --git a/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-038.json b/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-038.json index a55497df..db417b53 100644 --- a/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-038.json +++ b/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-038.json @@ -1 +1,6 @@ -{"numExpectedTables":1,"numCorrectlyDetectedTables":1,"numErroneouslyDetectedTables":0,"expectedFailure":false} \ No newline at end of file +{ + "numExpectedTables": 1, + "numCorrectlyDetectedTables": 1, + "numErroneouslyDetectedTables": 0, + "expectedFailure": false +} diff --git a/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-039.json b/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-039.json index a55497df..db417b53 100644 --- a/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-039.json +++ b/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-039.json @@ -1 +1,6 @@ -{"numExpectedTables":1,"numCorrectlyDetectedTables":1,"numErroneouslyDetectedTables":0,"expectedFailure":false} \ No newline at end of file +{ + "numExpectedTables": 1, + "numCorrectlyDetectedTables": 1, + "numErroneouslyDetectedTables": 0, + "expectedFailure": false +} diff --git a/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-040.json b/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-040.json index a55497df..db417b53 100644 --- a/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-040.json +++ b/tests/files/tabula/icdar2013-dataset/competition-dataset-us/us-040.json @@ -1 +1,6 @@ -{"numExpectedTables":1,"numCorrectlyDetectedTables":1,"numErroneouslyDetectedTables":0,"expectedFailure":false} \ No newline at end of file +{ + "numExpectedTables": 1, + "numCorrectlyDetectedTables": 1, + "numErroneouslyDetectedTables": 0, + "expectedFailure": false +} diff --git a/tests/test_cli.py b/tests/test_cli.py old mode 100755 new mode 100644 index 7d29e10e..27ac41c5 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -1,22 +1,10 @@ -# -*- coding: utf-8 -*- - import os -import sys -import pytest from click.testing import CliRunner from camelot.cli import cli from camelot.utils import TemporaryDirectory - - -testdir = os.path.dirname(os.path.abspath(__file__)) -testdir = os.path.join(testdir, "files") - -skip_on_windows = pytest.mark.skipif( - sys.platform.startswith("win"), - reason="Ghostscript not installed in Windows test environment", -) +from tests.conftest import skip_on_windows def test_help_output(): @@ -34,7 +22,7 @@ def test_help_output(): @skip_on_windows -def test_cli_lattice(): +def test_cli_lattice(testdir): with TemporaryDirectory() as tempdir: infile = os.path.join(testdir, "foo.pdf") outfile = os.path.join(tempdir, "foo.csv") @@ -54,7 +42,7 @@ def test_cli_lattice(): assert format_error in result.output -def test_cli_stream(): +def test_cli_stream(testdir): with TemporaryDirectory() as tempdir: infile = os.path.join(testdir, "budget.pdf") outfile = os.path.join(tempdir, "budget.csv") @@ -74,7 +62,7 @@ def test_cli_stream(): assert format_error in result.output -def test_cli_password(): +def test_cli_password(testdir): with TemporaryDirectory() as tempdir: infile = os.path.join(testdir, "health_protected.pdf") outfile = os.path.join(tempdir, "health_protected.csv") @@ -119,7 +107,7 @@ def test_cli_password(): assert output_error in str(result.exception) -def test_cli_output_format(): +def test_cli_output_format(testdir): with TemporaryDirectory() as tempdir: infile = os.path.join(testdir, "health.pdf") @@ -174,7 +162,7 @@ def test_cli_output_format(): assert result.exit_code == 0, f"Output: {result.output}" -def test_cli_quiet(): +def test_cli_quiet(testdir): with TemporaryDirectory() as tempdir: infile = os.path.join(testdir, "empty.pdf") outfile = os.path.join(tempdir, "empty.csv") diff --git a/tests/test_common.py b/tests/test_common.py index 5d0054b8..ca9910d0 100644 --- a/tests/test_common.py +++ b/tests/test_common.py @@ -1,28 +1,19 @@ -# -*- coding: utf-8 -*- - import os -import sys +from pathlib import Path -import pytest import pandas as pd from pandas.testing import assert_frame_equal import camelot -from camelot.io import PDFHandler -from camelot.core import Table, TableList from camelot.__version__ import generate_version -from camelot.backends import ImageConversionBackend +from camelot.core import Table +from camelot.core import TableList +from camelot.io import PDFHandler +from .conftest import skip_on_windows +from .conftest import skip_pdftopng from .data import * -testdir = os.path.dirname(os.path.abspath(__file__)) -testdir = os.path.join(testdir, "files") - -skip_on_windows = pytest.mark.skipif( - sys.platform.startswith("win"), - reason="Ghostscript not installed in Windows test environment", -) - def test_version_generation(): version = (0, 7, 3) @@ -40,7 +31,7 @@ def test_version_generation_with_prerelease_revision(): @skip_on_windows -def test_parsing_report(): +def test_parsing_report(testdir): parsing_report = {"accuracy": 99.02, "whitespace": 12.24, "order": 1, "page": 1} filename = os.path.join(testdir, "foo.pdf") @@ -48,7 +39,7 @@ def test_parsing_report(): assert tables[0].parsing_report == parsing_report -def test_password(): +def test_password(testdir): df = pd.DataFrame(data_stream) filename = os.path.join(testdir, "health_protected.pdf") @@ -59,7 +50,8 @@ def test_password(): assert_frame_equal(df, tables[0].df) -def test_repr_poppler(): +@skip_pdftopng +def test_repr_poppler(testdir): filename = os.path.join(testdir, "foo.pdf") tables = camelot.read_pdf(filename, backend="poppler") assert repr(tables) == "" @@ -68,7 +60,7 @@ def test_repr_poppler(): @skip_on_windows -def test_repr_ghostscript(): +def test_repr_ghostscript(testdir): filename = os.path.join(testdir, "foo.pdf") tables = camelot.read_pdf(filename, backend="ghostscript") assert repr(tables) == "" @@ -76,6 +68,7 @@ def test_repr_ghostscript(): assert repr(tables[0].cells[0][0]) == "" +@skip_pdftopng def test_url_poppler(): url = "https://camelot-py.readthedocs.io/en/master/_static/pdf/foo.pdf" tables = camelot.read_pdf(url, backend="poppler") @@ -85,7 +78,7 @@ def test_url_poppler(): @skip_on_windows -def test_url_ghostscript(): +def test_url_ghostscript(testdir): url = "https://camelot-py.readthedocs.io/en/master/_static/pdf/foo.pdf" tables = camelot.read_pdf(url, backend="ghostscript") assert repr(tables) == "" @@ -93,6 +86,7 @@ def test_url_ghostscript(): assert repr(tables[0].cells[0][0]) == "" +@skip_pdftopng def test_pages_poppler(): url = "https://camelot-py.readthedocs.io/en/master/_static/pdf/foo.pdf" tables = camelot.read_pdf(url, backend="poppler") @@ -155,7 +149,7 @@ def _make_table(page, order): ] -def test_handler_pages_generator(): +def test_handler_pages_generator(testdir): filename = os.path.join(testdir, "foo.pdf") handler = PDFHandler(filename) @@ -172,3 +166,25 @@ def test_handler_pages_generator(): handler = PDFHandler(filename) assert handler._get_pages("1,2,5-10") == [1, 2, 5, 6, 7, 8, 9, 10] + + handler = PDFHandler( + os.path.join(testdir, "health_protected.pdf"), password="ownerpass" + ) + + assert handler._get_pages("all") == [1] + + +def test_handler_with_stream(testdir): + filename = os.path.join(testdir, "foo.pdf") + + with open(filename, "rb") as f: + handler = PDFHandler(f) + assert handler._get_pages("1") == [1] + + +def test_handler_with_pathlib(testdir): + filename = Path(os.path.join(testdir, "foo.pdf")) + + with open(filename, "rb") as f: + handler = PDFHandler(f) + assert handler._get_pages("1") == [1] diff --git a/tests/test_errors.py b/tests/test_errors.py old mode 100755 new mode 100644 index f6810c91..eaa720ec --- a/tests/test_errors.py +++ b/tests/test_errors.py @@ -1,115 +1,103 @@ -# -*- coding: utf-8 -*- - import os -import sys import warnings import pytest import camelot +from tests.conftest import skip_on_windows -testdir = os.path.dirname(os.path.abspath(__file__)) -testdir = os.path.join(testdir, "files") -filename = os.path.join(testdir, "foo.pdf") - -skip_on_windows = pytest.mark.skipif( - sys.platform.startswith("win"), - reason="Ghostscript not installed in Windows test environment", -) - - -def test_unknown_flavor(): +def test_unknown_flavor(foo_pdf): message = "Unknown flavor specified." " Use either 'lattice' or 'stream'" with pytest.raises(NotImplementedError, match=message): - tables = camelot.read_pdf(filename, flavor="chocolate") + camelot.read_pdf(foo_pdf, flavor="chocolate") -def test_input_kwargs(): +def test_input_kwargs(foo_pdf): message = "columns cannot be used with flavor='lattice'" with pytest.raises(ValueError, match=message): - tables = camelot.read_pdf(filename, columns=["10,20,30,40"]) + camelot.read_pdf(foo_pdf, columns=["10,20,30,40"]) -def test_unsupported_format(): +def test_unsupported_format(testdir): message = "File format not supported" filename = os.path.join(testdir, "foo.csv") with pytest.raises(NotImplementedError, match=message): - tables = camelot.read_pdf(filename) + camelot.read_pdf(filename) @skip_on_windows -def test_no_tables_found_logs_suppressed(): +def test_no_tables_found_logs_suppressed(testdir): filename = os.path.join(testdir, "foo.pdf") with warnings.catch_warnings(): # the test should fail if any warning is thrown warnings.simplefilter("error") try: - tables = camelot.read_pdf(filename, suppress_stdout=True) + camelot.read_pdf(filename, suppress_stdout=True) except Warning as e: warning_text = str(e) pytest.fail(f"Unexpected warning: {warning_text}") -def test_no_tables_found_warnings_suppressed(): +def test_no_tables_found_warnings_suppressed(testdir): filename = os.path.join(testdir, "empty.pdf") with warnings.catch_warnings(): # the test should fail if any warning is thrown warnings.simplefilter("error") try: - tables = camelot.read_pdf(filename, suppress_stdout=True) + camelot.read_pdf(filename, suppress_stdout=True) except Warning as e: warning_text = str(e) pytest.fail(f"Unexpected warning: {warning_text}") -def test_no_password(): +def test_no_password(testdir): filename = os.path.join(testdir, "health_protected.pdf") message = "File has not been decrypted" with pytest.raises(Exception, match=message): - tables = camelot.read_pdf(filename) + camelot.read_pdf(filename) -def test_bad_password(): +def test_bad_password(testdir): filename = os.path.join(testdir, "health_protected.pdf") message = "File has not been decrypted" with pytest.raises(Exception, match=message): - tables = camelot.read_pdf(filename, password="wrongpass") + camelot.read_pdf(filename, password="wrongpass") -def test_stream_equal_length(): +def test_stream_equal_length(foo_pdf): message = "Length of table_areas and columns" " should be equal" with pytest.raises(ValueError, match=message): - tables = camelot.read_pdf( - filename, + camelot.read_pdf( + foo_pdf, flavor="stream", table_areas=["10,20,30,40"], columns=["10,20,30,40", "10,20,30,40"], ) -def test_image_warning(): +def test_image_warning(testdir): filename = os.path.join(testdir, "image.pdf") with warnings.catch_warnings(): warnings.simplefilter("error", category=UserWarning) with pytest.raises(UserWarning) as e: - tables = camelot.read_pdf(filename) + camelot.read_pdf(filename) assert ( str(e.value) == "page-1 is image-based, camelot only works on text-based pages." ) -def test_stream_no_tables_on_page(): +def test_stream_no_tables_on_page(testdir): filename = os.path.join(testdir, "empty.pdf") with warnings.catch_warnings(): warnings.simplefilter("error") with pytest.raises(UserWarning) as e: - tables = camelot.read_pdf(filename, flavor="stream") + camelot.read_pdf(filename, flavor="stream") assert str(e.value) == "No tables found on page-1" -def test_stream_no_tables_in_area(): +def test_stream_no_tables_in_area(testdir): filename = os.path.join(testdir, "only_page_number.pdf") with warnings.catch_warnings(): warnings.simplefilter("error") @@ -118,7 +106,7 @@ def test_stream_no_tables_in_area(): assert str(e.value) == "No tables found in table area 1" -def test_lattice_no_tables_on_page(): +def test_lattice_no_tables_on_page(testdir): filename = os.path.join(testdir, "empty.pdf") with warnings.catch_warnings(): warnings.simplefilter("error", category=UserWarning) @@ -127,22 +115,22 @@ def test_lattice_no_tables_on_page(): assert str(e.value) == "No tables found on page-1" -def test_lattice_unknown_backend(): +def test_lattice_unknown_backend(foo_pdf): message = "Unknown backend 'mupdf' specified. Please use either 'poppler' or 'ghostscript'." with pytest.raises(NotImplementedError, match=message): - tables = camelot.read_pdf(filename, backend="mupdf") + tables = camelot.read_pdf(foo_pdf, backend="mupdf") -def test_lattice_no_convert_method(): - class ConversionBackend(object): +def test_lattice_no_convert_method(foo_pdf): + class ConversionBackend: pass message = "must implement a 'convert' method" with pytest.raises(NotImplementedError, match=message): - tables = camelot.read_pdf(filename, backend=ConversionBackend()) + camelot.read_pdf(foo_pdf, backend=ConversionBackend()) -def test_lattice_ghostscript_deprecation_warning(): +def test_lattice_ghostscript_deprecation_warning(foo_pdf): ghostscript_deprecation_warning = ( "'ghostscript' will be replaced by 'poppler' as the default image conversion" " backend in v0.12.0. You can try out 'poppler' with backend='poppler'." @@ -151,5 +139,5 @@ def test_lattice_ghostscript_deprecation_warning(): with warnings.catch_warnings(): warnings.simplefilter("error") with pytest.raises(DeprecationWarning) as e: - tables = camelot.read_pdf(filename) + camelot.read_pdf(foo_pdf) assert str(e.value) == ghostscript_deprecation_warning diff --git a/tests/test_image_conversion_backend.py b/tests/test_image_conversion_backend.py index 39f56e69..d1d85b0b 100644 --- a/tests/test_image_conversion_backend.py +++ b/tests/test_image_conversion_backend.py @@ -1,34 +1,36 @@ -# -*- coding: utf-8 -*- - import pytest -import camelot.backends.image_conversion from camelot.backends import ImageConversionBackend -class PopplerBackendError(object): +@pytest.fixture +def patch_backends(monkeypatch): + monkeypatch.setattr( + "camelot.backends.image_conversion.BACKENDS", + { + "poppler": PopplerBackendError, + "ghostscript": GhostscriptBackendNoError, + }, + raising=True, + ) + + +class PopplerBackendError: def convert(self, pdf_path, png_path): raise ValueError("Image conversion failed") -class GhostscriptBackendError(object): +class GhostscriptBackendError: def convert(self, pdf_path, png_path): raise ValueError("Image conversion failed") -class GhostscriptBackendNoError(object): +class GhostscriptBackendNoError: def convert(self, pdf_path, png_path): pass -def test_poppler_backend_error_when_no_use_fallback(monkeypatch): - BACKENDS = { - "poppler": PopplerBackendError, - "ghostscript": GhostscriptBackendNoError, - } - monkeypatch.setattr( - "camelot.backends.image_conversion.BACKENDS", BACKENDS, raising=True - ) +def test_poppler_backend_error_when_no_use_fallback(patch_backends): backend = ImageConversionBackend(use_fallback=False) message = "Image conversion failed with image conversion backend 'poppler'" @@ -36,22 +38,16 @@ def test_poppler_backend_error_when_no_use_fallback(monkeypatch): backend.convert("foo", "bar") -def test_ghostscript_backend_when_use_fallback(monkeypatch): - BACKENDS = { - "poppler": PopplerBackendError, - "ghostscript": GhostscriptBackendNoError, - } - monkeypatch.setattr( - "camelot.backends.image_conversion.BACKENDS", BACKENDS, raising=True - ) +def test_ghostscript_backend_when_use_fallback(patch_backends): backend = ImageConversionBackend() backend.convert("foo", "bar") def test_ghostscript_backend_error_when_use_fallback(monkeypatch): - BACKENDS = {"poppler": PopplerBackendError, "ghostscript": GhostscriptBackendError} + backends = {"poppler": PopplerBackendError, "ghostscript": GhostscriptBackendError} + monkeypatch.setattr( - "camelot.backends.image_conversion.BACKENDS", BACKENDS, raising=True + "camelot.backends.image_conversion.BACKENDS", backends, raising=True ) backend = ImageConversionBackend() diff --git a/tests/test_lattice.py b/tests/test_lattice.py index 7636b1b2..d2803049 100644 --- a/tests/test_lattice.py +++ b/tests/test_lattice.py @@ -1,29 +1,16 @@ -# -*- coding: utf-8 -*- - import os -import sys -import pytest import pandas as pd from pandas.testing import assert_frame_equal import camelot -from camelot.core import Table, TableList -from camelot.__version__ import generate_version +from .conftest import skip_on_windows from .data import * -testdir = os.path.dirname(os.path.abspath(__file__)) -testdir = os.path.join(testdir, "files") - -skip_on_windows = pytest.mark.skipif( - sys.platform.startswith("win"), - reason="Ghostscript not installed in Windows test environment", -) - @skip_on_windows -def test_lattice(): +def test_lattice(testdir): df = pd.DataFrame(data_lattice) filename = os.path.join( @@ -34,7 +21,7 @@ def test_lattice(): @skip_on_windows -def test_lattice_table_rotated(): +def test_lattice_table_rotated(testdir): df = pd.DataFrame(data_lattice_table_rotated) filename = os.path.join(testdir, "clockwise_table_1.pdf") @@ -47,7 +34,7 @@ def test_lattice_table_rotated(): @skip_on_windows -def test_lattice_two_tables(): +def test_lattice_two_tables(testdir): df1 = pd.DataFrame(data_lattice_two_tables_1) df2 = pd.DataFrame(data_lattice_two_tables_2) @@ -59,7 +46,7 @@ def test_lattice_two_tables(): @skip_on_windows -def test_lattice_table_regions(): +def test_lattice_table_regions(testdir): df = pd.DataFrame(data_lattice_table_regions) filename = os.path.join(testdir, "table_region.pdf") @@ -68,7 +55,7 @@ def test_lattice_table_regions(): @skip_on_windows -def test_lattice_table_areas(): +def test_lattice_table_areas(testdir): df = pd.DataFrame(data_lattice_table_areas) filename = os.path.join(testdir, "twotables_2.pdf") @@ -77,7 +64,7 @@ def test_lattice_table_areas(): @skip_on_windows -def test_lattice_process_background(): +def test_lattice_process_background(testdir): df = pd.DataFrame(data_lattice_process_background) filename = os.path.join(testdir, "background_lines_1.pdf") @@ -86,7 +73,7 @@ def test_lattice_process_background(): @skip_on_windows -def test_lattice_copy_text(): +def test_lattice_copy_text(testdir): df = pd.DataFrame(data_lattice_copy_text) filename = os.path.join(testdir, "row_span_1.pdf") @@ -95,7 +82,7 @@ def test_lattice_copy_text(): @skip_on_windows -def test_lattice_shift_text(): +def test_lattice_shift_text(testdir): df_lt = pd.DataFrame(data_lattice_shift_text_left_top) df_disable = pd.DataFrame(data_lattice_shift_text_disable) df_rb = pd.DataFrame(data_lattice_shift_text_right_bottom) @@ -112,7 +99,7 @@ def test_lattice_shift_text(): @skip_on_windows -def test_lattice_arabic(): +def test_lattice_arabic(testdir): df = pd.DataFrame(data_arabic) filename = os.path.join(testdir, "tabula/arabic.pdf") diff --git a/tests/test_plotting.py b/tests/test_plotting.py index 19dcfe62..17dc9adf 100644 --- a/tests/test_plotting.py +++ b/tests/test_plotting.py @@ -1,64 +1,53 @@ -# -*- coding: utf-8 -*- - import os -import sys import pytest import camelot - -testdir = os.path.dirname(os.path.abspath(__file__)) -testdir = os.path.join(testdir, "files") - -skip_on_windows = pytest.mark.skipif( - sys.platform.startswith("win"), - reason="Ghostscript not installed in Windows test environment", -) +from tests.conftest import skip_on_windows +from tests.conftest import skip_pdftopng @skip_on_windows @pytest.mark.mpl_image_compare(baseline_dir="files/baseline_plots", remove_text=True) -def test_text_plot(): +def test_text_plot(testdir): filename = os.path.join(testdir, "foo.pdf") tables = camelot.read_pdf(filename) return camelot.plot(tables[0], kind="text") @pytest.mark.mpl_image_compare(baseline_dir="files/baseline_plots", remove_text=True) -def test_textedge_plot(): +def test_textedge_plot(testdir): filename = os.path.join(testdir, "tabula/12s0324.pdf") tables = camelot.read_pdf(filename, flavor="stream") return camelot.plot(tables[0], kind="textedge") +@skip_pdftopng @pytest.mark.mpl_image_compare(baseline_dir="files/baseline_plots", remove_text=True) -def test_lattice_contour_plot_poppler(): +def test_lattice_contour_plot_poppler(testdir): filename = os.path.join(testdir, "foo.pdf") tables = camelot.read_pdf(filename, backend="poppler") return camelot.plot(tables[0], kind="contour") @skip_on_windows -@pytest.mark.skipif( - sys.platform.lower().startswith("darwin"), - reason="Unknown why this fails - if anybody has an idea, please fix it", -) @pytest.mark.mpl_image_compare(baseline_dir="files/baseline_plots", remove_text=True) -def test_lattice_contour_plot_ghostscript(): +def test_lattice_contour_plot_ghostscript(testdir): filename = os.path.join(testdir, "foo.pdf") tables = camelot.read_pdf(filename, backend="ghostscript") return camelot.plot(tables[0], kind="contour") @pytest.mark.mpl_image_compare(baseline_dir="files/baseline_plots", remove_text=True) -def test_stream_contour_plot(): +def test_stream_contour_plot(testdir): filename = os.path.join(testdir, "tabula/12s0324.pdf") tables = camelot.read_pdf(filename, flavor="stream") return camelot.plot(tables[0], kind="contour") +@skip_pdftopng @pytest.mark.mpl_image_compare(baseline_dir="files/baseline_plots", remove_text=True) -def test_line_plot_poppler(): +def test_line_plot_poppler(testdir): filename = os.path.join(testdir, "foo.pdf") tables = camelot.read_pdf(filename, backend="poppler") return camelot.plot(tables[0], kind="line") @@ -66,33 +55,31 @@ def test_line_plot_poppler(): @skip_on_windows @pytest.mark.mpl_image_compare(baseline_dir="files/baseline_plots", remove_text=True) -def test_line_plot_ghostscript(): +def test_line_plot_ghostscript(testdir): filename = os.path.join(testdir, "foo.pdf") tables = camelot.read_pdf(filename, backend="ghostscript") return camelot.plot(tables[0], kind="line") +@skip_pdftopng @pytest.mark.mpl_image_compare(baseline_dir="files/baseline_plots", remove_text=True) -def test_joint_plot_poppler(): +def test_joint_plot_poppler(testdir): filename = os.path.join(testdir, "foo.pdf") tables = camelot.read_pdf(filename, backend="poppler") return camelot.plot(tables[0], kind="joint") @skip_on_windows -@pytest.mark.skipif( - sys.platform.lower().startswith("darwin"), - reason="Unknown why this fails - if anybody has an idea, please fix it", -) @pytest.mark.mpl_image_compare(baseline_dir="files/baseline_plots", remove_text=True) -def test_joint_plot_ghostscript(): +def test_joint_plot_ghostscript(testdir): filename = os.path.join(testdir, "foo.pdf") tables = camelot.read_pdf(filename, backend="ghostscript") return camelot.plot(tables[0], kind="joint") +@skip_pdftopng @pytest.mark.mpl_image_compare(baseline_dir="files/baseline_plots", remove_text=True) -def test_grid_plot_poppler(): +def test_grid_plot_poppler(testdir): filename = os.path.join(testdir, "foo.pdf") tables = camelot.read_pdf(filename, backend="poppler") return camelot.plot(tables[0], kind="grid") @@ -100,7 +87,7 @@ def test_grid_plot_poppler(): @skip_on_windows @pytest.mark.mpl_image_compare(baseline_dir="files/baseline_plots", remove_text=True) -def test_grid_plot_ghostscript(): +def test_grid_plot_ghostscript(testdir): filename = os.path.join(testdir, "foo.pdf") tables = camelot.read_pdf(filename, backend="ghostscript") return camelot.plot(tables[0], kind="grid") diff --git a/tests/test_stream.py b/tests/test_stream.py index 0626ea7b..e86f23b7 100644 --- a/tests/test_stream.py +++ b/tests/test_stream.py @@ -1,22 +1,14 @@ -# -*- coding: utf-8 -*- - import os -import pytest import pandas as pd from pandas.testing import assert_frame_equal import camelot -from camelot.core import Table, TableList -from camelot.__version__ import generate_version from .data import * -testdir = os.path.dirname(os.path.abspath(__file__)) -testdir = os.path.join(testdir, "files") - -def test_stream(): +def test_stream(testdir): df = pd.DataFrame(data_stream) filename = os.path.join(testdir, "health.pdf") @@ -24,7 +16,7 @@ def test_stream(): assert_frame_equal(df, tables[0].df) -def test_stream_table_rotated(): +def test_stream_table_rotated(testdir): df = pd.DataFrame(data_stream_table_rotated) filename = os.path.join(testdir, "clockwise_table_2.pdf") @@ -36,7 +28,7 @@ def test_stream_table_rotated(): assert_frame_equal(df, tables[0].df) -def test_stream_two_tables(): +def test_stream_two_tables(testdir): df1 = pd.DataFrame(data_stream_two_tables_1) df2 = pd.DataFrame(data_stream_two_tables_2) @@ -48,7 +40,7 @@ def test_stream_two_tables(): assert df2.equals(tables[1].df) -def test_stream_table_regions(): +def test_stream_table_regions(testdir): df = pd.DataFrame(data_stream_table_areas) filename = os.path.join(testdir, "tabula/us-007.pdf") @@ -58,7 +50,7 @@ def test_stream_table_regions(): assert_frame_equal(df, tables[0].df) -def test_stream_table_areas(): +def test_stream_table_areas(testdir): df = pd.DataFrame(data_stream_table_areas) filename = os.path.join(testdir, "tabula/us-007.pdf") @@ -68,7 +60,7 @@ def test_stream_table_areas(): assert_frame_equal(df, tables[0].df) -def test_stream_columns(): +def test_stream_columns(testdir): df = pd.DataFrame(data_stream_columns) filename = os.path.join(testdir, "mexican_towns.pdf") @@ -78,7 +70,7 @@ def test_stream_columns(): assert_frame_equal(df, tables[0].df) -def test_stream_split_text(): +def test_stream_split_text(testdir): df = pd.DataFrame(data_stream_split_text) filename = os.path.join(testdir, "tabula/m27.pdf") @@ -91,7 +83,7 @@ def test_stream_split_text(): assert_frame_equal(df, tables[0].df) -def test_stream_flag_size(): +def test_stream_flag_size(testdir): df = pd.DataFrame(data_stream_flag_size) filename = os.path.join(testdir, "superscript.pdf") @@ -99,7 +91,7 @@ def test_stream_flag_size(): assert_frame_equal(df, tables[0].df) -def test_stream_strip_text(): +def test_stream_strip_text(testdir): df = pd.DataFrame(data_stream_strip_text) filename = os.path.join(testdir, "detect_vertical_false.pdf") @@ -107,7 +99,7 @@ def test_stream_strip_text(): assert_frame_equal(df, tables[0].df) -def test_stream_edge_tol(): +def test_stream_edge_tol(testdir): df = pd.DataFrame(data_stream_edge_tol) filename = os.path.join(testdir, "edge_tol.pdf") @@ -115,7 +107,7 @@ def test_stream_edge_tol(): assert_frame_equal(df, tables[0].df) -def test_stream_layout_kwargs(): +def test_stream_layout_kwargs(testdir): df = pd.DataFrame(data_stream_layout_kwargs) filename = os.path.join(testdir, "detect_vertical_false.pdf") @@ -125,7 +117,7 @@ def test_stream_layout_kwargs(): assert_frame_equal(df, tables[0].df) -def test_stream_duplicated_text(): +def test_stream_duplicated_text(testdir): df = pd.DataFrame(data_stream_duplicated_text) filename = os.path.join(testdir, "birdisland.pdf") diff --git a/tests/test_utils.py b/tests/test_utils.py new file mode 100644 index 00000000..9a68f386 --- /dev/null +++ b/tests/test_utils.py @@ -0,0 +1,45 @@ +"Test to check intersection logic when no intersection area returned" +import os + +from pdfminer.converter import PDFPageAggregator +from pdfminer.layout import ( + LAParams, + LTTextBoxHorizontal +) +from pdfminer.pdfinterp import PDFPageInterpreter, PDFResourceManager +from pdfminer.pdfpage import PDFPage + +from camelot.utils import bbox_intersection_area + + +def get_text_from_pdf(filename): + "Method to extract text object from pdf" + # https://stackoverflow.com/questions/22898145/how-to-extract-text-and-text-coordinates-from-a-pdf-file + # https://pdfminer-docs.readthedocs.io/programming.html#performing-layout-analysis + document = open(filename, 'rb') + # Create resource manager + rsrcmgr = PDFResourceManager() + # Set parameters for analysis. + laparams = LAParams() + # Create a PDF page aggregator object. + device = PDFPageAggregator(rsrcmgr, laparams=laparams) + interpreter = PDFPageInterpreter(rsrcmgr, device) + for page in PDFPage.get_pages(document): + interpreter.process_page(page) + # receive the LTPage object for the page. + layout = device.get_result() + for element in layout: + if isinstance(element, LTTextBoxHorizontal): + return element + + +def test_bbox_intersection_text(testdir): + """ + Test to check area of intersection between both boxes when no intersection area returned + """ + filename1 = os.path.join(testdir, "foo.pdf") + pdftextelement1 = get_text_from_pdf(filename1) + filename2 = os.path.join(testdir, "tabula/12s0324.pdf") + pdftextelement2 = get_text_from_pdf(filename2) + + assert bbox_intersection_area(pdftextelement1, pdftextelement2) == 0.0