From 45aa5c64e14a0e35b07a0b08dcce302ee9b03c0a Mon Sep 17 00:00:00 2001 From: Konstantin Alekseev Date: Sun, 3 May 2026 10:48:51 +0300 Subject: [PATCH 1/2] sync QuerySet with django-stubs --- django-stubs/db/backends/utils.pyi | 164 ++++------ django-stubs/db/models/__init__.pyi | 2 + django-stubs/db/models/expressions.pyi | 3 +- django-stubs/db/models/manager.pyi | 36 +-- django-stubs/db/models/query.pyi | 412 ++++++++++++++----------- django-stubs/db/models/utils.pyi | 13 +- django-stubs/forms/models.pyi | 4 +- django-stubs/test/testcases.pyi | 10 +- django-stubs/views/generic/list.pyi | 8 +- s/sync-files.txt | 1 + 10 files changed, 342 insertions(+), 311 deletions(-) diff --git a/django-stubs/db/backends/utils.pyi b/django-stubs/db/backends/utils.pyi index 86bebf2c6..4e08141b5 100644 --- a/django-stubs/db/backends/utils.pyi +++ b/django-stubs/db/backends/utils.pyi @@ -1,117 +1,89 @@ -import types -from collections.abc import Iterable, Iterator, Mapping, Sequence -from datetime import date, datetime, time +import datetime +from collections.abc import Iterator, Mapping, Sequence +from contextlib import AbstractContextManager from decimal import Decimal -from typing import IO, Any, Literal, TypeAlias +from logging import Logger +from types import TracebackType +from typing import Any, Literal, Protocol, TypeAlias, overload, type_check_only from uuid import UUID -import psycopg2.extensions -from django.db.backends.postgresql.base import DatabaseWrapper -from psycopg2.extensions import Column from typing_extensions import Self -logger: Any +logger: Logger + +# Protocol matching psycopg2.sql.Composable, to avoid depending psycopg2 +@type_check_only +class _Composable(Protocol): + def as_string(self, context: Any, /) -> str: ... + def __add__(self, other: Self, /) -> _Composable: ... + def __mul__(self, n: int, /) -> _Composable: ... + +_ExecuteQuery: TypeAlias = str | _Composable # Python types that can be adapted to SQL. -_Mixed: TypeAlias = None | bool | int | float | Decimal | str | bytes | datetime | UUID -_SQLType: TypeAlias = _Mixed | Sequence[_Mixed] | Mapping[str, _Mixed] +_SQLType: TypeAlias = ( + None + | bool + | int + | float + | Decimal + | str + | bytes + | datetime.date + | datetime.datetime + | UUID + | tuple[Any, ...] + | list[Any] +) +_ExecuteParameters: TypeAlias = Sequence[_SQLType] | Mapping[str, _SQLType] | None class CursorWrapper: - cursor: psycopg2.extensions.cursor = ... - db: DatabaseWrapper = ... - def __init__(self, cursor: psycopg2.extensions.cursor, db: DatabaseWrapper) -> None: ... - WRAP_ERROR_ATTRS: Any = ... + cursor: Any + db: Any + def __init__(self, cursor: Any, db: Any) -> None: ... + WRAP_ERROR_ATTRS: Any + APPS_NOT_READY_WARNING_MSG: str + + def __getattr__(self, attr: str) -> Any: ... def __iter__(self) -> Iterator[tuple[Any, ...]]: ... - def __next__(self) -> tuple[Any, ...]: ... def __enter__(self) -> Self: ... def __exit__( self, - exc_type: type[BaseException] | None, - exc_value: BaseException | None, - tb: types.TracebackType | None, + type: type[BaseException] | None, + value: BaseException | None, + traceback: TracebackType | None, ) -> None: ... def callproc( - self, - procname: str, - params: Sequence[_SQLType] | None = ..., - kparams: Mapping[str, int] | None = ..., - ) -> None: ... - def execute( - self, - sql: str, - params: Sequence[_SQLType] | Mapping[str, _SQLType] | None = ..., - ) -> None: ... - def executemany( - self, - sql: str, - param_list: Sequence[Sequence[_SQLType] | Mapping[str, _SQLType] | None], - ) -> None: ... - # copied over from psycopg2 since Django uses __getattr__ to proxy calls - @property - def description(self) -> tuple[Column, ...] | None: ... - def close(self) -> None: ... - @property - def closed(self) -> bool: ... - @property - def connection(self) -> psycopg2.extensions.connection: ... - @property - def name(self) -> str | None: ... - scrollable: bool | None - withhold: bool - def mogrify( - self, - operation: str, - parameters: Sequence[_SQLType] | Mapping[str, _SQLType] | None = ..., - ) -> bytes: ... - def setinputsizes(self, sizes: int) -> None: ... - def fetchone(self) -> tuple[Any, ...] | None: ... - def fetchmany(self, size: int = ...) -> list[tuple[Any, ...]]: ... - def fetchall(self) -> list[tuple[Any, ...]]: ... - def scroll(self, value: int, mode: Literal["relative", "absolute"] = ...) -> None: ... - arraysize: int - itersize: int - @property - def rowcount(self) -> int: ... - @property - def rownumber(self) -> int: ... - @property - def lastrowid(self) -> int | None: ... - @property - def query(self) -> str | None: ... - @property - def statusmessage(self) -> str | None: ... - def cast(self, oid: int, s: str) -> Any: ... - tzinfo_factory: Any - def nextset(self) -> None: ... - def setoutputsize(self, size: int, column: int = ...) -> None: ... - def copy_from( - self, - file: IO[str], - table: str, - sep: str = ..., - null: str = ..., - size: int = ..., - columns: Iterable[str] | None = ..., - ) -> None: ... - def copy_to( - self, - file: IO[str], - table: str, - sep: str = ..., - null: str = ..., - columns: str | None = ..., - ) -> None: ... - def copy_expert(self, sql: str, file: IO[str], size: int = ...) -> None: ... + self, procname: str, params: Sequence[Any] | None = None, kparams: dict[str, int] | None = None + ) -> Any: ... + def execute(self, sql: _ExecuteQuery, params: _ExecuteParameters | None = None) -> Any: ... + def executemany(self, sql: _ExecuteQuery, param_list: Sequence[_ExecuteParameters]) -> Any: ... class CursorDebugWrapper(CursorWrapper): - cursor: Any - db: Any + def debug_sql( + self, + sql: str | None = None, + params: _ExecuteParameters | Sequence[_ExecuteParameters] | None = None, + use_last_executed_query: bool = False, + many: bool = False, + ) -> AbstractContextManager[None]: ... -def typecast_date(s: str | None) -> date | None: ... -def typecast_time(s: str | None) -> time | None: ... -def typecast_timestamp(s: str | None) -> date | None: ... -def rev_typecast_decimal(d: Decimal) -> str: ... +def debug_transaction(connection: Any, sql: str) -> AbstractContextManager[None]: ... +def split_tzname_delta(tzname: str) -> tuple[str, str | None, str | None]: ... +@overload +def typecast_date(s: None | Literal[""]) -> None: ... # type: ignore[overload-overlap] +@overload +def typecast_date(s: str) -> datetime.date: ... +@overload +def typecast_time(s: None | Literal[""]) -> None: ... # type: ignore[overload-overlap] +@overload +def typecast_time(s: str) -> datetime.time: ... +@overload +def typecast_timestamp(s: None | Literal[""]) -> None: ... # type: ignore[overload-overlap] +@overload +def typecast_timestamp(s: str) -> datetime.datetime: ... def split_identifier(identifier: str) -> tuple[str, str]: ... -def truncate_name(identifier: str, length: int | None = ..., hash_len: int = ...) -> str: ... +def truncate_name(identifier: str, length: int | None = None, hash_len: int = 4) -> str: ... +def names_digest(*args: str, length: int) -> str: ... def format_number(value: Decimal | None, max_digits: int | None, decimal_places: int | None) -> str | None: ... def strip_quotes(table_name: str) -> str: ... diff --git a/django-stubs/db/models/__init__.pyi b/django-stubs/db/models/__init__.pyi index 30a2e4631..c26750d57 100644 --- a/django-stubs/db/models/__init__.pyi +++ b/django-stubs/db/models/__init__.pyi @@ -93,6 +93,7 @@ from .lookups import Transform as Transform from .manager import Manager as Manager from .query import Prefetch as Prefetch from .query import QuerySet as QuerySet +from .query import aprefetch_related_objects as aprefetch_related_objects from .query import prefetch_related_objects as prefetch_related_objects from .query_utils import FilteredRelation as FilteredRelation from .query_utils import Q as Q @@ -192,6 +193,7 @@ __all__ = [ "When", "Window", "WindowFrame", + "aprefetch_related_objects", "prefetch_related_objects", "signals", ] diff --git a/django-stubs/db/models/expressions.pyi b/django-stubs/db/models/expressions.pyi index 124613173..160ea03cc 100644 --- a/django-stubs/db/models/expressions.pyi +++ b/django-stubs/db/models/expressions.pyi @@ -6,7 +6,6 @@ from typing import Any, TypeAlias from django.db.models import Q, QuerySet from django.db.models.fields import Field from django.db.models.lookups import Lookup -from django.db.models.query import _BaseQuerySet from django.db.models.sql.compiler import SQLCompiler from typing_extensions import Self @@ -134,7 +133,7 @@ class Subquery(Expression): template: str = ... queryset: QuerySet[Any] = ... extra: dict[Any, Any] = ... - def __init__(self, queryset: _BaseQuerySet[Any], output_field: _OutputField | None = ..., **extra: Any) -> None: ... + def __init__(self, queryset: QuerySet[Any], output_field: _OutputField | None = ..., **extra: Any) -> None: ... class Exists(Subquery): negated: bool = ... diff --git a/django-stubs/db/models/manager.pyi b/django-stubs/db/models/manager.pyi index c84774d97..61d461a8c 100644 --- a/django-stubs/db/models/manager.pyi +++ b/django-stubs/db/models/manager.pyi @@ -1,4 +1,4 @@ -from collections.abc import Callable, Iterable, MutableMapping +from collections.abc import Callable, Iterable, Mapping from typing import Any, Generic, TypeVar from django.db.models.base import Model @@ -62,12 +62,12 @@ class ManyToManyRelatedManager(Manager[_T], Generic[_T, _V]): def add( self, *objs: QuerySet[_T] | _T | _V, - through_defaults: MutableMapping[str, Any] = ..., + through_defaults: Mapping[str, Any] = ..., ) -> None: ... async def aadd( self, *objs: QuerySet[_T] | _T | _V, - through_defaults: MutableMapping[str, Any] = ..., + through_defaults: Mapping[str, Any] = ..., ) -> None: ... def remove(self, *objs: QuerySet[_T] | _T | _V) -> None: ... async def aremove(self, *objs: QuerySet[_T] | _T | _V) -> None: ... @@ -76,55 +76,53 @@ class ManyToManyRelatedManager(Manager[_T], Generic[_T, _V]): objs: QuerySet[_T] | Iterable[_T], *, clear: bool = ..., - through_defaults: MutableMapping[str, Any] = ..., + through_defaults: Mapping[str, Any] = ..., ) -> None: ... async def aset( self, objs: QuerySet[_T] | Iterable[_T], *, clear: bool = ..., - through_defaults: MutableMapping[str, Any] = ..., + through_defaults: Mapping[str, Any] = ..., ) -> None: ... def clear(self) -> None: ... async def aclear(self) -> None: ... def create( self, - defaults: MutableMapping[str, Any] | None = ..., - through_defaults: MutableMapping[str, Any] | None = ..., + defaults: Mapping[str, Any] | None = ..., + through_defaults: Mapping[str, Any] | None = ..., **kwargs: Any, ) -> _T: ... async def acreate( self, - defaults: MutableMapping[str, Any] | None = ..., - through_defaults: MutableMapping[str, Any] | None = ..., + defaults: Mapping[str, Any] | None = ..., + through_defaults: Mapping[str, Any] | None = ..., **kwargs: Any, ) -> _T: ... def get_or_create( self, - defaults: MutableMapping[str, Any] | None = ..., + defaults: Mapping[str, Any] | None = ..., *, - through_defaults: MutableMapping[str, Any] = ..., + through_defaults: Mapping[str, Any] = ..., **kwargs: Any, ) -> tuple[_T, bool]: ... async def aget_or_create( self, - defaults: MutableMapping[str, Any] | None = ..., + defaults: Mapping[str, Any] | None = ..., *, - through_defaults: MutableMapping[str, Any] = ..., + through_defaults: Mapping[str, Any] = ..., **kwargs: Any, ) -> tuple[_T, bool]: ... def update_or_create( self, - defaults: MutableMapping[str, Any] | None = ..., - *, - through_defaults: MutableMapping[str, Any] = ..., + defaults: Mapping[str, Any] | None = None, + create_defaults: Mapping[str, Any] | None = None, **kwargs: Any, ) -> tuple[_T, bool]: ... async def aupdate_or_create( self, - defaults: MutableMapping[str, Any] | None = ..., - *, - through_defaults: MutableMapping[str, Any] = ..., + defaults: Mapping[str, Any] | None = None, + create_defaults: Mapping[str, Any] | None = None, **kwargs: Any, ) -> tuple[_T, bool]: ... diff --git a/django-stubs/db/models/query.pyi b/django-stubs/db/models/query.pyi index 9f5244655..64a77f369 100644 --- a/django-stubs/db/models/query.pyi +++ b/django-stubs/db/models/query.pyi @@ -1,255 +1,278 @@ import datetime -from collections.abc import AsyncIterator, Collection, Iterable, Iterator, MutableMapping, Reversible, Sequence, Sized -from typing import Any, Generic, TypeVar, overload +import sys +from collections.abc import AsyncIterator, Collection, Iterable, Iterator, Mapping, Sequence, Sized +from typing import Any, Generic, Literal, NamedTuple, TypeAlias, overload, type_check_only -from django.db import models +from django.db.backends.utils import _ExecuteQuery from django.db.models import Manager from django.db.models.base import Model -from django.db.models.expressions import Combinable as Combinable -from django.db.models.expressions import F as F -from django.db.models.query_utils import Q as Q +from django.db.models.expressions import Combinable, OrderBy from django.db.models.sql.query import Query, RawQuery -from typing_extensions import Self +from django.db.models.utils import AltersData +from django.utils.functional import cached_property +from typing_extensions import Self, TypeVar, override -_T = TypeVar("_T", bound=models.Model) +_T = TypeVar("_T", covariant=True) +_ContainsT = TypeVar("_ContainsT") +_Model = TypeVar("_Model", bound=Model, covariant=True) +_Row = TypeVar("_Row", covariant=True, default=_Model) # ONLY use together with _Model +_TupleT = TypeVar("_TupleT", bound=tuple[Any, ...], covariant=True) -class _BaseQuerySet(Sized, Generic[_T]): - model: type[_T] +_OrderByFieldName: TypeAlias = str | Combinable | OrderBy + +MAX_GET_RESULTS: int +REPR_OUTPUT_SIZE: int +PROHIBITED_FILTER_KWARGS: frozenset[str] + +class BaseIterable(Generic[_T]): + queryset: QuerySet[Model] + chunked_fetch: bool + chunk_size: int + def __init__(self, queryset: QuerySet[Model], chunked_fetch: bool = False, chunk_size: int = 100) -> None: ... + def __aiter__(self) -> AsyncIterator[_T]: ... + +class ModelIterable(BaseIterable[_Model], Generic[_Model]): + def __iter__(self) -> Iterator[_Model]: ... + +class RawModelIterable(BaseIterable[dict[str, Any]]): + def __iter__(self) -> Iterator[dict[str, Any]]: ... + +class ValuesIterable(BaseIterable[dict[str, Any]]): + def __iter__(self) -> Iterator[dict[str, Any]]: ... + +class ValuesListIterable(BaseIterable[_TupleT]): + def __iter__(self) -> Iterator[_TupleT]: ... + +class NamedValuesListIterable(ValuesListIterable[NamedTuple]): + @override + def __iter__(self) -> Iterator[NamedTuple]: ... + +class FlatValuesListIterable(BaseIterable[_T]): + def __iter__(self) -> Iterator[_T]: ... + +@type_check_only +class _SupportsContains(Generic[_ContainsT]): + def __contains__(self, item: _ContainsT, /) -> bool: ... + +# Using `object` (not `_Row | None`) to satisfy Collection protocol and support `User | AnonymousUser` patterns +class QuerySet(AltersData, _SupportsContains[object], Iterable[_Row], Sized, Generic[_Model, _Row]): + model: type[_Model] query: Query + _iterable_class: type[BaseIterable[Any]] + _result_cache: list[_Row] | None def __init__( self, - model: type[models.Model] | None = ..., - query: Query | None = ..., - using: str | None = ..., - hints: dict[str, models.Model] | None = ..., + model: type[Model] | None = None, + query: Query | None = None, + using: str | None = None, + hints: dict[str, Model] | None = None, ) -> None: ... @classmethod - def as_manager(cls) -> Manager[_T]: ... + def as_manager(cls) -> Manager[_Model]: ... + def __deepcopy__(self, memo: dict[int, Any]) -> Self: ... + if sys.version_info >= (3, 11): + @override + def __getstate__(self) -> dict[str, Any]: ... + else: + def __getstate__(self) -> dict[str, Any]: ... + @override def __len__(self) -> int: ... + @override + def __iter__(self) -> Iterator[_Row]: ... + def __aiter__(self) -> AsyncIterator[_Row]: ... def __bool__(self) -> bool: ... - def __class_getitem__(cls, item: type[_T]) -> Any: ... - def __getstate__(self) -> dict[str, Any]: ... + @overload + def __getitem__(self, i: int) -> _Row: ... + @overload + def __getitem__(self, s: slice) -> Self: ... + def __class_getitem__(cls, item: type[_Model]) -> Self: ... # pyright: ignore[reportGeneralTypeIssues] # Technically, the other QuerySet must be of the same type _T, but _T is covariant - def __and__(self, other: _BaseQuerySet[_T]) -> Self: ... - def __or__(self, other: _BaseQuerySet[_T]) -> Self: ... - def iterator(self, chunk_size: int = ...) -> Iterator[_T]: ... - def aiterator(self, chunk_size: int = ...) -> AsyncIterator[_T]: ... + def __and__(self, other: QuerySet[_Model, _Row]) -> Self: ... + def __or__(self, other: QuerySet[_Model, _Row]) -> Self: ... + def __xor__(self, other: QuerySet[_Model, _Row]) -> Self: ... + # IMPORTANT: When updating any of the following methods' signatures, please ALSO modify + # the corresponding method in BaseManager. + def iterator(self, chunk_size: int | None = None) -> Iterator[_Row]: ... + def aiterator(self, chunk_size: int = 2000) -> AsyncIterator[_Row]: ... def aggregate(self, *args: Any, **kwargs: Any) -> dict[str, Any]: ... async def aaggregate(self, *args: Any, **kwargs: Any) -> dict[str, Any]: ... - def get(self, *args: Any, **kwargs: Any) -> _T: ... - async def aget(self, *args: Any, **kwargs: Any) -> _T: ... - def create(self, **kwargs: Any) -> _T: ... - async def acreate(self, **kwargs: Any) -> _T: ... + def count(self) -> int: ... + async def acount(self) -> int: ... + def get(self, *args: Any, **kwargs: Any) -> _Row: ... + async def aget(self, *args: Any, **kwargs: Any) -> _Row: ... + def create(self, **kwargs: Any) -> _Model: ... + async def acreate(self, **kwargs: Any) -> _Model: ... def bulk_create( self, - objs: Iterable[_T], - batch_size: int | None = ..., - ignore_conflicts: bool = ..., - update_conflicts: bool | None = ..., - update_fields: Sequence[str] | None = ..., - unique_fields: Sequence[str] | None = ..., - ) -> list[_T]: ... + objs: Iterable[_Model], + 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[_Model]: ... async def abulk_create( self, - objs: Iterable[_T], - batch_size: int | None = ..., - ignore_conflicts: bool = ..., - update_conflicts: bool | None = ..., - update_fields: Sequence[str] | None = ..., - unique_fields: Sequence[str] | None = ..., - ) -> list[_T]: ... - def bulk_update(self, objs: Iterable[_T], fields: Sequence[str], batch_size: int | None = ...) -> int: ... - async def abulk_update(self, objs: Iterable[_T], fields: Sequence[str], batch_size: int | None = ...) -> int: ... - def get_or_create(self, defaults: MutableMapping[str, Any] | None = ..., **kwargs: Any) -> tuple[_T, bool]: ... - async def aget_or_create( - self, defaults: MutableMapping[str, Any] | None = ..., **kwargs: Any - ) -> tuple[_T, bool]: ... - def update_or_create(self, defaults: MutableMapping[str, Any] | None = ..., **kwargs: Any) -> tuple[_T, bool]: ... + objs: Iterable[_Model], + 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[_Model]: ... + def bulk_update(self, objs: Iterable[_Model], fields: Iterable[str], batch_size: int | None = None) -> int: ... + async def abulk_update( + self, objs: Iterable[_Model], fields: Iterable[str], batch_size: int | None = None + ) -> int: ... + def get_or_create(self, defaults: Mapping[str, Any] | None = None, **kwargs: Any) -> tuple[_Model, bool]: ... + async def aget_or_create(self, defaults: Mapping[str, Any] | None = None, **kwargs: Any) -> tuple[_Model, bool]: ... + def update_or_create( + self, + defaults: Mapping[str, Any] | None = None, + create_defaults: Mapping[str, Any] | None = None, + **kwargs: Any, + ) -> tuple[_Model, bool]: ... async def aupdate_or_create( - self, defaults: MutableMapping[str, Any] | None = ..., **kwargs: Any - ) -> tuple[_T, bool]: ... - def earliest(self, *fields: Any, field_name: Any | None = ...) -> _T: ... - async def aearliest(self, *fields: Any, field_name: Any | None = ...) -> _T: ... - def latest(self, *fields: Any, field_name: Any | None = ...) -> _T: ... - async def alatest(self, *fields: Any, field_name: Any | None = ...) -> _T: ... - def first(self) -> _T | None: ... - async def afirst(self) -> _T | None: ... - def last(self) -> _T | None: ... - async def alast(self) -> _T | None: ... - def in_bulk(self, id_list: Iterable[Any] = ..., *, field_name: str = ...) -> dict[Any, _T]: ... - async def ain_bulk(self, id_list: Iterable[Any] = ..., *, field_name: str = ...) -> dict[Any, _T]: ... + self, + defaults: Mapping[str, Any] | None = None, + create_defaults: Mapping[str, Any] | None = None, + **kwargs: Any, + ) -> tuple[_Model, bool]: ... + def earliest(self, *fields: str | OrderBy) -> _Row: ... + async def aearliest(self, *fields: str | OrderBy) -> _Row: ... + def latest(self, *fields: str | OrderBy) -> _Row: ... + async def alatest(self, *fields: str | OrderBy) -> _Row: ... + def first(self) -> _Row | None: ... + async def afirst(self) -> _Row | None: ... + def last(self) -> _Row | None: ... + async def alast(self) -> _Row | None: ... + def in_bulk(self, id_list: Iterable[Any] | None = None, *, field_name: str = "pk") -> dict[Any, _Model]: ... + async def ain_bulk(self, id_list: Iterable[Any] | None = None, *, field_name: str = "pk") -> dict[Any, _Model]: ... def delete(self) -> tuple[int, dict[str, int]]: ... async def adelete(self) -> tuple[int, dict[str, int]]: ... + def _raw_delete(self, using: str | None) -> int: ... def update(self, **kwargs: Any) -> int: ... async def aupdate(self, **kwargs: Any) -> int: ... def exists(self) -> bool: ... async def aexists(self) -> bool: ... - def contains(self, obj: _T) -> bool: ... - async def acontains(self, obj: _T) -> bool: ... - def explain(self, *, format: Any | None = ..., **options: Any) -> str: ... - async def aexplain(self, *, format: Any | None = ..., **options: Any) -> str: ... + def contains(self, obj: Model) -> bool: ... + async def acontains(self, obj: Model) -> bool: ... + def explain(self, *, format: str | None = None, **options: Any) -> str: ... + async def aexplain(self, *, format: str | None = None, **options: Any) -> str: ... def raw( self, - raw_query: str, - params: tuple[Any] | list[Any] | dict[str, Any] = ..., - translations: dict[str, str] | None = ..., - using: str | None = ..., - ) -> RawQuerySet[_T]: ... + raw_query: _ExecuteQuery, + params: Any = (), + translations: dict[str, str] | None = None, + using: str | None = None, + ) -> RawQuerySet[_Model]: ... # The type of values may be overridden to be more specific in the mypy plugin, depending on the fields param - def values(self, *fields: str | Combinable, **expressions: Any) -> ValuesQuerySet[_T, dict[str, Any]]: ... + def values(self, *fields: str | Combinable, **expressions: Any) -> QuerySet[_Model, dict[str, Any]]: ... # The type of values_list may be overridden to be more specific in the mypy plugin, depending on the fields param def values_list( - self, *fields: str | Combinable, flat: bool = ..., named: bool = ... - ) -> ValuesQuerySet[_T, Any]: ... - def dates(self, field_name: str, kind: str, order: str = ...) -> ValuesQuerySet[_T, datetime.date]: ... + self, *fields: str | Combinable, flat: bool = False, named: bool = False + ) -> QuerySet[_Model, Any]: ... + def dates( + self, + field_name: str, + kind: Literal["year", "month", "week", "day"], + order: Literal["ASC", "DESC"] = "ASC", + ) -> QuerySet[_Model, datetime.date]: ... def datetimes( self, field_name: str, - kind: str, - order: str = ..., - tzinfo: datetime.tzinfo | None = ..., - ) -> ValuesQuerySet[_T, datetime.datetime]: ... + kind: Literal["year", "month", "week", "day", "hour", "minute", "second"], + order: Literal["ASC", "DESC"] = "ASC", + tzinfo: datetime.tzinfo | None = None, + ) -> QuerySet[_Model, datetime.datetime]: ... def none(self) -> Self: ... def all(self) -> Self: ... def filter(self, *args: Any, **kwargs: Any) -> Self: ... def exclude(self, *args: Any, **kwargs: Any) -> Self: ... def complex_filter(self, filter_obj: Any) -> Self: ... - def count(self) -> int: ... - async def acount(self) -> int: ... - def union(self, *other_qs: Any, all: bool = ...) -> Self: ... - def intersection(self, *other_qs: Any) -> Self: ... - def difference(self, *other_qs: Any) -> Self: ... + def union(self, *other_qs: QuerySet[Model, Any], all: bool = False) -> Self: ... + def intersection(self, *other_qs: QuerySet[Model, Any]) -> Self: ... + def difference(self, *other_qs: QuerySet[Model, Any]) -> Self: ... def select_for_update( - self, - nowait: bool = ..., - skip_locked: bool = ..., - of: Sequence[str] = ..., - no_key: bool = ..., + self, nowait: bool = False, skip_locked: bool = False, of: Sequence[str] = (), no_key: bool = False ) -> Self: ... - def select_related(self, *fields: Any) -> Self: ... + @overload + def select_related(self, clear: None, /) -> Self: ... + @overload + def select_related(self, *fields: str) -> Self: ... def prefetch_related(self, *lookups: Any) -> Self: ... def annotate(self, *args: Any, **kwargs: Any) -> Self: ... def alias(self, *args: Any, **kwargs: Any) -> Self: ... - def order_by(self, *field_names: Any) -> Self: ... - def distinct(self, *field_names: Any) -> Self: ... + def order_by(self, *field_names: _OrderByFieldName) -> Self: ... + def distinct(self, *field_names: str) -> Self: ... # extra() return type won't be supported any time soon def extra( self, - select: dict[str, Any] | None = ..., - where: list[str] | None = ..., - params: list[Any] | None = ..., - tables: list[str] | None = ..., - order_by: Sequence[str] | None = ..., - select_params: Sequence[Any] | None = ..., - ) -> QuerySet[Any]: ... + select: dict[str, Any] | None = None, + where: Sequence[str] | None = None, + params: Sequence[Any] | None = None, + tables: Sequence[str] | None = None, + order_by: Sequence[_OrderByFieldName] | None = None, + select_params: Sequence[Any] | None = None, + ) -> QuerySet[Any, Any]: ... def reverse(self) -> Self: ... - def defer(self, *fields: Any) -> Self: ... - def only(self, *fields: Any) -> Self: ... + @overload + def defer(self, clear: None, /) -> Self: ... + @overload + def defer(self, *fields: str) -> Self: ... + def only(self, *fields: str) -> Self: ... def using(self, alias: str | None) -> Self: ... @property def ordered(self) -> bool: ... @property def db(self) -> str: ... + def _fetch_all(self) -> None: ... def resolve_expression(self, *args: Any, **kwargs: Any) -> Any: ... -class QuerySet(_BaseQuerySet[_T], Collection[_T], Reversible[_T], Sized): - def __iter__(self) -> Iterator[_T]: ... - def __aiter__(self) -> AsyncIterator[_T]: ... - def __contains__(self, x: object) -> bool: ... - @overload - def __getitem__(self, i: int) -> _T: ... - @overload - def __getitem__(self, s: slice) -> Self: ... - def __reversed__(self) -> Iterator[_T]: ... - -_Row = TypeVar("_Row", covariant=True) - -class BaseIterable(Sequence[_Row]): - def __init__( - self, - queryset: _BaseQuerySet[Any], - chunked_fetch: bool = ..., - chunk_size: int = ..., - ) -> None: ... - def __iter__(self) -> Iterator[_Row]: ... - def __aiter__(self) -> AsyncIterator[_Row]: ... - def __contains__(self, x: object) -> bool: ... - def __len__(self) -> int: ... - @overload - def __getitem__(self, i: int) -> _Row: ... - @overload - def __getitem__(self, s: slice) -> Sequence[_Row]: ... - -class ModelIterable(BaseIterable[Model]): ... -class ValuesIterable(BaseIterable[dict[str, Any]]): ... -class ValuesListIterable(BaseIterable[tuple[Any, ...]]): ... -class NamedValuesListIterable(ValuesListIterable): ... - -class FlatValuesListIterable(BaseIterable[Any]): - def __iter__(self) -> Iterator[Any]: ... - def __aiter__(self) -> AsyncIterator[Any]: ... - -class ValuesQuerySet(_BaseQuerySet[_T], Collection[_Row], Sized): - def __contains__(self, x: object) -> bool: ... - def __iter__(self) -> Iterator[_Row]: ... - def __aiter__(self) -> AsyncIterator[_Row]: ... - @overload - def __getitem__(self, i: int) -> _Row: ... - @overload - def __getitem__(self, s: slice) -> Self: ... - def iterator(self, chunk_size: int = ...) -> Iterator[_Row]: ... # type: ignore[override] - async def aiterator(self, chunk_size: int = ...) -> Iterator[_Row]: ... # type: ignore[override] - def get(self, *args: Any, **kwargs: Any) -> _Row: ... # type: ignore[override] - async def aget(self, *args: Any, **kwargs: Any) -> _Row: ... # type: ignore[override] - def earliest(self, *fields: Any, field_name: Any | None = ...) -> _Row: ... # type: ignore[override] - async def aearliest(self, *fields: Any, field_name: Any | None = ...) -> _Row: ... # type: ignore[override] - def latest(self, *fields: Any, field_name: Any | None = ...) -> _Row: ... # type: ignore[override] - async def alatest(self, *fields: Any, field_name: Any | None = ...) -> _Row: ... # type: ignore[override] - def first(self) -> _Row | None: ... # type: ignore[override] - async def afirst(self) -> _Row | None: ... # type: ignore[override] - def last(self) -> _Row | None: ... # type: ignore[override] - async def alast(self) -> _Row | None: ... # type: ignore[override] - -class RawQuerySet(Iterable[_T], Sized): +class RawQuerySet(_SupportsContains[object], Iterable[_Model], Sized): + raw_query: RawQuery | str + model: type[_Model] | None query: RawQuery + params: tuple[Any, ...] | None + translations: dict[str, str] + def __init__( self, raw_query: RawQuery | str, - model: type[models.Model] | None = ..., - query: Query | None = ..., - params: tuple[Any] = ..., - translations: dict[str, str] | None = ..., - using: str = ..., - hints: dict[str, models.Model] | None = ..., + model: type[_Model] | None = None, + query: Query | None = None, + params: tuple[Any, ...] = (), + translations: dict[str, str] | None = None, + using: str | None = None, + hints: dict[str, Model] | None = None, ) -> None: ... + def resolve_model_init_order(self) -> tuple[list[str], list[int], list[tuple[str, int]]]: ... + def prefetch_related(self, *lookups: Any) -> Self: ... + @override def __len__(self) -> int: ... - def __iter__(self) -> Iterator[_T]: ... - def __aiter__(self) -> AsyncIterator[_T]: ... def __bool__(self) -> bool: ... + @override + def __iter__(self) -> Iterator[_Model]: ... + def __aiter__(self) -> AsyncIterator[_Model]: ... + def iterator(self) -> Iterator[_Model]: ... @overload - def __getitem__(self, k: int) -> _T: ... + def __getitem__(self, k: int) -> _Model: ... @overload def __getitem__(self, k: str) -> Any: ... @overload - def __getitem__(self, k: slice) -> RawQuerySet[_T]: ... - @property - def columns(self) -> list[str]: ... + def __getitem__(self, k: slice) -> Self: ... @property def db(self) -> str: ... - def iterator(self) -> Iterator[_T]: ... - async def aiterator(self) -> Iterator[_T]: ... - @property + def using(self, alias: str | None) -> Self: ... + @cached_property + def columns(self) -> list[str]: ... + @cached_property def model_fields(self) -> dict[str, str]: ... - def prefetch_related(self, *lookups: Any) -> RawQuerySet[_T]: ... - def resolve_model_init_order( - self, - ) -> tuple[list[str], list[int], list[tuple[str, int]]]: ... - def using(self, alias: str | None) -> RawQuerySet[_T]: ... -class Prefetch(Generic[_T]): +class Prefetch(Generic[_Model]): prefetch_through: str prefetch_to: str - queryset: QuerySet[_T] + queryset: QuerySet[_Model] def __init__( self, lookup: str, @@ -260,12 +283,37 @@ class Prefetch(Generic[_T]): def add_prefix(self, prefix: str) -> None: ... def get_current_prefetch_to(self, level: int) -> str: ... def get_current_to_attr(self, level: int) -> tuple[str, str]: ... - def get_current_queryset(self, level: int) -> QuerySet[Any] | None: ... + def get_current_querysets(self, level: int) -> list[QuerySet[Any]] | None: ... -def prefetch_related_objects( - model_instances: Iterable[models.Model], *related_lookups: str | Prefetch[Any] +def normalize_prefetch_lookups( + lookups: Sequence[str | Prefetch[Any]], prefix: str | None = None +) -> list[Prefetch[Any]]: ... +def prefetch_related_objects(model_instances: Sequence[_Model], *related_lookups: str | Prefetch[Any]) -> None: ... +async def aprefetch_related_objects( + model_instances: Sequence[_Model], *related_lookups: str | Prefetch[Any] ) -> None: ... def get_prefetcher(instance: Model, through_attr: str, to_attr: str) -> tuple[Any, Any, bool, bool]: ... +def prefetch_one_level( + instances: Sequence[Model], prefetcher: Any, lookup: Prefetch[Any], level: int +) -> tuple[list[Any], list[Prefetch[Any]]]: ... class InstanceCheckMeta(type): ... -class EmptyQuerySet(metaclass=InstanceCheckMeta): ... + +class EmptyQuerySet(metaclass=InstanceCheckMeta): + def __init__(self, *args: Any, **kwargs: Any) -> None: ... + +class RelatedPopulator: + db: str + cols_start: int + cols_end: int + init_list: list[str] + reorder_for_init: Any + model_cls: type[Model] + pk_idx: int + related_populators: list[RelatedPopulator] + local_setter: Any + remote_setter: Any + def __init__(self, klass_info: dict[str, Any], select: Any, db: str) -> None: ... + def populate(self, row: Sequence[Any], from_obj: Model) -> None: ... + +def get_related_populators(klass_info: dict[str, Any], select: Any, db: str) -> list[RelatedPopulator]: ... diff --git a/django-stubs/db/models/utils.pyi b/django-stubs/db/models/utils.pyi index 966e03d45..afa683c08 100644 --- a/django-stubs/db/models/utils.pyi +++ b/django-stubs/db/models/utils.pyi @@ -1,3 +1,14 @@ +from collections.abc import Iterable, Iterator, Mapping +from typing import Any, NamedTuple + from django.db.models.base import Model +from typing_extensions import override + +def make_model_tuple(model: type[Model] | str | tuple[str, str]) -> tuple[str, str]: ... +def resolve_callables(mapping: Mapping[str, Any]) -> Iterator[tuple[str, Any]]: ... +def unpickle_named_row(names: Iterable[str], values: Iterable[Any]) -> NamedTuple: ... +def create_namedtuple_class(*names: str) -> type[NamedTuple]: ... -def make_model_tuple(model: type[Model] | str) -> tuple[str, str]: ... +class AltersData: + @override + def __init_subclass__(cls, **kwargs: Any) -> None: ... diff --git a/django-stubs/forms/models.pyi b/django-stubs/forms/models.pyi index 01741fcb0..045970916 100644 --- a/django-stubs/forms/models.pyi +++ b/django-stubs/forms/models.pyi @@ -9,7 +9,7 @@ from django.db import models from django.db.models import ForeignKey from django.db.models.base import Model from django.db.models.manager import Manager -from django.db.models.query import QuerySet, _BaseQuerySet +from django.db.models.query import QuerySet from django.db.models.query_utils import Q from django.forms.fields import CharField, ChoiceField, Field from django.forms.forms import BaseForm, DeclarativeFieldsMetaclass @@ -279,7 +279,7 @@ class ModelMultipleChoiceField(ModelChoiceField): widget: Any = ... hidden_widget: Any = ... default_error_messages: Any = ... - def __init__(self, queryset: _BaseQuerySet[Any], **kwargs: Any) -> None: ... + def __init__(self, queryset: QuerySet[Any], **kwargs: Any) -> None: ... def _get_foreign_key( parent_model: type[Model], diff --git a/django-stubs/test/testcases.pyi b/django-stubs/test/testcases.pyi index 5b361ba9a..d209ae3b7 100644 --- a/django-stubs/test/testcases.pyi +++ b/django-stubs/test/testcases.pyi @@ -10,7 +10,7 @@ from django.core.servers.basehttp import ThreadedWSGIServer, WSGIRequestHandler from django.db import connections as connections from django.db.backends.sqlite3.base import DatabaseWrapper from django.db.models import Model -from django.db.models.query import ValuesQuerySet, _BaseQuerySet +from django.db.models.query import QuerySet from django.forms.fields import EmailField from django.http.response import HttpResponse, HttpResponseBase from django.template.base import Template @@ -167,7 +167,7 @@ class TransactionTestCase(SimpleTestCase): @overload def assertQuerySetEqual( self, - qs: _BaseQuerySet[_M], + qs: QuerySet[_M], values: Iterable[_T], transform: Callable[[_M], _T] = ..., ordered: bool = ..., @@ -176,7 +176,7 @@ class TransactionTestCase(SimpleTestCase): @overload def assertQuerySetEqual( # pyright: ignore[reportOverlappingOverload] self, - qs: ValuesQuerySet[_M, _R], + qs: QuerySet[_M, _R], values: Iterable[_T], transform: Callable[[_R], _T] = ..., ordered: bool = ..., @@ -186,7 +186,7 @@ class TransactionTestCase(SimpleTestCase): @overload def assertQuerysetEqual( self, - qs: _BaseQuerySet[_M], + qs: QuerySet[_M], values: Iterable[_T], transform: Callable[[_M], _T] = ..., ordered: bool = ..., @@ -195,7 +195,7 @@ class TransactionTestCase(SimpleTestCase): @overload def assertQuerysetEqual( # pyright: ignore[reportOverlappingOverload] self, - qs: ValuesQuerySet[_M, _R], + qs: QuerySet[_M, _R], values: Iterable[_T], transform: Callable[[_R], _T] = ..., ordered: bool = ..., diff --git a/django-stubs/views/generic/list.pyi b/django-stubs/views/generic/list.pyi index 72bfb4a3c..e12b34ac0 100644 --- a/django-stubs/views/generic/list.pyi +++ b/django-stubs/views/generic/list.pyi @@ -3,7 +3,7 @@ from typing import Any from django.core.paginator import Paginator from django.db.models import Model -from django.db.models.query import QuerySet, _BaseQuerySet +from django.db.models.query import QuerySet from django.http import HttpRequest, HttpResponse from django.views.generic.base import ContextMixin, TemplateResponseMixin, View @@ -20,9 +20,9 @@ class MultipleObjectMixin(ContextMixin): def get_queryset(self) -> QuerySet[Any]: ... def get_ordering(self) -> Sequence[str]: ... def paginate_queryset( - self, queryset: _BaseQuerySet[Any], page_size: int + self, queryset: QuerySet[Any], page_size: int ) -> tuple[Paginator, int, QuerySet[Any], bool]: ... - def get_paginate_by(self, queryset: _BaseQuerySet[Any]) -> int | None: ... + def get_paginate_by(self, queryset: QuerySet[Any]) -> int | None: ... def get_paginator( self, queryset: QuerySet[Any], @@ -33,7 +33,7 @@ class MultipleObjectMixin(ContextMixin): ) -> Paginator: ... def get_paginate_orphans(self) -> int: ... def get_allow_empty(self) -> bool: ... - def get_context_object_name(self, object_list: _BaseQuerySet[Any]) -> str | None: ... + def get_context_object_name(self, object_list: QuerySet[Any]) -> str | None: ... class BaseListView(MultipleObjectMixin, View): def get(self, request: HttpRequest, *args: Any, **kwargs: Any) -> HttpResponse: ... diff --git a/s/sync-files.txt b/s/sync-files.txt index 982418dbb..c2c4c92c1 100644 --- a/s/sync-files.txt +++ b/s/sync-files.txt @@ -24,4 +24,5 @@ django-stubs/core/validators.pyi #django-stubs/utils/deconstruct.pyi django-stubs/utils/decorators.pyi #django-stubs/db/models/__init__.pyi +#django-stubs/db/models/query.pyi django-stubs/contrib/admin/decorators.pyi From 0fa41a4af0e3a7b5c6d02fc89df66bbff5c67f97 Mon Sep 17 00:00:00 2001 From: Konstantin Alekseev Date: Thu, 21 May 2026 05:41:49 +0300 Subject: [PATCH 2/2] drop types-psycopg2 dependency --- .../contrib/postgres/fields/ranges.pyi | 18 +++-- pyproject.toml | 2 - tests/trout/models.py | 2 +- uv.lock | 78 ------------------- 4 files changed, 12 insertions(+), 88 deletions(-) diff --git a/django-stubs/contrib/postgres/fields/ranges.pyi b/django-stubs/contrib/postgres/fields/ranges.pyi index 9d6963d65..61f710a88 100644 --- a/django-stubs/contrib/postgres/fields/ranges.pyi +++ b/django-stubs/contrib/postgres/fields/ranges.pyi @@ -1,7 +1,11 @@ from typing import Any from django.db import models -from psycopg2.extras import DateRange, DateTimeTZRange, NumericRange +from psycopg2.extras import ( # type: ignore[import-untyped] # ty: ignore[unresolved-import] + DateRange, + DateTimeTZRange, + NumericRange, +) class RangeField(models.Field[Any, Any]): empty_strings_allowed: bool = ... @@ -12,22 +16,22 @@ class RangeField(models.Field[Any, Any]): def value_to_string(self, obj: Any) -> Any: ... class IntegerRangeField(RangeField): - def __get__(self, instance: Any, owner: Any) -> NumericRange: ... # type: ignore[override] + def __get__(self, instance: Any, owner: Any) -> NumericRange: ... # type: ignore[no-any-unimported] class BigIntegerRangeField(RangeField): - def __get__(self, instance: Any, owner: Any) -> NumericRange: ... # type: ignore[override] + def __get__(self, instance: Any, owner: Any) -> NumericRange: ... # type: ignore[no-any-unimported] class DecimalRangeField(RangeField): - def __get__(self, instance: Any, owner: Any) -> NumericRange: ... # type: ignore[override] + def __get__(self, instance: Any, owner: Any) -> NumericRange: ... # type: ignore[no-any-unimported] class FloatRangeField(RangeField): - def __get__(self, instance: Any, owner: Any) -> NumericRange: ... # type: ignore[override] + def __get__(self, instance: Any, owner: Any) -> NumericRange: ... # type: ignore[no-any-unimported] class DateTimeRangeField(RangeField): - def __get__(self, instance: Any, owner: Any) -> DateTimeTZRange: ... # type: ignore[override] + def __get__(self, instance: Any, owner: Any) -> DateTimeTZRange: ... # type: ignore[no-any-unimported] class DateRangeField(RangeField): - def __get__(self, instance: Any, owner: Any) -> DateRange: ... # type: ignore[override] + def __get__(self, instance: Any, owner: Any) -> DateRange: ... # type: ignore[no-any-unimported] class RangeOperators: EQUAL: str diff --git a/pyproject.toml b/pyproject.toml index 819716a12..7cc22b967 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,7 +7,6 @@ authors = [{ name = "django-types team & contributors" }] license = "MIT" keywords = ["django", "types", "mypy", "stubs"] requires-python = ">=3.10" -dependencies = ["types-psycopg2>=2.9.21.13"] [project.urls] Repository = "https://github.com/sbdchd/django-types" @@ -21,7 +20,6 @@ dev = [ "ty>=0.0.35", "types-PyYAML>=6.0.1", "types-pytz>=2021.3.0", - "psycopg2-binary>=2.9.3", "pyright>=1.1.406", "ruff>=0.1.0", "tomlkit>=0.12.1", diff --git a/tests/trout/models.py b/tests/trout/models.py index ea0d2335b..6e0713ee1 100644 --- a/tests/trout/models.py +++ b/tests/trout/models.py @@ -40,7 +40,7 @@ require_GET, require_POST, ) -from psycopg2.extras import execute_values +from psycopg2.extras import execute_values # type: ignore[import-untyped] # ty: ignore[unresolved-import] from django.db.models.fields.generated import GeneratedField diff --git a/uv.lock b/uv.lock index d2403901b..ba839da82 100644 --- a/uv.lock +++ b/uv.lock @@ -120,9 +120,6 @@ wheels = [ name = "django-types" version = "0.24.0" source = { editable = "." } -dependencies = [ - { name = "types-psycopg2" }, -] [package.dev-dependencies] dev = [ @@ -130,7 +127,6 @@ dev = [ { name = "django" }, { name = "mypy" }, { name = "pre-commit" }, - { name = "psycopg2-binary" }, { name = "pyright" }, { name = "pytest" }, { name = "ruff" }, @@ -142,7 +138,6 @@ dev = [ ] [package.metadata] -requires-dist = [{ name = "types-psycopg2", specifier = ">=2.9.21.13" }] [package.metadata.requires-dev] dev = [ @@ -150,7 +145,6 @@ dev = [ { name = "django", specifier = ">=5.2,<6.0" }, { name = "mypy", specifier = ">=2.1.0" }, { name = "pre-commit", specifier = ">=4.3.0" }, - { name = "psycopg2-binary", specifier = ">=2.9.3" }, { name = "pyright", specifier = ">=1.1.406" }, { name = "pytest", specifier = ">=7.1.1" }, { name = "ruff", specifier = ">=0.1.0" }, @@ -414,69 +408,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/80/6e/4b28b62ecb6aae56769c34a8ff1d661473ec1e9519e2d5f8b2c150086b26/pre_commit-4.6.0-py2.py3-none-any.whl", hash = "sha256:e2cf246f7299edcabcf15f9b0571fdce06058527f0a06535068a86d38089f29b", size = 226472, upload-time = "2026-04-21T20:31:40.092Z" }, ] -[[package]] -name = "psycopg2-binary" -version = "2.9.12" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/2a/60/a3624f79acea344c16fbef3a94d28b89a8042ddfb8f3e4ca83f538671409/psycopg2_binary-2.9.12.tar.gz", hash = "sha256:5ac9444edc768c02a6b6a591f070b8aae28ff3a99be57560ac996001580f294c", size = 379686, upload-time = "2026-04-21T09:40:34.304Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/78/80/49bacf9e51617d8309f6f0123e29edc793f6f5f6700c7d1f1b20782fbb37/psycopg2_binary-2.9.12-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9b818ceff717f98851a64bffd4c5eb5b3059ae280276dcecc52ac658dcf006a4", size = 3712314, upload-time = "2026-04-20T23:33:31.363Z" }, - { url = "https://files.pythonhosted.org/packages/d3/f2/98eeac7d60c43df9338287834edf9b3e69be68a2db78a57b1b81d705e735/psycopg2_binary-2.9.12-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d2fa0d7caca8635c56e373055094eeda3208d901d55dd0ff5abc1d4e47f82b56", size = 3822389, upload-time = "2026-04-20T23:33:34.178Z" }, - { url = "https://files.pythonhosted.org/packages/9f/7c/30575e75f14d5351a56a1971bb43fe7f8bf7edf1b654fb1bec65c42a8812/psycopg2_binary-2.9.12-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:864c261b3690e1207d14bbfe0a61e27567981b80c47a778561e49f676f7ce433", size = 4578448, upload-time = "2026-04-20T23:33:37.073Z" }, - { url = "https://files.pythonhosted.org/packages/65/9b/4df366d89f28c527dc39d0b6c98a5ca74e30d37ac097b73f3352147568ae/psycopg2_binary-2.9.12-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c5ee5213445dd45312459029b8c4c0a695461eb517b753d2582315bd07995f5e", size = 4273705, upload-time = "2026-04-20T23:33:39.291Z" }, - { url = "https://files.pythonhosted.org/packages/4e/8a/c566803818eb03161ba869b6ba612bf7ad56816d98b9e5121e0a22ad6b0b/psycopg2_binary-2.9.12-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6f9cae1f848779b5b01f417e762c40d026ea93eb0648249a604728cda991dde3", size = 5893784, upload-time = "2026-04-20T23:33:41.658Z" }, - { url = "https://files.pythonhosted.org/packages/63/fe/0dfa5797e0b229e0567bc378695224caf14d547f73b05be0c80549089772/psycopg2_binary-2.9.12-cp310-cp310-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:63a3ebbd543d3d1eda088ac99164e8c5bac15293ee91f20281fd17d050aee1c4", size = 4109306, upload-time = "2026-04-20T23:33:43.953Z" }, - { url = "https://files.pythonhosted.org/packages/3c/89/28063adf17a4ba501eedd9890feab0c649ee4d8bd0a97df0ff1e9584feab/psycopg2_binary-2.9.12-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d6fcbba8c9fed08a73b8ac61ea79e4821e45b1e92bb466230c5e746bbf3d5256", size = 3654400, upload-time = "2026-04-20T23:33:46.115Z" }, - { url = "https://files.pythonhosted.org/packages/84/94/5a01de0aa4ead0b8d8d1aa4ec18cec0bd36d03fa714eaa5bb8a0b1b50020/psycopg2_binary-2.9.12-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:36512911ebb2b60a0c3e44d0bb5048c1980aced91235d133b7874f3d1d93487c", size = 3299215, upload-time = "2026-04-20T23:33:48.202Z" }, - { url = "https://files.pythonhosted.org/packages/7a/85/723bb085a61c6ac2dc0a0043f375f2fe7365363e27b073bad56ca5bda979/psycopg2_binary-2.9.12-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:8ffdb59fe88f99589e34354a130217aa1fd2d615612402d6edc8b3dbc7a44463", size = 3047724, upload-time = "2026-04-20T23:33:50.74Z" }, - { url = "https://files.pythonhosted.org/packages/b4/67/4d8b1e0d2fc4166677380eac0edf9cdff91013aca2546e8ef7bc04b56158/psycopg2_binary-2.9.12-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:a46fe069b65255df410f856d842bc235f90e22ffdf532dda625fd4213d3fd9b1", size = 3349183, upload-time = "2026-04-20T23:33:59.635Z" }, - { url = "https://files.pythonhosted.org/packages/73/99/21af7a5498637ea4dc91a17c281a53bc1d632fbafe00f6689fbfb32a9fed/psycopg2_binary-2.9.12-cp310-cp310-win_amd64.whl", hash = "sha256:ab29414b25dcb698bf26bf213e3348abdcd07bbd5de032a5bec15bd75b298b03", size = 2757036, upload-time = "2026-04-20T23:34:01.606Z" }, - { url = "https://files.pythonhosted.org/packages/d5/19/d4ce60954f3bb9d8e3bc5e5c4d1f2487de2d3851bf2391d54954c9df12a6/psycopg2_binary-2.9.12-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5c8ce6c61bd1b1f6b9c24ee32211599f6166af2c55abb19456090a21fd16554b", size = 3712338, upload-time = "2026-04-20T23:34:03.961Z" }, - { url = "https://files.pythonhosted.org/packages/53/71/c85409ee0d78890f0660eff262e815e7dd2bb741a17611d82e9e8cd9dc5e/psycopg2_binary-2.9.12-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b4a9eaa6e7f4ff91bec10aa3fb296878e75187bced5cc4bafe17dc40915e1326", size = 3822407, upload-time = "2026-04-20T23:34:05.977Z" }, - { url = "https://files.pythonhosted.org/packages/3c/ed/60486c2c7f0d4d1ede2bfb1ed27e2498477ce646bc7f6b2759906303117e/psycopg2_binary-2.9.12-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:c6528cefc8e50fcc6f4a107e27a672058b36cc5736d665476aeb413ba88dbb06", size = 4578425, upload-time = "2026-04-20T23:34:08.246Z" }, - { url = "https://files.pythonhosted.org/packages/0b/b9/656cb03fad9f4f49f2145c334b1126ee75189929ca4e6187d485a2d59951/psycopg2_binary-2.9.12-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e4e184b1fb6072bf05388aa41c697e1b2d01b3473f107e7ec44f186a32cfd0b8", size = 4273709, upload-time = "2026-04-20T23:34:10.974Z" }, - { url = "https://files.pythonhosted.org/packages/99/66/08cf0da0e25cc6fb142c89be45fc8418792858f0c4cbff5e24530ff02cd6/psycopg2_binary-2.9.12-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4766ab678563054d3f1d064a4db19cc4b5f9e3a8d9018592a8285cf200c248f3", size = 5893779, upload-time = "2026-04-20T23:34:13.905Z" }, - { url = "https://files.pythonhosted.org/packages/17/d7/eecd9ce8e146d3721115d82d3836efdbb712187e4590325df549989d18f4/psycopg2_binary-2.9.12-cp311-cp311-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:5a0253224780c978746cb9be55a946bcdaf40fe3519c0f622924cdabdafe2c39", size = 4109308, upload-time = "2026-04-20T23:34:16.761Z" }, - { url = "https://files.pythonhosted.org/packages/b6/2e/b1dc289b362cc8d45697b57eefbd673186f49a4ea0906928988e3affcc98/psycopg2_binary-2.9.12-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:0dc9228d47c46bda253d2ecd6bb93b56a9f2d7ad33b684a1fa3622bf74ffe30c", size = 3654405, upload-time = "2026-04-20T23:34:19.303Z" }, - { url = "https://files.pythonhosted.org/packages/eb/e4/4c4aea6473214dbdbd0fbba11aa4691e76dc01722c55724c5951719865ff/psycopg2_binary-2.9.12-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f921f3cd87035ef7df233383011d7a53ea1d346224752c1385f1edfd790ceb6a", size = 3299187, upload-time = "2026-04-20T23:34:21.206Z" }, - { url = "https://files.pythonhosted.org/packages/ba/5d/b03b99986446a4f57b170ed9a2579fb7ff9783ca0fa5226b19db99737fee/psycopg2_binary-2.9.12-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:3d999bd982a723113c1a45b55a7a6a90d64d0ed2278020ed625c490ff7bef96c", size = 3047716, upload-time = "2026-04-20T23:34:23.077Z" }, - { url = "https://files.pythonhosted.org/packages/14/86/382ee4afbd1d97500c9d2862b20c2fdeddf4b7335e984df3fb4309f64108/psycopg2_binary-2.9.12-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:29d4d134bd0ab46ffb04e94aa3c5fa3ef582e9026609165e2f758ff76fc3a3be", size = 3349237, upload-time = "2026-04-20T23:34:25.211Z" }, - { url = "https://files.pythonhosted.org/packages/a8/16/9a57c75ba1eda7165c017342f526810d5f5a12647dde749c99ae9a7141d7/psycopg2_binary-2.9.12-cp311-cp311-win_amd64.whl", hash = "sha256:cb4a1dacdd48077150dc762a9e5ddbf32c256d66cb46f80839391aa458774936", size = 2757036, upload-time = "2026-04-20T23:34:27.77Z" }, - { url = "https://files.pythonhosted.org/packages/e2/9f/ef4ef3c8e15083df90ca35265cfd1a081a2f0cc07bb229c6314c6af817f4/psycopg2_binary-2.9.12-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:5cdc05117180c5fa9c40eea8ea559ce64d73824c39d928b7da9fb5f6a9392433", size = 3712459, upload-time = "2026-04-20T23:34:30.549Z" }, - { url = "https://files.pythonhosted.org/packages/b5/01/3dd14e46ba48c1e1a6ec58ee599fa1b5efa00c246d5046cd903d0eeb1af1/psycopg2_binary-2.9.12-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d3227a3bc228c10d21011a99245edca923e4e8bf461857e869a507d9a41fe9f6", size = 3822936, upload-time = "2026-04-20T23:34:32.77Z" }, - { url = "https://files.pythonhosted.org/packages/a6/f7/0640e4901119d8a9f7a1784b927f494e2198e213ceb593753d1f2c8b1b30/psycopg2_binary-2.9.12-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:995ce929eede89db6254b50827e2b7fd61e50d11f0b116b29fffe4a2e53c4580", size = 4578676, upload-time = "2026-04-20T23:34:35.18Z" }, - { url = "https://files.pythonhosted.org/packages/b0/55/44df3965b5f297c50cc0b1b594a31c67d6127a9d133045b8a66611b14dfb/psycopg2_binary-2.9.12-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:9fe06d93e72f1c048e731a2e3e7854a5bfaa58fc736068df90b352cefe66f03f", size = 4274917, upload-time = "2026-04-20T23:34:37.982Z" }, - { url = "https://files.pythonhosted.org/packages/b0/4b/74535248b1eac0c9336862e8617c765ac94dac76f9e25d7c4a79588c8907/psycopg2_binary-2.9.12-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:40e7b28b63aaf737cb3a1edc3a9bbc9a9f4ad3dcb7152e8c1130e4050eddcb7d", size = 5894843, upload-time = "2026-04-20T23:34:40.856Z" }, - { url = "https://files.pythonhosted.org/packages/f2/ba/f1bf8d2ae71868ad800b661099086ee52bc0f8d9f05be1acd8ebb06757cc/psycopg2_binary-2.9.12-cp312-cp312-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:89d19a9f7899e8eb0656a2b3a08e0da04c720a06db6e0033eab5928aabe60fa9", size = 4110556, upload-time = "2026-04-20T23:34:44.016Z" }, - { url = "https://files.pythonhosted.org/packages/45/46/c15706c338403b7c420bcc0c2905aad116cc064545686d8bf85f1999ea00/psycopg2_binary-2.9.12-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:612b965daee295ae2da8f8218ce1d274645dc76ef3f1abf6a0a94fd57eff876d", size = 3655714, upload-time = "2026-04-20T23:34:46.233Z" }, - { url = "https://files.pythonhosted.org/packages/b3/7c/a2d5dc09b64a4564db242a0fe418fde7d33f6f8259dd2c5b9d7def00fb5a/psycopg2_binary-2.9.12-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:b9a339b79d37c1b45f3235265f07cdeb0cb5ad7acd2ac7720a5920989c17c24e", size = 3301154, upload-time = "2026-04-20T23:34:49.528Z" }, - { url = "https://files.pythonhosted.org/packages/c0/e8/cc8c9a4ce71461f9ec548d38cadc41dc184b34c73e6455450775a9334ccd/psycopg2_binary-2.9.12-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:3471336e1acfd9c7fe507b8bad5af9317b6a89294f9eb37bd9a030bb7bebcdc6", size = 3048882, upload-time = "2026-04-20T23:34:51.86Z" }, - { url = "https://files.pythonhosted.org/packages/19/6a/31e2296bc0787c5ab75d3d118e40b239db8151b5192b90b77c72bc9256e9/psycopg2_binary-2.9.12-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7af18183109e23502c8b2ae7f6926c0882766f35b5175a4cd737ad825e4d7a1b", size = 3351298, upload-time = "2026-04-20T23:34:54.124Z" }, - { url = "https://files.pythonhosted.org/packages/5f/a8/75f4e3e11203b590150abed2cf7794b9c9c9f7eceddae955191138b44dde/psycopg2_binary-2.9.12-cp312-cp312-win_amd64.whl", hash = "sha256:398fcd4db988c7d7d3713e2b8e18939776fd3fb447052daae4f24fa39daede4c", size = 2757230, upload-time = "2026-04-20T23:34:56.242Z" }, - { url = "https://files.pythonhosted.org/packages/91/bb/4608c96f970f6e0c56572e87027ef4404f709382a3503e9934526d7ba051/psycopg2_binary-2.9.12-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:7c729a73c7b1b84de3582f73cdd27d905121dc2c531f3d9a3c32a3011033b965", size = 3712419, upload-time = "2026-04-20T23:34:58.754Z" }, - { url = "https://files.pythonhosted.org/packages/5e/af/48f76af9d50d61cf390f8cd657b503168b089e2e9298e48465d029fcc713/psycopg2_binary-2.9.12-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4413d0caef93c5cf50b96863df4c2efe8c269bf2267df353225595e7e15e8df7", size = 3822990, upload-time = "2026-04-20T23:35:00.821Z" }, - { url = "https://files.pythonhosted.org/packages/7a/df/aba0f99397cd811d32e06fc0cc781f1f3ce98bc0e729cb423925085d781a/psycopg2_binary-2.9.12-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:4dfcf8e45ebb0c663be34a3442f65e17311f3367089cd4e5e3a3e8e62c978777", size = 4578696, upload-time = "2026-04-20T23:35:03.409Z" }, - { url = "https://files.pythonhosted.org/packages/95/9c/eaa74021ac4e4d5c2f83d82fc6615a63f4fe6c94dc4e94c3990427053f67/psycopg2_binary-2.9.12-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c41321a14dd74aceb6a9a643b9253a334521babfa763fa873e33d89cfa122fb5", size = 4274982, upload-time = "2026-04-20T23:35:05.583Z" }, - { url = "https://files.pythonhosted.org/packages/35/ed/c25deff98bd26187ba48b3b250a3ffc3037c46c5b89362534a15d200e0db/psycopg2_binary-2.9.12-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:83946ba43979ebfdc99a3cd0ee775c89f221df026984ba19d46133d8d75d3cd9", size = 5894867, upload-time = "2026-04-20T23:35:07.902Z" }, - { url = "https://files.pythonhosted.org/packages/9a/81/8d0e21ca77373c6c9589e5c4528f6e8f0c08c62cafc76fb0bddb7a2cee22/psycopg2_binary-2.9.12-cp313-cp313-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:411e85815652d13560fbe731878daa5d92378c4995a22302071890ec3397d019", size = 4110578, upload-time = "2026-04-20T23:35:10.149Z" }, - { url = "https://files.pythonhosted.org/packages/00/fc/f481e2435bd8f742d0123309174aae4165160ad3ef17c1b99c3622c241d2/psycopg2_binary-2.9.12-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:1c8ad4c08e00f7679559eaed7aff1edfffc60c086b976f93972f686384a95e2c", size = 3655816, upload-time = "2026-04-20T23:35:12.56Z" }, - { url = "https://files.pythonhosted.org/packages/53/79/b9f46466bdbe9f239c96cde8be33c1aace4842f06013b47b730dc9759187/psycopg2_binary-2.9.12-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:00814e40fa23c2b37ef0a1e3c749d89982c73a9cb5046137f0752a22d432e82f", size = 3301307, upload-time = "2026-04-20T23:35:15.029Z" }, - { url = "https://files.pythonhosted.org/packages/3f/19/7dc003b32fe35024df89b658104f7c8538a8b2dcbde7a4e746ce929742e7/psycopg2_binary-2.9.12-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:98062447aebc20ed20add1f547a364fd0ef8933640d5372ff1873f8deb9b61be", size = 3048968, upload-time = "2026-04-20T23:35:16.757Z" }, - { url = "https://files.pythonhosted.org/packages/91/58/2dbd7db5c604d45f4950d988506aae672a14126ec22998ced5021cbb76bb/psycopg2_binary-2.9.12-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:66a7685d7e548f10fb4ce32fb01a7b7f4aa702134de92a292c7bd9e0d3dbd290", size = 3351369, upload-time = "2026-04-20T23:35:18.933Z" }, - { url = "https://files.pythonhosted.org/packages/42/ee/dee8dcaad07f735824de3d6563bc67119fa6c28257b17977a8d624f02fab/psycopg2_binary-2.9.12-cp313-cp313-win_amd64.whl", hash = "sha256:b6937f5fe4e180aeee87de907a2fa982ded6f7f15d7218f78a083e4e1d68f2a0", size = 2757347, upload-time = "2026-04-20T23:35:21.283Z" }, - { url = "https://files.pythonhosted.org/packages/13/1b/708c0dca874acfad6d65314271859899a79007686f3a1f74e82a2ed4b645/psycopg2_binary-2.9.12-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:6f3b3de8a74ef8db215f22edffb19e32dc6fa41340456de7ec99efdc8a7b3ec2", size = 3712428, upload-time = "2026-04-20T23:35:23.453Z" }, - { url = "https://files.pythonhosted.org/packages/d6/39/ddbea9d4b4de6aca9431b6ed253f530f8a02d3b8f9bcfd0dbfe2b3de6fe4/psycopg2_binary-2.9.12-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1006fb62f0f0bc5ce256a832356c6262e91be43f5e4eb15b5eaf38079464caf2", size = 3823184, upload-time = "2026-04-20T23:35:25.92Z" }, - { url = "https://files.pythonhosted.org/packages/bf/a0/bc2fef74b106fa345567122a0659e6d94512ed7dc0131ec44c9e5aba3725/psycopg2_binary-2.9.12-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:840066105706cd2eb29b9a1c2329620056582a4bf3e8169dec5c447042d0869f", size = 4579157, upload-time = "2026-04-20T23:35:28.542Z" }, - { url = "https://files.pythonhosted.org/packages/57/d7/d4e3b2005d3de607ca4fbb0e8742e248056e52184a6b94ebda3c1c2c329b/psycopg2_binary-2.9.12-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:863f5d12241ebe1c76a72a04c2113b6dc905f90b9cef0e9be0efd994affd9354", size = 4274970, upload-time = "2026-04-20T23:35:30.418Z" }, - { url = "https://files.pythonhosted.org/packages/2e/42/c9853f8db3967fe08bcde11f53d53b85d351750cae726ce001cb68afa9c1/psycopg2_binary-2.9.12-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a99eaab34a9010f1a086b126de467466620a750634d114d20455f3a824aae033", size = 5895175, upload-time = "2026-04-20T23:35:33.584Z" }, - { url = "https://files.pythonhosted.org/packages/eb/fd/b82b5601a97630308bef079f545ffec481bbbc795c2ba5ec416a01d03f60/psycopg2_binary-2.9.12-cp314-cp314-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ffdd7dc5463ccd61845ac37b7012d0f35a1548df9febe14f8dd549be4a0bc81e", size = 4110658, upload-time = "2026-04-20T23:35:35.638Z" }, - { url = "https://files.pythonhosted.org/packages/62/8c/32ca69b0389ef25dd22937bf9e8fbe2ce27aea20b05ded48c4ce4cb42475/psycopg2_binary-2.9.12-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:54a0dfecab1b48731f934e06139dfe11e24219fb6d0ceb32177cf0375f14c7b5", size = 3656251, upload-time = "2026-04-20T23:35:37.854Z" }, - { url = "https://files.pythonhosted.org/packages/c4/29/96992a2b59e3b9d730fcf9612d0a387305025dc867a9fc490a9e496e074e/psycopg2_binary-2.9.12-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:96937c9c5d891f772430f418a7a8b4691a90c3e6b93cf72b5bd7cad8cbca32a5", size = 3301810, upload-time = "2026-04-20T23:35:39.927Z" }, - { url = "https://files.pythonhosted.org/packages/56/ad/44b06659949b243ae10112cd3b20a197f9bf3e81d5651379b9eb889bfaad/psycopg2_binary-2.9.12-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:77b348775efd4cdab410ec6609d81ccecd1139c90265fa583a7255c8064bc03d", size = 3048977, upload-time = "2026-04-20T23:35:41.806Z" }, - { url = "https://files.pythonhosted.org/packages/1d/f2/10a1bcebadb6aa55e280e1f58975c36a7b560ea525184c7aa4064c466633/psycopg2_binary-2.9.12-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:527e6342b3e44c2f0544f6b8e927d60de7f163f5723b8f1dfa7d2a84298738cd", size = 3351466, upload-time = "2026-04-20T23:35:43.993Z" }, - { url = "https://files.pythonhosted.org/packages/20/be/b732c8418ffa5bcfda002890f5dc4c869fc17db66ff11f53b17cfe44afc0/psycopg2_binary-2.9.12-cp314-cp314-win_amd64.whl", hash = "sha256:f12ae41fcafadb39b2785e64a40f9db05d6de2ac114077457e0e7c597f3af980", size = 2848762, upload-time = "2026-04-20T23:35:46.421Z" }, -] - [[package]] name = "pygments" version = "2.20.0" @@ -716,15 +647,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/7a/fb/59325221bce52f6e833d6865ce8360ef7d5e1e21151b38df6dc77c4327a7/ty-0.0.35-py3-none-win_arm64.whl", hash = "sha256:619c52c0fb2aa21961a848a1995135ad3b6d0a9aa54da0194e60f679cc200e13", size = 10925457, upload-time = "2026-05-10T18:25:10.352Z" }, ] -[[package]] -name = "types-psycopg2" -version = "2.9.21.20260509" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/71/9e/a78cffd63e14c45fc05664c42739b2b15938acff92ca59e22b22ced5695e/types_psycopg2-2.9.21.20260509.tar.gz", hash = "sha256:0422105f691a409e9d8048c2205aca9d694b70823248c6614393444017e9f088", size = 27215, upload-time = "2026-05-09T04:58:40.256Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/be/b3/f4d11df63430d7e14b2889caf73f6f6bf9147a51d866ce2da4c07d9f3c8b/types_psycopg2-2.9.21.20260509-py3-none-any.whl", hash = "sha256:69f6dae384bbea830dff23621936423035db152af901331e6f9c46f7c4f4b24f", size = 24940, upload-time = "2026-05-09T04:58:39.208Z" }, -] - [[package]] name = "types-pytz" version = "2026.2.0.20260506"