diff --git a/mypy.ini b/mypy.ini new file mode 100644 index 00000000..9d814c8b --- /dev/null +++ b/mypy.ini @@ -0,0 +1,36 @@ +[mypy] +# The mypy configurations: https://mypy.readthedocs.io/en/latest/config_file.html +python_version = 3.10 + +check_untyped_defs = True +disallow_any_generics = True +disallow_untyped_calls = True +disallow_untyped_decorators = True +ignore_errors = False +ignore_missing_imports = True +implicit_reexport = False +strict_optional = True +strict_equality = True +no_implicit_optional = True +warn_unused_ignores = True +warn_redundant_casts = True +warn_unused_configs = True +warn_unreachable = True +warn_no_return = True +show_error_codes = True + +plugins = + mypy_django_plugin.main + +[mypy.plugins.django-stubs] +django_settings_module = polymorphic.tests.settings + +[mypy-polymorphic.*] +ignore_missing_imports = True + +[mypy-*.migrations.*] +# Django migrations should not produce any errors: +ignore_errors = True + +[mypy-tests.*] +ignore_errors = True diff --git a/pyproject.toml b/pyproject.toml index 818b221a..fc0406bf 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -50,6 +50,7 @@ classifiers = [ ] dependencies = [ "Django >= 4.2", + ] [project.urls] @@ -146,6 +147,7 @@ show_missing = true dev = [ "coverage>=7.6.1", "dj-database-url>=2.2.0", + "django-stubs>=5.2.8", "django-test-migrations>=1.5.0", "ipdb>=0.13.13", "ipython>=8.18.1", diff --git a/src/polymorphic/__init__.pyi b/src/polymorphic/__init__.pyi new file mode 100644 index 00000000..4f46ad79 --- /dev/null +++ b/src/polymorphic/__init__.pyi @@ -0,0 +1,6 @@ +VERSION: str +__version__ = VERSION +__title__ = str +__author__ = str +__license__ = str +__copyright__ = str diff --git a/src/polymorphic/admin/__init__.pyi b/src/polymorphic/admin/__init__.pyi new file mode 100644 index 00000000..fddb52c9 --- /dev/null +++ b/src/polymorphic/admin/__init__.pyi @@ -0,0 +1,25 @@ +from .childadmin import PolymorphicChildModelAdmin as PolymorphicChildModelAdmin +from .filters import PolymorphicChildModelFilter as PolymorphicChildModelFilter +from .forms import PolymorphicModelChoiceForm as PolymorphicModelChoiceForm +from .generic import GenericPolymorphicInlineModelAdmin as GenericPolymorphicInlineModelAdmin +from .generic import GenericStackedPolymorphicInline as GenericStackedPolymorphicInline +from .helpers import PolymorphicInlineAdminForm as PolymorphicInlineAdminForm +from .helpers import PolymorphicInlineAdminFormSet as PolymorphicInlineAdminFormSet +from .helpers import PolymorphicInlineSupportMixin as PolymorphicInlineSupportMixin +from .inlines import PolymorphicInlineModelAdmin as PolymorphicInlineModelAdmin +from .inlines import StackedPolymorphicInline as StackedPolymorphicInline +from .parentadmin import PolymorphicParentModelAdmin as PolymorphicParentModelAdmin + +__all__ = [ + "PolymorphicParentModelAdmin", + "PolymorphicChildModelAdmin", + "PolymorphicModelChoiceForm", + "PolymorphicChildModelFilter", + "PolymorphicInlineAdminForm", + "PolymorphicInlineAdminFormSet", + "PolymorphicInlineSupportMixin", + "PolymorphicInlineModelAdmin", + "StackedPolymorphicInline", + "GenericPolymorphicInlineModelAdmin", + "GenericStackedPolymorphicInline", +] diff --git a/src/polymorphic/admin/childadmin.pyi b/src/polymorphic/admin/childadmin.pyi new file mode 100644 index 00000000..7c5b73e5 --- /dev/null +++ b/src/polymorphic/admin/childadmin.pyi @@ -0,0 +1,53 @@ +from typing import Any, ClassVar, Sequence + +from django.contrib import admin +from django_stubs.db import models +from django_stubs.forms import ModelForm +from django_stubs.http import HttpRequest, HttpResponse + +from polymorphic.utils import get_base_polymorphic_model as get_base_polymorphic_model + +from ..admin import PolymorphicParentModelAdmin as PolymorphicParentModelAdmin + +class ParentAdminNotRegistered(RuntimeError): ... + +class PolymorphicChildModelAdmin(admin.ModelAdmin[Any]): + base_model: type[models.Model] | None + base_form: type[ModelForm[Any]] | None + base_fieldsets: list[tuple[str | None, dict[str, Any]]] | None + extra_fieldset_title: str + show_in_index: bool + def __init__( + self, model: type[models.Model], admin_site: Any, *args: Any, **kwargs: Any + ) -> None: ... + def get_form( + self, request: HttpRequest, obj: Any = None, change: bool = False, **kwargs: Any + ) -> type[ModelForm[Any]]: ... + def get_model_perms(self, request: HttpRequest) -> dict[str, bool]: ... + change_form_template: ClassVar[str] + delete_confirmation_template: ClassVar[str] + object_history_template: ClassVar[str] + def response_post_save_add(self, request: HttpRequest, obj: Any) -> HttpResponse: ... + def response_post_save_change(self, request: HttpRequest, obj: Any) -> HttpResponse: ... + def render_change_form( + self, + request: HttpRequest, + context: Any, + add: bool = False, + change: bool = False, + form_url: str = "", + obj: Any = None, + ) -> HttpResponse: ... + def delete_view( + self, request: HttpRequest, object_id: str, context: Any = None + ) -> HttpResponse: ... + def history_view( + self, request: HttpRequest, object_id: str, extra_context: Any = None + ) -> HttpResponse: ... + def get_base_fieldsets( + self, request: HttpRequest, obj: Any = None + ) -> list[tuple[str | None, dict[str, Any]]]: ... + def get_fieldsets(self, request: HttpRequest, obj: Any = None) -> list[Any]: ... + def get_subclass_fields( + self, request: HttpRequest, obj: Any = None + ) -> Sequence[str] | list[str]: ... diff --git a/src/polymorphic/admin/filters.pyi b/src/polymorphic/admin/filters.pyi new file mode 100644 index 00000000..27bdbe82 --- /dev/null +++ b/src/polymorphic/admin/filters.pyi @@ -0,0 +1,11 @@ +from typing import Any + +from django.contrib import admin +from django_stubs.db.models.query import QuerySet +from django_stubs.http import HttpRequest + +class PolymorphicChildModelFilter(admin.SimpleListFilter): + title: str + parameter_name: str + def lookups(self, request: HttpRequest, model_admin): ... + def queryset(self, request: HttpRequest, queryset: QuerySet[Any]): ... diff --git a/src/polymorphic/admin/forms.pyi b/src/polymorphic/admin/forms.pyi new file mode 100644 index 00000000..8b4cab5c --- /dev/null +++ b/src/polymorphic/admin/forms.pyi @@ -0,0 +1,7 @@ +from _typeshed import Incomplete +from django_stubs import forms + +class PolymorphicModelChoiceForm(forms.Form): + type_label: str + ct_id: Incomplete + def __init__(self, *args, **kwargs) -> None: ... diff --git a/src/polymorphic/admin/generic.pyi b/src/polymorphic/admin/generic.pyi new file mode 100644 index 00000000..94064bc3 --- /dev/null +++ b/src/polymorphic/admin/generic.pyi @@ -0,0 +1,33 @@ +from typing import Any + +from django.utils.functional import cached_property as cached_property +from django_stubs.contrib.contenttypes.admin import GenericInlineModelAdmin +from django_stubs.contrib.contenttypes.models import ContentType +from django_stubs.forms.models import BaseInlineFormSet +from django_stubs.http import HttpRequest + +from polymorphic.formsets import ( + BaseGenericPolymorphicInlineFormSet as BaseGenericPolymorphicInlineFormSet, +) +from polymorphic.formsets import GenericPolymorphicFormSetChild as GenericPolymorphicFormSetChild +from polymorphic.formsets import polymorphic_child_forms_factory as polymorphic_child_forms_factory + +from .inlines import PolymorphicInlineModelAdmin as PolymorphicInlineModelAdmin + +class GenericPolymorphicInlineModelAdmin(PolymorphicInlineModelAdmin, GenericInlineModelAdmin): + formset: Any = BaseGenericPolymorphicInlineFormSet + def get_formset( + self, request: HttpRequest, obj: Any = None, **kwargs: Any + ) -> type[BaseInlineFormSet[Any, Any, Any]]: ... + class Child(PolymorphicInlineModelAdmin.Child): + formset_child = GenericPolymorphicFormSetChild + ct_field: str + ct_fk_field: str + @cached_property + def content_type(self) -> ContentType: ... + def get_formset_child( + self, request: HttpRequest, obj: Any = None, **kwargs: Any + ) -> GenericPolymorphicFormSetChild: ... + +class GenericStackedPolymorphicInline(GenericPolymorphicInlineModelAdmin): + template: str diff --git a/src/polymorphic/admin/helpers.pyi b/src/polymorphic/admin/helpers.pyi new file mode 100644 index 00000000..44166802 --- /dev/null +++ b/src/polymorphic/admin/helpers.pyi @@ -0,0 +1,24 @@ +from _typeshed import Incomplete +from django_stubs.contrib.admin.helpers import InlineAdminForm, InlineAdminFormSet + +from polymorphic.formsets import BasePolymorphicModelFormSet as BasePolymorphicModelFormSet + +class PolymorphicInlineAdminForm(InlineAdminForm): + def polymorphic_ctype_field(self): ... + @property + def is_empty(self): ... + +class PolymorphicInlineAdminFormSet(InlineAdminFormSet): + request: Incomplete + obj: Incomplete + def __init__(self, *args, **kwargs) -> None: ... + def __iter__(self): ... + def get_child_fieldsets(self, child_inline): ... + def get_child_readonly_fields(self, child_inline): ... + def get_child_prepopulated_fields(self, child_inline): ... + def inline_formset_data(self): ... + +class PolymorphicInlineSupportMixin: + def get_inline_formsets( + self, request, formsets, inline_instances, obj=None, *args, **kwargs + ): ... diff --git a/src/polymorphic/admin/inlines.pyi b/src/polymorphic/admin/inlines.pyi new file mode 100644 index 00000000..900b80e4 --- /dev/null +++ b/src/polymorphic/admin/inlines.pyi @@ -0,0 +1,51 @@ +from typing import Any, Sequence + +from django_stubs.contrib.admin.options import InlineModelAdmin +from django_stubs.db import models +from django_stubs.forms import Media +from django_stubs.forms.models import BaseInlineFormSet +from django_stubs.http import HttpRequest + +from polymorphic.formsets import BasePolymorphicInlineFormSet as BasePolymorphicInlineFormSet +from polymorphic.formsets import PolymorphicFormSetChild as PolymorphicFormSetChild +from polymorphic.formsets import UnsupportedChildType as UnsupportedChildType +from polymorphic.formsets import polymorphic_child_forms_factory as polymorphic_child_forms_factory +from polymorphic.formsets.utils import add_media as add_media + +from .helpers import PolymorphicInlineSupportMixin as PolymorphicInlineSupportMixin + +class PolymorphicInlineModelAdmin(InlineModelAdmin[Any, Any]): + formset: type[BaseInlineFormSet[Any, Any, Any]] + polymorphic_media: Media + extra: int + child_inlines: Sequence[type[PolymorphicInlineModelAdmin.Child]] + child_inline_instances: list[PolymorphicInlineModelAdmin.Child] + def __init__(self, parent_model: type[models.Model], admin_site: Any) -> None: ... + def get_child_inlines(self) -> Sequence[type[PolymorphicInlineModelAdmin.Child]]: ... + def get_child_inline_instances(self) -> list[PolymorphicInlineModelAdmin.Child]: ... + def get_child_inline_instance( + self, model: type[models.Model] + ) -> PolymorphicInlineModelAdmin.Child: ... + def get_formset( + self, request: HttpRequest, obj: Any = None, **kwargs: Any + ) -> type[BaseInlineFormSet[Any, Any, Any]]: ... + def get_formset_children( + self, request: HttpRequest, obj: Any = None + ) -> list[PolymorphicFormSetChild]: ... + def get_fieldsets(self, request: HttpRequest, obj: Any = None) -> list[Any]: ... + def get_fields(self, request: HttpRequest, obj: Any = None) -> Any: ... + @property + def media(self) -> Media: ... + class Child(InlineModelAdmin[Any, Any]): + formset_child = PolymorphicFormSetChild + extra: int + parent_inline: PolymorphicInlineModelAdmin + def __init__(self, parent_inline: PolymorphicInlineModelAdmin) -> None: ... + def get_formset(self, request: HttpRequest, obj: Any = None, **kwargs: Any) -> Any: ... + def get_fields(self, request: HttpRequest, obj: Any = None) -> Any: ... + def get_formset_child( + self, request: HttpRequest, obj: Any = None, **kwargs: Any + ) -> PolymorphicFormSetChild: ... + +class StackedPolymorphicInline(PolymorphicInlineModelAdmin): + template: str diff --git a/src/polymorphic/admin/parentadmin.pyi b/src/polymorphic/admin/parentadmin.pyi new file mode 100644 index 00000000..6105999e --- /dev/null +++ b/src/polymorphic/admin/parentadmin.pyi @@ -0,0 +1,58 @@ +from typing import Any, ClassVar, Sequence + +from django_stubs.contrib import admin +from django_stubs.db.models import Model +from django_stubs.db.models.query import QuerySet +from django_stubs.forms import ModelForm +from django_stubs.http import HttpRequest, HttpResponse + +from polymorphic.utils import get_base_polymorphic_model as get_base_polymorphic_model + +from .forms import PolymorphicModelChoiceForm as PolymorphicModelChoiceForm + +class RegistrationClosed(RuntimeError): ... +class ChildAdminNotRegistered(RuntimeError): ... + +class PolymorphicParentModelAdmin(admin.ModelAdmin[Any]): + base_model: type[Model] | None + child_models: Sequence[type[Model]] | None + polymorphic_list: bool + add_type_template: str | None + add_type_form: type[ModelForm[Any]] + pk_regex: str + def __init__(self, model: type[Model], admin_site: Any, *args: Any, **kwargs: Any) -> None: ... + def register_child( + self, model: type[Model], model_admin: type[admin.ModelAdmin[Any]] + ) -> None: ... + def get_child_models(self) -> Sequence[type[Model]]: ... + def get_child_type_choices( + self, request: HttpRequest, action: str + ) -> list[tuple[str, str]]: ... + def get_queryset(self, request: HttpRequest) -> QuerySet[Any]: ... + def add_view( + self, request: HttpRequest, form_url: str = "", extra_context: Any = None + ) -> HttpResponse: ... + def change_view( + self, request: HttpRequest, object_id: str, *args: Any, **kwargs: Any + ) -> HttpResponse: ... + def changeform_view( + self, + request: HttpRequest, + object_id: str | None = None, + *args: Any, + **kwargs: Any, + ) -> HttpResponse: ... + def history_view( + self, request: HttpRequest, object_id: str, extra_context: Any = None + ) -> HttpResponse: ... + def delete_view( + self, request: HttpRequest, object_id: str, extra_context: Any = None + ) -> HttpResponse: ... + def get_preserved_filters(self, request: HttpRequest) -> str: ... + def get_urls(self) -> list[Any]: ... + def subclass_view(self, request: HttpRequest, path: str) -> HttpResponse: ... + def add_type_view(self, request: HttpRequest, form_url: str = "") -> HttpResponse: ... + def render_add_type_form( + self, request: HttpRequest, context: Any, form_url: str = "" + ) -> HttpResponse: ... + change_list_template: ClassVar[str] diff --git a/src/polymorphic/apps.pyi b/src/polymorphic/apps.pyi new file mode 100644 index 00000000..8976d67f --- /dev/null +++ b/src/polymorphic/apps.pyi @@ -0,0 +1,11 @@ +from typing import Any + +from django_stubs.apps import AppConfig + +def check_reserved_field_names( + app_configs: list[type[AppConfig]] | None, **kwargs +) -> list[Any]: ... + +class PolymorphicConfig(AppConfig): + ignored_models: list[Any] + verbose_name: str diff --git a/src/polymorphic/base.pyi b/src/polymorphic/base.pyi new file mode 100644 index 00000000..c5870747 --- /dev/null +++ b/src/polymorphic/base.pyi @@ -0,0 +1,22 @@ +from typing import Any + +from django.db.models.base import ModelBase + +from .managers import PolymorphicManager as PolymorphicManager +from .query import PolymorphicQuerySet as PolymorphicQuerySet + +POLYMORPHIC_SPECIAL_Q_KWORDS: set[str] +DUMPDATA_COMMAND: str + +class ManagerInheritanceWarning(RuntimeWarning): ... + +class PolymorphicModelBase(ModelBase): + def __new__( + cls, model_name: str, bases: tuple[type, ...], attrs: dict[str, Any], **kwargs: Any + ): ... + @classmethod + def validate_model_manager( + cls, manager: PolymorphicManager[Any], model_name: str, manager_name: str + ): ... + @property + def base_objects(self) -> PolymorphicManager[Any]: ... diff --git a/src/polymorphic/contrib/__init__.pyi b/src/polymorphic/contrib/__init__.pyi new file mode 100644 index 00000000..e69de29b diff --git a/src/polymorphic/contrib/extra_views.pyi b/src/polymorphic/contrib/extra_views.pyi new file mode 100644 index 00000000..a8c20899 --- /dev/null +++ b/src/polymorphic/contrib/extra_views.pyi @@ -0,0 +1,23 @@ +import extra_views +from _typeshed import Incomplete + +from polymorphic.formsets import BasePolymorphicInlineFormSet, BasePolymorphicModelFormSet + +__all__ = ["PolymorphicFormSetView", "PolymorphicInlineFormSetView", "PolymorphicInlineFormSet"] + +class PolymorphicFormSetMixin: + formset_class = BasePolymorphicModelFormSet + factory_kwargs: Incomplete + formset_children: Incomplete + def get_formset_children(self): ... + def get_formset_child_kwargs(self): ... + def get_formset(self): ... + +class PolymorphicFormSetView(PolymorphicFormSetMixin, extra_views.ModelFormSetView): + formset_class = BasePolymorphicModelFormSet + +class PolymorphicInlineFormSetView(PolymorphicFormSetMixin, extra_views.InlineFormSetView): + formset_class = BasePolymorphicInlineFormSet + +class PolymorphicInlineFormSet(PolymorphicFormSetMixin, extra_views.InlineFormSetFactory): + formset_class = BasePolymorphicInlineFormSet diff --git a/src/polymorphic/contrib/guardian.pyi b/src/polymorphic/contrib/guardian.pyi new file mode 100644 index 00000000..28d49b7c --- /dev/null +++ b/src/polymorphic/contrib/guardian.pyi @@ -0,0 +1 @@ +def get_polymorphic_base_content_type(obj): ... diff --git a/src/polymorphic/formsets/__init__.pyi b/src/polymorphic/formsets/__init__.pyi new file mode 100644 index 00000000..e7c15698 --- /dev/null +++ b/src/polymorphic/formsets/__init__.pyi @@ -0,0 +1,25 @@ +from .generic import BaseGenericPolymorphicInlineFormSet as BaseGenericPolymorphicInlineFormSet +from .generic import GenericPolymorphicFormSetChild as GenericPolymorphicFormSetChild +from .generic import ( + generic_polymorphic_inlineformset_factory as generic_polymorphic_inlineformset_factory, +) +from .models import BasePolymorphicInlineFormSet as BasePolymorphicInlineFormSet +from .models import BasePolymorphicModelFormSet as BasePolymorphicModelFormSet +from .models import PolymorphicFormSetChild as PolymorphicFormSetChild +from .models import UnsupportedChildType as UnsupportedChildType +from .models import polymorphic_child_forms_factory as polymorphic_child_forms_factory +from .models import polymorphic_inlineformset_factory as polymorphic_inlineformset_factory +from .models import polymorphic_modelformset_factory as polymorphic_modelformset_factory + +__all__ = [ + "BasePolymorphicModelFormSet", + "BasePolymorphicInlineFormSet", + "PolymorphicFormSetChild", + "UnsupportedChildType", + "polymorphic_modelformset_factory", + "polymorphic_inlineformset_factory", + "polymorphic_child_forms_factory", + "BaseGenericPolymorphicInlineFormSet", + "GenericPolymorphicFormSetChild", + "generic_polymorphic_inlineformset_factory", +] diff --git a/src/polymorphic/formsets/generic.pyi b/src/polymorphic/formsets/generic.pyi new file mode 100644 index 00000000..85ebbf8a --- /dev/null +++ b/src/polymorphic/formsets/generic.pyi @@ -0,0 +1,39 @@ +from typing import Any + +from _typeshed import Incomplete +from django_stubs.contrib.contenttypes.forms import BaseGenericInlineFormSet + +from .models import BasePolymorphicModelFormSet as BasePolymorphicModelFormSet +from .models import PolymorphicFormSetChild as PolymorphicFormSetChild +from .models import polymorphic_child_forms_factory as polymorphic_child_forms_factory + +class GenericPolymorphicFormSetChild(PolymorphicFormSetChild): + ct_field: Incomplete + fk_field: Incomplete + def __init__(self, *args, **kwargs) -> None: ... + def get_form(self, ct_field: str = "content_type", fk_field: str = "object_id", **kwargs): ... + +class BaseGenericPolymorphicInlineFormSet( + BaseGenericInlineFormSet[Any, Any], BasePolymorphicModelFormSet +): ... + +def generic_polymorphic_inlineformset_factory( + model, + formset_children, + form=..., + formset=..., + ct_field: str = "content_type", + fk_field: str = "object_id", + fields=None, + exclude=None, + extra: int = 1, + can_order: bool = False, + can_delete: bool = True, + max_num=None, + formfield_callback=None, + validate_max: bool = False, + for_concrete_model: bool = True, + min_num=None, + validate_min: bool = False, + child_form_kwargs=None, +): ... diff --git a/src/polymorphic/formsets/models.pyi b/src/polymorphic/formsets/models.pyi new file mode 100644 index 00000000..f1c12b80 --- /dev/null +++ b/src/polymorphic/formsets/models.pyi @@ -0,0 +1,108 @@ +from typing import Any + +from _typeshed import Incomplete +from django_stubs.forms.models import BaseInlineFormSet, BaseModelFormSet +from django_stubs.utils.functional import cached_property as cached_property + +from polymorphic.models import PolymorphicModel as PolymorphicModel + +from .utils import add_media as add_media + +class UnsupportedChildType(LookupError): ... + +class PolymorphicFormSetChild: + model: Incomplete + fields: Incomplete + exclude: Incomplete + formfield_callback: Incomplete + widgets: Incomplete + localized_fields: Incomplete + labels: Incomplete + help_texts: Incomplete + error_messages: Incomplete + def __init__( + self, + model, + form=..., + fields=None, + exclude=None, + formfield_callback=None, + widgets=None, + localized_fields=None, + labels=None, + help_texts=None, + error_messages=None, + ) -> None: ... + @cached_property + def content_type(self): ... + def get_form(self, **kwargs): ... + +def polymorphic_child_forms_factory(formset_children, **kwargs): ... + +class BasePolymorphicModelFormSet(BaseModelFormSet[Any, Any]): + child_forms: Incomplete + queryset_data: Incomplete + def __init__(self, *args, **kwargs) -> None: ... + def add_fields(self, form, index) -> None: ... + def get_form_class(self, model): ... + def is_multipart(self): ... + @property + def media(self): ... + @cached_property + def empty_forms(self): ... + @property + def empty_form(self) -> None: ... + +def polymorphic_modelformset_factory( + model, + formset_children, + formset=..., + form=..., + fields=None, + exclude=None, + extra: int = 1, + can_order: bool = False, + can_delete: bool = True, + max_num=None, + formfield_callback=None, + widgets=None, + validate_max: bool = False, + localized_fields=None, + labels=None, + help_texts=None, + error_messages=None, + min_num=None, + validate_min: bool = False, + field_classes=None, + child_form_kwargs=None, +): ... + +class BasePolymorphicInlineFormSet( + BaseInlineFormSet[Any, Any, Any], BasePolymorphicModelFormSet +): ... + +def polymorphic_inlineformset_factory( + parent_model, + model, + formset_children, + formset=..., + fk_name=None, + form=..., + fields=None, + exclude=None, + extra: int = 1, + can_order: bool = False, + can_delete: bool = True, + max_num=None, + formfield_callback=None, + widgets=None, + validate_max: bool = False, + localized_fields=None, + labels=None, + help_texts=None, + error_messages=None, + min_num=None, + validate_min: bool = False, + field_classes=None, + child_form_kwargs=None, +): ... diff --git a/src/polymorphic/formsets/utils.pyi b/src/polymorphic/formsets/utils.pyi new file mode 100644 index 00000000..2b7ef10d --- /dev/null +++ b/src/polymorphic/formsets/utils.pyi @@ -0,0 +1 @@ +def add_media(dest, media) -> None: ... diff --git a/src/polymorphic/managers.pyi b/src/polymorphic/managers.pyi new file mode 100644 index 00000000..b15aecd0 --- /dev/null +++ b/src/polymorphic/managers.pyi @@ -0,0 +1,21 @@ +from typing import Any, TypeVar + +from django_stubs.db.models import Manager, Model +from django_stubs.query import QuerySet + +from polymorphic.query import PolymorphicQuerySet + +_M = TypeVar("_M", bound=Model) + +class PolymorphicManager(Manager[_M]): + queryset_class: type[PolymorphicQuerySet[_M]] + @classmethod + def from_queryset( + cls, queryset_class: type[QuerySet], class_name: str | None = None + ) -> Any: ... + def get_queryset(self) -> PolymorphicQuerySet[_M]: ... + def non_polymorphic(self) -> PolymorphicQuerySet[_M]: ... + def instance_of(self, *args: type[Model]) -> PolymorphicQuerySet[_M]: ... + def not_instance_of(self, *args: type[Model]) -> PolymorphicQuerySet[_M]: ... + def get_real_instances(self, base_result_objects: Any = None) -> list[_M]: ... + def create_from_super(self, obj: Model, **kwargs: Any) -> _M: ... diff --git a/src/polymorphic/models.pyi b/src/polymorphic/models.pyi new file mode 100644 index 00000000..ad812b6e --- /dev/null +++ b/src/polymorphic/models.pyi @@ -0,0 +1,30 @@ +from typing import Any, ClassVar + +from django.contrib.contenttypes.models import ContentType +from django.db import models + +from .base import PolymorphicModelBase as PolymorphicModelBase +from .managers import PolymorphicManager as PolymorphicManager + +class PolymorphicTypeUndefined(LookupError): ... +class PolymorphicTypeInvalid(RuntimeError): ... + +class PolymorphicModel(models.Model, metaclass=PolymorphicModelBase): + polymorphic_model_marker: bool + polymorphic_query_multiline_output: bool + polymorphic_ctype: models.ForeignKey[ContentType] + polymorphic_internal_model_fields: list[str] + objects: PolymorphicManager[Any] + class Meta: + abstract = True + base_manager_name: ClassVar[str] + + @classmethod + def translate_polymorphic_Q_object(cls, q: models.Q) -> models.Q: ... + def pre_save_polymorphic(self, using: str = ...) -> None: ... + def save(self, *args: Any, **kwargs: Any) -> None: ... + def get_real_instance_class(self) -> type[PolymorphicModel] | None: ... + def get_real_concrete_instance_class_id(self) -> int | None: ... + def get_real_concrete_instance_class(self) -> type[PolymorphicModel] | None: ... + def get_real_instance(self) -> PolymorphicModel: ... + def __init__(self, *args: Any, **kwargs: Any) -> None: ... diff --git a/src/polymorphic/query.py b/src/polymorphic/query.py index 30f1dd86..53cbb333 100644 --- a/src/polymorphic/query.py +++ b/src/polymorphic/query.py @@ -260,6 +260,9 @@ def _polymorphic_add_immediate_loading(self, field_names): field_names.remove("pk") field_names.add(self.model._meta.pk.name) + if self.model.polymorphic_ctype_id: + field_names.add(self.model.polymorphic_ctype.field.name) + if defer: # Remove any existing deferred names from the current set before # setting the new names. diff --git a/src/polymorphic/query.pyi b/src/polymorphic/query.pyi new file mode 100644 index 00000000..4a727e42 --- /dev/null +++ b/src/polymorphic/query.pyi @@ -0,0 +1,43 @@ +from typing import Any, Iterator, TypeVar + +from django.db.models import Model +from django_stubs.query import ModelIterable, QuerySet + +from .query_translate import translate_polymorphic_field_path as translate_polymorphic_field_path +from .query_translate import ( + translate_polymorphic_filter_definitions_in_args as translate_polymorphic_filter_definitions_in_args, +) +from .query_translate import ( + translate_polymorphic_filter_definitions_in_kwargs as translate_polymorphic_filter_definitions_in_kwargs, +) +from .query_translate import translate_polymorphic_Q_object as translate_polymorphic_Q_object + +Polymorphic_QuerySet_objects_per_request: int + +_M = TypeVar("_M", bound=Model) + +class PolymorphicModelIterable(ModelIterable): + def __iter__(self) -> Iterator[Any]: ... + +def transmogrify(cls: type[_M], obj: Any) -> _M: ... + +class PolymorphicQuerySet(QuerySet[_M]): + polymorphic_disabled: bool + polymorphic_deferred_loading: tuple[set[str], bool] + def __init__(self, *args: Any, **kwargs: Any) -> None: ... + @classmethod + def as_manager(cls) -> Any: ... + def bulk_create( + self, objs: Any, batch_size: int | None = None, ignore_conflicts: bool = False + ) -> list[_M]: ... + def non_polymorphic(self) -> PolymorphicQuerySet[_M]: ... + def instance_of(self, *args: type[Model]) -> PolymorphicQuerySet[_M]: ... + def not_instance_of(self, *args: type[Model]) -> PolymorphicQuerySet[_M]: ... + def order_by(self, *field_names: Any) -> PolymorphicQuerySet[_M]: ... + def defer(self, *fields: Any) -> PolymorphicQuerySet[_M]: ... + def only(self, *fields: Any) -> PolymorphicQuerySet[_M]: ... + def annotate(self, *args: Any, **kwargs: Any) -> PolymorphicQuerySet[_M]: ... + def aggregate(self, *args: Any, **kwargs: Any) -> dict[str, Any]: ... + class _p_list_class(list[Any]): ... + + def get_real_instances(self, base_result_objects: Any = None) -> list[_M]: ... diff --git a/src/polymorphic/query_translate.pyi b/src/polymorphic/query_translate.pyi new file mode 100644 index 00000000..04452fe8 --- /dev/null +++ b/src/polymorphic/query_translate.pyi @@ -0,0 +1,20 @@ +from typing import Any, Iterable + +from django.db import models +from django.db.models import Model + +def translate_polymorphic_filter_definitions_in_kwargs( + queryset_model: type[Model], kwargs: dict[str, Any], using: str = ... +) -> list[models.Q]: ... +def translate_polymorphic_Q_object( + queryset_model: type[Model], potential_q_object: models.Q, using: str = ... +) -> models.Q: ... +def translate_polymorphic_filter_definitions_in_args( + queryset_model: type[Model], args: Iterable[Any], using: str = ... +) -> list[models.Q]: ... +def translate_polymorphic_field_path(queryset_model: type[Model], field_path: str) -> str: ... +def create_instanceof_q( + modellist: Iterable[type[Model]] | type[Model], + not_instance_of: bool = False, + using: str = ..., +) -> models.Q | None: ... diff --git a/src/polymorphic/showfields.pyi b/src/polymorphic/showfields.pyi new file mode 100644 index 00000000..746c31d9 --- /dev/null +++ b/src/polymorphic/showfields.pyi @@ -0,0 +1,22 @@ +from typing import Pattern + +RE_DEFERRED: Pattern[str] + +class ShowFieldBase: + polymorphic_query_multiline_output: bool + polymorphic_showfield_type: bool + polymorphic_showfield_content: bool + polymorphic_showfield_deferred: bool + polymorphic_showfield_max_line_width: None | int + polymorphic_showfield_max_field_width: int + polymorphic_showfield_old_format: bool + +class ShowFieldType(ShowFieldBase): + polymorphic_showfield_type: bool + +class ShowFieldContent(ShowFieldBase): + polymorphic_showfield_content: bool + +class ShowFieldTypeAndContent(ShowFieldBase): + polymorphic_showfield_type: bool + polymorphic_showfield_content: bool diff --git a/src/polymorphic/templatetags/__init__.pyi b/src/polymorphic/templatetags/__init__.pyi new file mode 100644 index 00000000..e69de29b diff --git a/src/polymorphic/templatetags/polymorphic_admin_tags.pyi b/src/polymorphic/templatetags/polymorphic_admin_tags.pyi new file mode 100644 index 00000000..0ace9ea4 --- /dev/null +++ b/src/polymorphic/templatetags/polymorphic_admin_tags.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete +from django.template import Node + +register: Incomplete + +class BreadcrumbScope(Node): + base_opts: Incomplete + nodelist: Incomplete + def __init__(self, base_opts, nodelist) -> None: ... + @classmethod + def parse(cls, parser, token): ... + def render(self, context): ... + +@register.tag +def breadcrumb_scope(parser, token): ... diff --git a/src/polymorphic/templatetags/polymorphic_formset_tags.pyi b/src/polymorphic/templatetags/polymorphic_formset_tags.pyi new file mode 100644 index 00000000..4469c999 --- /dev/null +++ b/src/polymorphic/templatetags/polymorphic_formset_tags.pyi @@ -0,0 +1,15 @@ +from collections.abc import Generator + +from _typeshed import Incomplete + +from polymorphic.formsets import BasePolymorphicModelFormSet as BasePolymorphicModelFormSet + +register: Incomplete + +def include_empty_form(formset) -> Generator[Incomplete, Incomplete]: ... +@register.filter +def as_script_options(formset): ... +@register.filter +def as_form_type(form): ... +@register.filter +def as_model_name(model): ... diff --git a/src/polymorphic/tests/__init__.pyi b/src/polymorphic/tests/__init__.pyi new file mode 100644 index 00000000..9d59148a --- /dev/null +++ b/src/polymorphic/tests/__init__.pyi @@ -0,0 +1 @@ +HEADLESS: bool diff --git a/src/polymorphic/tests/admin.pyi b/src/polymorphic/tests/admin.pyi new file mode 100644 index 00000000..fced6d04 --- /dev/null +++ b/src/polymorphic/tests/admin.pyi @@ -0,0 +1,51 @@ +from _typeshed import Incomplete +from django_stubs.admin import ModelAdmin +from django_stubs.query import QuerySet +from django_stubs.http import HttpRequest +from typing import Any, ClassVar +from polymorphic.admin import ( + PolymorphicChildModelAdmin as PolymorphicChildModelAdmin, + PolymorphicChildModelFilter as PolymorphicChildModelFilter, + PolymorphicInlineSupportMixin as PolymorphicInlineSupportMixin, + PolymorphicParentModelAdmin as PolymorphicParentModelAdmin, + StackedPolymorphicInline as StackedPolymorphicInline, +) +from polymorphic.tests.models import ( + InlineModelA as InlineModelA, + InlineModelB as InlineModelB, + InlineParent as InlineParent, + Model2A as Model2A, + Model2B as Model2B, + Model2C as Model2C, + Model2D as Model2D, + NoChildren as NoChildren, + PlainA as PlainA, +) + +class Model2Admin(PolymorphicParentModelAdmin): + list_filter: ClassVar[Any] + child_models: Any + +class Model2DAdmin(PolymorphicChildModelAdmin): + exclude: ClassVar[Any] + +class PlainAAdmin(ModelAdmin): + search_fields: Incomplete + def get_queryset(self, request: HttpRequest) -> QuerySet: ... + +class Inline(StackedPolymorphicInline): + model = InlineModelA + def get_child_inlines(self): ... + class InlineModelAChild(StackedPolymorphicInline.Child): + model = InlineModelA + + class InlineModelBChild(StackedPolymorphicInline.Child): + model = InlineModelB + autocomplete_fields: ClassVar[Any] + +class InlineParentAdmin(PolymorphicInlineSupportMixin, ModelAdmin): + inlines: ClassVar[Any] + extra: int + +class NoChildrenAdmin(PolymorphicParentModelAdmin): + child_models: Incomplete diff --git a/src/polymorphic/tests/admintestcase.pyi b/src/polymorphic/tests/admintestcase.pyi new file mode 100644 index 00000000..49dfd025 --- /dev/null +++ b/src/polymorphic/tests/admintestcase.pyi @@ -0,0 +1,32 @@ +from _typeshed import Incomplete +from django_stubs.test import TestCase +from django_stubs.urls import include as include + +class AdminTestCase(TestCase): + model: Incomplete + admin_class: Incomplete + @classmethod + def setUpClass(cls) -> None: ... + admin_site: Incomplete + def setUp(self) -> None: ... + def tearDown(self) -> None: ... + def register(self, model): ... + def admin_register(self, model, admin_site) -> None: ... + def get_admin_instance(self, model): ... + @classmethod + def tearDownClass(cls) -> None: ... + def get_add_url(self, model): ... + def get_changelist_url(self, model): ... + def get_change_url(self, model, object_id): ... + def get_history_url(self, model, object_id): ... + def get_delete_url(self, model, object_id): ... + def admin_get_add(self, model, qs: str = ""): ... + def admin_post_add(self, model, formdata, qs: str = ""): ... + def admin_get_changelist(self, model): ... + def admin_get_change(self, model, object_id, query=None, **extra): ... + def admin_post_change(self, model, object_id, formdata, **extra): ... + def admin_get_history(self, model, object_id, query=None, **extra): ... + def admin_get_delete(self, model, object_id, query=None, **extra): ... + def admin_post_delete(self, model, object_id, **extra): ... + def create_admin_request(self, method, url, data=None, **extra): ... + def assertFormSuccess(self, request_url, response) -> None: ... diff --git a/src/polymorphic/tests/debug.pyi b/src/polymorphic/tests/debug.pyi new file mode 100644 index 00000000..7d7765a7 --- /dev/null +++ b/src/polymorphic/tests/debug.pyi @@ -0,0 +1 @@ +from .settings import * diff --git a/src/polymorphic/tests/errata/__init__.pyi b/src/polymorphic/tests/errata/__init__.pyi new file mode 100644 index 00000000..e69de29b diff --git a/src/polymorphic/tests/errata/migrations/__init__.pyi b/src/polymorphic/tests/errata/migrations/__init__.pyi new file mode 100644 index 00000000..e69de29b diff --git a/src/polymorphic/tests/errata/models.pyi b/src/polymorphic/tests/errata/models.pyi new file mode 100644 index 00000000..39e210d9 --- /dev/null +++ b/src/polymorphic/tests/errata/models.pyi @@ -0,0 +1,6 @@ +from _typeshed import Incomplete +from django_stubs.db import models + +class BadModel(models.Model): + instance_of: models.CharField + not_instance_of: models.IntegerField diff --git a/src/polymorphic/tests/errata/test_errata.pyi b/src/polymorphic/tests/errata/test_errata.pyi new file mode 100644 index 00000000..815dc75e --- /dev/null +++ b/src/polymorphic/tests/errata/test_errata.pyi @@ -0,0 +1,4 @@ +from django_stubs.test import SimpleTestCase + +class TestErrata(SimpleTestCase): + def test_reserved_field_name_triggers_system_check(self) -> None: ... diff --git a/src/polymorphic/tests/migrations/__init__.pyi b/src/polymorphic/tests/migrations/__init__.pyi new file mode 100644 index 00000000..e69de29b diff --git a/src/polymorphic/tests/models.pyi b/src/polymorphic/tests/models.pyi new file mode 100644 index 00000000..45d34975 --- /dev/null +++ b/src/polymorphic/tests/models.pyi @@ -0,0 +1,508 @@ +from _typeshed import Incomplete +from typing import Any, ClassVar +from django.contrib.auth.models import Group +from django.db import models +from django_stubs.db.models import Manager +from django_stubs.db.models.query import QuerySet +from polymorphic.managers import PolymorphicManager as PolymorphicManager +from polymorphic.models import PolymorphicModel as PolymorphicModel +from polymorphic.query import PolymorphicQuerySet as PolymorphicQuerySet +from polymorphic.showfields import ( + ShowFieldContent as ShowFieldContent, + ShowFieldType as ShowFieldType, + ShowFieldTypeAndContent as ShowFieldTypeAndContent, +) + +class PlainA(models.Model): + field1: Incomplete + +class PlainB(PlainA): + field2: Incomplete + +class PlainC(PlainB): + field3: Incomplete + +class Model2A(ShowFieldType, PolymorphicModel): + field1: Incomplete + polymorphic_showfield_deferred: bool + +class Model2B(Model2A): + field2: Incomplete + +class Model2C(Model2B): + field3: Incomplete + +class Model2D(Model2C): + field4: Incomplete + +class ModelExtraA(ShowFieldTypeAndContent, PolymorphicModel): + field1: Incomplete + +class ModelExtraB(ModelExtraA): + field2: Incomplete + +class ModelExtraC(ModelExtraB): + field3: Incomplete + +class ModelExtraExternal(models.Model): + topic: Incomplete + +class ModelShow1(ShowFieldType, PolymorphicModel): + field1: Incomplete + m2m: Incomplete + +class ModelShow2(ShowFieldContent, PolymorphicModel): + field1: Incomplete + m2m: Incomplete + +class ModelShow3(ShowFieldTypeAndContent, PolymorphicModel): + field1: Incomplete + m2m: Incomplete + +class ModelShow1_plain(PolymorphicModel): + field1: Incomplete + +class ModelShow2_plain(ModelShow1_plain): + field2: Incomplete + +class Base(ShowFieldType, PolymorphicModel): + polymorphic_showfield_deferred: bool + field_b: Incomplete + +class ModelX(Base): + field_x: Incomplete + +class ModelY(Base): + field_y: Incomplete + +class Enhance_Plain(models.Model): + field_p: Incomplete + objects: ClassVar[Any] + +class Enhance_Base(ShowFieldTypeAndContent, PolymorphicModel): + base_id: Incomplete + field_b: Incomplete + +class Enhance_Inherit(Enhance_Base, Enhance_Plain): + field_i: Incomplete + +class RelationAbstractModel(models.Model): + class Meta: + abstract = True + +class RelationBase(RelationAbstractModel, ShowFieldTypeAndContent, PolymorphicModel): + field_base: Incomplete + fk: Incomplete + m2m: Incomplete + +class RelationA(RelationBase): + field_a: Incomplete + +class RelationB(RelationBase): + field_b: Incomplete + +class RelationBC(RelationB): + field_c: Incomplete + +class RelatingModel(models.Model): + many2many: Incomplete + +class One2OneRelatingModel(PolymorphicModel): + one2one: Incomplete + field1: Incomplete + +class One2OneRelatingModelDerived(One2OneRelatingModel): + field2: Incomplete + +class ModelUnderRelParent(PolymorphicModel): + field1: Incomplete + +class ModelUnderRelChild(PolymorphicModel): + parent: Incomplete + +class MyManagerQuerySet(PolymorphicQuerySet[Any]): + def my_queryset_foo(self): ... + +class MyManager(PolymorphicManager[Any]): + queryset_class = MyManagerQuerySet + def get_queryset(self): ... + def my_queryset_foo(self): ... + +class ModelWithMyManager(ShowFieldTypeAndContent, Model2A): + objects: Incomplete + field4: Incomplete + +class ModelWithMyManagerNoDefault(ShowFieldTypeAndContent, Model2A): + objects: Incomplete + my_objects: Incomplete + field4: Incomplete + +class ModelWithMyManagerDefault(ShowFieldTypeAndContent, Model2A): + my_objects: Incomplete + objects: Incomplete + field4: Incomplete + +class ModelWithMyManager2(ShowFieldTypeAndContent, Model2A): + objects: Incomplete + field4: Incomplete + +class ModelArticle(PolymorphicModel): + sales_points: Incomplete + +class ModelPackage(ModelArticle): + name: Incomplete + +class ModelComponent(ModelArticle): + name: Incomplete + +class ModelOrderLine(models.Model): + articles: Incomplete + +class MROBase1(ShowFieldType, PolymorphicModel): + objects: Incomplete + field1: Incomplete + +class MROBase2(MROBase1): ... + +class MROBase3(models.Model): + base_3_id: Incomplete + objects: Incomplete + +class MRODerived(MROBase2, MROBase3): ... +class ParentModelWithManager(PolymorphicModel): ... + +class ChildModelWithManager(PolymorphicModel): + field1: Incomplete + fk: Incomplete + objects: Incomplete + +class PlainMyManagerQuerySet(QuerySet[Any]): + def my_queryset_foo(self): ... + +class PlainMyManager(models.Manager[Any]): + def my_queryset_foo(self): ... + def get_queryset(self): ... + +class PlainParentModelWithManager(models.Model): ... + +class PlainChildModelWithManager(models.Model): + fk: Incomplete + objects: Incomplete + +class BlogBase(ShowFieldTypeAndContent, PolymorphicModel): + name: Incomplete + +class BlogA(BlogBase): + info: Incomplete + +class BlogB(BlogBase): ... + +class BlogEntry(ShowFieldTypeAndContent, PolymorphicModel): + blog: Incomplete + text: Incomplete + +class BlogEntry_limit_choices_to(ShowFieldTypeAndContent, PolymorphicModel): + blog: Incomplete + text: Incomplete + +class ModelFieldNameTest(ShowFieldType, PolymorphicModel): + modelfieldnametest: Incomplete + +class InitTestModel(ShowFieldType, PolymorphicModel): + bar: Incomplete + def __init__(self, *args, **kwargs) -> None: ... + +class InitTestModelSubclass(InitTestModel): + def x(self): ... + +class Top(PolymorphicModel): + name: Incomplete + +class Middle(Top): + description: Incomplete + +class Bottom(Middle): + author: Incomplete + +class UUIDProject(ShowFieldTypeAndContent, PolymorphicModel): + uuid_primary_key: Incomplete + topic: Incomplete + +class UUIDArtProject(UUIDProject): + artist: Incomplete + +class UUIDResearchProject(UUIDProject): + supervisor: Incomplete + +class UUIDArtProjectA(UUIDArtProject): ... +class UUIDArtProjectB(UUIDArtProjectA): ... +class UUIDArtProjectC(UUIDArtProjectB): ... +class UUIDArtProjectD(UUIDArtProjectC): ... + +class UUIDPlainA(models.Model): + uuid_primary_key: Incomplete + field1: Incomplete + +class UUIDPlainB(UUIDPlainA): + field2: Incomplete + +class UUIDPlainC(UUIDPlainB): + field3: Incomplete + +class ProxyBase(PolymorphicModel): + some_data: Incomplete + +class ProxyChild(ProxyBase): + class Meta: + proxy = True + +class NonProxyChild(ProxyBase): + name: Incomplete + +class ProxiedBase(ShowFieldTypeAndContent, PolymorphicModel): + name: Incomplete + +class ProxyModelBase(ProxiedBase): + class Meta: + proxy = True + +class ProxyModelA(ProxyModelBase): + field1: Incomplete + +class ProxyModelB(ProxyModelBase): + field2: Incomplete + +class RelatedNameClash(ShowFieldType, PolymorphicModel): + ctype: Incomplete + +class ParentLinkAndRelatedName(ModelShow1_plain): + superclass: Incomplete + +class CustomPkBase(ShowFieldTypeAndContent, PolymorphicModel): + b: Incomplete + +class CustomPkInherit(CustomPkBase): + custom_id: Incomplete + i: Incomplete + +class DateModel(PolymorphicModel): + date: Incomplete + +class AbstractModel(PolymorphicModel): + class Meta: + abstract = True + +class SwappableModel(AbstractModel): + class Meta: + swappable: str + +class SwappedModel(AbstractModel): ... + +class InlineParent(models.Model): + title: Incomplete + +class InlineModelA(PolymorphicModel): + parent: Incomplete + field1: Incomplete + +class InlineModelB(InlineModelA): + field2: Incomplete + plain_a: Incomplete + +class AbstractProject(PolymorphicModel): + topic: Incomplete + class Meta: + abstract = True + +class ArtProject(AbstractProject): + artist: Incomplete + +class Duck(PolymorphicModel): + name: Incomplete + +class RedheadDuck(Duck): + class Meta: + proxy = True + +class RubberDuck(Duck): + class Meta: + proxy = True + +class MultiTableBase(PolymorphicModel): + field1: Incomplete + +class MultiTableDerived(MultiTableBase): + field2: Incomplete + +class SubclassSelectorAbstractBaseModel(PolymorphicModel): + base_field: Incomplete + +class SubclassSelectorAbstractModel(SubclassSelectorAbstractBaseModel): + abstract_field: Incomplete + class Meta: + abstract = True + +class SubclassSelectorAbstractConcreteModel(SubclassSelectorAbstractModel): + concrete_field: Incomplete + +class SubclassSelectorProxyBaseModel(PolymorphicModel): + base_field: Incomplete + +class SubclassSelectorProxyModel(SubclassSelectorProxyBaseModel): + class Meta: + proxy = True + +class SubclassSelectorProxyConcreteModel(SubclassSelectorProxyModel): + concrete_field: Incomplete + +class NonPolymorphicParent(PolymorphicModel, Group): + test: Incomplete + objects: Manager[Any] + +class Participant(PolymorphicModel): ... + +class UserProfile(Participant): + name: Incomplete + +class Team(models.Model): + team_name: Incomplete + user_profiles: Incomplete + +class BlueHeadDuck(Duck): + color: str + def __init__(self, *args, **kwargs) -> None: ... + +class HomeDuck(models.Model): + home: str + def __init__(self, *args, **kwargs) -> None: ... + class Meta: + abstract = True + +class PurpleHeadDuck(HomeDuck, BlueHeadDuck): + class Meta: + proxy = True + +class Account(PolymorphicModel): + user: Incomplete + +class SpecialAccount1(Account): + extra1: Incomplete + +class SpecialAccount1_1(SpecialAccount1): + extra2: Incomplete + +class SpecialAccount2(Account): + extra1: Incomplete + +class ModelMixin(models.Model): + class Meta: + abstract = True + + created_at: Incomplete + modified_at: Incomplete + +class PolymorphicMixin(PolymorphicModel): + class Meta: + abstract = True + + created_at: Incomplete + modified_at: Incomplete + +class Foo(PolymorphicModel): ... +class Bar(PolymorphicMixin, PolymorphicModel): ... +class Baz(ModelMixin, PolymorphicModel): ... + +class MyBaseQuerySet(PolymorphicQuerySet[Any]): + def filter_by_user(self, _): ... + +class MyBaseModel(PolymorphicModel): + objects: Incomplete + +class MyChild1QuerySet(MyBaseQuerySet): + def filter_by_user(self, num): ... + +class MyChild1Model(MyBaseModel): + fieldA: Incomplete + objects: Incomplete + +class MyChild2QuerySet(MyBaseQuerySet): + def filter_by_user(self, num): ... + +class MyChild2Model(MyBaseModel): + fieldB: Incomplete + objects: Incomplete + base_manager: Incomplete + +class SpecialQuerySet(PolymorphicQuerySet[Any]): + def has_text(self, text): ... + +class SpecialPolymorphicManager(Incomplete): + def custom_queryset(self): ... + +class AbstractManagerTest(PolymorphicModel): + objects: Incomplete + basic_manager: Incomplete + default_manager: Incomplete + abstract_field: Incomplete + class Meta: + abstract = True + +class RelatedManagerTest(models.Model): ... + +class DerivedManagerTest(AbstractManagerTest): + related_test: Incomplete + +class DerivedManagerTest2(DerivedManagerTest): + objects: Incomplete + +class FKTestBase(PolymorphicModel): ... +class FKTestChild(Base): ... + +class FKTest(models.Model): + fk: Incomplete + +class NoChildren(PolymorphicModel): + field1: Incomplete + +class NormalBase(models.Model): + nb_field: Incomplete + objects: ClassVar[Any] + +class NormalExtension(NormalBase): + ne_field: Incomplete + +class PolyExtension(PolymorphicModel, NormalExtension): + poly_ext_field: Incomplete + +class PolyExtChild(PolyExtension): + poly_child_field: Incomplete + +class DeepCopyTester(PolymorphicModel): + binary_field: Incomplete + +class DeepCopyTester2(DeepCopyTester): + binary_field2: Incomplete + +class DucksLake(models.Model): + lake: Incomplete + duck: Incomplete + time: Incomplete + +class Lake(models.Model): + ducks: Incomplete + +class LakeWithThrough(models.Model): + ducks: Incomplete + +class ChoiceBlank(PolymorphicModel): ... + +class ChoiceAthlete(ChoiceBlank): + choice: Incomplete + +class BetMultiple(models.Model): + answer: Incomplete + +class RankedAthlete(models.Model): + choiceAthlete: Incomplete + bet: Incomplete + rank: Incomplete diff --git a/src/polymorphic/tests/settings.pyi b/src/polymorphic/tests/settings.pyi new file mode 100644 index 00000000..86061e29 --- /dev/null +++ b/src/polymorphic/tests/settings.pyi @@ -0,0 +1,20 @@ +from _typeshed import Incomplete + +DEBUG: bool +rdbms: Incomplete +sqlite_dbs: Incomplete +DATABASES: Incomplete +creds: Incomplete +dbs: Incomplete +ports: Incomplete +DEFAULT_AUTO_FIELD: str +INSTALLED_APPS: Incomplete +MIDDLEWARE: Incomplete +SITE_ID: int +TEMPLATES: Incomplete +POLYMORPHIC_TEST_SWAPPABLE: str +SECRET_KEY: str +STATIC_URL: str +ALLOWED_HOSTS: Incomplete +ROOT_URLCONF: str +USE_TZ: bool diff --git a/src/polymorphic/tests/test_admin.pyi b/src/polymorphic/tests/test_admin.pyi new file mode 100644 index 00000000..5d3e083e --- /dev/null +++ b/src/polymorphic/tests/test_admin.pyi @@ -0,0 +1,59 @@ +from _typeshed import Incomplete +from django.contrib.staticfiles.testing import StaticLiveServerTestCase +from polymorphic import tests as tests +from polymorphic.admin import ( + PolymorphicChildModelAdmin as PolymorphicChildModelAdmin, + PolymorphicChildModelFilter as PolymorphicChildModelFilter, + PolymorphicInlineSupportMixin as PolymorphicInlineSupportMixin, + PolymorphicParentModelAdmin as PolymorphicParentModelAdmin, + StackedPolymorphicInline as StackedPolymorphicInline, +) +from polymorphic.tests.admintestcase import AdminTestCase as AdminTestCase +from polymorphic.tests.models import ( + InlineModelA as InlineModelA, + InlineModelB as InlineModelB, + InlineParent as InlineParent, + Model2A as Model2A, + Model2B as Model2B, + Model2C as Model2C, + Model2D as Model2D, + NoChildren as NoChildren, + PlainA as PlainA, +) +from time import sleep as sleep + +class PolymorphicAdminTests(AdminTestCase): + def test_admin_registration(self): ... + def test_get_child_inlines(self) -> None: ... + def test_admin_inlines(self) -> None: ... + +class _GenericAdminFormTest(StaticLiveServerTestCase): + HEADLESS: Incomplete + admin_username: str + admin_password: str + admin: Incomplete + def admin_url(self): ... + def add_url(self, model): ... + def change_url(self, model, id): ... + def list_url(self, model): ... + def get_object_ids(self, model): ... + @classmethod + def setUpClass(cls) -> None: ... + @classmethod + def tearDownClass(cls) -> None: ... + page: Incomplete + def setUp(self) -> None: ... + def tearDown(self) -> None: ... + +class StackedInlineTests(_GenericAdminFormTest): + def test_admin_inline_add_autocomplete(self) -> None: ... + def test_inline_form_ordering_and_removal(self) -> None: ... + +class PolymorphicFormTests(_GenericAdminFormTest): + def test_admin_polymorphic_add(self) -> None: ... + +class PolymorphicNoChildrenTests(_GenericAdminFormTest): + def test_admin_no_polymorphic_children(self) -> None: ... + +class AdminRecentActionsTests(_GenericAdminFormTest): + def test_admin_recent_actions(self) -> None: ... diff --git a/src/polymorphic/tests/test_contrib.pyi b/src/polymorphic/tests/test_contrib.pyi new file mode 100644 index 00000000..bc20e391 --- /dev/null +++ b/src/polymorphic/tests/test_contrib.pyi @@ -0,0 +1,8 @@ +from django.test import TestCase +from polymorphic.contrib.guardian import ( + get_polymorphic_base_content_type as get_polymorphic_base_content_type, +) +from polymorphic.tests.models import Model2D as Model2D, PlainC as PlainC + +class ContribTests(TestCase): + def test_contrib_guardian(self) -> None: ... diff --git a/src/polymorphic/tests/test_inheritance.pyi b/src/polymorphic/tests/test_inheritance.pyi new file mode 100644 index 00000000..b4ee2e2b --- /dev/null +++ b/src/polymorphic/tests/test_inheritance.pyi @@ -0,0 +1,6 @@ +from django.test import TestCase +from polymorphic.managers import PolymorphicManager as PolymorphicManager +from polymorphic.tests.models import Bar as Bar, Baz as Baz, Foo as Foo + +class InheritanceTests(TestCase): + def test_mixin_inherited_managers(self) -> None: ... diff --git a/src/polymorphic/tests/test_multidb.pyi b/src/polymorphic/tests/test_multidb.pyi new file mode 100644 index 00000000..7608f711 --- /dev/null +++ b/src/polymorphic/tests/test_multidb.pyi @@ -0,0 +1,29 @@ +from _typeshed import Incomplete +from django.test import TestCase +from polymorphic.tests.models import ( + Base as Base, + BlogA as BlogA, + BlogEntry as BlogEntry, + Model2A as Model2A, + Model2B as Model2B, + Model2C as Model2C, + Model2D as Model2D, + ModelX as ModelX, + ModelY as ModelY, + One2OneRelatingModel as One2OneRelatingModel, + RelatingModel as RelatingModel, + RelationA as RelationA, + RelationB as RelationB, + RelationBase as RelationBase, +) + +class MultipleDatabasesTests(TestCase): + databases: Incomplete + def test_save_to_non_default_database(self): ... + def test_instance_of_filter_on_non_default_database(self): ... + def test_forward_many_to_one_descriptor_on_non_default_database(self) -> None: ... + def test_reverse_many_to_one_descriptor_on_non_default_database(self) -> None: ... + def test_reverse_one_to_one_descriptor_on_non_default_database(self) -> None: ... + def test_many_to_many_descriptor_on_non_default_database(self) -> None: ... + def test_deletion_cascade_on_non_default_db(self) -> None: ... + def test_create_from_super(self) -> None: ... diff --git a/src/polymorphic/tests/test_orm.pyi b/src/polymorphic/tests/test_orm.pyi new file mode 100644 index 00000000..6b6f4bd5 --- /dev/null +++ b/src/polymorphic/tests/test_orm.pyi @@ -0,0 +1,178 @@ +from django.test import TransactionTestCase +from polymorphic import query_translate as query_translate +from polymorphic.managers import PolymorphicManager as PolymorphicManager +from polymorphic.models import ( + PolymorphicTypeInvalid as PolymorphicTypeInvalid, + PolymorphicTypeUndefined as PolymorphicTypeUndefined, +) +from polymorphic.tests.models import ( + Account as Account, + ArtProject as ArtProject, + Base as Base, + BlogA as BlogA, + BlogB as BlogB, + BlogBase as BlogBase, + BlogEntry as BlogEntry, + BlogEntry_limit_choices_to as BlogEntry_limit_choices_to, + ChildModelWithManager as ChildModelWithManager, + CustomPkBase as CustomPkBase, + CustomPkInherit as CustomPkInherit, + Duck as Duck, + Enhance_Base as Enhance_Base, + Enhance_Inherit as Enhance_Inherit, + Enhance_Plain as Enhance_Plain, + InitTestModelSubclass as InitTestModelSubclass, + InlineModelA as InlineModelA, + InlineModelB as InlineModelB, + InlineParent as InlineParent, + MRODerived as MRODerived, + Model2A as Model2A, + Model2B as Model2B, + Model2C as Model2C, + Model2D as Model2D, + ModelExtraA as ModelExtraA, + ModelExtraB as ModelExtraB, + ModelExtraC as ModelExtraC, + ModelExtraExternal as ModelExtraExternal, + ModelFieldNameTest as ModelFieldNameTest, + ModelOrderLine as ModelOrderLine, + ModelShow1 as ModelShow1, + ModelShow1_plain as ModelShow1_plain, + ModelShow2 as ModelShow2, + ModelShow2_plain as ModelShow2_plain, + ModelShow3 as ModelShow3, + ModelUnderRelChild as ModelUnderRelChild, + ModelUnderRelParent as ModelUnderRelParent, + ModelWithMyManager as ModelWithMyManager, + ModelWithMyManager2 as ModelWithMyManager2, + ModelWithMyManagerDefault as ModelWithMyManagerDefault, + ModelWithMyManagerNoDefault as ModelWithMyManagerNoDefault, + ModelX as ModelX, + ModelY as ModelY, + MultiTableDerived as MultiTableDerived, + MyManager as MyManager, + MyManagerQuerySet as MyManagerQuerySet, + NonPolymorphicParent as NonPolymorphicParent, + NonProxyChild as NonProxyChild, + One2OneRelatingModel as One2OneRelatingModel, + One2OneRelatingModelDerived as One2OneRelatingModelDerived, + ParentLinkAndRelatedName as ParentLinkAndRelatedName, + ParentModelWithManager as ParentModelWithManager, + PlainA as PlainA, + PlainB as PlainB, + PlainC as PlainC, + PlainChildModelWithManager as PlainChildModelWithManager, + PlainMyManager as PlainMyManager, + PlainMyManagerQuerySet as PlainMyManagerQuerySet, + PlainParentModelWithManager as PlainParentModelWithManager, + ProxiedBase as ProxiedBase, + ProxyBase as ProxyBase, + ProxyChild as ProxyChild, + ProxyModelA as ProxyModelA, + ProxyModelB as ProxyModelB, + ProxyModelBase as ProxyModelBase, + PurpleHeadDuck as PurpleHeadDuck, + RedheadDuck as RedheadDuck, + RelatingModel as RelatingModel, + RelationA as RelationA, + RelationB as RelationB, + RelationBC as RelationBC, + RelationBase as RelationBase, + RubberDuck as RubberDuck, + SpecialAccount1 as SpecialAccount1, + SpecialAccount1_1 as SpecialAccount1_1, + SpecialAccount2 as SpecialAccount2, + SubclassSelectorAbstractBaseModel as SubclassSelectorAbstractBaseModel, + SubclassSelectorAbstractConcreteModel as SubclassSelectorAbstractConcreteModel, + SubclassSelectorProxyBaseModel as SubclassSelectorProxyBaseModel, + SubclassSelectorProxyConcreteModel as SubclassSelectorProxyConcreteModel, + UUIDArtProject as UUIDArtProject, + UUIDArtProjectA as UUIDArtProjectA, + UUIDArtProjectB as UUIDArtProjectB, + UUIDArtProjectC as UUIDArtProjectC, + UUIDArtProjectD as UUIDArtProjectD, + UUIDPlainA as UUIDPlainA, + UUIDPlainB as UUIDPlainB, + UUIDPlainC as UUIDPlainC, + UUIDProject as UUIDProject, + UUIDResearchProject as UUIDResearchProject, +) + +class PolymorphicTests(TransactionTestCase): + def test_annotate_aggregate_order(self) -> None: ... + def test_limit_choices_to(self) -> None: ... + def test_primary_key_custom_field_problem(self) -> None: ... + def create_model2abcd(self): ... + def test_simple_inheritance(self): ... + def test_defer_fields(self) -> None: ... + def test_defer_related_fields(self) -> None: ... + def test_manual_get_real_instance(self) -> None: ... + def test_get_real_instance_with_stale_content_type(self) -> None: ... + def test_non_polymorphic(self): ... + def test_get_real_instances(self): ... + def test_queryset_missing_derived(self) -> None: ... + def test_queryset_missing_contenttype(self) -> None: ... + def test_translate_polymorphic_q_object(self): ... + def test_create_instanceof_q(self) -> None: ... + def test_base_manager(self): ... + def test_instance_default_manager(self): ... + def test_foreignkey_field(self) -> None: ... + def test_onetoone_field(self) -> None: ... + def test_manytomany_field(self): ... + def test_extra_method(self): ... + def test_instance_of_filter(self): ... + def test_polymorphic___filter(self): ... + def test_polymorphic_applabel___filter(self): ... + def test_query_filter_exclude_is_immutable(self) -> None: ... + def test_polymorphic___filter_field(self) -> None: ... + def test_polymorphic___filter_reverse_field(self) -> None: ... + def test_delete(self): ... + def test_combine_querysets(self) -> None: ... + def test_multiple_inheritance(self) -> None: ... + def test_relation_base(self) -> None: ... + def test_user_defined_manager(self): ... + def test_user_defined_manager_as_secondary(self): ... + def test_user_objects_manager_as_secondary(self) -> None: ... + def test_user_defined_queryset_as_manager(self): ... + def test_manager_inheritance(self) -> None: ... + def test_queryset_assignment(self) -> None: ... + def test_proxy_models(self) -> None: ... + def test_queryset_on_proxy_model_does_not_return_superclasses(self) -> None: ... + def test_proxy_get_real_instance_class(self) -> None: ... + def test_content_types_for_proxy_models(self) -> None: ... + def test_proxy_model_inheritance(self) -> None: ... + def test_custom_pk(self) -> None: ... + def test_fix_getattribute(self) -> None: ... + def test_parent_link_and_related_name(self) -> None: ... + def test_polymorphic__accessor_caching(self) -> None: ... + def test_polymorphic__aggregate(self) -> None: ... + def test_polymorphic__aggregate_empty_queryset(self) -> None: ... + def test_polymorphic__complex_aggregate(self): ... + def test_polymorphic__filtered_relation(self) -> None: ... + def test_polymorphic__expressions(self) -> None: ... + def test_null_polymorphic_id(self) -> None: ... + def test_invalid_polymorphic_id(self) -> None: ... + def test_bulk_create_abstract_inheritance(self) -> None: ... + def test_bulk_create_proxy_inheritance(self) -> None: ... + def test_bulk_create_unsupported_multi_table_inheritance(self) -> None: ... + def test_bulk_create_ignore_conflicts(self) -> None: ... + def test_bulk_create_no_ignore_conflicts(self) -> None: ... + def test_can_query_using_subclass_selector_on_abstract_model(self) -> None: ... + def test_can_query_using_subclass_selector_on_proxy_model(self) -> None: ... + def test_prefetch_related_behaves_normally_with_polymorphic_model(self) -> None: ... + def test_prefetch_related_with_missing(self) -> None: ... + def test_refresh_from_db_fields(self) -> None: ... + def test_non_polymorphic_parent(self) -> None: ... + def test_iteration(self) -> None: ... + def test_transmogrify_with_init(self) -> None: ... + def test_subqueries(self) -> None: ... + def test_one_to_one_primary_key(self) -> None: ... + def test_manager_override(self) -> None: ... + def test_abstract_managers(self) -> None: ... + def test_fk_polymorphism(self) -> None: ... + def test_polymorphic_extension(self) -> None: ... + def test_manytomany_without_through_field(self) -> None: ... + def test_manytomany_with_through_field(self) -> None: ... + def test_create_from_super(self) -> None: ... + def test_through_models_creates_and_reads(self) -> None: ... + def test_through_model_updates(self) -> None: ... diff --git a/src/polymorphic/tests/test_query_translate.pyi b/src/polymorphic/tests/test_query_translate.pyi new file mode 100644 index 00000000..003b3af8 --- /dev/null +++ b/src/polymorphic/tests/test_query_translate.pyi @@ -0,0 +1,9 @@ +from django.test import TestCase +from polymorphic.query_translate import ( + translate_polymorphic_filter_definitions_in_args as translate_polymorphic_filter_definitions_in_args, +) +from polymorphic.tests.models import Bottom as Bottom, Middle as Middle, Top as Top + +class QueryTranslateTests(TestCase): + def test_translate_with_not_pickleable_query(self) -> None: ... + def test_deep_copy_of_q_objects(self) -> None: ... diff --git a/src/polymorphic/tests/test_regression.pyi b/src/polymorphic/tests/test_regression.pyi new file mode 100644 index 00000000..dd730c45 --- /dev/null +++ b/src/polymorphic/tests/test_regression.pyi @@ -0,0 +1,12 @@ +from django.test import TestCase +from polymorphic.tests.models import ( + Bottom as Bottom, + Middle as Middle, + Team as Team, + Top as Top, + UserProfile as UserProfile, +) + +class RegressionTests(TestCase): + def test_for_query_result_incomplete_with_inheritance(self) -> None: ... + def test_pr_254(self) -> None: ... diff --git a/src/polymorphic/tests/test_utils.pyi b/src/polymorphic/tests/test_utils.pyi new file mode 100644 index 00000000..022196e2 --- /dev/null +++ b/src/polymorphic/tests/test_utils.pyi @@ -0,0 +1,24 @@ +from django.test import TransactionTestCase +from polymorphic.models import ( + PolymorphicModel as PolymorphicModel, + PolymorphicTypeUndefined as PolymorphicTypeUndefined, +) +from polymorphic.tests.models import ( + Enhance_Base as Enhance_Base, + Enhance_Inherit as Enhance_Inherit, + Model2A as Model2A, + Model2B as Model2B, + Model2C as Model2C, + Model2D as Model2D, +) +from polymorphic.utils import ( + get_base_polymorphic_model as get_base_polymorphic_model, + reset_polymorphic_ctype as reset_polymorphic_ctype, + sort_by_subclass as sort_by_subclass, +) + +class UtilsTests(TransactionTestCase): + def test_sort_by_subclass(self) -> None: ... + def test_reset_polymorphic_ctype(self): ... + def test_get_base_polymorphic_model(self) -> None: ... + def test_get_base_polymorphic_model_skip_abstract(self) -> None: ... diff --git a/src/polymorphic/tests/urls.pyi b/src/polymorphic/tests/urls.pyi new file mode 100644 index 00000000..7e0c0313 --- /dev/null +++ b/src/polymorphic/tests/urls.pyi @@ -0,0 +1,3 @@ +from _typeshed import Incomplete + +urlpatterns: Incomplete diff --git a/src/polymorphic/utils.pyi b/src/polymorphic/utils.pyi new file mode 100644 index 00000000..c0d4cde9 --- /dev/null +++ b/src/polymorphic/utils.pyi @@ -0,0 +1,14 @@ +from typing import Any, TypeVar + +from django.db.models import Model + +from polymorphic.base import PolymorphicModelBase as PolymorphicModelBase +from polymorphic.models import PolymorphicModel as PolymorphicModel + +_M = TypeVar("_M", bound=Model) + +def reset_polymorphic_ctype(*models: type[Model], **filters: Any) -> None: ... +def sort_by_subclass(*classes: type[_M]) -> list[type[_M]]: ... +def get_base_polymorphic_model( + ChildModel: type[Model], allow_abstract: bool = False +) -> type[Model] | None: ... diff --git a/uv.lock b/uv.lock index be722a39..5eb1cbb7 100644 --- a/uv.lock +++ b/uv.lock @@ -641,6 +641,7 @@ cx-oracle = [ dev = [ { name = "coverage" }, { name = "dj-database-url" }, + { name = "django-stubs" }, { name = "django-test-migrations" }, { name = "ipdb" }, { name = "ipython", version = "8.38.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, @@ -695,6 +696,7 @@ cx-oracle = [{ name = "cx-oracle", specifier = ">=8.3.0" }] dev = [ { name = "coverage", specifier = ">=7.6.1" }, { name = "dj-database-url", specifier = ">=2.2.0" }, + { name = "django-stubs", specifier = ">=5.2.8" }, { name = "django-test-migrations", specifier = ">=1.5.0" }, { name = "ipdb", specifier = ">=0.13.13" }, { name = "ipython", specifier = ">=8.18.1" }, @@ -738,6 +740,37 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/5e/8e/c80904ce5cb94f78cdd7d794cb7b4a8e8891a7515621bbce5f2a45de6555/django_reversion-6.1.0-py3-none-any.whl", hash = "sha256:1f5815791d9accdb0bad9d5982668f217dc65225be57041ae9641dbdcd838ce3", size = 86196, upload-time = "2025-12-12T20:23:50.18Z" }, ] +[[package]] +name = "django-stubs" +version = "5.2.8" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "django", version = "5.2.9", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.12'" }, + { name = "django", version = "6.0", 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" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/6c/75/97626224fd8f1787bb6f7f06944efcfddd5da7764bf741cf7f59d102f4a0/django_stubs-5.2.8.tar.gz", hash = "sha256:9bba597c9a8ed8c025cae4696803d5c8be1cf55bfc7648a084cbf864187e2f8b", size = 257709, upload-time = "2025-12-01T08:13:09.569Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7d/3f/7c9543ad5ade5ce1d33d187a3abd82164570314ebee72c6206ab5c044ebf/django_stubs-5.2.8-py3-none-any.whl", hash = "sha256:a3c63119fd7062ac63d58869698d07c9e5ec0561295c4e700317c54e8d26716c", size = 508136, upload-time = "2025-12-01T08:13:07.963Z" }, +] + +[[package]] +name = "django-stubs-ext" +version = "5.2.8" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "django", version = "5.2.9", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.12'" }, + { name = "django", version = "6.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/14/a2/d67f4a5200ff7626b104eddceaf529761cba4ed318a73ffdb0677551be73/django_stubs_ext-5.2.8.tar.gz", hash = "sha256:b39938c46d7a547cd84e4a6378dbe51a3dd64d70300459087229e5fee27e5c6b", size = 6487, upload-time = "2025-12-01T08:12:37.486Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/da/2d/cb0151b780c3730cf0f2c0fcb1b065a5e88f877cf7a9217483c375353af1/django_stubs_ext-5.2.8-py3-none-any.whl", hash = "sha256:1dd5470c9675591362c78a157a3cf8aec45d0e7a7f0cf32f227a1363e54e0652", size = 9949, upload-time = "2025-12-01T08:12:36.397Z" }, +] + [[package]] name = "django-test-migrations" version = "1.5.0" @@ -2172,6 +2205,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/00/c0/8f5d070730d7836adc9c9b6408dec68c6ced86b304a9b26a14df072a6e8c/traitlets-5.14.3-py3-none-any.whl", hash = "sha256:b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f", size = 85359, upload-time = "2024-04-19T11:11:46.763Z" }, ] +[[package]] +name = "types-pyyaml" +version = "6.0.12.20250915" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7e/69/3c51b36d04da19b92f9e815be12753125bd8bc247ba0470a982e6979e71c/types_pyyaml-6.0.12.20250915.tar.gz", hash = "sha256:0f8b54a528c303f0e6f7165687dd33fafa81c807fcac23f632b63aa624ced1d3", size = 17522, upload-time = "2025-09-15T03:01:00.728Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bd/e0/1eed384f02555dde685fff1a1ac805c1c7dcb6dd019c916fe659b1c1f9ec/types_pyyaml-6.0.12.20250915-py3-none-any.whl", hash = "sha256:e7d4d9e064e89a3b3cae120b4990cd370874d2bf12fa5f46c97018dd5d3c9ab6", size = 20338, upload-time = "2025-09-15T03:00:59.218Z" }, +] + [[package]] name = "typing-extensions" version = "4.15.0"