Skip to content

Commit 2cb2f67

Browse files
API: Implement primitive data types (#442)
Till now we had not implemented the additional primitive data types introduced in the [API specification]. Many of them are still not usable since we for example do not support asynchronous operations yet. But I still think it is better to have them implemented for later use. [API specification]: https://industrialdigitaltwin.io/aas-specifications/IDTA-01002/v3.1/specification/interfaces-payload.html#_primitive_data_types --------- Co-authored-by: s-heppner <iat@s-heppner.com>
1 parent b9ef3a4 commit 2cb2f67

3 files changed

Lines changed: 80 additions & 6 deletions

File tree

sdk/basyx/aas/model/base.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
BlobType = bytes
2929

3030
# The following string aliases are constrained by the decorator functions defined in the string_constraints module,
31-
# wherever they are used for an instance attributes.
31+
# wherever they are used for an instance's attributes.
3232
ContentType = str # any mimetype as in RFC2046
3333
Identifier = str
3434
LabelType = str
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
# Copyright (c) 2025 the Eclipse BaSyx Authors
2+
#
3+
# This program and the accompanying materials are made available under the terms of the MIT License, available in
4+
# the LICENSE file of this project.
5+
#
6+
# SPDX-License-Identifier: MIT
7+
"""
8+
This module implements constraint functions for the listed constrained string types.
9+
All types are constrained in length (min and max).
10+
11+
.. warning::
12+
This module is intended for internal use only.
13+
14+
The following types aliased in the :mod:`~server.app.interfaces.base` module are constrained:
15+
16+
- :class:`~server.app.interfaces.base.CodeType`
17+
- :class:`~server.app.interfaces.base.ShortIdType`
18+
- :class:`~server.app.interfaces.base.LocatorType`
19+
- :class:`~server.app.interfaces.base.TextType`
20+
- :class:`~server.app.interfaces.base.SchemeType`
21+
"""
22+
23+
from typing import Callable, Type
24+
from basyx.aas.model._string_constraints import check, constrain_attr, _T
25+
26+
27+
def check_code_type(value: str, type_name: str = "CodeType") -> None:
28+
return check(value, type_name, 1, 32)
29+
30+
31+
def check_short_id_type(value: str, type_name: str = "ShortIdType") -> None:
32+
return check(value, type_name, 1, 128)
33+
34+
35+
def check_locator_type(value: str, type_name: str = "LocatorType") -> None:
36+
return check(value, type_name, 1, 2048)
37+
38+
39+
def check_text_type(value: str, type_name: str = "TextType") -> None:
40+
return check(value, type_name, 1, 2048)
41+
42+
43+
def check_scheme_type(value: str, type_name: str = "SchemeType") -> None:
44+
return check(value, type_name, 1, 128)
45+
46+
47+
def constrain_code_type(pub_attr_name: str) -> Callable[[Type[_T]], Type[_T]]:
48+
return constrain_attr(pub_attr_name, check_code_type)
49+
50+
51+
def constrain_short_id_type(pub_attr_name: str) -> Callable[[Type[_T]], Type[_T]]:
52+
return constrain_attr(pub_attr_name, check_short_id_type)
53+
54+
55+
def constrain_locator_type(pub_attr_name: str) -> Callable[[Type[_T]], Type[_T]]:
56+
return constrain_attr(pub_attr_name, check_locator_type)
57+
58+
59+
def constrain_text_type(pub_attr_name: str) -> Callable[[Type[_T]], Type[_T]]:
60+
return constrain_attr(pub_attr_name, check_text_type)
61+
62+
63+
def constrain_scheme_type(pub_attr_name: str) -> Callable[[Type[_T]], Type[_T]]:
64+
return constrain_attr(pub_attr_name, check_scheme_type)

server/app/interfaces/base.py

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
from basyx.aas.adapter._generic import XML_NS_MAP
2020
from basyx.aas.adapter.xml import XMLConstructables, read_aas_xml_element, xml_serialization
2121
from basyx.aas.model import AbstractObjectStore
22+
from basyx.aas.model.datatypes import NonNegativeInteger
2223
from lxml import etree
2324
from werkzeug import Request, Response
2425
from werkzeug.exceptions import BadRequest, NotFound
@@ -28,6 +29,15 @@
2829
from app.adapter import ServerAASToJsonEncoder, ServerStrictAASFromJsonDecoder, ServerStrictStrippedAASFromJsonDecoder
2930
from app.model import AssetAdministrationShellDescriptor, AssetLink, SubmodelDescriptor
3031
from app.util.converters import base64url_decode
32+
from . import _string_constraints
33+
34+
# The following string aliases are constrained by the decorator functions defined in the string_constraints module,
35+
# wherever they are used for an instances attributes.
36+
CodeType = str
37+
ShortIdType = str
38+
LocatorType = str
39+
TextType = str
40+
SchemeType = str
3141

3242
T = TypeVar("T")
3343

@@ -44,15 +54,16 @@ def __str__(self):
4454
return self.name.capitalize()
4555

4656

57+
@_string_constraints.constrain_code_type("code")
4758
class Message:
4859
def __init__(
4960
self,
50-
code: str,
61+
code: CodeType,
5162
text: str,
5263
message_type: MessageType = MessageType.UNDEFINED,
5364
timestamp: Optional[datetime.datetime] = None,
5465
):
55-
self.code: str = code
66+
self.code: CodeType = code
5667
self.text: str = text
5768
self.message_type: MessageType = message_type
5869
self.timestamp: datetime.datetime = (
@@ -203,9 +214,8 @@ def _get_slice(cls, request: Request, iterator: Iterable[T]) -> Tuple[Iterator[T
203214
limit_str = request.args.get("limit", default="10")
204215
cursor_str = request.args.get("cursor", default="1")
205216
try:
206-
limit, cursor = int(limit_str), int(cursor_str) - 1 # cursor is 1-indexed
207-
if limit < 0 or cursor < 0:
208-
raise ValueError
217+
limit, cursor = (NonNegativeInteger(int(limit_str)),
218+
NonNegativeInteger(int(cursor_str) - 1)) # cursor is 1-indexed
209219
except ValueError:
210220
raise BadRequest("Limit can not be negative, cursor must be positive!")
211221
start_index = cursor

0 commit comments

Comments
 (0)