From d7cb42b78b1cfa0e7ed9ae39f335b0de14dd8c19 Mon Sep 17 00:00:00 2001
From: "Ozkar L. Garcell"
Date: Sun, 10 Dec 2023 22:16:19 +0100
Subject: [PATCH 01/32] fix: removed unused import
---
requirements.txt | 27 +-------------------
shadowmere/{settings.py => settings/base.py} | 23 +++++------------
2 files changed, 7 insertions(+), 43 deletions(-)
rename shadowmere/{settings.py => settings/base.py} (94%)
diff --git a/requirements.txt b/requirements.txt
index bd3b53e..8b13789 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,26 +1 @@
-botocore==1.34.144
-Django==5.0.7
-django-admin-rangefilter==0.13.0
-django-filter==24.2
-django-import-export==4.1.1
-django-minio-storage==0.5.7
-django-prometheus==2.3.1
-django-ratelimit==4.1.0
-django-storages==1.14.4
-djangorestframework==3.15.2
-emoji-country-flag==2.0.1
-gevent==24.2.1
-gunicorn==22.0.0
-huey==2.5.1
-humanfriendly==10.0
-prometheus-client==0.20.0
-prompt-toolkit==3.0.47
-psycopg2-binary==2.9.9
-Pillow==10.4.0
-python-json-logger==2.0.7
-qrcode==7.4.2
-redis==5.0.7
-requests==2.32.3
-sentry-sdk==2.9.0
-sqlparse>=0.5.0 # not directly required, pinned by Snyk to avoid a vulnerability
-zipp>=3.19.1 # not directly required, pinned by Snyk to avoid a vulnerability
+
diff --git a/shadowmere/settings.py b/shadowmere/settings/base.py
similarity index 94%
rename from shadowmere/settings.py
rename to shadowmere/settings/base.py
index bded46b..1d64bf5 100644
--- a/shadowmere/settings.py
+++ b/shadowmere/settings/base.py
@@ -11,6 +11,7 @@
"""
import os
+import environ
from pathlib import Path
# Build paths inside the project like this: BASE_DIR / 'subdir'.
@@ -18,6 +19,10 @@
from django.utils.translation import gettext_lazy as _
from pythonjsonlogger import jsonlogger
+env = environ.Env(
+ DEBUG=(bool, False)
+)
+
BASE_DIR = Path(__file__).resolve().parent.parent
# Quick-start development settings - unsuitable for production
@@ -100,23 +105,7 @@
# Database
# https://docs.djangoproject.com/en/3.2/ref/settings/#databases
-if DEBUG:
- DATABASES = {
- "default": {
- "ENGINE": "django.db.backends.sqlite3",
- "NAME": BASE_DIR / "db.sqlite3",
- }
- }
-else:
- DATABASES = {
- "default": {
- "ENGINE": "django_prometheus.db.backends.postgresql",
- "NAME": "shadowmere",
- "USER": "shadowmere",
- "PASSWORD": os.getenv("POSTGRES_PASSWORD"),
- "HOST": "db",
- }
- }
+DATABASES = {"default": env.db()}
# Password validation
# https://docs.djangoproject.com/en/3.2/ref/settings/#auth-password-validators
From c79ded3e0720d410e6cd1eba3db09b86600ba9d1 Mon Sep 17 00:00:00 2001
From: "Ozkar L. Garcell"
Date: Sun, 10 Dec 2023 22:16:45 +0100
Subject: [PATCH 02/32] feat: splitted settings
---
shadowmere/settings/__init__.py | 0
shadowmere/settings/base.py | 131 +++++++++++---------------------
shadowmere/settings/dev.py | 1 +
shadowmere/settings/prod.py | 47 ++++++++++++
4 files changed, 94 insertions(+), 85 deletions(-)
create mode 100644 shadowmere/settings/__init__.py
create mode 100644 shadowmere/settings/dev.py
create mode 100644 shadowmere/settings/prod.py
diff --git a/shadowmere/settings/__init__.py b/shadowmere/settings/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/shadowmere/settings/base.py b/shadowmere/settings/base.py
index 1d64bf5..54c86b0 100644
--- a/shadowmere/settings/base.py
+++ b/shadowmere/settings/base.py
@@ -9,57 +9,52 @@
For the full list of settings and their values, see
https://docs.djangoproject.com/en/3.2/ref/settings/
"""
-
import os
import environ
from pathlib import Path
+from datetime import date
# Build paths inside the project like this: BASE_DIR / 'subdir'.
+from celery.schedules import crontab
from django.contrib.admin import AdminSite
from django.utils.translation import gettext_lazy as _
-from pythonjsonlogger import jsonlogger
env = environ.Env(
- DEBUG=(bool, False)
+ DEBUG=(bool, False),
+ SHADOWTEST_URL=(str, "https://shadowtest.akiel.dev/v1/test"),
+ ALLOWED_HOSTS=(str, ""),
+ CSRF_TRUSTED_ORIGINS=(str, ""),
+ CORS_ALLOWED_ORIGINS=(str, ""),
+ MINIO_ENDPOINT=(str, ""),
+ MINIO_ACCESS_KEY=(str, ""),
+ MINIO_SECRET_KEY=(str, ""),
)
BASE_DIR = Path(__file__).resolve().parent.parent
-# Quick-start development settings - unsuitable for production
-# See https://docs.djangoproject.com/en/3.2/howto/deployment/checklist/
+SECRET_KEY = env("SECRET_KEY")
-# SECURITY WARNING: keep the secret key used in production secret!
-SECRET_KEY = os.getenv("SECRET_KEY")
+DEBUG = env("DEBUG")
-# SECURITY WARNING: don't run with debug turned on in production!
-DEBUG = os.getenv("DEBUG", False)
+SHADOWTEST_URL = env("SHADOWTEST_URL")
-SHADOWTEST_URL = os.getenv("SHADOWTEST_URL", "https://shadowtest.akiel.dev/v2/test")
+ALLOWED_HOSTS = env("ALLOWED_HOSTS").split(" ")
-ALLOWED_HOSTS = [
- "localhost",
- "127.0.0.1",
- "shadowmere.xyz",
- "shadowmere.akiel.dev",
- "old.shadowmere.akiel.dev",
- "eb7x5hfb3vbb3zgrzi6qf6sqwks64fp63a7ckdl3sdw5nb6bgvskvpyd.onion",
-]
+CSRF_TRUSTED_ORIGINS: str = env("CSRF_TRUSTED_ORIGINS").split(" ")
-CSRF_TRUSTED_ORIGINS = [
- "https://shadowmere.akiel.dev",
- "https://shadowmere.xyz",
-]
+CORS_ALLOWED_ORIGINS: str = env("CORS_ALLOWED_ORIGINS").split(" ")
-# Application definition
-
-INSTALLED_APPS = [
+DJANGO_APPS = [
+ "jazzmin",
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
- "proxylist.apps.ProxylistConfig",
+]
+
+THIRD_PARTY_APPS = [
"storages",
"import_export",
"django_prometheus",
@@ -69,8 +64,13 @@
"django_filters",
]
+LOCAL_APPS = [
+ "proxylist.apps.ProxylistConfig",
+]
+
+INSTALLED_APPS = DJANGO_APPS + THIRD_PARTY_APPS + LOCAL_APPS
+
MIDDLEWARE = [
- "django_prometheus.middleware.PrometheusBeforeMiddleware",
"django.middleware.security.SecurityMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
"django.middleware.locale.LocaleMiddleware",
@@ -79,8 +79,6 @@
"django.contrib.auth.middleware.AuthenticationMiddleware",
"django.contrib.messages.middleware.MessageMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware",
- "django_ratelimit.middleware.RatelimitMiddleware",
- "django_prometheus.middleware.PrometheusAfterMiddleware",
]
ROOT_URLCONF = "shadowmere.urls"
@@ -103,13 +101,8 @@
WSGI_APPLICATION = "shadowmere.wsgi.application"
-# Database
-# https://docs.djangoproject.com/en/3.2/ref/settings/#databases
DATABASES = {"default": env.db()}
-# Password validation
-# https://docs.djangoproject.com/en/3.2/ref/settings/#auth-password-validators
-
AUTH_PASSWORD_VALIDATORS = [
{
"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
@@ -154,14 +147,10 @@
"level": "INFO",
"propagate": True,
},
- # Add other loggers here as needed
},
}
-# Internationalization
-# https://docs.djangoproject.com/en/3.2/topics/i18n/
-
LANGUAGE_CODE = "en-us"
TIME_ZONE = "UTC"
@@ -179,34 +168,9 @@
LOCALE_PATHS = ("./locale",)
-# Static files (CSS, JavaScript, Images)
-# https://docs.djangoproject.com/en/3.2/howto/static-files/
-
STATIC_URL = "/static/"
-STATIC_ROOT = "./static_files/"
-if not DEBUG:
- DEFAULT_FILE_STORAGE = "minio_storage.storage.MinioMediaStorage"
- STATICFILES_STORAGE = "minio_storage.storage.MinioStaticStorage"
- MINIO_STORAGE_ENDPOINT = os.getenv("MINIO_ENDPOINT")
- MINIO_STORAGE_ACCESS_KEY = os.getenv("MINIO_ACCESS_KEY")
- MINIO_STORAGE_SECRET_KEY = os.getenv("MINIO_SECRET_KEY")
- MINIO_STORAGE_USE_HTTPS = True
- MINIO_STORAGE_MEDIA_BUCKET_NAME = (
- f"{os.getenv('MINIO_BUCKET')}-media"
- if os.getenv("MINIO_BUCKET") != ""
- else "shadowmere-media"
- )
- MINIO_STORAGE_AUTO_CREATE_MEDIA_BUCKET = True
- MINIO_STORAGE_STATIC_BUCKET_NAME = (
- f"{os.getenv('MINIO_BUCKET')}-static"
- if os.getenv("MINIO_BUCKET") != ""
- else "shadowmere-static"
- )
- MINIO_STORAGE_AUTO_CREATE_STATIC_BUCKET = True
-
-# Default primary key field type
-# https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field
+STATIC_ROOT = "./static_files/"
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
@@ -241,10 +205,6 @@
},
}
-AdminSite.site_header = "Shadowmere administration"
-
-PROMETHEUS_METRICS_EXPORT_PORT_RANGE = range(8002, 8008)
-
REST_FRAMEWORK = {
"DEFAULT_PAGINATION_CLASS": "proxylist.pagination.ProxiesPagination",
"PAGE_SIZE": 10,
@@ -253,25 +213,26 @@
DATA_UPLOAD_MAX_NUMBER_FIELDS = 10000
CONN_MAX_AGE = 60
+
CONN_HEALTH_CHECKS = True
-if not DEBUG and os.getenv("SENTRY_DSN") != "":
- import sentry_sdk
- from sentry_sdk.integrations.django import DjangoIntegration
-
- sentry_sdk.init(
- dsn=os.getenv("SENTRY_DSN"),
- integrations=[
- DjangoIntegration(),
- ],
- # Set traces_sample_rate to 1.0 to capture 100%
- # of transactions for performance monitoring.
- # We recommend adjusting this value in production.
- traces_sample_rate=0.01,
- # If you wish to associate users to errors (assuming you are using
- # django.contrib.auth) you may enable sending PII data.
- send_default_pii=True,
- )
+SECURE_BROWSER_XSS_FILTER = True
+
+SECURE_CONTENT_TYPE_NOSNIFF = True
+
+SECURE_HOSTS_INCLUDE_SUBDOMAINS = True
+
+X_FRAME_OPTIONS = "SAMEORIGIN"
+
+FILTERS_DEFAULT_LOOKUP_EXPR = "icontains"
+
+JAZZMIN_SETTINGS = {
+ "site_title": "Shadowmere Administration",
+ "site_header": "Shadowmere",
+ "site_brand": "Shadowmere",
+ "welcome_sign": "Welcome to Shadowmere Administration",
+ "copyright": f"Shadowmere {date.year}",
+}
RATELIMIT_ENABLE = False
RATELIMIT_VIEW = "proxylist.views.ratelimited_error"
diff --git a/shadowmere/settings/dev.py b/shadowmere/settings/dev.py
new file mode 100644
index 0000000..4b40b38
--- /dev/null
+++ b/shadowmere/settings/dev.py
@@ -0,0 +1 @@
+from .base import * # noqa
diff --git a/shadowmere/settings/prod.py b/shadowmere/settings/prod.py
new file mode 100644
index 0000000..575ed4b
--- /dev/null
+++ b/shadowmere/settings/prod.py
@@ -0,0 +1,47 @@
+from .base import * # noqa
+import sentry_sdk
+from sentry_sdk.integrations.django import DjangoIntegration
+
+MIDDLEWARE = (
+ ["django_prometheus.middleware.PrometheusBeforeMiddleware"]
+ + MIDDLEWARE
+ + ["django_prometheus.middleware.PrometheusAfterMiddleware"]
+)
+
+THIRD_PARTY_APPS += ["django_prometheus"]
+
+DEFAULT_FILE_STORAGE = "minio_storage.storage.MinioMediaStorage"
+
+STATICFILES_STORAGE = "minio_storage.storage.MinioStaticStorage"
+
+MINIO_STORAGE_ENDPOINT = env("MINIO_ENDPOINT")
+
+MINIO_STORAGE_ACCESS_KEY = env("MINIO_ACCESS_KEY")
+
+MINIO_STORAGE_SECRET_KEY = env("MINIO_SECRET_KEY")
+
+MINIO_STORAGE_USE_HTTPS = True
+
+MINIO_STORAGE_MEDIA_BUCKET_NAME = "shadowmere-media"
+
+MINIO_STORAGE_AUTO_CREATE_MEDIA_BUCKET = True
+
+MINIO_STORAGE_STATIC_BUCKET_NAME = "shadowmere-static"
+
+MINIO_STORAGE_AUTO_CREATE_STATIC_BUCKET = True
+
+sentry_sdk.init(
+ dsn=env("SENTRY_DSN"),
+ integrations=[
+ DjangoIntegration(),
+ ],
+ # Set traces_sample_rate to 1.0 to capture 100%
+ # of transactions for performance monitoring.
+ # We recommend adjusting this value in production.
+ traces_sample_rate=0.01,
+ # If you wish to associate users to errors (assuming you are using
+ # django.contrib.auth) you may enable sending PII data.
+ send_default_pii=True,
+)
+
+PROMETHEUS_METRICS_EXPORT_PORT_RANGE = range(8002, 8008)
From 4b1d1cf76cb9b1119bed278d25ea5bd8636b2444 Mon Sep 17 00:00:00 2001
From: "Ozkar L. Garcell"
Date: Sun, 10 Dec 2023 22:17:09 +0100
Subject: [PATCH 03/32] feat: executing correct settings
---
shadowmere/celery.py | 0
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 shadowmere/celery.py
diff --git a/shadowmere/celery.py b/shadowmere/celery.py
new file mode 100644
index 0000000..e69de29
From ec8295b5efd5f28691960a9adcaea25a413da233 Mon Sep 17 00:00:00 2001
From: "Ozkar L. Garcell"
Date: Sun, 10 Dec 2023 22:17:19 +0100
Subject: [PATCH 04/32] feat: added docker scripts
---
docker/celery/beat/start | 7 +++++++
docker/celery/worker/start | 7 +++++++
docker/entrypoint | 30 ++++++++++++++++++++++++++++++
docker/start | 15 +++++++++++++++
docker/wait_for_migration.sh | 16 ++++++++++++++++
5 files changed, 75 insertions(+)
create mode 100644 docker/celery/beat/start
create mode 100644 docker/celery/worker/start
create mode 100755 docker/entrypoint
create mode 100755 docker/start
create mode 100755 docker/wait_for_migration.sh
diff --git a/docker/celery/beat/start b/docker/celery/beat/start
new file mode 100644
index 0000000..be41c09
--- /dev/null
+++ b/docker/celery/beat/start
@@ -0,0 +1,7 @@
+#!/bin/bash
+
+set -o errexit
+set -o nounset
+
+rm -f './celerybeat.pid'
+celery -A shadowmere beat -l info
diff --git a/docker/celery/worker/start b/docker/celery/worker/start
new file mode 100644
index 0000000..35e1855
--- /dev/null
+++ b/docker/celery/worker/start
@@ -0,0 +1,7 @@
+#!/bin/bash
+
+set -o errexit
+set -o pipefail
+set -o nounset
+
+celery -A shadowmere worker -l info -E
diff --git a/docker/entrypoint b/docker/entrypoint
new file mode 100755
index 0000000..89d4d8b
--- /dev/null
+++ b/docker/entrypoint
@@ -0,0 +1,30 @@
+#!/bin/bash
+
+set -o errexit
+set -o pipefail
+cmd="$@"
+
+function postgres_ready(){
+python << END
+import sys
+import psycopg2
+import os
+
+try:
+ dbname = os.getenv('POSTGRES_DB')
+ user = os.getenv('POSTGRES_USER')
+ password = os.getenv('POSTGRES_PASSWORD')
+ conn = psycopg2.connect(dbname=dbname, user=user, password=password, host='db', port=5432)
+except psycopg2.OperationalError:
+ sys.exit(-1)
+sys.exit(0)
+END
+}
+
+until postgres_ready; do
+ >&2 echo "Postgres is unavailable - sleeping"
+ sleep 1
+done
+
+>&2 echo "Postgres is up - continuing..."
+exec $cmd
diff --git a/docker/start b/docker/start
new file mode 100755
index 0000000..35388e8
--- /dev/null
+++ b/docker/start
@@ -0,0 +1,15 @@
+#!/bin/bash
+
+set -o errexit
+set -o pipefail
+set -o nounset
+set -o xtrace
+
+python manage.py migrate --no-input
+python manage.py initadmin
+if [ "${DEBUG}" == "True" ]; then
+ python manage.py runserver 0.0.0.0:8001
+else
+ python manage.py collectstatic --no-input
+ gunicorn shadowmere.wsgi:application --bind 0.0.0.0:8001 -k gevent -w 6 --capture-output
+fi
diff --git a/docker/wait_for_migration.sh b/docker/wait_for_migration.sh
new file mode 100755
index 0000000..8d85db1
--- /dev/null
+++ b/docker/wait_for_migration.sh
@@ -0,0 +1,16 @@
+#!/bin/bash
+
+set -e
+
+cmd="$@"
+
+if [ "${IS_DJANGO_SERVICE}" == "True" ]; then
+ echo "Waiting for the database to become available..."
+ until python3 manage.py migrate; do
+ echo "Database is unavailable, sleeping for 5 seconds..."
+ done
+else
+ sleep 30
+fi
+
+exec $cmd
From 4bea753a39e0c81973a5ed458dcb3e0bc033fa07 Mon Sep 17 00:00:00 2001
From: "Ozkar L. Garcell"
Date: Sun, 10 Dec 2023 22:17:32 +0100
Subject: [PATCH 05/32] feat: static methods for proxyadmin
---
proxylist/admin.py | 3 +++
1 file changed, 3 insertions(+)
diff --git a/proxylist/admin.py b/proxylist/admin.py
index 56396ea..130dbaf 100644
--- a/proxylist/admin.py
+++ b/proxylist/admin.py
@@ -17,6 +17,8 @@ class Meta:
@admin.register(Proxy)
class ProxyAdmin(ImportExportModelAdmin):
+
+ @staticmethod
def update_status(modeladmin, request, queryset):
for proxy in queryset:
update_proxy_status(proxy)
@@ -26,6 +28,7 @@ def update_status(modeladmin, request, queryset):
# This means the proxy is either a duplicate or no longer valid
proxy.delete()
+ @staticmethod
def quality(self, obj):
if obj.times_checked > 0:
return obj.times_check_succeeded * 100 / obj.times_checked
From 7e2531e79c9bb9779d4c1fd2799b0c3d81b2ce6f Mon Sep 17 00:00:00 2001
From: "Ozkar L. Garcell"
Date: Sun, 10 Dec 2023 22:17:43 +0100
Subject: [PATCH 06/32] feat: improved dockerignore
---
.dockerignore | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/.dockerignore b/.dockerignore
index 02b272a..3948023 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -1,4 +1,7 @@
venv/
.env*
db.sqlite3
-.github
+.github/
+.git/
+.idea/
+.venv/
From d9ab5b322a1057f621a908f47c2fd094d6df035c Mon Sep 17 00:00:00 2001
From: "Ozkar L. Garcell"
Date: Sun, 10 Dec 2023 22:17:57 +0100
Subject: [PATCH 07/32] feat: added docker compose recipe for dev env
---
docker-compose.dev.yml | 53 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 53 insertions(+)
create mode 100644 docker-compose.dev.yml
diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml
new file mode 100644
index 0000000..6fae01d
--- /dev/null
+++ b/docker-compose.dev.yml
@@ -0,0 +1,53 @@
+version: "3"
+volumes:
+ shadowmere_data:
+ redis_data:
+
+services:
+ redis:
+ image: redis:alpine
+ restart: always
+ volumes:
+ - redis_data:/data
+
+ db:
+ image: postgres:alpine
+ restart: always
+ volumes:
+ - shadowmere_data:/var/lib/postgresql/data
+ env_file: .env
+
+ shadowmere:
+ &shadowmere
+ build:
+ context: .
+ image: guamulo/shadowmere
+ restart: always
+ command: /start
+ env_file: .env
+ depends_on:
+ - db
+ ports:
+ - "8001:8001"
+
+ celery:
+ <<: *shadowmere
+ image: guamulo/shadowmere-celeryworker
+ restart: always
+ command: /wait_for_migration.sh /start-celeryworker
+ env_file: .env
+ depends_on:
+ - redis
+ ports: []
+ volumes:
+ - /var/run/docker.sock:/var/run/docker.sock
+
+ celery_beat:
+ <<: *shadowmere
+ image: guamulo/shadowmere-celerybeat
+ restart: always
+ command: /wait_for_migration.sh /start-celerybeat
+ env_file: .env
+ ports: []
+ depends_on:
+ - redis
From 5b9ea89fe66ea8c6d8474c792fbedfc45e1b65cd Mon Sep 17 00:00:00 2001
From: "Ozkar L. Garcell"
Date: Sun, 10 Dec 2023 22:18:08 +0100
Subject: [PATCH 08/32] feat: uisng envs
---
manage.py | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/manage.py b/manage.py
index 7ec304c..b0afc13 100755
--- a/manage.py
+++ b/manage.py
@@ -1,12 +1,13 @@
#!/usr/bin/env python
-"""Django's command-line utility for administrative tasks."""
import os
import sys
def main():
- """Run administrative tasks."""
- os.environ.setdefault("DJANGO_SETTINGS_MODULE", "shadowmere.settings")
+ if os.getenv("DEBUG") == "True":
+ os.environ.setdefault("DJANGO_SETTINGS_MODULE", "shadowmere.settings.dev")
+ else:
+ os.environ.setdefault("DJANGO_SETTINGS_MODULE", "shadowmere.settings.prod")
try:
from django.core.management import execute_from_command_line
except ImportError as exc:
From 76dfc2ccf0bf948fa1cb1e4a1a86e290cec41b52 Mon Sep 17 00:00:00 2001
From: "Ozkar L. Garcell"
Date: Sun, 10 Dec 2023 22:18:22 +0100
Subject: [PATCH 09/32] feat: potry lock and toml
---
poetry.lock | 1515 +++++++++++++++++++++++++++++++++++++++++++++++++++
poetry.toml | 3 +
2 files changed, 1518 insertions(+)
create mode 100644 poetry.lock
create mode 100644 poetry.toml
diff --git a/poetry.lock b/poetry.lock
new file mode 100644
index 0000000..6c1dacd
--- /dev/null
+++ b/poetry.lock
@@ -0,0 +1,1515 @@
+# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand.
+
+[[package]]
+name = "amqp"
+version = "5.2.0"
+description = "Low-level AMQP client for Python (fork of amqplib)."
+optional = false
+python-versions = ">=3.6"
+files = [
+ {file = "amqp-5.2.0-py3-none-any.whl", hash = "sha256:827cb12fb0baa892aad844fd95258143bce4027fdac4fccddbc43330fd281637"},
+ {file = "amqp-5.2.0.tar.gz", hash = "sha256:a1ecff425ad063ad42a486c902807d1482311481c8ad95a72694b2975e75f7fd"},
+]
+
+[package.dependencies]
+vine = ">=5.0.0,<6.0.0"
+
+[[package]]
+name = "argon2-cffi"
+version = "23.1.0"
+description = "Argon2 for Python"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "argon2_cffi-23.1.0-py3-none-any.whl", hash = "sha256:c670642b78ba29641818ab2e68bd4e6a78ba53b7eff7b4c3815ae16abf91c7ea"},
+ {file = "argon2_cffi-23.1.0.tar.gz", hash = "sha256:879c3e79a2729ce768ebb7d36d4609e3a78a4ca2ec3a9f12286ca057e3d0db08"},
+]
+
+[package.dependencies]
+argon2-cffi-bindings = "*"
+
+[package.extras]
+dev = ["argon2-cffi[tests,typing]", "tox (>4)"]
+docs = ["furo", "myst-parser", "sphinx", "sphinx-copybutton", "sphinx-notfound-page"]
+tests = ["hypothesis", "pytest"]
+typing = ["mypy"]
+
+[[package]]
+name = "argon2-cffi-bindings"
+version = "21.2.0"
+description = "Low-level CFFI bindings for Argon2"
+optional = false
+python-versions = ">=3.6"
+files = [
+ {file = "argon2-cffi-bindings-21.2.0.tar.gz", hash = "sha256:bb89ceffa6c791807d1305ceb77dbfacc5aa499891d2c55661c6459651fc39e3"},
+ {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:ccb949252cb2ab3a08c02024acb77cfb179492d5701c7cbdbfd776124d4d2367"},
+ {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9524464572e12979364b7d600abf96181d3541da11e23ddf565a32e70bd4dc0d"},
+ {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b746dba803a79238e925d9046a63aa26bf86ab2a2fe74ce6b009a1c3f5c8f2ae"},
+ {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:58ed19212051f49a523abb1dbe954337dc82d947fb6e5a0da60f7c8471a8476c"},
+ {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:bd46088725ef7f58b5a1ef7ca06647ebaf0eb4baff7d1d0d177c6cc8744abd86"},
+ {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-musllinux_1_1_i686.whl", hash = "sha256:8cd69c07dd875537a824deec19f978e0f2078fdda07fd5c42ac29668dda5f40f"},
+ {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:f1152ac548bd5b8bcecfb0b0371f082037e47128653df2e8ba6e914d384f3c3e"},
+ {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-win32.whl", hash = "sha256:603ca0aba86b1349b147cab91ae970c63118a0f30444d4bc80355937c950c082"},
+ {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-win_amd64.whl", hash = "sha256:b2ef1c30440dbbcba7a5dc3e319408b59676e2e039e2ae11a8775ecf482b192f"},
+ {file = "argon2_cffi_bindings-21.2.0-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:e415e3f62c8d124ee16018e491a009937f8cf7ebf5eb430ffc5de21b900dad93"},
+ {file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:3e385d1c39c520c08b53d63300c3ecc28622f076f4c2b0e6d7e796e9f6502194"},
+ {file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2c3e3cc67fdb7d82c4718f19b4e7a87123caf8a93fde7e23cf66ac0337d3cb3f"},
+ {file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6a22ad9800121b71099d0fb0a65323810a15f2e292f2ba450810a7316e128ee5"},
+ {file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f9f8b450ed0547e3d473fdc8612083fd08dd2120d6ac8f73828df9b7d45bb351"},
+ {file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:93f9bf70084f97245ba10ee36575f0c3f1e7d7724d67d8e5b08e61787c320ed7"},
+ {file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:3b9ef65804859d335dc6b31582cad2c5166f0c3e7975f324d9ffaa34ee7e6583"},
+ {file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4966ef5848d820776f5f562a7d45fdd70c2f330c961d0d745b784034bd9f48d"},
+ {file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:20ef543a89dee4db46a1a6e206cd015360e5a75822f76df533845c3cbaf72670"},
+ {file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ed2937d286e2ad0cc79a7087d3c272832865f779430e0cc2b4f3718d3159b0cb"},
+ {file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:5e00316dabdaea0b2dd82d141cc66889ced0cdcbfa599e8b471cf22c620c329a"},
+]
+
+[package.dependencies]
+cffi = ">=1.0.1"
+
+[package.extras]
+dev = ["cogapp", "pre-commit", "pytest", "wheel"]
+tests = ["pytest"]
+
+[[package]]
+name = "asgiref"
+version = "3.7.2"
+description = "ASGI specs, helper code, and adapters"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "asgiref-3.7.2-py3-none-any.whl", hash = "sha256:89b2ef2247e3b562a16eef663bc0e2e703ec6468e2fa8a5cd61cd449786d4f6e"},
+ {file = "asgiref-3.7.2.tar.gz", hash = "sha256:9e0ce3aa93a819ba5b45120216b23878cf6e8525eb3848653452b4192b92afed"},
+]
+
+[package.dependencies]
+typing-extensions = {version = ">=4", markers = "python_version < \"3.11\""}
+
+[package.extras]
+tests = ["mypy (>=0.800)", "pytest", "pytest-asyncio"]
+
+[[package]]
+name = "async-timeout"
+version = "4.0.3"
+description = "Timeout context manager for asyncio programs"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "async-timeout-4.0.3.tar.gz", hash = "sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f"},
+ {file = "async_timeout-4.0.3-py3-none-any.whl", hash = "sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028"},
+]
+
+[[package]]
+name = "attrs"
+version = "23.1.0"
+description = "Classes Without Boilerplate"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "attrs-23.1.0-py3-none-any.whl", hash = "sha256:1f28b4522cdc2fb4256ac1a020c78acf9cba2c6b461ccd2c126f3aa8e8335d04"},
+ {file = "attrs-23.1.0.tar.gz", hash = "sha256:6279836d581513a26f1bf235f9acd333bc9115683f14f7e8fae46c98fc50e015"},
+]
+
+[package.extras]
+cov = ["attrs[tests]", "coverage[toml] (>=5.3)"]
+dev = ["attrs[docs,tests]", "pre-commit"]
+docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope-interface"]
+tests = ["attrs[tests-no-zope]", "zope-interface"]
+tests-no-zope = ["cloudpickle", "hypothesis", "mypy (>=1.1.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"]
+
+[[package]]
+name = "billiard"
+version = "4.2.0"
+description = "Python multiprocessing fork with improvements and bugfixes"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "billiard-4.2.0-py3-none-any.whl", hash = "sha256:07aa978b308f334ff8282bd4a746e681b3513db5c9a514cbdd810cbbdc19714d"},
+ {file = "billiard-4.2.0.tar.gz", hash = "sha256:9a3c3184cb275aa17a732f93f65b20c525d3d9f253722d26a82194803ade5a2c"},
+]
+
+[[package]]
+name = "botocore"
+version = "1.33.11"
+description = "Low-level, data-driven core of boto 3."
+optional = false
+python-versions = ">= 3.7"
+files = [
+ {file = "botocore-1.33.11-py3-none-any.whl", hash = "sha256:b46227eb3fa9cfdc8f5a83920ef347e67adea8095830ed265a3373b13b54421f"},
+ {file = "botocore-1.33.11.tar.gz", hash = "sha256:b14b328f902d120de0a09eaa657a9a701c0ceeb711197c2f01ef0523f855086c"},
+]
+
+[package.dependencies]
+jmespath = ">=0.7.1,<2.0.0"
+python-dateutil = ">=2.1,<3.0.0"
+urllib3 = {version = ">=1.25.4,<2.1", markers = "python_version >= \"3.10\""}
+
+[package.extras]
+crt = ["awscrt (==0.19.17)"]
+
+[[package]]
+name = "cattrs"
+version = "23.2.3"
+description = "Composable complex class support for attrs and dataclasses."
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "cattrs-23.2.3-py3-none-any.whl", hash = "sha256:0341994d94971052e9ee70662542699a3162ea1e0c62f7ce1b4a57f563685108"},
+ {file = "cattrs-23.2.3.tar.gz", hash = "sha256:a934090d95abaa9e911dac357e3a8699e0b4b14f8529bcc7d2b1ad9d51672b9f"},
+]
+
+[package.dependencies]
+attrs = ">=23.1.0"
+exceptiongroup = {version = ">=1.1.1", markers = "python_version < \"3.11\""}
+typing-extensions = {version = ">=4.1.0,<4.6.3 || >4.6.3", markers = "python_version < \"3.11\""}
+
+[package.extras]
+bson = ["pymongo (>=4.4.0)"]
+cbor2 = ["cbor2 (>=5.4.6)"]
+msgpack = ["msgpack (>=1.0.5)"]
+orjson = ["orjson (>=3.9.2)"]
+pyyaml = ["pyyaml (>=6.0)"]
+tomlkit = ["tomlkit (>=0.11.8)"]
+ujson = ["ujson (>=5.7.0)"]
+
+[[package]]
+name = "celery"
+version = "5.3.6"
+description = "Distributed Task Queue."
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "celery-5.3.6-py3-none-any.whl", hash = "sha256:9da4ea0118d232ce97dff5ed4974587fb1c0ff5c10042eb15278487cdd27d1af"},
+ {file = "celery-5.3.6.tar.gz", hash = "sha256:870cc71d737c0200c397290d730344cc991d13a057534353d124c9380267aab9"},
+]
+
+[package.dependencies]
+billiard = ">=4.2.0,<5.0"
+click = ">=8.1.2,<9.0"
+click-didyoumean = ">=0.3.0"
+click-plugins = ">=1.1.1"
+click-repl = ">=0.2.0"
+kombu = ">=5.3.4,<6.0"
+python-dateutil = ">=2.8.2"
+tzdata = ">=2022.7"
+vine = ">=5.1.0,<6.0"
+
+[package.extras]
+arangodb = ["pyArango (>=2.0.2)"]
+auth = ["cryptography (==41.0.5)"]
+azureblockblob = ["azure-storage-blob (>=12.15.0)"]
+brotli = ["brotli (>=1.0.0)", "brotlipy (>=0.7.0)"]
+cassandra = ["cassandra-driver (>=3.25.0,<4)"]
+consul = ["python-consul2 (==0.1.5)"]
+cosmosdbsql = ["pydocumentdb (==2.3.5)"]
+couchbase = ["couchbase (>=3.0.0)"]
+couchdb = ["pycouchdb (==1.14.2)"]
+django = ["Django (>=2.2.28)"]
+dynamodb = ["boto3 (>=1.26.143)"]
+elasticsearch = ["elastic-transport (<=8.10.0)", "elasticsearch (<=8.11.0)"]
+eventlet = ["eventlet (>=0.32.0)"]
+gevent = ["gevent (>=1.5.0)"]
+librabbitmq = ["librabbitmq (>=2.0.0)"]
+memcache = ["pylibmc (==1.6.3)"]
+mongodb = ["pymongo[srv] (>=4.0.2)"]
+msgpack = ["msgpack (==1.0.7)"]
+pymemcache = ["python-memcached (==1.59)"]
+pyro = ["pyro4 (==4.82)"]
+pytest = ["pytest-celery (==0.0.0)"]
+redis = ["redis (>=4.5.2,!=4.5.5,<6.0.0)"]
+s3 = ["boto3 (>=1.26.143)"]
+slmq = ["softlayer-messaging (>=1.0.3)"]
+solar = ["ephem (==4.1.5)"]
+sqlalchemy = ["sqlalchemy (>=1.4.48,<2.1)"]
+sqs = ["boto3 (>=1.26.143)", "kombu[sqs] (>=5.3.0)", "pycurl (>=7.43.0.5)", "urllib3 (>=1.26.16)"]
+tblib = ["tblib (>=1.3.0)", "tblib (>=1.5.0)"]
+yaml = ["PyYAML (>=3.10)"]
+zookeeper = ["kazoo (>=1.3.1)"]
+zstd = ["zstandard (==0.22.0)"]
+
+[[package]]
+name = "certifi"
+version = "2023.11.17"
+description = "Python package for providing Mozilla's CA Bundle."
+optional = false
+python-versions = ">=3.6"
+files = [
+ {file = "certifi-2023.11.17-py3-none-any.whl", hash = "sha256:e036ab49d5b79556f99cfc2d9320b34cfbe5be05c5871b51de9329f0603b0474"},
+ {file = "certifi-2023.11.17.tar.gz", hash = "sha256:9b469f3a900bf28dc19b8cfbf8019bf47f7fdd1a65a1d4ffb98fc14166beb4d1"},
+]
+
+[[package]]
+name = "cffi"
+version = "1.16.0"
+description = "Foreign Function Interface for Python calling C code."
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "cffi-1.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6b3d6606d369fc1da4fd8c357d026317fbb9c9b75d36dc16e90e84c26854b088"},
+ {file = "cffi-1.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ac0f5edd2360eea2f1daa9e26a41db02dd4b0451b48f7c318e217ee092a213e9"},
+ {file = "cffi-1.16.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7e61e3e4fa664a8588aa25c883eab612a188c725755afff6289454d6362b9673"},
+ {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a72e8961a86d19bdb45851d8f1f08b041ea37d2bd8d4fd19903bc3083d80c896"},
+ {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5b50bf3f55561dac5438f8e70bfcdfd74543fd60df5fa5f62d94e5867deca684"},
+ {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7651c50c8c5ef7bdb41108b7b8c5a83013bfaa8a935590c5d74627c047a583c7"},
+ {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4108df7fe9b707191e55f33efbcb2d81928e10cea45527879a4749cbe472614"},
+ {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:32c68ef735dbe5857c810328cb2481e24722a59a2003018885514d4c09af9743"},
+ {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:673739cb539f8cdaa07d92d02efa93c9ccf87e345b9a0b556e3ecc666718468d"},
+ {file = "cffi-1.16.0-cp310-cp310-win32.whl", hash = "sha256:9f90389693731ff1f659e55c7d1640e2ec43ff725cc61b04b2f9c6d8d017df6a"},
+ {file = "cffi-1.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:e6024675e67af929088fda399b2094574609396b1decb609c55fa58b028a32a1"},
+ {file = "cffi-1.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b84834d0cf97e7d27dd5b7f3aca7b6e9263c56308ab9dc8aae9784abb774d404"},
+ {file = "cffi-1.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1b8ebc27c014c59692bb2664c7d13ce7a6e9a629be20e54e7271fa696ff2b417"},
+ {file = "cffi-1.16.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee07e47c12890ef248766a6e55bd38ebfb2bb8edd4142d56db91b21ea68b7627"},
+ {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8a9d3ebe49f084ad71f9269834ceccbf398253c9fac910c4fd7053ff1386936"},
+ {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e70f54f1796669ef691ca07d046cd81a29cb4deb1e5f942003f401c0c4a2695d"},
+ {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5bf44d66cdf9e893637896c7faa22298baebcd18d1ddb6d2626a6e39793a1d56"},
+ {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b78010e7b97fef4bee1e896df8a4bbb6712b7f05b7ef630f9d1da00f6444d2e"},
+ {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c6a164aa47843fb1b01e941d385aab7215563bb8816d80ff3a363a9f8448a8dc"},
+ {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e09f3ff613345df5e8c3667da1d918f9149bd623cd9070c983c013792a9a62eb"},
+ {file = "cffi-1.16.0-cp311-cp311-win32.whl", hash = "sha256:2c56b361916f390cd758a57f2e16233eb4f64bcbeee88a4881ea90fca14dc6ab"},
+ {file = "cffi-1.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:db8e577c19c0fda0beb7e0d4e09e0ba74b1e4c092e0e40bfa12fe05b6f6d75ba"},
+ {file = "cffi-1.16.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956"},
+ {file = "cffi-1.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:68e7c44931cc171c54ccb702482e9fc723192e88d25a0e133edd7aff8fcd1f6e"},
+ {file = "cffi-1.16.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abd808f9c129ba2beda4cfc53bde801e5bcf9d6e0f22f095e45327c038bfe68e"},
+ {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88e2b3c14bdb32e440be531ade29d3c50a1a59cd4e51b1dd8b0865c54ea5d2e2"},
+ {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357"},
+ {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b7be2d771cdba2942e13215c4e340bfd76398e9227ad10402a8767ab1865d2e6"},
+ {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e715596e683d2ce000574bae5d07bd522c781a822866c20495e52520564f0969"},
+ {file = "cffi-1.16.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2d92b25dbf6cae33f65005baf472d2c245c050b1ce709cc4588cdcdd5495b520"},
+ {file = "cffi-1.16.0-cp312-cp312-win32.whl", hash = "sha256:b2ca4e77f9f47c55c194982e10f058db063937845bb2b7a86c84a6cfe0aefa8b"},
+ {file = "cffi-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:68678abf380b42ce21a5f2abde8efee05c114c2fdb2e9eef2efdb0257fba1235"},
+ {file = "cffi-1.16.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc"},
+ {file = "cffi-1.16.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a09582f178759ee8128d9270cd1344154fd473bb77d94ce0aeb2a93ebf0feaf0"},
+ {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e760191dd42581e023a68b758769e2da259b5d52e3103c6060ddc02c9edb8d7b"},
+ {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:80876338e19c951fdfed6198e70bc88f1c9758b94578d5a7c4c91a87af3cf31c"},
+ {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a6a14b17d7e17fa0d207ac08642c8820f84f25ce17a442fd15e27ea18d67c59b"},
+ {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6602bc8dc6f3a9e02b6c22c4fc1e47aa50f8f8e6d3f78a5e16ac33ef5fefa324"},
+ {file = "cffi-1.16.0-cp38-cp38-win32.whl", hash = "sha256:131fd094d1065b19540c3d72594260f118b231090295d8c34e19a7bbcf2e860a"},
+ {file = "cffi-1.16.0-cp38-cp38-win_amd64.whl", hash = "sha256:31d13b0f99e0836b7ff893d37af07366ebc90b678b6664c955b54561fc36ef36"},
+ {file = "cffi-1.16.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:582215a0e9adbe0e379761260553ba11c58943e4bbe9c36430c4ca6ac74b15ed"},
+ {file = "cffi-1.16.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b29ebffcf550f9da55bec9e02ad430c992a87e5f512cd63388abb76f1036d8d2"},
+ {file = "cffi-1.16.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dc9b18bf40cc75f66f40a7379f6a9513244fe33c0e8aa72e2d56b0196a7ef872"},
+ {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cb4a35b3642fc5c005a6755a5d17c6c8b6bcb6981baf81cea8bfbc8903e8ba8"},
+ {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b86851a328eedc692acf81fb05444bdf1891747c25af7529e39ddafaf68a4f3f"},
+ {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c0f31130ebc2d37cdd8e44605fb5fa7ad59049298b3f745c74fa74c62fbfcfc4"},
+ {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f8e709127c6c77446a8c0a8c8bf3c8ee706a06cd44b1e827c3e6a2ee6b8c098"},
+ {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:748dcd1e3d3d7cd5443ef03ce8685043294ad6bd7c02a38d1bd367cfd968e000"},
+ {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8895613bcc094d4a1b2dbe179d88d7fb4a15cee43c052e8885783fac397d91fe"},
+ {file = "cffi-1.16.0-cp39-cp39-win32.whl", hash = "sha256:ed86a35631f7bfbb28e108dd96773b9d5a6ce4811cf6ea468bb6a359b256b1e4"},
+ {file = "cffi-1.16.0-cp39-cp39-win_amd64.whl", hash = "sha256:3686dffb02459559c74dd3d81748269ffb0eb027c39a6fc99502de37d501faa8"},
+ {file = "cffi-1.16.0.tar.gz", hash = "sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0"},
+]
+
+[package.dependencies]
+pycparser = "*"
+
+[[package]]
+name = "charset-normalizer"
+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.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]]
+name = "click"
+version = "8.1.7"
+description = "Composable command line interface toolkit"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"},
+ {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"},
+]
+
+[package.dependencies]
+colorama = {version = "*", markers = "platform_system == \"Windows\""}
+
+[[package]]
+name = "click-didyoumean"
+version = "0.3.0"
+description = "Enables git-like *did-you-mean* feature in click"
+optional = false
+python-versions = ">=3.6.2,<4.0.0"
+files = [
+ {file = "click-didyoumean-0.3.0.tar.gz", hash = "sha256:f184f0d851d96b6d29297354ed981b7dd71df7ff500d82fa6d11f0856bee8035"},
+ {file = "click_didyoumean-0.3.0-py3-none-any.whl", hash = "sha256:a0713dc7a1de3f06bc0df5a9567ad19ead2d3d5689b434768a6145bff77c0667"},
+]
+
+[package.dependencies]
+click = ">=7"
+
+[[package]]
+name = "click-plugins"
+version = "1.1.1"
+description = "An extension module for click to enable registering CLI commands via setuptools entry-points."
+optional = false
+python-versions = "*"
+files = [
+ {file = "click-plugins-1.1.1.tar.gz", hash = "sha256:46ab999744a9d831159c3411bb0c79346d94a444df9a3a3742e9ed63645f264b"},
+ {file = "click_plugins-1.1.1-py2.py3-none-any.whl", hash = "sha256:5d262006d3222f5057fd81e1623d4443e41dcda5dc815c06b442aa3c02889fc8"},
+]
+
+[package.dependencies]
+click = ">=4.0"
+
+[package.extras]
+dev = ["coveralls", "pytest (>=3.6)", "pytest-cov", "wheel"]
+
+[[package]]
+name = "click-repl"
+version = "0.3.0"
+description = "REPL plugin for Click"
+optional = false
+python-versions = ">=3.6"
+files = [
+ {file = "click-repl-0.3.0.tar.gz", hash = "sha256:17849c23dba3d667247dc4defe1757fff98694e90fe37474f3feebb69ced26a9"},
+ {file = "click_repl-0.3.0-py3-none-any.whl", hash = "sha256:fb7e06deb8da8de86180a33a9da97ac316751c094c6899382da7feeeeb51b812"},
+]
+
+[package.dependencies]
+click = ">=7.0"
+prompt-toolkit = ">=3.0.36"
+
+[package.extras]
+testing = ["pytest (>=7.2.1)", "pytest-cov (>=4.0.0)", "tox (>=4.4.3)"]
+
+[[package]]
+name = "colorama"
+version = "0.4.6"
+description = "Cross-platform colored terminal text."
+optional = false
+python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
+files = [
+ {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"},
+ {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
+]
+
+[[package]]
+name = "defusedxml"
+version = "0.7.1"
+description = "XML bomb protection for Python stdlib modules"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
+files = [
+ {file = "defusedxml-0.7.1-py2.py3-none-any.whl", hash = "sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61"},
+ {file = "defusedxml-0.7.1.tar.gz", hash = "sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69"},
+]
+
+[[package]]
+name = "diff-match-patch"
+version = "20230430"
+description = "Diff Match and Patch"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "diff-match-patch-20230430.tar.gz", hash = "sha256:953019cdb9c9d2c9e47b5b12bcff3cf4746fc4598eb406076fa1fc27e6a1f15c"},
+ {file = "diff_match_patch-20230430-py3-none-any.whl", hash = "sha256:dce43505fb7b1b317de7195579388df0746d90db07015ed47a85e5e44930ef93"},
+]
+
+[package.extras]
+dev = ["attribution (==1.6.2)", "black (==23.3.0)", "flit (==3.8.0)", "mypy (==1.2.0)", "ufmt (==2.1.0)", "usort (==1.0.6)"]
+
+[[package]]
+name = "django"
+version = "5.0"
+description = "A high-level Python web framework that encourages rapid development and clean, pragmatic design."
+optional = false
+python-versions = ">=3.10"
+files = [
+ {file = "Django-5.0-py3-none-any.whl", hash = "sha256:3a9fd52b8dbeae335ddf4a9dfa6c6a0853a1122f1fb071a8d5eca979f73a05c8"},
+ {file = "Django-5.0.tar.gz", hash = "sha256:7d29e14dfbc19cb6a95a4bd669edbde11f5d4c6a71fdaa42c2d40b6846e807f7"},
+]
+
+[package.dependencies]
+asgiref = ">=3.7.0"
+sqlparse = ">=0.3.1"
+tzdata = {version = "*", markers = "sys_platform == \"win32\""}
+
+[package.extras]
+argon2 = ["argon2-cffi (>=19.1.0)"]
+bcrypt = ["bcrypt"]
+
+[[package]]
+name = "django-admin-rangefilter"
+version = "0.12.0"
+description = "django-admin-rangefilter app, add the filter by a custom date range on the admin UI."
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
+files = [
+ {file = "django-admin-rangefilter-0.12.0.tar.gz", hash = "sha256:56035f4190d35aad4e699f8fd81306f964642edc96e15ec2a532a1598a466615"},
+ {file = "django_admin_rangefilter-0.12.0-py2.py3-none-any.whl", hash = "sha256:4fd7211271c70c51469fc39b182b70f1199ab9ce0b16264654a2eec96751d686"},
+]
+
+[[package]]
+name = "django-environ"
+version = "0.11.2"
+description = "A package that allows you to utilize 12factor inspired environment variables to configure your Django application."
+optional = false
+python-versions = ">=3.6,<4"
+files = [
+ {file = "django-environ-0.11.2.tar.gz", hash = "sha256:f32a87aa0899894c27d4e1776fa6b477e8164ed7f6b3e410a62a6d72caaf64be"},
+ {file = "django_environ-0.11.2-py2.py3-none-any.whl", hash = "sha256:0ff95ab4344bfeff693836aa978e6840abef2e2f1145adff7735892711590c05"},
+]
+
+[package.extras]
+develop = ["coverage[toml] (>=5.0a4)", "furo (>=2021.8.17b43,<2021.9.dev0)", "pytest (>=4.6.11)", "sphinx (>=3.5.0)", "sphinx-notfound-page"]
+docs = ["furo (>=2021.8.17b43,<2021.9.dev0)", "sphinx (>=3.5.0)", "sphinx-notfound-page"]
+testing = ["coverage[toml] (>=5.0a4)", "pytest (>=4.6.11)"]
+
+[[package]]
+name = "django-filter"
+version = "23.5"
+description = "Django-filter is a reusable Django application for allowing users to filter querysets dynamically."
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "django-filter-23.5.tar.gz", hash = "sha256:67583aa43b91fe8c49f74a832d95f4d8442be628fd4c6d65e9f811f5153a4e5c"},
+ {file = "django_filter-23.5-py3-none-any.whl", hash = "sha256:99122a201d83860aef4fe77758b69dda913e874cc5e0eaa50a86b0b18d708400"},
+]
+
+[package.dependencies]
+Django = ">=3.2"
+
+[[package]]
+name = "django-import-export"
+version = "3.3.3"
+description = "Django application and library for importing and exporting data with included admin integration."
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "django-import-export-3.3.3.tar.gz", hash = "sha256:2c1b16e1cf2ea5f62a165d8867e7c6dcff25673ab7201fd18aaf67c9ee90367e"},
+ {file = "django_import_export-3.3.3-py3-none-any.whl", hash = "sha256:78973202e93897326ab0411d64eaf89b72779fcb21ee9e5f64f3fb96571a5978"},
+]
+
+[package.dependencies]
+diff-match-patch = "*"
+Django = ">=3.2"
+tablib = {version = "3.5.0", extras = ["html", "ods", "xls", "xlsx", "yaml"]}
+
+[[package]]
+name = "django-jazzmin"
+version = "2.6.0"
+description = "Drop-in theme for django admin, that utilises AdminLTE 3 & Bootstrap 4 to make yo' admin look jazzy"
+optional = false
+python-versions = ">=3.6.2"
+files = [
+ {file = "django_jazzmin-2.6.0-py3-none-any.whl", hash = "sha256:fb554c2d564649c65243b13385121fdbdda58521f49544f9d7cb9c414a4908d4"},
+ {file = "django_jazzmin-2.6.0.tar.gz", hash = "sha256:5bb07055cf19183030724f976904fd8b6337559727959340a43832fab0531812"},
+]
+
+[package.dependencies]
+django = ">=2.2"
+
+[[package]]
+name = "django-minio-storage"
+version = "0.5.7"
+description = "Django file storage using the minio python client"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "django-minio-storage-0.5.7.tar.gz", hash = "sha256:9e499600340b7a7a4bc86063f54218631b65bc46dee9d2faf578f17ebc2a6d92"},
+ {file = "django_minio_storage-0.5.7-py3-none-any.whl", hash = "sha256:2e36b4f3c44c83a124e7b811e19c502cbeab77149bc7c73763e901b1948737bb"},
+]
+
+[package.dependencies]
+django = ">=3.2"
+minio = ">=7.1.16"
+
+[[package]]
+name = "django-prometheus"
+version = "2.3.1"
+description = "Django middlewares to monitor your application with Prometheus.io."
+optional = false
+python-versions = "*"
+files = [
+ {file = "django-prometheus-2.3.1.tar.gz", hash = "sha256:f9c8b6c780c9419ea01043c63a437d79db2c33353451347894408184ad9c3e1e"},
+ {file = "django_prometheus-2.3.1-py2.py3-none-any.whl", hash = "sha256:cf9b26f7ba2e4568f08f8f91480a2882023f5908579681bcf06a4d2465f12168"},
+]
+
+[package.dependencies]
+prometheus-client = ">=0.7"
+
+[[package]]
+name = "django-storages"
+version = "1.14.2"
+description = "Support for many storage backends in Django"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "django-storages-1.14.2.tar.gz", hash = "sha256:51b36af28cc5813b98d5f3dfe7459af638d84428c8df4a03990c7d74d1bea4e5"},
+ {file = "django_storages-1.14.2-py3-none-any.whl", hash = "sha256:1db759346b52ada6c2efd9f23d8241ecf518813eb31db9e2589207174f58f6ad"},
+]
+
+[package.dependencies]
+Django = ">=3.2"
+
+[package.extras]
+azure = ["azure-core (>=1.13)", "azure-storage-blob (>=12)"]
+boto3 = ["boto3 (>=1.4.4)"]
+dropbox = ["dropbox (>=7.2.1)"]
+google = ["google-cloud-storage (>=1.27)"]
+libcloud = ["apache-libcloud"]
+s3 = ["boto3 (>=1.4.4)"]
+sftp = ["paramiko (>=1.15)"]
+
+[[package]]
+name = "djangorestframework"
+version = "3.14.0"
+description = "Web APIs for Django, made easy."
+optional = false
+python-versions = ">=3.6"
+files = [
+ {file = "djangorestframework-3.14.0-py3-none-any.whl", hash = "sha256:eb63f58c9f218e1a7d064d17a70751f528ed4e1d35547fdade9aaf4cd103fd08"},
+ {file = "djangorestframework-3.14.0.tar.gz", hash = "sha256:579a333e6256b09489cbe0a067e66abe55c6595d8926be6b99423786334350c8"},
+]
+
+[package.dependencies]
+django = ">=3.0"
+pytz = "*"
+
+[[package]]
+name = "emoji-country-flag"
+version = "1.3.2"
+description = "En/Decode unicode country flags emoji"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "emoji-country-flag-1.3.2.tar.gz", hash = "sha256:42d9fc1a8ec27b3ef2c18a39532dcdbf0527afbc95749be02a3afc1f1b165aa3"},
+ {file = "emoji_country_flag-1.3.2-py2.py3-none-any.whl", hash = "sha256:6ddcf8f3bc55b2f59b1d7d9dc830e90f9423f555dd37862c4c2e220d42726f73"},
+]
+
+[package.extras]
+test = ["emoji", "pytest", "setuptools"]
+
+[[package]]
+name = "et-xmlfile"
+version = "1.1.0"
+description = "An implementation of lxml.xmlfile for the standard library"
+optional = false
+python-versions = ">=3.6"
+files = [
+ {file = "et_xmlfile-1.1.0-py3-none-any.whl", hash = "sha256:a2ba85d1d6a74ef63837eed693bcb89c3f752169b0e3e7ae5b16ca5e1b3deada"},
+ {file = "et_xmlfile-1.1.0.tar.gz", hash = "sha256:8eb9e2bc2f8c97e37a2dc85a09ecdcdec9d8a396530a6d5a33b30b9a92da0c5c"},
+]
+
+[[package]]
+name = "exceptiongroup"
+version = "1.2.0"
+description = "Backport of PEP 654 (exception groups)"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "exceptiongroup-1.2.0-py3-none-any.whl", hash = "sha256:4bfd3996ac73b41e9b9628b04e079f193850720ea5945fc96a08633c66912f14"},
+ {file = "exceptiongroup-1.2.0.tar.gz", hash = "sha256:91f5c769735f051a4290d52edd0858999b57e5876e9f85937691bd4c9fa3ed68"},
+]
+
+[package.extras]
+test = ["pytest (>=6)"]
+
+[[package]]
+name = "gunicorn"
+version = "21.2.0"
+description = "WSGI HTTP Server for UNIX"
+optional = false
+python-versions = ">=3.5"
+files = [
+ {file = "gunicorn-21.2.0-py3-none-any.whl", hash = "sha256:3213aa5e8c24949e792bcacfc176fef362e7aac80b76c56f6b5122bf350722f0"},
+ {file = "gunicorn-21.2.0.tar.gz", hash = "sha256:88ec8bff1d634f98e61b9f65bc4bf3cd918a90806c6f5c48bc5603849ec81033"},
+]
+
+[package.dependencies]
+packaging = "*"
+
+[package.extras]
+eventlet = ["eventlet (>=0.24.1)"]
+gevent = ["gevent (>=1.4.0)"]
+setproctitle = ["setproctitle"]
+tornado = ["tornado (>=0.2)"]
+
+[[package]]
+name = "h11"
+version = "0.14.0"
+description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761"},
+ {file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"},
+]
+
+[[package]]
+name = "idna"
+version = "3.6"
+description = "Internationalized Domain Names in Applications (IDNA)"
+optional = false
+python-versions = ">=3.5"
+files = [
+ {file = "idna-3.6-py3-none-any.whl", hash = "sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f"},
+ {file = "idna-3.6.tar.gz", hash = "sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca"},
+]
+
+[[package]]
+name = "jmespath"
+version = "1.0.1"
+description = "JSON Matching Expressions"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "jmespath-1.0.1-py3-none-any.whl", hash = "sha256:02e2e4cc71b5bcab88332eebf907519190dd9e6e82107fa7f83b1003a6252980"},
+ {file = "jmespath-1.0.1.tar.gz", hash = "sha256:90261b206d6defd58fdd5e85f478bf633a2901798906be2ad389150c5c60edbe"},
+]
+
+[[package]]
+name = "kombu"
+version = "5.3.4"
+description = "Messaging library for Python."
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "kombu-5.3.4-py3-none-any.whl", hash = "sha256:63bb093fc9bb80cfb3a0972336a5cec1fa7ac5f9ef7e8237c6bf8dda9469313e"},
+ {file = "kombu-5.3.4.tar.gz", hash = "sha256:0bb2e278644d11dea6272c17974a3dbb9688a949f3bb60aeb5b791329c44fadc"},
+]
+
+[package.dependencies]
+amqp = ">=5.1.1,<6.0.0"
+vine = "*"
+
+[package.extras]
+azureservicebus = ["azure-servicebus (>=7.10.0)"]
+azurestoragequeues = ["azure-identity (>=1.12.0)", "azure-storage-queue (>=12.6.0)"]
+confluentkafka = ["confluent-kafka (>=2.2.0)"]
+consul = ["python-consul2"]
+librabbitmq = ["librabbitmq (>=2.0.0)"]
+mongodb = ["pymongo (>=4.1.1)"]
+msgpack = ["msgpack"]
+pyro = ["pyro4"]
+qpid = ["qpid-python (>=0.26)", "qpid-tools (>=0.26)"]
+redis = ["redis (>=4.5.2,!=4.5.5,<6.0.0)"]
+slmq = ["softlayer-messaging (>=1.0.3)"]
+sqlalchemy = ["sqlalchemy (>=1.4.48,<2.1)"]
+sqs = ["boto3 (>=1.26.143)", "pycurl (>=7.43.0.5)", "urllib3 (>=1.26.16)"]
+yaml = ["PyYAML (>=3.10)"]
+zookeeper = ["kazoo (>=2.8.0)"]
+
+[[package]]
+name = "lsprotocol"
+version = "2023.0.0"
+description = "Python implementation of the Language Server Protocol."
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "lsprotocol-2023.0.0-py3-none-any.whl", hash = "sha256:e85fc87ee26c816adca9eb497bb3db1a7c79c477a11563626e712eaccf926a05"},
+ {file = "lsprotocol-2023.0.0.tar.gz", hash = "sha256:c9d92e12a3f4ed9317d3068226592860aab5357d93cf5b2451dc244eee8f35f2"},
+]
+
+[package.dependencies]
+attrs = ">=21.3.0"
+cattrs = "*"
+
+[[package]]
+name = "markuppy"
+version = "1.14"
+description = "An HTML/XML generator"
+optional = false
+python-versions = "*"
+files = [
+ {file = "MarkupPy-1.14.tar.gz", hash = "sha256:1adee2c0a542af378fe84548ff6f6b0168f3cb7f426b46961038a2bcfaad0d5f"},
+]
+
+[[package]]
+name = "minio"
+version = "7.2.0"
+description = "MinIO Python SDK for Amazon S3 Compatible Cloud Storage"
+optional = false
+python-versions = "*"
+files = [
+ {file = "minio-7.2.0-py3-none-any.whl", hash = "sha256:10656272c16156fa08436ce2b27e25e4134ef5142a8c259513ee26fb514531a6"},
+ {file = "minio-7.2.0.tar.gz", hash = "sha256:4b015b018d10c1505f7c3e724fa7c2267760ac7bee6463a624cbf22cd272877b"},
+]
+
+[package.dependencies]
+argon2-cffi = "*"
+certifi = "*"
+pycryptodome = "*"
+urllib3 = "*"
+
+[[package]]
+name = "odfpy"
+version = "1.4.1"
+description = "Python API and tools to manipulate OpenDocument files"
+optional = false
+python-versions = "*"
+files = [
+ {file = "odfpy-1.4.1.tar.gz", hash = "sha256:db766a6e59c5103212f3cc92ec8dd50a0f3a02790233ed0b52148b70d3c438ec"},
+]
+
+[package.dependencies]
+defusedxml = "*"
+
+[[package]]
+name = "openpyxl"
+version = "3.1.2"
+description = "A Python library to read/write Excel 2010 xlsx/xlsm files"
+optional = false
+python-versions = ">=3.6"
+files = [
+ {file = "openpyxl-3.1.2-py2.py3-none-any.whl", hash = "sha256:f91456ead12ab3c6c2e9491cf33ba6d08357d802192379bb482f1033ade496f5"},
+ {file = "openpyxl-3.1.2.tar.gz", hash = "sha256:a6f5977418eff3b2d5500d54d9db50c8277a368436f4e4f8ddb1be3422870184"},
+]
+
+[package.dependencies]
+et-xmlfile = "*"
+
+[[package]]
+name = "packaging"
+version = "23.2"
+description = "Core utilities for Python packages"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7"},
+ {file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"},
+]
+
+[[package]]
+name = "pillow"
+version = "10.1.0"
+description = "Python Imaging Library (Fork)"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "Pillow-10.1.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:1ab05f3db77e98f93964697c8efc49c7954b08dd61cff526b7f2531a22410106"},
+ {file = "Pillow-10.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6932a7652464746fcb484f7fc3618e6503d2066d853f68a4bd97193a3996e273"},
+ {file = "Pillow-10.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5f63b5a68daedc54c7c3464508d8c12075e56dcfbd42f8c1bf40169061ae666"},
+ {file = "Pillow-10.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0949b55eb607898e28eaccb525ab104b2d86542a85c74baf3a6dc24002edec2"},
+ {file = "Pillow-10.1.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:ae88931f93214777c7a3aa0a8f92a683f83ecde27f65a45f95f22d289a69e593"},
+ {file = "Pillow-10.1.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:b0eb01ca85b2361b09480784a7931fc648ed8b7836f01fb9241141b968feb1db"},
+ {file = "Pillow-10.1.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d27b5997bdd2eb9fb199982bb7eb6164db0426904020dc38c10203187ae2ff2f"},
+ {file = "Pillow-10.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7df5608bc38bd37ef585ae9c38c9cd46d7c81498f086915b0f97255ea60c2818"},
+ {file = "Pillow-10.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:41f67248d92a5e0a2076d3517d8d4b1e41a97e2df10eb8f93106c89107f38b57"},
+ {file = "Pillow-10.1.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:1fb29c07478e6c06a46b867e43b0bcdb241b44cc52be9bc25ce5944eed4648e7"},
+ {file = "Pillow-10.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2cdc65a46e74514ce742c2013cd4a2d12e8553e3a2563c64879f7c7e4d28bce7"},
+ {file = "Pillow-10.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50d08cd0a2ecd2a8657bd3d82c71efd5a58edb04d9308185d66c3a5a5bed9610"},
+ {file = "Pillow-10.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:062a1610e3bc258bff2328ec43f34244fcec972ee0717200cb1425214fe5b839"},
+ {file = "Pillow-10.1.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:61f1a9d247317fa08a308daaa8ee7b3f760ab1809ca2da14ecc88ae4257d6172"},
+ {file = "Pillow-10.1.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:a646e48de237d860c36e0db37ecaecaa3619e6f3e9d5319e527ccbc8151df061"},
+ {file = "Pillow-10.1.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:47e5bf85b80abc03be7455c95b6d6e4896a62f6541c1f2ce77a7d2bb832af262"},
+ {file = "Pillow-10.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:a92386125e9ee90381c3369f57a2a50fa9e6aa8b1cf1d9c4b200d41a7dd8e992"},
+ {file = "Pillow-10.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:0f7c276c05a9767e877a0b4c5050c8bee6a6d960d7f0c11ebda6b99746068c2a"},
+ {file = "Pillow-10.1.0-cp312-cp312-macosx_10_10_x86_64.whl", hash = "sha256:a89b8312d51715b510a4fe9fc13686283f376cfd5abca8cd1c65e4c76e21081b"},
+ {file = "Pillow-10.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:00f438bb841382b15d7deb9a05cc946ee0f2c352653c7aa659e75e592f6fa17d"},
+ {file = "Pillow-10.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3d929a19f5469b3f4df33a3df2983db070ebb2088a1e145e18facbc28cae5b27"},
+ {file = "Pillow-10.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9a92109192b360634a4489c0c756364c0c3a2992906752165ecb50544c251312"},
+ {file = "Pillow-10.1.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:0248f86b3ea061e67817c47ecbe82c23f9dd5d5226200eb9090b3873d3ca32de"},
+ {file = "Pillow-10.1.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:9882a7451c680c12f232a422730f986a1fcd808da0fd428f08b671237237d651"},
+ {file = "Pillow-10.1.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:1c3ac5423c8c1da5928aa12c6e258921956757d976405e9467c5f39d1d577a4b"},
+ {file = "Pillow-10.1.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:806abdd8249ba3953c33742506fe414880bad78ac25cc9a9b1c6ae97bedd573f"},
+ {file = "Pillow-10.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:eaed6977fa73408b7b8a24e8b14e59e1668cfc0f4c40193ea7ced8e210adf996"},
+ {file = "Pillow-10.1.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:fe1e26e1ffc38be097f0ba1d0d07fcade2bcfd1d023cda5b29935ae8052bd793"},
+ {file = "Pillow-10.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7a7e3daa202beb61821c06d2517428e8e7c1aab08943e92ec9e5755c2fc9ba5e"},
+ {file = "Pillow-10.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:24fadc71218ad2b8ffe437b54876c9382b4a29e030a05a9879f615091f42ffc2"},
+ {file = "Pillow-10.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa1d323703cfdac2036af05191b969b910d8f115cf53093125e4058f62012c9a"},
+ {file = "Pillow-10.1.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:912e3812a1dbbc834da2b32299b124b5ddcb664ed354916fd1ed6f193f0e2d01"},
+ {file = "Pillow-10.1.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:7dbaa3c7de82ef37e7708521be41db5565004258ca76945ad74a8e998c30af8d"},
+ {file = "Pillow-10.1.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:9d7bc666bd8c5a4225e7ac71f2f9d12466ec555e89092728ea0f5c0c2422ea80"},
+ {file = "Pillow-10.1.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:baada14941c83079bf84c037e2d8b7506ce201e92e3d2fa0d1303507a8538212"},
+ {file = "Pillow-10.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:2ef6721c97894a7aa77723740a09547197533146fba8355e86d6d9a4a1056b14"},
+ {file = "Pillow-10.1.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:0a026c188be3b443916179f5d04548092e253beb0c3e2ee0a4e2cdad72f66099"},
+ {file = "Pillow-10.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:04f6f6149f266a100374ca3cc368b67fb27c4af9f1cc8cb6306d849dcdf12616"},
+ {file = "Pillow-10.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bb40c011447712d2e19cc261c82655f75f32cb724788df315ed992a4d65696bb"},
+ {file = "Pillow-10.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1a8413794b4ad9719346cd9306118450b7b00d9a15846451549314a58ac42219"},
+ {file = "Pillow-10.1.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:c9aeea7b63edb7884b031a35305629a7593272b54f429a9869a4f63a1bf04c34"},
+ {file = "Pillow-10.1.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:b4005fee46ed9be0b8fb42be0c20e79411533d1fd58edabebc0dd24626882cfd"},
+ {file = "Pillow-10.1.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:4d0152565c6aa6ebbfb1e5d8624140a440f2b99bf7afaafbdbf6430426497f28"},
+ {file = "Pillow-10.1.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d921bc90b1defa55c9917ca6b6b71430e4286fc9e44c55ead78ca1a9f9eba5f2"},
+ {file = "Pillow-10.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:cfe96560c6ce2f4c07d6647af2d0f3c54cc33289894ebd88cfbb3bcd5391e256"},
+ {file = "Pillow-10.1.0-pp310-pypy310_pp73-macosx_10_10_x86_64.whl", hash = "sha256:937bdc5a7f5343d1c97dc98149a0be7eb9704e937fe3dc7140e229ae4fc572a7"},
+ {file = "Pillow-10.1.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b1c25762197144e211efb5f4e8ad656f36c8d214d390585d1d21281f46d556ba"},
+ {file = "Pillow-10.1.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:afc8eef765d948543a4775f00b7b8c079b3321d6b675dde0d02afa2ee23000b4"},
+ {file = "Pillow-10.1.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:883f216eac8712b83a63f41b76ddfb7b2afab1b74abbb413c5df6680f071a6b9"},
+ {file = "Pillow-10.1.0-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:b920e4d028f6442bea9a75b7491c063f0b9a3972520731ed26c83e254302eb1e"},
+ {file = "Pillow-10.1.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1c41d960babf951e01a49c9746f92c5a7e0d939d1652d7ba30f6b3090f27e412"},
+ {file = "Pillow-10.1.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:1fafabe50a6977ac70dfe829b2d5735fd54e190ab55259ec8aea4aaea412fa0b"},
+ {file = "Pillow-10.1.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:3b834f4b16173e5b92ab6566f0473bfb09f939ba14b23b8da1f54fa63e4b623f"},
+ {file = "Pillow-10.1.0.tar.gz", hash = "sha256:e6bf8de6c36ed96c86ea3b6e1d5273c53f46ef518a062464cd7ef5dd2cf92e38"},
+]
+
+[package.extras]
+docs = ["furo", "olefile", "sphinx (>=2.4)", "sphinx-copybutton", "sphinx-inline-tabs", "sphinx-removed-in", "sphinxext-opengraph"]
+tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout"]
+
+[[package]]
+name = "prometheus-client"
+version = "0.19.0"
+description = "Python client for the Prometheus monitoring system."
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "prometheus_client-0.19.0-py3-none-any.whl", hash = "sha256:c88b1e6ecf6b41cd8fb5731c7ae919bf66df6ec6fafa555cd6c0e16ca169ae92"},
+ {file = "prometheus_client-0.19.0.tar.gz", hash = "sha256:4585b0d1223148c27a225b10dbec5ae9bc4c81a99a3fa80774fa6209935324e1"},
+]
+
+[package.extras]
+twisted = ["twisted"]
+
+[[package]]
+name = "prompt-toolkit"
+version = "3.0.41"
+description = "Library for building powerful interactive command lines in Python"
+optional = false
+python-versions = ">=3.7.0"
+files = [
+ {file = "prompt_toolkit-3.0.41-py3-none-any.whl", hash = "sha256:f36fe301fafb7470e86aaf90f036eef600a3210be4decf461a5b1ca8403d3cb2"},
+ {file = "prompt_toolkit-3.0.41.tar.gz", hash = "sha256:941367d97fc815548822aa26c2a269fdc4eb21e9ec05fc5d447cf09bad5d75f0"},
+]
+
+[package.dependencies]
+wcwidth = "*"
+
+[[package]]
+name = "psycopg2-binary"
+version = "2.9.9"
+description = "psycopg2 - Python-PostgreSQL Database Adapter"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "psycopg2-binary-2.9.9.tar.gz", hash = "sha256:7f01846810177d829c7692f1f5ada8096762d9172af1b1a28d4ab5b77c923c1c"},
+ {file = "psycopg2_binary-2.9.9-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c2470da5418b76232f02a2fcd2229537bb2d5a7096674ce61859c3229f2eb202"},
+ {file = "psycopg2_binary-2.9.9-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c6af2a6d4b7ee9615cbb162b0738f6e1fd1f5c3eda7e5da17861eacf4c717ea7"},
+ {file = "psycopg2_binary-2.9.9-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:75723c3c0fbbf34350b46a3199eb50638ab22a0228f93fb472ef4d9becc2382b"},
+ {file = "psycopg2_binary-2.9.9-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:83791a65b51ad6ee6cf0845634859d69a038ea9b03d7b26e703f94c7e93dbcf9"},
+ {file = "psycopg2_binary-2.9.9-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0ef4854e82c09e84cc63084a9e4ccd6d9b154f1dbdd283efb92ecd0b5e2b8c84"},
+ {file = "psycopg2_binary-2.9.9-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ed1184ab8f113e8d660ce49a56390ca181f2981066acc27cf637d5c1e10ce46e"},
+ {file = "psycopg2_binary-2.9.9-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d2997c458c690ec2bc6b0b7ecbafd02b029b7b4283078d3b32a852a7ce3ddd98"},
+ {file = "psycopg2_binary-2.9.9-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:b58b4710c7f4161b5e9dcbe73bb7c62d65670a87df7bcce9e1faaad43e715245"},
+ {file = "psycopg2_binary-2.9.9-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:0c009475ee389757e6e34611d75f6e4f05f0cf5ebb76c6037508318e1a1e0d7e"},
+ {file = "psycopg2_binary-2.9.9-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8dbf6d1bc73f1d04ec1734bae3b4fb0ee3cb2a493d35ede9badbeb901fb40f6f"},
+ {file = "psycopg2_binary-2.9.9-cp310-cp310-win32.whl", hash = "sha256:3f78fd71c4f43a13d342be74ebbc0666fe1f555b8837eb113cb7416856c79682"},
+ {file = "psycopg2_binary-2.9.9-cp310-cp310-win_amd64.whl", hash = "sha256:876801744b0dee379e4e3c38b76fc89f88834bb15bf92ee07d94acd06ec890a0"},
+ {file = "psycopg2_binary-2.9.9-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ee825e70b1a209475622f7f7b776785bd68f34af6e7a46e2e42f27b659b5bc26"},
+ {file = "psycopg2_binary-2.9.9-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1ea665f8ce695bcc37a90ee52de7a7980be5161375d42a0b6c6abedbf0d81f0f"},
+ {file = "psycopg2_binary-2.9.9-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:143072318f793f53819048fdfe30c321890af0c3ec7cb1dfc9cc87aa88241de2"},
+ {file = "psycopg2_binary-2.9.9-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c332c8d69fb64979ebf76613c66b985414927a40f8defa16cf1bc028b7b0a7b0"},
+ {file = "psycopg2_binary-2.9.9-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f7fc5a5acafb7d6ccca13bfa8c90f8c51f13d8fb87d95656d3950f0158d3ce53"},
+ {file = "psycopg2_binary-2.9.9-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:977646e05232579d2e7b9c59e21dbe5261f403a88417f6a6512e70d3f8a046be"},
+ {file = "psycopg2_binary-2.9.9-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:b6356793b84728d9d50ead16ab43c187673831e9d4019013f1402c41b1db9b27"},
+ {file = "psycopg2_binary-2.9.9-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:bc7bb56d04601d443f24094e9e31ae6deec9ccb23581f75343feebaf30423359"},
+ {file = "psycopg2_binary-2.9.9-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:77853062a2c45be16fd6b8d6de2a99278ee1d985a7bd8b103e97e41c034006d2"},
+ {file = "psycopg2_binary-2.9.9-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:78151aa3ec21dccd5cdef6c74c3e73386dcdfaf19bced944169697d7ac7482fc"},
+ {file = "psycopg2_binary-2.9.9-cp311-cp311-win32.whl", hash = "sha256:dc4926288b2a3e9fd7b50dc6a1909a13bbdadfc67d93f3374d984e56f885579d"},
+ {file = "psycopg2_binary-2.9.9-cp311-cp311-win_amd64.whl", hash = "sha256:b76bedd166805480ab069612119ea636f5ab8f8771e640ae103e05a4aae3e417"},
+ {file = "psycopg2_binary-2.9.9-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:8532fd6e6e2dc57bcb3bc90b079c60de896d2128c5d9d6f24a63875a95a088cf"},
+ {file = "psycopg2_binary-2.9.9-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b0605eaed3eb239e87df0d5e3c6489daae3f7388d455d0c0b4df899519c6a38d"},
+ {file = "psycopg2_binary-2.9.9-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f8544b092a29a6ddd72f3556a9fcf249ec412e10ad28be6a0c0d948924f2212"},
+ {file = "psycopg2_binary-2.9.9-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2d423c8d8a3c82d08fe8af900ad5b613ce3632a1249fd6a223941d0735fce493"},
+ {file = "psycopg2_binary-2.9.9-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2e5afae772c00980525f6d6ecf7cbca55676296b580c0e6abb407f15f3706996"},
+ {file = "psycopg2_binary-2.9.9-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e6f98446430fdf41bd36d4faa6cb409f5140c1c2cf58ce0bbdaf16af7d3f119"},
+ {file = "psycopg2_binary-2.9.9-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:c77e3d1862452565875eb31bdb45ac62502feabbd53429fdc39a1cc341d681ba"},
+ {file = "psycopg2_binary-2.9.9-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:cb16c65dcb648d0a43a2521f2f0a2300f40639f6f8c1ecbc662141e4e3e1ee07"},
+ {file = "psycopg2_binary-2.9.9-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:911dda9c487075abd54e644ccdf5e5c16773470a6a5d3826fda76699410066fb"},
+ {file = "psycopg2_binary-2.9.9-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:57fede879f08d23c85140a360c6a77709113efd1c993923c59fde17aa27599fe"},
+ {file = "psycopg2_binary-2.9.9-cp312-cp312-win32.whl", hash = "sha256:64cf30263844fa208851ebb13b0732ce674d8ec6a0c86a4e160495d299ba3c93"},
+ {file = "psycopg2_binary-2.9.9-cp312-cp312-win_amd64.whl", hash = "sha256:81ff62668af011f9a48787564ab7eded4e9fb17a4a6a74af5ffa6a457400d2ab"},
+ {file = "psycopg2_binary-2.9.9-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:2293b001e319ab0d869d660a704942c9e2cce19745262a8aba2115ef41a0a42a"},
+ {file = "psycopg2_binary-2.9.9-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:03ef7df18daf2c4c07e2695e8cfd5ee7f748a1d54d802330985a78d2a5a6dca9"},
+ {file = "psycopg2_binary-2.9.9-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a602ea5aff39bb9fac6308e9c9d82b9a35c2bf288e184a816002c9fae930b77"},
+ {file = "psycopg2_binary-2.9.9-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8359bf4791968c5a78c56103702000105501adb557f3cf772b2c207284273984"},
+ {file = "psycopg2_binary-2.9.9-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:275ff571376626195ab95a746e6a04c7df8ea34638b99fc11160de91f2fef503"},
+ {file = "psycopg2_binary-2.9.9-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:f9b5571d33660d5009a8b3c25dc1db560206e2d2f89d3df1cb32d72c0d117d52"},
+ {file = "psycopg2_binary-2.9.9-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:420f9bbf47a02616e8554e825208cb947969451978dceb77f95ad09c37791dae"},
+ {file = "psycopg2_binary-2.9.9-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:4154ad09dac630a0f13f37b583eae260c6aa885d67dfbccb5b02c33f31a6d420"},
+ {file = "psycopg2_binary-2.9.9-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:a148c5d507bb9b4f2030a2025c545fccb0e1ef317393eaba42e7eabd28eb6041"},
+ {file = "psycopg2_binary-2.9.9-cp37-cp37m-win32.whl", hash = "sha256:68fc1f1ba168724771e38bee37d940d2865cb0f562380a1fb1ffb428b75cb692"},
+ {file = "psycopg2_binary-2.9.9-cp37-cp37m-win_amd64.whl", hash = "sha256:281309265596e388ef483250db3640e5f414168c5a67e9c665cafce9492eda2f"},
+ {file = "psycopg2_binary-2.9.9-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:60989127da422b74a04345096c10d416c2b41bd7bf2a380eb541059e4e999980"},
+ {file = "psycopg2_binary-2.9.9-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:246b123cc54bb5361588acc54218c8c9fb73068bf227a4a531d8ed56fa3ca7d6"},
+ {file = "psycopg2_binary-2.9.9-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:34eccd14566f8fe14b2b95bb13b11572f7c7d5c36da61caf414d23b91fcc5d94"},
+ {file = "psycopg2_binary-2.9.9-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:18d0ef97766055fec15b5de2c06dd8e7654705ce3e5e5eed3b6651a1d2a9a152"},
+ {file = "psycopg2_binary-2.9.9-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d3f82c171b4ccd83bbaf35aa05e44e690113bd4f3b7b6cc54d2219b132f3ae55"},
+ {file = "psycopg2_binary-2.9.9-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ead20f7913a9c1e894aebe47cccf9dc834e1618b7aa96155d2091a626e59c972"},
+ {file = "psycopg2_binary-2.9.9-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:ca49a8119c6cbd77375ae303b0cfd8c11f011abbbd64601167ecca18a87e7cdd"},
+ {file = "psycopg2_binary-2.9.9-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:323ba25b92454adb36fa425dc5cf6f8f19f78948cbad2e7bc6cdf7b0d7982e59"},
+ {file = "psycopg2_binary-2.9.9-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:1236ed0952fbd919c100bc839eaa4a39ebc397ed1c08a97fc45fee2a595aa1b3"},
+ {file = "psycopg2_binary-2.9.9-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:729177eaf0aefca0994ce4cffe96ad3c75e377c7b6f4efa59ebf003b6d398716"},
+ {file = "psycopg2_binary-2.9.9-cp38-cp38-win32.whl", hash = "sha256:804d99b24ad523a1fe18cc707bf741670332f7c7412e9d49cb5eab67e886b9b5"},
+ {file = "psycopg2_binary-2.9.9-cp38-cp38-win_amd64.whl", hash = "sha256:a6cdcc3ede532f4a4b96000b6362099591ab4a3e913d70bcbac2b56c872446f7"},
+ {file = "psycopg2_binary-2.9.9-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:72dffbd8b4194858d0941062a9766f8297e8868e1dd07a7b36212aaa90f49472"},
+ {file = "psycopg2_binary-2.9.9-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:30dcc86377618a4c8f3b72418df92e77be4254d8f89f14b8e8f57d6d43603c0f"},
+ {file = "psycopg2_binary-2.9.9-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:31a34c508c003a4347d389a9e6fcc2307cc2150eb516462a7a17512130de109e"},
+ {file = "psycopg2_binary-2.9.9-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:15208be1c50b99203fe88d15695f22a5bed95ab3f84354c494bcb1d08557df67"},
+ {file = "psycopg2_binary-2.9.9-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1873aade94b74715be2246321c8650cabf5a0d098a95bab81145ffffa4c13876"},
+ {file = "psycopg2_binary-2.9.9-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a58c98a7e9c021f357348867f537017057c2ed7f77337fd914d0bedb35dace7"},
+ {file = "psycopg2_binary-2.9.9-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:4686818798f9194d03c9129a4d9a702d9e113a89cb03bffe08c6cf799e053291"},
+ {file = "psycopg2_binary-2.9.9-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:ebdc36bea43063116f0486869652cb2ed7032dbc59fbcb4445c4862b5c1ecf7f"},
+ {file = "psycopg2_binary-2.9.9-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:ca08decd2697fdea0aea364b370b1249d47336aec935f87b8bbfd7da5b2ee9c1"},
+ {file = "psycopg2_binary-2.9.9-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ac05fb791acf5e1a3e39402641827780fe44d27e72567a000412c648a85ba860"},
+ {file = "psycopg2_binary-2.9.9-cp39-cp39-win32.whl", hash = "sha256:9dba73be7305b399924709b91682299794887cbbd88e38226ed9f6712eabee90"},
+ {file = "psycopg2_binary-2.9.9-cp39-cp39-win_amd64.whl", hash = "sha256:f7ae5d65ccfbebdfa761585228eb4d0df3a8b15cfb53bd953e713e09fbb12957"},
+]
+
+[[package]]
+name = "pycparser"
+version = "2.21"
+description = "C parser in Python"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
+files = [
+ {file = "pycparser-2.21-py2.py3-none-any.whl", hash = "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9"},
+ {file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"},
+]
+
+[[package]]
+name = "pycryptodome"
+version = "3.19.0"
+description = "Cryptographic library for Python"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
+files = [
+ {file = "pycryptodome-3.19.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:3006c44c4946583b6de24fe0632091c2653d6256b99a02a3db71ca06472ea1e4"},
+ {file = "pycryptodome-3.19.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:7c760c8a0479a4042111a8dd2f067d3ae4573da286c53f13cf6f5c53a5c1f631"},
+ {file = "pycryptodome-3.19.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:08ce3558af5106c632baf6d331d261f02367a6bc3733086ae43c0f988fe042db"},
+ {file = "pycryptodome-3.19.0-cp27-cp27m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45430dfaf1f421cf462c0dd824984378bef32b22669f2635cb809357dbaab405"},
+ {file = "pycryptodome-3.19.0-cp27-cp27m-musllinux_1_1_aarch64.whl", hash = "sha256:a9bcd5f3794879e91970f2bbd7d899780541d3ff439d8f2112441769c9f2ccea"},
+ {file = "pycryptodome-3.19.0-cp27-cp27m-win32.whl", hash = "sha256:190c53f51e988dceb60472baddce3f289fa52b0ec38fbe5fd20dd1d0f795c551"},
+ {file = "pycryptodome-3.19.0-cp27-cp27m-win_amd64.whl", hash = "sha256:22e0ae7c3a7f87dcdcf302db06ab76f20e83f09a6993c160b248d58274473bfa"},
+ {file = "pycryptodome-3.19.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:7822f36d683f9ad7bc2145b2c2045014afdbbd1d9922a6d4ce1cbd6add79a01e"},
+ {file = "pycryptodome-3.19.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:05e33267394aad6db6595c0ce9d427fe21552f5425e116a925455e099fdf759a"},
+ {file = "pycryptodome-3.19.0-cp27-cp27mu-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:829b813b8ee00d9c8aba417621b94bc0b5efd18c928923802ad5ba4cf1ec709c"},
+ {file = "pycryptodome-3.19.0-cp27-cp27mu-musllinux_1_1_aarch64.whl", hash = "sha256:fc7a79590e2b5d08530175823a242de6790abc73638cc6dc9d2684e7be2f5e49"},
+ {file = "pycryptodome-3.19.0-cp35-abi3-macosx_10_9_universal2.whl", hash = "sha256:542f99d5026ac5f0ef391ba0602f3d11beef8e65aae135fa5b762f5ebd9d3bfb"},
+ {file = "pycryptodome-3.19.0-cp35-abi3-macosx_10_9_x86_64.whl", hash = "sha256:61bb3ccbf4bf32ad9af32da8badc24e888ae5231c617947e0f5401077f8b091f"},
+ {file = "pycryptodome-3.19.0-cp35-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d49a6c715d8cceffedabb6adb7e0cbf41ae1a2ff4adaeec9432074a80627dea1"},
+ {file = "pycryptodome-3.19.0-cp35-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e249a784cc98a29c77cea9df54284a44b40cafbfae57636dd2f8775b48af2434"},
+ {file = "pycryptodome-3.19.0-cp35-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d033947e7fd3e2ba9a031cb2d267251620964705a013c5a461fa5233cc025270"},
+ {file = "pycryptodome-3.19.0-cp35-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:84c3e4fffad0c4988aef0d5591be3cad4e10aa7db264c65fadbc633318d20bde"},
+ {file = "pycryptodome-3.19.0-cp35-abi3-musllinux_1_1_i686.whl", hash = "sha256:139ae2c6161b9dd5d829c9645d781509a810ef50ea8b657e2257c25ca20efe33"},
+ {file = "pycryptodome-3.19.0-cp35-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:5b1986c761258a5b4332a7f94a83f631c1ffca8747d75ab8395bf2e1b93283d9"},
+ {file = "pycryptodome-3.19.0-cp35-abi3-win32.whl", hash = "sha256:536f676963662603f1f2e6ab01080c54d8cd20f34ec333dcb195306fa7826997"},
+ {file = "pycryptodome-3.19.0-cp35-abi3-win_amd64.whl", hash = "sha256:04dd31d3b33a6b22ac4d432b3274588917dcf850cc0c51c84eca1d8ed6933810"},
+ {file = "pycryptodome-3.19.0-pp27-pypy_73-manylinux2010_x86_64.whl", hash = "sha256:8999316e57abcbd8085c91bc0ef75292c8618f41ca6d2b6132250a863a77d1e7"},
+ {file = "pycryptodome-3.19.0-pp27-pypy_73-win32.whl", hash = "sha256:a0ab84755f4539db086db9ba9e9f3868d2e3610a3948cbd2a55e332ad83b01b0"},
+ {file = "pycryptodome-3.19.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:0101f647d11a1aae5a8ce4f5fad6644ae1b22bb65d05accc7d322943c69a74a6"},
+ {file = "pycryptodome-3.19.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8c1601e04d32087591d78e0b81e1e520e57a92796089864b20e5f18c9564b3fa"},
+ {file = "pycryptodome-3.19.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:506c686a1eee6c00df70010be3b8e9e78f406af4f21b23162bbb6e9bdf5427bc"},
+ {file = "pycryptodome-3.19.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:7919ccd096584b911f2a303c593280869ce1af9bf5d36214511f5e5a1bed8c34"},
+ {file = "pycryptodome-3.19.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:560591c0777f74a5da86718f70dfc8d781734cf559773b64072bbdda44b3fc3e"},
+ {file = "pycryptodome-3.19.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c1cc2f2ae451a676def1a73c1ae9120cd31af25db3f381893d45f75e77be2400"},
+ {file = "pycryptodome-3.19.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:17940dcf274fcae4a54ec6117a9ecfe52907ed5e2e438fe712fe7ca502672ed5"},
+ {file = "pycryptodome-3.19.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:d04f5f623a280fbd0ab1c1d8ecbd753193ab7154f09b6161b0f857a1a676c15f"},
+ {file = "pycryptodome-3.19.0.tar.gz", hash = "sha256:bc35d463222cdb4dbebd35e0784155c81e161b9284e567e7e933d722e533331e"},
+]
+
+[[package]]
+name = "pygls"
+version = "1.2.1"
+description = "A pythonic generic language server (pronounced like 'pie glass')"
+optional = false
+python-versions = ">=3.7.9,<4"
+files = [
+ {file = "pygls-1.2.1-py3-none-any.whl", hash = "sha256:7dcfcf12b6f15beb606afa46de2ed348b65a279c340ef2242a9a35c22eeafe94"},
+ {file = "pygls-1.2.1.tar.gz", hash = "sha256:04f9b9c115b622dcc346fb390289066565343d60245a424eca77cb429b911ed8"},
+]
+
+[package.dependencies]
+lsprotocol = "2023.0.0"
+
+[package.extras]
+ws = ["websockets (>=11.0.3,<12.0.0)"]
+
+[[package]]
+name = "pypng"
+version = "0.20220715.0"
+description = "Pure Python library for saving and loading PNG images"
+optional = false
+python-versions = "*"
+files = [
+ {file = "pypng-0.20220715.0-py3-none-any.whl", hash = "sha256:4a43e969b8f5aaafb2a415536c1a8ec7e341cd6a3f957fd5b5f32a4cfeed902c"},
+ {file = "pypng-0.20220715.0.tar.gz", hash = "sha256:739c433ba96f078315de54c0db975aee537cbc3e1d0ae4ed9aab0ca1e427e2c1"},
+]
+
+[[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"
+
+[[package]]
+name = "pytz"
+version = "2023.3.post1"
+description = "World timezone definitions, modern and historical"
+optional = false
+python-versions = "*"
+files = [
+ {file = "pytz-2023.3.post1-py2.py3-none-any.whl", hash = "sha256:ce42d816b81b68506614c11e8937d3aa9e41007ceb50bfdcb0749b921bf646c7"},
+ {file = "pytz-2023.3.post1.tar.gz", hash = "sha256:7b4fddbeb94a1eba4b557da24f19fdf9db575192544270a9101d8509f9f43d7b"},
+]
+
+[[package]]
+name = "pyyaml"
+version = "6.0.1"
+description = "YAML parser and emitter for Python"
+optional = false
+python-versions = ">=3.6"
+files = [
+ {file = "PyYAML-6.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a"},
+ {file = "PyYAML-6.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f"},
+ {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"},
+ {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"},
+ {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"},
+ {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"},
+ {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"},
+ {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"},
+ {file = "PyYAML-6.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab"},
+ {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"},
+ {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"},
+ {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"},
+ {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"},
+ {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"},
+ {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"},
+ {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"},
+ {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"},
+ {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd"},
+ {file = "PyYAML-6.0.1-cp36-cp36m-win32.whl", hash = "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585"},
+ {file = "PyYAML-6.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa"},
+ {file = "PyYAML-6.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3"},
+ {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27"},
+ {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3"},
+ {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c"},
+ {file = "PyYAML-6.0.1-cp37-cp37m-win32.whl", hash = "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba"},
+ {file = "PyYAML-6.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867"},
+ {file = "PyYAML-6.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595"},
+ {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"},
+ {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"},
+ {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"},
+ {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"},
+ {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"},
+ {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"},
+ {file = "PyYAML-6.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859"},
+ {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"},
+ {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"},
+ {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"},
+ {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"},
+ {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"},
+ {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"},
+]
+
+[[package]]
+name = "qrcode"
+version = "7.4.2"
+description = "QR Code image generator"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "qrcode-7.4.2-py3-none-any.whl", hash = "sha256:581dca7a029bcb2deef5d01068e39093e80ef00b4a61098a2182eac59d01643a"},
+ {file = "qrcode-7.4.2.tar.gz", hash = "sha256:9dd969454827e127dbd93696b20747239e6d540e082937c90f14ac95b30f5845"},
+]
+
+[package.dependencies]
+colorama = {version = "*", markers = "platform_system == \"Windows\""}
+pypng = "*"
+typing-extensions = "*"
+
+[package.extras]
+all = ["pillow (>=9.1.0)", "pytest", "pytest-cov", "tox", "zest.releaser[recommended]"]
+dev = ["pytest", "pytest-cov", "tox"]
+maintainer = ["zest.releaser[recommended]"]
+pil = ["pillow (>=9.1.0)"]
+test = ["coverage", "pytest"]
+
+[[package]]
+name = "redis"
+version = "5.0.1"
+description = "Python client for Redis database and key-value store"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "redis-5.0.1-py3-none-any.whl", hash = "sha256:ed4802971884ae19d640775ba3b03aa2e7bd5e8fb8dfaed2decce4d0fc48391f"},
+ {file = "redis-5.0.1.tar.gz", hash = "sha256:0dab495cd5753069d3bc650a0dde8a8f9edde16fc5691b689a566eda58100d0f"},
+]
+
+[package.dependencies]
+async-timeout = {version = ">=4.0.2", markers = "python_full_version <= \"3.11.2\""}
+
+[package.extras]
+hiredis = ["hiredis (>=1.0.0)"]
+ocsp = ["cryptography (>=36.0.1)", "pyopenssl (==20.0.1)", "requests (>=2.26.0)"]
+
+[[package]]
+name = "requests"
+version = "2.31.0"
+description = "Python HTTP for Humans."
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "requests-2.31.0-py3-none-any.whl", hash = "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f"},
+ {file = "requests-2.31.0.tar.gz", hash = "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"},
+]
+
+[package.dependencies]
+certifi = ">=2017.4.17"
+charset-normalizer = ">=2,<4"
+idna = ">=2.5,<4"
+urllib3 = ">=1.21.1,<3"
+
+[package.extras]
+socks = ["PySocks (>=1.5.6,!=1.5.7)"]
+use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"]
+
+[[package]]
+name = "ruff"
+version = "0.1.7"
+description = "An extremely fast Python linter and code formatter, written in Rust."
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "ruff-0.1.7-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:7f80496854fdc65b6659c271d2c26e90d4d401e6a4a31908e7e334fab4645aac"},
+ {file = "ruff-0.1.7-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:1ea109bdb23c2a4413f397ebd8ac32cb498bee234d4191ae1a310af760e5d287"},
+ {file = "ruff-0.1.7-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b0c2de9dd9daf5e07624c24add25c3a490dbf74b0e9bca4145c632457b3b42a"},
+ {file = "ruff-0.1.7-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:69a4bed13bc1d5dabf3902522b5a2aadfebe28226c6269694283c3b0cecb45fd"},
+ {file = "ruff-0.1.7-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:de02ca331f2143195a712983a57137c5ec0f10acc4aa81f7c1f86519e52b92a1"},
+ {file = "ruff-0.1.7-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:45b38c3f8788a65e6a2cab02e0f7adfa88872696839d9882c13b7e2f35d64c5f"},
+ {file = "ruff-0.1.7-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6c64cb67b2025b1ac6d58e5ffca8f7b3f7fd921f35e78198411237e4f0db8e73"},
+ {file = "ruff-0.1.7-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9dcc6bb2f4df59cb5b4b40ff14be7d57012179d69c6565c1da0d1f013d29951b"},
+ {file = "ruff-0.1.7-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:df2bb4bb6bbe921f6b4f5b6fdd8d8468c940731cb9406f274ae8c5ed7a78c478"},
+ {file = "ruff-0.1.7-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:276a89bcb149b3d8c1b11d91aa81898fe698900ed553a08129b38d9d6570e717"},
+ {file = "ruff-0.1.7-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:90c958fe950735041f1c80d21b42184f1072cc3975d05e736e8d66fc377119ea"},
+ {file = "ruff-0.1.7-py3-none-musllinux_1_2_i686.whl", hash = "sha256:6b05e3b123f93bb4146a761b7a7d57af8cb7384ccb2502d29d736eaade0db519"},
+ {file = "ruff-0.1.7-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:290ecab680dce94affebefe0bbca2322a6277e83d4f29234627e0f8f6b4fa9ce"},
+ {file = "ruff-0.1.7-py3-none-win32.whl", hash = "sha256:416dfd0bd45d1a2baa3b1b07b1b9758e7d993c256d3e51dc6e03a5e7901c7d80"},
+ {file = "ruff-0.1.7-py3-none-win_amd64.whl", hash = "sha256:4af95fd1d3b001fc41325064336db36e3d27d2004cdb6d21fd617d45a172dd96"},
+ {file = "ruff-0.1.7-py3-none-win_arm64.whl", hash = "sha256:0683b7bfbb95e6df3c7c04fe9d78f631f8e8ba4868dfc932d43d690698057e2e"},
+ {file = "ruff-0.1.7.tar.gz", hash = "sha256:dffd699d07abf54833e5f6cc50b85a6ff043715da8788c4a79bcd4ab4734d306"},
+]
+
+[[package]]
+name = "ruff-lsp"
+version = "0.0.45"
+description = "A Language Server Protocol implementation for Ruff."
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "ruff_lsp-0.0.45-py3-none-any.whl", hash = "sha256:6be86369fc2ed7a363d9377301beeb60130477d89d09339a2401717e158e9936"},
+ {file = "ruff_lsp-0.0.45.tar.gz", hash = "sha256:11c2d4979eabf81327b714f9395b91be1f3620a8861009ae4967f67e7de2671d"},
+]
+
+[package.dependencies]
+lsprotocol = ">=2023.0.0a1"
+packaging = ">=23.1"
+pygls = ">=1.1.0"
+ruff = ">=0.0.274"
+typing-extensions = "*"
+
+[package.extras]
+dev = ["mypy (==1.4.1)", "pip-tools (>=6.13.0,<7.0.0)", "pytest (>=7.3.1,<8.0.0)", "pytest-asyncio (==0.21.1)", "python-lsp-jsonrpc (==1.0.0)"]
+
+[[package]]
+name = "sentry-sdk"
+version = "1.38.0"
+description = "Python client for Sentry (https://sentry.io)"
+optional = false
+python-versions = "*"
+files = [
+ {file = "sentry-sdk-1.38.0.tar.gz", hash = "sha256:8feab81de6bbf64f53279b085bd3820e3e737403b0a0d9317f73a2c3374ae359"},
+ {file = "sentry_sdk-1.38.0-py2.py3-none-any.whl", hash = "sha256:0017fa73b8ae2d4e57fd2522ee3df30453715b29d2692142793ec5d5f90b94a6"},
+]
+
+[package.dependencies]
+certifi = "*"
+urllib3 = {version = ">=1.26.11", markers = "python_version >= \"3.6\""}
+
+[package.extras]
+aiohttp = ["aiohttp (>=3.5)"]
+arq = ["arq (>=0.23)"]
+asyncpg = ["asyncpg (>=0.23)"]
+beam = ["apache-beam (>=2.12)"]
+bottle = ["bottle (>=0.12.13)"]
+celery = ["celery (>=3)"]
+chalice = ["chalice (>=1.16.0)"]
+clickhouse-driver = ["clickhouse-driver (>=0.2.0)"]
+django = ["django (>=1.8)"]
+falcon = ["falcon (>=1.4)"]
+fastapi = ["fastapi (>=0.79.0)"]
+flask = ["blinker (>=1.1)", "flask (>=0.11)", "markupsafe"]
+grpcio = ["grpcio (>=1.21.1)"]
+httpx = ["httpx (>=0.16.0)"]
+huey = ["huey (>=2)"]
+loguru = ["loguru (>=0.5)"]
+opentelemetry = ["opentelemetry-distro (>=0.35b0)"]
+opentelemetry-experimental = ["opentelemetry-distro (>=0.40b0,<1.0)", "opentelemetry-instrumentation-aiohttp-client (>=0.40b0,<1.0)", "opentelemetry-instrumentation-django (>=0.40b0,<1.0)", "opentelemetry-instrumentation-fastapi (>=0.40b0,<1.0)", "opentelemetry-instrumentation-flask (>=0.40b0,<1.0)", "opentelemetry-instrumentation-requests (>=0.40b0,<1.0)", "opentelemetry-instrumentation-sqlite3 (>=0.40b0,<1.0)", "opentelemetry-instrumentation-urllib (>=0.40b0,<1.0)"]
+pure-eval = ["asttokens", "executing", "pure-eval"]
+pymongo = ["pymongo (>=3.1)"]
+pyspark = ["pyspark (>=2.4.4)"]
+quart = ["blinker (>=1.1)", "quart (>=0.16.1)"]
+rq = ["rq (>=0.6)"]
+sanic = ["sanic (>=0.8)"]
+sqlalchemy = ["sqlalchemy (>=1.2)"]
+starlette = ["starlette (>=0.19.1)"]
+starlite = ["starlite (>=1.48)"]
+tornado = ["tornado (>=5)"]
+
+[[package]]
+name = "six"
+version = "1.16.0"
+description = "Python 2 and 3 compatibility utilities"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
+files = [
+ {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"},
+ {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"},
+]
+
+[[package]]
+name = "sqlparse"
+version = "0.4.4"
+description = "A non-validating SQL parser."
+optional = false
+python-versions = ">=3.5"
+files = [
+ {file = "sqlparse-0.4.4-py3-none-any.whl", hash = "sha256:5430a4fe2ac7d0f93e66f1efc6e1338a41884b7ddf2a350cedd20ccc4d9d28f3"},
+ {file = "sqlparse-0.4.4.tar.gz", hash = "sha256:d446183e84b8349fa3061f0fe7f06ca94ba65b426946ffebe6e3e8295332420c"},
+]
+
+[package.extras]
+dev = ["build", "flake8"]
+doc = ["sphinx"]
+test = ["pytest", "pytest-cov"]
+
+[[package]]
+name = "tablib"
+version = "3.5.0"
+description = "Format agnostic tabular data library (XLS, JSON, YAML, CSV, etc.)"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "tablib-3.5.0-py3-none-any.whl", hash = "sha256:9821caa9eca6062ff7299fa645e737aecff982e6b2b42046928a6413c8dabfd9"},
+ {file = "tablib-3.5.0.tar.gz", hash = "sha256:f6661dfc45e1d4f51fa8a6239f9c8349380859a5bfaa73280645f046d6c96e33"},
+]
+
+[package.dependencies]
+markuppy = {version = "*", optional = true, markers = "extra == \"html\""}
+odfpy = {version = "*", optional = true, markers = "extra == \"ods\""}
+openpyxl = {version = ">=2.6.0", optional = true, markers = "extra == \"xlsx\""}
+pyyaml = {version = "*", optional = true, markers = "extra == \"yaml\""}
+xlrd = {version = "*", optional = true, markers = "extra == \"xls\""}
+xlwt = {version = "*", optional = true, markers = "extra == \"xls\""}
+
+[package.extras]
+all = ["markuppy", "odfpy", "openpyxl (>=2.6.0)", "pandas", "pyyaml", "tabulate", "xlrd", "xlwt"]
+cli = ["tabulate"]
+html = ["markuppy"]
+ods = ["odfpy"]
+pandas = ["pandas"]
+xls = ["xlrd", "xlwt"]
+xlsx = ["openpyxl (>=2.6.0)"]
+yaml = ["pyyaml"]
+
+[[package]]
+name = "typing-extensions"
+version = "4.8.0"
+description = "Backported and Experimental Type Hints for Python 3.8+"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "typing_extensions-4.8.0-py3-none-any.whl", hash = "sha256:8f92fc8806f9a6b641eaa5318da32b44d401efaac0f6678c9bc448ba3605faa0"},
+ {file = "typing_extensions-4.8.0.tar.gz", hash = "sha256:df8e4339e9cb77357558cbdbceca33c303714cf861d1eef15e1070055ae8b7ef"},
+]
+
+[[package]]
+name = "tzdata"
+version = "2023.3"
+description = "Provider of IANA time zone data"
+optional = false
+python-versions = ">=2"
+files = [
+ {file = "tzdata-2023.3-py2.py3-none-any.whl", hash = "sha256:7e65763eef3120314099b6939b5546db7adce1e7d6f2e179e3df563c70511eda"},
+ {file = "tzdata-2023.3.tar.gz", hash = "sha256:11ef1e08e54acb0d4f95bdb1be05da659673de4acbd21bf9c69e94cc5e907a3a"},
+]
+
+[[package]]
+name = "urllib3"
+version = "2.0.7"
+description = "HTTP library with thread-safe connection pooling, file post, and more."
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "urllib3-2.0.7-py3-none-any.whl", hash = "sha256:fdb6d215c776278489906c2f8916e6e7d4f5a9b602ccbcfdf7f016fc8da0596e"},
+ {file = "urllib3-2.0.7.tar.gz", hash = "sha256:c97dfde1f7bd43a71c8d2a58e369e9b2bf692d1334ea9f9cae55add7d0dd0f84"},
+]
+
+[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 = "uvicorn"
+version = "0.24.0.post1"
+description = "The lightning-fast ASGI server."
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "uvicorn-0.24.0.post1-py3-none-any.whl", hash = "sha256:7c84fea70c619d4a710153482c0d230929af7bcf76c7bfa6de151f0a3a80121e"},
+ {file = "uvicorn-0.24.0.post1.tar.gz", hash = "sha256:09c8e5a79dc466bdf28dead50093957db184de356fcdc48697bad3bde4c2588e"},
+]
+
+[package.dependencies]
+click = ">=7.0"
+h11 = ">=0.8"
+typing-extensions = {version = ">=4.0", markers = "python_version < \"3.11\""}
+
+[package.extras]
+standard = ["colorama (>=0.4)", "httptools (>=0.5.0)", "python-dotenv (>=0.13)", "pyyaml (>=5.1)", "uvloop (>=0.14.0,!=0.15.0,!=0.15.1)", "watchfiles (>=0.13)", "websockets (>=10.4)"]
+
+[[package]]
+name = "vine"
+version = "5.1.0"
+description = "Python promises."
+optional = false
+python-versions = ">=3.6"
+files = [
+ {file = "vine-5.1.0-py3-none-any.whl", hash = "sha256:40fdf3c48b2cfe1c38a49e9ae2da6fda88e4794c810050a728bd7413811fb1dc"},
+ {file = "vine-5.1.0.tar.gz", hash = "sha256:8b62e981d35c41049211cf62a0a1242d8c1ee9bd15bb196ce38aefd6799e61e0"},
+]
+
+[[package]]
+name = "wcwidth"
+version = "0.2.12"
+description = "Measures the displayed width of unicode strings in a terminal"
+optional = false
+python-versions = "*"
+files = [
+ {file = "wcwidth-0.2.12-py2.py3-none-any.whl", hash = "sha256:f26ec43d96c8cbfed76a5075dac87680124fa84e0855195a6184da9c187f133c"},
+ {file = "wcwidth-0.2.12.tar.gz", hash = "sha256:f01c104efdf57971bcb756f054dd58ddec5204dd15fa31d6503ea57947d97c02"},
+]
+
+[[package]]
+name = "xlrd"
+version = "2.0.1"
+description = "Library for developers to extract data from Microsoft Excel (tm) .xls spreadsheet files"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*"
+files = [
+ {file = "xlrd-2.0.1-py2.py3-none-any.whl", hash = "sha256:6a33ee89877bd9abc1158129f6e94be74e2679636b8a205b43b85206c3f0bbdd"},
+ {file = "xlrd-2.0.1.tar.gz", hash = "sha256:f72f148f54442c6b056bf931dbc34f986fd0c3b0b6b5a58d013c9aef274d0c88"},
+]
+
+[package.extras]
+build = ["twine", "wheel"]
+docs = ["sphinx"]
+test = ["pytest", "pytest-cov"]
+
+[[package]]
+name = "xlwt"
+version = "1.3.0"
+description = "Library to create spreadsheet files compatible with MS Excel 97/2000/XP/2003 XLS files, on any platform, with Python 2.6, 2.7, 3.3+"
+optional = false
+python-versions = "*"
+files = [
+ {file = "xlwt-1.3.0-py2.py3-none-any.whl", hash = "sha256:a082260524678ba48a297d922cc385f58278b8aa68741596a87de01a9c628b2e"},
+ {file = "xlwt-1.3.0.tar.gz", hash = "sha256:c59912717a9b28f1a3c2a98fd60741014b06b043936dcecbc113eaaada156c88"},
+]
+
+[metadata]
+lock-version = "2.0"
+python-versions = "^3.10"
+content-hash = "05fa8b336882246b6693e65438939ca68b15eec4b1a30c3929b3e9e57961cac1"
diff --git a/poetry.toml b/poetry.toml
new file mode 100644
index 0000000..4f3a13d
--- /dev/null
+++ b/poetry.toml
@@ -0,0 +1,3 @@
+[virtualenvs]
+path = ".venv"
+in-project = true
From 119679147ff68e3896e73afd1c4e0d54a319a4d0 Mon Sep 17 00:00:00 2001
From: "Ozkar L. Garcell"
Date: Sun, 10 Dec 2023 22:18:31 +0100
Subject: [PATCH 10/32] feat: pyproject config
---
pyproject.toml | 45 +++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 45 insertions(+)
create mode 100644 pyproject.toml
diff --git a/pyproject.toml b/pyproject.toml
new file mode 100644
index 0000000..07ca803
--- /dev/null
+++ b/pyproject.toml
@@ -0,0 +1,45 @@
+[tool.poetry]
+name = "shadowmere"
+version = "1.0.0"
+description = "An automatically tested list of Shadowsocks proxies."
+authors = ["Your Name "]
+license = "GPLv3"
+readme = "README.md"
+
+[tool.poetry.dependencies]
+python = "^3.12"
+django = "^5.0"
+celery = "^5.3.6"
+django-minio-storage = "^0.5.7"
+django-prometheus = "^2.3.1"
+django-storages = "^1.14.2"
+djangorestframework = "^3.14.0"
+emoji-country-flag = "^1.3.2"
+psycopg2-binary = "^2.9.9"
+pillow = "^10.1.0"
+qrcode = "^7.4.2"
+requests = "^2.31.0"
+redis = "^5.0.1"
+sentry-sdk = "^1.38.0"
+django-admin-rangefilter = "^0.12.0"
+django-filter = "^23.5"
+django-import-export = "^3.3.3"
+botocore = "^1.33.11"
+django-environ = "^0.11.2"
+uvicorn = "^0.24.0.post1"
+gunicorn = "^21.2.0"
+django-jazzmin = "^2.6.0"
+
+[tool.poetry.group.dev.dependencies]
+ruff = "^0.1.7"
+ruff-lsp = "^0.0.45"
+
+[build-system]
+requires = ["poetry-core"]
+build-backend = "poetry.core.masonry.api"
+
+[tool.ruff]
+select = ["E", "F"]
+ignore = []
+line-length = 120
+target-version = "py312"
From 93372e08e8cf107d8f858a02cbfab02ce325701d Mon Sep 17 00:00:00 2001
From: "Ozkar L. Garcell"
Date: Sun, 10 Dec 2023 22:19:20 +0100
Subject: [PATCH 11/32] feat/fix: removed prints and code reformat
---
proxylist/tasks.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/proxylist/tasks.py b/proxylist/tasks.py
index 35ec8de..4e475dc 100644
--- a/proxylist/tasks.py
+++ b/proxylist/tasks.py
@@ -14,6 +14,7 @@
from proxylist.base64_decoder import decode_base64
from proxylist.models import Proxy, Subscription, get_sip002, TaskLog
from proxylist.proxy import update_proxy_status, get_proxy_location
+from shadowmere.celery import app
CONCURRENT_CHECKS = 200
SUBSCRIPTION_TIMEOUT_SECONDS = 60
From 9c65dd7af8f6579940a14af3186ae64003125cfa Mon Sep 17 00:00:00 2001
From: "Ozkar L. Garcell"
Date: Sun, 10 Dec 2023 22:19:32 +0100
Subject: [PATCH 12/32] feat: code reformat and correct settings import
---
proxylist/proxy.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/proxylist/proxy.py b/proxylist/proxy.py
index ec5f70d..3189a88 100644
--- a/proxylist/proxy.py
+++ b/proxylist/proxy.py
@@ -1,8 +1,8 @@
import requests
from django.utils.timezone import now
+from django.conf import settings
from requests.exceptions import InvalidJSONError
-from shadowmere import settings
def get_proxy_location(proxy_url):
From 4ba584e5741311e5987df991ceb51efdea49d55f Mon Sep 17 00:00:00 2001
From: "Ozkar L. Garcell"
Date: Sun, 10 Dec 2023 22:19:44 +0100
Subject: [PATCH 13/32] feat: code reformat
---
proxylist/models.py | 14 +++-----------
1 file changed, 3 insertions(+), 11 deletions(-)
diff --git a/proxylist/models.py b/proxylist/models.py
index ad4b2f3..0a31d2b 100644
--- a/proxylist/models.py
+++ b/proxylist/models.py
@@ -78,14 +78,8 @@ def get_sip002(instance_url):
url = url.replace("ss://", "")
decoded_url = decode_base64(url.encode("ascii"))
if decoded_url:
- encoded_bits = (
- base64.b64encode(decoded_url.split(b"@")[0])
- .decode("ascii")
- .rstrip("=")
- )
- url = (
- f'ss://{encoded_bits}@{decoded_url.split(b"@")[1].decode("ascii")}'
- )
+ encoded_bits = base64.b64encode(decoded_url.split(b"@")[0]).decode("ascii").rstrip("=")
+ url = f'ss://{encoded_bits}@{decoded_url.split(b"@")[1].decode("ascii")}'
else:
return ""
except IndexError:
@@ -128,9 +122,7 @@ class SubscriptionKind(models.TextChoices):
BASE64 = "BASE64", "base64"
url = models.URLField(null=False, unique=True)
- kind = models.CharField(
- choices=SubscriptionKind.choices, default=SubscriptionKind.PLAIN, max_length=10
- )
+ kind = models.CharField(choices=SubscriptionKind.choices, default=SubscriptionKind.PLAIN, max_length=10)
alive = models.BooleanField(default=True)
alive_timestamp = models.DateTimeField(default=now)
enabled = models.BooleanField(default=True)
From 228a6c18409b9cba12d45e12dc3942b76df807af Mon Sep 17 00:00:00 2001
From: "Ozkar L. Garcell"
Date: Sun, 10 Dec 2023 22:19:57 +0100
Subject: [PATCH 14/32] feat/wip: multistage build
---
Dockerfile | 81 +++++++++++++++++++++++++++++++++++++++++++++---------
1 file changed, 68 insertions(+), 13 deletions(-)
diff --git a/Dockerfile b/Dockerfile
index 98d21bf..88f6e45 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,18 +1,73 @@
-FROM python:3.12-slim
-WORKDIR /home/
+FROM python:3.12-slim as python-base
-ENV APP_HOME=/home/
-ENV APP_USER=shadowmere
+ENV DEBIAN_FRONTEND=noninteractive \
+ LANG=C.UTF-8 \
+ LC_ALL=C.UTF-8 \
+ PYTHONFAULTHANDLER=1 \
+ PYTHONUNBUFFERED=1 \
+ PYTHONHASHSEED=random \
+ PYTHONDONTWRITEBYTECODE=1 \
+ PIP_NO_CACHE_DIR=off \
+ PIP_DISABLE_PIP_VERSION_CHECK=on \
+ PIP_DEFAULT_TIMEOUT=100 \
+ POETRY_VERSION="1.7.1" \
+ POETRY_HOME="/opt/poetry" \
+ POETRY_VENV="/opt/poetry-venv" \
+ POETRY_NO_INTERACTION=1 \
+ POETRY_VIRTUALENVS_IN_PROJECT=1 \
+ POETRY_VIRTUALENVS_CREATE=1 \
+ POETRY_CACHE_DIR="/opt/.cache" \
+ PROJECT_PATH="/shadowmere" \
+ PROJECT_USER="shadowmere" \
+ VENV_PATH="/shadowmere/.venv"
-RUN groupadd -r $APP_USER && \
- useradd -r -g $APP_USER -d $APP_HOME -s /sbin/nologin -c "Docker image user" $APP_USER
-RUN pip install --upgrade pip
+ENV PATH="${POETRY_HOME}/bin:${VENV_PATH}/bin:${PATH}"
-COPY requirements.txt /home/
-RUN pip install -r requirements.txt
-COPY . /home/
+FROM python-base as poetry-base
-RUN chown -R $APP_USER:$APP_USER $APP_HOME
-USER $APP_USER
+RUN python -m venv $POETRY_VENV \
+ && $POETRY_VENV/bin/pip install --no-cache-dir -U pip setuptools wheel \
+ && $POETRY_VENV/bin/pip install poetry==${POETRY_VERSION}
-CMD ["gunicorn", "shadowmere.wsgi:application", "--bind", "0.0.0.0:8001", "-k", "gevent", "-w", "6", "--capture-output"]
+FROM python-base as example-app
+
+COPY --from=poetry-base ${POETRY_VENV} ${POETRY_VENV}
+
+ENV PYTHONPATH="${PYTHONPATH}:$VENV_PATH/lib/python3.12/site-packages"
+ENV PATH="${PATH}:${POETRY_VENV}/bin"
+
+RUN groupadd -r $PROJECT_USER && \
+ useradd -r -g $PROJECT_USER -d $PROJECT_PATH -s /sbin/nologin -c "Docker image user" $PROJECT_USER
+
+WORKDIR $PROJECT_PATH
+
+COPY poetry.lock pyproject.toml ./
+
+#RUN poetry check
+
+RUN poetry install --no-interaction --no-cache --without dev
+
+# upload scripts
+COPY ./docker/entrypoint /entrypoint
+RUN sed -i 's/\r//' /entrypoint
+RUN chmod +x /entrypoint
+
+COPY ./docker/wait_for_migration.sh /wait_for_migration.sh
+RUN sed -i 's/\r//' /wait_for_migration.sh
+RUN chmod +x /wait_for_migration.sh
+
+COPY ./docker/start /start
+RUN sed -i 's/\r//' /start
+RUN chmod +x /start
+
+COPY ./docker/celery/worker/start /start-celeryworker
+RUN sed -i 's/\r//' /start-celeryworker
+RUN chmod +x /start-celeryworker
+
+COPY ./docker/celery/beat/start /start-celerybeat
+RUN sed -i 's/\r//' /start-celerybeat
+RUN chmod +x /start-celerybeat
+
+COPY . $PROJECT_PATH
+
+USER $PROJECT_USER
From f8b4f62e2eba97435dbf69f223abeff5453db412 Mon Sep 17 00:00:00 2001
From: "Ozkar L. Garcell"
Date: Wed, 5 Jun 2024 19:27:17 +0200
Subject: [PATCH 15/32] wip: new project layout
---
.../shadowmere/apps}/__init__.py | 0
.../shadowmere/apps/proxylist}/__init__.py | 0
.../shadowmere/apps/proxylist}/admin.py | 6 +-
app/shadowmere/apps/proxylist/apps.py | 5 +
.../apps/proxylist}/base64_decoder.py | 0
.../apps/proxylist}/fixtures/proxies.json | 0
.../apps/proxylist/management}/__init__.py | 0
.../management/commands}/__init__.py | 0
.../management/commands/clear_stats.py | 0
.../management/commands/initadmin.py | 0
.../management/commands/poll_subscriptions.py | 0
.../management/commands/reduce_checks_by.py | 0
.../management/commands/remove_low_quality.py | 0
.../management/commands/update_status.py | 0
.../shadowmere/apps/proxylist}/metrics.py | 5 +-
.../proxylist}/migrations/0001_initial.py | 0
.../migrations/0002_proxy_last_active.py | 1 -
.../migrations/0003_alter_proxy_url.py | 5 +-
..._times_check_failed_proxy_times_checked.py | 1 -
.../0005_remove_proxy_times_check_failed.py | 1 -
.../0006_proxy_times_check_succeeded.py | 1 -
..._ip_address_proxy_location_country_code.py | 1 -
..._proxy_location_country_alter_proxy_url.py | 31 ++++
.../proxylist}/migrations/0009_proxy_port.py | 1 -
.../0010_subscription_alter_proxy_url.py | 26 +++
.../0011_alter_subscription_kind.py | 17 ++
...subscription_alive_subscription_enabled.py | 0
...3_subscription_alive_timestamp_and_more.py | 0
.../proxylist}/migrations/0014_tasklog.py | 0
.../0015_alter_tasklog_start_time.py | 0
...og_finish_time_alter_tasklog_start_time.py | 0
.../migrations/0017_tasklog_details.py | 0
.../apps/proxylist/migrations}/__init__.py | 0
.../shadowmere/apps/proxylist}/models.py | 7 +-
app/shadowmere/apps/proxylist/pagination.py | 14 ++
.../shadowmere/apps/proxylist}/permissions.py | 2 +-
.../shadowmere/apps/proxylist}/proxy.py | 2 +-
.../shadowmere/apps/proxylist}/serializers.py | 3 +-
.../shadowmere/apps/proxylist}/tasks.py | 10 +-
.../apps/proxylist/tests}/__init__.py | 0
.../proxylist}/tests/test_country_codes.py | 0
.../apps/proxylist}/tests/test_ports.py | 0
.../apps/proxylist}/tests/test_proxies.py | 0
.../apps/proxylist}/tests/test_qr.py | 0
.../proxylist}/tests/test_subscription.py | 0
.../apps/proxylist}/tests/test_tasks.py | 0
.../shadowmere/apps/proxylist}/views.py | 39 ++---
docker/entrypoint | 30 ----
Dockerfile => docker/prod/Dockerfile | 0
docker/start | 15 --
docker/wait_for_migration.sh | 16 --
locale/es/LC_MESSAGES/django.mo | Bin 2119 -> 0 bytes
locale/es/LC_MESSAGES/django.po | 87 ----------
manage.py | 23 ---
proxylist/apps.py | 6 -
..._proxy_location_country_alter_proxy_url.py | 24 ---
.../0010_subscription_alter_proxy_url.py | 27 ---
.../0011_alter_subscription_kind.py | 18 --
proxylist/pagination.py | 12 --
shadowmere/asgi.py | 16 --
shadowmere/settings/__init__.py | 0
shadowmere/settings/dev.py | 1 -
shadowmere/settings/prod.py | 47 ------
shadowmere/urls.py | 24 ---
shadowmere/wsgi.py | 16 --
templates/index.html | 158 ------------------
66 files changed, 121 insertions(+), 577 deletions(-)
rename {proxylist => app/shadowmere/apps}/__init__.py (100%)
rename {proxylist/management => app/shadowmere/apps/proxylist}/__init__.py (100%)
rename {proxylist => app/shadowmere/apps/proxylist}/admin.py (95%)
create mode 100644 app/shadowmere/apps/proxylist/apps.py
rename {proxylist => app/shadowmere/apps/proxylist}/base64_decoder.py (100%)
rename {proxylist => app/shadowmere/apps/proxylist}/fixtures/proxies.json (100%)
rename {proxylist/management/commands => app/shadowmere/apps/proxylist/management}/__init__.py (100%)
rename {proxylist/migrations => app/shadowmere/apps/proxylist/management/commands}/__init__.py (100%)
rename {proxylist => app/shadowmere/apps/proxylist}/management/commands/clear_stats.py (100%)
rename {proxylist => app/shadowmere/apps/proxylist}/management/commands/initadmin.py (100%)
rename {proxylist => app/shadowmere/apps/proxylist}/management/commands/poll_subscriptions.py (100%)
rename {proxylist => app/shadowmere/apps/proxylist}/management/commands/reduce_checks_by.py (100%)
rename {proxylist => app/shadowmere/apps/proxylist}/management/commands/remove_low_quality.py (100%)
rename {proxylist => app/shadowmere/apps/proxylist}/management/commands/update_status.py (100%)
rename {proxylist => app/shadowmere/apps/proxylist}/metrics.py (84%)
rename {proxylist => app/shadowmere/apps/proxylist}/migrations/0001_initial.py (100%)
rename {proxylist => app/shadowmere/apps/proxylist}/migrations/0002_proxy_last_active.py (99%)
rename {proxylist => app/shadowmere/apps/proxylist}/migrations/0003_alter_proxy_url.py (81%)
rename {proxylist => app/shadowmere/apps/proxylist}/migrations/0004_proxy_times_check_failed_proxy_times_checked.py (99%)
rename {proxylist => app/shadowmere/apps/proxylist}/migrations/0005_remove_proxy_times_check_failed.py (99%)
rename {proxylist => app/shadowmere/apps/proxylist}/migrations/0006_proxy_times_check_succeeded.py (99%)
rename {proxylist => app/shadowmere/apps/proxylist}/migrations/0007_proxy_ip_address_proxy_location_country_code.py (99%)
create mode 100644 app/shadowmere/apps/proxylist/migrations/0008_proxy_location_country_alter_proxy_url.py
rename {proxylist => app/shadowmere/apps/proxylist}/migrations/0009_proxy_port.py (99%)
create mode 100644 app/shadowmere/apps/proxylist/migrations/0010_subscription_alter_proxy_url.py
create mode 100644 app/shadowmere/apps/proxylist/migrations/0011_alter_subscription_kind.py
rename {proxylist => app/shadowmere/apps/proxylist}/migrations/0012_subscription_alive_subscription_enabled.py (100%)
rename {proxylist => app/shadowmere/apps/proxylist}/migrations/0013_subscription_alive_timestamp_and_more.py (100%)
rename {proxylist => app/shadowmere/apps/proxylist}/migrations/0014_tasklog.py (100%)
rename {proxylist => app/shadowmere/apps/proxylist}/migrations/0015_alter_tasklog_start_time.py (100%)
rename {proxylist => app/shadowmere/apps/proxylist}/migrations/0016_alter_tasklog_finish_time_alter_tasklog_start_time.py (100%)
rename {proxylist => app/shadowmere/apps/proxylist}/migrations/0017_tasklog_details.py (100%)
rename {proxylist/tests => app/shadowmere/apps/proxylist/migrations}/__init__.py (100%)
rename {proxylist => app/shadowmere/apps/proxylist}/models.py (96%)
create mode 100644 app/shadowmere/apps/proxylist/pagination.py
rename {proxylist => app/shadowmere/apps/proxylist}/permissions.py (81%)
rename {proxylist => app/shadowmere/apps/proxylist}/proxy.py (100%)
rename {proxylist => app/shadowmere/apps/proxylist}/serializers.py (95%)
rename {proxylist => app/shadowmere/apps/proxylist}/tasks.py (97%)
rename {shadowmere => app/shadowmere/apps/proxylist/tests}/__init__.py (100%)
rename {proxylist => app/shadowmere/apps/proxylist}/tests/test_country_codes.py (100%)
rename {proxylist => app/shadowmere/apps/proxylist}/tests/test_ports.py (100%)
rename {proxylist => app/shadowmere/apps/proxylist}/tests/test_proxies.py (100%)
rename {proxylist => app/shadowmere/apps/proxylist}/tests/test_qr.py (100%)
rename {proxylist => app/shadowmere/apps/proxylist}/tests/test_subscription.py (100%)
rename {proxylist => app/shadowmere/apps/proxylist}/tests/test_tasks.py (100%)
rename {proxylist => app/shadowmere/apps/proxylist}/views.py (86%)
delete mode 100755 docker/entrypoint
rename Dockerfile => docker/prod/Dockerfile (100%)
delete mode 100755 docker/start
delete mode 100755 docker/wait_for_migration.sh
delete mode 100644 locale/es/LC_MESSAGES/django.mo
delete mode 100644 locale/es/LC_MESSAGES/django.po
delete mode 100755 manage.py
delete mode 100644 proxylist/apps.py
delete mode 100644 proxylist/migrations/0008_proxy_location_country_alter_proxy_url.py
delete mode 100644 proxylist/migrations/0010_subscription_alter_proxy_url.py
delete mode 100644 proxylist/migrations/0011_alter_subscription_kind.py
delete mode 100644 proxylist/pagination.py
delete mode 100644 shadowmere/asgi.py
delete mode 100644 shadowmere/settings/__init__.py
delete mode 100644 shadowmere/settings/dev.py
delete mode 100644 shadowmere/settings/prod.py
delete mode 100644 shadowmere/urls.py
delete mode 100644 shadowmere/wsgi.py
delete mode 100644 templates/index.html
diff --git a/proxylist/__init__.py b/app/shadowmere/apps/__init__.py
similarity index 100%
rename from proxylist/__init__.py
rename to app/shadowmere/apps/__init__.py
diff --git a/proxylist/management/__init__.py b/app/shadowmere/apps/proxylist/__init__.py
similarity index 100%
rename from proxylist/management/__init__.py
rename to app/shadowmere/apps/proxylist/__init__.py
diff --git a/proxylist/admin.py b/app/shadowmere/apps/proxylist/admin.py
similarity index 95%
rename from proxylist/admin.py
rename to app/shadowmere/apps/proxylist/admin.py
index 130dbaf..2dce17a 100644
--- a/proxylist/admin.py
+++ b/app/shadowmere/apps/proxylist/admin.py
@@ -1,4 +1,6 @@
import humanfriendly
+from apps.proxylist.models import Proxy, Subscription, TaskLog
+from apps.proxylist.proxy import update_proxy_status
from django.contrib import admin
from django.contrib.auth.models import Group
from django.db import IntegrityError
@@ -6,9 +8,6 @@
from import_export.admin import ImportExportModelAdmin
from rangefilter.filters import DateRangeFilter
-from proxylist.models import Proxy, Subscription, TaskLog
-from proxylist.proxy import update_proxy_status
-
class ProxyResource(resources.ModelResource):
class Meta:
@@ -17,7 +16,6 @@ class Meta:
@admin.register(Proxy)
class ProxyAdmin(ImportExportModelAdmin):
-
@staticmethod
def update_status(modeladmin, request, queryset):
for proxy in queryset:
diff --git a/app/shadowmere/apps/proxylist/apps.py b/app/shadowmere/apps/proxylist/apps.py
new file mode 100644
index 0000000..1b01159
--- /dev/null
+++ b/app/shadowmere/apps/proxylist/apps.py
@@ -0,0 +1,5 @@
+from django.apps import AppConfig
+
+
+class ProxylistConfig(AppConfig):
+ name = "apps.proxylist"
diff --git a/proxylist/base64_decoder.py b/app/shadowmere/apps/proxylist/base64_decoder.py
similarity index 100%
rename from proxylist/base64_decoder.py
rename to app/shadowmere/apps/proxylist/base64_decoder.py
diff --git a/proxylist/fixtures/proxies.json b/app/shadowmere/apps/proxylist/fixtures/proxies.json
similarity index 100%
rename from proxylist/fixtures/proxies.json
rename to app/shadowmere/apps/proxylist/fixtures/proxies.json
diff --git a/proxylist/management/commands/__init__.py b/app/shadowmere/apps/proxylist/management/__init__.py
similarity index 100%
rename from proxylist/management/commands/__init__.py
rename to app/shadowmere/apps/proxylist/management/__init__.py
diff --git a/proxylist/migrations/__init__.py b/app/shadowmere/apps/proxylist/management/commands/__init__.py
similarity index 100%
rename from proxylist/migrations/__init__.py
rename to app/shadowmere/apps/proxylist/management/commands/__init__.py
diff --git a/proxylist/management/commands/clear_stats.py b/app/shadowmere/apps/proxylist/management/commands/clear_stats.py
similarity index 100%
rename from proxylist/management/commands/clear_stats.py
rename to app/shadowmere/apps/proxylist/management/commands/clear_stats.py
diff --git a/proxylist/management/commands/initadmin.py b/app/shadowmere/apps/proxylist/management/commands/initadmin.py
similarity index 100%
rename from proxylist/management/commands/initadmin.py
rename to app/shadowmere/apps/proxylist/management/commands/initadmin.py
diff --git a/proxylist/management/commands/poll_subscriptions.py b/app/shadowmere/apps/proxylist/management/commands/poll_subscriptions.py
similarity index 100%
rename from proxylist/management/commands/poll_subscriptions.py
rename to app/shadowmere/apps/proxylist/management/commands/poll_subscriptions.py
diff --git a/proxylist/management/commands/reduce_checks_by.py b/app/shadowmere/apps/proxylist/management/commands/reduce_checks_by.py
similarity index 100%
rename from proxylist/management/commands/reduce_checks_by.py
rename to app/shadowmere/apps/proxylist/management/commands/reduce_checks_by.py
diff --git a/proxylist/management/commands/remove_low_quality.py b/app/shadowmere/apps/proxylist/management/commands/remove_low_quality.py
similarity index 100%
rename from proxylist/management/commands/remove_low_quality.py
rename to app/shadowmere/apps/proxylist/management/commands/remove_low_quality.py
diff --git a/proxylist/management/commands/update_status.py b/app/shadowmere/apps/proxylist/management/commands/update_status.py
similarity index 100%
rename from proxylist/management/commands/update_status.py
rename to app/shadowmere/apps/proxylist/management/commands/update_status.py
diff --git a/proxylist/metrics.py b/app/shadowmere/apps/proxylist/metrics.py
similarity index 84%
rename from proxylist/metrics.py
rename to app/shadowmere/apps/proxylist/metrics.py
index b0c29a4..a70cc93 100644
--- a/proxylist/metrics.py
+++ b/app/shadowmere/apps/proxylist/metrics.py
@@ -1,8 +1,7 @@
-from prometheus_client.core import GaugeMetricFamily, REGISTRY
+from apps.proxylist.models import Proxy
+from prometheus_client.core import REGISTRY, GaugeMetricFamily
from prometheus_client.registry import Collector
-from proxylist.models import Proxy
-
class CustomCollector(Collector):
def collect(self):
diff --git a/proxylist/migrations/0001_initial.py b/app/shadowmere/apps/proxylist/migrations/0001_initial.py
similarity index 100%
rename from proxylist/migrations/0001_initial.py
rename to app/shadowmere/apps/proxylist/migrations/0001_initial.py
diff --git a/proxylist/migrations/0002_proxy_last_active.py b/app/shadowmere/apps/proxylist/migrations/0002_proxy_last_active.py
similarity index 99%
rename from proxylist/migrations/0002_proxy_last_active.py
rename to app/shadowmere/apps/proxylist/migrations/0002_proxy_last_active.py
index b616d70..d76ad71 100644
--- a/proxylist/migrations/0002_proxy_last_active.py
+++ b/app/shadowmere/apps/proxylist/migrations/0002_proxy_last_active.py
@@ -5,7 +5,6 @@
class Migration(migrations.Migration):
-
dependencies = [
("proxylist", "0001_initial"),
]
diff --git a/proxylist/migrations/0003_alter_proxy_url.py b/app/shadowmere/apps/proxylist/migrations/0003_alter_proxy_url.py
similarity index 81%
rename from proxylist/migrations/0003_alter_proxy_url.py
rename to app/shadowmere/apps/proxylist/migrations/0003_alter_proxy_url.py
index 20ae4c1..13bb053 100644
--- a/proxylist/migrations/0003_alter_proxy_url.py
+++ b/app/shadowmere/apps/proxylist/migrations/0003_alter_proxy_url.py
@@ -1,11 +1,10 @@
# Generated by Django 3.2.11 on 2022-02-09 14:26
from django.db import migrations, models
-import proxylist.models
+import apps.proxylist.models
class Migration(migrations.Migration):
-
dependencies = [
("proxylist", "0002_proxy_last_active"),
]
@@ -17,7 +16,7 @@ class Migration(migrations.Migration):
field=models.CharField(
max_length=1024,
unique=True,
- validators=[proxylist.models.validate_not_existing],
+ validators=[apps.proxylist.models.validate_not_existing],
),
),
]
diff --git a/proxylist/migrations/0004_proxy_times_check_failed_proxy_times_checked.py b/app/shadowmere/apps/proxylist/migrations/0004_proxy_times_check_failed_proxy_times_checked.py
similarity index 99%
rename from proxylist/migrations/0004_proxy_times_check_failed_proxy_times_checked.py
rename to app/shadowmere/apps/proxylist/migrations/0004_proxy_times_check_failed_proxy_times_checked.py
index 0fd80c0..e2e659d 100644
--- a/proxylist/migrations/0004_proxy_times_check_failed_proxy_times_checked.py
+++ b/app/shadowmere/apps/proxylist/migrations/0004_proxy_times_check_failed_proxy_times_checked.py
@@ -4,7 +4,6 @@
class Migration(migrations.Migration):
-
dependencies = [
("proxylist", "0003_alter_proxy_url"),
]
diff --git a/proxylist/migrations/0005_remove_proxy_times_check_failed.py b/app/shadowmere/apps/proxylist/migrations/0005_remove_proxy_times_check_failed.py
similarity index 99%
rename from proxylist/migrations/0005_remove_proxy_times_check_failed.py
rename to app/shadowmere/apps/proxylist/migrations/0005_remove_proxy_times_check_failed.py
index 8d5c645..57603b5 100644
--- a/proxylist/migrations/0005_remove_proxy_times_check_failed.py
+++ b/app/shadowmere/apps/proxylist/migrations/0005_remove_proxy_times_check_failed.py
@@ -4,7 +4,6 @@
class Migration(migrations.Migration):
-
dependencies = [
("proxylist", "0004_proxy_times_check_failed_proxy_times_checked"),
]
diff --git a/proxylist/migrations/0006_proxy_times_check_succeeded.py b/app/shadowmere/apps/proxylist/migrations/0006_proxy_times_check_succeeded.py
similarity index 99%
rename from proxylist/migrations/0006_proxy_times_check_succeeded.py
rename to app/shadowmere/apps/proxylist/migrations/0006_proxy_times_check_succeeded.py
index bbbc80e..e095a59 100644
--- a/proxylist/migrations/0006_proxy_times_check_succeeded.py
+++ b/app/shadowmere/apps/proxylist/migrations/0006_proxy_times_check_succeeded.py
@@ -4,7 +4,6 @@
class Migration(migrations.Migration):
-
dependencies = [
("proxylist", "0005_remove_proxy_times_check_failed"),
]
diff --git a/proxylist/migrations/0007_proxy_ip_address_proxy_location_country_code.py b/app/shadowmere/apps/proxylist/migrations/0007_proxy_ip_address_proxy_location_country_code.py
similarity index 99%
rename from proxylist/migrations/0007_proxy_ip_address_proxy_location_country_code.py
rename to app/shadowmere/apps/proxylist/migrations/0007_proxy_ip_address_proxy_location_country_code.py
index d3c3c5b..b1af245 100644
--- a/proxylist/migrations/0007_proxy_ip_address_proxy_location_country_code.py
+++ b/app/shadowmere/apps/proxylist/migrations/0007_proxy_ip_address_proxy_location_country_code.py
@@ -4,7 +4,6 @@
class Migration(migrations.Migration):
-
dependencies = [
("proxylist", "0006_proxy_times_check_succeeded"),
]
diff --git a/app/shadowmere/apps/proxylist/migrations/0008_proxy_location_country_alter_proxy_url.py b/app/shadowmere/apps/proxylist/migrations/0008_proxy_location_country_alter_proxy_url.py
new file mode 100644
index 0000000..60ef86f
--- /dev/null
+++ b/app/shadowmere/apps/proxylist/migrations/0008_proxy_location_country_alter_proxy_url.py
@@ -0,0 +1,31 @@
+# Generated by Django 4.0.4 on 2022-06-06 12:09
+
+from django.db import migrations, models
+import apps.proxylist.models
+
+
+class Migration(migrations.Migration):
+ dependencies = [
+ ("proxylist", "0007_proxy_ip_address_proxy_location_country_code"),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name="proxy",
+ name="location_country",
+ field=models.CharField(default="", max_length=50),
+ ),
+ migrations.AlterField(
+ model_name="proxy",
+ name="url",
+ field=models.CharField(
+ max_length=1024,
+ unique=True,
+ validators=[
+ apps.proxylist.models.validate_sip002,
+ apps.proxylist.models.validate_not_existing,
+ apps.proxylist.models.validate_proxy_can_connect,
+ ],
+ ),
+ ),
+ ]
diff --git a/proxylist/migrations/0009_proxy_port.py b/app/shadowmere/apps/proxylist/migrations/0009_proxy_port.py
similarity index 99%
rename from proxylist/migrations/0009_proxy_port.py
rename to app/shadowmere/apps/proxylist/migrations/0009_proxy_port.py
index 869c665..28199aa 100644
--- a/proxylist/migrations/0009_proxy_port.py
+++ b/app/shadowmere/apps/proxylist/migrations/0009_proxy_port.py
@@ -4,7 +4,6 @@
class Migration(migrations.Migration):
-
dependencies = [
("proxylist", "0008_proxy_location_country_alter_proxy_url"),
]
diff --git a/app/shadowmere/apps/proxylist/migrations/0010_subscription_alter_proxy_url.py b/app/shadowmere/apps/proxylist/migrations/0010_subscription_alter_proxy_url.py
new file mode 100644
index 0000000..cef7754
--- /dev/null
+++ b/app/shadowmere/apps/proxylist/migrations/0010_subscription_alter_proxy_url.py
@@ -0,0 +1,26 @@
+# Generated by Django 4.1.7 on 2023-03-04 14:37
+
+from django.db import migrations, models
+import apps.proxylist.models
+
+
+class Migration(migrations.Migration):
+ dependencies = [
+ ("proxylist", "0009_proxy_port"),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name="Subscription",
+ fields=[
+ ("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
+ ("url", models.URLField(unique=True)),
+ ("kind", models.CharField(choices=[("1", "plain"), ("2", "base64")], default="1", max_length=10)),
+ ],
+ ),
+ migrations.AlterField(
+ model_name="proxy",
+ name="url",
+ field=models.CharField(max_length=1024, unique=True, validators=[apps.proxylist.models.proxy_validator]),
+ ),
+ ]
diff --git a/app/shadowmere/apps/proxylist/migrations/0011_alter_subscription_kind.py b/app/shadowmere/apps/proxylist/migrations/0011_alter_subscription_kind.py
new file mode 100644
index 0000000..d57b9f6
--- /dev/null
+++ b/app/shadowmere/apps/proxylist/migrations/0011_alter_subscription_kind.py
@@ -0,0 +1,17 @@
+# Generated by Django 4.1.7 on 2023-03-04 14:44
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+ dependencies = [
+ ("proxylist", "0010_subscription_alter_proxy_url"),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name="subscription",
+ name="kind",
+ field=models.CharField(choices=[("PLAIN", "plain"), ("BASE64", "base64")], default="PLAIN", max_length=10),
+ ),
+ ]
diff --git a/proxylist/migrations/0012_subscription_alive_subscription_enabled.py b/app/shadowmere/apps/proxylist/migrations/0012_subscription_alive_subscription_enabled.py
similarity index 100%
rename from proxylist/migrations/0012_subscription_alive_subscription_enabled.py
rename to app/shadowmere/apps/proxylist/migrations/0012_subscription_alive_subscription_enabled.py
diff --git a/proxylist/migrations/0013_subscription_alive_timestamp_and_more.py b/app/shadowmere/apps/proxylist/migrations/0013_subscription_alive_timestamp_and_more.py
similarity index 100%
rename from proxylist/migrations/0013_subscription_alive_timestamp_and_more.py
rename to app/shadowmere/apps/proxylist/migrations/0013_subscription_alive_timestamp_and_more.py
diff --git a/proxylist/migrations/0014_tasklog.py b/app/shadowmere/apps/proxylist/migrations/0014_tasklog.py
similarity index 100%
rename from proxylist/migrations/0014_tasklog.py
rename to app/shadowmere/apps/proxylist/migrations/0014_tasklog.py
diff --git a/proxylist/migrations/0015_alter_tasklog_start_time.py b/app/shadowmere/apps/proxylist/migrations/0015_alter_tasklog_start_time.py
similarity index 100%
rename from proxylist/migrations/0015_alter_tasklog_start_time.py
rename to app/shadowmere/apps/proxylist/migrations/0015_alter_tasklog_start_time.py
diff --git a/proxylist/migrations/0016_alter_tasklog_finish_time_alter_tasklog_start_time.py b/app/shadowmere/apps/proxylist/migrations/0016_alter_tasklog_finish_time_alter_tasklog_start_time.py
similarity index 100%
rename from proxylist/migrations/0016_alter_tasklog_finish_time_alter_tasklog_start_time.py
rename to app/shadowmere/apps/proxylist/migrations/0016_alter_tasklog_finish_time_alter_tasklog_start_time.py
diff --git a/proxylist/migrations/0017_tasklog_details.py b/app/shadowmere/apps/proxylist/migrations/0017_tasklog_details.py
similarity index 100%
rename from proxylist/migrations/0017_tasklog_details.py
rename to app/shadowmere/apps/proxylist/migrations/0017_tasklog_details.py
diff --git a/proxylist/tests/__init__.py b/app/shadowmere/apps/proxylist/migrations/__init__.py
similarity index 100%
rename from proxylist/tests/__init__.py
rename to app/shadowmere/apps/proxylist/migrations/__init__.py
diff --git a/proxylist/models.py b/app/shadowmere/apps/proxylist/models.py
similarity index 96%
rename from proxylist/models.py
rename to app/shadowmere/apps/proxylist/models.py
index 0a31d2b..4dc32a8 100644
--- a/proxylist/models.py
+++ b/app/shadowmere/apps/proxylist/models.py
@@ -1,17 +1,16 @@
import base64
import re
+from apps.proxylist.base64_decoder import decode_base64
+from apps.proxylist.proxy import get_proxy_location, update_proxy_status
from django.core.cache import cache
from django.core.exceptions import ValidationError
-from django.db import models, IntegrityError
+from django.db import IntegrityError, models
from django.db.models.signals import post_save
from django.dispatch import receiver
from django.utils.timezone import now
from django_prometheus.models import ExportModelOperationsMixin
-from proxylist.base64_decoder import decode_base64
-from proxylist.proxy import update_proxy_status, get_proxy_location
-
def validate_sip002(value):
if get_sip002(value) == "":
diff --git a/app/shadowmere/apps/proxylist/pagination.py b/app/shadowmere/apps/proxylist/pagination.py
new file mode 100644
index 0000000..10610e6
--- /dev/null
+++ b/app/shadowmere/apps/proxylist/pagination.py
@@ -0,0 +1,14 @@
+from rest_framework import pagination
+from rest_framework.response import Response
+
+
+class ProxiesPagination(pagination.PageNumberPagination):
+ def get_paginated_response(self, data):
+ return Response(
+ {
+ "count": self.page.paginator.count,
+ "total_pages": self.page.paginator.num_pages,
+ "current_page": self.page.number,
+ "results": data,
+ }
+ )
diff --git a/proxylist/permissions.py b/app/shadowmere/apps/proxylist/permissions.py
similarity index 81%
rename from proxylist/permissions.py
rename to app/shadowmere/apps/proxylist/permissions.py
index 205f51b..80b4124 100644
--- a/proxylist/permissions.py
+++ b/app/shadowmere/apps/proxylist/permissions.py
@@ -1,4 +1,4 @@
-from rest_framework.permissions import BasePermission, SAFE_METHODS
+from rest_framework.permissions import SAFE_METHODS, BasePermission
class GeneralPermission(BasePermission):
diff --git a/proxylist/proxy.py b/app/shadowmere/apps/proxylist/proxy.py
similarity index 100%
rename from proxylist/proxy.py
rename to app/shadowmere/apps/proxylist/proxy.py
index 3189a88..120eb40 100644
--- a/proxylist/proxy.py
+++ b/app/shadowmere/apps/proxylist/proxy.py
@@ -1,6 +1,6 @@
import requests
-from django.utils.timezone import now
from django.conf import settings
+from django.utils.timezone import now
from requests.exceptions import InvalidJSONError
diff --git a/proxylist/serializers.py b/app/shadowmere/apps/proxylist/serializers.py
similarity index 95%
rename from proxylist/serializers.py
rename to app/shadowmere/apps/proxylist/serializers.py
index de1b726..9bb6cf3 100644
--- a/proxylist/serializers.py
+++ b/app/shadowmere/apps/proxylist/serializers.py
@@ -1,7 +1,6 @@
+from apps.proxylist.models import Proxy
from rest_framework import serializers
-from proxylist.models import Proxy
-
class ProxySerializer(serializers.ModelSerializer):
class Meta:
diff --git a/proxylist/tasks.py b/app/shadowmere/apps/proxylist/tasks.py
similarity index 97%
rename from proxylist/tasks.py
rename to app/shadowmere/apps/proxylist/tasks.py
index 4e475dc..6f61b41 100644
--- a/proxylist/tasks.py
+++ b/app/shadowmere/apps/proxylist/tasks.py
@@ -3,18 +3,16 @@
from concurrent.futures import ThreadPoolExecutor
import requests
+from apps.proxylist.base64_decoder import decode_base64
+from apps.proxylist.models import Proxy, Subscription, TaskLog, get_sip002
+from apps.proxylist.proxy import get_proxy_location, update_proxy_status
from django.db import IntegrityError
from django.db.models import F, FloatField
from django.db.models.functions import Coalesce
from django.utils.timezone import now
from huey import crontab
from huey.contrib.djhuey import db_periodic_task
-from requests.exceptions import SSLError, ConnectionError, ReadTimeout
-
-from proxylist.base64_decoder import decode_base64
-from proxylist.models import Proxy, Subscription, get_sip002, TaskLog
-from proxylist.proxy import update_proxy_status, get_proxy_location
-from shadowmere.celery import app
+from requests.exceptions import ConnectionError, ReadTimeout, SSLError
CONCURRENT_CHECKS = 200
SUBSCRIPTION_TIMEOUT_SECONDS = 60
diff --git a/shadowmere/__init__.py b/app/shadowmere/apps/proxylist/tests/__init__.py
similarity index 100%
rename from shadowmere/__init__.py
rename to app/shadowmere/apps/proxylist/tests/__init__.py
diff --git a/proxylist/tests/test_country_codes.py b/app/shadowmere/apps/proxylist/tests/test_country_codes.py
similarity index 100%
rename from proxylist/tests/test_country_codes.py
rename to app/shadowmere/apps/proxylist/tests/test_country_codes.py
diff --git a/proxylist/tests/test_ports.py b/app/shadowmere/apps/proxylist/tests/test_ports.py
similarity index 100%
rename from proxylist/tests/test_ports.py
rename to app/shadowmere/apps/proxylist/tests/test_ports.py
diff --git a/proxylist/tests/test_proxies.py b/app/shadowmere/apps/proxylist/tests/test_proxies.py
similarity index 100%
rename from proxylist/tests/test_proxies.py
rename to app/shadowmere/apps/proxylist/tests/test_proxies.py
diff --git a/proxylist/tests/test_qr.py b/app/shadowmere/apps/proxylist/tests/test_qr.py
similarity index 100%
rename from proxylist/tests/test_qr.py
rename to app/shadowmere/apps/proxylist/tests/test_qr.py
diff --git a/proxylist/tests/test_subscription.py b/app/shadowmere/apps/proxylist/tests/test_subscription.py
similarity index 100%
rename from proxylist/tests/test_subscription.py
rename to app/shadowmere/apps/proxylist/tests/test_subscription.py
diff --git a/proxylist/tests/test_tasks.py b/app/shadowmere/apps/proxylist/tests/test_tasks.py
similarity index 100%
rename from proxylist/tests/test_tasks.py
rename to app/shadowmere/apps/proxylist/tests/test_tasks.py
diff --git a/proxylist/views.py b/app/shadowmere/apps/proxylist/views.py
similarity index 86%
rename from proxylist/views.py
rename to app/shadowmere/apps/proxylist/views.py
index 46e387f..29e40ce 100644
--- a/proxylist/views.py
+++ b/app/shadowmere/apps/proxylist/views.py
@@ -5,9 +5,14 @@
import flag
import qrcode
+from apps.proxylist.base64_decoder import decode_base64
+from apps.proxylist.metrics import register_metrics
+from apps.proxylist.models import Proxy, TaskLog
+from apps.proxylist.permissions import GeneralPermission
+from apps.proxylist.serializers import ProxySerializer
from django.core.paginator import Paginator
from django.http import HttpResponse, JsonResponse
-from django.shortcuts import render, get_object_or_404
+from django.shortcuts import get_object_or_404, render
from django.template.defaultfilters import urlencode
from django.utils.decorators import method_decorator
from django.utils.text import slugify
@@ -17,12 +22,6 @@
from rest_framework import viewsets
from rest_framework.response import Response
-from proxylist.base64_decoder import decode_base64
-from proxylist.metrics import register_metrics
-from proxylist.models import Proxy, TaskLog
-from proxylist.permissions import GeneralPermission
-from proxylist.serializers import ProxySerializer
-
@cache_page(None)
def list_proxies(request):
@@ -34,9 +33,7 @@ def list_proxies(request):
.distinct()
)
if location_country_code != "":
- proxy_list = Proxy.objects.filter(
- location_country_code=location_country_code, is_active=True
- ).order_by("-id")
+ proxy_list = Proxy.objects.filter(location_country_code=location_country_code, is_active=True).order_by("-id")
else:
proxy_list = Proxy.objects.filter(is_active=True).order_by("-id")
@@ -75,9 +72,7 @@ def get_flag_or_empty(country_code):
def get_proxy_config(proxy):
- method_password = decode_base64(
- proxy.url.split("@")[0].replace("ss://", "").encode("ascii")
- )
+ method_password = decode_base64(proxy.url.split("@")[0].replace("ss://", "").encode("ascii"))
server_and_port = proxy.url.split("@")[1]
config = {
"server": re.findall(r"^(.*?):\d+", server_and_port)[0],
@@ -108,9 +103,7 @@ def json_proxy_file(request, proxy_id):
"method": details["method"],
}
response = HttpResponse(json.dumps(config), content_type="application/json")
- response["Content-Disposition"] = (
- f'attachment; filename="shadowmere_config_{slugify(proxy.location)}.json"'
- )
+ response["Content-Disposition"] = f'attachment; filename="shadowmere_config_{slugify(proxy.location)}.json"'
return response
@@ -180,11 +173,7 @@ class PortViewSet(viewsets.ViewSet):
@method_decorator(cache_page(20 * 60))
def list(self, request, format=None):
ports = [
- port
- for port in Proxy.objects.filter(is_active=True)
- .values_list("port", flat=True)
- .distinct()
- if port != 0
+ port for port in Proxy.objects.filter(is_active=True).values_list("port", flat=True).distinct() if port != 0
]
ports.sort()
ports = [
@@ -212,9 +201,7 @@ class SubViewSet(viewsets.ViewSet):
def list(self, request, format=None):
servers = [
get_proxy_config(server)
- for server in Proxy.objects.filter(is_active=True).order_by(
- "location_country_code"
- )
+ for server in Proxy.objects.filter(is_active=True).order_by("location_country_code")
]
return Response(servers)
@@ -234,9 +221,7 @@ class Base64SubViewSet(viewsets.ViewSet):
@method_decorator(cache_page(20 * 60))
def list(self, request, format=None):
server_list = ""
- for proxy in Proxy.objects.filter(is_active=True).order_by(
- "location_country_code"
- ):
+ for proxy in Proxy.objects.filter(is_active=True).order_by("location_country_code"):
server_list += f"\n{proxy.url}#{get_flag_or_empty(proxy.location_country_code)} {proxy.location}"
b64_servers = base64.b64encode(server_list.encode("utf-8"))
return HttpResponse(b64_servers)
diff --git a/docker/entrypoint b/docker/entrypoint
deleted file mode 100755
index 89d4d8b..0000000
--- a/docker/entrypoint
+++ /dev/null
@@ -1,30 +0,0 @@
-#!/bin/bash
-
-set -o errexit
-set -o pipefail
-cmd="$@"
-
-function postgres_ready(){
-python << END
-import sys
-import psycopg2
-import os
-
-try:
- dbname = os.getenv('POSTGRES_DB')
- user = os.getenv('POSTGRES_USER')
- password = os.getenv('POSTGRES_PASSWORD')
- conn = psycopg2.connect(dbname=dbname, user=user, password=password, host='db', port=5432)
-except psycopg2.OperationalError:
- sys.exit(-1)
-sys.exit(0)
-END
-}
-
-until postgres_ready; do
- >&2 echo "Postgres is unavailable - sleeping"
- sleep 1
-done
-
->&2 echo "Postgres is up - continuing..."
-exec $cmd
diff --git a/Dockerfile b/docker/prod/Dockerfile
similarity index 100%
rename from Dockerfile
rename to docker/prod/Dockerfile
diff --git a/docker/start b/docker/start
deleted file mode 100755
index 35388e8..0000000
--- a/docker/start
+++ /dev/null
@@ -1,15 +0,0 @@
-#!/bin/bash
-
-set -o errexit
-set -o pipefail
-set -o nounset
-set -o xtrace
-
-python manage.py migrate --no-input
-python manage.py initadmin
-if [ "${DEBUG}" == "True" ]; then
- python manage.py runserver 0.0.0.0:8001
-else
- python manage.py collectstatic --no-input
- gunicorn shadowmere.wsgi:application --bind 0.0.0.0:8001 -k gevent -w 6 --capture-output
-fi
diff --git a/docker/wait_for_migration.sh b/docker/wait_for_migration.sh
deleted file mode 100755
index 8d85db1..0000000
--- a/docker/wait_for_migration.sh
+++ /dev/null
@@ -1,16 +0,0 @@
-#!/bin/bash
-
-set -e
-
-cmd="$@"
-
-if [ "${IS_DJANGO_SERVICE}" == "True" ]; then
- echo "Waiting for the database to become available..."
- until python3 manage.py migrate; do
- echo "Database is unavailable, sleeping for 5 seconds..."
- done
-else
- sleep 30
-fi
-
-exec $cmd
diff --git a/locale/es/LC_MESSAGES/django.mo b/locale/es/LC_MESSAGES/django.mo
deleted file mode 100644
index 14bc8084c9701b56ef4dcb924da72c8b6d7c55cf..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001
literal 2119
zcmb_d%WfP+6fMBK29S6xkPwI)OCS*Go`hA@ek7B4l8iDB%P$0oMNRj0PsKe|ovLal
z6Lts*i3KZQ!Hy+JERb2TL1O+RU%*Fjsy((R8If#gseD{r)%Tuz>(rSCuP^-|@VtWY
zHpbT&uVMUy5uOWA3Goi_BJd^P0QfxcbKnDv6ypuduRe3Uz6X30^C2+oyFbIPfD_EW
z1-=DbS`y-E;Jd)9h_MVjhdDnh#B;!JfZ_Y^fPY~9M_}M}3ol;*v#PLl3aDm|dWm;>53mXyZdvGmI5xIvFRPfWtP3D&wWGHa%VV(nc#^5bH8
z{U%$kGb)FqCsoe&)R`S0vX#X`(z1{~aB}BqSa}*xXkQ*0t2`58El|qYo5~kT^Q`Q_
z@vKfBDwKLcCowU}77{Lm#O_I)853Pxt<}PK1I#f9(KT_^;BDxY1Nk^O>B%*IfralN@CK9x=
z(wP|O(1Ap3mr@6r?BG+n%R@J7o6*H&?i_rjH5ZOjQxu$f&PWyoNgHB85}vJQAJZos
z$n*z0A={zKn9$F$#0HGIu~4obao~C!F&4WuaUPTOG%=MW=!2|s2eB~wV$+)2NEmgp
zXpgOf>Jr*)UAxt~(Wbrj)^=ymZ)|aCtdDvwS6Otm%3ZW$5^8J?qAfmD;hShfdQRxm
zc55r@4Wf+}-5eyn&PSgO`t3$&SF~fLb`X-W30>dqcB$X$wQ058YjwI;S{oZ%?d|P#
zY}I)sbB=acjuYy(`Zsn1lhtnbN}+PTE~8EcjtO^>1(pdQ=LuaJD&N>FDqMx=dXRlWx~!*e?c)_FH>|9E
zpy}KiUHovRA$IlgeUgOp@Y6qWknHCDL$uH(lZXy1WBQ8|dyJFMq@_v|R=m6q5iMS%
zIT1g`KuT#PnIWp?Q}amG^hn1~j`-hh(YjMjf2(iHNKU|WuEJx>K!tVYLur-7|2SG%
z8<#s@vNbeTCoW+Kdl#=fppOmKUHyAnJse)4i7G8X>=P5Od}
diff --git a/locale/es/LC_MESSAGES/django.po b/locale/es/LC_MESSAGES/django.po
deleted file mode 100644
index 0c984bc..0000000
--- a/locale/es/LC_MESSAGES/django.po
+++ /dev/null
@@ -1,87 +0,0 @@
-# SOME DESCRIPTIVE TITLE.
-# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
-# This file is distributed under the same license as the PACKAGE package.
-# FIRST AUTHOR , YEAR.
-#
-#, fuzzy
-msgid ""
-msgstr ""
-"Project-Id-Version: PACKAGE VERSION\n"
-"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2022-04-12 17:20+0000\n"
-"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
-"Last-Translator: FULL NAME \n"
-"Language-Team: LANGUAGE \n"
-"Language: \n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-
-#: shadowmere/settings.py:142
-msgid "Spanish"
-msgstr "EspaΓ±ol"
-
-#: shadowmere/settings.py:143
-msgid "English"
-msgstr "InglΓ©s"
-
-#: templates/index.html:49
-msgid "A list of Shadowsocks proxies"
-msgstr "Una lista de tΓΊneles Shadowsocks"
-
-#: templates/index.html:51
-msgid "Disclaimer:"
-msgstr "Aviso:"
-
-#: templates/index.html:51
-msgid ""
-"This website is only a list of tunnels collected all around internet. We do "
-"NOT provide or maintain any of these tunnels."
-msgstr ""
-"Este sitio web es sΓ³lo una lista de tΓΊneles recolectados en Internet. "
-"Nosotros no proveemos ni mantenemos estos tΓΊneles."
-
-#: templates/index.html:52
-msgid "Use them at your own risk."
-msgstr "Γselos bajo su propio riesgo"
-
-#: templates/index.html:57
-msgid "How do I use this?:"
-msgstr "ΒΏCΓ³mo uso esto?"
-
-#: templates/index.html:58
-msgid ""
-"Go give shadowsocks.org a quick "
-"look for information.\n"
-" Here is a list of clients for several\n"
-" platforms, but my favorite is Outline for any platform and\n"
-" shadowsocks for\n"
-" Android
\n"
-" "
-msgstr ""
-"Ve a dar un vistazo a shadowsocks.org"
-"a> para obtener informaciΓ³n. AquΓ hay una lista de clientes para varias plataformas,"
-"pero mi favorito es Outline para "
-"cualquier plataforma y shadowsocks para Android "
-
-#: templates/index.html:64
-msgid "Online:"
-msgstr "Conectados: "
-
-#: templates/index.html:69
-msgid "Last check:"
-msgstr "Γltima prueba: "
-
-#: templates/index.html:135
-msgid "of"
-msgstr "de"
-
-#: templates/index.html:146
-msgid "No active proxies found"
-msgstr "No se han encontrado tΓΊneles activos"
diff --git a/manage.py b/manage.py
deleted file mode 100755
index b0afc13..0000000
--- a/manage.py
+++ /dev/null
@@ -1,23 +0,0 @@
-#!/usr/bin/env python
-import os
-import sys
-
-
-def main():
- if os.getenv("DEBUG") == "True":
- os.environ.setdefault("DJANGO_SETTINGS_MODULE", "shadowmere.settings.dev")
- else:
- os.environ.setdefault("DJANGO_SETTINGS_MODULE", "shadowmere.settings.prod")
- try:
- from django.core.management import execute_from_command_line
- except ImportError as exc:
- raise ImportError(
- "Couldn't import Django. Are you sure it's installed and "
- "available on your PYTHONPATH environment variable? Did you "
- "forget to activate a virtual environment?"
- ) from exc
- execute_from_command_line(sys.argv)
-
-
-if __name__ == "__main__":
- main()
diff --git a/proxylist/apps.py b/proxylist/apps.py
deleted file mode 100644
index 493f3ae..0000000
--- a/proxylist/apps.py
+++ /dev/null
@@ -1,6 +0,0 @@
-from django.apps import AppConfig
-
-
-class ProxylistConfig(AppConfig):
- default_auto_field = "django.db.models.BigAutoField"
- name = "proxylist"
diff --git a/proxylist/migrations/0008_proxy_location_country_alter_proxy_url.py b/proxylist/migrations/0008_proxy_location_country_alter_proxy_url.py
deleted file mode 100644
index 162880e..0000000
--- a/proxylist/migrations/0008_proxy_location_country_alter_proxy_url.py
+++ /dev/null
@@ -1,24 +0,0 @@
-# Generated by Django 4.0.4 on 2022-06-06 12:09
-
-from django.db import migrations, models
-import proxylist.models
-
-
-class Migration(migrations.Migration):
-
- dependencies = [
- ('proxylist', '0007_proxy_ip_address_proxy_location_country_code'),
- ]
-
- operations = [
- migrations.AddField(
- model_name='proxy',
- name='location_country',
- field=models.CharField(default='', max_length=50),
- ),
- migrations.AlterField(
- model_name='proxy',
- name='url',
- field=models.CharField(max_length=1024, unique=True, validators=[proxylist.models.validate_sip002, proxylist.models.validate_not_existing, proxylist.models.validate_proxy_can_connect]),
- ),
- ]
diff --git a/proxylist/migrations/0010_subscription_alter_proxy_url.py b/proxylist/migrations/0010_subscription_alter_proxy_url.py
deleted file mode 100644
index 61d3453..0000000
--- a/proxylist/migrations/0010_subscription_alter_proxy_url.py
+++ /dev/null
@@ -1,27 +0,0 @@
-# Generated by Django 4.1.7 on 2023-03-04 14:37
-
-from django.db import migrations, models
-import proxylist.models
-
-
-class Migration(migrations.Migration):
-
- dependencies = [
- ('proxylist', '0009_proxy_port'),
- ]
-
- operations = [
- migrations.CreateModel(
- name='Subscription',
- fields=[
- ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
- ('url', models.URLField(unique=True)),
- ('kind', models.CharField(choices=[('1', 'plain'), ('2', 'base64')], default='1', max_length=10)),
- ],
- ),
- migrations.AlterField(
- model_name='proxy',
- name='url',
- field=models.CharField(max_length=1024, unique=True, validators=[proxylist.models.proxy_validator]),
- ),
- ]
diff --git a/proxylist/migrations/0011_alter_subscription_kind.py b/proxylist/migrations/0011_alter_subscription_kind.py
deleted file mode 100644
index 80d2567..0000000
--- a/proxylist/migrations/0011_alter_subscription_kind.py
+++ /dev/null
@@ -1,18 +0,0 @@
-# Generated by Django 4.1.7 on 2023-03-04 14:44
-
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
- dependencies = [
- ('proxylist', '0010_subscription_alter_proxy_url'),
- ]
-
- operations = [
- migrations.AlterField(
- model_name='subscription',
- name='kind',
- field=models.CharField(choices=[('PLAIN', 'plain'), ('BASE64', 'base64')], default='PLAIN', max_length=10),
- ),
- ]
diff --git a/proxylist/pagination.py b/proxylist/pagination.py
deleted file mode 100644
index ae8e612..0000000
--- a/proxylist/pagination.py
+++ /dev/null
@@ -1,12 +0,0 @@
-from rest_framework import pagination
-from rest_framework.response import Response
-
-
-class ProxiesPagination(pagination.PageNumberPagination):
- def get_paginated_response(self, data):
- return Response({
- 'count': self.page.paginator.count,
- 'total_pages': self.page.paginator.num_pages,
- 'current_page': self.page.number,
- 'results': data
- })
diff --git a/shadowmere/asgi.py b/shadowmere/asgi.py
deleted file mode 100644
index 824093a..0000000
--- a/shadowmere/asgi.py
+++ /dev/null
@@ -1,16 +0,0 @@
-"""
-ASGI config for shadowmere project.
-
-It exposes the ASGI callable as a module-level variable named ``application``.
-
-For more information on this file, see
-https://docs.djangoproject.com/en/3.2/howto/deployment/asgi/
-"""
-
-import os
-
-from django.core.asgi import get_asgi_application
-
-os.environ.setdefault("DJANGO_SETTINGS_MODULE", "shadowmere.settings")
-
-application = get_asgi_application()
diff --git a/shadowmere/settings/__init__.py b/shadowmere/settings/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/shadowmere/settings/dev.py b/shadowmere/settings/dev.py
deleted file mode 100644
index 4b40b38..0000000
--- a/shadowmere/settings/dev.py
+++ /dev/null
@@ -1 +0,0 @@
-from .base import * # noqa
diff --git a/shadowmere/settings/prod.py b/shadowmere/settings/prod.py
deleted file mode 100644
index 575ed4b..0000000
--- a/shadowmere/settings/prod.py
+++ /dev/null
@@ -1,47 +0,0 @@
-from .base import * # noqa
-import sentry_sdk
-from sentry_sdk.integrations.django import DjangoIntegration
-
-MIDDLEWARE = (
- ["django_prometheus.middleware.PrometheusBeforeMiddleware"]
- + MIDDLEWARE
- + ["django_prometheus.middleware.PrometheusAfterMiddleware"]
-)
-
-THIRD_PARTY_APPS += ["django_prometheus"]
-
-DEFAULT_FILE_STORAGE = "minio_storage.storage.MinioMediaStorage"
-
-STATICFILES_STORAGE = "minio_storage.storage.MinioStaticStorage"
-
-MINIO_STORAGE_ENDPOINT = env("MINIO_ENDPOINT")
-
-MINIO_STORAGE_ACCESS_KEY = env("MINIO_ACCESS_KEY")
-
-MINIO_STORAGE_SECRET_KEY = env("MINIO_SECRET_KEY")
-
-MINIO_STORAGE_USE_HTTPS = True
-
-MINIO_STORAGE_MEDIA_BUCKET_NAME = "shadowmere-media"
-
-MINIO_STORAGE_AUTO_CREATE_MEDIA_BUCKET = True
-
-MINIO_STORAGE_STATIC_BUCKET_NAME = "shadowmere-static"
-
-MINIO_STORAGE_AUTO_CREATE_STATIC_BUCKET = True
-
-sentry_sdk.init(
- dsn=env("SENTRY_DSN"),
- integrations=[
- DjangoIntegration(),
- ],
- # Set traces_sample_rate to 1.0 to capture 100%
- # of transactions for performance monitoring.
- # We recommend adjusting this value in production.
- traces_sample_rate=0.01,
- # If you wish to associate users to errors (assuming you are using
- # django.contrib.auth) you may enable sending PII data.
- send_default_pii=True,
-)
-
-PROMETHEUS_METRICS_EXPORT_PORT_RANGE = range(8002, 8008)
diff --git a/shadowmere/urls.py b/shadowmere/urls.py
deleted file mode 100644
index 846f376..0000000
--- a/shadowmere/urls.py
+++ /dev/null
@@ -1,24 +0,0 @@
-from django.contrib import admin
-from django.urls import path, include
-from rest_framework import routers
-
-import proxylist.views
-from proxylist import views
-
-router = routers.DefaultRouter()
-router.register(r"proxies", views.ProxyViewSet)
-router.register(r"country-codes", views.CountryCodeViewSet, basename="country-codes")
-router.register(r"ports", views.PortViewSet, basename="ports")
-router.register(r"sub", views.SubViewSet, basename="sub")
-router.register(r"b64sub", views.Base64SubViewSet, basename="b64sub")
-
-urlpatterns = [
- path("admin/", admin.site.urls),
- path("", proxylist.views.list_proxies),
- path("/config", proxylist.views.json_proxy_file),
- path("/qr", proxylist.views.qr_code),
- path("health", proxylist.views.healthcheck),
- path("api-auth/", include("rest_framework.urls", namespace="rest_framework")),
- path("api/", include(router.urls)),
- path("", include("django_prometheus.urls")),
-]
diff --git a/shadowmere/wsgi.py b/shadowmere/wsgi.py
deleted file mode 100644
index 107261a..0000000
--- a/shadowmere/wsgi.py
+++ /dev/null
@@ -1,16 +0,0 @@
-"""
-WSGI config for shadowmere project.
-
-It exposes the WSGI callable as a module-level variable named ``application``.
-
-For more information on this file, see
-https://docs.djangoproject.com/en/3.2/howto/deployment/wsgi/
-"""
-
-import os
-
-from django.core.wsgi import get_wsgi_application
-
-os.environ.setdefault("DJANGO_SETTINGS_MODULE", "shadowmere.settings")
-
-application = get_wsgi_application()
diff --git a/templates/index.html b/templates/index.html
deleted file mode 100644
index 04b0901..0000000
--- a/templates/index.html
+++ /dev/null
@@ -1,158 +0,0 @@
-{% load i18n %}
-
-
-
-
-
-
-
- Shadowmere
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Shadowmere
-
-
{% translate "A list of Shadowsocks proxies" %}
-
- {% translate "Disclaimer:" %} {% translate "This website is only a list of tunnels collected all around internet. We do NOT provide or maintain any of these tunnels." %}
- {% translate "Use them at your own risk." %}
-
{% translate "How do I use this?:" %}
- {% blocktranslate %}Go give shadowsocks.org a quick look for
- information.
- Here is a list of clients for several
- platforms, but my favorite is Outline for any platform and
- shadowsocks for
- Android
- {% endblocktranslate %}
-
{% translate "Online:" %} {{ proxy_list|length }} {% if location_country_code != "" %}
-
- {% endif %}
- {% if proxy_list|length > 0 %}
-
{% translate "Last check:" %} {{ latest_update }} UTC
- {% endif %}
-
-
-
- {% for country_code in country_codes %}
- {% if country_code.location_country_code != "" %}
-
-
-
- {% endif %}
- {% endfor %}
-
- {% if proxy_list %}
-
- {% for proxy in page_obj %}
-
-
-
-
{% widthratio proxy.times_check_succeeded proxy.times_checked 100 %}%
-
-
-
{{ proxy.url }}#{{ proxy.location|urlencode }}
-
{{ proxy.ip_address }} ⚓{{ proxy.port }}
-
-
-
-
-
-
-
-
×
-
-
-
-
-
- {% endfor %}
-
-
-
-
- {% else %}
-
{% translate "No active proxies found" %}
- {% endif %}
-
-
-Update cookies preferences
-
-
From d4c15112236c3d45c8348fedeed10c2bf9463d9e Mon Sep 17 00:00:00 2001
From: "Ozkar L. Garcell"
Date: Wed, 5 Jun 2024 19:28:23 +0200
Subject: [PATCH 16/32] WiP: project layout, config files
---
app/shadowmere/config/__init__.py | 0
app/shadowmere/config/asgi.py | 16 ++
app/shadowmere/config/settings/__init__.py | 0
app/shadowmere/config/settings/base.py | 224 +++++++++++++++++++++
app/shadowmere/config/settings/dev.py | 3 +
app/shadowmere/config/settings/prod.py | 57 ++++++
app/shadowmere/config/urls.py | 32 +++
app/shadowmere/config/wsgi.py | 16 ++
8 files changed, 348 insertions(+)
create mode 100644 app/shadowmere/config/__init__.py
create mode 100644 app/shadowmere/config/asgi.py
create mode 100644 app/shadowmere/config/settings/__init__.py
create mode 100644 app/shadowmere/config/settings/base.py
create mode 100644 app/shadowmere/config/settings/dev.py
create mode 100644 app/shadowmere/config/settings/prod.py
create mode 100644 app/shadowmere/config/urls.py
create mode 100644 app/shadowmere/config/wsgi.py
diff --git a/app/shadowmere/config/__init__.py b/app/shadowmere/config/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/app/shadowmere/config/asgi.py b/app/shadowmere/config/asgi.py
new file mode 100644
index 0000000..824093a
--- /dev/null
+++ b/app/shadowmere/config/asgi.py
@@ -0,0 +1,16 @@
+"""
+ASGI config for shadowmere project.
+
+It exposes the ASGI callable as a module-level variable named ``application``.
+
+For more information on this file, see
+https://docs.djangoproject.com/en/3.2/howto/deployment/asgi/
+"""
+
+import os
+
+from django.core.asgi import get_asgi_application
+
+os.environ.setdefault("DJANGO_SETTINGS_MODULE", "shadowmere.settings")
+
+application = get_asgi_application()
diff --git a/app/shadowmere/config/settings/__init__.py b/app/shadowmere/config/settings/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/app/shadowmere/config/settings/base.py b/app/shadowmere/config/settings/base.py
new file mode 100644
index 0000000..95b21ae
--- /dev/null
+++ b/app/shadowmere/config/settings/base.py
@@ -0,0 +1,224 @@
+from pathlib import Path
+
+import environ
+from django.utils.translation import gettext_lazy as _
+
+BASE_DIR = Path(__file__).resolve(strict=True).parent.parent.parent
+
+env = environ.Env(
+ SECRET_KEY=(str, ""),
+ DEBUG=(bool, False),
+ SHADOWTEST_URL=(str, ""),
+ ALLOWED_HOSTS=(str, ""),
+ CSRF_TRUSTED_ORIGINS=(str, ""),
+ MINIO_ENDPOINT=(str, ""),
+ MINIO_ACCESS_KEY=(str, ""),
+ MINIO_SECRET_KEY=(str, ""),
+ MINIO_BUCKET=(str, ""),
+ SENTRY_DSN=(str, ""),
+ REDIS_HOST=(str, ""),
+ REDIS_PORT=(int, 0),
+)
+
+SECRET_KEY = env("SECRET_KEY")
+
+DEBUG = env("DEBUG", default=False)
+
+SHADOWTEST_URL = env("SHADOWTEST_URL")
+
+ALLOWED_HOSTS = env("ALLOWED_HOSTS").split(" ")
+
+CSRF_TRUSTED_ORIGINS = env("CSRF_TRUSTED_ORIGINS").split(" ")
+
+SITE_ID = 1
+
+APPS_DIR = BASE_DIR / "apps"
+
+DJANGO_APPS = [
+ "jazzmin",
+ "django.contrib.admin",
+ "django.contrib.auth",
+ "django.contrib.contenttypes",
+ "django.contrib.sessions",
+ "django.contrib.messages",
+ "django.contrib.staticfiles",
+]
+
+THIRD_PARTY_APPS = [
+ "storages",
+ "import_export",
+ "rangefilter",
+ "huey.contrib.djhuey",
+ "rest_framework",
+ "django_filters",
+]
+
+LOCAL_APPS = ["apps.proxylist"]
+
+INSTALLED_APPS = DJANGO_APPS + THIRD_PARTY_APPS + LOCAL_APPS
+
+MIDDLEWARE = [
+ "django.middleware.security.SecurityMiddleware",
+ "django.contrib.sessions.middleware.SessionMiddleware",
+ "django.middleware.locale.LocaleMiddleware",
+ "django.middleware.common.CommonMiddleware",
+ "django.middleware.csrf.CsrfViewMiddleware",
+ "django.contrib.auth.middleware.AuthenticationMiddleware",
+ "django.contrib.messages.middleware.MessageMiddleware",
+ "django.middleware.clickjacking.XFrameOptionsMiddleware",
+ "django_ratelimit.middleware.RatelimitMiddleware",
+]
+
+ROOT_URLCONF = "config.urls"
+
+TEMPLATES = [
+ {
+ "BACKEND": "django.template.backends.django.DjangoTemplates",
+ "DIRS": [BASE_DIR / "templates"],
+ "APP_DIRS": True,
+ "OPTIONS": {
+ "context_processors": [
+ "django.template.context_processors.debug",
+ "django.template.context_processors.request",
+ "django.contrib.auth.context_processors.auth",
+ "django.contrib.messages.context_processors.messages",
+ ],
+ },
+ },
+]
+
+WSGI_APPLICATION = "config.wsgi.application"
+
+DATABASES = {"default": env.db()}
+
+AUTH_PASSWORD_VALIDATORS = [
+ {
+ "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
+ },
+ {
+ "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
+ },
+ {
+ "NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",
+ },
+ {
+ "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",
+ },
+]
+
+LOGGING = {
+ "version": 1,
+ "disable_existing_loggers": False,
+ "filters": {
+ "require_debug_false": {
+ "()": "django.utils.log.RequireDebugFalse",
+ },
+ "require_debug_true": {
+ "()": "django.utils.log.RequireDebugTrue",
+ },
+ },
+ "formatters": {
+ "django.server": {
+ "()": "django.utils.log.ServerFormatter",
+ "format": "[%(server_time)s] %(message)s",
+ }
+ },
+ "handlers": {
+ "console": {
+ "level": "INFO",
+ "filters": ["require_debug_true"],
+ "class": "logging.StreamHandler",
+ },
+ # Custom handler which we will use with logger 'django'.
+ # We want errors/warnings to be logged when DEBUG=False
+ "console_on_not_debug": {
+ "level": "WARNING",
+ "filters": ["require_debug_false"],
+ "class": "logging.StreamHandler",
+ },
+ "django.server": {
+ "level": "INFO",
+ "class": "logging.StreamHandler",
+ "formatter": "django.server",
+ },
+ },
+ "loggers": {
+ "django": {
+ "handlers": ["console", "console_on_not_debug"],
+ "level": "INFO",
+ },
+ "django.server": {
+ "handlers": ["django.server"],
+ "level": "INFO",
+ "propagate": False,
+ },
+ },
+}
+
+LANGUAGE_CODE = "en-us"
+
+TIME_ZONE = "UTC"
+
+USE_I18N = True
+
+USE_L10N = True
+
+USE_TZ = True
+
+LANGUAGES = [
+ ("es", _("Spanish")),
+ ("en", _("English")),
+]
+
+LOCALE_PATHS = ("./locale",)
+
+STATIC_URL = "/static/"
+
+STATIC_ROOT = "./static_files/"
+
+DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
+
+HUEY = {
+ "huey_class": "huey.RedisHuey",
+ "name": "shadowmere",
+ "results": True,
+ "store_none": False,
+ "immediate": False,
+ "utc": True,
+ "blocking": True,
+ "connection": {
+ "host": env("REDIS_HOST", default="redis"),
+ "port": env("REDIS_PORT", default=6379),
+ "db": 0,
+ "connection_pool": None,
+ "read_timeout": 1,
+ "url": None,
+ },
+ "consumer": {
+ "workers": 4,
+ "worker_type": "process",
+ "initial_delay": 0.1,
+ "backoff": 1.15,
+ "max_delay": 10.0,
+ "scheduler_interval": 1,
+ "periodic": True,
+ "check_worker_health": True,
+ "health_check_interval": 1,
+ },
+}
+
+REST_FRAMEWORK = {
+ "DEFAULT_PAGINATION_CLASS": "apps.proxylist.pagination.ProxiesPagination",
+ "PAGE_SIZE": 10,
+}
+
+DATA_UPLOAD_MAX_NUMBER_FIELDS = 10000
+
+RATELIMIT_VIEW = "apps.proxylist.views.ratelimited_error"
+
+JAZZMIN_SETTINGS = {
+ "site_title": "Shadowmere Admin",
+ "site_header": "Shadowmere",
+ "site_brand": "Shadowmere",
+ "welcome_sign": "Welcome to Shadowmere Admin",
+}
diff --git a/app/shadowmere/config/settings/dev.py b/app/shadowmere/config/settings/dev.py
new file mode 100644
index 0000000..8ecc929
--- /dev/null
+++ b/app/shadowmere/config/settings/dev.py
@@ -0,0 +1,3 @@
+from .base import * # noqa
+
+RATELIMIT_ENABLE = False
diff --git a/app/shadowmere/config/settings/prod.py b/app/shadowmere/config/settings/prod.py
new file mode 100644
index 0000000..5e4b8ef
--- /dev/null
+++ b/app/shadowmere/config/settings/prod.py
@@ -0,0 +1,57 @@
+from .base import * # noqa
+
+THIRD_PARTY_APPS += "django_prometheus," # noqa
+
+MIDDLEWARE.insert( # noqa
+ 0,
+ "django_prometheus.middleware.PrometheusBeforeMiddleware",
+)
+
+MIDDLEWARE.append( # noqa
+ "django_prometheus.middleware.PrometheusAfterMiddleware",
+)
+
+RATELIMIT_ENABLE = True
+
+DEFAULT_FILE_STORAGE = "minio_storage.storage.MinioMediaStorage"
+
+STATICFILES_STORAGE = "minio_storage.storage.MinioStaticStorage"
+
+MINIO_STORAGE_ENDPOINT = env("MINIO_ENDPOINT") # noqa
+
+MINIO_STORAGE_ACCESS_KEY = env("MINIO_ACCESS_KEY") # noqa
+
+MINIO_STORAGE_SECRET_KEY = env("MINIO_SECRET_KEY") # noqa
+
+MINIO_STORAGE_USE_HTTPS = True
+
+MINIO_STORAGE_MEDIA_BUCKET_NAME = (
+ f"{env('MINIO_BUCKET')}-media" # noqa
+ if env("MINIO_BUCKET") != "" # noqa
+ else "shadowmere-media"
+)
+
+MINIO_STORAGE_AUTO_CREATE_MEDIA_BUCKET = True
+
+MINIO_STORAGE_STATIC_BUCKET_NAME = (
+ f"{env('MINIO_BUCKET')}-static" # noqa
+ if env("MINIO_BUCKET") != "" # noqa
+ else "shadowmere-static"
+)
+
+MINIO_STORAGE_AUTO_CREATE_STATIC_BUCKET = True
+
+PROMETHEUS_METRICS_EXPORT_PORT_RANGE = range(8002, 8008)
+
+if env("SENTRY_DSN") != "": # noqa
+ import sentry_sdk
+ from sentry_sdk.integrations.django import DjangoIntegration
+
+ sentry_sdk.init(
+ dsn=env("SENTRY_DSN"), # noqa
+ integrations=[
+ DjangoIntegration(),
+ ],
+ traces_sample_rate=0.01,
+ send_default_pii=True,
+ )
diff --git a/app/shadowmere/config/urls.py b/app/shadowmere/config/urls.py
new file mode 100644
index 0000000..38e5f91
--- /dev/null
+++ b/app/shadowmere/config/urls.py
@@ -0,0 +1,32 @@
+from apps.proxylist.views import (
+ Base64SubViewSet,
+ CountryCodeViewSet,
+ PortViewSet,
+ ProxyViewSet,
+ SubViewSet,
+ healthcheck,
+ json_proxy_file,
+ list_proxies,
+ qr_code,
+)
+from django.contrib import admin
+from django.urls import include, path
+from rest_framework import routers
+
+router = routers.DefaultRouter()
+router.register(r"proxies", ProxyViewSet)
+router.register(r"country-codes", CountryCodeViewSet, basename="country-codes")
+router.register(r"ports", PortViewSet, basename="ports")
+router.register(r"sub", SubViewSet, basename="sub")
+router.register(r"b64sub", Base64SubViewSet, basename="b64sub")
+
+urlpatterns = [
+ path("admin/", admin.site.urls),
+ path("", list_proxies),
+ path("/config", json_proxy_file),
+ path("/qr", qr_code),
+ path("health", healthcheck),
+ path("api-auth/", include("rest_framework.urls", namespace="rest_framework")),
+ path("api/", include(router.urls)),
+ path("", include("django_prometheus.urls")),
+]
diff --git a/app/shadowmere/config/wsgi.py b/app/shadowmere/config/wsgi.py
new file mode 100644
index 0000000..107261a
--- /dev/null
+++ b/app/shadowmere/config/wsgi.py
@@ -0,0 +1,16 @@
+"""
+WSGI config for shadowmere project.
+
+It exposes the WSGI callable as a module-level variable named ``application``.
+
+For more information on this file, see
+https://docs.djangoproject.com/en/3.2/howto/deployment/wsgi/
+"""
+
+import os
+
+from django.core.wsgi import get_wsgi_application
+
+os.environ.setdefault("DJANGO_SETTINGS_MODULE", "shadowmere.settings")
+
+application = get_wsgi_application()
From 04effc767cd5931df0a29798d8a251b9a0b1d932 Mon Sep 17 00:00:00 2001
From: "Ozkar L. Garcell"
Date: Wed, 5 Jun 2024 19:29:01 +0200
Subject: [PATCH 17/32] wip: project layout, locales
---
.../locale/es/LC_MESSAGES/django.po | 87 +++++++++++++++++++
1 file changed, 87 insertions(+)
create mode 100644 app/shadowmere/locale/es/LC_MESSAGES/django.po
diff --git a/app/shadowmere/locale/es/LC_MESSAGES/django.po b/app/shadowmere/locale/es/LC_MESSAGES/django.po
new file mode 100644
index 0000000..0c984bc
--- /dev/null
+++ b/app/shadowmere/locale/es/LC_MESSAGES/django.po
@@ -0,0 +1,87 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR , YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2022-04-12 17:20+0000\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME \n"
+"Language-Team: LANGUAGE \n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+#: shadowmere/settings.py:142
+msgid "Spanish"
+msgstr "EspaΓ±ol"
+
+#: shadowmere/settings.py:143
+msgid "English"
+msgstr "InglΓ©s"
+
+#: templates/index.html:49
+msgid "A list of Shadowsocks proxies"
+msgstr "Una lista de tΓΊneles Shadowsocks"
+
+#: templates/index.html:51
+msgid "Disclaimer:"
+msgstr "Aviso:"
+
+#: templates/index.html:51
+msgid ""
+"This website is only a list of tunnels collected all around internet. We do "
+"NOT provide or maintain any of these tunnels."
+msgstr ""
+"Este sitio web es sΓ³lo una lista de tΓΊneles recolectados en Internet. "
+"Nosotros no proveemos ni mantenemos estos tΓΊneles."
+
+#: templates/index.html:52
+msgid "Use them at your own risk."
+msgstr "Γselos bajo su propio riesgo"
+
+#: templates/index.html:57
+msgid "How do I use this?:"
+msgstr "ΒΏCΓ³mo uso esto?"
+
+#: templates/index.html:58
+msgid ""
+"Go give shadowsocks.org a quick "
+"look for information.\n"
+" Here is a list of clients for several\n"
+" platforms, but my favorite is Outline for any platform and\n"
+" shadowsocks for\n"
+" Android\n"
+" "
+msgstr ""
+"Ve a dar un vistazo a shadowsocks.org"
+"a> para obtener informaciΓ³n. AquΓ hay una lista de clientes para varias plataformas,"
+"pero mi favorito es Outline para "
+"cualquier plataforma y shadowsocks para Android "
+
+#: templates/index.html:64
+msgid "Online:"
+msgstr "Conectados: "
+
+#: templates/index.html:69
+msgid "Last check:"
+msgstr "Γltima prueba: "
+
+#: templates/index.html:135
+msgid "of"
+msgstr "de"
+
+#: templates/index.html:146
+msgid "No active proxies found"
+msgstr "No se han encontrado tΓΊneles activos"
From da98f6a7f3d91c04122f4af7ab73b0d8b4647abe Mon Sep 17 00:00:00 2001
From: "Ozkar L. Garcell"
Date: Wed, 5 Jun 2024 19:29:12 +0200
Subject: [PATCH 18/32] wip: project layout, templates
---
app/shadowmere/templates/index.html | 158 ++++++++++++++++++++++++++++
1 file changed, 158 insertions(+)
create mode 100644 app/shadowmere/templates/index.html
diff --git a/app/shadowmere/templates/index.html b/app/shadowmere/templates/index.html
new file mode 100644
index 0000000..04b0901
--- /dev/null
+++ b/app/shadowmere/templates/index.html
@@ -0,0 +1,158 @@
+{% load i18n %}
+
+
+
+
+
+
+
+ Shadowmere
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Shadowmere
+
+
{% translate "A list of Shadowsocks proxies" %}
+
+ {% translate "Disclaimer:" %} {% translate "This website is only a list of tunnels collected all around internet. We do NOT provide or maintain any of these tunnels." %}
+ {% translate "Use them at your own risk." %}
+
{% translate "How do I use this?:" %}
+ {% blocktranslate %}Go give shadowsocks.org a quick look for
+ information.
+ Here is a list of clients for several
+ platforms, but my favorite is Outline for any platform and
+ shadowsocks for
+ Android
+ {% endblocktranslate %}
+
{% translate "Online:" %} {{ proxy_list|length }} {% if location_country_code != "" %}
+
+ {% endif %}
+ {% if proxy_list|length > 0 %}
+
{% translate "Last check:" %} {{ latest_update }} UTC
+ {% endif %}
+
+
+
+ {% for country_code in country_codes %}
+ {% if country_code.location_country_code != "" %}
+
+
+
+ {% endif %}
+ {% endfor %}
+
+ {% if proxy_list %}
+
+ {% for proxy in page_obj %}
+
+
+
+
{% widthratio proxy.times_check_succeeded proxy.times_checked 100 %}%
+
+
+
{{ proxy.url }}#{{ proxy.location|urlencode }}
+
{{ proxy.ip_address }} ⚓{{ proxy.port }}
+
+
+
+
+
+
+
+
×
+
+
+
+
+
+ {% endfor %}
+
+
+
+
+ {% else %}
+
{% translate "No active proxies found" %}
+ {% endif %}
+
+
+Update cookies preferences
+
+
From 20f3e25e283180c1f0cceaffce491accfb734dc5 Mon Sep 17 00:00:00 2001
From: "Ozkar L. Garcell"
Date: Wed, 5 Jun 2024 19:29:27 +0200
Subject: [PATCH 19/32] feat/wip: project layout, entrypoint
---
app/shadowmere/__init__.py | 0
app/shadowmere/manage.py | 27 +++++++++++++++++++++++++++
2 files changed, 27 insertions(+)
create mode 100644 app/shadowmere/__init__.py
create mode 100755 app/shadowmere/manage.py
diff --git a/app/shadowmere/__init__.py b/app/shadowmere/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/app/shadowmere/manage.py b/app/shadowmere/manage.py
new file mode 100755
index 0000000..ae72c44
--- /dev/null
+++ b/app/shadowmere/manage.py
@@ -0,0 +1,27 @@
+#!/usr/bin/env python
+import os
+import sys
+from pathlib import Path
+
+
+def main():
+ if os.getenv("DEBUG", "NO").lower() in ("on", "true", "y", "yes"):
+ os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings.dev")
+ else:
+ os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings.prod")
+ try:
+ from django.core.management import execute_from_command_line
+ except ImportError as exc:
+ raise ImportError(
+ "Couldn't import Django. Are you sure it's installed and "
+ "available on your PYTHONPATH environment variable? Did you "
+ "forget to activate a virtual environment?"
+ ) from exc
+
+ current_path = Path(__file__).parent.resolve()
+ sys.path.append(str(current_path / "shadowmere"))
+ execute_from_command_line(sys.argv)
+
+
+if __name__ == "__main__":
+ main()
From d836e1d80392162177d0a398d47b76f112f3a5a8 Mon Sep 17 00:00:00 2001
From: "Ozkar L. Garcell"
Date: Wed, 5 Jun 2024 19:29:46 +0200
Subject: [PATCH 20/32] fix: removed unused scripts
---
docker/celery/beat/start | 7 -------
docker/celery/worker/start | 7 -------
2 files changed, 14 deletions(-)
delete mode 100644 docker/celery/beat/start
delete mode 100644 docker/celery/worker/start
diff --git a/docker/celery/beat/start b/docker/celery/beat/start
deleted file mode 100644
index be41c09..0000000
--- a/docker/celery/beat/start
+++ /dev/null
@@ -1,7 +0,0 @@
-#!/bin/bash
-
-set -o errexit
-set -o nounset
-
-rm -f './celerybeat.pid'
-celery -A shadowmere beat -l info
diff --git a/docker/celery/worker/start b/docker/celery/worker/start
deleted file mode 100644
index 35e1855..0000000
--- a/docker/celery/worker/start
+++ /dev/null
@@ -1,7 +0,0 @@
-#!/bin/bash
-
-set -o errexit
-set -o pipefail
-set -o nounset
-
-celery -A shadowmere worker -l info -E
From 6297293a30778a919030ded3561666c4be01911c Mon Sep 17 00:00:00 2001
From: "Ozkar L. Garcell"
Date: Wed, 5 Jun 2024 19:29:59 +0200
Subject: [PATCH 21/32] feat: docker scripts for dev
---
docker/dev/Dockerfile | 70 +++++++++++++++++++++++++++++++++++++++++++
docker/dev/entrypoint | 30 +++++++++++++++++++
docker/dev/start | 15 ++++++++++
3 files changed, 115 insertions(+)
create mode 100644 docker/dev/Dockerfile
create mode 100755 docker/dev/entrypoint
create mode 100755 docker/dev/start
diff --git a/docker/dev/Dockerfile b/docker/dev/Dockerfile
new file mode 100644
index 0000000..b9271d1
--- /dev/null
+++ b/docker/dev/Dockerfile
@@ -0,0 +1,70 @@
+FROM python:3.12-slim as builder
+ENV DEBIAN_FRONTEND=noninteractive \
+ LANG=C.UTF-8 \
+ LC_ALL=C.UTF-8 \
+ PYTHONFAULTHANDLER=1 \
+ PYTHONUNBUFFERED=1 \
+ PYTHONHASHSEED=random \
+ PIP_NO_CACHE_DIR=off \
+ PIP_DISABLE_PIP_VERSION_CHECK=on \
+ PIP_DEFAULT_TIMEOUT=100 \
+ POETRY_NO_INTERACTION=1 \
+ POETRY_CACHE_DIR=/tmp/poetry_cache \
+ POETRY_NO_INTERACTION=1 \
+ POETRY_VIRTUALENVS_IN_PROJECT=1 \
+ POETRY_VIRTUALENVS_CREATE=1 \
+ PROJECT_PATH="/shadowmere"
+
+# install poetry
+RUN pip install --upgrade poetry
+
+# copy poetry and project files
+WORKDIR $PROJECT_PATH
+COPY ../../poetry.lock pyproject.toml ./
+
+# install dependencies and project
+RUN poetry install --no-root --no-interaction --no-cache && rm -rf $POETRY_CACHE_DIR
+
+
+# run stage
+FROM python:3.12-slim
+
+# Creating user
+ARG USERNAME=shadowmere
+ARG USER_UID=1000
+ARG USER_GID=$USER_UID
+
+# Timezone
+ARG TZ=UTC
+ENV TZ ${TZ}
+RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
+
+# OS dependencies
+RUN groupadd --gid $USER_GID $USERNAME && \
+ useradd --uid $USER_UID --gid $USER_GID -m $USERNAME && \
+ apt-get update && \
+ apt-get install -y sudo && \
+ apt-get clean autoclean && \
+ apt-get autoremove --yes && \
+ rm -rf /var/lib/apt && \
+ rm -rf /var/lib/dpkg && \
+ rm -rf /var/cache && \
+ rm -rf /var/log && \
+ echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME && \
+ chmod 0440 /etc/sudoers.d/$USERNAME
+
+ENV VIRTUAL_ENV=/shadowmere/.venv
+ENV PATH="/shadowmere/.venv/bin:$PATH"
+
+COPY --from=builder ${VIRTUAL_ENV} ${VIRTUAL_ENV}
+
+# upload scripts
+COPY --chmod=755 ../../docker/dev/entrypoint /entrypoint
+RUN sed -i 's/\r//' /entrypoint
+
+COPY --chmod=755 ../../docker/dev/start /start
+RUN sed -i 's/\r//' /start
+
+USER $USERNAME
+
+WORKDIR $PROJECT_PATH
diff --git a/docker/dev/entrypoint b/docker/dev/entrypoint
new file mode 100755
index 0000000..89d4d8b
--- /dev/null
+++ b/docker/dev/entrypoint
@@ -0,0 +1,30 @@
+#!/bin/bash
+
+set -o errexit
+set -o pipefail
+cmd="$@"
+
+function postgres_ready(){
+python << END
+import sys
+import psycopg2
+import os
+
+try:
+ dbname = os.getenv('POSTGRES_DB')
+ user = os.getenv('POSTGRES_USER')
+ password = os.getenv('POSTGRES_PASSWORD')
+ conn = psycopg2.connect(dbname=dbname, user=user, password=password, host='db', port=5432)
+except psycopg2.OperationalError:
+ sys.exit(-1)
+sys.exit(0)
+END
+}
+
+until postgres_ready; do
+ >&2 echo "Postgres is unavailable - sleeping"
+ sleep 1
+done
+
+>&2 echo "Postgres is up - continuing..."
+exec $cmd
diff --git a/docker/dev/start b/docker/dev/start
new file mode 100755
index 0000000..35388e8
--- /dev/null
+++ b/docker/dev/start
@@ -0,0 +1,15 @@
+#!/bin/bash
+
+set -o errexit
+set -o pipefail
+set -o nounset
+set -o xtrace
+
+python manage.py migrate --no-input
+python manage.py initadmin
+if [ "${DEBUG}" == "True" ]; then
+ python manage.py runserver 0.0.0.0:8001
+else
+ python manage.py collectstatic --no-input
+ gunicorn shadowmere.wsgi:application --bind 0.0.0.0:8001 -k gevent -w 6 --capture-output
+fi
From d302f6440c243d30e025c9d589c56c987a22b21c Mon Sep 17 00:00:00 2001
From: "Ozkar L. Garcell"
Date: Wed, 5 Jun 2024 19:30:24 +0200
Subject: [PATCH 22/32] wip: prod dockerfile
---
docker/prod/Dockerfile | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docker/prod/Dockerfile b/docker/prod/Dockerfile
index 88f6e45..f35dbb5 100644
--- a/docker/prod/Dockerfile
+++ b/docker/prod/Dockerfile
@@ -68,6 +68,6 @@ COPY ./docker/celery/beat/start /start-celerybeat
RUN sed -i 's/\r//' /start-celerybeat
RUN chmod +x /start-celerybeat
-COPY . $PROJECT_PATH
+COPY ../.. $PROJECT_PATH
USER $PROJECT_USER
From 8f00c291a112ebdc159c2e7eef38845d5b150b11 Mon Sep 17 00:00:00 2001
From: "Ozkar L. Garcell"
Date: Wed, 5 Jun 2024 19:30:36 +0200
Subject: [PATCH 23/32] feat: compose recipe for dev env
---
docker-compose.dev.yml | 44 +++++++++++++++++++++++-------------------
1 file changed, 24 insertions(+), 20 deletions(-)
diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml
index 6fae01d..20fcc9f 100644
--- a/docker-compose.dev.yml
+++ b/docker-compose.dev.yml
@@ -1,4 +1,3 @@
-version: "3"
volumes:
shadowmere_data:
redis_data:
@@ -9,6 +8,8 @@ services:
restart: always
volumes:
- redis_data:/data
+ ports:
+ - "6379:6379"
db:
image: postgres:alpine
@@ -17,37 +18,40 @@ services:
- shadowmere_data:/var/lib/postgresql/data
env_file: .env
- shadowmere:
+ backend:
&shadowmere
build:
context: .
- image: guamulo/shadowmere
- restart: always
+ dockerfile: ./docker/dev/Dockerfile
+ image: guamulo/shadowmere_backend
+ volumes:
+ - ./app/shadowmere:/app/shadowmere
+ working_dir: /app/shadowmere
command: /start
+ entrypoint: /entrypoint
+ restart: always
env_file: .env
- depends_on:
- - db
ports:
- "8001:8001"
+ depends_on:
+ - db
- celery:
+ huey:
<<: *shadowmere
- image: guamulo/shadowmere-celeryworker
+ image: guamulo/shadowmere_huey
restart: always
- command: /wait_for_migration.sh /start-celeryworker
- env_file: .env
+ command: ["python", "manage.py", "run_huey"]
+ env_file:
+ - .env
+ ports: []
depends_on:
- redis
- ports: []
- volumes:
- - /var/run/docker.sock:/var/run/docker.sock
+ - db
- celery_beat:
- <<: *shadowmere
- image: guamulo/shadowmere-celerybeat
+ frontend:
+ image: guamulo/shadowmere-frontend-njs
restart: always
- command: /wait_for_migration.sh /start-celerybeat
- env_file: .env
- ports: []
+ ports:
+ - "8000:80"
depends_on:
- - redis
+ - backend
\ No newline at end of file
From ce89509943bf941bb03906207cf874ca210e350d Mon Sep 17 00:00:00 2001
From: "Ozkar L. Garcell"
Date: Wed, 5 Jun 2024 19:30:53 +0200
Subject: [PATCH 24/32] feat: poetry and project config
---
poetry.lock | 582 ++++++++++++++++++++++++++-----------------------
pyproject.toml | 19 +-
2 files changed, 322 insertions(+), 279 deletions(-)
diff --git a/poetry.lock b/poetry.lock
index 6c1dacd..ca508b8 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -1,4 +1,4 @@
-# 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.8.2 and should not be changed by hand.
[[package]]
name = "amqp"
@@ -73,49 +73,36 @@ tests = ["pytest"]
[[package]]
name = "asgiref"
-version = "3.7.2"
+version = "3.8.1"
description = "ASGI specs, helper code, and adapters"
optional = false
-python-versions = ">=3.7"
+python-versions = ">=3.8"
files = [
- {file = "asgiref-3.7.2-py3-none-any.whl", hash = "sha256:89b2ef2247e3b562a16eef663bc0e2e703ec6468e2fa8a5cd61cd449786d4f6e"},
- {file = "asgiref-3.7.2.tar.gz", hash = "sha256:9e0ce3aa93a819ba5b45120216b23878cf6e8525eb3848653452b4192b92afed"},
+ {file = "asgiref-3.8.1-py3-none-any.whl", hash = "sha256:3e1e3ecc849832fe52ccf2cb6686b7a55f82bb1d6aee72a58826471390335e47"},
+ {file = "asgiref-3.8.1.tar.gz", hash = "sha256:c343bd80a0bec947a9860adb4c432ffa7db769836c64238fc34bdc3fec84d590"},
]
-[package.dependencies]
-typing-extensions = {version = ">=4", markers = "python_version < \"3.11\""}
-
[package.extras]
tests = ["mypy (>=0.800)", "pytest", "pytest-asyncio"]
-[[package]]
-name = "async-timeout"
-version = "4.0.3"
-description = "Timeout context manager for asyncio programs"
-optional = false
-python-versions = ">=3.7"
-files = [
- {file = "async-timeout-4.0.3.tar.gz", hash = "sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f"},
- {file = "async_timeout-4.0.3-py3-none-any.whl", hash = "sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028"},
-]
-
[[package]]
name = "attrs"
-version = "23.1.0"
+version = "23.2.0"
description = "Classes Without Boilerplate"
optional = false
python-versions = ">=3.7"
files = [
- {file = "attrs-23.1.0-py3-none-any.whl", hash = "sha256:1f28b4522cdc2fb4256ac1a020c78acf9cba2c6b461ccd2c126f3aa8e8335d04"},
- {file = "attrs-23.1.0.tar.gz", hash = "sha256:6279836d581513a26f1bf235f9acd333bc9115683f14f7e8fae46c98fc50e015"},
+ {file = "attrs-23.2.0-py3-none-any.whl", hash = "sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1"},
+ {file = "attrs-23.2.0.tar.gz", hash = "sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30"},
]
[package.extras]
cov = ["attrs[tests]", "coverage[toml] (>=5.3)"]
-dev = ["attrs[docs,tests]", "pre-commit"]
+dev = ["attrs[tests]", "pre-commit"]
docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope-interface"]
tests = ["attrs[tests-no-zope]", "zope-interface"]
-tests-no-zope = ["cloudpickle", "hypothesis", "mypy (>=1.1.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"]
+tests-mypy = ["mypy (>=1.6)", "pytest-mypy-plugins"]
+tests-no-zope = ["attrs[tests-mypy]", "cloudpickle", "hypothesis", "pympler", "pytest (>=4.3.0)", "pytest-xdist[psutil]"]
[[package]]
name = "billiard"
@@ -130,22 +117,22 @@ files = [
[[package]]
name = "botocore"
-version = "1.33.11"
+version = "1.34.119"
description = "Low-level, data-driven core of boto 3."
optional = false
-python-versions = ">= 3.7"
+python-versions = ">=3.8"
files = [
- {file = "botocore-1.33.11-py3-none-any.whl", hash = "sha256:b46227eb3fa9cfdc8f5a83920ef347e67adea8095830ed265a3373b13b54421f"},
- {file = "botocore-1.33.11.tar.gz", hash = "sha256:b14b328f902d120de0a09eaa657a9a701c0ceeb711197c2f01ef0523f855086c"},
+ {file = "botocore-1.34.119-py3-none-any.whl", hash = "sha256:4bdf7926a1290b2650d62899ceba65073dd2693e61c35f5cdeb3a286a0aaa27b"},
+ {file = "botocore-1.34.119.tar.gz", hash = "sha256:b253f15b24b87b070e176af48e8ef146516090429d30a7d8b136a4c079b28008"},
]
[package.dependencies]
jmespath = ">=0.7.1,<2.0.0"
python-dateutil = ">=2.1,<3.0.0"
-urllib3 = {version = ">=1.25.4,<2.1", markers = "python_version >= \"3.10\""}
+urllib3 = {version = ">=1.25.4,<2.2.0 || >2.2.0,<3", markers = "python_version >= \"3.10\""}
[package.extras]
-crt = ["awscrt (==0.19.17)"]
+crt = ["awscrt (==0.20.9)"]
[[package]]
name = "cattrs"
@@ -160,8 +147,6 @@ files = [
[package.dependencies]
attrs = ">=23.1.0"
-exceptiongroup = {version = ">=1.1.1", markers = "python_version < \"3.11\""}
-typing-extensions = {version = ">=4.1.0,<4.6.3 || >4.6.3", markers = "python_version < \"3.11\""}
[package.extras]
bson = ["pymongo (>=4.4.0)"]
@@ -174,13 +159,13 @@ ujson = ["ujson (>=5.7.0)"]
[[package]]
name = "celery"
-version = "5.3.6"
+version = "5.4.0"
description = "Distributed Task Queue."
optional = false
python-versions = ">=3.8"
files = [
- {file = "celery-5.3.6-py3-none-any.whl", hash = "sha256:9da4ea0118d232ce97dff5ed4974587fb1c0ff5c10042eb15278487cdd27d1af"},
- {file = "celery-5.3.6.tar.gz", hash = "sha256:870cc71d737c0200c397290d730344cc991d13a057534353d124c9380267aab9"},
+ {file = "celery-5.4.0-py3-none-any.whl", hash = "sha256:369631eb580cf8c51a82721ec538684994f8277637edde2dfc0dacd73ed97f64"},
+ {file = "celery-5.4.0.tar.gz", hash = "sha256:504a19140e8d3029d5acad88330c541d4c3f64c789d85f94756762d8bca7e706"},
]
[package.dependencies]
@@ -196,7 +181,7 @@ vine = ">=5.1.0,<6.0"
[package.extras]
arangodb = ["pyArango (>=2.0.2)"]
-auth = ["cryptography (==41.0.5)"]
+auth = ["cryptography (==42.0.5)"]
azureblockblob = ["azure-storage-blob (>=12.15.0)"]
brotli = ["brotli (>=1.0.0)", "brotlipy (>=0.7.0)"]
cassandra = ["cassandra-driver (>=3.25.0,<4)"]
@@ -206,22 +191,23 @@ couchbase = ["couchbase (>=3.0.0)"]
couchdb = ["pycouchdb (==1.14.2)"]
django = ["Django (>=2.2.28)"]
dynamodb = ["boto3 (>=1.26.143)"]
-elasticsearch = ["elastic-transport (<=8.10.0)", "elasticsearch (<=8.11.0)"]
+elasticsearch = ["elastic-transport (<=8.13.0)", "elasticsearch (<=8.13.0)"]
eventlet = ["eventlet (>=0.32.0)"]
+gcs = ["google-cloud-storage (>=2.10.0)"]
gevent = ["gevent (>=1.5.0)"]
librabbitmq = ["librabbitmq (>=2.0.0)"]
memcache = ["pylibmc (==1.6.3)"]
mongodb = ["pymongo[srv] (>=4.0.2)"]
-msgpack = ["msgpack (==1.0.7)"]
-pymemcache = ["python-memcached (==1.59)"]
+msgpack = ["msgpack (==1.0.8)"]
+pymemcache = ["python-memcached (>=1.61)"]
pyro = ["pyro4 (==4.82)"]
-pytest = ["pytest-celery (==0.0.0)"]
+pytest = ["pytest-celery[all] (>=1.0.0)"]
redis = ["redis (>=4.5.2,!=4.5.5,<6.0.0)"]
s3 = ["boto3 (>=1.26.143)"]
slmq = ["softlayer-messaging (>=1.0.3)"]
solar = ["ephem (==4.1.5)"]
sqlalchemy = ["sqlalchemy (>=1.4.48,<2.1)"]
-sqs = ["boto3 (>=1.26.143)", "kombu[sqs] (>=5.3.0)", "pycurl (>=7.43.0.5)", "urllib3 (>=1.26.16)"]
+sqs = ["boto3 (>=1.26.143)", "kombu[sqs] (>=5.3.4)", "pycurl (>=7.43.0.5)", "urllib3 (>=1.26.16)"]
tblib = ["tblib (>=1.3.0)", "tblib (>=1.5.0)"]
yaml = ["PyYAML (>=3.10)"]
zookeeper = ["kazoo (>=1.3.1)"]
@@ -229,13 +215,13 @@ zstd = ["zstandard (==0.22.0)"]
[[package]]
name = "certifi"
-version = "2023.11.17"
+version = "2024.6.2"
description = "Python package for providing Mozilla's CA Bundle."
optional = false
python-versions = ">=3.6"
files = [
- {file = "certifi-2023.11.17-py3-none-any.whl", hash = "sha256:e036ab49d5b79556f99cfc2d9320b34cfbe5be05c5871b51de9329f0603b0474"},
- {file = "certifi-2023.11.17.tar.gz", hash = "sha256:9b469f3a900bf28dc19b8cfbf8019bf47f7fdd1a65a1d4ffb98fc14166beb4d1"},
+ {file = "certifi-2024.6.2-py3-none-any.whl", hash = "sha256:ddc6c8ce995e6987e7faf5e3f1b02b302836a0e5d98ece18392cb1a36c72ad56"},
+ {file = "certifi-2024.6.2.tar.gz", hash = "sha256:3cd43f1c6fa7dedc5899d69d3ad0398fd018ad1a17fba83ddaf78aa46c747516"},
]
[[package]]
@@ -417,13 +403,13 @@ colorama = {version = "*", markers = "platform_system == \"Windows\""}
[[package]]
name = "click-didyoumean"
-version = "0.3.0"
+version = "0.3.1"
description = "Enables git-like *did-you-mean* feature in click"
optional = false
-python-versions = ">=3.6.2,<4.0.0"
+python-versions = ">=3.6.2"
files = [
- {file = "click-didyoumean-0.3.0.tar.gz", hash = "sha256:f184f0d851d96b6d29297354ed981b7dd71df7ff500d82fa6d11f0856bee8035"},
- {file = "click_didyoumean-0.3.0-py3-none-any.whl", hash = "sha256:a0713dc7a1de3f06bc0df5a9567ad19ead2d3d5689b434768a6145bff77c0667"},
+ {file = "click_didyoumean-0.3.1-py3-none-any.whl", hash = "sha256:5c4bb6007cfea5f2fd6583a2fb6701a22a41eb98957e63d0fac41c10e7c3117c"},
+ {file = "click_didyoumean-0.3.1.tar.gz", hash = "sha256:4f82fdff0dbe64ef8ab2279bd6aa3f6a99c3b28c05aa09cbfc07c9d7fbb5a463"},
]
[package.dependencies]
@@ -502,17 +488,17 @@ dev = ["attribution (==1.6.2)", "black (==23.3.0)", "flit (==3.8.0)", "mypy (==1
[[package]]
name = "django"
-version = "5.0"
+version = "5.0.6"
description = "A high-level Python web framework that encourages rapid development and clean, pragmatic design."
optional = false
python-versions = ">=3.10"
files = [
- {file = "Django-5.0-py3-none-any.whl", hash = "sha256:3a9fd52b8dbeae335ddf4a9dfa6c6a0853a1122f1fb071a8d5eca979f73a05c8"},
- {file = "Django-5.0.tar.gz", hash = "sha256:7d29e14dfbc19cb6a95a4bd669edbde11f5d4c6a71fdaa42c2d40b6846e807f7"},
+ {file = "Django-5.0.6-py3-none-any.whl", hash = "sha256:8363ac062bb4ef7c3f12d078f6fa5d154031d129a15170a1066412af49d30905"},
+ {file = "Django-5.0.6.tar.gz", hash = "sha256:ff1b61005004e476e0aeea47c7f79b85864c70124030e95146315396f1e7951f"},
]
[package.dependencies]
-asgiref = ">=3.7.0"
+asgiref = ">=3.7.0,<4"
sqlparse = ">=0.3.1"
tzdata = {version = "*", markers = "sys_platform == \"win32\""}
@@ -522,13 +508,13 @@ bcrypt = ["bcrypt"]
[[package]]
name = "django-admin-rangefilter"
-version = "0.12.0"
+version = "0.12.5"
description = "django-admin-rangefilter app, add the filter by a custom date range on the admin UI."
optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
+python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7"
files = [
- {file = "django-admin-rangefilter-0.12.0.tar.gz", hash = "sha256:56035f4190d35aad4e699f8fd81306f964642edc96e15ec2a532a1598a466615"},
- {file = "django_admin_rangefilter-0.12.0-py2.py3-none-any.whl", hash = "sha256:4fd7211271c70c51469fc39b182b70f1199ab9ce0b16264654a2eec96751d686"},
+ {file = "django_admin_rangefilter-0.12.5-py2.py3-none-any.whl", hash = "sha256:c2be9ca82115cadb5b5ea04b20bbe96a8aa6935b8921972cd797c2893d272c5d"},
+ {file = "django_admin_rangefilter-0.12.5.tar.gz", hash = "sha256:57970e7714f14f2a9b14619143b3695f6c727fa8fad50352ecf4286ec77a1d25"},
]
[[package]]
@@ -563,13 +549,13 @@ Django = ">=3.2"
[[package]]
name = "django-import-export"
-version = "3.3.3"
+version = "3.3.9"
description = "Django application and library for importing and exporting data with included admin integration."
optional = false
python-versions = ">=3.8"
files = [
- {file = "django-import-export-3.3.3.tar.gz", hash = "sha256:2c1b16e1cf2ea5f62a165d8867e7c6dcff25673ab7201fd18aaf67c9ee90367e"},
- {file = "django_import_export-3.3.3-py3-none-any.whl", hash = "sha256:78973202e93897326ab0411d64eaf89b72779fcb21ee9e5f64f3fb96571a5978"},
+ {file = "django_import_export-3.3.9-py3-none-any.whl", hash = "sha256:dd6cabc08ed6d1bd37a392e7fb542bd7d196b615c800168f5c69f0f55f49b103"},
+ {file = "django_import_export-3.3.9.tar.gz", hash = "sha256:16797965e93a8001fe812c61e3b71fb858c57c1bd16da195fe276d6de685348e"},
]
[package.dependencies]
@@ -579,17 +565,17 @@ tablib = {version = "3.5.0", extras = ["html", "ods", "xls", "xlsx", "yaml"]}
[[package]]
name = "django-jazzmin"
-version = "2.6.0"
+version = "2.6.2"
description = "Drop-in theme for django admin, that utilises AdminLTE 3 & Bootstrap 4 to make yo' admin look jazzy"
optional = false
-python-versions = ">=3.6.2"
+python-versions = ">=3.7"
files = [
- {file = "django_jazzmin-2.6.0-py3-none-any.whl", hash = "sha256:fb554c2d564649c65243b13385121fdbdda58521f49544f9d7cb9c414a4908d4"},
- {file = "django_jazzmin-2.6.0.tar.gz", hash = "sha256:5bb07055cf19183030724f976904fd8b6337559727959340a43832fab0531812"},
+ {file = "django_jazzmin-2.6.2-py3-none-any.whl", hash = "sha256:f7eb509b8a2e92260c2e836dc856fc9ca8888e572094201f9021d7b620bb96b2"},
+ {file = "django_jazzmin-2.6.2.tar.gz", hash = "sha256:2bfc33c4e6d59ee647930402d372692ae3514ea45940040eb7f50b481f6ef53b"},
]
[package.dependencies]
-django = ">=2.2"
+django = ">=3"
[[package]]
name = "django-minio-storage"
@@ -620,15 +606,26 @@ files = [
[package.dependencies]
prometheus-client = ">=0.7"
+[[package]]
+name = "django-ratelimit"
+version = "4.1.0"
+description = "Cache-based rate-limiting for Django."
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "django-ratelimit-4.1.0.tar.gz", hash = "sha256:555943b283045b917ad59f196829530d63be2a39adb72788d985b90c81ba808b"},
+ {file = "django_ratelimit-4.1.0-py2.py3-none-any.whl", hash = "sha256:d047a31cf94d83ef1465d7543ca66c6fc16695559b5f8d814d1b51df15110b92"},
+]
+
[[package]]
name = "django-storages"
-version = "1.14.2"
+version = "1.14.3"
description = "Support for many storage backends in Django"
optional = false
python-versions = ">=3.7"
files = [
- {file = "django-storages-1.14.2.tar.gz", hash = "sha256:51b36af28cc5813b98d5f3dfe7459af638d84428c8df4a03990c7d74d1bea4e5"},
- {file = "django_storages-1.14.2-py3-none-any.whl", hash = "sha256:1db759346b52ada6c2efd9f23d8241ecf518813eb31db9e2589207174f58f6ad"},
+ {file = "django-storages-1.14.3.tar.gz", hash = "sha256:95a12836cd998d4c7a4512347322331c662d9114c4344f932f5e9c0fce000608"},
+ {file = "django_storages-1.14.3-py3-none-any.whl", hash = "sha256:31f263389e95ce3a1b902fb5f739a7ed32895f7d8b80179fe7453ecc0dfe102e"},
]
[package.dependencies]
@@ -645,18 +642,17 @@ sftp = ["paramiko (>=1.15)"]
[[package]]
name = "djangorestframework"
-version = "3.14.0"
+version = "3.15.1"
description = "Web APIs for Django, made easy."
optional = false
python-versions = ">=3.6"
files = [
- {file = "djangorestframework-3.14.0-py3-none-any.whl", hash = "sha256:eb63f58c9f218e1a7d064d17a70751f528ed4e1d35547fdade9aaf4cd103fd08"},
- {file = "djangorestframework-3.14.0.tar.gz", hash = "sha256:579a333e6256b09489cbe0a067e66abe55c6595d8926be6b99423786334350c8"},
+ {file = "djangorestframework-3.15.1-py3-none-any.whl", hash = "sha256:3ccc0475bce968608cf30d07fb17d8e52d1d7fc8bfe779c905463200750cbca6"},
+ {file = "djangorestframework-3.15.1.tar.gz", hash = "sha256:f88fad74183dfc7144b2756d0d2ac716ea5b4c7c9840995ac3bfd8ec034333c1"},
]
[package.dependencies]
django = ">=3.0"
-pytz = "*"
[[package]]
name = "emoji-country-flag"
@@ -683,20 +679,6 @@ files = [
{file = "et_xmlfile-1.1.0.tar.gz", hash = "sha256:8eb9e2bc2f8c97e37a2dc85a09ecdcdec9d8a396530a6d5a33b30b9a92da0c5c"},
]
-[[package]]
-name = "exceptiongroup"
-version = "1.2.0"
-description = "Backport of PEP 654 (exception groups)"
-optional = false
-python-versions = ">=3.7"
-files = [
- {file = "exceptiongroup-1.2.0-py3-none-any.whl", hash = "sha256:4bfd3996ac73b41e9b9628b04e079f193850720ea5945fc96a08633c66912f14"},
- {file = "exceptiongroup-1.2.0.tar.gz", hash = "sha256:91f5c769735f051a4290d52edd0858999b57e5876e9f85937691bd4c9fa3ed68"},
-]
-
-[package.extras]
-test = ["pytest (>=6)"]
-
[[package]]
name = "gunicorn"
version = "21.2.0"
@@ -728,15 +710,43 @@ files = [
{file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"},
]
+[[package]]
+name = "huey"
+version = "2.5.0"
+description = "huey, a little task queue"
+optional = false
+python-versions = "*"
+files = [
+ {file = "huey-2.5.0.tar.gz", hash = "sha256:2ffb52fb5c46a1b0d53c79d59df3622312b27e2ab68d81a580985a8ea4ca3480"},
+]
+
+[package.extras]
+backends = ["redis (>=3.0.0)"]
+redis = ["redis (>=3.0.0)"]
+
+[[package]]
+name = "humanfriendly"
+version = "10.0"
+description = "Human friendly output for text interfaces using Python"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
+files = [
+ {file = "humanfriendly-10.0-py2.py3-none-any.whl", hash = "sha256:1697e1a8a8f550fd43c2865cd84542fc175a61dcb779b6fee18cf6b6ccba1477"},
+ {file = "humanfriendly-10.0.tar.gz", hash = "sha256:6b0b831ce8f15f7300721aa49829fc4e83921a9a301cc7f606be6686a2288ddc"},
+]
+
+[package.dependencies]
+pyreadline3 = {version = "*", markers = "sys_platform == \"win32\" and python_version >= \"3.8\""}
+
[[package]]
name = "idna"
-version = "3.6"
+version = "3.7"
description = "Internationalized Domain Names in Applications (IDNA)"
optional = false
python-versions = ">=3.5"
files = [
- {file = "idna-3.6-py3-none-any.whl", hash = "sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f"},
- {file = "idna-3.6.tar.gz", hash = "sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca"},
+ {file = "idna-3.7-py3-none-any.whl", hash = "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0"},
+ {file = "idna-3.7.tar.gz", hash = "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc"},
]
[[package]]
@@ -752,13 +762,13 @@ files = [
[[package]]
name = "kombu"
-version = "5.3.4"
+version = "5.3.7"
description = "Messaging library for Python."
optional = false
python-versions = ">=3.8"
files = [
- {file = "kombu-5.3.4-py3-none-any.whl", hash = "sha256:63bb093fc9bb80cfb3a0972336a5cec1fa7ac5f9ef7e8237c6bf8dda9469313e"},
- {file = "kombu-5.3.4.tar.gz", hash = "sha256:0bb2e278644d11dea6272c17974a3dbb9688a949f3bb60aeb5b791329c44fadc"},
+ {file = "kombu-5.3.7-py3-none-any.whl", hash = "sha256:5634c511926309c7f9789f1433e9ed402616b56836ef9878f01bd59267b4c7a9"},
+ {file = "kombu-5.3.7.tar.gz", hash = "sha256:011c4cd9a355c14a1de8d35d257314a1d2456d52b7140388561acac3cf1a97bf"},
]
[package.dependencies]
@@ -775,7 +785,7 @@ mongodb = ["pymongo (>=4.1.1)"]
msgpack = ["msgpack"]
pyro = ["pyro4"]
qpid = ["qpid-python (>=0.26)", "qpid-tools (>=0.26)"]
-redis = ["redis (>=4.5.2,!=4.5.5,<6.0.0)"]
+redis = ["redis (>=4.5.2,!=4.5.5,!=5.0.2)"]
slmq = ["softlayer-messaging (>=1.0.3)"]
sqlalchemy = ["sqlalchemy (>=1.4.48,<2.1)"]
sqs = ["boto3 (>=1.26.143)", "pycurl (>=7.43.0.5)", "urllib3 (>=1.26.16)"]
@@ -784,18 +794,18 @@ zookeeper = ["kazoo (>=2.8.0)"]
[[package]]
name = "lsprotocol"
-version = "2023.0.0"
+version = "2023.0.1"
description = "Python implementation of the Language Server Protocol."
optional = false
python-versions = ">=3.7"
files = [
- {file = "lsprotocol-2023.0.0-py3-none-any.whl", hash = "sha256:e85fc87ee26c816adca9eb497bb3db1a7c79c477a11563626e712eaccf926a05"},
- {file = "lsprotocol-2023.0.0.tar.gz", hash = "sha256:c9d92e12a3f4ed9317d3068226592860aab5357d93cf5b2451dc244eee8f35f2"},
+ {file = "lsprotocol-2023.0.1-py3-none-any.whl", hash = "sha256:c75223c9e4af2f24272b14c6375787438279369236cd568f596d4951052a60f2"},
+ {file = "lsprotocol-2023.0.1.tar.gz", hash = "sha256:cc5c15130d2403c18b734304339e51242d3018a05c4f7d0f198ad6e0cd21861d"},
]
[package.dependencies]
attrs = ">=21.3.0"
-cattrs = "*"
+cattrs = "!=23.2.1"
[[package]]
name = "markuppy"
@@ -809,19 +819,20 @@ files = [
[[package]]
name = "minio"
-version = "7.2.0"
+version = "7.2.7"
description = "MinIO Python SDK for Amazon S3 Compatible Cloud Storage"
optional = false
python-versions = "*"
files = [
- {file = "minio-7.2.0-py3-none-any.whl", hash = "sha256:10656272c16156fa08436ce2b27e25e4134ef5142a8c259513ee26fb514531a6"},
- {file = "minio-7.2.0.tar.gz", hash = "sha256:4b015b018d10c1505f7c3e724fa7c2267760ac7bee6463a624cbf22cd272877b"},
+ {file = "minio-7.2.7-py3-none-any.whl", hash = "sha256:59d1f255d852fe7104018db75b3bebbd987e538690e680f7c5de835e422de837"},
+ {file = "minio-7.2.7.tar.gz", hash = "sha256:473d5d53d79f340f3cd632054d0c82d2f93177ce1af2eac34a235bea55708d98"},
]
[package.dependencies]
argon2-cffi = "*"
certifi = "*"
pycryptodome = "*"
+typing-extensions = "*"
urllib3 = "*"
[[package]]
@@ -839,13 +850,13 @@ defusedxml = "*"
[[package]]
name = "openpyxl"
-version = "3.1.2"
+version = "3.1.3"
description = "A Python library to read/write Excel 2010 xlsx/xlsm files"
optional = false
python-versions = ">=3.6"
files = [
- {file = "openpyxl-3.1.2-py2.py3-none-any.whl", hash = "sha256:f91456ead12ab3c6c2e9491cf33ba6d08357d802192379bb482f1033ade496f5"},
- {file = "openpyxl-3.1.2.tar.gz", hash = "sha256:a6f5977418eff3b2d5500d54d9db50c8277a368436f4e4f8ddb1be3422870184"},
+ {file = "openpyxl-3.1.3-py2.py3-none-any.whl", hash = "sha256:25071b558db709de9e8782c3d3e058af3b23ffb2fc6f40c8f0c45a154eced2c3"},
+ {file = "openpyxl-3.1.3.tar.gz", hash = "sha256:8dd482e5350125b2388070bb2477927be2e8ebc27df61178709bc8c8751da2f9"},
]
[package.dependencies]
@@ -853,91 +864,110 @@ et-xmlfile = "*"
[[package]]
name = "packaging"
-version = "23.2"
+version = "24.0"
description = "Core utilities for Python packages"
optional = false
python-versions = ">=3.7"
files = [
- {file = "packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7"},
- {file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"},
+ {file = "packaging-24.0-py3-none-any.whl", hash = "sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5"},
+ {file = "packaging-24.0.tar.gz", hash = "sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9"},
]
[[package]]
name = "pillow"
-version = "10.1.0"
+version = "10.3.0"
description = "Python Imaging Library (Fork)"
optional = false
python-versions = ">=3.8"
files = [
- {file = "Pillow-10.1.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:1ab05f3db77e98f93964697c8efc49c7954b08dd61cff526b7f2531a22410106"},
- {file = "Pillow-10.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6932a7652464746fcb484f7fc3618e6503d2066d853f68a4bd97193a3996e273"},
- {file = "Pillow-10.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5f63b5a68daedc54c7c3464508d8c12075e56dcfbd42f8c1bf40169061ae666"},
- {file = "Pillow-10.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0949b55eb607898e28eaccb525ab104b2d86542a85c74baf3a6dc24002edec2"},
- {file = "Pillow-10.1.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:ae88931f93214777c7a3aa0a8f92a683f83ecde27f65a45f95f22d289a69e593"},
- {file = "Pillow-10.1.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:b0eb01ca85b2361b09480784a7931fc648ed8b7836f01fb9241141b968feb1db"},
- {file = "Pillow-10.1.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d27b5997bdd2eb9fb199982bb7eb6164db0426904020dc38c10203187ae2ff2f"},
- {file = "Pillow-10.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7df5608bc38bd37ef585ae9c38c9cd46d7c81498f086915b0f97255ea60c2818"},
- {file = "Pillow-10.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:41f67248d92a5e0a2076d3517d8d4b1e41a97e2df10eb8f93106c89107f38b57"},
- {file = "Pillow-10.1.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:1fb29c07478e6c06a46b867e43b0bcdb241b44cc52be9bc25ce5944eed4648e7"},
- {file = "Pillow-10.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2cdc65a46e74514ce742c2013cd4a2d12e8553e3a2563c64879f7c7e4d28bce7"},
- {file = "Pillow-10.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50d08cd0a2ecd2a8657bd3d82c71efd5a58edb04d9308185d66c3a5a5bed9610"},
- {file = "Pillow-10.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:062a1610e3bc258bff2328ec43f34244fcec972ee0717200cb1425214fe5b839"},
- {file = "Pillow-10.1.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:61f1a9d247317fa08a308daaa8ee7b3f760ab1809ca2da14ecc88ae4257d6172"},
- {file = "Pillow-10.1.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:a646e48de237d860c36e0db37ecaecaa3619e6f3e9d5319e527ccbc8151df061"},
- {file = "Pillow-10.1.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:47e5bf85b80abc03be7455c95b6d6e4896a62f6541c1f2ce77a7d2bb832af262"},
- {file = "Pillow-10.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:a92386125e9ee90381c3369f57a2a50fa9e6aa8b1cf1d9c4b200d41a7dd8e992"},
- {file = "Pillow-10.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:0f7c276c05a9767e877a0b4c5050c8bee6a6d960d7f0c11ebda6b99746068c2a"},
- {file = "Pillow-10.1.0-cp312-cp312-macosx_10_10_x86_64.whl", hash = "sha256:a89b8312d51715b510a4fe9fc13686283f376cfd5abca8cd1c65e4c76e21081b"},
- {file = "Pillow-10.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:00f438bb841382b15d7deb9a05cc946ee0f2c352653c7aa659e75e592f6fa17d"},
- {file = "Pillow-10.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3d929a19f5469b3f4df33a3df2983db070ebb2088a1e145e18facbc28cae5b27"},
- {file = "Pillow-10.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9a92109192b360634a4489c0c756364c0c3a2992906752165ecb50544c251312"},
- {file = "Pillow-10.1.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:0248f86b3ea061e67817c47ecbe82c23f9dd5d5226200eb9090b3873d3ca32de"},
- {file = "Pillow-10.1.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:9882a7451c680c12f232a422730f986a1fcd808da0fd428f08b671237237d651"},
- {file = "Pillow-10.1.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:1c3ac5423c8c1da5928aa12c6e258921956757d976405e9467c5f39d1d577a4b"},
- {file = "Pillow-10.1.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:806abdd8249ba3953c33742506fe414880bad78ac25cc9a9b1c6ae97bedd573f"},
- {file = "Pillow-10.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:eaed6977fa73408b7b8a24e8b14e59e1668cfc0f4c40193ea7ced8e210adf996"},
- {file = "Pillow-10.1.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:fe1e26e1ffc38be097f0ba1d0d07fcade2bcfd1d023cda5b29935ae8052bd793"},
- {file = "Pillow-10.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7a7e3daa202beb61821c06d2517428e8e7c1aab08943e92ec9e5755c2fc9ba5e"},
- {file = "Pillow-10.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:24fadc71218ad2b8ffe437b54876c9382b4a29e030a05a9879f615091f42ffc2"},
- {file = "Pillow-10.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa1d323703cfdac2036af05191b969b910d8f115cf53093125e4058f62012c9a"},
- {file = "Pillow-10.1.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:912e3812a1dbbc834da2b32299b124b5ddcb664ed354916fd1ed6f193f0e2d01"},
- {file = "Pillow-10.1.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:7dbaa3c7de82ef37e7708521be41db5565004258ca76945ad74a8e998c30af8d"},
- {file = "Pillow-10.1.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:9d7bc666bd8c5a4225e7ac71f2f9d12466ec555e89092728ea0f5c0c2422ea80"},
- {file = "Pillow-10.1.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:baada14941c83079bf84c037e2d8b7506ce201e92e3d2fa0d1303507a8538212"},
- {file = "Pillow-10.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:2ef6721c97894a7aa77723740a09547197533146fba8355e86d6d9a4a1056b14"},
- {file = "Pillow-10.1.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:0a026c188be3b443916179f5d04548092e253beb0c3e2ee0a4e2cdad72f66099"},
- {file = "Pillow-10.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:04f6f6149f266a100374ca3cc368b67fb27c4af9f1cc8cb6306d849dcdf12616"},
- {file = "Pillow-10.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bb40c011447712d2e19cc261c82655f75f32cb724788df315ed992a4d65696bb"},
- {file = "Pillow-10.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1a8413794b4ad9719346cd9306118450b7b00d9a15846451549314a58ac42219"},
- {file = "Pillow-10.1.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:c9aeea7b63edb7884b031a35305629a7593272b54f429a9869a4f63a1bf04c34"},
- {file = "Pillow-10.1.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:b4005fee46ed9be0b8fb42be0c20e79411533d1fd58edabebc0dd24626882cfd"},
- {file = "Pillow-10.1.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:4d0152565c6aa6ebbfb1e5d8624140a440f2b99bf7afaafbdbf6430426497f28"},
- {file = "Pillow-10.1.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d921bc90b1defa55c9917ca6b6b71430e4286fc9e44c55ead78ca1a9f9eba5f2"},
- {file = "Pillow-10.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:cfe96560c6ce2f4c07d6647af2d0f3c54cc33289894ebd88cfbb3bcd5391e256"},
- {file = "Pillow-10.1.0-pp310-pypy310_pp73-macosx_10_10_x86_64.whl", hash = "sha256:937bdc5a7f5343d1c97dc98149a0be7eb9704e937fe3dc7140e229ae4fc572a7"},
- {file = "Pillow-10.1.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b1c25762197144e211efb5f4e8ad656f36c8d214d390585d1d21281f46d556ba"},
- {file = "Pillow-10.1.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:afc8eef765d948543a4775f00b7b8c079b3321d6b675dde0d02afa2ee23000b4"},
- {file = "Pillow-10.1.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:883f216eac8712b83a63f41b76ddfb7b2afab1b74abbb413c5df6680f071a6b9"},
- {file = "Pillow-10.1.0-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:b920e4d028f6442bea9a75b7491c063f0b9a3972520731ed26c83e254302eb1e"},
- {file = "Pillow-10.1.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1c41d960babf951e01a49c9746f92c5a7e0d939d1652d7ba30f6b3090f27e412"},
- {file = "Pillow-10.1.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:1fafabe50a6977ac70dfe829b2d5735fd54e190ab55259ec8aea4aaea412fa0b"},
- {file = "Pillow-10.1.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:3b834f4b16173e5b92ab6566f0473bfb09f939ba14b23b8da1f54fa63e4b623f"},
- {file = "Pillow-10.1.0.tar.gz", hash = "sha256:e6bf8de6c36ed96c86ea3b6e1d5273c53f46ef518a062464cd7ef5dd2cf92e38"},
+ {file = "pillow-10.3.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:90b9e29824800e90c84e4022dd5cc16eb2d9605ee13f05d47641eb183cd73d45"},
+ {file = "pillow-10.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a2c405445c79c3f5a124573a051062300936b0281fee57637e706453e452746c"},
+ {file = "pillow-10.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:78618cdbccaa74d3f88d0ad6cb8ac3007f1a6fa5c6f19af64b55ca170bfa1edf"},
+ {file = "pillow-10.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:261ddb7ca91fcf71757979534fb4c128448b5b4c55cb6152d280312062f69599"},
+ {file = "pillow-10.3.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:ce49c67f4ea0609933d01c0731b34b8695a7a748d6c8d186f95e7d085d2fe475"},
+ {file = "pillow-10.3.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:b14f16f94cbc61215115b9b1236f9c18403c15dd3c52cf629072afa9d54c1cbf"},
+ {file = "pillow-10.3.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d33891be6df59d93df4d846640f0e46f1a807339f09e79a8040bc887bdcd7ed3"},
+ {file = "pillow-10.3.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b50811d664d392f02f7761621303eba9d1b056fb1868c8cdf4231279645c25f5"},
+ {file = "pillow-10.3.0-cp310-cp310-win32.whl", hash = "sha256:ca2870d5d10d8726a27396d3ca4cf7976cec0f3cb706debe88e3a5bd4610f7d2"},
+ {file = "pillow-10.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:f0d0591a0aeaefdaf9a5e545e7485f89910c977087e7de2b6c388aec32011e9f"},
+ {file = "pillow-10.3.0-cp310-cp310-win_arm64.whl", hash = "sha256:ccce24b7ad89adb5a1e34a6ba96ac2530046763912806ad4c247356a8f33a67b"},
+ {file = "pillow-10.3.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:5f77cf66e96ae734717d341c145c5949c63180842a545c47a0ce7ae52ca83795"},
+ {file = "pillow-10.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e4b878386c4bf293578b48fc570b84ecfe477d3b77ba39a6e87150af77f40c57"},
+ {file = "pillow-10.3.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fdcbb4068117dfd9ce0138d068ac512843c52295ed996ae6dd1faf537b6dbc27"},
+ {file = "pillow-10.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9797a6c8fe16f25749b371c02e2ade0efb51155e767a971c61734b1bf6293994"},
+ {file = "pillow-10.3.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:9e91179a242bbc99be65e139e30690e081fe6cb91a8e77faf4c409653de39451"},
+ {file = "pillow-10.3.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:1b87bd9d81d179bd8ab871603bd80d8645729939f90b71e62914e816a76fc6bd"},
+ {file = "pillow-10.3.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:81d09caa7b27ef4e61cb7d8fbf1714f5aec1c6b6c5270ee53504981e6e9121ad"},
+ {file = "pillow-10.3.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:048ad577748b9fa4a99a0548c64f2cb8d672d5bf2e643a739ac8faff1164238c"},
+ {file = "pillow-10.3.0-cp311-cp311-win32.whl", hash = "sha256:7161ec49ef0800947dc5570f86568a7bb36fa97dd09e9827dc02b718c5643f09"},
+ {file = "pillow-10.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:8eb0908e954d093b02a543dc963984d6e99ad2b5e36503d8a0aaf040505f747d"},
+ {file = "pillow-10.3.0-cp311-cp311-win_arm64.whl", hash = "sha256:4e6f7d1c414191c1199f8996d3f2282b9ebea0945693fb67392c75a3a320941f"},
+ {file = "pillow-10.3.0-cp312-cp312-macosx_10_10_x86_64.whl", hash = "sha256:e46f38133e5a060d46bd630faa4d9fa0202377495df1f068a8299fd78c84de84"},
+ {file = "pillow-10.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:50b8eae8f7334ec826d6eeffaeeb00e36b5e24aa0b9df322c247539714c6df19"},
+ {file = "pillow-10.3.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9d3bea1c75f8c53ee4d505c3e67d8c158ad4df0d83170605b50b64025917f338"},
+ {file = "pillow-10.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:19aeb96d43902f0a783946a0a87dbdad5c84c936025b8419da0a0cd7724356b1"},
+ {file = "pillow-10.3.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:74d28c17412d9caa1066f7a31df8403ec23d5268ba46cd0ad2c50fb82ae40462"},
+ {file = "pillow-10.3.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:ff61bfd9253c3915e6d41c651d5f962da23eda633cf02262990094a18a55371a"},
+ {file = "pillow-10.3.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d886f5d353333b4771d21267c7ecc75b710f1a73d72d03ca06df49b09015a9ef"},
+ {file = "pillow-10.3.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4b5ec25d8b17217d635f8935dbc1b9aa5907962fae29dff220f2659487891cd3"},
+ {file = "pillow-10.3.0-cp312-cp312-win32.whl", hash = "sha256:51243f1ed5161b9945011a7360e997729776f6e5d7005ba0c6879267d4c5139d"},
+ {file = "pillow-10.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:412444afb8c4c7a6cc11a47dade32982439925537e483be7c0ae0cf96c4f6a0b"},
+ {file = "pillow-10.3.0-cp312-cp312-win_arm64.whl", hash = "sha256:798232c92e7665fe82ac085f9d8e8ca98826f8e27859d9a96b41d519ecd2e49a"},
+ {file = "pillow-10.3.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:4eaa22f0d22b1a7e93ff0a596d57fdede2e550aecffb5a1ef1106aaece48e96b"},
+ {file = "pillow-10.3.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:cd5e14fbf22a87321b24c88669aad3a51ec052eb145315b3da3b7e3cc105b9a2"},
+ {file = "pillow-10.3.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1530e8f3a4b965eb6a7785cf17a426c779333eb62c9a7d1bbcf3ffd5bf77a4aa"},
+ {file = "pillow-10.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d512aafa1d32efa014fa041d38868fda85028e3f930a96f85d49c7d8ddc0383"},
+ {file = "pillow-10.3.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:339894035d0ede518b16073bdc2feef4c991ee991a29774b33e515f1d308e08d"},
+ {file = "pillow-10.3.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:aa7e402ce11f0885305bfb6afb3434b3cd8f53b563ac065452d9d5654c7b86fd"},
+ {file = "pillow-10.3.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:0ea2a783a2bdf2a561808fe4a7a12e9aa3799b701ba305de596bc48b8bdfce9d"},
+ {file = "pillow-10.3.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:c78e1b00a87ce43bb37642c0812315b411e856a905d58d597750eb79802aaaa3"},
+ {file = "pillow-10.3.0-cp38-cp38-win32.whl", hash = "sha256:72d622d262e463dfb7595202d229f5f3ab4b852289a1cd09650362db23b9eb0b"},
+ {file = "pillow-10.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:2034f6759a722da3a3dbd91a81148cf884e91d1b747992ca288ab88c1de15999"},
+ {file = "pillow-10.3.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:2ed854e716a89b1afcedea551cd85f2eb2a807613752ab997b9974aaa0d56936"},
+ {file = "pillow-10.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:dc1a390a82755a8c26c9964d457d4c9cbec5405896cba94cf51f36ea0d855002"},
+ {file = "pillow-10.3.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4203efca580f0dd6f882ca211f923168548f7ba334c189e9eab1178ab840bf60"},
+ {file = "pillow-10.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3102045a10945173d38336f6e71a8dc71bcaeed55c3123ad4af82c52807b9375"},
+ {file = "pillow-10.3.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:6fb1b30043271ec92dc65f6d9f0b7a830c210b8a96423074b15c7bc999975f57"},
+ {file = "pillow-10.3.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:1dfc94946bc60ea375cc39cff0b8da6c7e5f8fcdc1d946beb8da5c216156ddd8"},
+ {file = "pillow-10.3.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b09b86b27a064c9624d0a6c54da01c1beaf5b6cadfa609cf63789b1d08a797b9"},
+ {file = "pillow-10.3.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d3b2348a78bc939b4fed6552abfd2e7988e0f81443ef3911a4b8498ca084f6eb"},
+ {file = "pillow-10.3.0-cp39-cp39-win32.whl", hash = "sha256:45ebc7b45406febf07fef35d856f0293a92e7417ae7933207e90bf9090b70572"},
+ {file = "pillow-10.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:0ba26351b137ca4e0db0342d5d00d2e355eb29372c05afd544ebf47c0956ffeb"},
+ {file = "pillow-10.3.0-cp39-cp39-win_arm64.whl", hash = "sha256:50fd3f6b26e3441ae07b7c979309638b72abc1a25da31a81a7fbd9495713ef4f"},
+ {file = "pillow-10.3.0-pp310-pypy310_pp73-macosx_10_10_x86_64.whl", hash = "sha256:6b02471b72526ab8a18c39cb7967b72d194ec53c1fd0a70b050565a0f366d355"},
+ {file = "pillow-10.3.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:8ab74c06ffdab957d7670c2a5a6e1a70181cd10b727cd788c4dd9005b6a8acd9"},
+ {file = "pillow-10.3.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:048eeade4c33fdf7e08da40ef402e748df113fd0b4584e32c4af74fe78baaeb2"},
+ {file = "pillow-10.3.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e2ec1e921fd07c7cda7962bad283acc2f2a9ccc1b971ee4b216b75fad6f0463"},
+ {file = "pillow-10.3.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:4c8e73e99da7db1b4cad7f8d682cf6abad7844da39834c288fbfa394a47bbced"},
+ {file = "pillow-10.3.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:16563993329b79513f59142a6b02055e10514c1a8e86dca8b48a893e33cf91e3"},
+ {file = "pillow-10.3.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:dd78700f5788ae180b5ee8902c6aea5a5726bac7c364b202b4b3e3ba2d293170"},
+ {file = "pillow-10.3.0-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:aff76a55a8aa8364d25400a210a65ff59d0168e0b4285ba6bf2bd83cf675ba32"},
+ {file = "pillow-10.3.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:b7bc2176354defba3edc2b9a777744462da2f8e921fbaf61e52acb95bafa9828"},
+ {file = "pillow-10.3.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:793b4e24db2e8742ca6423d3fde8396db336698c55cd34b660663ee9e45ed37f"},
+ {file = "pillow-10.3.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d93480005693d247f8346bc8ee28c72a2191bdf1f6b5db469c096c0c867ac015"},
+ {file = "pillow-10.3.0-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:c83341b89884e2b2e55886e8fbbf37c3fa5efd6c8907124aeb72f285ae5696e5"},
+ {file = "pillow-10.3.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:1a1d1915db1a4fdb2754b9de292642a39a7fb28f1736699527bb649484fb966a"},
+ {file = "pillow-10.3.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:a0eaa93d054751ee9964afa21c06247779b90440ca41d184aeb5d410f20ff591"},
+ {file = "pillow-10.3.0.tar.gz", hash = "sha256:9d2455fbf44c914840c793e89aa82d0e1763a14253a000743719ae5946814b2d"},
]
[package.extras]
docs = ["furo", "olefile", "sphinx (>=2.4)", "sphinx-copybutton", "sphinx-inline-tabs", "sphinx-removed-in", "sphinxext-opengraph"]
+fpx = ["olefile"]
+mic = ["olefile"]
tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout"]
+typing = ["typing-extensions"]
+xmp = ["defusedxml"]
[[package]]
name = "prometheus-client"
-version = "0.19.0"
+version = "0.20.0"
description = "Python client for the Prometheus monitoring system."
optional = false
python-versions = ">=3.8"
files = [
- {file = "prometheus_client-0.19.0-py3-none-any.whl", hash = "sha256:c88b1e6ecf6b41cd8fb5731c7ae919bf66df6ec6fafa555cd6c0e16ca169ae92"},
- {file = "prometheus_client-0.19.0.tar.gz", hash = "sha256:4585b0d1223148c27a225b10dbec5ae9bc4c81a99a3fa80774fa6209935324e1"},
+ {file = "prometheus_client-0.20.0-py3-none-any.whl", hash = "sha256:cde524a85bce83ca359cc837f28b8c0db5cac7aa653a588fd7e84ba061c329e7"},
+ {file = "prometheus_client-0.20.0.tar.gz", hash = "sha256:287629d00b147a32dcb2be0b9df905da599b2d82f80377083ec8463309a4bb89"},
]
[package.extras]
@@ -945,13 +975,13 @@ twisted = ["twisted"]
[[package]]
name = "prompt-toolkit"
-version = "3.0.41"
+version = "3.0.46"
description = "Library for building powerful interactive command lines in Python"
optional = false
python-versions = ">=3.7.0"
files = [
- {file = "prompt_toolkit-3.0.41-py3-none-any.whl", hash = "sha256:f36fe301fafb7470e86aaf90f036eef600a3210be4decf461a5b1ca8403d3cb2"},
- {file = "prompt_toolkit-3.0.41.tar.gz", hash = "sha256:941367d97fc815548822aa26c2a269fdc4eb21e9ec05fc5d447cf09bad5d75f0"},
+ {file = "prompt_toolkit-3.0.46-py3-none-any.whl", hash = "sha256:45abe60a8300f3c618b23c16c4bb98c6fc80af8ce8b17c7ae92db48db3ee63c1"},
+ {file = "prompt_toolkit-3.0.46.tar.gz", hash = "sha256:869c50d682152336e23c4db7f74667639b5047494202ffe7670817053fd57795"},
]
[package.dependencies]
@@ -1040,72 +1070,73 @@ files = [
[[package]]
name = "pycparser"
-version = "2.21"
+version = "2.22"
description = "C parser in Python"
optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
+python-versions = ">=3.8"
files = [
- {file = "pycparser-2.21-py2.py3-none-any.whl", hash = "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9"},
- {file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"},
+ {file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"},
+ {file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"},
]
[[package]]
name = "pycryptodome"
-version = "3.19.0"
+version = "3.20.0"
description = "Cryptographic library for Python"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
files = [
- {file = "pycryptodome-3.19.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:3006c44c4946583b6de24fe0632091c2653d6256b99a02a3db71ca06472ea1e4"},
- {file = "pycryptodome-3.19.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:7c760c8a0479a4042111a8dd2f067d3ae4573da286c53f13cf6f5c53a5c1f631"},
- {file = "pycryptodome-3.19.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:08ce3558af5106c632baf6d331d261f02367a6bc3733086ae43c0f988fe042db"},
- {file = "pycryptodome-3.19.0-cp27-cp27m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45430dfaf1f421cf462c0dd824984378bef32b22669f2635cb809357dbaab405"},
- {file = "pycryptodome-3.19.0-cp27-cp27m-musllinux_1_1_aarch64.whl", hash = "sha256:a9bcd5f3794879e91970f2bbd7d899780541d3ff439d8f2112441769c9f2ccea"},
- {file = "pycryptodome-3.19.0-cp27-cp27m-win32.whl", hash = "sha256:190c53f51e988dceb60472baddce3f289fa52b0ec38fbe5fd20dd1d0f795c551"},
- {file = "pycryptodome-3.19.0-cp27-cp27m-win_amd64.whl", hash = "sha256:22e0ae7c3a7f87dcdcf302db06ab76f20e83f09a6993c160b248d58274473bfa"},
- {file = "pycryptodome-3.19.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:7822f36d683f9ad7bc2145b2c2045014afdbbd1d9922a6d4ce1cbd6add79a01e"},
- {file = "pycryptodome-3.19.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:05e33267394aad6db6595c0ce9d427fe21552f5425e116a925455e099fdf759a"},
- {file = "pycryptodome-3.19.0-cp27-cp27mu-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:829b813b8ee00d9c8aba417621b94bc0b5efd18c928923802ad5ba4cf1ec709c"},
- {file = "pycryptodome-3.19.0-cp27-cp27mu-musllinux_1_1_aarch64.whl", hash = "sha256:fc7a79590e2b5d08530175823a242de6790abc73638cc6dc9d2684e7be2f5e49"},
- {file = "pycryptodome-3.19.0-cp35-abi3-macosx_10_9_universal2.whl", hash = "sha256:542f99d5026ac5f0ef391ba0602f3d11beef8e65aae135fa5b762f5ebd9d3bfb"},
- {file = "pycryptodome-3.19.0-cp35-abi3-macosx_10_9_x86_64.whl", hash = "sha256:61bb3ccbf4bf32ad9af32da8badc24e888ae5231c617947e0f5401077f8b091f"},
- {file = "pycryptodome-3.19.0-cp35-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d49a6c715d8cceffedabb6adb7e0cbf41ae1a2ff4adaeec9432074a80627dea1"},
- {file = "pycryptodome-3.19.0-cp35-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e249a784cc98a29c77cea9df54284a44b40cafbfae57636dd2f8775b48af2434"},
- {file = "pycryptodome-3.19.0-cp35-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d033947e7fd3e2ba9a031cb2d267251620964705a013c5a461fa5233cc025270"},
- {file = "pycryptodome-3.19.0-cp35-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:84c3e4fffad0c4988aef0d5591be3cad4e10aa7db264c65fadbc633318d20bde"},
- {file = "pycryptodome-3.19.0-cp35-abi3-musllinux_1_1_i686.whl", hash = "sha256:139ae2c6161b9dd5d829c9645d781509a810ef50ea8b657e2257c25ca20efe33"},
- {file = "pycryptodome-3.19.0-cp35-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:5b1986c761258a5b4332a7f94a83f631c1ffca8747d75ab8395bf2e1b93283d9"},
- {file = "pycryptodome-3.19.0-cp35-abi3-win32.whl", hash = "sha256:536f676963662603f1f2e6ab01080c54d8cd20f34ec333dcb195306fa7826997"},
- {file = "pycryptodome-3.19.0-cp35-abi3-win_amd64.whl", hash = "sha256:04dd31d3b33a6b22ac4d432b3274588917dcf850cc0c51c84eca1d8ed6933810"},
- {file = "pycryptodome-3.19.0-pp27-pypy_73-manylinux2010_x86_64.whl", hash = "sha256:8999316e57abcbd8085c91bc0ef75292c8618f41ca6d2b6132250a863a77d1e7"},
- {file = "pycryptodome-3.19.0-pp27-pypy_73-win32.whl", hash = "sha256:a0ab84755f4539db086db9ba9e9f3868d2e3610a3948cbd2a55e332ad83b01b0"},
- {file = "pycryptodome-3.19.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:0101f647d11a1aae5a8ce4f5fad6644ae1b22bb65d05accc7d322943c69a74a6"},
- {file = "pycryptodome-3.19.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8c1601e04d32087591d78e0b81e1e520e57a92796089864b20e5f18c9564b3fa"},
- {file = "pycryptodome-3.19.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:506c686a1eee6c00df70010be3b8e9e78f406af4f21b23162bbb6e9bdf5427bc"},
- {file = "pycryptodome-3.19.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:7919ccd096584b911f2a303c593280869ce1af9bf5d36214511f5e5a1bed8c34"},
- {file = "pycryptodome-3.19.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:560591c0777f74a5da86718f70dfc8d781734cf559773b64072bbdda44b3fc3e"},
- {file = "pycryptodome-3.19.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c1cc2f2ae451a676def1a73c1ae9120cd31af25db3f381893d45f75e77be2400"},
- {file = "pycryptodome-3.19.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:17940dcf274fcae4a54ec6117a9ecfe52907ed5e2e438fe712fe7ca502672ed5"},
- {file = "pycryptodome-3.19.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:d04f5f623a280fbd0ab1c1d8ecbd753193ab7154f09b6161b0f857a1a676c15f"},
- {file = "pycryptodome-3.19.0.tar.gz", hash = "sha256:bc35d463222cdb4dbebd35e0784155c81e161b9284e567e7e933d722e533331e"},
+ {file = "pycryptodome-3.20.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:f0e6d631bae3f231d3634f91ae4da7a960f7ff87f2865b2d2b831af1dfb04e9a"},
+ {file = "pycryptodome-3.20.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:baee115a9ba6c5d2709a1e88ffe62b73ecc044852a925dcb67713a288c4ec70f"},
+ {file = "pycryptodome-3.20.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:417a276aaa9cb3be91f9014e9d18d10e840a7a9b9a9be64a42f553c5b50b4d1d"},
+ {file = "pycryptodome-3.20.0-cp27-cp27m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2a1250b7ea809f752b68e3e6f3fd946b5939a52eaeea18c73bdab53e9ba3c2dd"},
+ {file = "pycryptodome-3.20.0-cp27-cp27m-musllinux_1_1_aarch64.whl", hash = "sha256:d5954acfe9e00bc83ed9f5cb082ed22c592fbbef86dc48b907238be64ead5c33"},
+ {file = "pycryptodome-3.20.0-cp27-cp27m-win32.whl", hash = "sha256:06d6de87c19f967f03b4cf9b34e538ef46e99a337e9a61a77dbe44b2cbcf0690"},
+ {file = "pycryptodome-3.20.0-cp27-cp27m-win_amd64.whl", hash = "sha256:ec0bb1188c1d13426039af8ffcb4dbe3aad1d7680c35a62d8eaf2a529b5d3d4f"},
+ {file = "pycryptodome-3.20.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:5601c934c498cd267640b57569e73793cb9a83506f7c73a8ec57a516f5b0b091"},
+ {file = "pycryptodome-3.20.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:d29daa681517f4bc318cd8a23af87e1f2a7bad2fe361e8aa29c77d652a065de4"},
+ {file = "pycryptodome-3.20.0-cp27-cp27mu-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3427d9e5310af6680678f4cce149f54e0bb4af60101c7f2c16fdf878b39ccccc"},
+ {file = "pycryptodome-3.20.0-cp27-cp27mu-musllinux_1_1_aarch64.whl", hash = "sha256:3cd3ef3aee1079ae44afaeee13393cf68b1058f70576b11439483e34f93cf818"},
+ {file = "pycryptodome-3.20.0-cp35-abi3-macosx_10_9_universal2.whl", hash = "sha256:ac1c7c0624a862f2e53438a15c9259d1655325fc2ec4392e66dc46cdae24d044"},
+ {file = "pycryptodome-3.20.0-cp35-abi3-macosx_10_9_x86_64.whl", hash = "sha256:76658f0d942051d12a9bd08ca1b6b34fd762a8ee4240984f7c06ddfb55eaf15a"},
+ {file = "pycryptodome-3.20.0-cp35-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f35d6cee81fa145333137009d9c8ba90951d7d77b67c79cbe5f03c7eb74d8fe2"},
+ {file = "pycryptodome-3.20.0-cp35-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:76cb39afede7055127e35a444c1c041d2e8d2f1f9c121ecef573757ba4cd2c3c"},
+ {file = "pycryptodome-3.20.0-cp35-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:49a4c4dc60b78ec41d2afa392491d788c2e06edf48580fbfb0dd0f828af49d25"},
+ {file = "pycryptodome-3.20.0-cp35-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:fb3b87461fa35afa19c971b0a2b7456a7b1db7b4eba9a8424666104925b78128"},
+ {file = "pycryptodome-3.20.0-cp35-abi3-musllinux_1_1_i686.whl", hash = "sha256:acc2614e2e5346a4a4eab6e199203034924313626f9620b7b4b38e9ad74b7e0c"},
+ {file = "pycryptodome-3.20.0-cp35-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:210ba1b647837bfc42dd5a813cdecb5b86193ae11a3f5d972b9a0ae2c7e9e4b4"},
+ {file = "pycryptodome-3.20.0-cp35-abi3-win32.whl", hash = "sha256:8d6b98d0d83d21fb757a182d52940d028564efe8147baa9ce0f38d057104ae72"},
+ {file = "pycryptodome-3.20.0-cp35-abi3-win_amd64.whl", hash = "sha256:9b3ae153c89a480a0ec402e23db8d8d84a3833b65fa4b15b81b83be9d637aab9"},
+ {file = "pycryptodome-3.20.0-pp27-pypy_73-manylinux2010_x86_64.whl", hash = "sha256:4401564ebf37dfde45d096974c7a159b52eeabd9969135f0426907db367a652a"},
+ {file = "pycryptodome-3.20.0-pp27-pypy_73-win32.whl", hash = "sha256:ec1f93feb3bb93380ab0ebf8b859e8e5678c0f010d2d78367cf6bc30bfeb148e"},
+ {file = "pycryptodome-3.20.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:acae12b9ede49f38eb0ef76fdec2df2e94aad85ae46ec85be3648a57f0a7db04"},
+ {file = "pycryptodome-3.20.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f47888542a0633baff535a04726948e876bf1ed880fddb7c10a736fa99146ab3"},
+ {file = "pycryptodome-3.20.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6e0e4a987d38cfc2e71b4a1b591bae4891eeabe5fa0f56154f576e26287bfdea"},
+ {file = "pycryptodome-3.20.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:c18b381553638414b38705f07d1ef0a7cf301bc78a5f9bc17a957eb19446834b"},
+ {file = "pycryptodome-3.20.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a60fedd2b37b4cb11ccb5d0399efe26db9e0dd149016c1cc6c8161974ceac2d6"},
+ {file = "pycryptodome-3.20.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:405002eafad114a2f9a930f5db65feef7b53c4784495dd8758069b89baf68eab"},
+ {file = "pycryptodome-3.20.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2ab6ab0cb755154ad14e507d1df72de9897e99fd2d4922851a276ccc14f4f1a5"},
+ {file = "pycryptodome-3.20.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:acf6e43fa75aca2d33e93409f2dafe386fe051818ee79ee8a3e21de9caa2ac9e"},
+ {file = "pycryptodome-3.20.0.tar.gz", hash = "sha256:09609209ed7de61c2b560cc5c8c4fbf892f8b15b1faf7e4cbffac97db1fffda7"},
]
[[package]]
name = "pygls"
-version = "1.2.1"
+version = "1.3.1"
description = "A pythonic generic language server (pronounced like 'pie glass')"
optional = false
-python-versions = ">=3.7.9,<4"
+python-versions = ">=3.8"
files = [
- {file = "pygls-1.2.1-py3-none-any.whl", hash = "sha256:7dcfcf12b6f15beb606afa46de2ed348b65a279c340ef2242a9a35c22eeafe94"},
- {file = "pygls-1.2.1.tar.gz", hash = "sha256:04f9b9c115b622dcc346fb390289066565343d60245a424eca77cb429b911ed8"},
+ {file = "pygls-1.3.1-py3-none-any.whl", hash = "sha256:6e00f11efc56321bdeb6eac04f6d86131f654c7d49124344a9ebb968da3dd91e"},
+ {file = "pygls-1.3.1.tar.gz", hash = "sha256:140edceefa0da0e9b3c533547c892a42a7d2fd9217ae848c330c53d266a55018"},
]
[package.dependencies]
-lsprotocol = "2023.0.0"
+cattrs = ">=23.1.2"
+lsprotocol = "2023.0.1"
[package.extras]
-ws = ["websockets (>=11.0.3,<12.0.0)"]
+ws = ["websockets (>=11.0.3)"]
[[package]]
name = "pypng"
@@ -1118,31 +1149,31 @@ files = [
{file = "pypng-0.20220715.0.tar.gz", hash = "sha256:739c433ba96f078315de54c0db975aee537cbc3e1d0ae4ed9aab0ca1e427e2c1"},
]
+[[package]]
+name = "pyreadline3"
+version = "3.4.1"
+description = "A python implementation of GNU readline."
+optional = false
+python-versions = "*"
+files = [
+ {file = "pyreadline3-3.4.1-py3-none-any.whl", hash = "sha256:b0efb6516fd4fb07b45949053826a62fa4cb353db5be2bbb4a7aa1fdd1e345fb"},
+ {file = "pyreadline3-3.4.1.tar.gz", hash = "sha256:6f3d1f7b8a31ba32b73917cefc1f28cc660562f39aea8646d30bd6eff21f7bae"},
+]
+
[[package]]
name = "python-dateutil"
-version = "2.8.2"
+version = "2.9.0.post0"
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"},
+ {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"},
+ {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"},
]
[package.dependencies]
six = ">=1.5"
-[[package]]
-name = "pytz"
-version = "2023.3.post1"
-description = "World timezone definitions, modern and historical"
-optional = false
-python-versions = "*"
-files = [
- {file = "pytz-2023.3.post1-py2.py3-none-any.whl", hash = "sha256:ce42d816b81b68506614c11e8937d3aa9e41007ceb50bfdcb0749b921bf646c7"},
- {file = "pytz-2023.3.post1.tar.gz", hash = "sha256:7b4fddbeb94a1eba4b557da24f19fdf9db575192544270a9101d8509f9f43d7b"},
-]
-
[[package]]
name = "pyyaml"
version = "6.0.1"
@@ -1217,31 +1248,28 @@ test = ["coverage", "pytest"]
[[package]]
name = "redis"
-version = "5.0.1"
+version = "5.0.4"
description = "Python client for Redis database and key-value store"
optional = false
python-versions = ">=3.7"
files = [
- {file = "redis-5.0.1-py3-none-any.whl", hash = "sha256:ed4802971884ae19d640775ba3b03aa2e7bd5e8fb8dfaed2decce4d0fc48391f"},
- {file = "redis-5.0.1.tar.gz", hash = "sha256:0dab495cd5753069d3bc650a0dde8a8f9edde16fc5691b689a566eda58100d0f"},
+ {file = "redis-5.0.4-py3-none-any.whl", hash = "sha256:7adc2835c7a9b5033b7ad8f8918d09b7344188228809c98df07af226d39dec91"},
+ {file = "redis-5.0.4.tar.gz", hash = "sha256:ec31f2ed9675cc54c21ba854cfe0462e6faf1d83c8ce5944709db8a4700b9c61"},
]
-[package.dependencies]
-async-timeout = {version = ">=4.0.2", markers = "python_full_version <= \"3.11.2\""}
-
[package.extras]
hiredis = ["hiredis (>=1.0.0)"]
ocsp = ["cryptography (>=36.0.1)", "pyopenssl (==20.0.1)", "requests (>=2.26.0)"]
[[package]]
name = "requests"
-version = "2.31.0"
+version = "2.32.3"
description = "Python HTTP for Humans."
optional = false
-python-versions = ">=3.7"
+python-versions = ">=3.8"
files = [
- {file = "requests-2.31.0-py3-none-any.whl", hash = "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f"},
- {file = "requests-2.31.0.tar.gz", hash = "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"},
+ {file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"},
+ {file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"},
]
[package.dependencies]
@@ -1256,28 +1284,28 @@ use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"]
[[package]]
name = "ruff"
-version = "0.1.7"
+version = "0.1.15"
description = "An extremely fast Python linter and code formatter, written in Rust."
optional = false
python-versions = ">=3.7"
files = [
- {file = "ruff-0.1.7-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:7f80496854fdc65b6659c271d2c26e90d4d401e6a4a31908e7e334fab4645aac"},
- {file = "ruff-0.1.7-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:1ea109bdb23c2a4413f397ebd8ac32cb498bee234d4191ae1a310af760e5d287"},
- {file = "ruff-0.1.7-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b0c2de9dd9daf5e07624c24add25c3a490dbf74b0e9bca4145c632457b3b42a"},
- {file = "ruff-0.1.7-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:69a4bed13bc1d5dabf3902522b5a2aadfebe28226c6269694283c3b0cecb45fd"},
- {file = "ruff-0.1.7-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:de02ca331f2143195a712983a57137c5ec0f10acc4aa81f7c1f86519e52b92a1"},
- {file = "ruff-0.1.7-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:45b38c3f8788a65e6a2cab02e0f7adfa88872696839d9882c13b7e2f35d64c5f"},
- {file = "ruff-0.1.7-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6c64cb67b2025b1ac6d58e5ffca8f7b3f7fd921f35e78198411237e4f0db8e73"},
- {file = "ruff-0.1.7-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9dcc6bb2f4df59cb5b4b40ff14be7d57012179d69c6565c1da0d1f013d29951b"},
- {file = "ruff-0.1.7-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:df2bb4bb6bbe921f6b4f5b6fdd8d8468c940731cb9406f274ae8c5ed7a78c478"},
- {file = "ruff-0.1.7-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:276a89bcb149b3d8c1b11d91aa81898fe698900ed553a08129b38d9d6570e717"},
- {file = "ruff-0.1.7-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:90c958fe950735041f1c80d21b42184f1072cc3975d05e736e8d66fc377119ea"},
- {file = "ruff-0.1.7-py3-none-musllinux_1_2_i686.whl", hash = "sha256:6b05e3b123f93bb4146a761b7a7d57af8cb7384ccb2502d29d736eaade0db519"},
- {file = "ruff-0.1.7-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:290ecab680dce94affebefe0bbca2322a6277e83d4f29234627e0f8f6b4fa9ce"},
- {file = "ruff-0.1.7-py3-none-win32.whl", hash = "sha256:416dfd0bd45d1a2baa3b1b07b1b9758e7d993c256d3e51dc6e03a5e7901c7d80"},
- {file = "ruff-0.1.7-py3-none-win_amd64.whl", hash = "sha256:4af95fd1d3b001fc41325064336db36e3d27d2004cdb6d21fd617d45a172dd96"},
- {file = "ruff-0.1.7-py3-none-win_arm64.whl", hash = "sha256:0683b7bfbb95e6df3c7c04fe9d78f631f8e8ba4868dfc932d43d690698057e2e"},
- {file = "ruff-0.1.7.tar.gz", hash = "sha256:dffd699d07abf54833e5f6cc50b85a6ff043715da8788c4a79bcd4ab4734d306"},
+ {file = "ruff-0.1.15-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:5fe8d54df166ecc24106db7dd6a68d44852d14eb0729ea4672bb4d96c320b7df"},
+ {file = "ruff-0.1.15-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:6f0bfbb53c4b4de117ac4d6ddfd33aa5fc31beeaa21d23c45c6dd249faf9126f"},
+ {file = "ruff-0.1.15-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e0d432aec35bfc0d800d4f70eba26e23a352386be3a6cf157083d18f6f5881c8"},
+ {file = "ruff-0.1.15-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9405fa9ac0e97f35aaddf185a1be194a589424b8713e3b97b762336ec79ff807"},
+ {file = "ruff-0.1.15-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c66ec24fe36841636e814b8f90f572a8c0cb0e54d8b5c2d0e300d28a0d7bffec"},
+ {file = "ruff-0.1.15-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:6f8ad828f01e8dd32cc58bc28375150171d198491fc901f6f98d2a39ba8e3ff5"},
+ {file = "ruff-0.1.15-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:86811954eec63e9ea162af0ffa9f8d09088bab51b7438e8b6488b9401863c25e"},
+ {file = "ruff-0.1.15-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fd4025ac5e87d9b80e1f300207eb2fd099ff8200fa2320d7dc066a3f4622dc6b"},
+ {file = "ruff-0.1.15-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b17b93c02cdb6aeb696effecea1095ac93f3884a49a554a9afa76bb125c114c1"},
+ {file = "ruff-0.1.15-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:ddb87643be40f034e97e97f5bc2ef7ce39de20e34608f3f829db727a93fb82c5"},
+ {file = "ruff-0.1.15-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:abf4822129ed3a5ce54383d5f0e964e7fef74a41e48eb1dfad404151efc130a2"},
+ {file = "ruff-0.1.15-py3-none-musllinux_1_2_i686.whl", hash = "sha256:6c629cf64bacfd136c07c78ac10a54578ec9d1bd2a9d395efbee0935868bf852"},
+ {file = "ruff-0.1.15-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:1bab866aafb53da39c2cadfb8e1c4550ac5340bb40300083eb8967ba25481447"},
+ {file = "ruff-0.1.15-py3-none-win32.whl", hash = "sha256:2417e1cb6e2068389b07e6fa74c306b2810fe3ee3476d5b8a96616633f40d14f"},
+ {file = "ruff-0.1.15-py3-none-win_amd64.whl", hash = "sha256:3837ac73d869efc4182d9036b1405ef4c73d9b1f88da2413875e34e0d6919587"},
+ {file = "ruff-0.1.15-py3-none-win_arm64.whl", hash = "sha256:9a933dfb1c14ec7a33cceb1e49ec4a16b51ce3c20fd42663198746efc0427360"},
+ {file = "ruff-0.1.15.tar.gz", hash = "sha256:f6dfa8c1b21c913c326919056c390966648b680966febcb796cc9d1aaab8564e"},
]
[[package]]
@@ -1303,13 +1331,13 @@ dev = ["mypy (==1.4.1)", "pip-tools (>=6.13.0,<7.0.0)", "pytest (>=7.3.1,<8.0.0)
[[package]]
name = "sentry-sdk"
-version = "1.38.0"
+version = "1.45.0"
description = "Python client for Sentry (https://sentry.io)"
optional = false
python-versions = "*"
files = [
- {file = "sentry-sdk-1.38.0.tar.gz", hash = "sha256:8feab81de6bbf64f53279b085bd3820e3e737403b0a0d9317f73a2c3374ae359"},
- {file = "sentry_sdk-1.38.0-py2.py3-none-any.whl", hash = "sha256:0017fa73b8ae2d4e57fd2522ee3df30453715b29d2692142793ec5d5f90b94a6"},
+ {file = "sentry-sdk-1.45.0.tar.gz", hash = "sha256:509aa9678c0512344ca886281766c2e538682f8acfa50fd8d405f8c417ad0625"},
+ {file = "sentry_sdk-1.45.0-py2.py3-none-any.whl", hash = "sha256:1ce29e30240cc289a027011103a8c83885b15ef2f316a60bcc7c5300afa144f1"},
]
[package.dependencies]
@@ -1323,6 +1351,7 @@ asyncpg = ["asyncpg (>=0.23)"]
beam = ["apache-beam (>=2.12)"]
bottle = ["bottle (>=0.12.13)"]
celery = ["celery (>=3)"]
+celery-redbeat = ["celery-redbeat (>=2)"]
chalice = ["chalice (>=1.16.0)"]
clickhouse-driver = ["clickhouse-driver (>=0.2.0)"]
django = ["django (>=1.8)"]
@@ -1333,6 +1362,7 @@ grpcio = ["grpcio (>=1.21.1)"]
httpx = ["httpx (>=0.16.0)"]
huey = ["huey (>=2)"]
loguru = ["loguru (>=0.5)"]
+openai = ["openai (>=1.0.0)", "tiktoken (>=0.3.0)"]
opentelemetry = ["opentelemetry-distro (>=0.35b0)"]
opentelemetry-experimental = ["opentelemetry-distro (>=0.40b0,<1.0)", "opentelemetry-instrumentation-aiohttp-client (>=0.40b0,<1.0)", "opentelemetry-instrumentation-django (>=0.40b0,<1.0)", "opentelemetry-instrumentation-fastapi (>=0.40b0,<1.0)", "opentelemetry-instrumentation-flask (>=0.40b0,<1.0)", "opentelemetry-instrumentation-requests (>=0.40b0,<1.0)", "opentelemetry-instrumentation-sqlite3 (>=0.40b0,<1.0)", "opentelemetry-instrumentation-urllib (>=0.40b0,<1.0)"]
pure-eval = ["asttokens", "executing", "pure-eval"]
@@ -1359,19 +1389,18 @@ files = [
[[package]]
name = "sqlparse"
-version = "0.4.4"
+version = "0.5.0"
description = "A non-validating SQL parser."
optional = false
-python-versions = ">=3.5"
+python-versions = ">=3.8"
files = [
- {file = "sqlparse-0.4.4-py3-none-any.whl", hash = "sha256:5430a4fe2ac7d0f93e66f1efc6e1338a41884b7ddf2a350cedd20ccc4d9d28f3"},
- {file = "sqlparse-0.4.4.tar.gz", hash = "sha256:d446183e84b8349fa3061f0fe7f06ca94ba65b426946ffebe6e3e8295332420c"},
+ {file = "sqlparse-0.5.0-py3-none-any.whl", hash = "sha256:c204494cd97479d0e39f28c93d46c0b2d5959c7b9ab904762ea6c7af211c8663"},
+ {file = "sqlparse-0.5.0.tar.gz", hash = "sha256:714d0a4932c059d16189f58ef5411ec2287a4360f17cdd0edd2d09d4c5087c93"},
]
[package.extras]
-dev = ["build", "flake8"]
+dev = ["build", "hatch"]
doc = ["sphinx"]
-test = ["pytest", "pytest-cov"]
[[package]]
name = "tablib"
@@ -1404,40 +1433,40 @@ yaml = ["pyyaml"]
[[package]]
name = "typing-extensions"
-version = "4.8.0"
+version = "4.12.1"
description = "Backported and Experimental Type Hints for Python 3.8+"
optional = false
python-versions = ">=3.8"
files = [
- {file = "typing_extensions-4.8.0-py3-none-any.whl", hash = "sha256:8f92fc8806f9a6b641eaa5318da32b44d401efaac0f6678c9bc448ba3605faa0"},
- {file = "typing_extensions-4.8.0.tar.gz", hash = "sha256:df8e4339e9cb77357558cbdbceca33c303714cf861d1eef15e1070055ae8b7ef"},
+ {file = "typing_extensions-4.12.1-py3-none-any.whl", hash = "sha256:6024b58b69089e5a89c347397254e35f1bf02a907728ec7fee9bf0fe837d203a"},
+ {file = "typing_extensions-4.12.1.tar.gz", hash = "sha256:915f5e35ff76f56588223f15fdd5938f9a1cf9195c0de25130c627e4d597f6d1"},
]
[[package]]
name = "tzdata"
-version = "2023.3"
+version = "2024.1"
description = "Provider of IANA time zone data"
optional = false
python-versions = ">=2"
files = [
- {file = "tzdata-2023.3-py2.py3-none-any.whl", hash = "sha256:7e65763eef3120314099b6939b5546db7adce1e7d6f2e179e3df563c70511eda"},
- {file = "tzdata-2023.3.tar.gz", hash = "sha256:11ef1e08e54acb0d4f95bdb1be05da659673de4acbd21bf9c69e94cc5e907a3a"},
+ {file = "tzdata-2024.1-py2.py3-none-any.whl", hash = "sha256:9068bc196136463f5245e51efda838afa15aaeca9903f49050dfa2679db4d252"},
+ {file = "tzdata-2024.1.tar.gz", hash = "sha256:2674120f8d891909751c38abcdfd386ac0a5a1127954fbc332af6b5ceae07efd"},
]
[[package]]
name = "urllib3"
-version = "2.0.7"
+version = "2.2.1"
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.2.1-py3-none-any.whl", hash = "sha256:450b20ec296a467077128bff42b73080516e71b56ff59a60a02bef2232c4fa9d"},
+ {file = "urllib3-2.2.1.tar.gz", hash = "sha256:d0570876c61ab9e520d776c38acbbb5b05a776d3f9ff98a5c8fd5162a444cf19"},
]
[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"]
+h2 = ["h2 (>=4,<5)"]
socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"]
zstd = ["zstandard (>=0.18.0)"]
@@ -1455,7 +1484,6 @@ files = [
[package.dependencies]
click = ">=7.0"
h11 = ">=0.8"
-typing-extensions = {version = ">=4.0", markers = "python_version < \"3.11\""}
[package.extras]
standard = ["colorama (>=0.4)", "httptools (>=0.5.0)", "python-dotenv (>=0.13)", "pyyaml (>=5.1)", "uvloop (>=0.14.0,!=0.15.0,!=0.15.1)", "watchfiles (>=0.13)", "websockets (>=10.4)"]
@@ -1473,13 +1501,13 @@ files = [
[[package]]
name = "wcwidth"
-version = "0.2.12"
+version = "0.2.13"
description = "Measures the displayed width of unicode strings in a terminal"
optional = false
python-versions = "*"
files = [
- {file = "wcwidth-0.2.12-py2.py3-none-any.whl", hash = "sha256:f26ec43d96c8cbfed76a5075dac87680124fa84e0855195a6184da9c187f133c"},
- {file = "wcwidth-0.2.12.tar.gz", hash = "sha256:f01c104efdf57971bcb756f054dd58ddec5204dd15fa31d6503ea57947d97c02"},
+ {file = "wcwidth-0.2.13-py2.py3-none-any.whl", hash = "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859"},
+ {file = "wcwidth-0.2.13.tar.gz", hash = "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5"},
]
[[package]]
@@ -1511,5 +1539,5 @@ files = [
[metadata]
lock-version = "2.0"
-python-versions = "^3.10"
-content-hash = "05fa8b336882246b6693e65438939ca68b15eec4b1a30c3929b3e9e57961cac1"
+python-versions = "^3.12"
+content-hash = "292798843bea6f6f117ae3bb6407709dd89a5bd4518f3739fedeb42a99a958bc"
diff --git a/pyproject.toml b/pyproject.toml
index 07ca803..e603ce3 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,4 +1,4 @@
-[tool.poetry]
+[project]
name = "shadowmere"
version = "1.0.0"
description = "An automatically tested list of Shadowsocks proxies."
@@ -6,6 +6,9 @@ authors = ["Your Name "]
license = "GPLv3"
readme = "README.md"
+[tool.poetry]
+package-mode = false
+
[tool.poetry.dependencies]
python = "^3.12"
django = "^5.0"
@@ -29,6 +32,9 @@ django-environ = "^0.11.2"
uvicorn = "^0.24.0.post1"
gunicorn = "^21.2.0"
django-jazzmin = "^2.6.0"
+huey = "^2.5.0"
+humanfriendly = "^10.0"
+django-ratelimit = "^4.1.0"
[tool.poetry.group.dev.dependencies]
ruff = "^0.1.7"
@@ -39,7 +45,16 @@ requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
[tool.ruff]
-select = ["E", "F"]
+exclude = ["migrations"]
+select = ["E", "F", "I", "W", "N"]
ignore = []
line-length = 120
target-version = "py312"
+fix = true
+
+[tool.ruff.format]
+docstring-code-format = true
+docstring-code-line-length = 120
+
+[tool.ruff.lint.isort]
+combine-as-imports = true
From af9748a8d49b80cfe98b45bc3109480dca832b88 Mon Sep 17 00:00:00 2001
From: "Ozkar L. Garcell"
Date: Sat, 8 Jun 2024 20:25:46 +0200
Subject: [PATCH 25/32] feat/wip: utils module
---
app/shadowmere/utils/__init__.py | 0
.../proxylist => utils}/base64_decoder.py | 0
.../{apps/proxylist => utils}/proxy.py | 0
app/shadowmere/utils/uri_scheme.py | 24 ++++++++++++++++++
app/shadowmere/utils/validators.py | 25 +++++++++++++++++++
5 files changed, 49 insertions(+)
create mode 100644 app/shadowmere/utils/__init__.py
rename app/shadowmere/{apps/proxylist => utils}/base64_decoder.py (100%)
rename app/shadowmere/{apps/proxylist => utils}/proxy.py (100%)
create mode 100644 app/shadowmere/utils/uri_scheme.py
create mode 100644 app/shadowmere/utils/validators.py
diff --git a/app/shadowmere/utils/__init__.py b/app/shadowmere/utils/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/app/shadowmere/apps/proxylist/base64_decoder.py b/app/shadowmere/utils/base64_decoder.py
similarity index 100%
rename from app/shadowmere/apps/proxylist/base64_decoder.py
rename to app/shadowmere/utils/base64_decoder.py
diff --git a/app/shadowmere/apps/proxylist/proxy.py b/app/shadowmere/utils/proxy.py
similarity index 100%
rename from app/shadowmere/apps/proxylist/proxy.py
rename to app/shadowmere/utils/proxy.py
diff --git a/app/shadowmere/utils/uri_scheme.py b/app/shadowmere/utils/uri_scheme.py
new file mode 100644
index 0000000..959da23
--- /dev/null
+++ b/app/shadowmere/utils/uri_scheme.py
@@ -0,0 +1,24 @@
+import base64
+
+from utils.base64_decoder import decode_base64
+
+
+def get_sip002(instance_url):
+ try:
+ url = instance_url
+ if "#" in url:
+ url = url.split("#")[0]
+ if "=" in url:
+ url = url.replace("=", "")
+ if "@" not in url:
+ url = url.replace("ss://", "")
+ decoded_url = decode_base64(url.encode("ascii"))
+ if decoded_url:
+ encoded_bits = base64.b64encode(decoded_url.split(b"@")[0]).decode("ascii").rstrip("=")
+ url = f'ss://{encoded_bits}@{decoded_url.split(b"@")[1].decode("ascii")}'
+ else:
+ return ""
+ except IndexError:
+ return ""
+
+ return url
diff --git a/app/shadowmere/utils/validators.py b/app/shadowmere/utils/validators.py
new file mode 100644
index 0000000..5d7d478
--- /dev/null
+++ b/app/shadowmere/utils/validators.py
@@ -0,0 +1,25 @@
+from django.core.exceptions import ValidationError
+from utils.proxy import get_proxy_location
+from utils.uri_scheme import get_sip002
+
+
+def validate_sip002(value: str) -> None:
+ if get_sip002(value) == "":
+ raise ValidationError(
+ "The value entered is not SIP002 compatible",
+ params={"value": value},
+ )
+
+
+def validate_proxy_can_connect(value: str) -> None:
+ location = get_proxy_location(get_sip002(value))
+ if location is None or location == "unknown":
+ raise ValidationError(
+ "Can't get the location for this address",
+ params={"value": value},
+ )
+
+
+def proxy_validator(value: str) -> None:
+ validate_sip002(value)
+ validate_proxy_can_connect(value)
From 609c9bdcc49e6cc462fb1b5a5a3324624c7a75c5 Mon Sep 17 00:00:00 2001
From: "Ozkar L. Garcell"
Date: Sat, 8 Jun 2024 20:26:08 +0200
Subject: [PATCH 26/32] feat: using signals module
---
app/shadowmere/apps/proxylist/apps.py | 3 ++
app/shadowmere/apps/proxylist/signals.py | 37 ++++++++++++++++++++++++
2 files changed, 40 insertions(+)
create mode 100644 app/shadowmere/apps/proxylist/signals.py
diff --git a/app/shadowmere/apps/proxylist/apps.py b/app/shadowmere/apps/proxylist/apps.py
index 1b01159..d7203e4 100644
--- a/app/shadowmere/apps/proxylist/apps.py
+++ b/app/shadowmere/apps/proxylist/apps.py
@@ -3,3 +3,6 @@
class ProxylistConfig(AppConfig):
name = "apps.proxylist"
+
+ def ready(self) -> None:
+ import apps.proxylist.signals # noqa
diff --git a/app/shadowmere/apps/proxylist/signals.py b/app/shadowmere/apps/proxylist/signals.py
new file mode 100644
index 0000000..dea6408
--- /dev/null
+++ b/app/shadowmere/apps/proxylist/signals.py
@@ -0,0 +1,37 @@
+import re
+
+from apps.proxylist.models import Proxy
+from django.core.cache import cache
+from django.db import IntegrityError
+from django.db.models.signals import post_save
+from django.dispatch import receiver
+from utils.proxy import update_proxy_status
+from utils.uri_scheme import get_sip002
+
+
+@receiver(post_save, sender=Proxy)
+def update_url_and_location_after_save(sender, instance, created, **kwargs):
+ url = get_sip002(instance.url)
+ if url != instance.url:
+ instance.url = url
+ instance.save()
+ return
+
+ if instance.port == 0:
+ server_and_port = instance.url.split("@")[1]
+ instance.port = int(re.findall(r":(\d+)", server_and_port)[-1])
+ instance.save()
+ return
+
+ if instance.location == "":
+ update_proxy_status(instance)
+ try:
+ instance.save()
+ except IntegrityError:
+ # This means the proxy is either a duplicate or no longer valid
+ instance.delete()
+
+
+@receiver(post_save, sender=Proxy)
+def clear_cache(sender, instance, **kwargs):
+ cache.clear()
From e3de031c8a56b9d64af582f541138b5c5404bd2e Mon Sep 17 00:00:00 2001
From: "Ozkar L. Garcell"
Date: Sat, 8 Jun 2024 20:26:33 +0200
Subject: [PATCH 27/32] feat: improved models, updated migrations wih new
modules
---
.../migrations/0003_alter_proxy_url.py | 1 -
..._proxy_location_country_alter_proxy_url.py | 7 +-
.../0010_subscription_alter_proxy_url.py | 4 +-
..._address_alter_proxy_is_active_and_more.py | 43 ++++++++
app/shadowmere/apps/proxylist/models.py | 104 ++----------------
5 files changed, 56 insertions(+), 103 deletions(-)
create mode 100644 app/shadowmere/apps/proxylist/migrations/0018_alter_proxy_ip_address_alter_proxy_is_active_and_more.py
diff --git a/app/shadowmere/apps/proxylist/migrations/0003_alter_proxy_url.py b/app/shadowmere/apps/proxylist/migrations/0003_alter_proxy_url.py
index 13bb053..04f4573 100644
--- a/app/shadowmere/apps/proxylist/migrations/0003_alter_proxy_url.py
+++ b/app/shadowmere/apps/proxylist/migrations/0003_alter_proxy_url.py
@@ -16,7 +16,6 @@ class Migration(migrations.Migration):
field=models.CharField(
max_length=1024,
unique=True,
- validators=[apps.proxylist.models.validate_not_existing],
),
),
]
diff --git a/app/shadowmere/apps/proxylist/migrations/0008_proxy_location_country_alter_proxy_url.py b/app/shadowmere/apps/proxylist/migrations/0008_proxy_location_country_alter_proxy_url.py
index 60ef86f..a795708 100644
--- a/app/shadowmere/apps/proxylist/migrations/0008_proxy_location_country_alter_proxy_url.py
+++ b/app/shadowmere/apps/proxylist/migrations/0008_proxy_location_country_alter_proxy_url.py
@@ -1,7 +1,7 @@
# Generated by Django 4.0.4 on 2022-06-06 12:09
from django.db import migrations, models
-import apps.proxylist.models
+from utils import validators
class Migration(migrations.Migration):
@@ -22,9 +22,8 @@ class Migration(migrations.Migration):
max_length=1024,
unique=True,
validators=[
- apps.proxylist.models.validate_sip002,
- apps.proxylist.models.validate_not_existing,
- apps.proxylist.models.validate_proxy_can_connect,
+ validators.validate_sip002,
+ validators.validate_proxy_can_connect,
],
),
),
diff --git a/app/shadowmere/apps/proxylist/migrations/0010_subscription_alter_proxy_url.py b/app/shadowmere/apps/proxylist/migrations/0010_subscription_alter_proxy_url.py
index cef7754..8aff90f 100644
--- a/app/shadowmere/apps/proxylist/migrations/0010_subscription_alter_proxy_url.py
+++ b/app/shadowmere/apps/proxylist/migrations/0010_subscription_alter_proxy_url.py
@@ -1,7 +1,7 @@
# Generated by Django 4.1.7 on 2023-03-04 14:37
from django.db import migrations, models
-import apps.proxylist.models
+from utils import validators
class Migration(migrations.Migration):
@@ -21,6 +21,6 @@ class Migration(migrations.Migration):
migrations.AlterField(
model_name="proxy",
name="url",
- field=models.CharField(max_length=1024, unique=True, validators=[apps.proxylist.models.proxy_validator]),
+ field=models.CharField(max_length=1024, unique=True, validators=[validators.proxy_validator]),
),
]
diff --git a/app/shadowmere/apps/proxylist/migrations/0018_alter_proxy_ip_address_alter_proxy_is_active_and_more.py b/app/shadowmere/apps/proxylist/migrations/0018_alter_proxy_ip_address_alter_proxy_is_active_and_more.py
new file mode 100644
index 0000000..bb6cbda
--- /dev/null
+++ b/app/shadowmere/apps/proxylist/migrations/0018_alter_proxy_ip_address_alter_proxy_is_active_and_more.py
@@ -0,0 +1,43 @@
+# Generated by Django 5.0.6 on 2024-06-08 18:23
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('proxylist', '0017_tasklog_details'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='proxy',
+ name='ip_address',
+ field=models.CharField(blank=True, db_index=True, max_length=100, null=True),
+ ),
+ migrations.AlterField(
+ model_name='proxy',
+ name='is_active',
+ field=models.BooleanField(db_index=True, default=False),
+ ),
+ migrations.AlterField(
+ model_name='proxy',
+ name='location',
+ field=models.CharField(blank=True, max_length=100, null=True),
+ ),
+ migrations.AlterField(
+ model_name='proxy',
+ name='location_country',
+ field=models.CharField(blank=True, db_index=True, max_length=50, null=True),
+ ),
+ migrations.AlterField(
+ model_name='proxy',
+ name='location_country_code',
+ field=models.CharField(blank=True, db_index=True, max_length=3, null=True),
+ ),
+ migrations.AlterField(
+ model_name='proxy',
+ name='port',
+ field=models.IntegerField(db_index=True, default=0),
+ ),
+ ]
diff --git a/app/shadowmere/apps/proxylist/models.py b/app/shadowmere/apps/proxylist/models.py
index 4dc32a8..9752b01 100644
--- a/app/shadowmere/apps/proxylist/models.py
+++ b/app/shadowmere/apps/proxylist/models.py
@@ -1,46 +1,7 @@
-import base64
-import re
-
-from apps.proxylist.base64_decoder import decode_base64
-from apps.proxylist.proxy import get_proxy_location, update_proxy_status
-from django.core.cache import cache
-from django.core.exceptions import ValidationError
-from django.db import IntegrityError, models
-from django.db.models.signals import post_save
-from django.dispatch import receiver
+from django.db import models
from django.utils.timezone import now
from django_prometheus.models import ExportModelOperationsMixin
-
-
-def validate_sip002(value):
- if get_sip002(value) == "":
- raise ValidationError(
- "The value entered is not SIP002 compatible",
- params={"value": value},
- )
-
-
-def validate_not_existing(value):
- if Proxy.objects.filter(url=get_sip002(value)):
- raise ValidationError(
- "This proxy was already imported",
- params={"value": value},
- )
-
-
-def validate_proxy_can_connect(value):
- location = get_proxy_location(get_sip002(value))
- if location is None or location == "unknown":
- raise ValidationError(
- "Can't get the location for this address",
- params={"value": value},
- )
-
-
-def proxy_validator(value):
- validate_sip002(value)
- validate_not_existing(value)
- validate_proxy_can_connect(value)
+from utils.validators import proxy_validator
class Proxy(ExportModelOperationsMixin("proxy"), models.Model):
@@ -51,12 +12,12 @@ class Proxy(ExportModelOperationsMixin("proxy"), models.Model):
proxy_validator,
],
)
- location = models.CharField(max_length=100, default="")
- location_country_code = models.CharField(max_length=3, default="")
- location_country = models.CharField(max_length=50, default="")
- ip_address = models.CharField(max_length=100, default="")
- port = models.IntegerField(default=0)
- is_active = models.BooleanField(default=False)
+ location = models.CharField(max_length=100, blank=True, null=True)
+ location_country_code = models.CharField(max_length=3, blank=True, null=True, db_index=True)
+ location_country = models.CharField(max_length=50, blank=True, null=True, db_index=True)
+ ip_address = models.CharField(max_length=100, blank=True, null=True, db_index=True)
+ port = models.IntegerField(default=0, db_index=True)
+ is_active = models.BooleanField(default=False, db_index=True)
last_checked = models.DateTimeField(auto_now=True)
last_active = models.DateTimeField(blank=True, default=now)
times_checked = models.IntegerField(default=0)
@@ -66,55 +27,6 @@ def __str__(self):
return f"{self.location} ({self.url})"
-def get_sip002(instance_url):
- try:
- url = instance_url
- if "#" in url:
- url = url.split("#")[0]
- if "=" in url:
- url = url.replace("=", "")
- if "@" not in url:
- url = url.replace("ss://", "")
- decoded_url = decode_base64(url.encode("ascii"))
- if decoded_url:
- encoded_bits = base64.b64encode(decoded_url.split(b"@")[0]).decode("ascii").rstrip("=")
- url = f'ss://{encoded_bits}@{decoded_url.split(b"@")[1].decode("ascii")}'
- else:
- return ""
- except IndexError:
- return ""
-
- return url
-
-
-@receiver(post_save, sender=Proxy)
-def update_url_and_location_after_save(sender, instance, created, **kwargs):
- url = get_sip002(instance.url)
- if url != instance.url:
- instance.url = url
- instance.save()
- return
-
- if instance.port == 0:
- server_and_port = instance.url.split("@")[1]
- instance.port = int(re.findall(r":(\d+)", server_and_port)[-1])
- instance.save()
- return
-
- if instance.location == "":
- update_proxy_status(instance)
- try:
- instance.save()
- except IntegrityError:
- # This means the proxy is either a duplicate or no longer valid
- instance.delete()
-
-
-@receiver(post_save, sender=Proxy)
-def clear_cache(sender, instance, **kwargs):
- cache.clear()
-
-
class Subscription(models.Model):
class SubscriptionKind(models.TextChoices):
PLAIN = "PLAIN", "plain"
From 4029b7cb7a7bb9168cb1b4807b869d4e2969ed7c Mon Sep 17 00:00:00 2001
From: "Ozkar L. Garcell"
Date: Sat, 8 Jun 2024 20:26:45 +0200
Subject: [PATCH 28/32] feat/fix: updated imports
---
app/shadowmere/apps/proxylist/admin.py | 2 +-
app/shadowmere/apps/proxylist/tasks.py | 7 ++++---
.../apps/proxylist/tests/test_subscription.py | 10 +++++-----
app/shadowmere/apps/proxylist/views.py | 2 +-
4 files changed, 11 insertions(+), 10 deletions(-)
diff --git a/app/shadowmere/apps/proxylist/admin.py b/app/shadowmere/apps/proxylist/admin.py
index 2dce17a..5033615 100644
--- a/app/shadowmere/apps/proxylist/admin.py
+++ b/app/shadowmere/apps/proxylist/admin.py
@@ -1,12 +1,12 @@
import humanfriendly
from apps.proxylist.models import Proxy, Subscription, TaskLog
-from apps.proxylist.proxy import update_proxy_status
from django.contrib import admin
from django.contrib.auth.models import Group
from django.db import IntegrityError
from import_export import resources
from import_export.admin import ImportExportModelAdmin
from rangefilter.filters import DateRangeFilter
+from utils.proxy import update_proxy_status
class ProxyResource(resources.ModelResource):
diff --git a/app/shadowmere/apps/proxylist/tasks.py b/app/shadowmere/apps/proxylist/tasks.py
index 6f61b41..9d95cdf 100644
--- a/app/shadowmere/apps/proxylist/tasks.py
+++ b/app/shadowmere/apps/proxylist/tasks.py
@@ -3,9 +3,7 @@
from concurrent.futures import ThreadPoolExecutor
import requests
-from apps.proxylist.base64_decoder import decode_base64
-from apps.proxylist.models import Proxy, Subscription, TaskLog, get_sip002
-from apps.proxylist.proxy import get_proxy_location, update_proxy_status
+from apps.proxylist.models import Proxy, Subscription, TaskLog
from django.db import IntegrityError
from django.db.models import F, FloatField
from django.db.models.functions import Coalesce
@@ -13,6 +11,9 @@
from huey import crontab
from huey.contrib.djhuey import db_periodic_task
from requests.exceptions import ConnectionError, ReadTimeout, SSLError
+from utils.base64_decoder import decode_base64
+from utils.proxy import get_proxy_location, update_proxy_status
+from utils.uri_scheme import get_sip002
CONCURRENT_CHECKS = 200
SUBSCRIPTION_TIMEOUT_SECONDS = 60
diff --git a/app/shadowmere/apps/proxylist/tests/test_subscription.py b/app/shadowmere/apps/proxylist/tests/test_subscription.py
index 02dc90e..743e1fc 100644
--- a/app/shadowmere/apps/proxylist/tests/test_subscription.py
+++ b/app/shadowmere/apps/proxylist/tests/test_subscription.py
@@ -1,11 +1,8 @@
-import base64
import json
-import flag
from django.urls import reverse
from rest_framework.test import APITestCase
-
-from proxylist.base64_decoder import decode_base64
+from utils.base64_decoder import decode_base64
class SubEndpointTests(APITestCase):
@@ -52,4 +49,7 @@ def test_get_b64sub(self):
response = self.client.get(reverse("b64sub-list"))
self.assertEqual(response.status_code, 200)
content = decode_base64(response.content).decode("utf-8")
- assert content == '\nss://Y2hhY2hhMjAtaWV0Zi1wb2x5MTMwNTpwcG15SVVQMmV1WU0@37.218.242.73:8091/#π³π± Waalwijk, NB, Netherlands\nss://Y2hhY2hhMjAtaWV0Zi1wb2x5MTMwNTpHIXlCd1BXSDNWYW8@196.196.156.122:807#πΈπͺ Stockholm, AB, Sweden\nss://YWVzLTI1Ni1nY206ZmFCQW9ENTRrODdVSkc3@169.197.142.39:2375#πΊπΈ unknown'
+ assert (
+ content
+ == "\nss://Y2hhY2hhMjAtaWV0Zi1wb2x5MTMwNTpwcG15SVVQMmV1WU0@37.218.242.73:8091/#π³π± Waalwijk, NB, Netherlands\nss://Y2hhY2hhMjAtaWV0Zi1wb2x5MTMwNTpHIXlCd1BXSDNWYW8@196.196.156.122:807#πΈπͺ Stockholm, AB, Sweden\nss://YWVzLTI1Ni1nY206ZmFCQW9ENTRrODdVSkc3@169.197.142.39:2375#πΊπΈ unknown"
+ )
diff --git a/app/shadowmere/apps/proxylist/views.py b/app/shadowmere/apps/proxylist/views.py
index 29e40ce..ce5e746 100644
--- a/app/shadowmere/apps/proxylist/views.py
+++ b/app/shadowmere/apps/proxylist/views.py
@@ -5,7 +5,6 @@
import flag
import qrcode
-from apps.proxylist.base64_decoder import decode_base64
from apps.proxylist.metrics import register_metrics
from apps.proxylist.models import Proxy, TaskLog
from apps.proxylist.permissions import GeneralPermission
@@ -21,6 +20,7 @@
from django_ratelimit.decorators import ratelimit
from rest_framework import viewsets
from rest_framework.response import Response
+from utils.base64_decoder import decode_base64
@cache_page(None)
From 3f5c2bc634387cdf083bf967450c0aa61e3f413c Mon Sep 17 00:00:00 2001
From: "Ozkar L. Garcell"
Date: Sun, 9 Jun 2024 20:00:20 +0200
Subject: [PATCH 29/32] feat" updated imports for management commands
---
.../apps/proxylist/management/commands/clear_stats.py | 3 +--
.../apps/proxylist/management/commands/poll_subscriptions.py | 3 +--
.../apps/proxylist/management/commands/reduce_checks_by.py | 3 +--
.../apps/proxylist/management/commands/remove_low_quality.py | 5 ++---
.../apps/proxylist/management/commands/update_status.py | 3 +--
5 files changed, 6 insertions(+), 11 deletions(-)
diff --git a/app/shadowmere/apps/proxylist/management/commands/clear_stats.py b/app/shadowmere/apps/proxylist/management/commands/clear_stats.py
index b6dc362..08acf40 100644
--- a/app/shadowmere/apps/proxylist/management/commands/clear_stats.py
+++ b/app/shadowmere/apps/proxylist/management/commands/clear_stats.py
@@ -1,7 +1,6 @@
+from apps.proxylist.models import Proxy
from django.core.management.base import BaseCommand
-from proxylist.models import Proxy
-
class Command(BaseCommand):
help = "Clear all quality statistics"
diff --git a/app/shadowmere/apps/proxylist/management/commands/poll_subscriptions.py b/app/shadowmere/apps/proxylist/management/commands/poll_subscriptions.py
index 3c5cca0..6e6e981 100644
--- a/app/shadowmere/apps/proxylist/management/commands/poll_subscriptions.py
+++ b/app/shadowmere/apps/proxylist/management/commands/poll_subscriptions.py
@@ -1,7 +1,6 @@
+from apps.proxylist.tasks import poll_subscriptions
from django.core.management.base import BaseCommand
-from proxylist.tasks import poll_subscriptions
-
class Command(BaseCommand):
help = "Poll all subscriptions looking for new keys"
diff --git a/app/shadowmere/apps/proxylist/management/commands/reduce_checks_by.py b/app/shadowmere/apps/proxylist/management/commands/reduce_checks_by.py
index 9b7dae8..c593add 100644
--- a/app/shadowmere/apps/proxylist/management/commands/reduce_checks_by.py
+++ b/app/shadowmere/apps/proxylist/management/commands/reduce_checks_by.py
@@ -1,7 +1,6 @@
+from apps.proxylist.models import Proxy
from django.core.management.base import BaseCommand
-from proxylist.models import Proxy
-
class Command(BaseCommand):
help = "Clear all quality statistics"
diff --git a/app/shadowmere/apps/proxylist/management/commands/remove_low_quality.py b/app/shadowmere/apps/proxylist/management/commands/remove_low_quality.py
index 733c437..6310995 100644
--- a/app/shadowmere/apps/proxylist/management/commands/remove_low_quality.py
+++ b/app/shadowmere/apps/proxylist/management/commands/remove_low_quality.py
@@ -1,8 +1,7 @@
-from django.core.management.base import BaseCommand
-
-from proxylist.tasks import (
+from apps.proxylist.tasks import (
remove_low_quality_proxies,
)
+from django.core.management.base import BaseCommand
class Command(BaseCommand):
diff --git a/app/shadowmere/apps/proxylist/management/commands/update_status.py b/app/shadowmere/apps/proxylist/management/commands/update_status.py
index 407b048..9938107 100644
--- a/app/shadowmere/apps/proxylist/management/commands/update_status.py
+++ b/app/shadowmere/apps/proxylist/management/commands/update_status.py
@@ -1,7 +1,6 @@
+from apps.proxylist.tasks import update_status
from django.core.management.base import BaseCommand
-from proxylist.tasks import update_status
-
class Command(BaseCommand):
help = "Update the status of the proxy list"
From dcdd12a7f433baf432765e8a4a982cea85efd6bf Mon Sep 17 00:00:00 2001
From: "Ozkar L. Garcell"
Date: Sun, 9 Jun 2024 20:01:24 +0200
Subject: [PATCH 30/32] fix: actions and display attr
---
app/shadowmere/apps/proxylist/admin.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/app/shadowmere/apps/proxylist/admin.py b/app/shadowmere/apps/proxylist/admin.py
index 5033615..a60bdd3 100644
--- a/app/shadowmere/apps/proxylist/admin.py
+++ b/app/shadowmere/apps/proxylist/admin.py
@@ -17,7 +17,7 @@ class Meta:
@admin.register(Proxy)
class ProxyAdmin(ImportExportModelAdmin):
@staticmethod
- def update_status(modeladmin, request, queryset):
+ def update_status(queryset):
for proxy in queryset:
update_proxy_status(proxy)
try:
@@ -27,7 +27,7 @@ def update_status(modeladmin, request, queryset):
proxy.delete()
@staticmethod
- def quality(self, obj):
+ def quality(obj):
if obj.times_checked > 0:
return obj.times_check_succeeded * 100 / obj.times_checked
else:
From 41b6d05ba6d4fbcfe58ba286ef519c786a85766f Mon Sep 17 00:00:00 2001
From: "Ozkar L. Garcell"
Date: Sun, 9 Jun 2024 20:01:31 +0200
Subject: [PATCH 31/32] feat: removed unused code
---
app/shadowmere/apps/proxylist/views.py | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/app/shadowmere/apps/proxylist/views.py b/app/shadowmere/apps/proxylist/views.py
index ce5e746..2076e9d 100644
--- a/app/shadowmere/apps/proxylist/views.py
+++ b/app/shadowmere/apps/proxylist/views.py
@@ -153,7 +153,7 @@ class CountryCodeViewSet(viewsets.ViewSet):
"""
@method_decorator(cache_page(20 * 60))
- def list(self, request, format=None):
+ def list(self, request):
country_codes = [
{"code": code["location_country_code"], "name": code["location_country"]}
for code in Proxy.objects.filter(is_active=True)
@@ -171,7 +171,7 @@ class PortViewSet(viewsets.ViewSet):
"""
@method_decorator(cache_page(20 * 60))
- def list(self, request, format=None):
+ def list(self, request):
ports = [
port for port in Proxy.objects.filter(is_active=True).values_list("port", flat=True).distinct() if port != 0
]
@@ -198,7 +198,7 @@ class SubViewSet(viewsets.ViewSet):
)
)
@method_decorator(cache_page(20 * 60))
- def list(self, request, format=None):
+ def list(self, request):
servers = [
get_proxy_config(server)
for server in Proxy.objects.filter(is_active=True).order_by("location_country_code")
@@ -219,7 +219,7 @@ class Base64SubViewSet(viewsets.ViewSet):
)
)
@method_decorator(cache_page(20 * 60))
- def list(self, request, format=None):
+ def list(self, request):
server_list = ""
for proxy in Proxy.objects.filter(is_active=True).order_by("location_country_code"):
server_list += f"\n{proxy.url}#{get_flag_or_empty(proxy.location_country_code)} {proxy.location}"
From fe1774972819e98b5e564d80a4cc324624c4272d Mon Sep 17 00:00:00 2001
From: "Jorge Alberto Diaz Orozco (Akiel)"
Date: Sat, 20 Jul 2024 14:09:42 +0200
Subject: [PATCH 32/32] feat/fix: rebased branch
---
app/shadowmere/config/settings/base.py | 4 -
app/shadowmere/config/settings/dev.py | 12 ++
app/shadowmere/config/settings/prod.py | 15 ++
app/shadowmere/config/urls.py | 7 +-
shadowmere/celery.py | 0
shadowmere/settings/base.py | 238 -------------------------
6 files changed, 31 insertions(+), 245 deletions(-)
delete mode 100644 shadowmere/celery.py
delete mode 100644 shadowmere/settings/base.py
diff --git a/app/shadowmere/config/settings/base.py b/app/shadowmere/config/settings/base.py
index 95b21ae..089c6a4 100644
--- a/app/shadowmere/config/settings/base.py
+++ b/app/shadowmere/config/settings/base.py
@@ -89,8 +89,6 @@
WSGI_APPLICATION = "config.wsgi.application"
-DATABASES = {"default": env.db()}
-
AUTH_PASSWORD_VALIDATORS = [
{
"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
@@ -174,8 +172,6 @@
STATIC_URL = "/static/"
-STATIC_ROOT = "./static_files/"
-
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
HUEY = {
diff --git a/app/shadowmere/config/settings/dev.py b/app/shadowmere/config/settings/dev.py
index 8ecc929..7e0bfa7 100644
--- a/app/shadowmere/config/settings/dev.py
+++ b/app/shadowmere/config/settings/dev.py
@@ -1,3 +1,15 @@
from .base import * # noqa
RATELIMIT_ENABLE = False
+
+DATABASES = {
+ "default": {
+ "ENGINE": "django.db.backends.sqlite3",
+ "NAME": BASE_DIR / "db.sqlite3",
+ }
+}
+
+CSRF_TRUSTED_ORIGINS = [
+ "http://127.0.0.1:8000",
+ "http://localhost:8000",
+]
diff --git a/app/shadowmere/config/settings/prod.py b/app/shadowmere/config/settings/prod.py
index 5e4b8ef..e7bf015 100644
--- a/app/shadowmere/config/settings/prod.py
+++ b/app/shadowmere/config/settings/prod.py
@@ -55,3 +55,18 @@
traces_sample_rate=0.01,
send_default_pii=True,
)
+
+DATABASES = {
+ "default": {
+ "ENGINE": "django_prometheus.db.backends.postgresql",
+ "NAME": "shadowmere",
+ "USER": "shadowmere",
+ "PASSWORD": env("POSTGRES_PASSWORD"),
+ "HOST": "db",
+ }
+}
+
+CSRF_TRUSTED_ORIGINS = [
+ "https://shadowmere.akiel.dev",
+ "https://shadowmere.xyz",
+]
diff --git a/app/shadowmere/config/urls.py b/app/shadowmere/config/urls.py
index 38e5f91..8aadfef 100644
--- a/app/shadowmere/config/urls.py
+++ b/app/shadowmere/config/urls.py
@@ -1,3 +1,7 @@
+from django.contrib import admin
+from django.urls import include, path
+from rest_framework import routers
+
from apps.proxylist.views import (
Base64SubViewSet,
CountryCodeViewSet,
@@ -9,9 +13,6 @@
list_proxies,
qr_code,
)
-from django.contrib import admin
-from django.urls import include, path
-from rest_framework import routers
router = routers.DefaultRouter()
router.register(r"proxies", ProxyViewSet)
diff --git a/shadowmere/celery.py b/shadowmere/celery.py
deleted file mode 100644
index e69de29..0000000
diff --git a/shadowmere/settings/base.py b/shadowmere/settings/base.py
deleted file mode 100644
index 54c86b0..0000000
--- a/shadowmere/settings/base.py
+++ /dev/null
@@ -1,238 +0,0 @@
-"""
-Django settings for shadowmere project.
-
-Generated by 'django-admin startproject' using Django 3.2.8.
-
-For more information on this file, see
-https://docs.djangoproject.com/en/3.2/topics/settings/
-
-For the full list of settings and their values, see
-https://docs.djangoproject.com/en/3.2/ref/settings/
-"""
-import os
-import environ
-from pathlib import Path
-from datetime import date
-
-# Build paths inside the project like this: BASE_DIR / 'subdir'.
-from celery.schedules import crontab
-from django.contrib.admin import AdminSite
-from django.utils.translation import gettext_lazy as _
-
-env = environ.Env(
- DEBUG=(bool, False),
- SHADOWTEST_URL=(str, "https://shadowtest.akiel.dev/v1/test"),
- ALLOWED_HOSTS=(str, ""),
- CSRF_TRUSTED_ORIGINS=(str, ""),
- CORS_ALLOWED_ORIGINS=(str, ""),
- MINIO_ENDPOINT=(str, ""),
- MINIO_ACCESS_KEY=(str, ""),
- MINIO_SECRET_KEY=(str, ""),
-)
-
-BASE_DIR = Path(__file__).resolve().parent.parent
-
-SECRET_KEY = env("SECRET_KEY")
-
-DEBUG = env("DEBUG")
-
-SHADOWTEST_URL = env("SHADOWTEST_URL")
-
-ALLOWED_HOSTS = env("ALLOWED_HOSTS").split(" ")
-
-CSRF_TRUSTED_ORIGINS: str = env("CSRF_TRUSTED_ORIGINS").split(" ")
-
-CORS_ALLOWED_ORIGINS: str = env("CORS_ALLOWED_ORIGINS").split(" ")
-
-DJANGO_APPS = [
- "jazzmin",
- "django.contrib.admin",
- "django.contrib.auth",
- "django.contrib.contenttypes",
- "django.contrib.sessions",
- "django.contrib.messages",
- "django.contrib.staticfiles",
-]
-
-THIRD_PARTY_APPS = [
- "storages",
- "import_export",
- "django_prometheus",
- "rangefilter",
- "huey.contrib.djhuey",
- "rest_framework",
- "django_filters",
-]
-
-LOCAL_APPS = [
- "proxylist.apps.ProxylistConfig",
-]
-
-INSTALLED_APPS = DJANGO_APPS + THIRD_PARTY_APPS + LOCAL_APPS
-
-MIDDLEWARE = [
- "django.middleware.security.SecurityMiddleware",
- "django.contrib.sessions.middleware.SessionMiddleware",
- "django.middleware.locale.LocaleMiddleware",
- "django.middleware.common.CommonMiddleware",
- "django.middleware.csrf.CsrfViewMiddleware",
- "django.contrib.auth.middleware.AuthenticationMiddleware",
- "django.contrib.messages.middleware.MessageMiddleware",
- "django.middleware.clickjacking.XFrameOptionsMiddleware",
-]
-
-ROOT_URLCONF = "shadowmere.urls"
-
-TEMPLATES = [
- {
- "BACKEND": "django.template.backends.django.DjangoTemplates",
- "DIRS": [BASE_DIR / "templates"],
- "APP_DIRS": True,
- "OPTIONS": {
- "context_processors": [
- "django.template.context_processors.debug",
- "django.template.context_processors.request",
- "django.contrib.auth.context_processors.auth",
- "django.contrib.messages.context_processors.messages",
- ],
- },
- },
-]
-
-WSGI_APPLICATION = "shadowmere.wsgi.application"
-
-DATABASES = {"default": env.db()}
-
-AUTH_PASSWORD_VALIDATORS = [
- {
- "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
- },
- {
- "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
- },
- {
- "NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",
- },
- {
- "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",
- },
-]
-
-from pythonjsonlogger import jsonlogger
-
-LOGGING = {
- "version": 1,
- "disable_existing_loggers": False,
- "formatters": {
- "json": {
- "()": "pythonjsonlogger.jsonlogger.JsonFormatter",
- "format": "%(levelname)s %(name)s %(message)s %(asctime)s %(module)s %(task)s",
- },
- },
- "handlers": {
- "console": {
- "level": "DEBUG",
- "class": "logging.StreamHandler",
- "formatter": "json",
- },
- },
- "loggers": {
- "django": {
- "handlers": ["console"],
- "level": "INFO",
- "propagate": True,
- },
- "django.server": {
- "handlers": ["console"],
- "level": "INFO",
- "propagate": True,
- },
- },
-}
-
-
-LANGUAGE_CODE = "en-us"
-
-TIME_ZONE = "UTC"
-
-USE_I18N = True
-
-USE_L10N = True
-
-USE_TZ = True
-
-LANGUAGES = [
- ("es", _("Spanish")),
- ("en", _("English")),
-]
-
-LOCALE_PATHS = ("./locale",)
-
-STATIC_URL = "/static/"
-
-STATIC_ROOT = "./static_files/"
-
-DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
-
-HUEY = {
- "huey_class": "huey.RedisHuey", # Huey implementation to use.
- "name": "shadowmere", # Use db name for huey.
- "results": True, # Store return values of tasks.
- "store_none": False, # If a task returns None, do not save to results.
- "immediate": False, # If DEBUG=True, run synchronously.
- "utc": True, # Use UTC for all times internally.
- "blocking": True, # Perform blocking pop rather than poll Redis.
- "connection": {
- "host": "localhost" if DEBUG else "redis",
- "port": 6379,
- "db": 0,
- "connection_pool": None, # Definitely you should use pooling!
- # ... tons of other options, see redis-py for details.
- # huey-specific connection parameters.
- "read_timeout": 1, # If not polling (blocking pop), use timeout.
- "url": None, # Allow Redis config via a DSN.
- },
- "consumer": {
- "workers": 4,
- "worker_type": "process",
- "initial_delay": 0.1, # Smallest polling interval, same as -d.
- "backoff": 1.15, # Exponential backoff using this rate, -b.
- "max_delay": 10.0, # Max possible polling interval, -m.
- "scheduler_interval": 1, # Check schedule every second, -s.
- "periodic": True, # Enable crontab feature.
- "check_worker_health": True, # Enable worker health checks.
- "health_check_interval": 1, # Check worker health every second.
- },
-}
-
-REST_FRAMEWORK = {
- "DEFAULT_PAGINATION_CLASS": "proxylist.pagination.ProxiesPagination",
- "PAGE_SIZE": 10,
-}
-
-DATA_UPLOAD_MAX_NUMBER_FIELDS = 10000
-
-CONN_MAX_AGE = 60
-
-CONN_HEALTH_CHECKS = True
-
-SECURE_BROWSER_XSS_FILTER = True
-
-SECURE_CONTENT_TYPE_NOSNIFF = True
-
-SECURE_HOSTS_INCLUDE_SUBDOMAINS = True
-
-X_FRAME_OPTIONS = "SAMEORIGIN"
-
-FILTERS_DEFAULT_LOOKUP_EXPR = "icontains"
-
-JAZZMIN_SETTINGS = {
- "site_title": "Shadowmere Administration",
- "site_header": "Shadowmere",
- "site_brand": "Shadowmere",
- "welcome_sign": "Welcome to Shadowmere Administration",
- "copyright": f"Shadowmere {date.year}",
-}
-
-RATELIMIT_ENABLE = False
-RATELIMIT_VIEW = "proxylist.views.ratelimited_error"