diff --git a/stubs/django-polymorphic/@tests/django_settings.py b/stubs/django-polymorphic/@tests/django_settings.py new file mode 100644 index 000000000000..48169e93db7b --- /dev/null +++ b/stubs/django-polymorphic/@tests/django_settings.py @@ -0,0 +1,12 @@ +SECRET_KEY = "1" + +INSTALLED_APPS = ( + "django.contrib.contenttypes", + "django.contrib.sites", + "django.contrib.sessions", + "django.contrib.messages", + "django.contrib.admin.apps.SimpleAdminConfig", + "django.contrib.staticfiles", + "django.contrib.auth", + "polymorphic", +) diff --git a/stubs/django-polymorphic/@tests/stubtest_allowlist.txt b/stubs/django-polymorphic/@tests/stubtest_allowlist.txt new file mode 100644 index 000000000000..bb8953c9ee6f --- /dev/null +++ b/stubs/django-polymorphic/@tests/stubtest_allowlist.txt @@ -0,0 +1,45 @@ +# Admin __init__ methods with *args +polymorphic.admin.PolymorphicChildModelAdmin.__init__ +polymorphic.admin.PolymorphicParentModelAdmin.__init__ +polymorphic.admin.childadmin.PolymorphicChildModelAdmin.__init__ +polymorphic.admin.parentadmin.PolymorphicParentModelAdmin.__init__ + +# Admin get_form - stub includes change parameter for compatibility with Django base class +polymorphic.admin.PolymorphicChildModelAdmin.get_form +polymorphic.admin.childadmin.PolymorphicChildModelAdmin.get_form + +# QuerySet methods - version-specific Django parameters +polymorphic.query.PolymorphicQuerySet.__repr__ +polymorphic.query.PolymorphicQuerySet.bulk_create +polymorphic.query.PolymorphicQuerySet._p_list_class.__repr__ +polymorphic.managers.PolymorphicQuerySet.__repr__ +polymorphic.managers.PolymorphicQuerySet.bulk_create +polymorphic.managers.PolymorphicQuerySet._p_list_class.__repr__ + +# Model attributes - Django auto-generated +polymorphic.models.PolymorphicModel.polymorphic_ctype_id + +# Type annotation helpers (not runtime classes) +polymorphic.models.PolymorphicModel@AnnotatedWith + +# Optional dependencies - contrib modules may require additional packages +polymorphic.contrib.extra_views + +# Template properties - read-only at runtime +polymorphic.admin.PolymorphicChildModelAdmin.change_form_template +polymorphic.admin.PolymorphicChildModelAdmin.delete_confirmation_template +polymorphic.admin.PolymorphicChildModelAdmin.object_history_template +polymorphic.admin.PolymorphicParentModelAdmin.change_list_template +polymorphic.admin.childadmin.PolymorphicChildModelAdmin.change_form_template +polymorphic.admin.childadmin.PolymorphicChildModelAdmin.delete_confirmation_template +polymorphic.admin.childadmin.PolymorphicChildModelAdmin.object_history_template +polymorphic.admin.parentadmin.PolymorphicParentModelAdmin.change_list_template + +# __all__ differences - stub uses list for easier editing +polymorphic.admin.__all__ +polymorphic.formsets.__all__ +polymorphic.managers.__all__ + +# Descriptor vs typed value - normal for stubs +polymorphic.models.PolymorphicModel.objects +polymorphic.models.PolymorphicModel.polymorphic_ctype diff --git a/stubs/django-polymorphic/METADATA.toml b/stubs/django-polymorphic/METADATA.toml new file mode 100644 index 000000000000..e8cc65ad26d4 --- /dev/null +++ b/stubs/django-polymorphic/METADATA.toml @@ -0,0 +1,7 @@ +version = "4.10.*" +upstream_repository = "https://github.com/jazzband/django-polymorphic" +requires = ["django-stubs"] + +[tool.stubtest] +mypy_plugins = ["mypy_django_plugin.main"] +mypy_plugins_config = {"django-stubs" = {"django_settings_module" = "@tests.django_settings"}} diff --git a/stubs/django-polymorphic/polymorphic/__init__.pyi b/stubs/django-polymorphic/polymorphic/__init__.pyi new file mode 100644 index 000000000000..86d77fc1582e --- /dev/null +++ b/stubs/django-polymorphic/polymorphic/__init__.pyi @@ -0,0 +1,9 @@ +from typing import Final + +VERSION: Final[str] + +__title__: Final = "Django Polymorphic" +__version__ = VERSION # version synonym for backwards compatibility +__author__: Final[str] +__license__: Final = "BSD-3-Clause" +__copyright__: Final[str] diff --git a/stubs/django-polymorphic/polymorphic/admin/__init__.pyi b/stubs/django-polymorphic/polymorphic/admin/__init__.pyi new file mode 100644 index 000000000000..26f07812949c --- /dev/null +++ b/stubs/django-polymorphic/polymorphic/admin/__init__.pyi @@ -0,0 +1,31 @@ +from .childadmin import PolymorphicChildModelAdmin as PolymorphicChildModelAdmin +from .filters import PolymorphicChildModelFilter as PolymorphicChildModelFilter +from .forms import PolymorphicModelChoiceForm as PolymorphicModelChoiceForm +from .generic import ( + GenericPolymorphicInlineModelAdmin as GenericPolymorphicInlineModelAdmin, + GenericStackedPolymorphicInline as GenericStackedPolymorphicInline, +) +from .helpers import ( + PolymorphicInlineAdminForm as PolymorphicInlineAdminForm, + PolymorphicInlineAdminFormSet as PolymorphicInlineAdminFormSet, + PolymorphicInlineSupportMixin as PolymorphicInlineSupportMixin, +) +from .inlines import ( + PolymorphicInlineModelAdmin as PolymorphicInlineModelAdmin, + StackedPolymorphicInline as StackedPolymorphicInline, +) +from .parentadmin import PolymorphicParentModelAdmin as PolymorphicParentModelAdmin + +__all__ = [ + "PolymorphicParentModelAdmin", + "PolymorphicChildModelAdmin", + "PolymorphicModelChoiceForm", + "PolymorphicChildModelFilter", + "PolymorphicInlineAdminForm", + "PolymorphicInlineAdminFormSet", + "PolymorphicInlineSupportMixin", + "PolymorphicInlineModelAdmin", + "StackedPolymorphicInline", + "GenericPolymorphicInlineModelAdmin", + "GenericStackedPolymorphicInline", +] diff --git a/stubs/django-polymorphic/polymorphic/admin/childadmin.pyi b/stubs/django-polymorphic/polymorphic/admin/childadmin.pyi new file mode 100644 index 000000000000..8da43dd2cf27 --- /dev/null +++ b/stubs/django-polymorphic/polymorphic/admin/childadmin.pyi @@ -0,0 +1,39 @@ +from collections.abc import Sequence +from typing import Any, ClassVar + +from django.contrib import admin +from django.db import models +from django.forms import Form, ModelForm +from django.http import HttpRequest, HttpResponse, HttpResponseRedirect + +class ParentAdminNotRegistered(RuntimeError): ... + +class PolymorphicChildModelAdmin(admin.ModelAdmin[Any]): + base_model: type[models.Model] | None + base_form: type[Form] | None + base_fieldsets: Sequence[tuple[str | None, dict[str, Any]]] | None + extra_fieldset_title: str + show_in_index: bool + change_form_template: ClassVar[list[str]] # type: ignore[misc] + delete_confirmation_template: ClassVar[list[str]] # type: ignore[misc] + object_history_template: ClassVar[list[str]] # type: ignore[misc] + def get_form( + self, request: HttpRequest, obj: Any | None = None, change: bool = False, **kwargs: Any + ) -> type[ModelForm[Any]]: ... + def get_model_perms(self, request: HttpRequest) -> dict[str, bool]: ... + def get_base_fieldsets(self, request: HttpRequest, obj: Any = None) -> list[tuple[str | None, dict[str, Any]]] | None: ... + def get_fieldsets(self, request: HttpRequest, obj: Any = None) -> list[tuple[str | None, dict[str, Any]]]: ... # type: ignore[override] + def get_subclass_fields(self, request: HttpRequest, obj: Any = None) -> list[str]: ... + def response_post_save_add(self, request: HttpRequest, obj: Any) -> HttpResponseRedirect: ... + def response_post_save_change(self, request: HttpRequest, obj: Any) -> HttpResponseRedirect: ... + def render_change_form( + self, + request: HttpRequest, + context: dict[str, Any], + add: bool = False, + change: bool = False, + form_url: str = "", + obj: Any = None, + ) -> HttpResponse: ... + def delete_view(self, request: HttpRequest, object_id: str, context: dict[str, Any] | None = None) -> HttpResponse: ... + def history_view(self, request: HttpRequest, object_id: str, extra_context: dict[str, Any] | None = None) -> HttpResponse: ... diff --git a/stubs/django-polymorphic/polymorphic/admin/filters.pyi b/stubs/django-polymorphic/polymorphic/admin/filters.pyi new file mode 100644 index 000000000000..15b2447d6302 --- /dev/null +++ b/stubs/django-polymorphic/polymorphic/admin/filters.pyi @@ -0,0 +1,12 @@ +from collections.abc import Iterable +from typing import Any + +from django.contrib.admin import ModelAdmin, SimpleListFilter +from django.db.models import QuerySet +from django.http import HttpRequest + +class PolymorphicChildModelFilter(SimpleListFilter): + title: str + parameter_name: str + def lookups(self, request: HttpRequest, model_admin: ModelAdmin[Any]) -> Iterable[tuple[str, str]]: ... + def queryset(self, request: HttpRequest, queryset: QuerySet[Any]) -> QuerySet[Any]: ... diff --git a/stubs/django-polymorphic/polymorphic/admin/forms.pyi b/stubs/django-polymorphic/polymorphic/admin/forms.pyi new file mode 100644 index 000000000000..d453d478f27f --- /dev/null +++ b/stubs/django-polymorphic/polymorphic/admin/forms.pyi @@ -0,0 +1,8 @@ +from typing import Any + +from django import forms + +class PolymorphicModelChoiceForm(forms.Form): + type_label: str + ct_id: forms.ChoiceField + def __init__(self, *args: Any, **kwargs: Any) -> None: ... diff --git a/stubs/django-polymorphic/polymorphic/admin/generic.pyi b/stubs/django-polymorphic/polymorphic/admin/generic.pyi new file mode 100644 index 000000000000..2f4157ae0fc8 --- /dev/null +++ b/stubs/django-polymorphic/polymorphic/admin/generic.pyi @@ -0,0 +1,25 @@ +from typing import Any + +from django.contrib.contenttypes.admin import GenericInlineModelAdmin +from django.contrib.contenttypes.models import ContentType +from django.http import HttpRequest + +from ..formsets import BaseGenericPolymorphicInlineFormSet, GenericPolymorphicFormSetChild +from .inlines import PolymorphicInlineModelAdmin + +class GenericPolymorphicInlineModelAdmin(PolymorphicInlineModelAdmin, GenericInlineModelAdmin): + formset: type[BaseGenericPolymorphicInlineFormSet] # type: ignore[assignment] + def get_formset(self, request: HttpRequest, obj: Any = None, **kwargs: Any) -> type[BaseGenericPolymorphicInlineFormSet]: ... # type: ignore[override] + + class Child(PolymorphicInlineModelAdmin.Child): + formset_child: type[GenericPolymorphicFormSetChild] # type: ignore[assignment] + ct_field: str + ct_fk_field: str + @property + def content_type(self) -> ContentType: ... + def get_formset_child( + self, request: HttpRequest, obj: Any = None, **kwargs: Any + ) -> GenericPolymorphicFormSetChild: ... # type: ignore[override] + +class GenericStackedPolymorphicInline(GenericPolymorphicInlineModelAdmin): + template: str diff --git a/stubs/django-polymorphic/polymorphic/admin/helpers.pyi b/stubs/django-polymorphic/polymorphic/admin/helpers.pyi new file mode 100644 index 000000000000..d1e8f8823a56 --- /dev/null +++ b/stubs/django-polymorphic/polymorphic/admin/helpers.pyi @@ -0,0 +1,25 @@ +from collections.abc import Iterator +from typing import Any + +from django.contrib.admin.helpers import AdminField, InlineAdminForm, InlineAdminFormSet +from django.http import HttpRequest + +class PolymorphicInlineAdminForm(InlineAdminForm): + def polymorphic_ctype_field(self) -> AdminField: ... + @property + def is_empty(self) -> bool: ... + +class PolymorphicInlineAdminFormSet(InlineAdminFormSet): + request: HttpRequest | None + obj: Any | None + def __init__(self, *args: Any, **kwargs: Any) -> None: ... + def __iter__(self) -> Iterator[PolymorphicInlineAdminForm]: ... + def get_child_fieldsets(self, child_inline: Any) -> list[tuple[str | None, dict[str, Any]]]: ... + def get_child_readonly_fields(self, child_inline: Any) -> list[str]: ... + def get_child_prepopulated_fields(self, child_inline: Any) -> dict[str, Any]: ... + def inline_formset_data(self) -> str: ... + +class PolymorphicInlineSupportMixin: + def get_inline_formsets( + self, request: HttpRequest, formsets: list[Any], inline_instances: list[Any], obj: Any = None, *args: Any, **kwargs: Any + ) -> list[InlineAdminFormSet]: ... diff --git a/stubs/django-polymorphic/polymorphic/admin/inlines.pyi b/stubs/django-polymorphic/polymorphic/admin/inlines.pyi new file mode 100644 index 000000000000..da87f9740ea7 --- /dev/null +++ b/stubs/django-polymorphic/polymorphic/admin/inlines.pyi @@ -0,0 +1,36 @@ +from typing import Any + +from django.contrib.admin.options import InlineModelAdmin +from django.contrib.admin.sites import AdminSite +from django.db import models +from django.forms import Media +from django.http import HttpRequest + +from ..formsets import BasePolymorphicInlineFormSet, PolymorphicFormSetChild + +class PolymorphicInlineModelAdmin(InlineModelAdmin[Any, Any]): + formset: type[BasePolymorphicInlineFormSet] # type: ignore[assignment] + polymorphic_media: Media + extra: int + child_inlines: tuple[type[PolymorphicInlineModelAdmin.Child], ...] + child_inline_instances: list[PolymorphicInlineModelAdmin.Child] + def __init__(self, parent_model: type[models.Model], admin_site: AdminSite) -> None: ... + def get_child_inlines(self) -> list[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_children(self, request: HttpRequest, obj: Any = None) -> list[PolymorphicFormSetChild]: ... + def get_formset(self, request: HttpRequest, obj: Any = None, **kwargs: Any) -> type[BasePolymorphicInlineFormSet]: ... # type: ignore[override] + def get_fieldsets(self, request: HttpRequest, obj: Any = None) -> list[tuple[str | None, dict[str, Any]]]: ... # type: ignore[override] + def get_fields(self, request: HttpRequest, obj: Any = None) -> list[str]: ... # type: ignore[override] + + class Child(InlineModelAdmin[Any, Any]): + formset_child: type[PolymorphicFormSetChild] + extra: int + parent_inline: PolymorphicInlineModelAdmin + def __init__(self, parent_inline: PolymorphicInlineModelAdmin) -> None: ... + def get_formset(self, request: HttpRequest, obj: Any = None, **kwargs: Any) -> None: ... # type: ignore[override] + def get_fields(self, request: HttpRequest, obj: Any = None) -> list[str]: ... # type: ignore[override] + def get_formset_child(self, request: HttpRequest, obj: Any = None, **kwargs: Any) -> PolymorphicFormSetChild: ... + +class StackedPolymorphicInline(PolymorphicInlineModelAdmin): + template: str diff --git a/stubs/django-polymorphic/polymorphic/admin/parentadmin.pyi b/stubs/django-polymorphic/polymorphic/admin/parentadmin.pyi new file mode 100644 index 000000000000..f4e1099627a2 --- /dev/null +++ b/stubs/django-polymorphic/polymorphic/admin/parentadmin.pyi @@ -0,0 +1,37 @@ +from collections.abc import Sequence +from typing import Any, ClassVar + +from django.contrib import admin +from django.db import models +from django.db.models import QuerySet +from django.forms import Form +from django.http import HttpRequest, HttpResponse + +class RegistrationClosed(RuntimeError): ... +class ChildAdminNotRegistered(RuntimeError): ... + +class PolymorphicParentModelAdmin(admin.ModelAdmin[Any]): + base_model: type[models.Model] | None + child_models: Sequence[type[models.Model]] | None + polymorphic_list: bool + add_type_template: str | Sequence[str] | None + add_type_form: type[Form] + pk_regex: str + change_list_template: ClassVar[list[str]] # type: ignore[misc] + def register_child(self, model: type[models.Model], model_admin: type[admin.ModelAdmin[Any]]) -> None: ... + def get_child_models(self) -> Sequence[type[models.Model]]: ... + def get_child_type_choices(self, request: HttpRequest, action: str) -> list[tuple[int, str]]: ... + def get_queryset(self, request: HttpRequest) -> QuerySet[Any]: ... + def add_view(self, request: HttpRequest, form_url: str = "", extra_context: dict[str, Any] | None = None) -> HttpResponse: ... + def change_view( + self, request: HttpRequest, object_id: str, form_url: str = "", extra_context: dict[str, Any] | None = None + ) -> HttpResponse: ... + def changeform_view( + self, request: HttpRequest, object_id: str | None = None, form_url: str = "", extra_context: dict[str, Any] | None = None + ) -> HttpResponse: ... + def history_view(self, request: HttpRequest, object_id: str, extra_context: dict[str, Any] | None = None) -> HttpResponse: ... + def delete_view(self, request: HttpRequest, object_id: str, extra_context: dict[str, Any] | None = None) -> HttpResponse: ... + 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: dict[str, Any], form_url: str = "") -> HttpResponse: ... diff --git a/stubs/django-polymorphic/polymorphic/apps.pyi b/stubs/django-polymorphic/polymorphic/apps.pyi new file mode 100644 index 000000000000..98859ab977a1 --- /dev/null +++ b/stubs/django-polymorphic/polymorphic/apps.pyi @@ -0,0 +1,12 @@ +from _typeshed import Unused +from collections.abc import Sequence +from typing import Final + +from django.apps import AppConfig +from django.core.checks import CheckMessage + +def check_reserved_field_names(app_configs: Sequence[AppConfig] | None, **kwargs: Unused) -> list[CheckMessage]: ... + +class PolymorphicConfig(AppConfig): + name: Final = "polymorphic" + verbose_name: str = "Django Polymorphic" diff --git a/stubs/django-polymorphic/polymorphic/base.pyi b/stubs/django-polymorphic/polymorphic/base.pyi new file mode 100644 index 000000000000..606df104f3ef --- /dev/null +++ b/stubs/django-polymorphic/polymorphic/base.pyi @@ -0,0 +1,23 @@ +from typing import Any + +from django.db import models +from django.db.models.base import ModelBase + +from .managers import PolymorphicManager as PolymorphicManager + +POLYMORPHIC_SPECIAL_Q_KWORDS: set[str] + +check_dump: bool + +class ManagerInheritanceWarning(RuntimeWarning): ... + +class PolymorphicModelBase(ModelBase): + def __new__(cls, model_name: str, bases: tuple[type, ...], attrs: dict[str, Any], **kwargs: Any) -> type: ... + @property + def base_objects(self) -> models.Manager[Any]: ... + @property + def _base_objects(self) -> models.Manager[Any]: ... + @property + def _default_manager(self) -> PolymorphicManager[Any]: ... + @property + def _base_manager(self) -> PolymorphicManager[Any]: ... diff --git a/stubs/django-polymorphic/polymorphic/contrib/__init__.pyi b/stubs/django-polymorphic/polymorphic/contrib/__init__.pyi new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/stubs/django-polymorphic/polymorphic/contrib/extra_views.pyi b/stubs/django-polymorphic/polymorphic/contrib/extra_views.pyi new file mode 100644 index 000000000000..931527d89bfa --- /dev/null +++ b/stubs/django-polymorphic/polymorphic/contrib/extra_views.pyi @@ -0,0 +1,28 @@ +from typing import Any + +from django.forms import BaseFormSet + +from ..formsets import ( + BasePolymorphicInlineFormSet as BasePolymorphicInlineFormSet, + BasePolymorphicModelFormSet as BasePolymorphicModelFormSet, + PolymorphicFormSetChild, +) + +__all__ = ["PolymorphicFormSetView", "PolymorphicInlineFormSetView", "PolymorphicInlineFormSet"] + +class PolymorphicFormSetMixin: + formset_class: type[BaseFormSet[Any]] + factory_kwargs: dict[str, Any] + formset_children: list[PolymorphicFormSetChild] | None + def get_formset_children(self) -> list[PolymorphicFormSetChild]: ... + def get_formset_child_kwargs(self) -> dict[str, Any]: ... + def get_formset(self) -> type[BaseFormSet[Any]]: ... + +class PolymorphicFormSetView(PolymorphicFormSetMixin): + formset_class: type[BasePolymorphicModelFormSet] + +class PolymorphicInlineFormSetView(PolymorphicFormSetMixin): + formset_class: type[BasePolymorphicInlineFormSet] + +class PolymorphicInlineFormSet(PolymorphicFormSetMixin): + formset_class: type[BasePolymorphicInlineFormSet] diff --git a/stubs/django-polymorphic/polymorphic/contrib/guardian.pyi b/stubs/django-polymorphic/polymorphic/contrib/guardian.pyi new file mode 100644 index 000000000000..227990f9238f --- /dev/null +++ b/stubs/django-polymorphic/polymorphic/contrib/guardian.pyi @@ -0,0 +1,5 @@ +from typing import Any + +from django.contrib.contenttypes.models import ContentType + +def get_polymorphic_base_content_type(obj: Any) -> ContentType: ... diff --git a/stubs/django-polymorphic/polymorphic/deletion.pyi b/stubs/django-polymorphic/polymorphic/deletion.pyi new file mode 100644 index 000000000000..6b0a066433d3 --- /dev/null +++ b/stubs/django-polymorphic/polymorphic/deletion.pyi @@ -0,0 +1,21 @@ +from collections.abc import Callable, Hashable +from typing import Any + +from django.db.models import Field +from django.db.models.deletion import Collector +from django.db.models.query import QuerySet + +def migration_fingerprint(value: Any) -> Hashable: ... + +class PolymorphicGuard: + action: Callable[[Collector, Field[Any, Any], QuerySet[Any], str], None] + def __init__(self, action: Callable[[Collector, Field[Any, Any], QuerySet[Any], str], None]) -> None: ... + def __call__(self, collector: Collector, field: Field[Any, Any], sub_objs: QuerySet[Any], using: str) -> None: ... + @property + def migration_key(self) -> Hashable: ... + def __eq__(self, other: object) -> bool: ... + def __hash__(self) -> int: ... + +class PolymorphicGuardSerializer: + value: PolymorphicGuard + def serialize(self) -> tuple[str, set[str]]: ... diff --git a/stubs/django-polymorphic/polymorphic/formsets/__init__.pyi b/stubs/django-polymorphic/polymorphic/formsets/__init__.pyi new file mode 100644 index 000000000000..895de671f513 --- /dev/null +++ b/stubs/django-polymorphic/polymorphic/formsets/__init__.pyi @@ -0,0 +1,27 @@ +from .generic import ( + BaseGenericPolymorphicInlineFormSet as BaseGenericPolymorphicInlineFormSet, + GenericPolymorphicFormSetChild as GenericPolymorphicFormSetChild, + generic_polymorphic_inlineformset_factory as generic_polymorphic_inlineformset_factory, +) +from .models import ( + BasePolymorphicInlineFormSet as BasePolymorphicInlineFormSet, + BasePolymorphicModelFormSet as BasePolymorphicModelFormSet, + PolymorphicFormSetChild as PolymorphicFormSetChild, + UnsupportedChildType as UnsupportedChildType, + polymorphic_child_forms_factory as polymorphic_child_forms_factory, + polymorphic_inlineformset_factory as polymorphic_inlineformset_factory, + 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/stubs/django-polymorphic/polymorphic/formsets/generic.pyi b/stubs/django-polymorphic/polymorphic/formsets/generic.pyi new file mode 100644 index 000000000000..51ea7d630479 --- /dev/null +++ b/stubs/django-polymorphic/polymorphic/formsets/generic.pyi @@ -0,0 +1,37 @@ +from collections.abc import Callable, Iterable +from typing import Any + +from django.contrib.contenttypes.forms import BaseGenericInlineFormSet +from django.db import models +from django.forms import ModelForm + +from .models import BasePolymorphicModelFormSet, PolymorphicFormSetChild + +class GenericPolymorphicFormSetChild(PolymorphicFormSetChild): + ct_field: str + fk_field: str + def __init__(self, *args: Any, ct_field: str = "content_type", fk_field: str = "object_id", **kwargs: Any) -> None: ... + def get_form(self, ct_field: str = "content_type", fk_field: str = "object_id", **kwargs: Any) -> type[ModelForm[Any]]: ... + +class BaseGenericPolymorphicInlineFormSet(BaseGenericInlineFormSet[Any, Any], BasePolymorphicModelFormSet): ... + +def generic_polymorphic_inlineformset_factory( + model: type[models.Model], + formset_children: Iterable[PolymorphicFormSetChild], + form: type[ModelForm[Any]] = ..., + formset: type[BaseGenericPolymorphicInlineFormSet] = ..., + ct_field: str = "content_type", + fk_field: str = "object_id", + fields: list[str] | None = None, + exclude: list[str] | None = None, + extra: int = 1, + can_order: bool = False, + can_delete: bool = True, + max_num: int | None = None, + formfield_callback: Callable[..., Any] | None = None, + validate_max: bool = False, + for_concrete_model: bool = True, + min_num: int | None = None, + validate_min: bool = False, + child_form_kwargs: dict[str, Any] | None = None, +) -> type[BaseGenericPolymorphicInlineFormSet]: ... diff --git a/stubs/django-polymorphic/polymorphic/formsets/models.pyi b/stubs/django-polymorphic/polymorphic/formsets/models.pyi new file mode 100644 index 000000000000..a01ff05fab30 --- /dev/null +++ b/stubs/django-polymorphic/polymorphic/formsets/models.pyi @@ -0,0 +1,102 @@ +from collections.abc import Callable, Iterable +from typing import Any + +from django.contrib.contenttypes.models import ContentType +from django.db import models +from django.forms import BaseForm, BaseInlineFormSet, BaseModelFormSet, Media, ModelForm + +class UnsupportedChildType(LookupError): ... + +class PolymorphicFormSetChild: + model: type[models.Model] + fields: list[str] | None + exclude: tuple[str, ...] | list[str] + formfield_callback: Callable[..., Any] | None + widgets: dict[str, Any] | None + localized_fields: list[str] | None + labels: dict[str, str] | None + help_texts: dict[str, str] | None + error_messages: dict[str, dict[str, str]] | None + def __init__( + self, + model: type[models.Model], + form: type[ModelForm[Any]] = ..., + fields: list[str] | None = None, + exclude: tuple[str, ...] | list[str] | None = None, + formfield_callback: Callable[..., Any] | None = None, + widgets: dict[str, Any] | None = None, + localized_fields: list[str] | None = None, + labels: dict[str, str] | None = None, + help_texts: dict[str, str] | None = None, + error_messages: dict[str, dict[str, str]] | None = None, + ) -> None: ... + @property + def content_type(self) -> ContentType: ... + def get_form(self, **kwargs: Any) -> type[ModelForm[Any]]: ... + +def polymorphic_child_forms_factory( + formset_children: Iterable[PolymorphicFormSetChild], **kwargs: Any +) -> dict[type[models.Model], type[ModelForm[Any]]]: ... + +class BasePolymorphicModelFormSet(BaseModelFormSet[Any, Any]): + child_forms: dict[type[models.Model], type[ModelForm[Any]]] + queryset_data: Any + @property + def media(self) -> Media: ... + @property + def empty_forms(self) -> list[BaseForm]: ... + @property + def empty_form(self) -> BaseForm: ... + def get_form_class(self, model: type[models.Model]) -> type[ModelForm[Any]]: ... + def is_multipart(self) -> bool: ... + +class BasePolymorphicInlineFormSet(BaseInlineFormSet[Any, Any, Any], BasePolymorphicModelFormSet): ... + +def polymorphic_modelformset_factory( + model: type[models.Model], + formset_children: Iterable[PolymorphicFormSetChild], + formset: type[BasePolymorphicModelFormSet] = ..., + form: type[ModelForm[Any]] = ..., + fields: list[str] | None = None, + exclude: list[str] | None = None, + extra: int = 1, + can_order: bool = False, + can_delete: bool = True, + max_num: int | None = None, + formfield_callback: Callable[..., Any] | None = None, + widgets: dict[str, Any] | None = None, + validate_max: bool = False, + localized_fields: list[str] | None = None, + labels: dict[str, str] | None = None, + help_texts: dict[str, str] | None = None, + error_messages: dict[str, dict[str, str]] | None = None, + min_num: int | None = None, + validate_min: bool = False, + field_classes: dict[str, type[Any]] | None = None, + child_form_kwargs: dict[str, Any] | None = None, +) -> type[BasePolymorphicModelFormSet]: ... +def polymorphic_inlineformset_factory( + parent_model: type[models.Model], + model: type[models.Model], + formset_children: Iterable[PolymorphicFormSetChild], + formset: type[BasePolymorphicInlineFormSet] = ..., + fk_name: str | None = None, + form: type[ModelForm[Any]] = ..., + fields: list[str] | None = None, + exclude: list[str] | None = None, + extra: int = 1, + can_order: bool = False, + can_delete: bool = True, + max_num: int | None = None, + formfield_callback: Callable[..., Any] | None = None, + widgets: dict[str, Any] | None = None, + validate_max: bool = False, + localized_fields: list[str] | None = None, + labels: dict[str, str] | None = None, + help_texts: dict[str, str] | None = None, + error_messages: dict[str, dict[str, str]] | None = None, + min_num: int | None = None, + validate_min: bool = False, + field_classes: dict[str, type[Any]] | None = None, + child_form_kwargs: dict[str, Any] | None = None, +) -> type[BasePolymorphicInlineFormSet]: ... diff --git a/stubs/django-polymorphic/polymorphic/formsets/utils.pyi b/stubs/django-polymorphic/polymorphic/formsets/utils.pyi new file mode 100644 index 000000000000..ce0b1b829160 --- /dev/null +++ b/stubs/django-polymorphic/polymorphic/formsets/utils.pyi @@ -0,0 +1,3 @@ +from django.forms import Media + +def add_media(dest: Media, media: Media) -> None: ... diff --git a/stubs/django-polymorphic/polymorphic/managers.pyi b/stubs/django-polymorphic/polymorphic/managers.pyi new file mode 100644 index 000000000000..da512dd87b8f --- /dev/null +++ b/stubs/django-polymorphic/polymorphic/managers.pyi @@ -0,0 +1,22 @@ +from collections.abc import Iterable +from typing import Any +from typing_extensions import Self, TypeVar + +from django.db import models + +from .query import PolymorphicQuerySet as PolymorphicQuerySet + +__all__ = ["PolymorphicManager", "PolymorphicQuerySet"] + +_T = TypeVar("_T", bound=models.Model, default=models.Model) + +class PolymorphicManager(models.Manager[_T]): + queryset_class: type[PolymorphicQuerySet[_T]] + @classmethod + def from_queryset(cls, queryset_class: type[models.query.QuerySet[_T, _T]], class_name: str | None = None) -> type[Self]: ... + def get_queryset(self) -> PolymorphicQuerySet[_T]: ... + def non_polymorphic(self) -> PolymorphicQuerySet[_T]: ... + def instance_of(self, *args: type[models.Model]) -> PolymorphicQuerySet[_T]: ... + def not_instance_of(self, *args: type[models.Model]) -> PolymorphicQuerySet[_T]: ... + def get_real_instances(self, base_result_objects: Iterable[_T] | None = None) -> list[_T]: ... + def create_from_super(self, obj: models.Model, **kwargs: Any) -> _T: ... diff --git a/stubs/django-polymorphic/polymorphic/models.pyi b/stubs/django-polymorphic/polymorphic/models.pyi new file mode 100644 index 000000000000..b0bc7267d6bc --- /dev/null +++ b/stubs/django-polymorphic/polymorphic/models.pyi @@ -0,0 +1,44 @@ +from collections.abc import Iterable +from typing import ClassVar +from typing_extensions import Self + +from django.contrib.contenttypes.models import ContentType +from django.db import models +from django.db.models import Q +from django.db.models.base import ModelBase +from django.utils.functional import classproperty + +from .base import PolymorphicModelBase as PolymorphicModelBase +from .managers import PolymorphicManager as PolymorphicManager + +class PolymorphicTypeUndefined(LookupError): ... +class PolymorphicTypeInvalid(RuntimeError): ... + +class PolymorphicModel(models.Model, metaclass=PolymorphicModelBase): + _meta_skip: ClassVar[bool] = True + polymorphic_model_marker: ClassVar[bool] = True + polymorphic_query_multiline_output: ClassVar[bool] = False + polymorphic_ctype: models.ForeignKey[ContentType | None, ContentType | None] + polymorphic_internal_model_fields: ClassVar[list[str]] = ["polymorphic_ctype"] + objects: ClassVar[PolymorphicManager[Self]] + @classproperty + def polymorphic_primary_key_name(cls) -> str: ... + + class Meta: + abstract: ClassVar[bool] = True + + @classmethod + def translate_polymorphic_Q_object(cls, q: Q) -> Q: ... + def pre_save_polymorphic(self, using: str = ...) -> None: ... + def save( + self, + force_insert: bool | tuple[ModelBase, ...] = False, + force_update: bool = False, + using: str | None = None, + update_fields: Iterable[str] | None = None, + ) -> None: ... + def get_real_instance_class(self) -> type[Self] | None: ... + def get_real_concrete_instance_class_id(self) -> int | None: ... + def get_real_concrete_instance_class(self) -> type[Self] | None: ... + def get_real_instance(self) -> Self: ... + def delete(self, using: str | None = None, keep_parents: bool = False) -> tuple[int, dict[str, int]]: ... diff --git a/stubs/django-polymorphic/polymorphic/query.pyi b/stubs/django-polymorphic/polymorphic/query.pyi new file mode 100644 index 000000000000..423776d4ec2a --- /dev/null +++ b/stubs/django-polymorphic/polymorphic/query.pyi @@ -0,0 +1,64 @@ +from collections.abc import Collection, Iterable, Iterator, Sequence +from typing import Any, overload +from typing_extensions import Self, TypeVar + +from django.db import models +from django.db.models.expressions import Combinable +from django.db.models.query import ModelIterable, QuerySet + +from .query_translate import ( + translate_polymorphic_field_path as translate_polymorphic_field_path, + translate_polymorphic_filter_definitions_in_args as translate_polymorphic_filter_definitions_in_args, + translate_polymorphic_filter_definitions_in_kwargs as translate_polymorphic_filter_definitions_in_kwargs, + translate_polymorphic_Q_object as translate_polymorphic_Q_object, +) + +_T = TypeVar("_T", bound=models.Model, default=models.Model) + +Polymorphic_QuerySet_objects_per_request: int = 2000 + +class _Inconsistent: ... + +class PolymorphicModelIterable(ModelIterable[_T]): + def __iter__(self) -> Iterator[_T]: ... + def _polymorphic_iterator(self, base_iter: Iterator[_T]) -> Iterator[_T]: ... + +def transmogrify(cls: type[_T], obj: models.Model) -> _T: ... + +class PolymorphicQuerySet(QuerySet[_T]): + polymorphic_disabled: bool + polymorphic_deferred_loading: tuple[set[str], bool] + def __init__(self, *args: Any, **kwargs: Any) -> None: ... + def _clone(self, *args: Any, **kwargs: Any) -> Self: ... + @classmethod + def as_manager(cls) -> models.Manager[_T]: ... + def bulk_create( + self, + objs: Iterable[_T], + batch_size: int | None = None, + ignore_conflicts: bool = False, + update_conflicts: bool = False, + update_fields: Collection[str] | None = None, + unique_fields: Collection[str] | None = None, + ) -> list[_T]: ... + def non_polymorphic(self) -> Self: ... + def instance_of(self, *args: type[models.Model]) -> Self: ... + def not_instance_of(self, *args: type[models.Model]) -> Self: ... + def _filter_or_exclude(self, negate: bool, args: Any, kwargs: Any) -> Self: ... + def order_by(self, *field_names: str | Combinable) -> Self: ... + @overload + def defer(self, field: None, /) -> Self: ... + @overload + def defer(self, *fields: str) -> Self: ... + def only(self, *fields: str) -> Self: ... + def _polymorphic_add_deferred_loading(self, field_names: Iterable[str]) -> None: ... + def _polymorphic_add_immediate_loading(self, field_names: Iterable[str]) -> None: ... + def _process_aggregate_args(self, args: Sequence[Any], kwargs: dict[str, Any]) -> None: ... + def annotate(self, *args: Any, **kwargs: Any) -> Self: ... + def aggregate(self, *args: Any, **kwargs: Any) -> dict[str, Any]: ... + def _values(self, *args: Any, **kwargs: Any) -> Self: ... + def _get_real_instances(self, base_result_objects: Iterable[_T]) -> list[_T]: ... + def get_real_instances(self, base_result_objects: Iterable[_T] | None = None) -> list[_T]: ... + def delete(self) -> tuple[int, dict[str, int]]: ... + + class _p_list_class(list[Any]): ... diff --git a/stubs/django-polymorphic/polymorphic/query_translate.pyi b/stubs/django-polymorphic/polymorphic/query_translate.pyi new file mode 100644 index 000000000000..a157c5ed9ec6 --- /dev/null +++ b/stubs/django-polymorphic/polymorphic/query_translate.pyi @@ -0,0 +1,19 @@ +from collections.abc import Sequence +from typing import Any + +from django.db import models +from django.db.models import Q + +def translate_polymorphic_filter_definitions_in_kwargs( + queryset_model: type[models.Model], kwargs: dict[str, Any], using: str = ... +) -> list[Q]: ... +def translate_polymorphic_Q_object( + queryset_model: type[models.Model], potential_q_object: Q | Any, using: str = ... +) -> Q | Any: ... +def translate_polymorphic_filter_definitions_in_args( + queryset_model: type[models.Model], args: Sequence[Q], using: str = ... +) -> list[Q]: ... +def translate_polymorphic_field_path(queryset_model: type[models.Model], field_path: str) -> str: ... +def create_instanceof_q( + modellist: type[models.Model] | Sequence[type[models.Model]], not_instance_of: bool = False, using: str = ... +) -> Q | None: ... diff --git a/stubs/django-polymorphic/polymorphic/related_descriptors.pyi b/stubs/django-polymorphic/polymorphic/related_descriptors.pyi new file mode 100644 index 000000000000..0a372cb8c25b --- /dev/null +++ b/stubs/django-polymorphic/polymorphic/related_descriptors.pyi @@ -0,0 +1,10 @@ +from typing import Any + +from django.db.models.fields.related_descriptors import ForwardOneToOneDescriptor, ReverseOneToOneDescriptor +from django.db.models.query import QuerySet + +class NonPolymorphicForwardOneToOneDescriptor(ForwardOneToOneDescriptor[Any]): + def get_queryset(self, **hints: Any) -> QuerySet[Any]: ... + +class NonPolymorphicReverseOneToOneDescriptor(ReverseOneToOneDescriptor[Any, Any]): + def get_queryset(self, **hints: Any) -> QuerySet[Any]: ... diff --git a/stubs/django-polymorphic/polymorphic/showfields.pyi b/stubs/django-polymorphic/polymorphic/showfields.pyi new file mode 100644 index 000000000000..7af1608dd5e3 --- /dev/null +++ b/stubs/django-polymorphic/polymorphic/showfields.pyi @@ -0,0 +1,28 @@ +import re +from collections.abc import Sequence + +RE_DEFERRED: re.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: int | None + polymorphic_showfield_max_field_width: int + polymorphic_showfield_old_format: bool + def _showfields_get_content(self, field_name: str, field_type: type = ...) -> str: ... + def _showfields_add_regular_fields(self, parts: list[tuple[bool, str, str]]) -> None: ... + def _showfields_add_dynamic_fields( + self, field_list: Sequence[str], title: str, parts: list[tuple[bool, str, str]] + ) -> None: ... + +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/stubs/django-polymorphic/polymorphic/templatetags/__init__.pyi b/stubs/django-polymorphic/polymorphic/templatetags/__init__.pyi new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/stubs/django-polymorphic/polymorphic/templatetags/polymorphic_admin_tags.pyi b/stubs/django-polymorphic/polymorphic/templatetags/polymorphic_admin_tags.pyi new file mode 100644 index 000000000000..ae979f2d9a44 --- /dev/null +++ b/stubs/django-polymorphic/polymorphic/templatetags/polymorphic_admin_tags.pyi @@ -0,0 +1,16 @@ +from typing_extensions import Self + +from django.template import Context, Library, Node, NodeList +from django.template.base import FilterExpression, Parser, Token + +register: Library + +class BreadcrumbScope(Node): + base_opts: FilterExpression + nodelist: NodeList + def __init__(self, base_opts: FilterExpression, nodelist: NodeList) -> None: ... + @classmethod + def parse(cls, parser: Parser, token: Token) -> Self: ... + def render(self, context: Context) -> str: ... + +def breadcrumb_scope(parser: Parser, token: Token) -> BreadcrumbScope: ... diff --git a/stubs/django-polymorphic/polymorphic/templatetags/polymorphic_formset_tags.pyi b/stubs/django-polymorphic/polymorphic/templatetags/polymorphic_formset_tags.pyi new file mode 100644 index 000000000000..cd0b374412d5 --- /dev/null +++ b/stubs/django-polymorphic/polymorphic/templatetags/polymorphic_formset_tags.pyi @@ -0,0 +1,13 @@ +from collections.abc import Generator +from typing import Any + +from django.db import models +from django.forms import BaseForm, BaseFormSet +from django.template import Library + +register: Library + +def include_empty_form(formset: BaseFormSet[Any]) -> Generator[BaseForm, None, None]: ... +def as_script_options(formset: BaseFormSet[Any]) -> str: ... +def as_form_type(form: BaseForm) -> str: ... +def as_model_name(model: type[models.Model]) -> str: ... diff --git a/stubs/django-polymorphic/polymorphic/utils.pyi b/stubs/django-polymorphic/polymorphic/utils.pyi new file mode 100644 index 000000000000..597631defb5d --- /dev/null +++ b/stubs/django-polymorphic/polymorphic/utils.pyi @@ -0,0 +1,27 @@ +from dataclasses import dataclass +from typing import Any + +from django.db import models +from django.db.models import Q +from django.db.models.query import QuerySet + +from .models import PolymorphicModel + +@dataclass(frozen=True) +class ParentLinkInfo: + model: type[models.Model] + link: models.Field[Any, Any] + +def reset_polymorphic_ctype(*models: type[PolymorphicModel], **filters: Any) -> None: ... +def sort_by_subclass(*classes: type[models.Model]) -> list[type[models.Model]]: ... +def get_base_polymorphic_model( + ChildModel: type[PolymorphicModel], allow_abstract: bool = False +) -> type[PolymorphicModel] | None: ... +def route_to_ancestor(model_class: type[models.Model], ancestor_model: type[models.Model]) -> list[ParentLinkInfo]: ... +def is_model_loaded(model: type[models.Model]) -> bool: ... +def concrete_descendants(model_class: type[models.Model], include_proxy: bool = False) -> list[type[models.Model]]: ... +def prepare_for_copy(obj: models.Model) -> None: ... +def lazy_ctype(model: type[models.Model], using: str = ...) -> int | QuerySet[Any]: ... +def _lazy_ctype(model: type[models.Model], using: str = ...) -> int | Q: ... +def _map_queryname_to_class(base_model: type[models.Model], qry_name: str) -> type[models.Model]: ... +def _clear_utility_caches() -> None: ...