Skip to content

Commit c862c7f

Browse files
authored
fix: fix objects attribute for pyright 1.1.324 (typeddjango#181)
The way CPython works at runtime is to give a higher priority to the metaclass descriptors than the ones in the class itself. Pyright 1.1.324 adjusted that but made our `.objects` typing break when using our own custom managers. Nowadays we can use `Self` for that, which not only is more elegant but also solves this issue in a way that both mypy and pyright can resolve correctly. Related issues: - microsoft/pyright#5792 - microsoft/pyright#5686
1 parent de817c6 commit c862c7f

File tree

10 files changed

+50
-31
lines changed

10 files changed

+50
-31
lines changed

django-stubs/contrib/admin/models.pyi

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from typing import Any, Optional, Union
1+
from typing import Any, ClassVar, Optional, Union
22
from uuid import UUID
33

44
from django.db import models
@@ -28,7 +28,7 @@ class LogEntry(models.Model):
2828
object_repr: models.CharField[Any] = ...
2929
action_flag: models.PositiveSmallIntegerField[Any] = ...
3030
change_message: models.TextField[Any] = ...
31-
objects: LogEntryManager = ...
31+
objects: ClassVar[LogEntryManager] = ...
3232
def is_addition(self) -> bool: ...
3333
def is_change(self) -> bool: ...
3434
def is_deletion(self) -> bool: ...

django-stubs/contrib/auth/models.pyi

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import sys
2-
from typing import Any, Collection, Optional, Set, Tuple, Type, TypeVar, Union
2+
from typing import Any, ClassVar, Collection, Optional, Set, Tuple, Type, TypeVar, Union
33

44
from django.contrib.auth.backends import ModelBackend
55
from django.contrib.auth.base_user import AbstractBaseUser as AbstractBaseUser
@@ -15,6 +15,11 @@ if sys.version_info < (3, 8):
1515
else:
1616
from typing import Literal
1717

18+
if sys.version_info < (3, 11):
19+
from typing_extensions import Self
20+
else:
21+
from typing import Self
22+
1823
_AnyUser = Union[Model, "AnonymousUser"]
1924

2025
def update_last_login(
@@ -28,7 +33,7 @@ class PermissionManager(models.Manager["Permission"]):
2833

2934
class Permission(models.Model):
3035
content_type_id: int
31-
objects: PermissionManager
36+
objects: ClassVar[PermissionManager]
3237

3338
name = models.CharField(max_length=255)
3439
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
@@ -39,7 +44,7 @@ class GroupManager(models.Manager["Group"]):
3944
def get_by_natural_key(self, name: str) -> Group: ...
4045

4146
class Group(models.Model):
42-
objects: GroupManager
47+
objects: ClassVar[GroupManager]
4348

4449
name = models.CharField(max_length=150)
4550
permissions = models.ManyToManyField[Permission, Any](Permission)
@@ -104,7 +109,7 @@ class AbstractUser(AbstractBaseUser, PermissionsMixin):
104109
) -> None: ...
105110

106111
class User(AbstractUser):
107-
objects: UserManager[User]
112+
objects: ClassVar[UserManager[Self]] # type: ignore[assignment]
108113

109114
class AnonymousUser:
110115
id: Any = ...

django-stubs/contrib/contenttypes/models.pyi

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from typing import Any, Dict, Optional, Tuple, Type, Union
1+
from typing import Any, ClassVar, Dict, Optional, Tuple, Type, Union
22

33
from django.contrib.auth.models import Permission
44
from django.db import models
@@ -22,7 +22,7 @@ class ContentType(models.Model):
2222
id: int
2323
app_label: models.CharField[Any] = ...
2424
model: models.CharField[Any] = ...
25-
objects: ContentTypeManager = ...
25+
objects: ClassVar[ContentTypeManager] = ...
2626
permission_set: Manager[Permission]
2727
@property
2828
def name(self) -> str: ...

django-stubs/contrib/sessions/base_session.pyi

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from datetime import datetime
2-
from typing import Any, Dict, Optional, Type
2+
from typing import Any, ClassVar, Dict, Optional, Type
33

44
from django.contrib.sessions.backends.base import SessionBase
55
from django.db import models
@@ -14,7 +14,7 @@ class AbstractBaseSession(models.Model):
1414
expire_date: datetime
1515
session_data: str
1616
session_key: str
17-
objects: Any = ...
17+
objects: ClassVar[BaseSessionManager] = ...
1818
@classmethod
1919
def get_session_store_class(cls) -> Optional[Type[SessionBase]]: ...
2020
def get_decoded(self) -> Dict[str, int]: ...

django-stubs/contrib/sites/models.pyi

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from typing import Any, Optional, Tuple, Type
1+
from typing import Any, ClassVar, Optional, Tuple, Type
22

33
from django.db import models
44
from django.http.request import HttpRequest
@@ -11,7 +11,7 @@ class SiteManager(models.Manager["Site"]):
1111
def get_by_natural_key(self, domain: str) -> Site: ...
1212

1313
class Site(models.Model):
14-
objects: SiteManager
14+
objects: ClassVar[SiteManager]
1515

1616
domain = models.CharField(max_length=100)
1717
name = models.CharField(max_length=50)

django-stubs/db/models/__init__.pyi

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@ from .aggregates import StdDev as StdDev
1111
from .aggregates import Sum as Sum
1212
from .aggregates import Variance as Variance
1313
from .base import Model as Model
14-
from .constraints import Deferrable as Deferrable
1514
from .constraints import BaseConstraint as BaseConstraint
1615
from .constraints import CheckConstraint as CheckConstraint
16+
from .constraints import Deferrable as Deferrable
1717
from .constraints import UniqueConstraint as UniqueConstraint
1818
from .deletion import CASCADE as CASCADE
1919
from .deletion import DO_NOTHING as DO_NOTHING

django-stubs/db/models/base.pyi

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import sys
12
from typing import (
23
Any,
34
Callable,
@@ -22,6 +23,11 @@ from django.core.exceptions import ObjectDoesNotExist, ValidationError
2223
from django.db.models.manager import BaseManager
2324
from django.db.models.options import Options
2425

26+
if sys.version_info < (3, 11):
27+
from typing_extensions import Self
28+
else:
29+
from typing import Self
30+
2531
_M = TypeVar("_M", bound=Any)
2632
_Self = TypeVar("_Self", bound="Model")
2733

@@ -32,24 +38,18 @@ class ModelState:
3238
adding: bool = ...
3339
fields_cache: ModelStateFieldsCacheDescriptor = ...
3440

35-
class ModelBase(type):
36-
# FIXME: It would be better to use _Self instead of _M here,
37-
# but pyright says Type[_Self] cannot be assigned here... Maybe a bug in pyright?
38-
@property
39-
def objects(cls: Type[_M]) -> BaseManager[_M]: ...
40-
@property
41-
def _meta(cls: Type[_M]) -> Options[_M]: ...
42-
@property
43-
def _default_manager(cls: Type[_M]) -> BaseManager[_M]: ...
41+
class ModelBase(type): ...
4442

4543
class Model(metaclass=ModelBase):
4644
DoesNotExist: ClassVar[type[ObjectDoesNotExist]]
4745
MultipleObjectsReturned: ClassVar[type[BaseMultipleObjectsReturned]]
46+
_meta: ClassVar[Options[Self]]
47+
_default_manager: ClassVar[BaseManager[Self]]
48+
objects: ClassVar[BaseManager[Self]]
4849

4950
class Meta: ...
5051
pk: Any = ...
5152
_state: ModelState
52-
_meta: Options[Any]
5353
def __init__(self, *args: Any, **kwargs: Any) -> None: ...
5454
@classmethod
5555
def add_to_class(cls, name: str, value: Any) -> Any: ...
@@ -67,7 +67,10 @@ class Model(metaclass=ModelBase):
6767
self, using: Any = ..., keep_parents: bool = ...
6868
) -> Tuple[int, Dict[str, int]]: ...
6969
def full_clean(
70-
self, exclude: Optional[Collection[str]] = ..., validate_unique: bool = True, validate_constraints: bool = True
70+
self,
71+
exclude: Optional[Collection[str]] = ...,
72+
validate_unique: bool = True,
73+
validate_constraints: bool = True,
7174
) -> None: ...
7275
def clean(self) -> None: ...
7376
def clean_fields(self, exclude: Optional[Collection[str]] = ...) -> None: ...

django-stubs/db/transaction.pyi

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,9 @@ _C = TypeVar("_C", bound=Callable[..., Any])
2828
class Atomic:
2929
using: Optional[str] = ...
3030
savepoint: bool = ...
31-
def __init__(self, using: Optional[str], savepoint: bool, durable: bool = ...) -> None: ...
31+
def __init__(
32+
self, using: Optional[str], savepoint: bool, durable: bool = ...
33+
) -> None: ...
3234
# When decorating, return the decorated function as-is, rather than clobbering it as ContextDecorator does.
3335
def __call__(self, func: _C) -> _C: ...
3436
def __enter__(self) -> None: ...
@@ -40,7 +42,9 @@ def atomic(using: _C) -> _C: ...
4042

4143
# Decorator or context-manager with parameters
4244
@overload
43-
def atomic(using: Optional[str] = ..., savepoint: bool = ..., durable: bool = ...) -> Atomic: ...
45+
def atomic(
46+
using: Optional[str] = ..., savepoint: bool = ..., durable: bool = ...
47+
) -> Atomic: ...
4448

4549
# Bare decorator
4650
@overload

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"devDependencies": {
3-
"pyright": "1.1.301"
3+
"pyright": "1.1.324"
44
},
55
"volta": {
66
"node": "18.15.0"

yarn.lock

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,14 @@
22
# yarn lockfile v1
33

44

5-
6-
version "1.1.301"
7-
resolved "https://registry.npmjs.org/pyright/-/pyright-1.1.301.tgz"
8-
integrity sha512-Y4MMELxQ/5+/FlWjbQTg5wbP3z+V4IyFcATSsNLpZbJm0y4gz6ijf/b0zZV1sA8yJstf6xJ98vw5qxPM0yU8Zg==
5+
fsevents@~2.3.2:
6+
version "2.3.3"
7+
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6"
8+
integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==
9+
10+
11+
version "1.1.324"
12+
resolved "https://registry.yarnpkg.com/pyright/-/pyright-1.1.324.tgz#6a964835c0e1aabf039cb35d8587e0d9ce7b37bf"
13+
integrity sha512-/Ng8G2Gb17dzQEHKgPa+Z5a6LPCLYNA4BVno1UdpDjnC9iLw0VAn5k/RNuaGkB/mhA82lV0OBcd5JEdaWcA3qg==
14+
optionalDependencies:
15+
fsevents "~2.3.2"

0 commit comments

Comments
 (0)