diff --git a/stubs/django-filter/django_filters/fields.pyi b/stubs/django-filter/django_filters/fields.pyi index 1d9678da586e..07285856082d 100644 --- a/stubs/django-filter/django_filters/fields.pyi +++ b/stubs/django-filter/django_filters/fields.pyi @@ -1,8 +1,11 @@ -from collections.abc import Sequence -from typing import Any, NamedTuple +from collections.abc import Iterable, Mapping, Sequence +from typing import Any, Callable, NamedTuple from typing_extensions import TypeAlias from django import forms +from django.db.models import Choices +from django.forms import Widget +from django_stubs_ext import StrOrPromise DJANGO_50: bool @@ -15,30 +18,49 @@ DJANGO_50: bool # `widget = Select` will not typecheck. # `Any` gives too much freedom, but does not create false positives. _ClassLevelWidget: TypeAlias = Any +_ValidatorCallable: TypeAlias = Callable[[Any], None] + +# Based on django-stubs utils/choices.pyi +_Choice: TypeAlias = tuple[Any, Any] +_ChoiceNamedGroup: TypeAlias = tuple[str, Iterable[_Choice]] +_Choices: TypeAlias = Iterable[_Choice | _ChoiceNamedGroup] +_ChoicesMapping: TypeAlias = Mapping[Any, Any] +_ChoicesInput: TypeAlias = _Choices | _ChoicesMapping | type[Choices] | Callable[[], _Choices | _ChoicesMapping] class RangeField(forms.MultiValueField): widget: _ClassLevelWidget = ... def __init__( - self, fields: tuple[forms.Field, forms.Field] | None = None, *args: Any, **kwargs: Any + self, + fields: tuple[forms.Field, forms.Field] | None = None, + *, + # Inherited from MultiValueField + require_all_fields: bool = True, + required: bool = ..., + widget: Widget | type[Widget] | None = ..., + label: StrOrPromise | None = ..., + initial: Any | None = ..., + help_text: StrOrPromise = ..., + error_messages: Mapping[str, StrOrPromise] | None = ..., + show_hidden_initial: bool = ..., + validators: Sequence[_ValidatorCallable] = ..., + localize: bool = ..., + disabled: bool = ..., + label_suffix: str | None = ..., ) -> None: ... # Args/kwargs can be any field params, passes to parent def compress(self, data_list: list[Any] | None) -> slice | None: ... # Data list elements can be any field value type class DateRangeField(RangeField): widget: _ClassLevelWidget = ... - def __init__(self, *args: Any, **kwargs: Any) -> None: ... # Args/kwargs can be any field params for parent def compress(self, data_list: list[Any] | None) -> slice | None: ... # Date values in list can be any date type class DateTimeRangeField(RangeField): widget: _ClassLevelWidget = ... - def __init__(self, *args: Any, **kwargs: Any) -> None: ... # Args/kwargs can be any field params for parent class IsoDateTimeRangeField(RangeField): widget: _ClassLevelWidget = ... - def __init__(self, *args: Any, **kwargs: Any) -> None: ... # Args/kwargs can be any field params for parent class TimeRangeField(RangeField): widget: _ClassLevelWidget = ... - def __init__(self, *args: Any, **kwargs: Any) -> None: ... # Args/kwargs can be any field params for parent class Lookup(NamedTuple): value: Any # Lookup values can be any filterable type @@ -46,7 +68,22 @@ class Lookup(NamedTuple): class LookupChoiceField(forms.MultiValueField): def __init__( - self, field: forms.Field, lookup_choices: Sequence[tuple[str, str]], *args: Any, **kwargs: Any + self, + field: forms.Field, + lookup_choices: Sequence[tuple[str, str]], + *, + require_all_fields: bool = True, + required: bool = ..., + widget: Widget | type[Widget] | None = ..., + label: StrOrPromise | None = ..., + initial: Any | None = ..., + help_text: StrOrPromise = ..., + error_messages: Mapping[str, StrOrPromise] | None = ..., + show_hidden_initial: bool = ..., + validators: Sequence[_ValidatorCallable] = ..., + localize: bool = ..., + disabled: bool = ..., + label_suffix: str | None = ..., ) -> None: ... # Args/kwargs can be any field params, uses kwargs for empty_label def compress(self, data_list: list[Any] | None) -> Lookup | None: ... # Data list can contain any lookup components @@ -57,7 +94,6 @@ class IsoDateTimeField(forms.DateTimeField): class BaseCSVField(forms.Field): base_widget_class: _ClassLevelWidget = ... - def __init__(self, *args: Any, **kwargs: Any) -> None: ... # Args/kwargs can be any field params for widget config def clean(self, value: Any) -> Any: ... # Cleaned values can be any valid field type class BaseRangeField(BaseCSVField): @@ -80,17 +116,51 @@ class ModelChoiceIterator(forms.models.ModelChoiceIterator): class ChoiceIteratorMixin: null_label: str | None null_value: Any # Null choice values can be any type (None, empty string, etc.) - def __init__(self, *args: Any, **kwargs: Any) -> None: ... # Args/kwargs can be any field params for null config + def __init__(self, *, null_label: str | None, null_value: Any) -> None: ... class ChoiceField(ChoiceIteratorMixin, forms.ChoiceField): iterator = ChoiceIterator empty_label: str | None - def __init__(self, *args: Any, **kwargs: Any) -> None: ... # Args/kwargs can be any field params for label config + def __init__( + self, + *, + choices: _ChoicesInput = (), + required: bool = ..., + widget: Widget | type[Widget] | None = ..., + label: StrOrPromise | None = ..., + initial: Any | None = ..., + help_text: StrOrPromise = ..., + error_messages: Mapping[str, StrOrPromise] | None = ..., + show_hidden_initial: bool = ..., + validators: Sequence[_ValidatorCallable] = ..., + localize: bool = ..., + disabled: bool = ..., + label_suffix: str | None = ..., + null_label: str | None, + null_value: Any, + ) -> None: ... class MultipleChoiceField(ChoiceIteratorMixin, forms.MultipleChoiceField): iterator = ChoiceIterator empty_label: str | None - def __init__(self, *args: Any, **kwargs: Any) -> None: ... # Args/kwargs can be any field params, sets empty_label + def __init__( + self, + *, + choices: _ChoicesInput = (), + required: bool = ..., + widget: Widget | type[Widget] | None = ..., + label: StrOrPromise | None = ..., + initial: Any | None = ..., + help_text: StrOrPromise = ..., + error_messages: Mapping[str, StrOrPromise] | None = ..., + show_hidden_initial: bool = ..., + validators: Sequence[_ValidatorCallable] = ..., + localize: bool = ..., + disabled: bool = ..., + label_suffix: str | None = ..., + null_label: str | None, + null_value: Any, + ) -> None: ... class ModelChoiceField(ChoiceIteratorMixin, forms.ModelChoiceField[Any]): iterator = ModelChoiceIterator diff --git a/stubs/django-filter/django_filters/filters.pyi b/stubs/django-filter/django_filters/filters.pyi index 714ddc89f720..b2439fefd6db 100644 --- a/stubs/django-filter/django_filters/filters.pyi +++ b/stubs/django-filter/django_filters/filters.pyi @@ -87,7 +87,19 @@ class BooleanFilter(Filter): class ChoiceFilter(Filter): field_class: type[Any] # Base class for choice-based filters null_value: Any # Null value can be any type (None, empty string, etc.) - def __init__(self, *args: Any, **kwargs: Any) -> None: ... # Uses kwargs for null_value config + def __init__( + self, + field_name: str | None = None, + lookup_expr: str | None = None, + *, + null_value: Any = None, + # Inherited from Filter + label: str | None = None, + method: Callable[..., Any] | str | None = None, # Filter methods can return various types + distinct: bool = False, + exclude: bool = False, + **kwargs: Any, # Field kwargs stored as extra (required, help_text, etc.) + ) -> None: ... def filter(self, qs: QuerySet[Any], value: Any) -> QuerySet[Any]: ... class TypedChoiceFilter(Filter): @@ -101,7 +113,20 @@ class MultipleChoiceFilter(Filter): always_filter: bool conjoined: bool null_value: Any # Multiple choice null values vary by implementation - def __init__(self, *args: Any, **kwargs: Any) -> None: ... # Uses kwargs for distinct, conjoined, null_value config + def __init__( + self, + field_name: str | None = None, + lookup_expr: str | None = None, + *, + distinct: bool = True, # Overrides distinct default + conjoined: bool = False, + null_value: Any = None, + # Inherited from Filter + label: str | None = None, + method: Callable[..., Any] | str | None = None, # Filter methods can return various types + exclude: bool = False, + **kwargs: Any, # Field kwargs stored as extra (required, help_text, etc.) + ) -> None: ... def is_noop(self, qs: QuerySet[Any], value: Any) -> bool: ... # Value can be any filter input def filter(self, qs: QuerySet[Any], value: Any) -> QuerySet[Any]: ... def get_filter_predicate(self, v: Any) -> Q: ... # Predicate value can be any filter input type @@ -126,7 +151,7 @@ class DurationFilter(Filter): class QuerySetRequestMixin: queryset: QuerySet[Any] | None - def __init__(self, *args: Any, **kwargs: Any) -> None: ... # Uses kwargs for queryset config + def __init__(self, *, queryset: QuerySet[Any] | None) -> None: ... def get_request(self) -> Any: ... # Request can be HttpRequest or other request types def get_queryset(self, request: Any) -> QuerySet[Any]: ... # Request parameter accepts various request types @property @@ -134,7 +159,21 @@ class QuerySetRequestMixin: class ModelChoiceFilter(QuerySetRequestMixin, ChoiceFilter): field_class: type[ModelChoiceField] # More specific than parent ChoiceField - def __init__(self, *args: Any, **kwargs: Any) -> None: ... # Uses kwargs for empty_label config + def __init__( + self, + field_name: str | None = None, + lookup_expr: str | None = None, + *, + queryset: QuerySet[Any] | None, + # Inherited from ChoiceFilter + null_value: Any = None, + # Inherited from Filter + label: str | None = None, + method: Callable[..., Any] | str | None = None, # Filter methods can return various types + distinct: bool = False, + exclude: bool = False, + **kwargs: Any, # Field kwargs stored as extra (required, help_text, etc.) + ) -> None: ... class ModelMultipleChoiceFilter(QuerySetRequestMixin, MultipleChoiceFilter): field_class: type[ModelMultipleChoiceField] # More specific than parent MultipleChoiceField @@ -159,7 +198,20 @@ class DateRangeFilter(ChoiceFilter): choices: list[tuple[str, str]] | None filters: dict[str, Filter] | None def __init__( - self, choices: list[tuple[str, str]] | None = None, filters: dict[str, Filter] | None = None, *args: Any, **kwargs: Any + self, + choices: list[tuple[str, str]] | None = None, + filters: dict[str, Filter] | None = None, + field_name: str | None = None, + lookup_expr: str | None = None, + *, + # Inherited from ChoiceFilter + null_value: Any = None, + # Inherited from Filter + label: str | None = None, + method: Callable[..., Any] | str | None = None, # Filter methods can return various types + distinct: bool = False, + exclude: bool = False, + **kwargs: Any, # Field kwargs stored as extra (required, help_text, etc.) ) -> None: ... # Uses args/kwargs for choice and filter configuration def filter(self, qs: QuerySet[Any], value: Any) -> QuerySet[Any]: ... @@ -186,14 +238,11 @@ class AllValuesMultipleFilter(MultipleChoiceFilter): class BaseCSVFilter(Filter): base_field_class: type[BaseCSVField] = ... field_class: type[Any] # Base class for CSV-based filters - def __init__(self, *args: Any, **kwargs: Any) -> None: ... # Uses kwargs for help_text and widget config -class BaseInFilter(BaseCSVFilter): - def __init__(self, *args: Any, **kwargs: Any) -> None: ... # Sets lookup_expr and passes through +class BaseInFilter(BaseCSVFilter): ... class BaseRangeFilter(BaseCSVFilter): base_field_class: type[BaseRangeField] = ... - def __init__(self, *args: Any, **kwargs: Any) -> None: ... # Sets lookup_expr and passes through class LookupChoiceFilter(Filter): field_class: type[forms.CharField] @@ -205,7 +254,15 @@ class LookupChoiceFilter(Filter): field_name: str | None = None, lookup_choices: list[tuple[str, str]] | None = None, field_class: type[Field] | None = None, - **kwargs: Any, # Handles empty_label and other field config + *, + # Inherited from ChoiceFilter + null_value: Any = None, + # Inherited from Filter + label: str | None = None, + method: Callable[..., Any] | str | None = None, # Filter methods can return various types + distinct: bool = False, + exclude: bool = False, + **kwargs: Any, # Field kwargs stored as extra (required, help_text, etc.) ) -> None: ... @classmethod def normalize_lookup(cls, lookup: Any) -> tuple[Any, str]: ... @@ -219,7 +276,21 @@ class OrderingFilter(BaseCSVFilter, ChoiceFilter): field_class: type[BaseCSVField] # Inherits CSV field behavior for comma-separated ordering descending_fmt: str param_map: dict[str, str] | None - def __init__(self, *args: Any, **kwargs: Any) -> None: ... # Uses kwargs for fields and field_labels config + def __init__( + self, + field_name: str | None = None, + lookup_expr: str | None = None, + *, + # Inherited from ChoiceFilter + null_value: Any = None, + # Inherited from Filter + field_labels: dict[Any, Any] | None = None, + label: str | None = None, + method: Callable[..., Any] | str | None = None, # Filter methods can return various types + distinct: bool = False, + exclude: bool = False, + **kwargs: Any, # Field kwargs stored as extra (required, help_text, etc.) + ) -> None: ... def get_ordering_value(self, param: str) -> str: ... def filter(self, qs: QuerySet[Any], value: Any) -> QuerySet[Any]: ... @classmethod diff --git a/stubs/django-filter/django_filters/rest_framework/__init__.pyi b/stubs/django-filter/django_filters/rest_framework/__init__.pyi index adb475260a84..8d5d8ac63dde 100644 --- a/stubs/django-filter/django_filters/rest_framework/__init__.pyi +++ b/stubs/django-filter/django_filters/rest_framework/__init__.pyi @@ -1,3 +1,38 @@ from .backends import DjangoFilterBackend as DjangoFilterBackend from .filters import * from .filterset import FilterSet as FilterSet + +__all__ = [ + "DjangoFilterBackend", + "FilterSet", + "BooleanFilter", + "AllValuesFilter", + "AllValuesMultipleFilter", + "BaseCSVFilter", + "BaseInFilter", + "BaseRangeFilter", + "CharFilter", + "ChoiceFilter", + "DateFilter", + "DateFromToRangeFilter", + "DateRangeFilter", + "DateTimeFilter", + "DateTimeFromToRangeFilter", + "DurationFilter", + "Filter", + "IsoDateTimeFilter", + "IsoDateTimeFromToRangeFilter", + "LookupChoiceFilter", + "ModelChoiceFilter", + "ModelMultipleChoiceFilter", + "MultipleChoiceFilter", + "NumberFilter", + "NumericRangeFilter", + "OrderingFilter", + "RangeFilter", + "TimeFilter", + "TimeRangeFilter", + "TypedChoiceFilter", + "TypedMultipleChoiceFilter", + "UUIDFilter", +] diff --git a/stubs/django-filter/django_filters/rest_framework/filters.pyi b/stubs/django-filter/django_filters/rest_framework/filters.pyi index c289dc59509a..9dec2084d15f 100644 --- a/stubs/django-filter/django_filters/rest_framework/filters.pyi +++ b/stubs/django-filter/django_filters/rest_framework/filters.pyi @@ -1,5 +1,3 @@ -from typing import Any - from ..filters import ( AllValuesFilter, AllValuesMultipleFilter, @@ -67,5 +65,4 @@ __all__ = [ ] # REST framework specific BooleanFilter that uses BooleanWidget by default -class BooleanFilter(_BaseBooleanFilter): - def __init__(self, *args: Any, **kwargs: Any) -> None: ... # Accepts any filter initialization params +class BooleanFilter(_BaseBooleanFilter): ... diff --git a/stubs/django-filter/django_filters/widgets.pyi b/stubs/django-filter/django_filters/widgets.pyi index ab1c51636d2a..8707dc0fdbfb 100644 --- a/stubs/django-filter/django_filters/widgets.pyi +++ b/stubs/django-filter/django_filters/widgets.pyi @@ -30,7 +30,6 @@ class LinkWidget(forms.Widget): class SuffixedMultiWidget(forms.MultiWidget): suffixes: list[str] - def __init__(self, *args: Any, **kwargs: Any) -> None: ... # Args/kwargs can be any widget params for MultiWidget def suffixed(self, name: str, suffix: str) -> str: ... # Widget value and context can contain any data types def get_context(self, name: str, value: Any, attrs: dict[str, Any] | None) -> dict[str, Any]: ... @@ -70,16 +69,12 @@ class BaseCSVWidget(forms.Widget): # Can be widget class or instance - __init__ converts to instance via instantiation or deepcopy surrogate: type[Any] = ... - # Args/kwargs can be any widget params for surrogate init - def __init__(self, *args: Any, **kwargs: Any) -> None: ... # CSV widget data can contain any types def value_from_datadict(self, data: Mapping[str, Any], files: Mapping[str, Any], name: str) -> list[str]: ... # Widget value and renderer can be any type def render(self, name: str, value: Any, attrs: dict[str, Any] | None = None, renderer: Any | None = None) -> SafeString: ... -class CSVWidget(BaseCSVWidget, forms.TextInput): - # Args/kwargs can be any widget params, attrs for styling - def __init__(self, *args: Any, attrs: dict[str, Any] | None = None, **kwargs: Any) -> None: ... +class CSVWidget(BaseCSVWidget, forms.TextInput): ... class QueryArrayWidget(BaseCSVWidget, forms.TextInput): # Query array widget data can contain any types