Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Upgrade to Python 3.12 #134

Merged
merged 11 commits into from
Sep 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
secrets: inherit
with:
# Cannot be set with an env var. Value must match in the release job.
python-version: 3.8
python-version: 3.12

release:
concurrency: release
Expand All @@ -25,7 +25,7 @@ jobs:
if: github.ref_name == 'main'
env:
# Value must match in the test job.
PYTHON_VERSION: 3.8
PYTHON_VERSION: 3.12
steps:
- name: 🛫 Checkout
uses: actions/checkout@v4
Expand Down
14 changes: 7 additions & 7 deletions Pipfile
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,14 @@ importlib-metadata = "==4.13.0" # TODO: remove. needed by old portal
django-formtools = "==2.2" # TODO: remove. needed by old portal
django-otp = "==1.0.2" # TODO: remove. needed by old portal
# https://pypi.org/user/codeforlife/
cfl-common = "==7.1.1" # TODO: remove
codeforlife-portal = "==7.1.1" # TODO: remove
rapid-router = "==6.0.1" # TODO: remove
cfl-common = "==7.3.3" # TODO: remove
codeforlife-portal = "==7.3.3" # TODO: remove
rapid-router = "==6.5.2" # TODO: remove
phonenumbers = "==8.12.12" # TODO: remove

[dev-packages]
black = "==23.1.0"
pytest = "==7.2.1"
black = "==24.8.0"
pytest = "==8.3.3"
pytest-cov = "==5.0.0"
pytest-env = "==0.8.1"
pytest-xdist = {version = "==3.5.0", extras = ["psutil"]}
Expand All @@ -34,12 +34,12 @@ django-extensions = "==3.2.1"
django-test-migrations = "==1.2.0"
pyparsing = "==3.0.9"
pydot = "==1.4.2"
pylint = "==3.0.2"
pylint = "==3.2.7"
pylint-django = "==2.5.5"
isort = "==5.13.2"
mypy = "==1.6.1"
django-stubs = {version = "==4.2.6", extras = ["compatible-mypy"]}
djangorestframework-stubs = {version = "==3.14.4", extras = ["compatible-mypy"]}

[requires]
python_version = "3.8"
python_version = "3.12"
463 changes: 245 additions & 218 deletions Pipfile.lock

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion codeforlife/models/signals/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,5 @@
https://docs.djangoproject.com/en/3.2/ref/signals/#module-django.db.models.signals
"""


from .general import UpdateFields, update_fields_includes
from .receiver import model_receiver
1 change: 1 addition & 0 deletions codeforlife/settings/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
cfl_settings.EXAMPLE_SETTING
`
"""

from .custom import *
from .django import *
from .third_party import *
1 change: 1 addition & 0 deletions codeforlife/settings/custom.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""
This file contains all of our custom settings we define for our own purposes.
"""

import os

# The name of the current service.
Expand Down
1 change: 1 addition & 0 deletions codeforlife/settings/django.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
This file contains all the settings Django supports out of the box.
https://docs.djangoproject.com/en/3.2/ref/settings/
"""

import os
from pathlib import Path

Expand Down
1 change: 1 addition & 0 deletions codeforlife/settings/third_party.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""
This file contains custom settings defined by third party extensions.
"""

from .django import DEBUG

# CORS
Expand Down
2 changes: 2 additions & 0 deletions codeforlife/tests/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,8 @@ def login_as(self, user: TypedUser, password: str = "password"):
user: The user to log in as.
password: The user's password.
"""
auth_user = None

if isinstance(user, AdminSchoolTeacherUser):
auth_user = self.login_admin_school_teacher(user.email, password)
elif isinstance(user, NonAdminSchoolTeacherUser):
Expand Down
23 changes: 16 additions & 7 deletions codeforlife/tests/model_serializer.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,8 @@ def _assert_data_is_subset_of_model(self, data: DataDict, model):
elif isinstance(value, Model):
data[field] = getattr(value, "id")

self.assertDictContainsSubset(data, model_to_dict(model))
model_dict = model_to_dict(model)
self.assertDictEqual(model_dict | data, model_dict)

def _assert_many(
self,
Expand All @@ -146,9 +147,9 @@ def _assert_many(
assert len(new_data) == len(validated_data)

kwargs.pop("many", None) # many must be True
serializer: ModelListSerializer[
RequestUser, AnyModel
] = self._init_model_serializer(*args, **kwargs, many=True)
serializer: ModelListSerializer[RequestUser, AnyModel] = (
self._init_model_serializer(*args, **kwargs, many=True)
)

models = get_models(serializer, deepcopy(validated_data))
assert len(models) == len(validated_data)
Expand Down Expand Up @@ -336,7 +337,12 @@ def assert_update_many(
)

def assert_to_representation(
self, instance: AnyModel, new_data: DataDict, *args, **kwargs
self,
instance: AnyModel,
new_data: DataDict,
*args,
non_model_fields: t.Optional[NonModelFields] = None,
**kwargs,
):
"""Assert:
1. the new data fields not contained in the model are equal.
Expand All @@ -345,6 +351,7 @@ def assert_to_representation(
Args:
instance: The model instance to represent.
new_data: The field values not contained in the model.
non_model_fields: Data fields that are not in the model.
"""
serializer = self._init_model_serializer(*args, **kwargs)
data = serializer.to_representation(instance)
Expand All @@ -353,12 +360,14 @@ def assert_new_data_is_subset_of_data(new_data: DataDict, data):
assert isinstance(data, dict)

for field, new_value in new_data.items():
value = data[field]
if isinstance(new_value, dict):
assert_new_data_is_subset_of_data(new_value, data[field])
assert_new_data_is_subset_of_data(new_value, value)
else:
assert new_value == data.pop(field)
assert new_value == value

assert_new_data_is_subset_of_data(new_data, data)
data = self._get_data(data, None, non_model_fields)
self._assert_data_is_subset_of_model(data, instance)


Expand Down
20 changes: 10 additions & 10 deletions codeforlife/tests/model_view_set.py
Original file line number Diff line number Diff line change
Expand Up @@ -614,9 +614,9 @@ class ModelViewSetTestCase(
basename: str
model_view_set_class: t.Type[ModelViewSet[RequestUser, AnyModel]]
client: ModelViewSetClient[RequestUser, AnyModel]
client_class: t.Type[
ModelViewSetClient[RequestUser, AnyModel]
] = ModelViewSetClient
client_class: t.Type[ModelViewSetClient[RequestUser, AnyModel]] = (
ModelViewSetClient
)

@classmethod
def get_model_class(cls) -> t.Type[AnyModel]:
Expand Down Expand Up @@ -743,11 +743,10 @@ def datetime_values_to_representation(data: DataDict):

# Assert the JSON model provided in the response is an exact match or
# subset of the serialized model.
(
self.assertDictContainsSubset
if contains_subset
else self.assertDictEqual
)(json_model, serialized_model)
self.assertDictEqual(
serialized_model | json_model if contains_subset else json_model,
serialized_model,
)

def assert_get_serializer_class(
self,
Expand Down Expand Up @@ -820,6 +819,7 @@ def assert_get_serializer_context(
*args, **kwargs, action=action
)
actual_serializer_context = model_view_set.get_serializer_context()
self.assertDictContainsSubset(
serializer_context, actual_serializer_context
self.assertDictEqual(
actual_serializer_context | serializer_context,
actual_serializer_context,
)
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
© Ocado Group
Created on 30/01/2024 at 12:36:00(+00:00).
"""

from ....tests import TestCase
from ...models import User
from .independent import IndependentPasswordValidator
Expand Down
1 change: 1 addition & 0 deletions codeforlife/user/auth/password_validators/student_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
© Ocado Group
Created on 30/01/2024 at 12:36:00(+00:00).
"""

from ....tests import TestCase
from ...models import User
from .student import StudentPasswordValidator
Expand Down
1 change: 1 addition & 0 deletions codeforlife/user/auth/password_validators/teacher_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
© Ocado Group
Created on 30/01/2024 at 12:36:00(+00:00).
"""

from ....tests import TestCase
from ...models import User
from .teacher import TeacherPasswordValidator
Expand Down
1 change: 1 addition & 0 deletions codeforlife/user/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
© Ocado Group
Created on 05/02/2024 at 13:48:55(+00:00).
"""

from .auth_factor import AuthFactor
from .klass import Class
from .otp_bypass_token import OtpBypassToken
Expand Down
1 change: 1 addition & 0 deletions codeforlife/user/models/teacher.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ def get_queryset(self):
objects: models.Manager["NonSchoolTeacher"] = Manager()


# pylint: disable-next=invalid-name
TypedTeacher = t.Union[
SchoolTeacher,
AdminSchoolTeacher,
Expand Down
1 change: 1 addition & 0 deletions codeforlife/user/models/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -605,6 +605,7 @@ class Meta(TypedModelMeta):
)


# pylint: disable-next=invalid-name
TypedUser = t.Union[
TeacherUser,
SchoolTeacherUser,
Expand Down
4 changes: 2 additions & 2 deletions codeforlife/user/serializers/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ class Meta(BaseUserSerializer.Meta):
def to_representation(self, instance):
try:
student = (
StudentSerializer(instance.new_student).data
dict(StudentSerializer(instance.new_student).data)
if instance.new_student and instance.new_student.class_field
else None
)
Expand All @@ -83,7 +83,7 @@ def to_representation(self, instance):

try:
teacher = (
TeacherSerializer[Teacher](instance.new_teacher).data
dict(TeacherSerializer[Teacher](instance.new_teacher).data)
if instance.new_teacher
else None
)
Expand Down
6 changes: 6 additions & 0 deletions codeforlife/user/serializers/user_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ def test_to_representation__teacher(self):
},
"student": None,
},
# TODO: remove in new schema.
non_model_fields={"requesting_to_join_class", "teacher", "student"},
)

def test_to_representation__student(self):
Expand All @@ -48,6 +50,8 @@ def test_to_representation__student(self):
"school": user.student.class_field.teacher.school.id,
},
},
# TODO: remove in new schema.
non_model_fields={"requesting_to_join_class", "teacher", "student"},
)

def test_to_representation__indy(self):
Expand All @@ -62,4 +66,6 @@ def test_to_representation__indy(self):
"teacher": None,
"student": None,
},
# TODO: remove in new schema.
non_model_fields={"requesting_to_join_class", "teacher", "student"},
)
1 change: 0 additions & 1 deletion codeforlife/user/views/school_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
Created on 20/01/2024 at 09:47:30(+00:00).
"""


from ...permissions import OR, AllowNone
from ...tests import ModelViewSetTestCase
from ..models import School, SchoolTeacherUser, StudentUser, User
Expand Down
4 changes: 2 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
© Ocado Group
Created on 11/12/2023 at 10:59:40(+00:00).

Setup the Code for Life package during installation.
Setup the Code for Life package during installation.
"""

import json
Expand Down Expand Up @@ -93,7 +93,7 @@ def parse_requirements(packages: t.Dict[str, t.Dict[str, t.Any]]):
include_package_data=True,
data_files=[get_data_files(DATA_DIR), get_data_files(USER_FIXTURES_DIR)],
package_data={"codeforlife": ["py.typed"]},
python_requires="==3.8.*",
python_requires="==3.12.*",
install_requires=install_requires,
extras_require={"dev": dev_requires},
dependency_links=[],
Expand Down