diff --git a/engine/blog/admin.py b/engine/blog/admin.py index 54e427b3..0c44db09 100644 --- a/engine/blog/admin.py +++ b/engine/blog/admin.py @@ -1,6 +1,8 @@ from django.contrib.admin import register from django.db.models import TextField -from django_summernote.admin import SummernoteModelAdminMixin +from django_summernote.admin import ( + SummernoteModelAdminMixin, +) from unfold.admin import ModelAdmin from unfold_markdown import MarkdownWidget @@ -11,7 +13,7 @@ from engine.core.admin import ActivationActionsMixin, FieldsetsMixin @register(Post) class PostAdmin( SummernoteModelAdminMixin, FieldsetsMixin, ActivationActionsMixin, ModelAdmin -): # type: ignore [misc, type-arg] +): list_display = ("title", "author", "slug", "created", "modified") list_filter = ("author", "tags", "created", "modified") search_fields = ("title", "content", "slug") @@ -40,7 +42,7 @@ class PostAdmin( @register(PostTag) -class PostTagAdmin(ModelAdmin): # type: ignore [type-arg] +class PostTagAdmin(ModelAdmin): list_display = ("tag_name", "name") search_fields = ("tag_name", "name") ordering = ("tag_name",) diff --git a/engine/blog/apps.py b/engine/blog/apps.py index 500c1bdd..87fa6ba2 100644 --- a/engine/blog/apps.py +++ b/engine/blog/apps.py @@ -9,5 +9,5 @@ class BlogConfig(AppConfig): # noinspection PyUnresolvedReferences def ready(self) -> None: - import engine.blog.elasticsearch.documents + import engine.blog.elasticsearch.documents # noqa: F401 import engine.blog.signals # noqa: F401 diff --git a/engine/blog/elasticsearch/documents.py b/engine/blog/elasticsearch/documents.py index 779c644a..122b7bad 100644 --- a/engine/blog/elasticsearch/documents.py +++ b/engine/blog/elasticsearch/documents.py @@ -10,7 +10,7 @@ from engine.core.elasticsearch import ( from engine.core.elasticsearch.documents import BaseDocument -class PostDocument(ActiveOnlyMixin, BaseDocument): # type: ignore [misc] +class PostDocument(ActiveOnlyMixin, BaseDocument): title = fields.TextField( attr="title", analyzer="standard", diff --git a/engine/blog/filters.py b/engine/blog/filters.py index fd6f1db3..0b8fc327 100644 --- a/engine/blog/filters.py +++ b/engine/blog/filters.py @@ -4,7 +4,7 @@ from engine.blog.models import Post from engine.core.filters import CaseInsensitiveListFilter -class PostFilter(FilterSet): # type: ignore [misc] +class PostFilter(FilterSet): uuid = UUIDFilter(field_name="uuid", lookup_expr="exact") slug = CharFilter(field_name="slug", lookup_expr="exact") author = UUIDFilter(field_name="author__uuid", lookup_expr="exact") diff --git a/engine/blog/models.py b/engine/blog/models.py index 7c9658de..e187f866 100644 --- a/engine/blog/models.py +++ b/engine/blog/models.py @@ -15,8 +15,8 @@ from markdown_field import MarkdownField from engine.core.abstract import NiceModel -class Post(NiceModel): # type: ignore [django-manager-missing] - __doc__ = _( # type: ignore [assignment] +class Post(NiceModel): + __doc__ = _( "Represents a blog post model. " "The Post class defines the structure and behavior of a blog post. " "It includes attributes for author, title, content, optional file attachment, slug, and associated tags. " diff --git a/engine/blog/viewsets.py b/engine/blog/viewsets.py index 0ca86f77..a617ec96 100644 --- a/engine/blog/viewsets.py +++ b/engine/blog/viewsets.py @@ -11,8 +11,8 @@ from engine.core.permissions import EvibesPermission @extend_schema_view(**POST_SCHEMA) -class PostViewSet(ReadOnlyModelViewSet): # type: ignore [type-arg] - __doc__ = _( # type: ignore [assignment] +class PostViewSet(ReadOnlyModelViewSet): + __doc__ = _( "Encapsulates operations for managing and retrieving Post entities in a read-only model view set. " "This class is tailored to handle Post objects that are active and allows filtration based on defined " "filters. It integrates with Django's backend filtering system and ensures operations align with the " diff --git a/engine/core/abstract.py b/engine/core/abstract.py index 9f7cf6c4..40851d7d 100644 --- a/engine/core/abstract.py +++ b/engine/core/abstract.py @@ -24,12 +24,12 @@ class NiceModel(Model): ) created = CreationDateTimeField( _("created"), help_text=_("when the object first appeared on the database") - ) # type: ignore [no-untyped-call] + ) modified = ModificationDateTimeField( _("modified"), help_text=_("when the object was last modified") - ) # type: ignore [no-untyped-call] + ) - def save( # type: ignore [override] + def save( self, *, force_insert: bool = False, diff --git a/engine/core/admin.py b/engine/core/admin.py index a4a1a2e9..f9afb886 100644 --- a/engine/core/admin.py +++ b/engine/core/admin.py @@ -31,6 +31,7 @@ from mptt.admin import DraggableMPTTAdmin from unfold.admin import ModelAdmin, TabularInline from unfold.contrib.import_export.forms import ExportForm, ImportForm from unfold.decorators import action +from unfold.typing import FieldsetsType from unfold.widgets import UnfoldAdminSelectWidget, UnfoldAdminTextInputWidget from engine.core.forms import ( @@ -70,9 +71,7 @@ class FieldsetsMixin: additional_fields: list[str] | None = [] model: ClassVar[Type[Model]] - def get_fieldsets( - self, request: HttpRequest, obj: Any = None - ) -> list[tuple[str, dict[str, list[str]]]]: + def get_fieldsets(self, request: HttpRequest, obj: Any = None) -> FieldsetsType: if request: pass @@ -82,8 +81,8 @@ class FieldsetsMixin: fieldsets = [] def add_translations_fieldset( - fss: list[tuple[str, dict[str, list[str]]]], - ) -> list[tuple[str, dict[str, list[str]]]]: + fss: FieldsetsType, + ) -> FieldsetsType: with suppress(NotRegistered): transoptions = translator.get_options_for_model(self.model) translation_fields = [] @@ -95,7 +94,7 @@ class FieldsetsMixin: _("translations"), {"classes": ["tab"], "fields": translation_fields}, ) - ] # type: ignore [list-item] + ] return fss if self.general_fields: @@ -140,8 +139,8 @@ class FieldsetsMixin: ts.append(name) if ts: fieldsets.append((_("timestamps"), {"classes": ["tab"], "fields": ts})) - fieldsets = add_translations_fieldset(fieldsets) # type: ignore [arg-type, assignment] - return fieldsets # type: ignore [return-value] + fieldsets = add_translations_fieldset(fieldsets) + return fieldsets # noinspection PyUnresolvedReferences @@ -161,14 +160,14 @@ class ActivationActionsMixin: def activate_selected(self, request: HttpRequest, queryset: QuerySet[Any]) -> None: try: queryset.update(is_active=True) - self.message_user( # type: ignore [attr-defined] + self.message_user( request=request, message=_("selected items have been activated.").lower(), level=messages.SUCCESS, ) except Exception as e: - self.message_user(request=request, message=str(e), level=messages.ERROR) # type: ignore [attr-defined] + self.message_user(request=request, message=str(e), level=messages.ERROR) @action( description=_("deactivate selected %(verbose_name_plural)s").lower(), @@ -179,17 +178,17 @@ class ActivationActionsMixin: ) -> None: try: queryset.update(is_active=False) - self.message_user( # type: ignore [attr-defined] + self.message_user( request=request, message=_("selected items have been deactivated.").lower(), level=messages.SUCCESS, ) except Exception as e: - self.message_user(request=request, message=str(e), level=messages.ERROR) # type: ignore [attr-defined] + self.message_user(request=request, message=str(e), level=messages.ERROR) -class AttributeValueInline(TabularInline): # type: ignore [type-arg] +class AttributeValueInline(TabularInline): model = AttributeValue extra = 0 autocomplete_fields = ["attribute"] @@ -201,7 +200,7 @@ class AttributeValueInline(TabularInline): # type: ignore [type-arg] return super().get_queryset(request).select_related("attribute", "product") -class ProductImageInline(TabularInline): # type: ignore [type-arg] +class ProductImageInline(TabularInline): model = ProductImage extra = 0 tab = True @@ -212,7 +211,7 @@ class ProductImageInline(TabularInline): # type: ignore [type-arg] return super().get_queryset(request).select_related("product") -class StockInline(TabularInline): # type: ignore [type-arg] +class StockInline(TabularInline): model = Stock extra = 0 form = StockForm @@ -224,7 +223,7 @@ class StockInline(TabularInline): # type: ignore [type-arg] return super().get_queryset(request).select_related("vendor", "product") -class OrderProductInline(TabularInline): # type: ignore [type-arg] +class OrderProductInline(TabularInline): model = OrderProduct extra = 0 readonly_fields = ("product", "quantity", "buy_price") @@ -242,7 +241,7 @@ class OrderProductInline(TabularInline): # type: ignore [type-arg] ) -class CategoryChildrenInline(TabularInline): # type: ignore [type-arg] +class CategoryChildrenInline(TabularInline): model = Category fk_name = "parent" extra = 0 @@ -255,9 +254,9 @@ class CategoryChildrenInline(TabularInline): # type: ignore [type-arg] @register(AttributeGroup) class AttributeGroupAdmin( DjangoQLSearchMixin, FieldsetsMixin, ActivationActionsMixin, ModelAdmin -): # type: ignore [misc, type-arg] +): # noinspection PyClassVar - model = AttributeGroup # type: ignore [misc] + model = AttributeGroup list_display = ( "name", "modified", @@ -281,9 +280,9 @@ class AttributeGroupAdmin( @register(Attribute) class AttributeAdmin( DjangoQLSearchMixin, FieldsetsMixin, ActivationActionsMixin, ModelAdmin -): # type: ignore [misc, type-arg] +): # noinspection PyClassVar - model = Attribute # type: ignore [misc] + model = Attribute list_display = ( "name", "group", @@ -320,9 +319,9 @@ class AttributeAdmin( @register(AttributeValue) -class AttributeValueAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): # type: ignore [misc, type-arg] +class AttributeValueAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): # noinspection PyClassVar - model = AttributeValue # type: ignore [misc] + model = AttributeValue list_display = ( "attribute", "value", @@ -413,9 +412,9 @@ class CategoryAdmin( @register(Brand) class BrandAdmin( DjangoQLSearchMixin, FieldsetsMixin, ActivationActionsMixin, ModelAdmin -): # type: ignore [misc, type-arg] +): # noinspection PyClassVar - model = Brand # type: ignore [misc] + model = Brand list_display = ( "name", "priority", @@ -451,9 +450,9 @@ class ProductAdmin( ActivationActionsMixin, ModelAdmin, ImportExportModelAdmin, -): # type: ignore [misc, type-arg] +): # noinspection PyClassVar - model = Product # type: ignore [misc] + model = Product list_display = ( "sku", "name", @@ -532,9 +531,9 @@ class ProductAdmin( @register(ProductTag) class ProductTagAdmin( DjangoQLSearchMixin, FieldsetsMixin, ActivationActionsMixin, ModelAdmin -): # type: ignore [misc, type-arg] +): # noinspection PyClassVar - model = ProductTag # type: ignore [misc] + model = ProductTag list_display = ("tag_name",) search_fields = ("tag_name",) readonly_fields = ( @@ -552,9 +551,9 @@ class ProductTagAdmin( @register(CategoryTag) class CategoryTagAdmin( DjangoQLSearchMixin, FieldsetsMixin, ActivationActionsMixin, ModelAdmin -): # type: ignore [misc, type-arg] +): # noinspection PyClassVar - model = CategoryTag # type: ignore [misc] + model = CategoryTag list_display = ( "name", "tag_name", @@ -580,9 +579,9 @@ class CategoryTagAdmin( @register(Vendor) class VendorAdmin( DjangoQLSearchMixin, FieldsetsMixin, ActivationActionsMixin, ModelAdmin -): # type: ignore [misc, type-arg] +): # noinspection PyClassVar - model = Vendor # type: ignore [misc] + model = Vendor list_display = ( "name", "markup_percent", @@ -622,9 +621,9 @@ class VendorAdmin( @register(Feedback) class FeedbackAdmin( DjangoQLSearchMixin, FieldsetsMixin, ActivationActionsMixin, ModelAdmin -): # type: ignore [misc, type-arg] +): # noinspection PyClassVar - model = Feedback # type: ignore [misc] + model = Feedback list_display = ( "order_product", "rating", @@ -657,9 +656,9 @@ class FeedbackAdmin( @register(Order) class OrderAdmin( DjangoQLSearchMixin, FieldsetsMixin, ActivationActionsMixin, ModelAdmin -): # type: ignore [misc, type-arg] +): # noinspection PyClassVar - model = Order # type: ignore [misc] + model = Order list_display = ( "human_readable_id", "user", @@ -710,9 +709,9 @@ class OrderAdmin( @register(OrderProduct) class OrderProductAdmin( DjangoQLSearchMixin, FieldsetsMixin, ActivationActionsMixin, ModelAdmin -): # type: ignore [misc, type-arg] +): # noinspection PyClassVar - model = OrderProduct # type: ignore [misc] + model = OrderProduct list_display = ( "order", "product", @@ -750,9 +749,9 @@ class OrderProductAdmin( @register(PromoCode) class PromoCodeAdmin( DjangoQLSearchMixin, FieldsetsMixin, ActivationActionsMixin, ModelAdmin -): # type: ignore [misc, type-arg] +): # noinspection PyClassVar - model = PromoCode # type: ignore [misc] + model = PromoCode list_display = ( "code", "discount_percent", @@ -796,9 +795,9 @@ class PromoCodeAdmin( @register(Promotion) class PromotionAdmin( DjangoQLSearchMixin, FieldsetsMixin, ActivationActionsMixin, ModelAdmin -): # type: ignore [misc, type-arg] +): # noinspection PyClassVar - model = Promotion # type: ignore [misc] + model = Promotion list_display = ( "name", "discount_percent", @@ -825,9 +824,9 @@ class PromotionAdmin( @register(Stock) class StockAdmin( DjangoQLSearchMixin, FieldsetsMixin, ActivationActionsMixin, ModelAdmin -): # type: ignore [misc, type-arg] +): # noinspection PyClassVar - model = Stock # type: ignore [misc] + model = Stock form = StockForm list_display = ( "product", @@ -875,9 +874,9 @@ class StockAdmin( @register(Wishlist) class WishlistAdmin( DjangoQLSearchMixin, FieldsetsMixin, ActivationActionsMixin, ModelAdmin -): # type: ignore [misc, type-arg] +): # noinspection PyClassVar - model = Wishlist # type: ignore [misc] + model = Wishlist list_display = ( "user", "modified", @@ -903,9 +902,9 @@ class WishlistAdmin( @register(ProductImage) class ProductImageAdmin( DjangoQLSearchMixin, FieldsetsMixin, ActivationActionsMixin, ModelAdmin -): # type: ignore [misc, type-arg] +): # noinspection PyClassVar - model = ProductImage # type: ignore [misc] + model = ProductImage list_display = ( "alt", "product", @@ -939,9 +938,9 @@ class ProductImageAdmin( @register(Address) -class AddressAdmin(DjangoQLSearchMixin, FieldsetsMixin, GISModelAdmin): # type: ignore [misc] +class AddressAdmin(DjangoQLSearchMixin, FieldsetsMixin, GISModelAdmin): # noinspection PyClassVar - model = Address # type: ignore [misc] + model = Address list_display = ( "street", "city", @@ -991,9 +990,9 @@ class AddressAdmin(DjangoQLSearchMixin, FieldsetsMixin, GISModelAdmin): # type: @register(CustomerRelationshipManagementProvider) class CustomerRelationshipManagementProviderAdmin( DjangoQLSearchMixin, FieldsetsMixin, ModelAdmin -): # type: ignore [misc, type-arg] +): # noinspection PyClassVar - model = CustomerRelationshipManagementProvider # type: ignore [misc] + model = CustomerRelationshipManagementProvider list_display = ( "name", "default", @@ -1020,9 +1019,9 @@ class CustomerRelationshipManagementProviderAdmin( @register(OrderCrmLink) -class OrderCrmLinkAdmin(DjangoQLSearchMixin, FieldsetsMixin, ModelAdmin): # type: ignore [misc, type-arg] +class OrderCrmLinkAdmin(DjangoQLSearchMixin, FieldsetsMixin, ModelAdmin): # noinspection PyClassVar - model = OrderCrmLink # type: ignore [misc] + model = OrderCrmLink list_display = ( "crm_lead_id", "order", @@ -1086,7 +1085,7 @@ class ConstanceConfig: # noinspection PyTypeChecker site.unregister([Config]) # noinspection PyTypeChecker -site.register([ConstanceConfig], BaseConstanceAdmin) # type: ignore [list-item] +site.register([ConstanceConfig], BaseConstanceAdmin) site.site_title = settings.PROJECT_NAME site.site_header = "eVibes" site.index_title = settings.PROJECT_NAME diff --git a/engine/core/elasticsearch/__init__.py b/engine/core/elasticsearch/__init__.py index 7756e3ae..185ec46b 100644 --- a/engine/core/elasticsearch/__init__.py +++ b/engine/core/elasticsearch/__init__.py @@ -434,9 +434,9 @@ def _lang_analyzer(lang_code: str) -> str: class ActiveOnlyMixin: def get_queryset(self) -> QuerySet[Any]: - return super().get_queryset().filter(is_active=True) # type: ignore [no-any-return, misc] + return super().get_queryset().filter(is_active=True) - def should_index_object(self, obj) -> bool: # type: ignore [no-untyped-def] + def should_index_object(self, obj) -> bool: return getattr(obj, "is_active", False) diff --git a/engine/core/elasticsearch/documents.py b/engine/core/elasticsearch/documents.py index f741f8c7..cf7f05b5 100644 --- a/engine/core/elasticsearch/documents.py +++ b/engine/core/elasticsearch/documents.py @@ -13,7 +13,7 @@ from engine.core.elasticsearch import ( from engine.core.models import Brand, Category, Product -class BaseDocument(Document): # type: ignore [misc] +class BaseDocument(Document): name = fields.TextField( attr="name", analyzer="standard", @@ -197,7 +197,7 @@ add_multilang_fields(BrandDocument) registry.register_document(BrandDocument) -class TestModelDocument(Document): # type: ignore [misc] +class TestModelDocument(Document): class Index: name = "testmodels" diff --git a/engine/core/filters.py b/engine/core/filters.py index cd27fcf0..70fa2ef1 100644 --- a/engine/core/filters.py +++ b/engine/core/filters.py @@ -51,7 +51,7 @@ from engine.core.models import ( logger = logging.getLogger(__name__) -class CaseInsensitiveListFilter(BaseInFilter, CharFilter): # type: ignore [misc] +class CaseInsensitiveListFilter(BaseInFilter, CharFilter): def filter(self, qs: QuerySet[Any], value: Any) -> QuerySet[Any]: if not value: return qs @@ -74,7 +74,7 @@ class CaseInsensitiveListFilter(BaseInFilter, CharFilter): # type: ignore [misc # noinspection PyUnusedLocal -class ProductFilter(FilterSet): # type: ignore [misc] +class ProductFilter(FilterSet): search = CharFilter(field_name="name", method="search_products", label=_("Search")) uuid = UUIDFilter(field_name="uuid", lookup_expr="exact", label=_("UUID")) name = CharFilter(lookup_expr="icontains", label=_("Name")) @@ -188,7 +188,7 @@ class ProductFilter(FilterSet): # type: ignore [misc] if not value: return queryset - es_products = process_query(query=value, indexes=("products",)) # type: ignore + es_products = process_query(query=value, indexes=("products",)) uuids = [p.get("uuid") for p in (es_products or {}).get("products", [])][:33] if not uuids: return queryset.none() @@ -392,7 +392,7 @@ class ProductFilter(FilterSet): # type: ignore [misc] # noinspection PyUnusedLocal -class OrderFilter(FilterSet): # type: ignore [misc] +class OrderFilter(FilterSet): search = CharFilter( method="filter_search", label=_("Search (ID, product name or part number)"), @@ -455,7 +455,7 @@ class OrderFilter(FilterSet): # type: ignore [misc] ).distinct() -class WishlistFilter(FilterSet): # type: ignore [misc] +class WishlistFilter(FilterSet): uuid = UUIDFilter(field_name="uuid", lookup_expr="exact") user_email = CharFilter( field_name="user__email", lookup_expr="iexact", label=_("User email") @@ -479,7 +479,7 @@ class WishlistFilter(FilterSet): # type: ignore [misc] # noinspection PyUnusedLocal -class CategoryFilter(FilterSet): # type: ignore [misc] +class CategoryFilter(FilterSet): search = CharFilter( field_name="name", method="search_categories", label=_("Search") ) @@ -521,7 +521,7 @@ class CategoryFilter(FilterSet): # type: ignore [misc] for category in process_query(query=value, indexes=("categories",))[ "categories" ] - ] # type: ignore + ] return queryset.filter(uuid__in=uuids) @@ -621,7 +621,7 @@ class CategoryFilter(FilterSet): # type: ignore [misc] # noinspection PyUnusedLocal -class BrandFilter(FilterSet): # type: ignore [misc] +class BrandFilter(FilterSet): search = CharFilter(field_name="name", method="search_brands", label=_("Search")) uuid = UUIDFilter(field_name="uuid", lookup_expr="exact") name = CharFilter(lookup_expr="icontains", label=_("Name")) @@ -653,12 +653,12 @@ class BrandFilter(FilterSet): # type: ignore [misc] uuids = [ brand.get("uuid") for brand in process_query(query=value, indexes=("brands",))["brands"] - ] # type: ignore + ] return queryset.filter(uuid__in=uuids) -class FeedbackFilter(FilterSet): # type: ignore [misc] +class FeedbackFilter(FilterSet): uuid = UUIDFilter(field_name="uuid", lookup_expr="exact", label=_("UUID")) product_uuid = UUIDFilter( field_name="order_product__product__uuid", @@ -687,7 +687,7 @@ class FeedbackFilter(FilterSet): # type: ignore [misc] fields = ["uuid", "product_uuid", "user_uuid", "order_by"] -class AddressFilter(FilterSet): # type: ignore [misc] +class AddressFilter(FilterSet): uuid = UUIDFilter(field_name="uuid", lookup_expr="exact", label=_("UUID")) user_uuid = UUIDFilter( field_name="user__uuid", lookup_expr="exact", label=_("User UUID") diff --git a/engine/core/graphene/__init__.py b/engine/core/graphene/__init__.py index 382eefd7..c461af03 100644 --- a/engine/core/graphene/__init__.py +++ b/engine/core/graphene/__init__.py @@ -3,7 +3,7 @@ from typing import Any from graphene import Mutation -class BaseMutation(Mutation): # type: ignore [misc] +class BaseMutation(Mutation): def __init__(self, *args: list[Any], **kwargs: dict[Any, Any]) -> None: super().__init__(*args, **kwargs) diff --git a/engine/core/graphene/dashboard_mutations/product.py b/engine/core/graphene/dashboard_mutations/product.py index 0bbc97af..747158dc 100644 --- a/engine/core/graphene/dashboard_mutations/product.py +++ b/engine/core/graphene/dashboard_mutations/product.py @@ -53,7 +53,7 @@ def resolve_tags(product, tag_uuids): product.tags.set(tags) -class AttributeInput(InputObjectType): # type: ignore[misc] +class AttributeInput(InputObjectType): attribute_uuid = UUID(required=False, name="attributeUuid") group_name = String(required=False, name="groupName") attribute_name = String(required=False, name="attributeName") @@ -61,7 +61,7 @@ class AttributeInput(InputObjectType): # type: ignore[misc] value = String(required=True) -class ProductInput(InputObjectType): # type: ignore[misc] +class ProductInput(InputObjectType): name = NonNull(String) description = String(required=False) is_digital = Boolean(required=False, name="isDigital") @@ -85,15 +85,15 @@ class CreateProduct(BaseMutation): product = Field(ProductType) @staticmethod - def mutate(parent, info, product_data): # type: ignore [override] + def mutate(parent, info, product_data): user = info.context.user if not user.has_perm("core.add_product"): raise PermissionDenied(permission_denied_message) - category = Category.objects.get(uuid=product_data["category_uuid"]) # type: ignore[index] + category = Category.objects.get(uuid=product_data["category_uuid"]) brand = None if product_data.get("brand_uuid"): - with suppress(Brand.DoesNotExist): # type: ignore[name-defined] - brand = Brand.objects.get(uuid=product_data["brand_uuid"]) # type: ignore[index] + with suppress(Brand.DoesNotExist): + brand = Brand.objects.get(uuid=product_data["brand_uuid"]) product = Product.objects.create( name=product_data["name"], @@ -124,7 +124,7 @@ class UpdateProduct(BaseMutation): product = Field(ProductType) @staticmethod - def mutate(parent, info, product_uuid, product_data): # type: ignore [override] + def mutate(parent, info, product_uuid, product_data): user = info.context.user if not user.has_perm("core.change_product"): raise PermissionDenied(permission_denied_message) @@ -142,10 +142,10 @@ class UpdateProduct(BaseMutation): updates[model_field] = product_data[field_in] if product_data.get("category_uuid"): - product.category = Category.objects.get(uuid=product_data["category_uuid"]) # type: ignore[index] + product.category = Category.objects.get(uuid=product_data["category_uuid"]) if product_data.get("brand_uuid") is not None: if product_data.get("brand_uuid"): - product.brand = Brand.objects.get(uuid=product_data["brand_uuid"]) # type: ignore[index] + product.brand = Brand.objects.get(uuid=product_data["brand_uuid"]) else: product.brand = None @@ -171,7 +171,7 @@ class DeleteProduct(BaseMutation): ok = Boolean() @staticmethod - def mutate(parent, info, product_uuid): # type: ignore [override] + def mutate(parent, info, product_uuid): user = info.context.user if not user.has_perm("core.delete_product"): raise PermissionDenied(permission_denied_message) diff --git a/engine/core/graphene/mutations.py b/engine/core/graphene/mutations.py index e0d9fde4..4f1dd3a1 100644 --- a/engine/core/graphene/mutations.py +++ b/engine/core/graphene/mutations.py @@ -49,7 +49,7 @@ class CacheOperator(BaseMutation): data = GenericScalar(description=_("cached data")) @staticmethod - def mutate(parent, info, key, data=None, timeout=None) -> dict[Any, Any]: # type: ignore [override] + def mutate(parent, info, key, data=None, timeout=None) -> dict[Any, Any]: return camelize(web_cache(info.context, key, data, timeout)) @@ -64,7 +64,7 @@ class RequestCursedURL(BaseMutation): data = GenericScalar(description=_("camelized JSON data from the requested URL")) @staticmethod - def mutate(parent, info, url) -> dict[str, Any]: # type: ignore [override] + def mutate(parent, info, url) -> dict[str, Any]: if not is_url_safe(url): raise BadRequest(_("only URLs starting with http(s):// are allowed")) try: @@ -94,7 +94,7 @@ class AddOrderProduct(BaseMutation): order = Field(OrderType) @staticmethod - def mutate(parent, info, product_uuid, order_uuid, attributes=None): # type: ignore [override] + def mutate(parent, info, product_uuid, order_uuid, attributes=None): user = info.context.user try: order = Order.objects.get(uuid=order_uuid) @@ -123,7 +123,7 @@ class RemoveOrderProduct(BaseMutation): order = Field(OrderType) @staticmethod - def mutate(parent, info, product_uuid, order_uuid, attributes=None): # type: ignore [override] + def mutate(parent, info, product_uuid, order_uuid, attributes=None): user = info.context.user try: order = Order.objects.get(uuid=order_uuid) @@ -150,7 +150,7 @@ class RemoveAllOrderProducts(BaseMutation): order = Field(OrderType) @staticmethod - def mutate(parent, info, order_uuid): # type: ignore [override] + def mutate(parent, info, order_uuid): user = info.context.user order = Order.objects.get(uuid=order_uuid) if not (user.has_perm("core.delete_orderproduct") or user == order.user): @@ -173,7 +173,7 @@ class RemoveOrderProductsOfAKind(BaseMutation): order = Field(OrderType) @staticmethod - def mutate(parent, info, product_uuid, order_uuid): # type: ignore [override] + def mutate(parent, info, product_uuid, order_uuid): user = info.context.user order = Order.objects.get(uuid=order_uuid) if not (user.has_perm("core.delete_orderproduct") or user == order.user): @@ -214,7 +214,7 @@ class BuyOrder(BaseMutation): shipping_address=None, billing_address=None, chosen_products=None, - ): # type: ignore [override] + ): if not any([order_uuid, order_hr_id]) or all([order_uuid, order_hr_id]): raise BadRequest( _( @@ -276,7 +276,7 @@ class BulkOrderAction(BaseMutation): products, order_uuid=None, order_hr_id=None, - ): # type: ignore [override] + ): if not any([order_uuid, order_hr_id]) or all([order_uuid, order_hr_id]): raise BadRequest( _( @@ -326,7 +326,7 @@ class BulkWishlistAction(BaseMutation): action, products, wishlist_uuid=None, - ): # type: ignore [override] + ): if not wishlist_uuid: raise BadRequest(_("please provide wishlist_uuid value")) user = info.context.user @@ -379,7 +379,7 @@ class BuyUnregisteredOrder(BaseMutation): customer_shipping_address=None, promocode_uuid=None, is_business=False, - ): # type: ignore [override] + ): order = Order.objects.create(status="MOMENTAL") transaction = order.buy_without_registration( products=products, @@ -408,7 +408,7 @@ class AddWishlistProduct(BaseMutation): wishlist = Field(WishlistType) @staticmethod - def mutate(parent, info, product_uuid, wishlist_uuid): # type: ignore [override] + def mutate(parent, info, product_uuid, wishlist_uuid): user = info.context.user try: wishlist = Wishlist.objects.get(uuid=wishlist_uuid) @@ -436,7 +436,7 @@ class RemoveWishlistProduct(BaseMutation): wishlist = Field(WishlistType) @staticmethod - def mutate(parent, info, product_uuid, wishlist_uuid): # type: ignore [override] + def mutate(parent, info, product_uuid, wishlist_uuid): user = info.context.user try: wishlist = Wishlist.objects.get(uuid=wishlist_uuid) @@ -463,7 +463,7 @@ class RemoveAllWishlistProducts(BaseMutation): wishlist = Field(WishlistType) @staticmethod - def mutate(parent, info, wishlist_uuid): # type: ignore [override] + def mutate(parent, info, wishlist_uuid): user = info.context.user try: wishlist = Wishlist.objects.get(uuid=wishlist_uuid) @@ -494,7 +494,7 @@ class BuyWishlist(BaseMutation): transaction = Field(TransactionType, required=False) @staticmethod - def mutate(parent, info, wishlist_uuid, force_balance=False, force_payment=False): # type: ignore [override] + def mutate(parent, info, wishlist_uuid, force_balance=False, force_payment=False): user = info.context.user try: wishlist = Wishlist.objects.get(uuid=wishlist_uuid) @@ -557,7 +557,7 @@ class BuyProduct(BaseMutation): attributes=None, force_balance=False, force_payment=False, - ): # type: ignore [override] + ): user = info.context.user order = Order.objects.create(user=user, status="MOMENTAL") order.add_product( @@ -589,7 +589,7 @@ class FeedbackProductAction(BaseMutation): feedback = Field(FeedbackType, required=False) @staticmethod - def mutate(parent, info, order_product_uuid, action, comment=None, rating=None): # type: ignore [override] + def mutate(parent, info, order_product_uuid, action, comment=None, rating=None): user = info.context.user try: order_product = OrderProduct.objects.get(uuid=order_product_uuid) @@ -620,7 +620,7 @@ class CreateAddress(BaseMutation): address = Field(AddressType) @staticmethod - def mutate(parent, info, raw_data): # type: ignore [override] + def mutate(parent, info, raw_data): user = info.context.user if info.context.user.is_authenticated else None address = Address.objects.create(raw_data=raw_data, user=user) @@ -635,7 +635,7 @@ class DeleteAddress(BaseMutation): success = Boolean() @staticmethod - def mutate(parent, info, uuid): # type: ignore [override] + def mutate(parent, info, uuid): try: address = Address.objects.get(uuid=uuid) if ( @@ -663,7 +663,7 @@ class AutocompleteAddress(BaseMutation): suggestions = GenericScalar() @staticmethod - def mutate(parent, info, q, limit): # type: ignore [override] + def mutate(parent, info, q, limit): if 1 > limit > 10: raise BadRequest(_("limit must be between 1 and 10")) try: @@ -688,7 +688,7 @@ class ContactUs(BaseMutation): error = String() @staticmethod - def mutate(parent, info, email, name, subject, message, phone_number=None): # type: ignore [override] + def mutate(parent, info, email, name, subject, message, phone_number=None): try: contact_us_email.delay( { @@ -717,7 +717,7 @@ class Search(BaseMutation): description = _("elasticsearch - works like a charm") @staticmethod - def mutate(parent, info, query): # type: ignore [override] + def mutate(parent, info, query): data = process_query(query=query, request=info.context) # noinspection PyTypeChecker diff --git a/engine/core/graphene/object_types.py b/engine/core/graphene/object_types.py index 1f6abe78..c1b3f879 100644 --- a/engine/core/graphene/object_types.py +++ b/engine/core/graphene/object_types.py @@ -60,7 +60,7 @@ from engine.payments.graphene.object_types import TransactionType logger = logging.getLogger(__name__) -class SEOMetaType(ObjectType): # type: ignore [misc] +class SEOMetaType(ObjectType): title = String() description = String() canonical = String() @@ -71,7 +71,7 @@ class SEOMetaType(ObjectType): # type: ignore [misc] hreflang = String() -class AttributeType(DjangoObjectType): # type: ignore [misc] +class AttributeType(DjangoObjectType): values = List(lambda: AttributeValueType, description=_("attribute values")) class Meta: @@ -91,7 +91,7 @@ class AttributeType(DjangoObjectType): # type: ignore [misc] return base_qs -class AttributeGroupType(DjangoObjectType): # type: ignore [misc] +class AttributeGroupType(DjangoObjectType): attributes = List(lambda: AttributeType, description=_("grouped attributes")) class Meta: @@ -112,7 +112,7 @@ class AttributeGroupType(DjangoObjectType): # type: ignore [misc] return qs -class BrandType(DjangoObjectType): # type: ignore [misc] +class BrandType(DjangoObjectType): categories = List(lambda: CategoryType, description=_("categories")) seo_meta = Field(SEOMetaType, description=_("SEO Meta snapshot")) @@ -198,17 +198,17 @@ class BrandType(DjangoObjectType): # type: ignore [misc] } -class FilterableAttributeType(ObjectType): # type: ignore [misc] +class FilterableAttributeType(ObjectType): attribute_name = String(required=True) possible_values = List(String, required=True) -class MinMaxPriceType(ObjectType): # type: ignore [misc] +class MinMaxPriceType(ObjectType): min_price = Float() max_price = Float() -class CategoryType(DjangoObjectType): # type: ignore [misc] +class CategoryType(DjangoObjectType): children = List( lambda: CategoryType, description=_("categories"), @@ -358,7 +358,7 @@ class CategoryType(DjangoObjectType): # type: ignore [misc] } -class VendorType(DjangoObjectType): # type: ignore [misc] +class VendorType(DjangoObjectType): markup_percent = Float(description=_("markup percentage")) class Meta: @@ -369,7 +369,7 @@ class VendorType(DjangoObjectType): # type: ignore [misc] description = _("vendors") -class AddressType(DjangoObjectType): # type: ignore [misc] +class AddressType(DjangoObjectType): latitude = Float(description=_("Latitude (Y coordinate)")) longitude = Float(description=_("Longitude (X coordinate)")) @@ -399,7 +399,7 @@ class AddressType(DjangoObjectType): # type: ignore [misc] return self.location.y if self.location else None -class FeedbackType(DjangoObjectType): # type: ignore [misc] +class FeedbackType(DjangoObjectType): comment = String(description=_("comment")) rating = Int( description=_("rating value from 1 to 10, inclusive, or 0 if not set.") @@ -413,7 +413,7 @@ class FeedbackType(DjangoObjectType): # type: ignore [misc] description = _("represents feedback from a user.") -class OrderProductType(DjangoObjectType): # type: ignore [misc] +class OrderProductType(DjangoObjectType): attributes = GenericScalar(description=_("attributes")) notifications = GenericScalar(description=_("notifications")) download_url = String( @@ -451,7 +451,7 @@ class OrderProductType(DjangoObjectType): # type: ignore [misc] return self.download_url -class OrderType(DjangoObjectType): # type: ignore [misc] +class OrderType(DjangoObjectType): order_products = DjangoFilterConnectionField( OrderProductType, description=_("a list of order products in this order") ) @@ -508,7 +508,7 @@ class OrderType(DjangoObjectType): # type: ignore [misc] return None -class ProductImageType(DjangoObjectType): # type: ignore [misc] +class ProductImageType(DjangoObjectType): image = String(description=_("image url")) class Meta: @@ -522,7 +522,7 @@ class ProductImageType(DjangoObjectType): # type: ignore [misc] return info.context.build_absolute_uri(self.image.url) if self.image else "" -class ProductType(DjangoObjectType): # type: ignore [misc] +class ProductType(DjangoObjectType): category = Field(CategoryType, description=_("category")) images = DjangoFilterConnectionField(ProductImageType, description=_("images")) feedbacks = DjangoFilterConnectionField(FeedbackType, description=_("feedbacks")) @@ -646,7 +646,7 @@ class ProductType(DjangoObjectType): # type: ignore [misc] return self.discount_price -class AttributeValueType(DjangoObjectType): # type: ignore [misc] +class AttributeValueType(DjangoObjectType): value = String(description=_("attribute value")) class Meta: @@ -657,7 +657,7 @@ class AttributeValueType(DjangoObjectType): # type: ignore [misc] description = _("attribute value") -class PromoCodeType(DjangoObjectType): # type: ignore [misc] +class PromoCodeType(DjangoObjectType): discount = Float() discount_type = String() @@ -679,13 +679,13 @@ class PromoCodeType(DjangoObjectType): # type: ignore [misc] float(self.discount_percent) if self.discount_percent else float(self.discount_amount) - ) # type: ignore [arg-type] + ) def resolve_discount_type(self: PromoCode, _info) -> str: return "percent" if self.discount_percent else "amount" -class PromotionType(DjangoObjectType): # type: ignore [misc] +class PromotionType(DjangoObjectType): products = DjangoFilterConnectionField( ProductType, description=_("products on sale") ) @@ -698,7 +698,7 @@ class PromotionType(DjangoObjectType): # type: ignore [misc] description = _("promotions") -class StockType(DjangoObjectType): # type: ignore [misc] +class StockType(DjangoObjectType): vendor = Field(VendorType, description=_("vendor")) product = Field(ProductType, description=_("product")) @@ -710,7 +710,7 @@ class StockType(DjangoObjectType): # type: ignore [misc] description = _("stocks") -class WishlistType(DjangoObjectType): # type: ignore [misc] +class WishlistType(DjangoObjectType): products = DjangoFilterConnectionField( ProductType, description=_("wishlisted products") ) @@ -722,7 +722,7 @@ class WishlistType(DjangoObjectType): # type: ignore [misc] description = _("wishlists") -class ProductTagType(DjangoObjectType): # type: ignore [misc] +class ProductTagType(DjangoObjectType): product_set = DjangoFilterConnectionField( ProductType, description=_("tagged products") ) @@ -735,7 +735,7 @@ class ProductTagType(DjangoObjectType): # type: ignore [misc] description = _("product tags") -class CategoryTagType(DjangoObjectType): # type: ignore [misc] +class CategoryTagType(DjangoObjectType): category_set = DjangoFilterConnectionField( CategoryType, description=_("tagged categories") ) @@ -748,7 +748,7 @@ class CategoryTagType(DjangoObjectType): # type: ignore [misc] description = _("categories tags") -class ConfigType(ObjectType): # type: ignore [misc] +class ConfigType(ObjectType): project_name = String(description=_("project name")) company_name = String(description=_("company name")) company_address = String(description=_("company address")) @@ -768,7 +768,7 @@ class ConfigType(ObjectType): # type: ignore [misc] description = _("company configuration") -class LanguageType(ObjectType): # type: ignore [misc] +class LanguageType(ObjectType): code = String(description=_("language code")) name = String(description=_("language name")) flag = String(description=_("language flag, if exists :)")) @@ -777,34 +777,34 @@ class LanguageType(ObjectType): # type: ignore [misc] description = _("supported languages") -class SearchProductsResultsType(ObjectType): # type: ignore [misc] +class SearchProductsResultsType(ObjectType): uuid = UUID() name = String() slug = String() image = String() -class SearchCategoriesResultsType(ObjectType): # type: ignore [misc] +class SearchCategoriesResultsType(ObjectType): uuid = UUID() name = String() slug = String() image = String() -class SearchBrandsResultsType(ObjectType): # type: ignore [misc] +class SearchBrandsResultsType(ObjectType): uuid = UUID() name = String() slug = String() image = String() -class SearchPostsResultsType(ObjectType): # type: ignore [misc] +class SearchPostsResultsType(ObjectType): uuid = UUID() name = String() slug = String() -class SearchResultsType(ObjectType): # type: ignore [misc] +class SearchResultsType(ObjectType): products = List( description=_("products search results"), of_type=SearchProductsResultsType ) @@ -817,6 +817,6 @@ class SearchResultsType(ObjectType): # type: ignore [misc] posts = List(description=_("posts search results"), of_type=SearchPostsResultsType) -class BulkProductInput(InputObjectType): # type: ignore [misc] +class BulkProductInput(InputObjectType): uuid = UUID(required=True) attributes = GenericScalar(required=False) diff --git a/engine/core/management/commands/check_translated.py b/engine/core/management/commands/check_translated.py index 29e62927..afdcdac3 100644 --- a/engine/core/management/commands/check_translated.py +++ b/engine/core/management/commands/check_translated.py @@ -95,17 +95,17 @@ class Command(BaseCommand): ) def handle(self, *args: list[Any], **options: dict[str, str | list[str]]) -> None: - langs: list[str] = options.get("target_languages", []) # type: ignore [assignment] + langs: list[str] = options.get("target_languages", []) if "ALL" in langs: langs = list(dict(settings.LANGUAGES).keys()) apps_to_scan: set[str] = set(options["target_apps"]) if "ALL" in apps_to_scan: apps_to_scan = set(TRANSLATABLE_APPS) - root_path: str = options.get("root_path") or "/app/" # type: ignore [assignment] + root_path: str = options.get("root_path") or "/app/" configs = list(apps.get_app_configs()) # noinspection PyTypeChecker - configs.append(RootDirectory()) # type: ignore [arg-type] + configs.append(RootDirectory()) errors = 0 diff --git a/engine/core/management/commands/deepl_translate.py b/engine/core/management/commands/deepl_translate.py index b5441ea5..395ea2cc 100644 --- a/engine/core/management/commands/deepl_translate.py +++ b/engine/core/management/commands/deepl_translate.py @@ -30,7 +30,7 @@ def placeholderize(text: str) -> tuple[str, list[str]]: """ placeholders: list[str] = [] - def _repl(match: re.Match) -> str: # type: ignore [type-arg] + def _repl(match: re.Match) -> str: idx = len(placeholders) placeholders.append(match.group(0)) return f"__PH_{idx}__" @@ -107,9 +107,9 @@ class Command(BaseCommand): ) def handle(self, *args: list[Any], **options: dict[Any, Any]) -> None: - target_langs: list[str] = options["target_languages"] # type: ignore [assignment] + target_langs: list[str] = options["target_languages"] if "ALL" in target_langs: - target_langs = DEEPL_TARGET_LANGUAGES_MAPPING.keys() # type: ignore [assignment] + target_langs = DEEPL_TARGET_LANGUAGES_MAPPING.keys() target_apps = set(options["target_apps"]) if "ALL" in target_apps: target_apps = { @@ -125,7 +125,7 @@ class Command(BaseCommand): try: import readline except ImportError: - readline = None # type: ignore [assignment] + readline = None for target_lang in target_langs: api_code = DEEPL_TARGET_LANGUAGES_MAPPING.get(target_lang) @@ -176,16 +176,16 @@ class Command(BaseCommand): if readline: def hook() -> None: - readline.insert_text(default) # type: ignore [attr-defined] # noqa: B023 - readline.redisplay() # type: ignore [attr-defined] + readline.insert_text(default) # noqa: B023 + readline.redisplay() - readline.set_pre_input_hook(hook) # type: ignore [attr-defined] + readline.set_pre_input_hook(hook) prompt = f"Enter translation for '{e.msgid}': " user_in = input(prompt).strip() if readline: - readline.set_pre_input_hook(None) # type: ignore [attr-defined] + readline.set_pre_input_hook(None) if user_in: e.msgstr = user_in diff --git a/engine/core/management/commands/delete_never_ordered_products.py b/engine/core/management/commands/delete_never_ordered_products.py index 11a47347..7f9c8f10 100644 --- a/engine/core/management/commands/delete_never_ordered_products.py +++ b/engine/core/management/commands/delete_never_ordered_products.py @@ -19,7 +19,7 @@ class Command(BaseCommand): ) def handle(self, *args: list[Any], **options: dict[Any, Any]) -> None: - size: int = options["size"] # type: ignore [assignment] + size: int = options["size"] while True: batch_ids = list( Product.objects.filter(orderproduct__isnull=True).values_list( diff --git a/engine/core/management/commands/delete_products_by_description.py b/engine/core/management/commands/delete_products_by_description.py index f39e1434..f249cf4d 100644 --- a/engine/core/management/commands/delete_products_by_description.py +++ b/engine/core/management/commands/delete_products_by_description.py @@ -19,7 +19,7 @@ class Command(BaseCommand): ) def handle(self, *args: list[Any], **options: dict[Any, Any]) -> None: - size: int = options["size"] # type: ignore [assignment] + size: int = options["size"] while True: batch_ids = list( Product.objects.filter( diff --git a/engine/core/management/commands/fetch_products.py b/engine/core/management/commands/fetch_products.py index 27bd635a..56cd1922 100644 --- a/engine/core/management/commands/fetch_products.py +++ b/engine/core/management/commands/fetch_products.py @@ -11,7 +11,7 @@ class Command(BaseCommand): self.style.SUCCESS("Starting fetching products task in worker container...") ) - update_products_task.delay() # type: ignore [attr-defined] + update_products_task.delay() self.stdout.write( self.style.SUCCESS( diff --git a/engine/core/managers.py b/engine/core/managers.py index 36882106..69b24961 100644 --- a/engine/core/managers.py +++ b/engine/core/managers.py @@ -14,7 +14,7 @@ class AddressManager(models.Manager): if not kwargs.get("raw_data"): raise ValueError("'raw_data' (address string) must be provided.") - params: dict[str, str | int] = { # type: ignore [annotation-unchecked] + params: dict[str, str | int] = { "format": "json", "addressdetails": 1, "q": kwargs.get("raw_data"), diff --git a/engine/core/models.py b/engine/core/models.py index 63d8aaa8..7ff1797a 100644 --- a/engine/core/models.py +++ b/engine/core/models.py @@ -70,8 +70,8 @@ from evibes.utils.misc import create_object logger = logging.getLogger(__name__) -class AttributeGroup(ExportModelOperationsMixin("attribute_group"), NiceModel): # type: ignore [misc] - __doc__ = _( # type: ignore +class AttributeGroup(ExportModelOperationsMixin("attribute_group"), NiceModel): + __doc__ = _( "Represents a group of attributes, which can be hierarchical." " This class is used to manage and organize attribute groups." " An attribute group can have a parent group, forming a hierarchical structure." @@ -106,8 +106,8 @@ class AttributeGroup(ExportModelOperationsMixin("attribute_group"), NiceModel): verbose_name_plural = _("attribute groups") -class Vendor(ExportModelOperationsMixin("vendor"), NiceModel): # type: ignore [misc] - __doc__ = _( # type: ignore +class Vendor(ExportModelOperationsMixin("vendor"), NiceModel): + __doc__ = _( "Represents a vendor entity capable of storing information about external vendors and their interaction requirements." " The Vendor class is used to define and manage information related to an external vendor." " It stores the vendor's name, authentication details required for communication," @@ -164,7 +164,7 @@ class Vendor(ExportModelOperationsMixin("vendor"), NiceModel): # type: ignore [ def __str__(self) -> str: return self.name - def save( # type: ignore [override] + def save( self, *, force_insert: bool = False, @@ -198,8 +198,8 @@ class Vendor(ExportModelOperationsMixin("vendor"), NiceModel): # type: ignore [ ] -class ProductTag(ExportModelOperationsMixin("product_tag"), NiceModel): # type: ignore [misc] - __doc__ = _( # type: ignore +class ProductTag(ExportModelOperationsMixin("product_tag"), NiceModel): + __doc__ = _( "Represents a product tag used for classifying or identifying products." " The ProductTag class is designed to uniquely identify and classify products through a combination" " of an internal tag identifier and a user-friendly display name." @@ -230,8 +230,8 @@ class ProductTag(ExportModelOperationsMixin("product_tag"), NiceModel): # type: verbose_name_plural = _("product tags") -class CategoryTag(ExportModelOperationsMixin("category_tag"), NiceModel): # type: ignore [misc] - __doc__ = _( # type: ignore +class CategoryTag(ExportModelOperationsMixin("category_tag"), NiceModel): + __doc__ = _( "Represents a category tag used for products." " This class models a category tag that can be used to associate and classify products." " It includes attributes for an internal tag identifier and a user-friendly display name." @@ -261,8 +261,8 @@ class CategoryTag(ExportModelOperationsMixin("category_tag"), NiceModel): # typ verbose_name_plural = _("category tags") -class Category(ExportModelOperationsMixin("category"), NiceModel, MPTTModel): # type: ignore [misc, django-manager-missing] - __doc__ = _( # type: ignore +class Category(ExportModelOperationsMixin("category"), NiceModel, MPTTModel): + __doc__ = _( "Represents a category entity to organize and group related items in a hierarchical structure." " Categories may have hierarchical relationships with other categories, supporting parent-child relationships." " The class includes fields for metadata and visual representation," @@ -437,7 +437,7 @@ class Category(ExportModelOperationsMixin("category"), NiceModel, MPTTModel): # ): bucket["possible_values"].append(value) - return list(by_attr.values()) # type: ignore [arg-type] + return list(by_attr.values()) @cached_property def image_url(self) -> str: @@ -452,8 +452,8 @@ class Category(ExportModelOperationsMixin("category"), NiceModel, MPTTModel): # ordering = ["tree_id", "lft"] -class Brand(ExportModelOperationsMixin("brand"), NiceModel): # type: ignore [misc] - __doc__ = _( # type: ignore +class Brand(ExportModelOperationsMixin("brand"), NiceModel): + __doc__ = _( "Represents a Brand object in the system. " "This class handles information and attributes related to a brand, including its name, logos, " "description, associated categories, a unique slug, and priority order. " @@ -522,8 +522,8 @@ class Brand(ExportModelOperationsMixin("brand"), NiceModel): # type: ignore [mi verbose_name_plural = _("brands") -class Stock(ExportModelOperationsMixin("stock"), NiceModel): # type: ignore [misc] - __doc__ = _( # type: ignore +class Stock(ExportModelOperationsMixin("stock"), NiceModel): + __doc__ = _( "Represents the stock of a product managed in the system." " This class provides details about the relationship between vendors, products, and their stock information, " "as well as inventory-related properties like price, purchase price, quantity, SKU, and digital assets." @@ -588,8 +588,8 @@ class Stock(ExportModelOperationsMixin("stock"), NiceModel): # type: ignore [mi verbose_name_plural = _("stock entries") -class Product(ExportModelOperationsMixin("product"), NiceModel): # type: ignore [misc] - __doc__ = _( # type: ignore +class Product(ExportModelOperationsMixin("product"), NiceModel): + __doc__ = _( "Represents a product with attributes such as category, brand, tags, digital status, name, description, part number, and slug." " Provides related utility properties to retrieve ratings, feedback counts, price, quantity, and total orders." " Designed for use in a system that handles e-commerce or inventory management." @@ -695,7 +695,7 @@ class Product(ExportModelOperationsMixin("product"), NiceModel): # type: ignore @cached_property def discount_price(self) -> float | None: - return self.promos.first().discount_percent if self.promos.exists() else None # type: ignore [union-attr] + return self.promos.first().discount_percent if self.promos.exists() else None @property def rating(self) -> float: @@ -736,8 +736,8 @@ class Product(ExportModelOperationsMixin("product"), NiceModel): # type: ignore self.__dict__["personal_orders_only"] = value -class Attribute(ExportModelOperationsMixin("attribute"), NiceModel): # type: ignore [misc] - __doc__ = _( # type: ignore +class Attribute(ExportModelOperationsMixin("attribute"), NiceModel): + __doc__ = _( "Represents an attribute in the system." " This class is used to define and manage attributes," " which are customizable pieces of data that can be associated with other entities." @@ -795,8 +795,8 @@ class Attribute(ExportModelOperationsMixin("attribute"), NiceModel): # type: ig verbose_name_plural = _("attributes") -class AttributeValue(ExportModelOperationsMixin("attribute_value"), NiceModel): # type: ignore [misc] - __doc__ = _( # type: ignore +class AttributeValue(ExportModelOperationsMixin("attribute_value"), NiceModel): + __doc__ = _( "Represents a specific value for an attribute that is linked to a product. " "It links the 'attribute' to a unique 'value', allowing " "better organization and dynamic representation of product characteristics." @@ -833,8 +833,8 @@ class AttributeValue(ExportModelOperationsMixin("attribute_value"), NiceModel): verbose_name_plural = _("attribute values") -class ProductImage(ExportModelOperationsMixin("product_image"), NiceModel): # type: ignore [misc] - __doc__ = _( # type: ignore +class ProductImage(ExportModelOperationsMixin("product_image"), NiceModel): + __doc__ = _( "Represents a product image associated with a product in the system. " "This class is designed to manage images for products, including functionality " "for uploading image files, associating them with specific products, and " @@ -886,8 +886,8 @@ class ProductImage(ExportModelOperationsMixin("product_image"), NiceModel): # t verbose_name_plural = _("product images") -class Promotion(ExportModelOperationsMixin("promotion"), NiceModel): # type: ignore [misc] - __doc__ = _( # type: ignore +class Promotion(ExportModelOperationsMixin("promotion"), NiceModel): + __doc__ = _( "Represents a promotional campaign for products with a discount. " "This class is used to define and manage promotional campaigns that offer a " "percentage-based discount for products. The class includes attributes for " @@ -932,8 +932,8 @@ class Promotion(ExportModelOperationsMixin("promotion"), NiceModel): # type: ig return str(self.id) -class Wishlist(ExportModelOperationsMixin("wishlist"), NiceModel): # type: ignore [misc] - __doc__ = _( # type: ignore +class Wishlist(ExportModelOperationsMixin("wishlist"), NiceModel): + __doc__ = _( "Represents a user's wishlist for storing and managing desired products. " "The class provides functionality to manage a collection of products, " "supporting operations such as adding and removing products, " @@ -1003,8 +1003,8 @@ class Wishlist(ExportModelOperationsMixin("wishlist"), NiceModel): # type: igno return self -class Documentary(ExportModelOperationsMixin("attribute_group"), NiceModel): # type: ignore [misc] - __doc__ = _( # type: ignore +class Documentary(ExportModelOperationsMixin("attribute_group"), NiceModel): + __doc__ = _( "Represents a documentary record tied to a product. " "This class is used to store information about documentaries related to specific " "products, including file uploads and their metadata. It contains methods and " @@ -1034,8 +1034,8 @@ class Documentary(ExportModelOperationsMixin("attribute_group"), NiceModel): # return self.document.name.split(".")[-1] or _("unresolved") -class Address(ExportModelOperationsMixin("address"), NiceModel): # type: ignore [misc] - __doc__ = _( # type: ignore +class Address(ExportModelOperationsMixin("address"), NiceModel): + __doc__ = _( "Represents an address entity that includes location details and associations with a user. " "Provides functionality for geographic and address data storage, as well " "as integration with geocoding services. " @@ -1099,8 +1099,8 @@ class Address(ExportModelOperationsMixin("address"), NiceModel): # type: ignore return f"{base} for {self.user.email}" if self.user else base -class PromoCode(ExportModelOperationsMixin("promocode"), NiceModel): # type: ignore [misc] - __doc__ = _( # type: ignore +class PromoCode(ExportModelOperationsMixin("promocode"), NiceModel): + __doc__ = _( "Represents a promotional code that can be used for discounts, managing its validity, " "type of discount, and application. " "The PromoCode class stores details about a promotional code, including its unique " @@ -1211,13 +1211,13 @@ class PromoCode(ExportModelOperationsMixin("promocode"), NiceModel): # type: ig if self.discount_type == "percent": promo_amount -= round( promo_amount * (float(self.discount_percent) / 100), 2 - ) # type: ignore [arg-type] + ) order.attributes.update( {"promocode_uuid": str(self.uuid), "final_price": promo_amount} ) order.save() elif self.discount_type == "amount": - promo_amount -= round(float(self.discount_amount), 2) # type: ignore [arg-type] + promo_amount -= round(float(self.discount_amount), 2) order.attributes.update( {"promocode_uuid": str(self.uuid), "final_price": promo_amount} ) @@ -1230,8 +1230,8 @@ class PromoCode(ExportModelOperationsMixin("promocode"), NiceModel): # type: ig return promo_amount -class Order(ExportModelOperationsMixin("order"), NiceModel): # type: ignore [misc] - __doc__ = _( # type: ignore +class Order(ExportModelOperationsMixin("order"), NiceModel): + __doc__ = _( "Represents an order placed by a user." " This class models an order within the application," " including its various attributes such as billing and shipping information," @@ -1341,7 +1341,7 @@ class Order(ExportModelOperationsMixin("order"), NiceModel): # type: ignore [mi ( self.user.attributes.get("is_business", False) and self.user.attributes.get("business_identificator") - ) # type: ignore [union-attr] + ) if self.user else False ) @@ -1410,7 +1410,7 @@ class Order(ExportModelOperationsMixin("order"), NiceModel): # type: ignore [mi if promotions.exists(): buy_price -= round( product.price * (promotions.first().discount_percent / 100), 2 - ) # type: ignore [union-attr] + ) order_product, is_created = OrderProduct.objects.get_or_create( product=product, @@ -1800,8 +1800,8 @@ class Order(ExportModelOperationsMixin("order"), NiceModel): # type: ignore [mi return None -class Feedback(ExportModelOperationsMixin("feedback"), NiceModel): # type: ignore [misc] - __doc__ = _( # type: ignore +class Feedback(ExportModelOperationsMixin("feedback"), NiceModel): + __doc__ = _( "Manages user feedback for products. " "This class is designed to capture and store user feedback for specific products " "that they have purchased. It contains attributes to store user comments, " @@ -1849,8 +1849,8 @@ class Feedback(ExportModelOperationsMixin("feedback"), NiceModel): # type: igno verbose_name_plural = _("feedbacks") -class OrderProduct(ExportModelOperationsMixin("order_product"), NiceModel): # type: ignore [misc] - __doc__ = _( # type: ignore +class OrderProduct(ExportModelOperationsMixin("order_product"), NiceModel): + __doc__ = _( "Represents products associated with orders and their attributes. " "The OrderProduct model maintains information about a product that is part of an order, " "including details such as purchase price, quantity, product attributes, and status. It " @@ -1969,12 +1969,12 @@ class OrderProduct(ExportModelOperationsMixin("order_product"), NiceModel): # t @property def total_price(self: Self) -> float: - return round(float(self.buy_price) * self.quantity, 2) # type: ignore [arg-type] + return round(float(self.buy_price) * self.quantity, 2) @property def download_url(self: Self) -> str: if self.product and self.product.stocks: - if self.product.is_digital and self.product.stocks.first().digital_asset: # type: ignore [union-attr] + if self.product.is_digital and self.product.stocks.first().digital_asset: if hasattr(self, "download"): return self.download.url else: @@ -2010,7 +2010,7 @@ class OrderProduct(ExportModelOperationsMixin("order_product"), NiceModel): # t class CustomerRelationshipManagementProvider( ExportModelOperationsMixin("crm_provider"), NiceModel -): # type: ignore [misc] +): name = CharField(max_length=128, unique=True, verbose_name=_("name")) integration_url = URLField( blank=True, null=True, help_text=_("URL of the integration") @@ -2053,7 +2053,7 @@ class CustomerRelationshipManagementProvider( verbose_name_plural = _("CRMs") -class OrderCrmLink(ExportModelOperationsMixin("order_crm_link"), NiceModel): # type: ignore +class OrderCrmLink(ExportModelOperationsMixin("order_crm_link"), NiceModel): order = ForeignKey(to=Order, on_delete=PROTECT, related_name="crm_links") crm = ForeignKey( to=CustomerRelationshipManagementProvider, @@ -2070,8 +2070,8 @@ class OrderCrmLink(ExportModelOperationsMixin("order_crm_link"), NiceModel): # verbose_name_plural = _("orders CRM links") -class DigitalAssetDownload(ExportModelOperationsMixin("attribute_group"), NiceModel): # type: ignore [misc] - __doc__ = _( # type: ignore +class DigitalAssetDownload(ExportModelOperationsMixin("attribute_group"), NiceModel): + __doc__ = _( "Represents the downloading functionality for digital assets associated with orders. " "The DigitalAssetDownload class provides the ability to manage and access " "downloads related to order products. It maintains information about the " diff --git a/engine/core/serializers/detail.py b/engine/core/serializers/detail.py index 834c5bec..2286779c 100644 --- a/engine/core/serializers/detail.py +++ b/engine/core/serializers/detail.py @@ -50,7 +50,7 @@ class AttributeGroupDetailSerializer(ModelSerializer): class CategoryDetailListSerializer(ListSerializer): - def to_representation(self, data): # type: ignore[override] + def to_representation(self, data): items = list(data) with suppress(Exception): Category.bulk_prefetch_filterable_attributes(items) @@ -92,7 +92,7 @@ class CategoryDetailSerializer(ModelSerializer): CategorySimpleSerializer(children, many=True, context=self.context).data if obj.children.exists() else [] - ) # type: ignore [return-value] + ) class BrandDetailSerializer(ModelSerializer): diff --git a/engine/core/serializers/simple.py b/engine/core/serializers/simple.py index 7f88badc..22a7f1c5 100644 --- a/engine/core/serializers/simple.py +++ b/engine/core/serializers/simple.py @@ -25,9 +25,9 @@ from engine.core.models import ( from engine.core.serializers.utility import AddressSerializer -class AttributeGroupSimpleSerializer(ModelSerializer): # type: ignore [type-arg] - parent = PrimaryKeyRelatedField(read_only=True) # type: ignore [assignment, var-annotated] - children = PrimaryKeyRelatedField(many=True, read_only=True) # type: ignore [assignment, var-annotated] +class AttributeGroupSimpleSerializer(ModelSerializer): + parent = PrimaryKeyRelatedField(read_only=True) + children = PrimaryKeyRelatedField(many=True, read_only=True) class Meta: model = AttributeGroup @@ -39,7 +39,7 @@ class AttributeGroupSimpleSerializer(ModelSerializer): # type: ignore [type-arg ] -class CategorySimpleSerializer(ModelSerializer): # type: ignore [type-arg] +class CategorySimpleSerializer(ModelSerializer): children = SerializerMethodField() class Meta: @@ -63,10 +63,10 @@ class CategorySimpleSerializer(ModelSerializer): # type: ignore [type-arg] CategorySimpleSerializer(children, many=True, context=self.context).data if obj.children.exists() else [] - ) # type: ignore [return-value] + ) -class BrandSimpleSerializer(ModelSerializer): # type: ignore [type-arg] +class BrandSimpleSerializer(ModelSerializer): class Meta: model = Brand fields = [ @@ -77,7 +77,7 @@ class BrandSimpleSerializer(ModelSerializer): # type: ignore [type-arg] ] -class ProductTagSimpleSerializer(ModelSerializer): # type: ignore [type-arg] +class ProductTagSimpleSerializer(ModelSerializer): class Meta: model = ProductTag fields = [ @@ -87,8 +87,8 @@ class ProductTagSimpleSerializer(ModelSerializer): # type: ignore [type-arg] ] -class ProductImageSimpleSerializer(ModelSerializer): # type: ignore [type-arg] - product: PrimaryKeyRelatedField = PrimaryKeyRelatedField(read_only=True) # type: ignore [type-arg] +class ProductImageSimpleSerializer(ModelSerializer): + product: PrimaryKeyRelatedField = PrimaryKeyRelatedField(read_only=True) class Meta: model = ProductImage @@ -101,7 +101,7 @@ class ProductImageSimpleSerializer(ModelSerializer): # type: ignore [type-arg] ] -class AttributeSimpleSerializer(ModelSerializer): # type: ignore [type-arg] +class AttributeSimpleSerializer(ModelSerializer): group = AttributeGroupSimpleSerializer(read_only=True) class Meta: @@ -114,9 +114,9 @@ class AttributeSimpleSerializer(ModelSerializer): # type: ignore [type-arg] ] -class AttributeValueSimpleSerializer(ModelSerializer): # type: ignore [type-arg] +class AttributeValueSimpleSerializer(ModelSerializer): attribute = AttributeSimpleSerializer(read_only=True) - product: PrimaryKeyRelatedField = PrimaryKeyRelatedField(read_only=True) # type: ignore [type-arg] + product: PrimaryKeyRelatedField = PrimaryKeyRelatedField(read_only=True) class Meta: model = AttributeValue @@ -128,7 +128,7 @@ class AttributeValueSimpleSerializer(ModelSerializer): # type: ignore [type-arg ] -class ProductSimpleSerializer(ModelSerializer): # type: ignore [type-arg] +class ProductSimpleSerializer(ModelSerializer): brand = BrandSimpleSerializer(read_only=True) category = CategorySimpleSerializer(read_only=True) tags = ProductTagSimpleSerializer(many=True, read_only=True) @@ -185,7 +185,7 @@ class ProductSimpleSerializer(ModelSerializer): # type: ignore [type-arg] return obj.discount_price -class VendorSimpleSerializer(ModelSerializer): # type: ignore [type-arg] +class VendorSimpleSerializer(ModelSerializer): class Meta: model = Vendor fields = [ @@ -194,7 +194,7 @@ class VendorSimpleSerializer(ModelSerializer): # type: ignore [type-arg] ] -class StockSimpleSerializer(ModelSerializer): # type: ignore [type-arg] +class StockSimpleSerializer(ModelSerializer): vendor = VendorSimpleSerializer(read_only=True) product = ProductSimpleSerializer(read_only=True) @@ -211,7 +211,7 @@ class StockSimpleSerializer(ModelSerializer): # type: ignore [type-arg] ] -class PromoCodeSimpleSerializer(ModelSerializer): # type: ignore [type-arg] +class PromoCodeSimpleSerializer(ModelSerializer): class Meta: model = PromoCode fields = [ @@ -220,7 +220,7 @@ class PromoCodeSimpleSerializer(ModelSerializer): # type: ignore [type-arg] ] -class PromotionSimpleSerializer(ModelSerializer): # type: ignore [type-arg] +class PromotionSimpleSerializer(ModelSerializer): products = ProductSimpleSerializer(many=True, read_only=True) class Meta: @@ -233,8 +233,8 @@ class PromotionSimpleSerializer(ModelSerializer): # type: ignore [type-arg] ] -class WishlistSimpleSerializer(ModelSerializer): # type: ignore [type-arg] - user: PrimaryKeyRelatedField = PrimaryKeyRelatedField(read_only=True) # type: ignore [type-arg] +class WishlistSimpleSerializer(ModelSerializer): + user: PrimaryKeyRelatedField = PrimaryKeyRelatedField(read_only=True) products = ProductSimpleSerializer(many=True, read_only=True) class Meta: @@ -246,8 +246,8 @@ class WishlistSimpleSerializer(ModelSerializer): # type: ignore [type-arg] ] -class FeedbackSimpleSerializer(ModelSerializer): # type: ignore [type-arg] - order_product: PrimaryKeyRelatedField = PrimaryKeyRelatedField(read_only=True) # type: ignore [type-arg] +class FeedbackSimpleSerializer(ModelSerializer): + order_product: PrimaryKeyRelatedField = PrimaryKeyRelatedField(read_only=True) class Meta: model = Feedback @@ -258,7 +258,7 @@ class FeedbackSimpleSerializer(ModelSerializer): # type: ignore [type-arg] ] -class OrderProductSimpleSerializer(ModelSerializer): # type: ignore [type-arg] +class OrderProductSimpleSerializer(ModelSerializer): product = ProductSimpleSerializer(read_only=True) class Meta: @@ -272,8 +272,8 @@ class OrderProductSimpleSerializer(ModelSerializer): # type: ignore [type-arg] ] -class OrderSimpleSerializer(ModelSerializer): # type: ignore [type-arg] - user: PrimaryKeyRelatedField = PrimaryKeyRelatedField(read_only=True) # type: ignore [type-arg] +class OrderSimpleSerializer(ModelSerializer): + user: PrimaryKeyRelatedField = PrimaryKeyRelatedField(read_only=True) promo_code = PromoCodeSimpleSerializer(read_only=True) order_products = OrderProductSimpleSerializer(many=True, read_only=True) billing_address = AddressSerializer(read_only=True, required=False) diff --git a/engine/core/serializers/utility.py b/engine/core/serializers/utility.py index 4b2cd298..ea015f3c 100644 --- a/engine/core/serializers/utility.py +++ b/engine/core/serializers/utility.py @@ -18,19 +18,19 @@ from rest_framework.serializers import ListSerializer, ModelSerializer, Serializ from engine.core.models import Address -class AddressAutocompleteInputSerializer(Serializer): # type: ignore [type-arg] +class AddressAutocompleteInputSerializer(Serializer): q = CharField(required=True) limit = IntegerField(required=False, min_value=1, max_value=10, default=5) -class AddressSuggestionSerializer(Serializer): # type: ignore [type-arg] +class AddressSuggestionSerializer(Serializer): display_name = CharField() lat = FloatField() lon = FloatField() address = DictField(child=CharField()) -class AddressSerializer(ModelSerializer): # type: ignore [type-arg] +class AddressSerializer(ModelSerializer): latitude = FloatField(source="location.y", read_only=True) longitude = FloatField(source="location.x", read_only=True) @@ -59,7 +59,7 @@ class AddressSerializer(ModelSerializer): # type: ignore [type-arg] ] -class AddressCreateSerializer(ModelSerializer): # type: ignore [type-arg] +class AddressCreateSerializer(ModelSerializer): raw_data = CharField( write_only=True, max_length=512, @@ -76,10 +76,10 @@ class AddressCreateSerializer(ModelSerializer): # type: ignore [type-arg] user = None if self.context["request"].user.is_authenticated: user = self.context["request"].user - return Address.objects.create(raw_data=raw, user=user, **validated_data) # type: ignore [no-untyped-call] + return Address.objects.create(raw_data=raw, user=user, **validated_data) -class DoFeedbackSerializer(Serializer): # type: ignore [type-arg] +class DoFeedbackSerializer(Serializer): comment = CharField(required=True) rating = IntegerField(min_value=1, max_value=10, default=10) action = CharField(default="add") @@ -94,13 +94,13 @@ class DoFeedbackSerializer(Serializer): # type: ignore [type-arg] return data -class CacheOperatorSerializer(Serializer): # type: ignore [type-arg] +class CacheOperatorSerializer(Serializer): key = CharField(required=True) - data = JSONField(required=False) # type: ignore [assignment] + data = JSONField(required=False) timeout = IntegerField(required=False) -class ContactUsSerializer(Serializer): # type: ignore [type-arg] +class ContactUsSerializer(Serializer): email = CharField(required=True) name = CharField(required=True) subject = CharField(required=True) @@ -108,13 +108,13 @@ class ContactUsSerializer(Serializer): # type: ignore [type-arg] message = CharField(required=True) -class LanguageSerializer(Serializer): # type: ignore [type-arg] +class LanguageSerializer(Serializer): code = CharField(required=True) name = CharField(required=True) flag = CharField() -class RecursiveField(Field): # type: ignore [type-arg] +class RecursiveField(Field): def to_representation(self, value: Any) -> Any: parent = self.parent if isinstance(parent, ListSerializer): @@ -127,45 +127,45 @@ class RecursiveField(Field): # type: ignore [type-arg] return data -class AddOrderProductSerializer(Serializer): # type: ignore [type-arg] +class AddOrderProductSerializer(Serializer): product_uuid = CharField(required=True) attributes = ListField(required=False, child=DictField(), default=list) -class BulkAddOrderProductsSerializer(Serializer): # type: ignore [type-arg] +class BulkAddOrderProductsSerializer(Serializer): products = ListField(child=AddOrderProductSerializer(), required=True) -class RemoveOrderProductSerializer(Serializer): # type: ignore [type-arg] +class RemoveOrderProductSerializer(Serializer): product_uuid = CharField(required=True) attributes = JSONField(required=False, default=dict) -class BulkRemoveOrderProductsSerializer(Serializer): # type: ignore [type-arg] +class BulkRemoveOrderProductsSerializer(Serializer): products = ListField(child=RemoveOrderProductSerializer(), required=True) -class AddWishlistProductSerializer(Serializer): # type: ignore [type-arg] +class AddWishlistProductSerializer(Serializer): product_uuid = CharField(required=True) -class RemoveWishlistProductSerializer(Serializer): # type: ignore [type-arg] +class RemoveWishlistProductSerializer(Serializer): product_uuid = CharField(required=True) -class BulkAddWishlistProductSerializer(Serializer): # type: ignore [type-arg] +class BulkAddWishlistProductSerializer(Serializer): product_uuids = ListField( child=CharField(required=True), allow_empty=False, max_length=64 ) -class BulkRemoveWishlistProductSerializer(Serializer): # type: ignore [type-arg] +class BulkRemoveWishlistProductSerializer(Serializer): product_uuids = ListField( child=CharField(required=True), allow_empty=False, max_length=64 ) -class BuyOrderSerializer(Serializer): # type: ignore [type-arg] +class BuyOrderSerializer(Serializer): force_balance = BooleanField(required=False, default=False) force_payment = BooleanField(required=False, default=False) promocode_uuid = CharField(required=False) @@ -174,7 +174,7 @@ class BuyOrderSerializer(Serializer): # type: ignore [type-arg] chosen_products = AddOrderProductSerializer(many=True, required=False) -class BuyUnregisteredOrderSerializer(Serializer): # type: ignore [type-arg] +class BuyUnregisteredOrderSerializer(Serializer): products = AddOrderProductSerializer(many=True, required=True) promocode_uuid = UUIDField(required=False) customer_name = CharField(required=True) @@ -185,7 +185,7 @@ class BuyUnregisteredOrderSerializer(Serializer): # type: ignore [type-arg] payment_method = CharField(required=True) -class BuyAsBusinessOrderSerializer(Serializer): # type: ignore [type-arg] +class BuyAsBusinessOrderSerializer(Serializer): products = AddOrderProductSerializer(many=True, required=True) business_identificator = CharField(required=True) promocode_uuid = UUIDField(required=False) diff --git a/engine/core/signals.py b/engine/core/signals.py index 44c20d51..3f4b8aca 100644 --- a/engine/core/signals.py +++ b/engine/core/signals.py @@ -156,8 +156,8 @@ def process_order_changes(instance: Order, created: bool, **kwargs: dict[Any, An ) order_product.order.user.payments_balance.amount -= ( order_product.buy_price - ) # type: ignore [union-attr, operator] - order_product.order.user.payments_balance.save() # type: ignore [union-attr] + ) + order_product.order.user.payments_balance.save() order_product.save() continue @@ -169,7 +169,7 @@ def process_order_changes(instance: Order, created: bool, **kwargs: dict[Any, An price=order_product.buy_price ) .first() - .vendor.name.lower() # type: ignore [union-attr, attr-defined, misc] + .vendor.name.lower() ) vendor = create_object( @@ -177,7 +177,7 @@ def process_order_changes(instance: Order, created: bool, **kwargs: dict[Any, An f"{vendor_name.title()}Vendor", ) - vendor.buy_order_product(order_product) # type: ignore [attr-defined] + vendor.buy_order_product(order_product) except Exception as e: order_product.add_error( diff --git a/engine/core/sitemaps.py b/engine/core/sitemaps.py index ce30bfe6..b43e65c5 100644 --- a/engine/core/sitemaps.py +++ b/engine/core/sitemaps.py @@ -12,7 +12,7 @@ class SitemapLanguageMixin: return getattr(req, "LANGUAGE_CODE", settings.LANGUAGE_CODE) -class StaticPagesSitemap(SitemapLanguageMixin, Sitemap): # type: ignore [type-arg] +class StaticPagesSitemap(SitemapLanguageMixin, Sitemap): protocol = "https" changefreq = "monthly" priority = 0.8 @@ -58,7 +58,7 @@ class StaticPagesSitemap(SitemapLanguageMixin, Sitemap): # type: ignore [type-a return obj.get("lastmod") -class ProductSitemap(SitemapLanguageMixin, Sitemap): # type: ignore [type-arg] +class ProductSitemap(SitemapLanguageMixin, Sitemap): protocol = "https" changefreq = "daily" priority = 0.9 @@ -84,7 +84,7 @@ class ProductSitemap(SitemapLanguageMixin, Sitemap): # type: ignore [type-arg] return f"/{self._lang()}/product/{obj.slug if obj.slug else '404-non-existent-product'}" -class CategorySitemap(SitemapLanguageMixin, Sitemap): # type: ignore [type-arg] +class CategorySitemap(SitemapLanguageMixin, Sitemap): protocol = "https" changefreq = "weekly" priority = 0.7 @@ -109,7 +109,7 @@ class CategorySitemap(SitemapLanguageMixin, Sitemap): # type: ignore [type-arg] return f"/{self._lang()}/catalog/{obj.slug if obj.slug else '404-non-existent-category'}" -class BrandSitemap(SitemapLanguageMixin, Sitemap): # type: ignore [type-arg] +class BrandSitemap(SitemapLanguageMixin, Sitemap): protocol = "https" changefreq = "weekly" priority = 0.6 diff --git a/engine/core/templatetags/arith.py b/engine/core/templatetags/arith.py index fbd9dfa1..a3e000d2 100644 --- a/engine/core/templatetags/arith.py +++ b/engine/core/templatetags/arith.py @@ -8,7 +8,7 @@ register = template.Library() def _to_float(val: object) -> float: conv: float = 0.0 with suppress(Exception): - return float(val) # type: ignore [arg-type] + return float(val) return conv diff --git a/engine/core/utils/__init__.py b/engine/core/utils/__init__.py index 5a23312a..bb6e3a41 100644 --- a/engine/core/utils/__init__.py +++ b/engine/core/utils/__init__.py @@ -66,15 +66,15 @@ def get_random_code() -> str: return get_random_string(20) -def get_product_uuid_as_path(instance, filename: str = "") -> str: # type: ignore [no-untyped-def] +def get_product_uuid_as_path(instance, filename: str = "") -> str: return "products" + "/" + str(instance.product.uuid) + "/" + filename -def get_vendor_name_as_path(instance, filename: str = "") -> str: # type: ignore [no-untyped-def] +def get_vendor_name_as_path(instance, filename: str = "") -> str: return "vendors_responses/" + str(instance.name) + "/" + filename -def get_brand_name_as_path(instance, filename: str = "") -> str: # type: ignore [no-untyped-def] +def get_brand_name_as_path(instance, filename: str = "") -> str: return "brands/" + str(instance.name) + "/" + filename @@ -150,7 +150,7 @@ def get_project_parameters() -> Any: return parameters -def resolve_translations_for_elasticsearch(instance, field_name: str) -> None: # type: ignore [no-untyped-def] +def resolve_translations_for_elasticsearch(instance, field_name: str) -> None: """ Resolves translations for a given field in an Elasticsearch-compatible format. It checks if the localized version of the field contains data, @@ -211,7 +211,7 @@ def is_status_code_success(status_code: int) -> bool: def get_dynamic_email_connection() -> EmailBackend: - return mail.get_connection( # type: ignore [no-any-return] + return mail.get_connection( host=config.EMAIL_HOST, port=config.EMAIL_PORT, username=config.EMAIL_HOST_USER, diff --git a/engine/core/utils/caching.py b/engine/core/utils/caching.py index a51754a5..7f1a9fe1 100644 --- a/engine/core/utils/caching.py +++ b/engine/core/utils/caching.py @@ -43,14 +43,14 @@ def web_cache( request: Request | Context, key: str, data: dict[str, Any], timeout: int ) -> dict[str, Any]: if not data and not timeout: - return {"data": get_cached_value(request.user, key)} # type: ignore [assignment, arg-type] + return {"data": get_cached_value(request.user, key)} if (data and not timeout) or (timeout and not data): raise BadRequest(_("both data and timeout are required")) if not 0 < int(timeout) < 216000: raise BadRequest( _("invalid timeout value, it must be between 0 and 216000 seconds") ) - return {"data": set_cached_value(request.user, key, data, timeout)} # type: ignore [assignment, arg-type] + return {"data": set_cached_value(request.user, key, data, timeout)} def set_default_cache() -> None: diff --git a/engine/core/utils/commerce.py b/engine/core/utils/commerce.py index f6035e6e..4a9e2c91 100644 --- a/engine/core/utils/commerce.py +++ b/engine/core/utils/commerce.py @@ -160,7 +160,7 @@ def get_top_returned_products( p = product_by_id[pid] img = "" with suppress(Exception): - img = p.images.first().image_url if p.images.exists() else "" # type: ignore [union-attr] + img = p.images.first().image_url if p.images.exists() else "" result.append( { "name": p.name, diff --git a/engine/core/utils/emailing.py b/engine/core/utils/emailing.py index c570ba1c..4cd82d2d 100644 --- a/engine/core/utils/emailing.py +++ b/engine/core/utils/emailing.py @@ -121,7 +121,7 @@ def send_order_finished_email(order_pk: str) -> tuple[bool, str]: "order_products": ops, "project_name": settings.PROJECT_NAME, "contact_email": config.EMAIL_FROM, - "total_price": round(sum(0.0 or op.buy_price for op in ops), 2), # type: ignore [misc] + "total_price": round(sum(0.0 or op.buy_price for op in ops), 2), "display_system_attributes": order.user.has_perm("core.view_order"), "today": datetime.today(), }, diff --git a/engine/core/utils/vendors.py b/engine/core/utils/vendors.py index efd18be0..3edf4304 100644 --- a/engine/core/utils/vendors.py +++ b/engine/core/utils/vendors.py @@ -16,7 +16,7 @@ def get_vendors_integrations(name: str | None = None) -> list[AbstractVendor]: for vendor in vendors: try: - module_name, class_name = vendor.integration_path.rsplit(".", 1) # type: ignore [union-attr] + module_name, class_name = vendor.integration_path.rsplit(".", 1) vendors_integrations.append(create_object(module_name, class_name)) except Exception as e: logger.warning( diff --git a/engine/core/validators.py b/engine/core/validators.py index 525bb927..3b3643d0 100644 --- a/engine/core/validators.py +++ b/engine/core/validators.py @@ -11,11 +11,11 @@ def validate_category_image_dimensions( if image: try: - width, height = get_image_dimensions(image.file) # type: ignore [arg-type] + width, height = get_image_dimensions(image.file) except (FileNotFoundError, OSError, ValueError): return - if int(width) > max_width or int(height) > max_height: # type: ignore [arg-type] + if int(width) > max_width or int(height) > max_height: raise ValidationError( _( f"image dimensions should not exceed w{max_width} x h{max_height} pixels" diff --git a/engine/core/vendors/__init__.py b/engine/core/vendors/__init__.py index b2c2f249..28145d4f 100644 --- a/engine/core/vendors/__init__.py +++ b/engine/core/vendors/__init__.py @@ -343,7 +343,7 @@ class AbstractVendor: f"No rate found for {currency} in {rates} with probider {provider}..." ) - return float(round(price / rate, 2)) if rate else float(round(price, 2)) # type: ignore [arg-type, operator] + return float(round(price / rate, 2)) if rate else float(round(price, 2)) @staticmethod def round_price_marketologically(price: float) -> float: @@ -536,7 +536,7 @@ class AbstractVendor: Attribute.objects.filter(name=key, group=attr_group) .order_by("uuid") .first() - ) # type: ignore [assignment] + ) fields_to_update: list[str] = [] if not attribute.is_active: attribute.is_active = True diff --git a/engine/core/views.py b/engine/core/views.py index 8ca22bf2..21c69e7d 100644 --- a/engine/core/views.py +++ b/engine/core/views.py @@ -104,7 +104,7 @@ def sitemap_index(request, *args, **kwargs): # noinspection PyTypeChecker -sitemap_index.__doc__ = _( # type: ignore [assignment] +sitemap_index.__doc__ = _( "Handles the request for the sitemap index and returns an XML response. " "It ensures the response includes the appropriate content type header for XML." ) @@ -119,7 +119,7 @@ def sitemap_detail(request, *args, **kwargs): # noinspection PyTypeChecker -sitemap_detail.__doc__ = _( # type: ignore [assignment] +sitemap_detail.__doc__ = _( "Handles the detailed view response for a sitemap. " "This function processes the request, fetches the appropriate " "sitemap detail response, and sets the Content-Type header for XML." @@ -157,7 +157,7 @@ class CustomRedocView(SpectacularRedocView): class SupportedLanguagesView(APIView): __doc__ = _( "Returns a list of supported languages and their corresponding information." - ) # type: ignore [assignment] + ) serializer_class = LanguageSerializer permission_classes = [ @@ -189,7 +189,7 @@ class SupportedLanguagesView(APIView): @extend_schema_view(**PARAMETERS_SCHEMA) class WebsiteParametersView(APIView): - __doc__ = _("Returns the parameters of the website as a JSON object.") # type: ignore [assignment] + __doc__ = _("Returns the parameters of the website as a JSON object.") serializer_class = None permission_classes = [ @@ -212,7 +212,7 @@ class WebsiteParametersView(APIView): class CacheOperatorView(APIView): __doc__ = _( "Handles cache operations such as reading and setting cache data with a specified key and timeout." - ) # type: ignore [assignment] + ) serializer_class = CacheOperatorSerializer permission_classes = [ @@ -229,9 +229,9 @@ class CacheOperatorView(APIView): return Response( data=web_cache( request, - request.data.get("key"), # type: ignore [arg-type] + request.data.get("key"), request.data.get("data", {}), - request.data.get("timeout"), # type: ignore [arg-type] + request.data.get("timeout"), ), status=status.HTTP_200_OK, ) @@ -239,7 +239,7 @@ class CacheOperatorView(APIView): @extend_schema_view(**CONTACT_US_SCHEMA) class ContactUsView(APIView): - __doc__ = _("Handles `contact us` form submissions.") # type: ignore [assignment] + __doc__ = _("Handles `contact us` form submissions.") serializer_class = ContactUsSerializer renderer_classes = [ @@ -253,7 +253,7 @@ class ContactUsView(APIView): def post(self, request: Request, *args, **kwargs) -> Response: serializer = self.serializer_class(data=request.data) serializer.is_valid(raise_exception=True) - contact_us_email.delay(serializer.validated_data) # type: ignore [attr-defined] + contact_us_email.delay(serializer.validated_data) return Response(data=serializer.data, status=status.HTTP_200_OK) @@ -262,7 +262,7 @@ class ContactUsView(APIView): class RequestCursedURLView(APIView): __doc__ = _( "Handles requests for processing and validating URLs from incoming POST requests." - ) # type: ignore [assignment] + ) permission_classes = [ AllowAny, @@ -304,7 +304,7 @@ class RequestCursedURLView(APIView): @extend_schema_view(**SEARCH_SCHEMA) class GlobalSearchView(APIView): - __doc__ = _("Handles global search queries.") # type: ignore [assignment] + __doc__ = _("Handles global search queries.") renderer_classes = [ CamelCaseJSONRenderer, @@ -327,7 +327,7 @@ class GlobalSearchView(APIView): @extend_schema_view(**BUY_AS_BUSINESS_SCHEMA) class BuyAsBusinessView(APIView): - __doc__ = _("Handles the logic of buying as a business without registration.") # type: ignore [assignment] + __doc__ = _("Handles the logic of buying as a business without registration.") # noinspection PyUnusedLocal @method_decorator( @@ -374,7 +374,7 @@ class BuyAsBusinessView(APIView): @extend_schema_view(**DOWNLOAD_DIGITAL_ASSET_SCHEMA) class DownloadDigitalAssetView(APIView): - __doc__ = _( # type: ignore [assignment] + __doc__ = _( "Handles the downloading of a digital asset associated with an order.\n" "This function attempts to serve the digital asset file located in the " "storage directory of the project. If the file is not found, an HTTP 404 " @@ -409,7 +409,7 @@ class DownloadDigitalAssetView(APIView): if not order_product.download.order_product.product: raise BadRequest(_("the order product does not have a product")) - file_path = order_product.download.order_product.product.stocks.first().digital_asset.path # type: ignore [union-attr] + file_path = order_product.download.order_product.product.stocks.first().digital_asset.path content_type, encoding = mimetypes.guess_type(file_path) if not content_type: @@ -453,7 +453,7 @@ def favicon_view(request: HttpRequest, *args, **kwargs) -> HttpResponse | FileRe # noinspection PyTypeChecker -favicon_view.__doc__ = _( # type: ignore [assignment] +favicon_view.__doc__ = _( "Handles requests for the favicon of a website.\n" "This function attempts to serve the favicon file located in the static directory of the project. " "If the favicon file is not found, an HTTP 404 error is raised to indicate the resource is unavailable." @@ -465,7 +465,7 @@ def index(request: HttpRequest, *args, **kwargs) -> HttpResponse | HttpResponseR # noinspection PyTypeChecker -index.__doc__ = _( # type: ignore [assignment] +index.__doc__ = _( "Redirects the request to the admin index page. " "The function handles incoming HTTP requests and redirects them to the Django " "admin interface index page. It uses Django's `redirect` function for handling " @@ -478,9 +478,7 @@ def version(request: HttpRequest, *args, **kwargs) -> HttpResponse: # noinspection PyTypeChecker -version.__doc__ = _( # type: ignore [assignment] - "Returns current version of the eVibes. " -) +version.__doc__ = _("Returns current version of the eVibes. ") def dashboard_callback(request: HttpRequest, context: Context) -> Context: @@ -631,7 +629,7 @@ def dashboard_callback(request: HttpRequest, context: Context) -> Context: with suppress(Exception): quick_links_section = settings.UNFOLD.get("SIDEBAR", {}).get("navigation", [])[ 1 - ] # type: ignore[assignment] + ] for item in quick_links_section.get("items", []): title = item.get("title") link = item.get("link") @@ -661,7 +659,7 @@ def dashboard_callback(request: HttpRequest, context: Context) -> Context: if product: img = ( product.images.first().image_url if product.images.exists() else "" - ) # type: ignore [union-attr] + ) most_wished = { "name": product.name, "image": img, @@ -684,7 +682,7 @@ def dashboard_callback(request: HttpRequest, context: Context) -> Context: if not pid or pid not in product_by_id: continue p = product_by_id[pid] - img = p.images.first().image_url if p.images.exists() else "" # type: ignore [union-attr] + img = p.images.first().image_url if p.images.exists() else "" most_wished_list.append( { "name": p.name, @@ -783,7 +781,7 @@ def dashboard_callback(request: HttpRequest, context: Context) -> Context: if product: img = ( product.images.first().image_url if product.images.exists() else "" - ) # type: ignore [union-attr] + ) most_popular = { "name": product.name, "image": img, @@ -806,7 +804,7 @@ def dashboard_callback(request: HttpRequest, context: Context) -> Context: if not pid or pid not in product_by_id: continue p = product_by_id[pid] - img = p.images.first().image_url if p.images.exists() else "" # type: ignore [union-attr] + img = p.images.first().image_url if p.images.exists() else "" most_popular_list.append( { "name": p.name, @@ -905,6 +903,4 @@ def dashboard_callback(request: HttpRequest, context: Context) -> Context: return context -dashboard_callback.__doc__ = _( # type: ignore [assignment] - "Returns custom variables for Dashboard. " -) +dashboard_callback.__doc__ = _("Returns custom variables for Dashboard. ") diff --git a/engine/core/viewsets.py b/engine/core/viewsets.py index 367d436f..c0681ae4 100644 --- a/engine/core/viewsets.py +++ b/engine/core/viewsets.py @@ -139,7 +139,7 @@ logger = logging.getLogger(__name__) class EvibesViewSet(ModelViewSet): - __doc__ = _( # type: ignore + __doc__ = _( "Defines a viewset for managing Evibes-related operations. " "The EvibesViewSet class inherits from ModelViewSet and provides functionality " "for handling actions and operations on Evibes entities. It includes support " @@ -161,7 +161,7 @@ class EvibesViewSet(ModelViewSet): # noinspection PyTypeChecker return self.action_serializer_classes.get( self.action, super().get_serializer_class() - ) # type: ignore [arg-type] + ) @extend_schema_view(**ATTRIBUTE_GROUP_SCHEMA) diff --git a/engine/core/widgets.py b/engine/core/widgets.py index eb484863..10098d34 100644 --- a/engine/core/widgets.py +++ b/engine/core/widgets.py @@ -11,7 +11,7 @@ from django.utils.safestring import SafeString class JSONTableWidget(forms.Widget): template_name = "json_table_widget.html" - def format_value(self, value: str | dict[str, Any]) -> str | dict[str, Any]: # type: ignore [override] + def format_value(self, value: str | dict[str, Any]) -> str | dict[str, Any]: if isinstance(value, dict): return value try: @@ -40,8 +40,8 @@ class JSONTableWidget(forms.Widget): json_data = {} try: - keys = data.getlist(f"{name}_key") # type: ignore [attr-defined] - values = data.getlist(f"{name}_value") # type: ignore [attr-defined] + keys = data.getlist(f"{name}_key") + values = data.getlist(f"{name}_value") for key, value in zip(keys, values, strict=True): if key.strip(): try: diff --git a/engine/payments/admin.py b/engine/payments/admin.py index 4cd4b905..222a7cb8 100644 --- a/engine/payments/admin.py +++ b/engine/payments/admin.py @@ -9,7 +9,7 @@ from engine.payments.forms import GatewayForm, TransactionForm from engine.payments.models import Balance, Gateway, Transaction -class TransactionInline(TabularInline): # type: ignore [type-arg] +class TransactionInline(TabularInline): model = Transaction form = TransactionForm extra = 1 @@ -23,7 +23,7 @@ class TransactionInline(TabularInline): # type: ignore [type-arg] @register(Balance) -class BalanceAdmin(ActivationActionsMixin, ModelAdmin): # type: ignore [misc, type-arg] +class BalanceAdmin(ActivationActionsMixin, ModelAdmin): inlines = (TransactionInline,) list_display = ("user", "amount") search_fields = ("user__email",) @@ -35,7 +35,7 @@ class BalanceAdmin(ActivationActionsMixin, ModelAdmin): # type: ignore [misc, t @register(Transaction) -class TransactionAdmin(ActivationActionsMixin, ModelAdmin): # type: ignore [misc, type-arg] +class TransactionAdmin(ActivationActionsMixin, ModelAdmin): list_display = ("balance", "amount", "order", "modified", "created") search_fields = ("balance__user__email", "currency", "payment_method") list_filter = ("currency", "payment_method") @@ -44,7 +44,7 @@ class TransactionAdmin(ActivationActionsMixin, ModelAdmin): # type: ignore [mis @register(Gateway) -class GatewayAdmin(ActivationActionsMixin, ModelAdmin): # type: ignore [misc] +class GatewayAdmin(ActivationActionsMixin, ModelAdmin): list_display = ( "name", "can_be_used", @@ -57,8 +57,8 @@ class GatewayAdmin(ActivationActionsMixin, ModelAdmin): # type: ignore [misc] ordering = ("name",) form = GatewayForm - def can_be_used(self, obj: Gateway) -> bool: # type: ignore[override] + def can_be_used(self, obj: Gateway) -> bool: return obj.can_be_used - can_be_used.boolean = True # type: ignore[attr-defined] - can_be_used.short_description = _("can be used") # type: ignore[attr-defined] + can_be_used.boolean = True + can_be_used.short_description = _("can be used") diff --git a/engine/payments/forms.py b/engine/payments/forms.py index cfa3d522..41de8563 100644 --- a/engine/payments/forms.py +++ b/engine/payments/forms.py @@ -4,7 +4,7 @@ from engine.core.widgets import JSONTableWidget from engine.payments.models import Gateway, Transaction -class TransactionForm(forms.ModelForm): # type: ignore [type-arg] +class TransactionForm(forms.ModelForm): class Meta: model = Transaction fields = "__all__" @@ -13,7 +13,7 @@ class TransactionForm(forms.ModelForm): # type: ignore [type-arg] } -class GatewayForm(forms.ModelForm): # type: ignore [type-arg] +class GatewayForm(forms.ModelForm): class Meta: model = Gateway fields = "__all__" diff --git a/engine/payments/managers.py b/engine/payments/managers.py index 80148a1e..36a28f90 100644 --- a/engine/payments/managers.py +++ b/engine/payments/managers.py @@ -58,6 +58,6 @@ class GatewayQuerySet(QuerySet): ).order_by("-priority") -class GatewayManager(Manager.from_queryset(GatewayQuerySet)): # type: ignore [misc] +class GatewayManager(Manager.from_queryset(GatewayQuerySet)): def get_queryset(self) -> QuerySet: return super().get_queryset().can_be_used() diff --git a/engine/payments/serializers.py b/engine/payments/serializers.py index f2faac8c..4c89b6f6 100644 --- a/engine/payments/serializers.py +++ b/engine/payments/serializers.py @@ -4,17 +4,17 @@ from rest_framework.serializers import ModelSerializer, Serializer from engine.payments.models import Transaction -class DepositSerializer(Serializer): # type: ignore [type-arg] +class DepositSerializer(Serializer): amount = FloatField(required=True) -class TransactionSerializer(ModelSerializer): # type: ignore [type-arg] +class TransactionSerializer(ModelSerializer): class Meta: model = Transaction fields = "__all__" -class TransactionProcessSerializer(ModelSerializer): # type: ignore [type-arg] +class TransactionProcessSerializer(ModelSerializer): process = JSONField(required=True) order_hr_id = SerializerMethodField(read_only=True, required=False) order_uuid = SerializerMethodField(read_only=True, required=False) @@ -31,6 +31,6 @@ class TransactionProcessSerializer(ModelSerializer): # type: ignore [type-arg] read_only_fields = ("process", "order_hr_id", "order_uuid") -class LimitsSerializer(Serializer): # type: ignore [type-arg] +class LimitsSerializer(Serializer): min_amount = FloatField(read_only=True) max_amount = FloatField(read_only=True) diff --git a/engine/payments/signals.py b/engine/payments/signals.py index 32a55b8a..3aa05c04 100644 --- a/engine/payments/signals.py +++ b/engine/payments/signals.py @@ -38,7 +38,7 @@ def process_transaction_changes( <= instance.amount <= instance.gateway.maximum_transaction_amount ): - gateway.process_transaction(instance) # type: ignore [union-attr] + gateway.process_transaction(instance) else: raise BadLimitsError( _( diff --git a/engine/payments/views.py b/engine/payments/views.py index d63fff22..4afd4628 100644 --- a/engine/payments/views.py +++ b/engine/payments/views.py @@ -24,7 +24,7 @@ logger = logging.getLogger(__name__) @extend_schema_view(**DEPOSIT_SCHEMA) class DepositView(APIView): - __doc__ = _( # type: ignore [assignment] + __doc__ = _( "This class provides an API endpoint to handle deposit transactions.\n" "It supports the creation of a deposit transaction after validating the " "provided data. If the user is not authenticated, an appropriate response " @@ -57,7 +57,7 @@ class DepositView(APIView): @extend_schema(exclude=True) class CallbackAPIView(APIView): - __doc__ = _( # type: ignore [assignment] + __doc__ = _( "Handles incoming callback requests to the API.\n" "This class processes and routes incoming HTTP POST requests to the appropriate " "pgateway handler based on the provided gateway parameter. It is designed to handle " @@ -92,7 +92,7 @@ class CallbackAPIView(APIView): @extend_schema_view(**LIMITS_SCHEMA) class LimitsAPIView(APIView): - __doc__ = _( # type: ignore [assignment] + __doc__ = _( "This endpoint returns minimal and maximal allowed deposit amounts across available gateways." ) diff --git a/engine/payments/viewsets.py b/engine/payments/viewsets.py index 585ee39e..c8644bf0 100644 --- a/engine/payments/viewsets.py +++ b/engine/payments/viewsets.py @@ -9,8 +9,8 @@ from engine.payments.serializers import TransactionSerializer @extend_schema_view(**TRANSACTION_SCHEMA) -class TransactionViewSet(ReadOnlyModelViewSet): # type: ignore - __doc__ = _( # type: ignore [assignment] +class TransactionViewSet(ReadOnlyModelViewSet): + __doc__ = _( "ViewSet for handling read-only operations on the Transaction model. " "This class provides a read-only interface for interacting with transaction data. " "It uses the TransactionSerializer for serializing and deserializing " diff --git a/engine/vibes_auth/admin.py b/engine/vibes_auth/admin.py index 8e393a30..0e2aad00 100644 --- a/engine/vibes_auth/admin.py +++ b/engine/vibes_auth/admin.py @@ -44,7 +44,7 @@ from engine.vibes_auth.models import ( ) -class BalanceInline(TabularInline): # type: ignore [type-arg] +class BalanceInline(TabularInline): model = Balance can_delete = False extra = 0 @@ -54,7 +54,7 @@ class BalanceInline(TabularInline): # type: ignore [type-arg] icon = "fa-solid fa-wallet" -class OrderInline(TabularInline): # type: ignore [type-arg] +class OrderInline(TabularInline): model = Order extra = 0 verbose_name = _("order") @@ -63,7 +63,7 @@ class OrderInline(TabularInline): # type: ignore [type-arg] icon = "fa-solid fa-cart-shopping" -class UserAdmin(ActivationActionsMixin, BaseUserAdmin, ModelAdmin): # type: ignore [misc, type-arg] +class UserAdmin(ActivationActionsMixin, BaseUserAdmin, ModelAdmin): inlines = (BalanceInline, OrderInline) fieldsets = ( (None, {"fields": ("email", "password")}), @@ -165,11 +165,11 @@ class ChatThreadAdmin(ModelAdmin): readonly_fields = ("created", "modified") @admin.action(description=_("Close selected threads")) - def close_threads(self, request, queryset): # type: ignore[no-untyped-def] + def close_threads(self, request, queryset): queryset.update(status=ThreadStatus.CLOSED) @admin.action(description=_("Open selected threads")) - def open_threads(self, request, queryset): # type: ignore[no-untyped-def] + def open_threads(self, request, queryset): queryset.update(status=ThreadStatus.OPEN) diff --git a/engine/vibes_auth/forms.py b/engine/vibes_auth/forms.py index 26725eac..fba74eff 100644 --- a/engine/vibes_auth/forms.py +++ b/engine/vibes_auth/forms.py @@ -4,7 +4,7 @@ from engine.core.widgets import JSONTableWidget from engine.vibes_auth.models import User -class UserForm(UserChangeForm): # type: ignore [type-arg] +class UserForm(UserChangeForm): password = ReadOnlyPasswordHashField(label="Password") class Meta: diff --git a/engine/vibes_auth/messaging/auth.py b/engine/vibes_auth/messaging/auth.py index 035843bb..f658efe5 100644 --- a/engine/vibes_auth/messaging/auth.py +++ b/engine/vibes_auth/messaging/auth.py @@ -36,7 +36,7 @@ class JWTAuthMiddleware(BaseMiddleware): def __init__(self, token_str: str): self.META = {"HTTP_X_EVIBES_AUTH": f"Bearer {token_str}"} - user, _ = jwt_auth.authenticate(_Req(token)) # type: ignore[arg-type] + user, _ = jwt_auth.authenticate(_Req(token)) scope["user"] = user return await super().__call__(scope, receive, send) diff --git a/engine/vibes_auth/messaging/forwarders/telegram.py b/engine/vibes_auth/messaging/forwarders/telegram.py index a9f1ae41..5e523e53 100644 --- a/engine/vibes_auth/messaging/forwarders/telegram.py +++ b/engine/vibes_auth/messaging/forwarders/telegram.py @@ -26,7 +26,7 @@ def _get_bot() -> Bot | None: if not is_telegram_enabled(): logger.warning("Telegram forwarder disabled: missing aiogram or TELEGRAM_TOKEN") return None - return Bot(token=settings.TELEGRAM_TOKEN, parse_mode=ParseMode.HTML) # type: ignore[arg-type] + return Bot(token=settings.TELEGRAM_TOKEN, parse_mode=ParseMode.HTML) def build_router() -> Router | None: @@ -37,7 +37,7 @@ def build_router() -> Router | None: router: Router = Router() @router.message(Command("start")) - async def cmd_start(message: types.Message): # type: ignore[valid-type] + async def cmd_start(message: types.Message): parts = (message.text or "").split(maxsplit=1) if len(parts) < 2: await message.answer( @@ -50,12 +50,12 @@ def build_router() -> Router | None: def _link(): try: retrieved_user = User.objects.get(activation_token=token) - except User.DoesNotExist: # type: ignore[attr-defined] + except User.DoesNotExist: return None attrs = dict(retrieved_user.attributes or {}) - attrs["telegram_id"] = message.from_user.id if message.from_user else None # type: ignore[union-attr] + attrs["telegram_id"] = message.from_user.id if message.from_user else None retrieved_user.attributes = attrs - retrieved_user.save(update_fields=["attributes", "modified"]) # type: ignore[attr-defined] + retrieved_user.save(update_fields=["attributes", "modified"]) return retrieved_user user = await asyncio.to_thread(_link) @@ -65,8 +65,8 @@ def build_router() -> Router | None: await message.answer("Your Telegram account has been linked successfully.") @router.message(Command("unlink")) - async def cmd_unlink(message: types.Message): # type: ignore[valid-type] - tid = message.from_user.id if message.from_user else None # type: ignore[union-attr] + async def cmd_unlink(message: types.Message): + tid = message.from_user.id if message.from_user else None if not tid: await message.answer("Cannot unlink: no Telegram user id.") return @@ -83,7 +83,7 @@ def build_router() -> Router | None: await message.answer("No linked account found.") @router.message(Command("help")) - async def cmd_help(message: types.Message): # type: ignore[valid-type] + async def cmd_help(message: types.Message): await message.answer( "Commands:\n" "/start — link your account\n" @@ -92,7 +92,7 @@ def build_router() -> Router | None: ) @router.message() - async def any_message(message: types.Message): # type: ignore[valid-type] + async def any_message(message: types.Message): from engine.vibes_auth.messaging.services import ( send_message as svc_send_message, ) @@ -106,7 +106,7 @@ def build_router() -> Router | None: staff_user = User.objects.get( attributes__telegram_id=tid, is_staff=True, is_active=True ) - except User.DoesNotExist: # type: ignore[attr-defined] + except User.DoesNotExist: return None, None, None # group check if not staff_user.groups.filter(name=USER_SUPPORT_GROUP_NAME).exists(): @@ -193,7 +193,7 @@ def install_aiohttp_webhook(app) -> None: if not is_telegram_enabled(): logger.warning("Telegram forwarder not installed: disabled") return - dp = Dispatcher() # type: ignore[call-arg] + dp = Dispatcher() router = build_router() if router: dp.include_router(router) @@ -202,5 +202,5 @@ def install_aiohttp_webhook(app) -> None: return SimpleRequestHandler(dispatcher=dp, bot=bot).register( app, path="/telegram/webhook/" + settings.TELEGRAM_TOKEN - ) # type: ignore[arg-type] + ) logger.info("Telegram webhook handler installed on aiohttp app.") diff --git a/engine/vibes_auth/messaging/services.py b/engine/vibes_auth/messaging/services.py index 91427d9c..0c99e08c 100644 --- a/engine/vibes_auth/messaging/services.py +++ b/engine/vibes_auth/messaging/services.py @@ -103,7 +103,7 @@ def send_message( def auto_reply(thread: ChatThread) -> None: text = _("We're searching for the operator to answer you already, hold by!") - msg = ChatMessage.objects.create( # type: ignore [misc] + msg = ChatMessage.objects.create( thread=thread, sender_type=SenderType.SYSTEM, sender_user=None, diff --git a/engine/vibes_auth/models.py b/engine/vibes_auth/models.py index 7156b0c6..13df78d8 100644 --- a/engine/vibes_auth/models.py +++ b/engine/vibes_auth/models.py @@ -37,9 +37,9 @@ from engine.vibes_auth.managers import UserManager from engine.vibes_auth.validators import validate_phone_number -class User(AbstractUser, NiceModel): # type: ignore [django-manager-missing] +class User(AbstractUser, NiceModel): __doc__ = _( - "Represents a User entity with customized fields and methods for extended functionality. " # type: ignore + "Represents a User entity with customized fields and methods for extended functionality. " "This class extends the AbstractUser model and integrates additional features like " "custom email login, validation methods, subscription status, verification, and " "attributes storage. It also provides utilities for managing recently viewed items and " @@ -62,9 +62,9 @@ class User(AbstractUser, NiceModel): # type: ignore [django-manager-missing] validate_phone_number, ], ) - username: None = None # type: ignore [assignment] - first_name = CharField(_("first_name"), max_length=150, blank=True, null=True) # type: ignore [assignment] - last_name = CharField(_("last_name"), max_length=150, blank=True, null=True) # type: ignore [assignment] + username: None = None + first_name = CharField(_("first_name"), max_length=150, blank=True, null=True) + last_name = CharField(_("last_name"), max_length=150, blank=True, null=True) avatar = ImageField( null=True, verbose_name=_("avatar"), @@ -106,7 +106,7 @@ class User(AbstractUser, NiceModel): # type: ignore [django-manager-missing] USERNAME_FIELD = "email" REQUIRED_FIELDS = [] # noinspection PyClassVar - objects = UserManager() # type: ignore [misc, assignment] + objects = UserManager() @cached_property def avatar_url(self) -> str: diff --git a/engine/vibes_auth/serializers.py b/engine/vibes_auth/serializers.py index 1db4cc02..9876ce65 100644 --- a/engine/vibes_auth/serializers.py +++ b/engine/vibes_auth/serializers.py @@ -200,7 +200,7 @@ class TokenObtainPairSerializer(TokenObtainSerializer): refresh = self.get_token(self.user) data["refresh"] = str(refresh) # noinspection PyUnresolvedReferences - data["access"] = str(refresh.access_token) # type: ignore [attr-defined] + data["access"] = str(refresh.access_token) data["user"] = ( UserSerializer(self.user).data if self.retrieve_user else self.user.pk ) diff --git a/engine/vibes_auth/views.py b/engine/vibes_auth/views.py index b6dc60b8..3ff1597c 100644 --- a/engine/vibes_auth/views.py +++ b/engine/vibes_auth/views.py @@ -30,7 +30,7 @@ logger = logging.getLogger(__name__) @extend_schema_view(**TOKEN_OBTAIN_SCHEMA) class TokenObtainPairView(TokenViewBase): - __doc__ = _( # type: ignore [assignment] + __doc__ = _( "Represents a view for getting a pair of access and refresh tokens and user's data. " "This view manages the process of handling token-based authentication where " "clients can get a pair of JWT tokens (access and refresh) using provided " @@ -38,12 +38,12 @@ class TokenObtainPairView(TokenViewBase): "rate limiting to protect against brute force attacks." ) - serializer_class = TokenObtainPairSerializer # type: ignore [assignment] - _serializer_class = TokenObtainPairSerializer # type: ignore [assignment] - permission_classes: list[Type[BasePermission]] = [ # type: ignore [assignment] + serializer_class = TokenObtainPairSerializer + _serializer_class = TokenObtainPairSerializer + permission_classes: list[Type[BasePermission]] = [ AllowAny, ] - authentication_classes: list[str] = [] # type: ignore [assignment] + authentication_classes: list[str] = [] @method_decorator(ratelimit(key="ip", rate="10/h")) def post( @@ -54,7 +54,7 @@ class TokenObtainPairView(TokenViewBase): @extend_schema_view(**TOKEN_REFRESH_SCHEMA) class TokenRefreshView(TokenViewBase): - __doc__ = _( # type: ignore [assignment] + __doc__ = _( "Handles refreshing of tokens for authentication purposes. " "This class is used to provide functionality for token refresh " "operations as part of an authentication system. It ensures that " @@ -63,12 +63,12 @@ class TokenRefreshView(TokenViewBase): "refresh inputs and produce appropriate outputs." ) - serializer_class = TokenRefreshSerializer # type: ignore [assignment] - _serializer_class = TokenRefreshSerializer # type: ignore [assignment] - permission_classes: list[Type[BasePermission]] = [ # type: ignore [assignment] + serializer_class = TokenRefreshSerializer + _serializer_class = TokenRefreshSerializer + permission_classes: list[Type[BasePermission]] = [ AllowAny, ] - authentication_classes: list[str] = [] # type: ignore [assignment] + authentication_classes: list[str] = [] @method_decorator(ratelimit(key="ip", rate="10/h")) def post( @@ -79,16 +79,16 @@ class TokenRefreshView(TokenViewBase): @extend_schema_view(**TOKEN_VERIFY_SCHEMA) class TokenVerifyView(TokenViewBase): - __doc__ = _( # type: ignore [assignment] + __doc__ = _( "Represents a view for verifying JSON Web Tokens (JWT) using specific serialization and validation logic. " ) - serializer_class = TokenVerifySerializer # type: ignore [assignment] - _serializer_class = TokenVerifySerializer # type: ignore [assignment] - permission_classes: list[Type[BasePermission]] = [ # type: ignore [assignment] + serializer_class = TokenVerifySerializer + _serializer_class = TokenVerifySerializer + permission_classes: list[Type[BasePermission]] = [ AllowAny, ] - authentication_classes: list[str] = [] # type: ignore [assignment] + authentication_classes: list[str] = [] def post( self, request: Request, *args: list[Any], **kwargs: dict[Any, Any] diff --git a/engine/vibes_auth/viewsets.py b/engine/vibes_auth/viewsets.py index 6e71ddc4..c0aa7d45 100644 --- a/engine/vibes_auth/viewsets.py +++ b/engine/vibes_auth/viewsets.py @@ -41,7 +41,7 @@ class UserViewSet( mixins.DestroyModelMixin, GenericViewSet, ): - __doc__ = _( # type: ignore [assignment] + __doc__ = _( "User view set implementation.\n" "Provides a set of actions that manage user-related data such as creation, " "retrieval, updates, deletion, and custom actions including password reset, " @@ -89,16 +89,16 @@ class UserViewSet( try: if not compare_digest( request.data.get("password"), request.data.get("confirm_password") - ): # type: ignore [arg-type] + ): return Response( {"error": _("passwords do not match")}, status=status.HTTP_400_BAD_REQUEST, ) - uuid = urlsafe_base64_decode(request.data.get("uidb_64")).decode() # type: ignore [arg-type] + uuid = urlsafe_base64_decode(request.data.get("uidb_64")).decode() user = User.objects.get(pk=uuid) - validate_password(password=request.data.get("password"), user=user) # type: ignore [arg-type] + validate_password(password=request.data.get("password"), user=user) password_reset_token = PasswordResetTokenGenerator() if not password_reset_token.check_token(user, request.data.get("token")): @@ -147,11 +147,11 @@ class UserViewSet( detail = "" activation_error: Type[Exception] | None = None try: - uuid = urlsafe_base64_decode(request.data.get("uidb_64")).decode() # type: ignore [arg-type] + uuid = urlsafe_base64_decode(request.data.get("uidb_64")).decode() user = User.objects.get(pk=uuid) if not user.check_token( urlsafe_base64_decode(request.data.get("token")).decode() - ): # type: ignore [arg-type] + ): return Response( {"error": _("activation link is invalid!")}, status=status.HTTP_400_BAD_REQUEST, @@ -175,7 +175,7 @@ class UserViewSet( detail = str(traceback.format_exc()) if user is None: if settings.DEBUG: - raise Exception from activation_error # type: ignore [misc] + raise Exception from activation_error return Response( {"error": _("activation link is invalid!"), "detail": detail}, status=status.HTTP_400_BAD_REQUEST, diff --git a/evibes/ftpstorage.py b/evibes/ftpstorage.py index a0e736ff..54b16ebf 100644 --- a/evibes/ftpstorage.py +++ b/evibes/ftpstorage.py @@ -4,7 +4,7 @@ from urllib.parse import urlparse from storages.backends.ftp import FTPStorage -class AbsoluteFTPStorage(FTPStorage): # type: ignore +class AbsoluteFTPStorage(FTPStorage): # noinspection PyProtectedMember # noinspection PyUnresolvedReferences diff --git a/evibes/locale/ar_AR/LC_MESSAGES/django.mo b/evibes/locale/ar_AR/LC_MESSAGES/django.mo index 0ee529c7..fcf5e77d 100644 Binary files a/evibes/locale/ar_AR/LC_MESSAGES/django.mo and b/evibes/locale/ar_AR/LC_MESSAGES/django.mo differ diff --git a/evibes/locale/ar_AR/LC_MESSAGES/django.po b/evibes/locale/ar_AR/LC_MESSAGES/django.po index d94ab378..eb6e5f21 100644 --- a/evibes/locale/ar_AR/LC_MESSAGES/django.po +++ b/evibes/locale/ar_AR/LC_MESSAGES/django.po @@ -167,10 +167,10 @@ msgid "" "## Authentication\n" "- Authentication is handled via JWT tokens. Include the token in the `X-EVIBES-AUTH` header of your requests in the format `Bearer `.\n" "- Access token lifetime is {\n" -" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600\n" "} {\"minutes\" if not DEBUG else \"hours\"}.\n" "- Refresh token lifetime is {\n" -" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600\n" "} hours.\n" "- Refresh tokens are automatically rotated and invalidated after usage for enhanced security.\n" "\n" @@ -216,9 +216,9 @@ msgstr "" "## المصادقة\n" "- يتم التعامل مع المصادقة عبر رموز JWT المميزة. قم بتضمين الرمز المميز في رأس \"X-EVIBES-AUTH\" لطلباتك بصيغة \"حامل \".\n" "{\n" -" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600\n" "} {\"minutes\" if not DEBUG else \"hours\"}{\n" -" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600\n" "}- يتم تدوير رموز التحديث تلقائيًا وإبطالها بعد الاستخدام لتعزيز الأمان.\n" "\n" "## التدويل (i18n)\n" diff --git a/evibes/locale/cs_CZ/LC_MESSAGES/django.mo b/evibes/locale/cs_CZ/LC_MESSAGES/django.mo index 09f709fb..84571096 100644 Binary files a/evibes/locale/cs_CZ/LC_MESSAGES/django.mo and b/evibes/locale/cs_CZ/LC_MESSAGES/django.mo differ diff --git a/evibes/locale/cs_CZ/LC_MESSAGES/django.po b/evibes/locale/cs_CZ/LC_MESSAGES/django.po index 51e910ae..c9d1a538 100644 --- a/evibes/locale/cs_CZ/LC_MESSAGES/django.po +++ b/evibes/locale/cs_CZ/LC_MESSAGES/django.po @@ -167,10 +167,10 @@ msgid "" "## Authentication\n" "- Authentication is handled via JWT tokens. Include the token in the `X-EVIBES-AUTH` header of your requests in the format `Bearer `.\n" "- Access token lifetime is {\n" -" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600\n" "} {\"minutes\" if not DEBUG else \"hours\"}.\n" "- Refresh token lifetime is {\n" -" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600\n" "} hours.\n" "- Refresh tokens are automatically rotated and invalidated after usage for enhanced security.\n" "\n" @@ -216,10 +216,10 @@ msgstr "" "## Ověřování\n" "- Ověřování se provádí pomocí tokenů JWT. Token zahrňte do hlavičky `X-EVIBES-AUTH` svých požadavků ve formátu `Bearer `.\n" "- Životnost přístupového tokenu je {\n" -" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600\n" "}. {\"minutes\" if not DEBUG else \"hours\"}.\n" "- Životnost tokenu pro obnovení je {\n" -" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600\n" "} hodin.\n" "- Tokeny pro obnovení jsou po použití automaticky rotovány a zneplatněny z důvodu vyšší bezpečnosti.\n" "\n" diff --git a/evibes/locale/da_DK/LC_MESSAGES/django.mo b/evibes/locale/da_DK/LC_MESSAGES/django.mo index c2ed534d..463771cf 100644 Binary files a/evibes/locale/da_DK/LC_MESSAGES/django.mo and b/evibes/locale/da_DK/LC_MESSAGES/django.mo differ diff --git a/evibes/locale/da_DK/LC_MESSAGES/django.po b/evibes/locale/da_DK/LC_MESSAGES/django.po index 8105f764..f5af89df 100644 --- a/evibes/locale/da_DK/LC_MESSAGES/django.po +++ b/evibes/locale/da_DK/LC_MESSAGES/django.po @@ -167,10 +167,10 @@ msgid "" "## Authentication\n" "- Authentication is handled via JWT tokens. Include the token in the `X-EVIBES-AUTH` header of your requests in the format `Bearer `.\n" "- Access token lifetime is {\n" -" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600\n" "} {\"minutes\" if not DEBUG else \"hours\"}.\n" "- Refresh token lifetime is {\n" -" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600\n" "} hours.\n" "- Refresh tokens are automatically rotated and invalidated after usage for enhanced security.\n" "\n" @@ -216,10 +216,10 @@ msgstr "" "## Autentificering\n" "- Autentificering håndteres via JWT-tokens. Inkluder tokenet i `X-EVIBES-AUTH`-headeren i dine anmodninger i formatet `Bearer `.\n" "- Adgangstokenets levetid er {\n" -" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600\n" "} {\"minutes\" if not DEBUG else \"hours\"}.\n" "- Opdateringstokenets levetid er {\n" -" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600\n" "} timer.\n" "- Refresh-tokens bliver automatisk roteret og ugyldiggjort efter brug for at øge sikkerheden.\n" "\n" diff --git a/evibes/locale/de_DE/LC_MESSAGES/django.mo b/evibes/locale/de_DE/LC_MESSAGES/django.mo index e480d5f1..dcf494f4 100644 Binary files a/evibes/locale/de_DE/LC_MESSAGES/django.mo and b/evibes/locale/de_DE/LC_MESSAGES/django.mo differ diff --git a/evibes/locale/de_DE/LC_MESSAGES/django.po b/evibes/locale/de_DE/LC_MESSAGES/django.po index d0bf1209..3f46812e 100644 --- a/evibes/locale/de_DE/LC_MESSAGES/django.po +++ b/evibes/locale/de_DE/LC_MESSAGES/django.po @@ -170,10 +170,10 @@ msgid "" "## Authentication\n" "- Authentication is handled via JWT tokens. Include the token in the `X-EVIBES-AUTH` header of your requests in the format `Bearer `.\n" "- Access token lifetime is {\n" -" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600\n" "} {\"minutes\" if not DEBUG else \"hours\"}.\n" "- Refresh token lifetime is {\n" -" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600\n" "} hours.\n" "- Refresh tokens are automatically rotated and invalidated after usage for enhanced security.\n" "\n" @@ -219,10 +219,10 @@ msgstr "" "## Authentifizierung\n" "- Die Authentifizierung erfolgt über JWT-Tokens. Fügen Sie das Token in den `X-EVIBES-AUTH`-Header Ihrer Anfragen im Format `Bearer ` ein.\n" "- Die Lebensdauer des Zugangstokens beträgt {\n" -" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600\n" "} {\"minutes\" if not DEBUG else \"hours\"}.\n" "- Die Lebensdauer von Auffrischungstoken beträgt {\n" -" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600\n" "} Stunden.\n" "- Refresh-Tokens werden automatisch rotiert und nach der Verwendung ungültig gemacht, um die Sicherheit zu erhöhen.\n" "\n" diff --git a/evibes/locale/en_GB/LC_MESSAGES/django.mo b/evibes/locale/en_GB/LC_MESSAGES/django.mo index e4b4500a..54e4717b 100644 Binary files a/evibes/locale/en_GB/LC_MESSAGES/django.mo and b/evibes/locale/en_GB/LC_MESSAGES/django.mo differ diff --git a/evibes/locale/en_GB/LC_MESSAGES/django.po b/evibes/locale/en_GB/LC_MESSAGES/django.po index ef41096d..de4fb4d6 100644 --- a/evibes/locale/en_GB/LC_MESSAGES/django.po +++ b/evibes/locale/en_GB/LC_MESSAGES/django.po @@ -171,10 +171,10 @@ msgid "" "## Authentication\n" "- Authentication is handled via JWT tokens. Include the token in the `X-EVIBES-AUTH` header of your requests in the format `Bearer `.\n" "- Access token lifetime is {\n" -" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600\n" "} {\"minutes\" if not DEBUG else \"hours\"}.\n" "- Refresh token lifetime is {\n" -" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600\n" "} hours.\n" "- Refresh tokens are automatically rotated and invalidated after usage for enhanced security.\n" "\n" @@ -220,10 +220,10 @@ msgstr "" "## Authentication\n" "- Authentication is handled via JWT tokens. Include the token in the `X-EVIBES-AUTH` header of your requests in the format `Bearer `.\n" "- Access token lifetime is {\n" -" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600\n" "} {\"minutes\" if not DEBUG else \"hours\"}.\n" "- Refresh token lifetime is {\n" -" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600\n" "} hours.\n" "- Refresh tokens are automatically rotated and invalidated after usage for enhanced security.\n" "\n" diff --git a/evibes/locale/en_US/LC_MESSAGES/django.mo b/evibes/locale/en_US/LC_MESSAGES/django.mo index 259f5851..a360a149 100644 Binary files a/evibes/locale/en_US/LC_MESSAGES/django.mo and b/evibes/locale/en_US/LC_MESSAGES/django.mo differ diff --git a/evibes/locale/en_US/LC_MESSAGES/django.po b/evibes/locale/en_US/LC_MESSAGES/django.po index 0bfce1c8..e8de4c1b 100644 --- a/evibes/locale/en_US/LC_MESSAGES/django.po +++ b/evibes/locale/en_US/LC_MESSAGES/django.po @@ -167,10 +167,10 @@ msgid "" "## Authentication\n" "- Authentication is handled via JWT tokens. Include the token in the `X-EVIBES-AUTH` header of your requests in the format `Bearer `.\n" "- Access token lifetime is {\n" -" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600\n" "} {\"minutes\" if not DEBUG else \"hours\"}.\n" "- Refresh token lifetime is {\n" -" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600\n" "} hours.\n" "- Refresh tokens are automatically rotated and invalidated after usage for enhanced security.\n" "\n" @@ -216,10 +216,10 @@ msgstr "" "## Authentication\n" "- Authentication is handled via JWT tokens. Include the token in the `X-EVIBES-AUTH` header of your requests in the format `Bearer `.\n" "- Access token lifetime is {\n" -" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600\n" "} {\"minutes\" if not DEBUG else \"hours\"}.\n" "- Refresh token lifetime is {\n" -" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600\n" "} hours.\n" "- Refresh tokens are automatically rotated and invalidated after usage for enhanced security.\n" "\n" diff --git a/evibes/locale/es_ES/LC_MESSAGES/django.mo b/evibes/locale/es_ES/LC_MESSAGES/django.mo index 87e30617..ecfd8546 100644 Binary files a/evibes/locale/es_ES/LC_MESSAGES/django.mo and b/evibes/locale/es_ES/LC_MESSAGES/django.mo differ diff --git a/evibes/locale/es_ES/LC_MESSAGES/django.po b/evibes/locale/es_ES/LC_MESSAGES/django.po index 2b0e273e..0ffc1cee 100644 --- a/evibes/locale/es_ES/LC_MESSAGES/django.po +++ b/evibes/locale/es_ES/LC_MESSAGES/django.po @@ -169,10 +169,10 @@ msgid "" "## Authentication\n" "- Authentication is handled via JWT tokens. Include the token in the `X-EVIBES-AUTH` header of your requests in the format `Bearer `.\n" "- Access token lifetime is {\n" -" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600\n" "} {\"minutes\" if not DEBUG else \"hours\"}.\n" "- Refresh token lifetime is {\n" -" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600\n" "} hours.\n" "- Refresh tokens are automatically rotated and invalidated after usage for enhanced security.\n" "\n" @@ -218,10 +218,10 @@ msgstr "" "## Autenticación\n" "- La autenticación se gestiona mediante tokens JWT. Incluya el token en la cabecera `X-EVIBES-AUTH` de sus peticiones con el formato `Bearer `.\n" "- La duración del token de acceso es {\n" -" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600\n" "} {\"minutes\" if not DEBUG else \"hours\"}.\n" "- La duración del token de actualización es de {\n" -" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600\n" "} horas.\n" "- Los tokens de actualización se rotan automáticamente y se invalidan después de su uso para mejorar la seguridad.\n" "\n" diff --git a/evibes/locale/fa_IR/LC_MESSAGES/django.po b/evibes/locale/fa_IR/LC_MESSAGES/django.po index 67548e09..3cc87687 100644 --- a/evibes/locale/fa_IR/LC_MESSAGES/django.po +++ b/evibes/locale/fa_IR/LC_MESSAGES/django.po @@ -182,7 +182,7 @@ msgid "" "EVIBES-AUTH` header of your requests in the format `Bearer `.\n" "- Access token lifetime is {\n" " SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not " -"DEBUG else 3600 # type: ignore [union-attr]\n" +"DEBUG else 3600\n" "} {\"minutes\" if not DEBUG else \"hours\"}.\n" "- Refresh token lifetime is {\n" " SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600 # " diff --git a/evibes/locale/fr_FR/LC_MESSAGES/django.mo b/evibes/locale/fr_FR/LC_MESSAGES/django.mo index 9ff63217..7c80f5b1 100644 Binary files a/evibes/locale/fr_FR/LC_MESSAGES/django.mo and b/evibes/locale/fr_FR/LC_MESSAGES/django.mo differ diff --git a/evibes/locale/fr_FR/LC_MESSAGES/django.po b/evibes/locale/fr_FR/LC_MESSAGES/django.po index 32e383b6..c7d9039c 100644 --- a/evibes/locale/fr_FR/LC_MESSAGES/django.po +++ b/evibes/locale/fr_FR/LC_MESSAGES/django.po @@ -172,10 +172,10 @@ msgid "" "## Authentication\n" "- Authentication is handled via JWT tokens. Include the token in the `X-EVIBES-AUTH` header of your requests in the format `Bearer `.\n" "- Access token lifetime is {\n" -" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600\n" "} {\"minutes\" if not DEBUG else \"hours\"}.\n" "- Refresh token lifetime is {\n" -" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600\n" "} hours.\n" "- Refresh tokens are automatically rotated and invalidated after usage for enhanced security.\n" "\n" @@ -221,10 +221,10 @@ msgstr "" "## Authentification\n" "- L'authentification est gérée par des jetons JWT. Incluez le jeton dans l'en-tête `X-EVIBES-AUTH` de vos requêtes au format `Bearer `.\n" "- La durée de vie du jeton d'accès est de {\n" -" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600\n" "} {\"minutes\" if not DEBUG else \"hours\"}.\n" "- La durée de vie du jeton de rafraîchissement est de {\n" -" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600\n" "} heures.\n" "- Les jetons de rafraîchissement font l'objet d'une rotation automatique et sont invalidés après utilisation pour une meilleure sécurité.\n" "\n" diff --git a/evibes/locale/he_IL/LC_MESSAGES/django.mo b/evibes/locale/he_IL/LC_MESSAGES/django.mo index 5fe2e76a..f828a579 100644 Binary files a/evibes/locale/he_IL/LC_MESSAGES/django.mo and b/evibes/locale/he_IL/LC_MESSAGES/django.mo differ diff --git a/evibes/locale/he_IL/LC_MESSAGES/django.po b/evibes/locale/he_IL/LC_MESSAGES/django.po index 650f2f06..99e4d0a2 100644 --- a/evibes/locale/he_IL/LC_MESSAGES/django.po +++ b/evibes/locale/he_IL/LC_MESSAGES/django.po @@ -166,10 +166,10 @@ msgid "" "## Authentication\n" "- Authentication is handled via JWT tokens. Include the token in the `X-EVIBES-AUTH` header of your requests in the format `Bearer `.\n" "- Access token lifetime is {\n" -" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600\n" "} {\"minutes\" if not DEBUG else \"hours\"}.\n" "- Refresh token lifetime is {\n" -" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600\n" "} hours.\n" "- Refresh tokens are automatically rotated and invalidated after usage for enhanced security.\n" "\n" @@ -198,9 +198,9 @@ msgstr "" "\n" "## ממשקי API זמינים - **REST API:** ממשק RESTful מלא (תיעוד זה) - **GraphQL API:** זמין ב-`/graphql/` עם ממשק GraphiQL לשאילתות אינטראקטיביות ## אימות - האימות מתבצע באמצעות אסימוני JWT. כלול את האסימון בכותרת `X-EVIBES-AUTH` של בקשותיך בפורמט `Bearer `.\n" "- אורך חיי אסימון הגישה הוא {\n" -" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600\n" "} {\"minutes\" if not DEBUG else \"hours\"}. - אורך חיי אסימון הרענון הוא {\n" -" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600\n" "} שעות. - אסימוני הרענון מסתובבים באופן אוטומטי ומבוטלים לאחר השימוש לשם אבטחה משופרת. ## בינלאומיות (i18n) - הגדר את הכותרת `Accept-Language` כדי לציין את השפה המועדפת עליך (לדוגמה, `Accept-Language: en-US`).\n" "- ניתן לאחזר את השפות הזמינות מנקודת הקצה `/app/languages/`. - כל התוכן המוצג למשתמש תומך במספר שפות באופן מובנה. ## פורמטים של תגובה ה-API תומך במספר פורמטים של תגובה: - **JSON** (ברירת מחדל, בפורמט camelCase) - **XML** (הוסף `?format=xml` או הגדר `Accept: application/xml`)\n" "- **YAML** (הוסף `?format=yaml` או הגדר `Accept: application/x-yaml`) ## תקינות וניטור - בדיקות תקינות: `/health/` - מדדי Prometheus (מוגנים באמצעות אימות בסיסי): `/prometheus/` ## גרסה גרסת ה-API הנוכחית: {EVIBES_VERSION}\n" diff --git a/evibes/locale/hi_IN/LC_MESSAGES/django.po b/evibes/locale/hi_IN/LC_MESSAGES/django.po index 8005be12..e5498dc3 100644 --- a/evibes/locale/hi_IN/LC_MESSAGES/django.po +++ b/evibes/locale/hi_IN/LC_MESSAGES/django.po @@ -182,7 +182,7 @@ msgid "" "EVIBES-AUTH` header of your requests in the format `Bearer `.\n" "- Access token lifetime is {\n" " SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not " -"DEBUG else 3600 # type: ignore [union-attr]\n" +"DEBUG else 3600\n" "} {\"minutes\" if not DEBUG else \"hours\"}.\n" "- Refresh token lifetime is {\n" " SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600 # " diff --git a/evibes/locale/hr_HR/LC_MESSAGES/django.po b/evibes/locale/hr_HR/LC_MESSAGES/django.po index 67548e09..3cc87687 100644 --- a/evibes/locale/hr_HR/LC_MESSAGES/django.po +++ b/evibes/locale/hr_HR/LC_MESSAGES/django.po @@ -182,7 +182,7 @@ msgid "" "EVIBES-AUTH` header of your requests in the format `Bearer `.\n" "- Access token lifetime is {\n" " SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not " -"DEBUG else 3600 # type: ignore [union-attr]\n" +"DEBUG else 3600\n" "} {\"minutes\" if not DEBUG else \"hours\"}.\n" "- Refresh token lifetime is {\n" " SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600 # " diff --git a/evibes/locale/id_ID/LC_MESSAGES/django.mo b/evibes/locale/id_ID/LC_MESSAGES/django.mo index 20023f79..2253df77 100644 Binary files a/evibes/locale/id_ID/LC_MESSAGES/django.mo and b/evibes/locale/id_ID/LC_MESSAGES/django.mo differ diff --git a/evibes/locale/id_ID/LC_MESSAGES/django.po b/evibes/locale/id_ID/LC_MESSAGES/django.po index 7480da57..8850c554 100644 --- a/evibes/locale/id_ID/LC_MESSAGES/django.po +++ b/evibes/locale/id_ID/LC_MESSAGES/django.po @@ -167,10 +167,10 @@ msgid "" "## Authentication\n" "- Authentication is handled via JWT tokens. Include the token in the `X-EVIBES-AUTH` header of your requests in the format `Bearer `.\n" "- Access token lifetime is {\n" -" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600\n" "} {\"minutes\" if not DEBUG else \"hours\"}.\n" "- Refresh token lifetime is {\n" -" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600\n" "} hours.\n" "- Refresh tokens are automatically rotated and invalidated after usage for enhanced security.\n" "\n" @@ -216,10 +216,10 @@ msgstr "" "## Otentikasi\n" "- Otentikasi ditangani melalui token JWT. Sertakan token di header `X-EVIBES-AUTH` pada permintaan Anda dalam format `Bearer `.\n" "- Masa berlaku token akses adalah {\n" -" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600\n" "} {\"minutes\" if not DEBUG else \"hours\"}.\n" "- Masa berlaku token refresh adalah {\n" -" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600\n" "} jam.\n" "- Refresh token secara otomatis dirotasi dan dibatalkan setelah digunakan untuk meningkatkan keamanan.\n" "\n" diff --git a/evibes/locale/it_IT/LC_MESSAGES/django.mo b/evibes/locale/it_IT/LC_MESSAGES/django.mo index 8437d9fd..6193c30d 100644 Binary files a/evibes/locale/it_IT/LC_MESSAGES/django.mo and b/evibes/locale/it_IT/LC_MESSAGES/django.mo differ diff --git a/evibes/locale/it_IT/LC_MESSAGES/django.po b/evibes/locale/it_IT/LC_MESSAGES/django.po index 4c075280..aa18c595 100644 --- a/evibes/locale/it_IT/LC_MESSAGES/django.po +++ b/evibes/locale/it_IT/LC_MESSAGES/django.po @@ -168,10 +168,10 @@ msgid "" "## Authentication\n" "- Authentication is handled via JWT tokens. Include the token in the `X-EVIBES-AUTH` header of your requests in the format `Bearer `.\n" "- Access token lifetime is {\n" -" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600\n" "} {\"minutes\" if not DEBUG else \"hours\"}.\n" "- Refresh token lifetime is {\n" -" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600\n" "} hours.\n" "- Refresh tokens are automatically rotated and invalidated after usage for enhanced security.\n" "\n" @@ -217,10 +217,10 @@ msgstr "" "## Autenticazione\n" "- L'autenticazione è gestita tramite token JWT. Includere il token nell'intestazione `X-EVIBES-AUTH` delle richieste nel formato `Bearer `.\n" "- La durata di vita del token di accesso è {\n" -" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600\n" "} {\"minutes\" if not DEBUG else \"hours\"}.\n" "- La durata del token di aggiornamento è di {\n" -" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600\n" "} ore.\n" "- I token di aggiornamento vengono ruotati e invalidati automaticamente dopo l'uso per una maggiore sicurezza.\n" "\n" diff --git a/evibes/locale/ja_JP/LC_MESSAGES/django.mo b/evibes/locale/ja_JP/LC_MESSAGES/django.mo index acea4d0c..691e46c3 100644 Binary files a/evibes/locale/ja_JP/LC_MESSAGES/django.mo and b/evibes/locale/ja_JP/LC_MESSAGES/django.mo differ diff --git a/evibes/locale/ja_JP/LC_MESSAGES/django.po b/evibes/locale/ja_JP/LC_MESSAGES/django.po index 0a9e9239..28542c42 100644 --- a/evibes/locale/ja_JP/LC_MESSAGES/django.po +++ b/evibes/locale/ja_JP/LC_MESSAGES/django.po @@ -165,10 +165,10 @@ msgid "" "## Authentication\n" "- Authentication is handled via JWT tokens. Include the token in the `X-EVIBES-AUTH` header of your requests in the format `Bearer `.\n" "- Access token lifetime is {\n" -" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600\n" "} {\"minutes\" if not DEBUG else \"hours\"}.\n" "- Refresh token lifetime is {\n" -" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600\n" "} hours.\n" "- Refresh tokens are automatically rotated and invalidated after usage for enhanced security.\n" "\n" @@ -214,10 +214,10 @@ msgstr "" "## 認証\n" "- 認証はJWTトークンで行われる。リクエストの `X-EVIBES-AUTH` ヘッダーに `Bearer ` という形式でトークンを含めてください。\n" "- アクセストークンの有効期限は {\n" -" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600\n" "} {\"minutes\" if not DEBUG else \"hours\"}。\n" "- リフレッシュ・トークンの有効期限は {\n" -" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600\n" "} 時間です。\n" "- リフレッシュ・トークンはセキュリティ強化のため、使用後に自動的にローテーションされ無効化されます。\n" "\n" diff --git a/evibes/locale/kk_KZ/LC_MESSAGES/django.po b/evibes/locale/kk_KZ/LC_MESSAGES/django.po index 8005be12..e5498dc3 100644 --- a/evibes/locale/kk_KZ/LC_MESSAGES/django.po +++ b/evibes/locale/kk_KZ/LC_MESSAGES/django.po @@ -182,7 +182,7 @@ msgid "" "EVIBES-AUTH` header of your requests in the format `Bearer `.\n" "- Access token lifetime is {\n" " SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not " -"DEBUG else 3600 # type: ignore [union-attr]\n" +"DEBUG else 3600\n" "} {\"minutes\" if not DEBUG else \"hours\"}.\n" "- Refresh token lifetime is {\n" " SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600 # " diff --git a/evibes/locale/ko_KR/LC_MESSAGES/django.mo b/evibes/locale/ko_KR/LC_MESSAGES/django.mo index 220284d2..502707b1 100644 Binary files a/evibes/locale/ko_KR/LC_MESSAGES/django.mo and b/evibes/locale/ko_KR/LC_MESSAGES/django.mo differ diff --git a/evibes/locale/ko_KR/LC_MESSAGES/django.po b/evibes/locale/ko_KR/LC_MESSAGES/django.po index 11234db6..8f962d81 100644 --- a/evibes/locale/ko_KR/LC_MESSAGES/django.po +++ b/evibes/locale/ko_KR/LC_MESSAGES/django.po @@ -165,10 +165,10 @@ msgid "" "## Authentication\n" "- Authentication is handled via JWT tokens. Include the token in the `X-EVIBES-AUTH` header of your requests in the format `Bearer `.\n" "- Access token lifetime is {\n" -" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600\n" "} {\"minutes\" if not DEBUG else \"hours\"}.\n" "- Refresh token lifetime is {\n" -" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600\n" "} hours.\n" "- Refresh tokens are automatically rotated and invalidated after usage for enhanced security.\n" "\n" @@ -214,10 +214,10 @@ msgstr "" "## 인증\n" "- 인증은 JWT 토큰을 통해 처리됩니다. 토큰을 요청의 `X-EVIBES-AUTH` 헤더에 `Bearer ` 형식으로 포함하세요.\n" "- 액세스 토큰 수명은 {\n" -" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600\n" "}입니다. {\"minutes\" if not DEBUG else \"hours\"}입니다.\n" "- 새로 고침 토큰 수명은 {\n" -" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600\n" "} 시간입니다.\n" "- 새로 고침 토큰은 보안 강화를 위해 사용 후 자동으로 교체되고 무효화됩니다.\n" "\n" diff --git a/evibes/locale/nl_NL/LC_MESSAGES/django.mo b/evibes/locale/nl_NL/LC_MESSAGES/django.mo index aa50179e..572ca955 100644 Binary files a/evibes/locale/nl_NL/LC_MESSAGES/django.mo and b/evibes/locale/nl_NL/LC_MESSAGES/django.mo differ diff --git a/evibes/locale/nl_NL/LC_MESSAGES/django.po b/evibes/locale/nl_NL/LC_MESSAGES/django.po index 78b7d5e3..94a26b9b 100644 --- a/evibes/locale/nl_NL/LC_MESSAGES/django.po +++ b/evibes/locale/nl_NL/LC_MESSAGES/django.po @@ -169,10 +169,10 @@ msgid "" "## Authentication\n" "- Authentication is handled via JWT tokens. Include the token in the `X-EVIBES-AUTH` header of your requests in the format `Bearer `.\n" "- Access token lifetime is {\n" -" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600\n" "} {\"minutes\" if not DEBUG else \"hours\"}.\n" "- Refresh token lifetime is {\n" -" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600\n" "} hours.\n" "- Refresh tokens are automatically rotated and invalidated after usage for enhanced security.\n" "\n" @@ -218,10 +218,10 @@ msgstr "" "## Authenticatie\n" "- Authenticatie wordt afgehandeld via JWT tokens. Neem het token op in de `X-EVIBES-AUTH` header van je verzoeken in het formaat `Bearer `.\n" "- De levensduur van het toegangstoken is {\n" -" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600\n" "} {\"minutes\" if not DEBUG else \"hours\"}.\n" "- De levensduur van een verversingstoken is {\n" -" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600\n" "} uur.\n" "- Refresh tokens worden automatisch geroteerd en ongeldig gemaakt na gebruik voor een betere beveiliging.\n" "\n" diff --git a/evibes/locale/no_NO/LC_MESSAGES/django.mo b/evibes/locale/no_NO/LC_MESSAGES/django.mo index 4a78bdb1..8caf3868 100644 Binary files a/evibes/locale/no_NO/LC_MESSAGES/django.mo and b/evibes/locale/no_NO/LC_MESSAGES/django.mo differ diff --git a/evibes/locale/no_NO/LC_MESSAGES/django.po b/evibes/locale/no_NO/LC_MESSAGES/django.po index d0385347..a6d2f41c 100644 --- a/evibes/locale/no_NO/LC_MESSAGES/django.po +++ b/evibes/locale/no_NO/LC_MESSAGES/django.po @@ -167,10 +167,10 @@ msgid "" "## Authentication\n" "- Authentication is handled via JWT tokens. Include the token in the `X-EVIBES-AUTH` header of your requests in the format `Bearer `.\n" "- Access token lifetime is {\n" -" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600\n" "} {\"minutes\" if not DEBUG else \"hours\"}.\n" "- Refresh token lifetime is {\n" -" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600\n" "} hours.\n" "- Refresh tokens are automatically rotated and invalidated after usage for enhanced security.\n" "\n" @@ -216,10 +216,10 @@ msgstr "" "## Autentisering\n" "- Autentisering håndteres via JWT-tokens. Inkluder tokenet i `X-EVIBES-AUTH`-overskriften i forespørslene dine i formatet `Bearer `.\n" "- Levetiden for tilgangstoken er {\n" -" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600\n" "}. {\"minutes\" if not DEBUG else \"hours\"}.\n" "- Levetiden for oppdateringstoken er {\n" -" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600\n" "} timer.\n" "- Oppdateringstokener roteres automatisk og ugyldiggjøres etter bruk for økt sikkerhet.\n" "\n" diff --git a/evibes/locale/pl_PL/LC_MESSAGES/django.mo b/evibes/locale/pl_PL/LC_MESSAGES/django.mo index 82be2da8..be7e7de9 100644 Binary files a/evibes/locale/pl_PL/LC_MESSAGES/django.mo and b/evibes/locale/pl_PL/LC_MESSAGES/django.mo differ diff --git a/evibes/locale/pl_PL/LC_MESSAGES/django.po b/evibes/locale/pl_PL/LC_MESSAGES/django.po index b7090574..7d097514 100644 --- a/evibes/locale/pl_PL/LC_MESSAGES/django.po +++ b/evibes/locale/pl_PL/LC_MESSAGES/django.po @@ -167,10 +167,10 @@ msgid "" "## Authentication\n" "- Authentication is handled via JWT tokens. Include the token in the `X-EVIBES-AUTH` header of your requests in the format `Bearer `.\n" "- Access token lifetime is {\n" -" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600\n" "} {\"minutes\" if not DEBUG else \"hours\"}.\n" "- Refresh token lifetime is {\n" -" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600\n" "} hours.\n" "- Refresh tokens are automatically rotated and invalidated after usage for enhanced security.\n" "\n" @@ -216,10 +216,10 @@ msgstr "" "## Uwierzytelnianie\n" "- Uwierzytelnianie jest obsługiwane za pomocą tokenów JWT. Dołącz token w nagłówku `X-EVIBES-AUTH` swoich żądań w formacie `Bearer `.\n" "- Okres ważności tokenu dostępu wynosi {\n" -" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600\n" "} {\"minutes\" if not DEBUG else \"hours\"}.\n" "- Okres ważności tokenu odświeżania wynosi {\n" -" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600\n" "} godzin.\n" "- Tokeny odświeżania są automatycznie obracane i unieważniane po użyciu w celu zwiększenia bezpieczeństwa.\n" "\n" diff --git a/evibes/locale/pt_BR/LC_MESSAGES/django.mo b/evibes/locale/pt_BR/LC_MESSAGES/django.mo index e03c7942..0455d4c9 100644 Binary files a/evibes/locale/pt_BR/LC_MESSAGES/django.mo and b/evibes/locale/pt_BR/LC_MESSAGES/django.mo differ diff --git a/evibes/locale/pt_BR/LC_MESSAGES/django.po b/evibes/locale/pt_BR/LC_MESSAGES/django.po index bb0a89f5..a642a7ab 100644 --- a/evibes/locale/pt_BR/LC_MESSAGES/django.po +++ b/evibes/locale/pt_BR/LC_MESSAGES/django.po @@ -168,10 +168,10 @@ msgid "" "## Authentication\n" "- Authentication is handled via JWT tokens. Include the token in the `X-EVIBES-AUTH` header of your requests in the format `Bearer `.\n" "- Access token lifetime is {\n" -" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600\n" "} {\"minutes\" if not DEBUG else \"hours\"}.\n" "- Refresh token lifetime is {\n" -" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600\n" "} hours.\n" "- Refresh tokens are automatically rotated and invalidated after usage for enhanced security.\n" "\n" @@ -217,10 +217,10 @@ msgstr "" "## Autenticação\n" "- A autenticação é tratada por meio de tokens JWT. Inclua o token no cabeçalho `X-EVIBES-AUTH` de suas solicitações no formato `Bearer `.\n" "- O tempo de vida do token de acesso é {\n" -" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600\n" "} {\"minutes\" if not DEBUG else \"hours\"}.\n" "- A vida útil do token de atualização é de {\n" -" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600\n" "} horas.\n" "- Os tokens de atualização são automaticamente girados e invalidados após o uso para aumentar a segurança.\n" "\n" diff --git a/evibes/locale/ro_RO/LC_MESSAGES/django.mo b/evibes/locale/ro_RO/LC_MESSAGES/django.mo index a5478065..11f9a168 100644 Binary files a/evibes/locale/ro_RO/LC_MESSAGES/django.mo and b/evibes/locale/ro_RO/LC_MESSAGES/django.mo differ diff --git a/evibes/locale/ro_RO/LC_MESSAGES/django.po b/evibes/locale/ro_RO/LC_MESSAGES/django.po index d4a3af57..c96a5a2c 100644 --- a/evibes/locale/ro_RO/LC_MESSAGES/django.po +++ b/evibes/locale/ro_RO/LC_MESSAGES/django.po @@ -168,10 +168,10 @@ msgid "" "## Authentication\n" "- Authentication is handled via JWT tokens. Include the token in the `X-EVIBES-AUTH` header of your requests in the format `Bearer `.\n" "- Access token lifetime is {\n" -" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600\n" "} {\"minutes\" if not DEBUG else \"hours\"}.\n" "- Refresh token lifetime is {\n" -" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600\n" "} hours.\n" "- Refresh tokens are automatically rotated and invalidated after usage for enhanced security.\n" "\n" @@ -217,10 +217,10 @@ msgstr "" "## Autentificare\n" "- Autentificarea este gestionată prin jetoane JWT. Includeți tokenul în antetul `X-EVIBES-AUTH` al cererilor dvs. în formatul `Bearer `.\n" "- Durata de viață a jetonului de acces este {\n" -" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600\n" "} {\"minutes\" if not DEBUG else \"hours\"}.\n" "- Durata de viață a jetonului de reînnoire este de {\n" -" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600\n" "} ore.\n" "- Jetoanele de reîmprospătare sunt rotite automat și invalidate după utilizare pentru o securitate sporită.\n" "\n" diff --git a/evibes/locale/ru_RU/LC_MESSAGES/django.mo b/evibes/locale/ru_RU/LC_MESSAGES/django.mo index 29158a75..ce5352dc 100644 Binary files a/evibes/locale/ru_RU/LC_MESSAGES/django.mo and b/evibes/locale/ru_RU/LC_MESSAGES/django.mo differ diff --git a/evibes/locale/ru_RU/LC_MESSAGES/django.po b/evibes/locale/ru_RU/LC_MESSAGES/django.po index e98e1260..050ad3fc 100644 --- a/evibes/locale/ru_RU/LC_MESSAGES/django.po +++ b/evibes/locale/ru_RU/LC_MESSAGES/django.po @@ -167,10 +167,10 @@ msgid "" "## Authentication\n" "- Authentication is handled via JWT tokens. Include the token in the `X-EVIBES-AUTH` header of your requests in the format `Bearer `.\n" "- Access token lifetime is {\n" -" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600\n" "} {\"minutes\" if not DEBUG else \"hours\"}.\n" "- Refresh token lifetime is {\n" -" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600\n" "} hours.\n" "- Refresh tokens are automatically rotated and invalidated after usage for enhanced security.\n" "\n" @@ -216,10 +216,10 @@ msgstr "" "## Аутентификация\n" "- Аутентификация осуществляется с помощью JWT-токенов. Включите токен в заголовок `X-EVIBES-AUTH` ваших запросов в формате `Bearer <ваш_токен>`.\n" "- Срок действия токена доступа составляет {\n" -" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600\n" "} {\"minutes\" if not DEBUG else \"hours\"}.\n" "- Время жизни токена обновления составляет {\n" -" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600\n" "} часов.\n" "- Для повышения безопасности маркеры доступа автоматически поворачиваются и аннулируются после использования.\n" "\n" diff --git a/evibes/locale/sv_SE/LC_MESSAGES/django.mo b/evibes/locale/sv_SE/LC_MESSAGES/django.mo index 14e652c4..7944343e 100644 Binary files a/evibes/locale/sv_SE/LC_MESSAGES/django.mo and b/evibes/locale/sv_SE/LC_MESSAGES/django.mo differ diff --git a/evibes/locale/sv_SE/LC_MESSAGES/django.po b/evibes/locale/sv_SE/LC_MESSAGES/django.po index fd8febf1..cd42d4c7 100644 --- a/evibes/locale/sv_SE/LC_MESSAGES/django.po +++ b/evibes/locale/sv_SE/LC_MESSAGES/django.po @@ -167,10 +167,10 @@ msgid "" "## Authentication\n" "- Authentication is handled via JWT tokens. Include the token in the `X-EVIBES-AUTH` header of your requests in the format `Bearer `.\n" "- Access token lifetime is {\n" -" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600\n" "} {\"minutes\" if not DEBUG else \"hours\"}.\n" "- Refresh token lifetime is {\n" -" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600\n" "} hours.\n" "- Refresh tokens are automatically rotated and invalidated after usage for enhanced security.\n" "\n" @@ -216,10 +216,10 @@ msgstr "" "## Autentisering\n" "- Autentisering hanteras via JWT-tokens. Inkludera token i `X-EVIBES-AUTH`-huvudet för dina förfrågningar i formatet `Bearer `.\n" "- Åtkomsttokenens livstid är {\n" -" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600\n" "} {\"minutes\" if not DEBUG else \"hours\"}.\n" "- Uppdateringstokenens livslängd är {\n" -" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600\n" "} timmar.\n" "- Uppdateringstokens roteras automatiskt och ogiltigförklaras efter användning för ökad säkerhet.\n" "\n" diff --git a/evibes/locale/th_TH/LC_MESSAGES/django.mo b/evibes/locale/th_TH/LC_MESSAGES/django.mo index 4cdf9be0..e8ef9ea4 100644 Binary files a/evibes/locale/th_TH/LC_MESSAGES/django.mo and b/evibes/locale/th_TH/LC_MESSAGES/django.mo differ diff --git a/evibes/locale/th_TH/LC_MESSAGES/django.po b/evibes/locale/th_TH/LC_MESSAGES/django.po index 729d5b0e..fdbb4318 100644 --- a/evibes/locale/th_TH/LC_MESSAGES/django.po +++ b/evibes/locale/th_TH/LC_MESSAGES/django.po @@ -167,10 +167,10 @@ msgid "" "## Authentication\n" "- Authentication is handled via JWT tokens. Include the token in the `X-EVIBES-AUTH` header of your requests in the format `Bearer `.\n" "- Access token lifetime is {\n" -" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600\n" "} {\"minutes\" if not DEBUG else \"hours\"}.\n" "- Refresh token lifetime is {\n" -" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600\n" "} hours.\n" "- Refresh tokens are automatically rotated and invalidated after usage for enhanced security.\n" "\n" @@ -199,9 +199,9 @@ msgstr "" "\n" "## API ที่มีให้บริการ - **REST API:** อินเทอร์เฟซ RESTful แบบเต็มรูปแบบ (เอกสารนี้) - **GraphQL API:** สามารถใช้งานได้ที่ `/graphql/` พร้อมอินเทอร์เฟซ GraphiQL สำหรับการสืบค้นแบบโต้ตอบ ## การยืนยันตัวตน - การยืนยันตัวตนดำเนินการผ่านโทเค็น JWT โปรดใส่โทเค็นในหัวข้อ `X-EVIBES-AUTH` ของคำขอของคุณในรูปแบบ `Bearer `\n" "- ระยะเวลาการใช้งานโทเค็นการเข้าถึงคือ {\n" -" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600\n" "} {\"minutes\" if not DEBUG else \"hours\"}. - ระยะเวลาการใช้งานโทเค็นการรีเฟรชคือ {\n" -" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600\n" "} ชั่วโมง. - โทเค็นการรีเฟรชจะถูกหมุนเวียนและยกเลิกการใช้งานโดยอัตโนมัติหลังการใช้งานเพื่อเพิ่มความปลอดภัย. ## การแปลภาษา (i18n) - ตั้งค่าหัวข้อ `Accept-Language` เพื่อระบุภาษาที่คุณต้องการ (เช่น `Accept-Language: en-US`).\n" "- ภาษาที่มีให้บริการสามารถดึงข้อมูลได้จากจุดสิ้นสุด `/app/languages/` - เนื้อหาที่แสดงต่อผู้ใช้ทั้งหมดรองรับหลายภาษาโดยอัตโนมัติ ## รูปแบบการตอบกลับ API รองรับรูปแบบการตอบกลับหลายรูปแบบ: - **JSON** (ค่าเริ่มต้น, รูปแบบ camelCase) - **XML** (เพิ่ม `?format=xml` หรือตั้งค่า `Accept: application/xml`)\n" "- **YAML** (เพิ่ม `?format=yaml` หรือตั้งค่า `Accept: application/x-yaml`) ## สุขภาพและการตรวจสอบ - การตรวจสอบสุขภาพ: `/health/` - เมตริก Prometheus (ป้องกันด้วย basic-auth): `/prometheus/` ## เวอร์ชัน เวอร์ชัน API ปัจจุบัน: {EVIBES_VERSION}\n" diff --git a/evibes/locale/tr_TR/LC_MESSAGES/django.mo b/evibes/locale/tr_TR/LC_MESSAGES/django.mo index df5587a6..323531ae 100644 Binary files a/evibes/locale/tr_TR/LC_MESSAGES/django.mo and b/evibes/locale/tr_TR/LC_MESSAGES/django.mo differ diff --git a/evibes/locale/tr_TR/LC_MESSAGES/django.po b/evibes/locale/tr_TR/LC_MESSAGES/django.po index 85515970..88e176f3 100644 --- a/evibes/locale/tr_TR/LC_MESSAGES/django.po +++ b/evibes/locale/tr_TR/LC_MESSAGES/django.po @@ -168,10 +168,10 @@ msgid "" "## Authentication\n" "- Authentication is handled via JWT tokens. Include the token in the `X-EVIBES-AUTH` header of your requests in the format `Bearer `.\n" "- Access token lifetime is {\n" -" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600\n" "} {\"minutes\" if not DEBUG else \"hours\"}.\n" "- Refresh token lifetime is {\n" -" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600\n" "} hours.\n" "- Refresh tokens are automatically rotated and invalidated after usage for enhanced security.\n" "\n" @@ -217,10 +217,10 @@ msgstr "" "## Kimlik Doğrulama\n" "- Kimlik doğrulama JWT belirteçleri aracılığıyla gerçekleştirilir. Belirteci, isteklerinizin `X-EVIBES-AUTH` başlığına `Bearer ` biçiminde ekleyin.\n" "- Erişim belirteci ömrü {\n" -" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600\n" "} {\"minutes\" if not DEBUG else \"hours\"}.\n" "- Yenileme belirteci ömrü {\n" -" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600\n" "} saattir.\n" "- Yenileme belirteçleri, gelişmiş güvenlik için kullanımdan sonra otomatik olarak döndürülür ve geçersiz kılınır.\n" "\n" diff --git a/evibes/locale/vi_VN/LC_MESSAGES/django.mo b/evibes/locale/vi_VN/LC_MESSAGES/django.mo index f1f402c2..5e938b3c 100644 Binary files a/evibes/locale/vi_VN/LC_MESSAGES/django.mo and b/evibes/locale/vi_VN/LC_MESSAGES/django.mo differ diff --git a/evibes/locale/vi_VN/LC_MESSAGES/django.po b/evibes/locale/vi_VN/LC_MESSAGES/django.po index ac7d4f89..e001c9ec 100644 --- a/evibes/locale/vi_VN/LC_MESSAGES/django.po +++ b/evibes/locale/vi_VN/LC_MESSAGES/django.po @@ -169,10 +169,10 @@ msgid "" "## Authentication\n" "- Authentication is handled via JWT tokens. Include the token in the `X-EVIBES-AUTH` header of your requests in the format `Bearer `.\n" "- Access token lifetime is {\n" -" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600\n" "} {\"minutes\" if not DEBUG else \"hours\"}.\n" "- Refresh token lifetime is {\n" -" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600\n" "} hours.\n" "- Refresh tokens are automatically rotated and invalidated after usage for enhanced security.\n" "\n" @@ -201,9 +201,9 @@ msgstr "" "\n" "## Các API có sẵn - **REST API:** Giao diện RESTful đầy đủ (tài liệu này) - **GraphQL API:** Có sẵn tại `/graphql/` với giao diện GraphiQL cho các truy vấn tương tác ## Xác thực - Xác thực được xử lý thông qua token JWT. Bao gồm token trong tiêu đề `X-EVIBES-AUTH` của yêu cầu của bạn theo định dạng `Bearer `.\n" "- Thời hạn sử dụng của token truy cập là {\n" -" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600\n" "} {\"minutes\" if not DEBUG else \"hours\"}. - Thời hạn sử dụng của token làm mới là {\n" -" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600\n" "} giờ. - Token làm mới được tự động xoay vòng và vô hiệu hóa sau khi sử dụng để tăng cường bảo mật. ## Quốc tế hóa (i18n) - Đặt tiêu đề `Accept-Language` để chỉ định ngôn ngữ ưa thích của bạn (ví dụ: `Accept-Language: en-US`).\n" "- Các ngôn ngữ có sẵn có thể được lấy từ điểm cuối `/app/languages/`. - Tất cả nội dung hiển thị cho người dùng đều hỗ trợ nhiều ngôn ngữ ngay từ đầu. ## Định dạng phản hồi API hỗ trợ nhiều định dạng phản hồi: - **JSON** (mặc định, định dạng camelCase) - **XML** (thêm `?format=xml` hoặc đặt `Accept: application/xml`)\n" "- **YAML** (thêm `?format=yaml` hoặc đặt `Accept: application/x-yaml`) ## Sức khỏe & Giám sát - Kiểm tra sức khỏe: `/health/` - Chỉ số Prometheus (bảo vệ bằng basic-auth): `/prometheus/` ## Phiên bản Phiên bản API hiện tại: {EVIBES_VERSION}\n" diff --git a/evibes/locale/zh_Hans/LC_MESSAGES/django.mo b/evibes/locale/zh_Hans/LC_MESSAGES/django.mo index ef86cd4d..53efaf86 100644 Binary files a/evibes/locale/zh_Hans/LC_MESSAGES/django.mo and b/evibes/locale/zh_Hans/LC_MESSAGES/django.mo differ diff --git a/evibes/locale/zh_Hans/LC_MESSAGES/django.po b/evibes/locale/zh_Hans/LC_MESSAGES/django.po index 0653ba03..45baf191 100644 --- a/evibes/locale/zh_Hans/LC_MESSAGES/django.po +++ b/evibes/locale/zh_Hans/LC_MESSAGES/django.po @@ -165,10 +165,10 @@ msgid "" "## Authentication\n" "- Authentication is handled via JWT tokens. Include the token in the `X-EVIBES-AUTH` header of your requests in the format `Bearer `.\n" "- Access token lifetime is {\n" -" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600\n" "} {\"minutes\" if not DEBUG else \"hours\"}.\n" "- Refresh token lifetime is {\n" -" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600\n" "} hours.\n" "- Refresh tokens are automatically rotated and invalidated after usage for enhanced security.\n" "\n" @@ -214,10 +214,10 @@ msgstr "" "## 验证\n" "- 通过 JWT 标记进行身份验证。在请求的 `X-EVIBES-AUTH` 头中包含令牌,格式为 `Bearer `。\n" "- 访问令牌的有效期为 {\n" -" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\").total_seconds() // 60 if not DEBUG else 3600\n" "}{\"minutes\" if not DEBUG else \"hours\"}。\n" "- 刷新令牌的有效期为 {\n" -" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600 # type: ignore [union-attr]\n" +" SIMPLE_JWT.get(\"REFRESH_TOKEN_LIFETIME\").total_seconds() // 3600\n" "} 小时。\n" "- 刷新令牌在使用后会自动轮换和失效,以增强安全性。\n" "\n" diff --git a/evibes/pagination.py b/evibes/pagination.py index 0a509595..ad0376cb 100644 --- a/evibes/pagination.py +++ b/evibes/pagination.py @@ -17,9 +17,9 @@ class CustomPagination(PageNumberPagination): "backward": self.get_previous_link(), }, "counts": { - "total_pages": None or self.page.paginator.num_pages, # type: ignore [union-attr] + "total_pages": None or self.page.paginator.num_pages, "page_size": None or self.page_size, - "total_items": None or self.page.paginator.count, # type: ignore [union-attr] + "total_items": None or self.page.paginator.count, }, "data": data, } diff --git a/evibes/settings/base.py b/evibes/settings/base.py index 15c94f21..4b062315 100644 --- a/evibes/settings/base.py +++ b/evibes/settings/base.py @@ -348,7 +348,7 @@ LANGUAGE_URL_OVERRIDES: dict[str, str] = { code.split("-")[0]: code for code, _ in LANGUAGES if "-" in code } -CURRENCY_CODE: str = dict(CURRENCIES_BY_LANGUAGES).get(LANGUAGE_CODE) # type: ignore[assignment] +CURRENCY_CODE: str = dict(CURRENCIES_BY_LANGUAGES).get(LANGUAGE_CODE) MODELTRANSLATION_FALLBACK_LANGUAGES: tuple[str, ...] = (LANGUAGE_CODE, "en-us", "de-de") @@ -435,7 +435,7 @@ if getenv("SENTRY_DSN"): request = event.get("request", {}) data = request.get("data", {}) if data: - request["data"] = scrub_sensitive(data) # type: ignore [arg-type] + request["data"] = scrub_sensitive(data) event["request"] = request return event diff --git a/evibes/settings/drf.py b/evibes/settings/drf.py index 9bfcdec7..d67eceb4 100644 --- a/evibes/settings/drf.py +++ b/evibes/settings/drf.py @@ -11,6 +11,11 @@ from evibes.settings.base import ( SECRET_KEY, ) +JSON_CAMEL_CASE = { + "RENDERER_CLASS": "drf_orjson_renderer.renderers.ORJSONRenderer", + "PARSER_CLASS": "drf_orjson_renderer.parsers.ORJSONParser", +} + REST_FRAMEWORK: dict[str, str | int | list[str] | tuple[str, ...] | dict[str, bool]] = { "DEFAULT_PAGINATION_CLASS": "evibes.pagination.CustomPagination", "PAGE_SIZE": 30, @@ -22,12 +27,12 @@ REST_FRAMEWORK: dict[str, str | int | list[str] | tuple[str, ...] | dict[str, bo "rest_framework.renderers.MultiPartRenderer", "rest_framework_xml.renderers.XMLRenderer", "rest_framework_yaml.renderers.YAMLRenderer", + "djangorestframework_camel_case.render.CamelCaseBrowsableAPIRenderer", ), "DEFAULT_PARSER_CLASSES": ( "djangorestframework_camel_case.parser.CamelCaseJSONParser", "djangorestframework_camel_case.parser.CamelCaseMultiPartParser", - "rest_framework.parsers.FormParser", - "rest_framework.parsers.MultiPartParser", + "djangorestframework_camel_case.parser.CamelCaseFormParser", "rest_framework_xml.parsers.XMLParser", "rest_framework_yaml.parsers.YAMLParser", ), @@ -39,9 +44,7 @@ REST_FRAMEWORK: dict[str, str | int | list[str] | tuple[str, ...] | dict[str, bo } SIMPLE_JWT: dict[str, timedelta | str | bool] = { - "ACCESS_TOKEN_LIFETIME": timedelta(hours=8) - if not DEBUG # noqa: F405 - else timedelta(hours=88), + "ACCESS_TOKEN_LIFETIME": timedelta(hours=8) if not DEBUG else timedelta(hours=88), "REFRESH_TOKEN_LIFETIME": timedelta(days=8), "ROTATE_REFRESH_TOKENS": True, "BLACKLIST_AFTER_ROTATION": True, @@ -76,10 +79,10 @@ eVibes is a powerful e-commerce platform that allows you to launch and manage an ## Authentication - Authentication is handled via JWT tokens. Include the token in the `X-EVIBES-AUTH` header of your requests in the format `Bearer `. - Access token lifetime is { - SIMPLE_JWT.get("ACCESS_TOKEN_LIFETIME").total_seconds() // 60 if not DEBUG else 3600 # type: ignore [union-attr] + SIMPLE_JWT.get("ACCESS_TOKEN_LIFETIME").total_seconds() // 60 if not DEBUG else 3600 } {"minutes" if not DEBUG else "hours"}. - Refresh token lifetime is { - SIMPLE_JWT.get("REFRESH_TOKEN_LIFETIME").total_seconds() // 3600 # type: ignore [union-attr] + SIMPLE_JWT.get("REFRESH_TOKEN_LIFETIME").total_seconds() // 3600 } hours. - Refresh tokens are automatically rotated and invalidated after usage for enhanced security. @@ -104,7 +107,7 @@ Current API version: {EVIBES_VERSION} SPECTACULAR_SETTINGS = { "DEFAULT_GENERATOR_CLASS": "drf_spectacular_websocket.schemas.WsSchemaGenerator", - "TITLE": f"{PROJECT_NAME} API", # type: ignore [index] + "TITLE": f"{PROJECT_NAME} API", "DESCRIPTION": SPECTACULAR_DESCRIPTION, "VERSION": EVIBES_VERSION, # noqa: F405 "TOS": "https://evibes.wiseless.xyz/terms-of-service", @@ -124,7 +127,7 @@ SPECTACULAR_SETTINGS = { }, "SERVERS": [ { - "url": f"https://api.{BASE_DOMAIN}/", # type: ignore [index] + "url": f"https://api.{BASE_DOMAIN}/", "description": "Production Server", }, {"url": "http://api.localhost:8000/", "description": "Development Server"}, diff --git a/pyproject.toml b/pyproject.toml index 0d48cc86..f04df32d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -14,27 +14,27 @@ dependencies = [ "coverage==7.13.0", "click==8.3.1", "cryptography==46.0.3", - "django==5.2.8", + "django==5.2.9", "django-cacheops==7.2", "django-constance==4.3.4", "django-cors-headers==4.9.0", - "django-dbbackup==5.0.1", + "django-dbbackup==5.1.0", "django-elasticsearch-dsl==8.2", "django-extensions==4.1", "django-filter==25.2", "django-health-check==3.20.0", "django-import-export[all]>=4.3.14", - "django-json-widget==2.1.0", + "django-json-widget==2.1.1", "django-mailbox==4.10.1", "django-model-utils==5.0.0", - "django-modeltranslation==0.19.17", + "django-modeltranslation==0.19.19", "django-mptt==0.18.0", "django-prometheus==2.4.1", "django-redis==6.0.0", "django-ratelimit==4.1.0", "django-storages==1.14.6", "django-summernote==0.8.20.0", - "django-unfold==0.73.1", + "django-unfold==0.74.1", "django-unfold-markdown==0.1.2", "django-widget-tweaks==1.5.0", "django-md-field==0.1.0", @@ -48,8 +48,9 @@ dependencies = [ "docutils==0.22.3", "drf-spectacular[sidecar]==0.29.0", "drf-spectacular-websocket>=1.3.1", + "drf-orjson-renderer>=1.8.0", "elasticsearch-dsl==8.18.0", - "filelock==3.20.0", + "filelock==3.20.1", "filetype==1.2.0", "graphene-django==3.2.3", "graphene-file-upload==1.3.0", @@ -65,10 +66,10 @@ dependencies = [ "python-slugify==8.0.4", "psutil==7.1.3", "psycopg2==2.9.11", - "pymdown-extensions==10.18", + "pymdown-extensions==10.19.1", "redis==7.1.0", "requests==2.32.5", - "sentry-sdk[django,celery,opentelemetry]==2.47.0", + "sentry-sdk[django,celery,opentelemetry]==2.48.0", "six==1.17.0", "swapper==1.4.0", "uvicorn==0.38.0", @@ -88,10 +89,19 @@ worker = [ linting = [ "ruff==0.14.9", "basedpyright>=1.36.1", - "pyright==1.1.387", + "pyright==1.1.407", "celery-types>=0.23.0", + "django-stubs==5.2.8", + "djangorestframework-stubs==3.16.6", + "types-requests==2.32.4.20250913", + "types-redis==4.6.0.20241004", + "types-paramiko==4.0.0.20250822", + "types-psutil==7.1.3.20251211", + "types-pillow==10.2.0.20240822", + "types-docutils==0.22.3.20251115", + "types-six==1.17.0.20251009", ] -openai = ["openai==2.12.0"] +openai = ["openai==2.13.0"] jupyter = ["jupyter==1.1.1"] [tool.uv] @@ -115,3 +125,22 @@ known-first-party = ["evibes", "engine"] [tool.ruff.format] quote-style = "double" indent-style = "space" + +[tool.pyright] +typeCheckingMode = "strict" +pythonVersion = "3.12" +useLibraryCodeForTypes = true +reportMissingTypeStubs = "none" +exclude = [ + "**/__pycache__/**", + "**/.venv/**", + "**/.uv/**", + "media/**", + "static/**", + "storefront/**", + "**/migrations/**", +] +extraPaths = ["./evibes", "./engine"] + +[tool.django-stubs] +django_settings_module = "evibes.settings" \ No newline at end of file diff --git a/pyrightconfig.json b/pyrightconfig.json deleted file mode 100644 index 591101b0..00000000 --- a/pyrightconfig.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "$schema": "https://raw.githubusercontent.com/microsoft/pyright/main/packages/pyright/schema/pyrightconfig.schema.json", - "typeCheckingMode": "strict", - "pythonVersion": "3.12", - "useLibraryCodeForTypes": true, - "reportMissingTypeStubs": "warning", - "exclude": [ - "**/__pycache__/**", - "**/.venv/**", - "**/.uv/**", - "media/**", - "static/**", - "storefront/**", - "**/migrations/**" - ], - "executionEnvironments": [ - { - "root": "./", - "pythonVersion": "3.12", - "extraPaths": ["./evibes", "./engine"] - } - ] -} diff --git a/uv.lock b/uv.lock index f3bffb9c..0f37be72 100644 --- a/uv.lock +++ b/uv.lock @@ -699,19 +699,19 @@ wheels = [ [[package]] name = "debugpy" -version = "1.8.18" +version = "1.8.19" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/62/1a/7cb5531840d7ba5d9329644109e62adee41f2f0083d9f8a4039f01de58cf/debugpy-1.8.18.tar.gz", hash = "sha256:02551b1b84a91faadd2db9bc4948873f2398190c95b3cc6f97dc706f43e8c433", size = 1644467, upload-time = "2025-12-10T19:48:07.236Z" } +sdist = { url = "https://files.pythonhosted.org/packages/73/75/9e12d4d42349b817cd545b89247696c67917aab907012ae5b64bbfea3199/debugpy-1.8.19.tar.gz", hash = "sha256:eea7e5987445ab0b5ed258093722d5ecb8bb72217c5c9b1e21f64efe23ddebdb", size = 1644590, upload-time = "2025-12-15T21:53:28.044Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/83/01/439626e3572a33ac543f25bc1dac1e80bc01c7ce83f3c24dc4441302ca13/debugpy-1.8.18-cp312-cp312-macosx_15_0_universal2.whl", hash = "sha256:530c38114725505a7e4ea95328dbc24aabb9be708c6570623c8163412e6d1d6b", size = 2549961, upload-time = "2025-12-10T19:48:21.73Z" }, - { url = "https://files.pythonhosted.org/packages/cd/73/1eeaa15c20a2b627be57a65bc1ebf2edd8d896950eac323588b127d776f2/debugpy-1.8.18-cp312-cp312-manylinux_2_34_x86_64.whl", hash = "sha256:a114865099283cbed4c9330cb0c9cb7a04cfa92e803577843657302d526141ec", size = 4309855, upload-time = "2025-12-10T19:48:23.41Z" }, - { url = "https://files.pythonhosted.org/packages/e4/6f/2da8ded21ae55df7067e57bd7f67ffed7e08b634f29bdba30c03d3f19918/debugpy-1.8.18-cp312-cp312-win32.whl", hash = "sha256:4d26736dfabf404e9f3032015ec7b0189e7396d0664e29e5bdbe7ac453043c95", size = 5280577, upload-time = "2025-12-10T19:48:25.386Z" }, - { url = "https://files.pythonhosted.org/packages/f5/8e/ebe887218c5b84f9421de7eb7bb7cdf196e84535c3f504a562219297d755/debugpy-1.8.18-cp312-cp312-win_amd64.whl", hash = "sha256:7e68ba950acbcf95ee862210133681f408cbb78d1c9badbb515230ec55ed6487", size = 5322458, upload-time = "2025-12-10T19:48:28.049Z" }, - { url = "https://files.pythonhosted.org/packages/fe/3f/45af037e91e308274a092eb6a86282865fb1f11148cdb7616e811aae33d7/debugpy-1.8.18-cp313-cp313-macosx_15_0_universal2.whl", hash = "sha256:75d14dd04b617ee38e46786394ec0dd5e1ac5e3d10ffb034fd6c7b72111174c2", size = 2538826, upload-time = "2025-12-10T19:48:29.434Z" }, - { url = "https://files.pythonhosted.org/packages/cc/f4/2de6bf624de05134d1bbe0a8750d484363cd212c3ade3d04f5c77d47d0ce/debugpy-1.8.18-cp313-cp313-manylinux_2_34_x86_64.whl", hash = "sha256:1b224887af5121fa702f9f542968170d104e3f9cac827d85fdefe89702dc235c", size = 4292542, upload-time = "2025-12-10T19:48:30.836Z" }, - { url = "https://files.pythonhosted.org/packages/93/54/89de7ef84d5ac39fc64a773feaedd902536cc5295814cd22d19c6d9dea35/debugpy-1.8.18-cp313-cp313-win32.whl", hash = "sha256:636a5445a3336e4aba323a3545ca2bb373b04b0bc14084a4eb20c989db44429f", size = 5280460, upload-time = "2025-12-10T19:48:32.696Z" }, - { url = "https://files.pythonhosted.org/packages/4f/59/651329e618406229edbef6508a5aa05e43cd027f042740c5b27e46854b23/debugpy-1.8.18-cp313-cp313-win_amd64.whl", hash = "sha256:6da217ac8c1152d698b9809484d50c75bef9cc02fd6886a893a6df81ec952ff8", size = 5322399, upload-time = "2025-12-10T19:48:35.057Z" }, - { url = "https://files.pythonhosted.org/packages/dc/0d/bf7ac329c132436c57124202b5b5ccd6366e5d8e75eeb184cf078c826e8d/debugpy-1.8.18-py2.py3-none-any.whl", hash = "sha256:ab8cf0abe0fe2dfe1f7e65abc04b1db8740f9be80c1274acb625855c5c3ece6e", size = 5286576, upload-time = "2025-12-10T19:48:56.071Z" }, + { url = "https://files.pythonhosted.org/packages/4a/15/d762e5263d9e25b763b78be72dc084c7a32113a0bac119e2f7acae7700ed/debugpy-1.8.19-cp312-cp312-macosx_15_0_universal2.whl", hash = "sha256:bccb1540a49cde77edc7ce7d9d075c1dbeb2414751bc0048c7a11e1b597a4c2e", size = 2549995, upload-time = "2025-12-15T21:53:43.773Z" }, + { url = "https://files.pythonhosted.org/packages/a7/88/f7d25c68b18873b7c53d7c156ca7a7ffd8e77073aa0eac170a9b679cf786/debugpy-1.8.19-cp312-cp312-manylinux_2_34_x86_64.whl", hash = "sha256:e9c68d9a382ec754dc05ed1d1b4ed5bd824b9f7c1a8cd1083adb84b3c93501de", size = 4309891, upload-time = "2025-12-15T21:53:45.26Z" }, + { url = "https://files.pythonhosted.org/packages/c5/4f/a65e973aba3865794da65f71971dca01ae66666132c7b2647182d5be0c5f/debugpy-1.8.19-cp312-cp312-win32.whl", hash = "sha256:6599cab8a783d1496ae9984c52cb13b7c4a3bd06a8e6c33446832a5d97ce0bee", size = 5286355, upload-time = "2025-12-15T21:53:46.763Z" }, + { url = "https://files.pythonhosted.org/packages/d8/3a/d3d8b48fec96e3d824e404bf428276fb8419dfa766f78f10b08da1cb2986/debugpy-1.8.19-cp312-cp312-win_amd64.whl", hash = "sha256:66e3d2fd8f2035a8f111eb127fa508469dfa40928a89b460b41fd988684dc83d", size = 5328239, upload-time = "2025-12-15T21:53:48.868Z" }, + { url = "https://files.pythonhosted.org/packages/71/3d/388035a31a59c26f1ecc8d86af607d0c42e20ef80074147cd07b180c4349/debugpy-1.8.19-cp313-cp313-macosx_15_0_universal2.whl", hash = "sha256:91e35db2672a0abaf325f4868fcac9c1674a0d9ad9bb8a8c849c03a5ebba3e6d", size = 2538859, upload-time = "2025-12-15T21:53:50.478Z" }, + { url = "https://files.pythonhosted.org/packages/4a/19/c93a0772d0962294f083dbdb113af1a7427bb632d36e5314297068f55db7/debugpy-1.8.19-cp313-cp313-manylinux_2_34_x86_64.whl", hash = "sha256:85016a73ab84dea1c1f1dcd88ec692993bcbe4532d1b49ecb5f3c688ae50c606", size = 4292575, upload-time = "2025-12-15T21:53:51.821Z" }, + { url = "https://files.pythonhosted.org/packages/5c/56/09e48ab796b0a77e3d7dc250f95251832b8bf6838c9632f6100c98bdf426/debugpy-1.8.19-cp313-cp313-win32.whl", hash = "sha256:b605f17e89ba0ecee994391194285fada89cee111cfcd29d6f2ee11cbdc40976", size = 5286209, upload-time = "2025-12-15T21:53:53.602Z" }, + { url = "https://files.pythonhosted.org/packages/fb/4e/931480b9552c7d0feebe40c73725dd7703dcc578ba9efc14fe0e6d31cfd1/debugpy-1.8.19-cp313-cp313-win_amd64.whl", hash = "sha256:c30639998a9f9cd9699b4b621942c0179a6527f083c72351f95c6ab1728d5b73", size = 5328206, upload-time = "2025-12-15T21:53:55.433Z" }, + { url = "https://files.pythonhosted.org/packages/25/3e/e27078370414ef35fafad2c06d182110073daaeb5d3bf734b0b1eeefe452/debugpy-1.8.19-py2.py3-none-any.whl", hash = "sha256:360ffd231a780abbc414ba0f005dad409e71c78637efe8f2bd75837132a41d38", size = 5292321, upload-time = "2025-12-15T21:54:16.024Z" }, ] [[package]] @@ -752,16 +752,16 @@ wheels = [ [[package]] name = "django" -version = "5.2.8" +version = "5.2.9" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "asgiref" }, { name = "sqlparse" }, { name = "tzdata", marker = "sys_platform == 'win32'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/05/a2/933dbbb3dd9990494960f6e64aca2af4c0745b63b7113f59a822df92329e/django-5.2.8.tar.gz", hash = "sha256:23254866a5bb9a2cfa6004e8b809ec6246eba4b58a7589bc2772f1bcc8456c7f", size = 10849032, upload-time = "2025-11-05T14:07:32.778Z" } +sdist = { url = "https://files.pythonhosted.org/packages/eb/1c/188ce85ee380f714b704283013434976df8d3a2df8e735221a02605b6794/django-5.2.9.tar.gz", hash = "sha256:16b5ccfc5e8c27e6c0561af551d2ea32852d7352c67d452ae3e76b4f6b2ca495", size = 10848762, upload-time = "2025-12-02T14:01:08.418Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/5e/3d/a035a4ee9b1d4d4beee2ae6e8e12fe6dee5514b21f62504e22efcbd9fb46/django-5.2.8-py3-none-any.whl", hash = "sha256:37e687f7bd73ddf043e2b6b97cfe02fcbb11f2dbb3adccc6a2b18c6daa054d7f", size = 8289692, upload-time = "2025-11-05T14:07:28.761Z" }, + { url = "https://files.pythonhosted.org/packages/17/b0/7f42bfc38b8f19b78546d47147e083ed06e12fc29c42da95655e0962c6c2/django-5.2.9-py3-none-any.whl", hash = "sha256:3a4ea88a70370557ab1930b332fd2887a9f48654261cdffda663fef5976bb00a", size = 8290652, upload-time = "2025-12-02T14:01:03.485Z" }, ] [[package]] @@ -832,14 +832,14 @@ wheels = [ [[package]] name = "django-dbbackup" -version = "5.0.1" +version = "5.1.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "django" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/1e/c8/e8d0352f3b5f6f3a0b12ea56a47fc9808aa1bb8753f6d362b7acadec72c6/django_dbbackup-5.0.1.tar.gz", hash = "sha256:52e1ed0c8082eb29b2e96231db0101a47a34442176542c27659992918ae9ef2a", size = 25316, upload-time = "2025-11-07T11:05:05.679Z" } +sdist = { url = "https://files.pythonhosted.org/packages/1c/97/0504a820ea4a3550386fdfb73d7808d3458e4882d33f0b7cef23439d3b4a/django_dbbackup-5.1.0.tar.gz", hash = "sha256:66c236bbfa0c9bda33a61d30be8c5961d70fa73fed2fe7f829559ac216354130", size = 26361, upload-time = "2025-12-17T13:23:12.072Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/fb/b1/b0bbab8cf34fb8ca09f19d054b1c44f061b5188f4aa40cc6b274de566ac1/django_dbbackup-5.0.1-py3-none-any.whl", hash = "sha256:5f9f764fcd9be3c7d6acde31ad3a20ec9093fc42014cd3e84e71eae9201d675f", size = 33403, upload-time = "2025-11-07T11:05:04.265Z" }, + { url = "https://files.pythonhosted.org/packages/da/a3/62fc9ecb4222fffdb1a56f187888c4e237edb763dbafc64677115d0788d7/django_dbbackup-5.1.0-py3-none-any.whl", hash = "sha256:611291606bf6a80903733a99235963e65236c23bca26c2edca453b928b504c67", size = 34612, upload-time = "2025-12-17T13:23:10.538Z" }, ] [[package]] @@ -924,11 +924,11 @@ wheels = [ [[package]] name = "django-json-widget" -version = "2.1.0" +version = "2.1.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/3f/84/db3338004d664cad952119a44254987fe23805243b167c5211aa52c0f5e4/django_json_widget-2.1.0.tar.gz", hash = "sha256:0f040b8b329d5032dc1136cf50c01dc7563a07b8f0c3f5324b9051bc3e6eaa83", size = 383610, upload-time = "2025-10-24T15:12:16.258Z" } +sdist = { url = "https://files.pythonhosted.org/packages/f9/30/923ff229ee284bf2fac7a289ca446fb2725d94b2a34c7cb006c4f811e6c0/django_json_widget-2.1.1.tar.gz", hash = "sha256:dc8102e2fa9accd0f661ea1988c9389f8fbbcb8a4bb9cbfb8fa0525b3c1265c1", size = 384026, upload-time = "2025-12-12T11:22:05.953Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f0/c5/313336b98874ae1e8776e62777a75ce0c97ab47b66475bc7979f2e7176b4/django_json_widget-2.1.0-py2.py3-none-any.whl", hash = "sha256:fc30781292000c745449632d0f2d6ddd8f2415172664ae9fad42f1cd407a5612", size = 293397, upload-time = "2025-10-24T15:12:13.209Z" }, + { url = "https://files.pythonhosted.org/packages/19/6a/bdbcc079d11d312e463565819089fe83ae6c7f17f274effa4777ca069f64/django_json_widget-2.1.1-py2.py3-none-any.whl", hash = "sha256:2fa3d6fb6dba9436a29ad2cee23fa794381f54a6678ec7d74e990ae081d9800b", size = 293721, upload-time = "2025-12-12T11:22:04.195Z" }, ] [[package]] @@ -963,14 +963,15 @@ wheels = [ [[package]] name = "django-modeltranslation" -version = "0.19.17" +version = "0.19.19" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "django" }, + { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a7/32/34f33d0a375087197e1e7b6e27a87332c3dfaa970cb38ec353b6198b855b/django_modeltranslation-0.19.17.tar.gz", hash = "sha256:13bd9cab4e4aed0bef5624c17a7da2ac8c5538f0650adbd89ce8c878cbef02fd", size = 77741, upload-time = "2025-09-14T10:14:36.05Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c1/af/3c34fca94fccae681a15734bc6557cf9be958d1d063ddbb233580b894054/django_modeltranslation-0.19.19.tar.gz", hash = "sha256:26dd8454f19540a2eb05e303608a2d89dd80aacb75ab95f8ea272cf4324d2644", size = 77750, upload-time = "2025-12-15T10:25:38.112Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/83/87/f8cf0626e502fd6fd996b8dc590985ed5002b63dfb4442f954670bd101b7/django_modeltranslation-0.19.17-py3-none-any.whl", hash = "sha256:fda198c08b4ede0c2fd09b795ab420a04c7b5a868315fdf4aade0d0a526c269f", size = 93423, upload-time = "2025-09-14T10:14:34.536Z" }, + { url = "https://files.pythonhosted.org/packages/a7/2a/fdf265e91e37ee363b2c45f3d2a01752a3b38ab082a3ec0b0677105bd367/django_modeltranslation-0.19.19-py3-none-any.whl", hash = "sha256:55ac2ce47486b9e8ca18b155f7705170a53b7e1346bf7bf89304e99787486e8f", size = 93441, upload-time = "2025-12-15T10:25:35.942Z" }, ] [[package]] @@ -1032,6 +1033,34 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/1f/21/3cedee63417bc5553eed0c204be478071c9ab208e5e259e97287590194f1/django_storages-1.14.6-py3-none-any.whl", hash = "sha256:11b7b6200e1cb5ffcd9962bd3673a39c7d6a6109e8096f0e03d46fab3d3aabd9", size = 33095, upload-time = "2025-04-02T02:34:53.291Z" }, ] +[[package]] +name = "django-stubs" +version = "5.2.8" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "django" }, + { name = "django-stubs-ext" }, + { name = "types-pyyaml" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/6c/75/97626224fd8f1787bb6f7f06944efcfddd5da7764bf741cf7f59d102f4a0/django_stubs-5.2.8.tar.gz", hash = "sha256:9bba597c9a8ed8c025cae4696803d5c8be1cf55bfc7648a084cbf864187e2f8b", size = 257709, upload-time = "2025-12-01T08:13:09.569Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7d/3f/7c9543ad5ade5ce1d33d187a3abd82164570314ebee72c6206ab5c044ebf/django_stubs-5.2.8-py3-none-any.whl", hash = "sha256:a3c63119fd7062ac63d58869698d07c9e5ec0561295c4e700317c54e8d26716c", size = 508136, upload-time = "2025-12-01T08:13:07.963Z" }, +] + +[[package]] +name = "django-stubs-ext" +version = "5.2.8" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "django" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/14/a2/d67f4a5200ff7626b104eddceaf529761cba4ed318a73ffdb0677551be73/django_stubs_ext-5.2.8.tar.gz", hash = "sha256:b39938c46d7a547cd84e4a6378dbe51a3dd64d70300459087229e5fee27e5c6b", size = 6487, upload-time = "2025-12-01T08:12:37.486Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/da/2d/cb0151b780c3730cf0f2c0fcb1b065a5e88f877cf7a9217483c375353af1/django_stubs_ext-5.2.8-py3-none-any.whl", hash = "sha256:1dd5470c9675591362c78a157a3cf8aec45d0e7a7f0cf32f227a1363e54e0652", size = 9949, upload-time = "2025-12-01T08:12:36.397Z" }, +] + [[package]] name = "django-summernote" version = "0.8.20.0" @@ -1056,14 +1085,14 @@ wheels = [ [[package]] name = "django-unfold" -version = "0.73.1" +version = "0.74.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "django" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/03/80/fb57c7016a784f86ab5e73a7e843941daad9feea1d44b31a8f40f24d190e/django_unfold-0.73.1.tar.gz", hash = "sha256:2c1bbf24d2fc162fe5d0e19b27c1f8287fdd5343b1ffe2b78ee26586ed1a4837", size = 1103069, upload-time = "2025-12-09T09:11:29.087Z" } +sdist = { url = "https://files.pythonhosted.org/packages/78/88/d98c21ed315e5cb025f45aaea1e95d35c0fd11fb9123cb4c1278c33e70ad/django_unfold-0.74.1.tar.gz", hash = "sha256:573f793f975b9dbe324859121a179ae3f4d600d580e28e038736d7a2696e86dc", size = 1103394, upload-time = "2025-12-15T17:06:36Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/79/89/4d5716871f9c7aea6c2a567ac297380efa870c4641641a87b45a7b8587c0/django_unfold-0.73.1-py3-none-any.whl", hash = "sha256:7241275b75f0784a28410afa6bb4660f427eb7b62d48726195b35374887f017d", size = 1216980, upload-time = "2025-12-09T09:11:27.761Z" }, + { url = "https://files.pythonhosted.org/packages/2d/21/1c5482019bf2b454ac3e67cf0de456eb3dccc2f478a865a2f8a4fba28ef7/django_unfold-0.74.1-py3-none-any.whl", hash = "sha256:0b0a4b13c568309f3bb0a14d5bd7353b47b676d97695954d9631245df84e18f3", size = 1217338, upload-time = "2025-12-15T17:06:34.418Z" }, ] [[package]] @@ -1149,6 +1178,22 @@ crypto = [ { name = "cryptography" }, ] +[[package]] +name = "djangorestframework-stubs" +version = "3.16.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "django-stubs" }, + { name = "requests" }, + { name = "types-pyyaml" }, + { name = "types-requests" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/38/ed/6e16dbe8e79af9d2cdbcbd89553e59d18ecab7e9820ebb751085fc29fc0e/djangorestframework_stubs-3.16.6.tar.gz", hash = "sha256:b8d3e73604280f69c628ff7900f0e84703d9ff47cd050fccb5f751438e4c5813", size = 32274, upload-time = "2025-12-03T22:26:23.238Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/93/e3/d75f9e06d13d7fe8ed25473627c277992b7fad80747a4eaa1c7faa97e09e/djangorestframework_stubs-3.16.6-py3-none-any.whl", hash = "sha256:9bf2e5c83478edca3b8eb5ffd673737243ade16ce4b47b633a4ea62fe6924331", size = 56506, upload-time = "2025-12-03T22:26:21.88Z" }, +] + [[package]] name = "djangorestframework-xml" version = "2.0.0" @@ -1182,6 +1227,20 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/11/a8/c6a4b901d17399c77cd81fb001ce8961e9f5e04d3daf27e8925cb012e163/docutils-0.22.3-py3-none-any.whl", hash = "sha256:bd772e4aca73aff037958d44f2be5229ded4c09927fcf8690c577b66234d6ceb", size = 633032, upload-time = "2025-11-06T02:35:52.391Z" }, ] +[[package]] +name = "drf-orjson-renderer" +version = "1.8.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "django" }, + { name = "djangorestframework" }, + { name = "orjson" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b4/2d/97e1d2f2db68c7893b08295e8d4125da000985d6ad8b73f148a60fa599fe/drf_orjson_renderer-1.8.0.tar.gz", hash = "sha256:0cd506cc13471526b7ea679d56b7a346f033fab2103c9fa10f6d7c6fa60b6d22", size = 9650, upload-time = "2025-12-17T18:35:22.479Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7e/1a/8dab7b29cd33f94b927fba554ba4dfc4483f8e215e0e3ecaea88bdc045cb/drf_orjson_renderer-1.8.0-py3-none-any.whl", hash = "sha256:386ef0feda21147a490886a233b34b2ec0baf874a1de07e689aa8bc264c9baff", size = 7704, upload-time = "2025-12-17T18:35:21.085Z" }, +] + [[package]] name = "drf-spectacular" version = "0.29.0" @@ -1328,6 +1387,7 @@ dependencies = [ { name = "djangorestframework-xml" }, { name = "djangorestframework-yaml" }, { name = "docutils" }, + { name = "drf-orjson-renderer" }, { name = "drf-spectacular", extra = ["sidecar"] }, { name = "drf-spectacular-websocket" }, { name = "elasticsearch-dsl" }, @@ -1369,8 +1429,17 @@ jupyter = [ linting = [ { name = "basedpyright" }, { name = "celery-types" }, + { name = "django-stubs" }, + { name = "djangorestframework-stubs" }, { name = "pyright" }, { name = "ruff" }, + { name = "types-docutils" }, + { name = "types-paramiko" }, + { name = "types-pillow" }, + { name = "types-psutil" }, + { name = "types-redis" }, + { name = "types-requests" }, + { name = "types-six" }, ] openai = [ { name = "openai" }, @@ -1396,30 +1465,31 @@ requires-dist = [ { name = "colorlog", specifier = "==6.10.1" }, { name = "coverage", specifier = "==7.13.0" }, { name = "cryptography", specifier = "==46.0.3" }, - { name = "django", specifier = "==5.2.8" }, + { name = "django", specifier = "==5.2.9" }, { name = "django-cacheops", specifier = "==7.2" }, { name = "django-celery-beat", marker = "extra == 'worker'", specifier = "==2.8.1" }, { name = "django-celery-results", marker = "extra == 'worker'", specifier = "==2.6.0" }, { name = "django-constance", specifier = "==4.3.4" }, { name = "django-cors-headers", specifier = "==4.9.0" }, - { name = "django-dbbackup", specifier = "==5.0.1" }, + { name = "django-dbbackup", specifier = "==5.1.0" }, { name = "django-elasticsearch-dsl", specifier = "==8.2" }, { name = "django-extensions", specifier = "==4.1" }, { name = "django-filter", specifier = "==25.2" }, { name = "django-health-check", specifier = "==3.20.0" }, { name = "django-import-export", extras = ["all"], specifier = ">=4.3.14" }, - { name = "django-json-widget", specifier = "==2.1.0" }, + { name = "django-json-widget", specifier = "==2.1.1" }, { name = "django-mailbox", specifier = "==4.10.1" }, { name = "django-md-field", specifier = "==0.1.0" }, { name = "django-model-utils", specifier = "==5.0.0" }, - { name = "django-modeltranslation", specifier = "==0.19.17" }, + { name = "django-modeltranslation", specifier = "==0.19.19" }, { name = "django-mptt", specifier = "==0.18.0" }, { name = "django-prometheus", specifier = "==2.4.1" }, { name = "django-ratelimit", specifier = "==4.1.0" }, { name = "django-redis", specifier = "==6.0.0" }, { name = "django-storages", specifier = "==1.14.6" }, + { name = "django-stubs", marker = "extra == 'linting'", specifier = "==5.2.8" }, { name = "django-summernote", specifier = "==0.8.20.0" }, - { name = "django-unfold", specifier = "==0.73.1" }, + { name = "django-unfold", specifier = "==0.74.1" }, { name = "django-unfold-markdown", specifier = "==0.1.2" }, { name = "django-widget-tweaks", specifier = "==1.5.0" }, { name = "djangoql", specifier = "==0.18.1" }, @@ -1427,20 +1497,22 @@ requires-dist = [ { name = "djangorestframework-camel-case", specifier = "==1.4.2" }, { name = "djangorestframework-recursive", specifier = "==0.1.2" }, { name = "djangorestframework-simplejwt", extras = ["crypto"], specifier = "==5.5.1" }, + { name = "djangorestframework-stubs", marker = "extra == 'linting'", specifier = "==3.16.6" }, { name = "djangorestframework-xml", specifier = "==2.0.0" }, { name = "djangorestframework-yaml", specifier = "==2.0.0" }, { name = "docutils", specifier = "==0.22.3" }, + { name = "drf-orjson-renderer", specifier = ">=1.8.0" }, { name = "drf-spectacular", extras = ["sidecar"], specifier = "==0.29.0" }, { name = "drf-spectacular-websocket", specifier = ">=1.3.1" }, { name = "elasticsearch-dsl", specifier = "==8.18.0" }, - { name = "filelock", specifier = "==3.20.0" }, + { name = "filelock", specifier = "==3.20.1" }, { name = "filetype", specifier = "==1.2.0" }, { name = "graphene-django", specifier = "==3.2.3" }, { name = "graphene-file-upload", specifier = "==1.3.0" }, { name = "gunicorn", specifier = "==23.0.0" }, { name = "httpx", specifier = "==0.28.1" }, { name = "jupyter", marker = "extra == 'jupyter'", specifier = "==1.1.1" }, - { name = "openai", marker = "extra == 'openai'", specifier = "==2.12.0" }, + { name = "openai", marker = "extra == 'openai'", specifier = "==2.13.0" }, { name = "paramiko", specifier = "==4.0.0" }, { name = "pillow", specifier = "==12.0.0" }, { name = "pip", specifier = ">=25.3" }, @@ -1449,17 +1521,24 @@ requires-dist = [ { name = "psycopg2", specifier = "==2.9.11" }, { name = "pygraphviz", marker = "sys_platform != 'win32' and extra == 'graph'", specifier = "==1.14" }, { name = "pyjwt", specifier = "==2.10.1" }, - { name = "pymdown-extensions", specifier = "==10.18" }, - { name = "pyright", marker = "extra == 'linting'", specifier = "==1.1.387" }, + { name = "pymdown-extensions", specifier = "==10.19.1" }, + { name = "pyright", marker = "extra == 'linting'", specifier = "==1.1.407" }, { name = "pytest", specifier = "==9.0.2" }, { name = "pytest-django", specifier = "==4.11.1" }, { name = "python-slugify", specifier = "==8.0.4" }, { name = "redis", specifier = "==7.1.0" }, { name = "requests", specifier = "==2.32.5" }, { name = "ruff", marker = "extra == 'linting'", specifier = "==0.14.9" }, - { name = "sentry-sdk", extras = ["django", "celery", "opentelemetry"], specifier = "==2.47.0" }, + { name = "sentry-sdk", extras = ["django", "celery", "opentelemetry"], specifier = "==2.48.0" }, { name = "six", specifier = "==1.17.0" }, { name = "swapper", specifier = "==1.4.0" }, + { name = "types-docutils", marker = "extra == 'linting'", specifier = "==0.22.3.20251115" }, + { name = "types-paramiko", marker = "extra == 'linting'", specifier = "==4.0.0.20250822" }, + { name = "types-pillow", marker = "extra == 'linting'", specifier = "==10.2.0.20240822" }, + { name = "types-psutil", marker = "extra == 'linting'", specifier = "==7.1.3.20251211" }, + { name = "types-redis", marker = "extra == 'linting'", specifier = "==4.6.0.20241004" }, + { name = "types-requests", marker = "extra == 'linting'", specifier = "==2.32.4.20250913" }, + { name = "types-six", marker = "extra == 'linting'", specifier = "==1.17.0.20251009" }, { name = "uvicorn", specifier = "==0.38.0" }, { name = "websockets", specifier = "==15.0.1" }, { name = "whitenoise", specifier = ">=6.11.0" }, @@ -1499,11 +1578,11 @@ wheels = [ [[package]] name = "filelock" -version = "3.20.0" +version = "3.20.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/58/46/0028a82567109b5ef6e4d2a1f04a583fb513e6cf9527fcdd09afd817deeb/filelock-3.20.0.tar.gz", hash = "sha256:711e943b4ec6be42e1d4e6690b48dc175c822967466bb31c0c293f34334c13f4", size = 18922, upload-time = "2025-10-08T18:03:50.056Z" } +sdist = { url = "https://files.pythonhosted.org/packages/a7/23/ce7a1126827cedeb958fc043d61745754464eb56c5937c35bbf2b8e26f34/filelock-3.20.1.tar.gz", hash = "sha256:b8360948b351b80f420878d8516519a2204b07aefcdcfd24912a5d33127f188c", size = 19476, upload-time = "2025-12-15T23:54:28.027Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/76/91/7216b27286936c16f5b4d0c530087e4a54eead683e6b0b73dd0c64844af6/filelock-3.20.0-py3-none-any.whl", hash = "sha256:339b4732ffda5cd79b13f4e2711a31b0365ce445d95d243bb996273d072546a2", size = 16054, upload-time = "2025-10-08T18:03:48.35Z" }, + { url = "https://files.pythonhosted.org/packages/e3/7f/a1a97644e39e7316d850784c642093c99df1290a460df4ede27659056834/filelock-3.20.1-py3-none-any.whl", hash = "sha256:15d9e9a67306188a44baa72f569d2bfd803076269365fdea0934385da4dc361a", size = 16666, upload-time = "2025-12-15T23:54:26.874Z" }, ] [[package]] @@ -2497,7 +2576,7 @@ wheels = [ [[package]] name = "notebook" -version = "7.5.0" +version = "7.5.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "jupyter-server" }, @@ -2506,9 +2585,9 @@ dependencies = [ { name = "notebook-shim" }, { name = "tornado" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/89/ac/a97041621250a4fc5af379fb377942841eea2ca146aab166b8fcdfba96c2/notebook-7.5.0.tar.gz", hash = "sha256:3b27eaf9913033c28dde92d02139414c608992e1df4b969c843219acf2ff95e4", size = 14052074, upload-time = "2025-11-19T08:36:20.093Z" } +sdist = { url = "https://files.pythonhosted.org/packages/8a/a9/882707b0aa639e6d7d3e7df4bfbe07479d832e9a8f02d8471002a4ea6d65/notebook-7.5.1.tar.gz", hash = "sha256:b2fb4cef4d47d08c33aecce1c6c6e84be05436fbd791f88fce8df9fbca088b75", size = 14058696, upload-time = "2025-12-16T07:38:59.223Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/73/96/00df2a4760f10f5af0f45c4955573cae6189931f9a30265a35865f8c1031/notebook-7.5.0-py3-none-any.whl", hash = "sha256:3300262d52905ca271bd50b22617681d95f08a8360d099e097726e6d2efb5811", size = 14460968, upload-time = "2025-11-19T08:36:15.869Z" }, + { url = "https://files.pythonhosted.org/packages/d1/86/ca516cb58ad2cb2064124d31cf0fd8b012fca64bebeb26da2d2ddf03fc79/notebook-7.5.1-py3-none-any.whl", hash = "sha256:f4e2451c19910c33b88709b84537e11f6368c1cdff1aa0c43db701aea535dd44", size = 14468080, upload-time = "2025-12-16T07:38:55.644Z" }, ] [[package]] @@ -2575,7 +2654,7 @@ sdist = { url = "https://files.pythonhosted.org/packages/97/73/8ade73f6749177003 [[package]] name = "openai" -version = "2.12.0" +version = "2.13.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, @@ -2587,9 +2666,9 @@ dependencies = [ { name = "tqdm" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/86/f9/fb8abeb4cdba6f24daf3d7781f42ceb1be1ff579eb20705899e617dd95f1/openai-2.12.0.tar.gz", hash = "sha256:cc6dcbcb8bccf05976d983f6516c5c1f447b71c747720f1530b61e8f858bcbc9", size = 626183, upload-time = "2025-12-15T16:17:15.097Z" } +sdist = { url = "https://files.pythonhosted.org/packages/0f/39/8e347e9fda125324d253084bb1b82407e5e3c7777a03dc398f79b2d95626/openai-2.13.0.tar.gz", hash = "sha256:9ff633b07a19469ec476b1e2b5b26c5ef700886524a7a72f65e6f0b5203142d5", size = 626583, upload-time = "2025-12-16T18:19:44.387Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c3/a1/f055214448cb4b176e89459d889af9615fe7d927634fb5a2cecfb7674bc5/openai-2.12.0-py3-none-any.whl", hash = "sha256:7177998ce49ba3f90bcce8b5769a6666d90b1f328f0518d913aaec701271485a", size = 1066590, upload-time = "2025-12-15T16:17:13.301Z" }, + { url = "https://files.pythonhosted.org/packages/bb/d5/eb52edff49d3d5ea116e225538c118699ddeb7c29fa17ec28af14bc10033/openai-2.13.0-py3-none-any.whl", hash = "sha256:746521065fed68df2f9c2d85613bb50844343ea81f60009b60e6a600c9352c79", size = 1066837, upload-time = "2025-12-16T18:19:43.124Z" }, ] [[package]] @@ -2673,6 +2752,44 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/7a/5e/5958555e09635d09b75de3c4f8b9cae7335ca545d77392ffe7331534c402/opentelemetry_semantic_conventions-0.60b1-py3-none-any.whl", hash = "sha256:9fa8c8b0c110da289809292b0591220d3a7b53c1526a23021e977d68597893fb", size = 219982, upload-time = "2025-12-11T13:32:36.955Z" }, ] +[[package]] +name = "orjson" +version = "3.11.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/04/b8/333fdb27840f3bf04022d21b654a35f58e15407183aeb16f3b41aa053446/orjson-3.11.5.tar.gz", hash = "sha256:82393ab47b4fe44ffd0a7659fa9cfaacc717eb617c93cde83795f14af5c2e9d5", size = 5972347, upload-time = "2025-12-06T15:55:39.458Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ef/a4/8052a029029b096a78955eadd68ab594ce2197e24ec50e6b6d2ab3f4e33b/orjson-3.11.5-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:334e5b4bff9ad101237c2d799d9fd45737752929753bf4faf4b207335a416b7d", size = 245347, upload-time = "2025-12-06T15:54:22.061Z" }, + { url = "https://files.pythonhosted.org/packages/64/67/574a7732bd9d9d79ac620c8790b4cfe0717a3d5a6eb2b539e6e8995e24a0/orjson-3.11.5-cp312-cp312-macosx_15_0_arm64.whl", hash = "sha256:ff770589960a86eae279f5d8aa536196ebda8273a2a07db2a54e82b93bc86626", size = 129435, upload-time = "2025-12-06T15:54:23.615Z" }, + { url = "https://files.pythonhosted.org/packages/52/8d/544e77d7a29d90cf4d9eecd0ae801c688e7f3d1adfa2ebae5e1e94d38ab9/orjson-3.11.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ed24250e55efbcb0b35bed7caaec8cedf858ab2f9f2201f17b8938c618c8ca6f", size = 132074, upload-time = "2025-12-06T15:54:24.694Z" }, + { url = "https://files.pythonhosted.org/packages/6e/57/b9f5b5b6fbff9c26f77e785baf56ae8460ef74acdb3eae4931c25b8f5ba9/orjson-3.11.5-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a66d7769e98a08a12a139049aac2f0ca3adae989817f8c43337455fbc7669b85", size = 130520, upload-time = "2025-12-06T15:54:26.185Z" }, + { url = "https://files.pythonhosted.org/packages/f6/6d/d34970bf9eb33f9ec7c979a262cad86076814859e54eb9a059a52f6dc13d/orjson-3.11.5-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:86cfc555bfd5794d24c6a1903e558b50644e5e68e6471d66502ce5cb5fdef3f9", size = 136209, upload-time = "2025-12-06T15:54:27.264Z" }, + { url = "https://files.pythonhosted.org/packages/e7/39/bc373b63cc0e117a105ea12e57280f83ae52fdee426890d57412432d63b3/orjson-3.11.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a230065027bc2a025e944f9d4714976a81e7ecfa940923283bca7bbc1f10f626", size = 139837, upload-time = "2025-12-06T15:54:28.75Z" }, + { url = "https://files.pythonhosted.org/packages/cb/aa/7c4818c8d7d324da220f4f1af55c343956003aa4d1ce1857bdc1d396ba69/orjson-3.11.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b29d36b60e606df01959c4b982729c8845c69d1963f88686608be9ced96dbfaa", size = 137307, upload-time = "2025-12-06T15:54:29.856Z" }, + { url = "https://files.pythonhosted.org/packages/46/bf/0993b5a056759ba65145effe3a79dd5a939d4a070eaa5da2ee3180fbb13f/orjson-3.11.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c74099c6b230d4261fdc3169d50efc09abf38ace1a42ea2f9994b1d79153d477", size = 139020, upload-time = "2025-12-06T15:54:31.024Z" }, + { url = "https://files.pythonhosted.org/packages/65/e8/83a6c95db3039e504eda60fc388f9faedbb4f6472f5aba7084e06552d9aa/orjson-3.11.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e697d06ad57dd0c7a737771d470eedc18e68dfdefcdd3b7de7f33dfda5b6212e", size = 141099, upload-time = "2025-12-06T15:54:32.196Z" }, + { url = "https://files.pythonhosted.org/packages/b9/b4/24fdc024abfce31c2f6812973b0a693688037ece5dc64b7a60c1ce69e2f2/orjson-3.11.5-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:e08ca8a6c851e95aaecc32bc44a5aa75d0ad26af8cdac7c77e4ed93acf3d5b69", size = 413540, upload-time = "2025-12-06T15:54:33.361Z" }, + { url = "https://files.pythonhosted.org/packages/d9/37/01c0ec95d55ed0c11e4cae3e10427e479bba40c77312b63e1f9665e0737d/orjson-3.11.5-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:e8b5f96c05fce7d0218df3fdfeb962d6b8cfff7e3e20264306b46dd8b217c0f3", size = 151530, upload-time = "2025-12-06T15:54:34.6Z" }, + { url = "https://files.pythonhosted.org/packages/f9/d4/f9ebc57182705bb4bbe63f5bbe14af43722a2533135e1d2fb7affa0c355d/orjson-3.11.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ddbfdb5099b3e6ba6d6ea818f61997bb66de14b411357d24c4612cf1ebad08ca", size = 141863, upload-time = "2025-12-06T15:54:35.801Z" }, + { url = "https://files.pythonhosted.org/packages/0d/04/02102b8d19fdcb009d72d622bb5781e8f3fae1646bf3e18c53d1bc8115b5/orjson-3.11.5-cp312-cp312-win32.whl", hash = "sha256:9172578c4eb09dbfcf1657d43198de59b6cef4054de385365060ed50c458ac98", size = 135255, upload-time = "2025-12-06T15:54:37.209Z" }, + { url = "https://files.pythonhosted.org/packages/d4/fb/f05646c43d5450492cb387de5549f6de90a71001682c17882d9f66476af5/orjson-3.11.5-cp312-cp312-win_amd64.whl", hash = "sha256:2b91126e7b470ff2e75746f6f6ee32b9ab67b7a93c8ba1d15d3a0caaf16ec875", size = 133252, upload-time = "2025-12-06T15:54:38.401Z" }, + { url = "https://files.pythonhosted.org/packages/dc/a6/7b8c0b26ba18c793533ac1cd145e131e46fcf43952aa94c109b5b913c1f0/orjson-3.11.5-cp312-cp312-win_arm64.whl", hash = "sha256:acbc5fac7e06777555b0722b8ad5f574739e99ffe99467ed63da98f97f9ca0fe", size = 126777, upload-time = "2025-12-06T15:54:39.515Z" }, + { url = "https://files.pythonhosted.org/packages/10/43/61a77040ce59f1569edf38f0b9faadc90c8cf7e9bec2e0df51d0132c6bb7/orjson-3.11.5-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:3b01799262081a4c47c035dd77c1301d40f568f77cc7ec1bb7db5d63b0a01629", size = 245271, upload-time = "2025-12-06T15:54:40.878Z" }, + { url = "https://files.pythonhosted.org/packages/55/f9/0f79be617388227866d50edd2fd320cb8fb94dc1501184bb1620981a0aba/orjson-3.11.5-cp313-cp313-macosx_15_0_arm64.whl", hash = "sha256:61de247948108484779f57a9f406e4c84d636fa5a59e411e6352484985e8a7c3", size = 129422, upload-time = "2025-12-06T15:54:42.403Z" }, + { url = "https://files.pythonhosted.org/packages/77/42/f1bf1549b432d4a78bfa95735b79b5dac75b65b5bb815bba86ad406ead0a/orjson-3.11.5-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:894aea2e63d4f24a7f04a1908307c738d0dce992e9249e744b8f4e8dd9197f39", size = 132060, upload-time = "2025-12-06T15:54:43.531Z" }, + { url = "https://files.pythonhosted.org/packages/25/49/825aa6b929f1a6ed244c78acd7b22c1481fd7e5fda047dc8bf4c1a807eb6/orjson-3.11.5-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ddc21521598dbe369d83d4d40338e23d4101dad21dae0e79fa20465dbace019f", size = 130391, upload-time = "2025-12-06T15:54:45.059Z" }, + { url = "https://files.pythonhosted.org/packages/42/ec/de55391858b49e16e1aa8f0bbbb7e5997b7345d8e984a2dec3746d13065b/orjson-3.11.5-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7cce16ae2f5fb2c53c3eafdd1706cb7b6530a67cc1c17abe8ec747f5cd7c0c51", size = 135964, upload-time = "2025-12-06T15:54:46.576Z" }, + { url = "https://files.pythonhosted.org/packages/1c/40/820bc63121d2d28818556a2d0a09384a9f0262407cf9fa305e091a8048df/orjson-3.11.5-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e46c762d9f0e1cfb4ccc8515de7f349abbc95b59cb5a2bd68df5973fdef913f8", size = 139817, upload-time = "2025-12-06T15:54:48.084Z" }, + { url = "https://files.pythonhosted.org/packages/09/c7/3a445ca9a84a0d59d26365fd8898ff52bdfcdcb825bcc6519830371d2364/orjson-3.11.5-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d7345c759276b798ccd6d77a87136029e71e66a8bbf2d2755cbdde1d82e78706", size = 137336, upload-time = "2025-12-06T15:54:49.426Z" }, + { url = "https://files.pythonhosted.org/packages/9a/b3/dc0d3771f2e5d1f13368f56b339c6782f955c6a20b50465a91acb79fe961/orjson-3.11.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75bc2e59e6a2ac1dd28901d07115abdebc4563b5b07dd612bf64260a201b1c7f", size = 138993, upload-time = "2025-12-06T15:54:50.939Z" }, + { url = "https://files.pythonhosted.org/packages/d1/a2/65267e959de6abe23444659b6e19c888f242bf7725ff927e2292776f6b89/orjson-3.11.5-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:54aae9b654554c3b4edd61896b978568c6daa16af96fa4681c9b5babd469f863", size = 141070, upload-time = "2025-12-06T15:54:52.414Z" }, + { url = "https://files.pythonhosted.org/packages/63/c9/da44a321b288727a322c6ab17e1754195708786a04f4f9d2220a5076a649/orjson-3.11.5-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:4bdd8d164a871c4ec773f9de0f6fe8769c2d6727879c37a9666ba4183b7f8228", size = 413505, upload-time = "2025-12-06T15:54:53.67Z" }, + { url = "https://files.pythonhosted.org/packages/7f/17/68dc14fa7000eefb3d4d6d7326a190c99bb65e319f02747ef3ebf2452f12/orjson-3.11.5-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:a261fef929bcf98a60713bf5e95ad067cea16ae345d9a35034e73c3990e927d2", size = 151342, upload-time = "2025-12-06T15:54:55.113Z" }, + { url = "https://files.pythonhosted.org/packages/c4/c5/ccee774b67225bed630a57478529fc026eda33d94fe4c0eac8fe58d4aa52/orjson-3.11.5-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:c028a394c766693c5c9909dec76b24f37e6a1b91999e8d0c0d5feecbe93c3e05", size = 141823, upload-time = "2025-12-06T15:54:56.331Z" }, + { url = "https://files.pythonhosted.org/packages/67/80/5d00e4155d0cd7390ae2087130637671da713959bb558db9bac5e6f6b042/orjson-3.11.5-cp313-cp313-win32.whl", hash = "sha256:2cc79aaad1dfabe1bd2d50ee09814a1253164b3da4c00a78c458d82d04b3bdef", size = 135236, upload-time = "2025-12-06T15:54:57.507Z" }, + { url = "https://files.pythonhosted.org/packages/95/fe/792cc06a84808dbdc20ac6eab6811c53091b42f8e51ecebf14b540e9cfe4/orjson-3.11.5-cp313-cp313-win_amd64.whl", hash = "sha256:ff7877d376add4e16b274e35a3f58b7f37b362abf4aa31863dadacdd20e3a583", size = 133167, upload-time = "2025-12-06T15:54:58.71Z" }, + { url = "https://files.pythonhosted.org/packages/46/2c/d158bd8b50e3b1cfdcf406a7e463f6ffe3f0d167b99634717acdaf5e299f/orjson-3.11.5-cp313-cp313-win_arm64.whl", hash = "sha256:59ac72ea775c88b163ba8d21b0177628bd015c5dd060647bbab6e22da3aad287", size = 126712, upload-time = "2025-12-06T15:54:59.892Z" }, +] + [[package]] name = "packaging" version = "25.0" @@ -3075,15 +3192,15 @@ wheels = [ [[package]] name = "pymdown-extensions" -version = "10.18" +version = "10.19.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "markdown" }, { name = "pyyaml" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/d4/95/e4fa281e3f13b3d9c4aaebb21ef44879840325fa418276dd921209a5e9f9/pymdown_extensions-10.18.tar.gz", hash = "sha256:20252abe6367354b24191431617a072ee6be9f68c5afcc74ea5573508a61f9e5", size = 847697, upload-time = "2025-12-07T17:22:12.857Z" } +sdist = { url = "https://files.pythonhosted.org/packages/72/2d/9f30cee56d4d6d222430d401e85b0a6a1ae229819362f5786943d1a8c03b/pymdown_extensions-10.19.1.tar.gz", hash = "sha256:4969c691009a389fb1f9712dd8e7bd70dcc418d15a0faf70acb5117d022f7de8", size = 847839, upload-time = "2025-12-14T17:25:24.42Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/46/a4/aa2bada4a2fd648f40f19affa55d2c01dc7ff5ea9cffd3dfdeb6114951db/pymdown_extensions-10.18-py3-none-any.whl", hash = "sha256:090bca72be43f7d3186374e23c782899dbef9dc153ef24c59dcd3c346f9ffcae", size = 266703, upload-time = "2025-12-07T17:22:11.22Z" }, + { url = "https://files.pythonhosted.org/packages/fb/35/b763e8fbcd51968329b9adc52d188fc97859f85f2ee15fe9f379987d99c5/pymdown_extensions-10.19.1-py3-none-any.whl", hash = "sha256:e8698a66055b1dc0dca2a7f2c9d0ea6f5faa7834a9c432e3535ab96c0c4e509b", size = 266693, upload-time = "2025-12-14T17:25:22.999Z" }, ] [[package]] @@ -3113,15 +3230,15 @@ wheels = [ [[package]] name = "pyright" -version = "1.1.387" +version = "1.1.407" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "nodeenv" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c2/32/e7187478d3105d6d7edc9b754d56472ee06557c25cc404911288fee1796a/pyright-1.1.387.tar.gz", hash = "sha256:577de60224f7fe36505d5b181231e3a395d427b7873be0bbcaa962a29ea93a60", size = 21939, upload-time = "2024-10-30T08:46:31.44Z" } +sdist = { url = "https://files.pythonhosted.org/packages/a6/1b/0aa08ee42948b61745ac5b5b5ccaec4669e8884b53d31c8ec20b2fcd6b6f/pyright-1.1.407.tar.gz", hash = "sha256:099674dba5c10489832d4a4b2d302636152a9a42d317986c38474c76fe562262", size = 4122872, upload-time = "2025-10-24T23:17:15.145Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a0/18/c497df36641b0572f5bd59ae147b08ccaa6b8086397d50e1af97cc2ddcf6/pyright-1.1.387-py3-none-any.whl", hash = "sha256:6a1f495a261a72e12ad17e20d1ae3df4511223c773b19407cfa006229b1b08a5", size = 18577, upload-time = "2024-10-30T08:46:29.701Z" }, + { url = "https://files.pythonhosted.org/packages/dc/93/b69052907d032b00c40cb656d21438ec00b3a471733de137a3f65a49a0a0/pyright-1.1.407-py3-none-any.whl", hash = "sha256:6dd419f54fcc13f03b52285796d65e639786373f433e243f8b94cf93a7444d21", size = 5997008, upload-time = "2025-10-24T23:17:13.159Z" }, ] [[package]] @@ -3459,15 +3576,15 @@ wheels = [ [[package]] name = "sentry-sdk" -version = "2.47.0" +version = "2.48.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "certifi" }, { name = "urllib3" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/4a/2a/d225cbf87b6c8ecce5664db7bcecb82c317e448e3b24a2dcdaacb18ca9a7/sentry_sdk-2.47.0.tar.gz", hash = "sha256:8218891d5e41b4ea8d61d2aed62ed10c80e39d9f2959d6f939efbf056857e050", size = 381895, upload-time = "2025-12-03T14:06:36.846Z" } +sdist = { url = "https://files.pythonhosted.org/packages/40/f0/0e9dc590513d5e742d7799e2038df3a05167cba084c6ca4f3cdd75b55164/sentry_sdk-2.48.0.tar.gz", hash = "sha256:5213190977ff7fdff8a58b722fb807f8d5524a80488626ebeda1b5676c0c1473", size = 384828, upload-time = "2025-12-16T14:55:41.722Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/bd/ac/d6286ea0d49e7b58847faf67b00e56bb4ba3d525281e2ac306e1f1f353da/sentry_sdk-2.47.0-py2.py3-none-any.whl", hash = "sha256:d72f8c61025b7d1d9e52510d03a6247b280094a327dd900d987717a4fce93412", size = 411088, upload-time = "2025-12-03T14:06:35.374Z" }, + { url = "https://files.pythonhosted.org/packages/4d/19/8d77f9992e5cbfcaa9133c3bf63b4fbbb051248802e1e803fed5c552fbb2/sentry_sdk-2.48.0-py2.py3-none-any.whl", hash = "sha256:6b12ac256769d41825d9b7518444e57fa35b5642df4c7c5e322af4d2c8721172", size = 414555, upload-time = "2025-12-16T14:55:40.152Z" }, ] [package.optional-dependencies] @@ -3615,21 +3732,21 @@ wheels = [ [[package]] name = "tornado" -version = "6.5.3" +version = "6.5.4" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/7f/2e/3d22d478f27cb4b41edd4db7f10cd7846d0a28ea443342de3dba97035166/tornado-6.5.3.tar.gz", hash = "sha256:16abdeb0211796ffc73765bc0a20119712d68afeeaf93d1a3f2edf6b3aee8d5a", size = 513348, upload-time = "2025-12-11T04:16:42.225Z" } +sdist = { url = "https://files.pythonhosted.org/packages/37/1d/0a336abf618272d53f62ebe274f712e213f5a03c0b2339575430b8362ef2/tornado-6.5.4.tar.gz", hash = "sha256:a22fa9047405d03260b483980635f0b041989d8bcc9a313f8fe18b411d84b1d7", size = 513632, upload-time = "2025-12-15T19:21:03.836Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d3/e9/bf22f66e1d5d112c0617974b5ce86666683b32c09b355dfcd59f8d5c8ef6/tornado-6.5.3-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:2dd7d7e8d3e4635447a8afd4987951e3d4e8d1fb9ad1908c54c4002aabab0520", size = 443860, upload-time = "2025-12-11T04:16:26.638Z" }, - { url = "https://files.pythonhosted.org/packages/ca/9c/594b631f0b8dc5977080c7093d1e96f1377c10552577d2c31bb0208c9362/tornado-6.5.3-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:5977a396f83496657779f59a48c38096ef01edfe4f42f1c0634b791dde8165d0", size = 442118, upload-time = "2025-12-11T04:16:28.32Z" }, - { url = "https://files.pythonhosted.org/packages/78/f6/685b869f5b5b9d9547571be838c6106172082751696355b60fc32a4988ed/tornado-6.5.3-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f72ac800be2ac73ddc1504f7aa21069a4137e8d70c387172c063d363d04f2208", size = 445700, upload-time = "2025-12-11T04:16:29.64Z" }, - { url = "https://files.pythonhosted.org/packages/91/4c/f0d19edf24912b7f21ae5e941f7798d132ad4d9b71441c1e70917a297265/tornado-6.5.3-cp39-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c43c4fc4f5419c6561cfb8b884a8f6db7b142787d47821e1a0e1296253458265", size = 445041, upload-time = "2025-12-11T04:16:30.799Z" }, - { url = "https://files.pythonhosted.org/packages/eb/2b/e02da94f4a4aef2bb3b923c838ef284a77548a5f06bac2a8682b36b4eead/tornado-6.5.3-cp39-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:de8b3fed4b3afb65d542d7702ac8767b567e240f6a43020be8eaef59328f117b", size = 445270, upload-time = "2025-12-11T04:16:32.316Z" }, - { url = "https://files.pythonhosted.org/packages/58/e2/7a7535d23133443552719dba526dacbb7415f980157da9f14950ddb88ad6/tornado-6.5.3-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:dbc4b4c32245b952566e17a20d5c1648fbed0e16aec3fc7e19f3974b36e0e47c", size = 445957, upload-time = "2025-12-11T04:16:33.913Z" }, - { url = "https://files.pythonhosted.org/packages/a0/1f/9ff92eca81ff17a86286ec440dcd5eab0400326eb81761aa9a4eecb1ffb9/tornado-6.5.3-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:db238e8a174b4bfd0d0238b8cfcff1c14aebb4e2fcdafbf0ea5da3b81caceb4c", size = 445371, upload-time = "2025-12-11T04:16:35.093Z" }, - { url = "https://files.pythonhosted.org/packages/70/b1/1d03ae4526a393b0b839472a844397337f03c7f3a1e6b5c82241f0e18281/tornado-6.5.3-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:892595c100cd9b53a768cbfc109dfc55dec884afe2de5290611a566078d9692d", size = 445348, upload-time = "2025-12-11T04:16:36.679Z" }, - { url = "https://files.pythonhosted.org/packages/4b/7d/7c181feadc8941f418d0d26c3790ee34ffa4bd0a294bc5201d44ebd19c1e/tornado-6.5.3-cp39-abi3-win32.whl", hash = "sha256:88141456525fe291e47bbe1ba3ffb7982549329f09b4299a56813923af2bd197", size = 446433, upload-time = "2025-12-11T04:16:38.332Z" }, - { url = "https://files.pythonhosted.org/packages/34/98/4f7f938606e21d0baea8c6c39a7c8e95bdf8e50b0595b1bb6f0de2af7a6e/tornado-6.5.3-cp39-abi3-win_amd64.whl", hash = "sha256:ba4b513d221cc7f795a532c1e296f36bcf6a60e54b15efd3f092889458c69af1", size = 446842, upload-time = "2025-12-11T04:16:39.867Z" }, - { url = "https://files.pythonhosted.org/packages/7a/27/0e3fca4c4edf33fb6ee079e784c63961cd816971a45e5e4cacebe794158d/tornado-6.5.3-cp39-abi3-win_arm64.whl", hash = "sha256:278c54d262911365075dd45e0b6314308c74badd6ff9a54490e7daccdd5ed0ea", size = 445863, upload-time = "2025-12-11T04:16:41.099Z" }, + { url = "https://files.pythonhosted.org/packages/ab/a9/e94a9d5224107d7ce3cc1fab8d5dc97f5ea351ccc6322ee4fb661da94e35/tornado-6.5.4-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:d6241c1a16b1c9e4cc28148b1cda97dd1c6cb4fb7068ac1bedc610768dff0ba9", size = 443909, upload-time = "2025-12-15T19:20:48.382Z" }, + { url = "https://files.pythonhosted.org/packages/db/7e/f7b8d8c4453f305a51f80dbb49014257bb7d28ccb4bbb8dd328ea995ecad/tornado-6.5.4-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:2d50f63dda1d2cac3ae1fa23d254e16b5e38153758470e9956cbc3d813d40843", size = 442163, upload-time = "2025-12-15T19:20:49.791Z" }, + { url = "https://files.pythonhosted.org/packages/ba/b5/206f82d51e1bfa940ba366a8d2f83904b15942c45a78dd978b599870ab44/tornado-6.5.4-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d1cf66105dc6acb5af613c054955b8137e34a03698aa53272dbda4afe252be17", size = 445746, upload-time = "2025-12-15T19:20:51.491Z" }, + { url = "https://files.pythonhosted.org/packages/8e/9d/1a3338e0bd30ada6ad4356c13a0a6c35fbc859063fa7eddb309183364ac1/tornado-6.5.4-cp39-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:50ff0a58b0dc97939d29da29cd624da010e7f804746621c78d14b80238669335", size = 445083, upload-time = "2025-12-15T19:20:52.778Z" }, + { url = "https://files.pythonhosted.org/packages/50/d4/e51d52047e7eb9a582da59f32125d17c0482d065afd5d3bc435ff2120dc5/tornado-6.5.4-cp39-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e5fb5e04efa54cf0baabdd10061eb4148e0be137166146fff835745f59ab9f7f", size = 445315, upload-time = "2025-12-15T19:20:53.996Z" }, + { url = "https://files.pythonhosted.org/packages/27/07/2273972f69ca63dbc139694a3fc4684edec3ea3f9efabf77ed32483b875c/tornado-6.5.4-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:9c86b1643b33a4cd415f8d0fe53045f913bf07b4a3ef646b735a6a86047dda84", size = 446003, upload-time = "2025-12-15T19:20:56.101Z" }, + { url = "https://files.pythonhosted.org/packages/d1/83/41c52e47502bf7260044413b6770d1a48dda2f0246f95ee1384a3cd9c44a/tornado-6.5.4-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:6eb82872335a53dd063a4f10917b3efd28270b56a33db69009606a0312660a6f", size = 445412, upload-time = "2025-12-15T19:20:57.398Z" }, + { url = "https://files.pythonhosted.org/packages/10/c7/bc96917f06cbee182d44735d4ecde9c432e25b84f4c2086143013e7b9e52/tornado-6.5.4-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:6076d5dda368c9328ff41ab5d9dd3608e695e8225d1cd0fd1e006f05da3635a8", size = 445392, upload-time = "2025-12-15T19:20:58.692Z" }, + { url = "https://files.pythonhosted.org/packages/0c/1a/d7592328d037d36f2d2462f4bc1fbb383eec9278bc786c1b111cbbd44cfa/tornado-6.5.4-cp39-abi3-win32.whl", hash = "sha256:1768110f2411d5cd281bac0a090f707223ce77fd110424361092859e089b38d1", size = 446481, upload-time = "2025-12-15T19:21:00.008Z" }, + { url = "https://files.pythonhosted.org/packages/d6/6d/c69be695a0a64fd37a97db12355a035a6d90f79067a3cf936ec2b1dc38cd/tornado-6.5.4-cp39-abi3-win_amd64.whl", hash = "sha256:fa07d31e0cd85c60713f2b995da613588aa03e1303d75705dca6af8babc18ddc", size = 446886, upload-time = "2025-12-15T19:21:01.287Z" }, + { url = "https://files.pythonhosted.org/packages/50/49/8dc3fd90902f70084bd2cd059d576ddb4f8bb44c2c7c0e33a11422acb17e/tornado-6.5.4-cp39-abi3-win_arm64.whl", hash = "sha256:053e6e16701eb6cbe641f308f4c1a9541f91b6261991160391bfc342e8a551a1", size = 445910, upload-time = "2025-12-15T19:21:02.571Z" }, ] [[package]] @@ -3653,6 +3770,122 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/00/c0/8f5d070730d7836adc9c9b6408dec68c6ced86b304a9b26a14df072a6e8c/traitlets-5.14.3-py3-none-any.whl", hash = "sha256:b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f", size = 85359, upload-time = "2024-04-19T11:11:46.763Z" }, ] +[[package]] +name = "types-cffi" +version = "1.17.0.20250915" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "types-setuptools" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/2a/98/ea454cea03e5f351323af6a482c65924f3c26c515efd9090dede58f2b4b6/types_cffi-1.17.0.20250915.tar.gz", hash = "sha256:4362e20368f78dabd5c56bca8004752cc890e07a71605d9e0d9e069dbaac8c06", size = 17229, upload-time = "2025-09-15T03:01:25.31Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/aa/ec/092f2b74b49ec4855cdb53050deb9699f7105b8fda6fe034c0781b8687f3/types_cffi-1.17.0.20250915-py3-none-any.whl", hash = "sha256:cef4af1116c83359c11bb4269283c50f0688e9fc1d7f0eeb390f3661546da52c", size = 20112, upload-time = "2025-09-15T03:01:24.187Z" }, +] + +[[package]] +name = "types-docutils" +version = "0.22.3.20251115" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/eb/d7/576ec24bf61a280f571e1f22284793adc321610b9bcfba1bf468cf7b334f/types_docutils-0.22.3.20251115.tar.gz", hash = "sha256:0f79ea6a7bd4d12d56c9f824a0090ffae0ea4204203eb0006392906850913e16", size = 56828, upload-time = "2025-11-15T02:59:57.371Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9c/01/61ac9eb38f1f978b47443dc6fd2e0a3b0f647c2da741ddad30771f1b2b6f/types_docutils-0.22.3.20251115-py3-none-any.whl", hash = "sha256:c6e53715b65395d00a75a3a8a74e352c669bc63959e65a207dffaa22f4a2ad6e", size = 91951, upload-time = "2025-11-15T02:59:56.413Z" }, +] + +[[package]] +name = "types-paramiko" +version = "4.0.0.20250822" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cryptography" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b7/b8/c6ff3b10c2f7b9897650af746f0dc6c5cddf054db857bc79d621f53c7d22/types_paramiko-4.0.0.20250822.tar.gz", hash = "sha256:1b56b0cbd3eec3d2fd123c9eb2704e612b777e15a17705a804279ea6525e0c53", size = 28730, upload-time = "2025-08-22T03:03:43.262Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/79/a1/b3774ed924a66ee2c041224d89c36f0c21f4f6cf75036d6ee7698bf8a4b9/types_paramiko-4.0.0.20250822-py3-none-any.whl", hash = "sha256:55bdb14db75ca89039725ec64ae3fa26b8d57b6991cfb476212fa8f83a59753c", size = 38833, upload-time = "2025-08-22T03:03:42.072Z" }, +] + +[[package]] +name = "types-pillow" +version = "10.2.0.20240822" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/18/4a/4495264dddaa600d65d68bcedb64dcccf9d9da61adff51f7d2ffd8e4c9ce/types-Pillow-10.2.0.20240822.tar.gz", hash = "sha256:559fb52a2ef991c326e4a0d20accb3bb63a7ba8d40eb493e0ecb0310ba52f0d3", size = 35389, upload-time = "2024-08-22T02:32:48.15Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/66/23/e81a5354859831fcf54d488d33b80ba6133ea84f874a9c0ec40a4881e133/types_Pillow-10.2.0.20240822-py3-none-any.whl", hash = "sha256:d9dab025aba07aeb12fd50a6799d4eac52a9603488eca09d7662543983f16c5d", size = 54354, upload-time = "2024-08-22T02:32:46.664Z" }, +] + +[[package]] +name = "types-psutil" +version = "7.1.3.20251211" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d2/d5/85165865b060fed80b5991574c2ae0ddfd4786398dc8bceddfe0a8960b74/types_psutil-7.1.3.20251211.tar.gz", hash = "sha256:2c25f8fd3a1a4aebdffb861b97755c9a2d5d8019dd6ec1a2f2a77ec796652c89", size = 25198, upload-time = "2025-12-11T03:16:44.651Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/29/61/658be05b56aeec195386b3f5c48cfa5bdaf8e989de3e4d802eeba457bd05/types_psutil-7.1.3.20251211-py3-none-any.whl", hash = "sha256:369872d955d7d47d77f4832b41e2300f832126e3fa97eb107d2d6a294c23c650", size = 32055, upload-time = "2025-12-11T03:16:43.864Z" }, +] + +[[package]] +name = "types-pyopenssl" +version = "24.1.0.20240722" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cryptography" }, + { name = "types-cffi" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/93/29/47a346550fd2020dac9a7a6d033ea03fccb92fa47c726056618cc889745e/types-pyOpenSSL-24.1.0.20240722.tar.gz", hash = "sha256:47913b4678a01d879f503a12044468221ed8576263c1540dcb0484ca21b08c39", size = 8458, upload-time = "2024-07-22T02:32:22.558Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/98/05/c868a850b6fbb79c26f5f299b768ee0adc1f9816d3461dcf4287916f655b/types_pyOpenSSL-24.1.0.20240722-py3-none-any.whl", hash = "sha256:6a7a5d2ec042537934cfb4c9d4deb0e16c4c6250b09358df1f083682fe6fda54", size = 7499, upload-time = "2024-07-22T02:32:21.232Z" }, +] + +[[package]] +name = "types-pyyaml" +version = "6.0.12.20250915" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7e/69/3c51b36d04da19b92f9e815be12753125bd8bc247ba0470a982e6979e71c/types_pyyaml-6.0.12.20250915.tar.gz", hash = "sha256:0f8b54a528c303f0e6f7165687dd33fafa81c807fcac23f632b63aa624ced1d3", size = 17522, upload-time = "2025-09-15T03:01:00.728Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bd/e0/1eed384f02555dde685fff1a1ac805c1c7dcb6dd019c916fe659b1c1f9ec/types_pyyaml-6.0.12.20250915-py3-none-any.whl", hash = "sha256:e7d4d9e064e89a3b3cae120b4990cd370874d2bf12fa5f46c97018dd5d3c9ab6", size = 20338, upload-time = "2025-09-15T03:00:59.218Z" }, +] + +[[package]] +name = "types-redis" +version = "4.6.0.20241004" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cryptography" }, + { name = "types-pyopenssl" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/3a/95/c054d3ac940e8bac4ca216470c80c26688a0e79e09f520a942bb27da3386/types-redis-4.6.0.20241004.tar.gz", hash = "sha256:5f17d2b3f9091ab75384153bfa276619ffa1cf6a38da60e10d5e6749cc5b902e", size = 49679, upload-time = "2024-10-04T02:43:59.224Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/55/82/7d25dce10aad92d2226b269bce2f85cfd843b4477cd50245d7d40ecf8f89/types_redis-4.6.0.20241004-py3-none-any.whl", hash = "sha256:ef5da68cb827e5f606c8f9c0b49eeee4c2669d6d97122f301d3a55dc6a63f6ed", size = 58737, upload-time = "2024-10-04T02:43:57.968Z" }, +] + +[[package]] +name = "types-requests" +version = "2.32.4.20250913" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/36/27/489922f4505975b11de2b5ad07b4fe1dca0bca9be81a703f26c5f3acfce5/types_requests-2.32.4.20250913.tar.gz", hash = "sha256:abd6d4f9ce3a9383f269775a9835a4c24e5cd6b9f647d64f88aa4613c33def5d", size = 23113, upload-time = "2025-09-13T02:40:02.309Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2a/20/9a227ea57c1285986c4cf78400d0a91615d25b24e257fd9e2969606bdfae/types_requests-2.32.4.20250913-py3-none-any.whl", hash = "sha256:78c9c1fffebbe0fa487a418e0fa5252017e9c60d1a2da394077f1780f655d7e1", size = 20658, upload-time = "2025-09-13T02:40:01.115Z" }, +] + +[[package]] +name = "types-setuptools" +version = "80.9.0.20250822" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/19/bd/1e5f949b7cb740c9f0feaac430e301b8f1c5f11a81e26324299ea671a237/types_setuptools-80.9.0.20250822.tar.gz", hash = "sha256:070ea7716968ec67a84c7f7768d9952ff24d28b65b6594797a464f1b3066f965", size = 41296, upload-time = "2025-08-22T03:02:08.771Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b6/2d/475bf15c1cdc172e7a0d665b6e373ebfb1e9bf734d3f2f543d668b07a142/types_setuptools-80.9.0.20250822-py3-none-any.whl", hash = "sha256:53bf881cb9d7e46ed12c76ef76c0aaf28cfe6211d3fab12e0b83620b1a8642c3", size = 63179, upload-time = "2025-08-22T03:02:07.643Z" }, +] + +[[package]] +name = "types-six" +version = "1.17.0.20251009" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ee/f7/448215bc7695cfa0c8a7e0dcfa54fe31b1d52fb87004fed32e659dd85c80/types_six-1.17.0.20251009.tar.gz", hash = "sha256:efe03064ecd0ffb0f7afe133990a2398d8493d8d1c1cc10ff3dfe476d57ba44f", size = 15552, upload-time = "2025-10-09T02:54:26.02Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b8/2f/94baa623421940e3eb5d2fc63570ebb046f2bb4d9573b8787edab3ed2526/types_six-1.17.0.20251009-py3-none-any.whl", hash = "sha256:2494f4c2a58ada0edfe01ea84b58468732e43394c572d9cf5b1dd06d86c487a3", size = 19935, upload-time = "2025-10-09T02:54:25.096Z" }, +] + [[package]] name = "typing-extensions" version = "4.15.0"