Add type hint descriptors for related fields, reorganize type hinting documentation and add robust type hint tests

This commit is contained in:
Brian Kohan 2026-02-05 13:17:34 -08:00
parent b4c93f0292
commit 3912cc6ba6
No known key found for this signature in database
GPG Key ID: 5C6CE8BA38C43FC1
44 changed files with 1352 additions and 511 deletions

View File

@ -19,3 +19,36 @@ The ``PolymorphicQuerySet`` class
.. autoclass:: polymorphic.managers.PolymorphicQuerySet
:members:
:show-inheritance:
.. _type_hint_descriptors:
Type Hint Descriptors
---------------------
.. autodata:: polymorphic.managers._All
.. autodata:: polymorphic.managers._Base
.. autodata:: polymorphic.managers._Through
.. autodata:: polymorphic.managers._Nullable
.. autodata:: polymorphic.managers.Nullable
.. autoclass:: polymorphic.managers.PolymorphicForwardManyToOneDescriptor
:members:
:show-inheritance:
.. autoclass:: polymorphic.managers.PolymorphicReverseManyToOneDescriptor
:members:
:show-inheritance:
.. autoclass:: polymorphic.managers.PolymorphicForwardOneToOneDescriptor
:members:
:show-inheritance:
.. autoclass:: polymorphic.managers.PolymorphicReverseOneToOneDescriptor
:members:
:show-inheritance:
.. autoclass:: polymorphic.managers.PolymorphicManyToManyDescriptor
:members:
:show-inheritance:

View File

@ -282,6 +282,7 @@ intersphinx_mapping = {
"https://docs.djangoproject.com/en/stable/_objects/",
),
"python": ("https://docs.python.org/3", None),
"typing-extensions": ("https://typing-extensions.readthedocs.io/en/latest/", None),
"django-guardian": ("https://django-guardian.readthedocs.io/en/stable", None),
"django-reversion": ("https://django-reversion.readthedocs.io/en/stable", None),
"django-extra-views": ("https://django-extra-views.readthedocs.io/en/stable", None),

View File

@ -4,12 +4,14 @@ Type Hints
.. versionadded:: 4.11
:pypi:`django-polymorphic` is now fully typed, and ships with type hints for all public
APIs. Typing is checked against :pypi:`mypy` and :pypi:`pyright` in the CI pipeline.
APIs. Typing is checked with :pypi:`mypy` and :pypi:`pyright` in the CI pipeline.
The utility and power of the Django ORM derives from its dynamism. This however makes static type
checking more difficult. To use the type hints effectively, it is recommended to use
:pypi:`django-stubs` and :pypi:`django-stubs-ext` which provides type hints for the Django ORM
itself.`
The utility and power of the Django ORM derives from its dynamism but this makes static typing
more difficult. There are *no additional runtime dependencies* but **to use the packaged type hint
classes and descriptors, you must install the following in your type checking context**:
* :pypi:`django-stubs` (required)
* :pypi:`django-stubs-ext` (optional)
.. tip::
@ -20,6 +22,80 @@ itself.`
Correct type hints for polymorphic managers and querysets cannot be automatically inferred - you
will have to add them explicitly if you want them:
.. literalinclude:: ../src/polymorphic/tests/examples/type_hints/models.py
.. _typing_managers:
Managers
--------
You can type your managers like this. It might not always be the case that you can add hints for all
child model types, especially if they are included in dependent apps. You can alleviate some of this
complexity with forward type references but strict typing may not always be appropriate.
.. literalinclude:: ../src/polymorphic/tests/examples/type_hints/managers/models.py
:language: python
:linenos:
.. code-block:: python
ParentModel.objects.all() # type: PolymorphicQuerySet[ParentModel | Child1 | Child2]
ParentModel.objects.instance_of(Child1) # type: PolymorphicQuerySet[Child1]
Child1.objects.non_polymorphic() # type: QuerySet[Child1]
.. _typing_foreign_key:
Foreign Key
-----------
:pypi:`django-polymorphic` includes several :ref:`type hint descriptors <type_hint_descriptors>`.
You can use them to type your forward and reverse relationship fields. For foreign key relationships
we provide :class:`~polymorphic.managers.PolymorphicForwardManyToOneDescriptor` and
:class:`~polymorphic.managers.PolymorphicReverseManyToOneDescriptor`:
.. literalinclude:: ../src/polymorphic/tests/examples/type_hints/fk/models.py
:language: python
:linenos:
.. code-block:: python
RelatedModel().parent: Optional[ParentModel | Child1 | Child2]
RelatedModel().children.all(): PolymorphicQuerySet[ParentModel | Child1 | Child2]
.. _typing_one_to_one:
One to One
----------
For foreign key relationships
we provide :class:`~polymorphic.managers.PolymorphicForwardOneToOneDescriptor` and
:class:`~polymorphic.managers.PolymorphicReverseOneToOneDescriptor`:
.. literalinclude:: ../src/polymorphic/tests/examples/type_hints/one2one/models.py
:language: python
:linenos:
.. code-block:: python
RelatedModel().parent_forward: ParentModel | Child1 | Child2 | None
RelatedModel().parent_reverse: ParentModel | Child1 | Child2
.. _typing_many_to_many:
Many to Many
------------
You can use the same :class:`~polymorphic.managers.PolymorphicManyToManyDescriptor` for
both forward and reverse :class:`~django.db.models.ManyToManyField` relationships.
The following example shows two :class:`~django.db.models.ManyToManyField` relationships:
1. :class:`~polymorphic.models.PolymorphicModel` -> :class:`~django.db.models.Model`
(with a custom through model)
2. :class:`~django.db.models.Model` -> :class:`~polymorphic.models.PolymorphicModel`
(with the default through model)
For the custom through model you will need to annotate using the :ref:`foreign key descriptors
<typing_foreign_key>` as well.
.. literalinclude:: ../src/polymorphic/tests/examples/type_hints/m2m/models.py
:language: python
:linenos:

View File

@ -37,12 +37,12 @@ setup python="python":
# install git pre-commit hooks
install-precommit:
@just run --no-default-groups --group precommit --exact pre-commit install
@just run --no-default-groups --group precommit --exact --isolated pre-commit install
# update and install development dependencies
install *OPTS:
uv sync {{ OPTS }}
@just install-precommit
uv sync {{ OPTS }}
# install playwright dependencies
install-playwright:
@ -113,6 +113,7 @@ remake-test-migrations:
- rm src/polymorphic/tests/other/migrations/00*.py
- rm src/polymorphic/tests/examples/**/migrations/00*.py
- rm src/polymorphic/tests/examples/integrations/**/migrations/00*.py
- rm src/polymorphic/tests/examples/type_hints/**/migrations/00*.py
uv run --no-default-groups --exact --isolated --resolution lowest-direct --group integrations --script ./manage.py makemigrations
# open the html documentation

View File

@ -206,7 +206,7 @@ typing = [
"django-stubs-ext>=5.1.1",
"djangorestframework-stubs>=3.16.1",
"pyright>=1.1.390",
"mypy>=1.14.1",
"mypy>=1.19.1",
]
lint = [
"ruff>=0.9.8",

View File

@ -52,7 +52,7 @@ def polymorphic_base_manager(self):
and mgr.__class__ is models.Manager
and mgr.auto_created
):
manager = PolymorphicManager()
manager: PolymorphicManager = PolymorphicManager()
manager.name = "_base_manager"
manager.model = self.model
manager.auto_created = True

View File

@ -5,11 +5,18 @@ The manager class for use in the models.
from __future__ import annotations
from collections.abc import Iterable
from typing import TYPE_CHECKING, Any, cast, overload
from typing import TYPE_CHECKING, Any, Generic, Literal, TypeAlias, cast, overload
from django.contrib.contenttypes.models import ContentType
from django.db import DEFAULT_DB_ALIAS, models, transaction
from typing_extensions import Generic, Self, TypeVar
from django.db.models.fields.related_descriptors import (
ForwardManyToOneDescriptor,
ForwardOneToOneDescriptor,
ManyToManyDescriptor,
ReverseManyToOneDescriptor,
ReverseOneToOneDescriptor,
)
from typing_extensions import Self, TypeVar
from polymorphic.query import PolymorphicQuerySet
@ -17,11 +24,43 @@ if TYPE_CHECKING:
from .models import PolymorphicModel # noqa: F401
__all__ = ["PolymorphicManager", "PolymorphicQuerySet"]
__all__ = [
"PolymorphicManager",
"PolymorphicQuerySet",
"PolymorphicManyToManyDescriptor",
"PolymorphicReverseManyToOneDescriptor",
"PolymorphicForwardManyToOneDescriptor",
"PolymorphicForwardOneToOneDescriptor",
"PolymorphicReverseOneToOneDescriptor",
"Nullable",
]
_All = TypeVar("_All", bound="PolymorphicModel", default="PolymorphicModel", covariant=True)
_Base = TypeVar("_Base", bound="PolymorphicModel", default=_All, covariant=True)
_Through = TypeVar("_Through", bound="PolymorphicModel", default=_Base, covariant=True)
_All = TypeVar("_All", bound="PolymorphicModel", covariant=True)
"""
This :class:`~typing.TypeVar` represents the union of all possible polymorphic types
that a manager may return. All models must derive from
:class:`~polymorphic.models.PolymorphicModel`
"""
_Base = TypeVar("_Base", bound="PolymorphicModel", default="PolymorphicModel", covariant=True)
"""
This :class:`~typing.TypeVar` represents the base model type from which polymorphic
models derive. For managers on a :class:`~polymorphic.models.PolymorphicModel` subclass,
you will likely want to use :data:`~typing.Self`.
"""
_Through = TypeVar("_Through", bound=models.Model, default=models.Model, covariant=True)
"""
This :class:`~typing.TypeVar` represents the "through" model type for many-to-many
relations. By default it is just a regular :class:`~django.db.models.Model`, which
will lack the foreign key relations to the linked models.
"""
_Nullable = TypeVar("_Nullable", Literal[True], Literal[False], default=Literal[False])
"""
Provided for nullable relations - should be set to ``Literal[True]`` if the relation is
nullable, otherwise can be left as the default ``Literal[False]``.
"""
_A = TypeVar("_A", bound="PolymorphicModel")
_B = TypeVar("_B", bound="PolymorphicModel")
@ -29,6 +68,10 @@ _C = TypeVar("_C", bound="PolymorphicModel")
_D = TypeVar("_D", bound="PolymorphicModel")
Nullable: TypeAlias = Literal[True]
"""A more readable type hint alias to indicate that a relation is nullable."""
class PolymorphicManager(models.Manager[_All], Generic[_All, _Base]):
"""
Manager for PolymorphicModel
@ -42,10 +85,11 @@ class PolymorphicManager(models.Manager[_All], Generic[_All, _Base]):
if TYPE_CHECKING:
def all(self) -> PolymorphicQuerySet[_All, _Base]: ...
def filter(self, *args: Any, **kwargs: Any) -> PolymorphicQuerySet[_All, _Base]: ...
@classmethod
def from_queryset(
cls, queryset_class: type[models.query.QuerySet[_All, _All]], class_name: str | None = None
cls, queryset_class: type[models.query.QuerySet[_All]], class_name: str | None = None
) -> type[Self]:
manager = super().from_queryset(queryset_class, class_name=class_name)
# also set our version, Django uses _queryset_class
@ -100,7 +144,7 @@ class PolymorphicManager(models.Manager[_All], Generic[_All, _Base]):
def get_real_instances(self, base_result_objects: Iterable[_All] | None = None) -> list[_All]:
return self.all().get_real_instances(base_result_objects=base_result_objects)
def create_from_super(self, obj: models.Model, **kwargs: Any) -> _All:
def create_from_super(self, obj: models.Model, **kwargs: Any) -> _Base:
"""
Create an instance of this manager's model class from the given instance of a
parent class.
@ -130,7 +174,7 @@ class PolymorphicManager(models.Manager[_All], Generic[_All, _Base]):
ctype = ContentType.objects.db_manager(
using=(obj._state.db or DEFAULT_DB_ALIAS)
).get_for_model(self.model)
nobj = self.model(**kwargs, polymorphic_ctype=ctype)
nobj: _Base = self.model(**kwargs, polymorphic_ctype=ctype) # type: ignore[assignment]
nobj.save_base(raw=True, using=obj._state.db or DEFAULT_DB_ALIAS, force_insert=True)
# force update the content type, but first we need to
# retrieve a clean copy from the db to fill in the null
@ -149,31 +193,256 @@ class PolymorphicManager(models.Manager[_All], Generic[_All, _Base]):
if TYPE_CHECKING:
from django.db.models.fields.related_descriptors import (
ManyRelatedManager,
ManyToManyDescriptor,
RelatedManager,
)
class PolymorphicManyRelatedManager( # type: ignore[type-var]
PolymorphicManager[_All, _Base],
ManyRelatedManager[_All, _Through], # pyright: ignore[reportInvalidTypeArguments]
Generic[_All, _Base, _Through],
): ...
class PolymorphicRelatedManager( # type: ignore[type-var]
PolymorphicManager[_All, _Base],
RelatedManager[_All], # pyright: ignore[reportInvalidTypeArguments]
Generic[_All, _Base],
): ...
else:
class PolymorphicRelatedManager(PolymorphicManager[_All, _Base], Generic[_All, _Base]): ...
class PolymorphicManyRelatedManager(
PolymorphicManager[_All, _Base],
Generic[_All, _Base, _Through],
): ...
class PolymorphicManyToManyDescriptor(ManyToManyDescriptor, Generic[_All, _Base, _Through]):
@overload # type: ignore[override]
def __get__(self, instance: None, cls: Any | None = None, /) -> Self: ...
@overload
def __get__(
self, instance: models.Model, cls: Any | None = None, /
) -> PolymorphicManyRelatedManager[_All, _Base, _Through]: ...
class PolymorphicManyToManyDescriptor(ManyToManyDescriptor, Generic[_All, _Base, _Through]):
"""
Use this descriptor class as a type hint for your forward and reverse
:class:`~django.db.models.ManyToManyField` relations to/from polymorphic models.
For example:
def __get__(
self, instance: models.Model | None, cls: Any | None = None, /
) -> Self | PolymorphicManyRelatedManager[_All, _Base, _Through]: ...
.. code-block:: python
class PolymorphicRelatedManager( # type: ignore[type-var]
RelatedManager[_All], # pyright: ignore[reportInvalidTypeArguments]
PolymorphicManager[_All, _Base],
Generic[_All, _Base],
): ...
to_parents: PolymorphicManyToManyDescriptor[
ParentModel | Child1 | Child2, # all possible polymorphic types
ParentModel, # the base type (for non_polymorphic)
ThroughModel # if custom through model
] = models.ManyToManyField( # type: ignore[assignment]
"ParentModel",
related_name="to_parents_reverse"
)
"""
@overload # type: ignore[override]
def __get__(self, instance: None, cls: Any | None = None, /) -> Self: ...
@overload
def __get__(
self, instance: models.Model, cls: Any | None = None, /
) -> PolymorphicManyRelatedManager[_All, _Base, _Through]: ...
def __get__(
self, instance: models.Model | None, cls: Any | None = None, /
) -> Self | PolymorphicManyRelatedManager[_All, _Base, _Through]:
return cast( # pragma: no cover
Self | PolymorphicManyRelatedManager[_All, _Base, _Through],
super().__get__(instance, cls),
)
class PolymorphicReverseManyToOneDescriptor(
ReverseManyToOneDescriptor,
Generic[_All, _Base],
):
"""
Use this descriptor class as a type hint for your reverse
:class:`~django.db.models.ForeignKey` relations to polymorphic models. For example:
.. code-block:: python
class ParentModel(PolymorphicModel):
models.ForeignKey(
RelatedModel,
on_delete=models.CASCADE,
null=True,
related_name="reverse"
)
class RelatedModel(models.Model):
reverse: PolymorphicReverseManyToOneDescriptor[
ParentModel | Child1 | Child2,
ParentModel
]
"""
@overload
def __get__(self, instance: None, cls: Any | None = None, /) -> Self: ...
@overload
def __get__(
self, instance: models.Model, cls: Any | None = None, /
) -> PolymorphicRelatedManager[_All, _Base]: ...
def __get__(
self, instance: models.Model | None, cls: Any | None = None, /
) -> Self | PolymorphicRelatedManager[_All, _Base]:
return cast( # pragma: no cover
Self | PolymorphicRelatedManager[_All, _Base], super().__get__(instance, cls)
)
class PolymorphicForwardManyToOneDescriptor(
ForwardManyToOneDescriptor,
Generic[_All, _Base, _Nullable],
):
"""
Use this descriptor class as a type hint for your
:class:`~django.db.models.ForeignKey` relations to polymorphic models. For example:
.. note::
Your typing system will likely flag an assignment error on the class attribute
- this is unfortunate but unavoidable - we suggest you add a
`# type: ignore[assignment]`.
.. code-block:: python
parent: PolymorphicForwardManyToOneDescriptor[
ParentModel | Child1 | Child2,
ParentModel,
Nullable,
] = models.ForeignKey(
ParentModel,
on_delete=models.CASCADE,
null=True,
)
"""
@overload # type: ignore[override]
def __get__(self, instance: None, cls: Any | None = None, /) -> Self: ...
@overload
def __get__(
self: PolymorphicForwardManyToOneDescriptor[_All, _Base, Literal[False]],
instance: models.Model,
cls: Any | None = None,
/,
) -> _All: ...
@overload
def __get__(
self: PolymorphicForwardManyToOneDescriptor[_All, _Base, Literal[True]],
instance: models.Model,
cls: Any | None = None,
/,
) -> _All | None: ...
def __get__(
self, instance: models.Model | None, cls: Any | None = None, /
) -> Self | _All | None:
return cast( # pragma: no cover
Self | _All | None, super().__get__(instance, cls)
)
def get_queryset(self, **hints: Any) -> PolymorphicQuerySet[_All, _Base]:
return cast( # pragma: no cover
PolymorphicQuerySet[_All, _Base],
super().get_queryset(**hints),
)
class PolymorphicForwardOneToOneDescriptor(
ForwardOneToOneDescriptor,
PolymorphicForwardManyToOneDescriptor[_All, _Base, _Nullable],
Generic[_All, _Base, _Nullable],
):
"""
Use this descriptor class as a type hint for your
:class:`~django.db.models.OneToOneField` relations to polymorphic models. For
example:
.. note::
Your typing system will likely flag an assignment error on the class attribute
- this is unfortunate but unavoidable - we suggest you add a
`# type: ignore[assignment]`.
.. code-block:: python
parent: PolymorphicForwardOneToOneDescriptor[
ParentModel | Child1 | Child2,
ParentModel,
Nullable,
] = models.OneToOneField(
ParentModel,
on_delete=models.CASCADE,
null=True,
)
"""
class PolymorphicReverseOneToOneDescriptor(
ReverseOneToOneDescriptor,
Generic[_All, _Base, _Nullable],
):
"""
Use this descriptor class as a type hint for your reverse
:class:`~django.db.models.OneToOneField` relations to polymorphic models. For
example:
.. code-block:: python
class ParentModel(PolymorphicModel):
models.OneToOneField(
RelatedModel,
on_delete=models.CASCADE,
null=True,
related_name="reverse"
)
class RelatedModel(models.Model):
reverse: PolymorphicReverseOneToOneDescriptor[
ParentModel | Child1 | Child2,
ParentModel,
Nullable,
]
"""
@overload
def __get__(self, instance: None, cls: Any | None = None, /) -> Self: ...
@overload
def __get__(
self: PolymorphicReverseOneToOneDescriptor[_All, _Base, Literal[False]],
instance: models.Model,
cls: Any | None = None,
/,
) -> _All: ...
@overload
def __get__(
self: PolymorphicReverseOneToOneDescriptor[_All, _Base, Literal[True]],
instance: models.Model,
cls: Any | None = None,
/,
) -> _All | None: ...
def __get__(
self, instance: models.Model | None, cls: Any | None = None, /
) -> Self | _All | None:
return cast( # pragma: no cover
Self | _All | None, super().__get__(instance, cls)
)
def get_queryset(self, **hints: Any) -> PolymorphicQuerySet[_All, _Base]:
return cast( # pragma: no cover
PolymorphicQuerySet[_All, _Base],
super().get_queryset(**hints),
)

View File

@ -30,7 +30,7 @@ if TYPE_CHECKING:
from .models import PolymorphicModel # noqa: F401
_All = TypeVar("_All", bound="PolymorphicModel", covariant=True)
_Base = TypeVar("_Base", bound="PolymorphicModel", covariant=True)
_Base = TypeVar("_Base", bound="PolymorphicModel", default="PolymorphicModel", covariant=True)
_A = TypeVar("_A", bound="PolymorphicModel")
_B = TypeVar("_B", bound="PolymorphicModel")
@ -143,7 +143,7 @@ def transmogrify(cls: type[_All], obj: models.Model) -> _All:
# PolymorphicQuerySet
class PolymorphicQuerySet(QuerySet[_All, _All], Generic[_All, _Base]):
class PolymorphicQuerySet(QuerySet[_All], Generic[_All, _Base]):
"""
QuerySet for PolymorphicModel
@ -187,7 +187,7 @@ class PolymorphicQuerySet(QuerySet[_All, _All], Generic[_All, _Base]):
from .managers import PolymorphicManager
manager = PolymorphicManager[_All].from_queryset(cls)()
manager = PolymorphicManager[_All, _Base].from_queryset(cls)()
setattr(manager, "_built_with_as_manager", True)
return manager

View File

@ -1,4 +1,4 @@
# Generated by Django 4.2 on 2026-02-02 17:01
# Generated by Django 4.2 on 2026-02-05 14:47
from decimal import Decimal
from django.conf import settings

View File

@ -1,4 +1,4 @@
# Generated by Django 4.2 on 2026-02-02 17:01
# Generated by Django 4.2 on 2026-02-05 14:47
from django.conf import settings
from django.db import migrations, models

View File

@ -1,4 +1,4 @@
# Generated by Django 4.2 on 2026-02-02 17:01
# Generated by Django 4.2 on 2026-02-05 14:47
from django.db import migrations, models
import django.db.models.deletion

View File

@ -1,7 +0,0 @@
from django.apps import AppConfig
class TypeHintsConfig(AppConfig):
name = "polymorphic.tests.examples.type_hints"
label = "type_hints"
verbose_name = "Type Hints Examples"

View File

@ -0,0 +1,7 @@
from django.apps import AppConfig
class TypeHintsFKConfig(AppConfig):
name = "polymorphic.tests.examples.type_hints.fk"
label = "type_hints_fk"
verbose_name = "Type Hints Foreign Key Example"

View File

@ -0,0 +1,58 @@
# Generated by Django 4.2 on 2026-02-05 14:47
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
initial = True
dependencies = [
('contenttypes', '0002_remove_content_type_name'),
]
operations = [
migrations.CreateModel(
name='ParentModel',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('polymorphic_ctype', models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='polymorphic_%(app_label)s.%(class)s_set+', to='contenttypes.contenttype')),
],
options={
'abstract': False,
},
),
migrations.CreateModel(
name='Child1',
fields=[
('parentmodel_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='type_hints_fk.parentmodel')),
],
options={
'abstract': False,
},
bases=('type_hints_fk.parentmodel',),
),
migrations.CreateModel(
name='RelatedModel',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('parent', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='type_hints_fk.parentmodel')),
],
),
migrations.AddField(
model_name='parentmodel',
name='related_forward',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='parents_reverse', to='type_hints_fk.relatedmodel'),
),
migrations.CreateModel(
name='Child2',
fields=[
('child1_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='type_hints_fk.child1')),
],
options={
'abstract': False,
},
bases=('type_hints_fk.child1',),
),
]

View File

@ -0,0 +1,47 @@
from django.db import models
from polymorphic.models import PolymorphicModel
from polymorphic.managers import (
PolymorphicForwardManyToOneDescriptor,
PolymorphicReverseManyToOneDescriptor,
Nullable, # Alias for typing.Literal[True]
)
class ParentModel(PolymorphicModel):
related_forward = models.ForeignKey(
"RelatedModel", on_delete=models.CASCADE, related_name="parents_reverse"
)
class Child1(ParentModel):
pass
class Child2(Child1):
pass
class RelatedModel(models.Model):
# fmt: off
# Foreign Key Descriptor Type Hint:
# 1. Class Attribute: ForwardManyToOneDescriptor
# 2. Instance attribute: Union of all listed model types or None
parent: PolymorphicForwardManyToOneDescriptor[
ParentModel | Child1 | Child2, # all possible polymorphic types
ParentModel, # the base type (for non_polymorphic)
Nullable, # when null=True
] = models.ForeignKey( # type: ignore[assignment]
ParentModel,
on_delete=models.CASCADE,
null=True,
)
# Reverse FK Relation Descriptor Type Hint:
# 1. Class Attribute: ReverseManyToOneDescriptor
# 2. Instance attribute: Union of all listed model types
parents_reverse: PolymorphicReverseManyToOneDescriptor[
ParentModel | Child1 | Child2, # all possible polymorphic types
ParentModel, # the base type (for non_polymorphic)
# nullable defaults to False
]
# fmt: on

View File

@ -0,0 +1,41 @@
import typing as t
from typing_extensions import assert_type
from django.test import TestCase
from .models import ParentModel, Child1, Child2, RelatedModel
class TypeHintsFKTest(TestCase):
def test_type_hints(self):
related = RelatedModel.objects.create()
parent = ParentModel.objects.create(related_forward=related)
child1 = Child1.objects.create(related_forward=related)
child2 = Child2.objects.create(related_forward=related)
assert_type(related.parent, t.Optional[ParentModel | Child1 | Child2])
related.parent = child1
related.save()
if t.TYPE_CHECKING:
from django.db.models.fields.related import ForeignKey
from django.db.models.fields.reverse_related import ManyToOneRel
assert_type(
RelatedModel.parents_reverse.field, ForeignKey[t.Any, t.Any]
)
assert_type(RelatedModel.parents_reverse.rel, ManyToOneRel)
_1: t.Optional[ParentModel | Child1 | Child2] = (
related.parents_reverse.first()
)
assert _1 == parent
_2: t.Optional[ParentModel | Child1 | Child2] = (
related.parents_reverse.filter().first()
)
assert _2 == parent
_3: t.Optional[ParentModel] = (
related.parents_reverse.non_polymorphic().last()
)
assert _3 == ParentModel.objects.non_polymorphic().get(pk=child2.pk)

View File

@ -0,0 +1,7 @@
from django.apps import AppConfig
class TypeHintsM2MConfig(AppConfig):
name = "polymorphic.tests.examples.type_hints.m2m"
label = "type_hints_m2m"
verbose_name = "Type Hints M2M Example"

View File

@ -0,0 +1,84 @@
# Generated by Django 4.2 on 2026-02-05 14:47
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
initial = True
dependencies = [
('contenttypes', '0002_remove_content_type_name'),
]
operations = [
migrations.CreateModel(
name='ParentModel',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('polymorphic_ctype', models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='polymorphic_%(app_label)s.%(class)s_set+', to='contenttypes.contenttype')),
],
options={
'abstract': False,
},
),
migrations.CreateModel(
name='PolyThrough',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('parent', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='parents', to='type_hints_m2m.parentmodel')),
('polymorphic_ctype', models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='polymorphic_%(app_label)s.%(class)s_set+', to='contenttypes.contenttype')),
],
options={
'abstract': False,
},
),
migrations.CreateModel(
name='Child1',
fields=[
('parentmodel_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='type_hints_m2m.parentmodel')),
],
options={
'abstract': False,
},
bases=('type_hints_m2m.parentmodel',),
),
migrations.CreateModel(
name='ThroughChild',
fields=[
('polythrough_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='type_hints_m2m.polythrough')),
],
options={
'abstract': False,
},
bases=('type_hints_m2m.polythrough',),
),
migrations.CreateModel(
name='RelatedModel',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('to_parents', models.ManyToManyField(related_name='to_parents_reverse', to='type_hints_m2m.parentmodel')),
],
),
migrations.AddField(
model_name='polythrough',
name='related',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='type_hints_m2m.relatedmodel'),
),
migrations.AddField(
model_name='parentmodel',
name='to_related',
field=models.ManyToManyField(related_name='to_related_reverse', through='type_hints_m2m.PolyThrough', to='type_hints_m2m.relatedmodel'),
),
migrations.CreateModel(
name='Child2',
fields=[
('child1_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='type_hints_m2m.child1')),
],
options={
'abstract': False,
},
bases=('type_hints_m2m.child1',),
),
]

View File

@ -0,0 +1,75 @@
from __future__ import annotations
from typing import ClassVar
from django.db import models
from polymorphic.models import PolymorphicModel
from polymorphic.managers import (
PolymorphicManager,
PolymorphicManyToManyDescriptor,
PolymorphicForwardManyToOneDescriptor,
PolymorphicReverseManyToOneDescriptor,
)
class ParentModel(PolymorphicModel):
to_related = models.ManyToManyField( # type: ignore[var-annotated]
"RelatedModel", related_name="to_related_reverse", through="PolyThrough"
)
parents: PolymorphicReverseManyToOneDescriptor[
ParentModel | Child1 | Child2, ParentModel
]
objects: ClassVar[
PolymorphicManager[ParentModel | Child1 | Child2, ParentModel]
]
class Child1(ParentModel):
pass
class Child2(Child1):
pass
class PolyThrough(PolymorphicModel):
parent: PolymorphicForwardManyToOneDescriptor[
ParentModel | Child1 | Child2, ParentModel
] = models.ForeignKey( # type: ignore[assignment]
ParentModel, on_delete=models.CASCADE, related_name="parents"
)
related = models.ForeignKey("RelatedModel", on_delete=models.CASCADE)
objects: ClassVar[
PolymorphicManager[PolyThrough | ThroughChild, PolyThrough]
]
class ThroughChild(PolyThrough):
pass
class RelatedModel(models.Model):
# fmt: off
# ManyToMany Descriptor Type Hint:
# 1. Class Attribute: ManyToManyDescriptor
# 2. Instance attribute: PolymorphicManager for related type(s)
to_parents: PolymorphicManyToManyDescriptor[
ParentModel | Child1 | Child2, # all possible polymorphic types
ParentModel, # the base type (for non_polymorphic)
# no custom through model
] = models.ManyToManyField( # type: ignore[assignment]
"ParentModel",
related_name="to_parents_reverse"
)
# ManyToMany Descriptor for the reverse relation
# 1. Class Attribute: ManyToManyDescriptor
# 2. Instance attribute: PolymorphicManager for related type(s)
to_related_reverse: PolymorphicManyToManyDescriptor[
ParentModel | Child1 | Child2,
ParentModel,
PolyThrough # custom through model (may be polymorphic!)
]
# fmt: on

View File

@ -0,0 +1,89 @@
import typing as t
from django.test import TestCase
from django.db import models
# from django.db import models
from .models import (
ParentModel,
Child1,
Child2,
RelatedModel,
PolyThrough,
ThroughChild,
)
class TypeHintsM2MTest(TestCase):
def test_type_hints(self):
parent = ParentModel.objects.create()
child1 = Child1.objects.create()
child2 = Child2.objects.create()
related1 = RelatedModel.objects.create()
related2 = RelatedModel.objects.create()
_t1 = PolyThrough.objects.create(parent=child1, related=related1)
_t2 = ThroughChild.objects.create(parent=child2, related=related2)
related1.to_parents.add(parent)
related1.to_related_reverse.add(child2)
related2.to_parents.add(child2)
related1.refresh_from_db()
assert set(related1.to_parents.all()) == {parent}
assert set(related2.to_parents.all()) == {child2}
assert set(related1.to_related_reverse.all()) == {child1, child2}
assert set(related2.to_related_reverse.all()) == {child2}
assert parent.to_related.count() == 0
assert set(child1.to_related.all()) == {related1}
assert set(child2.to_related.all()) == {related1, related2}
through1: type[PolyThrough] = parent.to_related.through
assert through1.objects.count() == 3
tlist1: t.List[PolyThrough | ThroughChild] = list(
parent.to_related.through.objects.all()
)
assert len(tlist1) == 3
_1: t.List[PolyThrough] = list(
parent.to_related.through.objects.non_polymorphic()
)
assert len(_1) == 3
_2: t.List[ParentModel | Child1 | Child2] = list(
related1.to_related_reverse.all()
)
assert set(_2) == {child1, child2}
_3: t.List[ParentModel | Child1 | Child2] = list(
related1.to_parents.all()
)
assert set(_3) == {parent}
_through2: type[models.Model] = related1.to_parents.through
_through3: type[PolyThrough] = related1.to_related_reverse.through
assert _through2.objects.count() == 2 # type: ignore[attr-defined]
assert set(_through3.objects.all()) == {
_t1,
_t2,
PolyThrough.objects.last(),
}
_4: t.List[ParentModel] = list(
related1.to_related_reverse.non_polymorphic()
)
assert set(_4) == set(
ParentModel.objects.non_polymorphic().filter(
pk__in=[child1.pk, child2.pk]
)
)
_5: t.List[ParentModel] = list(
related1.to_parents.all().non_polymorphic()
)
assert set(_5) == {parent}

View File

@ -0,0 +1,7 @@
from django.apps import AppConfig
class TypeHintsManagersConfig(AppConfig):
name = "polymorphic.tests.examples.type_hints.managers"
label = "type_hints_managers"
verbose_name = "Type Hints Managers Example"

View File

@ -0,0 +1,46 @@
# Generated by Django 4.2 on 2026-02-05 14:47
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
initial = True
dependencies = [
('contenttypes', '0002_remove_content_type_name'),
]
operations = [
migrations.CreateModel(
name='ParentModel',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('polymorphic_ctype', models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='polymorphic_%(app_label)s.%(class)s_set+', to='contenttypes.contenttype')),
],
options={
'abstract': False,
},
),
migrations.CreateModel(
name='Child1',
fields=[
('parentmodel_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='type_hints_managers.parentmodel')),
],
options={
'abstract': False,
},
bases=('type_hints_managers.parentmodel',),
),
migrations.CreateModel(
name='Child2',
fields=[
('child1_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='type_hints_managers.child1')),
],
options={
'abstract': False,
},
bases=('type_hints_managers.child1',),
),
]

View File

@ -0,0 +1,28 @@
from __future__ import annotations
import typing as t
from typing_extensions import Self
from polymorphic.models import PolymorphicModel
from polymorphic.managers import PolymorphicManager
class ParentModel(PolymorphicModel):
# fmt: off
# If you want a polymorphic manager with type hint support you can
# override the default one like this:
objects: t.ClassVar[
PolymorphicManager[
Self | Child1 | Child2, # union of all polymorphic types
Self, # the base type (for non_polymorphic)
]
] = PolymorphicManager()
# fmt: on
class Child1(ParentModel):
# you may also override the type hints for the child default
# managers to narrow the filter returns at this level
objects: t.ClassVar[PolymorphicManager[Self | Child2, Self]]
class Child2(Child1):
objects: t.ClassVar[PolymorphicManager[Self, Self]]

View File

@ -0,0 +1,83 @@
import typing as t
from django.test import TestCase
from .models import ParentModel, Child1, Child2
class TypeHintsManagersTest(TestCase):
def test_type_hints(self):
parent = ParentModel.objects.create()
child1 = Child1.objects.create()
child2 = Child2.objects.create()
_1: t.Optional[ParentModel | Child1 | Child2] = (
ParentModel.objects.first()
)
assert _1 == parent or _1 == child1 or _1 == child2
assert _1 == parent
_2: t.Optional[ParentModel | Child1 | Child2] = (
ParentModel.objects.order_by("pk").first()
)
assert _2 == parent
_3: t.Optional[Child1 | Child2] = Child1.objects.first()
assert _3 == child1 or _3 == child2
_4: Child1 | Child2 = Child1.objects.filter().all().get(pk=child1.pk)
assert _4 == child1
_5: t.Optional[Child2] = Child2.objects.first()
assert _5 == child2
_6: Child2 = Child2.objects.filter().get(pk=child2.pk)
assert _6 == child2
assert ParentModel.objects.count() == 3
assert Child1.objects.count() == 2
assert Child2.objects.count() == 1
# mypy has trouble with these - they work on pyright/pylance. I consider this
# a failing of mypy type inference not a deficiency in our typing - for now
# we can ignore the errors
_7: t.Optional[ParentModel] = (
ParentModel.objects.non_polymorphic().first() # type: ignore[assignment]
)
assert _7 == parent
_8: t.Optional[ParentModel] = (
ParentModel.objects.all().non_polymorphic().first() # type: ignore[assignment]
)
assert _8 == parent
_9: t.Optional[Child1] = Child1.objects.non_polymorphic().first() # type: ignore[assignment]
assert _9 == child1
_10: t.Optional[Child1] = (
Child1.objects.filter().non_polymorphic().all().first() # type: ignore[assignment]
)
assert _10 == child1
_11: t.Optional[Child2] = Child2.objects.non_polymorphic().first()
assert _11 == child2
_12: Child2 = (
Child2.objects.filter().non_polymorphic().get(pk=child2.pk)
)
assert _12 == child2
_13: t.Optional[ParentModel] = ParentModel.objects.instance_of(
ParentModel
).first()
assert _13 == parent
_14: t.Optional[ParentModel] = (
ParentModel.objects.all().instance_of(ParentModel).first()
)
assert _14 == parent
_15: t.Optional[Child1] = ParentModel.objects.instance_of(
Child1
).first()
assert _15 == child1
_16: t.Optional[Child1] = (
ParentModel.objects.all().instance_of(Child1).first()
)
assert _16 == child1
_17: t.Optional[Child2] = ParentModel.objects.instance_of(
Child2
).first()
assert _17 == child2
_18: t.Optional[Child2] = (
ParentModel.objects.all().instance_of(Child2).first()
)
assert _18 == child2

View File

@ -1,125 +0,0 @@
# Generated by Django 4.2 on 2026-02-02 17:01
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
initial = True
dependencies = [
('contenttypes', '0002_remove_content_type_name'),
]
operations = [
migrations.CreateModel(
name='Article',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('title', models.CharField(max_length=100)),
],
options={
'abstract': False,
},
),
migrations.CreateModel(
name='MediaOutlet',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=100)),
('polymorphic_ctype', models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='polymorphic_%(app_label)s.%(class)s_set+', to='contenttypes.contenttype')),
],
options={
'abstract': False,
},
),
migrations.CreateModel(
name='Topic',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=50)),
('articles', models.ManyToManyField(related_name='topics', to='type_hints.article')),
('polymorphic_ctype', models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='polymorphic_%(app_label)s.%(class)s_set+', to='contenttypes.contenttype')),
],
options={
'abstract': False,
},
),
migrations.CreateModel(
name='BlogPost',
fields=[
('article_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='type_hints.article')),
('author', models.CharField(max_length=100)),
],
options={
'abstract': False,
},
bases=('type_hints.article',),
),
migrations.CreateModel(
name='EditorialTopic',
fields=[
('topic_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='type_hints.topic')),
('editor', models.CharField(max_length=100)),
],
options={
'abstract': False,
},
bases=('type_hints.topic',),
),
migrations.CreateModel(
name='LocationTopic',
fields=[
('topic_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='type_hints.topic')),
('location', models.CharField(max_length=100)),
],
options={
'abstract': False,
},
bases=('type_hints.topic',),
),
migrations.CreateModel(
name='NewsArticle',
fields=[
('article_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='type_hints.article')),
('source', models.CharField(max_length=100)),
],
options={
'abstract': False,
},
bases=('type_hints.article',),
),
migrations.CreateModel(
name='Newspaper',
fields=[
('mediaoutlet_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='type_hints.mediaoutlet')),
('service_area', models.CharField(max_length=100)),
],
options={
'abstract': False,
},
bases=('type_hints.mediaoutlet',),
),
migrations.CreateModel(
name='OnlineBlog',
fields=[
('mediaoutlet_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='type_hints.mediaoutlet')),
('url', models.URLField()),
],
options={
'abstract': False,
},
bases=('type_hints.mediaoutlet',),
),
migrations.AddField(
model_name='article',
name='outlet',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='articles', to='type_hints.mediaoutlet'),
),
migrations.AddField(
model_name='article',
name='polymorphic_ctype',
field=models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='polymorphic_%(app_label)s.%(class)s_set+', to='contenttypes.contenttype'),
),
]

View File

@ -1,73 +1,76 @@
from __future__ import annotations
import typing as t
from typing_extensions import Self
from django.db import models
from polymorphic.models import PolymorphicModel
from polymorphic.managers import PolymorphicManager
# from __future__ import annotations
# import typing as t
# from typing_extensions import Self
# from django.db import models
# from polymorphic.models import PolymorphicModel
# from polymorphic.managers import PolymorphicManager
if t.TYPE_CHECKING:
from polymorphic.managers import (
PolymorphicManyToManyDescriptor,
PolymorphicRelatedManager,
)
# if t.TYPE_CHECKING:
# # The polymorphic manager and related descriptors type hints are only available
# # during type checking
# from polymorphic.managers import (
# PolymorphicManyToManyDescriptor,
# PolymorphicRelatedManager,
# )
class Article(PolymorphicModel):
title = models.CharField(max_length=100)
# class Article(PolymorphicModel):
# title = models.CharField(max_length=100)
outlet: "MediaOutlet" | "Newspaper" | "OnlineBlog" = models.ForeignKey( # type: ignore[assignment]
"MediaOutlet", on_delete=models.CASCADE, related_name="articles"
)
# outlet: "MediaOutlet" | "Newspaper" | "OnlineBlog" = models.ForeignKey( # type: ignore[assignment]
# "MediaOutlet", on_delete=models.CASCADE, related_name="articles"
# )
objects: t.ClassVar[
PolymorphicManager[Self | "BlogPost" | "NewsArticle", Self]
] = PolymorphicManager()
# objects: t.ClassVar[
# PolymorphicManager[Self | "BlogPost" | "NewsArticle", Self]
# ] = PolymorphicManager()
topics: PolymorphicManyToManyDescriptor[
"Topic" | "LocationTopic" | "EditorialTopic", "Topic"
]
# topics: PolymorphicManyToManyDescriptor[
# "Topic" | "LocationTopic" | "EditorialTopic", "Topic"
# ]
class BlogPost(Article):
author = models.CharField(max_length=100)
# class BlogPost(Article):
# author = models.CharField(max_length=100)
class NewsArticle(Article):
source = models.CharField(max_length=100)
# class NewsArticle(Article):
# source = models.CharField(max_length=100)
class Topic(PolymorphicModel):
name = models.CharField(max_length=50)
articles: PolymorphicManyToManyDescriptor[
Article | BlogPost | NewsArticle, Article
] = models.ManyToManyField(Article, related_name="topics") # type: ignore[assignment]
# class Topic(PolymorphicModel):
# name = models.CharField(max_length=50)
articles2 = models.ManyToManyField(Article, related_name="topics2")
if t.TYPE_CHECKING:
objects: t.ClassVar[
PolymorphicManager[Self | "LocationTopic" | "EditorialTopic", Self]
]
# articles: PolymorphicManyToManyDescriptor[
# Article | BlogPost | NewsArticle, Article
# ] = models.ManyToManyField(Article, related_name="topics") # type: ignore[assignment]
# articles2 = models.ManyToManyField(Article, related_name="topics2")
# if t.TYPE_CHECKING:
# objects: t.ClassVar[
# PolymorphicManager[Self | "LocationTopic" | "EditorialTopic", Self]
# ]
class LocationTopic(Topic):
location = models.CharField(max_length=100)
# class LocationTopic(Topic):
# location = models.CharField(max_length=100)
class EditorialTopic(Topic):
editor = models.CharField(max_length=100)
# class EditorialTopic(Topic):
# editor = models.CharField(max_length=100)
class MediaOutlet(PolymorphicModel):
name = models.CharField(max_length=100)
# class MediaOutlet(PolymorphicModel):
# name = models.CharField(max_length=100)
articles: PolymorphicRelatedManager[
Article | NewsArticle | BlogPost, "Article"
]
# articles: PolymorphicRelatedManager[
# Article | NewsArticle | BlogPost, "Article"
# ]
class Newspaper(MediaOutlet):
service_area = models.CharField(max_length=100)
# class Newspaper(MediaOutlet):
# service_area = models.CharField(max_length=100)
class OnlineBlog(MediaOutlet):
url = models.URLField()
# class OnlineBlog(MediaOutlet):
# url = models.URLField()

View File

@ -0,0 +1,7 @@
from django.apps import AppConfig
class TypeHintsOne2OneConfig(AppConfig):
name = "polymorphic.tests.examples.type_hints.one2one"
label = "type_hints_one2one"
verbose_name = "Type Hints One2One Example"

View File

@ -0,0 +1,58 @@
# Generated by Django 4.2 on 2026-02-05 14:47
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
initial = True
dependencies = [
('contenttypes', '0002_remove_content_type_name'),
]
operations = [
migrations.CreateModel(
name='ParentModel',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('polymorphic_ctype', models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='polymorphic_%(app_label)s.%(class)s_set+', to='contenttypes.contenttype')),
],
options={
'abstract': False,
},
),
migrations.CreateModel(
name='Child1',
fields=[
('parentmodel_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='type_hints_one2one.parentmodel')),
],
options={
'abstract': False,
},
bases=('type_hints_one2one.parentmodel',),
),
migrations.CreateModel(
name='RelatedModel',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('parent_forward', models.OneToOneField(null=True, on_delete=django.db.models.deletion.CASCADE, to='type_hints_one2one.parentmodel')),
],
),
migrations.AddField(
model_name='parentmodel',
name='related_forward',
field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='parent_reverse', to='type_hints_one2one.relatedmodel'),
),
migrations.CreateModel(
name='Child2',
fields=[
('child1_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='type_hints_one2one.child1')),
],
options={
'abstract': False,
},
bases=('type_hints_one2one.child1',),
),
]

View File

@ -0,0 +1,47 @@
from django.db import models
from polymorphic.models import PolymorphicModel
from polymorphic.managers import (
PolymorphicForwardOneToOneDescriptor,
PolymorphicReverseOneToOneDescriptor,
Nullable, # Alias for typing.Literal[True]
)
class ParentModel(PolymorphicModel):
related_forward = models.OneToOneField(
"RelatedModel", on_delete=models.CASCADE, related_name="parent_reverse"
)
class Child1(ParentModel):
pass
class Child2(Child1):
pass
class RelatedModel(models.Model):
# fmt: off
# Forward Relation Descriptor Type Hint:
# 1. Class Attribute: ForwardOneToOneDescriptor
# 2. Instance attribute: Union of all listed model types or None
parent_forward: PolymorphicForwardOneToOneDescriptor[
ParentModel | Child1 | Child2, # all possible polymorphic types
ParentModel, # the base type (for non_polymorphic)
Nullable, # when null=True
] = models.OneToOneField( # type: ignore[assignment]
"ParentModel",
on_delete=models.CASCADE,
null=True
)
# Reverse Relation Descriptor Type Hint:
# 1. Class Attribute: ReverseOneToOneDescriptor
# 2. Instance attribute: Union of all listed model types
parent_reverse: PolymorphicReverseOneToOneDescriptor[
ParentModel | Child1 | Child2, # possible polymorphic types
ParentModel, # the base type (for non_polymorphic)
# nullable defaults to False
]
# fmt: on

View File

@ -0,0 +1,43 @@
import typing as t
from django.db.models.fields.reverse_related import OneToOneRel
from typing_extensions import assert_type
from django.test import TestCase
from polymorphic.managers import PolymorphicQuerySet
# from django.db import models
from .models import ParentModel, Child1, Child2, RelatedModel
class TypeHintsOne2OneTest(TestCase):
def test_type_hints(self):
related1 = RelatedModel.objects.create()
related2 = RelatedModel.objects.create()
related3 = RelatedModel.objects.create()
parent = ParentModel.objects.create(related_forward=related1)
child1 = Child1.objects.create(related_forward=related2)
Child2.objects.create(related_forward=related3)
assert_type(
related1.parent_forward, t.Optional[ParentModel | Child1 | Child2]
)
assert_type(related1.parent_reverse, ParentModel | Child1 | Child2)
related1.parent_forward = child1
related1.save()
assert_type(RelatedModel.parent_reverse.related, OneToOneRel)
_1: PolymorphicQuerySet[ParentModel | Child1 | Child2, ParentModel] = (
RelatedModel.parent_reverse.get_queryset()
)
assert _1.all().count() == 3
# assert_type(RelatedModel.parent_forward.related, OneToOneRel)
_2: PolymorphicQuerySet[ParentModel | Child1 | Child2, ParentModel] = (
RelatedModel.parent_forward.get_queryset()
)
assert _2.all().count() == 3
_3: ParentModel | Child1 | Child2 = related1.parent_reverse
assert _3 == parent
_4: t.Optional[ParentModel | Child1 | Child2] = related1.parent_forward
assert _4 == child1

View File

@ -1,126 +0,0 @@
from typing_extensions import assert_type
from django.test import TestCase
from .models import (
Article,
BlogPost,
NewsArticle,
Topic,
LocationTopic,
EditorialTopic,
MediaOutlet,
Newspaper,
OnlineBlog,
)
class TypeHintsTest(TestCase):
def test_type_hints_example_models(self):
# Just a placeholder test to ensure the example models file is included in test
# runs
daily = Newspaper.objects.create(
name="The Daily Times", service_area="New York"
)
rg = OnlineBlog.objects.create(name="ReplyGuy")
article = Article.objects.create(title="Test Article", outlet=daily)
bp = BlogPost.objects.create(
title="Test Blog Post", author="Author A", outlet=rg
)
na = NewsArticle.objects.create(
title="Test News Article", source="Source A", outlet=daily
)
general_int = Topic.objects.create(name="General Interest")
location_topic = LocationTopic.objects.create(
name="Food", location="Los Angeles"
)
editorial_topic = EditorialTopic.objects.create(
name="Politics", editor="BCK"
)
general_int.articles.add(article, bp, na)
location_topic.articles.add(na)
editorial_topic.articles.add(bp)
objs: list[Article | BlogPost | NewsArticle] = list(
Article.objects.all()
)
objs0: list[Article | BlogPost | NewsArticle] = list(
Article.objects.all().all()
)
objs01: list[Article | BlogPost | NewsArticle] = list(
Article.objects.filter()
)
objs2: list[BlogPost] = list(
Article.objects.instance_of(BlogPost).all()
)
objs3: list[BlogPost | NewsArticle] = list(
Article.objects.instance_of(NewsArticle, BlogPost).all()
)
for art in Article.objects.instance_of(NewsArticle, BlogPost):
assert_type(art, NewsArticle | BlogPost)
objs4: list[BlogPost] = list(
Article.objects.all().instance_of(BlogPost).all()
)
objs5: list[BlogPost | NewsArticle] = list(
Article.objects.all().instance_of(NewsArticle, BlogPost).all()
)
assert len(objs) == len(objs0) == len(objs01) == 3
assert len(objs2) == 1
assert len(objs3) == 2
assert len(objs4) == 1
assert len(objs5) == 2
topics: list[Topic | LocationTopic | EditorialTopic] = list(
article.topics.all()
)
topics2: list[Topic | LocationTopic | EditorialTopic] = list(
article.topics.all().all()
)
non_poly_topics: list[Topic] = list(article.topics.non_polymorphic())
for tpc1 in article.topics.all():
assert_type(tpc1, Topic | LocationTopic | EditorialTopic)
for tpc2 in article.topics.all().all():
assert_type(tpc2, Topic | LocationTopic | EditorialTopic)
for tpc3 in article.topics.filter():
assert_type(tpc3, Topic | LocationTopic | EditorialTopic)
for tpc4 in article.topics.non_polymorphic():
assert_type(tpc4, Topic)
for tpc5 in article.topics.all().non_polymorphic():
assert_type(tpc5, Topic)
for tpc6 in article.topics.all().instance_of(BlogPost):
assert_type(tpc6, BlogPost)
assert len(topics) == 1
assert len(topics2) == 1
assert len(non_poly_topics) == 1
assert bp.topics.count() == 2
for art2 in general_int.articles.all():
assert_type(art2, Article | BlogPost | NewsArticle)
assert_type(article.outlet, Newspaper | OnlineBlog | MediaOutlet)
assert_type(bp.outlet, Newspaper | OnlineBlog | MediaOutlet)
assert_type(na.outlet, Newspaper | OnlineBlog | MediaOutlet)
for art3 in daily.articles.all():
assert_type(art3, Article | BlogPost | NewsArticle)
for art4 in daily.articles.filter().all():
assert_type(art4, Article | BlogPost | NewsArticle)
# reveal_type(Topic.articles)
# reveal_type(Topic.articles2)
# reveal_type(Topic.objects.first().articles2)

View File

@ -1,4 +1,4 @@
# Generated by Django 4.2 on 2026-02-02 17:01
# Generated by Django 4.2 on 2026-02-05 14:47
from django.db import migrations, models
import django.db.models.deletion

View File

@ -1,4 +1,4 @@
# Generated by Django 4.2 on 2026-02-02 17:01
# Generated by Django 4.2 on 2026-02-05 14:47
from django.conf import settings
from django.db import migrations, models
@ -14,8 +14,8 @@ class Migration(migrations.Migration):
initial = True
dependencies = [
('auth', '0012_alter_user_first_name_max_length'),
('contenttypes', '0002_remove_content_type_name'),
('auth', '0012_alter_user_first_name_max_length'),
]
operations = [

View File

@ -1,4 +1,4 @@
# Generated by Django 4.2 on 2026-02-02 17:01
# Generated by Django 4.2 on 2026-02-05 14:47
from django.db import migrations, models
import django.db.models.deletion

View File

@ -105,7 +105,10 @@ elif rdbms == "oracle": # pragma: no cover
}
DEFAULT_AUTO_FIELD = "django.db.models.AutoField"
INSTALLED_APPS = [
"polymorphic.tests.examples.type_hints",
"polymorphic.tests.examples.type_hints.managers",
"polymorphic.tests.examples.type_hints.one2one",
"polymorphic.tests.examples.type_hints.m2m",
"polymorphic.tests.examples.type_hints.fk",
"polymorphic.tests.examples.integrations",
"polymorphic.tests",
"polymorphic.tests.deletion",

302
uv.lock
View File

@ -44,14 +44,14 @@ wheels = [
[[package]]
name = "asgiref"
version = "3.11.0"
version = "3.11.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "typing-extensions", marker = "python_full_version < '3.11'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/76/b9/4db2509eabd14b4a8c71d1b24c8d5734c52b8560a7b1e1a8b56c8d25568b/asgiref-3.11.0.tar.gz", hash = "sha256:13acff32519542a1736223fb79a715acdebe24286d98e8b164a73085f40da2c4", size = 37969, upload-time = "2025-11-19T15:32:20.106Z" }
sdist = { url = "https://files.pythonhosted.org/packages/63/40/f03da1264ae8f7cfdbf9146542e5e7e8100a4c66ab48e791df9a03d3f6c0/asgiref-3.11.1.tar.gz", hash = "sha256:5f184dc43b7e763efe848065441eac62229c9f7b0475f41f80e207a114eda4ce", size = 38550, upload-time = "2026-02-03T13:30:14.33Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/91/be/317c2c55b8bbec407257d45f5c8d1b6867abc76d12043f2d3d58c538a4ea/asgiref-3.11.0-py3-none-any.whl", hash = "sha256:1db9021efadb0d9512ce8ffaf72fcef601c7b73a8807a1bb2ef143dc6b14846d", size = 24096, upload-time = "2025-11-19T15:32:19.004Z" },
{ url = "https://files.pythonhosted.org/packages/5c/0a/a72d10ed65068e115044937873362e6e32fab1b7dce0046aeb224682c989/asgiref-3.11.1-py3-none-any.whl", hash = "sha256:e8667a091e69529631969fd45dc268fa79b99c92c5fcdda727757e52146ec133", size = 24345, upload-time = "2026-02-03T13:30:13.039Z" },
]
[[package]]
@ -350,101 +350,101 @@ wheels = [
[[package]]
name = "coverage"
version = "7.13.2"
version = "7.13.3"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/ad/49/349848445b0e53660e258acbcc9b0d014895b6739237920886672240f84b/coverage-7.13.2.tar.gz", hash = "sha256:044c6951ec37146b72a50cc81ef02217d27d4c3640efd2640311393cbbf143d3", size = 826523, upload-time = "2026-01-25T13:00:04.889Z" }
sdist = { url = "https://files.pythonhosted.org/packages/11/43/3e4ac666cc35f231fa70c94e9f38459299de1a152813f9d2f60fc5f3ecaf/coverage-7.13.3.tar.gz", hash = "sha256:f7f6182d3dfb8802c1747eacbfe611b669455b69b7c037484bb1efbbb56711ac", size = 826832, upload-time = "2026-02-03T14:02:30.944Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/a4/2d/63e37369c8e81a643afe54f76073b020f7b97ddbe698c5c944b51b0a2bc5/coverage-7.13.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f4af3b01763909f477ea17c962e2cca8f39b350a4e46e3a30838b2c12e31b81b", size = 218842, upload-time = "2026-01-25T12:57:15.3Z" },
{ url = "https://files.pythonhosted.org/packages/57/06/86ce882a8d58cbcb3030e298788988e618da35420d16a8c66dac34f138d0/coverage-7.13.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:36393bd2841fa0b59498f75466ee9bdec4f770d3254f031f23e8fd8e140ffdd2", size = 219360, upload-time = "2026-01-25T12:57:17.572Z" },
{ url = "https://files.pythonhosted.org/packages/cd/84/70b0eb1ee19ca4ef559c559054c59e5b2ae4ec9af61398670189e5d276e9/coverage-7.13.2-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:9cc7573518b7e2186bd229b1a0fe24a807273798832c27032c4510f47ffdb896", size = 246123, upload-time = "2026-01-25T12:57:19.087Z" },
{ url = "https://files.pythonhosted.org/packages/35/fb/05b9830c2e8275ebc031e0019387cda99113e62bb500ab328bb72578183b/coverage-7.13.2-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:ca9566769b69a5e216a4e176d54b9df88f29d750c5b78dbb899e379b4e14b30c", size = 247930, upload-time = "2026-01-25T12:57:20.929Z" },
{ url = "https://files.pythonhosted.org/packages/81/aa/3f37858ca2eed4f09b10ca3c6ddc9041be0a475626cd7fd2712f4a2d526f/coverage-7.13.2-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9c9bdea644e94fd66d75a6f7e9a97bb822371e1fe7eadae2cacd50fcbc28e4dc", size = 249804, upload-time = "2026-01-25T12:57:22.904Z" },
{ url = "https://files.pythonhosted.org/packages/b6/b3/c904f40c56e60a2d9678a5ee8df3d906d297d15fb8bec5756c3b0a67e2df/coverage-7.13.2-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:5bd447332ec4f45838c1ad42268ce21ca87c40deb86eabd59888859b66be22a5", size = 246815, upload-time = "2026-01-25T12:57:24.314Z" },
{ url = "https://files.pythonhosted.org/packages/41/91/ddc1c5394ca7fd086342486440bfdd6b9e9bda512bf774599c7c7a0081e0/coverage-7.13.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:7c79ad5c28a16a1277e1187cf83ea8dafdcc689a784228a7d390f19776db7c31", size = 247843, upload-time = "2026-01-25T12:57:26.544Z" },
{ url = "https://files.pythonhosted.org/packages/87/d2/cdff8f4cd33697883c224ea8e003e9c77c0f1a837dc41d95a94dd26aad67/coverage-7.13.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:76e06ccacd1fb6ada5d076ed98a8c6f66e2e6acd3df02819e2ee29fd637b76ad", size = 245850, upload-time = "2026-01-25T12:57:28.507Z" },
{ url = "https://files.pythonhosted.org/packages/f5/42/e837febb7866bf2553ab53dd62ed52f9bb36d60c7e017c55376ad21fbb05/coverage-7.13.2-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:49d49e9a5e9f4dc3d3dac95278a020afa6d6bdd41f63608a76fa05a719d5b66f", size = 246116, upload-time = "2026-01-25T12:57:30.16Z" },
{ url = "https://files.pythonhosted.org/packages/09/b1/4a3f935d7df154df02ff4f71af8d61298d713a7ba305d050ae475bfbdde2/coverage-7.13.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ed2bce0e7bfa53f7b0b01c722da289ef6ad4c18ebd52b1f93704c21f116360c8", size = 246720, upload-time = "2026-01-25T12:57:32.165Z" },
{ url = "https://files.pythonhosted.org/packages/e1/fe/538a6fd44c515f1c5197a3f078094cbaf2ce9f945df5b44e29d95c864bff/coverage-7.13.2-cp310-cp310-win32.whl", hash = "sha256:1574983178b35b9af4db4a9f7328a18a14a0a0ce76ffaa1c1bacb4cc82089a7c", size = 221465, upload-time = "2026-01-25T12:57:33.511Z" },
{ url = "https://files.pythonhosted.org/packages/5e/09/4b63a024295f326ec1a40ec8def27799300ce8775b1cbf0d33b1790605c4/coverage-7.13.2-cp310-cp310-win_amd64.whl", hash = "sha256:a360a8baeb038928ceb996f5623a4cd508728f8f13e08d4e96ce161702f3dd99", size = 222397, upload-time = "2026-01-25T12:57:34.927Z" },
{ url = "https://files.pythonhosted.org/packages/6c/01/abca50583a8975bb6e1c59eff67ed8e48bb127c07dad5c28d9e96ccc09ec/coverage-7.13.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:060ebf6f2c51aff5ba38e1f43a2095e087389b1c69d559fde6049a4b0001320e", size = 218971, upload-time = "2026-01-25T12:57:36.953Z" },
{ url = "https://files.pythonhosted.org/packages/eb/0e/b6489f344d99cd1e5b4d5e1be52dfd3f8a3dc5112aa6c33948da8cabad4e/coverage-7.13.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c1ea8ca9db5e7469cd364552985e15911548ea5b69c48a17291f0cac70484b2e", size = 219473, upload-time = "2026-01-25T12:57:38.934Z" },
{ url = "https://files.pythonhosted.org/packages/17/11/db2f414915a8e4ec53f60b17956c27f21fb68fcf20f8a455ce7c2ccec638/coverage-7.13.2-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:b780090d15fd58f07cf2011943e25a5f0c1c894384b13a216b6c86c8a8a7c508", size = 249896, upload-time = "2026-01-25T12:57:40.365Z" },
{ url = "https://files.pythonhosted.org/packages/80/06/0823fe93913663c017e508e8810c998c8ebd3ec2a5a85d2c3754297bdede/coverage-7.13.2-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:88a800258d83acb803c38175b4495d293656d5fac48659c953c18e5f539a274b", size = 251810, upload-time = "2026-01-25T12:57:42.045Z" },
{ url = "https://files.pythonhosted.org/packages/61/dc/b151c3cc41b28cdf7f0166c5fa1271cbc305a8ec0124cce4b04f74791a18/coverage-7.13.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6326e18e9a553e674d948536a04a80d850a5eeefe2aae2e6d7cf05d54046c01b", size = 253920, upload-time = "2026-01-25T12:57:44.026Z" },
{ url = "https://files.pythonhosted.org/packages/2d/35/e83de0556e54a4729a2b94ea816f74ce08732e81945024adee46851c2264/coverage-7.13.2-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:59562de3f797979e1ff07c587e2ac36ba60ca59d16c211eceaa579c266c5022f", size = 250025, upload-time = "2026-01-25T12:57:45.624Z" },
{ url = "https://files.pythonhosted.org/packages/39/67/af2eb9c3926ce3ea0d58a0d2516fcbdacf7a9fc9559fe63076beaf3f2596/coverage-7.13.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:27ba1ed6f66b0e2d61bfa78874dffd4f8c3a12f8e2b5410e515ab345ba7bc9c3", size = 251612, upload-time = "2026-01-25T12:57:47.713Z" },
{ url = "https://files.pythonhosted.org/packages/26/62/5be2e25f3d6c711d23b71296f8b44c978d4c8b4e5b26871abfc164297502/coverage-7.13.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8be48da4d47cc68754ce643ea50b3234557cbefe47c2f120495e7bd0a2756f2b", size = 249670, upload-time = "2026-01-25T12:57:49.378Z" },
{ url = "https://files.pythonhosted.org/packages/b3/51/400d1b09a8344199f9b6a6fc1868005d766b7ea95e7882e494fa862ca69c/coverage-7.13.2-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:2a47a4223d3361b91176aedd9d4e05844ca67d7188456227b6bf5e436630c9a1", size = 249395, upload-time = "2026-01-25T12:57:50.86Z" },
{ url = "https://files.pythonhosted.org/packages/e0/36/f02234bc6e5230e2f0a63fd125d0a2093c73ef20fdf681c7af62a140e4e7/coverage-7.13.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:c6f141b468740197d6bd38f2b26ade124363228cc3f9858bd9924ab059e00059", size = 250298, upload-time = "2026-01-25T12:57:52.287Z" },
{ url = "https://files.pythonhosted.org/packages/b0/06/713110d3dd3151b93611c9cbfc65c15b4156b44f927fced49ac0b20b32a4/coverage-7.13.2-cp311-cp311-win32.whl", hash = "sha256:89567798404af067604246e01a49ef907d112edf2b75ef814b1364d5ce267031", size = 221485, upload-time = "2026-01-25T12:57:53.876Z" },
{ url = "https://files.pythonhosted.org/packages/16/0c/3ae6255fa1ebcb7dec19c9a59e85ef5f34566d1265c70af5b2fc981da834/coverage-7.13.2-cp311-cp311-win_amd64.whl", hash = "sha256:21dd57941804ae2ac7e921771a5e21bbf9aabec317a041d164853ad0a96ce31e", size = 222421, upload-time = "2026-01-25T12:57:55.433Z" },
{ url = "https://files.pythonhosted.org/packages/b5/37/fabc3179af4d61d89ea47bd04333fec735cd5e8b59baad44fed9fc4170d7/coverage-7.13.2-cp311-cp311-win_arm64.whl", hash = "sha256:10758e0586c134a0bafa28f2d37dd2cdb5e4a90de25c0fc0c77dabbad46eca28", size = 221088, upload-time = "2026-01-25T12:57:57.41Z" },
{ url = "https://files.pythonhosted.org/packages/46/39/e92a35f7800222d3f7b2cbb7bbc3b65672ae8d501cb31801b2d2bd7acdf1/coverage-7.13.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f106b2af193f965d0d3234f3f83fc35278c7fb935dfbde56ae2da3dd2c03b84d", size = 219142, upload-time = "2026-01-25T12:58:00.448Z" },
{ url = "https://files.pythonhosted.org/packages/45/7a/8bf9e9309c4c996e65c52a7c5a112707ecdd9fbaf49e10b5a705a402bbb4/coverage-7.13.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:78f45d21dc4d5d6bd29323f0320089ef7eae16e4bef712dff79d184fa7330af3", size = 219503, upload-time = "2026-01-25T12:58:02.451Z" },
{ url = "https://files.pythonhosted.org/packages/87/93/17661e06b7b37580923f3f12406ac91d78aeed293fb6da0b69cc7957582f/coverage-7.13.2-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:fae91dfecd816444c74531a9c3d6ded17a504767e97aa674d44f638107265b99", size = 251006, upload-time = "2026-01-25T12:58:04.059Z" },
{ url = "https://files.pythonhosted.org/packages/12/f0/f9e59fb8c310171497f379e25db060abef9fa605e09d63157eebec102676/coverage-7.13.2-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:264657171406c114787b441484de620e03d8f7202f113d62fcd3d9688baa3e6f", size = 253750, upload-time = "2026-01-25T12:58:05.574Z" },
{ url = "https://files.pythonhosted.org/packages/e5/b1/1935e31add2232663cf7edd8269548b122a7d100047ff93475dbaaae673e/coverage-7.13.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ae47d8dcd3ded0155afbb59c62bd8ab07ea0fd4902e1c40567439e6db9dcaf2f", size = 254862, upload-time = "2026-01-25T12:58:07.647Z" },
{ url = "https://files.pythonhosted.org/packages/af/59/b5e97071ec13df5f45da2b3391b6cdbec78ba20757bc92580a5b3d5fa53c/coverage-7.13.2-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:8a0b33e9fd838220b007ce8f299114d406c1e8edb21336af4c97a26ecfd185aa", size = 251420, upload-time = "2026-01-25T12:58:09.309Z" },
{ url = "https://files.pythonhosted.org/packages/3f/75/9495932f87469d013dc515fb0ce1aac5fa97766f38f6b1a1deb1ee7b7f3a/coverage-7.13.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b3becbea7f3ce9a2d4d430f223ec15888e4deb31395840a79e916368d6004cce", size = 252786, upload-time = "2026-01-25T12:58:10.909Z" },
{ url = "https://files.pythonhosted.org/packages/6a/59/af550721f0eb62f46f7b8cb7e6f1860592189267b1c411a4e3a057caacee/coverage-7.13.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:f819c727a6e6eeb8711e4ce63d78c620f69630a2e9d53bc95ca5379f57b6ba94", size = 250928, upload-time = "2026-01-25T12:58:12.449Z" },
{ url = "https://files.pythonhosted.org/packages/9b/b1/21b4445709aae500be4ab43bbcfb4e53dc0811c3396dcb11bf9f23fd0226/coverage-7.13.2-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:4f7b71757a3ab19f7ba286e04c181004c1d61be921795ee8ba6970fd0ec91da5", size = 250496, upload-time = "2026-01-25T12:58:14.047Z" },
{ url = "https://files.pythonhosted.org/packages/ba/b1/0f5d89dfe0392990e4f3980adbde3eb34885bc1effb2dc369e0bf385e389/coverage-7.13.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b7fc50d2afd2e6b4f6f2f403b70103d280a8e0cb35320cbbe6debcda02a1030b", size = 252373, upload-time = "2026-01-25T12:58:15.976Z" },
{ url = "https://files.pythonhosted.org/packages/01/c9/0cf1a6a57a9968cc049a6b896693faa523c638a5314b1fc374eb2b2ac904/coverage-7.13.2-cp312-cp312-win32.whl", hash = "sha256:292250282cf9bcf206b543d7608bda17ca6fc151f4cbae949fc7e115112fbd41", size = 221696, upload-time = "2026-01-25T12:58:17.517Z" },
{ url = "https://files.pythonhosted.org/packages/4d/05/d7540bf983f09d32803911afed135524570f8c47bb394bf6206c1dc3a786/coverage-7.13.2-cp312-cp312-win_amd64.whl", hash = "sha256:eeea10169fac01549a7921d27a3e517194ae254b542102267bef7a93ed38c40e", size = 222504, upload-time = "2026-01-25T12:58:19.115Z" },
{ url = "https://files.pythonhosted.org/packages/15/8b/1a9f037a736ced0a12aacf6330cdaad5008081142a7070bc58b0f7930cbc/coverage-7.13.2-cp312-cp312-win_arm64.whl", hash = "sha256:2a5b567f0b635b592c917f96b9a9cb3dbd4c320d03f4bf94e9084e494f2e8894", size = 221120, upload-time = "2026-01-25T12:58:21.334Z" },
{ url = "https://files.pythonhosted.org/packages/a7/f0/3d3eac7568ab6096ff23791a526b0048a1ff3f49d0e236b2af6fb6558e88/coverage-7.13.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ed75de7d1217cf3b99365d110975f83af0528c849ef5180a12fd91b5064df9d6", size = 219168, upload-time = "2026-01-25T12:58:23.376Z" },
{ url = "https://files.pythonhosted.org/packages/a3/a6/f8b5cfeddbab95fdef4dcd682d82e5dcff7a112ced57a959f89537ee9995/coverage-7.13.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:97e596de8fa9bada4d88fde64a3f4d37f1b6131e4faa32bad7808abc79887ddc", size = 219537, upload-time = "2026-01-25T12:58:24.932Z" },
{ url = "https://files.pythonhosted.org/packages/7b/e6/8d8e6e0c516c838229d1e41cadcec91745f4b1031d4db17ce0043a0423b4/coverage-7.13.2-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:68c86173562ed4413345410c9480a8d64864ac5e54a5cda236748031e094229f", size = 250528, upload-time = "2026-01-25T12:58:26.567Z" },
{ url = "https://files.pythonhosted.org/packages/8e/78/befa6640f74092b86961f957f26504c8fba3d7da57cc2ab7407391870495/coverage-7.13.2-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:7be4d613638d678b2b3773b8f687537b284d7074695a43fe2fbbfc0e31ceaed1", size = 253132, upload-time = "2026-01-25T12:58:28.251Z" },
{ url = "https://files.pythonhosted.org/packages/9d/10/1630db1edd8ce675124a2ee0f7becc603d2bb7b345c2387b4b95c6907094/coverage-7.13.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d7f63ce526a96acd0e16c4af8b50b64334239550402fb1607ce6a584a6d62ce9", size = 254374, upload-time = "2026-01-25T12:58:30.294Z" },
{ url = "https://files.pythonhosted.org/packages/ed/1d/0d9381647b1e8e6d310ac4140be9c428a0277330991e0c35bdd751e338a4/coverage-7.13.2-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:406821f37f864f968e29ac14c3fccae0fec9fdeba48327f0341decf4daf92d7c", size = 250762, upload-time = "2026-01-25T12:58:32.036Z" },
{ url = "https://files.pythonhosted.org/packages/43/e4/5636dfc9a7c871ee8776af83ee33b4c26bc508ad6cee1e89b6419a366582/coverage-7.13.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ee68e5a4e3e5443623406b905db447dceddffee0dceb39f4e0cd9ec2a35004b5", size = 252502, upload-time = "2026-01-25T12:58:33.961Z" },
{ url = "https://files.pythonhosted.org/packages/02/2a/7ff2884d79d420cbb2d12fed6fff727b6d0ef27253140d3cdbbd03187ee0/coverage-7.13.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2ee0e58cca0c17dd9c6c1cdde02bb705c7b3fbfa5f3b0b5afeda20d4ebff8ef4", size = 250463, upload-time = "2026-01-25T12:58:35.529Z" },
{ url = "https://files.pythonhosted.org/packages/91/c0/ba51087db645b6c7261570400fc62c89a16278763f36ba618dc8657a187b/coverage-7.13.2-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:6e5bbb5018bf76a56aabdb64246b5288d5ae1b7d0dd4d0534fe86df2c2992d1c", size = 250288, upload-time = "2026-01-25T12:58:37.226Z" },
{ url = "https://files.pythonhosted.org/packages/03/07/44e6f428551c4d9faf63ebcefe49b30e5c89d1be96f6a3abd86a52da9d15/coverage-7.13.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a55516c68ef3e08e134e818d5e308ffa6b1337cc8b092b69b24287bf07d38e31", size = 252063, upload-time = "2026-01-25T12:58:38.821Z" },
{ url = "https://files.pythonhosted.org/packages/c2/67/35b730ad7e1859dd57e834d1bc06080d22d2f87457d53f692fce3f24a5a9/coverage-7.13.2-cp313-cp313-win32.whl", hash = "sha256:5b20211c47a8abf4abc3319d8ce2464864fa9f30c5fcaf958a3eed92f4f1fef8", size = 221716, upload-time = "2026-01-25T12:58:40.484Z" },
{ url = "https://files.pythonhosted.org/packages/0d/82/e5fcf5a97c72f45fc14829237a6550bf49d0ab882ac90e04b12a69db76b4/coverage-7.13.2-cp313-cp313-win_amd64.whl", hash = "sha256:14f500232e521201cf031549fb1ebdfc0a40f401cf519157f76c397e586c3beb", size = 222522, upload-time = "2026-01-25T12:58:43.247Z" },
{ url = "https://files.pythonhosted.org/packages/b1/f1/25d7b2f946d239dd2d6644ca2cc060d24f97551e2af13b6c24c722ae5f97/coverage-7.13.2-cp313-cp313-win_arm64.whl", hash = "sha256:9779310cb5a9778a60c899f075a8514c89fa6d10131445c2207fc893e0b14557", size = 221145, upload-time = "2026-01-25T12:58:45Z" },
{ url = "https://files.pythonhosted.org/packages/9e/f7/080376c029c8f76fadfe43911d0daffa0cbdc9f9418a0eead70c56fb7f4b/coverage-7.13.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:e64fa5a1e41ce5df6b547cbc3d3699381c9e2c2c369c67837e716ed0f549d48e", size = 219861, upload-time = "2026-01-25T12:58:46.586Z" },
{ url = "https://files.pythonhosted.org/packages/42/11/0b5e315af5ab35f4c4a70e64d3314e4eec25eefc6dec13be3a7d5ffe8ac5/coverage-7.13.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:b01899e82a04085b6561eb233fd688474f57455e8ad35cd82286463ba06332b7", size = 220207, upload-time = "2026-01-25T12:58:48.277Z" },
{ url = "https://files.pythonhosted.org/packages/b2/0c/0874d0318fb1062117acbef06a09cf8b63f3060c22265adaad24b36306b7/coverage-7.13.2-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:838943bea48be0e2768b0cf7819544cdedc1bbb2f28427eabb6eb8c9eb2285d3", size = 261504, upload-time = "2026-01-25T12:58:49.904Z" },
{ url = "https://files.pythonhosted.org/packages/83/5e/1cd72c22ecb30751e43a72f40ba50fcef1b7e93e3ea823bd9feda8e51f9a/coverage-7.13.2-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:93d1d25ec2b27e90bcfef7012992d1f5121b51161b8bffcda756a816cf13c2c3", size = 263582, upload-time = "2026-01-25T12:58:51.582Z" },
{ url = "https://files.pythonhosted.org/packages/9b/da/8acf356707c7a42df4d0657020308e23e5a07397e81492640c186268497c/coverage-7.13.2-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:93b57142f9621b0d12349c43fc7741fe578e4bc914c1e5a54142856cfc0bf421", size = 266008, upload-time = "2026-01-25T12:58:53.234Z" },
{ url = "https://files.pythonhosted.org/packages/41/41/ea1730af99960309423c6ea8d6a4f1fa5564b2d97bd1d29dda4b42611f04/coverage-7.13.2-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f06799ae1bdfff7ccb8665d75f8291c69110ba9585253de254688aa8a1ccc6c5", size = 260762, upload-time = "2026-01-25T12:58:55.372Z" },
{ url = "https://files.pythonhosted.org/packages/22/fa/02884d2080ba71db64fdc127b311db60e01fe6ba797d9c8363725e39f4d5/coverage-7.13.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:7f9405ab4f81d490811b1d91c7a20361135a2df4c170e7f0b747a794da5b7f23", size = 263571, upload-time = "2026-01-25T12:58:57.52Z" },
{ url = "https://files.pythonhosted.org/packages/d2/6b/4083aaaeba9b3112f55ac57c2ce7001dc4d8fa3fcc228a39f09cc84ede27/coverage-7.13.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:f9ab1d5b86f8fbc97a5b3cd6280a3fd85fef3b028689d8a2c00918f0d82c728c", size = 261200, upload-time = "2026-01-25T12:58:59.255Z" },
{ url = "https://files.pythonhosted.org/packages/e9/d2/aea92fa36d61955e8c416ede9cf9bf142aa196f3aea214bb67f85235a050/coverage-7.13.2-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:f674f59712d67e841525b99e5e2b595250e39b529c3bda14764e4f625a3fa01f", size = 260095, upload-time = "2026-01-25T12:59:01.066Z" },
{ url = "https://files.pythonhosted.org/packages/0d/ae/04ffe96a80f107ea21b22b2367175c621da920063260a1c22f9452fd7866/coverage-7.13.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:c6cadac7b8ace1ba9144feb1ae3cb787a6065ba6d23ffc59a934b16406c26573", size = 262284, upload-time = "2026-01-25T12:59:02.802Z" },
{ url = "https://files.pythonhosted.org/packages/1c/7a/6f354dcd7dfc41297791d6fb4e0d618acb55810bde2c1fd14b3939e05c2b/coverage-7.13.2-cp313-cp313t-win32.whl", hash = "sha256:14ae4146465f8e6e6253eba0cccd57423e598a4cb925958b240c805300918343", size = 222389, upload-time = "2026-01-25T12:59:04.563Z" },
{ url = "https://files.pythonhosted.org/packages/8d/d5/080ad292a4a3d3daf411574be0a1f56d6dee2c4fdf6b005342be9fac807f/coverage-7.13.2-cp313-cp313t-win_amd64.whl", hash = "sha256:9074896edd705a05769e3de0eac0a8388484b503b68863dd06d5e473f874fd47", size = 223450, upload-time = "2026-01-25T12:59:06.677Z" },
{ url = "https://files.pythonhosted.org/packages/88/96/df576fbacc522e9fb8d1c4b7a7fc62eb734be56e2cba1d88d2eabe08ea3f/coverage-7.13.2-cp313-cp313t-win_arm64.whl", hash = "sha256:69e526e14f3f854eda573d3cf40cffd29a1a91c684743d904c33dbdcd0e0f3e7", size = 221707, upload-time = "2026-01-25T12:59:08.363Z" },
{ url = "https://files.pythonhosted.org/packages/55/53/1da9e51a0775634b04fcc11eb25c002fc58ee4f92ce2e8512f94ac5fc5bf/coverage-7.13.2-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:387a825f43d680e7310e6f325b2167dd093bc8ffd933b83e9aa0983cf6e0a2ef", size = 219213, upload-time = "2026-01-25T12:59:11.909Z" },
{ url = "https://files.pythonhosted.org/packages/46/35/b3caac3ebbd10230fea5a33012b27d19e999a17c9285c4228b4b2e35b7da/coverage-7.13.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:f0d7fea9d8e5d778cd5a9e8fc38308ad688f02040e883cdc13311ef2748cb40f", size = 219549, upload-time = "2026-01-25T12:59:13.638Z" },
{ url = "https://files.pythonhosted.org/packages/76/9c/e1cf7def1bdc72c1907e60703983a588f9558434a2ff94615747bd73c192/coverage-7.13.2-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:e080afb413be106c95c4ee96b4fffdc9e2fa56a8bbf90b5c0918e5c4449412f5", size = 250586, upload-time = "2026-01-25T12:59:15.808Z" },
{ url = "https://files.pythonhosted.org/packages/ba/49/f54ec02ed12be66c8d8897270505759e057b0c68564a65c429ccdd1f139e/coverage-7.13.2-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:a7fc042ba3c7ce25b8a9f097eb0f32a5ce1ccdb639d9eec114e26def98e1f8a4", size = 253093, upload-time = "2026-01-25T12:59:17.491Z" },
{ url = "https://files.pythonhosted.org/packages/fb/5e/aaf86be3e181d907e23c0f61fccaeb38de8e6f6b47aed92bf57d8fc9c034/coverage-7.13.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d0ba505e021557f7f8173ee8cd6b926373d8653e5ff7581ae2efce1b11ef4c27", size = 254446, upload-time = "2026-01-25T12:59:19.752Z" },
{ url = "https://files.pythonhosted.org/packages/28/c8/a5fa01460e2d75b0c853b392080d6829d3ca8b5ab31e158fa0501bc7c708/coverage-7.13.2-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:7de326f80e3451bd5cc7239ab46c73ddb658fe0b7649476bc7413572d36cd548", size = 250615, upload-time = "2026-01-25T12:59:21.928Z" },
{ url = "https://files.pythonhosted.org/packages/86/0b/6d56315a55f7062bb66410732c24879ccb2ec527ab6630246de5fe45a1df/coverage-7.13.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:abaea04f1e7e34841d4a7b343904a3f59481f62f9df39e2cd399d69a187a9660", size = 252452, upload-time = "2026-01-25T12:59:23.592Z" },
{ url = "https://files.pythonhosted.org/packages/30/19/9bc550363ebc6b0ea121977ee44d05ecd1e8bf79018b8444f1028701c563/coverage-7.13.2-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:9f93959ee0c604bccd8e0697be21de0887b1f73efcc3aa73a3ec0fd13feace92", size = 250418, upload-time = "2026-01-25T12:59:25.392Z" },
{ url = "https://files.pythonhosted.org/packages/1f/53/580530a31ca2f0cc6f07a8f2ab5460785b02bb11bdf815d4c4d37a4c5169/coverage-7.13.2-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:13fe81ead04e34e105bf1b3c9f9cdf32ce31736ee5d90a8d2de02b9d3e1bcb82", size = 250231, upload-time = "2026-01-25T12:59:27.888Z" },
{ url = "https://files.pythonhosted.org/packages/e2/42/dd9093f919dc3088cb472893651884bd675e3df3d38a43f9053656dca9a2/coverage-7.13.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d6d16b0f71120e365741bca2cb473ca6fe38930bc5431c5e850ba949f708f892", size = 251888, upload-time = "2026-01-25T12:59:29.636Z" },
{ url = "https://files.pythonhosted.org/packages/fa/a6/0af4053e6e819774626e133c3d6f70fae4d44884bfc4b126cb647baee8d3/coverage-7.13.2-cp314-cp314-win32.whl", hash = "sha256:9b2f4714bb7d99ba3790ee095b3b4ac94767e1347fe424278a0b10acb3ff04fe", size = 221968, upload-time = "2026-01-25T12:59:31.424Z" },
{ url = "https://files.pythonhosted.org/packages/c4/cc/5aff1e1f80d55862442855517bb8ad8ad3a68639441ff6287dde6a58558b/coverage-7.13.2-cp314-cp314-win_amd64.whl", hash = "sha256:e4121a90823a063d717a96e0a0529c727fb31ea889369a0ee3ec00ed99bf6859", size = 222783, upload-time = "2026-01-25T12:59:33.118Z" },
{ url = "https://files.pythonhosted.org/packages/de/20/09abafb24f84b3292cc658728803416c15b79f9ee5e68d25238a895b07d9/coverage-7.13.2-cp314-cp314-win_arm64.whl", hash = "sha256:6873f0271b4a15a33e7590f338d823f6f66f91ed147a03938d7ce26efd04eee6", size = 221348, upload-time = "2026-01-25T12:59:34.939Z" },
{ url = "https://files.pythonhosted.org/packages/b6/60/a3820c7232db63be060e4019017cd3426751c2699dab3c62819cdbcea387/coverage-7.13.2-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:f61d349f5b7cd95c34017f1927ee379bfbe9884300d74e07cf630ccf7a610c1b", size = 219950, upload-time = "2026-01-25T12:59:36.624Z" },
{ url = "https://files.pythonhosted.org/packages/fd/37/e4ef5975fdeb86b1e56db9a82f41b032e3d93a840ebaf4064f39e770d5c5/coverage-7.13.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:a43d34ce714f4ca674c0d90beb760eb05aad906f2c47580ccee9da8fe8bfb417", size = 220209, upload-time = "2026-01-25T12:59:38.339Z" },
{ url = "https://files.pythonhosted.org/packages/54/df/d40e091d00c51adca1e251d3b60a8b464112efa3004949e96a74d7c19a64/coverage-7.13.2-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:bff1b04cb9d4900ce5c56c4942f047dc7efe57e2608cb7c3c8936e9970ccdbee", size = 261576, upload-time = "2026-01-25T12:59:40.446Z" },
{ url = "https://files.pythonhosted.org/packages/c5/44/5259c4bed54e3392e5c176121af9f71919d96dde853386e7730e705f3520/coverage-7.13.2-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:6ae99e4560963ad8e163e819e5d77d413d331fd00566c1e0856aa252303552c1", size = 263704, upload-time = "2026-01-25T12:59:42.346Z" },
{ url = "https://files.pythonhosted.org/packages/16/bd/ae9f005827abcbe2c70157459ae86053971c9fa14617b63903abbdce26d9/coverage-7.13.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e79a8c7d461820257d9aa43716c4efc55366d7b292e46b5b37165be1d377405d", size = 266109, upload-time = "2026-01-25T12:59:44.073Z" },
{ url = "https://files.pythonhosted.org/packages/a2/c0/8e279c1c0f5b1eaa3ad9b0fb7a5637fc0379ea7d85a781c0fe0bb3cfc2ab/coverage-7.13.2-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:060ee84f6a769d40c492711911a76811b4befb6fba50abb450371abb720f5bd6", size = 260686, upload-time = "2026-01-25T12:59:45.804Z" },
{ url = "https://files.pythonhosted.org/packages/b2/47/3a8112627e9d863e7cddd72894171c929e94491a597811725befdcd76bce/coverage-7.13.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:3bca209d001fd03ea2d978f8a4985093240a355c93078aee3f799852c23f561a", size = 263568, upload-time = "2026-01-25T12:59:47.929Z" },
{ url = "https://files.pythonhosted.org/packages/92/bc/7ea367d84afa3120afc3ce6de294fd2dcd33b51e2e7fbe4bbfd200f2cb8c/coverage-7.13.2-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:6b8092aa38d72f091db61ef83cb66076f18f02da3e1a75039a4f218629600e04", size = 261174, upload-time = "2026-01-25T12:59:49.717Z" },
{ url = "https://files.pythonhosted.org/packages/33/b7/f1092dcecb6637e31cc2db099581ee5c61a17647849bae6b8261a2b78430/coverage-7.13.2-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:4a3158dc2dcce5200d91ec28cd315c999eebff355437d2765840555d765a6e5f", size = 260017, upload-time = "2026-01-25T12:59:51.463Z" },
{ url = "https://files.pythonhosted.org/packages/2b/cd/f3d07d4b95fbe1a2ef0958c15da614f7e4f557720132de34d2dc3aa7e911/coverage-7.13.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:3973f353b2d70bd9796cc12f532a05945232ccae966456c8ed7034cb96bbfd6f", size = 262337, upload-time = "2026-01-25T12:59:53.407Z" },
{ url = "https://files.pythonhosted.org/packages/e0/db/b0d5b2873a07cb1e06a55d998697c0a5a540dcefbf353774c99eb3874513/coverage-7.13.2-cp314-cp314t-win32.whl", hash = "sha256:79f6506a678a59d4ded048dc72f1859ebede8ec2b9a2d509ebe161f01c2879d3", size = 222749, upload-time = "2026-01-25T12:59:56.316Z" },
{ url = "https://files.pythonhosted.org/packages/e5/2f/838a5394c082ac57d85f57f6aba53093b30d9089781df72412126505716f/coverage-7.13.2-cp314-cp314t-win_amd64.whl", hash = "sha256:196bfeabdccc5a020a57d5a368c681e3a6ceb0447d153aeccc1ab4d70a5032ba", size = 223857, upload-time = "2026-01-25T12:59:58.201Z" },
{ url = "https://files.pythonhosted.org/packages/44/d4/b608243e76ead3a4298824b50922b89ef793e50069ce30316a65c1b4d7ef/coverage-7.13.2-cp314-cp314t-win_arm64.whl", hash = "sha256:69269ab58783e090bfbf5b916ab3d188126e22d6070bbfc93098fdd474ef937c", size = 221881, upload-time = "2026-01-25T13:00:00.449Z" },
{ url = "https://files.pythonhosted.org/packages/d2/db/d291e30fdf7ea617a335531e72294e0c723356d7fdde8fba00610a76bda9/coverage-7.13.2-py3-none-any.whl", hash = "sha256:40ce1ea1e25125556d8e76bd0b61500839a07944cc287ac21d5626f3e620cad5", size = 210943, upload-time = "2026-01-25T13:00:02.388Z" },
{ url = "https://files.pythonhosted.org/packages/ab/07/1c8099563a8a6c389a31c2d0aa1497cee86d6248bb4b9ba5e779215db9f9/coverage-7.13.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0b4f345f7265cdbdb5ec2521ffff15fa49de6d6c39abf89fc7ad68aa9e3a55f0", size = 219143, upload-time = "2026-02-03T13:59:40.459Z" },
{ url = "https://files.pythonhosted.org/packages/69/39/a892d44af7aa092cab70e0cc5cdbba18eeccfe1d6930695dab1742eef9e9/coverage-7.13.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:96c3be8bae9d0333e403cc1a8eb078a7f928b5650bae94a18fb4820cc993fb9b", size = 219663, upload-time = "2026-02-03T13:59:41.951Z" },
{ url = "https://files.pythonhosted.org/packages/9a/25/9669dcf4c2bb4c3861469e6db20e52e8c11908cf53c14ec9b12e9fd4d602/coverage-7.13.3-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:d6f4a21328ea49d38565b55599e1c02834e76583a6953e5586d65cb1efebd8f8", size = 246424, upload-time = "2026-02-03T13:59:43.418Z" },
{ url = "https://files.pythonhosted.org/packages/f3/68/d9766c4e298aca62ea5d9543e1dd1e4e1439d7284815244d8b7db1840bfb/coverage-7.13.3-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:fc970575799a9d17d5c3fafd83a0f6ccf5d5117cdc9ad6fbd791e9ead82418b0", size = 248228, upload-time = "2026-02-03T13:59:44.816Z" },
{ url = "https://files.pythonhosted.org/packages/f0/e2/eea6cb4a4bd443741adf008d4cccec83a1f75401df59b6559aca2bdd9710/coverage-7.13.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:87ff33b652b3556b05e204ae20793d1f872161b0fa5ec8a9ac76f8430e152ed6", size = 250103, upload-time = "2026-02-03T13:59:46.271Z" },
{ url = "https://files.pythonhosted.org/packages/db/77/664280ecd666c2191610842177e2fab9e5dbdeef97178e2078fed46a3d2c/coverage-7.13.3-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:7df8759ee57b9f3f7b66799b7660c282f4375bef620ade1686d6a7b03699e75f", size = 247107, upload-time = "2026-02-03T13:59:48.53Z" },
{ url = "https://files.pythonhosted.org/packages/2b/df/2a672eab99e0d0eba52d8a63e47dc92245eee26954d1b2d3c8f7d372151f/coverage-7.13.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f45c9bcb16bee25a798ccba8a2f6a1251b19de6a0d617bb365d7d2f386c4e20e", size = 248143, upload-time = "2026-02-03T13:59:50.027Z" },
{ url = "https://files.pythonhosted.org/packages/a5/dc/a104e7a87c13e57a358b8b9199a8955676e1703bb372d79722b54978ae45/coverage-7.13.3-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:318b2e4753cbf611061e01b6cc81477e1cdfeb69c36c4a14e6595e674caadb56", size = 246148, upload-time = "2026-02-03T13:59:52.025Z" },
{ url = "https://files.pythonhosted.org/packages/2b/89/e113d3a58dc20b03b7e59aed1e53ebc9ca6167f961876443e002b10e3ae9/coverage-7.13.3-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:24db3959de8ee394eeeca89ccb8ba25305c2da9a668dd44173394cbd5aa0777f", size = 246414, upload-time = "2026-02-03T13:59:53.859Z" },
{ url = "https://files.pythonhosted.org/packages/3f/60/a3fd0a6e8d89b488396019a2268b6a1f25ab56d6d18f3be50f35d77b47dc/coverage-7.13.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:be14d0622125edef21b3a4d8cd2d138c4872bf6e38adc90fd92385e3312f406a", size = 247023, upload-time = "2026-02-03T13:59:55.454Z" },
{ url = "https://files.pythonhosted.org/packages/19/fa/de4840bb939dbb22ba0648a6d8069fa91c9cf3b3fca8b0d1df461e885b3d/coverage-7.13.3-cp310-cp310-win32.whl", hash = "sha256:53be4aab8ddef18beb6188f3a3fdbf4d1af2277d098d4e618be3a8e6c88e74be", size = 221751, upload-time = "2026-02-03T13:59:57.383Z" },
{ url = "https://files.pythonhosted.org/packages/de/87/233ff8b7ef62fb63f58c78623b50bef69681111e0c4d43504f422d88cda4/coverage-7.13.3-cp310-cp310-win_amd64.whl", hash = "sha256:bfeee64ad8b4aae3233abb77eb6b52b51b05fa89da9645518671b9939a78732b", size = 222686, upload-time = "2026-02-03T13:59:58.825Z" },
{ url = "https://files.pythonhosted.org/packages/ec/09/1ac74e37cf45f17eb41e11a21854f7f92a4c2d6c6098ef4a1becb0c6d8d3/coverage-7.13.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5907605ee20e126eeee2abe14aae137043c2c8af2fa9b38d2ab3b7a6b8137f73", size = 219276, upload-time = "2026-02-03T14:00:00.296Z" },
{ url = "https://files.pythonhosted.org/packages/2e/cb/71908b08b21beb2c437d0d5870c4ec129c570ca1b386a8427fcdb11cf89c/coverage-7.13.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a88705500988c8acad8b8fd86c2a933d3aa96bec1ddc4bc5cb256360db7bbd00", size = 219776, upload-time = "2026-02-03T14:00:02.414Z" },
{ url = "https://files.pythonhosted.org/packages/09/85/c4f3dd69232887666a2c0394d4be21c60ea934d404db068e6c96aa59cd87/coverage-7.13.3-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:7bbb5aa9016c4c29e3432e087aa29ebee3f8fda089cfbfb4e6d64bd292dcd1c2", size = 250196, upload-time = "2026-02-03T14:00:04.197Z" },
{ url = "https://files.pythonhosted.org/packages/9c/cc/560ad6f12010344d0778e268df5ba9aa990aacccc310d478bf82bf3d302c/coverage-7.13.3-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:0c2be202a83dde768937a61cdc5d06bf9fb204048ca199d93479488e6247656c", size = 252111, upload-time = "2026-02-03T14:00:05.639Z" },
{ url = "https://files.pythonhosted.org/packages/f0/66/3193985fb2c58e91f94cfbe9e21a6fdf941e9301fe2be9e92c072e9c8f8c/coverage-7.13.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0f45e32ef383ce56e0ca099b2e02fcdf7950be4b1b56afaab27b4ad790befe5b", size = 254217, upload-time = "2026-02-03T14:00:07.738Z" },
{ url = "https://files.pythonhosted.org/packages/c5/78/f0f91556bf1faa416792e537c523c5ef9db9b1d32a50572c102b3d7c45b3/coverage-7.13.3-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:6ed2e787249b922a93cd95c671cc9f4c9797a106e81b455c83a9ddb9d34590c0", size = 250318, upload-time = "2026-02-03T14:00:09.224Z" },
{ url = "https://files.pythonhosted.org/packages/6f/aa/fc654e45e837d137b2c1f3a2cc09b4aea1e8b015acd2f774fa0f3d2ddeba/coverage-7.13.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:05dd25b21afffe545e808265897c35f32d3e4437663923e0d256d9ab5031fb14", size = 251909, upload-time = "2026-02-03T14:00:10.712Z" },
{ url = "https://files.pythonhosted.org/packages/73/4d/ab53063992add8a9ca0463c9d92cce5994a29e17affd1c2daa091b922a93/coverage-7.13.3-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:46d29926349b5c4f1ea4fca95e8c892835515f3600995a383fa9a923b5739ea4", size = 249971, upload-time = "2026-02-03T14:00:12.402Z" },
{ url = "https://files.pythonhosted.org/packages/29/25/83694b81e46fcff9899694a1b6f57573429cdd82b57932f09a698f03eea5/coverage-7.13.3-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:fae6a21537519c2af00245e834e5bf2884699cc7c1055738fd0f9dc37a3644ad", size = 249692, upload-time = "2026-02-03T14:00:13.868Z" },
{ url = "https://files.pythonhosted.org/packages/d4/ef/d68fc304301f4cb4bf6aefa0045310520789ca38dabdfba9dbecd3f37919/coverage-7.13.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:c672d4e2f0575a4ca2bf2aa0c5ced5188220ab806c1bb6d7179f70a11a017222", size = 250597, upload-time = "2026-02-03T14:00:15.461Z" },
{ url = "https://files.pythonhosted.org/packages/8d/85/240ad396f914df361d0f71e912ddcedb48130c71b88dc4193fe3c0306f00/coverage-7.13.3-cp311-cp311-win32.whl", hash = "sha256:fcda51c918c7a13ad93b5f89a58d56e3a072c9e0ba5c231b0ed81404bf2648fb", size = 221773, upload-time = "2026-02-03T14:00:17.462Z" },
{ url = "https://files.pythonhosted.org/packages/2f/71/165b3a6d3d052704a9ab52d11ea64ef3426745de517dda44d872716213a7/coverage-7.13.3-cp311-cp311-win_amd64.whl", hash = "sha256:d1a049b5c51b3b679928dd35e47c4a2235e0b6128b479a7596d0ef5b42fa6301", size = 222711, upload-time = "2026-02-03T14:00:19.449Z" },
{ url = "https://files.pythonhosted.org/packages/51/d0/0ddc9c5934cdd52639c5df1f1eb0fdab51bb52348f3a8d1c7db9c600d93a/coverage-7.13.3-cp311-cp311-win_arm64.whl", hash = "sha256:79f2670c7e772f4917895c3d89aad59e01f3dbe68a4ed2d0373b431fad1dcfba", size = 221377, upload-time = "2026-02-03T14:00:20.968Z" },
{ url = "https://files.pythonhosted.org/packages/94/44/330f8e83b143f6668778ed61d17ece9dc48459e9e74669177de02f45fec5/coverage-7.13.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:ed48b4170caa2c4420e0cd27dc977caaffc7eecc317355751df8373dddcef595", size = 219441, upload-time = "2026-02-03T14:00:22.585Z" },
{ url = "https://files.pythonhosted.org/packages/08/e7/29db05693562c2e65bdf6910c0af2fd6f9325b8f43caf7a258413f369e30/coverage-7.13.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8f2adf4bcffbbec41f366f2e6dffb9d24e8172d16e91da5799c9b7ed6b5716e6", size = 219801, upload-time = "2026-02-03T14:00:24.186Z" },
{ url = "https://files.pythonhosted.org/packages/90/ae/7f8a78249b02b0818db46220795f8ac8312ea4abd1d37d79ea81db5cae81/coverage-7.13.3-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:01119735c690786b6966a1e9f098da4cd7ca9174c4cfe076d04e653105488395", size = 251306, upload-time = "2026-02-03T14:00:25.798Z" },
{ url = "https://files.pythonhosted.org/packages/62/71/a18a53d1808e09b2e9ebd6b47dad5e92daf4c38b0686b4c4d1b2f3e42b7f/coverage-7.13.3-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:8bb09e83c603f152d855f666d70a71765ca8e67332e5829e62cb9466c176af23", size = 254051, upload-time = "2026-02-03T14:00:27.474Z" },
{ url = "https://files.pythonhosted.org/packages/4a/0a/eb30f6455d04c5a3396d0696cad2df0269ae7444bb322f86ffe3376f7bf9/coverage-7.13.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b607a40cba795cfac6d130220d25962931ce101f2f478a29822b19755377fb34", size = 255160, upload-time = "2026-02-03T14:00:29.024Z" },
{ url = "https://files.pythonhosted.org/packages/7b/7e/a45baac86274ce3ed842dbb84f14560c673ad30535f397d89164ec56c5df/coverage-7.13.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:44f14a62f5da2e9aedf9080e01d2cda61df39197d48e323538ec037336d68da8", size = 251709, upload-time = "2026-02-03T14:00:30.641Z" },
{ url = "https://files.pythonhosted.org/packages/c0/df/dd0dc12f30da11349993f3e218901fdf82f45ee44773596050c8f5a1fb25/coverage-7.13.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:debf29e0b157769843dff0981cc76f79e0ed04e36bb773c6cac5f6029054bd8a", size = 253083, upload-time = "2026-02-03T14:00:32.14Z" },
{ url = "https://files.pythonhosted.org/packages/ab/32/fc764c8389a8ce95cb90eb97af4c32f392ab0ac23ec57cadeefb887188d3/coverage-7.13.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:824bb95cd71604031ae9a48edb91fd6effde669522f960375668ed21b36e3ec4", size = 251227, upload-time = "2026-02-03T14:00:34.721Z" },
{ url = "https://files.pythonhosted.org/packages/dd/ca/d025e9da8f06f24c34d2da9873957cfc5f7e0d67802c3e34d0caa8452130/coverage-7.13.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:8f1010029a5b52dc427c8e2a8dbddb2303ddd180b806687d1acd1bb1d06649e7", size = 250794, upload-time = "2026-02-03T14:00:36.278Z" },
{ url = "https://files.pythonhosted.org/packages/45/c7/76bf35d5d488ec8f68682eb8e7671acc50a6d2d1c1182de1d2b6d4ffad3b/coverage-7.13.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:cd5dee4fd7659d8306ffa79eeaaafd91fa30a302dac3af723b9b469e549247e0", size = 252671, upload-time = "2026-02-03T14:00:38.368Z" },
{ url = "https://files.pythonhosted.org/packages/bf/10/1921f1a03a7c209e1cb374f81a6b9b68b03cdb3ecc3433c189bc90e2a3d5/coverage-7.13.3-cp312-cp312-win32.whl", hash = "sha256:f7f153d0184d45f3873b3ad3ad22694fd73aadcb8cdbc4337ab4b41ea6b4dff1", size = 221986, upload-time = "2026-02-03T14:00:40.442Z" },
{ url = "https://files.pythonhosted.org/packages/3c/7c/f5d93297f8e125a80c15545edc754d93e0ed8ba255b65e609b185296af01/coverage-7.13.3-cp312-cp312-win_amd64.whl", hash = "sha256:03a6e5e1e50819d6d7436f5bc40c92ded7e484e400716886ac921e35c133149d", size = 222793, upload-time = "2026-02-03T14:00:42.106Z" },
{ url = "https://files.pythonhosted.org/packages/43/59/c86b84170015b4555ebabca8649bdf9f4a1f737a73168088385ed0f947c4/coverage-7.13.3-cp312-cp312-win_arm64.whl", hash = "sha256:51c4c42c0e7d09a822b08b6cf79b3c4db8333fffde7450da946719ba0d45730f", size = 221410, upload-time = "2026-02-03T14:00:43.726Z" },
{ url = "https://files.pythonhosted.org/packages/81/f3/4c333da7b373e8c8bfb62517e8174a01dcc373d7a9083698e3b39d50d59c/coverage-7.13.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:853c3d3c79ff0db65797aad79dee6be020efd218ac4510f15a205f1e8d13ce25", size = 219468, upload-time = "2026-02-03T14:00:45.829Z" },
{ url = "https://files.pythonhosted.org/packages/d6/31/0714337b7d23630c8de2f4d56acf43c65f8728a45ed529b34410683f7217/coverage-7.13.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f75695e157c83d374f88dcc646a60cb94173304a9258b2e74ba5a66b7614a51a", size = 219839, upload-time = "2026-02-03T14:00:47.407Z" },
{ url = "https://files.pythonhosted.org/packages/12/99/bd6f2a2738144c98945666f90cae446ed870cecf0421c767475fcf42cdbe/coverage-7.13.3-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:2d098709621d0819039f3f1e471ee554f55a0b2ac0d816883c765b14129b5627", size = 250828, upload-time = "2026-02-03T14:00:49.029Z" },
{ url = "https://files.pythonhosted.org/packages/6f/99/97b600225fbf631e6f5bfd3ad5bcaf87fbb9e34ff87492e5a572ff01bbe2/coverage-7.13.3-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:16d23d6579cf80a474ad160ca14d8b319abaa6db62759d6eef53b2fc979b58c8", size = 253432, upload-time = "2026-02-03T14:00:50.655Z" },
{ url = "https://files.pythonhosted.org/packages/5f/5c/abe2b3490bda26bd4f5e3e799be0bdf00bd81edebedc2c9da8d3ef288fa8/coverage-7.13.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:00d34b29a59d2076e6f318b30a00a69bf63687e30cd882984ed444e753990cc1", size = 254672, upload-time = "2026-02-03T14:00:52.757Z" },
{ url = "https://files.pythonhosted.org/packages/31/ba/5d1957c76b40daff53971fe0adb84d9c2162b614280031d1d0653dd010c1/coverage-7.13.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ab6d72bffac9deb6e6cb0f61042e748de3f9f8e98afb0375a8e64b0b6e11746b", size = 251050, upload-time = "2026-02-03T14:00:54.332Z" },
{ url = "https://files.pythonhosted.org/packages/69/dc/dffdf3bfe9d32090f047d3c3085378558cb4eb6778cda7de414ad74581ed/coverage-7.13.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e129328ad1258e49cae0123a3b5fcb93d6c2fa90d540f0b4c7cdcdc019aaa3dc", size = 252801, upload-time = "2026-02-03T14:00:56.121Z" },
{ url = "https://files.pythonhosted.org/packages/87/51/cdf6198b0f2746e04511a30dc9185d7b8cdd895276c07bdb538e37f1cd50/coverage-7.13.3-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2213a8d88ed35459bda71597599d4eec7c2ebad201c88f0bfc2c26fd9b0dd2ea", size = 250763, upload-time = "2026-02-03T14:00:58.719Z" },
{ url = "https://files.pythonhosted.org/packages/d7/1a/596b7d62218c1d69f2475b69cc6b211e33c83c902f38ee6ae9766dd422da/coverage-7.13.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:00dd3f02de6d5f5c9c3d95e3e036c3c2e2a669f8bf2d3ceb92505c4ce7838f67", size = 250587, upload-time = "2026-02-03T14:01:01.197Z" },
{ url = "https://files.pythonhosted.org/packages/f7/46/52330d5841ff660f22c130b75f5e1dd3e352c8e7baef5e5fef6b14e3e991/coverage-7.13.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f9bada7bc660d20b23d7d312ebe29e927b655cf414dadcdb6335a2075695bd86", size = 252358, upload-time = "2026-02-03T14:01:02.824Z" },
{ url = "https://files.pythonhosted.org/packages/36/8a/e69a5be51923097ba7d5cff9724466e74fe486e9232020ba97c809a8b42b/coverage-7.13.3-cp313-cp313-win32.whl", hash = "sha256:75b3c0300f3fa15809bd62d9ca8b170eb21fcf0100eb4b4154d6dc8b3a5bbd43", size = 222007, upload-time = "2026-02-03T14:01:04.876Z" },
{ url = "https://files.pythonhosted.org/packages/0a/09/a5a069bcee0d613bdd48ee7637fa73bc09e7ed4342b26890f2df97cc9682/coverage-7.13.3-cp313-cp313-win_amd64.whl", hash = "sha256:a2f7589c6132c44c53f6e705e1a6677e2b7821378c22f7703b2cf5388d0d4587", size = 222812, upload-time = "2026-02-03T14:01:07.296Z" },
{ url = "https://files.pythonhosted.org/packages/3d/4f/d62ad7dfe32f9e3d4a10c178bb6f98b10b083d6e0530ca202b399371f6c1/coverage-7.13.3-cp313-cp313-win_arm64.whl", hash = "sha256:123ceaf2b9d8c614f01110f908a341e05b1b305d6b2ada98763b9a5a59756051", size = 221433, upload-time = "2026-02-03T14:01:09.156Z" },
{ url = "https://files.pythonhosted.org/packages/04/b2/4876c46d723d80b9c5b695f1a11bf5f7c3dabf540ec00d6edc076ff025e6/coverage-7.13.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:cc7fd0f726795420f3678ac82ff882c7fc33770bd0074463b5aef7293285ace9", size = 220162, upload-time = "2026-02-03T14:01:11.409Z" },
{ url = "https://files.pythonhosted.org/packages/fc/04/9942b64a0e0bdda2c109f56bda42b2a59d9d3df4c94b85a323c1cae9fc77/coverage-7.13.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:d358dc408edc28730aed5477a69338e444e62fba0b7e9e4a131c505fadad691e", size = 220510, upload-time = "2026-02-03T14:01:13.038Z" },
{ url = "https://files.pythonhosted.org/packages/5a/82/5cfe1e81eae525b74669f9795f37eb3edd4679b873d79d1e6c1c14ee6c1c/coverage-7.13.3-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:5d67b9ed6f7b5527b209b24b3df9f2e5bf0198c1bbf99c6971b0e2dcb7e2a107", size = 261801, upload-time = "2026-02-03T14:01:14.674Z" },
{ url = "https://files.pythonhosted.org/packages/0b/ec/a553d7f742fd2cd12e36a16a7b4b3582d5934b496ef2b5ea8abeb10903d4/coverage-7.13.3-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:59224bfb2e9b37c1335ae35d00daa3a5b4e0b1a20f530be208fff1ecfa436f43", size = 263882, upload-time = "2026-02-03T14:01:16.343Z" },
{ url = "https://files.pythonhosted.org/packages/e1/58/8f54a2a93e3d675635bc406de1c9ac8d551312142ff52c9d71b5e533ad45/coverage-7.13.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ae9306b5299e31e31e0d3b908c66bcb6e7e3ddca143dea0266e9ce6c667346d3", size = 266306, upload-time = "2026-02-03T14:01:18.02Z" },
{ url = "https://files.pythonhosted.org/packages/1a/be/e593399fd6ea1f00aee79ebd7cc401021f218d34e96682a92e1bae092ff6/coverage-7.13.3-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:343aaeb5f8bb7bcd38620fd7bc56e6ee8207847d8c6103a1e7b72322d381ba4a", size = 261051, upload-time = "2026-02-03T14:01:19.757Z" },
{ url = "https://files.pythonhosted.org/packages/5c/e5/e9e0f6138b21bcdebccac36fbfde9cf15eb1bbcea9f5b1f35cd1f465fb91/coverage-7.13.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:b2182129f4c101272ff5f2f18038d7b698db1bf8e7aa9e615cb48440899ad32e", size = 263868, upload-time = "2026-02-03T14:01:21.487Z" },
{ url = "https://files.pythonhosted.org/packages/9a/bf/de72cfebb69756f2d4a2dde35efcc33c47d85cd3ebdf844b3914aac2ef28/coverage-7.13.3-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:94d2ac94bd0cc57c5626f52f8c2fffed1444b5ae8c9fc68320306cc2b255e155", size = 261498, upload-time = "2026-02-03T14:01:23.097Z" },
{ url = "https://files.pythonhosted.org/packages/f2/91/4a2d313a70fc2e98ca53afd1c8ce67a89b1944cd996589a5b1fe7fbb3e5c/coverage-7.13.3-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:65436cde5ecabe26fb2f0bf598962f0a054d3f23ad529361326ac002c61a2a1e", size = 260394, upload-time = "2026-02-03T14:01:24.949Z" },
{ url = "https://files.pythonhosted.org/packages/40/83/25113af7cf6941e779eb7ed8de2a677865b859a07ccee9146d4cc06a03e3/coverage-7.13.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:db83b77f97129813dbd463a67e5335adc6a6a91db652cc085d60c2d512746f96", size = 262579, upload-time = "2026-02-03T14:01:26.703Z" },
{ url = "https://files.pythonhosted.org/packages/1e/19/a5f2b96262977e82fb9aabbe19b4d83561f5d063f18dde3e72f34ffc3b2f/coverage-7.13.3-cp313-cp313t-win32.whl", hash = "sha256:dfb428e41377e6b9ba1b0a32df6db5409cb089a0ed1d0a672dc4953ec110d84f", size = 222679, upload-time = "2026-02-03T14:01:28.553Z" },
{ url = "https://files.pythonhosted.org/packages/81/82/ef1747b88c87a5c7d7edc3704799ebd650189a9158e680a063308b6125ef/coverage-7.13.3-cp313-cp313t-win_amd64.whl", hash = "sha256:5badd7e596e6b0c89aa8ec6d37f4473e4357f982ce57f9a2942b0221cd9cf60c", size = 223740, upload-time = "2026-02-03T14:01:30.776Z" },
{ url = "https://files.pythonhosted.org/packages/1c/4c/a67c7bb5b560241c22736a9cb2f14c5034149ffae18630323fde787339e4/coverage-7.13.3-cp313-cp313t-win_arm64.whl", hash = "sha256:989aa158c0eb19d83c76c26f4ba00dbb272485c56e452010a3450bdbc9daafd9", size = 221996, upload-time = "2026-02-03T14:01:32.495Z" },
{ url = "https://files.pythonhosted.org/packages/5e/b3/677bb43427fed9298905106f39c6520ac75f746f81b8f01104526a8026e4/coverage-7.13.3-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:c6f6169bbdbdb85aab8ac0392d776948907267fcc91deeacf6f9d55f7a83ae3b", size = 219513, upload-time = "2026-02-03T14:01:34.29Z" },
{ url = "https://files.pythonhosted.org/packages/42/53/290046e3bbf8986cdb7366a42dab3440b9983711eaff044a51b11006c67b/coverage-7.13.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:2f5e731627a3d5ef11a2a35aa0c6f7c435867c7ccbc391268eb4f2ca5dbdcc10", size = 219850, upload-time = "2026-02-03T14:01:35.984Z" },
{ url = "https://files.pythonhosted.org/packages/ea/2b/ab41f10345ba2e49d5e299be8663be2b7db33e77ac1b85cd0af985ea6406/coverage-7.13.3-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:9db3a3285d91c0b70fab9f39f0a4aa37d375873677efe4e71e58d8321e8c5d39", size = 250886, upload-time = "2026-02-03T14:01:38.287Z" },
{ url = "https://files.pythonhosted.org/packages/72/2d/b3f6913ee5a1d5cdd04106f257e5fac5d048992ffc2d9995d07b0f17739f/coverage-7.13.3-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:06e49c5897cb12e3f7ecdc111d44e97c4f6d0557b81a7a0204ed70a8b038f86f", size = 253393, upload-time = "2026-02-03T14:01:40.118Z" },
{ url = "https://files.pythonhosted.org/packages/f0/f6/b1f48810ffc6accf49a35b9943636560768f0812330f7456aa87dc39aff5/coverage-7.13.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fb25061a66802df9fc13a9ba1967d25faa4dae0418db469264fd9860a921dde4", size = 254740, upload-time = "2026-02-03T14:01:42.413Z" },
{ url = "https://files.pythonhosted.org/packages/57/d0/e59c54f9be0b61808f6bc4c8c4346bd79f02dd6bbc3f476ef26124661f20/coverage-7.13.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:99fee45adbb1caeb914da16f70e557fb7ff6ddc9e4b14de665bd41af631367ef", size = 250905, upload-time = "2026-02-03T14:01:44.163Z" },
{ url = "https://files.pythonhosted.org/packages/d5/f7/5291bcdf498bafbee3796bb32ef6966e9915aebd4d0954123c8eae921c32/coverage-7.13.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:318002f1fd819bdc1651c619268aa5bc853c35fa5cc6d1e8c96bd9cd6c828b75", size = 252753, upload-time = "2026-02-03T14:01:45.974Z" },
{ url = "https://files.pythonhosted.org/packages/a0/a9/1dcafa918c281554dae6e10ece88c1add82db685be123e1b05c2056ff3fb/coverage-7.13.3-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:71295f2d1d170b9977dc386d46a7a1b7cbb30e5405492529b4c930113a33f895", size = 250716, upload-time = "2026-02-03T14:01:48.844Z" },
{ url = "https://files.pythonhosted.org/packages/44/bb/4ea4eabcce8c4f6235df6e059fbc5db49107b24c4bdffc44aee81aeca5a8/coverage-7.13.3-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:5b1ad2e0dc672625c44bc4fe34514602a9fd8b10d52ddc414dc585f74453516c", size = 250530, upload-time = "2026-02-03T14:01:50.793Z" },
{ url = "https://files.pythonhosted.org/packages/6d/31/4a6c9e6a71367e6f923b27b528448c37f4e959b7e4029330523014691007/coverage-7.13.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:b2beb64c145593a50d90db5c7178f55daeae129123b0d265bdb3cbec83e5194a", size = 252186, upload-time = "2026-02-03T14:01:52.607Z" },
{ url = "https://files.pythonhosted.org/packages/27/92/e1451ef6390a4f655dc42da35d9971212f7abbbcad0bdb7af4407897eb76/coverage-7.13.3-cp314-cp314-win32.whl", hash = "sha256:3d1aed4f4e837a832df2f3b4f68a690eede0de4560a2dbc214ea0bc55aabcdb4", size = 222253, upload-time = "2026-02-03T14:01:55.071Z" },
{ url = "https://files.pythonhosted.org/packages/8a/98/78885a861a88de020c32a2693487c37d15a9873372953f0c3c159d575a43/coverage-7.13.3-cp314-cp314-win_amd64.whl", hash = "sha256:9f9efbbaf79f935d5fbe3ad814825cbce4f6cdb3054384cb49f0c0f496125fa0", size = 223069, upload-time = "2026-02-03T14:01:56.95Z" },
{ url = "https://files.pythonhosted.org/packages/eb/fb/3784753a48da58a5337972abf7ca58b1fb0f1bda21bc7b4fae992fd28e47/coverage-7.13.3-cp314-cp314-win_arm64.whl", hash = "sha256:31b6e889c53d4e6687ca63706148049494aace140cffece1c4dc6acadb70a7b3", size = 221633, upload-time = "2026-02-03T14:01:58.758Z" },
{ url = "https://files.pythonhosted.org/packages/40/f9/75b732d9674d32cdbffe801ed5f770786dd1c97eecedef2125b0d25102dc/coverage-7.13.3-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:c5e9787cec750793a19a28df7edd85ac4e49d3fb91721afcdc3b86f6c08d9aa8", size = 220243, upload-time = "2026-02-03T14:02:01.109Z" },
{ url = "https://files.pythonhosted.org/packages/cf/7e/2868ec95de5a65703e6f0c87407ea822d1feb3619600fbc3c1c4fa986090/coverage-7.13.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:e5b86db331c682fd0e4be7098e6acee5e8a293f824d41487c667a93705d415ca", size = 220515, upload-time = "2026-02-03T14:02:02.862Z" },
{ url = "https://files.pythonhosted.org/packages/7d/eb/9f0d349652fced20bcaea0f67fc5777bd097c92369f267975732f3dc5f45/coverage-7.13.3-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:edc7754932682d52cf6e7a71806e529ecd5ce660e630e8bd1d37109a2e5f63ba", size = 261874, upload-time = "2026-02-03T14:02:04.727Z" },
{ url = "https://files.pythonhosted.org/packages/ee/a5/6619bc4a6c7b139b16818149a3e74ab2e21599ff9a7b6811b6afde99f8ec/coverage-7.13.3-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:d3a16d6398666510a6886f67f43d9537bfd0e13aca299688a19daa84f543122f", size = 264004, upload-time = "2026-02-03T14:02:06.634Z" },
{ url = "https://files.pythonhosted.org/packages/29/b7/90aa3fc645a50c6f07881fca4fd0ba21e3bfb6ce3a7078424ea3a35c74c9/coverage-7.13.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:303d38b19626c1981e1bb067a9928236d88eb0e4479b18a74812f05a82071508", size = 266408, upload-time = "2026-02-03T14:02:09.037Z" },
{ url = "https://files.pythonhosted.org/packages/62/55/08bb2a1e4dcbae384e638f0effef486ba5987b06700e481691891427d879/coverage-7.13.3-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:284e06eadfe15ddfee2f4ee56631f164ef897a7d7d5a15bca5f0bb88889fc5ba", size = 260977, upload-time = "2026-02-03T14:02:11.755Z" },
{ url = "https://files.pythonhosted.org/packages/9b/76/8bd4ae055a42d8fb5dd2230e5cf36ff2e05f85f2427e91b11a27fea52ed7/coverage-7.13.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:d401f0864a1d3198422816878e4e84ca89ec1c1bf166ecc0ae01380a39b888cd", size = 263868, upload-time = "2026-02-03T14:02:13.565Z" },
{ url = "https://files.pythonhosted.org/packages/e3/f9/ba000560f11e9e32ec03df5aa8477242c2d95b379c99ac9a7b2e7fbacb1a/coverage-7.13.3-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:3f379b02c18a64de78c4ccdddf1c81c2c5ae1956c72dacb9133d7dd7809794ab", size = 261474, upload-time = "2026-02-03T14:02:16.069Z" },
{ url = "https://files.pythonhosted.org/packages/90/4b/4de4de8f9ca7af4733bfcf4baa440121b7dbb3856daf8428ce91481ff63b/coverage-7.13.3-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:7a482f2da9086971efb12daca1d6547007ede3674ea06e16d7663414445c683e", size = 260317, upload-time = "2026-02-03T14:02:17.996Z" },
{ url = "https://files.pythonhosted.org/packages/05/71/5cd8436e2c21410ff70be81f738c0dddea91bcc3189b1517d26e0102ccb3/coverage-7.13.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:562136b0d401992118d9b49fbee5454e16f95f85b120a4226a04d816e33fe024", size = 262635, upload-time = "2026-02-03T14:02:20.405Z" },
{ url = "https://files.pythonhosted.org/packages/e7/f8/2834bb45bdd70b55a33ec354b8b5f6062fc90e5bb787e14385903a979503/coverage-7.13.3-cp314-cp314t-win32.whl", hash = "sha256:ca46e5c3be3b195098dd88711890b8011a9fa4feca942292bb84714ce5eab5d3", size = 223035, upload-time = "2026-02-03T14:02:22.323Z" },
{ url = "https://files.pythonhosted.org/packages/26/75/f8290f0073c00d9ae14056d2b84ab92dff21d5370e464cb6cb06f52bf580/coverage-7.13.3-cp314-cp314t-win_amd64.whl", hash = "sha256:06d316dbb3d9fd44cca05b2dbcfbef22948493d63a1f28e828d43e6cc505fed8", size = 224142, upload-time = "2026-02-03T14:02:24.143Z" },
{ url = "https://files.pythonhosted.org/packages/03/01/43ac78dfea8946c4a9161bbc034b5549115cb2b56781a4b574927f0d141a/coverage-7.13.3-cp314-cp314t-win_arm64.whl", hash = "sha256:299d66e9218193f9dc6e4880629ed7c4cd23486005166247c283fb98531656c3", size = 222166, upload-time = "2026-02-03T14:02:26.005Z" },
{ url = "https://files.pythonhosted.org/packages/7d/fb/70af542d2d938c778c9373ce253aa4116dbe7c0a5672f78b2b2ae0e1b94b/coverage-7.13.3-py3-none-any.whl", hash = "sha256:90a8af9dba6429b2573199622d72e0ebf024d6276f16abce394ad4d181bb0910", size = 211237, upload-time = "2026-02-03T14:02:27.986Z" },
]
[package.optional-dependencies]
@ -543,7 +543,7 @@ wheels = [
[[package]]
name = "django"
version = "5.2.10"
version = "5.2.11"
source = { registry = "https://pypi.org/simple" }
resolution-markers = [
"python_full_version == '3.11.*'",
@ -554,14 +554,14 @@ dependencies = [
{ name = "sqlparse", marker = "python_full_version < '3.12'" },
{ name = "tzdata", marker = "python_full_version < '3.12' and sys_platform == 'win32'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/e6/e5/2671df24bf0ded831768ef79532e5a7922485411a5696f6d979568591a37/django-5.2.10.tar.gz", hash = "sha256:74df100784c288c50a2b5cad59631d71214f40f72051d5af3fdf220c20bdbbbe", size = 10880754, upload-time = "2026-01-06T18:55:26.817Z" }
sdist = { url = "https://files.pythonhosted.org/packages/17/f2/3e57ef696b95067e05ae206171e47a8e53b9c84eec56198671ef9eaa51a6/django-5.2.11.tar.gz", hash = "sha256:7f2d292ad8b9ee35e405d965fbbad293758b858c34bbf7f3df551aeeac6f02d3", size = 10885017, upload-time = "2026-02-03T13:52:50.554Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/fa/de/f1a7cd896daec85832136ab509d9b2a6daed4939dbe26313af3e95fc5f5e/django-5.2.10-py3-none-any.whl", hash = "sha256:cf85067a64250c95d5f9067b056c5eaa80591929f7e16fbcd997746e40d6c45c", size = 8290820, upload-time = "2026-01-06T18:55:20.009Z" },
{ url = "https://files.pythonhosted.org/packages/91/a7/2b112ab430575bf3135b8304ac372248500d99c352f777485f53fdb9537e/django-5.2.11-py3-none-any.whl", hash = "sha256:e7130df33ada9ab5e5e929bc19346a20fe383f5454acb2cc004508f242ee92c0", size = 8291375, upload-time = "2026-02-03T13:52:42.47Z" },
]
[[package]]
name = "django"
version = "6.0.1"
version = "6.0.2"
source = { registry = "https://pypi.org/simple" }
resolution-markers = [
"python_full_version >= '3.12'",
@ -571,9 +571,9 @@ dependencies = [
{ name = "sqlparse", marker = "python_full_version >= '3.12'" },
{ name = "tzdata", marker = "python_full_version >= '3.12' and sys_platform == 'win32'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/b5/9b/016f7e55e855ee738a352b05139d4f8b278d0b451bd01ebef07456ef3b0e/django-6.0.1.tar.gz", hash = "sha256:ed76a7af4da21551573b3d9dfc1f53e20dd2e6c7d70a3adc93eedb6338130a5f", size = 11069565, upload-time = "2026-01-06T18:55:53.069Z" }
sdist = { url = "https://files.pythonhosted.org/packages/26/3e/a1c4207c5dea4697b7a3387e26584919ba987d8f9320f59dc0b5c557a4eb/django-6.0.2.tar.gz", hash = "sha256:3046a53b0e40d4b676c3b774c73411d7184ae2745fe8ce5e45c0f33d3ddb71a7", size = 10886874, upload-time = "2026-02-03T13:50:31.596Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/95/b5/814ed98bd21235c116fd3436a7ed44d47560329a6d694ec8aac2982dbb93/django-6.0.1-py3-none-any.whl", hash = "sha256:a92a4ff14f664a896f9849009cb8afaca7abe0d6fc53325f3d1895a15253433d", size = 8338791, upload-time = "2026-01-06T18:55:46.175Z" },
{ url = "https://files.pythonhosted.org/packages/96/ba/a6e2992bc5b8c688249c00ea48cb1b7a9bc09839328c81dc603671460928/django-6.0.2-py3-none-any.whl", hash = "sha256:610dd3b13d15ec3f1e1d257caedd751db8033c5ad8ea0e2d1219a8acf446ecc6", size = 8339381, upload-time = "2026-02-03T13:50:15.501Z" },
]
[[package]]
@ -581,8 +581,8 @@ name = "django-extra-views"
version = "0.16.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "django", version = "5.2.10", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.12'" },
{ name = "django", version = "6.0.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" },
{ name = "django", version = "5.2.11", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.12'" },
{ name = "django", version = "6.0.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/ac/61/c6d2ced11fc4235d2aeb422ad5af3b516effd942e2be5a263a5d93dcb1e2/django_extra_views-0.16.0.tar.gz", hash = "sha256:7f8e07bd6c9388816a7c08d752661172d4078758c2079fc0cadddfcf5cd38ae3", size = 13235, upload-time = "2025-04-22T15:10:58.475Z" }
wheels = [
@ -594,8 +594,8 @@ name = "django-filter"
version = "25.2"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "django", version = "5.2.10", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.12'" },
{ name = "django", version = "6.0.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" },
{ name = "django", version = "5.2.11", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.12'" },
{ name = "django", version = "6.0.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/2c/e4/465d2699cd388c0005fb8d6ae6709f239917c6d8790ac35719676fffdcf3/django_filter-25.2.tar.gz", hash = "sha256:760e984a931f4468d096f5541787efb8998c61217b73006163bf2f9523fe8f23", size = 143818, upload-time = "2025-10-05T09:51:31.521Z" }
wheels = [
@ -607,8 +607,8 @@ name = "django-guardian"
version = "3.2.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "django", version = "5.2.10", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.12'" },
{ name = "django", version = "6.0.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" },
{ name = "django", version = "5.2.11", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.12'" },
{ name = "django", version = "6.0.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" },
{ name = "typing-extensions", marker = "python_full_version < '3.13'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/e2/f9/bcff6a931298b9eb55e1550b55ab964fab747f594ba6d2d81cbe19736c5f/django_guardian-3.2.0.tar.gz", hash = "sha256:9e18ecd2e211b665972690c2d03d27bce0ea4932b5efac24a4bb9d526950a69e", size = 99940, upload-time = "2025-09-16T10:35:53.609Z" }
@ -621,8 +621,8 @@ name = "django-polymorphic"
version = "4.11.0"
source = { editable = "." }
dependencies = [
{ name = "django", version = "5.2.10", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.12'" },
{ name = "django", version = "6.0.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" },
{ name = "django", version = "5.2.11", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.12'" },
{ name = "django", version = "6.0.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" },
{ name = "typing-extensions" },
]
@ -752,7 +752,7 @@ dev = [
{ name = "furo", specifier = ">=2025.7.19" },
{ name = "ipdb", specifier = ">=0.13.13" },
{ name = "ipython", specifier = ">=8.18.1" },
{ name = "mypy", specifier = ">=1.14.1" },
{ name = "mypy", specifier = ">=1.19.1" },
{ name = "pre-commit", specifier = ">=3.5.0" },
{ name = "pyright", specifier = ">=1.1.390" },
{ name = "pytest", specifier = ">=8.3.4" },
@ -809,7 +809,7 @@ typing = [
{ name = "django-stubs", specifier = ">=5.1.1" },
{ name = "django-stubs-ext", specifier = ">=5.1.1" },
{ name = "djangorestframework-stubs", specifier = ">=3.16.1" },
{ name = "mypy", specifier = ">=1.14.1" },
{ name = "mypy", specifier = ">=1.19.1" },
{ name = "pyright", specifier = ">=1.1.390" },
]
@ -818,8 +818,8 @@ name = "django-reversion"
version = "6.1.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "django", version = "5.2.10", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.12'" },
{ name = "django", version = "6.0.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" },
{ name = "django", version = "5.2.11", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.12'" },
{ name = "django", version = "6.0.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/9b/8b/72000ad3ba05cb72134f62ad093267e3d83d8fdf1406102d2a1a2ec7d55e/django_reversion-6.1.0.tar.gz", hash = "sha256:31dd7fee02e2a21af7c2d0a61c1c0f27ba07df2317c9a0a3f31d3ee40069025d", size = 76140, upload-time = "2025-12-12T20:23:51.948Z" }
wheels = [
@ -831,8 +831,8 @@ name = "django-stubs"
version = "5.2.9"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "django", version = "5.2.10", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.12'" },
{ name = "django", version = "6.0.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" },
{ name = "django", version = "5.2.11", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.12'" },
{ name = "django", version = "6.0.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" },
{ name = "django-stubs-ext" },
{ name = "tomli", marker = "python_full_version < '3.11'" },
{ name = "types-pyyaml" },
@ -848,8 +848,8 @@ name = "django-stubs-ext"
version = "5.2.9"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "django", version = "5.2.10", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.12'" },
{ name = "django", version = "6.0.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" },
{ name = "django", version = "5.2.11", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.12'" },
{ name = "django", version = "6.0.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" },
{ name = "typing-extensions" },
]
sdist = { url = "https://files.pythonhosted.org/packages/55/03/9c2be939490d2282328db4611bc5956899f5ff7eabc3e88bd4b964a87373/django_stubs_ext-5.2.9.tar.gz", hash = "sha256:6db4054d1580657b979b7d391474719f1a978773e66c7070a5e246cd445a25a9", size = 6497, upload-time = "2026-01-20T23:58:59.462Z" }
@ -874,8 +874,8 @@ name = "djangorestframework"
version = "3.16.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "django", version = "5.2.10", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.12'" },
{ name = "django", version = "6.0.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" },
{ name = "django", version = "5.2.11", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.12'" },
{ name = "django", version = "6.0.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/8a/95/5376fe618646fde6899b3cdc85fd959716bb67542e273a76a80d9f326f27/djangorestframework-3.16.1.tar.gz", hash = "sha256:166809528b1aced0a17dc66c24492af18049f2c9420dbd0be29422029cfc3ff7", size = 1089735, upload-time = "2025-08-06T17:50:53.251Z" }
wheels = [
@ -884,17 +884,16 @@ wheels = [
[[package]]
name = "djangorestframework-stubs"
version = "3.16.7"
version = "3.16.8"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "django-stubs" },
{ name = "types-pyyaml" },
{ name = "types-requests" },
{ name = "typing-extensions" },
]
sdist = { url = "https://files.pythonhosted.org/packages/35/50/889b1121dc0831aa9f6ece8409d41a5f4667da2a963172516841f343fd35/djangorestframework_stubs-3.16.7.tar.gz", hash = "sha256:e53bc346e9950ebdd1bb2bbc19d7e5c8b7acc894e381df55da69248f47ab78ff", size = 32296, upload-time = "2026-01-13T11:42:48.3Z" }
sdist = { url = "https://files.pythonhosted.org/packages/78/d5/87166a827833eb39703856ef957ca0fb4e9d15285331251186a2e738c20c/djangorestframework_stubs-3.16.8.tar.gz", hash = "sha256:f6d464b54fa2f929610e957446c04e6ac29558265418e0a2d9f653a4cdd410b5", size = 32312, upload-time = "2026-02-03T22:35:53.182Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/9e/99/7c969728d66388e22fdaba94e1a9c56490954e2f12f598416e380a53b26d/djangorestframework_stubs-3.16.7-py3-none-any.whl", hash = "sha256:70f80050144875f80ce8ac823ff8628f6e3eb7336495394bb9803251721d9358", size = 56522, upload-time = "2026-01-13T11:42:46.118Z" },
{ url = "https://files.pythonhosted.org/packages/ea/e9/d9c363b08d07d975c21793fe821b2020dfd3627ac4ce19c5c12df94ce9d0/djangorestframework_stubs-3.16.8-py3-none-any.whl", hash = "sha256:c5bf61def0f330a071dd5f470f05710189d06c467b3f3e186b32c5a23d4952fb", size = 56517, upload-time = "2026-02-03T22:35:50.67Z" },
]
[[package]]
@ -1911,28 +1910,27 @@ wheels = [
[[package]]
name = "ruff"
version = "0.14.14"
version = "0.15.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/2e/06/f71e3a86b2df0dfa2d2f72195941cd09b44f87711cb7fa5193732cb9a5fc/ruff-0.14.14.tar.gz", hash = "sha256:2d0f819c9a90205f3a867dbbd0be083bee9912e170fd7d9704cc8ae45824896b", size = 4515732, upload-time = "2026-01-22T22:30:17.527Z" }
sdist = { url = "https://files.pythonhosted.org/packages/c8/39/5cee96809fbca590abea6b46c6d1c586b49663d1d2830a751cc8fc42c666/ruff-0.15.0.tar.gz", hash = "sha256:6bdea47cdbea30d40f8f8d7d69c0854ba7c15420ec75a26f463290949d7f7e9a", size = 4524893, upload-time = "2026-02-03T17:53:35.357Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/d2/89/20a12e97bc6b9f9f68343952da08a8099c57237aef953a56b82711d55edd/ruff-0.14.14-py3-none-linux_armv6l.whl", hash = "sha256:7cfe36b56e8489dee8fbc777c61959f60ec0f1f11817e8f2415f429552846aed", size = 10467650, upload-time = "2026-01-22T22:30:08.578Z" },
{ url = "https://files.pythonhosted.org/packages/a3/b1/c5de3fd2d5a831fcae21beda5e3589c0ba67eec8202e992388e4b17a6040/ruff-0.14.14-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:6006a0082336e7920b9573ef8a7f52eec837add1265cc74e04ea8a4368cd704c", size = 10883245, upload-time = "2026-01-22T22:30:04.155Z" },
{ url = "https://files.pythonhosted.org/packages/b8/7c/3c1db59a10e7490f8f6f8559d1db8636cbb13dccebf18686f4e3c9d7c772/ruff-0.14.14-py3-none-macosx_11_0_arm64.whl", hash = "sha256:026c1d25996818f0bf498636686199d9bd0d9d6341c9c2c3b62e2a0198b758de", size = 10231273, upload-time = "2026-01-22T22:30:34.642Z" },
{ url = "https://files.pythonhosted.org/packages/a1/6e/5e0e0d9674be0f8581d1f5e0f0a04761203affce3232c1a1189d0e3b4dad/ruff-0.14.14-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f666445819d31210b71e0a6d1c01e24447a20b85458eea25a25fe8142210ae0e", size = 10585753, upload-time = "2026-01-22T22:30:31.781Z" },
{ url = "https://files.pythonhosted.org/packages/23/09/754ab09f46ff1884d422dc26d59ba18b4e5d355be147721bb2518aa2a014/ruff-0.14.14-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3c0f18b922c6d2ff9a5e6c3ee16259adc513ca775bcf82c67ebab7cbd9da5bc8", size = 10286052, upload-time = "2026-01-22T22:30:24.827Z" },
{ url = "https://files.pythonhosted.org/packages/c8/cc/e71f88dd2a12afb5f50733851729d6b571a7c3a35bfdb16c3035132675a0/ruff-0.14.14-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1629e67489c2dea43e8658c3dba659edbfd87361624b4040d1df04c9740ae906", size = 11043637, upload-time = "2026-01-22T22:30:13.239Z" },
{ url = "https://files.pythonhosted.org/packages/67/b2/397245026352494497dac935d7f00f1468c03a23a0c5db6ad8fc49ca3fb2/ruff-0.14.14-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:27493a2131ea0f899057d49d303e4292b2cae2bb57253c1ed1f256fbcd1da480", size = 12194761, upload-time = "2026-01-22T22:30:22.542Z" },
{ url = "https://files.pythonhosted.org/packages/5b/06/06ef271459f778323112c51b7587ce85230785cd64e91772034ddb88f200/ruff-0.14.14-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:01ff589aab3f5b539e35db38425da31a57521efd1e4ad1ae08fc34dbe30bd7df", size = 12005701, upload-time = "2026-01-22T22:30:20.499Z" },
{ url = "https://files.pythonhosted.org/packages/41/d6/99364514541cf811ccc5ac44362f88df66373e9fec1b9d1c4cc830593fe7/ruff-0.14.14-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1cc12d74eef0f29f51775f5b755913eb523546b88e2d733e1d701fe65144e89b", size = 11282455, upload-time = "2026-01-22T22:29:59.679Z" },
{ url = "https://files.pythonhosted.org/packages/ca/71/37daa46f89475f8582b7762ecd2722492df26421714a33e72ccc9a84d7a5/ruff-0.14.14-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb8481604b7a9e75eff53772496201690ce2687067e038b3cc31aaf16aa0b974", size = 11215882, upload-time = "2026-01-22T22:29:57.032Z" },
{ url = "https://files.pythonhosted.org/packages/2c/10/a31f86169ec91c0705e618443ee74ede0bdd94da0a57b28e72db68b2dbac/ruff-0.14.14-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:14649acb1cf7b5d2d283ebd2f58d56b75836ed8c6f329664fa91cdea19e76e66", size = 11180549, upload-time = "2026-01-22T22:30:27.175Z" },
{ url = "https://files.pythonhosted.org/packages/fd/1e/c723f20536b5163adf79bdd10c5f093414293cdf567eed9bdb7b83940f3f/ruff-0.14.14-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:e8058d2145566510790eab4e2fad186002e288dec5e0d343a92fe7b0bc1b3e13", size = 10543416, upload-time = "2026-01-22T22:30:01.964Z" },
{ url = "https://files.pythonhosted.org/packages/3e/34/8a84cea7e42c2d94ba5bde1d7a4fae164d6318f13f933d92da6d7c2041ff/ruff-0.14.14-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:e651e977a79e4c758eb807f0481d673a67ffe53cfa92209781dfa3a996cf8412", size = 10285491, upload-time = "2026-01-22T22:30:29.51Z" },
{ url = "https://files.pythonhosted.org/packages/55/ef/b7c5ea0be82518906c978e365e56a77f8de7678c8bb6651ccfbdc178c29f/ruff-0.14.14-py3-none-musllinux_1_2_i686.whl", hash = "sha256:cc8b22da8d9d6fdd844a68ae937e2a0adf9b16514e9a97cc60355e2d4b219fc3", size = 10733525, upload-time = "2026-01-22T22:30:06.499Z" },
{ url = "https://files.pythonhosted.org/packages/6a/5b/aaf1dfbcc53a2811f6cc0a1759de24e4b03e02ba8762daabd9b6bd8c59e3/ruff-0.14.14-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:16bc890fb4cc9781bb05beb5ab4cd51be9e7cb376bf1dd3580512b24eb3fda2b", size = 11315626, upload-time = "2026-01-22T22:30:36.848Z" },
{ url = "https://files.pythonhosted.org/packages/2c/aa/9f89c719c467dfaf8ad799b9bae0df494513fb21d31a6059cb5870e57e74/ruff-0.14.14-py3-none-win32.whl", hash = "sha256:b530c191970b143375b6a68e6f743800b2b786bbcf03a7965b06c4bf04568167", size = 10502442, upload-time = "2026-01-22T22:30:38.93Z" },
{ url = "https://files.pythonhosted.org/packages/87/44/90fa543014c45560cae1fffc63ea059fb3575ee6e1cb654562197e5d16fb/ruff-0.14.14-py3-none-win_amd64.whl", hash = "sha256:3dde1435e6b6fe5b66506c1dff67a421d0b7f6488d466f651c07f4cab3bf20fd", size = 11630486, upload-time = "2026-01-22T22:30:10.852Z" },
{ url = "https://files.pythonhosted.org/packages/9e/6a/40fee331a52339926a92e17ae748827270b288a35ef4a15c9c8f2ec54715/ruff-0.14.14-py3-none-win_arm64.whl", hash = "sha256:56e6981a98b13a32236a72a8da421d7839221fa308b223b9283312312e5ac76c", size = 10920448, upload-time = "2026-01-22T22:30:15.417Z" },
{ url = "https://files.pythonhosted.org/packages/bc/88/3fd1b0aa4b6330d6aaa63a285bc96c9f71970351579152d231ed90914586/ruff-0.15.0-py3-none-linux_armv6l.whl", hash = "sha256:aac4ebaa612a82b23d45964586f24ae9bc23ca101919f5590bdb368d74ad5455", size = 10354332, upload-time = "2026-02-03T17:52:54.892Z" },
{ url = "https://files.pythonhosted.org/packages/72/f6/62e173fbb7eb75cc29fe2576a1e20f0a46f671a2587b5f604bfb0eaf5f6f/ruff-0.15.0-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:dcd4be7cc75cfbbca24a98d04d0b9b36a270d0833241f776b788d59f4142b14d", size = 10767189, upload-time = "2026-02-03T17:53:19.778Z" },
{ url = "https://files.pythonhosted.org/packages/99/e4/968ae17b676d1d2ff101d56dc69cf333e3a4c985e1ec23803df84fc7bf9e/ruff-0.15.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:d747e3319b2bce179c7c1eaad3d884dc0a199b5f4d5187620530adf9105268ce", size = 10075384, upload-time = "2026-02-03T17:53:29.241Z" },
{ url = "https://files.pythonhosted.org/packages/a2/bf/9843c6044ab9e20af879c751487e61333ca79a2c8c3058b15722386b8cae/ruff-0.15.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:650bd9c56ae03102c51a5e4b554d74d825ff3abe4db22b90fd32d816c2e90621", size = 10481363, upload-time = "2026-02-03T17:52:43.332Z" },
{ url = "https://files.pythonhosted.org/packages/55/d9/4ada5ccf4cd1f532db1c8d44b6f664f2208d3d93acbeec18f82315e15193/ruff-0.15.0-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a6664b7eac559e3048223a2da77769c2f92b43a6dfd4720cef42654299a599c9", size = 10187736, upload-time = "2026-02-03T17:53:00.522Z" },
{ url = "https://files.pythonhosted.org/packages/86/e2/f25eaecd446af7bb132af0a1d5b135a62971a41f5366ff41d06d25e77a91/ruff-0.15.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6f811f97b0f092b35320d1556f3353bf238763420ade5d9e62ebd2b73f2ff179", size = 10968415, upload-time = "2026-02-03T17:53:15.705Z" },
{ url = "https://files.pythonhosted.org/packages/e7/dc/f06a8558d06333bf79b497d29a50c3a673d9251214e0d7ec78f90b30aa79/ruff-0.15.0-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:761ec0a66680fab6454236635a39abaf14198818c8cdf691e036f4bc0f406b2d", size = 11809643, upload-time = "2026-02-03T17:53:23.031Z" },
{ url = "https://files.pythonhosted.org/packages/dd/45/0ece8db2c474ad7df13af3a6d50f76e22a09d078af63078f005057ca59eb/ruff-0.15.0-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:940f11c2604d317e797b289f4f9f3fa5555ffe4fb574b55ed006c3d9b6f0eb78", size = 11234787, upload-time = "2026-02-03T17:52:46.432Z" },
{ url = "https://files.pythonhosted.org/packages/8a/d9/0e3a81467a120fd265658d127db648e4d3acfe3e4f6f5d4ea79fac47e587/ruff-0.15.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bcbca3d40558789126da91d7ef9a7c87772ee107033db7191edefa34e2c7f1b4", size = 11112797, upload-time = "2026-02-03T17:52:49.274Z" },
{ url = "https://files.pythonhosted.org/packages/b2/cb/8c0b3b0c692683f8ff31351dfb6241047fa873a4481a76df4335a8bff716/ruff-0.15.0-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:9a121a96db1d75fa3eb39c4539e607f628920dd72ff1f7c5ee4f1b768ac62d6e", size = 11033133, upload-time = "2026-02-03T17:53:33.105Z" },
{ url = "https://files.pythonhosted.org/packages/f8/5e/23b87370cf0f9081a8c89a753e69a4e8778805b8802ccfe175cc410e50b9/ruff-0.15.0-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:5298d518e493061f2eabd4abd067c7e4fb89e2f63291c94332e35631c07c3662", size = 10442646, upload-time = "2026-02-03T17:53:06.278Z" },
{ url = "https://files.pythonhosted.org/packages/e1/9a/3c94de5ce642830167e6d00b5c75aacd73e6347b4c7fc6828699b150a5ee/ruff-0.15.0-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:afb6e603d6375ff0d6b0cee563fa21ab570fd15e65c852cb24922cef25050cf1", size = 10195750, upload-time = "2026-02-03T17:53:26.084Z" },
{ url = "https://files.pythonhosted.org/packages/30/15/e396325080d600b436acc970848d69df9c13977942fb62bb8722d729bee8/ruff-0.15.0-py3-none-musllinux_1_2_i686.whl", hash = "sha256:77e515f6b15f828b94dc17d2b4ace334c9ddb7d9468c54b2f9ed2b9c1593ef16", size = 10676120, upload-time = "2026-02-03T17:53:09.363Z" },
{ url = "https://files.pythonhosted.org/packages/8d/c9/229a23d52a2983de1ad0fb0ee37d36e0257e6f28bfd6b498ee2c76361874/ruff-0.15.0-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:6f6e80850a01eb13b3e42ee0ebdf6e4497151b48c35051aab51c101266d187a3", size = 11201636, upload-time = "2026-02-03T17:52:57.281Z" },
{ url = "https://files.pythonhosted.org/packages/6f/b0/69adf22f4e24f3677208adb715c578266842e6e6a3cc77483f48dd999ede/ruff-0.15.0-py3-none-win32.whl", hash = "sha256:238a717ef803e501b6d51e0bdd0d2c6e8513fe9eec14002445134d3907cd46c3", size = 10465945, upload-time = "2026-02-03T17:53:12.591Z" },
{ url = "https://files.pythonhosted.org/packages/51/ad/f813b6e2c97e9b4598be25e94a9147b9af7e60523b0cb5d94d307c15229d/ruff-0.15.0-py3-none-win_amd64.whl", hash = "sha256:dd5e4d3301dc01de614da3cdffc33d4b1b96fb89e45721f1598e5532ccf78b18", size = 11564657, upload-time = "2026-02-03T17:52:51.893Z" },
{ url = "https://files.pythonhosted.org/packages/f6/b0/2d823f6e77ebe560f4e397d078487e8d52c1516b331e3521bc75db4272ca/ruff-0.15.0-py3-none-win_arm64.whl", hash = "sha256:c480d632cc0ca3f0727acac8b7d053542d9e114a462a145d0b00e7cd658c515a", size = 10865753, upload-time = "2026-02-03T17:53:03.014Z" },
]
[[package]]
@ -2125,8 +2123,8 @@ name = "sphinxcontrib-django"
version = "2.5"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "django", version = "5.2.10", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.12'" },
{ name = "django", version = "6.0.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" },
{ name = "django", version = "5.2.11", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.12'" },
{ name = "django", version = "6.0.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" },
{ name = "pprintpp" },
{ name = "sphinx", version = "8.1.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
{ name = "sphinx", version = "9.0.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.11.*'" },
@ -2308,18 +2306,6 @@ 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-requests"
version = "2.32.4.20260107"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "urllib3" },
]
sdist = { url = "https://files.pythonhosted.org/packages/0f/f3/a0663907082280664d745929205a89d41dffb29e89a50f753af7d57d0a96/types_requests-2.32.4.20260107.tar.gz", hash = "sha256:018a11ac158f801bfa84857ddec1650750e393df8a004a8a9ae2a9bec6fcb24f", size = 23165, upload-time = "2026-01-07T03:20:54.091Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/1c/12/709ea261f2bf91ef0a26a9eed20f2623227a8ed85610c1e54c5805692ecb/types_requests-2.32.4.20260107-py3-none-any.whl", hash = "sha256:b703fe72f8ce5b31ef031264fe9395cac8f46a04661a79f7ed31a80fb308730d", size = 20676, upload-time = "2026-01-07T03:20:52.929Z" },
]
[[package]]
name = "typing-extensions"
version = "4.15.0"