From b02a77ec5e125d8559a8bc68f56de75e0031a6fd Mon Sep 17 00:00:00 2001 From: Alexander-D-Karpov Date: Fri, 29 Sep 2023 20:07:14 +0300 Subject: [PATCH] major music loader fixes, added music player --- akarpov/common/api.py | 19 + akarpov/music/api/serializers.py | 53 ++- akarpov/music/api/urls.py | 17 + akarpov/music/api/views.py | 58 +++ akarpov/music/migrations/0007_song_creator.py | 25 ++ akarpov/music/migrations/0008_song_meta.py | 17 + akarpov/music/models.py | 20 +- akarpov/music/services/base.py | 10 +- akarpov/music/services/db.py | 24 +- akarpov/music/services/file.py | 12 +- akarpov/music/services/yandex.py | 123 +++--- akarpov/music/services/youtube.py | 6 +- akarpov/music/tasks.py | 26 +- akarpov/music/urls.py | 1 + akarpov/music/views.py | 15 +- akarpov/static/css/music-player.css | 67 ++++ akarpov/static/js/music-player.js | 326 ++++++++++++++++ akarpov/templates/music/player.html | 19 + akarpov/templates/music/upload.html | 2 +- akarpov/utils/files.py | 15 +- config/api_router.py | 4 + poetry.lock | 360 ++++++++++++++++-- 22 files changed, 1075 insertions(+), 144 deletions(-) create mode 100644 akarpov/music/api/urls.py create mode 100644 akarpov/music/api/views.py create mode 100644 akarpov/music/migrations/0007_song_creator.py create mode 100644 akarpov/music/migrations/0008_song_meta.py create mode 100644 akarpov/static/css/music-player.css create mode 100644 akarpov/static/js/music-player.js create mode 100644 akarpov/templates/music/player.html diff --git a/akarpov/common/api.py b/akarpov/common/api.py index 23e4dee..45e2ea1 100644 --- a/akarpov/common/api.py +++ b/akarpov/common/api.py @@ -1,5 +1,8 @@ from rest_framework import serializers from rest_framework.pagination import PageNumberPagination +from rest_framework.permissions import SAFE_METHODS, BasePermission + +from akarpov.utils.models import get_object_user class SmallResultsSetPagination(PageNumberPagination): @@ -24,3 +27,19 @@ class RecursiveField(serializers.Serializer): def to_representation(self, value): serializer = self.parent.parent.__class__(value, context=self.context) return serializer.data + + +class IsCreatorOrReadOnly(BasePermission): + def has_permission(self, request, view): + return bool( + request.method in SAFE_METHODS + or request.user + and get_object_user(view.get_object()) == request.user + ) + + +class SetUserModelSerializer(serializers.ModelSerializer): + def create(self, validated_data): + creator = self.context["request"].user + obj = self.Meta.model.objects.create(creator=creator, **validated_data) + return obj diff --git a/akarpov/music/api/serializers.py b/akarpov/music/api/serializers.py index 4100c9a..5230fe5 100644 --- a/akarpov/music/api/serializers.py +++ b/akarpov/music/api/serializers.py @@ -1,11 +1,15 @@ +from drf_spectacular.utils import extend_schema_field from rest_framework import serializers -from akarpov.music.models import Album, Author, Song +from akarpov.common.api import SetUserModelSerializer +from akarpov.music.models import Album, Author, Playlist, Song +from akarpov.users.api.serializers import UserPublicInfoSerializer class AuthorSerializer(serializers.ModelSerializer): url = serializers.SerializerMethodField(method_name="get_url") + @extend_schema_field(serializers.URLField) def get_url(self, obj): return obj.get_absolute_url() @@ -17,6 +21,7 @@ class Meta: class AlbumSerializer(serializers.ModelSerializer): url = serializers.SerializerMethodField(method_name="get_url") + @extend_schema_field(serializers.URLField) def get_url(self, obj): return obj.get_absolute_url() @@ -32,7 +37,6 @@ class SongSerializer(serializers.ModelSerializer): class Meta: model = Song fields = [ - "id", "image", "link", "length", @@ -42,3 +46,48 @@ class Meta: "authors", "album", ] + extra_kwargs = { + "slug": {"read_only": True}, + "creator": {"read_only": True}, + "length": {"read_only": True}, + "played": {"read_only": True}, + } + + +class ListSongSerializer(SetUserModelSerializer): + album = serializers.CharField(source="album.name", read_only=True) + + class Meta: + model = Song + fields = ["name", "slug", "file", "image_cropped", "length", "album"] + extra_kwargs = { + "slug": {"read_only": True}, + "image_cropped": {"read_only": True}, + "length": {"read_only": True}, + "album": {"read_only": True}, + } + + +class PlaylistSerializer(SetUserModelSerializer): + creator = UserPublicInfoSerializer() + + class Meta: + model = Playlist + fields = ["name", "slug", "private", "creator"] + extra_kwargs = { + "slug": {"read_only": True}, + "creator": {"read_only": True}, + } + + +class FullPlaylistSerializer(serializers.ModelSerializer): + songs = ListSongSerializer(many=True, read_only=True) + creator = UserPublicInfoSerializer(read_only=True) + + class Meta: + model = Playlist + fields = ["name", "private", "creator", "songs"] + extra_kwargs = { + "slug": {"read_only": True}, + "creator": {"read_only": True}, + } diff --git a/akarpov/music/api/urls.py b/akarpov/music/api/urls.py new file mode 100644 index 0000000..41af9cd --- /dev/null +++ b/akarpov/music/api/urls.py @@ -0,0 +1,17 @@ +from django.urls import path + +from akarpov.music.api.views import ( + ListCreatePlaylistAPIView, + ListCreateSongAPIView, + RetrieveUpdateDestroyPlaylistAPIView, + RetrieveUpdateDestroySongAPIView, +) + +app_name = "music" + +urlpatterns = [ + path("playlists/", ListCreatePlaylistAPIView.as_view()), + path("playlists/", RetrieveUpdateDestroyPlaylistAPIView.as_view()), + path("song/", ListCreateSongAPIView.as_view()), + path("song/", RetrieveUpdateDestroySongAPIView.as_view()), +] diff --git a/akarpov/music/api/views.py b/akarpov/music/api/views.py new file mode 100644 index 0000000..ed6842e --- /dev/null +++ b/akarpov/music/api/views.py @@ -0,0 +1,58 @@ +from rest_framework import generics, permissions + +from akarpov.common.api import IsCreatorOrReadOnly +from akarpov.music.api.serializers import ( + FullPlaylistSerializer, + ListSongSerializer, + PlaylistSerializer, + SongSerializer, +) +from akarpov.music.models import Playlist, Song + + +class ListCreatePlaylistAPIView(generics.ListCreateAPIView): + permission_classes = [permissions.IsAuthenticated] + serializer_class = PlaylistSerializer + + def get_queryset(self): + return Playlist.objects.filter(creator=self.request.user) + + +class RetrieveUpdateDestroyPlaylistAPIView(generics.RetrieveUpdateDestroyAPIView): + lookup_field = "slug" + lookup_url_kwarg = "slug" + permission_classes = [IsCreatorOrReadOnly] + serializer_class = FullPlaylistSerializer + + def __init__(self, **kwargs): + super().__init__(**kwargs) + self.object = None + + def get_object(self): + if not self.object: + self.object = super().get_object() + return self.object + + +class ListCreateSongAPIView(generics.ListCreateAPIView): + serializer_class = ListSongSerializer + permission_classes = [IsCreatorOrReadOnly] + + def get_queryset(self): + return Song.objects.all() + + +class RetrieveUpdateDestroySongAPIView(generics.RetrieveUpdateDestroyAPIView): + lookup_field = "slug" + lookup_url_kwarg = "slug" + permission_classes = [IsCreatorOrReadOnly] + serializer_class = SongSerializer + + def __init__(self, **kwargs): + super().__init__(**kwargs) + self.object = None + + def get_object(self): + if not self.object: + self.object = super().get_object() + return self.object diff --git a/akarpov/music/migrations/0007_song_creator.py b/akarpov/music/migrations/0007_song_creator.py new file mode 100644 index 0000000..d7f2fb3 --- /dev/null +++ b/akarpov/music/migrations/0007_song_creator.py @@ -0,0 +1,25 @@ +# Generated by Django 4.2.5 on 2023-09-27 08:06 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ("music", "0006_tempfileupload"), + ] + + operations = [ + migrations.AddField( + model_name="song", + name="creator", + field=models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="songs", + to=settings.AUTH_USER_MODEL, + ), + ), + ] diff --git a/akarpov/music/migrations/0008_song_meta.py b/akarpov/music/migrations/0008_song_meta.py new file mode 100644 index 0000000..4ea5105 --- /dev/null +++ b/akarpov/music/migrations/0008_song_meta.py @@ -0,0 +1,17 @@ +# Generated by Django 4.2.5 on 2023-09-29 15:31 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("music", "0007_song_creator"), + ] + + operations = [ + migrations.AddField( + model_name="song", + name="meta", + field=models.JSONField(blank=True, null=True), + ), + ] diff --git a/akarpov/music/models.py b/akarpov/music/models.py index 7294a79..5017625 100644 --- a/akarpov/music/models.py +++ b/akarpov/music/models.py @@ -38,10 +38,26 @@ class Song(BaseImageModel, ShortLinkModel): album = models.ForeignKey( Album, null=True, related_name="songs", on_delete=models.SET_NULL ) + creator = models.ForeignKey( + "users.User", related_name="songs", on_delete=models.SET_NULL, null=True + ) + meta = models.JSONField(blank=True, null=True) def get_absolute_url(self): return reverse("music:song", kwargs={"slug": self.slug}) + @property + def full_props(self) -> str: + if self.album and self.authors: + return f"{self.album.name} - " + ", ".join( + self.authors.values_list("name", flat=True) + ) + elif self.album: + return f"{self.album.name}" + elif self.album: + return ", ".join(self.authors.values_list("name", flat=True)) + return "" + def __str__(self): return self.name @@ -80,8 +96,8 @@ class Meta: class SongInQue(models.Model): - name = models.CharField(blank=True, max_length=250) - status = models.CharField(null=True, blank=True, max_length=250) + name = models.CharField(blank=True, max_length=500) + status = models.CharField(null=True, blank=True, max_length=500) error = models.BooleanField(default=False) diff --git a/akarpov/music/services/base.py b/akarpov/music/services/base.py index 58d94fd..6ef94ac 100644 --- a/akarpov/music/services/base.py +++ b/akarpov/music/services/base.py @@ -1,11 +1,11 @@ from akarpov.music.tasks import list_tracks, process_dir, process_file -def load_tracks(address: str): +def load_tracks(address: str, user_id: int): if address.startswith("/"): - process_dir.apply_async(kwargs={"path": address}) - list_tracks.apply_async(kwargs={"url": address}) + process_dir.apply_async(kwargs={"path": address, "user_id": user_id}) + list_tracks.apply_async(kwargs={"url": address, "user_id": user_id}) -def load_track_file(file): - process_file.apply_async(kwargs={"path": file}) +def load_track_file(file, user_id: int): + process_file.apply_async(kwargs={"path": file, "user_id": user_id}) diff --git a/akarpov/music/services/db.py b/akarpov/music/services/db.py index b5ef3ad..7096ed2 100644 --- a/akarpov/music/services/db.py +++ b/akarpov/music/services/db.py @@ -13,6 +13,7 @@ def load_track( path: str, image_path: str | None = None, + user_id: int | None = None, authors: list[str] | str | None = None, album: str | None = None, name: str | None = None, @@ -20,12 +21,19 @@ def load_track( **kwargs, ) -> Song: p_name = path.split("/")[-1] + + if album and type(album) is str and album.startswith("['"): + album = album.replace("['", "").replace("']", "") + if authors: authors = [Author.objects.get_or_create(name=x)[0] for x in authors if authors] else: authors = [] if album: - album = Album.objects.get_or_create(name=album)[0] + if type(album) is str: + album = Album.objects.get_or_create(name=album)[0] + elif type(album) is list: + album = Album.objects.get_or_create(name=album[0])[0] else: album = None @@ -45,9 +53,11 @@ def load_track( tag = MP3(path, ID3=ID3) if image_path: if not image_path.endswith(".png"): + nm = image_path im = Image.open(image_path) image_path = image_path.replace(image_path.split(".")[-1], "png") im.save(image_path) + os.remove(nm) song = Song( link=link if link else "", @@ -56,6 +66,12 @@ def load_track( album=album, ) + if user_id: + song.user_id = user_id + + if kwargs: + song.meta = kwargs + if image_path: with open(path, "rb") as file, open(image_path, "rb") as image: song.image = File(image, name=image_path.split("/")[-1]) @@ -96,4 +112,10 @@ def load_track( tag.tags.add(TCON(text=kwargs["genre"])) tag.save() + if os.path.exists(path): + os.remove(path) + + if os.path.exists(image_path): + os.remove(image_path) + return song diff --git a/akarpov/music/services/file.py b/akarpov/music/services/file.py index a4c28f6..1ae0359 100644 --- a/akarpov/music/services/file.py +++ b/akarpov/music/services/file.py @@ -11,18 +11,18 @@ from akarpov.music.services.db import load_track -def load_dir(path: str): +def load_dir(path: str, user_id: int): path = Path(path) for f in list(path.glob("**/*.mp3")): - process_mp3_file(str(f)) + process_mp3_file(str(f), user_id=user_id) -def load_file(path: str): - process_mp3_file(path) +def load_file(path: str, user_id: int): + process_mp3_file(path, user_id) -def process_mp3_file(path: str) -> None: +def process_mp3_file(path: str, user_id: int) -> None: tag = mutagen.File(path, easy=True) if "artist" in tag: author = tag["artist"] @@ -55,6 +55,6 @@ def process_mp3_file(path: str) -> None: im.save(image_pth) except UnidentifiedImageError: pass - load_track(path, image_pth, author, album, name) + load_track(path, image_pth, user_id, author, album, name) if image_pth and os.path.exists(image_pth): os.remove(image_pth) diff --git a/akarpov/music/services/yandex.py b/akarpov/music/services/yandex.py index bb18ddb..035baf0 100644 --- a/akarpov/music/services/yandex.py +++ b/akarpov/music/services/yandex.py @@ -1,18 +1,13 @@ import os -from pathlib import Path from random import randint from django.conf import settings -from django.core.files import File from django.utils.text import slugify -from mutagen.easyid3 import EasyID3 -from mutagen.id3 import APIC, ID3, TCON, TORY -from mutagen.mp3 import MP3 -from pydub import AudioSegment from yandex_music import Client, Playlist, Search, Track from akarpov.music import tasks -from akarpov.music.models import Album, Author, Song, SongInQue +from akarpov.music.models import Song, SongInQue +from akarpov.music.services.db import load_track def login() -> Client: @@ -48,88 +43,56 @@ def search_ym(name: str): return info -def load_file_meta(track: int): +def load_file_meta(track: int, user_id: int): que = SongInQue.objects.create() + client = login() + track = client.tracks(track)[0] # type: Track + que.name = track.title + que.save() + try: - client = login() - track = client.tracks(track)[0] # type: Track - que.name = track.title - que.save() - - try: - if sng := Song.objects.filter( - name=track.title, album__name=track.albums[0].title - ): - que.delete() - return sng.first() - except IndexError: + if sng := Song.objects.filter( + name=track.title, album__name=track.albums[0].title + ): que.delete() - return - - filename = slugify(f"{track.artists[0].name} - {track.title}") - orig_path = f"{settings.MEDIA_ROOT}/{filename}" - - track.download(filename=orig_path, codec="mp3") - - path = orig_path + ".mp3" - AudioSegment.from_file(orig_path).export(path) - os.remove(orig_path) - - # load album image - img_pth = str(settings.MEDIA_ROOT + f"/_{str(randint(10000, 99999))}.png") - - track.download_cover(filename=img_pth) - - album = track.albums[0] - - # set music meta - tag = MP3(path, ID3=ID3) - tag.tags.add( - APIC( - encoding=3, # 3 is for utf-8 - mime="image/png", # image/jpeg or image/png - type=3, # 3 is for the cover image - desc="Cover", - data=open(img_pth, "rb").read(), - ) - ) - tag.tags.add(TORY(text=str(album.year))) - tag.tags.add(TCON(text=album.genre)) - tag.save() - - os.remove(img_pth) - tag = EasyID3(path) - - tag["title"] = track.title - tag["album"] = album.title - tag["artist"] = track.artists[0].name - - tag.save() - - # save track - ms_path = Path(path) - song = Song( - name=track.title, - author=Author.objects.get_or_create(name=track.artists[0].name)[0], - album=Album.objects.get_or_create(name=album.title)[0], - ) - with ms_path.open(mode="rb") as f: - song.file = File(f, name=ms_path.name) - song.save() - os.remove(path) + return sng.first() + except IndexError: que.delete() - return song - except Exception as e: - que.name = e - que.error = True - que.save() + return + + filename = slugify(f"{track.artists[0].name} - {track.title}") + orig_path = f"{settings.MEDIA_ROOT}/{filename}.mp3" + album = track.albums[0] + + track.download(filename=orig_path, codec="mp3") + img_pth = str(settings.MEDIA_ROOT + f"/_{str(randint(10000, 99999))}.png") + + track.download_cover(filename=img_pth) + song = load_track( + orig_path, + img_pth, + user_id, + [x.name for x in track.artists], + album.title, + track.title, + release=album.release_date, + genre=album.genre, + ) + if os.path.exists(orig_path): + os.remove(orig_path) + if os.path.exists(img_pth): + os.remove(img_pth) + + return str(song) -def load_playlist(link: str): +def load_playlist(link: str, user_id: int): author = link.split("/")[4] playlist_id = link.split("/")[-1] client = login() playlist = client.users_playlists(int(playlist_id), author) # type: Playlist for track in playlist.fetch_tracks(): - tasks.load_ym_file_meta.apply_async(kwargs={"track": track.track.id}) + tasks.load_ym_file_meta.apply_async( + kwargs={"track": track.track.id, "user_id": user_id} + ) diff --git a/akarpov/music/services/youtube.py b/akarpov/music/services/youtube.py index 24fee82..a52d676 100644 --- a/akarpov/music/services/youtube.py +++ b/akarpov/music/services/youtube.py @@ -64,7 +64,7 @@ def parse_description(description: str) -> list: return list_of_chapters -def download_from_youtube_link(link: str) -> Song: +def download_from_youtube_link(link: str, user_id: int) -> Song: song = None with YoutubeDL(ydl_opts) as ydl: @@ -118,6 +118,7 @@ def download_from_youtube_link(link: str) -> Song: song = load_track( chapter_path, f"{img_pth}.png", + user_id, info["artists"], info["album_name"], chapters[i][2], @@ -127,6 +128,7 @@ def download_from_youtube_link(link: str) -> Song: song = load_track( chapter_path, f"{img_pth}.png", + user_id, info["artists"], info["album_name"], chapters[i][2], @@ -152,6 +154,7 @@ def download_from_youtube_link(link: str) -> Song: song = load_track( path, f"{img_pth}.png", + user_id, info["artists"], info["album_name"], title, @@ -161,6 +164,7 @@ def download_from_youtube_link(link: str) -> Song: song = load_track( path, f"{img_pth}.png", + user_id, info["artists"], info["album_name"], title, diff --git a/akarpov/music/tasks.py b/akarpov/music/tasks.py index 13194e6..12d9a6d 100644 --- a/akarpov/music/tasks.py +++ b/akarpov/music/tasks.py @@ -11,44 +11,44 @@ @shared_task -def list_tracks(url): +def list_tracks(url, user_id): if "music.yandex.ru" in url: - yandex.load_playlist(url) + yandex.load_playlist(url, user_id) elif "channel" in url or "/c/" in url: p = Channel(url) for video in p.video_urls: - process_yb.apply_async(kwargs={"url": video}) + process_yb.apply_async(kwargs={"url": video, "user_id": user_id}) elif "playlist" in url or "&list=" in url: p = Playlist(url) for video in p.video_urls: - process_yb.apply_async(kwargs={"url": video}) + process_yb.apply_async(kwargs={"url": video, "user_id": user_id}) else: - process_yb.apply_async(kwargs={"url": url}) + process_yb.apply_async(kwargs={"url": url, "user_id": user_id}) return url @shared_task(max_retries=5) -def process_yb(url): - youtube.download_from_youtube_link(url) +def process_yb(url, user_id): + youtube.download_from_youtube_link(url, user_id) return url @shared_task -def process_dir(path): - load_dir(path) +def process_dir(path, user_id): + load_dir(path, user_id) return path @shared_task -def process_file(path): - load_file(path) +def process_file(path, user_id): + load_file(path, user_id) return path @shared_task -def load_ym_file_meta(track): - return yandex.load_file_meta(track) +def load_ym_file_meta(track, user_id): + return yandex.load_file_meta(track, user_id) @shared_task() diff --git a/akarpov/music/urls.py b/akarpov/music/urls.py index a674d47..6696296 100644 --- a/akarpov/music/urls.py +++ b/akarpov/music/urls.py @@ -12,4 +12,5 @@ path("author/", views.author_view, name="author"), path("playlist/", views.playlist_view, name="playlist"), path("radio/", views.radio_main_view, name="radio"), + path("player/", views.music_player_view, name="player"), ] diff --git a/akarpov/music/views.py b/akarpov/music/views.py index 22acfdb..e785c04 100644 --- a/akarpov/music/views.py +++ b/akarpov/music/views.py @@ -55,7 +55,7 @@ def get_success_url(self): return "" def form_valid(self, form): - load_tracks(form.data["address"]) + load_tracks(form.data["address"], user_id=self.request.user.id) return super().form_valid(form) @@ -73,7 +73,7 @@ def get_success_url(self): def form_valid(self, form): for file in form.cleaned_data["file"]: t = TempFileUpload.objects.create(file=file) - load_track_file(t.file.path) + load_track_file(t.file.path, user_id=self.request.user.id) return super().form_valid(form) @@ -86,3 +86,14 @@ class MainRadioView(generic.TemplateView): radio_main_view = MainRadioView.as_view() + + +class MusicPlayerView(generic.ListView): + template_name = "music/player.html" + model = Song + + def get_queryset(self): + return Song.objects.all() + + +music_player_view = MusicPlayerView.as_view() diff --git a/akarpov/static/css/music-player.css b/akarpov/static/css/music-player.css new file mode 100644 index 0000000..16df516 --- /dev/null +++ b/akarpov/static/css/music-player.css @@ -0,0 +1,67 @@ +@import url('https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css'); + +*,*:before,*:after{outline:0;-webkit-box-sizing:border-box;box-sizing:border-box;} +input,button{outline:none;} +a,a:hover,a:visited{color:#ddd;text-decoration:none;} +.flex{display:-webkit-flex;display:flex;} +.flex-wrap{display:-webkit-flex;display:flex;-webkit-flex-wrap:wrap;flex-wrap:wrap;} +.flex-align{-webkit-align-items:center;align-items:center;} +.w-full{width:100%;} + +/* HTML5 Audio Player with Playlist, source: https://codepen.io/sekedus/pen/ExxjZEz */ +#simp button,#simp input,#simp img{border:0;} +#simp{max-width:600px;font-size:14px;font-family:"Segoe UI", Tahoma, sans-serif;text-align:initial;line-height:initial;background:#17212b;color:#ddd;margin:0 auto;border-radius:6px;overflow:hidden;} +#simp .simp-album{padding:20px 25px 5px;} +#simp .simp-album .simp-cover{margin-right:20px;} +#simp .simp-album .simp-cover img{max-width:80px;width:100%;margin:0;padding:0;display:block;} +#simp .simp-album .simp-title{font-size:120%;font-weight:bold;} +#simp .simp-album .simp-artist{font-size:90%;color:#6c7883;} +#simp .simp-controls{padding:15px;} +#simp .simp-controls button{font-size:130%;width:32px;height:32px;background:none;color:#ddd;padding:7px;cursor:pointer;border:0;border-radius:3px;} +#simp .simp-controls button[disabled]{color:#636469;cursor:initial;} +#simp .simp-controls button:not([disabled]):hover{background:#4082bc;color:#fff;} +#simp .simp-controls .simp-prev,#simp .simp-controls .simp-next{font-size:100%;} +#simp .simp-controls .simp-tracker,#simp .simp-controls .simp-volume{flex:1;margin-left:10px;position:relative;} +#simp .simp-controls .simp-buffer {position:absolute;top:50%;right:0;left:0;height:5px;margin-top:-2.5px;border-radius:100px;} +#simp .simp-controls .simp-loading .simp-buffer {-webkit-animation:audio-progress 1s linear infinite;animation:audio-progress 1s linear infinite;background-image: linear-gradient(-45deg, #000 25%, transparent 25%, transparent 50%, #000 50%, #000 75%, transparent 75%, transparent);background-repeat:repeat-x;background-size:25px 25px;color:transparent;} +#simp .simp-controls .simp-time,#simp .simp-controls .simp-others{margin-left:10px;} +#simp .simp-controls .simp-volume{max-width:110px;} +#simp .simp-controls .simp-volume .simp-mute{margin-right:5px;} +#simp .simp-controls .simp-others .simp-active{background:#242f3d;} +#simp .simp-controls .simp-others .simp-shide button{font-size:100%;padding:0;width:24px;height:14px;display:block;} +#simp .simp-controls input[type=range]{-webkit-appearance:none;background:transparent;height:19px;margin:0;width:100%;display:block;position:relative;z-index:2;} +#simp .simp-controls input[type=range]::-webkit-slider-runnable-track{background:rgba(183,197,205,.66);height:5px;border-radius:2.5px;transition:box-shadow .3s ease;position:relative;} +#simp .simp-controls input[type=range]::-moz-range-track{background:rgba(183,197,205,.66);height:5px;border-radius:2.5px;transition:box-shadow .3s ease;position:relative;} +#simp .simp-controls .simp-load .simp-progress::-webkit-slider-runnable-track{background:#2f3841;} +#simp .simp-controls .simp-load .simp-progress::-moz-range-track{background:#2f3841;} +#simp .simp-controls .simp-loading .simp-progress::-webkit-slider-runnable-track{background:rgba(255,255,255,.25);} +#simp .simp-controls .simp-loading .simp-progress::-moz-range-track{background:rgba(255,255,255,.25);} +#simp .simp-controls input[type=range]::-webkit-slider-thumb{-webkit-appearance:none;background:#fff;height:13px;width:13px;margin-top:-4px;cursor:pointer;border-radius:50%;box-shadow:0 1px 1px rgba(0,0,0,.15), 0 0 0 1px rgba(47,52,61,.2);} +#simp .simp-controls input[type=range]::-moz-range-thumb{-webkit-appearance:none;background:#fff;height:13px;width:13px;cursor:pointer;border-radius:50%;box-shadow:0 1px 1px rgba(0,0,0,.15), 0 0 0 1px rgba(47,52,61,.2);} +#simp .simp-footer{padding:10px 10px 12px;font-size:90%;text-align:center;opacity:.7;} +#simp .simp-display{overflow:hidden;max-height:650px;transition:max-height .5s ease-in-out;} +#simp .simp-hide{max-height:0;} +/* playlist */ +#simp ul{margin:5px 0 0;padding:0;list-style:none;max-height:245px;} +#simp ul li{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;display:block;margin:0;padding:8px 20px;cursor:pointer;} +#simp ul li:last-child{padding-bottom:13px;} +#simp ul li:nth-child(odd){background:#0e1621;} +#simp ul li:hover{background:#242f3d;} +#simp ul li.simp-active{background:#4082bc;color:#fff;} +#simp ul li .simp-desc{font-size:90%;opacity:.5;margin-left:5px;} +/* playlist scrollbar */ +#simp ul{overflow-y:auto;overflow-x:hidden;scrollbar-color:#73797f #2f3841;} +#simp ul::-webkit-scrollbar-track{background-color:#2f3841;} +#simp ul::-webkit-scrollbar{width:6px;background-color:#2f3841;} +#simp ul::-webkit-scrollbar-thumb{background-color:#73797f;} +/* progress animation */ +@-webkit-keyframes audio-progress{to{background-position:25px 0;}} +@keyframes audio-progress{to{background-position:25px 0;}} +/* mobile */ +@media screen and (max-width:480px) { +#simp .simp-controls .simp-volume,#simp .simp-controls .simp-others{display:none;} +#simp .simp-controls .simp-time{margin-right:10px;} +} +@media screen and (max-width:370px) { +#simp .simp-time .simp-slash,#simp .simp-time .end-time{display:none;} +} diff --git a/akarpov/static/js/music-player.js b/akarpov/static/js/music-player.js new file mode 100644 index 0000000..2e27ae1 --- /dev/null +++ b/akarpov/static/js/music-player.js @@ -0,0 +1,326 @@ +function addEventListener_multi(element, eventNames, handler) { + var events = eventNames.split(' '); + events.forEach(e => element.addEventListener(e, handler, false)); +} + +// Random numbers in a specific range +function getRandom(min, max) { + min = Math.ceil(min); + max = Math.floor(max); + return Math.floor(Math.random() * (max - min + 1)) + min; +} + +// Position element inside element +function getRelativePos(elm) { + var pPos = elm.parentNode.getBoundingClientRect(); // parent pos + var cPos = elm.getBoundingClientRect(); // target pos + var pos = {}; + + pos.top = cPos.top - pPos.top + elm.parentNode.scrollTop, + pos.right = cPos.right - pPos.right, + pos.bottom = cPos.bottom - pPos.bottom, + pos.left = cPos.left - pPos.left; + + return pos; +} + +function formatTime(val) { + var h = 0, m = 0, s; + val = parseInt(val, 10); + if (val > 60 * 60) { + h = parseInt(val / (60 * 60), 10); + val -= h * 60 * 60; + } + if (val > 60) { + m = parseInt(val / 60, 10); + val -= m * 60; + } + s = val; + val = (h > 0)? h + ':' : ''; + val += (m > 0)? ((m < 10 && h > 0)? '0' : '') + m + ':' : '0:'; + val += ((s < 10)? '0' : '') + s; + return val; +} + +function simp_initTime() { + simp_controls.querySelector('.start-time').innerHTML = formatTime(simp_audio.currentTime); //calculate current value time + if (!simp_isStream) { + simp_controls.querySelector('.end-time').innerHTML = formatTime(simp_audio.duration); //calculate total value time + simp_progress.value = simp_audio.currentTime / simp_audio.duration * 100; //progress bar + } + + // ended of the audio + if (simp_audio.currentTime == simp_audio.duration) { + simp_controls.querySelector('.simp-plause').classList.remove('fa-pause'); + simp_controls.querySelector('.simp-plause').classList.add('fa-play'); + simp_audio.removeEventListener('timeupdate', simp_initTime); + + if (simp_isNext) { //auto load next audio + var elem; + simp_a_index++; + if (simp_a_index == simp_a_url.length) { //repeat all audio + simp_a_index = 0; + elem = simp_a_url[0]; + } else { + elem = simp_a_url[simp_a_index]; + } + simp_changeAudio(elem); + simp_setAlbum(simp_a_index); + } else { + simp_isPlaying = false; + } + } +} + +function simp_initAudio() { + // if readyState more than 2, audio file has loaded + simp_isLoaded = simp_audio.readyState == 4 ? true : false; + simp_isStream = simp_audio.duration == 'Infinity' ? true : false; + simp_controls.querySelector('.simp-plause').disabled = false; + simp_progress.disabled = simp_isStream ? true : false; + if (!simp_isStream) { + simp_progress.parentNode.classList.remove('simp-load','simp-loading'); + simp_controls.querySelector('.end-time').innerHTML = formatTime(simp_audio.duration); + } + simp_audio.addEventListener('timeupdate', simp_initTime); //tracking load progress + if (simp_isLoaded && simp_isPlaying) simp_audio.play(); + + // progress bar click event + addEventListener_multi(simp_progress, 'touchstart mousedown', function(e) { + if (simp_isStream) { + e.stopPropagation(); + return false; + } + if (simp_audio.readyState == 4) { + simp_audio.removeEventListener('timeupdate', simp_initTime); + simp_audio.pause(); + } + }); + + addEventListener_multi(simp_progress, 'touchend mouseup', function(e) { + if (simp_isStream) { + e.stopPropagation(); + return false; + } + if (simp_audio.readyState == 4) { + simp_audio.currentTime = simp_progress.value * simp_audio.duration / 100; + simp_audio.addEventListener('timeupdate', simp_initTime); + if (simp_isPlaying) simp_audio.play(); + } + }); +} + +function simp_loadAudio(elem) { + simp_progress.parentNode.classList.add('simp-loading'); + simp_controls.querySelector('.simp-plause').disabled = true; + simp_audio.querySelector('source').src = elem.dataset.src; + simp_audio.load(); + + simp_audio.volume = parseFloat(simp_v_num / 100); //based on valume input value + simp_audio.addEventListener('canplaythrough', simp_initAudio); //play audio without stop for buffering + + // if audio fails to load, only IE/Edge 9.0 or above + simp_audio.addEventListener('error', function() { + alert('Please reload the page.'); + }); +} + +function simp_setAlbum(index) { + simp_cover.innerHTML = simp_a_url[index].dataset.cover ? '
' : ''; + simp_title.innerHTML = simp_source[index].querySelector('.simp-source').innerHTML; + simp_artist.innerHTML = simp_source[index].querySelector('.simp-desc') ? simp_source[index].querySelector('.simp-desc').innerHTML : ''; +} + +function simp_changeAudio(elem) { + simp_isLoaded = false; + simp_controls.querySelector('.simp-prev').disabled = simp_a_index == 0 ? true : false; + simp_controls.querySelector('.simp-plause').disabled = simp_auto_load ? true : false; + simp_controls.querySelector('.simp-next').disabled = simp_a_index == simp_a_url.length-1 ? true : false; + simp_progress.parentNode.classList.add('simp-load'); + simp_progress.disabled = true; + simp_progress.value = 0; + simp_controls.querySelector('.start-time').innerHTML = '00:00'; + simp_controls.querySelector('.end-time').innerHTML = '00:00'; + elem = simp_isRandom && simp_isNext ? simp_a_url[getRandom(0, simp_a_url.length-1)] : elem; + + // playlist, audio is running + for (var i = 0; i < simp_a_url.length; i++) { + simp_a_url[i].parentNode.classList.remove('simp-active'); + if (simp_a_url[i] == elem) { + simp_a_index = i; + simp_a_url[i].parentNode.classList.add('simp-active'); + } + } + + // scrolling to element inside element + var simp_active = getRelativePos(simp_source[simp_a_index]); + simp_source[simp_a_index].parentNode.scrollTop = simp_active.top; + + if (simp_auto_load || simp_isPlaying) simp_loadAudio(elem); + + if (simp_isPlaying) { + simp_controls.querySelector('.simp-plause').classList.remove('fa-play'); + simp_controls.querySelector('.simp-plause').classList.add('fa-pause'); + } +} + +function simp_startScript() { + ap_simp = document.querySelector('#simp'); + simp_audio = ap_simp.querySelector('#audio'); + simp_album = ap_simp.querySelector('.simp-album'); + simp_cover = simp_album.querySelector('.simp-cover'); + simp_title = simp_album.querySelector('.simp-title'); + simp_artist = simp_album.querySelector('.simp-artist'); + simp_controls = ap_simp.querySelector('.simp-controls'); + simp_progress = simp_controls.querySelector('.simp-progress'); + simp_volume = simp_controls.querySelector('.simp-volume'); + simp_v_slider = simp_volume.querySelector('.simp-v-slider'); + simp_v_num = simp_v_slider.value; //default volume + simp_others = simp_controls.querySelector('.simp-others'); + simp_auto_load = simp_config.auto_load; //auto load audio file + + if (simp_config.shide_top) simp_album.parentNode.classList.toggle('simp-hide'); + if (simp_config.shide_btm) { + simp_playlist.classList.add('simp-display'); + simp_playlist.classList.toggle('simp-hide'); + } + + if (simp_a_url.length <= 1) { + simp_controls.querySelector('.simp-prev').style.display = 'none'; + simp_controls.querySelector('.simp-next').style.display = 'none'; + simp_others.querySelector('.simp-plext').style.display = 'none'; + simp_others.querySelector('.simp-random').style.display = 'none'; + } + + // Playlist listeners + simp_source.forEach(function(item, index) { + if (item.classList.contains('simp-active')) simp_a_index = index; //playlist contains '.simp-active' + item.addEventListener('click', function() { + simp_audio.removeEventListener('timeupdate', simp_initTime); + simp_a_index = index; + simp_changeAudio(this.querySelector('.simp-source')); + simp_setAlbum(simp_a_index); + }); + }); + + // FIRST AUDIO LOAD ======= + simp_changeAudio(simp_a_url[simp_a_index]); + simp_setAlbum(simp_a_index); + // FIRST AUDIO LOAD ======= + + // Controls listeners + simp_controls.querySelector('.simp-plauseward').addEventListener('click', function(e) { + var eles = e.target.classList; + if (eles.contains('simp-plause')) { + if (simp_audio.paused) { + if (!simp_isLoaded) simp_loadAudio(simp_a_url[simp_a_index]); + simp_audio.play(); + simp_isPlaying = true; + eles.remove('fa-play'); + eles.add('fa-pause'); + } else { + simp_audio.pause(); + simp_isPlaying = false; + eles.remove('fa-pause'); + eles.add('fa-play'); + } + } else { + if (eles.contains('simp-prev') && simp_a_index != 0) { + simp_a_index = simp_a_index-1; + e.target.disabled = simp_a_index == 0 ? true : false; + } else if (eles.contains('simp-next') && simp_a_index != simp_a_url.length-1) { + simp_a_index = simp_a_index+1; + e.target.disabled = simp_a_index == simp_a_url.length-1 ? true : false; + } + simp_audio.removeEventListener('timeupdate', simp_initTime); + simp_changeAudio(simp_a_url[simp_a_index]); + simp_setAlbum(simp_a_index); + } + }); + + // Audio volume + simp_volume.addEventListener('click', function(e) { + var eles = e.target.classList; + if (eles.contains('simp-mute')) { + if (eles.contains('fa-volume-up')) { + eles.remove('fa-volume-up'); + eles.add('fa-volume-off'); + simp_v_slider.value = 0; + } else { + eles.remove('fa-volume-off'); + eles.add('fa-volume-up'); + simp_v_slider.value = simp_v_num; + } + } else { + simp_v_num = simp_v_slider.value; + if (simp_v_num != 0) { + simp_controls.querySelector('.simp-mute').classList.remove('fa-volume-off'); + simp_controls.querySelector('.simp-mute').classList.add('fa-volume-up'); + } + } + simp_audio.volume = parseFloat(simp_v_slider.value / 100); + }); + + // Others + simp_others.addEventListener('click', function(e) { + var eles = e.target.classList; + if (eles.contains('simp-plext')) { + simp_isNext = simp_isNext && !simp_isRandom ? false : true; + if (!simp_isRandom) simp_isRanext = simp_isRanext ? false : true; + eles.contains('simp-active') && !simp_isRandom ? eles.remove('simp-active') : eles.add('simp-active'); + } else if (eles.contains('simp-random')) { + simp_isRandom = simp_isRandom ? false : true; + if (simp_isNext && !simp_isRanext) { + simp_isNext = false; + simp_others.querySelector('.simp-plext').classList.remove('simp-active'); + } else { + simp_isNext = true; + simp_others.querySelector('.simp-plext').classList.add('simp-active'); + } + eles.contains('simp-active') ? eles.remove('simp-active') : eles.add('simp-active'); + } else if (eles.contains('simp-shide-top')) { + simp_album.parentNode.classList.toggle('simp-hide'); + } else if (eles.contains('simp-shide-bottom')) { + simp_playlist.classList.add('simp-display'); + simp_playlist.classList.toggle('simp-hide'); + } + }); +} + +// Start simple player +if (document.querySelector('#simp')) { + var simp_auto_load, simp_audio, simp_album, simp_cover, simp_title, simp_artist, simp_controls, simp_progress, simp_volume, simp_v_slider, simp_v_num, simp_others; + var ap_simp = document.querySelector('#simp'); + var simp_playlist = ap_simp.querySelector('.simp-playlist'); + var simp_source = simp_playlist.querySelectorAll('li'); + var simp_a_url = simp_playlist.querySelectorAll('[data-src]'); + var simp_a_index = 0; + var simp_isPlaying = false; + var simp_isNext = false; //auto play + var simp_isRandom = false; //play random + var simp_isRanext = false; //check if before random starts, simp_isNext value is true + var simp_isStream = false; //radio streaming + var simp_isLoaded = false; //audio file has loaded + var simp_config = ap_simp.dataset.config ? JSON.parse(ap_simp.dataset.config) : { + shide_top: false, //show/hide album + shide_btm: false, //show/hide playlist + auto_load: false //auto load audio file + }; + + var simp_elem = ''; + simp_elem += ''; + simp_elem += '
Title
Artist
'; + simp_elem += '
'; + simp_elem += '
'; + simp_elem += '
'; + simp_elem += '
00:00 / 00:00
'; + simp_elem += '
'; + simp_elem += '
'; + simp_elem += '
'; //simp-controls + + var simp_player = document.createElement('div'); + simp_player.classList.add('simp-player'); + simp_player.innerHTML = simp_elem; + ap_simp.insertBefore(simp_player, simp_playlist); + simp_startScript(); +} diff --git a/akarpov/templates/music/player.html b/akarpov/templates/music/player.html new file mode 100644 index 0000000..ae351d5 --- /dev/null +++ b/akarpov/templates/music/player.html @@ -0,0 +1,19 @@ +{% extends 'base.html' %} +{% load static %} + {% block css %} + + {% endblock %} + {% block content %} +
+
+
+
    + {% for song in song_list %} +
  • {{ song.name }}{{ song.full_props }}
  • + {% endfor %} +
+
+
+
+ +{% endblock content %} diff --git a/akarpov/templates/music/upload.html b/akarpov/templates/music/upload.html index da1a1e6..7a5be42 100644 --- a/akarpov/templates/music/upload.html +++ b/akarpov/templates/music/upload.html @@ -2,7 +2,7 @@ {% load static %} {% load crispy_forms_tags %} -{% block title %}editing post on akarpov{% endblock %} +{% block title %}loading music on akarpov{% endblock %} {% block content %}
diff --git a/akarpov/utils/files.py b/akarpov/utils/files.py index 441cfb5..d24ef3f 100644 --- a/akarpov/utils/files.py +++ b/akarpov/utils/files.py @@ -60,11 +60,14 @@ def crop_image(image_path: str, length: int = 500): def user_file_upload_mixin(instance, filename): """stores user uploaded files at their folder in media dir""" username = "" - if isinstance(instance, get_user_model()): - username = instance.username + "/" - elif hasattr(instance, "user"): - username = instance.user.username + "/" - elif hasattr(instance, "creator"): - username = instance.creator.username + "/" + try: + if isinstance(instance, get_user_model()): + username = instance.username + "/" + elif hasattr(instance, "user"): + username = instance.user.username + "/" + elif hasattr(instance, "creator"): + username = instance.creator.username + "/" + except AttributeError: + username = "__all" return os.path.join(f"uploads/{username}", filename) diff --git a/config/api_router.py b/config/api_router.py index 94b4eb1..0f23f2b 100644 --- a/config/api_router.py +++ b/config/api_router.py @@ -32,6 +32,10 @@ "blog/", include("akarpov.blog.api.urls", namespace="blog"), ), + path( + "music/", + include("akarpov.music.api.urls", namespace="music"), + ), path( "tools/", include( diff --git a/poetry.lock b/poetry.lock index 1f4a22c..f0b0206 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,9 +1,10 @@ -# This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.4.2 and should not be changed by hand. [[package]] name = "aiofiles" version = "23.2.1" description = "File support for asyncio." +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -15,6 +16,7 @@ files = [ name = "aiohttp" version = "3.8.5" description = "Async http client/server framework (asyncio)" +category = "main" optional = false python-versions = ">=3.6" files = [ @@ -123,6 +125,7 @@ speedups = ["Brotli", "aiodns", "cchardet"] name = "aiosignal" version = "1.3.1" description = "aiosignal: a list of registered asynchronous callbacks" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -137,6 +140,7 @@ frozenlist = ">=1.1.0" name = "alabaster" version = "0.7.13" description = "A configurable sidebar-enabled Sphinx theme" +category = "main" optional = false python-versions = ">=3.6" files = [ @@ -148,6 +152,7 @@ files = [ name = "amqp" version = "5.1.1" description = "Low-level AMQP client for Python (fork of amqplib)." +category = "main" optional = false python-versions = ">=3.6" files = [ @@ -162,6 +167,7 @@ vine = ">=5.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 = [ @@ -178,6 +184,7 @@ Pillow = ">=3.3.1" name = "annotated-types" version = "0.5.0" description = "Reusable constraint types to use with typing.Annotated" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -189,6 +196,7 @@ files = [ name = "anyio" version = "4.0.0" description = "High level compatibility layer for multiple asynchronous event loop implementations" +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -209,6 +217,7 @@ trio = ["trio (>=0.22)"] 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 = [ @@ -220,6 +229,7 @@ files = [ name = "appnope" version = "0.1.3" description = "Disable App Nap on macOS >= 10.9" +category = "main" optional = false python-versions = "*" files = [ @@ -231,6 +241,7 @@ files = [ name = "argcomplete" version = "1.10.3" description = "Bash tab completion for argparse" +category = "main" optional = false python-versions = "*" files = [ @@ -245,6 +256,7 @@ test = ["coverage", "flake8", "pexpect", "wheel"] name = "argon2-cffi" version = "21.3.0" description = "The secure Argon2 password hashing algorithm." +category = "main" optional = false python-versions = ">=3.6" files = [ @@ -264,6 +276,7 @@ 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 = [ @@ -301,6 +314,7 @@ tests = ["pytest"] name = "asgiref" version = "3.7.2" description = "ASGI specs, helper code, and adapters" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -315,6 +329,7 @@ tests = ["mypy (>=0.800)", "pytest", "pytest-asyncio"] name = "astroid" version = "2.15.6" description = "An abstract syntax tree for Python with inference support." +category = "main" optional = false python-versions = ">=3.7.2" files = [ @@ -330,6 +345,7 @@ wrapt = {version = ">=1.14,<2", markers = "python_version >= \"3.11\""} name = "asttokens" version = "2.4.0" description = "Annotate AST trees with source code positions" +category = "main" optional = false python-versions = "*" files = [ @@ -347,6 +363,7 @@ test = ["astroid", "pytest"] name = "async-timeout" version = "4.0.3" description = "Timeout context manager for asyncio programs" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -358,6 +375,7 @@ files = [ name = "attrs" version = "23.1.0" description = "Classes Without Boilerplate" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -376,6 +394,7 @@ tests-no-zope = ["cloudpickle", "hypothesis", "mypy (>=1.1.1)", "pympler", "pyte name = "autobahn" version = "23.6.2" description = "WebSocket client & server library, WAMP real-time framework" +category = "main" optional = false python-versions = ">=3.9" files = [ @@ -404,6 +423,7 @@ 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 = [ @@ -422,6 +442,7 @@ visualize = ["Twisted (>=16.1.1)", "graphviz (>0.5.1)"] name = "babel" version = "2.12.1" description = "Internationalization utilities" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -433,6 +454,7 @@ files = [ name = "backcall" version = "0.2.0" description = "Specifications for callback functions passed in to an API" +category = "main" optional = false python-versions = "*" files = [ @@ -444,6 +466,7 @@ files = [ name = "beautifulsoup4" version = "4.8.2" description = "Screen-scraping library" +category = "main" optional = false python-versions = "*" files = [ @@ -463,6 +486,7 @@ lxml = ["lxml"] name = "billiard" version = "4.1.0" description = "Python multiprocessing fork with improvements and bugfixes" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -474,6 +498,7 @@ files = [ name = "black" version = "23.7.0" description = "The uncompromising code formatter." +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -518,6 +543,7 @@ uvloop = ["uvloop (>=0.15.2)"] name = "blis" version = "0.7.10" description = "The Blis BLAS-like linear algebra library, as a self-contained C-extension." +category = "main" optional = false python-versions = "*" files = [ @@ -558,6 +584,7 @@ numpy = {version = ">=1.19.0", markers = "python_version >= \"3.9\""} name = "brotli" version = "1.1.0" description = "Python bindings for the Brotli compression library" +category = "main" optional = false python-versions = "*" files = [ @@ -650,6 +677,7 @@ files = [ name = "brotlicffi" version = "1.0.9.2" description = "Python CFFI bindings to the Brotli library" +category = "main" optional = false python-versions = "*" files = [ @@ -692,6 +720,7 @@ 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 = [ @@ -711,6 +740,7 @@ 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 = [ @@ -733,6 +763,7 @@ test = ["flake8", "isort", "pytest"] name = "catalogue" version = "2.0.9" description = "Super lightweight function registries for your library" +category = "main" optional = false python-versions = ">=3.6" files = [ @@ -744,6 +775,7 @@ files = [ name = "celery" version = "5.3.4" description = "Distributed Task Queue." +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -800,6 +832,7 @@ zstd = ["zstandard (==0.21.0)"] name = "certifi" version = "2023.7.22" description = "Python package for providing Mozilla's CA Bundle." +category = "main" optional = false python-versions = ">=3.6" files = [ @@ -811,6 +844,7 @@ files = [ name = "cffi" version = "1.15.1" description = "Foreign Function Interface for Python calling C code." +category = "main" optional = false python-versions = "*" files = [ @@ -887,6 +921,7 @@ 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 = [ @@ -898,6 +933,7 @@ 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 = [ @@ -918,6 +954,7 @@ tests = ["async-timeout", "coverage (>=4.5,<5.0)", "pytest", "pytest-asyncio", " name = "channels-redis" version = "4.1.0" description = "Redis-backed ASGI channel layer implementation" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -939,6 +976,7 @@ tests = ["async-timeout", "cryptography (>=1.3.0)", "pytest", "pytest-asyncio", name = "chardet" version = "3.0.4" description = "Universal encoding detector for Python 2 and 3" +category = "main" optional = false python-versions = "*" files = [ @@ -950,6 +988,7 @@ files = [ name = "charset-normalizer" version = "3.2.0" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." +category = "main" optional = false python-versions = ">=3.7.0" files = [ @@ -1034,6 +1073,7 @@ files = [ name = "click" version = "8.1.7" description = "Composable command line interface toolkit" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1048,6 +1088,7 @@ 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 = [ @@ -1062,6 +1103,7 @@ 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 = [ @@ -1079,6 +1121,7 @@ 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 = [ @@ -1097,6 +1140,7 @@ 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 = [ @@ -1108,6 +1152,7 @@ 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 = [ @@ -1118,6 +1163,7 @@ files = [ name = "confection" version = "0.1.2" description = "The sweetest config system for Python" +category = "main" optional = false python-versions = ">=3.6" files = [ @@ -1133,6 +1179,7 @@ srsly = ">=2.4.0,<3.0.0" name = "constantly" version = "15.1.0" description = "Symbolic constants in Python" +category = "main" optional = false python-versions = "*" files = [ @@ -1144,6 +1191,7 @@ files = [ name = "contourpy" version = "1.1.0" description = "Python library for calculating contours of 2D quadrilateral grids" +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -1202,6 +1250,7 @@ test-no-images = ["pytest", "pytest-cov", "wurlitzer"] name = "coverage" version = "7.3.1" description = "Code coverage measurement for Python" +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -1266,6 +1315,7 @@ 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 = [ @@ -1284,6 +1334,7 @@ test = ["pytest", "pytest-django"] name = "cron-descriptor" version = "1.4.0" description = "A Python library that converts cron expressions into human readable strings." +category = "main" optional = false python-versions = "*" files = [ @@ -1297,6 +1348,7 @@ dev = ["polib"] name = "cryptography" version = "41.0.3" description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1342,6 +1394,7 @@ 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 = [ @@ -1361,6 +1414,7 @@ test = ["flake8", "isort", "pytest"] name = "cycler" version = "0.11.0" description = "Composable style cycles" +category = "main" optional = false python-versions = ">=3.6" files = [ @@ -1372,6 +1426,7 @@ files = [ name = "cymem" version = "2.0.7" description = "Manage calls to calloc/free through Cython" +category = "main" optional = false python-versions = "*" files = [ @@ -1409,6 +1464,7 @@ files = [ name = "daphne" version = "4.0.0" description = "Django ASGI (HTTP/WebSocket) server" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1428,6 +1484,7 @@ tests = ["django", "hypothesis", "pytest", "pytest-asyncio"] name = "decorator" version = "5.1.1" description = "Decorators for Humans" +category = "main" optional = false python-versions = ">=3.5" files = [ @@ -1439,6 +1496,7 @@ files = [ 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 = [ @@ -1450,6 +1508,7 @@ files = [ name = "dill" version = "0.3.7" description = "serialize all of Python" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1464,6 +1523,7 @@ graph = ["objgraph (>=1.7.2)"] name = "distlib" version = "0.3.7" description = "Distribution utilities" +category = "main" optional = false python-versions = "*" files = [ @@ -1475,6 +1535,7 @@ files = [ name = "django" version = "4.2.5" description = "A high-level Python web framework that encourages rapid development and clean, pragmatic design." +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -1495,6 +1556,7 @@ 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 = [ @@ -1506,6 +1568,7 @@ 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 = [ @@ -1523,6 +1586,7 @@ requests-oauthlib = ">=0.3.0" name = "django-anymail" version = "10.1" description = "Django email backends and webhooks for Amazon SES, Brevo (Sendinblue), MailerSend, Mailgun, Mailjet, Mandrill, Postal, Postmark, SendGrid, and SparkPost" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1543,6 +1607,7 @@ postal = ["cryptography"] name = "django-cacheops" version = "7.0.1" description = "A slick ORM cache with automatic granular event-driven invalidation for Django." +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1558,6 +1623,7 @@ redis = ">=3.0.0" name = "django-celery-beat" version = "2.5.0" description = "Database-backed Periodic Tasks." +category = "main" optional = false python-versions = "*" files = [ @@ -1577,6 +1643,7 @@ tzdata = "*" name = "django-ckeditor" version = "6.7.0" description = "Django admin CKEditor integration." +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -1592,6 +1659,7 @@ django-js-asset = ">=2.0" name = "django-classy-tags" version = "4.1.0" description = "Class based template tags for Django" +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -1606,6 +1674,7 @@ django = ">=3.2" name = "django-colorfield" version = "0.8.0" description = "simple color field for your models with a nice color-picker in the admin-interface." +category = "main" optional = false python-versions = "*" files = [ @@ -1620,6 +1689,7 @@ Pillow = ">=9.0.0" name = "django-cors-headers" version = "4.2.0" 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 = [ @@ -1634,6 +1704,7 @@ Django = ">=3.2" name = "django-coverage-plugin" version = "3.1.0" description = "Django template coverage.py plugin" +category = "main" optional = false python-versions = "*" files = [ @@ -1648,6 +1719,7 @@ coverage = "*" name = "django-crispy-forms" version = "1.14.0" description = "Best way to have Django DRY forms" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1659,6 +1731,7 @@ files = [ name = "django-debug-toolbar" version = "4.2.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 = [ @@ -1674,6 +1747,7 @@ sqlparse = ">=0.2" 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 = [ @@ -1682,14 +1756,15 @@ files = [ ] [package.extras] -develop = ["coverage[toml] (>=5.0a4)", "furo (>=2021.8.17b43,<2021.9.dev0)", "pytest (>=4.6.11)", "sphinx (>=3.5.0)", "sphinx-notfound-page"] -docs = ["furo (>=2021.8.17b43,<2021.9.dev0)", "sphinx (>=3.5.0)", "sphinx-notfound-page"] +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"] 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 = [ @@ -1704,6 +1779,7 @@ 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 = [ @@ -1718,6 +1794,7 @@ jsonfield = ">=3.0.0" name = "django-filter" version = "23.2" description = "Django-filter is a reusable Django application for allowing users to filter querysets dynamically." +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1732,6 +1809,7 @@ Django = ">=3.2" name = "django-health-check" version = "3.17.0" description = "Run checks on services like databases, queue servers, celery processes, etc." +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -1750,6 +1828,7 @@ test = ["celery", "pytest", "pytest-cov", "pytest-django", "redis"] name = "django-ipware" version = "5.0.0" description = "A Django application to retrieve user's IP address" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1761,6 +1840,7 @@ 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 = [ @@ -1775,6 +1855,7 @@ django = ">=2.2" name = "django-js-asset" version = "2.1.0" description = "script tag with additional attributes for django.forms.Media" +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -1792,6 +1873,7 @@ tests = ["coverage"] name = "django-location-field" version = "2.7.2" description = "Location field for Django" +category = "main" optional = false python-versions = "*" files = [ @@ -1802,6 +1884,7 @@ files = [ name = "django-model-utils" version = "4.3.1" description = "Django model mixins and utilities" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1816,6 +1899,7 @@ Django = ">=3.2" name = "django-polymorphic" version = "3.1.0" description = "Seamless polymorphic inheritance for Django models" +category = "main" optional = false python-versions = "*" files = [ @@ -1830,6 +1914,7 @@ Django = ">=2.1" name = "django-redis" version = "5.3.0" description = "Full featured redis cache backend for Django." +category = "main" optional = false python-versions = ">=3.6" files = [ @@ -1848,6 +1933,7 @@ 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 = [ @@ -1866,6 +1952,7 @@ 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 = [ @@ -1876,6 +1963,7 @@ files = [ name = "django-sekizai" version = "4.1.0" description = "Django Sekizai" +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -1891,6 +1979,7 @@ 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 = [ @@ -1911,6 +2000,7 @@ 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 = [ @@ -1937,6 +2027,7 @@ compatible-mypy = ["mypy (>=0.991,<1.0)"] name = "django-stubs-ext" version = "4.2.2" description = "Monkey-patching and extensions for django-stubs" +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -1952,6 +2043,7 @@ typing-extensions = "*" name = "django-tables2" version = "2.6.0" description = "Table/data-grid framework for Django" +category = "main" optional = false python-versions = "*" files = [ @@ -1969,6 +2061,7 @@ tablib = ["tablib"] name = "django-timezone-field" version = "6.0.1" 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 = [ @@ -1983,6 +2076,7 @@ Django = ">=3.2,<5.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 = [ @@ -1997,6 +2091,7 @@ python-magic = "*" name = "djangorestframework" version = "3.14.0" description = "Web APIs for Django, made easy." +category = "main" optional = false python-versions = ">=3.6" files = [ @@ -2012,6 +2107,7 @@ 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 = [ @@ -2039,6 +2135,7 @@ markdown = ["types-Markdown (>=0.1.5)"] name = "dnspython" version = "2.4.2" description = "DNS toolkit" +category = "main" optional = false python-versions = ">=3.8,<4.0" files = [ @@ -2058,6 +2155,7 @@ wmi = ["wmi (>=1.5.1,<2.0.0)"] name = "docutils" version = "0.20.1" description = "Docutils -- Python Documentation Utilities" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -2069,6 +2167,7 @@ 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 = [ @@ -2079,6 +2178,7 @@ files = [ name = "drf-spectacular" version = "0.26.4" description = "Sane and flexible OpenAPI 3 schema generation for Django REST framework" +category = "main" optional = false python-versions = ">=3.6" files = [ @@ -2102,6 +2202,7 @@ sidecar = ["drf-spectacular-sidecar"] name = "ebcdic" version = "1.1.1" description = "Additional EBCDIC codecs" +category = "main" optional = false python-versions = "*" files = [ @@ -2112,6 +2213,7 @@ files = [ name = "email-validator" version = "2.0.0.post2" description = "A robust email address syntax and deliverability validation library." +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -2127,6 +2229,7 @@ idna = ">=2.0.0" name = "execnet" version = "2.0.2" description = "execnet: rapid multi-Python deployment" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -2141,6 +2244,7 @@ testing = ["hatch", "pre-commit", "pytest", "tox"] name = "executing" version = "1.2.0" description = "Get the currently executing AST node of a frame, and other information" +category = "main" optional = false python-versions = "*" files = [ @@ -2155,6 +2259,7 @@ tests = ["asttokens", "littleutils", "pytest", "rich"] name = "extract-msg" version = "0.28.7" description = "Extracts emails and attachments saved in Microsoft Outlook's .msg files" +category = "main" optional = false python-versions = "*" files = [ @@ -2173,6 +2278,7 @@ tzlocal = ">=2.1" 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 = [ @@ -2191,6 +2297,7 @@ doc = ["Sphinx", "sphinx-rtd-theme", "sphinxcontrib-spelling"] name = "faker" version = "19.4.0" description = "Faker is a Python package that generates fake data for you." +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -2205,6 +2312,7 @@ python-dateutil = ">=2.4" name = "fastapi" version = "0.101.1" description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -2235,6 +2343,7 @@ 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 = [ @@ -2252,6 +2361,7 @@ dev = ["Sphinx (==2.1.0)", "future (==0.17.1)", "numpy (==1.16.4)", "pytest (==4 name = "filelock" version = "3.12.3" description = "A platform independent file lock." +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -2267,6 +2377,7 @@ testing = ["covdefaults (>=2.3)", "coverage (>=7.3)", "diff-cover (>=7.7)", "pyt 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 = [ @@ -2283,6 +2394,7 @@ pyflakes = ">=3.1.0,<3.2.0" name = "flake8-isort" version = "6.0.0" description = "flake8 plugin that integrates isort ." +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -2301,6 +2413,7 @@ test = ["pytest"] name = "flower" version = "2.0.1" description = "Celery Flower" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -2319,6 +2432,7 @@ tornado = ">=5.0.0,<7.0.0" name = "fonttools" version = "4.42.1" description = "Tools to manipulate font files" +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -2376,6 +2490,7 @@ woff = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "zopfli (>=0.1.4)"] name = "frozenlist" version = "1.4.0" description = "A list-like structure which implements collections.abc.MutableSequence" +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -2446,6 +2561,7 @@ files = [ name = "fsspec" version = "2023.9.0" description = "File-system specification" +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -2481,6 +2597,7 @@ tqdm = ["tqdm"] name = "funcy" version = "1.18" description = "A fancy and practical functional tools" +category = "main" optional = false python-versions = "*" files = [ @@ -2492,6 +2609,7 @@ files = [ name = "future" version = "0.18.3" 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 = [ @@ -2502,6 +2620,7 @@ files = [ name = "greenlet" version = "2.0.2" description = "Lightweight in-process concurrent programming" +category = "main" optional = false python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*" files = [ @@ -2575,6 +2694,7 @@ test = ["objgraph", "psutil"] name = "gunicorn" version = "21.2.0" description = "WSGI HTTP Server for UNIX" +category = "main" optional = false python-versions = ">=3.5" files = [ @@ -2595,6 +2715,7 @@ 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 = [ @@ -2606,6 +2727,7 @@ files = [ name = "hiredis" version = "2.2.3" description = "Python wrapper for hiredis" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -2704,6 +2826,7 @@ files = [ name = "httpcore" version = "0.17.3" description = "A minimal low-level HTTP client." +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -2715,16 +2838,17 @@ files = [ anyio = ">=3.0,<5.0" certifi = "*" h11 = ">=0.13,<0.15" -sniffio = "==1.*" +sniffio = ">=1.0.0,<2.0.0" [package.extras] http2 = ["h2 (>=3,<5)"] -socks = ["socksio (==1.*)"] +socks = ["socksio (>=1.0.0,<2.0.0)"] [[package]] name = "httptools" version = "0.6.0" description = "A collection of framework independent HTTP protocol utils." +category = "main" optional = false python-versions = ">=3.5.0" files = [ @@ -2772,6 +2896,7 @@ test = ["Cython (>=0.29.24,<0.30.0)"] name = "httpx" version = "0.24.1" description = "The next generation HTTP client." +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -2787,14 +2912,15 @@ sniffio = "*" [package.extras] brotli = ["brotli", "brotlicffi"] -cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<14)"] +cli = ["click (>=8.0.0,<9.0.0)", "pygments (>=2.0.0,<3.0.0)", "rich (>=10,<14)"] http2 = ["h2 (>=3,<5)"] -socks = ["socksio (==1.*)"] +socks = ["socksio (>=1.0.0,<2.0.0)"] [[package]] name = "huggingface-hub" version = "0.16.4" description = "Client library to download and publish models, datasets and other repos on the huggingface.co hub" +category = "main" optional = false python-versions = ">=3.7.0" files = [ @@ -2827,6 +2953,7 @@ typing = ["pydantic", "types-PyYAML", "types-requests", "types-simplejson", "typ name = "humanize" version = "4.8.0" description = "Python humanize utilities" +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -2841,6 +2968,7 @@ 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 = [ @@ -2855,6 +2983,7 @@ idna = ">=2.5" name = "identify" version = "2.5.27" description = "File identification library for Python" +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -2869,6 +2998,7 @@ license = ["ukkonen"] name = "idna" version = "3.4" description = "Internationalized Domain Names in Applications (IDNA)" +category = "main" optional = false python-versions = ">=3.5" files = [ @@ -2880,6 +3010,7 @@ files = [ name = "imageio" version = "2.31.3" 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 = [ @@ -2911,6 +3042,7 @@ 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 = [ @@ -2922,6 +3054,7 @@ files = [ name = "imapclient" version = "2.1.0" description = "Easy-to-use, Pythonic and complete IMAP client library" +category = "main" optional = false python-versions = "*" files = [ @@ -2940,6 +3073,7 @@ test = ["mock (>=1.3.0)"] name = "incremental" version = "22.10.0" description = "\"A small library that versions your Python projects.\"" +category = "main" optional = false python-versions = "*" files = [ @@ -2955,6 +3089,7 @@ 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 = [ @@ -2966,6 +3101,7 @@ files = [ name = "iniconfig" version = "2.0.0" description = "brain-dead simple config-ini parsing" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -2977,6 +3113,7 @@ 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 = [ @@ -2992,6 +3129,7 @@ ipython = {version = ">=7.31.1", markers = "python_version >= \"3.11\""} name = "ipython" version = "8.15.0" description = "IPython: Productive Interactive Computing" +category = "main" optional = false python-versions = ">=3.9" files = [ @@ -3030,6 +3168,7 @@ test-extra = ["curio", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.21)", "pa name = "isort" version = "5.12.0" description = "A Python utility / library to sort Python imports." +category = "main" optional = false python-versions = ">=3.8.0" files = [ @@ -3047,6 +3186,7 @@ requirements-deprecated-finder = ["pip-api", "pipreqs"] name = "itsdangerous" version = "2.1.2" description = "Safely pass data to untrusted environments and back." +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -3058,6 +3198,7 @@ files = [ name = "jedi" version = "0.19.0" description = "An autocompletion tool for Python that can be used for text editors." +category = "main" optional = false python-versions = ">=3.6" files = [ @@ -3077,6 +3218,7 @@ testing = ["Django (<3.1)", "attrs", "colorama", "docopt", "pytest (<7.0.0)"] name = "jinja2" version = "3.1.2" description = "A very fast and expressive template engine." +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -3094,6 +3236,7 @@ i18n = ["Babel (>=2.7)"] 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 = [ @@ -3108,6 +3251,7 @@ Django = ">=2.2" name = "jsonschema" version = "4.19.0" description = "An implementation of JSON Schema validation for Python" +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -3129,6 +3273,7 @@ format-nongpl = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339- name = "jsonschema-specifications" version = "2023.7.1" description = "The JSON Schema meta-schemas and vocabularies, exposed as a Registry" +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -3143,6 +3288,7 @@ referencing = ">=0.28.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 = [ @@ -3256,6 +3402,7 @@ files = [ name = "kombu" version = "5.3.2" description = "Messaging library for Python." +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -3288,6 +3435,7 @@ zookeeper = ["kazoo (>=2.8.0)"] name = "langcodes" version = "3.3.0" description = "Tools for labeling human languages with IETF language tags" +category = "main" optional = false python-versions = ">=3.6" files = [ @@ -3302,6 +3450,7 @@ data = ["language-data (>=1.1,<2.0)"] name = "lazy-object-proxy" version = "1.9.0" description = "A fast and thorough lazy object proxy." +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -3347,6 +3496,7 @@ files = [ name = "livereload" version = "2.6.3" description = "Python LiveReload is an awesome tool for web developers" +category = "main" optional = false python-versions = "*" files = [ @@ -3362,6 +3512,7 @@ tornado = {version = "*", markers = "python_version > \"2.7\""} name = "lxml" version = "4.9.3" description = "Powerful and Pythonic XML processing library combining libxml2/libxslt with the ElementTree API." +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, != 3.4.*" files = [ @@ -3469,6 +3620,7 @@ source = ["Cython (>=0.29.35)"] name = "mako" version = "1.2.4" description = "A super-fast templating language that borrows the best ideas from the existing templating languages." +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -3488,6 +3640,7 @@ testing = ["pytest"] name = "markdown" version = "3.4.4" description = "Python implementation of John Gruber's Markdown." +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -3503,6 +3656,7 @@ testing = ["coverage", "pyyaml"] name = "markupsafe" version = "2.1.3" description = "Safely add untrusted strings to HTML/XML markup." +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -3562,6 +3716,7 @@ files = [ name = "matplotlib" version = "3.7.2" description = "Python plotting package" +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -3623,6 +3778,7 @@ 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 = [ @@ -3637,6 +3793,7 @@ traitlets = "*" name = "mccabe" version = "0.7.0" description = "McCabe checker, plugin for flake8" +category = "main" optional = false python-versions = ">=3.6" files = [ @@ -3648,6 +3805,7 @@ files = [ name = "mpmath" version = "1.3.0" description = "Python library for arbitrary-precision floating-point arithmetic" +category = "main" optional = false python-versions = "*" files = [ @@ -3665,6 +3823,7 @@ tests = ["pytest (>=4.6)"] name = "msgpack" version = "1.0.5" description = "MessagePack serializer" +category = "main" optional = false python-versions = "*" files = [ @@ -3737,6 +3896,7 @@ files = [ name = "multidict" version = "6.0.4" description = "multidict implementation" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -3820,6 +3980,7 @@ files = [ name = "murmurhash" version = "1.0.9" description = "Cython bindings for MurmurHash" +category = "main" optional = false python-versions = ">=3.6" files = [ @@ -3857,6 +4018,7 @@ 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 = [ @@ -3868,6 +4030,7 @@ files = [ name = "mypy" version = "0.991" description = "Optional static typing for Python" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -3917,6 +4080,7 @@ 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 = [ @@ -3928,6 +4092,7 @@ files = [ name = "networkx" version = "3.1" description = "Python package for creating and manipulating graphs and networks" +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -3946,6 +4111,7 @@ test = ["codecov (>=2.1)", "pytest (>=7.2)", "pytest-cov (>=4.0)"] 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 = [ @@ -3960,6 +4126,7 @@ setuptools = "*" name = "numpy" version = "1.25.2" description = "Fundamental package for array computing in Python" +category = "main" optional = false python-versions = ">=3.9" files = [ @@ -3994,6 +4161,7 @@ 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 = [ @@ -4010,6 +4178,7 @@ signedtoken = ["cryptography (>=3.0.0)", "pyjwt (>=2.0.0,<3)"] name = "olefile" version = "0.46" 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.*" files = [ @@ -4020,6 +4189,7 @@ files = [ name = "orjson" version = "3.9.6" description = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -4089,6 +4259,7 @@ files = [ name = "packaging" version = "23.1" description = "Core utilities for Python packages" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -4100,6 +4271,7 @@ files = [ name = "parso" version = "0.8.3" description = "A Python Parser" +category = "main" optional = false python-versions = ">=3.6" files = [ @@ -4115,6 +4287,7 @@ testing = ["docopt", "pytest (<6.0.0)"] name = "pathspec" version = "0.11.2" description = "Utility library for gitignore style pattern matching of file paths." +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -4126,6 +4299,7 @@ files = [ name = "pathy" version = "0.10.2" description = "pathlib.Path subclasses for local and cloud bucket storage" +category = "main" optional = false python-versions = ">= 3.6" files = [ @@ -4148,6 +4322,7 @@ test = ["mock", "pytest", "pytest-coverage", "typer-cli"] name = "pdfminer-six" version = "20191110" description = "PDF parser and analyzer" +category = "main" optional = false python-versions = "*" files = [ @@ -4169,6 +4344,7 @@ docs = ["sphinx", "sphinx-argparse"] name = "pexpect" version = "4.8.0" description = "Pexpect allows easy control of interactive console applications." +category = "main" optional = false python-versions = "*" files = [ @@ -4183,6 +4359,7 @@ ptyprocess = ">=0.5" name = "pgvector" version = "0.2.2" description = "pgvector support for Python" +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -4196,6 +4373,7 @@ numpy = "*" name = "pickleshare" version = "0.7.5" description = "Tiny 'shelve'-like database with concurrency support" +category = "main" optional = false python-versions = "*" files = [ @@ -4207,6 +4385,7 @@ files = [ name = "pillow" version = "10.0.0" description = "Python Imaging Library (Fork)" +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -4276,6 +4455,7 @@ tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "pa name = "platformdirs" version = "3.10.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 = [ @@ -4291,6 +4471,7 @@ test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4)", "pytest-co name = "pluggy" version = "1.3.0" description = "plugin and hook calling mechanisms for python" +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -4306,6 +4487,7 @@ testing = ["pytest", "pytest-benchmark"] name = "pre-commit" version = "3.4.0" description = "A framework for managing and maintaining multi-language pre-commit hooks." +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -4324,6 +4506,7 @@ virtualenv = ">=20.10.0" name = "preshed" version = "3.0.8" description = "Cython hash table that trusts the keys are pre-hashed" +category = "main" optional = false python-versions = ">=3.6" files = [ @@ -4365,6 +4548,7 @@ murmurhash = ">=0.28.0,<1.1.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 = [ @@ -4392,6 +4576,7 @@ video = ["ffmpeg-python"] name = "prometheus-client" version = "0.17.1" description = "Python client for the Prometheus monitoring system." +category = "main" optional = false python-versions = ">=3.6" files = [ @@ -4406,6 +4591,7 @@ twisted = ["twisted"] name = "prompt-toolkit" version = "3.0.39" description = "Library for building powerful interactive command lines in Python" +category = "main" optional = false python-versions = ">=3.7.0" files = [ @@ -4420,6 +4606,7 @@ wcwidth = "*" name = "psutil" version = "5.9.5" 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.*" files = [ @@ -4446,6 +4633,7 @@ test = ["enum34", "ipaddress", "mock", "pywin32", "wmi"] name = "psycopg2-binary" version = "2.9.7" description = "psycopg2 - Python-PostgreSQL Database Adapter" +category = "main" optional = false python-versions = ">=3.6" files = [ @@ -4515,6 +4703,7 @@ files = [ name = "ptyprocess" version = "0.7.0" description = "Run a subprocess in a pseudo terminal" +category = "main" optional = false python-versions = "*" files = [ @@ -4526,6 +4715,7 @@ files = [ name = "pure-eval" version = "0.2.2" description = "Safely evaluate AST nodes without side effects" +category = "main" optional = false python-versions = "*" files = [ @@ -4540,6 +4730,7 @@ tests = ["pytest"] name = "pyasn1" version = "0.5.0" 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 = [ @@ -4551,6 +4742,7 @@ 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 = [ @@ -4565,6 +4757,7 @@ 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 = [ @@ -4575,6 +4768,7 @@ files = [ name = "pycodestyle" version = "2.11.0" description = "Python style guide checker" +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -4586,6 +4780,7 @@ files = [ name = "pycparser" version = "2.21" description = "C parser in Python" +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ @@ -4597,6 +4792,7 @@ files = [ name = "pycryptodome" version = "3.18.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 = [ @@ -4638,6 +4834,7 @@ files = [ name = "pycryptodomex" version = "3.18.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 = [ @@ -4679,6 +4876,7 @@ files = [ name = "pydantic" version = "2.3.0" description = "Data validation using Python type hints" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -4698,6 +4896,7 @@ email = ["email-validator (>=2.0.0)"] name = "pydantic-core" version = "2.6.3" description = "" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -4816,6 +5015,7 @@ typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" name = "pydantic-extra-types" version = "2.1.0" description = "Extra Pydantic types." +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -4833,6 +5033,7 @@ all = ["phonenumbers (>=8,<9)", "pycountry (>=22,<23)"] name = "pydantic-settings" version = "2.0.3" description = "Settings management using Pydantic" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -4848,6 +5049,7 @@ python-dotenv = ">=0.21.0" name = "pydotplus" version = "2.0.2" description = "Python interface to Graphviz's Dot language" +category = "main" optional = false python-versions = "*" files = [ @@ -4861,6 +5063,7 @@ 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 = [ @@ -4872,6 +5075,7 @@ files = [ name = "pyexifinfo" version = "0.4.0" description = "Simple Metadata extraction using Exiftool" +category = "main" optional = false python-versions = "*" files = [ @@ -4882,6 +5086,7 @@ files = [ name = "pyflakes" version = "3.1.0" description = "passive checker of Python programs" +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -4893,6 +5098,7 @@ files = [ name = "pygments" version = "2.16.1" description = "Pygments is a syntax highlighting package written in Python." +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -4907,6 +5113,7 @@ plugins = ["importlib-metadata"] name = "pyjwt" version = "2.8.0" description = "JSON Web Token implementation in Python" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -4927,6 +5134,7 @@ tests = ["coverage[toml] (==5.0.4)", "pytest (>=6.0.0,<7.0.0)"] name = "pylint" version = "2.17.5" description = "python code static checker" +category = "main" optional = false python-versions = ">=3.7.2" files = [ @@ -4951,6 +5159,7 @@ 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 = [ @@ -4966,6 +5175,7 @@ pylint-plugin-utils = ">=0.2.1" name = "pylint-django" version = "2.5.3" description = "A Pylint plugin to help Pylint understand the Django web framework" +category = "main" optional = false python-versions = "*" files = [ @@ -4985,6 +5195,7 @@ with-django = ["Django"] 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 = [ @@ -4999,6 +5210,7 @@ pylint = ">=1.7" name = "pyopenssl" version = "23.2.0" description = "Python wrapper module around the OpenSSL library" +category = "main" optional = false python-versions = ">=3.6" files = [ @@ -5017,6 +5229,7 @@ test = ["flaky", "pretend", "pytest (>=3.0.1)"] name = "pyparsing" version = "3.0.9" description = "pyparsing module - Classes and methods to define and execute parsing grammars" +category = "main" optional = false python-versions = ">=3.6.8" files = [ @@ -5031,6 +5244,7 @@ diagrams = ["jinja2", "railroad-diagrams"] 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 = [ @@ -5043,6 +5257,7 @@ files = [ name = "pytest" version = "7.4.2" description = "pytest: simple powerful testing with Python" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -5063,6 +5278,7 @@ 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 = [ @@ -5081,6 +5297,7 @@ testing = ["coverage (>=6.2)", "flaky (>=3.5.0)", "hypothesis (>=5.7.1)", "mypy name = "pytest-django" version = "4.5.2" description = "A Django plugin for pytest." +category = "main" optional = false python-versions = ">=3.5" files = [ @@ -5099,6 +5316,7 @@ 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 = [ @@ -5118,6 +5336,7 @@ 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 = [ @@ -5133,6 +5352,7 @@ wrapt = ">=1.11.0,<2.0.0" name = "pytest-mock" version = "3.11.1" description = "Thin-wrapper around the mock package for easier use with pytest" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -5150,6 +5370,7 @@ 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 = [ @@ -5169,6 +5390,7 @@ dev = ["black", "flake8", "pre-commit"] name = "pytest-xdist" version = "3.3.1" description = "pytest xdist plugin for distributed testing, most importantly across multiple CPUs" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -5189,6 +5411,7 @@ testing = ["filelock"] name = "python-crontab" version = "3.0.0" description = "Python Crontab API" +category = "main" optional = false python-versions = "*" files = [ @@ -5207,6 +5430,7 @@ cron-schedule = ["croniter"] name = "python-dateutil" version = "2.8.2" description = "Extensions to the standard Python datetime module" +category = "main" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" files = [ @@ -5221,6 +5445,7 @@ six = ">=1.5" name = "python-dotenv" version = "1.0.0" description = "Read key-value pairs from a .env file and set them as environment variables" +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -5235,6 +5460,7 @@ cli = ["click (>=5.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 = [ @@ -5246,6 +5472,7 @@ files = [ name = "python-mpd2" version = "3.1.0" description = "A Python MPD client library" +category = "main" optional = false python-versions = ">=3.6" files = [ @@ -5260,6 +5487,7 @@ twisted = ["Twisted"] name = "python-multipart" version = "0.0.6" description = "A streaming multipart parser for Python" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -5274,6 +5502,7 @@ dev = ["atomicwrites (==1.2.1)", "attrs (==19.2.0)", "coverage (==6.5.0)", "hatc name = "python-pptx" version = "0.6.21" description = "Generate and manipulate Open XML PowerPoint (.pptx) files" +category = "main" optional = false python-versions = "*" files = [ @@ -5289,6 +5518,7 @@ XlsxWriter = ">=0.5.7" name = "python-slugify" version = "7.0.0" description = "A Python slugify application that also handles Unicode" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -5306,6 +5536,7 @@ 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 = [ @@ -5324,6 +5555,7 @@ 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 = [ @@ -5335,6 +5567,7 @@ files = [ name = "pytz" version = "2023.3.post1" description = "World timezone definitions, modern and historical" +category = "main" optional = false python-versions = "*" files = [ @@ -5346,6 +5579,7 @@ files = [ name = "pyyaml" version = "6.0.1" description = "YAML parser and emitter for Python" +category = "main" optional = false python-versions = ">=3.6" files = [ @@ -5395,6 +5629,7 @@ files = [ name = "rawpy" version = "0.18.1" description = "RAW image processing for Python, a wrapper for libraw" +category = "main" optional = false python-versions = "*" files = [ @@ -5427,6 +5662,7 @@ numpy = "*" 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 = [ @@ -5445,6 +5681,7 @@ ocsp = ["cryptography (>=36.0.1)", "pyopenssl (==20.0.1)", "requests (>=2.26.0)" name = "referencing" version = "0.30.2" description = "JSON Referencing + Python" +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -5460,6 +5697,7 @@ rpds-py = ">=0.7.0" name = "regex" version = "2023.8.8" description = "Alternative regular expression module, to replace re." +category = "main" optional = false python-versions = ">=3.6" files = [ @@ -5557,6 +5795,7 @@ files = [ name = "requests" version = "2.31.0" description = "Python HTTP for Humans." +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -5579,6 +5818,7 @@ 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 = [ @@ -5597,6 +5837,7 @@ rsa = ["oauthlib[signedtoken] (>=3.0.0)"] name = "rpds-py" version = "0.10.2" description = "Python bindings to Rust's persistent data structures (rpds)" +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -5703,6 +5944,7 @@ files = [ name = "safetensors" version = "0.3.3" description = "Fast and Safe Tensor serialization" +category = "main" optional = false python-versions = "*" files = [ @@ -5712,9 +5954,6 @@ files = [ {file = "safetensors-0.3.3-cp310-cp310-macosx_12_0_x86_64.whl", hash = "sha256:17f41344d9a075f2f21b289a49a62e98baff54b5754240ba896063bce31626bf"}, {file = "safetensors-0.3.3-cp310-cp310-macosx_13_0_arm64.whl", hash = "sha256:f1045f798e1a16a6ced98d6a42ec72936d367a2eec81dc5fade6ed54638cd7d2"}, {file = "safetensors-0.3.3-cp310-cp310-macosx_13_0_x86_64.whl", hash = "sha256:eaf0e4bc91da13f21ac846a39429eb3f3b7ed06295a32321fa3eb1a59b5c70f3"}, - {file = "safetensors-0.3.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25149180d4dc8ca48bac2ac3852a9424b466e36336a39659b35b21b2116f96fc"}, - {file = "safetensors-0.3.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c9e943bf78c39de8865398a71818315e7d5d1af93c7b30d4da3fc852e62ad9bc"}, - {file = "safetensors-0.3.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cccfcac04a010354e87c7a2fe16a1ff004fc4f6e7ef8efc966ed30122ce00bc7"}, {file = "safetensors-0.3.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a07121f427e646a50d18c1be0fa1a2cbf6398624c31149cd7e6b35486d72189e"}, {file = "safetensors-0.3.3-cp310-cp310-win32.whl", hash = "sha256:a85e29cbfddfea86453cc0f4889b4bcc6b9c155be9a60e27be479a34e199e7ef"}, {file = "safetensors-0.3.3-cp310-cp310-win_amd64.whl", hash = "sha256:e13adad4a3e591378f71068d14e92343e626cf698ff805f61cdb946e684a218e"}, @@ -5723,9 +5962,6 @@ files = [ {file = "safetensors-0.3.3-cp311-cp311-macosx_12_0_universal2.whl", hash = "sha256:f84a74cbe9859b28e3d6d7715ac1dd3097bebf8d772694098f6d42435245860c"}, {file = "safetensors-0.3.3-cp311-cp311-macosx_13_0_arm64.whl", hash = "sha256:10d637423d98ab2e6a4ad96abf4534eb26fcaf8ca3115623e64c00759374e90d"}, {file = "safetensors-0.3.3-cp311-cp311-macosx_13_0_universal2.whl", hash = "sha256:3b46f5de8b44084aff2e480874c550c399c730c84b2e8ad1bddb062c94aa14e9"}, - {file = "safetensors-0.3.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e76da691a82dfaf752854fa6d17c8eba0c8466370c5ad8cf1bfdf832d3c7ee17"}, - {file = "safetensors-0.3.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c4e342fd54e66aa9512dd13e410f791e47aa4feeb5f4c9a20882c72f3d272f29"}, - {file = "safetensors-0.3.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:178fd30b5dc73bce14a39187d948cedd0e5698e2f055b7ea16b5a96c9b17438e"}, {file = "safetensors-0.3.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3e8fdf7407dba44587ed5e79d5de3533d242648e1f2041760b21474bd5ea5c8c"}, {file = "safetensors-0.3.3-cp311-cp311-win32.whl", hash = "sha256:7d3b744cee8d7a46ffa68db1a2ff1a1a432488e3f7a5a97856fe69e22139d50c"}, {file = "safetensors-0.3.3-cp311-cp311-win_amd64.whl", hash = "sha256:f579877d30feec9b6ba409d05fa174633a4fc095675a4a82971d831a8bb60b97"}, @@ -5733,9 +5969,6 @@ files = [ {file = "safetensors-0.3.3-cp37-cp37m-macosx_11_0_x86_64.whl", hash = "sha256:41adb1d39e8aad04b16879e3e0cbcb849315999fad73bc992091a01e379cb058"}, {file = "safetensors-0.3.3-cp37-cp37m-macosx_12_0_x86_64.whl", hash = "sha256:0f2b404250b3b877b11d34afcc30d80e7035714a1116a3df56acaca6b6c00096"}, {file = "safetensors-0.3.3-cp37-cp37m-macosx_13_0_x86_64.whl", hash = "sha256:b43956ef20e9f4f2e648818a9e7b3499edd6b753a0f5526d4f6a6826fbee8446"}, - {file = "safetensors-0.3.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d61a99b34169981f088ccfbb2c91170843efc869a0a0532f422db7211bf4f474"}, - {file = "safetensors-0.3.3-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c0008aab36cd20e9a051a68563c6f80d40f238c2611811d7faa5a18bf3fd3984"}, - {file = "safetensors-0.3.3-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:93d54166072b143084fdcd214a080a088050c1bb1651016b55942701b31334e4"}, {file = "safetensors-0.3.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1c32ee08f61cea56a5d62bbf94af95df6040c8ab574afffaeb7b44ae5da1e9e3"}, {file = "safetensors-0.3.3-cp37-cp37m-win32.whl", hash = "sha256:351600f367badd59f7bfe86d317bb768dd8c59c1561c6fac43cafbd9c1af7827"}, {file = "safetensors-0.3.3-cp37-cp37m-win_amd64.whl", hash = "sha256:034717e297849dae1af0a7027a14b8647bd2e272c24106dced64d83e10d468d1"}, @@ -5745,9 +5978,6 @@ files = [ {file = "safetensors-0.3.3-cp38-cp38-macosx_12_0_x86_64.whl", hash = "sha256:69ccee8d05f55cdf76f7e6c87d2bdfb648c16778ef8acfd2ecc495e273e9233e"}, {file = "safetensors-0.3.3-cp38-cp38-macosx_13_0_arm64.whl", hash = "sha256:c08a9a4b7a4ca389232fa8d097aebc20bbd4f61e477abc7065b5c18b8202dede"}, {file = "safetensors-0.3.3-cp38-cp38-macosx_13_0_x86_64.whl", hash = "sha256:a002868d2e3f49bbe81bee2655a411c24fa1f8e68b703dec6629cb989d6ae42e"}, - {file = "safetensors-0.3.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3bd2704cb41faa44d3ec23e8b97330346da0395aec87f8eaf9c9e2c086cdbf13"}, - {file = "safetensors-0.3.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4b2951bf3f0ad63df5e6a95263652bd6c194a6eb36fd4f2d29421cd63424c883"}, - {file = "safetensors-0.3.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:07114cec116253ca2e7230fdea30acf76828f21614afd596d7b5438a2f719bd8"}, {file = "safetensors-0.3.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6ab43aeeb9eadbb6b460df3568a662e6f1911ecc39387f8752afcb6a7d96c087"}, {file = "safetensors-0.3.3-cp38-cp38-win32.whl", hash = "sha256:f2f59fce31dd3429daca7269a6b06f65e6547a0c248f5116976c3f1e9b73f251"}, {file = "safetensors-0.3.3-cp38-cp38-win_amd64.whl", hash = "sha256:c31ca0d8610f57799925bf08616856b39518ab772c65093ef1516762e796fde4"}, @@ -5757,9 +5987,6 @@ files = [ {file = "safetensors-0.3.3-cp39-cp39-macosx_12_0_x86_64.whl", hash = "sha256:12b83f1986cd16ea0454c636c37b11e819d60dd952c26978310a0835133480b7"}, {file = "safetensors-0.3.3-cp39-cp39-macosx_13_0_arm64.whl", hash = "sha256:f439175c827c2f1bbd54df42789c5204a10983a30bc4242bc7deaf854a24f3f0"}, {file = "safetensors-0.3.3-cp39-cp39-macosx_13_0_x86_64.whl", hash = "sha256:0085be33b8cbcb13079b3a8e131656e05b0bc5e6970530d4c24150f7afd76d70"}, - {file = "safetensors-0.3.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e3ec70c87b1e910769034206ad5efc051069b105aac1687f6edcd02526767f4"}, - {file = "safetensors-0.3.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f490132383e5e490e710608f4acffcb98ed37f91b885c7217d3f9f10aaff9048"}, - {file = "safetensors-0.3.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:79d1b6c7ed5596baf79c80fbce5198c3cdcc521ae6a157699f427aba1a90082d"}, {file = "safetensors-0.3.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad3cc8006e7a86ee7c88bd2813ec59cd7cc75b03e6fa4af89b9c7b235b438d68"}, {file = "safetensors-0.3.3-cp39-cp39-win32.whl", hash = "sha256:ab29f54c6b8c301ca05fa014728996bd83aac6e21528f893aaf8945c71f42b6d"}, {file = "safetensors-0.3.3-cp39-cp39-win_amd64.whl", hash = "sha256:0fa82004eae1a71e2aa29843ef99de9350e459a0fc2f65fc6ee0da9690933d2d"}, @@ -5782,6 +6009,7 @@ torch = ["numpy (>=1.21.6)", "torch (>=1.10)"] name = "sentry-sdk" version = "1.30.0" description = "Python client for Sentry (https://sentry.io)" +category = "main" optional = false python-versions = "*" files = [ @@ -5825,6 +6053,7 @@ tornado = ["tornado (>=5)"] name = "service-identity" version = "23.1.0" description = "Service identity verification for pyOpenSSL & cryptography." +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -5849,6 +6078,7 @@ tests = ["coverage[toml] (>=5.0.2)", "pytest"] name = "setuptools" version = "68.2.0" description = "Easily download, build, install, upgrade, and uninstall Python packages" +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -5865,6 +6095,7 @@ testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs ( name = "six" version = "1.12.0" description = "Python 2 and 3 compatibility utilities" +category = "main" optional = false python-versions = ">=2.6, !=3.0.*, !=3.1.*" files = [ @@ -5876,6 +6107,7 @@ files = [ name = "smart-open" version = "6.4.0" description = "Utils for streaming large files (S3, HDFS, GCS, Azure Blob Storage, gzip, bz2...)" +category = "main" optional = false python-versions = ">=3.6,<4.0" files = [ @@ -5897,6 +6129,7 @@ webhdfs = ["requests"] name = "sniffio" version = "1.3.0" description = "Sniff out which async library your code is running under" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -5908,6 +6141,7 @@ 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 = [ @@ -5919,6 +6153,7 @@ files = [ name = "sortedcontainers" version = "2.4.0" description = "Sorted Containers -- Sorted List, Sorted Dict, Sorted Set" +category = "main" optional = false python-versions = "*" files = [ @@ -5930,6 +6165,7 @@ files = [ name = "soupsieve" version = "2.5" description = "A modern CSS selector implementation for Beautiful Soup." +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -5941,6 +6177,7 @@ files = [ name = "spacy" version = "3.6.1" description = "Industrial-strength Natural Language Processing (NLP) in Python" +category = "main" optional = false python-versions = ">=3.6" files = [ @@ -6029,6 +6266,7 @@ transformers = ["spacy-transformers (>=1.1.2,<1.3.0)"] name = "spacy-alignments" version = "0.9.0" description = "A spaCy package for the Rust tokenizations library" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -6063,6 +6301,7 @@ files = [ name = "spacy-legacy" version = "3.0.12" description = "Legacy registered functions for spaCy backwards compatibility" +category = "main" optional = false python-versions = ">=3.6" files = [ @@ -6074,6 +6313,7 @@ files = [ name = "spacy-loggers" version = "1.0.4" description = "Logging utilities for SpaCy" +category = "main" optional = false python-versions = ">=3.6" files = [ @@ -6085,6 +6325,7 @@ files = [ name = "spacy-lookups-data" version = "1.0.5" description = "Additional lookup tables and data resources for spaCy" +category = "main" optional = false python-versions = ">=3.6" files = [ @@ -6099,6 +6340,7 @@ setuptools = "*" name = "spacy-transformers" version = "1.2.5" description = "spaCy pipelines for pre-trained BERT and other transformers" +category = "main" optional = false python-versions = ">=3.6" files = [ @@ -6157,6 +6399,7 @@ cuda92 = ["cupy-cuda92 (>=5.0.0b4)"] name = "speechrecognition" version = "3.8.1" description = "Library for performing speech recognition, with support for several engines and APIs, online and offline." +category = "main" optional = false python-versions = "*" files = [ @@ -6167,6 +6410,7 @@ files = [ name = "sphinx" version = "7.2.5" description = "Python documentation generator" +category = "main" optional = false python-versions = ">=3.9" files = [ @@ -6201,6 +6445,7 @@ 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 = [ @@ -6220,6 +6465,7 @@ test = ["pytest", "pytest-cov"] name = "sphinxcontrib-applehelp" version = "1.0.7" description = "sphinxcontrib-applehelp is a Sphinx extension which outputs Apple help books" +category = "main" optional = false python-versions = ">=3.9" files = [ @@ -6238,6 +6484,7 @@ test = ["pytest"] name = "sphinxcontrib-devhelp" version = "1.0.5" description = "sphinxcontrib-devhelp is a sphinx extension which outputs Devhelp documents" +category = "main" optional = false python-versions = ">=3.9" files = [ @@ -6256,6 +6503,7 @@ test = ["pytest"] name = "sphinxcontrib-htmlhelp" version = "2.0.4" description = "sphinxcontrib-htmlhelp is a sphinx extension which renders HTML help files" +category = "main" optional = false python-versions = ">=3.9" files = [ @@ -6274,6 +6522,7 @@ 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 = [ @@ -6288,6 +6537,7 @@ test = ["flake8", "mypy", "pytest"] name = "sphinxcontrib-qthelp" version = "1.0.6" description = "sphinxcontrib-qthelp is a sphinx extension which outputs QtHelp documents" +category = "main" optional = false python-versions = ">=3.9" files = [ @@ -6306,6 +6556,7 @@ test = ["pytest"] name = "sphinxcontrib-serializinghtml" version = "1.1.9" description = "sphinxcontrib-serializinghtml is a sphinx extension which outputs \"serialized\" HTML files (json and pickle)" +category = "main" optional = false python-versions = ">=3.9" files = [ @@ -6324,6 +6575,7 @@ test = ["pytest"] name = "spotipy" version = "2.16.1" description = "A light weight Python library for the Spotify Web API" +category = "main" optional = false python-versions = "*" files = [ @@ -6344,6 +6596,7 @@ test = ["mock (==2.0.0)"] name = "sqlalchemy" version = "2.0.20" description = "Database Abstraction Library" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -6391,7 +6644,7 @@ files = [ ] [package.dependencies] -greenlet = {version = "!=0.4.17", markers = "platform_machine == \"win32\" or platform_machine == \"WIN32\" or platform_machine == \"AMD64\" or platform_machine == \"amd64\" or platform_machine == \"x86_64\" or platform_machine == \"ppc64le\" or platform_machine == \"aarch64\""} +greenlet = {version = "!=0.4.17", markers = "platform_machine == \"aarch64\" or platform_machine == \"ppc64le\" or platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"win32\" or platform_machine == \"WIN32\""} typing-extensions = ">=4.2.0" [package.extras] @@ -6422,6 +6675,7 @@ sqlcipher = ["sqlcipher3-binary"] name = "sqlparse" version = "0.4.4" description = "A non-validating SQL parser." +category = "main" optional = false python-versions = ">=3.5" files = [ @@ -6438,6 +6692,7 @@ test = ["pytest", "pytest-cov"] name = "srsly" version = "2.4.7" description = "Modern high-performance serialization utilities for Python" +category = "main" optional = false python-versions = ">=3.6" files = [ @@ -6478,6 +6733,7 @@ catalogue = ">=2.0.3,<2.1.0" name = "stack-data" version = "0.6.2" description = "Extract data from python stack frames and tracebacks for informative displays" +category = "main" optional = false python-versions = "*" files = [ @@ -6497,6 +6753,7 @@ 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 = [ @@ -6514,6 +6771,7 @@ full = ["httpx (>=0.22.0)", "itsdangerous", "jinja2", "python-multipart", "pyyam name = "structlog" version = "23.1.0" description = "Structured Logging for Python" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -6531,6 +6789,7 @@ typing = ["mypy", "rich", "twisted"] name = "sympy" version = "1.12" description = "Computer algebra system (CAS) in Python" +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -6545,6 +6804,7 @@ mpmath = ">=0.19" 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 = [ @@ -6566,6 +6826,7 @@ yaml = ["pyyaml"] name = "termcolor" version = "2.3.0" description = "ANSI color formatting for output in terminal" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -6580,6 +6841,7 @@ tests = ["pytest", "pytest-cov"] name = "text-unidecode" version = "1.3" description = "The most basic Text::Unidecode port" +category = "main" optional = false python-versions = "*" files = [ @@ -6591,6 +6853,7 @@ files = [ name = "textract" version = "1.6.5" description = "extract text from any document. no muss. no fuss." +category = "main" optional = false python-versions = "*" files = [ @@ -6601,7 +6864,7 @@ files = [ [package.dependencies] argcomplete = ">=1.10.0,<1.11.0" beautifulsoup4 = ">=4.8.0,<4.9.0" -chardet = "==3.*" +chardet = ">=3.0.0,<4.0.0" docx2txt = ">=0.8,<1.0" extract-msg = "<=0.29" "pdfminer.six" = "20191110" @@ -6617,6 +6880,7 @@ pocketsphinx = ["pocketsphinx (==0.1.15)"] name = "thinc" version = "8.1.12" description = "A refreshing functional take on deep learning, compatible with your favorite libraries" +category = "main" optional = false python-versions = ">=3.6" files = [ @@ -6692,6 +6956,7 @@ torch = ["torch (>=1.6.0)"] name = "tinycss2" version = "1.2.1" description = "A tiny CSS parser" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -6710,6 +6975,7 @@ test = ["flake8", "isort", "pytest"] name = "tokenizers" version = "0.13.3" description = "Fast and Customizable Tokenizers" +category = "main" optional = false python-versions = "*" files = [ @@ -6764,6 +7030,7 @@ testing = ["black (==22.3)", "datasets", "numpy", "pytest", "requests"] name = "tomli" version = "2.0.1" description = "A lil' TOML parser" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -6775,6 +7042,7 @@ files = [ name = "tomlkit" version = "0.12.1" description = "Style preserving TOML library" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -6786,6 +7054,7 @@ files = [ name = "torch" version = "2.0.1" description = "Tensors and Dynamic neural networks in Python with strong GPU acceleration" +category = "main" optional = false python-versions = ">=3.8.0" files = [ @@ -6825,6 +7094,7 @@ opt-einsum = ["opt-einsum (>=3.3)"] name = "tornado" version = "6.3.3" description = "Tornado is a Python web framework and asynchronous networking library, originally developed at FriendFeed." +category = "main" optional = false python-versions = ">= 3.8" files = [ @@ -6845,6 +7115,7 @@ files = [ name = "tqdm" version = "4.66.1" description = "Fast, Extensible Progress Meter" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -6865,6 +7136,7 @@ telegram = ["requests"] name = "traitlets" version = "5.9.0" description = "Traitlets Python configuration system" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -6880,6 +7152,7 @@ test = ["argcomplete (>=2.0)", "pre-commit", "pytest", "pytest-mock"] name = "transformers" version = "4.30.2" description = "State-of-the-art Machine Learning for JAX, PyTorch and TensorFlow" +category = "main" optional = false python-versions = ">=3.7.0" files = [ @@ -6949,6 +7222,7 @@ vision = ["Pillow"] name = "twisted" version = "23.8.0" description = "An asynchronous networking framework written in Python" +category = "main" optional = false python-versions = ">=3.7.1" files = [ @@ -6989,6 +7263,7 @@ 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 = [ @@ -7017,6 +7292,7 @@ files = [ name = "txaio" version = "23.1.1" description = "Compatibility API between asyncio/Twisted/Trollius" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -7033,6 +7309,7 @@ twisted = ["twisted (>=20.3.0)", "zope.interface (>=5.2.0)"] name = "typer" version = "0.9.0" description = "Typer, build great CLIs. Easy to code. Based on Python type hints." +category = "main" optional = false python-versions = ">=3.6" files = [ @@ -7054,6 +7331,7 @@ test = ["black (>=22.3.0,<23.0.0)", "coverage (>=6.2,<7.0)", "isort (>=5.0.6,<6. name = "types-pytz" version = "2023.3.0.1" description = "Typing stubs for pytz" +category = "main" optional = false python-versions = "*" files = [ @@ -7065,6 +7343,7 @@ files = [ name = "types-pyyaml" version = "6.0.12.11" description = "Typing stubs for PyYAML" +category = "main" optional = false python-versions = "*" files = [ @@ -7076,6 +7355,7 @@ files = [ name = "types-requests" version = "2.31.0.2" description = "Typing stubs for requests" +category = "main" optional = false python-versions = "*" files = [ @@ -7090,6 +7370,7 @@ types-urllib3 = "*" name = "types-urllib3" version = "1.26.25.14" description = "Typing stubs for urllib3" +category = "main" optional = false python-versions = "*" files = [ @@ -7101,6 +7382,7 @@ files = [ name = "typing-extensions" version = "4.7.1" description = "Backported and Experimental Type Hints for Python 3.7+" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -7112,6 +7394,7 @@ files = [ name = "tzdata" version = "2023.3" description = "Provider of IANA time zone data" +category = "main" optional = false python-versions = ">=2" files = [ @@ -7123,6 +7406,7 @@ files = [ name = "tzlocal" version = "5.0.1" description = "tzinfo object for the local timezone" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -7140,6 +7424,7 @@ devenv = ["black", "check-manifest", "flake8", "pyroma", "pytest (>=4.3)", "pyte name = "ujson" version = "5.8.0" description = "Ultra fast JSON encoder and decoder for Python" +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -7210,6 +7495,7 @@ files = [ name = "uritemplate" version = "4.1.1" description = "Implementation of RFC 6570 URI Templates" +category = "main" optional = false python-versions = ">=3.6" files = [ @@ -7221,6 +7507,7 @@ files = [ name = "urllib3" version = "2.0.4" description = "HTTP library with thread-safe connection pooling, file post, and more." +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -7238,6 +7525,7 @@ 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 = [ @@ -7248,6 +7536,7 @@ files = [ name = "uvicorn" version = "0.23.2" description = "The lightning-fast ASGI server." +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -7262,7 +7551,7 @@ h11 = ">=0.8" httptools = {version = ">=0.5.0", optional = true, markers = "extra == \"standard\""} python-dotenv = {version = ">=0.13", optional = true, markers = "extra == \"standard\""} pyyaml = {version = ">=5.1", optional = true, markers = "extra == \"standard\""} -uvloop = {version = ">=0.14.0,<0.15.0 || >0.15.0,<0.15.1 || >0.15.1", optional = true, markers = "(sys_platform != \"win32\" and sys_platform != \"cygwin\") and platform_python_implementation != \"PyPy\" and extra == \"standard\""} +uvloop = {version = ">=0.14.0,<0.15.0 || >0.15.0,<0.15.1 || >0.15.1", optional = true, markers = "sys_platform != \"win32\" and sys_platform != \"cygwin\" and platform_python_implementation != \"PyPy\" and extra == \"standard\""} watchfiles = {version = ">=0.13", optional = true, markers = "extra == \"standard\""} websockets = {version = ">=10.4", optional = true, markers = "extra == \"standard\""} @@ -7273,6 +7562,7 @@ standard = ["colorama (>=0.4)", "httptools (>=0.5.0)", "python-dotenv (>=0.13)", name = "uvloop" version = "0.17.0" description = "Fast implementation of asyncio event loop on top of libuv" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -7317,6 +7607,7 @@ test = ["Cython (>=0.29.32,<0.30.0)", "aiohttp", "flake8 (>=3.9.2,<3.10.0)", "my name = "vine" version = "5.0.0" description = "Promises, promises, promises." +category = "main" optional = false python-versions = ">=3.6" files = [ @@ -7328,6 +7619,7 @@ files = [ name = "virtualenv" version = "20.24.4" description = "Virtual Python Environment builder" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -7348,6 +7640,7 @@ test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess name = "vtk" version = "9.2.6" description = "VTK is an open-source toolkit for 3D computer graphics, image processing, and visualization" +category = "main" optional = false python-versions = "*" files = [ @@ -7385,6 +7678,7 @@ web = ["wslink (>=1.0.4)"] name = "wand" version = "0.6.11" description = "Ctypes-based simple MagickWand API binding for Python" +category = "main" optional = false python-versions = "*" files = [ @@ -7400,6 +7694,7 @@ test = ["pytest (>=7.2.0)"] name = "wasabi" version = "1.1.2" description = "A lightweight console printing and formatting toolkit" +category = "main" optional = false python-versions = ">=3.6" files = [ @@ -7414,6 +7709,7 @@ colorama = {version = ">=0.4.6", markers = "sys_platform == \"win32\" and python name = "watchdog" version = "3.0.0" description = "Filesystem events monitoring" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -7453,6 +7749,7 @@ 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 = [ @@ -7483,6 +7780,7 @@ anyio = ">=3.0.0" name = "wcwidth" version = "0.2.6" description = "Measures the displayed width of unicode strings in a terminal" +category = "main" optional = false python-versions = "*" files = [ @@ -7494,6 +7792,7 @@ files = [ name = "webencodings" version = "0.5.1" description = "Character encoding aliases for legacy web content" +category = "main" optional = false python-versions = "*" files = [ @@ -7505,6 +7804,7 @@ files = [ name = "websockets" version = "11.0.3" description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -7584,6 +7884,7 @@ files = [ name = "werkzeug" version = "2.3.7" description = "The comprehensive WSGI web application library." +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -7602,6 +7903,7 @@ watchdog = ["watchdog (>=2.3)"] name = "whitenoise" version = "6.5.0" description = "Radically simplified static file serving for WSGI applications" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -7616,6 +7918,7 @@ brotli = ["Brotli"] name = "wrapt" version = "1.15.0" description = "Module for decorators, wrappers and monkey patching." +category = "main" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" files = [ @@ -7700,6 +8003,7 @@ files = [ name = "xlrd" version = "1.2.0" description = "Library for developers to extract data from Microsoft Excel (tm) spreadsheet files" +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ @@ -7711,6 +8015,7 @@ files = [ name = "xlsxwriter" version = "3.1.2" description = "A Python module for creating Excel XLSX files." +category = "main" optional = false python-versions = ">=3.6" files = [ @@ -7722,6 +8027,7 @@ files = [ name = "xvfbwrapper" version = "0.2.9" description = "run headless display inside X virtual framebuffer (Xvfb)" +category = "main" optional = false python-versions = "*" files = [ @@ -7732,6 +8038,7 @@ files = [ name = "yandex-music" version = "2.1.1" description = "Неофициальная Python библиотека для работы с API сервиса Яндекс.Музыка." +category = "main" optional = false python-versions = "~=3.7" files = [ @@ -7747,6 +8054,7 @@ requests = {version = "*", extras = ["socks"]} name = "yarl" version = "1.9.2" description = "Yet another URL library" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -7834,6 +8142,7 @@ multidict = ">=4.0" name = "yt-dlp" version = "2023.7.6" description = "A youtube-dl fork with additional features and patches" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -7853,6 +8162,7 @@ websockets = "*" name = "zope-interface" version = "6.0" description = "Interfaces for Python" +category = "main" optional = false python-versions = ">=3.7" files = [