From 384a59c2b6b3527bd2cb461b77e4ba74f2358315 Mon Sep 17 00:00:00 2001 From: rrimpila Date: Wed, 1 Apr 2026 16:50:58 +0300 Subject: [PATCH 1/3] LABP-283 Add code book model and import --- funidata_utils/schemas/sisu/code_book.py | 48 +++++++++++++++++++ .../resources/sis_resources.py | 4 ++ 2 files changed, 52 insertions(+) create mode 100644 funidata_utils/schemas/sisu/code_book.py diff --git a/funidata_utils/schemas/sisu/code_book.py b/funidata_utils/schemas/sisu/code_book.py new file mode 100644 index 0000000..2b1c945 --- /dev/null +++ b/funidata_utils/schemas/sisu/code_book.py @@ -0,0 +1,48 @@ +from typing import Annotated, Literal + +from pydantic import Field, field_serializer, conset, conlist + +from funidata_utils.schemas.common_serializers import serialize_as_list +from funidata_utils.schemas.sisu import LocalizedString +from funidata_utils.schemas.sisu.base import SisBase +from funidata_utils.schemas.sisu.common import ( + STRIPPED_STR, sis_code_urn_pattern, SIS_MAX_VERY_LARGE_SET_SIZE, OTM_ID_REGEX_VALIDATED_STR, + SIS_MAX_SMALL_SET_SIZE, +) + + +class Code(SisBase): + name: LocalizedString + shortName: LocalizedString | None + urn: Annotated[STRIPPED_STR, Field(pattern=sis_code_urn_pattern('.+'))] + parentUrn: Annotated[STRIPPED_STR, Field(pattern=sis_code_urn_pattern('.+'))] | None + isLeafNode: bool | None + universitySpecifier: str | None # Literal['HY', 'JYU', 'LUT', 'TUNI', 'AALTO', 'ARC', 'SHH'] | None but I really don't want to keep updating this... + deprecated: bool | None + exceptionalVirtaValue: str | None + type: Literal['Code'] + +class CompetencyCode(Code): + type: Literal['CompetencyCode'] + credits: int | None + +class CountryCode(Code): + type: Literal['CountryCode'] + numeric: str | None + alpha2: str | None + alpha3: str | None + +class CodeBook(SisBase): + documentState: Literal['ACTIVE', 'DRAFT', 'DELETED'] + urn: Annotated[STRIPPED_STR, Field(pattern=sis_code_urn_pattern('.+'))] + codeBookType: Literal['COMMON', 'CUSTOM'] | None + name: LocalizedString + classificationScopeUrns: conset(Annotated[STRIPPED_STR, Field(pattern=sis_code_urn_pattern('classification-scope'))], max_length=SIS_MAX_SMALL_SET_SIZE) | None # noqa + universityOrgIds: conlist(OTM_ID_REGEX_VALIDATED_STR, max_length=1) | None # noqa + codeVisibility: Literal['ALWAYS_VISIBLE', 'HIDING_CODES_ALLOWED'] + codes: conset(Code | CompetencyCode | CountryCode, min_length=1, max_length=SIS_MAX_VERY_LARGE_SET_SIZE) # noqa + + @field_serializer("classificationScopeUrns", "codes") + def serialize_set_as_list(self, v, _info) -> list | None: + serialized_list = serialize_as_list(v) + return serialized_list \ No newline at end of file diff --git a/funidata_utils/sis_integration/resources/sis_resources.py b/funidata_utils/sis_integration/resources/sis_resources.py index 1d095e5..b2dc590 100644 --- a/funidata_utils/sis_integration/resources/sis_resources.py +++ b/funidata_utils/sis_integration/resources/sis_resources.py @@ -315,6 +315,10 @@ class CodeBooks(BaseResource): endpoint='/kori/api/codebooks/v1/export', default_export_limit=_DEFAULT_EXPORT_LIMIT, ) + imports = SisImport( + endpoint='/kori/api/codebooks/v1/import', + default_import_limit=_DEFAULT_IMPORT_LIMIT, + ) class CurriculumPeriods(BaseResource): From 7d3e9b25395c1ae937f88b1d4e37f9abf6065874 Mon Sep 17 00:00:00 2001 From: rrimpila Date: Thu, 2 Apr 2026 15:34:43 +0300 Subject: [PATCH 2/3] LABP-283 Reformat --- funidata_utils/schemas/sisu/code_book.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/funidata_utils/schemas/sisu/code_book.py b/funidata_utils/schemas/sisu/code_book.py index 2b1c945..5f615b6 100644 --- a/funidata_utils/schemas/sisu/code_book.py +++ b/funidata_utils/schemas/sisu/code_book.py @@ -17,27 +17,31 @@ class Code(SisBase): urn: Annotated[STRIPPED_STR, Field(pattern=sis_code_urn_pattern('.+'))] parentUrn: Annotated[STRIPPED_STR, Field(pattern=sis_code_urn_pattern('.+'))] | None isLeafNode: bool | None - universitySpecifier: str | None # Literal['HY', 'JYU', 'LUT', 'TUNI', 'AALTO', 'ARC', 'SHH'] | None but I really don't want to keep updating this... + universitySpecifier: str | None # Literal['HY', 'JYU', 'LUT', 'TUNI', 'AALTO', 'ARC', 'SHH'] | None but I really don't want to keep updating this... deprecated: bool | None exceptionalVirtaValue: str | None type: Literal['Code'] + class CompetencyCode(Code): type: Literal['CompetencyCode'] credits: int | None + class CountryCode(Code): type: Literal['CountryCode'] numeric: str | None alpha2: str | None alpha3: str | None + class CodeBook(SisBase): documentState: Literal['ACTIVE', 'DRAFT', 'DELETED'] urn: Annotated[STRIPPED_STR, Field(pattern=sis_code_urn_pattern('.+'))] codeBookType: Literal['COMMON', 'CUSTOM'] | None name: LocalizedString - classificationScopeUrns: conset(Annotated[STRIPPED_STR, Field(pattern=sis_code_urn_pattern('classification-scope'))], max_length=SIS_MAX_SMALL_SET_SIZE) | None # noqa + classificationScopeUrns: conset(Annotated[STRIPPED_STR, Field(pattern=sis_code_urn_pattern('classification-scope'))], + max_length=SIS_MAX_SMALL_SET_SIZE) | None # noqa universityOrgIds: conlist(OTM_ID_REGEX_VALIDATED_STR, max_length=1) | None # noqa codeVisibility: Literal['ALWAYS_VISIBLE', 'HIDING_CODES_ALLOWED'] codes: conset(Code | CompetencyCode | CountryCode, min_length=1, max_length=SIS_MAX_VERY_LARGE_SET_SIZE) # noqa @@ -45,4 +49,4 @@ class CodeBook(SisBase): @field_serializer("classificationScopeUrns", "codes") def serialize_set_as_list(self, v, _info) -> list | None: serialized_list = serialize_as_list(v) - return serialized_list \ No newline at end of file + return serialized_list From e1e7fce173cd88e2bd2caf81b7bcd9f84212b035 Mon Sep 17 00:00:00 2001 From: rrimpila Date: Tue, 7 Apr 2026 12:39:57 +0300 Subject: [PATCH 3/3] LABP-283 Fix review note --- funidata_utils/schemas/sisu/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/funidata_utils/schemas/sisu/__init__.py b/funidata_utils/schemas/sisu/__init__.py index 251db60..bf34afa 100644 --- a/funidata_utils/schemas/sisu/__init__.py +++ b/funidata_utils/schemas/sisu/__init__.py @@ -45,3 +45,4 @@ from .cooperation_network import CooperationNetwork from .term_registration import (TermRegistration, StudyRightTermRegistrations) from .enrolment_calculation_config import EnrolmentCalculationConfig +from .code_book import CodeBook