1
1
from __future__ import annotations
2
2
3
- from typing import ClassVar , TypeVar
3
+ from typing import Any , ClassVar , TypeVar , overload
4
4
5
5
from django .db import models
6
6
from django .db .models import Manager
@@ -40,7 +40,7 @@ class InheritanceManagerTestParent(models.Model):
40
40
on_delete = models .CASCADE )
41
41
objects : ClassVar [InheritanceManager [InheritanceManagerTestParent ]] = InheritanceManager ()
42
42
43
- def __str__ (self ):
43
+ def __str__ (self ) -> str :
44
44
return "{}({})" .format (
45
45
self .__class__ .__name__ [len ('InheritanceManagerTest' ):],
46
46
self .pk ,
@@ -214,7 +214,7 @@ class Tracked(models.Model):
214
214
215
215
tracker = FieldTracker ()
216
216
217
- def save (self , * args , ** kwargs ) :
217
+ def save (self , * args : Any , ** kwargs : Any ) -> None :
218
218
""" No-op save() to ensure that FieldTracker.patch_save() works. """
219
219
super ().save (* args , ** kwargs )
220
220
@@ -226,7 +226,7 @@ class TrackerTimeStamped(TimeStampedModel):
226
226
227
227
tracker = FieldTracker ()
228
228
229
- def save (self , * args , ** kwargs ) :
229
+ def save (self , * args : Any , ** kwargs : Any ) -> None :
230
230
""" Automatically add "modified" to update_fields."""
231
231
update_fields = kwargs .get ('update_fields' )
232
232
if update_fields is not None :
@@ -244,7 +244,7 @@ class TrackedFK(models.Model):
244
244
245
245
class TrackedAbstract (AbstractTracked ):
246
246
name = models .CharField (max_length = 20 )
247
- number = models .IntegerField () # type: ignore[assignment]
247
+ number = models .IntegerField ()
248
248
mutable = MutableField (default = None )
249
249
250
250
tracker = FieldTracker ()
@@ -261,7 +261,7 @@ class TrackedNonFieldAttr(models.Model):
261
261
number = models .FloatField ()
262
262
263
263
@property
264
- def rounded (self ):
264
+ def rounded (self ) -> int | None :
265
265
return round (self .number ) if self .number is not None else None
266
266
267
267
tracker = FieldTracker (fields = ['rounded' ])
@@ -360,28 +360,37 @@ class StringyDescriptor:
360
360
"""
361
361
Descriptor that returns a string version of the underlying integer value.
362
362
"""
363
- def __init__ (self , name ):
363
+ def __init__ (self , name : str ):
364
364
self .name = name
365
365
366
- def __get__ (self , obj , cls = None ):
366
+ @overload
367
+ def __get__ (self , obj : None , cls : type [models .Model ] | None = None ) -> StringyDescriptor :
368
+ ...
369
+
370
+ @overload
371
+ def __get__ (self , obj : models .Model , cls : type [models .Model ]) -> str :
372
+ ...
373
+
374
+ def __get__ (self , obj : models .Model | None , cls : type [models .Model ] | None = None ) -> StringyDescriptor | str :
367
375
if obj is None :
368
376
return self
369
377
if self .name in obj .get_deferred_fields ():
370
378
# This queries the database, and sets the value on the instance.
379
+ assert cls is not None
371
380
fields_map = {f .name : f for f in cls ._meta .fields }
372
381
field = fields_map [self .name ]
373
382
DeferredAttribute (field = field ).__get__ (obj , cls )
374
383
return str (obj .__dict__ [self .name ])
375
384
376
- def __set__ (self , obj , value ) :
385
+ def __set__ (self , obj : object , value : str ) -> None :
377
386
obj .__dict__ [self .name ] = int (value )
378
387
379
- def __delete__ (self , obj ) :
388
+ def __delete__ (self , obj : object ) -> None :
380
389
del obj .__dict__ [self .name ]
381
390
382
391
383
392
class CustomDescriptorField (models .IntegerField ):
384
- def contribute_to_class (self , cls , name , * args , ** kwargs ) :
393
+ def contribute_to_class (self , cls : type [ models . Model ] , name : str , * args : Any , ** kwargs : Any ) -> None :
385
394
super ().contribute_to_class (cls , name , * args , ** kwargs )
386
395
setattr (cls , name , StringyDescriptor (name ))
387
396
0 commit comments