From e582fb2f219145fa8332b110fa3a3093ba07a836 Mon Sep 17 00:00:00 2001 From: Jon Wood Date: Mon, 1 Apr 2024 21:38:09 +0000 Subject: [PATCH] Bare bones notification support --- apps/notifications/__init__.py | 11 + apps/notifications/views.py | 43 +++ css/notifications.scss | 7 + gulpfile.js | 5 +- js/notifications.js | 33 +++ js/serviceworker.js | 10 + main.py | 2 + models/web_push.py | 17 ++ poetry.lock | 424 ++++++++++++++++++++++++++++- pyproject.toml | 1 + templates/notifications/index.html | 23 ++ 11 files changed, 570 insertions(+), 6 deletions(-) create mode 100644 apps/notifications/__init__.py create mode 100644 apps/notifications/views.py create mode 100644 css/notifications.scss create mode 100644 js/notifications.js create mode 100644 templates/notifications/index.html diff --git a/apps/notifications/__init__.py b/apps/notifications/__init__.py new file mode 100644 index 000000000..9904f7c68 --- /dev/null +++ b/apps/notifications/__init__.py @@ -0,0 +1,11 @@ +""" + Notifications App + + Push/SMS notifcations and management thereof +""" + +from flask import Blueprint + +notifications = Blueprint("notifications", __name__) + +from . import views # noqa diff --git a/apps/notifications/views.py b/apps/notifications/views.py new file mode 100644 index 000000000..eb8d6c823 --- /dev/null +++ b/apps/notifications/views.py @@ -0,0 +1,43 @@ +from apps.common import json_response +from main import db +from flask import render_template, request, current_app as app +from flask_login import current_user, login_required + +from . import notifications +from models.web_push import public_key, WebPushTarget + + +@notifications.route("/") +@login_required +def index(): + return render_template("notifications/index.html", public_key=public_key()) + + +@notifications.route("/register", methods=["POST"]) +@json_response +@login_required +def register(): + payload = request.json + + target = WebPushTarget.query.filter_by( + user=current_user, endpoint=payload["endpoint"] + ).first() + + if target is None: + app.logger.info("Creating new target") + target = WebPushTarget( + user=current_user, + endpoint=payload["endpoint"], + subscription_info=payload, + expires=payload.get("expires", None), + ) + + db.session.add(target) + db.session.commit() + else: + app.logger.info("Using existing target") + + return { + "id": target.id, + "user_id": target.user_id, + } diff --git a/css/notifications.scss b/css/notifications.scss new file mode 100644 index 000000000..1e30a6f2f --- /dev/null +++ b/css/notifications.scss @@ -0,0 +1,7 @@ +.state { + display: none; +} + +.state.visible { + display: block; +} diff --git a/gulpfile.js b/gulpfile.js index 6d4cff1e0..7d71a996f 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -93,6 +93,7 @@ const main_js = (cb) => pump(jsBuild('main.js'), cb), volunteer_schedule_js = (cb) => pump(jsBuild('volunteer-schedule.js'), cb), arrivals_js = (cb) => pump(jsBuild('arrivals.js'), cb), serviceworker_js = (cb) => pump(jsBuild('serviceworker.js'), cb), + notifications_js = (cb) => pump(jsBuild('notifications.js'), cb); function js(cb) { @@ -102,7 +103,8 @@ function js(cb) { schedule_js, volunteer_schedule_js, arrivals_js, - serviceworker_js + serviceworker_js, + notifications_js )(cb); } @@ -116,6 +118,7 @@ function css(cb) { 'css/receipt.scss', 'css/schedule.scss', 'css/volunteer_schedule.scss', + 'css/notifications.scss', 'css/flask-admin.scss', 'css/dhtmlxscheduler_flat.css' ]), diff --git a/js/notifications.js b/js/notifications.js new file mode 100644 index 000000000..e4454d656 --- /dev/null +++ b/js/notifications.js @@ -0,0 +1,33 @@ +async function enableNotifications(event) { + let vapid_key = document.querySelector("meta[name=vapid_key]").getAttribute("value"); + let worker = await navigator.serviceWorker.ready; + let result = await worker.pushManager.subscribe({ + userVisibleOnly: true, + applicationServerKey: vapid_key, + }); + + let response = await fetch("/account/notifications/register", { + method: "POST", + headers: { + "Content-Type": "application/json" + }, + body: JSON.stringify(result.toJSON()) + }); +} + +async function checkPermissions() { + let worker = await navigator.serviceWorker.ready; + + if ("pushManager" in worker) { + let permissions = await worker.pushManager.permissionState(); + document.getElementById('notification-state').querySelectorAll('.state').forEach(el => { el.classList.add('visible') }) + document.getElementById(`notification-state-${permissions}`).classList.add('visible') + } else { + console.log("No push notification support."); + } +} + +if ("serviceWorker" in navigator) { + checkPermissions(); + document.getElementById("enable-notifications").addEventListener("click", enableNotifications); +} diff --git a/js/serviceworker.js b/js/serviceworker.js index 0344139bd..c1aa0492b 100644 --- a/js/serviceworker.js +++ b/js/serviceworker.js @@ -69,3 +69,13 @@ registerRoute( ], }), ); + +addEventListener("push", (event) => { + console.log("Push event received", event); + const message = event.data.text() + self.registration.showNotification(message); +}); + +addEventListener("notificationclick", (event) => { + self.clients.openWindow("http://localhost:2345"); +}); diff --git a/main.py b/main.py index 10e8c02d4..5d105fb9f 100644 --- a/main.py +++ b/main.py @@ -314,6 +314,7 @@ def shell_imports(): from apps.volunteer import volunteer from apps.volunteer.admin import volunteer_admin from apps.volunteer.admin.notify import notify + from apps.notifications import notifications app.register_blueprint(base) app.register_blueprint(users) @@ -329,6 +330,7 @@ def shell_imports(): app.register_blueprint(admin, url_prefix="/admin") app.register_blueprint(volunteer, url_prefix="/volunteer") app.register_blueprint(notify, url_prefix="/volunteer/admin/notify") + app.register_blueprint(notifications, url_prefix="/account/notifications") volunteer_admin.init_app(app) diff --git a/models/web_push.py b/models/web_push.py index 32839054d..9c4970144 100644 --- a/models/web_push.py +++ b/models/web_push.py @@ -1,9 +1,26 @@ from datetime import datetime from main import db +from flask import current_app as app +from pywebpush import webpush from . import BaseModel +def public_key(): + return app.config["WEBPUSH_PUBLIC_KEY"] + + +def notify(target, message): + webpush( + subscription_info=target.subscription_info, + data=message, + vapid_private_key=app.config["WEBPUSH_PRIVATE_KEY"], + vapid_claims={ + "sub": "mailto:contact@emfcamp.org", + }, + ) + + class WebPushTarget(BaseModel): __table_name__ = "web_push_target" id = db.Column(db.Integer, primary_key=True) diff --git a/poetry.lock b/poetry.lock index 90d1e4edd..6a7b07fd6 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,9 +1,121 @@ -# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.4.2 and should not be changed by hand. + +[[package]] +name = "aiohttp" +version = "3.9.3" +description = "Async http client/server framework (asyncio)" +category = "main" +optional = false +python-versions = ">=3.8" +files = [ + {file = "aiohttp-3.9.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:939677b61f9d72a4fa2a042a5eee2a99a24001a67c13da113b2e30396567db54"}, + {file = "aiohttp-3.9.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1f5cd333fcf7590a18334c90f8c9147c837a6ec8a178e88d90a9b96ea03194cc"}, + {file = "aiohttp-3.9.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:82e6aa28dd46374f72093eda8bcd142f7771ee1eb9d1e223ff0fa7177a96b4a5"}, + {file = "aiohttp-3.9.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f56455b0c2c7cc3b0c584815264461d07b177f903a04481dfc33e08a89f0c26b"}, + {file = "aiohttp-3.9.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bca77a198bb6e69795ef2f09a5f4c12758487f83f33d63acde5f0d4919815768"}, + {file = "aiohttp-3.9.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e083c285857b78ee21a96ba1eb1b5339733c3563f72980728ca2b08b53826ca5"}, + {file = "aiohttp-3.9.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ab40e6251c3873d86ea9b30a1ac6d7478c09277b32e14745d0d3c6e76e3c7e29"}, + {file = "aiohttp-3.9.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:df822ee7feaaeffb99c1a9e5e608800bd8eda6e5f18f5cfb0dc7eeb2eaa6bbec"}, + {file = "aiohttp-3.9.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:acef0899fea7492145d2bbaaaec7b345c87753168589cc7faf0afec9afe9b747"}, + {file = "aiohttp-3.9.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:cd73265a9e5ea618014802ab01babf1940cecb90c9762d8b9e7d2cc1e1969ec6"}, + {file = "aiohttp-3.9.3-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:a78ed8a53a1221393d9637c01870248a6f4ea5b214a59a92a36f18151739452c"}, + {file = "aiohttp-3.9.3-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:6b0e029353361f1746bac2e4cc19b32f972ec03f0f943b390c4ab3371840aabf"}, + {file = "aiohttp-3.9.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7cf5c9458e1e90e3c390c2639f1017a0379a99a94fdfad3a1fd966a2874bba52"}, + {file = "aiohttp-3.9.3-cp310-cp310-win32.whl", hash = "sha256:3e59c23c52765951b69ec45ddbbc9403a8761ee6f57253250c6e1536cacc758b"}, + {file = "aiohttp-3.9.3-cp310-cp310-win_amd64.whl", hash = "sha256:055ce4f74b82551678291473f66dc9fb9048a50d8324278751926ff0ae7715e5"}, + {file = "aiohttp-3.9.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6b88f9386ff1ad91ace19d2a1c0225896e28815ee09fc6a8932fded8cda97c3d"}, + {file = "aiohttp-3.9.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c46956ed82961e31557b6857a5ca153c67e5476972e5f7190015018760938da2"}, + {file = "aiohttp-3.9.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:07b837ef0d2f252f96009e9b8435ec1fef68ef8b1461933253d318748ec1acdc"}, + {file = "aiohttp-3.9.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dad46e6f620574b3b4801c68255492e0159d1712271cc99d8bdf35f2043ec266"}, + {file = "aiohttp-3.9.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5ed3e046ea7b14938112ccd53d91c1539af3e6679b222f9469981e3dac7ba1ce"}, + {file = "aiohttp-3.9.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:039df344b45ae0b34ac885ab5b53940b174530d4dd8a14ed8b0e2155b9dddccb"}, + {file = "aiohttp-3.9.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7943c414d3a8d9235f5f15c22ace69787c140c80b718dcd57caaade95f7cd93b"}, + {file = "aiohttp-3.9.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:84871a243359bb42c12728f04d181a389718710129b36b6aad0fc4655a7647d4"}, + {file = "aiohttp-3.9.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:5eafe2c065df5401ba06821b9a054d9cb2848867f3c59801b5d07a0be3a380ae"}, + {file = "aiohttp-3.9.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:9d3c9b50f19704552f23b4eaea1fc082fdd82c63429a6506446cbd8737823da3"}, + {file = "aiohttp-3.9.3-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:f033d80bc6283092613882dfe40419c6a6a1527e04fc69350e87a9df02bbc283"}, + {file = "aiohttp-3.9.3-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:2c895a656dd7e061b2fd6bb77d971cc38f2afc277229ce7dd3552de8313a483e"}, + {file = "aiohttp-3.9.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1f5a71d25cd8106eab05f8704cd9167b6e5187bcdf8f090a66c6d88b634802b4"}, + {file = "aiohttp-3.9.3-cp311-cp311-win32.whl", hash = "sha256:50fca156d718f8ced687a373f9e140c1bb765ca16e3d6f4fe116e3df7c05b2c5"}, + {file = "aiohttp-3.9.3-cp311-cp311-win_amd64.whl", hash = "sha256:5fe9ce6c09668063b8447f85d43b8d1c4e5d3d7e92c63173e6180b2ac5d46dd8"}, + {file = "aiohttp-3.9.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:38a19bc3b686ad55804ae931012f78f7a534cce165d089a2059f658f6c91fa60"}, + {file = "aiohttp-3.9.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:770d015888c2a598b377bd2f663adfd947d78c0124cfe7b959e1ef39f5b13869"}, + {file = "aiohttp-3.9.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ee43080e75fc92bf36219926c8e6de497f9b247301bbf88c5c7593d931426679"}, + {file = "aiohttp-3.9.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:52df73f14ed99cee84865b95a3d9e044f226320a87af208f068ecc33e0c35b96"}, + {file = "aiohttp-3.9.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dc9b311743a78043b26ffaeeb9715dc360335e5517832f5a8e339f8a43581e4d"}, + {file = "aiohttp-3.9.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b955ed993491f1a5da7f92e98d5dad3c1e14dc175f74517c4e610b1f2456fb11"}, + {file = "aiohttp-3.9.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:504b6981675ace64c28bf4a05a508af5cde526e36492c98916127f5a02354d53"}, + {file = "aiohttp-3.9.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a6fe5571784af92b6bc2fda8d1925cccdf24642d49546d3144948a6a1ed58ca5"}, + {file = "aiohttp-3.9.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ba39e9c8627edc56544c8628cc180d88605df3892beeb2b94c9bc857774848ca"}, + {file = "aiohttp-3.9.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:e5e46b578c0e9db71d04c4b506a2121c0cb371dd89af17a0586ff6769d4c58c1"}, + {file = "aiohttp-3.9.3-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:938a9653e1e0c592053f815f7028e41a3062e902095e5a7dc84617c87267ebd5"}, + {file = "aiohttp-3.9.3-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:c3452ea726c76e92f3b9fae4b34a151981a9ec0a4847a627c43d71a15ac32aa6"}, + {file = "aiohttp-3.9.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:ff30218887e62209942f91ac1be902cc80cddb86bf00fbc6783b7a43b2bea26f"}, + {file = "aiohttp-3.9.3-cp312-cp312-win32.whl", hash = "sha256:38f307b41e0bea3294a9a2a87833191e4bcf89bb0365e83a8be3a58b31fb7f38"}, + {file = "aiohttp-3.9.3-cp312-cp312-win_amd64.whl", hash = "sha256:b791a3143681a520c0a17e26ae7465f1b6f99461a28019d1a2f425236e6eedb5"}, + {file = "aiohttp-3.9.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:0ed621426d961df79aa3b963ac7af0d40392956ffa9be022024cd16297b30c8c"}, + {file = "aiohttp-3.9.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:7f46acd6a194287b7e41e87957bfe2ad1ad88318d447caf5b090012f2c5bb528"}, + {file = "aiohttp-3.9.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:feeb18a801aacb098220e2c3eea59a512362eb408d4afd0c242044c33ad6d542"}, + {file = "aiohttp-3.9.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f734e38fd8666f53da904c52a23ce517f1b07722118d750405af7e4123933511"}, + {file = "aiohttp-3.9.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b40670ec7e2156d8e57f70aec34a7216407848dfe6c693ef131ddf6e76feb672"}, + {file = "aiohttp-3.9.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fdd215b7b7fd4a53994f238d0f46b7ba4ac4c0adb12452beee724ddd0743ae5d"}, + {file = "aiohttp-3.9.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:017a21b0df49039c8f46ca0971b3a7fdc1f56741ab1240cb90ca408049766168"}, + {file = "aiohttp-3.9.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e99abf0bba688259a496f966211c49a514e65afa9b3073a1fcee08856e04425b"}, + {file = "aiohttp-3.9.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:648056db9a9fa565d3fa851880f99f45e3f9a771dd3ff3bb0c048ea83fb28194"}, + {file = "aiohttp-3.9.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:8aacb477dc26797ee089721536a292a664846489c49d3ef9725f992449eda5a8"}, + {file = "aiohttp-3.9.3-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:522a11c934ea660ff8953eda090dcd2154d367dec1ae3c540aff9f8a5c109ab4"}, + {file = "aiohttp-3.9.3-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:5bce0dc147ca85caa5d33debc4f4d65e8e8b5c97c7f9f660f215fa74fc49a321"}, + {file = "aiohttp-3.9.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:4b4af9f25b49a7be47c0972139e59ec0e8285c371049df1a63b6ca81fdd216a2"}, + {file = "aiohttp-3.9.3-cp38-cp38-win32.whl", hash = "sha256:298abd678033b8571995650ccee753d9458dfa0377be4dba91e4491da3f2be63"}, + {file = "aiohttp-3.9.3-cp38-cp38-win_amd64.whl", hash = "sha256:69361bfdca5468c0488d7017b9b1e5ce769d40b46a9f4a2eed26b78619e9396c"}, + {file = "aiohttp-3.9.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:0fa43c32d1643f518491d9d3a730f85f5bbaedcbd7fbcae27435bb8b7a061b29"}, + {file = "aiohttp-3.9.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:835a55b7ca49468aaaac0b217092dfdff370e6c215c9224c52f30daaa735c1c1"}, + {file = "aiohttp-3.9.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:06a9b2c8837d9a94fae16c6223acc14b4dfdff216ab9b7202e07a9a09541168f"}, + {file = "aiohttp-3.9.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:abf151955990d23f84205286938796c55ff11bbfb4ccfada8c9c83ae6b3c89a3"}, + {file = "aiohttp-3.9.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:59c26c95975f26e662ca78fdf543d4eeaef70e533a672b4113dd888bd2423caa"}, + {file = "aiohttp-3.9.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f95511dd5d0e05fd9728bac4096319f80615aaef4acbecb35a990afebe953b0e"}, + {file = "aiohttp-3.9.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:595f105710293e76b9dc09f52e0dd896bd064a79346234b521f6b968ffdd8e58"}, + {file = "aiohttp-3.9.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7c8b816c2b5af5c8a436df44ca08258fc1a13b449393a91484225fcb7545533"}, + {file = "aiohttp-3.9.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:f1088fa100bf46e7b398ffd9904f4808a0612e1d966b4aa43baa535d1b6341eb"}, + {file = "aiohttp-3.9.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f59dfe57bb1ec82ac0698ebfcdb7bcd0e99c255bd637ff613760d5f33e7c81b3"}, + {file = "aiohttp-3.9.3-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:361a1026c9dd4aba0109e4040e2aecf9884f5cfe1b1b1bd3d09419c205e2e53d"}, + {file = "aiohttp-3.9.3-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:363afe77cfcbe3a36353d8ea133e904b108feea505aa4792dad6585a8192c55a"}, + {file = "aiohttp-3.9.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8e2c45c208c62e955e8256949eb225bd8b66a4c9b6865729a786f2aa79b72e9d"}, + {file = "aiohttp-3.9.3-cp39-cp39-win32.whl", hash = "sha256:f7217af2e14da0856e082e96ff637f14ae45c10a5714b63c77f26d8884cf1051"}, + {file = "aiohttp-3.9.3-cp39-cp39-win_amd64.whl", hash = "sha256:27468897f628c627230dba07ec65dc8d0db566923c48f29e084ce382119802bc"}, + {file = "aiohttp-3.9.3.tar.gz", hash = "sha256:90842933e5d1ff760fae6caca4b2b3edba53ba8f4b71e95dacf2818a2aca06f7"}, +] + +[package.dependencies] +aiosignal = ">=1.1.2" +attrs = ">=17.3.0" +frozenlist = ">=1.1.1" +multidict = ">=4.5,<7.0" +yarl = ">=1.0,<2.0" + +[package.extras] +speedups = ["Brotli", "aiodns", "brotlicffi"] + +[[package]] +name = "aiosignal" +version = "1.3.1" +description = "aiosignal: a list of registered asynchronous callbacks" +category = "main" +optional = false +python-versions = ">=3.7" +files = [ + {file = "aiosignal-1.3.1-py3-none-any.whl", hash = "sha256:f8376fb07dd1e86a584e4fcdec80b36b7f81aac666ebc724e2c090300dd83b17"}, + {file = "aiosignal-1.3.1.tar.gz", hash = "sha256:54cd96e15e1649b75d6c87526a6ff0b6c1b0dd3459f43d9ca11d48c339b68cfc"}, +] + +[package.dependencies] +frozenlist = ">=1.1.0" [[package]] name = "alembic" version = "1.13.0" description = "A database migration tool for SQLAlchemy." +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -23,6 +135,7 @@ tz = ["backports.zoneinfo"] name = "aniso8601" version = "9.0.1" description = "A library for parsing ISO 8601 strings." +category = "main" optional = false python-versions = "*" files = [ @@ -37,6 +150,7 @@ dev = ["black", "coverage", "isort", "pre-commit", "pyenchant", "pylint"] name = "apiron" version = "7.1.0.post3" description = "apiron helps you cook a tasty client for RESTful APIs. Just don't wash it with SOAP." +category = "main" optional = false python-versions = "*" files = [ @@ -55,6 +169,7 @@ docs = ["importlib-metadata (>=4.5.0,<5)", "sphinx (>=4.3.2,<5)", "sphinx-autobu name = "appdirs" version = "1.4.4" description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." +category = "main" optional = false python-versions = "*" files = [ @@ -66,6 +181,7 @@ files = [ name = "asttokens" version = "2.4.1" description = "Annotate AST trees with source code positions" +category = "main" optional = false python-versions = "*" files = [ @@ -84,6 +200,7 @@ test = ["astroid (>=1,<2)", "astroid (>=2,<4)", "pytest"] name = "attrs" version = "23.1.0" description = "Classes Without Boilerplate" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -102,6 +219,7 @@ tests-no-zope = ["cloudpickle", "hypothesis", "mypy (>=1.1.1)", "pympler", "pyte name = "awesome-slugify" version = "1.6.5" description = "Python flexible slugify function" +category = "main" optional = false python-versions = "*" files = [ @@ -116,6 +234,7 @@ Unidecode = ">=0.04.14,<0.05" name = "beautifulsoup4" version = "4.12.2" description = "Screen-scraping library" +category = "main" optional = false python-versions = ">=3.6.0" files = [ @@ -134,6 +253,7 @@ lxml = ["lxml"] name = "black" version = "22.3.0" description = "The uncompromising code formatter." +category = "dev" optional = false python-versions = ">=3.6.2" files = [ @@ -178,6 +298,7 @@ uvloop = ["uvloop (>=0.15.2)"] name = "blinker" version = "1.7.0" description = "Fast, simple object-to-object and broadcast signaling" +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -189,6 +310,7 @@ files = [ name = "brotli" version = "1.1.0" description = "Python bindings for the Brotli compression library" +category = "dev" optional = false python-versions = "*" files = [ @@ -281,6 +403,7 @@ files = [ name = "cachelib" version = "0.9.0" description = "A collection of cache libraries in the same API interface." +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -292,6 +415,7 @@ files = [ name = "cairocffi" version = "1.6.1" description = "cffi-based cairo bindings for Python" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -311,6 +435,7 @@ xcb = ["xcffib (>=1.4.0)"] name = "cairosvg" version = "2.7.1" description = "A Simple SVG Converter based on Cairo" +category = "dev" optional = false python-versions = ">=3.5" files = [ @@ -333,6 +458,7 @@ test = ["flake8", "isort", "pytest"] name = "certifi" version = "2023.11.17" description = "Python package for providing Mozilla's CA Bundle." +category = "main" optional = false python-versions = ">=3.6" files = [ @@ -344,6 +470,7 @@ files = [ name = "cffi" version = "1.16.0" description = "Foreign Function Interface for Python calling C code." +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -408,6 +535,7 @@ pycparser = "*" name = "charset-normalizer" version = "3.3.2" 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 = [ @@ -507,6 +635,7 @@ files = [ name = "click" version = "8.1.7" description = "Composable command line interface toolkit" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -521,6 +650,7 @@ colorama = {version = "*", markers = "platform_system == \"Windows\""} 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 = [ @@ -532,6 +662,7 @@ files = [ name = "configargparse" version = "1.7" description = "A drop-in replacement for argparse that allows options to also be set via config files and/or environment variables." +category = "dev" optional = false python-versions = ">=3.5" files = [ @@ -547,6 +678,7 @@ yaml = ["PyYAML"] name = "coverage" version = "6.5.0" description = "Code coverage measurement for Python" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -609,6 +741,7 @@ toml = ["tomli"] name = "coveralls" version = "3.3.1" description = "Show coverage stats online via coveralls.io" +category = "dev" optional = false python-versions = ">= 3.5" files = [ @@ -617,7 +750,7 @@ files = [ ] [package.dependencies] -coverage = ">=4.1,<6.0.dev0 || >6.1,<6.1.1 || >6.1.1,<7.0" +coverage = ">=4.1,<6.0.0 || >6.1,<6.1.1 || >6.1.1,<7.0" docopt = ">=0.6.1" requests = ">=1.0.0" @@ -628,6 +761,7 @@ yaml = ["PyYAML (>=3.10)"] name = "cryptography" version = "41.0.7" description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -673,6 +807,7 @@ test-randomorder = ["pytest-randomly"] name = "cssselect2" version = "0.7.0" description = "CSS selectors for Python ElementTree" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -692,6 +827,7 @@ test = ["flake8", "isort", "pytest"] name = "cssutils" version = "2.9.0" description = "A CSS Cascading Style Sheets library for Python" +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -707,6 +843,7 @@ testing = ["cssselect", "importlib-resources", "jaraco.test (>=5.1)", "lxml", "p name = "decorator" version = "5.1.1" description = "Decorators for Humans" +category = "main" optional = false python-versions = ">=3.5" files = [ @@ -718,6 +855,7 @@ files = [ name = "defusedxml" version = "0.7.1" description = "XML bomb protection for Python stdlib modules" +category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" files = [ @@ -729,6 +867,7 @@ files = [ name = "dnspython" version = "2.4.2" description = "DNS toolkit" +category = "main" optional = false python-versions = ">=3.8,<4.0" files = [ @@ -748,6 +887,7 @@ wmi = ["wmi (>=1.5.1,<2.0.0)"] name = "docopt" version = "0.6.2" description = "Pythonic argument parser, that will make you smile" +category = "dev" optional = false python-versions = "*" files = [ @@ -758,6 +898,7 @@ files = [ name = "email-validator" version = "1.3.1" description = "A robust email address syntax and deliverability validation library." +category = "main" optional = false python-versions = ">=3.5" files = [ @@ -773,6 +914,7 @@ idna = ">=2.0.0" name = "executing" version = "2.0.1" description = "Get the currently executing AST node of a frame, and other information" +category = "main" optional = false python-versions = ">=3.5" files = [ @@ -787,6 +929,7 @@ tests = ["asttokens (>=2.1.0)", "coverage", "coverage-enable-subprocess", "ipyth name = "faker" version = "21.0.0" description = "Faker is a Python package that generates fake data for you." +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -801,6 +944,7 @@ python-dateutil = ">=2.4" name = "flake8" version = "3.8.3" description = "the modular source code checker: pep8 pyflakes and co" +category = "dev" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" files = [ @@ -817,6 +961,7 @@ pyflakes = ">=2.2.0,<2.3.0" name = "flake8-print" version = "4.0.1" description = "print statement checker plugin for flake8" +category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -833,6 +978,7 @@ six = "*" name = "flask" version = "2.3.3" description = "A simple framework for building complex web applications." +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -855,6 +1001,7 @@ dotenv = ["python-dotenv"] name = "flask-admin" version = "1.6.1" description = "Simple and extensible admin interface framework for Flask" +category = "main" optional = false python-versions = ">=3.6" files = [ @@ -874,6 +1021,7 @@ azure = ["azure-storage-blob"] name = "flask-basicauth" version = "0.2.0" description = "HTTP basic access authentication for Flask." +category = "dev" optional = false python-versions = "*" files = [ @@ -887,6 +1035,7 @@ Flask = "*" name = "flask-caching" version = "2.1.0" description = "Adds caching support to Flask applications." +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -902,6 +1051,7 @@ Flask = "*" name = "flask-cors" version = "3.0.10" description = "A Flask extension adding a decorator for CORS support" +category = "main" optional = false python-versions = "*" files = [ @@ -917,6 +1067,7 @@ Six = "*" name = "flask-debugtoolbar" version = "0.14.1" description = "A toolbar overlay for debugging Flask applications." +category = "main" optional = false python-versions = ">=2.7" files = [ @@ -936,6 +1087,7 @@ werkzeug = "*" name = "flask-login" version = "0.6.3" description = "User authentication and session management for Flask." +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -951,6 +1103,7 @@ Werkzeug = ">=1.0.1" name = "flask-mailman" version = "0.3.0" description = "Porting Django's email implementation to your Flask applications." +category = "main" optional = false python-versions = ">=3.6.2,<4.0.0" files = [ @@ -971,6 +1124,7 @@ test = ["black (>=21.5b2,<22.0)", "flake8 (>=3.9.2,<4.0.0)", "isort (>=5.8.0,<6. name = "flask-migrate" version = "3.1.0" description = "SQLAlchemy database migrations for Flask applications using Alembic." +category = "main" optional = false python-versions = ">=3.6" files = [ @@ -987,6 +1141,7 @@ Flask-SQLAlchemy = ">=1.0" name = "flask-restful" version = "0.3.10" description = "Simple framework for creating REST APIs" +category = "main" optional = false python-versions = "*" files = [ @@ -1007,6 +1162,7 @@ docs = ["sphinx"] name = "flask-shell-ipython" version = "0.5.1" description = "Replace default `flask shell` command by similar command running IPython." +category = "main" optional = false python-versions = ">=3.6, <4" files = [ @@ -1022,6 +1178,7 @@ IPython = ">=5.0.0" name = "flask-sqlalchemy" version = "3.0.5" description = "Add SQLAlchemy support to your Flask application." +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1037,6 +1194,7 @@ sqlalchemy = ">=1.4.18" name = "flask-static-digest" version = "0.4.0" description = "Flask extension for md5 tagging and compressing (gzip / brotli) static files." +category = "main" optional = false python-versions = ">=3.6" files = [ @@ -1054,6 +1212,7 @@ brotli = ["Brotli (>=1.0.9)"] name = "flask-wtf" version = "1.2.1" description = "Form rendering, validation, and CSRF protection for Flask with WTForms." +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -1073,6 +1232,7 @@ email = ["email-validator"] name = "freezegun" version = "1.3.1" description = "Let your Python tests travel through time" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1083,10 +1243,98 @@ files = [ [package.dependencies] python-dateutil = ">=2.7" +[[package]] +name = "frozenlist" +version = "1.4.1" +description = "A list-like structure which implements collections.abc.MutableSequence" +category = "main" +optional = false +python-versions = ">=3.8" +files = [ + {file = "frozenlist-1.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f9aa1878d1083b276b0196f2dfbe00c9b7e752475ed3b682025ff20c1c1f51ac"}, + {file = "frozenlist-1.4.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:29acab3f66f0f24674b7dc4736477bcd4bc3ad4b896f5f45379a67bce8b96868"}, + {file = "frozenlist-1.4.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:74fb4bee6880b529a0c6560885fce4dc95936920f9f20f53d99a213f7bf66776"}, + {file = "frozenlist-1.4.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:590344787a90ae57d62511dd7c736ed56b428f04cd8c161fcc5e7232c130c69a"}, + {file = "frozenlist-1.4.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:068b63f23b17df8569b7fdca5517edef76171cf3897eb68beb01341131fbd2ad"}, + {file = "frozenlist-1.4.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c849d495bf5154cd8da18a9eb15db127d4dba2968d88831aff6f0331ea9bd4c"}, + {file = "frozenlist-1.4.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9750cc7fe1ae3b1611bb8cfc3f9ec11d532244235d75901fb6b8e42ce9229dfe"}, + {file = "frozenlist-1.4.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a9b2de4cf0cdd5bd2dee4c4f63a653c61d2408055ab77b151c1957f221cabf2a"}, + {file = "frozenlist-1.4.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0633c8d5337cb5c77acbccc6357ac49a1770b8c487e5b3505c57b949b4b82e98"}, + {file = "frozenlist-1.4.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:27657df69e8801be6c3638054e202a135c7f299267f1a55ed3a598934f6c0d75"}, + {file = "frozenlist-1.4.1-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:f9a3ea26252bd92f570600098783d1371354d89d5f6b7dfd87359d669f2109b5"}, + {file = "frozenlist-1.4.1-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:4f57dab5fe3407b6c0c1cc907ac98e8a189f9e418f3b6e54d65a718aaafe3950"}, + {file = "frozenlist-1.4.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:e02a0e11cf6597299b9f3bbd3f93d79217cb90cfd1411aec33848b13f5c656cc"}, + {file = "frozenlist-1.4.1-cp310-cp310-win32.whl", hash = "sha256:a828c57f00f729620a442881cc60e57cfcec6842ba38e1b19fd3e47ac0ff8dc1"}, + {file = "frozenlist-1.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:f56e2333dda1fe0f909e7cc59f021eba0d2307bc6f012a1ccf2beca6ba362439"}, + {file = "frozenlist-1.4.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:a0cb6f11204443f27a1628b0e460f37fb30f624be6051d490fa7d7e26d4af3d0"}, + {file = "frozenlist-1.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b46c8ae3a8f1f41a0d2ef350c0b6e65822d80772fe46b653ab6b6274f61d4a49"}, + {file = "frozenlist-1.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fde5bd59ab5357e3853313127f4d3565fc7dad314a74d7b5d43c22c6a5ed2ced"}, + {file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:722e1124aec435320ae01ee3ac7bec11a5d47f25d0ed6328f2273d287bc3abb0"}, + {file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2471c201b70d58a0f0c1f91261542a03d9a5e088ed3dc6c160d614c01649c106"}, + {file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c757a9dd70d72b076d6f68efdbb9bc943665ae954dad2801b874c8c69e185068"}, + {file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f146e0911cb2f1da549fc58fc7bcd2b836a44b79ef871980d605ec392ff6b0d2"}, + {file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f9c515e7914626b2a2e1e311794b4c35720a0be87af52b79ff8e1429fc25f19"}, + {file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:c302220494f5c1ebeb0912ea782bcd5e2f8308037b3c7553fad0e48ebad6ad82"}, + {file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:442acde1e068288a4ba7acfe05f5f343e19fac87bfc96d89eb886b0363e977ec"}, + {file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:1b280e6507ea8a4fa0c0a7150b4e526a8d113989e28eaaef946cc77ffd7efc0a"}, + {file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:fe1a06da377e3a1062ae5fe0926e12b84eceb8a50b350ddca72dc85015873f74"}, + {file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:db9e724bebd621d9beca794f2a4ff1d26eed5965b004a97f1f1685a173b869c2"}, + {file = "frozenlist-1.4.1-cp311-cp311-win32.whl", hash = "sha256:e774d53b1a477a67838a904131c4b0eef6b3d8a651f8b138b04f748fccfefe17"}, + {file = "frozenlist-1.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:fb3c2db03683b5767dedb5769b8a40ebb47d6f7f45b1b3e3b4b51ec8ad9d9825"}, + {file = "frozenlist-1.4.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:1979bc0aeb89b33b588c51c54ab0161791149f2461ea7c7c946d95d5f93b56ae"}, + {file = "frozenlist-1.4.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:cc7b01b3754ea68a62bd77ce6020afaffb44a590c2289089289363472d13aedb"}, + {file = "frozenlist-1.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c9c92be9fd329ac801cc420e08452b70e7aeab94ea4233a4804f0915c14eba9b"}, + {file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c3894db91f5a489fc8fa6a9991820f368f0b3cbdb9cd8849547ccfab3392d86"}, + {file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ba60bb19387e13597fb059f32cd4d59445d7b18b69a745b8f8e5db0346f33480"}, + {file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8aefbba5f69d42246543407ed2461db31006b0f76c4e32dfd6f42215a2c41d09"}, + {file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:780d3a35680ced9ce682fbcf4cb9c2bad3136eeff760ab33707b71db84664e3a"}, + {file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9acbb16f06fe7f52f441bb6f413ebae6c37baa6ef9edd49cdd567216da8600cd"}, + {file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:23b701e65c7b36e4bf15546a89279bd4d8675faabc287d06bbcfac7d3c33e1e6"}, + {file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:3e0153a805a98f5ada7e09826255ba99fb4f7524bb81bf6b47fb702666484ae1"}, + {file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:dd9b1baec094d91bf36ec729445f7769d0d0cf6b64d04d86e45baf89e2b9059b"}, + {file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:1a4471094e146b6790f61b98616ab8e44f72661879cc63fa1049d13ef711e71e"}, + {file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:5667ed53d68d91920defdf4035d1cdaa3c3121dc0b113255124bcfada1cfa1b8"}, + {file = "frozenlist-1.4.1-cp312-cp312-win32.whl", hash = "sha256:beee944ae828747fd7cb216a70f120767fc9f4f00bacae8543c14a6831673f89"}, + {file = "frozenlist-1.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:64536573d0a2cb6e625cf309984e2d873979709f2cf22839bf2d61790b448ad5"}, + {file = "frozenlist-1.4.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:20b51fa3f588ff2fe658663db52a41a4f7aa6c04f6201449c6c7c476bd255c0d"}, + {file = "frozenlist-1.4.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:410478a0c562d1a5bcc2f7ea448359fcb050ed48b3c6f6f4f18c313a9bdb1826"}, + {file = "frozenlist-1.4.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c6321c9efe29975232da3bd0af0ad216800a47e93d763ce64f291917a381b8eb"}, + {file = "frozenlist-1.4.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:48f6a4533887e189dae092f1cf981f2e3885175f7a0f33c91fb5b7b682b6bab6"}, + {file = "frozenlist-1.4.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6eb73fa5426ea69ee0e012fb59cdc76a15b1283d6e32e4f8dc4482ec67d1194d"}, + {file = "frozenlist-1.4.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fbeb989b5cc29e8daf7f976b421c220f1b8c731cbf22b9130d8815418ea45887"}, + {file = "frozenlist-1.4.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:32453c1de775c889eb4e22f1197fe3bdfe457d16476ea407472b9442e6295f7a"}, + {file = "frozenlist-1.4.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:693945278a31f2086d9bf3df0fe8254bbeaef1fe71e1351c3bd730aa7d31c41b"}, + {file = "frozenlist-1.4.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:1d0ce09d36d53bbbe566fe296965b23b961764c0bcf3ce2fa45f463745c04701"}, + {file = "frozenlist-1.4.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:3a670dc61eb0d0eb7080890c13de3066790f9049b47b0de04007090807c776b0"}, + {file = "frozenlist-1.4.1-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:dca69045298ce5c11fd539682cff879cc1e664c245d1c64da929813e54241d11"}, + {file = "frozenlist-1.4.1-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:a06339f38e9ed3a64e4c4e43aec7f59084033647f908e4259d279a52d3757d09"}, + {file = "frozenlist-1.4.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b7f2f9f912dca3934c1baec2e4585a674ef16fe00218d833856408c48d5beee7"}, + {file = "frozenlist-1.4.1-cp38-cp38-win32.whl", hash = "sha256:e7004be74cbb7d9f34553a5ce5fb08be14fb33bc86f332fb71cbe5216362a497"}, + {file = "frozenlist-1.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:5a7d70357e7cee13f470c7883a063aae5fe209a493c57d86eb7f5a6f910fae09"}, + {file = "frozenlist-1.4.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:bfa4a17e17ce9abf47a74ae02f32d014c5e9404b6d9ac7f729e01562bbee601e"}, + {file = "frozenlist-1.4.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b7e3ed87d4138356775346e6845cccbe66cd9e207f3cd11d2f0b9fd13681359d"}, + {file = "frozenlist-1.4.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c99169d4ff810155ca50b4da3b075cbde79752443117d89429595c2e8e37fed8"}, + {file = "frozenlist-1.4.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:edb678da49d9f72c9f6c609fbe41a5dfb9a9282f9e6a2253d5a91e0fc382d7c0"}, + {file = "frozenlist-1.4.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6db4667b187a6742b33afbbaf05a7bc551ffcf1ced0000a571aedbb4aa42fc7b"}, + {file = "frozenlist-1.4.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:55fdc093b5a3cb41d420884cdaf37a1e74c3c37a31f46e66286d9145d2063bd0"}, + {file = "frozenlist-1.4.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:82e8211d69a4f4bc360ea22cd6555f8e61a1bd211d1d5d39d3d228b48c83a897"}, + {file = "frozenlist-1.4.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:89aa2c2eeb20957be2d950b85974b30a01a762f3308cd02bb15e1ad632e22dc7"}, + {file = "frozenlist-1.4.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9d3e0c25a2350080e9319724dede4f31f43a6c9779be48021a7f4ebde8b2d742"}, + {file = "frozenlist-1.4.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7268252af60904bf52c26173cbadc3a071cece75f873705419c8681f24d3edea"}, + {file = "frozenlist-1.4.1-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:0c250a29735d4f15321007fb02865f0e6b6a41a6b88f1f523ca1596ab5f50bd5"}, + {file = "frozenlist-1.4.1-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:96ec70beabbd3b10e8bfe52616a13561e58fe84c0101dd031dc78f250d5128b9"}, + {file = "frozenlist-1.4.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:23b2d7679b73fe0e5a4560b672a39f98dfc6f60df63823b0a9970525325b95f6"}, + {file = "frozenlist-1.4.1-cp39-cp39-win32.whl", hash = "sha256:a7496bfe1da7fb1a4e1cc23bb67c58fab69311cc7d32b5a99c2007b4b2a0e932"}, + {file = "frozenlist-1.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:e6a20a581f9ce92d389a8c7d7c3dd47c81fd5d6e655c8dddf341e14aa48659d0"}, + {file = "frozenlist-1.4.1-py3-none-any.whl", hash = "sha256:04ced3e6a46b4cfffe20f9ae482818e34eba9b5fb0ce4056e4cc9b6e212d09b7"}, + {file = "frozenlist-1.4.1.tar.gz", hash = "sha256:c037a86e8513059a2613aaba4d817bb90b9d9b6b69aace3ce9c877e8c8ed402b"}, +] + [[package]] name = "geoalchemy2" version = "0.14.2" description = "Using SQLAlchemy with Spatial Databases" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1105,6 +1353,7 @@ shapely = ["Shapely (>=1.7)"] name = "gevent" version = "23.9.1" description = "Coroutine-based network library" +category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -1167,6 +1416,7 @@ test = ["cffi (>=1.12.2)", "coverage (>=5.0)", "dnspython (>=1.16.0,<2.0)", "idn name = "geventhttpclient" version = "2.0.11" description = "http client library for gevent" +category = "dev" optional = false python-versions = "*" files = [ @@ -1290,6 +1540,7 @@ six = "*" name = "greenlet" version = "3.0.2" description = "Lightweight in-process concurrent programming" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1361,6 +1612,7 @@ test = ["objgraph", "psutil"] name = "gunicorn" version = "20.1.0" description = "WSGI HTTP Server for UNIX" +category = "main" optional = false python-versions = ">=3.5" files = [ @@ -1377,10 +1629,25 @@ gevent = ["gevent (>=1.4.0)"] setproctitle = ["setproctitle"] tornado = ["tornado (>=0.2)"] +[[package]] +name = "http-ece" +version = "1.2.0" +description = "Encrypted Content Encoding for HTTP" +category = "main" +optional = false +python-versions = "*" +files = [ + {file = "http_ece-1.2.0.tar.gz", hash = "sha256:b5920f8efb8e1b5fb025713e3b36fda54336262010634b26dc1f98f85d1eb3de"}, +] + +[package.dependencies] +cryptography = ">=2.5" + [[package]] name = "hypothesis" version = "6.92.1" description = "A library for property-based testing" +category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -1412,6 +1679,7 @@ zoneinfo = ["backports.zoneinfo (>=0.2.1)", "tzdata (>=2023.3)"] name = "icalendar" version = "3.11.7" description = "iCalendar parser/generator" +category = "main" optional = false python-versions = "*" files = [ @@ -1427,6 +1695,7 @@ pytz = "*" name = "idna" version = "3.6" description = "Internationalized Domain Names in Applications (IDNA)" +category = "main" optional = false python-versions = ">=3.5" files = [ @@ -1438,6 +1707,7 @@ files = [ name = "importlib-metadata" version = "7.0.0" description = "Read metadata from Python packages" +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -1457,6 +1727,7 @@ testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs name = "iniconfig" version = "2.0.0" description = "brain-dead simple config-ini parsing" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1468,6 +1739,7 @@ files = [ name = "inlinestyler" version = "0.2.5" description = "Inlines external CSS into HTML elements." +category = "main" optional = false python-versions = "*" files = [ @@ -1484,6 +1756,7 @@ requests = ">=1.0.0" name = "ipdb" version = "0.13.13" description = "IPython-enabled pdb" +category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ @@ -1499,6 +1772,7 @@ ipython = {version = ">=7.31.1", markers = "python_version >= \"3.11\""} name = "ipython" version = "8.18.1" description = "IPython: Productive Interactive Computing" +category = "main" optional = false python-versions = ">=3.9" files = [ @@ -1534,6 +1808,7 @@ test-extra = ["curio", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.22)", "pa name = "iso8601" version = "2.1.0" description = "Simple module to parse ISO 8601 dates" +category = "main" optional = false python-versions = ">=3.7,<4.0" files = [ @@ -1545,6 +1820,7 @@ files = [ name = "itsdangerous" version = "2.1.2" description = "Safely pass data to untrusted environments and back." +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1556,6 +1832,7 @@ files = [ name = "jedi" version = "0.19.1" description = "An autocompletion tool for Python that can be used for text editors." +category = "main" optional = false python-versions = ">=3.6" files = [ @@ -1575,6 +1852,7 @@ testing = ["Django", "attrs", "colorama", "docopt", "pytest (<7.0.0)"] name = "jinja2" version = "3.1.3" description = "A very fast and expressive template engine." +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1592,6 +1870,7 @@ i18n = ["Babel (>=2.7)"] name = "levenshtein" version = "0.23.0" description = "Python extension for computing string edit distances and similarities." +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1712,6 +1991,7 @@ rapidfuzz = ">=3.1.0,<4.0.0" name = "locust" version = "2.20.0" description = "Developer friendly load testing framework" +category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -1738,6 +2018,7 @@ Werkzeug = ">=2.0.0" name = "logging-tree" version = "1.9" description = "Introspect and display the logger tree inside \"logging\"" +category = "main" optional = false python-versions = "*" files = [ @@ -1749,6 +2030,7 @@ files = [ name = "lxml" version = "4.9.3" description = "Powerful and Pythonic XML processing library combining libxml2/libxslt with the ElementTree API." +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, != 3.4.*" files = [ @@ -1856,6 +2138,7 @@ source = ["Cython (>=0.29.35)"] name = "lxml-stubs" version = "0.3.1" description = "Type annotations for the lxml package" +category = "dev" optional = false python-versions = "*" files = [ @@ -1870,6 +2153,7 @@ test = ["coverage[toml] (==5.2)", "pytest (>=6.0.0)", "pytest-mypy-plugins (==1. name = "mako" version = "1.3.0" description = "A super-fast templating language that borrows the best ideas from the existing templating languages." +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -1889,6 +2173,7 @@ testing = ["pytest"] name = "markdown" version = "3.5.1" description = "Python implementation of John Gruber's Markdown." +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -1904,6 +2189,7 @@ testing = ["coverage", "pyyaml"] name = "markupsafe" version = "2.1.3" description = "Safely add untrusted strings to HTML/XML markup." +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1973,6 +2259,7 @@ files = [ name = "matplotlib-inline" version = "0.1.6" description = "Inline Matplotlib backend for Jupyter" +category = "main" optional = false python-versions = ">=3.5" files = [ @@ -1987,6 +2274,7 @@ traitlets = "*" name = "mccabe" version = "0.6.1" description = "McCabe checker, plugin for flake8" +category = "dev" optional = false python-versions = "*" files = [ @@ -1998,6 +2286,7 @@ files = [ name = "mkdocs-material-extensions" version = "1.3.1" description = "Extension pack for Python Markdown and MkDocs Material." +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -2009,6 +2298,7 @@ files = [ name = "mock" version = "5.1.0" description = "Rolling backport of unittest.mock for all Pythons" +category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -2025,6 +2315,7 @@ test = ["pytest", "pytest-cov"] name = "msgpack" version = "1.0.7" description = "MessagePack serializer" +category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -2090,6 +2381,7 @@ files = [ name = "multidict" version = "6.0.4" description = "multidict implementation" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -2173,6 +2465,7 @@ files = [ name = "munch" version = "4.0.0" description = "A dot-accessible dictionary (a la JavaScript objects)" +category = "main" optional = false python-versions = ">=3.6" files = [ @@ -2188,6 +2481,7 @@ yaml = ["PyYAML (>=5.1.0)"] name = "mypy" version = "1.7.1" description = "Optional static typing for Python" +category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -2234,6 +2528,7 @@ reports = ["lxml"] 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 = [ @@ -2245,6 +2540,7 @@ files = [ name = "numpy" version = "1.26.2" description = "Fundamental package for array computing in Python" +category = "main" optional = false python-versions = ">=3.9" files = [ @@ -2290,6 +2586,7 @@ files = [ name = "ofxparse" version = "0.16" description = "Tools for working with the OFX (Open Financial Exchange) file format" +category = "main" optional = false python-versions = "*" files = [ @@ -2305,6 +2602,7 @@ six = "*" name = "packaging" version = "23.2" description = "Core utilities for Python packages" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -2316,6 +2614,7 @@ files = [ name = "parso" version = "0.8.3" description = "A Python Parser" +category = "main" optional = false python-versions = ">=3.6" files = [ @@ -2331,6 +2630,7 @@ testing = ["docopt", "pytest (<6.0.0)"] name = "pathspec" version = "0.12.1" description = "Utility library for gitignore style pattern matching of file paths." +category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -2342,6 +2642,7 @@ files = [ name = "pendulum" version = "2.1.2" description = "Python datetimes made easy" +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" files = [ @@ -2376,6 +2677,7 @@ pytzdata = ">=2020.1" name = "pexpect" version = "4.9.0" description = "Pexpect allows easy control of interactive console applications." +category = "main" optional = false python-versions = "*" files = [ @@ -2390,6 +2692,7 @@ ptyprocess = ">=0.5" name = "pillow" version = "10.2.0" description = "Python Imaging Library (Fork)" +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -2475,6 +2778,7 @@ xmp = ["defusedxml"] name = "platformdirs" version = "4.1.0" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." +category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -2490,6 +2794,7 @@ test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4)", "pytest-co name = "pluggy" version = "1.3.0" description = "plugin and hook calling mechanisms for python" +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -2505,6 +2810,7 @@ testing = ["pytest", "pytest-benchmark"] name = "prometheus-client" version = "0.19.0" description = "Python client for the Prometheus monitoring system." +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -2519,6 +2825,7 @@ twisted = ["twisted"] name = "prompt-toolkit" version = "3.0.43" description = "Library for building powerful interactive command lines in Python" +category = "main" optional = false python-versions = ">=3.7.0" files = [ @@ -2533,6 +2840,7 @@ wcwidth = "*" name = "psutil" version = "5.9.7" description = "Cross-platform lib for process and system monitoring in Python." +category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" files = [ @@ -2561,6 +2869,7 @@ test = ["enum34", "ipaddress", "mock", "pywin32", "wmi"] name = "psycopg2" version = "2.9.9" description = "psycopg2 - Python-PostgreSQL Database Adapter" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -2583,6 +2892,7 @@ files = [ name = "ptyprocess" version = "0.7.0" description = "Run a subprocess in a pseudo terminal" +category = "main" optional = false python-versions = "*" files = [ @@ -2594,6 +2904,7 @@ files = [ name = "pulp" version = "2.1" description = "PuLP is an LP modeler written in python. PuLP can generate MPS or LP files and call GLPK, COIN CLP/CBC, CPLEX, and GUROBI to solve linear problems." +category = "main" optional = false python-versions = "*" files = [ @@ -2608,6 +2919,7 @@ pyparsing = ">=2.0.1" name = "pure-eval" version = "0.2.2" description = "Safely evaluate AST nodes without side effects" +category = "main" optional = false python-versions = "*" files = [ @@ -2618,10 +2930,25 @@ files = [ [package.extras] tests = ["pytest"] +[[package]] +name = "py-vapid" +version = "1.9.0" +description = "Simple VAPID header generation library" +category = "main" +optional = false +python-versions = "*" +files = [ + {file = "py-vapid-1.9.0.tar.gz", hash = "sha256:0664ab7899742ef2b287397a4d461ef691ed0cc2f587205128d8cf617ffdb919"}, +] + +[package.dependencies] +cryptography = ">=2.5" + [[package]] name = "pyBarcode" version = "0.8b1" description = "Create standard barcodes with Python. No external modules needed (optional PIL support included)." +category = "main" optional = false python-versions = "*" files = [] @@ -2637,6 +2964,7 @@ resolved_reference = "2a99ee91d98519f8f296aa42cfea1fde37f80823" name = "pycodestyle" version = "2.6.0" description = "Python style guide checker" +category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ @@ -2648,6 +2976,7 @@ files = [ 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 = [ @@ -2659,6 +2988,7 @@ files = [ name = "pyee" version = "8.2.2" description = "A port of node.js's EventEmitter to python." +category = "main" optional = false python-versions = "*" files = [ @@ -2670,6 +3000,7 @@ files = [ name = "pyflakes" version = "2.2.0" description = "passive checker of Python programs" +category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ @@ -2681,6 +3012,7 @@ files = [ name = "pygments" version = "2.17.2" description = "Pygments is a syntax highlighting package written in Python." +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -2696,6 +3028,7 @@ windows-terminal = ["colorama (>=0.4.6)"] name = "pyparsing" version = "3.1.1" description = "pyparsing module - Classes and methods to define and execute parsing grammars" +category = "main" optional = false python-versions = ">=3.6.8" files = [ @@ -2710,6 +3043,7 @@ diagrams = ["jinja2", "railroad-diagrams"] name = "pyppeteer" version = "1.0.2" description = "Headless chrome/chromium automation library (unofficial port of puppeteer)" +category = "main" optional = false python-versions = ">=3.7,<4.0" files = [ @@ -2730,6 +3064,7 @@ websockets = ">=10.0,<11.0" name = "pytest" version = "7.4.3" description = "pytest: simple powerful testing with Python" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -2750,6 +3085,7 @@ testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "no name = "pytest-cov" version = "4.1.0" description = "Pytest plugin for measuring coverage." +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -2768,6 +3104,7 @@ testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtuale name = "pytest-random-order" version = "1.1.0" description = "Randomise the order in which pytest tests are run with some control over the randomness" +category = "dev" optional = false python-versions = ">=3.5.0" files = [ @@ -2782,6 +3119,7 @@ pytest = ">=3.0.0" name = "pytest-vcr" version = "1.0.2" description = "Plugin for managing VCR.py cassettes" +category = "main" optional = false python-versions = "*" files = [ @@ -2797,6 +3135,7 @@ vcrpy = "*" 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 = [ @@ -2811,6 +3150,7 @@ six = ">=1.5" name = "python-levenshtein" version = "0.23.0" description = "Python extension for computing string edit distances and similarities." +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -2825,6 +3165,7 @@ Levenshtein = "0.23.0" name = "python-memcached" version = "1.59" description = "Pure python memcached client" +category = "main" optional = false python-versions = "*" files = [ @@ -2839,6 +3180,7 @@ six = ">=1.4.0" name = "python-stdnum" version = "1.19" description = "Python module to handle standardized numbers and codes" +category = "main" optional = false python-versions = "*" files = [ @@ -2855,6 +3197,7 @@ soap-fallback = ["PySimpleSOAP"] name = "pytz" version = "2023.3.post1" description = "World timezone definitions, modern and historical" +category = "main" optional = false python-versions = "*" files = [ @@ -2866,6 +3209,7 @@ files = [ name = "pytzdata" version = "2020.1" description = "The Olson timezone database for Python." +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ @@ -2873,10 +3217,33 @@ files = [ {file = "pytzdata-2020.1.tar.gz", hash = "sha256:3efa13b335a00a8de1d345ae41ec78dd11c9f8807f522d39850f2dd828681540"}, ] +[[package]] +name = "pywebpush" +version = "2.0.0" +description = "WebPush publication library" +category = "main" +optional = false +python-versions = "*" +files = [ + {file = "pywebpush-2.0.0.tar.gz", hash = "sha256:03ccc3e975b60374b7634c495595616be523bf2c7da0d976e84fda9ac8c63301"}, +] + +[package.dependencies] +aiohttp = "*" +cryptography = ">=2.6.1" +http-ece = ">=1.1.0" +py-vapid = ">=1.7.0" +requests = ">=2.21.0" +six = ">=1.15.0" + +[package.extras] +dev = ["black", "mock", "pytest"] + [[package]] name = "pywin32" version = "306" description = "Python for Window Extensions" +category = "dev" optional = false python-versions = "*" files = [ @@ -2900,6 +3267,7 @@ files = [ name = "pywisetransfer" version = "0.3.1" description = "Python library for the TransferWise API" +category = "main" optional = false python-versions = ">=3.8,<4.0" files = [ @@ -2919,6 +3287,7 @@ dev = ["black (>=23.12.1,<24.0.0)", "munch-stubs (>=0.1.2,<0.2.0)", "pytest (>=7 name = "pyyaml" version = "6.0.1" description = "YAML parser and emitter for Python" +category = "main" optional = false python-versions = ">=3.6" files = [ @@ -2979,6 +3348,7 @@ files = [ name = "pyzbar" version = "0.1.9" description = "Read one-dimensional barcodes and QR codes from Python 2 and 3." +category = "dev" optional = false python-versions = "*" files = [ @@ -2994,6 +3364,7 @@ scripts = ["Pillow (>=3.2.0)"] name = "pyzmq" version = "25.1.2" description = "Python bindings for 0MQ" +category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -3099,6 +3470,7 @@ cffi = {version = "*", markers = "implementation_name == \"pypy\""} name = "rapidfuzz" version = "3.5.2" description = "rapid fuzzy string matching" +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -3201,6 +3573,7 @@ full = ["numpy"] name = "regex" version = "2023.10.3" description = "Alternative regular expression module, to replace re." +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -3298,6 +3671,7 @@ files = [ name = "requests" version = "2.31.0" description = "Python HTTP for Humans." +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -3319,6 +3693,7 @@ use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] name = "roundrobin" version = "0.0.4" description = "Collection of roundrobin utilities" +category = "dev" optional = false python-versions = "*" files = [ @@ -3329,6 +3704,7 @@ files = [ name = "segno" version = "1.6.0" description = "QR Code and Micro QR Code generator for Python" +category = "main" optional = false python-versions = ">=3.5" files = [ @@ -3340,6 +3716,7 @@ files = [ name = "setuptools" version = "69.0.2" description = "Easily download, build, install, upgrade, and uninstall Python packages" +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -3356,6 +3733,7 @@ testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jar name = "shapely" version = "2.0.2" description = "Manipulation and analysis of geometric objects" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -3406,13 +3784,14 @@ files = [ numpy = ">=1.14" [package.extras] -docs = ["matplotlib", "numpydoc (==1.1.*)", "sphinx", "sphinx-book-theme", "sphinx-remove-toctrees"] +docs = ["matplotlib", "numpydoc (>=1.1.0,<1.2.0)", "sphinx", "sphinx-book-theme", "sphinx-remove-toctrees"] test = ["pytest", "pytest-cov"] [[package]] name = "simplejson" version = "3.19.2" description = "Simple, fast, extensible JSON encoder/decoder for Python" +category = "main" optional = false python-versions = ">=2.5, !=3.0.*, !=3.1.*, !=3.2.*" files = [ @@ -3520,6 +3899,7 @@ files = [ 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 = [ @@ -3531,6 +3911,7 @@ files = [ name = "slotmachine" version = "0.0.6" description = "Conference talk scheduler" +category = "main" optional = false python-versions = "*" files = [] @@ -3550,6 +3931,7 @@ resolved_reference = "8ab12eff673ffbb517b5813ce90b2b1b60fc1d33" name = "sortedcontainers" version = "2.4.0" description = "Sorted Containers -- Sorted List, Sorted Dict, Sorted Set" +category = "dev" optional = false python-versions = "*" files = [ @@ -3561,6 +3943,7 @@ files = [ name = "soupsieve" version = "2.5" description = "A modern CSS selector implementation for Beautiful Soup." +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -3572,6 +3955,7 @@ files = [ name = "sqlalchemy" version = "1.4.50" description = "Database Abstraction Library" +category = "main" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" files = [ @@ -3624,7 +4008,7 @@ files = [ ] [package.dependencies] -greenlet = {version = "!=0.4.17", markers = "python_version >= \"3\" and (platform_machine == \"aarch64\" or platform_machine == \"ppc64le\" or platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"win32\" or platform_machine == \"WIN32\")"} +greenlet = {version = "!=0.4.17", markers = "python_version >= \"3\" and platform_machine == \"aarch64\" or python_version >= \"3\" and platform_machine == \"ppc64le\" or python_version >= \"3\" and platform_machine == \"x86_64\" or python_version >= \"3\" and platform_machine == \"amd64\" or python_version >= \"3\" and platform_machine == \"AMD64\" or python_version >= \"3\" and platform_machine == \"win32\" or python_version >= \"3\" and platform_machine == \"WIN32\""} [package.extras] aiomysql = ["aiomysql (>=0.2.0)", "greenlet (!=0.4.17)"] @@ -3651,6 +4035,7 @@ sqlcipher = ["sqlcipher3-binary"] name = "sqlalchemy-continuum" version = "1.4.0" description = "Versioning and auditing extension for SQLAlchemy." +category = "main" optional = false python-versions = "*" files = [ @@ -3673,6 +4058,7 @@ test = ["Flask (>=0.9)", "Flask-Login (>=0.2.9)", "Flask-SQLAlchemy (>=1.0)", "P name = "sqlalchemy-stubs" version = "0.4" description = "SQLAlchemy stubs and mypy plugin" +category = "dev" optional = false python-versions = "*" files = [ @@ -3688,6 +4074,7 @@ typing-extensions = ">=3.7.4" name = "sqlalchemy-utils" version = "0.41.1" description = "Various utility functions for SQLAlchemy." +category = "main" optional = false python-versions = ">=3.6" files = [ @@ -3716,6 +4103,7 @@ url = ["furl (>=0.4.1)"] name = "stack-data" version = "0.6.3" description = "Extract data from python stack frames and tracebacks for informative displays" +category = "main" optional = false python-versions = "*" files = [ @@ -3735,6 +4123,7 @@ tests = ["cython", "littleutils", "pygments", "pytest", "typeguard"] name = "stripe" version = "2.38.0" description = "Python bindings for the Stripe API" +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ @@ -3749,6 +4138,7 @@ requests = {version = ">=2.20", markers = "python_version >= \"3.0\""} name = "tinycss2" version = "1.2.1" description = "A tiny CSS parser" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -3767,6 +4157,7 @@ test = ["flake8", "isort", "pytest"] name = "tqdm" version = "4.66.1" description = "Fast, Extensible Progress Meter" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -3787,6 +4178,7 @@ telegram = ["requests"] name = "traitlets" version = "5.14.0" description = "Traitlets Python configuration system" +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -3802,6 +4194,7 @@ test = ["argcomplete (>=3.0.3)", "mypy (>=1.7.0)", "pre-commit", "pytest (>=7.0, name = "types-decorator" version = "5.1.8.4" description = "Typing stubs for decorator" +category = "dev" optional = false python-versions = "*" files = [ @@ -3813,6 +4206,7 @@ files = [ name = "types-markdown" version = "3.5.0.3" description = "Typing stubs for Markdown" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -3824,6 +4218,7 @@ files = [ name = "types-python-dateutil" version = "2.8.19.14" description = "Typing stubs for python-dateutil" +category = "dev" optional = false python-versions = "*" files = [ @@ -3835,6 +4230,7 @@ files = [ name = "types-pytz" version = "2023.3.1.1" description = "Typing stubs for pytz" +category = "dev" optional = false python-versions = "*" files = [ @@ -3846,6 +4242,7 @@ files = [ name = "types-pyyaml" version = "6.0.12.12" description = "Typing stubs for PyYAML" +category = "dev" optional = false python-versions = "*" files = [ @@ -3857,6 +4254,7 @@ files = [ name = "types-requests" version = "2.31.0.6" description = "Typing stubs for requests" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -3871,6 +4269,7 @@ types-urllib3 = "*" name = "types-simplejson" version = "3.19.0.2" description = "Typing stubs for simplejson" +category = "dev" optional = false python-versions = "*" files = [ @@ -3882,6 +4281,7 @@ files = [ name = "types-urllib3" version = "1.26.25.14" description = "Typing stubs for urllib3" +category = "dev" optional = false python-versions = "*" files = [ @@ -3893,6 +4293,7 @@ files = [ name = "typing-extensions" version = "4.9.0" description = "Backported and Experimental Type Hints for Python 3.8+" +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -3904,6 +4305,7 @@ files = [ name = "unidecode" version = "0.04.21" description = "ASCII transliterations of Unicode text" +category = "main" optional = false python-versions = "*" files = [ @@ -3915,6 +4317,7 @@ files = [ name = "urllib3" version = "1.26.18" description = "HTTP library with thread-safe connection pooling, file post, and more." +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" files = [ @@ -3931,6 +4334,7 @@ socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] name = "vcrpy" version = "5.1.0" description = "Automatically mock your HTTP interactions to simplify and speed up testing" +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -3947,6 +4351,7 @@ yarl = "*" name = "wcwidth" version = "0.2.12" description = "Measures the displayed width of unicode strings in a terminal" +category = "main" optional = false python-versions = "*" files = [ @@ -3958,6 +4363,7 @@ files = [ name = "webencodings" version = "0.5.1" description = "Character encoding aliases for legacy web content" +category = "dev" optional = false python-versions = "*" files = [ @@ -3969,6 +4375,7 @@ files = [ name = "websockets" version = "10.4" description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -4047,6 +4454,7 @@ files = [ name = "werkzeug" version = "3.0.1" description = "The comprehensive WSGI web application library." +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -4064,6 +4472,7 @@ watchdog = ["watchdog (>=2.3)"] name = "wrapt" version = "1.16.0" description = "Module for decorators, wrappers and monkey patching." +category = "main" optional = false python-versions = ">=3.6" files = [ @@ -4143,6 +4552,7 @@ files = [ name = "wtforms" version = "2.3.3" description = "A flexible forms validation and rendering library for Python web development." +category = "main" optional = false python-versions = "*" files = [ @@ -4162,6 +4572,7 @@ locale = ["Babel (>=1.3)"] name = "yarl" version = "1.9.4" description = "Yet another URL library" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -4265,6 +4676,7 @@ multidict = ">=4.0" name = "zipp" version = "3.17.0" description = "Backport of pathlib-compatible object wrapper for zip files" +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -4280,6 +4692,7 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p name = "zope-event" version = "5.0" description = "Very basic event publishing system" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -4298,6 +4711,7 @@ test = ["zope.testrunner"] name = "zope-interface" version = "6.1" description = "Interfaces for Python" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -4350,4 +4764,4 @@ testing = ["coverage (>=5.0.3)", "zope.event", "zope.testing"] [metadata] lock-version = "2.0" python-versions = "~3.11" -content-hash = "17d70e68295efbe6be37601d425500dbb2e75d4f8d16ae87088811c4f451fe0c" +content-hash = "c93093bcd9f6b9faa26d4f4e4d6d7c1b4a23cf8d827d074ab5b8cc9f00db02c5" diff --git a/pyproject.toml b/pyproject.toml index 52dc2dcf9..1cf95fb12 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -57,6 +57,7 @@ freezegun = "^1.1.0" logging_tree = "^1.9" flask-mailman = "^0.3.0" python-stdnum = "^1.19" +pywebpush = "^2.0" [tool.poetry.group.dev.dependencies] diff --git a/templates/notifications/index.html b/templates/notifications/index.html new file mode 100644 index 000000000..daf3d5fe0 --- /dev/null +++ b/templates/notifications/index.html @@ -0,0 +1,23 @@ +{% extends "base.html" %} +{% block title %}Notifications{% endblock %} +{% block head %} + + +{% endblock %} +{% block body %} +

Notifications

+
+
loading
+
enabled
+
+ denied +
+
+ +
+
+

Test

+{% endblock %} +{% block foot %} + +{% endblock %}