1010import io
1111import itertools
1212import json
13- from typing import Iterable , Type , Iterator , Tuple , Optional , List , Union , Dict , Callable , TypeVar , Any
13+ from typing import Any , Callable , Dict , Iterable , Iterator , List , Optional , Tuple , Type , TypeVar , Union
1414
1515import werkzeug .exceptions
1616import werkzeug .routing
1717import werkzeug .utils
18+ from basyx .aas import model
19+ from basyx .aas .adapter ._generic import XML_NS_MAP
20+ from basyx .aas .adapter .xml import XMLConstructables , read_aas_xml_element , xml_serialization
21+ from basyx .aas .model import AbstractObjectStore
1822from lxml import etree
19- from werkzeug import Response , Request
20- from werkzeug .exceptions import NotFound , BadRequest
23+ from werkzeug import Request , Response
24+ from werkzeug .exceptions import BadRequest , NotFound
2125from werkzeug .routing import MapAdapter
2226
2327import app .model
24- from basyx .aas import model
25- from basyx .aas .adapter ._generic import XML_NS_MAP
26- from app .adapter import ServerStrictStrippedAASFromJsonDecoder , ServerStrictAASFromJsonDecoder , ServerAASToJsonEncoder
27- from basyx .aas .adapter .xml import xml_serialization , XMLConstructables , read_aas_xml_element
28- from basyx .aas .model import AbstractObjectStore
28+ from app .adapter import ServerAASToJsonEncoder , ServerStrictAASFromJsonDecoder , ServerStrictStrippedAASFromJsonDecoder
29+ from app .model import AssetAdministrationShellDescriptor , AssetLink , SubmodelDescriptor
2930from app .util .converters import base64url_decode
30- from app .model import AssetLink , AssetAdministrationShellDescriptor , SubmodelDescriptor
31- from app .model .provider import _DESCRIPTOR_TYPE
32-
33-
3431
3532T = TypeVar ("T" )
3633
@@ -48,13 +45,19 @@ def __str__(self):
4845
4946
5047class Message :
51- def __init__ (self , code : str , text : str , message_type : MessageType = MessageType .UNDEFINED ,
52- timestamp : Optional [datetime .datetime ] = None ):
48+ def __init__ (
49+ self ,
50+ code : str ,
51+ text : str ,
52+ message_type : MessageType = MessageType .UNDEFINED ,
53+ timestamp : Optional [datetime .datetime ] = None ,
54+ ):
5355 self .code : str = code
5456 self .text : str = text
5557 self .message_type : MessageType = message_type
56- self .timestamp : datetime .datetime = timestamp if timestamp is not None \
57- else datetime .datetime .now (datetime .timezone .utc )
58+ self .timestamp : datetime .datetime = (
59+ timestamp if timestamp is not None else datetime .datetime .now (datetime .timezone .utc )
60+ )
5861
5962
6063class Result :
@@ -70,8 +73,9 @@ def __init__(self, success: bool, messages: Optional[List[Message]] = None):
7073
7174class APIResponse (abc .ABC , Response ):
7275 @abc .abstractmethod
73- def __init__ (self , obj : Optional [ResponseData ] = None , cursor : Optional [int ] = None ,
74- stripped : bool = False , * args , ** kwargs ):
76+ def __init__ (
77+ self , obj : Optional [ResponseData ] = None , cursor : Optional [int ] = None , stripped : bool = False , * args , ** kwargs
78+ ):
7579 super ().__init__ (* args , ** kwargs )
7680 if obj is None :
7781 self .status_code = 204
@@ -91,14 +95,9 @@ def serialize(self, obj: ResponseData, cursor: Optional[int], stripped: bool) ->
9195 if cursor is None :
9296 data = obj
9397 else :
94- data = {
95- "paging_metadata" : {"cursor" : str (cursor )},
96- "result" : obj
97- }
98+ data = {"paging_metadata" : {"cursor" : str (cursor )}, "result" : obj }
9899 return json .dumps (
99- data ,
100- cls = StrippedResultToJsonEncoder if stripped else ResultToJsonEncoder ,
101- separators = ("," , ":" )
100+ data , cls = StrippedResultToJsonEncoder if stripped else ResultToJsonEncoder , separators = ("," , ":" )
102101 )
103102
104103
@@ -166,18 +165,15 @@ def __init__(self, *args, content_type="text/xml", **kwargs):
166165class ResultToJsonEncoder (ServerAASToJsonEncoder ):
167166 @classmethod
168167 def _result_to_json (cls , result : Result ) -> Dict [str , object ]:
169- return {
170- "success" : result .success ,
171- "messages" : result .messages
172- }
168+ return {"success" : result .success , "messages" : result .messages }
173169
174170 @classmethod
175171 def _message_to_json (cls , message : Message ) -> Dict [str , object ]:
176172 return {
177173 "messageType" : message .message_type ,
178174 "text" : message .text ,
179175 "code" : message .code ,
180- "timestamp" : message .timestamp .isoformat ()
176+ "timestamp" : message .timestamp .isoformat (),
181177 }
182178
183179 def default (self , obj : object ) -> object :
@@ -204,8 +200,8 @@ def __call__(self, environ, start_response) -> Iterable[bytes]:
204200
205201 @classmethod
206202 def _get_slice (cls , request : Request , iterator : Iterable [T ]) -> Tuple [Iterator [T ], int ]:
207- limit_str = request .args .get (' limit' , default = "10" )
208- cursor_str = request .args .get (' cursor' , default = "1" )
203+ limit_str = request .args .get (" limit" , default = "10" )
204+ cursor_str = request .args .get (" cursor" , default = "1" )
209205 try :
210206 limit , cursor = int (limit_str ), int (cursor_str ) - 1 # cursor is 1-indexed
211207 if limit < 0 or cursor < 0 :
@@ -238,27 +234,31 @@ def get_response_type(request: Request) -> Type[APIResponse]:
238234 response_types : Dict [str , Type [APIResponse ]] = {
239235 "application/json" : JsonResponse ,
240236 "application/xml" : XmlResponse ,
241- "text/xml" : XmlResponseAlt
237+ "text/xml" : XmlResponseAlt ,
242238 }
243239 if len (request .accept_mimetypes ) == 0 or request .accept_mimetypes .best in (None , "*/*" ):
244240 return JsonResponse
245241 mime_type = request .accept_mimetypes .best_match (response_types )
246242 if mime_type is None :
247- raise werkzeug .exceptions .NotAcceptable ("This server supports the following content types: "
248- + ", " .join (response_types .keys ()))
243+ raise werkzeug .exceptions .NotAcceptable (
244+ "This server supports the following content types: " + ", " .join (response_types .keys ())
245+ )
249246 return response_types [mime_type ]
250247
251248 @staticmethod
252- def http_exception_to_response (exception : werkzeug .exceptions .HTTPException , response_type : Type [APIResponse ]) \
253- -> APIResponse :
249+ def http_exception_to_response (
250+ exception : werkzeug .exceptions .HTTPException , response_type : Type [APIResponse ]
251+ ) -> APIResponse :
254252 headers = exception .get_headers ()
255253 location = exception .get_response ().location
256254 if location is not None :
257255 headers .append (("Location" , location ))
258256 if exception .code and exception .code >= 400 :
259- message = Message (type (exception ).__name__ ,
260- exception .description if exception .description is not None else "" ,
261- MessageType .ERROR )
257+ message = Message (
258+ type (exception ).__name__ ,
259+ exception .description if exception .description is not None else "" ,
260+ MessageType .ERROR ,
261+ )
262262 result = Result (False , [message ])
263263 else :
264264 result = Result (False )
@@ -273,13 +273,13 @@ def _get_all_obj_of_type(self, type_: Type[T]) -> Iterator[T]:
273273 if isinstance (obj , type_ ):
274274 yield obj
275275
276- def _get_obj_ts (self , identifier : model .Identifier , type_ : Type [T ]) \
277- -> T :
276+ def _get_obj_ts (self , identifier : model .Identifier , type_ : Type [T ]) -> T :
278277 identifiable = self .object_store .get (identifier )
279278 if not isinstance (identifiable , type_ ):
280279 raise NotFound (f"No { type_ .__name__ } with { identifier } found!" )
281280 return identifiable
282281
282+
283283class HTTPApiDecoder :
284284 # these are the types we can construct (well, only the ones we need)
285285 type_constructables_map = {
@@ -313,8 +313,9 @@ def assert_type(cls, obj: object, type_: Type[T]) -> T:
313313 @classmethod
314314 def json_list (cls , data : Union [str , bytes ], expect_type : Type [T ], stripped : bool , expect_single : bool ) -> List [T ]:
315315 cls .check_type_support (expect_type )
316- decoder : Type [ServerStrictAASFromJsonDecoder ] = ServerStrictStrippedAASFromJsonDecoder if stripped \
317- else ServerStrictAASFromJsonDecoder
316+ decoder : Type [ServerStrictAASFromJsonDecoder ] = (
317+ ServerStrictStrippedAASFromJsonDecoder if stripped else ServerStrictAASFromJsonDecoder
318+ )
318319 try :
319320 parsed = json .loads (data , cls = decoder )
320321 if isinstance (parsed , list ) and expect_single :
@@ -371,8 +372,9 @@ def xml(cls, data: bytes, expect_type: Type[T], stripped: bool) -> T:
371372 cls .check_type_support (expect_type )
372373 try :
373374 xml_data = io .BytesIO (data )
374- rv = read_aas_xml_element (xml_data , cls .type_constructables_map [expect_type ],
375- stripped = stripped , failsafe = False )
375+ rv = read_aas_xml_element (
376+ xml_data , cls .type_constructables_map [expect_type ], stripped = stripped , failsafe = False
377+ )
376378 except (KeyError , ValueError ) as e :
377379 # xml deserialization creates an error chain. since we only return one error, return the root cause
378380 f : BaseException = e
@@ -397,8 +399,8 @@ def request_body(cls, request: Request, expect_type: Type[T], stripped: bool) ->
397399
398400 if request .mimetype not in valid_content_types :
399401 raise werkzeug .exceptions .UnsupportedMediaType (
400- f"Invalid content-type: { request .mimetype } ! Supported types: "
401- + ", " . join ( valid_content_types ) )
402+ f"Invalid content-type: { request .mimetype } ! Supported types: " + ", " . join ( valid_content_types )
403+ )
402404
403405 if request .mimetype == "application/json" :
404406 return cls .json (request .get_data (), expect_type , stripped )
0 commit comments