2828import itertools
2929import logging
3030import os
31- import re
3231from typing import Dict , Tuple , IO , Union , List , Set , Optional , Iterable , Iterator
3332
3433from .xml import read_aas_xml_file , write_aas_xml_file
4544RELATIONSHIP_TYPE_AAS_SUPL = "http://admin-shell.io/aasx/relationships/aas-suppl"
4645
4746
48- class AASXReader () :
47+ class AASXReader :
4948 """
5049 An AASXReader wraps an existing AASX package file to allow reading its contents and metadata.
5150
@@ -74,14 +73,14 @@ def __init__(self, file: Union[os.PathLike, str, IO], failsafe: bool = True):
7473 :raises FileNotFoundError: If the file does not exist
7574 :raises ValueError: If the file is not a valid OPC zip package
7675 """
77- self .failsafe = failsafe
76+ self .failsafe : bool = failsafe
7877 try :
79- logger .debug ("Opening {} as AASX pacakge for reading ..." . format ( file ) )
78+ logger .debug (f "Opening { file } as AASX package for reading ..." )
8079 self .reader = pyecma376_2 .ZipPackageReader (file )
8180 except FileNotFoundError :
8281 raise
8382 except Exception as e :
84- raise ValueError ("{ } is not a valid ECMA376-2 (OPC) file: {}" . format ( file , e ) ) from e
83+ raise ValueError (f" { file } is not a valid ECMA376-2 (OPC) file: { e } " ) from e
8584
8685 def get_core_properties (self ) -> pyecma376_2 .OPCCoreProperties :
8786 """
@@ -135,7 +134,7 @@ def read_into(self, object_store: model.AbstractObjectStore,
135134 objects from the AASX file to
136135 :param file_store: A :class:`SupplementaryFileContainer <.AbstractSupplementaryFileContainer>` to add the
137136 embedded supplementary files to
138- :param override_existing: If ``True``, existing objects in the object store are overridden with objects from the
137+ :param override_existing: If ``True``, existing objects in the ObjectStore are overridden with objects from the
139138 AASX that have the same :class:`~basyx.aas.model.base.Identifier`. Default behavior is to skip those objects
140139 from the AASX.
141140 :return: A set of the :class:`Identifiers <basyx.aas.model.base.Identifier>` of all
@@ -198,23 +197,23 @@ def _read_aas_part_into(self, part_name: str,
198197 from a File object of this part
199198 :param read_identifiables: A set of Identifiers of objects which have already been read. New objects'
200199 Identifiers are added to this set. Objects with already known Identifiers are skipped silently.
201- :param override_existing: If True, existing objects in the object store are overridden with objects from the
200+ :param override_existing: If True, existing objects in the ObjectStore are overridden with objects from the
202201 AASX that have the same Identifier. Default behavior is to skip those objects from the AASX.
203202 """
204203 for obj in self ._parse_aas_part (part_name , ** kwargs ):
205204 if obj .id in read_identifiables :
206205 continue
207206 if obj .id in object_store :
208207 if override_existing :
209- logger .info ("Overriding existing object in ObjectStore with {} ..." . format ( obj ) )
208+ logger .info (f "Overriding existing object in ObjectStore with { obj } ..." )
210209 object_store .discard (obj )
211210 else :
212211 if self .failsafe :
213- logger .warning ("Skipping {}, since an object with the same id is already contained in the "
214- "ObjectStore" . format ( obj ) )
212+ logger .warning (f "Skipping { obj } , since an object with the same id is already contained in the "
213+ "ObjectStore" )
215214 continue
216215 else :
217- raise ValueError ("Object with id {} is already contained in the ObjectStore" . format ( obj ) )
216+ raise ValueError (f "Object with id { obj } is already contained in the ObjectStore" )
218217 object_store .add (obj )
219218 read_identifiables .add (obj .id )
220219 if isinstance (obj , model .Submodel ):
@@ -232,17 +231,17 @@ def _parse_aas_part(self, part_name: str, **kwargs) -> model.DictObjectStore:
232231 content_type = self .reader .get_content_type (part_name )
233232 extension = part_name .split ("/" )[- 1 ].split ("." )[- 1 ]
234233 if content_type .split (";" )[0 ] in ("text/xml" , "application/xml" ) or content_type == "" and extension == "xml" :
235- logger .debug ("Parsing AAS objects from XML stream in OPC part {} ..." . format ( part_name ) )
234+ logger .debug (f "Parsing AAS objects from XML stream in OPC part { part_name } ..." )
236235 with self .reader .open_part (part_name ) as p :
237236 return read_aas_xml_file (p , failsafe = self .failsafe , ** kwargs )
238237 elif content_type .split (";" )[0 ] in ("text/json" , "application/json" ) \
239238 or content_type == "" and extension == "json" :
240- logger .debug ("Parsing AAS objects from JSON stream in OPC part {} ..." . format ( part_name ) )
239+ logger .debug (f "Parsing AAS objects from JSON stream in OPC part { part_name } ..." )
241240 with self .reader .open_part (part_name ) as p :
242241 return read_aas_json_file (io .TextIOWrapper (p , encoding = 'utf-8-sig' ), failsafe = self .failsafe , ** kwargs )
243242 else :
244- error_message = ("Could not determine part format of AASX part {} (Content Type: {}, extension: {} "
245- . format ( part_name , content_type , extension ) )
243+ error_message = (f "Could not determine part format of AASX part { part_name } (Content Type: { content_type } , "
244+ f" extension: { extension } " )
246245 if self .failsafe :
247246 logger .error (error_message )
248247 else :
@@ -255,7 +254,7 @@ def _collect_supplementary_files(self, part_name: str, submodel: model.Submodel,
255254 Helper function to search File objects within a single parsed Submodel, extract the referenced supplementary
256255 files and update the File object's values with the absolute path.
257256
258- :param part_name: The OPC part name of the part the submodel has been parsed from. This is used to resolve
257+ :param part_name: The OPC part name of the part the Submodel has been parsed from. This is used to resolve
259258 relative file paths.
260259 :param submodel: The Submodel to process
261260 :param file_store: The SupplementaryFileContainer to add the extracted supplementary files to
@@ -268,17 +267,17 @@ def _collect_supplementary_files(self, part_name: str, submodel: model.Submodel,
268267 # to refer to files within the AASX package. Thus, we must skip all other types of URIs (esp. absolute
269268 # URIs and network-path references)
270269 if element .value .startswith ('//' ) or ':' in element .value .split ('/' )[0 ]:
271- logger .info ("Skipping supplementary file %s , since it seems to be an absolute URI or network-path "
272- " URI reference", element . value )
270+ logger .info (f "Skipping supplementary file { element . value } , since it seems to be an absolute URI or "
271+ f"network-path URI reference" )
273272 continue
274273 absolute_name = pyecma376_2 .package_model .part_realpath (element .value , part_name )
275- logger .debug ("Reading supplementary file {} from AASX package ..." . format ( absolute_name ) )
274+ logger .debug (f "Reading supplementary file { absolute_name } from AASX package ..." )
276275 with self .reader .open_part (absolute_name ) as p :
277276 final_name = file_store .add_file (absolute_name , p , self .reader .get_content_type (absolute_name ))
278277 element .value = final_name
279278
280279
281- class AASXWriter () :
280+ class AASXWriter :
282281 """
283282 An AASXWriter wraps a new AASX package file to write its contents to it piece by piece.
284283
@@ -320,7 +319,7 @@ def __init__(self, file: Union[os.PathLike, str, IO], failsafe: bool = True):
320319 logged instead of causing exceptions. Defect objects are skipped.
321320 :param file: filename, path, or binary file handle opened for writing
322321 """
323- self .failsafe = failsafe
322+ self .failsafe : bool = failsafe
324323 # names of aas-spec parts, used by `_write_aasx_origin_relationships()`
325324 self ._aas_part_names : List [str ] = []
326325 # name of the thumbnail part (if any)
@@ -380,7 +379,7 @@ def write_aas(self,
380379 :param write_json: If ``True``, JSON parts are created for the AAS and each
381380 :class:`~basyx.aas.model.submodel.Submodel` in the AASX package file instead of XML parts.
382381 Defaults to ``False``.
383- :raises KeyError: If one of the AAS could not be retrieved from the object store (unresolvable
382+ :raises KeyError: If one of the AAS could not be retrieved from the ObjectStore (unresolvable
384383 :class:`Submodels <basyx.aas.model.submodel.Submodel>` and
385384 :class:`ConceptDescriptions <basyx.aas.model.concept.ConceptDescription>` are skipped, logging a
386385 warning/info message)
@@ -413,10 +412,10 @@ def write_aas(self,
413412 submodel = submodel_ref .resolve (object_store )
414413 except KeyError :
415414 if self .failsafe :
416- logger .warning ("Could not find submodel %s . Skipping it." , str ( submodel_ref ) )
415+ logger .warning (f "Could not find Submodel { submodel_ref } . Skipping it." )
417416 continue
418417 else :
419- raise KeyError (f"Could not find submodel { submodel_ref !r} " )
418+ raise KeyError (f"Could not find Submodel { submodel_ref !r} " )
420419 objects_to_be_written .add (submodel )
421420
422421 # Traverse object tree and check if semanticIds are referencing to existing ConceptDescriptions in the
@@ -433,15 +432,15 @@ def write_aas(self,
433432 cd = semantic_id .resolve (object_store )
434433 except KeyError :
435434 if self .failsafe :
436- logger .warning ("ConceptDescription for semanticId %s not found in object store. Skipping it." ,
437- str ( semantic_id ) )
435+ logger .warning (f "ConceptDescription for semanticId { semantic_id } not found in ObjectStore. "
436+ f"Skipping it." )
438437 continue
439438 else :
440- raise KeyError (f"ConceptDescription for semanticId { semantic_id !r} not found in object store ." )
439+ raise KeyError (f"ConceptDescription for semanticId { semantic_id !r} not found in ObjectStore ." )
441440 except model .UnexpectedTypeError as e :
442441 if self .failsafe :
443- logger .error ("semanticId %s resolves to %s, which is not a ConceptDescription. Skipping it." ,
444- str ( semantic_id ), e . value )
442+ logger .error (f "semanticId { semantic_id } resolves to { e . value } , "
443+ f"which is not a ConceptDescription. Skipping it." )
445444 continue
446445 else :
447446 raise TypeError (f"semanticId { semantic_id !r} resolves to { e .value !r} , which is not a"
@@ -469,7 +468,7 @@ def write_aas_objects(self,
469468 This method takes the AAS's :class:`~basyx.aas.model.base.Identifier` (as ``aas_id``) to retrieve it
470469 from the given object_store. If the list of written objects includes :class:`~basyx.aas.model.submodel.Submodel`
471470 objects, Supplementary files which are referenced by :class:`~basyx.aas.model.submodel.File` objects within
472- those submodels , are also added to the AASX package.
471+ those Submodels , are also added to the AASX package.
473472
474473 .. attention::
475474
@@ -494,7 +493,7 @@ def write_aas_objects(self,
494493 :param additional_relationships: Optional OPC/ECMA376 relationships which should originate at the AAS object
495494 part to be written, in addition to the aas-suppl relationships which are created automatically.
496495 """
497- logger .debug ("Writing AASX part {} with AAS objects ..." . format ( part_name ) )
496+ logger .debug (f "Writing AASX part { part_name } with AAS objects ..." )
498497
499498 objects : model .DictObjectStore [model .Identifiable ] = model .DictObjectStore ()
500499
@@ -504,7 +503,7 @@ def write_aas_objects(self,
504503 the_object = object_store .get_identifiable (identifier )
505504 except KeyError :
506505 if self .failsafe :
507- logger .error ("Could not find object {} in ObjectStore" . format ( identifier ) )
506+ logger .error (f "Could not find object { identifier } in ObjectStore" )
508507 continue
509508 else :
510509 raise KeyError (f"Could not find object { identifier !r} in ObjectStore" )
@@ -548,7 +547,7 @@ def write_all_aas_objects(self,
548547 :param additional_relationships: Optional OPC/ECMA376 relationships which should originate at the AAS object
549548 part to be written, in addition to the aas-suppl relationships which are created automatically.
550549 """
551- logger .debug ("Writing AASX part {} with AAS objects ..." . format ( part_name ) )
550+ logger .debug (f "Writing AASX part { part_name } with AAS objects ..." )
552551 supplementary_files : List [str ] = []
553552
554553 # Retrieve objects and scan for referenced supplementary files
@@ -575,36 +574,36 @@ def write_all_aas_objects(self,
575574 else :
576575 write_aas_xml_file (p , objects )
577576
578- # Write submodel 's supplementary files to AASX file
577+ # Write Submodel 's supplementary files to AASX file
579578 supplementary_file_names = []
580579 for file_name in supplementary_files :
581580 try :
582581 content_type = file_store .get_content_type (file_name )
583582 hash = file_store .get_sha256 (file_name )
584583 except KeyError :
585584 if self .failsafe :
586- logger .warning ("Could not find file {} in file store." . format ( file_name ) )
585+ logger .warning (f "Could not find file { file_name } in FileStore." )
587586 continue
588587 else :
589- raise KeyError (f"Could not find file { file_name } in file store ." )
588+ raise KeyError (f"Could not find file { file_name } in FileStore ." )
590589 # Check if this supplementary file has already been written to the AASX package or has a name conflict
591590 if self ._supplementary_part_names .get (file_name ) == hash :
592591 continue
593592 elif file_name in self ._supplementary_part_names :
594593 if self .failsafe :
595- logger .error ("Trying to write supplementary file {} to AASX twice with different contents "
596- . format ( file_name ) )
594+ logger .error (f "Trying to write supplementary file { file_name } to AASX "
595+ f"twice with different contents" )
597596 else :
598597 raise ValueError (f"Trying to write supplementary file { file_name } to AASX twice with"
599598 f" different contents" )
600- logger .debug ("Writing supplementary file {} to AASX package ..." . format ( file_name ) )
599+ logger .debug (f "Writing supplementary file { file_name } to AASX package ..." )
601600 with self .writer .open_part (file_name , content_type ) as p :
602601 file_store .write_file (file_name , p )
603602 supplementary_file_names .append (pyecma376_2 .package_model .normalize_part_name (file_name ))
604603 self ._supplementary_part_names [file_name ] = hash
605604
606- # Add relationships from submodel to supplementary parts
607- logger .debug ("Writing aas-suppl relationships for AAS object part {} to AASX package ..." . format ( part_name ) )
605+ # Add relationships from Submodel to supplementary parts
606+ logger .debug (f "Writing aas-suppl relationships for AAS object part { part_name } to AASX package ..." )
608607 self .writer .write_relationships (
609608 itertools .chain (
610609 (pyecma376_2 .OPCRelationship ("r{}" .format (i ),
@@ -643,7 +642,7 @@ def write_thumbnail(self, name: str, data: bytearray, content_type: str):
643642 :param content_type: OPC content type (MIME type) of the image file
644643 """
645644 if self ._thumbnail_part is not None :
646- raise RuntimeError ("package thumbnail has already been written to {}." . format ( self ._thumbnail_part ) )
645+ raise RuntimeError (f "package thumbnail has already been written to { self ._thumbnail_part } ." )
647646 with self .writer .open_part (name , content_type ) as p :
648647 p .write (data )
649648 self ._thumbnail_part = name
0 commit comments