diff --git a/sdk/basyx/aas/model/base.py b/sdk/basyx/aas/model/base.py index 35ccad5a..ca22d5bb 100644 --- a/sdk/basyx/aas/model/base.py +++ b/sdk/basyx/aas/model/base.py @@ -28,7 +28,7 @@ BlobType = bytes # The following string aliases are constrained by the decorator functions defined in the string_constraints module, -# wherever they are used for an instance attributes. +# wherever they are used for an instance's attributes. ContentType = str # any mimetype as in RFC2046 Identifier = str LabelType = str diff --git a/server/app/interfaces/_string_constraints.py b/server/app/interfaces/_string_constraints.py new file mode 100644 index 00000000..65a35fe0 --- /dev/null +++ b/server/app/interfaces/_string_constraints.py @@ -0,0 +1,64 @@ +# Copyright (c) 2025 the Eclipse BaSyx Authors +# +# This program and the accompanying materials are made available under the terms of the MIT License, available in +# the LICENSE file of this project. +# +# SPDX-License-Identifier: MIT +""" +This module implements constraint functions for the listed constrained string types. +All types are constrained in length (min and max). + +.. warning:: + This module is intended for internal use only. + +The following types aliased in the :mod:`~server.app.interfaces.base` module are constrained: + +- :class:`~server.app.interfaces.base.CodeType` +- :class:`~server.app.interfaces.base.ShortIdType` +- :class:`~server.app.interfaces.base.LocatorType` +- :class:`~server.app.interfaces.base.TextType` +- :class:`~server.app.interfaces.base.SchemeType` +""" + +from typing import Callable, Type +from basyx.aas.model._string_constraints import check, constrain_attr, _T + + +def check_code_type(value: str, type_name: str = "CodeType") -> None: + return check(value, type_name, 1, 32) + + +def check_short_id_type(value: str, type_name: str = "ShortIdType") -> None: + return check(value, type_name, 1, 128) + + +def check_locator_type(value: str, type_name: str = "LocatorType") -> None: + return check(value, type_name, 1, 2048) + + +def check_text_type(value: str, type_name: str = "TextType") -> None: + return check(value, type_name, 1, 2048) + + +def check_scheme_type(value: str, type_name: str = "SchemeType") -> None: + return check(value, type_name, 1, 128) + + +def constrain_code_type(pub_attr_name: str) -> Callable[[Type[_T]], Type[_T]]: + return constrain_attr(pub_attr_name, check_code_type) + + +def constrain_short_id_type(pub_attr_name: str) -> Callable[[Type[_T]], Type[_T]]: + return constrain_attr(pub_attr_name, check_short_id_type) + + +def constrain_locator_type(pub_attr_name: str) -> Callable[[Type[_T]], Type[_T]]: + return constrain_attr(pub_attr_name, check_locator_type) + + +def constrain_text_type(pub_attr_name: str) -> Callable[[Type[_T]], Type[_T]]: + return constrain_attr(pub_attr_name, check_text_type) + + +def constrain_scheme_type(pub_attr_name: str) -> Callable[[Type[_T]], Type[_T]]: + return constrain_attr(pub_attr_name, check_scheme_type) diff --git a/server/app/interfaces/base.py b/server/app/interfaces/base.py index 2f23b562..45d7f058 100644 --- a/server/app/interfaces/base.py +++ b/server/app/interfaces/base.py @@ -25,8 +25,17 @@ from basyx.aas.adapter.json import StrictStrippedAASFromJsonDecoder, StrictAASFromJsonDecoder, AASToJsonEncoder from basyx.aas.adapter.xml import xml_serialization, XMLConstructables, read_aas_xml_element from basyx.aas.model import AbstractObjectStore +from basyx.aas.model.datatypes import NonNegativeInteger from util.converters import base64url_decode +from . import _string_constraints +# The following string aliases are constrained by the decorator functions defined in the string_constraints module, +# wherever they are used for an instances attributes. +CodeType = str +ShortIdType = str +LocatorType = str +TextType = str +SchemeType = str T = TypeVar("T") @@ -43,10 +52,11 @@ def __str__(self): return self.name.capitalize() +@_string_constraints.constrain_code_type("code") class Message: - def __init__(self, code: str, text: str, message_type: MessageType = MessageType.UNDEFINED, + def __init__(self, code: CodeType, text: str, message_type: MessageType = MessageType.UNDEFINED, timestamp: Optional[datetime.datetime] = None): - self.code: str = code + self.code: CodeType = code self.text: str = text self.message_type: MessageType = message_type self.timestamp: datetime.datetime = timestamp if timestamp is not None \ @@ -203,9 +213,8 @@ def _get_slice(cls, request: Request, iterator: Iterable[T]) -> Tuple[Iterator[T limit_str = request.args.get('limit', default="10") cursor_str = request.args.get('cursor', default="1") try: - limit, cursor = int(limit_str), int(cursor_str) - 1 # cursor is 1-indexed - if limit < 0 or cursor < 0: - raise ValueError + limit, cursor = (NonNegativeInteger(int(limit_str)), + NonNegativeInteger(int(cursor_str) - 1)) # cursor is 1-indexed except ValueError: raise BadRequest("Limit can not be negative, cursor must be positive!") start_index = cursor diff --git a/server/app/interfaces/repository.py b/server/app/interfaces/repository.py index 03a3974c..713023d0 100644 --- a/server/app/interfaces/repository.py +++ b/server/app/interfaces/repository.py @@ -6,32 +6,6 @@ # SPDX-License-Identifier: MIT """ This module implements the "Specification of the Asset Administration Shell Part 2 Application Programming Interfaces". -However, several features and routes are currently not supported: - -1. Correlation ID: Not implemented because it was deemed unnecessary for this server. - -2. Extent Parameter (`withBlobValue/withoutBlobValue`): - Not implemented due to the lack of support in JSON/XML serialization. - -3. Route `/shells/{aasIdentifier}/asset-information/thumbnail`: Not implemented because the specification lacks clarity. - -4. Serialization and Description Routes: - - `/serialization` - - `/description` - These routes are not implemented at this time. - -5. Value, Path, and PATCH Routes: - - All `/…/value$`, `/…/path$`, and `PATCH` routes are currently not implemented. - -6. Operation Invocation Routes: The following routes are not implemented because operation invocation - is not yet supported by the `basyx-python-sdk`: - - `POST /submodels/{submodelIdentifier}/submodel-elements/{idShortPath}/invoke` - - `POST /submodels/{submodelIdentifier}/submodel-elements/{idShortPath}/invoke/$value` - - `POST /submodels/{submodelIdentifier}/submodel-elements/{idShortPath}/invoke-async` - - `POST /submodels/{submodelIdentifier}/submodel-elements/{idShortPath}/invoke-async/$value` - - `GET /submodels/{submodelIdentifier}/submodel-elements/{idShortPath}/operation-status/{handleId}` - - `GET /submodels/{submodelIdentifier}/submodel-elements/{idShortPath}/operation-results/{handleId}` - - `GET /submodels/{submodelIdentifier}/submodel-elements/{idShortPath}/operation-results/{handleId}/$value` """ import io