diff --git a/.github/workflows/linter.yaml b/.github/workflows/linter.yaml index 2d1ecc80..fc5185e8 100644 --- a/.github/workflows/linter.yaml +++ b/.github/workflows/linter.yaml @@ -36,7 +36,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - django-version: [django320] + django-version: [django420] steps: - run: | sudo apt update @@ -44,9 +44,9 @@ jobs: - uses: actions/checkout@v3 - uses: actions/setup-python@v4 with: - python-version: 3.9 + python-version: 3.11 - name: Install tox run: | python3 -m pip install --upgrade pip - python3 -m pip install 'tox<4.0' + python3 -m pip install tox - run: tox -e mypy-${{ matrix.django-version }} diff --git a/.github/workflows/unittests.yaml b/.github/workflows/unittests.yaml index b32b8890..d430abf6 100644 --- a/.github/workflows/unittests.yaml +++ b/.github/workflows/unittests.yaml @@ -17,18 +17,9 @@ jobs: max-parallel: 7 matrix: python-version: [3.9, '3.10', '3.11'] - django-version: [django320, django420] + django-version: [django420] db: [sqlite] include: - - python-version: '3.11' - django-version: django320 - db: mysql - - python-version: '3.11' - django-version: django320 - db: mariadb - - python-version: '3.11' - django-version: django320 - db: postgres - python-version: '3.11' django-version: django420 db: mysql diff --git a/src/tcms/core/ajax.py b/src/tcms/core/ajax.py index 5cd88817..b880dfbe 100644 --- a/src/tcms/core/ajax.py +++ b/src/tcms/core/ajax.py @@ -328,9 +328,7 @@ def _record_log_actions(log_actions_info: list[LogActionInfo]) -> None: params["who"], ) - def _simple_update( - self, models: Union[QuerySet, list[TCMSActionModel]], new_value: Any - ) -> None: + def _simple_update(self, models, new_value: Any) -> None: """A simple update method for most cases to update property of a set of cases In the most of the cases, the property update requires two steps, one is to update the @@ -355,19 +353,13 @@ def _simple_update( if original_value == str(new_value): continue - log_actions_info.append( - ( - model, - [ - { - "who": self.request.user, - "field": self.target_field, - "original_value": original_value, - "new_value": str(new_value), - } - ], - ) - ) + params = { + "who": self.request.user, + "field": self.target_field, + "original_value": original_value, + "new_value": str(new_value), + } + log_actions_info.append((model, [params])) setattr(model, self.target_field, new_value) changed.append(model) @@ -451,7 +443,7 @@ def __init__(self, *args, **kwargs): f.queryset = TestCaseRun.objects.select_related("case", "assignee").only( "case", "assignee__username" ) - f: forms.ModelChoiceField = self.fields["new_value"] + f = self.fields["new_value"] new_assignee_pk = self.data.get("new_value") f.error_messages["invalid_choice"] = f"No user with id {new_assignee_pk} exists." @@ -488,7 +480,7 @@ def __init__(self, *args, **kwargs): f.queryset = TestCaseRun.objects.select_related("case_run_status", "tested_by").only( "close_date", "tested_by__username", "case_run_status__name" ) - f: forms.ModelChoiceField = self.fields["new_value"] + f = self.fields["new_value"] new_status = self.data.get("new_value") f.error_messages[ "invalid_choice" @@ -517,15 +509,14 @@ def _update_case_run_status(self): if not f.is_valid(): return JsonResponseBadRequest({"message": form_error_messages_to_list(f)}) - request_user: User = self.request.user + request_user = self.request.user new_status = f.cleaned_data["new_value"] update_time = datetime.datetime.now() log_actions_info = [] - changed: list[TestCaseRun] = [] + changed = [] tested_by_changed = False - case_run: TestCaseRun for case_run in f.cleaned_data["case_run"]: if case_run.case_run_status == new_status: continue @@ -618,7 +609,7 @@ def __init__(self, *args, **kwargs): f.queryset = TestCase.objects.select_related("default_tester").only( "default_tester__username" ) - f: forms.ModelChoiceField = self.fields["new_value"] + f = self.fields["new_value"] f.error_messages["invalid_choice"] = ( f"{self.data['new_value']} cannot be set as a default tester, " f"since this user does not exist." @@ -654,7 +645,7 @@ def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) f = self.fields["case"] f.queryset = TestCase.objects.select_related("reviewer").only("reviewer__username") - f: forms.ModelChoiceField = self.fields["new_value"] + f = self.fields["new_value"] f.error_messages["invalid_choice"] = f"Reviewer {self.data['new_value']} is not found" @@ -680,7 +671,7 @@ class PatchTestCaseSortKeyForm(PatchTestCaseBaseForm): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.fields["case"].queryset = TestCase.objects.only("pk") - f: forms.ModelChoiceField = self.fields["plan"] + f = self.fields["plan"] f.error_messages["invalid_choice"] = f"No plan with id {self.data['plan']} exists." diff --git a/src/tcms/core/files.py b/src/tcms/core/files.py index d13ac380..648c1836 100644 --- a/src/tcms/core/files.py +++ b/src/tcms/core/files.py @@ -64,7 +64,7 @@ def post(self, request): if not upload_file: return HttpResponseRedirect(redirect_url) - upload_file: UploadedFile = request.FILES["upload_file"] + upload_file = request.FILES["upload_file"] if upload_file.size > settings.MAX_UPLOAD_SIZE: return prompt.alert( diff --git a/src/tcms/core/views/prompt.py b/src/tcms/core/views/prompt.py index 3d1b992e..d3bdb166 100644 --- a/src/tcms/core/views/prompt.py +++ b/src/tcms/core/views/prompt.py @@ -1,6 +1,8 @@ # -*- coding: utf-8 -*- # FIXME: Use exception to replace the feature +from typing import Optional + from django.http import HttpRequest from django.shortcuts import render @@ -8,7 +10,7 @@ PROMPT_INFO = "info" -def alert(request: HttpRequest, content: str, next_: str = None): +def alert(request: HttpRequest, content: str, next_: Optional[str] = None): return render( request, "prompt.html", @@ -16,7 +18,7 @@ def alert(request: HttpRequest, content: str, next_: str = None): ) -def info(request: HttpRequest, content: str, next_: str = None): +def info(request: HttpRequest, content: str, next_: Optional[str] = None): return render( request, "prompt.html", diff --git a/src/tcms/management/models.py b/src/tcms/management/models.py index 3f655b9b..7dda47b3 100644 --- a/src/tcms/management/models.py +++ b/src/tcms/management/models.py @@ -251,8 +251,7 @@ def to_xmlrpc(cls, query=None): return s.serialize_queryset() @classmethod - def search(cls, query): - val: Any + def search(cls, query: dict[str, Any]): criteria: dict[str, Any] = {} if val := query.get("build_id"): @@ -536,7 +535,7 @@ def get_active(cls): # FIXME: plugins_support is no longer available, this is dead code. -if register_model: +if register_model: # type: ignore register_model(Classification) register_model(Product) register_model(Priority) diff --git a/src/tcms/testcases/models.py b/src/tcms/testcases/models.py index 16166a42..492697b0 100644 --- a/src/tcms/testcases/models.py +++ b/src/tcms/testcases/models.py @@ -2,7 +2,7 @@ import logging from datetime import datetime -from typing import Any, Optional, Union +from typing import Any, Dict, Optional, Union from django.conf import settings from django.contrib.contenttypes.fields import GenericRelation @@ -235,7 +235,7 @@ def update(cls, case_ids, values): return tcs @classmethod - def search(cls, query, plan=None): + def search(cls, query: Dict[str, Any], plan: Optional[int] = None) -> QuerySet["TestCase"]: """List the cases with request""" from django.db.models import Q @@ -1052,7 +1052,7 @@ def _listen(): if settings.LISTENING_MODEL_SIGNAL: _listen() -if register_model: +if register_model: # type: ignore register_model(TestCase) register_model(TestCaseText) register_model(TestCasePlan) diff --git a/src/tcms/testcases/views.py b/src/tcms/testcases/views.py index e63ed823..6ce30783 100644 --- a/src/tcms/testcases/views.py +++ b/src/tcms/testcases/views.py @@ -763,7 +763,7 @@ def get_context_data(self, **kwargs): this_cls = TestCaseCaseRunDetailPanelView data = super(this_cls, self).get_context_data(**kwargs) - case: TestCase = get_object_or_404(TestCase.objects.only("pk"), pk=self.case_id) + case = get_object_or_404(TestCase.objects.only("pk"), pk=self.case_id) case_run = get_object_or_404(TestCaseRun, pk=self.case_run_id, case=case) # Data of TestCase @@ -1250,7 +1250,6 @@ def clone(request, template_name="case/clone.html"): src_plan = plan_from_request_or_none(request) dest_case = None - src_cases: TestCase for src_case in src_cases: author = None if keep_orig_author else request.user default_tester = None if keep_orig_default_tester else request.user diff --git a/src/tcms/testplans/models.py b/src/tcms/testplans/models.py index 55531776..69268096 100644 --- a/src/tcms/testplans/models.py +++ b/src/tcms/testplans/models.py @@ -80,7 +80,7 @@ class TestPlan(TCMSActionModel): ) env_group = models.ManyToManyField( "management.TCMSEnvGroup", related_name="plans", through="TCMSEnvPlanMap" - ) + ) # type: ignore tag = models.ManyToManyField("management.TestTag", through="testplans.TestPlanTag") class Meta: @@ -634,7 +634,7 @@ def set_email_settings_to_new_plan(sender, **kwargs): TestPlanEmailSettings.objects.create(plan=kwargs["instance"]) -if register_model: +if register_model: # type: ignore register_model(TestPlan) register_model(TestPlanText) register_model(TestPlanType) diff --git a/src/tcms/testplans/views.py b/src/tcms/testplans/views.py index 158ca848..37d915b7 100644 --- a/src/tcms/testplans/views.py +++ b/src/tcms/testplans/views.py @@ -994,7 +994,7 @@ def handle_no_permission(self): ) def patch(self, request, *args, **kwargs): - plan: TestPlan = TestPlan.objects.filter(pk=self.kwargs["plan_id"]).only("pk").first() + plan = TestPlan.objects.filter(pk=self.kwargs["plan_id"]).only("pk").first() if plan is None: return JsonResponseNotFound( { @@ -1004,7 +1004,7 @@ def patch(self, request, *args, **kwargs): ) data = json.loads(request.body) - user_input: Optional[str] = data.get("parent") + user_input = data.get("parent") if user_input is None: return JsonResponseBadRequest({"message": "Missing parent plan id."}) if not isinstance(user_input, int): @@ -1049,10 +1049,10 @@ class SetPlanActiveView(PermissionRequiredMixin, View): def patch(self, request, *args, **kwargs): plan_id = self.kwargs["plan_id"] - plan: TestPlan = TestPlan.objects.filter(pk=plan_id).only("is_active").first() + plan = TestPlan.objects.filter(pk=plan_id).only("is_active").first() if not plan: return JsonResponseNotFound({"message": f"Plan id {plan_id} does not exist."}) - original_value: str = str(plan.is_active) + original_value = str(plan.is_active) plan.is_active = self.enable plan.save(update_fields=["is_active"]) plan.log_action( diff --git a/src/tcms/testruns/helpers/serializer.py b/src/tcms/testruns/helpers/serializer.py index 39903dbc..6eb88368 100644 --- a/src/tcms/testruns/helpers/serializer.py +++ b/src/tcms/testruns/helpers/serializer.py @@ -5,7 +5,6 @@ import csv -from django.template import Template from django.template.loader import get_template # TODO: rewrite export module to export TestCaseRuns, TestPlans and other @@ -84,5 +83,5 @@ def write_to_xml(self, output): .. versionchanged:: 4.2 Element ``bugs`` is renamed to ``issues``. """ - xml_template: Template = get_template("run/export-to.xml") + xml_template = get_template("run/export-to.xml") output.write(xml_template.render({"case_runs": self.tcrs})) diff --git a/src/tcms/testruns/models.py b/src/tcms/testruns/models.py index 74850ff5..dfd69e9f 100644 --- a/src/tcms/testruns/models.py +++ b/src/tcms/testruns/models.py @@ -229,7 +229,7 @@ def add_cc(self, user): def add_env_value(self, env_value: TCMSEnvValue): return TCMSEnvRunValueMap.objects.get_or_create(run=self, value=env_value) - def remove_tag(self, tag): + def remove_tag(self, tag: TestTag) -> None: cursor = connection.writer_cursor cursor.execute( "DELETE from test_run_tags WHERE run_id = %s AND tag_id = %s", @@ -617,7 +617,7 @@ def _run_listen(): if settings.LISTENING_MODEL_SIGNAL: _run_listen() -if register_model: +if register_model: # type: ignore register_model(TestRun) register_model(TestCaseRun) register_model(TestRunTag) diff --git a/src/tcms/testruns/views.py b/src/tcms/testruns/views.py index 9b90f559..50389a4e 100644 --- a/src/tcms/testruns/views.py +++ b/src/tcms/testruns/views.py @@ -610,7 +610,7 @@ class RunStatisticsView(TemplateView): def get_context_data(self, **kwargs): data = super().get_context_data() run_id = self.kwargs["run_id"] - run: TestRun = get_object_or_404(TestRun.objects.only("pk"), pk=run_id) + run = get_object_or_404(TestRun.objects.only("pk"), pk=run_id) data.update( { "test_run": run, @@ -628,7 +628,7 @@ def get(request, run_id, template_name="run/get.html"): SUB_MODULE_NAME = "runs" # Get the test run - tr: TestRun = get_object_or_404(TestRun.objects.select_related(), pk=run_id) + tr = get_object_or_404(TestRun.objects.select_related(), pk=run_id) # Get the test case runs belong to the run # 2. get test run's all case runs @@ -695,7 +695,7 @@ def edit(request, run_id, template_name="run/edit.html"): SUB_MODULE_NAME = "runs" try: - tr: TestRun = TestRun.objects.select_related().get(run_id=run_id) + tr = TestRun.objects.select_related().get(run_id=run_id) except ObjectDoesNotExist: raise Http404 @@ -821,7 +821,6 @@ def get_context_data(self, **kwargs): automated_count = 0 manual_automated_count = 0 - case_run: TestCaseRun for case_run in case_runs: case_run.display_issues = issues_by_case_run.get(case_run.pk, ()) user_comments = comments.get(case_run.pk, []) diff --git a/src/tcms/xmlrpc/api/testrun.py b/src/tcms/xmlrpc/api/testrun.py index 0aeb4ca1..02681044 100644 --- a/src/tcms/xmlrpc/api/testrun.py +++ b/src/tcms/xmlrpc/api/testrun.py @@ -132,11 +132,10 @@ def add_tag(request, run_ids, tags): TestPlan.add_tag('1, 2', 'foo, bar') """ trs = TestRun.objects.filter(pk__in=pre_process_ids(value=run_ids)) - tags: list[str] = TestTag.string_to_list(tags) + tags = TestTag.string_to_list(tags) for tag in tags: t, _ = TestTag.objects.get_or_create(name=tag) - tr: TestRun for tr in trs.iterator(): tr.add_tag(tag=t) @@ -533,7 +532,6 @@ def remove_tag(request, run_ids, tags): trs = TestRun.objects.filter(run_id__in=pre_process_ids(value=run_ids)) tgs = TestTag.objects.filter(name__in=TestTag.string_to_list(tags)) - tr: TestRun for tr in trs.iterator(): for tg in tgs.iterator(): tr.remove_tag(tag=tg) diff --git a/tests/__init__.py b/tests/__init__.py index bc70ad9a..8a661c25 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -5,6 +5,7 @@ import re from functools import partial from http import HTTPStatus +from typing import ClassVar from urllib.parse import parse_qs, urlparse from django import test @@ -230,6 +231,9 @@ def get_max_plan_id(self): class BasePlanCase(AuthMixin, HelperAssertions, NitrateTestCase): """Base test case by providing essential Plan and Case objects used in tests""" + case_1: ClassVar + case_3: ClassVar + @classmethod def setUpTestData(cls): super().setUpTestData() diff --git a/tests/conftest.py b/tests/conftest.py index 0f6a353b..00237267 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -15,7 +15,7 @@ @pytest.fixture def tester(django_user_model): - user: User = django_user_model.objects.create(username="tester", email="tester@example.com") + user = django_user_model.objects.create(username="tester", email="tester@example.com") user.set_password(TESTER_PASSWORD) user.save() return user diff --git a/tests/core/test_ajax.py b/tests/core/test_ajax.py index f3cbb8a4..a36c1ec6 100644 --- a/tests/core/test_ajax.py +++ b/tests/core/test_ajax.py @@ -111,8 +111,6 @@ def test_change_assignee(self): mail.outbox = [] update_targets = [self.case_run_1, self.case_run_3] - case_run: TestCaseRun - resp = self.client.patch( self.url, data={ @@ -196,7 +194,7 @@ def test_ensure_mail_notify_is_sent(self): case = TestCase.objects.get(pk=self.case_2.pk) self.assertEqual(self.reviewer.username, case.reviewer.username) - out_mail: EmailMessage = mail.outbox[0] + out_mail = mail.outbox[0] self.assertEqual("You have been the reviewer of cases", out_mail.subject) self.assertListEqual([self.reviewer.email], out_mail.recipients()) @@ -248,7 +246,6 @@ def test_change_status(self): self.assertEqual(200, resp.status_code) - case_run: TestCaseRun for case_run in [self.case_run_1, self.case_run_3]: self.assertEqual( self.running_status, TestCaseRun.objects.get(pk=case_run.pk).case_run_status @@ -379,10 +376,9 @@ def test_new_sort_key_is_not_in_range(self): def test_update_sort_key(self): new_sort_key = 2 - update_targets: list[TestCaseRun] = [self.case_run_2, self.case_run_4] + update_targets = [self.case_run_2, self.case_run_4] - case_run: TestCaseRun - update_targets_pks: list[int] = [case_run.pk for case_run in update_targets] + update_targets_pks = [case_run.pk for case_run in update_targets] resp = self.client.patch( self.url, @@ -408,7 +404,7 @@ def test_update_sort_key(self): ) # Other case runs' sortkey should not be changed. - sort_keys: list[int] = TestCaseRun.objects.exclude(pk__in=update_targets_pks).values_list( + sort_keys = TestCaseRun.objects.exclude(pk__in=update_targets_pks).values_list( "sortkey", flat=True ) for sort_key in sort_keys: @@ -451,7 +447,6 @@ def test_set_default_tester(self): self.assertJsonResponse(resp, {}) - case: TestCase for case in [self.case_1, self.case_2]: self.assertEqual(self.user_1, TestCase.objects.get(pk=case.pk).default_tester) self.assertTrue( @@ -487,7 +482,6 @@ def test_given_username_does_not_exist(self): status_code=HTTPStatus.BAD_REQUEST, ) - case: TestCase for case in [self.case_1, self.case_2]: self.assertEqual(case.default_tester, TestCase.objects.get(pk=case.pk).default_tester) @@ -518,7 +512,6 @@ def test_change_priority(self): self.assertEqual(p4, TestCase.objects.get(pk=self.case_1.pk).priority) self.assertEqual(p4, TestCase.objects.get(pk=self.case_3.pk).priority) - case: TestCase for case in [self.case_1, self.case_3]: self.assertTrue( TCMSLogModel.objects.filter( @@ -565,7 +558,6 @@ def test_change_reviewer(self): resp = self.client.patch(self.url, data=data, content_type="application/json") self.assert200(resp) - case: TestCase for case in [self.case_1, self.case_3]: self.assertEqual(self.reviewer, TestCase.objects.get(pk=case.pk).reviewer) self.assertTrue( @@ -612,7 +604,6 @@ def test_change_status(self): resp = self.client.patch(self.url, data=data, content_type="application/json") self.assertJsonResponse(resp, {}) - case: TestCase for case in [self.case_1, self.case_3]: self.assertEqual( self.case_status_proposed, TestCase.objects.get(pk=case.pk).case_status diff --git a/tests/core/test_files.py b/tests/core/test_files.py index d4a492cc..8b9acc78 100644 --- a/tests/core/test_files.py +++ b/tests/core/test_files.py @@ -44,7 +44,7 @@ def setUp(self): klass_name = self.__class__.__name__ self.working_dir = tempfile.mkdtemp(prefix=klass_name) - file_content: bytes = b"abc" * 100 + file_content = b"abc" * 100 fd, self.upload_filename = tempfile.mkstemp( suffix=f"{klass_name}-upload-file.txt", dir=self.working_dir diff --git a/tests/core/test_views.py b/tests/core/test_views.py index 124b96ca..4773f436 100644 --- a/tests/core/test_views.py +++ b/tests/core/test_views.py @@ -153,7 +153,7 @@ class TestIndexView(test.TestCase): @classmethod def setUpTestData(cls): cls.password = "password" - cls.user: User = User.objects.create(username="tester", email="tester@localhost") + cls.user = User.objects.create(username="tester", email="tester@localhost") cls.user.set_password(cls.password) cls.user.save() diff --git a/tests/testplans/test_models.py b/tests/testplans/test_models.py index a60e93f5..e8777910 100644 --- a/tests/testplans/test_models.py +++ b/tests/testplans/test_models.py @@ -198,7 +198,7 @@ def test_collect_recipients(self): es.auto_to_case_default_tester = bool(auto_to_case_default_tester) es.save() - plan: TestPlan = TestPlan.objects.get(pk=self.plan.pk) + plan = TestPlan.objects.get(pk=self.plan.pk) # Since this test contains the case of plan.owner is None, # recover the plan's owner here. @@ -255,7 +255,7 @@ def setUpTestData(cls): def test_get_ancestor_ids(self): expected = [self.plan.pk, self.plan_2.pk, self.plan_3.pk] - plan: TestPlan = TestPlan.objects.get(pk=self.plan_4.pk) + plan = TestPlan.objects.get(pk=self.plan_4.pk) self.assertListEqual(expected, sorted(plan.get_ancestor_ids())) def test_get_ancestors(self): @@ -275,7 +275,7 @@ def test_get_ancestors(self): def test_get_descendant_ids(self): expected = [self.plan_4.pk, self.plan_5.pk, self.plan_6.pk, self.plan_7.pk] - plan: TestPlan = TestPlan.objects.get(pk=self.plan_3.pk) + plan = TestPlan.objects.get(pk=self.plan_3.pk) self.assertListEqual(expected, sorted(plan.get_descendant_ids())) def test_get_descendants(self): @@ -308,7 +308,7 @@ def test_get_direct_descendants(self): ] for parent_plan, expected in test_data: - plan: TestPlan = TestPlan.objects.get(pk=parent_plan) + plan = TestPlan.objects.get(pk=parent_plan) self.assertListEqual(expected, sorted(plan.get_descendant_ids(True))) @@ -678,7 +678,7 @@ def test_plan_add_env_group(group_name, tester, base_data): else: env_group = TCMSEnvGroup.objects.create(name=group_name, manager=tester) plan.add_env_group(env_group) - rels: list[TCMSEnvPlanMap] = list(TCMSEnvPlanMap.objects.all()) + rels = list(TCMSEnvPlanMap.objects.all()) assert 1 == len(rels) assert env_group == rels[0].group diff --git a/tests/testplans/test_views.py b/tests/testplans/test_views.py index 000a40cf..fd6974e1 100644 --- a/tests/testplans/test_views.py +++ b/tests/testplans/test_views.py @@ -7,7 +7,7 @@ import xml.etree.ElementTree as et from http import HTTPStatus from textwrap import dedent -from typing import Optional, Union +from typing import List, Optional, Tuple, Union from unittest.mock import Mock import pytest @@ -1136,14 +1136,11 @@ def test_parent_is_a_descendant_already(self): ) def test_change_parent(self): - targets = ( + targets = [ (self.plan_5, str(self.plan_5.parent.pk)), (self.plan_9, "None"), - ) - new_parent: TestPlan = self.plan_3 - - target_plan: TestPlan - expected_original_value: str + ] + new_parent = self.plan_3 for target_plan, expected_original_value in targets: resp = self.client.patch( diff --git a/tests/testruns/test_views.py b/tests/testruns/test_views.py index 67440818..00830f3a 100644 --- a/tests/testruns/test_views.py +++ b/tests/testruns/test_views.py @@ -1276,11 +1276,11 @@ def test_update_single_case_run(self): ) def test_update_multiple_case_runs(self): - case_runs: list[int] = [self.case_run_1.pk, self.case_run_2.pk] + case_runs = [self.case_run_1.pk, self.case_run_2.pk] response = self.client.post(self.update_url, {"case_run": case_runs}) for pk in case_runs: - case_run: TestCaseRun = TestCaseRun.objects.get(pk=pk) + case_run = TestCaseRun.objects.get(pk=pk) self.assertEqual( case_run.case.latest_text_version(), case_run.latest_text().case_text_version, @@ -1338,8 +1338,8 @@ def test_edit_run(self): self.assertRedirects(response, reverse("run-get", args=[run.pk])) def test_auto_update_run_status_when_all_case_runs_complete(self): - case_run: QuerySet = self.test_run.case_run - case_run.update(case_run_status=TestCaseRunStatus.objects.get(name="PASSED")) + status_passed = TestCaseRunStatus.objects.get(name="PASSED") + self.test_run.case_run.update(case_run_status=status_passed) post_data = { "summary": "New run summary", @@ -1360,7 +1360,7 @@ def test_auto_update_run_status_when_all_case_runs_complete(self): assert test_run.stop_date is not None def test_auto_update_run_status_when_partial_case_runs_complete(self): - case_runs: QuerySet[TestCaseRun] = self.test_run.case_run.all() + case_runs = self.test_run.case_run.all() case_runs[0].case_run_status = TestCaseRunStatus.objects.get(name="PASSED") case_runs[1].case_run_status = TestCaseRunStatus.objects.get(name="ERROR") case_runs[2].case_run_status = TestCaseRunStatus.objects.get(name="IDLE") diff --git a/tests/xmlrpc/test_testrun.py b/tests/xmlrpc/test_testrun.py index 4ce624d4..6b94da9b 100644 --- a/tests/xmlrpc/test_testrun.py +++ b/tests/xmlrpc/test_testrun.py @@ -18,6 +18,7 @@ from tcms.xmlrpc.utils import pre_process_ids from tests import factories as f from tests import user_should_have_perm +from tests.conftest import BaseDataContext from tests.xmlrpc.utils import XmlrpcAPIBaseTest, make_http_request @@ -441,7 +442,7 @@ def test_get_tags(run_id: int, expected, tester, base_data): [2, [1, 2]], ], ) -def test_get_test_case_runs(run_id, expected, tester, base_data): +def test_get_test_case_runs(run_id, expected, tester, base_data: BaseDataContext): plan = base_data.create_plan(pk=1, name="plan 1") case_1 = base_data.create_case(pk=1, summary="case 1") case_2 = base_data.create_case(pk=2, summary="case 2") @@ -450,7 +451,7 @@ def test_get_test_case_runs(run_id, expected, tester, base_data): plan.add_case(case_2) base_data.create_test_run(pk=1, plan=plan) - run_2: TestRun = base_data.create_test_run(pk=2, plan=plan) + run_2 = base_data.create_test_run(pk=2, plan=plan) TestCaseRun.objects.create( pk=1, run=run_2, diff --git a/tests/xmlrpc/test_user.py b/tests/xmlrpc/test_user.py index d871e5c7..3953565b 100644 --- a/tests/xmlrpc/test_user.py +++ b/tests/xmlrpc/test_user.py @@ -172,7 +172,7 @@ def setUp(self) -> None: def test_update_myself(self): request = make_http_request(user=self.user) data = XUser.update(request, self.user_new_attrs, request.user.pk) - user: User = User.objects.get(pk=request.user.pk) + user = User.objects.get(pk=request.user.pk) self.assertEqual(data["first_name"], user.first_name) self.assertEqual(data["last_name"], user.last_name) self.assertEqual(data["email"], user.email) @@ -180,7 +180,7 @@ def test_update_myself(self): def test_update_myself_without_passing_my_id(self): request = make_http_request(user=self.user) data = XUser.update(request, self.user_new_attrs) - user: User = User.objects.get(pk=request.user.pk) + user = User.objects.get(pk=request.user.pk) self.assertEqual(data["first_name"], user.first_name) self.assertEqual(data["last_name"], user.last_name) self.assertEqual(data["email"], user.email) @@ -193,7 +193,7 @@ def test_cannot_update_other_user_without_permission(self): def test_update_other_with_proper_permission(self): request = make_http_request(user=self.user_with_perm) data = XUser.update(request, self.user_new_attrs, self.user.pk) - user: User = User.objects.get(pk=self.user.pk) + user = User.objects.get(pk=self.user.pk) self.assertEqual(data["first_name"], user.first_name) self.assertEqual(data["last_name"], user.last_name) self.assertEqual(data["email"], user.email) diff --git a/tox.ini b/tox.ini index 31e45e45..2ec87fed 100644 --- a/tox.ini +++ b/tox.ini @@ -1,7 +1,7 @@ [tox] envlist = - {py39,py310,py311}-django{320,420}-sqlite - py311-django{320,420}-{mysql,mariadb,postgres} + {py39,py310,py311}-django{420}-sqlite + py311-django{420}-{mysql,mariadb,postgres} flake8 docs ; This is not that jslint :) @@ -11,12 +11,11 @@ envlist = doc8 isort bandit - mypy-django{320} + mypy-django{420} [testenv] passenv = * deps = - django320: Django>=3.2,<3.3 django420: Django>=4.2,<4.3 usedevelop = True extras = @@ -42,7 +41,7 @@ environment = MYSQL_ROOT_PASSWORD=pass MYSQL_DATABASE=nitrate -[testenv:{py39,py310}-django{320}-mysql] +[testenv:{py39,py310}-django{420}-mysql] docker = testdb_mysql allowlist_externals = @@ -61,7 +60,7 @@ commands_pre = sleep 25 bash {toxinidir}/contrib/scripts/adjust_mysql_auth_plugin.sh root pass -[testenv:{py39,py310}-django{320}-mariadb] +[testenv:{py39,py310}-django{420}-mariadb] docker = testdb_mariadb allowlist_externals = @@ -88,7 +87,7 @@ environment = POSTGRES_PASSWORD=nitrate POSTGRES_DB=testdb -[testenv:{py39,py310}-django{320}-postgres] +[testenv:{py39,py310}-django{420}-postgres] docker = testdb_postgres allowlist_externals = @@ -175,11 +174,11 @@ skip_install = true deps = bandit==1.7.4 commands = bandit -r {posargs:src/tcms} -[testenv:mypy-django{320}] +[testenv:mypy-django{420}] deps = {[testenv]deps} - django320: django-stubs==1.12.0 - django320: mypy==0.971 + django420: django-stubs==4.2.7 + django420: mypy>=1.7,<1.8 usedevelop = True extras = {[testenv]extras}