edupsyadmin 8.2.0__tar.gz → 8.2.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/CHANGELOG.md +6 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/PKG-INFO +1 -1
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/pyproject.toml +1 -1
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/src/edupsyadmin/__version__.py +1 -1
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/src/edupsyadmin/api/add_convenience_data.py +21 -19
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/src/edupsyadmin/api/cft_report.py +5 -3
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/src/edupsyadmin/api/display_client_details.py +4 -4
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/src/edupsyadmin/api/fill_form.py +9 -8
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/src/edupsyadmin/api/lgvt.py +10 -4
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/src/edupsyadmin/api/managers.py +10 -5
- edupsyadmin-8.2.1/src/edupsyadmin/api/types.py +81 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/src/edupsyadmin/db/clients.py +1 -1
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/src/edupsyadmin/tui/clients_overview.py +0 -2
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/src/edupsyadmin/tui/dialogs.py +0 -2
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/src/edupsyadmin/tui/edit_client.py +12 -13
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/src/edupsyadmin/tui/edupsyadmintui.py +5 -6
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/src/edupsyadmin/tui/fill_form_app.py +0 -2
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/src/edupsyadmin/tui/fill_form_widget.py +5 -6
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/test/edupsyadmin/api/test_add_convenience_data.py +8 -4
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/test/edupsyadmin/api/test_fill_form.py +13 -8
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/test/edupsyadmin/api/test_flatten_pdf.py +6 -2
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/test/edupsyadmin/tui/test_edupsyadmintui.py +5 -1
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/.github/workflows/publish.yml +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/.gitignore +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/.pre-commit-config.yaml +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/.python-version +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/.readthedocs.yaml +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/LICENSE.txt +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/README.md +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/docs/Makefile +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/docs/_static/samplewebuntisfile.csv +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/docs/clients_model.rst +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/docs/conf.py +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/docs/faq.rst +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/docs/index.rst +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/docs/make.bat +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/docs/requirements.txt +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/docs/taetigkeitsbericht_keywords.rst +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/docs/tutorial/cli.rst +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/docs/tutorial/configuration.rst +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/docs/tutorial/creatingdocumentation.rst +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/docs/tutorial/editingclients.rst +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/docs/tutorial/encryption.rst +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/docs/tutorial/helpfunction.rst +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/docs/tutorial/installation.rst +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/docs/tutorial/taetigkeitsbericht.rst +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/docs/tutorial/tui.rst +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/docs/tutorial/update.rst +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/py.typed +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/shellscripts/add_iLst.sh +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/shellscripts/add_iRst.sh +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/shellscripts/add_lrst.sh +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/shellscripts/add_nona_nons.sh +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/shellscripts/change_keywordtaet_nsessions.sh +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/shellscripts/profile.sh +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/shellscripts/publish_to_testpypi.sh +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/src/edupsyadmin/__init__.py +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/src/edupsyadmin/__main__.py +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/src/edupsyadmin/alembic/README +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/src/edupsyadmin/alembic/env.py +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/src/edupsyadmin/alembic/script.py.mako +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/src/edupsyadmin/alembic/versions/2026_02_21_0453-4087c43f0c7c_initial_migration.py +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/src/edupsyadmin/alembic/versions/2026_03_02_1222-635a9d68fbe8_add_case_active_column_to_clients.py +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/src/edupsyadmin/alembic.ini +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/src/edupsyadmin/api/__init__.py +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/src/edupsyadmin/api/flatten_pdf.py +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/src/edupsyadmin/api/migration.py +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/src/edupsyadmin/api/reports.py +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/src/edupsyadmin/api/setup_demo.py +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/src/edupsyadmin/api/taetigkeitsbericht_from_db.py +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/src/edupsyadmin/cli/__init__.py +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/src/edupsyadmin/cli/__main__.py +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/src/edupsyadmin/cli/commands/create_documentation.py +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/src/edupsyadmin/cli/commands/delete_client.py +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/src/edupsyadmin/cli/commands/edit_config.py +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/src/edupsyadmin/cli/commands/flatten_pdfs.py +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/src/edupsyadmin/cli/commands/get_clients.py +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/src/edupsyadmin/cli/commands/info.py +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/src/edupsyadmin/cli/commands/migrate_encryption.py +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/src/edupsyadmin/cli/commands/mk_report.py +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/src/edupsyadmin/cli/commands/new_client.py +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/src/edupsyadmin/cli/commands/rotate_key.py +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/src/edupsyadmin/cli/commands/set_client.py +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/src/edupsyadmin/cli/commands/setup_demo.py +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/src/edupsyadmin/cli/commands/taetigkeitsbericht.py +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/src/edupsyadmin/cli/commands/tui.py +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/src/edupsyadmin/cli/utils.py +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/src/edupsyadmin/core/__init__.py +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/src/edupsyadmin/core/config.py +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/src/edupsyadmin/core/encrypt.py +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/src/edupsyadmin/core/logger.py +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/src/edupsyadmin/core/paths.py +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/src/edupsyadmin/data/Faecher_BfsEV.md +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/src/edupsyadmin/data/Faecher_BfsKi.md +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/src/edupsyadmin/data/Faecher_Faks.md +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/src/edupsyadmin/data/sampleconfig.yml +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/src/edupsyadmin/data/taetigkeitsbericht_categories.csv +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/src/edupsyadmin/db/__init__.py +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/src/edupsyadmin/info.py +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/src/edupsyadmin/tui/__init__.py +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/src/edupsyadmin/tui/clients_overview_app.py +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/src/edupsyadmin/tui/edit_client_app.py +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/src/edupsyadmin/tui/editconfig.py +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/src/edupsyadmin/tui/editconfig.tcss +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/src/edupsyadmin/tui/edupsyadmintui.tcss +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/src/edupsyadmin/utils/__init__.py +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/src/edupsyadmin/utils/academic_year.py +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/src/edupsyadmin/utils/convert_measures.py +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/src/edupsyadmin/utils/datediff.py +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/src/edupsyadmin/utils/int_from_str.py +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/src/edupsyadmin/utils/path_utils.py +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/src/edupsyadmin/utils/python_type.py +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/src/edupsyadmin/utils/taetigkeitsbericht_check_key.py +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/test/.gitignore +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/test/edupsyadmin/api/test_decryption_behavior.py +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/test/edupsyadmin/api/test_managers.py +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/test/edupsyadmin/api/test_migration.py +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/test/edupsyadmin/api/test_taetigkeitsbericht_from_db.py +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/test/edupsyadmin/benchmark/test_cli_benchmark.py +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/test/edupsyadmin/benchmark/test_encrypt_benchmark.py +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/test/edupsyadmin/benchmark/test_key_derivation_benchmark.py +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/test/edupsyadmin/cli/test_utils.py +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/test/edupsyadmin/conftest.py +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/test/edupsyadmin/core/test_config.py +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/test/edupsyadmin/core/test_encrypt.py +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/test/edupsyadmin/core/test_logger.py +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/test/edupsyadmin/data/sample_form_anschreiben.pdf +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/test/edupsyadmin/data/sample_form_mantelbogen.pdf +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/test/edupsyadmin/sample_pdf_form.py +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/test/edupsyadmin/sample_webuntis_export.py +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/test/edupsyadmin/test_cli.py +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/test/edupsyadmin/tui/__snapshots__/test_clientsoverview/test_clients_overview.svg +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/test/edupsyadmin/tui/__snapshots__/test_dialogs/test_yes_no_dialog.svg +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/test/edupsyadmin/tui/__snapshots__/test_editclient/test_initial_layout_existing_client[client_dict_set_by_user0].svg +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/test/edupsyadmin/tui/__snapshots__/test_editclient/test_initial_layout_existing_client[client_dict_set_by_user1].svg +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/test/edupsyadmin/tui/__snapshots__/test_editclient/test_initial_layout_new_client.svg +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/test/edupsyadmin/tui/__snapshots__/test_editconfig/test_add_new_school_container.svg +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/test/edupsyadmin/tui/__snapshots__/test_editconfig/test_edit_new_school_container.svg +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/test/edupsyadmin/tui/__snapshots__/test_editconfig/test_initial_layout.svg +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/test/edupsyadmin/tui/__snapshots__/test_edupsyadmintui/test_edupsyadmintui_initial_layout.svg +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/test/edupsyadmin/tui/__snapshots__/test_fill_form_tui/test_initial_layout.svg +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/test/edupsyadmin/tui/test_clientsoverview.py +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/test/edupsyadmin/tui/test_dialogs.py +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/test/edupsyadmin/tui/test_editclient.py +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/test/edupsyadmin/tui/test_editconfig.py +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/test/edupsyadmin/tui/test_fill_form_tui.py +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/test/edupsyadmin/utils/test_academic_year.py +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/test/edupsyadmin/utils/test_convert_measures.py +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/test/edupsyadmin/utils/test_datediff.py +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/test/edupsyadmin/utils/test_int_from_str.py +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/test/edupsyadmin/utils/test_path_utils.py +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/test/edupsyadmin/utils/test_python_type.py +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/test/edupsyadmin/utils/test_taetigkeitsbericht_check_key.py +0 -0
- {edupsyadmin-8.2.0 → edupsyadmin-8.2.1}/uv.lock +0 -0
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "edupsyadmin"
|
|
7
|
-
version = "8.2.
|
|
7
|
+
version = "8.2.1"
|
|
8
8
|
authors = [{ name = "Lukas Liebermann" }]
|
|
9
9
|
description = "edupsyadmin provides tools to help school psychologists with their documentation"
|
|
10
10
|
readme = "README.md"
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
from datetime import date
|
|
2
2
|
from importlib.resources import files
|
|
3
|
-
from typing import Any
|
|
3
|
+
from typing import Any, cast
|
|
4
4
|
|
|
5
5
|
from dateutil.parser import parse
|
|
6
6
|
|
|
7
|
+
from edupsyadmin.api.types import ClientData
|
|
7
8
|
from edupsyadmin.core.config import config
|
|
8
9
|
from edupsyadmin.core.logger import logger
|
|
9
10
|
from edupsyadmin.utils.academic_year import (
|
|
@@ -49,7 +50,7 @@ def _date_to_german_string(isodate: date | str | None) -> str:
|
|
|
49
50
|
if (isodate is None) or (isodate == ""):
|
|
50
51
|
return ""
|
|
51
52
|
try:
|
|
52
|
-
return parse(isodate, dayfirst=False).strftime("%d.%m.%Y")
|
|
53
|
+
return parse(str(isodate), dayfirst=False).strftime("%d.%m.%Y")
|
|
53
54
|
except ValueError:
|
|
54
55
|
logger.error(f"'{isodate}' could not be parsed as a date")
|
|
55
56
|
raise
|
|
@@ -58,7 +59,7 @@ def _date_to_german_string(isodate: date | str | None) -> str:
|
|
|
58
59
|
raise
|
|
59
60
|
|
|
60
61
|
|
|
61
|
-
def _add_client_address(data:
|
|
62
|
+
def _add_client_address(data: ClientData) -> None:
|
|
62
63
|
"""Add client's name and address to data."""
|
|
63
64
|
first_name = data.get("first_name_encr", "")
|
|
64
65
|
last_name = data.get("last_name_encr", "")
|
|
@@ -74,7 +75,7 @@ def _add_client_address(data: dict[str, Any]) -> None:
|
|
|
74
75
|
logger.debug(f"Couldn't add home address because of missing data: {e}")
|
|
75
76
|
|
|
76
77
|
|
|
77
|
-
def _add_school_psychologist_address(data:
|
|
78
|
+
def _add_school_psychologist_address(data: ClientData) -> None:
|
|
78
79
|
"""Add school psychologist's address from config to data."""
|
|
79
80
|
data["schoolpsy_name"] = config.schoolpsy.schoolpsy_name
|
|
80
81
|
data["schoolpsy_street"] = config.schoolpsy.schoolpsy_street
|
|
@@ -85,7 +86,7 @@ def _add_school_psychologist_address(data: dict[str, Any]) -> None:
|
|
|
85
86
|
data["schoolpsy_addr_s_wname"] = data["schoolpsy_addr_m_wname"].replace("\n", ", ")
|
|
86
87
|
|
|
87
88
|
|
|
88
|
-
def _add_school_address(data:
|
|
89
|
+
def _add_school_address(data: ClientData) -> None:
|
|
89
90
|
"""Add school address from config to data."""
|
|
90
91
|
school_key = data.get("school")
|
|
91
92
|
if not school_key:
|
|
@@ -102,7 +103,7 @@ def _add_school_address(data: dict[str, Any]) -> None:
|
|
|
102
103
|
data["school_addr_s_wname"] = data["school_addr_m_wname"].replace("\n", ", ")
|
|
103
104
|
|
|
104
105
|
|
|
105
|
-
def _add_lrst_diagnosis(data:
|
|
106
|
+
def _add_lrst_diagnosis(data: ClientData) -> None:
|
|
106
107
|
"""Add long version of LRSt diagnosis to data."""
|
|
107
108
|
diagnosis = data.get("lrst_diagnosis_encr")
|
|
108
109
|
if not diagnosis:
|
|
@@ -122,23 +123,23 @@ def _add_lrst_diagnosis(data: dict[str, Any]) -> None:
|
|
|
122
123
|
)
|
|
123
124
|
|
|
124
125
|
|
|
125
|
-
def _add_dates(data:
|
|
126
|
+
def _add_dates(data: ClientData) -> None:
|
|
126
127
|
"""Add various formatted dates to data."""
|
|
127
128
|
data["today_date"] = date.today()
|
|
128
|
-
dates_to_convert = [
|
|
129
|
-
"birthday_encr",
|
|
130
|
-
"today_date",
|
|
131
|
-
"lrst_last_test_date_encr",
|
|
132
|
-
"document_shredding_date",
|
|
129
|
+
dates_to_convert: list[tuple[str, str]] = [
|
|
130
|
+
("birthday_encr", "birthday_encr_de"),
|
|
131
|
+
("today_date", "today_date_de"),
|
|
132
|
+
("lrst_last_test_date_encr", "lrst_last_test_date_encr_de"),
|
|
133
|
+
("document_shredding_date", "document_shredding_date_de"),
|
|
133
134
|
]
|
|
134
|
-
for idate in dates_to_convert:
|
|
135
|
-
|
|
136
|
-
data[gdate] = _date_to_german_string(data.get(idate))
|
|
135
|
+
for idate, gdate in dates_to_convert:
|
|
136
|
+
# TypedDict doesn't support dynamic key access with variables
|
|
137
|
+
cast(Any, data)[gdate] = _date_to_german_string(data.get(cast(Any, idate)))
|
|
137
138
|
|
|
138
139
|
data["school_year"] = get_this_academic_year_string()
|
|
139
140
|
|
|
140
141
|
|
|
141
|
-
def _add_nta_schoolyear(data:
|
|
142
|
+
def _add_nta_schoolyear(data: ClientData) -> None:
|
|
142
143
|
"""Add NTA/NOS end schoolyear to data."""
|
|
143
144
|
if (
|
|
144
145
|
data.get("nta_nos_end")
|
|
@@ -147,12 +148,13 @@ def _add_nta_schoolyear(data: dict[str, Any]) -> None:
|
|
|
147
148
|
):
|
|
148
149
|
data["nta_nos_end_schoolyear"] = get_academic_year_string(
|
|
149
150
|
get_estimated_end_of_academic_year(
|
|
150
|
-
grade_current=data["class_int"],
|
|
151
|
+
grade_current=cast(int, data["class_int"]),
|
|
152
|
+
grade_target=cast(int, data["nta_nos_end_grade"]),
|
|
151
153
|
)
|
|
152
154
|
)
|
|
153
155
|
|
|
154
156
|
|
|
155
|
-
def _convert_lrst_test_by(data:
|
|
157
|
+
def _convert_lrst_test_by(data: ClientData) -> None:
|
|
156
158
|
"""Convert lrst_last_test_by_encr to numerical value for forms."""
|
|
157
159
|
test_by = data.get("lrst_last_test_by_encr")
|
|
158
160
|
if not test_by:
|
|
@@ -176,7 +178,7 @@ def _convert_lrst_test_by(data: dict[str, Any]) -> None:
|
|
|
176
178
|
)
|
|
177
179
|
|
|
178
180
|
|
|
179
|
-
def add_convenience_data(data:
|
|
181
|
+
def add_convenience_data(data: ClientData) -> ClientData:
|
|
180
182
|
"""
|
|
181
183
|
Füge Daten hinzu, die sich aus einem Eintrag in einer `Client`-Datenbank,
|
|
182
184
|
der Konfigurationsdatei und einer Datei zu den Schulfächern (optional)
|
|
@@ -5,6 +5,7 @@ from edupsyadmin.api.managers import ClientsManager
|
|
|
5
5
|
|
|
6
6
|
# TODO: Remove FPDF dependency?
|
|
7
7
|
from edupsyadmin.api.reports import Report, normal_distribution_plot
|
|
8
|
+
from edupsyadmin.api.types import ClientData
|
|
8
9
|
from edupsyadmin.utils.convert_measures import iq_to_t, iq_to_z
|
|
9
10
|
from edupsyadmin.utils.datediff import mydatediff
|
|
10
11
|
|
|
@@ -34,10 +35,11 @@ def create_report(
|
|
|
34
35
|
clients_manager = ClientsManager(
|
|
35
36
|
database_url=database_url,
|
|
36
37
|
)
|
|
37
|
-
client_dict = clients_manager.get_decrypted_client(client_id)
|
|
38
|
+
client_dict: ClientData = clients_manager.get_decrypted_client(client_id)
|
|
38
39
|
|
|
39
40
|
testdate = datetime.strptime(test_date, "%Y-%m-%d").date()
|
|
40
|
-
|
|
41
|
+
birthday_str = client_dict.get("birthday_encr", "")
|
|
42
|
+
birthday = datetime.strptime(birthday_str, "%Y-%m-%d").date()
|
|
41
43
|
|
|
42
44
|
age_str = f"Alter: {mydatediff(birthday, testdate)}"
|
|
43
45
|
text = []
|
|
@@ -110,7 +112,7 @@ def create_report(
|
|
|
110
112
|
heading = f"CFT 20-R (Testdatum: {testdate}; Code: {client_id})"
|
|
111
113
|
report = Report(heading, text, fn_plot)
|
|
112
114
|
report.print_page()
|
|
113
|
-
report.output(directory / Path(f"{client_id}_Auswertung.pdf"))
|
|
115
|
+
report.output(str(directory / Path(f"{client_id}_Auswertung.pdf")))
|
|
114
116
|
|
|
115
117
|
# remove the plot png
|
|
116
118
|
fn_plot.unlink()
|
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
from typing import Any
|
|
2
|
-
|
|
3
1
|
from rich.console import Console
|
|
4
2
|
from rich.panel import Panel
|
|
5
3
|
from rich.table import Table
|
|
6
4
|
|
|
5
|
+
from edupsyadmin.api.types import ClientData
|
|
6
|
+
|
|
7
7
|
|
|
8
|
-
def display_client_details(client_data:
|
|
8
|
+
def display_client_details(client_data: ClientData) -> None:
|
|
9
9
|
"""Displays client details in a formatted way using rich."""
|
|
10
10
|
console = Console()
|
|
11
11
|
|
|
12
12
|
# Helper to print a table for a group of fields
|
|
13
|
-
def print_group_table(data:
|
|
13
|
+
def print_group_table(data: ClientData, title: str, fields: list[str]) -> None:
|
|
14
14
|
table = Table(show_header=False, box=None, padding=(0, 1))
|
|
15
15
|
table.add_column(style="cyan")
|
|
16
16
|
table.add_column()
|
|
@@ -7,10 +7,11 @@ from typing import Any
|
|
|
7
7
|
|
|
8
8
|
from liquid import Template, exceptions
|
|
9
9
|
|
|
10
|
+
from edupsyadmin.api.types import ClientData
|
|
10
11
|
from edupsyadmin.core.logger import logger
|
|
11
12
|
|
|
12
13
|
|
|
13
|
-
def _modify_bool_and_none_for_pdf_form(data:
|
|
14
|
+
def _modify_bool_and_none_for_pdf_form(data: ClientData) -> dict[str, Any]:
|
|
14
15
|
"""
|
|
15
16
|
Replace every boolean True with 'Yes' and False with 'Off', which are the
|
|
16
17
|
values checkboxes accept in most PDF forms. Replace None with empty
|
|
@@ -20,7 +21,7 @@ def _modify_bool_and_none_for_pdf_form(data: dict[str, Any]) -> dict[str, Any]:
|
|
|
20
21
|
:return: a modified dictionary where booleans are replaced
|
|
21
22
|
with string values and None values are replaced with an empty string
|
|
22
23
|
"""
|
|
23
|
-
updated_data = {}
|
|
24
|
+
updated_data: dict[str, Any] = {}
|
|
24
25
|
logger.debug("Replacing True with 'Yes' and False with 'Off'")
|
|
25
26
|
for key, value in data.items():
|
|
26
27
|
if isinstance(value, bool):
|
|
@@ -32,7 +33,7 @@ def _modify_bool_and_none_for_pdf_form(data: dict[str, Any]) -> dict[str, Any]:
|
|
|
32
33
|
return updated_data
|
|
33
34
|
|
|
34
35
|
|
|
35
|
-
def write_form_pdf(fn: Path, out_fn: Path, data:
|
|
36
|
+
def write_form_pdf(fn: Path, out_fn: Path, data: ClientData) -> None:
|
|
36
37
|
"""
|
|
37
38
|
Fill a pdf form with data using pypdf.
|
|
38
39
|
|
|
@@ -57,7 +58,7 @@ def write_form_pdf(fn: Path, out_fn: Path, data: dict[str, Any]) -> None:
|
|
|
57
58
|
if not fields:
|
|
58
59
|
logger.debug(f"The file {fn} is not a form.")
|
|
59
60
|
else:
|
|
60
|
-
logger.debug("\nForm fields:\n{fields.keys()}")
|
|
61
|
+
logger.debug(f"\nForm fields:\n{fields.keys()}")
|
|
61
62
|
logger.debug(f"\nData keys:\n{data_wo_bool.keys()}")
|
|
62
63
|
comb_key_fields = product(range(len(reader.pages)), fields.keys())
|
|
63
64
|
for i, key in comb_key_fields:
|
|
@@ -77,7 +78,7 @@ def write_form_pdf(fn: Path, out_fn: Path, data: dict[str, Any]) -> None:
|
|
|
77
78
|
writer.write(output_stream)
|
|
78
79
|
|
|
79
80
|
|
|
80
|
-
def write_form_pdf2(fn: Path, out_fn: Path, data:
|
|
81
|
+
def write_form_pdf2(fn: Path, out_fn: Path, data: ClientData) -> None:
|
|
81
82
|
"""
|
|
82
83
|
Fill a pdf form with data using fillpdf.
|
|
83
84
|
|
|
@@ -101,7 +102,7 @@ def write_form_pdf2(fn: Path, out_fn: Path, data: dict[str, Any]) -> None:
|
|
|
101
102
|
shutil.copyfile(fn, out_fn)
|
|
102
103
|
|
|
103
104
|
|
|
104
|
-
def write_form_md(fn: Path, out_fn: Path, data:
|
|
105
|
+
def write_form_md(fn: Path, out_fn: Path, data: ClientData) -> None:
|
|
105
106
|
"""
|
|
106
107
|
Render a liquid template with data passed to the function.
|
|
107
108
|
|
|
@@ -127,7 +128,7 @@ def write_form_md(fn: Path, out_fn: Path, data: dict[str, Any]) -> None:
|
|
|
127
128
|
|
|
128
129
|
|
|
129
130
|
def fill_form(
|
|
130
|
-
client_data:
|
|
131
|
+
client_data: ClientData,
|
|
131
132
|
form_paths: Sequence[str | os.PathLike[str]],
|
|
132
133
|
out_dir: str | os.PathLike[str] = ".",
|
|
133
134
|
use_fillpdf: bool = True,
|
|
@@ -150,7 +151,7 @@ def fill_form(
|
|
|
150
151
|
raise FileNotFoundError(
|
|
151
152
|
f"The template file does not exist: {fp}; cwd is: {Path.cwd()}"
|
|
152
153
|
)
|
|
153
|
-
out_fp = Path(out_dir, f"{client_data
|
|
154
|
+
out_fp = Path(out_dir, f"{client_data.get('client_id')}_{fp.name}")
|
|
154
155
|
logger.info(f"Writing to {out_fp.resolve()}")
|
|
155
156
|
if fp.suffix == ".md":
|
|
156
157
|
write_form_md(fp, out_fp, client_data)
|
|
@@ -3,10 +3,12 @@ import math
|
|
|
3
3
|
import os
|
|
4
4
|
from datetime import date, datetime
|
|
5
5
|
from pathlib import Path
|
|
6
|
+
from typing import Any, cast
|
|
6
7
|
|
|
7
8
|
import pandas as pd
|
|
8
9
|
|
|
9
10
|
from edupsyadmin.api.managers import ClientsManager
|
|
11
|
+
from edupsyadmin.api.types import ClientData
|
|
10
12
|
from edupsyadmin.core.config import config
|
|
11
13
|
from edupsyadmin.utils.convert_measures import percentile_to_t
|
|
12
14
|
|
|
@@ -122,10 +124,14 @@ def mk_report(
|
|
|
122
124
|
t_day = datetime.strptime(test_date, "%Y-%m-%d").date()
|
|
123
125
|
|
|
124
126
|
clients_manager = ClientsManager(database_url=database_url)
|
|
125
|
-
client_dict = clients_manager.get_decrypted_client(client_id)
|
|
126
|
-
|
|
127
|
-
name =
|
|
128
|
-
|
|
127
|
+
client_dict: ClientData = clients_manager.get_decrypted_client(client_id)
|
|
128
|
+
|
|
129
|
+
name = (
|
|
130
|
+
client_dict.get("first_name_encr", "")
|
|
131
|
+
+ " "
|
|
132
|
+
+ client_dict.get("last_name_encr", "")
|
|
133
|
+
)
|
|
134
|
+
schoolyear = int(cast(Any, client_dict.get("class_int", 0)))
|
|
129
135
|
|
|
130
136
|
results = get_indeces(fn_csv, name, schoolyear, t_day, version)
|
|
131
137
|
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import logging # just for interaction with the sqlalchemy logger
|
|
2
2
|
from datetime import datetime
|
|
3
|
-
from typing import Any
|
|
3
|
+
from typing import Any, cast
|
|
4
4
|
|
|
5
5
|
import pandas as pd
|
|
6
6
|
from sqlalchemy import create_engine, inspect, or_, select
|
|
7
7
|
from sqlalchemy.orm import sessionmaker
|
|
8
8
|
|
|
9
|
+
from edupsyadmin.api.types import ClientData
|
|
9
10
|
from edupsyadmin.core.config import config
|
|
10
11
|
from edupsyadmin.core.logger import logger
|
|
11
12
|
from edupsyadmin.db import clients as clients_db
|
|
@@ -50,14 +51,15 @@ class ClientsManager:
|
|
|
50
51
|
logger.info(f"added client: {new_client}")
|
|
51
52
|
return new_client.client_id
|
|
52
53
|
|
|
53
|
-
def get_decrypted_client(self, client_id: int) ->
|
|
54
|
+
def get_decrypted_client(self, client_id: int) -> ClientData:
|
|
54
55
|
logger.debug(f"trying to access client (client_id = {client_id})")
|
|
55
56
|
with self.Session() as session:
|
|
56
57
|
client = session.get(clients_db.Client, client_id)
|
|
57
58
|
if client is None:
|
|
58
59
|
raise ClientNotFoundError(client_id)
|
|
59
60
|
# Create a clean dictionary using the cached mapper
|
|
60
|
-
|
|
61
|
+
data = {c.key: getattr(client, c.key) for c in self._mapper.column_attrs}
|
|
62
|
+
return cast(ClientData, data)
|
|
61
63
|
|
|
62
64
|
def get_clients_overview(
|
|
63
65
|
self,
|
|
@@ -129,8 +131,11 @@ class ClientsManager:
|
|
|
129
131
|
with self.Session() as session:
|
|
130
132
|
stmt = select(clients_db.Client)
|
|
131
133
|
clients = session.scalars(stmt).all()
|
|
132
|
-
data = [
|
|
133
|
-
|
|
134
|
+
data: list[ClientData] = [
|
|
135
|
+
cast(
|
|
136
|
+
ClientData,
|
|
137
|
+
{c.key: getattr(client, c.key) for c in self._mapper.column_attrs},
|
|
138
|
+
)
|
|
134
139
|
for client in clients
|
|
135
140
|
]
|
|
136
141
|
return pd.DataFrame(data)
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
from datetime import date, datetime
|
|
2
|
+
from typing import TypedDict
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class ClientData(TypedDict, total=False):
|
|
6
|
+
# Base fields from Client model
|
|
7
|
+
client_id: int
|
|
8
|
+
first_name_encr: str
|
|
9
|
+
last_name_encr: str
|
|
10
|
+
gender_encr: str
|
|
11
|
+
birthday_encr: str
|
|
12
|
+
street_encr: str
|
|
13
|
+
city_encr: str
|
|
14
|
+
parent_encr: str
|
|
15
|
+
telephone1_encr: str
|
|
16
|
+
telephone2_encr: str
|
|
17
|
+
email_encr: str
|
|
18
|
+
notes_encr: str
|
|
19
|
+
keyword_taet_encr: str
|
|
20
|
+
lrst_diagnosis_encr: str
|
|
21
|
+
lrst_last_test_date_encr: str
|
|
22
|
+
lrst_last_test_by_encr: str
|
|
23
|
+
school: str
|
|
24
|
+
entry_date: date | None
|
|
25
|
+
class_name: str | None
|
|
26
|
+
class_int: int | None
|
|
27
|
+
estimated_graduation_date: date | None
|
|
28
|
+
document_shredding_date: date | None
|
|
29
|
+
datetime_created: datetime
|
|
30
|
+
datetime_lastmodified: datetime
|
|
31
|
+
notenschutz: bool
|
|
32
|
+
nos_rs: bool
|
|
33
|
+
nos_rs_ausn: bool
|
|
34
|
+
nos_rs_ausn_faecher: str | None
|
|
35
|
+
nos_les: bool
|
|
36
|
+
nos_other: bool
|
|
37
|
+
nos_other_details: str | None
|
|
38
|
+
nachteilsausgleich: bool
|
|
39
|
+
nta_zeitv: bool
|
|
40
|
+
nta_zeitv_vieltext: int | None
|
|
41
|
+
nta_zeitv_wenigtext: int | None
|
|
42
|
+
nta_font: bool
|
|
43
|
+
nta_aufg: bool
|
|
44
|
+
nta_struktur: bool
|
|
45
|
+
nta_arbeitsm: bool
|
|
46
|
+
nta_ersgew: bool
|
|
47
|
+
nta_vorlesen: bool
|
|
48
|
+
nta_other: bool
|
|
49
|
+
nta_other_details: str | None
|
|
50
|
+
nta_nos_notes: str | None
|
|
51
|
+
nta_nos_end: bool
|
|
52
|
+
nta_nos_end_grade: int | None
|
|
53
|
+
min_sessions: int
|
|
54
|
+
n_sessions: int
|
|
55
|
+
case_active: bool
|
|
56
|
+
|
|
57
|
+
# Convenience fields added by add_convenience_data
|
|
58
|
+
name: str
|
|
59
|
+
addr_s_nname: str
|
|
60
|
+
addr_m_wname: str
|
|
61
|
+
schoolpsy_name: str
|
|
62
|
+
schoolpsy_street: str
|
|
63
|
+
schoolpsy_city: str
|
|
64
|
+
schoolpsy_addr_m_wname: str
|
|
65
|
+
schoolpsy_addr_s_wname: str
|
|
66
|
+
school_name: str
|
|
67
|
+
school_street: str
|
|
68
|
+
school_city: str
|
|
69
|
+
school_head_w_school: str
|
|
70
|
+
school_addr_m_wname: str
|
|
71
|
+
school_addr_s_wname: str
|
|
72
|
+
lrst_diagnosis_long: str
|
|
73
|
+
today_date: date
|
|
74
|
+
birthday_encr_de: str
|
|
75
|
+
today_date_de: str
|
|
76
|
+
lrst_last_test_date_encr_de: str
|
|
77
|
+
document_shredding_date_de: str
|
|
78
|
+
school_year: str
|
|
79
|
+
nta_nos_end_schoolyear: str
|
|
80
|
+
lrst_schpsy: int
|
|
81
|
+
school_subjects: str
|
|
@@ -369,7 +369,7 @@ class Client(Base):
|
|
|
369
369
|
) -> None:
|
|
370
370
|
client_id_int_or_none = to_int_or_none(client_id)
|
|
371
371
|
if client_id_int_or_none is not None:
|
|
372
|
-
self.client_id =
|
|
372
|
+
self.client_id = client_id_int_or_none
|
|
373
373
|
self.first_name_encr = first_name_encr
|
|
374
374
|
self.last_name_encr = last_name_encr
|
|
375
375
|
self.gender_encr = (
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
from datetime import date
|
|
2
|
-
from typing import Any, ClassVar
|
|
1
|
+
from datetime import date, datetime
|
|
2
|
+
from typing import Any, ClassVar, cast
|
|
3
3
|
|
|
4
4
|
from textual import on
|
|
5
5
|
from textual.app import ComposeResult
|
|
@@ -18,6 +18,7 @@ from textual.widgets import (
|
|
|
18
18
|
)
|
|
19
19
|
from textual.widgets._select import NoSelection
|
|
20
20
|
|
|
21
|
+
from edupsyadmin.api.types import ClientData
|
|
21
22
|
from edupsyadmin.core.config import config
|
|
22
23
|
from edupsyadmin.db.clients import LRST_DIAG, LRST_TEST_BY, Client
|
|
23
24
|
from edupsyadmin.utils.python_type import get_python_type
|
|
@@ -64,15 +65,13 @@ LRST_FIELDS = [
|
|
|
64
65
|
DATE_REGEX = r"\d{4}-[0-1]\d-[0-3]\d"
|
|
65
66
|
|
|
66
67
|
|
|
67
|
-
def _to_str_or_bool(value:
|
|
68
|
+
def _to_str_or_bool(value: object) -> str | bool | None:
|
|
68
69
|
if value is None:
|
|
69
70
|
return None
|
|
70
|
-
if isinstance(value,
|
|
71
|
-
return value.isoformat()
|
|
72
|
-
if isinstance(value, bool | str): # check this before checking if int!
|
|
71
|
+
if isinstance(value, bool):
|
|
73
72
|
return value
|
|
74
|
-
if isinstance(value,
|
|
75
|
-
return
|
|
73
|
+
if isinstance(value, (date, datetime)):
|
|
74
|
+
return value.isoformat()
|
|
76
75
|
return str(value)
|
|
77
76
|
|
|
78
77
|
|
|
@@ -284,7 +283,7 @@ class EditClient(Container):
|
|
|
284
283
|
yield RichLog(classes="log", id="edit-client-log")
|
|
285
284
|
|
|
286
285
|
def _normalize_original_data(
|
|
287
|
-
self, data:
|
|
286
|
+
self, data: ClientData
|
|
288
287
|
) -> dict[str, str | bool | None]:
|
|
289
288
|
return {k: _to_str_or_bool(v) for k, v in data.items()}
|
|
290
289
|
|
|
@@ -394,7 +393,7 @@ class EditClient(Container):
|
|
|
394
393
|
widget.tooltip = tooltip
|
|
395
394
|
return widget
|
|
396
395
|
|
|
397
|
-
def update_client(self, client_id: int | None, data:
|
|
396
|
+
def update_client(self, client_id: int | None, data: ClientData | None) -> None:
|
|
398
397
|
self.client_id = client_id
|
|
399
398
|
data = data or _get_empty_client_dict()
|
|
400
399
|
|
|
@@ -519,12 +518,12 @@ class EditClient(Container):
|
|
|
519
518
|
|
|
520
519
|
|
|
521
520
|
# TODO: make defaults configurable
|
|
522
|
-
def _get_empty_client_dict() ->
|
|
521
|
+
def _get_empty_client_dict() -> ClientData:
|
|
523
522
|
defaults = {
|
|
524
523
|
"min_sessions": 45,
|
|
525
524
|
"n_session": 1,
|
|
526
525
|
}
|
|
527
|
-
empty_client_dict: dict[str,
|
|
526
|
+
empty_client_dict: dict[str, Any] = {}
|
|
528
527
|
for db_column in Client.__table__.columns:
|
|
529
528
|
field_type = get_python_type(db_column.type)
|
|
530
529
|
name = db_column.name
|
|
@@ -535,4 +534,4 @@ def _get_empty_client_dict() -> dict[str, str | bool | int]:
|
|
|
535
534
|
empty_client_dict[name] = False
|
|
536
535
|
else:
|
|
537
536
|
empty_client_dict[name] = ""
|
|
538
|
-
return empty_client_dict
|
|
537
|
+
return cast(ClientData, empty_client_dict)
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
1
|
from typing import TYPE_CHECKING, Any, ClassVar
|
|
4
2
|
|
|
5
3
|
from textual import work
|
|
@@ -10,6 +8,7 @@ from textual.message import Message
|
|
|
10
8
|
from textual.widgets import Footer, Header, LoadingIndicator
|
|
11
9
|
|
|
12
10
|
from edupsyadmin.api.fill_form import fill_form
|
|
11
|
+
from edupsyadmin.api.types import ClientData
|
|
13
12
|
from edupsyadmin.tui.clients_overview import ClientsOverview
|
|
14
13
|
from edupsyadmin.tui.edit_client import EditClient
|
|
15
14
|
from edupsyadmin.tui.fill_form_widget import FillForm, FillFormScreen
|
|
@@ -206,7 +205,7 @@ class EdupsyadminTui(App[None]):
|
|
|
206
205
|
if message.client_id is not None and message.client_data is not None:
|
|
207
206
|
edit_client_widget.update_client(message.client_id, message.client_data)
|
|
208
207
|
else:
|
|
209
|
-
edit_client_widget.update_client(None,
|
|
208
|
+
edit_client_widget.update_client(None, None)
|
|
210
209
|
self.notify("Daten erfolgreich gespeichert.", severity="information")
|
|
211
210
|
|
|
212
211
|
async def on_edit_client_cancel_edit(self, message: EditClient.CancelEdit) -> None:
|
|
@@ -214,7 +213,7 @@ class EdupsyadminTui(App[None]):
|
|
|
214
213
|
return
|
|
215
214
|
|
|
216
215
|
edit_client_widget = self.query_one(EditClient)
|
|
217
|
-
edit_client_widget.update_client(None,
|
|
216
|
+
edit_client_widget.update_client(None, None)
|
|
218
217
|
self.notify("Bearbeitung abgebrochen.", severity="information")
|
|
219
218
|
|
|
220
219
|
async def on_fill_form_start_fill(self, message: FillForm.StartFill) -> None:
|
|
@@ -295,7 +294,7 @@ class EdupsyadminTui(App[None]):
|
|
|
295
294
|
def __init__(
|
|
296
295
|
self,
|
|
297
296
|
client_id: int,
|
|
298
|
-
client_data:
|
|
297
|
+
client_data: ClientData | None,
|
|
299
298
|
error: Exception | None = None,
|
|
300
299
|
) -> None:
|
|
301
300
|
self.client_id = client_id
|
|
@@ -307,7 +306,7 @@ class EdupsyadminTui(App[None]):
|
|
|
307
306
|
def __init__(
|
|
308
307
|
self,
|
|
309
308
|
client_id: int | None = None,
|
|
310
|
-
client_data:
|
|
309
|
+
client_data: ClientData | None = None,
|
|
311
310
|
error: Exception | None = None,
|
|
312
311
|
) -> None:
|
|
313
312
|
self.client_id = client_id
|
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
1
|
from pathlib import Path
|
|
4
|
-
from typing import TYPE_CHECKING
|
|
2
|
+
from typing import TYPE_CHECKING
|
|
5
3
|
|
|
6
4
|
from rich.text import Text
|
|
7
5
|
from textual import on
|
|
@@ -21,6 +19,7 @@ from textual.widgets import (
|
|
|
21
19
|
Static,
|
|
22
20
|
)
|
|
23
21
|
|
|
22
|
+
from edupsyadmin.api.types import ClientData
|
|
24
23
|
from edupsyadmin.core.config import config
|
|
25
24
|
|
|
26
25
|
if TYPE_CHECKING:
|
|
@@ -164,7 +163,7 @@ class FillForm(Widget):
|
|
|
164
163
|
event.input.value = str(current_path)
|
|
165
164
|
|
|
166
165
|
# TODO: improve confusing function name
|
|
167
|
-
def update_client(self, client_id: int, client_data:
|
|
166
|
+
def update_client(self, client_id: int, client_data: ClientData) -> None:
|
|
168
167
|
"""Update the widget with data for a specific client."""
|
|
169
168
|
self.client_id = client_id
|
|
170
169
|
info = self.query_one("#client-info", Static)
|
|
@@ -177,7 +176,7 @@ class FillForm(Widget):
|
|
|
177
176
|
|
|
178
177
|
# TODO: improve confusing function name
|
|
179
178
|
# TODO: remove redundancy
|
|
180
|
-
def update_clients(self, clients_data: dict[int,
|
|
179
|
+
def update_clients(self, clients_data: dict[int, ClientData]) -> None:
|
|
181
180
|
"""Update the widget with data for multiple clients."""
|
|
182
181
|
self.client_ids = list(clients_data.keys())
|
|
183
182
|
info = self.query_one("#client-info", Static)
|
|
@@ -257,7 +256,7 @@ class FillFormScreen(Screen):
|
|
|
257
256
|
|
|
258
257
|
def on_mount(self) -> None:
|
|
259
258
|
"""Load the client data and update the FillForm widget."""
|
|
260
|
-
clients_data = {}
|
|
259
|
+
clients_data: dict[int, ClientData] = {}
|
|
261
260
|
for client_id in self.client_ids:
|
|
262
261
|
clients_data[client_id] = self.clients_manager.get_decrypted_client(
|
|
263
262
|
client_id
|