diff --git a/akarpov/blog/forms.py b/akarpov/blog/forms.py
index 400c2dd..cbe90c0 100644
--- a/akarpov/blog/forms.py
+++ b/akarpov/blog/forms.py
@@ -1,11 +1,12 @@
-from ckeditor.fields import RichTextFormField
from django import forms
+from django_ckeditor_5.fields import CKEditor5Field
+from django_ckeditor_5.widgets import CKEditor5Widget
from akarpov.blog.models import Post, Tag
class PostForm(forms.ModelForm):
- body = RichTextFormField(label="")
+ body = CKEditor5Field(config_name="extends")
image = forms.ImageField(help_text="better use horizontal images", required=False)
tags = forms.ModelMultipleChoiceField(
queryset=Tag.objects.all(), widget=forms.CheckboxSelectMultiple, required=True
@@ -14,3 +15,9 @@ class PostForm(forms.ModelForm):
class Meta:
model = Post
fields = ["title", "body", "image", "tags"]
+ widgets = {
+ "body": CKEditor5Widget(
+ attrs={"class": "django_ckeditor_5"},
+ config_name="extends",
+ )
+ }
diff --git a/akarpov/blog/migrations/0001_initial.py b/akarpov/blog/migrations/0001_initial.py
index c215ae4..f4c7b59 100644
--- a/akarpov/blog/migrations/0001_initial.py
+++ b/akarpov/blog/migrations/0001_initial.py
@@ -1,6 +1,5 @@
# Generated by Django 4.0.8 on 2022-11-23 08:30
-import ckeditor_uploader.fields
import colorfield.fields
from django.conf import settings
from django.db import migrations, models
@@ -56,7 +55,7 @@ class Migration(migrations.Migration):
),
),
("title", models.CharField(max_length=100)),
- ("body", ckeditor_uploader.fields.RichTextUploadingField()),
+ ("body", models.TextField()),
("slug", models.SlugField(blank=True, max_length=20)),
("post_views", models.IntegerField(default=0)),
("rating", models.IntegerField(default=0)),
diff --git a/akarpov/blog/migrations/0011_alter_post_body.py b/akarpov/blog/migrations/0011_alter_post_body.py
new file mode 100644
index 0000000..03c00b7
--- /dev/null
+++ b/akarpov/blog/migrations/0011_alter_post_body.py
@@ -0,0 +1,18 @@
+# Generated by Django 4.2.10 on 2024-03-29 15:35
+
+from django.db import migrations
+import django_ckeditor_5.fields
+
+
+class Migration(migrations.Migration):
+ dependencies = [
+ ("blog", "0010_alter_tag_color"),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name="post",
+ name="body",
+ field=django_ckeditor_5.fields.CKEditor5Field(),
+ ),
+ ]
diff --git a/akarpov/blog/models.py b/akarpov/blog/models.py
index fadc746..e3c3665 100644
--- a/akarpov/blog/models.py
+++ b/akarpov/blog/models.py
@@ -1,8 +1,8 @@
-from ckeditor_uploader.fields import RichTextUploadingField
from colorfield.fields import ColorField
from django.db import models
from django.db.models import Count
from django.urls import reverse
+from django_ckeditor_5.fields import CKEditor5Field
from drf_spectacular.utils import extend_schema_field
from rest_framework import serializers
@@ -16,7 +16,7 @@
class Post(BaseImageModel, ShortLinkModel, UserHistoryModel):
title = models.CharField(max_length=100, blank=False)
- body = RichTextUploadingField(blank=False)
+ body = CKEditor5Field(blank=False, config_name="extends")
creator = models.ForeignKey(User, on_delete=models.CASCADE, related_name="posts")
diff --git a/akarpov/music/api/permissions.py b/akarpov/music/api/permissions.py
new file mode 100644
index 0000000..cdb0f80
--- /dev/null
+++ b/akarpov/music/api/permissions.py
@@ -0,0 +1,56 @@
+from rest_framework import permissions
+
+from akarpov.users.models import User, UserAPIToken
+
+
+class GetBaseMusicPermission(permissions.BasePermission):
+ def get_token_data(self, request) -> (dict, User | None):
+ try:
+ token = request.headers["Authorization"]
+ if " " in token:
+ token = token.split(" ")[1]
+ except (KeyError, IndexError):
+ return {
+ "listen": False,
+ "upload": False,
+ "playlist": False,
+ }, None
+ try:
+ token = UserAPIToken.objects.cache().get(token=token)
+ except UserAPIToken.DoesNotExist:
+ return {
+ "listen": False,
+ "upload": False,
+ "playlist": False,
+ }, None
+ if "music" not in token.permissions:
+ return {
+ "listen": False,
+ "upload": False,
+ "playlist": False,
+ }, token.user
+ return token.permissions["music"], token.user
+
+
+class CanListenToMusic(GetBaseMusicPermission):
+ def has_permission(self, request, view):
+ token_data = self.get_token_data(request)
+ if "listen" in token_data:
+ return token_data["listen"]
+ return False
+
+
+class CanUploadMusic(GetBaseMusicPermission):
+ def has_permission(self, request, view):
+ token_data = self.get_token_data(request)
+ if "upload" in token_data:
+ return token_data["upload"]
+ return False
+
+
+class CanManagePlaylists(GetBaseMusicPermission):
+ def has_permission(self, request, view):
+ token_data = self.get_token_data(request)
+ if "playlist" in token_data:
+ return token_data["playlist"]
+ return False
diff --git a/akarpov/templates/base.html b/akarpov/templates/base.html
index be67455..3f64963 100644
--- a/akarpov/templates/base.html
+++ b/akarpov/templates/base.html
@@ -100,6 +100,7 @@
diff --git a/akarpov/templates/blog/form.html b/akarpov/templates/blog/form.html
index 51dbd3e..d78c049 100644
--- a/akarpov/templates/blog/form.html
+++ b/akarpov/templates/blog/form.html
@@ -8,13 +8,9 @@
{% endblock %}
diff --git a/akarpov/templates/users/confirm_delete_token.html b/akarpov/templates/users/confirm_delete_token.html
new file mode 100644
index 0000000..79fcb31
--- /dev/null
+++ b/akarpov/templates/users/confirm_delete_token.html
@@ -0,0 +1,12 @@
+{% extends "base.html" %}
+{% block content %}
+
+
Confirm Deletion
+
Are you sure you want to delete this token?
+
+
+{% endblock %}
diff --git a/akarpov/templates/users/create_token.html b/akarpov/templates/users/create_token.html
new file mode 100644
index 0000000..683f5a5
--- /dev/null
+++ b/akarpov/templates/users/create_token.html
@@ -0,0 +1,21 @@
+{% extends "base.html" %}
+{% load crispy_forms_tags %}
+
+{% block content %}
+
+
Create API Token
+
+
+{% endblock %}
diff --git a/akarpov/templates/users/list_tokens.html b/akarpov/templates/users/list_tokens.html
new file mode 100644
index 0000000..20eb227
--- /dev/null
+++ b/akarpov/templates/users/list_tokens.html
@@ -0,0 +1,27 @@
+{% extends "base.html" %}
+{% load humanize %}
+{% block content %}
+
+{% endblock %}
diff --git a/akarpov/templates/users/token_created.html b/akarpov/templates/users/token_created.html
new file mode 100644
index 0000000..02b7a7d
--- /dev/null
+++ b/akarpov/templates/users/token_created.html
@@ -0,0 +1,17 @@
+{% extends "base.html" %}
+{% load static %}
+{% block content %}
+
+
Token Created Successfully
+
Your new API token is:
+
{{ new_token }}
+
Please note it down. You won't be able to see it again.
+
Back to Tokens
+
+
+
+{% endblock %}
diff --git a/akarpov/templates/users/view_token.html b/akarpov/templates/users/view_token.html
new file mode 100644
index 0000000..44fb316
--- /dev/null
+++ b/akarpov/templates/users/view_token.html
@@ -0,0 +1,26 @@
+{% extends "base.html" %}
+{% block content %}
+
+
Token Details
+ {% if token.name %}
+
Name: {{ token.name }}
+ {% endif %}
+
Token: {{ token.token|slice:":5" }}***{{ token.token|slice:"-5:" }}
+
Last Used: {{ token.last_used|date:"Y-m-d H:i:s" }} ({{ token.last_used|timesince }} ago)
+
Active Until: {{ token.active_until|date:"Y-m-d" }}
+
Permissions:
+
+ {% for app, actions in token.permissions.items %}
+ - {{ app|title }}:
+
+ {% for action, value in actions.items %}
+ - {{ action|title }}: {{ value|yesno:"✅,❌" }}
+ {% endfor %}
+
+
+ {% endfor %}
+
+ {#
Edit TODO #}
+
Delete
+
+{% endblock %}
diff --git a/akarpov/users/admin.py b/akarpov/users/admin.py
index 29bdccf..cf210cb 100644
--- a/akarpov/users/admin.py
+++ b/akarpov/users/admin.py
@@ -4,6 +4,7 @@
from django.utils.translation import gettext_lazy as _
from .forms import UserAdminChangeForm, UserAdminCreationForm
+from .models import UserAPIToken
User = get_user_model()
@@ -33,3 +34,19 @@ class UserAdmin(auth_admin.UserAdmin):
)
list_display = ["username", "is_superuser"]
search_fields = ["username", "email"]
+
+
+@admin.register(UserAPIToken)
+class UserAPITokenAdmin(admin.ModelAdmin):
+ list_display = ["user", "active_until", "last_used"]
+ search_fields = ["user__username", "token"]
+ list_filter = ["active_until", "last_used"]
+ date_hierarchy = "active_until"
+ raw_id_fields = ["user"]
+ actions = ["deactivate_tokens"]
+
+ def deactivate_tokens(self, request, queryset):
+ queryset.update(active_until=None)
+ self.message_user(request, _("Tokens deactivated"))
+
+ deactivate_tokens.short_description = _("Deactivate selected tokens")
diff --git a/akarpov/users/api/authentification.py b/akarpov/users/api/authentification.py
new file mode 100644
index 0000000..499e138
--- /dev/null
+++ b/akarpov/users/api/authentification.py
@@ -0,0 +1,22 @@
+from rest_framework.authentication import BaseAuthentication
+
+from akarpov.users.models import UserAPIToken
+from akarpov.users.tasks import set_last_active_token
+
+
+class UserTokenAuthentication(BaseAuthentication):
+ def authenticate(self, request):
+ if "Authorization" not in request.headers:
+ return None
+ token = request.headers["Authorization"]
+ if " " in token:
+ token = token.split(" ")[1]
+ try:
+ token = UserAPIToken.objects.cache().get(token=token)
+ except UserAPIToken.DoesNotExist:
+ return None
+ if not token.is_active:
+ return None
+ set_last_active_token.delay(token.token)
+
+ return token.user, token
diff --git a/akarpov/users/forms.py b/akarpov/users/forms.py
index a61a853..0c443bf 100644
--- a/akarpov/users/forms.py
+++ b/akarpov/users/forms.py
@@ -1,10 +1,15 @@
+import json
+
from allauth.account.forms import SignupForm
from allauth.socialaccount.forms import SignupForm as SocialSignupForm
from django import forms
from django.contrib.auth import forms as admin_forms
from django.contrib.auth import get_user_model
+from django.forms import DateInput, TextInput
from django.utils.translation import gettext_lazy as _
+from akarpov.users.models import UserAPIToken
+
User = get_user_model()
@@ -45,3 +50,80 @@ class UserSocialSignupForm(SocialSignupForm):
class OTPForm(forms.Form):
otp_token = forms.CharField()
+
+
+class TokenCreationForm(forms.ModelForm):
+ permissions = forms.MultipleChoiceField(
+ choices=[], # To be set in __init__
+ widget=forms.CheckboxSelectMultiple,
+ required=False,
+ )
+
+ class Meta:
+ model = UserAPIToken
+ fields = ["name", "active_until", "permissions"]
+ widgets = {
+ "name": TextInput(attrs={"placeholder": "Token Name (Optional)"}),
+ "active_until": DateInput(attrs={"type": "date"}, format="%d.%m.%Y"),
+ }
+ # Make active_until not required
+ required = {
+ "active_until": False,
+ }
+
+ def __init__(self, *args, **kwargs):
+ permissions_context = kwargs.pop("permissions_context", None)
+ super().__init__(*args, **kwargs)
+
+ if permissions_context:
+ for app, actions in permissions_context.items():
+ field_name = f"permissions_{app}"
+ self.fields[field_name] = forms.MultipleChoiceField(
+ choices=[(action, action) for action in actions.keys()],
+ widget=forms.CheckboxSelectMultiple,
+ required=False,
+ label=app.capitalize(),
+ initial=[
+ item
+ for sublist in kwargs.get("initial", {}).get(field_name, [])
+ for item in sublist
+ ],
+ )
+ self.fields["active_until"].required = False
+
+ def get_permissions_choices(self):
+ permissions_choices = [
+ (f"{app}.{action}", description)
+ for app, actions in UserAPIToken.permission_template.items()
+ for action, description in actions.items()
+ ]
+ return permissions_choices
+
+ def clean(self):
+ cleaned_data = super().clean()
+ structured_permissions = {
+ category: {perm: False for perm in permissions.keys()}
+ for category, permissions in UserAPIToken.permission_template.items()
+ }
+
+ for category in structured_permissions.keys():
+ input_field_name = f"permissions_{category}"
+ if input_field_name in self.data:
+ selected_perms = self.data.getlist(input_field_name)
+ for perm in selected_perms:
+ if perm in structured_permissions[category]:
+ structured_permissions[category][perm] = True
+
+ cleaned_data["permissions"] = json.dumps(structured_permissions)
+
+ return cleaned_data
+
+ def save(self, commit=True):
+ instance = super().save(commit=False)
+ permissions_json = self.cleaned_data.get("permissions", "{}")
+ instance.permissions = json.loads(permissions_json)
+
+ if commit:
+ instance.save()
+
+ return instance
diff --git a/akarpov/users/middleware.py b/akarpov/users/middleware.py
index a04542a..fc8c452 100644
--- a/akarpov/users/middleware.py
+++ b/akarpov/users/middleware.py
@@ -6,6 +6,8 @@
from django_otp.plugins.otp_totp.models import TOTPDevice
from rest_framework.exceptions import AuthenticationFailed
+from akarpov.users.models import UserAPIToken
+
class EmailVerificationMiddleware(MiddlewareMixin):
def process_request(self, request):
@@ -21,12 +23,20 @@ def __init__(self, get_response):
def __call__(self, request):
response = self.get_response(request)
- if (
- request.path_info.startswith("/api/v1/music/")
- or request.path_info == "/api/v1/auth/token/"
- ):
+ if request.path_info == "/api/v1/auth/token/":
return response
+ if "Authorization" in request.headers:
+ try:
+ token = request.headers["Authorization"]
+ if " " in token:
+ token = token.split(" ")[1]
+ token = UserAPIToken.objects.cache().get(token=token)
+ request.token_permissions = token.permissions
+ return response
+ except (KeyError, AttributeError, UserAPIToken.DoesNotExist):
+ ...
+
# Check user is authenticated and OTP token input is not completed
is_authenticated = request.user.is_authenticated
otp_not_verified = not request.session.get("otp_verified", False)
diff --git a/akarpov/users/migrations/0015_userapitoken.py b/akarpov/users/migrations/0015_userapitoken.py
new file mode 100644
index 0000000..1e83a9f
--- /dev/null
+++ b/akarpov/users/migrations/0015_userapitoken.py
@@ -0,0 +1,40 @@
+# Generated by Django 4.2.10 on 2024-03-29 15:18
+
+from django.conf import settings
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+ dependencies = [
+ ("users", "0014_alter_user_agree_data_to_be_sold"),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name="UserAPIToken",
+ fields=[
+ (
+ "id",
+ models.BigAutoField(
+ auto_created=True,
+ primary_key=True,
+ serialize=False,
+ verbose_name="ID",
+ ),
+ ),
+ ("token", models.CharField(db_index=True, max_length=255, unique=True)),
+ ("created", models.DateTimeField(auto_now_add=True)),
+ ("active_until", models.DateTimeField(null=True)),
+ ("permissions", models.JSONField(default=dict)),
+ (
+ "user",
+ models.ForeignKey(
+ on_delete=django.db.models.deletion.CASCADE,
+ related_name="api_tokens",
+ to=settings.AUTH_USER_MODEL,
+ ),
+ ),
+ ],
+ ),
+ ]
diff --git a/akarpov/users/migrations/0016_userapitoken_last_used.py b/akarpov/users/migrations/0016_userapitoken_last_used.py
new file mode 100644
index 0000000..0ab81ce
--- /dev/null
+++ b/akarpov/users/migrations/0016_userapitoken_last_used.py
@@ -0,0 +1,17 @@
+# Generated by Django 4.2.10 on 2024-03-29 18:47
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+ dependencies = [
+ ("users", "0015_userapitoken"),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name="userapitoken",
+ name="last_used",
+ field=models.DateTimeField(blank=True, null=True),
+ ),
+ ]
diff --git a/akarpov/users/migrations/0017_userapitoken_name.py b/akarpov/users/migrations/0017_userapitoken_name.py
new file mode 100644
index 0000000..1d1ed47
--- /dev/null
+++ b/akarpov/users/migrations/0017_userapitoken_name.py
@@ -0,0 +1,17 @@
+# Generated by Django 4.2.10 on 2024-03-29 19:31
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+ dependencies = [
+ ("users", "0016_userapitoken_last_used"),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name="userapitoken",
+ name="name",
+ field=models.CharField(blank=True, max_length=255, null=True),
+ ),
+ ]
diff --git a/akarpov/users/models.py b/akarpov/users/models.py
index 3578b24..4ef13c0 100644
--- a/akarpov/users/models.py
+++ b/akarpov/users/models.py
@@ -1,9 +1,12 @@
+import secrets
+
from django.contrib.auth.models import AbstractUser
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
from django.core.validators import MinValueValidator
from django.db import models
from django.urls import reverse
+from django.utils import timezone
from django.utils.translation import gettext_lazy as _
from akarpov.common.models import BaseImageModel
@@ -78,6 +81,46 @@ def __str__(self):
return self
-class UserNotification:
- # TODO: add notification system
- ...
+class UserAPIToken(models.Model):
+ name = models.CharField(max_length=255, blank=True, null=True)
+ user = models.ForeignKey(
+ "User", related_name="api_tokens", on_delete=models.CASCADE
+ )
+ token = models.CharField(max_length=255, unique=True, db_index=True)
+ created = models.DateTimeField(auto_now_add=True)
+ active_until = models.DateTimeField(null=True)
+ permissions = models.JSONField(default=dict)
+ last_used = models.DateTimeField(null=True, blank=True)
+
+ permission_template = {
+ "music": {
+ "listen": "Listen to music",
+ "upload": "Upload music",
+ "playlist": "Manage playlists",
+ },
+ "users": {
+ "edit": "Edit user profile",
+ "delete": "Delete user profile",
+ },
+ "tools": {
+ "shorten": "Shorten links",
+ },
+ "files": {
+ "upload": "Upload files",
+ "download": "Download files",
+ },
+ }
+
+ def __str__(self):
+ return self.token
+
+ @property
+ def is_active(self) -> bool:
+ return self.active_until is None or self.active_until > timezone.now()
+
+ @staticmethod
+ def generate_token():
+ token = secrets.token_urlsafe(32)
+ while UserAPIToken.objects.filter(token=token).exists():
+ token = secrets.token_urlsafe(32)
+ return token
diff --git a/akarpov/users/tasks.py b/akarpov/users/tasks.py
new file mode 100644
index 0000000..c0c8f4e
--- /dev/null
+++ b/akarpov/users/tasks.py
@@ -0,0 +1,11 @@
+from celery import shared_task
+from django.utils import timezone
+
+from akarpov.users.models import UserAPIToken
+
+
+@shared_task
+def set_last_active_token(token: str):
+ token = UserAPIToken.objects.get(token=token)
+ token.last_used = timezone.now()
+ token.save()
diff --git a/akarpov/users/urls.py b/akarpov/users/urls.py
index 6f662c7..60a997d 100644
--- a/akarpov/users/urls.py
+++ b/akarpov/users/urls.py
@@ -1,13 +1,17 @@
from django.urls import include, path
from akarpov.users.views import (
+ create_token,
+ delete_token,
enable_2fa_view,
enforce_otp_login,
+ list_tokens,
user_detail_view,
user_history_delete_view,
user_history_view,
user_redirect_view,
user_update_view,
+ view_token,
)
app_name = "users"
@@ -17,7 +21,11 @@
path("update/", view=user_update_view, name="update"),
path("history/", view=user_history_view, name="history"),
path("history/delete", view=user_history_delete_view, name="history_delete"),
- path("
/", view=user_detail_view, name="detail"),
+ path("", view=user_detail_view, name="detail"),
path("2fa/login", enforce_otp_login, name="enforce_otp_login"),
path("2fa/enable", enable_2fa_view, name="enable_2fa"),
+ path("tokens/", list_tokens, name="list_tokens"),
+ path("tokens/create/", create_token, name="create_token"),
+ path("tokens//", view_token, name="view_token"),
+ path("tokens//delete/", delete_token, name="delete_token"),
]
diff --git a/akarpov/users/views.py b/akarpov/users/views.py
index 8bcb916..ffb17cb 100644
--- a/akarpov/users/views.py
+++ b/akarpov/users/views.py
@@ -5,16 +5,16 @@
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.messages.views import SuccessMessageMixin
from django.contrib.sites.shortcuts import get_current_site
-from django.http import HttpResponseRedirect
-from django.shortcuts import redirect, render
+from django.http import HttpResponseRedirect, QueryDict
+from django.shortcuts import get_object_or_404, redirect, render
from django.urls import reverse, reverse_lazy
from django.utils.translation import gettext_lazy as _
from django.views.generic import DetailView, ListView, RedirectView, UpdateView
from django_otp import user_has_device
from django_otp.plugins.otp_totp.models import TOTPDevice
-from akarpov.users.forms import OTPForm
-from akarpov.users.models import UserHistory
+from akarpov.users.forms import OTPForm, TokenCreationForm
+from akarpov.users.models import UserAPIToken, UserHistory
from akarpov.users.services.history import create_history_warning_note
from akarpov.users.services.two_factor import generate_qr_code
from akarpov.users.themes.models import Theme
@@ -203,3 +203,70 @@ def enforce_otp_login(request):
else:
form = OTPForm()
return render(request, "users/otp_verify.html", {"form": form})
+
+
+@login_required
+def list_tokens(request):
+ tokens = UserAPIToken.objects.filter(user=request.user).order_by("-last_used")
+ return render(request, "users/list_tokens.html", {"tokens": tokens})
+
+
+@login_required
+def create_token(request):
+ initial_data = {}
+
+ # Обработка параметров 'name' и 'active_until'
+ if "name" in request.GET:
+ initial_data["name"] = request.GET["name"]
+ if "active_until" in request.GET:
+ initial_data["active_until"] = request.GET["active_until"]
+
+ # Создаем QueryDict для разрешений, чтобы правильно обработать повторяющиеся ключи
+ permissions_query_dict = QueryDict("", mutable=True)
+
+ # Разбор параметров разрешений
+ permissions = request.GET.getlist("permissions")
+ for perm in permissions:
+ category, permission = perm.split(".")
+ permissions_query_dict.update({f"permissions_{category}": [permission]})
+
+ # Переводим QueryDict в обычный словарь для использования в initial
+ permissions_data = {key: value for key, value in permissions_query_dict.lists()}
+
+ initial_data.update(permissions_data)
+
+ for key, value_list in permissions_data.items():
+ initial_data[key] = [item for sublist in value_list for item in sublist]
+
+ form = TokenCreationForm(
+ initial=initial_data, permissions_context=UserAPIToken.permission_template
+ )
+ if request.method == "POST":
+ print(request.POST)
+ form = TokenCreationForm(request.POST)
+ if form.is_valid():
+ new_token = form.save(commit=False)
+ new_token.user = request.user
+ new_token.token = UserAPIToken.generate_token()
+ new_token.save()
+ token_created = new_token.token
+ return render(
+ request, "users/token_created.html", {"new_token": token_created}
+ )
+
+ return render(request, "users/create_token.html", {"form": form})
+
+
+@login_required
+def view_token(request, token_id):
+ token = get_object_or_404(UserAPIToken, id=token_id, user=request.user)
+ return render(request, "users/view_token.html", {"token": token})
+
+
+@login_required
+def delete_token(request, token_id):
+ token = get_object_or_404(UserAPIToken, id=token_id, user=request.user)
+ if request.method == "POST":
+ token.delete()
+ return redirect("users:list_tokens")
+ return render(request, "users/confirm_delete_token.html", {"token": token})
diff --git a/config/settings/base.py b/config/settings/base.py
index 959f1c2..c385457 100644
--- a/config/settings/base.py
+++ b/config/settings/base.py
@@ -1,6 +1,7 @@
"""
Base settings to build other settings files upon.
"""
+
from pathlib import Path
import environ
@@ -78,6 +79,7 @@
"auth.permission": {"ops": "all", "timeout": 60 * 15},
"music.*": {"ops": ("fetch", "get", "list"), "timeout": 60 * 15},
"otp_totp.totpdevice": {"ops": "all", "timeout": 15 * 60},
+ "users.userapitoken": {"ops": "all", "timeout": 20 * 60},
}
CACHEOPS_REDIS = env.str("REDIS_URL")
@@ -131,8 +133,7 @@
"rest_framework.authtoken",
"corsheaders",
"drf_spectacular",
- "ckeditor",
- "ckeditor_uploader",
+ "django_ckeditor_5",
"colorfield",
"polymorphic",
"cacheops",
@@ -510,6 +511,7 @@
"DEFAULT_AUTHENTICATION_CLASSES": (
"rest_framework.authentication.SessionAuthentication",
"rest_framework.authentication.TokenAuthentication",
+ "akarpov.users.api.authentification.UserTokenAuthentication",
),
"DEFAULT_PERMISSION_CLASSES": ("rest_framework.permissions.IsAuthenticated",),
"DEFAULT_SCHEMA_CLASS": "drf_spectacular.openapi.AutoSchema",
@@ -530,24 +532,128 @@
# CKEDITOR
# ------------------------------------------------------------------------------
-CKEDITOR_UPLOAD_PATH = "uploads/"
-CKEDITOR_CONFIGS = {
+CKEDITOR_5_UPLOAD_PATH = "uploads/"
+CKEDITOR_5_CONFIGS = {
"default": {
- "width": "full",
- "extra_plugins": [
- "autosave",
- "autogrow",
- "autolink",
- "autoembed",
- "clipboard",
- "dialog",
- "dialogui",
+ "toolbar": [
+ "heading",
+ "|",
+ "bold",
+ "italic",
+ "link",
+ "bulletedList",
+ "numberedList",
+ "blockQuote",
+ "imageUpload",
],
- "autosave": {
- "autoLoad": True,
- "delay": 60,
- "NotOlderThen": 20,
+ },
+ "extends": {
+ "blockToolbar": [
+ "paragraph",
+ "heading1",
+ "heading2",
+ "heading3",
+ "|",
+ "bulletedList",
+ "numberedList",
+ "|",
+ "blockQuote",
+ ],
+ "toolbar": [
+ "heading",
+ "|",
+ "outdent",
+ "indent",
+ "|",
+ "bold",
+ "italic",
+ "link",
+ "underline",
+ "strikethrough",
+ "code",
+ "subscript",
+ "superscript",
+ "highlight",
+ "|",
+ "codeBlock",
+ "sourceEditing",
+ "insertImage",
+ "bulletedList",
+ "numberedList",
+ "todoList",
+ "|",
+ "blockQuote",
+ "imageUpload",
+ "|",
+ "fontSize",
+ "fontFamily",
+ "fontColor",
+ "fontBackgroundColor",
+ "mediaEmbed",
+ "removeFormat",
+ "insertTable",
+ ],
+ "image": {
+ "toolbar": [
+ "imageTextAlternative",
+ "|",
+ "imageStyle:alignLeft",
+ "imageStyle:alignRight",
+ "imageStyle:alignCenter",
+ "imageStyle:side",
+ "|",
+ ],
+ "styles": [
+ "full",
+ "side",
+ "alignLeft",
+ "alignRight",
+ "alignCenter",
+ ],
},
+ "table": {
+ "contentToolbar": [
+ "tableColumn",
+ "tableRow",
+ "mergeTableCells",
+ "tableProperties",
+ "tableCellProperties",
+ ],
+ },
+ "heading": {
+ "options": [
+ {
+ "model": "paragraph",
+ "title": "Paragraph",
+ "class": "ck-heading_paragraph",
+ },
+ {
+ "model": "heading1",
+ "view": "h1",
+ "title": "Heading 1",
+ "class": "ck-heading_heading1",
+ },
+ {
+ "model": "heading2",
+ "view": "h2",
+ "title": "Heading 2",
+ "class": "ck-heading_heading2",
+ },
+ {
+ "model": "heading3",
+ "view": "h3",
+ "title": "Heading 3",
+ "class": "ck-heading_heading3",
+ },
+ ]
+ },
+ },
+ "list": {
+ "properties": {
+ "styles": "true",
+ "startIndex": "true",
+ "reversed": "true",
+ }
},
}
diff --git a/config/urls.py b/config/urls.py
index e63f2c6..04b2be6 100644
--- a/config/urls.py
+++ b/config/urls.py
@@ -43,7 +43,9 @@
path("forms/", include("akarpov.test_platform.urls", namespace="forms")),
path("tools/", include("akarpov.tools.urls", namespace="tools")),
path("gallery/", include("akarpov.gallery.urls", namespace="gallery")),
- path("ckeditor/", include("ckeditor_uploader.urls")),
+ path(
+ "ckeditor5/", include("django_ckeditor_5.urls"), name="ck_editor_5_upload_file"
+ ),
path("accounts/", include("allauth.urls")),
path("accounts/login/", OTPLoginView.as_view(), name="account_login"),
path("", include("akarpov.blog.urls", namespace="blog")),
diff --git a/poetry.lock b/poetry.lock
index f85e17a..8e91a42 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -1,10 +1,9 @@
-# This file is automatically @generated by Poetry 1.4.2 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 = "aiofiles"
version = "23.2.1"
description = "File support for asyncio."
-category = "main"
optional = false
python-versions = ">=3.7"
files = [
@@ -16,7 +15,6 @@ files = [
name = "aiohttp"
version = "3.9.3"
description = "Async http client/server framework (asyncio)"
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -112,7 +110,6 @@ speedups = ["Brotli", "aiodns", "brotlicffi"]
name = "aiosignal"
version = "1.3.1"
description = "aiosignal: a list of registered asynchronous callbacks"
-category = "main"
optional = false
python-versions = ">=3.7"
files = [
@@ -127,7 +124,6 @@ frozenlist = ">=1.1.0"
name = "alabaster"
version = "0.7.16"
description = "A light, configurable Sphinx theme"
-category = "main"
optional = false
python-versions = ">=3.9"
files = [
@@ -139,7 +135,6 @@ files = [
name = "amqp"
version = "5.2.0"
description = "Low-level AMQP client for Python (fork of amqplib)."
-category = "main"
optional = false
python-versions = ">=3.6"
files = [
@@ -154,7 +149,6 @@ vine = ">=5.0.0,<6.0.0"
name = "amzqr"
version = "0.0.1"
description = "Generater for amazing QR Codes. Including Common, Artistic and Animated QR Codes."
-category = "main"
optional = false
python-versions = ">=3"
files = [
@@ -171,7 +165,6 @@ Pillow = ">=3.3.1"
name = "annotated-types"
version = "0.6.0"
description = "Reusable constraint types to use with typing.Annotated"
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -183,7 +176,6 @@ files = [
name = "anyio"
version = "4.3.0"
description = "High level compatibility layer for multiple asynchronous event loop implementations"
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -204,7 +196,6 @@ trio = ["trio (>=0.23)"]
name = "appdirs"
version = "1.4.4"
description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
-category = "main"
optional = false
python-versions = "*"
files = [
@@ -216,7 +207,6 @@ files = [
name = "argcomplete"
version = "3.2.2"
description = "Bash tab completion for argparse"
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -231,7 +221,6 @@ test = ["coverage", "mypy", "pexpect", "ruff", "wheel"]
name = "argon2-cffi"
version = "21.3.0"
description = "The secure Argon2 password hashing algorithm."
-category = "main"
optional = false
python-versions = ">=3.6"
files = [
@@ -251,7 +240,6 @@ tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pytest"]
name = "argon2-cffi-bindings"
version = "21.2.0"
description = "Low-level CFFI bindings for Argon2"
-category = "main"
optional = false
python-versions = ">=3.6"
files = [
@@ -289,7 +277,6 @@ tests = ["pytest"]
name = "asgiref"
version = "3.7.2"
description = "ASGI specs, helper code, and adapters"
-category = "main"
optional = false
python-versions = ">=3.7"
files = [
@@ -304,7 +291,6 @@ tests = ["mypy (>=0.800)", "pytest", "pytest-asyncio"]
name = "astroid"
version = "3.1.0"
description = "An abstract syntax tree for Python with inference support."
-category = "main"
optional = false
python-versions = ">=3.8.0"
files = [
@@ -316,7 +302,6 @@ files = [
name = "asttokens"
version = "2.4.1"
description = "Annotate AST trees with source code positions"
-category = "main"
optional = false
python-versions = "*"
files = [
@@ -335,7 +320,6 @@ test = ["astroid (>=1,<2)", "astroid (>=2,<4)", "pytest"]
name = "async-timeout"
version = "4.0.3"
description = "Timeout context manager for asyncio programs"
-category = "main"
optional = false
python-versions = ">=3.7"
files = [
@@ -347,7 +331,6 @@ files = [
name = "attrs"
version = "23.2.0"
description = "Classes Without Boilerplate"
-category = "main"
optional = false
python-versions = ">=3.7"
files = [
@@ -367,7 +350,6 @@ tests-no-zope = ["attrs[tests-mypy]", "cloudpickle", "hypothesis", "pympler", "p
name = "audioread"
version = "3.0.1"
description = "Multi-library, cross-platform audio decoding."
-category = "main"
optional = false
python-versions = ">=3.6"
files = [
@@ -382,7 +364,6 @@ test = ["tox"]
name = "autobahn"
version = "23.6.2"
description = "WebSocket client & server library, WAMP real-time framework"
-category = "main"
optional = false
python-versions = ">=3.9"
files = [
@@ -411,7 +392,6 @@ xbr = ["base58 (>=2.1.0)", "bitarray (>=2.7.5)", "cbor2 (>=5.2.0)", "click (>=8.
name = "automat"
version = "22.10.0"
description = "Self-service finite-state machines for the programmer on the go."
-category = "main"
optional = false
python-versions = "*"
files = [
@@ -430,7 +410,6 @@ visualize = ["Twisted (>=16.1.1)", "graphviz (>0.5.1)"]
name = "babel"
version = "2.14.0"
description = "Internationalization utilities"
-category = "main"
optional = false
python-versions = ">=3.7"
files = [
@@ -445,7 +424,6 @@ dev = ["freezegun (>=1.0,<2.0)", "pytest (>=6.0)", "pytest-cov"]
name = "beautifulsoup4"
version = "4.12.3"
description = "Screen-scraping library"
-category = "main"
optional = false
python-versions = ">=3.6.0"
files = [
@@ -467,7 +445,6 @@ lxml = ["lxml"]
name = "billiard"
version = "4.2.0"
description = "Python multiprocessing fork with improvements and bugfixes"
-category = "main"
optional = false
python-versions = ">=3.7"
files = [
@@ -479,7 +456,6 @@ files = [
name = "black"
version = "23.12.1"
description = "The uncompromising code formatter."
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -524,7 +500,6 @@ uvloop = ["uvloop (>=0.15.2)"]
name = "brotli"
version = "1.1.0"
description = "Python bindings for the Brotli compression library"
-category = "main"
optional = false
python-versions = "*"
files = [
@@ -617,7 +592,6 @@ files = [
name = "brotlicffi"
version = "1.1.0.0"
description = "Python CFFI bindings to the Brotli library"
-category = "main"
optional = false
python-versions = ">=3.7"
files = [
@@ -657,7 +631,6 @@ cffi = ">=1.0.0"
name = "cairocffi"
version = "1.6.1"
description = "cffi-based cairo bindings for Python"
-category = "main"
optional = false
python-versions = ">=3.7"
files = [
@@ -677,7 +650,6 @@ xcb = ["xcffib (>=1.4.0)"]
name = "cairosvg"
version = "2.7.1"
description = "A Simple SVG Converter based on Cairo"
-category = "main"
optional = false
python-versions = ">=3.5"
files = [
@@ -700,7 +672,6 @@ test = ["flake8", "isort", "pytest"]
name = "celery"
version = "5.3.6"
description = "Distributed Task Queue."
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -757,7 +728,6 @@ zstd = ["zstandard (==0.22.0)"]
name = "certifi"
version = "2024.2.2"
description = "Python package for providing Mozilla's CA Bundle."
-category = "main"
optional = false
python-versions = ">=3.6"
files = [
@@ -769,7 +739,6 @@ files = [
name = "cffi"
version = "1.16.0"
description = "Foreign Function Interface for Python calling C code."
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -834,7 +803,6 @@ pycparser = "*"
name = "cfgv"
version = "3.4.0"
description = "Validate configuration and produce human readable error messages."
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -846,7 +814,6 @@ files = [
name = "channels"
version = "4.0.0"
description = "Brings async, event-driven capabilities to Django 3.2 and up."
-category = "main"
optional = false
python-versions = ">=3.7"
files = [
@@ -867,7 +834,6 @@ tests = ["async-timeout", "coverage (>=4.5,<5.0)", "pytest", "pytest-asyncio", "
name = "channels-redis"
version = "4.2.0"
description = "Redis-backed ASGI channel layer implementation"
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -889,7 +855,6 @@ tests = ["async-timeout", "cryptography (>=1.3.0)", "pytest", "pytest-asyncio",
name = "chardet"
version = "5.2.0"
description = "Universal encoding detector for Python 3"
-category = "main"
optional = false
python-versions = ">=3.7"
files = [
@@ -901,7 +866,6 @@ files = [
name = "charset-normalizer"
version = "3.3.2"
description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet."
-category = "main"
optional = false
python-versions = ">=3.7.0"
files = [
@@ -1001,7 +965,6 @@ files = [
name = "click"
version = "8.1.7"
description = "Composable command line interface toolkit"
-category = "main"
optional = false
python-versions = ">=3.7"
files = [
@@ -1016,7 +979,6 @@ colorama = {version = "*", markers = "platform_system == \"Windows\""}
name = "click-didyoumean"
version = "0.3.0"
description = "Enables git-like *did-you-mean* feature in click"
-category = "main"
optional = false
python-versions = ">=3.6.2,<4.0.0"
files = [
@@ -1031,7 +993,6 @@ click = ">=7"
name = "click-plugins"
version = "1.1.1"
description = "An extension module for click to enable registering CLI commands via setuptools entry-points."
-category = "main"
optional = false
python-versions = "*"
files = [
@@ -1049,7 +1010,6 @@ dev = ["coveralls", "pytest (>=3.6)", "pytest-cov", "wheel"]
name = "click-repl"
version = "0.3.0"
description = "REPL plugin for Click"
-category = "main"
optional = false
python-versions = ">=3.6"
files = [
@@ -1068,7 +1028,6 @@ testing = ["pytest (>=7.2.1)", "pytest-cov (>=4.0.0)", "tox (>=4.4.3)"]
name = "colorama"
version = "0.4.6"
description = "Cross-platform colored terminal text."
-category = "main"
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
files = [
@@ -1080,7 +1039,6 @@ files = [
name = "colorclass"
version = "2.2.2"
description = "Colorful worry-free console applications for Linux, Mac OS X, and Windows."
-category = "main"
optional = false
python-versions = ">=2.6"
files = [
@@ -1092,7 +1050,6 @@ files = [
name = "compressed-rtf"
version = "1.0.6"
description = "Compressed Rich Text Format (RTF) compression and decompression package"
-category = "main"
optional = false
python-versions = "*"
files = [
@@ -1103,7 +1060,6 @@ files = [
name = "constantly"
version = "23.10.4"
description = "Symbolic constants in Python"
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -1115,7 +1071,6 @@ files = [
name = "contourpy"
version = "1.2.0"
description = "Python library for calculating contours of 2D quadrilateral grids"
-category = "main"
optional = false
python-versions = ">=3.9"
files = [
@@ -1179,7 +1134,6 @@ test-no-images = ["pytest", "pytest-cov", "pytest-xdist", "wurlitzer"]
name = "coverage"
version = "7.4.3"
description = "Code coverage measurement for Python"
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -1244,7 +1198,6 @@ toml = ["tomli"]
name = "crispy-bootstrap5"
version = "0.7"
description = "Bootstrap5 template pack for django-crispy-forms"
-category = "main"
optional = false
python-versions = ">=3.7"
files = [
@@ -1263,7 +1216,6 @@ test = ["pytest", "pytest-django"]
name = "cron-descriptor"
version = "1.4.3"
description = "A Python library that converts cron expressions into human readable strings."
-category = "main"
optional = false
python-versions = "*"
files = [
@@ -1278,7 +1230,6 @@ dev = ["polib"]
name = "cryptography"
version = "42.0.5"
description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers."
-category = "main"
optional = false
python-versions = ">=3.7"
files = [
@@ -1333,7 +1284,6 @@ test-randomorder = ["pytest-randomly"]
name = "cssselect2"
version = "0.7.0"
description = "CSS selectors for Python ElementTree"
-category = "main"
optional = false
python-versions = ">=3.7"
files = [
@@ -1353,7 +1303,6 @@ test = ["flake8", "isort", "pytest"]
name = "cycler"
version = "0.12.1"
description = "Composable style cycles"
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -1369,7 +1318,6 @@ tests = ["pytest", "pytest-cov", "pytest-xdist"]
name = "dacite"
version = "1.8.1"
description = "Simple creation of data classes from dictionaries."
-category = "main"
optional = false
python-versions = ">=3.6"
files = [
@@ -1383,7 +1331,6 @@ dev = ["black", "coveralls", "mypy", "pre-commit", "pylint", "pytest (>=5)", "py
name = "daphne"
version = "4.1.0"
description = "Django ASGI (HTTP/WebSocket) server"
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -1403,7 +1350,6 @@ tests = ["django", "hypothesis", "pytest", "pytest-asyncio"]
name = "dawg-python"
version = "0.7.2"
description = "Pure-python reader for DAWGs (DAFSAs) created by dawgdic C++ library or DAWG Python extension."
-category = "main"
optional = false
python-versions = "*"
files = [
@@ -1415,7 +1361,6 @@ files = [
name = "decorator"
version = "5.1.1"
description = "Decorators for Humans"
-category = "main"
optional = false
python-versions = ">=3.5"
files = [
@@ -1427,7 +1372,6 @@ files = [
name = "deep-translator"
version = "1.4.2"
description = "A flexible python tool to translate between different languages in a simple way."
-category = "main"
optional = false
python-versions = ">=3.0"
files = [
@@ -1443,7 +1387,6 @@ requests = "*"
name = "defusedxml"
version = "0.7.1"
description = "XML bomb protection for Python stdlib modules"
-category = "main"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
files = [
@@ -1455,7 +1398,6 @@ files = [
name = "deprecated"
version = "1.2.14"
description = "Python @deprecated decorator to deprecate old python classes, functions or methods."
-category = "main"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
files = [
@@ -1473,7 +1415,6 @@ dev = ["PyTest", "PyTest-Cov", "bump2version (<1)", "sphinx (<2)", "tox"]
name = "dill"
version = "0.3.8"
description = "serialize all of Python"
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -1489,7 +1430,6 @@ profile = ["gprof2dot (>=2022.7.29)"]
name = "distlib"
version = "0.3.8"
description = "Distribution utilities"
-category = "main"
optional = false
python-versions = "*"
files = [
@@ -1501,7 +1441,6 @@ files = [
name = "django"
version = "4.2.10"
description = "A high-level Python web framework that encourages rapid development and clean, pragmatic design."
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -1522,7 +1461,6 @@ bcrypt = ["bcrypt"]
name = "django-active-link"
version = "0.1.8"
description = "The best way to highlight active links in your Django app."
-category = "main"
optional = false
python-versions = "*"
files = [
@@ -1534,7 +1472,6 @@ files = [
name = "django-allauth"
version = "0.54.0"
description = "Integrated set of Django applications addressing authentication, registration, account management as well as 3rd party (social) account authentication."
-category = "main"
optional = false
python-versions = ">=3.7"
files = [
@@ -1552,7 +1489,6 @@ requests-oauthlib = ">=0.3.0"
name = "django-anymail"
version = "10.2"
description = "Django email backends and webhooks for Amazon SES, Brevo (Sendinblue), MailerSend, Mailgun, Mailjet, Mandrill, Postal, Postmark, Resend, SendGrid, and SparkPost"
-category = "main"
optional = false
python-versions = ">=3.7"
files = [
@@ -1574,7 +1510,6 @@ resend = ["svix"]
name = "django-cacheops"
version = "7.0.2"
description = "A slick ORM cache with automatic granular event-driven invalidation for Django."
-category = "main"
optional = false
python-versions = ">=3.7"
files = [
@@ -1590,7 +1525,6 @@ redis = ">=3.0.0"
name = "django-celery-beat"
version = "2.5.0"
description = "Database-backed Periodic Tasks."
-category = "main"
optional = false
python-versions = "*"
files = [
@@ -1607,26 +1541,27 @@ python-crontab = ">=2.3.4"
tzdata = "*"
[[package]]
-name = "django-ckeditor"
-version = "6.7.1"
-description = "Django admin CKEditor integration."
-category = "main"
+name = "django-ckeditor-5"
+version = "0.2.12"
+description = "CKEditor 5 for Django."
optional = false
-python-versions = ">=3.8"
+python-versions = ">=3.7"
files = [
- {file = "django-ckeditor-6.7.1.tar.gz", hash = "sha256:7144f9ead662306266c728912487313b3b87ba2abf9dbb82c447f662ce25d1f7"},
- {file = "django_ckeditor-6.7.1-py3-none-any.whl", hash = "sha256:55b5f9ce3af47e3c8a8ed37d42be8439da2a664d6e571c2247c1db5c96459dd7"},
+ {file = "django-ckeditor-5-0.2.12.tar.gz", hash = "sha256:c7165f3736f3d29dddaeda09c175903bdf3cf2b3f376c46aa5be2cc30c2c4e97"},
+ {file = "django_ckeditor_5-0.2.12-py3-none-any.whl", hash = "sha256:f32cf1ce6e498d114baed8eda4b81526d61f55b55ee67ed985c26714365344e5"},
]
[package.dependencies]
-Django = ">=3.2"
-django-js-asset = ">=2.0"
+Django = ">=2.2"
+Pillow = "*"
+
+[package.extras]
+dev = ["bandit[toml] (==1.7.6)", "black (==22.12.0)", "codespell (==2.2.2)", "coverage (==7.4.0)", "mypy (==1.8.0)", "mypy-extensions (==1.0.0)", "pytest (==7.4.4)", "pytest-cov (==4.0.0)", "pytest-django (==4.5.2)", "pytest-mock (==3.10.0)", "safety (==2.3.5)", "types-setuptools (==65.6.0.2)", "typing-extensions (==4.9.0)"]
[[package]]
name = "django-classy-tags"
version = "4.1.0"
description = "Class based template tags for Django"
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -1641,7 +1576,6 @@ django = ">=3.2"
name = "django-colorfield"
version = "0.11.0"
description = "color field for django models with a nice color-picker in the admin."
-category = "main"
optional = false
python-versions = "*"
files = [
@@ -1656,7 +1590,6 @@ Pillow = ">=9.0.0"
name = "django-cors-headers"
version = "4.3.1"
description = "django-cors-headers is a Django application for handling the server headers required for Cross-Origin Resource Sharing (CORS)."
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -1672,7 +1605,6 @@ Django = ">=3.2"
name = "django-coverage-plugin"
version = "3.1.0"
description = "Django template coverage.py plugin"
-category = "main"
optional = false
python-versions = "*"
files = [
@@ -1687,7 +1619,6 @@ coverage = "*"
name = "django-crispy-forms"
version = "2.1"
description = "Best way to have Django DRY forms"
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -1702,7 +1633,6 @@ django = ">=4.2"
name = "django-debug-toolbar"
version = "4.3.0"
description = "A configurable set of panels that display various debug information about the current request/response."
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -1718,7 +1648,6 @@ sqlparse = ">=0.2"
name = "django-elasticsearch-dsl"
version = "8.0"
description = "Wrapper around elasticsearch-dsl-py for django models"
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -1737,7 +1666,6 @@ celery = ["celery (>=4.1.0)"]
name = "django-environ"
version = "0.9.0"
description = "A package that allows you to utilize 12factor inspired environment variables to configure your Django application."
-category = "main"
optional = false
python-versions = ">=3.4,<4"
files = [
@@ -1746,15 +1674,14 @@ files = [
]
[package.extras]
-develop = ["coverage[toml] (>=5.0a4)", "furo (>=2021.8.17b43,<2021.9.0)", "pytest (>=4.6.11)", "sphinx (>=3.5.0)", "sphinx-notfound-page"]
-docs = ["furo (>=2021.8.17b43,<2021.9.0)", "sphinx (>=3.5.0)", "sphinx-notfound-page"]
+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-extensions"
version = "3.2.3"
description = "Extensions for Django"
-category = "main"
optional = false
python-versions = ">=3.6"
files = [
@@ -1769,7 +1696,6 @@ Django = ">=3.2"
name = "django-extra-settings"
version = "0.9.1"
description = "config and manage typed extra settings using just the django admin."
-category = "main"
optional = false
python-versions = "*"
files = [
@@ -1784,7 +1710,6 @@ jsonfield = ">=3.0.0"
name = "django-filter"
version = "23.5"
description = "Django-filter is a reusable Django application for allowing users to filter querysets dynamically."
-category = "main"
optional = false
python-versions = ">=3.7"
files = [
@@ -1799,7 +1724,6 @@ Django = ">=3.2"
name = "django-health-check"
version = "3.18.1"
description = "Run checks on services like databases, queue servers, celery processes, etc."
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -1818,7 +1742,6 @@ test = ["celery", "pytest", "pytest-cov", "pytest-django", "redis"]
name = "django-ipware"
version = "5.0.2"
description = "A Django application to retrieve user's IP address"
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -1830,7 +1753,6 @@ files = [
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"
-category = "main"
optional = false
python-versions = ">=3.6.2"
files = [
@@ -1841,29 +1763,10 @@ files = [
[package.dependencies]
django = ">=2.2"
-[[package]]
-name = "django-js-asset"
-version = "2.2.0"
-description = "script tag with additional attributes for django.forms.Media"
-category = "main"
-optional = false
-python-versions = ">=3.8"
-files = [
- {file = "django_js_asset-2.2.0-py3-none-any.whl", hash = "sha256:7ef3e858e13d06f10799b56eea62b1e76706f42cf4e709be4e13356bc0ae30d8"},
- {file = "django_js_asset-2.2.0.tar.gz", hash = "sha256:0c57a82cae2317e83951d956110ce847f58ff0cdc24e314dbc18b35033917e94"},
-]
-
-[package.dependencies]
-django = ">=3.2"
-
-[package.extras]
-tests = ["coverage"]
-
[[package]]
name = "django-location-field"
version = "2.7.3"
description = "Location field for Django"
-category = "main"
optional = false
python-versions = "*"
files = [
@@ -1874,7 +1777,6 @@ files = [
name = "django-model-utils"
version = "4.4.0"
description = "Django model mixins and utilities"
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -1889,7 +1791,6 @@ Django = ">=3.2"
name = "django-otp"
version = "1.3.0"
description = "A pluggable framework for adding two-factor authentication to Django using one-time passwords."
-category = "main"
optional = false
python-versions = ">=3.7"
files = [
@@ -1907,7 +1808,6 @@ qrcode = ["qrcode"]
name = "django-polymorphic"
version = "3.1.0"
description = "Seamless polymorphic inheritance for Django models"
-category = "main"
optional = false
python-versions = "*"
files = [
@@ -1922,7 +1822,6 @@ Django = ">=2.1"
name = "django-redis"
version = "5.4.0"
description = "Full featured redis cache backend for Django."
-category = "main"
optional = false
python-versions = ">=3.6"
files = [
@@ -1941,7 +1840,6 @@ hiredis = ["redis[hiredis] (>=3,!=4.0.0,!=4.0.1)"]
name = "django-rest-auth"
version = "0.9.5"
description = "Create a set of REST API endpoints for Authentication and Registration"
-category = "main"
optional = false
python-versions = "*"
files = [
@@ -1960,7 +1858,6 @@ with-social = ["django-allauth (>=0.25.0)"]
name = "django-robots"
version = "5.0"
description = "Robots exclusion application for Django, complementing Sitemaps."
-category = "main"
optional = false
python-versions = ">=3.7"
files = [
@@ -1971,7 +1868,6 @@ files = [
name = "django-sekizai"
version = "4.1.0"
description = "Django Sekizai"
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -1987,7 +1883,6 @@ django-classy-tags = ">=3.0"
name = "django-structlog"
version = "5.3.0"
description = "Structured Logging for Django"
-category = "main"
optional = false
python-versions = ">=3.7"
files = [
@@ -2008,7 +1903,6 @@ celery = ["celery (>=5.1)"]
name = "django-stubs"
version = "1.14.0"
description = "Mypy stubs for Django"
-category = "main"
optional = false
python-versions = ">=3.7"
files = [
@@ -2035,7 +1929,6 @@ compatible-mypy = ["mypy (>=0.991,<1.0)"]
name = "django-stubs-ext"
version = "4.2.7"
description = "Monkey-patching and extensions for django-stubs"
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -2051,7 +1944,6 @@ typing-extensions = "*"
name = "django-tables2"
version = "2.7.0"
description = "Table/data-grid framework for Django"
-category = "main"
optional = false
python-versions = "*"
files = [
@@ -2069,7 +1961,6 @@ tablib = ["tablib"]
name = "django-timezone-field"
version = "6.1.0"
description = "A Django app providing DB, form, and REST framework fields for zoneinfo and pytz timezone objects."
-category = "main"
optional = false
python-versions = ">=3.8,<4.0"
files = [
@@ -2084,7 +1975,6 @@ Django = ">=3.2,<6.0"
name = "django-upload-validator"
version = "1.1.6"
description = "A simple Django file type validator using python-magic"
-category = "main"
optional = false
python-versions = "*"
files = [
@@ -2099,7 +1989,6 @@ python-magic = "*"
name = "djangorestframework"
version = "3.14.0"
description = "Web APIs for Django, made easy."
-category = "main"
optional = false
python-versions = ">=3.6"
files = [
@@ -2115,7 +2004,6 @@ pytz = "*"
name = "djangorestframework-stubs"
version = "1.8.0"
description = "PEP-484 stubs for django-rest-framework"
-category = "main"
optional = false
python-versions = ">=3.7"
files = [
@@ -2143,7 +2031,6 @@ markdown = ["types-Markdown (>=0.1.5)"]
name = "docutils"
version = "0.20.1"
description = "Docutils -- Python Documentation Utilities"
-category = "main"
optional = false
python-versions = ">=3.7"
files = [
@@ -2155,7 +2042,6 @@ files = [
name = "docx2txt"
version = "0.8"
description = "A pure python-based utility to extract text and images from docx files."
-category = "main"
optional = false
python-versions = "*"
files = [
@@ -2166,7 +2052,6 @@ files = [
name = "drf-spectacular"
version = "0.26.5"
description = "Sane and flexible OpenAPI 3 schema generation for Django REST framework"
-category = "main"
optional = false
python-versions = ">=3.6"
files = [
@@ -2190,7 +2075,6 @@ sidecar = ["drf-spectacular-sidecar"]
name = "easygui"
version = "0.98.3"
description = "EasyGUI is a module for very simple, very easy GUI programming in Python. EasyGUI is different from other GUI generators in that EasyGUI is NOT event-driven. Instead, all GUI interactions are invoked by simple function calls."
-category = "main"
optional = false
python-versions = "*"
files = [
@@ -2202,7 +2086,6 @@ files = [
name = "ebcdic"
version = "1.1.1"
description = "Additional EBCDIC codecs"
-category = "main"
optional = false
python-versions = "*"
files = [
@@ -2213,7 +2096,6 @@ files = [
name = "elastic-transport"
version = "8.12.0"
description = "Transport classes and utilities shared among Python Elastic client libraries"
-category = "main"
optional = false
python-versions = ">=3.7"
files = [
@@ -2232,7 +2114,6 @@ develop = ["aiohttp", "furo", "mock", "pytest", "pytest-asyncio", "pytest-cov",
name = "elasticsearch"
version = "8.12.1"
description = "Python client for Elasticsearch"
-category = "main"
optional = false
python-versions = ">=3.7"
files = [
@@ -2251,7 +2132,6 @@ requests = ["requests (>=2.4.0,<3.0.0)"]
name = "elasticsearch-dsl"
version = "8.12.0"
description = "Python client for Elasticsearch"
-category = "main"
optional = false
python-versions = ">=3.7"
files = [
@@ -2270,7 +2150,6 @@ develop = ["coverage", "pytest", "pytest-cov", "pytest-mock", "pytz", "sphinx (>
name = "execnet"
version = "2.0.2"
description = "execnet: rapid multi-Python deployment"
-category = "main"
optional = false
python-versions = ">=3.7"
files = [
@@ -2285,7 +2164,6 @@ testing = ["hatch", "pre-commit", "pytest", "tox"]
name = "executing"
version = "2.0.1"
description = "Get the currently executing AST node of a frame, and other information"
-category = "main"
optional = false
python-versions = ">=3.5"
files = [
@@ -2300,7 +2178,6 @@ tests = ["asttokens (>=2.1.0)", "coverage", "coverage-enable-subprocess", "ipyth
name = "extract-msg"
version = "0.47.0"
description = "Extracts emails and attachments saved in Microsoft Outlook's .msg files"
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -2328,7 +2205,6 @@ readthedocs = ["sphinx-rtd-theme"]
name = "factory-boy"
version = "3.3.0"
description = "A versatile test fixtures replacement based on thoughtbot's factory_bot for Ruby."
-category = "main"
optional = false
python-versions = ">=3.7"
files = [
@@ -2347,7 +2223,6 @@ doc = ["Sphinx", "sphinx-rtd-theme", "sphinxcontrib-spelling"]
name = "faker"
version = "23.3.0"
description = "Faker is a Python package that generates fake data for you."
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -2362,7 +2237,6 @@ python-dateutil = ">=2.4"
name = "fastapi"
version = "0.103.0"
description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production"
-category = "main"
optional = false
python-versions = ">=3.7"
files = [
@@ -2382,7 +2256,6 @@ all = ["email-validator (>=2.0.0)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)"
name = "ffmpeg-python"
version = "0.2.0"
description = "Python bindings for FFmpeg - with complex filtering support"
-category = "main"
optional = false
python-versions = "*"
files = [
@@ -2400,7 +2273,6 @@ dev = ["Sphinx (==2.1.0)", "future (==0.17.1)", "numpy (==1.16.4)", "pytest (==4
name = "filelock"
version = "3.13.1"
description = "A platform independent file lock."
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -2417,7 +2289,6 @@ typing = ["typing-extensions (>=4.8)"]
name = "flake8"
version = "6.1.0"
description = "the modular source code checker: pep8 pyflakes and co"
-category = "main"
optional = false
python-versions = ">=3.8.1"
files = [
@@ -2434,7 +2305,6 @@ pyflakes = ">=3.1.0,<3.2.0"
name = "flake8-isort"
version = "6.1.1"
description = "flake8 plugin that integrates isort"
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -2453,7 +2323,6 @@ test = ["pytest"]
name = "flower"
version = "2.0.1"
description = "Celery Flower"
-category = "main"
optional = false
python-versions = ">=3.7"
files = [
@@ -2472,7 +2341,6 @@ tornado = ">=5.0.0,<7.0.0"
name = "fonttools"
version = "4.49.0"
description = "Tools to manipulate font files"
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -2538,7 +2406,6 @@ woff = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "zopfli (>=0.1.4)"]
name = "frozenlist"
version = "1.4.1"
description = "A list-like structure which implements collections.abc.MutableSequence"
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -2625,7 +2492,6 @@ files = [
name = "funcy"
version = "2.0"
description = "A fancy and practical functional tools"
-category = "main"
optional = false
python-versions = "*"
files = [
@@ -2637,7 +2503,6 @@ files = [
name = "future"
version = "1.0.0"
description = "Clean single-source support for Python 3 and 2"
-category = "main"
optional = false
python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
files = [
@@ -2649,7 +2514,6 @@ files = [
name = "fuzzywuzzy"
version = "0.18.0"
description = "Fuzzy string matching in python"
-category = "main"
optional = false
python-versions = "*"
files = [
@@ -2664,7 +2528,6 @@ speedup = ["python-levenshtein (>=0.12)"]
name = "greenlet"
version = "3.0.3"
description = "Lightweight in-process concurrent programming"
-category = "main"
optional = false
python-versions = ">=3.7"
files = [
@@ -2736,7 +2599,6 @@ test = ["objgraph", "psutil"]
name = "gunicorn"
version = "21.2.0"
description = "WSGI HTTP Server for UNIX"
-category = "main"
optional = false
python-versions = ">=3.5"
files = [
@@ -2757,7 +2619,6 @@ tornado = ["tornado (>=0.2)"]
name = "h11"
version = "0.14.0"
description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1"
-category = "main"
optional = false
python-versions = ">=3.7"
files = [
@@ -2769,7 +2630,6 @@ files = [
name = "hiredis"
version = "2.3.2"
description = "Python wrapper for hiredis"
-category = "main"
optional = false
python-versions = ">=3.7"
files = [
@@ -2888,7 +2748,6 @@ files = [
name = "httpcore"
version = "1.0.4"
description = "A minimal low-level HTTP client."
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -2903,14 +2762,13 @@ h11 = ">=0.13,<0.15"
[package.extras]
asyncio = ["anyio (>=4.0,<5.0)"]
http2 = ["h2 (>=3,<5)"]
-socks = ["socksio (>=1.0.0,<2.0.0)"]
+socks = ["socksio (==1.*)"]
trio = ["trio (>=0.22.0,<0.25.0)"]
[[package]]
name = "httpx"
version = "0.27.0"
description = "The next generation HTTP client."
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -2921,21 +2779,20 @@ files = [
[package.dependencies]
anyio = "*"
certifi = "*"
-httpcore = ">=1.0.0,<2.0.0"
+httpcore = "==1.*"
idna = "*"
sniffio = "*"
[package.extras]
brotli = ["brotli", "brotlicffi"]
-cli = ["click (>=8.0.0,<9.0.0)", "pygments (>=2.0.0,<3.0.0)", "rich (>=10,<14)"]
+cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<14)"]
http2 = ["h2 (>=3,<5)"]
-socks = ["socksio (>=1.0.0,<2.0.0)"]
+socks = ["socksio (==1.*)"]
[[package]]
name = "humanize"
version = "4.9.0"
description = "Python humanize utilities"
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -2950,7 +2807,6 @@ tests = ["freezegun", "pytest", "pytest-cov"]
name = "hyperlink"
version = "21.0.0"
description = "A featureful, immutable, and correct URL for Python."
-category = "main"
optional = false
python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
files = [
@@ -2965,7 +2821,6 @@ idna = ">=2.5"
name = "identify"
version = "2.5.35"
description = "File identification library for Python"
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -2980,7 +2835,6 @@ license = ["ukkonen"]
name = "idna"
version = "3.6"
description = "Internationalized Domain Names in Applications (IDNA)"
-category = "main"
optional = false
python-versions = ">=3.5"
files = [
@@ -2992,7 +2846,6 @@ files = [
name = "imageio"
version = "2.34.0"
description = "Library for reading and writing a wide range of image, video, scientific, and volumetric data formats."
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -3025,7 +2878,6 @@ tifffile = ["tifffile"]
name = "imagesize"
version = "1.4.1"
description = "Getting image size from png/jpeg/jpeg2000/gif file"
-category = "main"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
files = [
@@ -3037,7 +2889,6 @@ files = [
name = "incremental"
version = "22.10.0"
description = "\"A small library that versions your Python projects.\""
-category = "main"
optional = false
python-versions = "*"
files = [
@@ -3053,7 +2904,6 @@ scripts = ["click (>=6.0)", "twisted (>=16.4.0)"]
name = "inflection"
version = "0.5.1"
description = "A port of Ruby on Rails inflector to Python"
-category = "main"
optional = false
python-versions = ">=3.5"
files = [
@@ -3065,7 +2915,6 @@ files = [
name = "iniconfig"
version = "2.0.0"
description = "brain-dead simple config-ini parsing"
-category = "main"
optional = false
python-versions = ">=3.7"
files = [
@@ -3077,7 +2926,6 @@ files = [
name = "ipdb"
version = "0.13.13"
description = "IPython-enabled pdb"
-category = "main"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
files = [
@@ -3093,7 +2941,6 @@ ipython = {version = ">=7.31.1", markers = "python_version >= \"3.11\""}
name = "ipython"
version = "8.22.1"
description = "IPython: Productive Interactive Computing"
-category = "main"
optional = false
python-versions = ">=3.10"
files = [
@@ -3129,7 +2976,6 @@ test-extra = ["curio", "ipython[test]", "matplotlib (!=3.2.0)", "nbformat", "num
name = "isort"
version = "5.13.2"
description = "A Python utility / library to sort Python imports."
-category = "main"
optional = false
python-versions = ">=3.8.0"
files = [
@@ -3144,7 +2990,6 @@ colors = ["colorama (>=0.4.6)"]
name = "jaconv"
version = "0.3.4"
description = "Pure-Python Japanese character interconverter for Hiragana, Katakana, Hankaku, Zenkaku and more"
-category = "main"
optional = false
python-versions = "*"
files = [
@@ -3155,7 +3000,6 @@ files = [
name = "jedi"
version = "0.19.1"
description = "An autocompletion tool for Python that can be used for text editors."
-category = "main"
optional = false
python-versions = ">=3.6"
files = [
@@ -3175,7 +3019,6 @@ testing = ["Django", "attrs", "colorama", "docopt", "pytest (<7.0.0)"]
name = "jinja2"
version = "3.1.3"
description = "A very fast and expressive template engine."
-category = "main"
optional = false
python-versions = ">=3.7"
files = [
@@ -3193,7 +3036,6 @@ i18n = ["Babel (>=2.7)"]
name = "joblib"
version = "1.3.2"
description = "Lightweight pipelining with Python functions"
-category = "main"
optional = false
python-versions = ">=3.7"
files = [
@@ -3205,7 +3047,6 @@ files = [
name = "jsonfield"
version = "3.1.0"
description = "A reusable Django field that allows you to store validated JSON in your model."
-category = "main"
optional = false
python-versions = ">=3.6"
files = [
@@ -3220,7 +3061,6 @@ Django = ">=2.2"
name = "jsonschema"
version = "4.21.1"
description = "An implementation of JSON Schema validation for Python"
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -3242,7 +3082,6 @@ format-nongpl = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-
name = "jsonschema-specifications"
version = "2023.12.1"
description = "The JSON Schema meta-schemas and vocabularies, exposed as a Registry"
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -3257,7 +3096,6 @@ referencing = ">=0.31.0"
name = "kiwisolver"
version = "1.4.5"
description = "A fast implementation of the Cassowary constraint solver"
-category = "main"
optional = false
python-versions = ">=3.7"
files = [
@@ -3371,7 +3209,6 @@ files = [
name = "kombu"
version = "5.3.5"
description = "Messaging library for Python."
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -3404,7 +3241,6 @@ zookeeper = ["kazoo (>=2.8.0)"]
name = "lark"
version = "1.1.8"
description = "a modern parsing library"
-category = "main"
optional = false
python-versions = ">=3.6"
files = [
@@ -3422,7 +3258,6 @@ regex = ["regex"]
name = "lazy-loader"
version = "0.3"
description = "lazy_loader"
-category = "main"
optional = false
python-versions = ">=3.7"
files = [
@@ -3438,7 +3273,6 @@ test = ["pytest (>=7.4)", "pytest-cov (>=4.1)"]
name = "levenshtein"
version = "0.23.0"
description = "Python extension for computing string edit distances and similarities."
-category = "main"
optional = false
python-versions = ">=3.7"
files = [
@@ -3559,7 +3393,6 @@ rapidfuzz = ">=3.1.0,<4.0.0"
name = "librosa"
version = "0.10.1"
description = "Python module for audio and music processing"
-category = "main"
optional = false
python-versions = ">=3.7"
files = [
@@ -3591,7 +3424,6 @@ tests = ["matplotlib (>=3.3.0)", "packaging (>=20.0)", "pytest", "pytest-cov", "
name = "livereload"
version = "2.6.3"
description = "Python LiveReload is an awesome tool for web developers"
-category = "main"
optional = false
python-versions = "*"
files = [
@@ -3607,7 +3439,6 @@ tornado = {version = "*", markers = "python_version > \"2.7\""}
name = "llvmlite"
version = "0.42.0"
description = "lightweight wrapper around basic LLVM functionality"
-category = "main"
optional = false
python-versions = ">=3.9"
files = [
@@ -3638,7 +3469,6 @@ files = [
name = "lxml"
version = "5.1.0"
description = "Powerful and Pythonic XML processing library combining libxml2/libxslt with the ElementTree API."
-category = "main"
optional = false
python-versions = ">=3.6"
files = [
@@ -3732,7 +3562,6 @@ source = ["Cython (>=3.0.7)"]
name = "mako"
version = "1.3.2"
description = "A super-fast templating language that borrows the best ideas from the existing templating languages."
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -3752,7 +3581,6 @@ testing = ["pytest"]
name = "markdown"
version = "3.5.2"
description = "Python implementation of John Gruber's Markdown."
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -3768,7 +3596,6 @@ testing = ["coverage", "pyyaml"]
name = "markdown-it-py"
version = "3.0.0"
description = "Python port of markdown-it. Markdown parsing, done right!"
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -3793,7 +3620,6 @@ testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"]
name = "markupsafe"
version = "2.1.5"
description = "Safely add untrusted strings to HTML/XML markup."
-category = "main"
optional = false
python-versions = ">=3.7"
files = [
@@ -3863,7 +3689,6 @@ files = [
name = "matplotlib"
version = "3.8.3"
description = "Python plotting package"
-category = "main"
optional = false
python-versions = ">=3.9"
files = [
@@ -3912,7 +3737,6 @@ python-dateutil = ">=2.7"
name = "matplotlib-inline"
version = "0.1.6"
description = "Inline Matplotlib backend for Jupyter"
-category = "main"
optional = false
python-versions = ">=3.5"
files = [
@@ -3927,7 +3751,6 @@ traitlets = "*"
name = "mccabe"
version = "0.7.0"
description = "McCabe checker, plugin for flake8"
-category = "main"
optional = false
python-versions = ">=3.6"
files = [
@@ -3939,7 +3762,6 @@ files = [
name = "mdurl"
version = "0.1.2"
description = "Markdown URL utilities"
-category = "main"
optional = false
python-versions = ">=3.7"
files = [
@@ -3951,7 +3773,6 @@ files = [
name = "msgpack"
version = "1.0.8"
description = "MessagePack serializer"
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -4011,13 +3832,13 @@ files = [
{file = "msgpack-1.0.8-cp39-cp39-win32.whl", hash = "sha256:f9af38a89b6a5c04b7d18c492c8ccf2aee7048aff1ce8437c4683bb5a1df893d"},
{file = "msgpack-1.0.8-cp39-cp39-win_amd64.whl", hash = "sha256:ed59dd52075f8fc91da6053b12e8c89e37aa043f8986efd89e61fae69dc1b011"},
{file = "msgpack-1.0.8-py3-none-any.whl", hash = "sha256:24f727df1e20b9876fa6e95f840a2a2651e34c0ad147676356f4bf5fbb0206ca"},
+ {file = "msgpack-1.0.8.tar.gz", hash = "sha256:95c02b0e27e706e48d0e5426d1710ca78e0f0628d6e89d5b5a5b91a5f12274f3"},
]
[[package]]
name = "msoffcrypto-tool"
version = "5.3.1"
description = "Python tool and library for decrypting MS Office files with passwords or other keys"
-category = "main"
optional = false
python-versions = ">=3.8,<4.0"
files = [
@@ -4033,7 +3854,6 @@ olefile = ">=0.46"
name = "multidict"
version = "6.0.5"
description = "multidict implementation"
-category = "main"
optional = false
python-versions = ">=3.7"
files = [
@@ -4133,7 +3953,6 @@ files = [
name = "mutagen"
version = "1.47.0"
description = "read and write audio tags for many formats"
-category = "main"
optional = false
python-versions = ">=3.7"
files = [
@@ -4145,7 +3964,6 @@ files = [
name = "mypy"
version = "0.991"
description = "Optional static typing for Python"
-category = "main"
optional = false
python-versions = ">=3.7"
files = [
@@ -4195,7 +4013,6 @@ reports = ["lxml"]
name = "mypy-extensions"
version = "1.0.0"
description = "Type system extensions for programs checked with the mypy type checker."
-category = "main"
optional = false
python-versions = ">=3.5"
files = [
@@ -4207,7 +4024,6 @@ files = [
name = "nltk"
version = "3.8.1"
description = "Natural Language Toolkit"
-category = "main"
optional = false
python-versions = ">=3.7"
files = [
@@ -4233,7 +4049,6 @@ twitter = ["twython"]
name = "nodeenv"
version = "1.8.0"
description = "Node.js virtual environment builder"
-category = "main"
optional = false
python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*"
files = [
@@ -4248,7 +4063,6 @@ setuptools = "*"
name = "numba"
version = "0.59.0"
description = "compiling Python code using LLVM"
-category = "main"
optional = false
python-versions = ">=3.9"
files = [
@@ -4276,14 +4090,13 @@ files = [
]
[package.dependencies]
-llvmlite = ">=0.42.0dev0,<0.43"
+llvmlite = "==0.42.*"
numpy = ">=1.22,<1.27"
[[package]]
name = "numpy"
version = "1.25.2"
description = "Fundamental package for array computing in Python"
-category = "main"
optional = false
python-versions = ">=3.9"
files = [
@@ -4318,7 +4131,6 @@ files = [
name = "oauthlib"
version = "3.2.2"
description = "A generic, spec-compliant, thorough implementation of the OAuth request-signing logic"
-category = "main"
optional = false
python-versions = ">=3.6"
files = [
@@ -4335,7 +4147,6 @@ signedtoken = ["cryptography (>=3.0.0)", "pyjwt (>=2.0.0,<3)"]
name = "olefile"
version = "0.47"
description = "Python package to parse, read and write Microsoft OLE2 files (Structured Storage or Compound Document, Microsoft Office)"
-category = "main"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
files = [
@@ -4350,7 +4161,6 @@ tests = ["pytest", "pytest-cov"]
name = "oletools"
version = "0.60.1"
description = "Python tools to analyze security characteristics of MS Office and OLE files (also called Structured Storage, Compound File Binary Format or Compound Document File Format), for Malware Analysis and Incident Response #DFIR"
-category = "main"
optional = false
python-versions = "*"
files = [
@@ -4361,7 +4171,7 @@ files = [
[package.dependencies]
colorclass = "*"
easygui = "*"
-msoffcrypto-tool = {version = "*", markers = "platform_python_implementation != \"PyPy\" or python_version >= \"3\" and platform_system != \"Windows\" and platform_system != \"Darwin\""}
+msoffcrypto-tool = {version = "*", markers = "platform_python_implementation != \"PyPy\" or python_version >= \"3\" and (platform_system != \"Windows\" and platform_system != \"Darwin\")"}
olefile = ">=0.46"
pcodedmp = ">=1.2.5"
pyparsing = ">=2.1.0,<3"
@@ -4373,7 +4183,6 @@ full = ["XLMMacroDeobfuscator"]
name = "packaging"
version = "23.2"
description = "Core utilities for Python packages"
-category = "main"
optional = false
python-versions = ">=3.7"
files = [
@@ -4385,7 +4194,6 @@ files = [
name = "parso"
version = "0.8.3"
description = "A Python Parser"
-category = "main"
optional = false
python-versions = ">=3.6"
files = [
@@ -4401,7 +4209,6 @@ testing = ["docopt", "pytest (<6.0.0)"]
name = "pathspec"
version = "0.12.1"
description = "Utility library for gitignore style pattern matching of file paths."
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -4413,7 +4220,6 @@ files = [
name = "pcodedmp"
version = "1.2.6"
description = "A VBA p-code disassembler"
-category = "main"
optional = false
python-versions = "*"
files = [
@@ -4429,7 +4235,6 @@ win-unicode-console = {version = "*", markers = "platform_system == \"Windows\"
name = "pdfminer-six"
version = "20221105"
description = "PDF parser and analyzer"
-category = "main"
optional = false
python-versions = ">=3.6"
files = [
@@ -4450,7 +4255,6 @@ image = ["Pillow"]
name = "pexpect"
version = "4.9.0"
description = "Pexpect allows easy control of interactive console applications."
-category = "main"
optional = false
python-versions = "*"
files = [
@@ -4465,7 +4269,6 @@ ptyprocess = ">=0.5"
name = "pgvector"
version = "0.2.5"
description = "pgvector support for Python"
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -4479,7 +4282,6 @@ numpy = "*"
name = "pillow"
version = "10.2.0"
description = "Python Imaging Library (Fork)"
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -4565,7 +4367,6 @@ xmp = ["defusedxml"]
name = "platformdirs"
version = "3.11.0"
description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
-category = "main"
optional = false
python-versions = ">=3.7"
files = [
@@ -4581,7 +4382,6 @@ test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4)", "pytest-co
name = "pluggy"
version = "1.4.0"
description = "plugin and hook calling mechanisms for python"
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -4597,7 +4397,6 @@ testing = ["pytest", "pytest-benchmark"]
name = "pooch"
version = "1.8.1"
description = "\"Pooch manages your Python library's sample data files: it automatically downloads and stores them in a local directory, with support for versioning and corruption checks.\""
-category = "main"
optional = false
python-versions = ">=3.7"
files = [
@@ -4619,7 +4418,6 @@ xxhash = ["xxhash (>=1.4.3)"]
name = "pre-commit"
version = "3.6.2"
description = "A framework for managing and maintaining multi-language pre-commit hooks."
-category = "main"
optional = false
python-versions = ">=3.9"
files = [
@@ -4638,7 +4436,6 @@ virtualenv = ">=20.10.0"
name = "preview-generator"
version = "0.29"
description = "A library for generating preview (thumbnails, text or json overview) for file-based content"
-category = "main"
optional = false
python-versions = ">= 3.7"
files = [
@@ -4666,7 +4463,6 @@ video = ["ffmpeg-python"]
name = "prometheus-client"
version = "0.20.0"
description = "Python client for the Prometheus monitoring system."
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -4681,7 +4477,6 @@ twisted = ["twisted"]
name = "prompt-toolkit"
version = "3.0.43"
description = "Library for building powerful interactive command lines in Python"
-category = "main"
optional = false
python-versions = ">=3.7.0"
files = [
@@ -4696,7 +4491,6 @@ wcwidth = "*"
name = "psutil"
version = "5.9.8"
description = "Cross-platform lib for process and system monitoring in Python."
-category = "main"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*"
files = [
@@ -4725,7 +4519,6 @@ test = ["enum34", "ipaddress", "mock", "pywin32", "wmi"]
name = "psycopg2-binary"
version = "2.9.9"
description = "psycopg2 - Python-PostgreSQL Database Adapter"
-category = "main"
optional = false
python-versions = ">=3.7"
files = [
@@ -4755,6 +4548,7 @@ files = [
{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"},
@@ -4763,6 +4557,8 @@ files = [
{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"},
@@ -4804,7 +4600,6 @@ files = [
name = "ptyprocess"
version = "0.7.0"
description = "Run a subprocess in a pseudo terminal"
-category = "main"
optional = false
python-versions = "*"
files = [
@@ -4816,7 +4611,6 @@ files = [
name = "pure-eval"
version = "0.2.2"
description = "Safely evaluate AST nodes without side effects"
-category = "main"
optional = false
python-versions = "*"
files = [
@@ -4831,7 +4625,6 @@ tests = ["pytest"]
name = "pyasn1"
version = "0.5.1"
description = "Pure-Python implementation of ASN.1 types and DER/BER/CER codecs (X.208)"
-category = "main"
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7"
files = [
@@ -4843,7 +4636,6 @@ files = [
name = "pyasn1-modules"
version = "0.3.0"
description = "A collection of ASN.1-based protocols modules"
-category = "main"
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7"
files = [
@@ -4858,7 +4650,6 @@ pyasn1 = ">=0.4.6,<0.6.0"
name = "pycld2"
version = "0.41"
description = "Python bindings around Google Chromium's embedded compact language detection library (CLD2)"
-category = "main"
optional = false
python-versions = "*"
files = [
@@ -4869,7 +4660,6 @@ files = [
name = "pycodestyle"
version = "2.11.1"
description = "Python style guide checker"
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -4881,7 +4671,6 @@ files = [
name = "pycparser"
version = "2.21"
description = "C parser in Python"
-category = "main"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
files = [
@@ -4893,7 +4682,6 @@ files = [
name = "pycryptodomex"
version = "3.20.0"
description = "Cryptographic library for Python"
-category = "main"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
files = [
@@ -4935,7 +4723,6 @@ files = [
name = "pydantic"
version = "2.6.3"
description = "Data validation using Python type hints"
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -4955,7 +4742,6 @@ email = ["email-validator (>=2.0.0)"]
name = "pydantic-core"
version = "2.16.3"
description = ""
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -5047,7 +4833,6 @@ typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0"
name = "pydantic-settings"
version = "2.2.1"
description = "Settings management using Pydantic"
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -5067,7 +4852,6 @@ yaml = ["pyyaml (>=6.0.1)"]
name = "pydotplus"
version = "2.0.2"
description = "Python interface to Graphviz's Dot language"
-category = "main"
optional = false
python-versions = "*"
files = [
@@ -5081,7 +4865,6 @@ pyparsing = ">=2.0.1"
name = "pydub"
version = "0.25.1"
description = "Manipulate audio with an simple and easy high level interface"
-category = "main"
optional = false
python-versions = "*"
files = [
@@ -5093,7 +4876,6 @@ files = [
name = "pyexifinfo"
version = "0.4.0"
description = "Simple Metadata extraction using Exiftool"
-category = "main"
optional = false
python-versions = "*"
files = [
@@ -5104,7 +4886,6 @@ files = [
name = "pyflakes"
version = "3.1.0"
description = "passive checker of Python programs"
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -5116,7 +4897,6 @@ files = [
name = "pygments"
version = "2.17.2"
description = "Pygments is a syntax highlighting package written in Python."
-category = "main"
optional = false
python-versions = ">=3.7"
files = [
@@ -5132,7 +4912,6 @@ windows-terminal = ["colorama (>=0.4.6)"]
name = "pyjwt"
version = "2.8.0"
description = "JSON Web Token implementation in Python"
-category = "main"
optional = false
python-versions = ">=3.7"
files = [
@@ -5153,7 +4932,6 @@ tests = ["coverage[toml] (==5.0.4)", "pytest (>=6.0.0,<7.0.0)"]
name = "pykakasi"
version = "2.2.1"
description = "Kana kanji simple inversion library"
-category = "main"
optional = false
python-versions = "*"
files = [
@@ -5174,7 +4952,6 @@ test = ["coverage[toml] (>=5.2)", "py-cpuinfo", "pytest", "pytest-benchmark", "p
name = "pylast"
version = "5.2.0"
description = "A Python interface to Last.fm and Libre.fm"
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -5192,7 +4969,6 @@ tests = ["flaky", "pytest", "pytest-cov", "pytest-random-order", "pyyaml"]
name = "pylint"
version = "3.1.0"
description = "python code static checker"
-category = "main"
optional = false
python-versions = ">=3.8.0"
files = [
@@ -5204,8 +4980,8 @@ files = [
astroid = ">=3.1.0,<=3.2.0-dev0"
colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""}
dill = [
- {version = ">=0.3.6", markers = "python_version >= \"3.11\""},
{version = ">=0.3.7", markers = "python_version >= \"3.12\""},
+ {version = ">=0.3.6", markers = "python_version >= \"3.11\" and python_version < \"3.12\""},
]
isort = ">=4.2.5,<5.13.0 || >5.13.0,<6"
mccabe = ">=0.6,<0.8"
@@ -5220,7 +4996,6 @@ testutils = ["gitpython (>3)"]
name = "pylint-celery"
version = "0.3"
description = "pylint-celery is a Pylint plugin to aid Pylint in recognising and understandingerrors caused when using the Celery library"
-category = "main"
optional = false
python-versions = "*"
files = [
@@ -5236,7 +5011,6 @@ pylint-plugin-utils = ">=0.2.1"
name = "pylint-django"
version = "2.5.5"
description = "A Pylint plugin to help Pylint understand the Django web framework"
-category = "main"
optional = false
python-versions = ">=3.7,<4.0"
files = [
@@ -5255,7 +5029,6 @@ with-django = ["Django (>=2.2)"]
name = "pylint-plugin-utils"
version = "0.8.2"
description = "Utilities and helpers for writing Pylint plugins"
-category = "main"
optional = false
python-versions = ">=3.7,<4.0"
files = [
@@ -5270,7 +5043,6 @@ pylint = ">=1.7"
name = "pymorphy3"
version = "1.3.1"
description = "Morphological analyzer (POS tagger + inflection engine) for Russian language."
-category = "main"
optional = false
python-versions = "*"
files = [
@@ -5291,7 +5063,6 @@ fast = ["DAWG (>=0.8)"]
name = "pymorphy3-dicts-ru"
version = "2.4.417150.4580142"
description = "Russian dictionaries for pymorphy2"
-category = "main"
optional = false
python-versions = "*"
files = [
@@ -5303,7 +5074,6 @@ files = [
name = "pyopenssl"
version = "24.0.0"
description = "Python wrapper module around the OpenSSL library"
-category = "main"
optional = false
python-versions = ">=3.7"
files = [
@@ -5322,7 +5092,6 @@ test = ["flaky", "pretend", "pytest (>=3.0.1)"]
name = "pyparsing"
version = "2.4.7"
description = "Python parsing module"
-category = "main"
optional = false
python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
files = [
@@ -5334,7 +5103,6 @@ files = [
name = "pypng"
version = "0.20220715.0"
description = "Pure Python library for saving and loading PNG images"
-category = "main"
optional = false
python-versions = "*"
files = [
@@ -5346,7 +5114,6 @@ files = [
name = "pysocks"
version = "1.7.1"
description = "A Python SOCKS client module. See https://github.com/Anorov/PySocks for more information."
-category = "main"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
files = [
@@ -5359,7 +5126,6 @@ files = [
name = "pytest"
version = "7.4.4"
description = "pytest: simple powerful testing with Python"
-category = "main"
optional = false
python-versions = ">=3.7"
files = [
@@ -5380,7 +5146,6 @@ testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "no
name = "pytest-asyncio"
version = "0.21.1"
description = "Pytest support for asyncio"
-category = "main"
optional = false
python-versions = ">=3.7"
files = [
@@ -5399,7 +5164,6 @@ testing = ["coverage (>=6.2)", "flaky (>=3.5.0)", "hypothesis (>=5.7.1)", "mypy
name = "pytest-django"
version = "4.8.0"
description = "A Django plugin for pytest."
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -5418,7 +5182,6 @@ testing = ["Django", "django-configurations (>=2.0)"]
name = "pytest-factoryboy"
version = "2.3.1"
description = "Factory Boy support for pytest."
-category = "main"
optional = false
python-versions = ">=3.7"
files = [
@@ -5438,7 +5201,6 @@ typing-extensions = "*"
name = "pytest-lambda"
version = "2.2.0"
description = "Define pytest fixtures with lambda functions."
-category = "main"
optional = false
python-versions = ">=3.7.0,<4.0.0"
files = [
@@ -5454,7 +5216,6 @@ wrapt = ">=1.11.0,<2.0.0"
name = "pytest-mock"
version = "3.12.0"
description = "Thin-wrapper around the mock package for easier use with pytest"
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -5472,7 +5233,6 @@ dev = ["pre-commit", "pytest-asyncio", "tox"]
name = "pytest-sugar"
version = "0.9.7"
description = "pytest-sugar is a plugin for pytest that changes the default look and feel of pytest (e.g. progressbar, show tests that fail instantly)."
-category = "main"
optional = false
python-versions = "*"
files = [
@@ -5492,7 +5252,6 @@ dev = ["black", "flake8", "pre-commit"]
name = "pytest-xdist"
version = "3.5.0"
description = "pytest xdist plugin for distributed testing, most importantly across multiple CPUs"
-category = "main"
optional = false
python-versions = ">=3.7"
files = [
@@ -5513,7 +5272,6 @@ testing = ["filelock"]
name = "python-crontab"
version = "3.0.0"
description = "Python Crontab API"
-category = "main"
optional = false
python-versions = "*"
files = [
@@ -5532,7 +5290,6 @@ cron-schedule = ["croniter"]
name = "python-dateutil"
version = "2.9.0.post0"
description = "Extensions to the standard Python datetime module"
-category = "main"
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7"
files = [
@@ -5547,7 +5304,6 @@ six = ">=1.5"
name = "python-dotenv"
version = "1.0.1"
description = "Read key-value pairs from a .env file and set them as environment variables"
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -5562,7 +5318,6 @@ cli = ["click (>=5.0)"]
name = "python-levenshtein"
version = "0.23.0"
description = "Python extension for computing string edit distances and similarities."
-category = "main"
optional = false
python-versions = ">=3.7"
files = [
@@ -5577,7 +5332,6 @@ Levenshtein = "0.23.0"
name = "python-magic"
version = "0.4.27"
description = "File type identification using libmagic"
-category = "main"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
files = [
@@ -5589,7 +5343,6 @@ files = [
name = "python-mpd2"
version = "3.1.1"
description = "A Python MPD client library"
-category = "main"
optional = false
python-versions = ">=3.6"
files = [
@@ -5604,7 +5357,6 @@ twisted = ["Twisted"]
name = "python-pptx"
version = "0.6.23"
description = "Generate and manipulate Open XML PowerPoint (.pptx) files"
-category = "main"
optional = false
python-versions = "*"
files = [
@@ -5621,7 +5373,6 @@ XlsxWriter = ">=0.5.7"
name = "python-slugify"
version = "8.0.1"
description = "A Python slugify application that also handles Unicode"
-category = "main"
optional = false
python-versions = ">=3.7"
files = [
@@ -5640,7 +5391,6 @@ unidecode = ["Unidecode (>=1.1.1)"]
name = "python3-openid"
version = "3.2.0"
description = "OpenID support for modern servers and consumers."
-category = "main"
optional = false
python-versions = "*"
files = [
@@ -5659,7 +5409,6 @@ postgresql = ["psycopg2"]
name = "pytube"
version = "15.0.0"
description = "Python 3 library for downloading YouTube Videos."
-category = "main"
optional = false
python-versions = ">=3.7"
files = [
@@ -5671,7 +5420,6 @@ files = [
name = "pytz"
version = "2023.4"
description = "World timezone definitions, modern and historical"
-category = "main"
optional = false
python-versions = "*"
files = [
@@ -5683,7 +5431,6 @@ files = [
name = "pyyaml"
version = "6.0.1"
description = "YAML parser and emitter for Python"
-category = "main"
optional = false
python-versions = ">=3.6"
files = [
@@ -5733,7 +5480,6 @@ files = [
name = "qrcode"
version = "7.4.2"
description = "QR Code image generator"
-category = "main"
optional = false
python-versions = ">=3.7"
files = [
@@ -5758,7 +5504,6 @@ test = ["coverage", "pytest"]
name = "rapidfuzz"
version = "3.6.1"
description = "rapid fuzzy string matching"
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -5861,7 +5606,6 @@ full = ["numpy"]
name = "rawpy"
version = "0.19.1"
description = "RAW image processing for Python, a wrapper for libraw"
-category = "main"
optional = false
python-versions = "*"
files = [
@@ -5897,7 +5641,6 @@ numpy = "*"
name = "red-black-tree-mod"
version = "1.20"
description = "Flexible python implementation of red black trees"
-category = "main"
optional = false
python-versions = "*"
files = [
@@ -5908,7 +5651,6 @@ files = [
name = "redis"
version = "4.6.0"
description = "Python client for Redis database and key-value store"
-category = "main"
optional = false
python-versions = ">=3.7"
files = [
@@ -5927,7 +5669,6 @@ ocsp = ["cryptography (>=36.0.1)", "pyopenssl (==20.0.1)", "requests (>=2.26.0)"
name = "referencing"
version = "0.33.0"
description = "JSON Referencing + Python"
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -5943,7 +5684,6 @@ rpds-py = ">=0.7.0"
name = "regex"
version = "2023.12.25"
description = "Alternative regular expression module, to replace re."
-category = "main"
optional = false
python-versions = ">=3.7"
files = [
@@ -6046,7 +5786,6 @@ files = [
name = "requests"
version = "2.31.0"
description = "Python HTTP for Humans."
-category = "main"
optional = false
python-versions = ">=3.7"
files = [
@@ -6069,7 +5808,6 @@ use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"]
name = "requests-oauthlib"
version = "1.3.1"
description = "OAuthlib authentication support for Requests."
-category = "main"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
files = [
@@ -6088,7 +5826,6 @@ rsa = ["oauthlib[signedtoken] (>=3.0.0)"]
name = "rich"
version = "13.7.1"
description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal"
-category = "main"
optional = false
python-versions = ">=3.7.0"
files = [
@@ -6107,7 +5844,6 @@ jupyter = ["ipywidgets (>=7.5.1,<9)"]
name = "rpds-py"
version = "0.18.0"
description = "Python bindings to Rust's persistent data structures (rpds)"
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -6216,7 +5952,6 @@ files = [
name = "rtfde"
version = "0.1.1"
description = "A library for extracting HTML content from RTF encapsulated HTML as commonly found in the exchange MSG email format."
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -6236,7 +5971,6 @@ msg-parse = ["extract-msg (>=0.27)"]
name = "scikit-learn"
version = "1.4.1.post1"
description = "A set of python modules for machine learning and data mining"
-category = "main"
optional = false
python-versions = ">=3.9"
files = [
@@ -6279,7 +6013,6 @@ tests = ["black (>=23.3.0)", "matplotlib (>=3.3.4)", "mypy (>=1.3)", "numpydoc (
name = "scipy"
version = "1.12.0"
description = "Fundamental algorithms for scientific computing in Python"
-category = "main"
optional = false
python-versions = ">=3.9"
files = [
@@ -6322,7 +6055,6 @@ test = ["asv", "gmpy2", "hypothesis", "mpmath", "pooch", "pytest", "pytest-cov",
name = "sentry-sdk"
version = "1.40.6"
description = "Python client for Sentry (https://sentry.io)"
-category = "main"
optional = false
python-versions = "*"
files = [
@@ -6368,7 +6100,6 @@ tornado = ["tornado (>=5)"]
name = "service-identity"
version = "24.1.0"
description = "Service identity verification for pyOpenSSL & cryptography."
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -6393,7 +6124,6 @@ tests = ["coverage[toml] (>=5.0.2)", "pytest"]
name = "setuptools"
version = "69.1.1"
description = "Easily download, build, install, upgrade, and uninstall Python packages"
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -6410,7 +6140,6 @@ testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jar
name = "six"
version = "1.15.0"
description = "Python 2 and 3 compatibility utilities"
-category = "main"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
files = [
@@ -6422,7 +6151,6 @@ files = [
name = "sniffio"
version = "1.3.1"
description = "Sniff out which async library your code is running under"
-category = "main"
optional = false
python-versions = ">=3.7"
files = [
@@ -6434,7 +6162,6 @@ files = [
name = "snowballstemmer"
version = "2.2.0"
description = "This package provides 29 stemmers for 28 languages generated from Snowball algorithms."
-category = "main"
optional = false
python-versions = "*"
files = [
@@ -6446,7 +6173,6 @@ files = [
name = "soundcloud-v2"
version = "1.3.1"
description = "Python wrapper for the v2 SoundCloud API"
-category = "main"
optional = false
python-versions = ">=3.6"
files = [
@@ -6466,7 +6192,6 @@ test = ["coveralls", "pytest", "pytest-dotenv"]
name = "soundfile"
version = "0.12.1"
description = "An audio library based on libsndfile, CFFI and NumPy"
-category = "main"
optional = false
python-versions = "*"
files = [
@@ -6490,7 +6215,6 @@ numpy = ["numpy"]
name = "soupsieve"
version = "2.5"
description = "A modern CSS selector implementation for Beautiful Soup."
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -6502,7 +6226,6 @@ files = [
name = "soxr"
version = "0.3.7"
description = "High quality, one-dimensional sample-rate conversion library"
-category = "main"
optional = false
python-versions = ">=3.6"
files = [
@@ -6549,7 +6272,6 @@ test = ["pytest"]
name = "speechrecognition"
version = "3.10.1"
description = "Library for performing speech recognition, with support for several engines and APIs, online and offline."
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -6568,7 +6290,6 @@ whisper-api = ["openai"]
name = "sphinx"
version = "7.2.6"
description = "Python documentation generator"
-category = "main"
optional = false
python-versions = ">=3.9"
files = [
@@ -6603,7 +6324,6 @@ test = ["cython (>=3.0)", "filelock", "html5lib", "pytest (>=4.6)", "setuptools
name = "sphinx-autobuild"
version = "2021.3.14"
description = "Rebuild Sphinx documentation on changes, with live-reload in the browser."
-category = "main"
optional = false
python-versions = ">=3.6"
files = [
@@ -6623,7 +6343,6 @@ test = ["pytest", "pytest-cov"]
name = "sphinxcontrib-applehelp"
version = "1.0.8"
description = "sphinxcontrib-applehelp is a Sphinx extension which outputs Apple help books"
-category = "main"
optional = false
python-versions = ">=3.9"
files = [
@@ -6640,7 +6359,6 @@ test = ["pytest"]
name = "sphinxcontrib-devhelp"
version = "1.0.6"
description = "sphinxcontrib-devhelp is a sphinx extension which outputs Devhelp documents"
-category = "main"
optional = false
python-versions = ">=3.9"
files = [
@@ -6657,7 +6375,6 @@ test = ["pytest"]
name = "sphinxcontrib-htmlhelp"
version = "2.0.5"
description = "sphinxcontrib-htmlhelp is a sphinx extension which renders HTML help files"
-category = "main"
optional = false
python-versions = ">=3.9"
files = [
@@ -6674,7 +6391,6 @@ test = ["html5lib", "pytest"]
name = "sphinxcontrib-jsmath"
version = "1.0.1"
description = "A sphinx extension which renders display math in HTML via JavaScript"
-category = "main"
optional = false
python-versions = ">=3.5"
files = [
@@ -6689,7 +6405,6 @@ test = ["flake8", "mypy", "pytest"]
name = "sphinxcontrib-qthelp"
version = "1.0.7"
description = "sphinxcontrib-qthelp is a sphinx extension which outputs QtHelp documents"
-category = "main"
optional = false
python-versions = ">=3.9"
files = [
@@ -6706,7 +6421,6 @@ test = ["pytest"]
name = "sphinxcontrib-serializinghtml"
version = "1.1.10"
description = "sphinxcontrib-serializinghtml is a sphinx extension which outputs \"serialized\" HTML files (json and pickle)"
-category = "main"
optional = false
python-versions = ">=3.9"
files = [
@@ -6723,7 +6437,6 @@ test = ["pytest"]
name = "spotdl"
version = "4.2.4"
description = "Download your Spotify playlists and songs along with album art and metadata"
-category = "main"
optional = false
python-versions = ">=3.8,<3.13"
files = [
@@ -6755,7 +6468,6 @@ ytmusicapi = ">=1.3.2,<2.0.0"
name = "spotipy"
version = "2.23.0"
description = "A light weight Python library for the Spotify Web API"
-category = "main"
optional = false
python-versions = "*"
files = [
@@ -6778,7 +6490,6 @@ test = ["mock (==2.0.0)"]
name = "sqlalchemy"
version = "2.0.27"
description = "Database Abstraction Library"
-category = "main"
optional = false
python-versions = ">=3.7"
files = [
@@ -6866,7 +6577,6 @@ sqlcipher = ["sqlcipher3_binary"]
name = "sqlparse"
version = "0.4.4"
description = "A non-validating SQL parser."
-category = "main"
optional = false
python-versions = ">=3.5"
files = [
@@ -6883,7 +6593,6 @@ test = ["pytest", "pytest-cov"]
name = "stack-data"
version = "0.6.3"
description = "Extract data from python stack frames and tracebacks for informative displays"
-category = "main"
optional = false
python-versions = "*"
files = [
@@ -6903,7 +6612,6 @@ tests = ["cython", "littleutils", "pygments", "pytest", "typeguard"]
name = "starlette"
version = "0.27.0"
description = "The little ASGI library that shines."
-category = "main"
optional = false
python-versions = ">=3.7"
files = [
@@ -6921,7 +6629,6 @@ full = ["httpx (>=0.22.0)", "itsdangerous", "jinja2", "python-multipart", "pyyam
name = "structlog"
version = "24.1.0"
description = "Structured Logging for Python"
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -6939,7 +6646,6 @@ typing = ["mypy (>=1.4)", "rich", "twisted"]
name = "syncedlyrics"
version = "0.7.0"
description = "Get an LRC format (synchronized) lyrics for your music"
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -6956,7 +6662,6 @@ requests = ">=2.31.0,<3.0.0"
name = "tablib"
version = "3.5.0"
description = "Format agnostic tabular data library (XLS, JSON, YAML, CSV, etc.)"
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -6978,7 +6683,6 @@ yaml = ["pyyaml"]
name = "termcolor"
version = "2.4.0"
description = "ANSI color formatting for output in terminal"
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -6993,7 +6697,6 @@ tests = ["pytest", "pytest-cov"]
name = "text-unidecode"
version = "1.3"
description = "The most basic Text::Unidecode port"
-category = "main"
optional = false
python-versions = "*"
files = [
@@ -7005,7 +6708,6 @@ files = [
name = "textract"
version = "1.6.5"
description = "extract text from any document. no muss. no fuss."
-category = "main"
optional = false
python-versions = "*"
files = []
@@ -7036,7 +6738,6 @@ resolved_reference = "c8c5729f8baea372a2a44cab1755be13457a1b4b"
name = "threadpoolctl"
version = "3.3.0"
description = "threadpoolctl"
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -7048,7 +6749,6 @@ files = [
name = "tinycss2"
version = "1.2.1"
description = "A tiny CSS parser"
-category = "main"
optional = false
python-versions = ">=3.7"
files = [
@@ -7067,7 +6767,6 @@ test = ["flake8", "isort", "pytest"]
name = "tomli"
version = "2.0.1"
description = "A lil' TOML parser"
-category = "main"
optional = false
python-versions = ">=3.7"
files = [
@@ -7079,7 +6778,6 @@ files = [
name = "tomlkit"
version = "0.12.4"
description = "Style preserving TOML library"
-category = "main"
optional = false
python-versions = ">=3.7"
files = [
@@ -7091,7 +6789,6 @@ files = [
name = "tornado"
version = "6.4"
description = "Tornado is a Python web framework and asynchronous networking library, originally developed at FriendFeed."
-category = "main"
optional = false
python-versions = ">= 3.8"
files = [
@@ -7112,7 +6809,6 @@ files = [
name = "tqdm"
version = "4.66.2"
description = "Fast, Extensible Progress Meter"
-category = "main"
optional = false
python-versions = ">=3.7"
files = [
@@ -7133,7 +6829,6 @@ telegram = ["requests"]
name = "traitlets"
version = "5.14.1"
description = "Traitlets Python configuration system"
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -7149,7 +6844,6 @@ test = ["argcomplete (>=3.0.3)", "mypy (>=1.7.0)", "pre-commit", "pytest (>=7.0,
name = "twisted"
version = "24.3.0"
description = "An asynchronous networking framework written in Python"
-category = "main"
optional = false
python-versions = ">=3.8.0"
files = [
@@ -7189,7 +6883,6 @@ windows-platform = ["pywin32 (!=226)", "pywin32 (!=226)", "twisted[all-non-platf
name = "twisted-iocpsupport"
version = "1.0.4"
description = "An extension for use in the twisted I/O Completion Ports reactor."
-category = "main"
optional = false
python-versions = "*"
files = [
@@ -7218,7 +6911,6 @@ files = [
name = "txaio"
version = "23.1.1"
description = "Compatibility API between asyncio/Twisted/Trollius"
-category = "main"
optional = false
python-versions = ">=3.7"
files = [
@@ -7235,7 +6927,6 @@ twisted = ["twisted (>=20.3.0)", "zope.interface (>=5.2.0)"]
name = "types-pytz"
version = "2024.1.0.20240203"
description = "Typing stubs for pytz"
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -7247,7 +6938,6 @@ files = [
name = "types-pyyaml"
version = "6.0.12.12"
description = "Typing stubs for PyYAML"
-category = "main"
optional = false
python-versions = "*"
files = [
@@ -7259,7 +6949,6 @@ files = [
name = "types-requests"
version = "2.31.0.20240218"
description = "Typing stubs for requests"
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -7274,7 +6963,6 @@ urllib3 = ">=2"
name = "typing-extensions"
version = "4.10.0"
description = "Backported and Experimental Type Hints for Python 3.8+"
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -7286,7 +6974,6 @@ files = [
name = "tzdata"
version = "2024.1"
description = "Provider of IANA time zone data"
-category = "main"
optional = false
python-versions = ">=2"
files = [
@@ -7298,7 +6985,6 @@ files = [
name = "tzlocal"
version = "5.2"
description = "tzinfo object for the local timezone"
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -7316,7 +7002,6 @@ devenv = ["check-manifest", "pytest (>=4.3)", "pytest-cov", "pytest-mock (>=3.3)
name = "unidecode"
version = "1.3.8"
description = "ASCII transliterations of Unicode text"
-category = "main"
optional = false
python-versions = ">=3.5"
files = [
@@ -7328,7 +7013,6 @@ files = [
name = "uritemplate"
version = "4.1.1"
description = "Implementation of RFC 6570 URI Templates"
-category = "main"
optional = false
python-versions = ">=3.6"
files = [
@@ -7340,7 +7024,6 @@ files = [
name = "urllib3"
version = "2.2.1"
description = "HTTP library with thread-safe connection pooling, file post, and more."
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -7358,7 +7041,6 @@ zstd = ["zstandard (>=0.18.0)"]
name = "uuid"
version = "1.30"
description = "UUID object and generation functions (Python 2.3 or higher)"
-category = "main"
optional = false
python-versions = "*"
files = [
@@ -7369,7 +7051,6 @@ files = [
name = "uuid6"
version = "2023.5.2"
description = "New time-based UUID formats which are suited for use as a database key"
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -7381,7 +7062,6 @@ files = [
name = "uvicorn"
version = "0.23.2"
description = "The lightning-fast ASGI server."
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -7400,7 +7080,6 @@ standard = ["colorama (>=0.4)", "httptools (>=0.5.0)", "python-dotenv (>=0.13)",
name = "vine"
version = "5.1.0"
description = "Python promises."
-category = "main"
optional = false
python-versions = ">=3.6"
files = [
@@ -7412,7 +7091,6 @@ files = [
name = "virtualenv"
version = "20.25.1"
description = "Virtual Python Environment builder"
-category = "main"
optional = false
python-versions = ">=3.7"
files = [
@@ -7433,7 +7111,6 @@ test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess
name = "vtk"
version = "9.3.0"
description = "VTK is an open-source toolkit for 3D computer graphics, image processing, and visualization"
-category = "main"
optional = false
python-versions = "*"
files = [
@@ -7475,7 +7152,6 @@ web = ["wslink (>=1.0.4)"]
name = "wand"
version = "0.6.13"
description = "Ctypes-based simple MagickWand API binding for Python"
-category = "main"
optional = false
python-versions = "*"
files = [
@@ -7491,7 +7167,6 @@ test = ["pytest (>=7.2.0)"]
name = "watchdog"
version = "4.0.0"
description = "Filesystem events monitoring"
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -7533,7 +7208,6 @@ watchmedo = ["PyYAML (>=3.10)"]
name = "watchfiles"
version = "0.18.1"
description = "Simple, modern and high performance file watching and code reload in python."
-category = "main"
optional = false
python-versions = ">=3.7"
files = [
@@ -7564,7 +7238,6 @@ anyio = ">=3.0.0"
name = "wcwidth"
version = "0.2.13"
description = "Measures the displayed width of unicode strings in a terminal"
-category = "main"
optional = false
python-versions = "*"
files = [
@@ -7576,7 +7249,6 @@ files = [
name = "webencodings"
version = "0.5.1"
description = "Character encoding aliases for legacy web content"
-category = "main"
optional = false
python-versions = "*"
files = [
@@ -7588,7 +7260,6 @@ files = [
name = "websockets"
version = "12.0"
description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)"
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -7670,7 +7341,6 @@ files = [
name = "werkzeug"
version = "2.3.8"
description = "The comprehensive WSGI web application library."
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -7689,7 +7359,6 @@ watchdog = ["watchdog (>=2.3)"]
name = "whitenoise"
version = "6.6.0"
description = "Radically simplified static file serving for WSGI applications"
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -7704,7 +7373,6 @@ brotli = ["Brotli"]
name = "win-unicode-console"
version = "0.5"
description = "Enable Unicode input and display when running Python from Windows console."
-category = "main"
optional = false
python-versions = "*"
files = [
@@ -7715,7 +7383,6 @@ files = [
name = "wrapt"
version = "1.16.0"
description = "Module for decorators, wrappers and monkey patching."
-category = "main"
optional = false
python-versions = ">=3.6"
files = [
@@ -7795,7 +7462,6 @@ files = [
name = "xlrd"
version = "2.0.1"
description = "Library for developers to extract data from Microsoft Excel (tm) .xls spreadsheet files"
-category = "main"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*"
files = [
@@ -7812,7 +7478,6 @@ test = ["pytest", "pytest-cov"]
name = "xlsxwriter"
version = "3.2.0"
description = "A Python module for creating Excel XLSX files."
-category = "main"
optional = false
python-versions = ">=3.6"
files = [
@@ -7824,7 +7489,6 @@ files = [
name = "xvfbwrapper"
version = "0.2.9"
description = "run headless display inside X virtual framebuffer (Xvfb)"
-category = "main"
optional = false
python-versions = "*"
files = [
@@ -7835,7 +7499,6 @@ files = [
name = "yandex-music"
version = "2.2.0"
description = "Неофициальная Python библиотека для работы с API сервиса Яндекс.Музыка."
-category = "main"
optional = false
python-versions = "~=3.7"
files = [
@@ -7851,7 +7514,6 @@ requests = {version = "*", extras = ["socks"]}
name = "yarl"
version = "1.9.4"
description = "Yet another URL library"
-category = "main"
optional = false
python-versions = ">=3.7"
files = [
@@ -7955,7 +7617,6 @@ multidict = ">=4.0"
name = "yt-dlp"
version = "2023.12.30"
description = "A youtube-dl fork with additional features and patches"
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -7977,7 +7638,6 @@ websockets = ">=12.0"
name = "ytmusicapi"
version = "1.5.4"
description = "Unofficial API for YouTube Music"
-category = "main"
optional = false
python-versions = ">=3.8"
files = [
@@ -7992,7 +7652,6 @@ requests = ">=2.22"
name = "zope-interface"
version = "6.2"
description = "Interfaces for Python"
-category = "main"
optional = false
python-versions = ">=3.7"
files = [
@@ -8045,4 +7704,4 @@ testing = ["coverage (>=5.0.3)", "zope.event", "zope.testing"]
[metadata]
lock-version = "2.0"
python-versions = ">=3.11,<3.13"
-content-hash = "70d22cd625166376e0dfc3ceabe0d7067cc69265ebc4731f642fea9ad8582897"
+content-hash = "702c5d8af4887ee7868e86472f96f32656a69d46f9305e337c1387a446202944"
diff --git a/pyproject.toml b/pyproject.toml
index 636e820..fdc1e45 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -27,7 +27,6 @@ django-allauth = "^0.54.0"
django-crispy-forms = "^2.1"
crispy-bootstrap5 = "^0.7"
django-redis = "^5.2.0"
-django-ckeditor = "^6.5.1"
django-colorfield = "^0.11.0"
djangorestframework = "^3.14.0"
django-rest-auth = "^0.9.5"
@@ -121,6 +120,7 @@ python-levenshtein = "^0.23.0"
pylast = "^5.2.0"
textract = {git = "https://github.com/Alexander-D-Karpov/textract.git", branch = "master"}
librosa = "^0.10.1"
+django-ckeditor-5 = "^0.2.12"
[build-system]