1"""
2Type stubs for typed model fields.
3
4These stubs tell type checkers that each field constructor returns the
5typed *descriptor* (`XField[T]`), not the primitive `T`. Combined with
6`Field.__get__`'s overloads, this gives you:
7
8 class User(postgres.Model):
9 email = types.EmailField()
10 age = types.IntegerField(allow_null=True)
11
12 User.email # EmailField[str] — typed reference
13 user.email # str — the loaded value
14 User.age # IntegerField[int | None]
15 user.age # int | None
16
17The return type is parameterized by nullability:
18- allow_null=False (default) → XField[T]
19- allow_null=True → XField[T | None]
20"""
21
22from collections.abc import Callable, Sequence
23from datetime import date, datetime, time, timedelta
24from decimal import Decimal
25from typing import Any, Literal, overload
26from uuid import UUID
27from zoneinfo import ZoneInfo
28
29from plain.postgres.base import Model
30from plain.postgres.deletion import OnDelete
31from plain.postgres.fields.binary import BinaryField as _BinaryField
32from plain.postgres.fields.boolean import BooleanField as _BooleanField
33from plain.postgres.fields.duration import DurationField as _DurationField
34from plain.postgres.fields.encrypted import EncryptedTextField as _EncryptedTextField
35from plain.postgres.fields.network import (
36 GenericIPAddressField as _GenericIPAddressField,
37)
38from plain.postgres.fields.numeric import BigIntegerField as _BigIntegerField
39from plain.postgres.fields.numeric import DecimalField as _DecimalField
40from plain.postgres.fields.numeric import FloatField as _FloatField
41from plain.postgres.fields.numeric import IntegerField as _IntegerField
42from plain.postgres.fields.numeric import SmallIntegerField as _SmallIntegerField
43from plain.postgres.fields.primary_key import PrimaryKeyField as _PrimaryKeyField
44from plain.postgres.fields.related_managers import (
45 ManyToManyManager,
46 ReverseForeignKeyManager,
47)
48from plain.postgres.fields.temporal import DateField as _DateField
49from plain.postgres.fields.temporal import DateTimeField as _DateTimeField
50from plain.postgres.fields.temporal import TimeField as _TimeField
51from plain.postgres.fields.text import EmailField as _EmailField
52from plain.postgres.fields.text import RandomStringField as _RandomStringField
53from plain.postgres.fields.text import TextField as _TextField
54from plain.postgres.fields.text import URLField as _URLField
55from plain.postgres.fields.timezones import TimeZoneField as _TimeZoneField
56from plain.postgres.fields.uuid import UUIDField as _UUIDField
57from plain.postgres.query import QuerySet
58
59# String fields
60@overload
61def TextField(
62 *,
63 max_length: int | None = None,
64 required: bool = True,
65 allow_null: Literal[True],
66 default: Any = ...,
67 choices: Any = None,
68 validators: Sequence[Callable[..., Any]] = (),
69) -> _TextField[str | None]: ...
70@overload
71def TextField(
72 *,
73 max_length: int | None = None,
74 required: bool = True,
75 allow_null: Literal[False] = False,
76 default: Any = ...,
77 choices: Any = None,
78 validators: Sequence[Callable[..., Any]] = (),
79) -> _TextField[str]: ...
80@overload
81def EmailField(
82 *,
83 max_length: int | None = None,
84 required: bool = True,
85 allow_null: Literal[True],
86 default: Any = ...,
87 choices: Any = None,
88 validators: Sequence[Callable[..., Any]] = (),
89) -> _EmailField[str | None]: ...
90@overload
91def EmailField(
92 *,
93 max_length: int | None = None,
94 required: bool = True,
95 allow_null: Literal[False] = False,
96 default: Any = ...,
97 choices: Any = None,
98 validators: Sequence[Callable[..., Any]] = (),
99) -> _EmailField[str]: ...
100@overload
101def URLField(
102 *,
103 max_length: int | None = None,
104 required: bool = True,
105 allow_null: Literal[True],
106 default: Any = ...,
107 choices: Any = None,
108 validators: Sequence[Callable[..., Any]] = (),
109) -> _URLField[str | None]: ...
110@overload
111def URLField(
112 *,
113 max_length: int | None = None,
114 required: bool = True,
115 allow_null: Literal[False] = False,
116 default: Any = ...,
117 choices: Any = None,
118 validators: Sequence[Callable[..., Any]] = (),
119) -> _URLField[str]: ...
120
121# Integer fields
122@overload
123def IntegerField(
124 *,
125 required: bool = True,
126 allow_null: Literal[True],
127 default: Any = ...,
128 validators: Sequence[Callable[..., Any]] = (),
129) -> _IntegerField[int | None]: ...
130@overload
131def IntegerField(
132 *,
133 required: bool = True,
134 allow_null: Literal[False] = False,
135 default: Any = ...,
136 validators: Sequence[Callable[..., Any]] = (),
137) -> _IntegerField[int]: ...
138@overload
139def BigIntegerField(
140 *,
141 required: bool = True,
142 allow_null: Literal[True],
143 default: Any = ...,
144 validators: Sequence[Callable[..., Any]] = (),
145) -> _BigIntegerField[int | None]: ...
146@overload
147def BigIntegerField(
148 *,
149 required: bool = True,
150 allow_null: Literal[False] = False,
151 default: Any = ...,
152 validators: Sequence[Callable[..., Any]] = (),
153) -> _BigIntegerField[int]: ...
154@overload
155def SmallIntegerField(
156 *,
157 required: bool = True,
158 allow_null: Literal[True],
159 default: Any = ...,
160 validators: Sequence[Callable[..., Any]] = (),
161) -> _SmallIntegerField[int | None]: ...
162@overload
163def SmallIntegerField(
164 *,
165 required: bool = True,
166 allow_null: Literal[False] = False,
167 default: Any = ...,
168 validators: Sequence[Callable[..., Any]] = (),
169) -> _SmallIntegerField[int]: ...
170def PrimaryKeyField() -> _PrimaryKeyField: ...
171
172# Numeric fields
173@overload
174def FloatField(
175 *,
176 required: bool = True,
177 allow_null: Literal[True],
178 default: Any = ...,
179 validators: Sequence[Callable[..., Any]] = (),
180) -> _FloatField[float | None]: ...
181@overload
182def FloatField(
183 *,
184 required: bool = True,
185 allow_null: Literal[False] = False,
186 default: Any = ...,
187 validators: Sequence[Callable[..., Any]] = (),
188) -> _FloatField[float]: ...
189@overload
190def DecimalField(
191 *,
192 max_digits: int | None = None,
193 decimal_places: int | None = None,
194 required: bool = True,
195 allow_null: Literal[True],
196 default: Any = ...,
197 validators: Sequence[Callable[..., Any]] = (),
198) -> _DecimalField[Decimal | None]: ...
199@overload
200def DecimalField(
201 *,
202 max_digits: int | None = None,
203 decimal_places: int | None = None,
204 required: bool = True,
205 allow_null: Literal[False] = False,
206 default: Any = ...,
207 validators: Sequence[Callable[..., Any]] = (),
208) -> _DecimalField[Decimal]: ...
209
210# Boolean field
211@overload
212def BooleanField(
213 *,
214 required: bool = True,
215 allow_null: Literal[True],
216 default: Any = ...,
217 validators: Sequence[Callable[..., Any]] = (),
218) -> _BooleanField[bool | None]: ...
219@overload
220def BooleanField(
221 *,
222 required: bool = True,
223 allow_null: Literal[False] = False,
224 default: Any = ...,
225 validators: Sequence[Callable[..., Any]] = (),
226) -> _BooleanField[bool]: ...
227
228# Date/time fields
229@overload
230def DateField(
231 *,
232 required: bool = True,
233 allow_null: Literal[True],
234 default: Any = ...,
235 validators: Sequence[Callable[..., Any]] = (),
236) -> _DateField[date | None]: ...
237@overload
238def DateField(
239 *,
240 required: bool = True,
241 allow_null: Literal[False] = False,
242 default: Any = ...,
243 validators: Sequence[Callable[..., Any]] = (),
244) -> _DateField[date]: ...
245@overload
246def DateTimeField(
247 *,
248 create_now: bool = False,
249 update_now: bool = False,
250 required: bool = True,
251 allow_null: Literal[True],
252 validators: Sequence[Callable[..., Any]] = (),
253) -> _DateTimeField[datetime | None]: ...
254@overload
255def DateTimeField(
256 *,
257 create_now: bool = False,
258 update_now: bool = False,
259 required: bool = True,
260 allow_null: Literal[False] = False,
261 validators: Sequence[Callable[..., Any]] = (),
262) -> _DateTimeField[datetime]: ...
263@overload
264def TimeField(
265 *,
266 required: bool = True,
267 allow_null: Literal[True],
268 default: Any = ...,
269 validators: Sequence[Callable[..., Any]] = (),
270) -> _TimeField[time | None]: ...
271@overload
272def TimeField(
273 *,
274 required: bool = True,
275 allow_null: Literal[False] = False,
276 default: Any = ...,
277 validators: Sequence[Callable[..., Any]] = (),
278) -> _TimeField[time]: ...
279@overload
280def DurationField(
281 *,
282 required: bool = True,
283 allow_null: Literal[True],
284 default: Any = ...,
285 validators: Sequence[Callable[..., Any]] = (),
286) -> _DurationField[timedelta | None]: ...
287@overload
288def DurationField(
289 *,
290 required: bool = True,
291 allow_null: Literal[False] = False,
292 default: Any = ...,
293 validators: Sequence[Callable[..., Any]] = (),
294) -> _DurationField[timedelta]: ...
295@overload
296def TimeZoneField(
297 *,
298 required: bool = True,
299 allow_null: Literal[True],
300 default: Any = ...,
301 validators: Sequence[Callable[..., Any]] = (),
302) -> _TimeZoneField[ZoneInfo | None]: ...
303@overload
304def TimeZoneField(
305 *,
306 required: bool = True,
307 allow_null: Literal[False] = False,
308 default: Any = ...,
309 validators: Sequence[Callable[..., Any]] = (),
310) -> _TimeZoneField[ZoneInfo]: ...
311
312# Other fields
313@overload
314def UUIDField(
315 *,
316 generate: bool = False,
317 required: bool = True,
318 allow_null: Literal[True],
319 validators: Sequence[Callable[..., Any]] = (),
320) -> _UUIDField[UUID | None]: ...
321@overload
322def UUIDField(
323 *,
324 generate: bool = False,
325 required: bool = True,
326 allow_null: Literal[False] = False,
327 validators: Sequence[Callable[..., Any]] = (),
328) -> _UUIDField[UUID]: ...
329@overload
330def RandomStringField(
331 *,
332 length: int,
333 required: bool = True,
334 allow_null: Literal[True],
335 validators: Sequence[Callable[..., Any]] = (),
336) -> _RandomStringField[str | None]: ...
337@overload
338def RandomStringField(
339 *,
340 length: int,
341 required: bool = True,
342 allow_null: Literal[False] = False,
343 validators: Sequence[Callable[..., Any]] = (),
344) -> _RandomStringField[str]: ...
345@overload
346def BinaryField(
347 *,
348 max_length: int | None = None,
349 required: bool = True,
350 allow_null: Literal[True],
351 validators: Sequence[Callable[..., Any]] = (),
352) -> _BinaryField[bytes | memoryview | None]: ...
353@overload
354def BinaryField(
355 *,
356 max_length: int | None = None,
357 required: Literal[False],
358 allow_null: Literal[True],
359 default: Literal[b""] | None,
360 validators: Sequence[Callable[..., Any]] = (),
361) -> _BinaryField[bytes | memoryview | None]: ...
362@overload
363def BinaryField(
364 *,
365 max_length: int | None = None,
366 required: bool = True,
367 allow_null: Literal[False] = False,
368 validators: Sequence[Callable[..., Any]] = (),
369) -> _BinaryField[bytes | memoryview]: ...
370@overload
371def BinaryField(
372 *,
373 max_length: int | None = None,
374 required: Literal[False],
375 allow_null: Literal[False] = False,
376 default: Literal[b""],
377 validators: Sequence[Callable[..., Any]] = (),
378) -> _BinaryField[bytes | memoryview]: ...
379@overload
380def GenericIPAddressField(
381 *,
382 protocol: str = "both",
383 unpack_ipv4: bool = False,
384 required: bool = True,
385 allow_null: Literal[True],
386 default: Any = ...,
387 validators: Sequence[Callable[..., Any]] = (),
388) -> _GenericIPAddressField[str | None]: ...
389@overload
390def GenericIPAddressField(
391 *,
392 protocol: str = "both",
393 unpack_ipv4: bool = False,
394 required: bool = True,
395 allow_null: Literal[False] = False,
396 default: Any = ...,
397 validators: Sequence[Callable[..., Any]] = (),
398) -> _GenericIPAddressField[str]: ...
399@overload
400def JSONField(
401 *,
402 encoder: Any = None,
403 decoder: Any = None,
404 required: bool = True,
405 allow_null: Literal[True],
406 default: Any = ...,
407 validators: Sequence[Callable[..., Any]] = (),
408) -> Any: ...
409@overload
410def JSONField(
411 *,
412 encoder: Any = None,
413 decoder: Any = None,
414 required: bool = True,
415 allow_null: Literal[False] = False,
416 default: Any = ...,
417 validators: Sequence[Callable[..., Any]] = (),
418) -> Any: ...
419
420# Encrypted fields
421@overload
422def EncryptedTextField(
423 *,
424 max_length: int | None = None,
425 required: bool = True,
426 allow_null: Literal[True],
427 validators: Sequence[Callable[..., Any]] = (),
428) -> _EncryptedTextField[str | None]: ...
429@overload
430def EncryptedTextField(
431 *,
432 max_length: int | None = None,
433 required: Literal[False],
434 allow_null: Literal[True],
435 default: Literal[""] | None,
436 validators: Sequence[Callable[..., Any]] = (),
437) -> _EncryptedTextField[str | None]: ...
438@overload
439def EncryptedTextField(
440 *,
441 max_length: int | None = None,
442 required: bool = True,
443 allow_null: Literal[False] = False,
444 validators: Sequence[Callable[..., Any]] = (),
445) -> _EncryptedTextField[str]: ...
446@overload
447def EncryptedTextField(
448 *,
449 max_length: int | None = None,
450 required: Literal[False],
451 allow_null: Literal[False] = False,
452 default: Literal[""],
453 validators: Sequence[Callable[..., Any]] = (),
454) -> _EncryptedTextField[str]: ...
455@overload
456def EncryptedJSONField(
457 *,
458 encoder: Any = None,
459 decoder: Any = None,
460 required: bool = True,
461 allow_null: Literal[True],
462 validators: Sequence[Callable[..., Any]] = (),
463) -> Any: ...
464@overload
465def EncryptedJSONField(
466 *,
467 encoder: Any = None,
468 decoder: Any = None,
469 required: bool = True,
470 allow_null: Literal[False] = False,
471 validators: Sequence[Callable[..., Any]] = (),
472) -> Any: ...
473
474# Related fields
475#
476# Two overload families:
477#
478# 1. Class-argument FK (`to=SomeModel`) — T is inferred from the class.
479# Returns `_ForeignKeyDescriptor[T, V]` whose `__get__` overloads keep
480# class-access typed as the descriptor itself (matching runtime
481# `ForwardForeignKeyDescriptor.__get__` which returns `self` when
482# `instance is None`) and instance-access as the related instance
483# (or `T | None` for nullable FKs).
484#
485# 2. String-argument FK (`to="SomeModel"`, `to="self"`) — T can't be
486# inferred from the string, so the return type falls back to bare `T`.
487# This requires an explicit LHS annotation (`parent: TreeNode | None = …`)
488# but preserves typing for forward references and self-references.
489#
490# `__set__` accepts the related instance, None (via V), or a bare PK
491# value (int) — matching what `ForwardForeignKeyDescriptor` already
492# accepts at runtime.
493#
494# NOTE: `bool` is a subclass of `int` in Python, so `child.parent = True`
495# type-checks here. The runtime `ForwardForeignKeyDescriptor.__set__`
496# explicitly rejects bool with `ValueError`, so this language quirk is
497# caught at runtime rather than silently coerced to PK 0/1.
498class _ForeignKeyDescriptor[T: Model, V]:
499 @overload
500 def __get__(self, instance: None, owner: type) -> _ForeignKeyDescriptor[T, V]: ...
501 @overload
502 def __get__(self, instance: Model, owner: type) -> V: ...
503 def __set__(self, instance: Model, value: V | int) -> None: ...
504
505# Class-argument FK overloads
506@overload
507def ForeignKeyField[T: Model](
508 to: type[T],
509 on_delete: OnDelete,
510 *,
511 related_query_name: str | None = None,
512 required: bool = True,
513 allow_null: Literal[True],
514 validators: Sequence[Callable[..., Any]] = (),
515) -> _ForeignKeyDescriptor[T, T | None]: ...
516@overload
517def ForeignKeyField[T: Model](
518 to: type[T],
519 on_delete: OnDelete,
520 *,
521 related_query_name: str | None = None,
522 required: bool = True,
523 allow_null: Literal[False] = False,
524 validators: Sequence[Callable[..., Any]] = (),
525) -> _ForeignKeyDescriptor[T, T]: ...
526
527# String-argument FK overloads (forward refs, self-refs) — T inferred from LHS annotation
528@overload
529def ForeignKeyField[T: Model](
530 to: str,
531 on_delete: OnDelete,
532 *,
533 related_query_name: str | None = None,
534 required: bool = True,
535 allow_null: Literal[True],
536 validators: Sequence[Callable[..., Any]] = (),
537) -> T | None: ...
538@overload
539def ForeignKeyField[T: Model](
540 to: str,
541 on_delete: OnDelete,
542 *,
543 related_query_name: str | None = None,
544 required: bool = True,
545 allow_null: Literal[False] = False,
546 validators: Sequence[Callable[..., Any]] = (),
547) -> T: ...
548def ManyToManyField[T: Model](
549 to: type[T] | str,
550 *,
551 through: Any,
552 through_fields: tuple[str, str] | None = None,
553 related_query_name: str | None = None,
554 symmetrical: bool | None = None,
555) -> ManyToManyManager[T]: ...
556
557# Reverse relation descriptors
558class ReverseForeignKey[T: Model, QS: QuerySet[Any] = QuerySet[Any]]:
559 """
560 Descriptor for the reverse side of a ForeignKeyField.
561
562 Type parameters:
563 _T: The related model type
564 _QS: The QuerySet type (use the model's custom QuerySet for proper method typing)
565
566 Example:
567 # With custom QuerySet for proper typing of custom methods like .enabled()
568 repos: ReverseForeignKey[Repo, RepoQuerySet] = ReverseForeignKey(to="Repo", field="organization")
569
570 # Usage: org.repos.query.enabled() # .enabled() is now recognized
571 """
572 def __init__(self, *, to: type[T] | str, field: str) -> None: ...
573 @overload
574 def __get__(self, instance: None, owner: type) -> ReverseForeignKey[T, QS]: ...
575 @overload
576 def __get__(
577 self, instance: Model, owner: type
578 ) -> ReverseForeignKeyManager[T, QS]: ...
579 def __get__(
580 self, instance: Model | None, owner: type
581 ) -> ReverseForeignKey[T, QS] | ReverseForeignKeyManager[T, QS]: ...
582
583class ReverseManyToMany[T: Model, QS: QuerySet[Any] = QuerySet[Any]]:
584 """
585 Descriptor for the reverse side of a ManyToManyField.
586
587 Type parameters:
588 _T: The related model type
589 _QS: The QuerySet type (use the model's custom QuerySet for proper method typing)
590 """
591 def __init__(self, *, to: type[T] | str, field: str) -> None: ...
592 @overload
593 def __get__(self, instance: None, owner: type) -> ReverseManyToMany[T, QS]: ...
594 @overload
595 def __get__(self, instance: Model, owner: type) -> ManyToManyManager[T, QS]: ...
596 def __get__(
597 self, instance: Model | None, owner: type
598 ) -> ReverseManyToMany[T, QS] | ManyToManyManager[T, QS]: ...
599
600# Export all types (should match types.py)
601__all__ = [
602 "BigIntegerField",
603 "BinaryField",
604 "BooleanField",
605 "DateField",
606 "DateTimeField",
607 "DecimalField",
608 "DurationField",
609 "EmailField",
610 "EncryptedJSONField",
611 "EncryptedTextField",
612 "FloatField",
613 "ForeignKeyField",
614 "GenericIPAddressField",
615 "IntegerField",
616 "JSONField",
617 "ManyToManyField",
618 "ManyToManyManager",
619 "PrimaryKeyField",
620 "RandomStringField",
621 "ReverseForeignKey",
622 "ReverseForeignKeyManager",
623 "ReverseManyToMany",
624 "SmallIntegerField",
625 "TextField",
626 "TimeField",
627 "TimeZoneField",
628 "URLField",
629 "UUIDField",
630]