diff --git a/aleksis/apps/untis/management/commands/untis_import_mysql.py b/aleksis/apps/untis/management/commands/untis_import_mysql.py index 2da36c8c0cb0d740a16956c448955bb577546873..f433d5fd5348bf5fe1a92efbdeebca61f6da0cf0 100644 --- a/aleksis/apps/untis/management/commands/untis_import_mysql.py +++ b/aleksis/apps/untis/management/commands/untis_import_mysql.py @@ -25,6 +25,6 @@ class Command(BaseCommand): def handle(self, *args, **options): command = COMMANDS_BY_NAME[options["command"]] background = options["background"] - school_id = options.get("school_id", None) - version = options.get("plan_version", None) + school_id = options.get("school_id") + version = options.get("plan_version") command.run(background=background, school_id=school_id, version=version) diff --git a/aleksis/apps/untis/tests/util/test_mysql_util.py b/aleksis/apps/untis/tests/util/test_mysql_util.py index 17a095295e9a698f3104b32cf2976560982cca6a..86974fb3cc382d6ffe5699d2312b2d0ad3bb34fb 100644 --- a/aleksis/apps/untis/tests/util/test_mysql_util.py +++ b/aleksis/apps/untis/tests/util/test_mysql_util.py @@ -4,12 +4,22 @@ from aleksis.apps.untis.util.mysql.util import ( untis_split_third, ) -test_lesson_element = """49~0~302~7r;~0;~0~0~175608~~~~~"Freiraum: Naturwissenschaften, Fokus Physik"~"Nawi"~~n~~;11;12;13;14;15;16;17;,49~0~302~7r;~0;~0~0~175608~~~~~"Freiraum: Naturwissenschaften, Fokus Physik"~"Nawi"~~n~~;11;12;13;14;15;16;17;""" +test_lesson_element = ( + '49~0~302~7r;~0;~0~0~175608~~~~~"Freiraum: Naturwissenschaften, Fokus Physik"~' + '"Nawi"~~n~~;11;12;13;14;15;16;17;,49~0~302~7r;~0;~0~0~175608~~' + '~~~"Freiraum: Naturwissenschaften, Fokus Physik"~"Nawi"~~n~~;11;12;13;14;15;16;17;' +) -test_lesson_element_partial = """49~0~302~7r;~0;~0~0~175608~~~~~"Freiraum: Naturwissenschaften, Fokus Physik"~"Nawi"~~n~~;11;12;13;14;15;16;17;""" +test_lesson_element_partial = ( + '49~0~302~7r;~0;~0~0~175608~~~~~"Freiraum: Naturwissenschaften,' + + ' Fokus Physik"~"Nawi"~~n~~;11;12;13;14;15;16;17;' +) test_lesson_element_partial_partial = ";11;12;13;14;15;16;17;" -test_lesson_element_second = """46~0~92~45;~45;~12~11~0~~B~~~~~~n~~;18;~"Wp_Eb"~~34~0~67900~0~0~~21700,45~0~92~45;~45;~0~0~19000~~~~~~~~n~~;18;~"Wp_Eb"~~34~0~67900~0~0~~0""" +test_lesson_element_second = ( + '46~0~92~45;~45;~12~11~0~~B~~~~~~n~~;18;~"Wp_Eb"~~34~0~67900~0~0~~' + + '21700,45~0~92~45;~45;~0~0~19000~~~~~~~~n~~;18;~"Wp_Eb"~~34~0~67900~0~0~~0' +) def test_untis_split_first(): @@ -22,14 +32,16 @@ def test_untis_split_first(): assert len(untis_split_first(test_lesson_element)) == 2 assert untis_split_first(test_lesson_element) == [ - """49~0~302~7r;~0;~0~0~175608~~~~~"Freiraum: Naturwissenschaften, Fokus Physik"~"Nawi"~~n~~;11;12;13;14;15;16;17;""", - """49~0~302~7r;~0;~0~0~175608~~~~~"Freiraum: Naturwissenschaften, Fokus Physik"~"Nawi"~~n~~;11;12;13;14;15;16;17;""", + '49~0~302~7r;~0;~0~0~175608~~~~~"Freiraum: Naturwissenschaften, ' + + 'Fokus Physik"~"Nawi"~~n~~;11;12;13;14;15;16;17;', + '49~0~302~7r;~0;~0~0~175608~~~~~"Freiraum: Naturwissenschaften, ' + + 'Fokus Physik"~"Nawi"~~n~~;11;12;13;14;15;16;17;', ] assert len(untis_split_first(test_lesson_element_second)) == 2 assert untis_split_first(test_lesson_element_second) == [ - """46~0~92~45;~45;~12~11~0~~B~~~~~~n~~;18;~"Wp_Eb"~~34~0~67900~0~0~~21700""", - """45~0~92~45;~45;~0~0~19000~~~~~~~~n~~;18;~"Wp_Eb"~~34~0~67900~0~0~~0""", + '46~0~92~45;~45;~12~11~0~~B~~~~~~n~~;18;~"Wp_Eb"~~34~0~67900~0~0~~21700', + '45~0~92~45;~45;~0~0~19000~~~~~~~~n~~;18;~"Wp_Eb"~~34~0~67900~0~0~~0', ] @@ -45,7 +57,7 @@ def test_untis_split_second(): assert untis_split_second("1~~3", int, remove_empty=False) == [1, None, 3] assert untis_split_second("1~~3", int) == [1, 3] - assert untis_split_second(""""asdf"~"asdf"~"asdf""") == ["asdf", "asdf", "asdf"] + assert untis_split_second('"asdf"~"asdf"~"asdf') == ["asdf", "asdf", "asdf"] assert len(untis_split_second(test_lesson_element_partial, remove_empty=False)) == 18 assert untis_split_second(test_lesson_element_partial, remove_empty=False) == [ @@ -82,7 +94,7 @@ def test_untis_split_third(): assert untis_split_third("1;;3", int, remove_empty=False) == [1, None, 3] assert untis_split_third("1;;3", int) == [1, 3] - assert untis_split_third(""""asdf";"asdf";"asdf""") == ["asdf", "asdf", "asdf"] + assert untis_split_third('"asdf";"asdf";"asdf') == ["asdf", "asdf", "asdf"] assert len(untis_split_third(test_lesson_element_partial_partial)) == 7 assert untis_split_third(test_lesson_element_partial_partial) == [ diff --git a/aleksis/apps/untis/util/mysql/importers/common_data.py b/aleksis/apps/untis/util/mysql/importers/common_data.py index 78eff319266b5b058a08989361ebf07138b97ff1..23d7d2786b14d7c273eeb2b933072df2a2dc8b37 100644 --- a/aleksis/apps/untis/util/mysql/importers/common_data.py +++ b/aleksis/apps/untis/util/mysql/importers/common_data.py @@ -2,7 +2,6 @@ import logging import re from datetime import datetime, time, timedelta from enum import Enum -from typing import Dict, Tuple from django.utils.translation import gettext as _ @@ -34,7 +33,7 @@ class CommonDataId(Enum): PERIOD = 40 -def import_subjects(validity_range: ValidityRange) -> Dict[int, cursus_models.Subject]: +def import_subjects(validity_range: ValidityRange) -> dict[int, cursus_models.Subject]: """Import subjects.""" subjects_ref = {} @@ -98,7 +97,7 @@ def import_subjects(validity_range: ValidityRange) -> Dict[int, cursus_models.Su return subjects_ref -def import_teachers(validity_range: ValidityRange) -> Dict[int, core_models.Person]: +def import_teachers(validity_range: ValidityRange) -> dict[int, core_models.Person]: """Import teachers.""" teachers_ref = {} @@ -161,8 +160,8 @@ def import_teachers(validity_range: ValidityRange) -> Dict[int, core_models.Pers def import_classes( - validity_range: ValidityRange, teachers_ref: Dict[int, core_models.Person] -) -> Dict[int, core_models.Group]: + validity_range: ValidityRange, teachers_ref: dict[int, core_models.Person] +) -> dict[int, core_models.Group]: """Import classes.""" classes_ref = {} @@ -271,7 +270,7 @@ def import_classes( return classes_ref -def import_rooms(validity_range: ValidityRange) -> Dict[int, core_models.Room]: +def import_rooms(validity_range: ValidityRange) -> dict[int, core_models.Room]: """Import rooms.""" ref = {} @@ -319,7 +318,7 @@ def import_rooms(validity_range: ValidityRange) -> Dict[int, core_models.Room]: def import_supervision_areas( validity_range: ValidityRange, breaks_ref, teachers_ref -) -> Dict[int, core_models.Room]: +) -> dict[int, core_models.Room]: """Import supervision areas.""" ref = {} @@ -329,9 +328,8 @@ def import_supervision_areas( for area in tqdm(areas, desc="Import supervision areas", **TQDM_DEFAULTS): if not area.name: raise RuntimeError( - "Supervision area ID {}: Cannot import supervision area without short name.".format( - area.corridor_id - ) + f"Supervision area ID {area.corridor_id}: " + "Cannot import supervision area without short name." ) short_name = area.name @@ -391,9 +389,8 @@ def import_supervision_areas( slot = breaks_ref[weekday][before_period_number] logger.info( - "Import supervision on weekday {} before the {}. period (teacher {})".format( - weekday, before_period_number, teacher - ) + f"Import supervision on weekday {weekday} before the " + f"{before_period_number}. period (teacher {teacher})" ) # Get or create @@ -461,8 +458,8 @@ def import_supervision_areas( def import_slots( validity_range: ValidityRange, -) -> Tuple[ - Dict[int, Dict[int, lesrooster_models.Slot]], Dict[int, Dict[int, lesrooster_models.BreakSlot]] +) -> tuple[ + dict[int, dict[int, lesrooster_models.Slot]], dict[int, dict[int, lesrooster_models.BreakSlot]] ]: """Import time periods an breaks.""" times = ( @@ -554,7 +551,7 @@ def import_slots( def import_absence_reasons( validity_range: ValidityRange, -) -> Dict[int, kolego_models.AbsenceReason]: +) -> dict[int, kolego_models.AbsenceReason]: """Import absence reasons.""" ref = {} @@ -566,9 +563,8 @@ def import_absence_reasons( for reason in tqdm(reasons, desc="Import absence reasons", **TQDM_DEFAULTS): if not reason.name: raise RuntimeError( - "Absence reason ID {}: Cannot import absence reason without short name.".format( - reason.absence_reason_id - ) + f"Absence reason ID {reason.absence_reason_id}: " + "Cannot import absence reason without short name." ) # Build values diff --git a/aleksis/apps/untis/util/mysql/importers/holidays.py b/aleksis/apps/untis/util/mysql/importers/holidays.py index db43a1b5a2403047fc765563efd06f78d92f9257..a8fbee630e3ea27f04d7f67009018d4f6547f252 100644 --- a/aleksis/apps/untis/util/mysql/importers/holidays.py +++ b/aleksis/apps/untis/util/mysql/importers/holidays.py @@ -1,5 +1,4 @@ import logging -from typing import Dict from tqdm import tqdm @@ -14,7 +13,7 @@ logger = logging.getLogger(__name__) def import_holidays( validity_range: lesrooster_models.ValidityRange, -) -> Dict[int, core_models.Holiday]: +) -> dict[int, core_models.Holiday]: """Import holidays.""" ref = {} diff --git a/aleksis/apps/untis/util/mysql/importers/terms.py b/aleksis/apps/untis/util/mysql/importers/terms.py index e71007086f5d8f9b2870d307a6d269719c9e8de0..8ce4f5fcb30078b11c6fd06e23d8b19cc74c5f9c 100644 --- a/aleksis/apps/untis/util/mysql/importers/terms.py +++ b/aleksis/apps/untis/util/mysql/importers/terms.py @@ -1,6 +1,6 @@ import logging from datetime import date, timedelta -from typing import Dict, Optional +from typing import Optional from django.db.models import Max, OuterRef, Q, QuerySet, Subquery from django.utils import timezone @@ -62,7 +62,7 @@ def import_terms( qs: Optional[QuerySet] = None, school_id: Optional[int] = None, version: Optional[int] = None, -) -> Dict[int, lesrooster_models.ValidityRange]: +) -> dict[int, lesrooster_models.ValidityRange]: """Import terms and school years as validity ranges and school terms.""" ranges_ref = {} diff --git a/aleksis/apps/untis/util/mysql/util.py b/aleksis/apps/untis/util/mysql/util.py index e7a6d1c9fcc7c7affa6b47f991cbea3e48cbb8a7..16c78ad5bd41fbf389bf6749ece0ac6c306321cb 100644 --- a/aleksis/apps/untis/util/mysql/util.py +++ b/aleksis/apps/untis/util/mysql/util.py @@ -1,8 +1,9 @@ import csv import logging import re +from collections.abc import Sequence from datetime import date, datetime -from typing import Any, Callable, Optional, Sequence, Type, Union +from typing import Any, Callable, Optional, Union from django.db.models import Model, QuerySet @@ -104,7 +105,7 @@ class UntisSemicolonDialect(UntisDialect): delimiter = ";" -def split_with_csv_parser(s: str, dialect: Type[csv.Dialect]) -> Sequence: +def split_with_csv_parser(s: str, dialect: type[csv.Dialect]) -> Sequence: """Split string with CSV parser.""" parsed = csv.reader([s], dialect=dialect) return next(parsed) diff --git a/pyproject.toml b/pyproject.toml index 0ccbaf317ba11e813b3c88fd41af9e63a1f47bae..e58173fa16885ad48e7ff84fad7e5f09a084aabc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -16,7 +16,7 @@ include = [ description = "AlekSIS (School Information System) — App for Untis import" authors = ["Dominik George <dominik.george@teckids.org>", "Julian Leucker <leuckeju@katharineum.de>", "Frank Poetzsch-Heffter <p-h@katharineum.de>", "Jonathan Weth <dev@jonathanweth.de>", "Tom Teichler <tom.teichler@teckids.org>", "mirabilos <thorsten.glaser@teckids.org>"] -maintainers = ["Jonathan Weth <dev@jonathanweth.de>", "Dominik George <dominik.george@teckids.org>"] +maintainers = ["Jonathan Weth <jonathan.weth@teckids.org>", "Dominik George <dominik.george@teckids.org>"] license = "EUPL-1.2-or-later" homepage = "https://aleksis.org" repository = "https://edugit.org/AlekSIS/official/AlekSIS-App-Untis" @@ -39,7 +39,6 @@ priority = "primary" name = "gitlab" url = "https://edugit.org/api/v4/projects/461/packages/pypi/simple" priority = "supplemental" - [tool.poetry.dependencies] python = "^3.10" mysqlclient = "^2.0.0" @@ -56,18 +55,16 @@ untis = "aleksis.apps.untis.apps:UntisConfig" django-stubs = "^4.2" safety = "^2.3.5" -ruff = "^0.1.5" - -curlylint = "^0.13.0" +ruff = "^0.8.2" [tool.poetry.group.test.dependencies] -pytest = "^7.2" -pytest-django = "^4.1" +pytest = "^8.3" +pytest-django = "^4.9" pytest-django-testing-postgresql = "^0.2" -pytest-cov = "^4.0.0" -pytest-sugar = "^0.9.2" -selenium = "<4.10.0" -freezegun = "^1.1.0" +pytest-cov = "^6.0.0" +pytest-sugar = "^1.0.0" +selenium = "^4.27.0" +freezegun = "^1.5.0" [tool.poetry.group.docs] optional = true @@ -78,20 +75,20 @@ sphinxcontrib-django = "^2.3.0" sphinxcontrib-svg2pdfconverter = "^1.1.1" sphinx-autodoc-typehints = "^1.7" sphinx_material = "^0.0.35" - [tool.ruff] -exclude = ["migrations", "tests"] +exclude = ["migrations"] line-length = 100 [tool.ruff.lint] select = ["E", "F", "UP", "B", "SIM", "I", "DJ", "A", "S"] ignore = ["UP034", "UP015", "B028"] - -[tool.ruff.isort] +[tool.ruff.lint.extend-per-file-ignores] +"**/*/tests/**/*.py" = ["S101", "ARG", "FBT", "PLR2004", "S311", "S105"] +[tool.ruff.lint.isort] known-first-party = ["aleksis"] section-order = ["future", "standard-library", "django", "third-party", "first-party", "local-folder"] -[tool.ruff.isort.sections] +[tool.ruff.lint.isort.sections] django = ["django"] [build-system] requires = ["poetry-core>=1.0.0"]