chore(api): update all dependencies (develop) (major)

This commit is contained in:
RenovateBot 2025-01-16 11:51:31 +00:00 committed by petitminion
parent 606066bf3b
commit e5aa82e141
22 changed files with 393 additions and 327 deletions

View File

@ -57,7 +57,7 @@ def import_listenbrainz_listenings(user, user_name, since):
new_ts = max( new_ts = max(
listens, listens,
key=lambda obj: datetime.datetime.fromtimestamp( key=lambda obj: datetime.datetime.fromtimestamp(
obj.listened_at, timezone.utc obj.listened_at, datetime.timezone.utc
), ),
) )
response = client.get_listens(username=user_name, min_ts=new_ts, count=100) response = client.get_listens(username=user_name, min_ts=new_ts, count=100)
@ -74,7 +74,7 @@ def add_lb_listenings_to_db(listens, user):
== "Funkwhale ListenBrainz plugin" == "Funkwhale ListenBrainz plugin"
and history_models.Listening.objects.filter( and history_models.Listening.objects.filter(
creation_date=datetime.datetime.fromtimestamp( creation_date=datetime.datetime.fromtimestamp(
listen.listened_at, timezone.utc listen.listened_at, datetime.timezone.utc
) )
).exists() ).exists()
): ):
@ -103,7 +103,7 @@ def add_lb_listenings_to_db(listens, user):
user = user user = user
fw_listen = history_models.Listening( fw_listen = history_models.Listening(
creation_date=datetime.datetime.fromtimestamp( creation_date=datetime.datetime.fromtimestamp(
listen.listened_at, timezone.utc listen.listened_at, datetime.timezone.utc
), ),
track=track, track=track,
actor=user.actor, actor=user.actor,
@ -125,7 +125,7 @@ def import_listenbrainz_favorites(user, user_name, since):
last_sync = min( last_sync = min(
response["feedback"], response["feedback"],
key=lambda obj: datetime.datetime.fromtimestamp( key=lambda obj: datetime.datetime.fromtimestamp(
obj["created"], timezone.utc obj["created"], datetime.timezone.utc
), ),
)["created"] )["created"]
add_lb_feedback_to_db(response["feedback"], user) add_lb_feedback_to_db(response["feedback"], user)
@ -149,7 +149,7 @@ def add_lb_feedback_to_db(feedbacks, user):
favorites_models.TrackFavorite.objects.get_or_create( favorites_models.TrackFavorite.objects.get_or_create(
actor=user.actor, actor=user.actor,
creation_date=datetime.datetime.fromtimestamp( creation_date=datetime.datetime.fromtimestamp(
feedback["created"], timezone.utc feedback["created"], datetime.timezone.utc
), ),
track=track, track=track,
source="Listenbrainz", source="Listenbrainz",

View File

@ -128,11 +128,6 @@ class ActorFactory(NoUpdateOnCreate, factory.django.DjangoModelFactory):
class Meta: class Meta:
model = models.Actor model = models.Actor
class Params:
with_real_keys = factory.Trait(
keys=factory.LazyFunction(keys.get_key_pair),
)
@factory.post_generation @factory.post_generation
def local(self, create, extracted, **kwargs): def local(self, create, extracted, **kwargs):
if not extracted and not kwargs: if not extracted and not kwargs:
@ -153,6 +148,26 @@ class ActorFactory(NoUpdateOnCreate, factory.django.DjangoModelFactory):
extracted.actor = self extracted.actor = self
extracted.save(update_fields=["user"]) extracted.save(update_fields=["user"])
else: else:
user = UserFactory(actor=self, **kwargs)
user.actor = self
user.save()
@factory.post_generation
def user(self, create, extracted, **kwargs):
"""
Handle the creation or assignment of the related user instance.
If `actor__user` is passed, it will be linked; otherwise, no user is created.
"""
if not create:
return
if extracted: # If a User instance is provided
extracted.actor = self
extracted.save(update_fields=["actor"])
elif kwargs:
from funkwhale_api.users.factories import UserFactory
# Create a User linked to this Actor
self.user = UserFactory(actor=self, **kwargs) self.user = UserFactory(actor=self, **kwargs)

View File

@ -30,7 +30,7 @@ def verify_date(raw_date):
ts = parse_http_date(raw_date) ts = parse_http_date(raw_date)
except ValueError as e: except ValueError as e:
raise forms.ValidationError(str(e)) raise forms.ValidationError(str(e))
dt = datetime.datetime.utcfromtimestamp(ts) dt = datetime.datetime.fromtimestamp(ts, datetime.timezone.utc)
dt = dt.replace(tzinfo=ZoneInfo("UTC")) dt = dt.replace(tzinfo=ZoneInfo("UTC"))
delta = datetime.timedelta(seconds=DATE_HEADER_VALID_FOR) delta = datetime.timedelta(seconds=DATE_HEADER_VALID_FOR)
now = timezone.now() now = timezone.now()

View File

@ -16,7 +16,7 @@ from . import models, utils
def filter_tags(queryset, name, value): def filter_tags(queryset, name, value):
non_empty_tags = [v.lower() for v in value if v] non_empty_tags = [v.lower() for v in value if v]
for tag in non_empty_tags: for tag in non_empty_tags:
queryset = queryset.filter(tagged_items__tag__name=tag).distinct() queryset = queryset.filter(tagged_items__tag__name__iexact=tag).distinct()
return queryset return queryset

View File

@ -630,7 +630,7 @@ def process_load_queue(stdout, **kwargs):
for path, event in batched_events.copy().items(): for path, event in batched_events.copy().items():
if time.time() - event["time"] <= flush_delay: if time.time() - event["time"] <= flush_delay:
continue continue
now = datetime.datetime.utcnow() now = datetime.datetime.now(datetime.timezone.utc)
stdout.write( stdout.write(
"{} -- Processing {}:{}...\n".format( "{} -- Processing {}:{}...\n".format(
now.strftime("%Y/%m/%d %H:%M:%S"), event["type"], event["path"] now.strftime("%Y/%m/%d %H:%M:%S"), event["type"], event["path"]

View File

@ -7,6 +7,7 @@ import urllib.parse
import uuid import uuid
import arrow import arrow
import slugify
from django.conf import settings from django.conf import settings
from django.contrib.contenttypes.fields import GenericRelation from django.contrib.contenttypes.fields import GenericRelation
from django.contrib.postgres.indexes import GinIndex from django.contrib.postgres.indexes import GinIndex
@ -775,6 +776,9 @@ TRACK_FILE_IMPORT_STATUS_CHOICES = (
def get_file_path(instance, filename): def get_file_path(instance, filename):
# Convert unicode characters in name to ASCII characters.
filename = slugify.slugify(filename, ok=slugify.SLUG_OK + ".", only_ascii=True)
if isinstance(instance, UploadVersion): if isinstance(instance, UploadVersion):
return common_utils.ChunkedPath("transcoded")(instance, filename) return common_utils.ChunkedPath("transcoded")(instance, filename)

View File

@ -176,7 +176,7 @@ def fail_import(upload, error_code, detail=None, **fields):
upload.import_metadata, "funkwhale", "config", "broadcast", default=True upload.import_metadata, "funkwhale", "config", "broadcast", default=True
) )
if broadcast: if broadcast:
signals.upload_import_status_updated.send( signals.upload_import_status_updated.send_robust(
old_status=old_status, old_status=old_status,
new_status=upload.import_status, new_status=upload.import_status,
upload=upload, upload=upload,
@ -297,7 +297,7 @@ def process_upload(upload, update_denormalization=True):
update_fields=["import_details", "import_status", "import_date", "track"] update_fields=["import_details", "import_status", "import_date", "track"]
) )
if broadcast: if broadcast:
signals.upload_import_status_updated.send( signals.upload_import_status_updated.send_robust(
old_status=old_status, old_status=old_status,
new_status=upload.import_status, new_status=upload.import_status,
upload=upload, upload=upload,
@ -341,7 +341,7 @@ def process_upload(upload, update_denormalization=True):
) )
if broadcast: if broadcast:
signals.upload_import_status_updated.send( signals.upload_import_status_updated.send_robust(
old_status=old_status, old_status=old_status,
new_status=upload.import_status, new_status=upload.import_status,
upload=upload, upload=upload,
@ -993,7 +993,7 @@ def albums_set_tags_from_tracks(ids=None, dry_run=False):
data = tags_tasks.get_tags_from_foreign_key( data = tags_tasks.get_tags_from_foreign_key(
ids=qs, ids=qs,
foreign_key_model=models.Track, foreign_key_model=models.Track,
foreign_key_attr="album", foreign_key_attr="albums",
) )
logger.info("Found automatic tags for %s albums…", len(data)) logger.info("Found automatic tags for %s albums…", len(data))
if dry_run: if dry_run:

View File

@ -419,12 +419,12 @@ class SubsonicViewSet(viewsets.GenericViewSet):
queryset = ( queryset = (
queryset.playable_by(actor) queryset.playable_by(actor)
.filter( .filter(
Q(tagged_items__tag__name=genre) Q(tagged_items__tag__name__iexact=genre)
| Q(artist_credit__artist__tagged_items__tag__name=genre) | Q(artist_credit__artist__tagged_items__tag__name__iexact=genre)
| Q( | Q(
artist_credit__albums__artist_credit__artist__tagged_items__tag__name=genre artist_credit__albums__artist_credit__artist__tagged_items__tag__name__iexact=genre
) )
| Q(artist_credit__albums__tagged_items__tag__name=genre) | Q(artist_credit__albums__tagged_items__tag__name__iexact=genre)
) )
.prefetch_related("uploads") .prefetch_related("uploads")
.distinct() .distinct()
@ -485,8 +485,8 @@ class SubsonicViewSet(viewsets.GenericViewSet):
elif type == "byGenre" and data.get("genre"): elif type == "byGenre" and data.get("genre"):
genre = data.get("genre") genre = data.get("genre")
queryset = queryset.filter( queryset = queryset.filter(
Q(tagged_items__tag__name=genre) Q(tagged_items__tag__name__iexact=genre)
| Q(artist_credit__artist__tagged_items__tag__name=genre) | Q(artist_credit__artist__tagged_items__tag__name__iexact=genre)
) )
elif type == "byYear": elif type == "byYear":
try: try:

View File

@ -11,12 +11,6 @@ class Migration(migrations.Migration):
] ]
operations = [ operations = [
CreateCollation(
"case_insensitive",
provider="icu",
locale="und-u-ks-level2",
deterministic=False,
),
migrations.AddField( migrations.AddField(
model_name="tag", model_name="tag",
name="mbid", name="mbid",
@ -25,8 +19,6 @@ class Migration(migrations.Migration):
migrations.AlterField( migrations.AlterField(
model_name="tag", model_name="tag",
name="name", name="name",
field=models.CharField( field=models.CharField(max_length=100, unique=True),
db_collation="case_insensitive", max_length=100, unique=True
),
), ),
] ]

View File

@ -12,7 +12,8 @@ TAG_REGEX = re.compile(r"^((\w+)([\d_]*))$")
class Tag(models.Model): class Tag(models.Model):
name = models.CharField( name = models.CharField(
max_length=100, unique=True, db_collation="case_insensitive" max_length=100,
unique=True,
) )
mbid = models.UUIDField(null=True, db_index=True, blank=True, unique=True) mbid = models.UUIDField(null=True, db_index=True, blank=True, unique=True)
creation_date = models.DateTimeField(default=timezone.now) creation_date = models.DateTimeField(default=timezone.now)

View File

@ -24,10 +24,10 @@ def get_tags_from_foreign_key(
objs = foreign_key_model.objects.filter( objs = foreign_key_model.objects.filter(
**{f"artist_credit__{foreign_key_attr}__pk__in": ids} **{f"artist_credit__{foreign_key_attr}__pk__in": ids}
).order_by("-id") ).order_by("-id")
objs = objs.only("id", f"artist_credit__{foreign_key_attr}_id").prefetch_related( objs = objs.only("id", f"artist_credit__{foreign_key_attr}__id").prefetch_related(
tagged_items_attr tagged_items_attr
) )
for obj in objs.iterator(): for obj in objs.iterator(chunk_size=1000):
for ac in obj.artist_credit.all(): for ac in obj.artist_credit.all():
# loop on all objects, store the objs tags + counter on the corresponding foreign key # loop on all objects, store the objs tags + counter on the corresponding foreign key
row_data = data.setdefault( row_data = data.setdefault(

View File

@ -0,0 +1,55 @@
# Generated by Django 5.1.5 on 2025-01-15 17:10
import oauth2_provider.models
from django.db import migrations, models
import oauth2_provider.models
from django.db import migrations, models
from oauth2_provider.settings import oauth2_settings
# see https://github.com/jazzband/django-oauth-toolkit/blob/master/oauth2_provider/migrations/0012_add_token_checksum.py
def forwards_func(apps, schema_editor):
"""
Forward migration touches every "old" accesstoken.token which will cause the checksum to be computed.
"""
AccessToken = apps.get_model(oauth2_settings.ACCESS_TOKEN_MODEL)
accesstokens = AccessToken._default_manager.iterator()
for accesstoken in accesstokens:
accesstoken.save(update_fields=["token_checksum"])
class Migration(migrations.Migration):
dependencies = [
("users", "0025_application_allowed_origins_and_more"),
]
operations = [
migrations.AddField(
model_name="accesstoken",
name="token_checksum",
field=oauth2_provider.models.TokenChecksumField(
blank=True, null=True, max_length=64
),
preserve_default=False,
),
migrations.AddField(
model_name="refreshtoken",
name="token_family",
field=models.UUIDField(blank=True, editable=False, null=True),
),
migrations.AlterField(
model_name="accesstoken",
name="token",
field=models.TextField(),
),
migrations.RunPython(forwards_func, migrations.RunPython.noop),
migrations.AlterField(
model_name="accesstoken",
name="token_checksum",
field=oauth2_provider.models.TokenChecksumField(
blank=False, max_length=64, db_index=True, unique=True
),
),
]

View File

@ -455,7 +455,11 @@ def create_actor(user, **kwargs):
args["private_key"] = private.decode("utf-8") args["private_key"] = private.decode("utf-8")
args["public_key"] = public.decode("utf-8") args["public_key"] = public.decode("utf-8")
return federation_models.Actor.objects.create(user=user, **args) actor = federation_models.Actor.objects.create(**args)
user.actor = actor
user.save()
return actor
def create_user_libraries(user): def create_user_libraries(user):

320
api/poetry.lock generated
View File

@ -544,6 +544,7 @@ description = "Foreign Function Interface for Python calling C code."
optional = false optional = false
python-versions = ">=3.8" python-versions = ">=3.8"
groups = ["main"] groups = ["main"]
markers = "platform_python_implementation != \"PyPy\""
files = [ files = [
{file = "cffi-1.17.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14"}, {file = "cffi-1.17.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14"},
{file = "cffi-1.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67"}, {file = "cffi-1.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67"},
@ -945,48 +946,52 @@ toml = ["tomli"]
[[package]] [[package]]
name = "cryptography" name = "cryptography"
version = "41.0.7" version = "44.0.0"
description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers."
optional = false optional = false
python-versions = ">=3.7" python-versions = "!=3.9.0,!=3.9.1,>=3.7"
groups = ["main"] groups = ["main"]
files = [ files = [
{file = "cryptography-41.0.7-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:3c78451b78313fa81607fa1b3f1ae0a5ddd8014c38a02d9db0616133987b9cdf"}, {file = "cryptography-44.0.0-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:84111ad4ff3f6253820e6d3e58be2cc2a00adb29335d4cacb5ab4d4d34f2a123"},
{file = "cryptography-41.0.7-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:928258ba5d6f8ae644e764d0f996d61a8777559f72dfeb2eea7e2fe0ad6e782d"}, {file = "cryptography-44.0.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b15492a11f9e1b62ba9d73c210e2416724633167de94607ec6069ef724fad092"},
{file = "cryptography-41.0.7-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5a1b41bc97f1ad230a41657d9155113c7521953869ae57ac39ac7f1bb471469a"}, {file = "cryptography-44.0.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:831c3c4d0774e488fdc83a1923b49b9957d33287de923d58ebd3cec47a0ae43f"},
{file = "cryptography-41.0.7-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:841df4caa01008bad253bce2a6f7b47f86dc9f08df4b433c404def869f590a15"}, {file = "cryptography-44.0.0-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:761817a3377ef15ac23cd7834715081791d4ec77f9297ee694ca1ee9c2c7e5eb"},
{file = "cryptography-41.0.7-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:5429ec739a29df2e29e15d082f1d9ad683701f0ec7709ca479b3ff2708dae65a"}, {file = "cryptography-44.0.0-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3c672a53c0fb4725a29c303be906d3c1fa99c32f58abe008a82705f9ee96f40b"},
{file = "cryptography-41.0.7-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:43f2552a2378b44869fe8827aa19e69512e3245a219104438692385b0ee119d1"}, {file = "cryptography-44.0.0-cp37-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:4ac4c9f37eba52cb6fbeaf5b59c152ea976726b865bd4cf87883a7e7006cc543"},
{file = "cryptography-41.0.7-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:af03b32695b24d85a75d40e1ba39ffe7db7ffcb099fe507b39fd41a565f1b157"}, {file = "cryptography-44.0.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:ed3534eb1090483c96178fcb0f8893719d96d5274dfde98aa6add34614e97c8e"},
{file = "cryptography-41.0.7-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:49f0805fc0b2ac8d4882dd52f4a3b935b210935d500b6b805f321addc8177406"}, {file = "cryptography-44.0.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:f3f6fdfa89ee2d9d496e2c087cebef9d4fcbb0ad63c40e821b39f74bf48d9c5e"},
{file = "cryptography-41.0.7-cp37-abi3-win32.whl", hash = "sha256:f983596065a18a2183e7f79ab3fd4c475205b839e02cbc0efbbf9666c4b3083d"}, {file = "cryptography-44.0.0-cp37-abi3-win32.whl", hash = "sha256:eb33480f1bad5b78233b0ad3e1b0be21e8ef1da745d8d2aecbb20671658b9053"},
{file = "cryptography-41.0.7-cp37-abi3-win_amd64.whl", hash = "sha256:90452ba79b8788fa380dfb587cca692976ef4e757b194b093d845e8d99f612f2"}, {file = "cryptography-44.0.0-cp37-abi3-win_amd64.whl", hash = "sha256:abc998e0c0eee3c8a1904221d3f67dcfa76422b23620173e28c11d3e626c21bd"},
{file = "cryptography-41.0.7-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:079b85658ea2f59c4f43b70f8119a52414cdb7be34da5d019a77bf96d473b960"}, {file = "cryptography-44.0.0-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:660cb7312a08bc38be15b696462fa7cc7cd85c3ed9c576e81f4dc4d8b2b31591"},
{file = "cryptography-41.0.7-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:b640981bf64a3e978a56167594a0e97db71c89a479da8e175d8bb5be5178c003"}, {file = "cryptography-44.0.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1923cb251c04be85eec9fda837661c67c1049063305d6be5721643c22dd4e2b7"},
{file = "cryptography-41.0.7-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:e3114da6d7f95d2dee7d3f4eec16dacff819740bbab931aff8648cb13c5ff5e7"}, {file = "cryptography-44.0.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:404fdc66ee5f83a1388be54300ae978b2efd538018de18556dde92575e05defc"},
{file = "cryptography-41.0.7-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:d5ec85080cce7b0513cfd233914eb8b7bbd0633f1d1703aa28d1dd5a72f678ec"}, {file = "cryptography-44.0.0-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:c5eb858beed7835e5ad1faba59e865109f3e52b3783b9ac21e7e47dc5554e289"},
{file = "cryptography-41.0.7-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:7a698cb1dac82c35fcf8fe3417a3aaba97de16a01ac914b89a0889d364d2f6be"}, {file = "cryptography-44.0.0-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:f53c2c87e0fb4b0c00fa9571082a057e37690a8f12233306161c8f4b819960b7"},
{file = "cryptography-41.0.7-pp38-pypy38_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:37a138589b12069efb424220bf78eac59ca68b95696fc622b6ccc1c0a197204a"}, {file = "cryptography-44.0.0-cp39-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:9e6fc8a08e116fb7c7dd1f040074c9d7b51d74a8ea40d4df2fc7aa08b76b9e6c"},
{file = "cryptography-41.0.7-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:68a2dec79deebc5d26d617bfdf6e8aab065a4f34934b22d3b5010df3ba36612c"}, {file = "cryptography-44.0.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:d2436114e46b36d00f8b72ff57e598978b37399d2786fd39793c36c6d5cb1c64"},
{file = "cryptography-41.0.7-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:09616eeaef406f99046553b8a40fbf8b1e70795a91885ba4c96a70793de5504a"}, {file = "cryptography-44.0.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a01956ddfa0a6790d594f5b34fc1bfa6098aca434696a03cfdbe469b8ed79285"},
{file = "cryptography-41.0.7-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:48a0476626da912a44cc078f9893f292f0b3e4c739caf289268168d8f4702a39"}, {file = "cryptography-44.0.0-cp39-abi3-win32.whl", hash = "sha256:eca27345e1214d1b9f9490d200f9db5a874479be914199194e746c893788d417"},
{file = "cryptography-41.0.7-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:c7f3201ec47d5207841402594f1d7950879ef890c0c495052fa62f58283fde1a"}, {file = "cryptography-44.0.0-cp39-abi3-win_amd64.whl", hash = "sha256:708ee5f1bafe76d041b53a4f95eb28cdeb8d18da17e597d46d7833ee59b97ede"},
{file = "cryptography-41.0.7-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:c5ca78485a255e03c32b513f8c2bc39fedb7f5c5f8535545bdc223a03b24f248"}, {file = "cryptography-44.0.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:37d76e6863da3774cd9db5b409a9ecfd2c71c981c38788d3fcfaf177f447b731"},
{file = "cryptography-41.0.7-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:d6c391c021ab1f7a82da5d8d0b3cee2f4b2c455ec86c8aebbc84837a631ff309"}, {file = "cryptography-44.0.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:f677e1268c4e23420c3acade68fac427fffcb8d19d7df95ed7ad17cdef8404f4"},
{file = "cryptography-41.0.7.tar.gz", hash = "sha256:13f93ce9bea8016c253b34afc6bd6a75993e5c40672ed5405a9c832f0d4a00bc"}, {file = "cryptography-44.0.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:f5e7cb1e5e56ca0933b4873c0220a78b773b24d40d186b6738080b73d3d0a756"},
{file = "cryptography-44.0.0-pp310-pypy310_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:8b3e6eae66cf54701ee7d9c83c30ac0a1e3fa17be486033000f2a73a12ab507c"},
{file = "cryptography-44.0.0-pp310-pypy310_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:be4ce505894d15d5c5037167ffb7f0ae90b7be6f2a98f9a5c3442395501c32fa"},
{file = "cryptography-44.0.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:62901fb618f74d7d81bf408c8719e9ec14d863086efe4185afd07c352aee1d2c"},
{file = "cryptography-44.0.0.tar.gz", hash = "sha256:cd4e834f340b4293430701e772ec543b0fbe6c2dea510a5286fe0acabe153a02"},
] ]
[package.dependencies] [package.dependencies]
cffi = ">=1.12" cffi = {version = ">=1.12", markers = "platform_python_implementation != \"PyPy\""}
[package.extras] [package.extras]
docs = ["sphinx (>=5.3.0)", "sphinx-rtd-theme (>=1.1.1)"] docs = ["sphinx (>=5.3.0)", "sphinx-rtd-theme (>=3.0.0)"]
docstest = ["pyenchant (>=1.6.11)", "sphinxcontrib-spelling (>=4.0.1)", "twine (>=1.12.0)"] docstest = ["pyenchant (>=3)", "readme-renderer (>=30.0)", "sphinxcontrib-spelling (>=7.3.1)"]
nox = ["nox"] nox = ["nox (>=2024.4.15)", "nox[uv] (>=2024.3.2)"]
pep8test = ["black", "check-sdist", "mypy", "ruff"] pep8test = ["check-sdist", "click (>=8.0.1)", "mypy (>=1.4)", "ruff (>=0.3.6)"]
sdist = ["build"] sdist = ["build (>=1.0.0)"]
ssh = ["bcrypt (>=3.1.5)"] ssh = ["bcrypt (>=3.1.5)"]
test = ["pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"] test = ["certifi (>=2024)", "cryptography-vectors (==44.0.0)", "pretend (>=0.7)", "pytest (>=7.4.0)", "pytest-benchmark (>=4.0)", "pytest-cov (>=2.10.1)", "pytest-xdist (>=3.5.0)"]
test-randomorder = ["pytest-randomly"] test-randomorder = ["pytest-randomly"]
[[package]] [[package]]
@ -1105,18 +1110,18 @@ with-social = ["django-allauth[socialaccount] (>=64.0.0)"]
[[package]] [[package]]
name = "django" name = "django"
version = "4.2.18" version = "5.1.5"
description = "A high-level Python web framework that encourages rapid development and clean, pragmatic design." description = "A high-level Python web framework that encourages rapid development and clean, pragmatic design."
optional = false optional = false
python-versions = ">=3.8" python-versions = ">=3.10"
groups = ["main", "dev"] groups = ["main", "dev"]
files = [ files = [
{file = "Django-4.2.18-py3-none-any.whl", hash = "sha256:ba52eff7e228f1c775d5b0db2ba53d8c49d2f8bfe6ca0234df6b7dd12fb25b19"}, {file = "Django-5.1.5-py3-none-any.whl", hash = "sha256:c46eb936111fffe6ec4bc9930035524a8be98ec2f74d8a0ff351226a3e52f459"},
{file = "Django-4.2.18.tar.gz", hash = "sha256:52ae8eacf635617c0f13b44f749e5ea13dc34262819b2cc8c8636abb08d82c4b"}, {file = "Django-5.1.5.tar.gz", hash = "sha256:19bbca786df50b9eca23cee79d495facf55c8f5c54c529d9bf1fe7b5ea086af3"},
] ]
[package.dependencies] [package.dependencies]
asgiref = ">=3.6.0,<4" asgiref = ">=3.8.1,<4"
sqlparse = ">=0.3.1" sqlparse = ">=0.3.1"
tzdata = {version = "*", markers = "sys_platform == \"win32\""} tzdata = {version = "*", markers = "sys_platform == \"win32\""}
@ -1126,20 +1131,21 @@ bcrypt = ["bcrypt"]
[[package]] [[package]]
name = "django-allauth" name = "django-allauth"
version = "0.63.6" version = "65.3.1"
description = "Integrated set of Django applications addressing authentication, registration, account management as well as 3rd party (social) account authentication." description = "Integrated set of Django applications addressing authentication, registration, account management as well as 3rd party (social) account authentication."
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.8"
groups = ["main"] groups = ["main"]
files = [ files = [
{file = "django_allauth-0.63.6.tar.gz", hash = "sha256:f15f49defb09e0604dad5214e53a69a1f723cb03176bb115c8930bcd19b91749"}, {file = "django_allauth-65.3.1.tar.gz", hash = "sha256:e02e951b71a2753a746459f2efa114c7c72bf2cef6887dbe8607a577c0350587"},
] ]
[package.dependencies] [package.dependencies]
Django = ">=3.2" asgiref = ">=3.8.1"
Django = ">=4.2.16"
[package.extras] [package.extras]
mfa = ["qrcode (>=7.0.0)"] mfa = ["fido2 (>=1.1.2)", "qrcode (>=7.0.0)"]
openid = ["python3-openid (>=3.0.8)"] openid = ["python3-openid (>=3.0.8)"]
saml = ["python3-saml (>=1.15.0,<2.0.0)"] saml = ["python3-saml (>=1.15.0,<2.0.0)"]
socialaccount = ["pyjwt[crypto] (>=1.7)", "requests (>=2.0.0)", "requests-oauthlib (>=0.3.0)"] socialaccount = ["pyjwt[crypto] (>=1.7)", "requests (>=2.0.0)", "requests-oauthlib (>=0.3.0)"]
@ -1147,18 +1153,18 @@ steam = ["python3-openid (>=3.0.8)"]
[[package]] [[package]]
name = "django-auth-ldap" name = "django-auth-ldap"
version = "4.8.0" version = "5.1.0"
description = "Django LDAP authentication backend" description = "Django LDAP authentication backend"
optional = false optional = false
python-versions = ">=3.8" python-versions = ">=3.9"
groups = ["main"] groups = ["main"]
files = [ files = [
{file = "django-auth-ldap-4.8.0.tar.gz", hash = "sha256:604250938ddc9fda619f247c7a59b0b2f06e53a7d3f46a156f28aa30dd71a738"}, {file = "django_auth_ldap-5.1.0-py3-none-any.whl", hash = "sha256:a5f7bdb54b2ab80e4e9eb080cd3e06e89e4c9d2d534ddb39b66cd970dd6d3536"},
{file = "django_auth_ldap-4.8.0-py3-none-any.whl", hash = "sha256:4b4b944f3c28bce362f33fb6e8db68429ed8fd8f12f0c0c4b1a4344a7ef225ce"}, {file = "django_auth_ldap-5.1.0.tar.gz", hash = "sha256:9c607e8d9c53cf2a0ccafbe0acfc33eb1d1fd474c46ec52d30aee0dca1da9668"},
] ]
[package.dependencies] [package.dependencies]
Django = ">=3.2" Django = ">=4.2"
python-ldap = ">=3.1" python-ldap = ">=3.1"
[[package]] [[package]]
@ -1195,14 +1201,14 @@ redis = ">=3.0.0"
[[package]] [[package]]
name = "django-cleanup" name = "django-cleanup"
version = "8.1.0" version = "9.0.0"
description = "Deletes old files." description = "Deletes old files."
optional = false optional = false
python-versions = "*" python-versions = ">=3.8"
groups = ["main"] groups = ["main"]
files = [ files = [
{file = "django-cleanup-8.1.0.tar.gz", hash = "sha256:70df905076a44e7a111b31198199af633dee08876e199e6dce36ca8dd6b8b10f"}, {file = "django_cleanup-9.0.0-py3-none-any.whl", hash = "sha256:19f8b0e830233f9f0f683b17181f414672a0f48afe3ea3cc80ba47ae40ad880c"},
{file = "django_cleanup-8.1.0-py2.py3-none-any.whl", hash = "sha256:7903873ea73b3f7e61e055340d27dba49b70634f60c87a573ad748e172836458"}, {file = "django_cleanup-9.0.0.tar.gz", hash = "sha256:bb9fb560aaf62959c81e31fa40885c36bbd5854d5aa21b90df2c7e4ba633531e"},
] ]
[[package]] [[package]]
@ -1238,14 +1244,14 @@ coverage = "*"
[[package]] [[package]]
name = "django-debug-toolbar" name = "django-debug-toolbar"
version = "4.4.6" version = "5.0.1"
description = "A configurable set of panels that display various debug information about the current request/response." description = "A configurable set of panels that display various debug information about the current request/response."
optional = false optional = false
python-versions = ">=3.8" python-versions = ">=3.9"
groups = ["dev"] groups = ["dev"]
files = [ files = [
{file = "django_debug_toolbar-4.4.6-py3-none-any.whl", hash = "sha256:3beb671c9ec44ffb817fad2780667f172bd1c067dbcabad6268ce39a81335f45"}, {file = "django_debug_toolbar-5.0.1-py3-none-any.whl", hash = "sha256:7456cc2e951db37dab335686db7803c4a0ecb6736d120705f6668db9548bf49f"},
{file = "django_debug_toolbar-4.4.6.tar.gz", hash = "sha256:36e421cb908c2f0675e07f9f41e3d1d8618dc386392ec82d23bcfcd5d29c7044"}, {file = "django_debug_toolbar-5.0.1.tar.gz", hash = "sha256:296f6f18a80710e84fbb8361538ae5ec522a75ebe9ab67db34bcf1026cbeb420"},
] ]
[package.dependencies] [package.dependencies]
@ -1317,21 +1323,20 @@ Django = ">=4.2"
[[package]] [[package]]
name = "django-oauth-toolkit" name = "django-oauth-toolkit"
version = "2.4.0" version = "3.0.1"
description = "OAuth2 Provider for Django" description = "OAuth2 Provider for Django"
optional = false optional = false
python-versions = ">=3.8" python-versions = ">=3.8"
groups = ["main"] groups = ["main"]
files = [ files = [
{file = "django_oauth_toolkit-2.4.0-py3-none-any.whl", hash = "sha256:4931d6bf64b6aee32a42f989f218769d1876f3daa53c6bf883d8ab793fb302ee"}, {file = "django_oauth_toolkit-3.0.1-py3-none-any.whl", hash = "sha256:3ef00b062a284f2031b0732b32dc899e3bbf0eac221bbb1cffcb50b8932e55ed"},
{file = "django_oauth_toolkit-2.4.0.tar.gz", hash = "sha256:8975eaf697413a8d54208ee068bc5ad6d1ed76f1df84e4882fbb25e7e6966e1b"}, {file = "django_oauth_toolkit-3.0.1.tar.gz", hash = "sha256:7200e4a9fb229b145a6d808cbf0423b6d69a87f68557437733eec3c0cf71db02"},
] ]
[package.dependencies] [package.dependencies]
django = ">=3.2,<4.0.0 || >4.0.0" django = ">=4.2"
jwcrypto = ">=0.8.0" jwcrypto = ">=1.5.0"
oauthlib = ">=3.1.0" oauthlib = ">=3.2.2"
pytz = ">=2024.1"
requests = ">=2.13.0" requests = ">=2.13.0"
[[package]] [[package]]
@ -1485,18 +1490,19 @@ doc = ["Sphinx", "sphinx-rtd-theme", "sphinxcontrib-spelling"]
[[package]] [[package]]
name = "faker" name = "faker"
version = "23.3.0" version = "33.3.1"
description = "Faker is a Python package that generates fake data for you." description = "Faker is a Python package that generates fake data for you."
optional = false optional = false
python-versions = ">=3.8" python-versions = ">=3.8"
groups = ["dev"] groups = ["dev"]
files = [ files = [
{file = "Faker-23.3.0-py3-none-any.whl", hash = "sha256:117ce1a2805c1bc5ca753b3dc6f9d567732893b2294b827d3164261ee8f20267"}, {file = "Faker-33.3.1-py3-none-any.whl", hash = "sha256:ac4cf2f967ce02c898efa50651c43180bd658a7707cfd676fcc5410ad1482c03"},
{file = "Faker-23.3.0.tar.gz", hash = "sha256:458d93580de34403a8dec1e8d5e6be2fee96c4deca63b95d71df7a6a80a690de"}, {file = "faker-33.3.1.tar.gz", hash = "sha256:49dde3b06a5602177bc2ad013149b6f60a290b7154539180d37b6f876ae79b20"},
] ]
[package.dependencies] [package.dependencies]
python-dateutil = ">=2.4" python-dateutil = ">=2.4"
typing-extensions = "*"
[[package]] [[package]]
name = "feedparser" name = "feedparser"
@ -1515,20 +1521,20 @@ sgmllib3k = "*"
[[package]] [[package]]
name = "flake8" name = "flake8"
version = "3.9.2" version = "7.1.1"
description = "the modular source code checker: pep8 pyflakes and co" description = "the modular source code checker: pep8 pyflakes and co"
optional = false optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" python-versions = ">=3.8.1"
groups = ["dev"] groups = ["dev"]
files = [ files = [
{file = "flake8-3.9.2-py2.py3-none-any.whl", hash = "sha256:bf8fd333346d844f616e8d47905ef3a3384edae6b4e9beb0c5101e25e3110907"}, {file = "flake8-7.1.1-py2.py3-none-any.whl", hash = "sha256:597477df7860daa5aa0fdd84bf5208a043ab96b8e96ab708770ae0364dd03213"},
{file = "flake8-3.9.2.tar.gz", hash = "sha256:07528381786f2a6237b061f6e96610a4167b226cb926e2aa2b6b1d78057c576b"}, {file = "flake8-7.1.1.tar.gz", hash = "sha256:049d058491e228e03e67b390f311bbf88fce2dbaa8fa673e7aea87b7198b8d38"},
] ]
[package.dependencies] [package.dependencies]
mccabe = ">=0.6.0,<0.7.0" mccabe = ">=0.7.0,<0.8.0"
pycodestyle = ">=2.7.0,<2.8.0" pycodestyle = ">=2.12.0,<2.13.0"
pyflakes = ">=2.3.0,<2.4.0" pyflakes = ">=3.2.0,<3.3.0"
[[package]] [[package]]
name = "frozendict" name = "frozendict"
@ -1695,23 +1701,24 @@ files = [
[[package]] [[package]]
name = "gunicorn" name = "gunicorn"
version = "21.2.0" version = "23.0.0"
description = "WSGI HTTP Server for UNIX" description = "WSGI HTTP Server for UNIX"
optional = false optional = false
python-versions = ">=3.5" python-versions = ">=3.7"
groups = ["main"] groups = ["main"]
files = [ files = [
{file = "gunicorn-21.2.0-py3-none-any.whl", hash = "sha256:3213aa5e8c24949e792bcacfc176fef362e7aac80b76c56f6b5122bf350722f0"}, {file = "gunicorn-23.0.0-py3-none-any.whl", hash = "sha256:ec400d38950de4dfd418cff8328b2c8faed0edb0d517d3394e457c317908ca4d"},
{file = "gunicorn-21.2.0.tar.gz", hash = "sha256:88ec8bff1d634f98e61b9f65bc4bf3cd918a90806c6f5c48bc5603849ec81033"}, {file = "gunicorn-23.0.0.tar.gz", hash = "sha256:f014447a0101dc57e294f6c18ca6b40227a4c90e9bdb586042628030cba004ec"},
] ]
[package.dependencies] [package.dependencies]
packaging = "*" packaging = "*"
[package.extras] [package.extras]
eventlet = ["eventlet (>=0.24.1)"] eventlet = ["eventlet (>=0.24.1,!=0.36.0)"]
gevent = ["gevent (>=1.4.0)"] gevent = ["gevent (>=1.4.0)"]
setproctitle = ["setproctitle"] setproctitle = ["setproctitle"]
testing = ["coverage", "eventlet", "gevent", "pytest", "pytest-cov"]
tornado = ["tornado (>=0.2)"] tornado = ["tornado (>=0.2)"]
[[package]] [[package]]
@ -2284,14 +2291,14 @@ traitlets = "*"
[[package]] [[package]]
name = "mccabe" name = "mccabe"
version = "0.6.1" version = "0.7.0"
description = "McCabe checker, plugin for flake8" description = "McCabe checker, plugin for flake8"
optional = false optional = false
python-versions = "*" python-versions = ">=3.6"
groups = ["dev"] groups = ["dev"]
files = [ files = [
{file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"}, {file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"},
{file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"}, {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"},
] ]
[[package]] [[package]]
@ -3069,26 +3076,26 @@ pyasn1 = ">=0.4.6,<0.7.0"
[[package]] [[package]]
name = "pycodestyle" name = "pycodestyle"
version = "2.7.0" version = "2.12.1"
description = "Python style guide checker" description = "Python style guide checker"
optional = false optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" python-versions = ">=3.8"
groups = ["dev"] groups = ["dev"]
files = [ files = [
{file = "pycodestyle-2.7.0-py2.py3-none-any.whl", hash = "sha256:514f76d918fcc0b55c6680472f0a37970994e07bbb80725808c17089be302068"}, {file = "pycodestyle-2.12.1-py2.py3-none-any.whl", hash = "sha256:46f0fb92069a7c28ab7bb558f05bfc0110dac69a0cd23c61ea0040283a9d78b3"},
{file = "pycodestyle-2.7.0.tar.gz", hash = "sha256:c389c1d06bf7904078ca03399a4816f974a1d590090fecea0c63ec26ebaf1cef"}, {file = "pycodestyle-2.12.1.tar.gz", hash = "sha256:6838eae08bbce4f6accd5d5572075c63626a15ee3e6f842df996bf62f6d73521"},
] ]
[[package]] [[package]]
name = "pycountry" name = "pycountry"
version = "23.12.11" version = "24.6.1"
description = "ISO country, subdivision, language, currency and script definitions and their translations" description = "ISO country, subdivision, language, currency and script definitions and their translations"
optional = false optional = false
python-versions = ">=3.8" python-versions = ">=3.8"
groups = ["main"] groups = ["main"]
files = [ files = [
{file = "pycountry-23.12.11-py3-none-any.whl", hash = "sha256:2ff91cff4f40ff61086e773d61e72005fe95de4a57bfc765509db05695dc50ab"}, {file = "pycountry-24.6.1-py3-none-any.whl", hash = "sha256:f1a4fb391cd7214f8eefd39556d740adcc233c778a27f8942c8dca351d6ce06f"},
{file = "pycountry-23.12.11.tar.gz", hash = "sha256:00569d82eaefbc6a490a311bfa84a9c571cff9ddbf8b0a4f4e7b4f868b4ad925"}, {file = "pycountry-24.6.1.tar.gz", hash = "sha256:b61b3faccea67f87d10c1f2b0fc0be714409e8fcdcc1315613174f6466c10221"},
] ]
[[package]] [[package]]
@ -3098,6 +3105,7 @@ description = "C parser in Python"
optional = false optional = false
python-versions = ">=3.8" python-versions = ">=3.8"
groups = ["main"] groups = ["main"]
markers = "platform_python_implementation != \"PyPy\""
files = [ files = [
{file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"}, {file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"},
{file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"}, {file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"},
@ -3123,14 +3131,14 @@ dev = ["black", "build", "flake8", "flake8-black", "isort", "jupyter-console", "
[[package]] [[package]]
name = "pyflakes" name = "pyflakes"
version = "2.3.1" version = "3.2.0"
description = "passive checker of Python programs" description = "passive checker of Python programs"
optional = false optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" python-versions = ">=3.8"
groups = ["dev"] groups = ["dev"]
files = [ files = [
{file = "pyflakes-2.3.1-py2.py3-none-any.whl", hash = "sha256:7893783d01b8a89811dd72d7dfd4d84ff098e5eed95cfa8905b22bbffe52efc3"}, {file = "pyflakes-3.2.0-py2.py3-none-any.whl", hash = "sha256:84b5be138a2dfbb40689ca07e2152deb896a65c3a3e24c251c5c62489568074a"},
{file = "pyflakes-2.3.1.tar.gz", hash = "sha256:f5bc8ecabc05bb9d291eb5203d6810b49040f6ff446a756326104746cc00c1db"}, {file = "pyflakes-3.2.0.tar.gz", hash = "sha256:1c61603ff154621fb2a9172037d84dca3500def8c8b630657d1701f026f8af3f"},
] ]
[[package]] [[package]]
@ -3299,22 +3307,22 @@ testing = ["coverage (>=6.2)", "hypothesis (>=5.7.1)"]
[[package]] [[package]]
name = "pytest-cov" name = "pytest-cov"
version = "4.1.0" version = "6.0.0"
description = "Pytest plugin for measuring coverage." description = "Pytest plugin for measuring coverage."
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.9"
groups = ["dev"] groups = ["dev"]
files = [ files = [
{file = "pytest-cov-4.1.0.tar.gz", hash = "sha256:3904b13dfbfec47f003b8e77fd5b589cd11904a21ddf1ab38a64f204d6a10ef6"}, {file = "pytest-cov-6.0.0.tar.gz", hash = "sha256:fde0b595ca248bb8e2d76f020b465f3b107c9632e6a1d1705f17834c89dcadc0"},
{file = "pytest_cov-4.1.0-py3-none-any.whl", hash = "sha256:6ba70b9e97e69fcc3fb45bfeab2d0a138fb65c4d0d6a41ef33983ad114be8c3a"}, {file = "pytest_cov-6.0.0-py3-none-any.whl", hash = "sha256:eee6f1b9e61008bd34975a4d5bab25801eb31898b032dd55addc93e96fcaaa35"},
] ]
[package.dependencies] [package.dependencies]
coverage = {version = ">=5.2.1", extras = ["toml"]} coverage = {version = ">=7.5", extras = ["toml"]}
pytest = ">=4.6" pytest = ">=4.6"
[package.extras] [package.extras]
testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtualenv"] testing = ["fields", "hunter", "process-tests", "pytest-xdist", "virtualenv"]
[[package]] [[package]]
name = "pytest-django" name = "pytest-django"
@ -3480,18 +3488,6 @@ files = [
{file = "python_magic-0.4.27-py2.py3-none-any.whl", hash = "sha256:c212960ad306f700aa0d01e5d7a325d20548ff97eb9920dcd29513174f0294d3"}, {file = "python_magic-0.4.27-py2.py3-none-any.whl", hash = "sha256:c212960ad306f700aa0d01e5d7a325d20548ff97eb9920dcd29513174f0294d3"},
] ]
[[package]]
name = "pytz"
version = "2024.2"
description = "World timezone definitions, modern and historical"
optional = false
python-versions = "*"
groups = ["main"]
files = [
{file = "pytz-2024.2-py2.py3-none-any.whl", hash = "sha256:31c7c1817eb7fae7ca4b8c7ee50c72f93aa2dd863de768e1ef4245d426aa0725"},
{file = "pytz-2024.2.tar.gz", hash = "sha256:2aa355083c50a0f93fa581709deac0c9ad65cca8a9e9beac660adcbd493c798a"},
]
[[package]] [[package]]
name = "pyyaml" name = "pyyaml"
version = "6.0.2" version = "6.0.2"
@ -3996,22 +3992,23 @@ test = ["Cython", "array-api-strict (>=2.0,<2.1.1)", "asv", "gmpy2", "hypothesis
[[package]] [[package]]
name = "sentry-sdk" name = "sentry-sdk"
version = "1.45.1" version = "2.20.0"
description = "Python client for Sentry (https://sentry.io)" description = "Python client for Sentry (https://sentry.io)"
optional = false optional = false
python-versions = "*" python-versions = ">=3.6"
groups = ["main"] groups = ["main"]
files = [ files = [
{file = "sentry_sdk-1.45.1-py2.py3-none-any.whl", hash = "sha256:608887855ccfe39032bfd03936e3a1c4f4fc99b3a4ac49ced54a4220de61c9c1"}, {file = "sentry_sdk-2.20.0-py2.py3-none-any.whl", hash = "sha256:c359a1edf950eb5e80cffd7d9111f3dbeef57994cb4415df37d39fda2cf22364"},
{file = "sentry_sdk-1.45.1.tar.gz", hash = "sha256:a16c997c0f4e3df63c0fc5e4207ccb1ab37900433e0f72fef88315d317829a26"}, {file = "sentry_sdk-2.20.0.tar.gz", hash = "sha256:afa82713a92facf847df3c6f63cec71eb488d826a50965def3d7722aa6f0fdab"},
] ]
[package.dependencies] [package.dependencies]
certifi = "*" certifi = "*"
urllib3 = {version = ">=1.26.11", markers = "python_version >= \"3.6\""} urllib3 = ">=1.26.11"
[package.extras] [package.extras]
aiohttp = ["aiohttp (>=3.5)"] aiohttp = ["aiohttp (>=3.5)"]
anthropic = ["anthropic (>=0.16)"]
arq = ["arq (>=0.23)"] arq = ["arq (>=0.23)"]
asyncpg = ["asyncpg (>=0.23)"] asyncpg = ["asyncpg (>=0.23)"]
beam = ["apache-beam (>=2.12)"] beam = ["apache-beam (>=2.12)"]
@ -4024,14 +4021,20 @@ django = ["django (>=1.8)"]
falcon = ["falcon (>=1.4)"] falcon = ["falcon (>=1.4)"]
fastapi = ["fastapi (>=0.79.0)"] fastapi = ["fastapi (>=0.79.0)"]
flask = ["blinker (>=1.1)", "flask (>=0.11)", "markupsafe"] flask = ["blinker (>=1.1)", "flask (>=0.11)", "markupsafe"]
grpcio = ["grpcio (>=1.21.1)"] grpcio = ["grpcio (>=1.21.1)", "protobuf (>=3.8.0)"]
http2 = ["httpcore[http2] (==1.*)"]
httpx = ["httpx (>=0.16.0)"] httpx = ["httpx (>=0.16.0)"]
huey = ["huey (>=2)"] huey = ["huey (>=2)"]
huggingface-hub = ["huggingface_hub (>=0.22)"]
langchain = ["langchain (>=0.0.210)"]
launchdarkly = ["launchdarkly-server-sdk (>=9.8.0)"]
litestar = ["litestar (>=2.0.0)"]
loguru = ["loguru (>=0.5)"] loguru = ["loguru (>=0.5)"]
openai = ["openai (>=1.0.0)", "tiktoken (>=0.3.0)"] openai = ["openai (>=1.0.0)", "tiktoken (>=0.3.0)"]
openfeature = ["openfeature-sdk (>=0.7.1)"]
opentelemetry = ["opentelemetry-distro (>=0.35b0)"] opentelemetry = ["opentelemetry-distro (>=0.35b0)"]
opentelemetry-experimental = ["opentelemetry-distro (>=0.40b0,<1.0)", "opentelemetry-instrumentation-aiohttp-client (>=0.40b0,<1.0)", "opentelemetry-instrumentation-django (>=0.40b0,<1.0)", "opentelemetry-instrumentation-fastapi (>=0.40b0,<1.0)", "opentelemetry-instrumentation-flask (>=0.40b0,<1.0)", "opentelemetry-instrumentation-requests (>=0.40b0,<1.0)", "opentelemetry-instrumentation-sqlite3 (>=0.40b0,<1.0)", "opentelemetry-instrumentation-urllib (>=0.40b0,<1.0)"] opentelemetry-experimental = ["opentelemetry-distro"]
pure-eval = ["asttokens", "executing", "pure-eval"] pure-eval = ["asttokens", "executing", "pure_eval"]
pymongo = ["pymongo (>=3.1)"] pymongo = ["pymongo (>=3.1)"]
pyspark = ["pyspark (>=2.4.4)"] pyspark = ["pyspark (>=2.4.4)"]
quart = ["blinker (>=1.1)", "quart (>=0.16.1)"] quart = ["blinker (>=1.1)", "quart (>=0.16.1)"]
@ -4040,7 +4043,8 @@ sanic = ["sanic (>=0.8)"]
sqlalchemy = ["sqlalchemy (>=1.2)"] sqlalchemy = ["sqlalchemy (>=1.2)"]
starlette = ["starlette (>=0.19.1)"] starlette = ["starlette (>=0.19.1)"]
starlite = ["starlite (>=1.48)"] starlite = ["starlite (>=1.48)"]
tornado = ["tornado (>=5)"] tornado = ["tornado (>=6)"]
unleash = ["UnleashClient (>=6.0.1)"]
[[package]] [[package]]
name = "service-identity" name = "service-identity"
@ -4301,14 +4305,14 @@ test = ["argcomplete (>=3.0.3)", "mypy (>=1.7.0)", "pre-commit", "pytest (>=7.0,
[[package]] [[package]]
name = "troi" name = "troi"
version = "2024.12.4.0" version = "2025.1.10.0"
description = "ListenBrainz' empathic music recommendation/playlisting engine" description = "ListenBrainz' empathic music recommendation/playlisting engine"
optional = false optional = false
python-versions = ">=3.9" python-versions = ">=3.9"
groups = ["main"] groups = ["main"]
files = [ files = [
{file = "troi-2024.12.4.0-py3-none-any.whl", hash = "sha256:9fcd2b3acb2612e1cd5500830c5075c5699019285b5974bdf905323761558379"}, {file = "troi-2025.1.10.0-py3-none-any.whl", hash = "sha256:80693228ab924d7c9e8f1c7dbbe4971b770e8ccc027ba3a35fbedf752b5a12f3"},
{file = "troi-2024.12.4.0.tar.gz", hash = "sha256:77c62696583aac7b6cd17c4f63a8e74008ba716769e9a4ff4133c0788e688a8f"}, {file = "troi-2025.1.10.0.tar.gz", hash = "sha256:c595365282ebe4bf6cebd0fbf5a27b051c96dff603d4b9719f333d82459d898e"},
] ]
[package.dependencies] [package.dependencies]
@ -4431,7 +4435,6 @@ files = [
{file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"},
{file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"},
] ]
markers = {dev = "python_version < \"3.12\""}
[[package]] [[package]]
name = "tzdata" name = "tzdata"
@ -4685,47 +4688,42 @@ files = [
[[package]] [[package]]
name = "watchdog" name = "watchdog"
version = "4.0.2" version = "6.0.0"
description = "Filesystem events monitoring" description = "Filesystem events monitoring"
optional = false optional = false
python-versions = ">=3.8" python-versions = ">=3.9"
groups = ["main"] groups = ["main"]
files = [ files = [
{file = "watchdog-4.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ede7f010f2239b97cc79e6cb3c249e72962404ae3865860855d5cbe708b0fd22"}, {file = "watchdog-6.0.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d1cdb490583ebd691c012b3d6dae011000fe42edb7a82ece80965b42abd61f26"},
{file = "watchdog-4.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a2cffa171445b0efa0726c561eca9a27d00a1f2b83846dbd5a4f639c4f8ca8e1"}, {file = "watchdog-6.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bc64ab3bdb6a04d69d4023b29422170b74681784ffb9463ed4870cf2f3e66112"},
{file = "watchdog-4.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c50f148b31b03fbadd6d0b5980e38b558046b127dc483e5e4505fcef250f9503"}, {file = "watchdog-6.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c897ac1b55c5a1461e16dae288d22bb2e412ba9807df8397a635d88f671d36c3"},
{file = "watchdog-4.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7c7d4bf585ad501c5f6c980e7be9c4f15604c7cc150e942d82083b31a7548930"}, {file = "watchdog-6.0.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6eb11feb5a0d452ee41f824e271ca311a09e250441c262ca2fd7ebcf2461a06c"},
{file = "watchdog-4.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:914285126ad0b6eb2258bbbcb7b288d9dfd655ae88fa28945be05a7b475a800b"}, {file = "watchdog-6.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ef810fbf7b781a5a593894e4f439773830bdecb885e6880d957d5b9382a960d2"},
{file = "watchdog-4.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:984306dc4720da5498b16fc037b36ac443816125a3705dfde4fd90652d8028ef"}, {file = "watchdog-6.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:afd0fe1b2270917c5e23c2a65ce50c2a4abb63daafb0d419fde368e272a76b7c"},
{file = "watchdog-4.0.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:1cdcfd8142f604630deef34722d695fb455d04ab7cfe9963055df1fc69e6727a"}, {file = "watchdog-6.0.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:bdd4e6f14b8b18c334febb9c4425a878a2ac20efd1e0b231978e7b150f92a948"},
{file = "watchdog-4.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:d7ab624ff2f663f98cd03c8b7eedc09375a911794dfea6bf2a359fcc266bff29"}, {file = "watchdog-6.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c7c15dda13c4eb00d6fb6fc508b3c0ed88b9d5d374056b239c4ad1611125c860"},
{file = "watchdog-4.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:132937547a716027bd5714383dfc40dc66c26769f1ce8a72a859d6a48f371f3a"}, {file = "watchdog-6.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6f10cb2d5902447c7d0da897e2c6768bca89174d0c6e1e30abec5421af97a5b0"},
{file = "watchdog-4.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:cd67c7df93eb58f360c43802acc945fa8da70c675b6fa37a241e17ca698ca49b"}, {file = "watchdog-6.0.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:490ab2ef84f11129844c23fb14ecf30ef3d8a6abafd3754a6f75ca1e6654136c"},
{file = "watchdog-4.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:bcfd02377be80ef3b6bc4ce481ef3959640458d6feaae0bd43dd90a43da90a7d"}, {file = "watchdog-6.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:76aae96b00ae814b181bb25b1b98076d5fc84e8a53cd8885a318b42b6d3a5134"},
{file = "watchdog-4.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:980b71510f59c884d684b3663d46e7a14b457c9611c481e5cef08f4dd022eed7"}, {file = "watchdog-6.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a175f755fc2279e0b7312c0035d52e27211a5bc39719dd529625b1930917345b"},
{file = "watchdog-4.0.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:aa160781cafff2719b663c8a506156e9289d111d80f3387cf3af49cedee1f040"}, {file = "watchdog-6.0.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e6f0e77c9417e7cd62af82529b10563db3423625c5fce018430b249bf977f9e8"},
{file = "watchdog-4.0.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f6ee8dedd255087bc7fe82adf046f0b75479b989185fb0bdf9a98b612170eac7"}, {file = "watchdog-6.0.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:90c8e78f3b94014f7aaae121e6b909674df5b46ec24d6bebc45c44c56729af2a"},
{file = "watchdog-4.0.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:0b4359067d30d5b864e09c8597b112fe0a0a59321a0f331498b013fb097406b4"}, {file = "watchdog-6.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e7631a77ffb1f7d2eefa4445ebbee491c720a5661ddf6df3498ebecae5ed375c"},
{file = "watchdog-4.0.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:770eef5372f146997638d737c9a3c597a3b41037cfbc5c41538fc27c09c3a3f9"}, {file = "watchdog-6.0.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:c7ac31a19f4545dd92fc25d200694098f42c9a8e391bc00bdd362c5736dbf881"},
{file = "watchdog-4.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:eeea812f38536a0aa859972d50c76e37f4456474b02bd93674d1947cf1e39578"}, {file = "watchdog-6.0.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:9513f27a1a582d9808cf21a07dae516f0fab1cf2d7683a742c498b93eedabb11"},
{file = "watchdog-4.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b2c45f6e1e57ebb4687690c05bc3a2c1fb6ab260550c4290b8abb1335e0fd08b"}, {file = "watchdog-6.0.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7a0e56874cfbc4b9b05c60c8a1926fedf56324bb08cfbc188969777940aef3aa"},
{file = "watchdog-4.0.2-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:10b6683df70d340ac3279eff0b2766813f00f35a1d37515d2c99959ada8f05fa"}, {file = "watchdog-6.0.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:e6439e374fc012255b4ec786ae3c4bc838cd7309a540e5fe0952d03687d8804e"},
{file = "watchdog-4.0.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:f7c739888c20f99824f7aa9d31ac8a97353e22d0c0e54703a547a218f6637eb3"}, {file = "watchdog-6.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7607498efa04a3542ae3e05e64da8202e58159aa1fa4acddf7678d34a35d4f13"},
{file = "watchdog-4.0.2-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:c100d09ac72a8a08ddbf0629ddfa0b8ee41740f9051429baa8e31bb903ad7508"}, {file = "watchdog-6.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:9041567ee8953024c83343288ccc458fd0a2d811d6a0fd68c4c22609e3490379"},
{file = "watchdog-4.0.2-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:f5315a8c8dd6dd9425b974515081fc0aadca1d1d61e078d2246509fd756141ee"}, {file = "watchdog-6.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:82dc3e3143c7e38ec49d61af98d6558288c415eac98486a5c581726e0737c00e"},
{file = "watchdog-4.0.2-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:2d468028a77b42cc685ed694a7a550a8d1771bb05193ba7b24006b8241a571a1"}, {file = "watchdog-6.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:212ac9b8bf1161dc91bd09c048048a95ca3a4c4f5e5d4a7d1b1a7d5752a7f96f"},
{file = "watchdog-4.0.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:f15edcae3830ff20e55d1f4e743e92970c847bcddc8b7509bcd172aa04de506e"}, {file = "watchdog-6.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:e3df4cbb9a450c6d49318f6d14f4bbc80d763fa587ba46ec86f99f9e6876bb26"},
{file = "watchdog-4.0.2-py3-none-manylinux2014_aarch64.whl", hash = "sha256:936acba76d636f70db8f3c66e76aa6cb5136a936fc2a5088b9ce1c7a3508fc83"}, {file = "watchdog-6.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:2cce7cfc2008eb51feb6aab51251fd79b85d9894e98ba847408f662b3395ca3c"},
{file = "watchdog-4.0.2-py3-none-manylinux2014_armv7l.whl", hash = "sha256:e252f8ca942a870f38cf785aef420285431311652d871409a64e2a0a52a2174c"}, {file = "watchdog-6.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:20ffe5b202af80ab4266dcd3e91aae72bf2da48c0d33bdb15c66658e685e94e2"},
{file = "watchdog-4.0.2-py3-none-manylinux2014_i686.whl", hash = "sha256:0e83619a2d5d436a7e58a1aea957a3c1ccbf9782c43c0b4fed80580e5e4acd1a"}, {file = "watchdog-6.0.0-py3-none-win32.whl", hash = "sha256:07df1fdd701c5d4c8e55ef6cf55b8f0120fe1aef7ef39a1c6fc6bc2e606d517a"},
{file = "watchdog-4.0.2-py3-none-manylinux2014_ppc64.whl", hash = "sha256:88456d65f207b39f1981bf772e473799fcdc10801062c36fd5ad9f9d1d463a73"}, {file = "watchdog-6.0.0-py3-none-win_amd64.whl", hash = "sha256:cbafb470cf848d93b5d013e2ecb245d4aa1c8fd0504e863ccefa32445359d680"},
{file = "watchdog-4.0.2-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:32be97f3b75693a93c683787a87a0dc8db98bb84701539954eef991fb35f5fbc"}, {file = "watchdog-6.0.0-py3-none-win_ia64.whl", hash = "sha256:a1914259fa9e1454315171103c6a30961236f508b9b623eae470268bbcc6a22f"},
{file = "watchdog-4.0.2-py3-none-manylinux2014_s390x.whl", hash = "sha256:c82253cfc9be68e3e49282831afad2c1f6593af80c0daf1287f6a92657986757"}, {file = "watchdog-6.0.0.tar.gz", hash = "sha256:9ddf7c82fda3ae8e24decda1338ede66e1c99883db93711d8fb941eaa2d8c282"},
{file = "watchdog-4.0.2-py3-none-manylinux2014_x86_64.whl", hash = "sha256:c0b14488bd336c5b1845cee83d3e631a1f8b4e9c5091ec539406e4a324f882d8"},
{file = "watchdog-4.0.2-py3-none-win32.whl", hash = "sha256:0d8a7e523ef03757a5aa29f591437d64d0d894635f8a50f370fe37f913ce4e19"},
{file = "watchdog-4.0.2-py3-none-win_amd64.whl", hash = "sha256:c344453ef3bf875a535b0488e3ad28e341adbd5a9ffb0f7d62cefacc8824ef2b"},
{file = "watchdog-4.0.2-py3-none-win_ia64.whl", hash = "sha256:baececaa8edff42cd16558a639a9b0ddf425f93d892e8392a56bf904f5eff22c"},
{file = "watchdog-4.0.2.tar.gz", hash = "sha256:b4dfbb6c49221be4535623ea4474a4d6ee0a9cef4a80b20c28db4d858b64e270"},
] ]
[package.extras] [package.extras]
@ -5076,4 +5074,4 @@ typesense = ["typesense"]
[metadata] [metadata]
lock-version = "2.1" lock-version = "2.1"
python-versions = "^3.10,<3.14" python-versions = "^3.10,<3.14"
content-hash = "81f2e39521ecc944870e2465090d8b0debc867cb1ce6e621b653feb360f6222a" content-hash = "5338d2d4fed2085b1c581613a567a79d3b96c602ea0dbc6ef9a882dd0efac036"

View File

@ -29,16 +29,16 @@ python = "^3.10,<3.14"
# Django # Django
dj-rest-auth = "7.0.1" dj-rest-auth = "7.0.1"
django = "4.2.18" django = "5.1.5"
django-allauth = "0.63.6" django-allauth = "65.3.1"
django-cache-memoize = "0.2.1" django-cache-memoize = "0.2.1"
django-cacheops = "==7.1" django-cacheops = "==7.1"
django-cleanup = "==8.1.0" django-cleanup = "==9.0.0"
django-cors-headers = "==4.6.0" django-cors-headers = "==4.6.0"
django-dynamic-preferences = "==1.17.0" django-dynamic-preferences = "==1.17.0"
django-environ = "==0.12.0" django-environ = "==0.12.0"
django-filter = "==24.3" django-filter = "==24.3"
django-oauth-toolkit = "2.4.0" django-oauth-toolkit = "3.0.1"
django-redis = "==5.4.0" django-redis = "==5.4.0"
django-storages = "==1.14.4" django-storages = "==1.14.4"
django-versatileimagefield = "==3.1" django-versatileimagefield = "==3.1"
@ -50,7 +50,7 @@ psycopg2-binary = "==2.9.10"
redis = "==5.2.1" redis = "==5.2.1"
# Django LDAP # Django LDAP
django-auth-ldap = "==4.8.0" django-auth-ldap = "==5.1.0"
python-ldap = "==3.4.4" python-ldap = "==3.4.4"
# Channels # Channels
@ -62,7 +62,7 @@ kombu = "5.4.2"
celery = "5.4.0" celery = "5.4.0"
# Deployment # Deployment
gunicorn = "==21.2.0" gunicorn = "==23.0.0"
uvicorn = { version = "==0.34.0", extras = ["standard"] } uvicorn = { version = "==0.34.0", extras = ["standard"] }
# Libs # Libs
@ -72,7 +72,7 @@ backports-zoneinfo = { version = "==0.2.1", python = "<3.9" }
bleach = "==6.2.0" bleach = "==6.2.0"
boto3 = "==1.35.99" boto3 = "==1.35.99"
click = "==8.1.8" click = "==8.1.8"
cryptography = "==41.0.7" cryptography = "==44.0.0"
defusedxml = "0.7.1" defusedxml = "0.7.1"
feedparser = "==6.0.11" feedparser = "==6.0.11"
python-ffmpeg = "==2.0.12" python-ffmpeg = "==2.0.12"
@ -84,12 +84,12 @@ pyld = "==2.0.4"
python-magic = "==0.4.27" python-magic = "==0.4.27"
requests = "==2.32.3" requests = "==2.32.3"
requests-http-message-signatures = "==0.3.1" requests-http-message-signatures = "==0.3.1"
sentry-sdk = "==1.45.1" sentry-sdk = "==2.20.0"
watchdog = "==4.0.2" watchdog = "==6.0.0"
troi = "==2024.12.4.0" troi = "==2025.1.10.0"
lb-matching-tools = "==2024.1.30.1" lb-matching-tools = "==2024.1.30.1"
unidecode = "==1.3.8" unidecode = "==1.3.8"
pycountry = "23.12.11" pycountry = "24.6.1"
# Typesense # Typesense
typesense = { version = "==0.21.0", optional = true } typesense = { version = "==0.21.0", optional = true }
@ -107,15 +107,15 @@ black = "==24.10.0"
coverage = { version = "==7.6.10", extras = ["toml"] } coverage = { version = "==7.6.10", extras = ["toml"] }
debugpy = "==1.8.11" debugpy = "==1.8.11"
django-coverage-plugin = "==3.1.0" django-coverage-plugin = "==3.1.0"
django-debug-toolbar = "==4.4.6" django-debug-toolbar = "==5.0.1"
factory-boy = "==3.3.1" factory-boy = "==3.3.1"
faker = "==23.3.0" faker = "==33.3.1"
flake8 = "==3.9.2" flake8 = "==7.1.1"
ipdb = "==0.13.13" ipdb = "==0.13.13"
pytest = "==8.3.4" pytest = "==8.3.4"
pytest-asyncio = "==0.25.2" pytest-asyncio = "==0.25.2"
prompt-toolkit = "==3.0.48" prompt-toolkit = "==3.0.48"
pytest-cov = "==4.1.0" pytest-cov = "==6.0.0"
pytest-django = "==4.9.0" pytest-django = "==4.9.0"
pytest-env = "==1.1.5" pytest-env = "==1.1.5"
pytest-mock = "==3.14.0" pytest-mock = "==3.14.0"

View File

@ -1,115 +1,115 @@
import pytest import pytest
from click.testing import CliRunner from click.testing import CliRunner
from funkwhale_api.cli import library, main from funkwhale_api.cli import library, main, users
@pytest.mark.parametrize( @pytest.mark.parametrize(
"cmd, args, handlers", "cmd, args, handlers",
[ [
# ( (
# ("users", "create"), ("users", "create"),
# ( (
# "--username", "--username",
# "testuser", "testuser",
# "--password", "--password",
# "testpassword", "testpassword",
# "--email", "--email",
# "test@hello.com", "test@hello.com",
# "--upload-quota", "--upload-quota",
# "35", "35",
# "--permission", "--permission",
# "library", "library",
# "--permission", "--permission",
# "moderation", "moderation",
# "--staff", "--staff",
# "--superuser", "--superuser",
# ), ),
# [ [
# ( (
# users, users,
# "handler_create_user", "handler_create_user",
# { {
# "username": "testuser", "username": "testuser",
# "password": "testpassword", "password": "testpassword",
# "email": "test@hello.com", "email": "test@hello.com",
# "upload_quota": 35, "upload_quota": 35,
# "permissions": ("library", "moderation"), "permissions": ("library", "moderation"),
# "is_staff": True, "is_staff": True,
# "is_superuser": True, "is_superuser": True,
# }, },
# ) )
# ], ],
# ), ),
# ( (
# ("users", "rm"), ("users", "rm"),
# ("testuser1", "testuser2", "--no-input"), ("testuser1", "testuser2", "--no-input"),
# [ [
# ( (
# users, users,
# "handler_delete_user", "handler_delete_user",
# {"usernames": ("testuser1", "testuser2"), "soft": True}, {"usernames": ("testuser1", "testuser2"), "soft": True},
# ) )
# ], ],
# ), ),
# ( (
# ("users", "rm"), ("users", "rm"),
# ( (
# "testuser1", "testuser1",
# "testuser2", "testuser2",
# "--no-input", "--no-input",
# "--hard", "--hard",
# ), ),
# [ [
# ( (
# users, users,
# "handler_delete_user", "handler_delete_user",
# {"usernames": ("testuser1", "testuser2"), "soft": False}, {"usernames": ("testuser1", "testuser2"), "soft": False},
# ) )
# ], ],
# ), ),
# ( (
# ("users", "set"), ("users", "set"),
# ( (
# "testuser1", "testuser1",
# "testuser2", "testuser2",
# "--no-input", "--no-input",
# "--inactive", "--inactive",
# "--upload-quota", "--upload-quota",
# "35", "35",
# "--no-staff", "--no-staff",
# "--superuser", "--superuser",
# "--permission-library", "--permission-library",
# "--no-permission-moderation", "--no-permission-moderation",
# "--no-permission-settings", "--no-permission-settings",
# "--password", "--password",
# "newpassword", "newpassword",
# ), ),
# [ [
# ( (
# users, users,
# "handler_update_user", "handler_update_user",
# { {
# "usernames": ("testuser1", "testuser2"), "usernames": ("testuser1", "testuser2"),
# "kwargs": { "kwargs": {
# "is_active": False, "is_active": False,
# "upload_quota": 35, "upload_quota": 35,
# "is_staff": False, "is_staff": False,
# "is_superuser": True, "is_superuser": True,
# "permission_library": True, "permission_library": True,
# "permission_moderation": False, "permission_moderation": False,
# "permission_settings": False, "permission_settings": False,
# "password": "newpassword", "password": "newpassword",
# }, },
# }, },
# ) )
# ], ],
# ), ),
# ( (
# ("albums", "add-tags-from-tracks"), ("albums", "add-tags-from-tracks"),
# tuple(), tuple(),
# [(library, "handler_add_tags_from_tracks", {"albums": True})], [(library, "handler_add_tags_from_tracks", {"albums": True})],
# ), ),
( (
("artists", "add-tags-from-tracks"), ("artists", "add-tags-from-tracks"),
tuple(), tuple(),

View File

@ -391,7 +391,7 @@ def migrator(transactional_db):
@pytest.fixture(autouse=True) @pytest.fixture(autouse=True)
def rsa_small_key(settings): def rsa_small_key(settings):
# smaller size for faster generation, since it's CPU hungry # smaller size for faster generation, since it's CPU hungry
settings.RSA_KEY_SIZE = 512 settings.RSA_KEY_SIZE = 1024
@pytest.fixture(autouse=True) @pytest.fixture(autouse=True)

View File

@ -4,7 +4,6 @@ import logging
import liblistenbrainz import liblistenbrainz
import pytest import pytest
from django.urls import reverse from django.urls import reverse
from django.utils import timezone
from config import plugins from config import plugins
from funkwhale_api.contrib.listenbrainz import funkwhale_ready from funkwhale_api.contrib.listenbrainz import funkwhale_ready
@ -52,7 +51,8 @@ def test_sync_listenings_from_listenbrainz(factories, mocker, caplog):
factories["music.Track"](mbid="f89db7f8-4a1f-4228-a0a1-e7ba028b7476") factories["music.Track"](mbid="f89db7f8-4a1f-4228-a0a1-e7ba028b7476")
track = factories["music.Track"](mbid="54c60860-f43d-484e-b691-7ab7ec8de559") track = factories["music.Track"](mbid="54c60860-f43d-484e-b691-7ab7ec8de559")
factories["history.Listening"]( factories["history.Listening"](
creation_date=datetime.datetime.fromtimestamp(1871, timezone.utc), track=track creation_date=datetime.datetime.fromtimestamp(1871, datetime.timezone.utc),
track=track,
) )
conf = { conf = {

View File

@ -19,7 +19,7 @@ def test_upload_import_status_updated_broadcast(factories, mocker):
upload = factories["music.Upload"]( upload = factories["music.Upload"](
import_status="finished", library__actor__user=user import_status="finished", library__actor__user=user
) )
signals.upload_import_status_updated.send( signals.upload_import_status_updated.send_robust(
sender=None, upload=upload, old_status="pending", new_status="finished" sender=None, upload=upload, old_status="pending", new_status="finished"
) )
group_send.assert_called_once_with( group_send.assert_called_once_with(

View File

@ -1460,7 +1460,7 @@ def test_tag_albums_from_tracks(queryset_equal_queries, factories, mocker):
get_tags_from_foreign_key.assert_called_once_with( get_tags_from_foreign_key.assert_called_once_with(
ids=expected_queryset.filter(pk__in=[1, 2]), ids=expected_queryset.filter(pk__in=[1, 2]),
foreign_key_model=models.Track, foreign_key_model=models.Track,
foreign_key_attr="album", foreign_key_attr="albums",
) )
add_tags_batch.assert_called_once_with( add_tags_batch.assert_called_once_with(

View File

@ -646,12 +646,11 @@ def test_search3(f, db, logged_in_api_client, factories):
@pytest.mark.parametrize("f", ["json"]) @pytest.mark.parametrize("f", ["json"])
def test_get_playlists(f, db, logged_in_api_client, factories): def test_get_playlists(f, db, logged_in_api_client, factories):
logged_in_api_client.user.create_actor()
url = reverse("api:subsonic:subsonic-get_playlists") url = reverse("api:subsonic:subsonic-get_playlists")
assert url.endswith("getPlaylists") is True assert url.endswith("getPlaylists") is True
playlist1 = factories["playlists.PlaylistTrack"]( playlist1 = factories["playlists.PlaylistTrack"](
playlist__actor__user=logged_in_api_client.user playlist__actor=logged_in_api_client.user.create_actor()
).playlist ).playlist
playlist2 = factories["playlists.PlaylistTrack"]( playlist2 = factories["playlists.PlaylistTrack"](
playlist__privacy_level="everyone" playlist__privacy_level="everyone"
@ -664,7 +663,6 @@ def test_get_playlists(f, db, logged_in_api_client, factories):
# no track # no track
playlist4 = factories["playlists.Playlist"](privacy_level="everyone") playlist4 = factories["playlists.Playlist"](privacy_level="everyone")
factories["users.User"](actor=playlist1.actor)
factories["users.User"](actor=playlist2.actor) factories["users.User"](actor=playlist2.actor)
factories["users.User"](actor=playlist3.actor) factories["users.User"](actor=playlist3.actor)
factories["users.User"](actor=playlist4.actor) factories["users.User"](actor=playlist4.actor)
@ -692,7 +690,6 @@ def test_get_playlist(f, db, logged_in_api_client, factories):
playlist = factories["playlists.PlaylistTrack"]( playlist = factories["playlists.PlaylistTrack"](
playlist__actor__user=logged_in_api_client.user playlist__actor__user=logged_in_api_client.user
).playlist ).playlist
factories["users.User"](actor=playlist.actor)
response = logged_in_api_client.get(url, {"f": f, "id": playlist.pk}) response = logged_in_api_client.get(url, {"f": f, "id": playlist.pk})

View File

@ -3,8 +3,8 @@ from funkwhale_api.tags import models, tasks
def test_get_tags_from_foreign_key(factories): def test_get_tags_from_foreign_key(factories):
rock_tag = factories["tags.Tag"](name="Rock") rock_tag = factories["tags.Tag"](name="rock")
rap_tag = factories["tags.Tag"](name="Rap") rap_tag = factories["tags.Tag"](name="rap")
artist = factories["music.Artist"]() artist = factories["music.Artist"]()
factories["music.Track"].create_batch( factories["music.Track"].create_batch(
3, artist_credit__artist=artist, set_tags=["rock", "rap"] 3, artist_credit__artist=artist, set_tags=["rock", "rap"]