1
1
# pylint: disable=too-many-lines; Allow more than 1000 lines
2
+ from __future__ import annotations
3
+
2
4
import logging
3
5
from base64 import b64encode
4
6
from datetime import timedelta
5
- from typing import Collection , Dict , Optional , Union
7
+ from typing import Collection
6
8
7
9
from dateutil .relativedelta import relativedelta
8
10
@@ -42,14 +44,14 @@ class UserManager(DjangoUserManager):
42
44
43
45
"""
44
46
45
- def user_with_student_id (self , student_id : Union [ int , str ] ) -> Optional [ "User" ] :
47
+ def user_with_student_id (self , student_id : int | str ) -> "User | None" :
46
48
"""Get a unique user object by FCPS student ID. (Ex. 1624472)"""
47
49
results = User .objects .filter (student_id = str (student_id ))
48
50
if len (results ) == 1 :
49
51
return results .first ()
50
52
return None
51
53
52
- def user_with_ion_id (self , student_id : Union [ int , str ] ) -> Optional [ "User" ] :
54
+ def user_with_ion_id (self , student_id : int | str ) -> "User | None" :
53
55
"""Get a unique user object by Ion ID. (Ex. 489)"""
54
56
if isinstance (student_id , str ) and not is_entirely_digit (student_id ):
55
57
return None
@@ -58,11 +60,11 @@ def user_with_ion_id(self, student_id: Union[int, str]) -> Optional["User"]:
58
60
return results .first ()
59
61
return None
60
62
61
- def users_in_year (self , year : int ) -> Union [ Collection ["User" ], QuerySet ] : # pylint: disable=unsubscriptable-object
63
+ def users_in_year (self , year : int ) -> Collection ["User" ] | QuerySet : # pylint: disable=unsubscriptable-object
62
64
"""Get a list of users in a specific graduation year."""
63
65
return User .objects .filter (graduation_year = year )
64
66
65
- def user_with_name (self , given_name : Optional [ str ] = None , last_name : Optional [ str ] = None ) -> "User" : # pylint: disable=unsubscriptable-object
67
+ def user_with_name (self , given_name : str | None = None , last_name : str | None = None ) -> "User" : # pylint: disable=unsubscriptable-object
66
68
"""Get a unique user object by given name (first/nickname) and/or last name.
67
69
68
70
Args:
@@ -86,14 +88,14 @@ def user_with_name(self, given_name: Optional[str] = None, last_name: Optional[s
86
88
except (User .DoesNotExist , User .MultipleObjectsReturned ):
87
89
return None
88
90
89
- def get_students (self ) -> Union [ Collection ["User" ], QuerySet ] : # pylint: disable=unsubscriptable-object
91
+ def get_students (self ) -> Collection ["User" ] | QuerySet : # pylint: disable=unsubscriptable-object
90
92
"""Get user objects that are students (quickly)."""
91
93
users = User .objects .filter (user_type = "student" , graduation_year__gte = get_senior_graduation_year ())
92
94
users = users .exclude (id__in = EXTRA )
93
95
94
96
return users
95
97
96
- def get_teachers (self ) -> Union [ Collection ["User" ], QuerySet ] : # pylint: disable=unsubscriptable-object
98
+ def get_teachers (self ) -> Collection ["User" ] | QuerySet : # pylint: disable=unsubscriptable-object
97
99
"""Get user objects that are teachers (quickly)."""
98
100
users = User .objects .filter (user_type = "teacher" )
99
101
users = users .exclude (id__in = EXTRA )
@@ -121,7 +123,7 @@ def get_teachers_attendance_users(self) -> "QuerySet[User]": # noqa
121
123
122
124
return users
123
125
124
- def get_teachers_sorted (self ) -> Union [ Collection ["User" ], QuerySet ] : # pylint: disable=unsubscriptable-object
126
+ def get_teachers_sorted (self ) -> Collection ["User" ] | QuerySet : # pylint: disable=unsubscriptable-object
125
127
"""Returns a ``QuerySet`` of teachers sorted by last name, then first name.
126
128
127
129
Returns:
@@ -171,8 +173,8 @@ def get_approve_announcements_users_sorted(self) -> "QuerySet[User]": # noqa
171
173
172
174
def exclude_from_search (
173
175
self ,
174
- existing_queryset : Optional [ Union [ Collection ["User" ], QuerySet ]] = None , # pylint: disable=unsubscriptable-object
175
- ) -> Union [ Collection ["User" ], QuerySet ] : # pylint: disable=unsubscriptable-object
176
+ existing_queryset : Collection ["User" ] | QuerySet | None = None , # pylint: disable=unsubscriptable-object
177
+ ) -> Collection ["User" ] | QuerySet : # pylint: disable=unsubscriptable-object
176
178
if existing_queryset is None :
177
179
existing_queryset = self
178
180
@@ -260,7 +262,7 @@ def get_signage_user() -> "User":
260
262
return User (id = 99999 )
261
263
262
264
@property
263
- def address (self ) -> Optional [ "Address" ] :
265
+ def address (self ) -> "Address" | None :
264
266
"""Returns the ``Address`` object representing this user's address, or ``None`` if it is not
265
267
set or the current user does not have permission to access it.
266
268
@@ -272,7 +274,7 @@ def address(self) -> Optional["Address"]:
272
274
return self .properties .address
273
275
274
276
@property
275
- def schedule (self ) -> Optional [ Union [ QuerySet , Collection ["Section" ]]] : # pylint: disable=unsubscriptable-object
277
+ def schedule (self ) -> QuerySet | Collection ["Section" ] | None : # pylint: disable=unsubscriptable-object
276
278
"""Returns a QuerySet of the ``Section`` objects representing the classes this student is
277
279
in, or ``None`` if the current user does not have permission to list this student's classes.
278
280
@@ -284,7 +286,7 @@ def schedule(self) -> Optional[Union[QuerySet, Collection["Section"]]]: # pylin
284
286
"""
285
287
return self .properties .schedule
286
288
287
- def member_of (self , group : Union [ Group , str ] ) -> bool :
289
+ def member_of (self , group : Group | str ) -> bool :
288
290
"""Returns whether a user is a member of a certain group.
289
291
290
292
Args:
@@ -402,7 +404,7 @@ def get_short_name(self) -> str:
402
404
return self .short_name
403
405
404
406
@property
405
- def primary_email_address (self ) -> Optional [ str ] :
407
+ def primary_email_address (self ) -> str | None :
406
408
try :
407
409
return self .primary_email .address if self .primary_email else None
408
410
except Email .DoesNotExist :
@@ -434,7 +436,7 @@ def tj_email(self) -> str:
434
436
return "{}@{}" .format (self .username , domain )
435
437
436
438
@property
437
- def non_tj_email (self ) -> Optional [ str ] :
439
+ def non_tj_email (self ) -> str | None :
438
440
"""
439
441
Returns the user's first non-TJ email found, or None if none is found.
440
442
@@ -476,7 +478,7 @@ def notification_email(self) -> str:
476
478
return email .address if email and email .address else self .tj_email
477
479
478
480
@property
479
- def default_photo (self ) -> Optional [ bytes ] :
481
+ def default_photo (self ) -> bytes | None :
480
482
"""Returns default photo (in binary) that should be used
481
483
482
484
Returns:
@@ -511,7 +513,7 @@ def grade(self) -> "Grade":
511
513
return Grade (self .graduation_year )
512
514
513
515
@property
514
- def permissions (self ) -> Dict [str , bool ]:
516
+ def permissions (self ) -> dict [str , bool ]:
515
517
"""Dynamically generate dictionary of privacy options.
516
518
517
519
Returns:
@@ -753,7 +755,7 @@ def is_global_admin(self) -> bool:
753
755
754
756
return self .member_of ("admin_all" ) and self .is_staff and self .is_superuser
755
757
756
- def can_manage_group (self , group : Union [ Group , str ] ) -> bool :
758
+ def can_manage_group (self , group : Group | str ) -> bool :
757
759
"""Checks whether this user has permission to edit/manage the given group (either
758
760
a Group or a group name).
759
761
@@ -1381,7 +1383,7 @@ def __getattr__(self, name):
1381
1383
raise AttributeError ("{!r} object has no attribute {!r}" .format (type (self ).__name__ , name ))
1382
1384
1383
1385
@cached_property
1384
- def base64 (self ) -> Optional [ bytes ] :
1386
+ def base64 (self ) -> bytes | None :
1385
1387
"""Returns base64 encoded binary data for a user's picture.
1386
1388
1387
1389
Returns:
@@ -1447,7 +1449,7 @@ def text(self) -> str:
1447
1449
return self ._name
1448
1450
1449
1451
@staticmethod
1450
- def number_from_name (name : str ) -> Optional [ int ] :
1452
+ def number_from_name (name : str ) -> int | None :
1451
1453
if name in Grade .names :
1452
1454
return Grade .names .index (name ) + 9
1453
1455
return None
0 commit comments