diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..5a9fb03 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,12 @@ +version: 2 +updates: + - package-ecosystem: "pip" + directory: "/" + schedule: + interval: "weekly" + - package-ecosystem: "github-actions" + # Workflow files stored in the + # default location of `.github/workflows` + directory: "/" + schedule: + interval: "weekly" diff --git a/.github/workflows/image-build-scan.yml b/.github/workflows/image-build-scan.yml index 7ad98a3..9f66092 100644 --- a/.github/workflows/image-build-scan.yml +++ b/.github/workflows/image-build-scan.yml @@ -24,31 +24,41 @@ jobs: # Only required for workflows in private repositories actions: read steps: - - name: Set up QEMU - uses: docker/setup-qemu-action@v2 + #---------------------------------------------- + # Checkout repo + #---------------------------------------------- - name: Checkout repository - uses: actions/checkout@v3 - id: checkout-repo - with: - fetch-depth: 0 + uses: actions/checkout@v4 + #---------------------------------------------- + # Set up Docker BuildX environment + #---------------------------------------------- - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 + uses: docker/setup-buildx-action@v3 + #---------------------------------------------- + # Log Docker into the GitHub Container Repository + #---------------------------------------------- - name: Log into registry ${{ env.REGISTRY }} if: github.event_name != 'pull_request' - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} + #---------------------------------------------- + # Extract Docker image metadata from GitHub events + #---------------------------------------------- - name: Extract Docker metadata id: meta - uses: docker/metadata-action@v4 + uses: docker/metadata-action@v5 with: images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} flavor: | latest=true + #---------------------------------------------- + # Build and push Docker image (not on PR) + #---------------------------------------------- - name: Build and push Docker image - uses: docker/build-push-action@v4 + uses: docker/build-push-action@v5 with: context: . push: ${{ github.event_name != 'pull_request' }} diff --git a/README.md b/README.md index 091995e..18d0a2a 100644 --- a/README.md +++ b/README.md @@ -20,13 +20,8 @@ Manage new or updating project dependencies with Poetry also, like so: # Environment variables -This project uses **django-confy** to set environment variables (in a `.env` file). -The following variables are required for the project to run (others have -default values): - - RT_URL=https://resourcetracking.dbca.wa.gov.au - USER_SSO=some.user@dbca.wa.gov.au - PASS_SSO=password +This project uses **python-dotenv** to set environment variables (in a `.env` file). +Most settings have default values; check `status.py` for required variables. # Running @@ -43,6 +38,6 @@ To build a new Docker image from the `Dockerfile`: docker image build -t ghcr.io/dbca-wa/healthcheck . -To run a Docker container locally, publishing port 8080 to a different local port: +To run a Docker container locally, publishing container port 8080 to a local port: - docker container run --rm --publish 8211:8080 --env-file .env ghcr.io/dbca-wa/healthcheck + docker container run --rm --publish 8080:8080 --env-file .env ghcr.io/dbca-wa/healthcheck diff --git a/kustomize/overlays/prod/deployment_patch.yaml b/kustomize/overlays/prod/deployment_patch.yaml index 5adbbe6..43020f1 100644 --- a/kustomize/overlays/prod/deployment_patch.yaml +++ b/kustomize/overlays/prod/deployment_patch.yaml @@ -27,11 +27,6 @@ spec: secretKeyRef: name: healthcheck-env-prod key: CSW_API - - name: DBCA_GOING_BUSHFIRES_URL - valueFrom: - secretKeyRef: - name: healthcheck-env-prod - key: DBCA_GOING_BUSHFIRES_URL - name: KMI_URL valueFrom: secretKeyRef: @@ -57,3 +52,78 @@ spec: secretKeyRef: name: healthcheck-env-prod key: TRACKING_POINTS_MAX_DELAY + - name: DBCA_GOING_BUSHFIRES_URL + valueFrom: + secretKeyRef: + name: healthcheck-env-prod + key: DBCA_GOING_BUSHFIRES_URL + - name: DBCA_CONTROL_LINES_URL + valueFrom: + secretKeyRef: + name: healthcheck-env-prod + key: DBCA_CONTROL_LINES_URL + - name: DFES_GOING_BUSHFIRES_URL + valueFrom: + secretKeyRef: + name: healthcheck-env-prod + key: DFES_GOING_BUSHFIRES_URL + - name: ALL_CURRENT_HOTSPOTS + valueFrom: + secretKeyRef: + name: healthcheck-env-prod + key: ALL_CURRENT_HOTSPOTS + - name: LIGHTNING_24H + valueFrom: + secretKeyRef: + name: healthcheck-env-prod + key: LIGHTNING_24H + - name: LIGHTNING_24_48H + valueFrom: + secretKeyRef: + name: healthcheck-env-prod + key: LIGHTNING_24_48H + - name: LIGHTNING_48_72H + valueFrom: + secretKeyRef: + name: healthcheck-env-prod + key: LIGHTNING_48_72H + - name: FUEL_AGE_1_6Y + valueFrom: + secretKeyRef: + name: healthcheck-env-prod + key: FUEL_AGE_1_6Y + - name: FUEL_AGE_NONFOREST_1_6Y + valueFrom: + secretKeyRef: + name: healthcheck-env-prod + key: FUEL_AGE_NONFOREST_1_6Y + - name: COG_BASEMAP + valueFrom: + secretKeyRef: + name: healthcheck-env-prod + key: COG_BASEMAP + - name: STATE_BASEMAP + valueFrom: + secretKeyRef: + name: healthcheck-env-prod + key: STATE_BASEMAP + - name: DBCA_BURN_PROGRAM + valueFrom: + secretKeyRef: + name: healthcheck-env-prod + key: DBCA_BURN_PROGRAM + - name: DAILY_ACTIVE_BURNS + valueFrom: + secretKeyRef: + name: healthcheck-env-prod + key: DAILY_ACTIVE_BURNS + - name: DBCA_LANDS_WATERS + valueFrom: + secretKeyRef: + name: healthcheck-env-prod + key: DBCA_LANDS_WATERS + - name: DBCA_LANDS_WATERS_INTEREST + valueFrom: + secretKeyRef: + name: healthcheck-env-prod + key: DBCA_LANDS_WATERS_INTEREST diff --git a/kustomize/overlays/prod/kustomization.yaml b/kustomize/overlays/prod/kustomization.yaml index afb98fb..0b2e5ac 100644 --- a/kustomize/overlays/prod/kustomization.yaml +++ b/kustomize/overlays/prod/kustomization.yaml @@ -16,7 +16,7 @@ labels: variant: prod images: - name: ghcr.io/dbca-wa/healthcheck - newTag: 1.1.12 + newTag: 1.1.13 patches: - path: deployment_patch.yaml - path: service_patch.yaml diff --git a/kustomize/overlays/uat/deployment_patch.yaml b/kustomize/overlays/uat/deployment_patch.yaml index b8ad670..aef38e7 100644 --- a/kustomize/overlays/uat/deployment_patch.yaml +++ b/kustomize/overlays/uat/deployment_patch.yaml @@ -27,11 +27,6 @@ spec: secretKeyRef: name: healthcheck-env-uat key: CSW_API - - name: DBCA_GOING_BUSHFIRES_URL - valueFrom: - secretKeyRef: - name: healthcheck-env-uat - key: DBCA_GOING_BUSHFIRES_URL - name: KMI_URL valueFrom: secretKeyRef: @@ -57,3 +52,78 @@ spec: secretKeyRef: name: healthcheck-env-uat key: TRACKING_POINTS_MAX_DELAY + - name: DBCA_GOING_BUSHFIRES_URL + valueFrom: + secretKeyRef: + name: healthcheck-env-uat + key: DBCA_GOING_BUSHFIRES_URL + - name: DBCA_CONTROL_LINES_URL + valueFrom: + secretKeyRef: + name: healthcheck-env-uat + key: DBCA_CONTROL_LINES_URL + - name: DFES_GOING_BUSHFIRES_URL + valueFrom: + secretKeyRef: + name: healthcheck-env-uat + key: DFES_GOING_BUSHFIRES_URL + - name: ALL_CURRENT_HOTSPOTS + valueFrom: + secretKeyRef: + name: healthcheck-env-uat + key: ALL_CURRENT_HOTSPOTS + - name: LIGHTNING_24H + valueFrom: + secretKeyRef: + name: healthcheck-env-uat + key: LIGHTNING_24H + - name: LIGHTNING_24_48H + valueFrom: + secretKeyRef: + name: healthcheck-env-uat + key: LIGHTNING_24_48H + - name: LIGHTNING_48_72H + valueFrom: + secretKeyRef: + name: healthcheck-env-uat + key: LIGHTNING_48_72H + - name: FUEL_AGE_1_6Y + valueFrom: + secretKeyRef: + name: healthcheck-env-uat + key: FUEL_AGE_1_6Y + - name: FUEL_AGE_NONFOREST_1_6Y + valueFrom: + secretKeyRef: + name: healthcheck-env-uat + key: FUEL_AGE_NONFOREST_1_6Y + - name: COG_BASEMAP + valueFrom: + secretKeyRef: + name: healthcheck-env-uat + key: COG_BASEMAP + - name: STATE_BASEMAP + valueFrom: + secretKeyRef: + name: healthcheck-env-uat + key: STATE_BASEMAP + - name: DBCA_BURN_PROGRAM + valueFrom: + secretKeyRef: + name: healthcheck-env-uat + key: DBCA_BURN_PROGRAM + - name: DAILY_ACTIVE_BURNS + valueFrom: + secretKeyRef: + name: healthcheck-env-uat + key: DAILY_ACTIVE_BURNS + - name: DBCA_LANDS_WATERS + valueFrom: + secretKeyRef: + name: healthcheck-env-uat + key: DBCA_LANDS_WATERS + - name: DBCA_LANDS_WATERS_INTEREST + valueFrom: + secretKeyRef: + name: healthcheck-env-uat + key: DBCA_LANDS_WATERS_INTEREST diff --git a/poetry.lock b/poetry.lock index 0ff991f..e2a7570 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,43 +1,22 @@ -# This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand. - -[[package]] -name = "appnope" -version = "0.1.3" -description = "Disable App Nap on macOS >= 10.9" -optional = false -python-versions = "*" -files = [ - {file = "appnope-0.1.3-py2.py3-none-any.whl", hash = "sha256:265a455292d0bd8a72453494fa24df5a11eb18373a60c7c0430889f22548605e"}, - {file = "appnope-0.1.3.tar.gz", hash = "sha256:02bd91c4de869fbb1e1c50aafc4098827a7a54ab2f39d9dcba6c9547ed920e24"}, -] +# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. [[package]] name = "asttokens" -version = "2.4.0" +version = "2.4.1" description = "Annotate AST trees with source code positions" optional = false python-versions = "*" files = [ - {file = "asttokens-2.4.0-py2.py3-none-any.whl", hash = "sha256:cf8fc9e61a86461aa9fb161a14a0841a03c405fa829ac6b202670b3495d2ce69"}, - {file = "asttokens-2.4.0.tar.gz", hash = "sha256:2e0171b991b2c959acc6c49318049236844a5da1d65ba2672c4880c1c894834e"}, + {file = "asttokens-2.4.1-py2.py3-none-any.whl", hash = "sha256:051ed49c3dcae8913ea7cd08e46a606dba30b79993209636c4875bc1d637bc24"}, + {file = "asttokens-2.4.1.tar.gz", hash = "sha256:b03869718ba9a6eb027e134bfdf69f38a236d681c83c160d510768af11254ba0"}, ] [package.dependencies] six = ">=1.12.0" [package.extras] -test = ["astroid", "pytest"] - -[[package]] -name = "backcall" -version = "0.2.0" -description = "Specifications for callback functions passed in to an API" -optional = false -python-versions = "*" -files = [ - {file = "backcall-0.2.0-py2.py3-none-any.whl", hash = "sha256:fbbce6a29f263178a1f7915c1940bde0ec2b2a967566fe1c65c1dfb7422bd255"}, - {file = "backcall-0.2.0.tar.gz", hash = "sha256:5cbdbf27be5e7cfadb448baf0aa95508f91f2bbc6c6437cd9cd06e2a4c215e1e"}, -] +astroid = ["astroid (>=1,<2)", "astroid (>=2,<4)"] +test = ["astroid (>=1,<2)", "astroid (>=2,<4)", "pytest"] [[package]] name = "bottle" @@ -52,112 +31,112 @@ files = [ [[package]] name = "certifi" -version = "2023.7.22" +version = "2023.11.17" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" files = [ - {file = "certifi-2023.7.22-py3-none-any.whl", hash = "sha256:92d6037539857d8206b8f6ae472e8b77db8058fec5937a1ef3f54304089edbb9"}, - {file = "certifi-2023.7.22.tar.gz", hash = "sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082"}, + {file = "certifi-2023.11.17-py3-none-any.whl", hash = "sha256:e036ab49d5b79556f99cfc2d9320b34cfbe5be05c5871b51de9329f0603b0474"}, + {file = "certifi-2023.11.17.tar.gz", hash = "sha256:9b469f3a900bf28dc19b8cfbf8019bf47f7fdd1a65a1d4ffb98fc14166beb4d1"}, ] [[package]] name = "charset-normalizer" -version = "3.3.0" +version = "3.3.2" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." optional = false python-versions = ">=3.7.0" files = [ - {file = "charset-normalizer-3.3.0.tar.gz", hash = "sha256:63563193aec44bce707e0c5ca64ff69fa72ed7cf34ce6e11d5127555756fd2f6"}, - {file = "charset_normalizer-3.3.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:effe5406c9bd748a871dbcaf3ac69167c38d72db8c9baf3ff954c344f31c4cbe"}, - {file = "charset_normalizer-3.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4162918ef3098851fcd8a628bf9b6a98d10c380725df9e04caf5ca6dd48c847a"}, - {file = "charset_normalizer-3.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0570d21da019941634a531444364f2482e8db0b3425fcd5ac0c36565a64142c8"}, - {file = "charset_normalizer-3.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5707a746c6083a3a74b46b3a631d78d129edab06195a92a8ece755aac25a3f3d"}, - {file = "charset_normalizer-3.3.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:278c296c6f96fa686d74eb449ea1697f3c03dc28b75f873b65b5201806346a69"}, - {file = "charset_normalizer-3.3.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a4b71f4d1765639372a3b32d2638197f5cd5221b19531f9245fcc9ee62d38f56"}, - {file = "charset_normalizer-3.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5969baeaea61c97efa706b9b107dcba02784b1601c74ac84f2a532ea079403e"}, - {file = "charset_normalizer-3.3.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a3f93dab657839dfa61025056606600a11d0b696d79386f974e459a3fbc568ec"}, - {file = "charset_normalizer-3.3.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:db756e48f9c5c607b5e33dd36b1d5872d0422e960145b08ab0ec7fd420e9d649"}, - {file = "charset_normalizer-3.3.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:232ac332403e37e4a03d209a3f92ed9071f7d3dbda70e2a5e9cff1c4ba9f0678"}, - {file = "charset_normalizer-3.3.0-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:e5c1502d4ace69a179305abb3f0bb6141cbe4714bc9b31d427329a95acfc8bdd"}, - {file = "charset_normalizer-3.3.0-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:2502dd2a736c879c0f0d3e2161e74d9907231e25d35794584b1ca5284e43f596"}, - {file = "charset_normalizer-3.3.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:23e8565ab7ff33218530bc817922fae827420f143479b753104ab801145b1d5b"}, - {file = "charset_normalizer-3.3.0-cp310-cp310-win32.whl", hash = "sha256:1872d01ac8c618a8da634e232f24793883d6e456a66593135aeafe3784b0848d"}, - {file = "charset_normalizer-3.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:557b21a44ceac6c6b9773bc65aa1b4cc3e248a5ad2f5b914b91579a32e22204d"}, - {file = "charset_normalizer-3.3.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:d7eff0f27edc5afa9e405f7165f85a6d782d308f3b6b9d96016c010597958e63"}, - {file = "charset_normalizer-3.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6a685067d05e46641d5d1623d7c7fdf15a357546cbb2f71b0ebde91b175ffc3e"}, - {file = "charset_normalizer-3.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0d3d5b7db9ed8a2b11a774db2bbea7ba1884430a205dbd54a32d61d7c2a190fa"}, - {file = "charset_normalizer-3.3.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2935ffc78db9645cb2086c2f8f4cfd23d9b73cc0dc80334bc30aac6f03f68f8c"}, - {file = "charset_normalizer-3.3.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9fe359b2e3a7729010060fbca442ca225280c16e923b37db0e955ac2a2b72a05"}, - {file = "charset_normalizer-3.3.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:380c4bde80bce25c6e4f77b19386f5ec9db230df9f2f2ac1e5ad7af2caa70459"}, - {file = "charset_normalizer-3.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f0d1e3732768fecb052d90d62b220af62ead5748ac51ef61e7b32c266cac9293"}, - {file = "charset_normalizer-3.3.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1b2919306936ac6efb3aed1fbf81039f7087ddadb3160882a57ee2ff74fd2382"}, - {file = "charset_normalizer-3.3.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:f8888e31e3a85943743f8fc15e71536bda1c81d5aa36d014a3c0c44481d7db6e"}, - {file = "charset_normalizer-3.3.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:82eb849f085624f6a607538ee7b83a6d8126df6d2f7d3b319cb837b289123078"}, - {file = "charset_normalizer-3.3.0-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:7b8b8bf1189b3ba9b8de5c8db4d541b406611a71a955bbbd7385bbc45fcb786c"}, - {file = "charset_normalizer-3.3.0-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:5adf257bd58c1b8632046bbe43ee38c04e1038e9d37de9c57a94d6bd6ce5da34"}, - {file = "charset_normalizer-3.3.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c350354efb159b8767a6244c166f66e67506e06c8924ed74669b2c70bc8735b1"}, - {file = "charset_normalizer-3.3.0-cp311-cp311-win32.whl", hash = "sha256:02af06682e3590ab952599fbadac535ede5d60d78848e555aa58d0c0abbde786"}, - {file = "charset_normalizer-3.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:86d1f65ac145e2c9ed71d8ffb1905e9bba3a91ae29ba55b4c46ae6fc31d7c0d4"}, - {file = "charset_normalizer-3.3.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:3b447982ad46348c02cb90d230b75ac34e9886273df3a93eec0539308a6296d7"}, - {file = "charset_normalizer-3.3.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:abf0d9f45ea5fb95051c8bfe43cb40cda383772f7e5023a83cc481ca2604d74e"}, - {file = "charset_normalizer-3.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b09719a17a2301178fac4470d54b1680b18a5048b481cb8890e1ef820cb80455"}, - {file = "charset_normalizer-3.3.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b3d9b48ee6e3967b7901c052b670c7dda6deb812c309439adaffdec55c6d7b78"}, - {file = "charset_normalizer-3.3.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:edfe077ab09442d4ef3c52cb1f9dab89bff02f4524afc0acf2d46be17dc479f5"}, - {file = "charset_normalizer-3.3.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3debd1150027933210c2fc321527c2299118aa929c2f5a0a80ab6953e3bd1908"}, - {file = "charset_normalizer-3.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:86f63face3a527284f7bb8a9d4f78988e3c06823f7bea2bd6f0e0e9298ca0403"}, - {file = "charset_normalizer-3.3.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:24817cb02cbef7cd499f7c9a2735286b4782bd47a5b3516a0e84c50eab44b98e"}, - {file = "charset_normalizer-3.3.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:c71f16da1ed8949774ef79f4a0260d28b83b3a50c6576f8f4f0288d109777989"}, - {file = "charset_normalizer-3.3.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:9cf3126b85822c4e53aa28c7ec9869b924d6fcfb76e77a45c44b83d91afd74f9"}, - {file = "charset_normalizer-3.3.0-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:b3b2316b25644b23b54a6f6401074cebcecd1244c0b8e80111c9a3f1c8e83d65"}, - {file = "charset_normalizer-3.3.0-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:03680bb39035fbcffe828eae9c3f8afc0428c91d38e7d61aa992ef7a59fb120e"}, - {file = "charset_normalizer-3.3.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4cc152c5dd831641e995764f9f0b6589519f6f5123258ccaca8c6d34572fefa8"}, - {file = "charset_normalizer-3.3.0-cp312-cp312-win32.whl", hash = "sha256:b8f3307af845803fb0b060ab76cf6dd3a13adc15b6b451f54281d25911eb92df"}, - {file = "charset_normalizer-3.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:8eaf82f0eccd1505cf39a45a6bd0a8cf1c70dcfc30dba338207a969d91b965c0"}, - {file = "charset_normalizer-3.3.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:dc45229747b67ffc441b3de2f3ae5e62877a282ea828a5bdb67883c4ee4a8810"}, - {file = "charset_normalizer-3.3.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f4a0033ce9a76e391542c182f0d48d084855b5fcba5010f707c8e8c34663d77"}, - {file = "charset_normalizer-3.3.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ada214c6fa40f8d800e575de6b91a40d0548139e5dc457d2ebb61470abf50186"}, - {file = "charset_normalizer-3.3.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b1121de0e9d6e6ca08289583d7491e7fcb18a439305b34a30b20d8215922d43c"}, - {file = "charset_normalizer-3.3.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1063da2c85b95f2d1a430f1c33b55c9c17ffaf5e612e10aeaad641c55a9e2b9d"}, - {file = "charset_normalizer-3.3.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:70f1d09c0d7748b73290b29219e854b3207aea922f839437870d8cc2168e31cc"}, - {file = "charset_normalizer-3.3.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:250c9eb0f4600361dd80d46112213dff2286231d92d3e52af1e5a6083d10cad9"}, - {file = "charset_normalizer-3.3.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:750b446b2ffce1739e8578576092179160f6d26bd5e23eb1789c4d64d5af7dc7"}, - {file = "charset_normalizer-3.3.0-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:fc52b79d83a3fe3a360902d3f5d79073a993597d48114c29485e9431092905d8"}, - {file = "charset_normalizer-3.3.0-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:588245972aca710b5b68802c8cad9edaa98589b1b42ad2b53accd6910dad3545"}, - {file = "charset_normalizer-3.3.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:e39c7eb31e3f5b1f88caff88bcff1b7f8334975b46f6ac6e9fc725d829bc35d4"}, - {file = "charset_normalizer-3.3.0-cp37-cp37m-win32.whl", hash = "sha256:abecce40dfebbfa6abf8e324e1860092eeca6f7375c8c4e655a8afb61af58f2c"}, - {file = "charset_normalizer-3.3.0-cp37-cp37m-win_amd64.whl", hash = "sha256:24a91a981f185721542a0b7c92e9054b7ab4fea0508a795846bc5b0abf8118d4"}, - {file = "charset_normalizer-3.3.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:67b8cc9574bb518ec76dc8e705d4c39ae78bb96237cb533edac149352c1f39fe"}, - {file = "charset_normalizer-3.3.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ac71b2977fb90c35d41c9453116e283fac47bb9096ad917b8819ca8b943abecd"}, - {file = "charset_normalizer-3.3.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:3ae38d325b512f63f8da31f826e6cb6c367336f95e418137286ba362925c877e"}, - {file = "charset_normalizer-3.3.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:542da1178c1c6af8873e143910e2269add130a299c9106eef2594e15dae5e482"}, - {file = "charset_normalizer-3.3.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:30a85aed0b864ac88309b7d94be09f6046c834ef60762a8833b660139cfbad13"}, - {file = "charset_normalizer-3.3.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:aae32c93e0f64469f74ccc730a7cb21c7610af3a775157e50bbd38f816536b38"}, - {file = "charset_normalizer-3.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15b26ddf78d57f1d143bdf32e820fd8935d36abe8a25eb9ec0b5a71c82eb3895"}, - {file = "charset_normalizer-3.3.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7f5d10bae5d78e4551b7be7a9b29643a95aded9d0f602aa2ba584f0388e7a557"}, - {file = "charset_normalizer-3.3.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:249c6470a2b60935bafd1d1d13cd613f8cd8388d53461c67397ee6a0f5dce741"}, - {file = "charset_normalizer-3.3.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:c5a74c359b2d47d26cdbbc7845e9662d6b08a1e915eb015d044729e92e7050b7"}, - {file = "charset_normalizer-3.3.0-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:b5bcf60a228acae568e9911f410f9d9e0d43197d030ae5799e20dca8df588287"}, - {file = "charset_normalizer-3.3.0-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:187d18082694a29005ba2944c882344b6748d5be69e3a89bf3cc9d878e548d5a"}, - {file = "charset_normalizer-3.3.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:81bf654678e575403736b85ba3a7867e31c2c30a69bc57fe88e3ace52fb17b89"}, - {file = "charset_normalizer-3.3.0-cp38-cp38-win32.whl", hash = "sha256:85a32721ddde63c9df9ebb0d2045b9691d9750cb139c161c80e500d210f5e26e"}, - {file = "charset_normalizer-3.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:468d2a840567b13a590e67dd276c570f8de00ed767ecc611994c301d0f8c014f"}, - {file = "charset_normalizer-3.3.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e0fc42822278451bc13a2e8626cf2218ba570f27856b536e00cfa53099724828"}, - {file = "charset_normalizer-3.3.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:09c77f964f351a7369cc343911e0df63e762e42bac24cd7d18525961c81754f4"}, - {file = "charset_normalizer-3.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:12ebea541c44fdc88ccb794a13fe861cc5e35d64ed689513a5c03d05b53b7c82"}, - {file = "charset_normalizer-3.3.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:805dfea4ca10411a5296bcc75638017215a93ffb584c9e344731eef0dcfb026a"}, - {file = "charset_normalizer-3.3.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:96c2b49eb6a72c0e4991d62406e365d87067ca14c1a729a870d22354e6f68115"}, - {file = "charset_normalizer-3.3.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:aaf7b34c5bc56b38c931a54f7952f1ff0ae77a2e82496583b247f7c969eb1479"}, - {file = "charset_normalizer-3.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:619d1c96099be5823db34fe89e2582b336b5b074a7f47f819d6b3a57ff7bdb86"}, - {file = "charset_normalizer-3.3.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a0ac5e7015a5920cfce654c06618ec40c33e12801711da6b4258af59a8eff00a"}, - {file = "charset_normalizer-3.3.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:93aa7eef6ee71c629b51ef873991d6911b906d7312c6e8e99790c0f33c576f89"}, - {file = "charset_normalizer-3.3.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7966951325782121e67c81299a031f4c115615e68046f79b85856b86ebffc4cd"}, - {file = "charset_normalizer-3.3.0-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:02673e456dc5ab13659f85196c534dc596d4ef260e4d86e856c3b2773ce09843"}, - {file = "charset_normalizer-3.3.0-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:c2af80fb58f0f24b3f3adcb9148e6203fa67dd3f61c4af146ecad033024dde43"}, - {file = "charset_normalizer-3.3.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:153e7b6e724761741e0974fc4dcd406d35ba70b92bfe3fedcb497226c93b9da7"}, - {file = "charset_normalizer-3.3.0-cp39-cp39-win32.whl", hash = "sha256:d47ecf253780c90ee181d4d871cd655a789da937454045b17b5798da9393901a"}, - {file = "charset_normalizer-3.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:d97d85fa63f315a8bdaba2af9a6a686e0eceab77b3089af45133252618e70884"}, - {file = "charset_normalizer-3.3.0-py3-none-any.whl", hash = "sha256:e46cd37076971c1040fc8c41273a8b3e2c624ce4f2be3f5dfcb7a430c1d3acc2"}, + {file = "charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-win32.whl", hash = "sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-win32.whl", hash = "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-win32.whl", hash = "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-win32.whl", hash = "sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-win32.whl", hash = "sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-win32.whl", hash = "sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d"}, + {file = "charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc"}, ] [[package]] @@ -184,13 +163,13 @@ files = [ [[package]] name = "exceptiongroup" -version = "1.1.3" +version = "1.2.0" description = "Backport of PEP 654 (exception groups)" optional = false python-versions = ">=3.7" files = [ - {file = "exceptiongroup-1.1.3-py3-none-any.whl", hash = "sha256:343280667a4585d195ca1cf9cef84a4e178c4b6cf2274caef9859782b567d5e3"}, - {file = "exceptiongroup-1.1.3.tar.gz", hash = "sha256:097acd85d473d75af5bb98e41b61ff7fe35efe6675e4f9370ec6ec5126d160e9"}, + {file = "exceptiongroup-1.2.0-py3-none-any.whl", hash = "sha256:4bfd3996ac73b41e9b9628b04e079f193850720ea5945fc96a08633c66912f14"}, + {file = "exceptiongroup-1.2.0.tar.gz", hash = "sha256:91f5c769735f051a4290d52edd0858999b57e5876e9f85937691bd4c9fa3ed68"}, ] [package.extras] @@ -198,13 +177,13 @@ test = ["pytest (>=6)"] [[package]] name = "executing" -version = "2.0.0" +version = "2.0.1" description = "Get the currently executing AST node of a frame, and other information" optional = false -python-versions = "*" +python-versions = ">=3.5" files = [ - {file = "executing-2.0.0-py2.py3-none-any.whl", hash = "sha256:06df6183df67389625f4e763921c6cf978944721abf3e714000200aab95b0657"}, - {file = "executing-2.0.0.tar.gz", hash = "sha256:0ff053696fdeef426cda5bd18eacd94f82c91f49823a2e9090124212ceea9b08"}, + {file = "executing-2.0.1-py2.py3-none-any.whl", hash = "sha256:eac49ca94516ccc753f9fb5ce82603156e590b27525a8bc32cce8ae302eb61bc"}, + {file = "executing-2.0.1.tar.gz", hash = "sha256:35afe2ce3affba8ee97f2d69927fa823b08b472b7b994e36a52a964b93d16147"}, ] [package.extras] @@ -212,53 +191,50 @@ tests = ["asttokens (>=2.1.0)", "coverage", "coverage-enable-subprocess", "ipyth [[package]] name = "idna" -version = "3.4" +version = "3.6" description = "Internationalized Domain Names in Applications (IDNA)" 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"}, + {file = "idna-3.6-py3-none-any.whl", hash = "sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f"}, + {file = "idna-3.6.tar.gz", hash = "sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca"}, ] [[package]] name = "ipython" -version = "8.16.1" +version = "8.18.1" description = "IPython: Productive Interactive Computing" optional = false python-versions = ">=3.9" files = [ - {file = "ipython-8.16.1-py3-none-any.whl", hash = "sha256:0852469d4d579d9cd613c220af7bf0c9cc251813e12be647cb9d463939db9b1e"}, - {file = "ipython-8.16.1.tar.gz", hash = "sha256:ad52f58fca8f9f848e256c629eff888efc0528c12fe0f8ec14f33205f23ef938"}, + {file = "ipython-8.18.1-py3-none-any.whl", hash = "sha256:e8267419d72d81955ec1177f8a29aaa90ac80ad647499201119e2f05e99aa397"}, + {file = "ipython-8.18.1.tar.gz", hash = "sha256:ca6f079bb33457c66e233e4580ebfc4128855b4cf6370dddd73842a9563e8a27"}, ] [package.dependencies] -appnope = {version = "*", markers = "sys_platform == \"darwin\""} -backcall = "*" colorama = {version = "*", markers = "sys_platform == \"win32\""} decorator = "*" exceptiongroup = {version = "*", markers = "python_version < \"3.11\""} jedi = ">=0.16" matplotlib-inline = "*" pexpect = {version = ">4.3", markers = "sys_platform != \"win32\""} -pickleshare = "*" -prompt-toolkit = ">=3.0.30,<3.0.37 || >3.0.37,<3.1.0" +prompt-toolkit = ">=3.0.41,<3.1.0" pygments = ">=2.4.0" stack-data = "*" traitlets = ">=5" [package.extras] -all = ["black", "curio", "docrepr", "exceptiongroup", "ipykernel", "ipyparallel", "ipywidgets", "matplotlib", "matplotlib (!=3.2.0)", "nbconvert", "nbformat", "notebook", "numpy (>=1.21)", "pandas", "pytest (<7)", "pytest (<7.1)", "pytest-asyncio", "qtconsole", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "stack-data", "testpath", "trio", "typing-extensions"] +all = ["black", "curio", "docrepr", "exceptiongroup", "ipykernel", "ipyparallel", "ipywidgets", "matplotlib", "matplotlib (!=3.2.0)", "nbconvert", "nbformat", "notebook", "numpy (>=1.22)", "pandas", "pickleshare", "pytest (<7)", "pytest (<7.1)", "pytest-asyncio (<0.22)", "qtconsole", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "stack-data", "testpath", "trio", "typing-extensions"] black = ["black"] -doc = ["docrepr", "exceptiongroup", "ipykernel", "matplotlib", "pytest (<7)", "pytest (<7.1)", "pytest-asyncio", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "stack-data", "testpath", "typing-extensions"] +doc = ["docrepr", "exceptiongroup", "ipykernel", "matplotlib", "pickleshare", "pytest (<7)", "pytest (<7.1)", "pytest-asyncio (<0.22)", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "stack-data", "testpath", "typing-extensions"] kernel = ["ipykernel"] nbconvert = ["nbconvert"] nbformat = ["nbformat"] notebook = ["ipywidgets", "notebook"] parallel = ["ipyparallel"] qtconsole = ["qtconsole"] -test = ["pytest (<7.1)", "pytest-asyncio", "testpath"] -test-extra = ["curio", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.21)", "pandas", "pytest (<7.1)", "pytest-asyncio", "testpath", "trio"] +test = ["pickleshare", "pytest (<7.1)", "pytest-asyncio (<0.22)", "testpath"] +test-extra = ["curio", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.22)", "pandas", "pickleshare", "pytest (<7.1)", "pytest-asyncio (<0.22)", "testpath", "trio"] [[package]] name = "jedi" @@ -310,38 +286,27 @@ testing = ["docopt", "pytest (<6.0.0)"] [[package]] name = "pexpect" -version = "4.8.0" +version = "4.9.0" description = "Pexpect allows easy control of interactive console applications." optional = false python-versions = "*" files = [ - {file = "pexpect-4.8.0-py2.py3-none-any.whl", hash = "sha256:0b48a55dcb3c05f3329815901ea4fc1537514d6ba867a152b581d69ae3710937"}, - {file = "pexpect-4.8.0.tar.gz", hash = "sha256:fc65a43959d153d0114afe13997d439c22823a27cefceb5ff35c2178c6784c0c"}, + {file = "pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523"}, + {file = "pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f"}, ] [package.dependencies] ptyprocess = ">=0.5" -[[package]] -name = "pickleshare" -version = "0.7.5" -description = "Tiny 'shelve'-like database with concurrency support" -optional = false -python-versions = "*" -files = [ - {file = "pickleshare-0.7.5-py2.py3-none-any.whl", hash = "sha256:9649af414d74d4df115d5d718f82acb59c9d418196b7b4290ed47a12ce62df56"}, - {file = "pickleshare-0.7.5.tar.gz", hash = "sha256:87683d47965c1da65cdacaf31c8441d12b8044cdec9aca500cd78fc2c683afca"}, -] - [[package]] name = "prompt-toolkit" -version = "3.0.39" +version = "3.0.43" description = "Library for building powerful interactive command lines in Python" optional = false python-versions = ">=3.7.0" files = [ - {file = "prompt_toolkit-3.0.39-py3-none-any.whl", hash = "sha256:9dffbe1d8acf91e3de75f3b544e4842382fc06c6babe903ac9acb74dc6e08d88"}, - {file = "prompt_toolkit-3.0.39.tar.gz", hash = "sha256:04505ade687dc26dc4284b1ad19a83be2f2afe83e7a828ace0c72f3a1df72aac"}, + {file = "prompt_toolkit-3.0.43-py3-none-any.whl", hash = "sha256:a11a29cb3bf0a28a387fe5122cdb649816a957cd9261dcedf8c9f1fef33eacf6"}, + {file = "prompt_toolkit-3.0.43.tar.gz", hash = "sha256:3527b7af26106cbc65a040bcc84839a3566ec1b051bb0bfe953631e704b0ff7d"}, ] [package.dependencies] @@ -374,31 +339,18 @@ tests = ["pytest"] [[package]] name = "pygments" -version = "2.16.1" +version = "2.17.2" description = "Pygments is a syntax highlighting package written in Python." optional = false python-versions = ">=3.7" files = [ - {file = "Pygments-2.16.1-py3-none-any.whl", hash = "sha256:13fc09fa63bc8d8671a6d247e1eb303c4b343eaee81d861f3404db2935653692"}, - {file = "Pygments-2.16.1.tar.gz", hash = "sha256:1daff0494820c69bc8941e407aa20f577374ee88364ee10a98fdbe0aece96e29"}, + {file = "pygments-2.17.2-py3-none-any.whl", hash = "sha256:b27c2826c47d0f3219f29554824c30c5e8945175d888647acd804ddd04af846c"}, + {file = "pygments-2.17.2.tar.gz", hash = "sha256:da46cec9fd2de5be3a8a784f434e4c4ab670b4ff54d605c4c2717e9d49c4c367"}, ] [package.extras] plugins = ["importlib-metadata"] - -[[package]] -name = "python-dateutil" -version = "2.8.2" -description = "Extensions to the standard Python datetime module" -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" +windows-terminal = ["colorama (>=0.4.6)"] [[package]] name = "python-dotenv" @@ -416,13 +368,13 @@ cli = ["click (>=5.0)"] [[package]] name = "pytz" -version = "2023.3" +version = "2023.3.post1" description = "World timezone definitions, modern and historical" 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"}, + {file = "pytz-2023.3.post1-py2.py3-none-any.whl", hash = "sha256:ce42d816b81b68506614c11e8937d3aa9e41007ceb50bfdcb0749b921bf646c7"}, + {file = "pytz-2023.3.post1.tar.gz", hash = "sha256:7b4fddbeb94a1eba4b557da24f19fdf9db575192544270a9101d8509f9f43d7b"}, ] [[package]] @@ -478,48 +430,47 @@ tests = ["cython", "littleutils", "pygments", "pytest", "typeguard"] [[package]] name = "traitlets" -version = "5.11.2" +version = "5.14.0" description = "Traitlets Python configuration system" optional = false python-versions = ">=3.8" files = [ - {file = "traitlets-5.11.2-py3-none-any.whl", hash = "sha256:98277f247f18b2c5cabaf4af369187754f4fb0e85911d473f72329db8a7f4fae"}, - {file = "traitlets-5.11.2.tar.gz", hash = "sha256:7564b5bf8d38c40fa45498072bf4dc5e8346eb087bbf1e2ae2d8774f6a0f078e"}, + {file = "traitlets-5.14.0-py3-none-any.whl", hash = "sha256:f14949d23829023013c47df20b4a76ccd1a85effb786dc060f34de7948361b33"}, + {file = "traitlets-5.14.0.tar.gz", hash = "sha256:fcdaa8ac49c04dfa0ed3ee3384ef6dfdb5d6f3741502be247279407679296772"}, ] [package.extras] docs = ["myst-parser", "pydata-sphinx-theme", "sphinx"] -test = ["argcomplete (>=3.0.3)", "mypy (>=1.5.1)", "pre-commit", "pytest (>=7.0,<7.5)", "pytest-mock", "pytest-mypy-testing"] +test = ["argcomplete (>=3.0.3)", "mypy (>=1.7.0)", "pre-commit", "pytest (>=7.0,<7.5)", "pytest-mock", "pytest-mypy-testing"] [[package]] name = "urllib3" -version = "2.0.7" +version = "2.1.0" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "urllib3-2.0.7-py3-none-any.whl", hash = "sha256:fdb6d215c776278489906c2f8916e6e7d4f5a9b602ccbcfdf7f016fc8da0596e"}, - {file = "urllib3-2.0.7.tar.gz", hash = "sha256:c97dfde1f7bd43a71c8d2a58e369e9b2bf692d1334ea9f9cae55add7d0dd0f84"}, + {file = "urllib3-2.1.0-py3-none-any.whl", hash = "sha256:55901e917a5896a349ff771be919f8bd99aff50b79fe58fec595eb37bbc56bb3"}, + {file = "urllib3-2.1.0.tar.gz", hash = "sha256:df7aa8afb0148fa78488e7899b2c59b5f4ffcfa82e6c54ccb9dd37c1d7b52d54"}, ] [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 = "wcwidth" -version = "0.2.8" +version = "0.2.12" description = "Measures the displayed width of unicode strings in a terminal" optional = false python-versions = "*" files = [ - {file = "wcwidth-0.2.8-py2.py3-none-any.whl", hash = "sha256:77f719e01648ed600dfa5402c347481c0992263b81a027344f3e1ba25493a704"}, - {file = "wcwidth-0.2.8.tar.gz", hash = "sha256:8705c569999ffbb4f6a87c6d1b80f324bd6db952f5eb0b95bc07517f4c1813d4"}, + {file = "wcwidth-0.2.12-py2.py3-none-any.whl", hash = "sha256:f26ec43d96c8cbfed76a5075dac87680124fa84e0855195a6184da9c187f133c"}, + {file = "wcwidth-0.2.12.tar.gz", hash = "sha256:f01c104efdf57971bcb756f054dd58ddec5204dd15fa31d6503ea57947d97c02"}, ] [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "94bb449c680c3d7e00bd9f447f06d9f796f1cf61f50ffe77be16d1f6202e7ce9" +content-hash = "38497ac32db28a82593951f7c090fa1e52bf36e7b6a8c4699c98574beab2e4f7" diff --git a/pyproject.toml b/pyproject.toml index 805127a..51457af 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "healthcheck" -version = "1.1.12" +version = "1.1.13" description = "Internal service endpoint health check for Spatial Support System" authors = ["ASI "] @@ -8,8 +8,7 @@ authors = ["ASI "] python = "^3.10" bottle = "0.12.25" requests = "2.31.0" -python-dateutil = "2.8.2" -pytz = "2023.3" +pytz = "2023.3.post1" python-dotenv = "1.0.0" [tool.poetry.group.dev.dependencies] diff --git a/status.py b/status.py index b6bab44..385c51a 100644 --- a/status.py +++ b/status.py @@ -1,82 +1,81 @@ from bottle import Bottle, static_file, response from datetime import datetime -from dateutil.tz import tzoffset -from dateutil.parser import parse import json import os import requests import xml.etree.ElementTree as ET +from zoneinfo import ZoneInfo -dot_env = os.path.join(os.getcwd(), '.env') +dot_env = os.path.join(os.getcwd(), ".env") if os.path.exists(dot_env): from dotenv import load_dotenv load_dotenv() app = application = Bottle() -OUTPUT_TEMPLATE = ''' +TZ = ZoneInfo(os.environ.get("TZ", "Australia/Perth")) +OUTPUT_TEMPLATE = """ - - - DBCA Spatial Support System health checks - - - -

DBCA Spatial Support System health checks

- {} - -''' -RT_URL = os.environ.get('RT_URL', 'https://resourcetracking.dbca.wa.gov.au') -SSS_DEVICES_URL = RT_URL + '/api/v1/device/?seen__isnull=false&format=json' -SSS_IRIDIUM_URL = RT_URL + '/api/v1/device/?seen__isnull=false&source_device_type=iriditrak&format=json' -SSS_TRACPLUS_URL = RT_URL + '/api/v1/device/?seen__isnull=false&source_device_type=tracplus&format=json' -SSS_DFES_URL = RT_URL + '/api/v1/device/?seen__isnull=false&source_device_type=dfes&format=json' -SSS_FLEETCARE_URL = RT_URL + '/api/v1/device/?seen__isnull=false&source_device_type=fleetcare&format=json' -CSW_API = os.environ.get('CSW_API', 'https://csw.dbca.wa.gov.au/catalogue/api/records/?format=json&application__name=sss') -KMI_URL = os.environ.get('KMI_URL', 'https://kmi.dbca.wa.gov.au/geoserver') + + +DBCA Spatial Support System health checks + + + +

DBCA Spatial Support System health checks

+{} + +""" +RT_URL = os.environ.get("RT_URL", "https://resourcetracking.dbca.wa.gov.au") +SSS_DEVICES_URL = RT_URL + "/api/v1/device/?seen__isnull=false&format=json" +SSS_IRIDIUM_URL = RT_URL + "/api/v1/device/?seen__isnull=false&source_device_type=iriditrak&format=json" +SSS_TRACPLUS_URL = RT_URL + "/api/v1/device/?seen__isnull=false&source_device_type=tracplus&format=json" +SSS_DFES_URL = RT_URL + "/api/v1/device/?seen__isnull=false&source_device_type=dfes&format=json" +SSS_FLEETCARE_URL = RT_URL + "/api/v1/device/?seen__isnull=false&source_device_type=fleetcare&format=json" +CSW_API = os.environ.get("CSW_API", "https://csw.dbca.wa.gov.au/catalogue/api/records/?format=json&application__name=sss") +KMI_URL = os.environ.get("KMI_URL", "https://kmi.dbca.wa.gov.au/geoserver") KMI_WFS_URL = f"{KMI_URL}/wfs" KMI_WMTS_URL = f"{KMI_URL}/public/gwc/service/wmts" -BFRS_URL = os.environ.get('BFRS_URL', 'https://bfrs.dbca.wa.gov.au/api/v1/profile/?format=json') -AUTH2_URL = os.environ.get('AUTH2_URL', 'https://auth2.dbca.wa.gov.au/healthcheck') -AUTH2_STATUS_URL = os.environ.get('AUTH2_URL', 'https://auth2.dbca.wa.gov.au/status') -USER_SSO = os.environ.get('USER_SSO', 'asi@dbca.wa.gov.au') -PASS_SSO = os.environ.get('PASS_SSO', 'password') -TRACKING_POINTS_MAX_DELAY = int(os.environ.get('TRACKING_POINTS_MAX_DELAY', 30)) # Minutes -DBCA_GOING_BUSHFIRES_URL = os.environ.get('DBCA_GOING_BUSHFIRES_URL', None) -AWST_TZ = tzoffset('AWST', 28800) # AWST timezone offset. - - -@app.route('/readiness') +BFRS_URL = os.environ.get("BFRS_URL", "https://bfrs.dbca.wa.gov.au/api/v1/profile/?format=json") +AUTH2_URL = os.environ.get("AUTH2_URL", "https://auth2.dbca.wa.gov.au/healthcheck") +AUTH2_STATUS_URL = os.environ.get("AUTH2_URL", "https://auth2.dbca.wa.gov.au/status") +USER_SSO = os.environ.get("USER_SSO", "asi@dbca.wa.gov.au") +PASS_SSO = os.environ.get("PASS_SSO", "password") +TRACKING_POINTS_MAX_DELAY = int(os.environ.get("TRACKING_POINTS_MAX_DELAY", 30)) # Minutes +DBCA_GOING_BUSHFIRES_URL = os.environ.get("DBCA_GOING_BUSHFIRES_URL", None) +DBCA_CONTROL_LINES_URL = os.environ.get("DBCA_CONTROL_LINES_URL", None) +DFES_GOING_BUSHFIRES_URL = os.environ.get("DFES_GOING_BUSHFIRES_URL", None) +ALL_CURRENT_HOTSPOTS = os.environ.get("ALL_CURRENT_HOTSPOTS", None) +LIGHTNING_24H = os.environ.get("LIGHTNING_24H", None) +LIGHTNING_24_48H = os.environ.get("LIGHTNING_24_48H", None) +LIGHTNING_48_72H = os.environ.get("LIGHTNING_48_72H", None) +FUEL_AGE_1_6Y = os.environ.get("FUEL_AGE_1_6Y", None) +FUEL_AGE_NONFOREST_1_6Y = os.environ.get("FUEL_AGE_NONFOREST_1_6Y", None) +COG_BASEMAP = os.environ.get("COG_BASEMAP", None) +STATE_BASEMAP = os.environ.get("STATE_BASEMAP", None) +DBCA_BURN_PROGRAM = os.environ.get("DBCA_BURN_PROGRAM", None) +DAILY_ACTIVE_BURNS = os.environ.get("DAILY_ACTIVE_BURNS", None) +DBCA_LANDS_WATERS = os.environ.get("DBCA_LANDS_WATERS", None) +DBCA_LANDS_WATERS_INTEREST = os.environ.get("DBCA_LANDS_WATERS_INTEREST", None) + + +@app.route("/readiness") def readiness(): - return 'OK' + return "OK" -@app.route('/liveness') +@app.route("/liveness") def liveness(): - return 'OK' + return "OK" -@app.route('/json') -def healthcheck_json(): +def healthcheck(): + """Query HTTP sources and derive a dictionary of response successes. + """ d = { - 'server_time': datetime.now().astimezone(AWST_TZ).isoformat(), - 'success': True, - 'latest_point': None, - 'latest_point_delay': None, - 'iridium_latest_point': None, - 'iridium_latest_point_delay': None, - 'tracplus_latest_point': None, - 'tracplus_latest_point_delay': None, - 'dfes_latest_point': None, - 'dfes_latest_point_delay': None, - 'fleetcare_latest_point': None, - 'fleetcare_latest_point_delay': None, - 'csw_catalogue_count': None, - 'todays_burns_count': None, - 'kmi_wmts_layer_count': None, - 'bfrs_profile_api_endpoint': None, - 'auth2_status': None + "server_time": datetime.now().astimezone(TZ).isoformat(timespec="seconds"), + "success": True, } session = requests.Session() @@ -86,107 +85,249 @@ def healthcheck_json(): trackingdata = session.get(SSS_DEVICES_URL) trackingdata.raise_for_status() trackingdata = trackingdata.json() - t = parse(trackingdata["objects"][0]["seen"]) - d['latest_point'] = t.astimezone(AWST_TZ).isoformat() - d['latest_point_delay'] = trackingdata["objects"][0]["age_minutes"] + t = datetime.fromisoformat(trackingdata["objects"][0]["seen"]).astimezone(TZ) + d["latest_point"] = t.isoformat() + d["latest_point_delay"] = trackingdata["objects"][0]["age_minutes"] if trackingdata["objects"][0]["age_minutes"] > TRACKING_POINTS_MAX_DELAY: - d['success'] = False + d["success"] = False except Exception as e: - d['success'] = False + d["success"] = False try: trackingdata = session.get(SSS_IRIDIUM_URL) trackingdata.raise_for_status() trackingdata = trackingdata.json() - t = parse(trackingdata["objects"][0]["seen"]) - d['iridium_latest_point'] = t.astimezone(AWST_TZ).isoformat() - d['iridium_latest_point_delay'] = trackingdata["objects"][0]["age_minutes"] + t = datetime.fromisoformat(trackingdata["objects"][0]["seen"]).astimezone(TZ) + d["iridium_latest_point"] = t.isoformat() + d["iridium_latest_point_delay"] = trackingdata["objects"][0]["age_minutes"] if trackingdata["objects"][0]["age_minutes"] > TRACKING_POINTS_MAX_DELAY: - d['success'] = False + d["success"] = False except Exception as e: - d['success'] = False + d["success"] = False try: trackingdata = session.get(SSS_TRACPLUS_URL) trackingdata.raise_for_status() trackingdata = trackingdata.json() - t = parse(trackingdata["objects"][0]["seen"]) - d['tracplus_latest_point'] = t.astimezone(AWST_TZ).isoformat() - d['tracplus_latest_point_delay'] = trackingdata["objects"][0]["age_minutes"] + t = datetime.fromisoformat(trackingdata["objects"][0]["seen"]).astimezone(TZ) + d["tracplus_latest_point"] = t.isoformat() + d["tracplus_latest_point_delay"] = trackingdata["objects"][0]["age_minutes"] except Exception as e: - d['success'] = False + d["success"] = False try: trackingdata = session.get(SSS_DFES_URL) trackingdata.raise_for_status() trackingdata = trackingdata.json() - t = parse(trackingdata["objects"][0]["seen"]) - d['dfes_latest_point'] = t.astimezone(AWST_TZ).isoformat() - d['dfes_latest_point_delay'] = trackingdata["objects"][0]["age_minutes"] + t = datetime.fromisoformat(trackingdata["objects"][0]["seen"]).astimezone(TZ) + d["dfes_latest_point"] = t.isoformat() + d["dfes_latest_point_delay"] = trackingdata["objects"][0]["age_minutes"] except Exception as e: - d['success'] = False + d["success"] = False try: trackingdata = session.get(SSS_FLEETCARE_URL) trackingdata.raise_for_status() trackingdata = trackingdata.json() - t = parse(trackingdata["objects"][0]["seen"]) - d['fleetcare_latest_point'] = t.astimezone(AWST_TZ).isoformat() - d['fleetcare_latest_point_delay'] = trackingdata["objects"][0]["age_minutes"] + t = datetime.fromisoformat(trackingdata["objects"][0]["seen"]).astimezone(TZ) + d["fleetcare_latest_point"] = t.isoformat() + d["fleetcare_latest_point_delay"] = trackingdata["objects"][0]["age_minutes"] if trackingdata["objects"][0]["age_minutes"] > TRACKING_POINTS_MAX_DELAY: - d['success'] = False + d["success"] = False except Exception as e: - d['success'] = False + d["success"] = False try: resp = session.get(CSW_API) resp.raise_for_status() j = resp.json() - d['csw_catalogue_count'] = len(j) + d["csw_catalogue_count"] = len(j) except Exception as e: - d['success'] = False + d["success"] = False try: - params = {'service': 'wfs', 'version': '1.1.0', 'request': 'GetFeature', 'typeNames': 'public:todays_burns', 'resultType': 'hits'} + params = {"service": "wfs", "version": "1.1.0", "request": "GetFeature", "typeNames": "public:todays_burns", "resultType": "hits"} # Send an anonymous request. resp = requests.get(KMI_WFS_URL, params=params) if not resp.status_code == 200: resp.raise_for_status() root = ET.fromstring(resp.content) resp_d = {i[0]: i[1] for i in root.items()} - d['todays_burns_count'] = int(resp_d['numberOfFeatures']) + d["todays_burns_count"] = int(resp_d["numberOfFeatures"]) except Exception as e: - d['success'] = False + d["success"] = False try: # Send an anonymous request. - resp = requests.get(KMI_WMTS_URL, params={'request': 'getcapabilities'}) + resp = requests.get(KMI_WMTS_URL, params={"request": "getcapabilities"}) if not resp.status_code == 200: resp.raise_for_status() root = ET.fromstring(resp.content) - ns = {'wmts': 'http://www.opengis.net/wmts/1.0', 'ows': 'http://www.opengis.net/ows/1.1'} - layers = root.findall('.//wmts:Layer', ns) - d['kmi_wmts_layer_count'] = len(layers) + ns = {"wmts": "http://www.opengis.net/wmts/1.0", "ows": "http://www.opengis.net/ows/1.1"} + layers = root.findall(".//wmts:Layer", ns) + d["kmi_wmts_layer_count"] = len(layers) except Exception as e: - d['success'] = False + d["success"] = False try: resp = session.get(BFRS_URL) resp.raise_for_status() j = resp.json() - d['bfrs_profile_api_endpoint'] = True + d["bfrs_profile_api_endpoint"] = True except Exception as e: - d['success'] = False + d["success"] = False if DBCA_GOING_BUSHFIRES_URL: try: url = f"{KMI_URL}/{DBCA_GOING_BUSHFIRES_URL}" resp = session.get(url) resp.raise_for_status() - d['dbca_going_bushfires_layer'] = True + d["dbca_going_bushfires_layer"] = True + except Exception as e: + d["dbca_going_bushfires_layer"] = False + d["success"] = False + + if DBCA_CONTROL_LINES_URL: + try: + url = f"{KMI_URL}/{DBCA_CONTROL_LINES_URL}" + resp = session.get(url) + resp.raise_for_status() + d["dbca_control_lines_layer"] = True + except Exception as e: + d["dbca_control_lines_layer"] = False + d["success"] = False + + if DFES_GOING_BUSHFIRES_URL: + try: + url = f"{KMI_URL}/{DFES_GOING_BUSHFIRES_URL}" + resp = session.get(url) + resp.raise_for_status() + d["dfes_going_bushfires_layer"] = True + except Exception as e: + d["dfes_going_bushfires_layer"] = False + d["success"] = False + + if ALL_CURRENT_HOTSPOTS: + try: + url = f"{KMI_URL}/{ALL_CURRENT_HOTSPOTS}" + resp = session.get(url) + resp.raise_for_status() + d["all_current_hotspots_layer"] = True + except Exception as e: + d["all_current_hotspots_layer"] = False + d["success"] = False + + if LIGHTNING_24H: + try: + url = f"{KMI_URL}/{LIGHTNING_24H}" + resp = session.get(url) + resp.raise_for_status() + d["lightning_24h_layer"] = True + except Exception as e: + d["lightning_24h_layer"] = False + d["success"] = False + + if LIGHTNING_24_48H: + try: + url = f"{KMI_URL}/{LIGHTNING_24_48H}" + resp = session.get(url) + resp.raise_for_status() + d["lightning_24_48h_layer"] = True + except Exception as e: + d["lightning_24_48h_layer"] = False + d["success"] = False + + if LIGHTNING_48_72H: + try: + url = f"{KMI_URL}/{LIGHTNING_48_72H}" + resp = session.get(url) + resp.raise_for_status() + d["lightning_48_72h_layer"] = True + except Exception as e: + d["lightning_48_72h_layer"] = False + d["success"] = False + + if FUEL_AGE_1_6Y: + try: + url = f"{KMI_URL}/{FUEL_AGE_1_6Y}" + resp = session.get(url) + resp.raise_for_status() + d["fuel_age_1_6y_layer"] = True + except Exception as e: + d["fuel_age_1_6y_layer"] = False + d["success"] = False + + if FUEL_AGE_NONFOREST_1_6Y: + try: + url = f"{KMI_URL}/{FUEL_AGE_NONFOREST_1_6Y}" + resp = session.get(url) + resp.raise_for_status() + d["fuel_age_nonforest_1_6y_layer"] = True except Exception as e: - d['dbca_going_bushfires_layer'] = False - d['success'] = False + d["fuel_age_nonforest_1_6y_layer"] = False + d["success"] = False + + if COG_BASEMAP: + try: + url = f"{KMI_URL}/{COG_BASEMAP}" + resp = session.get(url) + resp.raise_for_status() + d["cog_basemap_layer"] = True + except Exception as e: + d["cog_basemap_layer"] = False + d["success"] = False + + if STATE_BASEMAP: + try: + url = f"{KMI_URL}/{STATE_BASEMAP}" + resp = session.get(url) + resp.raise_for_status() + d["state_basemap_layer"] = True + except Exception as e: + d["state_basemap_layer"] = False + d["success"] = False + + if DBCA_BURN_PROGRAM: + try: + url = f"{KMI_URL}/{DBCA_BURN_PROGRAM}" + resp = session.get(url) + resp.raise_for_status() + d["dbca_burn_program_layer"] = True + except Exception as e: + d["dbca_burn_program_layer"] = False + d["success"] = False + + if DAILY_ACTIVE_BURNS: + try: + url = f"{KMI_URL}/{DAILY_ACTIVE_BURNS}" + # Don't use an authenticated session to download public layers. + resp = requests.get(url) + resp.raise_for_status() + d["daily_active_burns_layer"] = True + except Exception as e: + d["daily_active_burns_layer"] = False + d["success"] = False + + if DBCA_LANDS_WATERS: + try: + url = f"{KMI_URL}/{DBCA_LANDS_WATERS}" + # Don't use an authenticated session to download public layers. + resp = requests.get(url) + resp.raise_for_status() + d["dbca_lands_waters_layer"] = True + except Exception as e: + d["dbca_lands_waters_layer"] = False + d["success"] = False + + if DBCA_LANDS_WATERS_INTEREST: + try: + url = f"{KMI_URL}/{DBCA_LANDS_WATERS_INTEREST}" + resp = session.get(url) + resp.raise_for_status() + d["dbca_lands_waters_interest_layer"] = True + except Exception as e: + d["dbca_lands_waters_interest_layer"] = False + d["success"] = False try: resp = session.get(AUTH2_STATUS_URL) @@ -194,202 +335,194 @@ def healthcheck_json(): j = resp.json() d["auth2_status"] = j["healthy"] except Exception as e: - d['success'] = False + d["success"] = False - response.content_type = 'application/json' - response.set_header('Cache-Control', 'private, max-age=0') - return json.dumps(d) + return d -@app.route('/') -def healthcheck(): - now = datetime.now().astimezone(AWST_TZ) - output = f"Server time: {now.isoformat()}

" - success = True - session = requests.Session() - session.auth = (USER_SSO, PASS_SSO) +@app.route("/json") +def healthcheck_json(): + d = healthcheck() + response.content_type = "application/json" + # Mark response as 'never cache'. + response.set_header("Cache-Control", "private, max-age=0") + return json.dumps(d) - # All resource point tracking - try: - trackingdata = session.get(SSS_DEVICES_URL) - trackingdata.raise_for_status() - trackingdata = trackingdata.json() - # Output latest point - t = parse(trackingdata["objects"][0]["seen"]) - output += f"Latest tracking point (AWST): {t.astimezone(AWST_TZ).isoformat()}
" - # Output the delay - if trackingdata["objects"][0]["age_minutes"] > TRACKING_POINTS_MAX_DELAY: - success = False - output += "Resource Tracking Delay too high! Currently {0:.1f} min (max {1} min)

".format( - trackingdata["objects"][0]["age_minutes"], - TRACKING_POINTS_MAX_DELAY, - ) - else: - output += "Resource Tracking delay currently {0:.1f} min (max {1} min)

".format( - trackingdata["objects"][0]["age_minutes"], - TRACKING_POINTS_MAX_DELAY, - ) - except Exception as e: - success = False - output += f"Resource Tracking load had an error: {e}

" - # Iridium tracking - try: - trackingdata = session.get(SSS_IRIDIUM_URL) - trackingdata.raise_for_status() - trackingdata = trackingdata.json() - # Output latest point - t = parse(trackingdata["objects"][0]["seen"]) - output += f"Latest Iridium tracking point (AWST): {t.astimezone(AWST_TZ).isoformat()}
" - # Output the delay - if trackingdata["objects"][0]["age_minutes"] > TRACKING_POINTS_MAX_DELAY: - success = False - output += "Iridium tracking delay too high! Currently {0:.1f} min (max {1} min)

".format( - trackingdata["objects"][0]["age_minutes"], - TRACKING_POINTS_MAX_DELAY, - ) - else: - output += "Iridium tracking delay currently {0:.1f} min (max {1} min)

".format( - trackingdata["objects"][0]["age_minutes"], - TRACKING_POINTS_MAX_DELAY, - ) - except Exception as e: - success = False - output += f"Iridium resource tracking load had an error: {e}

" +@app.route("/") +def healthcheck_http(): + d = healthcheck() + output = f"

Server time: {d['server_time']}

\n" + output += "

\n" - # Tracplus Tracking - try: - trackingdata = session.get(SSS_TRACPLUS_URL) - trackingdata.raise_for_status() - trackingdata = trackingdata.json() - # Output latest point - t = parse(trackingdata["objects"][0]["seen"]) - output += f"Latest Tracplus tracking point (AWST): {t.astimezone(AWST_TZ).isoformat()}
" - # Output the delay - output += "Tracplus tracking delay currently {0:.1f} min

".format( - trackingdata["objects"][0]["age_minutes"], + output += f"Latest tracking point: {d['latest_point']}
\n" + if d["latest_point_delay"] > TRACKING_POINTS_MAX_DELAY: + output += "Resource Tracking Delay too high! Currently {0:.1f} min (max {1} min)
\n".format( + d["latest_point_delay"], + TRACKING_POINTS_MAX_DELAY, + ) + else: + output += "Resource Tracking delay currently {0:.1f} min (max {1} min)
\n".format( + d["latest_point_delay"], + TRACKING_POINTS_MAX_DELAY, ) - except Exception as e: - pass # Currently this does not cause the healthcheck to fail. - # DFES Tracking - try: - trackingdata = session.get(SSS_DFES_URL) - trackingdata.raise_for_status() - trackingdata = trackingdata.json() - # Output latest point - t = parse(trackingdata["objects"][0]["seen"]) - output += f"Latest DFES tracking point (AWST): {t.astimezone(AWST_TZ).isoformat()}
" - # Output the delay - output += "DFES tracking delay currently {0:.1f} min

".format( - trackingdata["objects"][0]["age_minutes"], + output += f"Latest Iridium tracking point: {d['iridium_latest_point']}
\n" + if d["iridium_latest_point_delay"] > TRACKING_POINTS_MAX_DELAY: + output += "Iridium tracking delay too high! Currently {0:.1f} min (max {1} min)
\n".format( + d["iridium_latest_point_delay"], + TRACKING_POINTS_MAX_DELAY, + ) + else: + output += "Iridium tracking delay currently {0:.1f} min (max {1} min)
\n".format( + d["iridium_latest_point_delay"], + TRACKING_POINTS_MAX_DELAY, ) - except Exception as e: - pass # Currently this does not cause the healthcheck to fail. - # Fleetcare Tracking - try: - trackingdata = session.get(SSS_FLEETCARE_URL) - trackingdata.raise_for_status() - trackingdata = trackingdata.json() - # Output latest point - t = parse(trackingdata["objects"][0]["seen"]) - output += f"Latest Fleetcare tracking point (AWST): {t.astimezone(AWST_TZ).isoformat()}
" - # Output the delay - if trackingdata["objects"][0]["age_minutes"] > TRACKING_POINTS_MAX_DELAY: - success = False - output += "Fleetcare tracking delay too high! Currently {0:.1f} min (max {1} min)

".format( - trackingdata["objects"][0]["age_minutes"], - TRACKING_POINTS_MAX_DELAY, - ) - else: - output += "Fleetcare tracking delay currently {0:.1f} min (max {1} min)

".format( - trackingdata["objects"][0]["age_minutes"], - TRACKING_POINTS_MAX_DELAY, - ) - except Exception as e: - success = False - output += f"Fleetcare resource tracking load had an error: {e}

" + output += f"Latest Tracplus tracking point: {d['tracplus_latest_point']}
\n" + output += "Tracplus tracking delay currently {0:.1f} min
\n".format( + d["tracplus_latest_point_delay"], + ) + + output += f"Latest DFES tracking point: {d['dfes_latest_point']}
\n" + output += "DFES tracking delay currently {0:.1f} min
\n".format( + d['dfes_latest_point_delay'], + ) + + output += f"Latest Fleetcare tracking point: {d['fleetcare_latest_point']}
\n" + if d["fleetcare_latest_point_delay"] > TRACKING_POINTS_MAX_DELAY: + output += "Fleetcare tracking delay too high! Currently {0:.1f} min (max {1} min)
\n".format( + d["fleetcare_latest_point_delay"], + TRACKING_POINTS_MAX_DELAY, + ) + else: + output += "Fleetcare tracking delay currently {0:.1f} min (max {1} min)
\n".format( + d["fleetcare_latest_point_delay"], + TRACKING_POINTS_MAX_DELAY, + ) - # CSW catalogue API endpoint - try: - resp = session.get(CSW_API) - resp.raise_for_status() - resp = resp.json() - output += f'CSW spatial catalogue for SSS: {len(resp)} layers

' - except Exception as e: - success = False - output += f"CSW API endpoint returned an error: {e}

" + output += "

\n

\n" - # Today's Burns WFS endpoint - try: - params = {'service': 'wfs', 'version': '1.1.0', 'request': 'GetFeature', 'typeNames': 'public:todays_burns', 'resultType': 'hits'} - # Send an anonymous request, as KMI doesn't always support basic auth nicely. - resp = requests.get(KMI_WFS_URL, params=params) - resp.raise_for_status() - root = ET.fromstring(resp.content) - d = {i[0]: i[1] for i in root.items()} - output += f"Today's burns count: {d['numberOfFeatures']}

" - except Exception as e: - success = False - output += f"Today's Burns WFS endpoint returned an error: {e}

" + if d["csw_catalogue_count"]: + output += f"CSW spatial catalogue for SSS: {d['csw_catalogue_count']} layers
\n" + else: + output += f"CSW API endpoint error
\n" - # KMI WMTS endpoint - try: - params = {'request': 'getcapabilities'} - # Send an anonymous request, as KMI doesn't always support basic auth nicely. - resp = requests.get(KMI_WMTS_URL, params=params) - resp.raise_for_status() - root = ET.fromstring(resp.content) - ns = {'wmts': 'http://www.opengis.net/wmts/1.0', 'ows': 'http://www.opengis.net/ows/1.1'} - layers = root.findall('.//wmts:Layer', ns) - output += f'KMI WMTS layer count (public workspace): {len(layers)}

' - except Exception as e: - success = False - output += f"KMI WMTS GetCapabilities request returned an error: {e}

" + if d["todays_burns_count"]: + output += f"Today's burns count (KMI): {d['todays_burns_count']}
\n" + else: + output += f"Today's burns count (KMI): error
\n" - # BFRS profile API endpoint - try: - resp = session.get(BFRS_URL) - resp.raise_for_status() - output += 'BFRS profile API endpoint: OK

' - except Exception as e: - success = False - output += f"BFRS profile API endpoint returned an error: {e}

" + if d["kmi_wmts_layer_count"]: + output += f"KMI WMTS layer count (public workspace): {d['kmi_wmts_layer_count']}
\n" + else: + output += f"KMI WMTS GetCapabilities error
\n" - if DBCA_GOING_BUSHFIRES_URL: - try: - url = f"{KMI_URL}/{DBCA_GOING_BUSHFIRES_URL}" - resp = session.get(url) - resp.raise_for_status() - output += 'DBCA Going Bushfires layer (KMI): OK

' - except Exception as e: - output += f"DBCA Going Bushfires layer (KMI) returned an error: {e}

" + if d["bfrs_profile_api_endpoint"]: + output += "BFRS profile API endpoint: OK
\n" + else: + output += f"BFRS profile API endpoint error
\n" - # AUTH2 healthcheck - try: - resp = session.get(AUTH2_URL) - resp.raise_for_status() - output += 'AUTH2 status: OK

' - except Exception as e: - success = False - output += f"AUTH2 returned an error: {e}

" + output += "

\n

\n" + + if d["dbca_going_bushfires_layer"]: + output += "DBCA Going Bushfires layer (KMI): OK
\n" + else: + output += f"DBCA Going Bushfires layer (KMI) error
\n" + + if d["dbca_control_lines_layer"]: + output += "DBCA Control Lines layer (KMI): OK
\n" + else: + output += f"DBCA Control Lines (KMI) error
\n" + + if d["dfes_going_bushfires_layer"]: + output += "DFES Going Bushfires layer (KMI): OK
\n" + else: + output += f"DFES Going Bushfires layer (KMI) error
\n" + + if d["all_current_hotspots_layer"]: + output += "All current hotspots layer (KMI): OK
\n" + else: + output += f"All current hotspots layer (KMI) error
\n" + + if d["lightning_24h_layer"]: + output += "Lightning 24h layer (KMI): OK
\n" + else: + output += f"Lightning 24h layer (KMI) error
\n" + + if d["lightning_24_48h_layer"]: + output += "Lightning 24-48h layer (KMI): OK
\n" + else: + output += f"Lightning 24-48h layer (KMI) error
\n" + + if d["lightning_48_72h_layer"]: + output += "Lightning 48-72h layer (KMI): OK
\n" + else: + output += f"Lightning 48-72h layer (KMI) error
\n" + + if d["fuel_age_1_6y_layer"]: + output += "Fuel age 1-6+ years layer (KMI): OK
\n" + else: + output += f"Fuel age 1-6+ years layer (KMI) error
\n" + + if d["fuel_age_nonforest_1_6y_layer"]: + output += "Fuel age non forest 1-6+ years layer (KMI): OK
\n" + else: + output += f"Fuel age non forest 1-6+ years layer (KMI) error
\n" + + if d["cog_basemap_layer"]: + output += "COG basemap layer (KMI): OK
\n" + else: + output += f"COG basemap layer (KMI) error
\n" + + if d["state_basemap_layer"]: + output += "State basemap layer (KMI): OK
\n" + else: + output += f"State basemap layer (KMI) error
\n" + + if d["dbca_burn_program_layer"]: + output += "DBCA burn options program layer (KMI): OK
\n" + else: + output += f"DBCA burn options program layer (KMI) error
\n" + + if d["daily_active_burns_layer"]: + output += "Daily active and planned prescribed burns layer (KMI): OK
\n" + else: + output += f"Daily active and planned prescribed burns layer (KMI) error
\n" + + if d["dbca_lands_waters_layer"]: + output += "DBCA legislated lands and waters layer (KMI): OK
\n" + else: + output += f"DBCA legislated lands and waters layer (KMI) error
\n" + + if d["dbca_lands_waters_interest_layer"]: + output += "DBCA lands and waters of interest layer (KMI): OK
\n" + else: + output += f"DBCA lands and waters of interest layer (KMI) error
\n" + + output += "

\n

\n" + + if d["auth2_status"]: + output += "AUTH2 status: OK
\n" + else: + output += f"AUTH2 error
\n" - # Success or failure. - if success: - output += "Finished checks, healthcheck succeeded!" + output += "

\n

\n" + if d["success"]: + output += "Finished checks, healthcheck succeeded!" else: - output += "Finished checks, something is wrong =(" + output += "Finished checks, something is wrong =(" + output += "

" - response.set_header('Cache-Control', 'private, max-age=0') + response.set_header("Cache-Control", "private, max-age=0") return OUTPUT_TEMPLATE.format(output) -@app.route('/favicon.ico', method='GET') +@app.route("/favicon.ico", method="GET") def get_favicon(): - return static_file('favicon.ico', root='./static/images/') + return static_file("favicon.ico", root="./static/images/") -if __name__ == '__main__': +if __name__ == "__main__": from bottle import run - run(application, host='0.0.0.0', port=os.environ.get('PORT', 8080)) + run(application, host="0.0.0.0", port=os.environ.get("PORT", 8080))