Commit 8328b1f3 authored by Sebastian Heppner's avatar Sebastian Heppner
Browse files

Merge branch 'docs/sphinx_autodocs' into 'improve/V30RC01'

Merge docs/sphinx_autodocs into improve/V30RC01

See merge request !74
parents 6711a5bb 5fafdf39
Pipeline #416695 passed with stage
in 1 minute and 58 seconds
......@@ -8,5 +8,6 @@
/venv/
/.coverage
/htmlcov/
/docs/build/
/test/test_config.ini
"""
This package contains different kinds of adapters.
json
This package offers an adapter for serialization and deserialization of PyI40AAS objects to/from JSON.
xml
This package offers an adapter for serialization and deserialization of PyI40AAS objects to/from XML.
:ref:`json <adapter.json.__init__>`: This package offers an adapter for serialization and deserialization of PyI40AAS
objects to/from JSON.
:ref:`xml <adapter.xml.__init__>`: This package offers an adapter for serialization and deserialization of PyI40AAS
objects to/from XML.
:ref:`aasx <adapter.aasx>`: This package offers functions for reading and writing AASX-files.
"""
......@@ -9,6 +9,8 @@
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
# specific language governing permissions and limitations under the License.
"""
.. _adapter.aasx:
Functionality for reading and writing AASX files according to "Details of the Asset Administration Shell Part 1 V2.0",
section 7.
......@@ -16,10 +18,12 @@ The AASX file format is built upon the Open Packaging Conventions (OPC; ECMA 376
for low level OPC reading and writing. It currently supports all required features except for embedded digital
signatures.
Writing and reading of AASX packages is performed through the AASXReader and AASXWriter classes. Each instance of these
classes wraps an existing AASX file resp. a file to be created and allows to read/write the included AAS objects
into/form object stores. For handling of embedded supplementary files, this module provides the
`AbstractSupplementaryFileContainer` class interface and the `DictSupplementaryFileContainer` implementation.
Writing and reading of AASX packages is performed through the :class:`~.AASXReader` and :class:`~.AASXWriter` classes.
Each instance of these classes wraps an existing AASX file resp. a file to be created and allows to read/write the
included AAS objects into/form :class:`ObjectStores <aas.model.provider.AbstractObjectStore>`.
For handling of embedded supplementary files, this module provides the
:class:`~.AbstractSupplementaryFileContainer` class
interface and the :class:`~.DictSupplementaryFileContainer` implementation.
"""
import abc
......@@ -51,11 +55,14 @@ class AASXReader:
Basic usage:
.. code-block:: python
objects = DictObjectStore()
files = DictSupplementaryFileContainer()
with AASXReader("filename.aasx") as reader:
meta_data = reader.get_core_properties()
reader.read_into(objects, files)
"""
def __init__(self, file: Union[os.PathLike, str, IO]):
"""
......@@ -91,6 +98,8 @@ class AASXReader:
The thumbnail image file is read into memory and returned as bytes object. You may use some python image library
for further processing or conversion, e.g. `pillow`:
.. code-block:: python
import io
from PIL import Image
thumbnail = Image.open(io.BytesIO(reader.get_thumbnail()))
......@@ -109,20 +118,27 @@ class AASXReader:
file_store: "AbstractSupplementaryFileContainer",
override_existing: bool = False) -> Set[model.Identifier]:
"""
Read the contents of the AASX package and add them into a given ObjectStore
Read the contents of the AASX package and add them into a given
:class:`ObjectStore <aas.model.provider.AbstractObjectStore>`
This function does the main job of reading the AASX file's contents. It traverses the relationships within the
package to find AAS JSON or XML parts, parses them and adds the contained AAS objects into the provided
`object_store`. While doing so, it searches all parsed Submodels for File objects to extract the supplementary
files. The referenced supplementary files are added to the given `file_store` and the File objects' values are
updated with the absolute name of the supplementary file to allow for robust resolution the file within the
`object_store`. While doing so, it searches all parsed :class:`Submodels <aas.model.submodel.Submodel>` for
:class:`~aas.model.submodel.File` objects to extract the supplementary
files. The referenced supplementary files are added to the given `file_store` and the
:class:`~aas.model.submodel.File` objects' values are updated with the absolute name of the supplementary file
to allow for robust resolution the file within the
`file_store` later.
:param object_store: An ObjectStore to add the AAS objects from the AASX file to
:param file_store: A SupplementaryFileContainer to add the embedded supplementary files to
:param override_existing: If True, existing objects in the object store are overridden with objects from the
AASX that have the same Identifer. Default behavior is to skip those objects from the AASX.
:return: A set of the Identifiers of all Identifiable objects parsed from the AASX file
:param object_store: An :class:`ObjectStore <aas.model.provider.AbstractObjectStore>` to add the AAS objects
from the AASX file to
:param file_store: A :class:`SupplementaryFileContainer <.AbstractSupplementaryFileContainer>` to add the
embedded supplementary files to
:param override_existing: If `True`, existing objects in the object store are overridden with objects from the
AASX that have the same :class:`~aas.model.base.Identifier`. Default behavior is to skip those objects from
the AASX.
:return: A set of the :class:`Identifiers <aas.model.base.Identifier>` of all
:class:`~aas.model.base.Identifiable` objects parsed from the AASX file
"""
# Find AASX-Origin part
core_rels = self.reader.get_related_parts_by_type()
......@@ -253,6 +269,8 @@ class AASXWriter:
Basic usage:
.. code-block:: python
# object_store and file_store are expected to be given (e.g. some storage backend or previously created data)
cp = OPCCoreProperties()
cp.creator = "ACPLT"
......@@ -267,8 +285,9 @@ class AASXWriter:
file_store)
writer.write_core_properties(cp)
Attention: The AASXWriter must always be closed using the close() method or its context manager functionality (as
shown above). Otherwise the resulting AASX file will lack important data structures and will not be readable.
**Attention:** The AASXWriter must always be closed using the :meth:`~.AASXWriter.close` method or its context
manager functionality (as shown above). Otherwise the resulting AASX file will lack important data structures
and will not be readable.
"""
AASX_ORIGIN_PART_NAME = "/aasx/aasx-origin"
......@@ -305,19 +324,24 @@ class AASXWriter:
file_store: "AbstractSupplementaryFileContainer",
write_json: bool = False) -> None:
"""
Convenience method to write one or more Asset Administration Shells with all included and referenced objects to
the AASX package according to the part name conventions from DotAAS.
Convenience method to write one or more
:class:`AssetAdministrationShells <aas.model.aas.AssetAdministrationShell>` with all included and referenced
objects to the AASX package according to the part name conventions from DotAAS.
This method takes the AASs' Identifiers (as `aas_ids`) to retrieve the AASs from the given object_store.
References to Submodels and ConceptDescriptions (via semanticId attributes) are also resolved using the
This method takes the AASs' :class:`Identifiers <aas.model.base.Identifier>` (as `aas_ids`) to retrieve the
AASs from the given object_store.
:class:`References <aas.model.base.Reference>` to :class:`Submodels <aas.model.submodel.Submodel>` and
:class:`ConceptDescriptions <aas.model.concept.ConceptDescription>` (via semanticId attributes) are also
resolved using the
`object_store`. All of these objects are written to an aas-spec part `/aasx/data.xml` or `/aasx/data.json` in
the AASX package, compliant to the convention presented in "Details of the Asset Administration Shell".
Supplementary files which are referenced by a File object in any of the Submodels are also added to the AASX
Supplementary files which are referenced by a :class:`~aas.model.submodel.File` object in any of the
:class:`Submodels <aas.model.submodel.Submodel>` are also added to the AASX
package.
This method uses `write_all_aas_objects()` to write the AASX part.
.. attention:
.. attention::
This method **must only be used once** on a single AASX package. Otherwise, the `/aasx/data.json`
(or `...xml`) part would be written twice to the package, hiding the first part and possibly causing
......@@ -326,16 +350,22 @@ class AASXWriter:
To write multiple Asset Administration Shells to a single AASX package file, call this method once, passing
a list of AAS Identifiers to the `aas_ids` parameter.
:param aas_ids: Identifier or Iterable of Identifers of the AAS(s) to be written to the AASX file
:param object_store: ObjectStore to retrieve the Identifiable AAS objects (AAS, Asset, ConceptDescriptions and
Submodels) from
:param file_store: SupplementaryFileContainer to retrieve supplementary files from, which are referenced by File
objects
:param write_json: If True, JSON parts are created for the AAS and each submodel in the AASX package file
instead of XML parts. Defaults to False.
:raises KeyError: If one of the AAS could not be retrieved from the object store (unresolvable Submodels and
ConceptDescriptions are skipped, logging a warning/info message)
:raises TypeError: If one of the given AAS ids does not resolve to an AAS (but another Identifiable object)
:param aas_ids: :class:`~aas.model.base.Identifier` or Iterable of
:class:`Identifiers <aas.model.base.Identifier>` of the AAS(s) to be written to the AASX file
:param object_store: :class:`ObjectStore <aas.model.provider.AbstractObjectStore>` to retrieve the
:class:`~aas.model.base.Identifiable` AAS objects (:class:`~aas.model.aas.AssetAdministrationShell`,
:class:`~aas.model.aas.Asset`, :class:`~aas.model.concept.ConceptDescription` and
:class:`~aas.model.submodel.Submodel`) from
:param file_store: :class:`SupplementaryFileContainer <~.AbstractSupplementaryFileContainer>` to retrieve
supplementary files from, which are referenced by :class:`~aas.model.submodel.File` objects
:param write_json: If `True`, JSON parts are created for the AAS and each :class:`~aas.model.submodel.Submodel`
in the AASX package file instead of XML parts. Defaults to `False`.
:raises KeyError: If one of the AAS could not be retrieved from the object store (unresolvable
:class:`Submodels <aas.model.submodel.Submodel>` and
:class:`ConceptDescriptions <aas.model.concept.ConceptDescription>` are skipped, logging a warning/info
message)
:raises TypeError: If one of the given AAS ids does not resolve to an AAS (but another
:class:`~aas.model.base.Identifiable` object)
"""
if isinstance(aas_ids, model.Identifier):
aas_ids = (aas_ids,)
......@@ -400,20 +430,24 @@ class AASXWriter:
"""
A thin wrapper around :meth:`write_all_aas_objects` to ensure downwards compatibility
This method takes a list of Identifiers (as `object_ids`) to retrieve the identified objects from the given
object_store. It then uses :meth:`write_all_aas_objects` to write the objects and any referenced supplementary
files from the `file_store` to the AASX package.
This method takes a list of :class:`~aas.model.base.Identifiers` (as `object_ids`) to retrieve the
identified objects from the given object_store. It then uses :meth:`write_all_aas_objects` to write the
objects and any referenced supplementary :class:`Files <aas.model.submodel.File>` from the `file_store` to the
AASX package.
.. attention:
.. attention::
You must make sure to call this method or `write_all_aas_object` only once per unique `part_name` on a
You must make sure to call this method or `write_all_aas_objects` only once per unique `part_name` on a
single package instance.
:param part_name: Passed to :meth:`write_all_aas_objects`
:param object_ids: A list of identifiers of the objects to be written to the AASX package. Only these
Identifiable objects (and included Referable objects) are written to the package.
:param object_store: The objects store to retrieve the Identifiable objects from
All other parameters are unaltered passed to the equally named parameters of :meth:`write_all_aas_objects`.
:param file_store: Passed to :meth:`write_all_aas_objects`
:param write_json: Passed to :meth:`write_all_aas_objects`
:param split_part: Passed to :meth:`write_all_aas_objects`
:param additional_relationships: Passed to :meth:`write_all_aas_objects`
"""
logger.debug("Writing AASX part {} with AAS objects ...".format(part_name))
......@@ -440,14 +474,16 @@ class AASXWriter:
split_part: bool = False,
additional_relationships: Iterable[pyecma376_2.OPCRelationship] = ()) -> None:
"""
Write all AAS objects in a given ObjectStore to an XML or JSON part in the AASX package and add the referenced
supplementary files to the package.
Write all AAS objects in a given :class:`ObjectStore <aas.model.provider.AbstractObjectStore>` to an XML or
JSON part in the AASX package and add the referenced supplementary files to the package.
This method takes an ObjectStore and writes all contained objects into an "aas_env" part in the AASX package. If
the ObjectStore includes Submodel objects, supplementary files which are referenced by File objects
This method takes an :class:`ObjectStore <aas.model.provider.AbstractObjectStore>` and writes all contained
objects into an "aas_env" part in the AASX package. If
the ObjectStore includes :class:`~aas.model.submodel.Submodel` objects, supplementary files which are
referenced by :class:`~aas.model.submodel.File` objects
within those Submodels, are fetched from the `file_store` and added to the AASX package.
.. attention:
.. attention::
You must make sure to call this method only once per unique `part_name` on a single package instance.
......@@ -630,16 +666,22 @@ class NameFriendlyfier:
Generate a friendly name from an AAS identifier.
TODO: This information is outdated. The whole class is no longer needed.
According to section 7.6 of "Details of the Asset Administration Shell", all non-alphanumerical characters are
replaced with underscores. We also replace all non-ASCII characters to generate valid URIs as the result.
If this replacement results in a collision with a previously generated friendly name of this NameFriendlifier,
a number is appended with underscore to the friendly name. Example
a number is appended with underscore to the friendly name.
Example:
.. code-block:: python
friendlyfier = NameFriendlyfier()
friendlyfier.get_friendly_name(model.Identifier("http://example.com/AAS-a", model.IdentifierType.IRI))
> "http___example_com_AAS_a"
>>> friendlyfier = NameFriendlyfier()
>>> friendlyfier.get_friendly_name(model.Identifier("http://example.com/AAS-a", model.IdentifierType.IRI))
"http___example_com_AAS_a"
>>> friendlyfier.get_friendly_name(model.Identifier("http://example.com/AAS+a", model.IdentifierType.IRI))
"http___example_com_AAS_a_1"
friendlyfier.get_friendly_name(model.Identifier("http://example.com/AAS+a", model.IdentifierType.IRI))
> "http___example_com_AAS_a_1"
"""
# friendlify name
......@@ -661,8 +703,8 @@ class AbstractSupplementaryFileContainer(metaclass=abc.ABCMeta):
Abstract interface for containers of supplementary files for AASs.
Supplementary files may be PDF files or other binary or textual files, referenced in a File object of an AAS by
their name. They are used to provide associated documents without embedding their contents (as Blob object) in the
AAS.
their name. They are used to provide associated documents without embedding their contents (as
:class:`~aas.model.submodel.Blob` object) in the AAS.
A SupplementaryFileContainer keeps track of the name and content_type (MIME type) for each file. Additionally it
allows to resolve name conflicts by comparing the files' contents and providing an alternative name for a dissimilar
......
"""
.. _adapter.json.__init__:
This package contains functionality for serialization and deserialization of PyI40AAS objects into/from JSON.
json_serialization:
The module offers a function to write an ObjectStore to a given file and therefore defines the custom JSONEncoder
`AASToJsonEncoder` which handles encoding of all PyI40AAS objects and their attributes by converting them into
standard python objects.
:ref:`json_serialization <adapter.json.json_serialization>`: The module offers a function to write an ObjectStore to a
given file and therefore defines the custom JSONEncoder :class:`~.aas.adapter.json.json_serialization.AASToJsonEncoder`
which handles encoding of all PyI40AAS objects and their attributes by converting them into standard python objects.
json_deserialization.py
The module implements custom JSONDecoder classes `AASFromJsonDecoder` and `StrictAASFromJsonDecoder`, that — when
used with Python's `json` module — detect AAS objects in the parsed JSON and convert them into the corresponding
PyI40AAS object. A function `read_json_aas_file()` is provided to read all AAS objects within a JSON file and return
them as PyI40AAS ObjectStore.
:ref:`json_deserialization <adapter.json.json_deserialization>`: The module implements custom JSONDecoder classes
:class:`~aas.adapter.json.json_deserialization.AASFromJsonDecoder` and
:class:`~aas.adapter.json.json_deserialization.StrictAASFromJsonDecoder`, that — when used with Python's `json`
module — detect AAS objects in the parsed JSON and convert them into the corresponding PyI40AAS object.
A function :meth:`~aas.adapter.json.json_deserialization.read_aas_json_file` is provided to read all AAS objects
within a JSON file and return them as PyI40AAS ObjectStore.
"""
import os.path
......
......@@ -9,16 +9,27 @@
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
# specific language governing permissions and limitations under the License.
"""
Module for deserializing Asset Administration Shell data from the official JSON format
.. _adapter.json.json_deserialization:
The module provides custom JSONDecoder classes `AASFromJsonDecoder` and `StrictAASFromJsonDecoder` to be used with
the Python standard `json` module. They contain a custom `object_hook` function to detect encoded AAS objects within the
JSON data and convert them to PyI40AAS objects while parsing. Additionally, there's the `read_json_aas_file()` function,
that takes a complete AAS JSON file, reads its contents and returns the contained AAS objects as DictObjectStore.
Module for deserializing Asset Administration Shell data from the official JSON format
This job is performed in a bottom-up approach: The `object_hook()` method gets called for every parsed JSON object
(as dict) and checks for existence of the `modelType` attribute. If it is present, the `AAS_CLASS_PARSERS` dict defines,
which of the constructor methods of the class is to be used for converting the dict into an object. Embedded
The module provides custom JSONDecoder classes :class:`~.AASFromJsonDecoder` and :class:`~.StrictAASFromJsonDecoder` to
be used with the Python standard `json` module.
Furthermore it provides two classes :class:`~aas.adapter.json.json_deserialization.StrippedAASFromJsonDecoder` and
:class:`~aas.adapter.json.json_deserialization.StrictStrippedAASFromJsonDecoder` for parsing stripped JSON objects,
which are used in the http adapter (see https://git.rwth-aachen.de/acplt/pyi40aas/-/issues/91).
The classes contain a custom :meth:`~aas.adapter.json.json_deserialization.AASFromJsonDecoder.object_hook` function
to detect encoded AAS objects within the JSON data and convert them to PyI40AAS objects while parsing. Additionally,
there's the :meth:`~aas.adapter.json.json_deserialization.read_aas_json_file_into` function, that takes a complete
AAS JSON file, reads its contents and stores the objects in the provided
:class:`~aas.model.provider.AbstractObjectStore`. :meth:`~aas.adapter.json.json_deserialization.read_aas_json_file` is
a wrapper for this function. Instead of storing the objects in a given :class:`~aas.model.provider.AbstractObjectStore`,
it returns a :class:`~aas.model.provider.DictObjectStore` containing parsed objects.
The deserialization is performed in a bottom-up approach: The `object_hook()` method gets called for every parsed JSON
object (as dict) and checks for existence of the `modelType` attribute. If it is present, the `AAS_CLASS_PARSERS` dict
defines, which of the constructor methods of the class is to be used for converting the dict into an object. Embedded
objects that should have a `modelType` themselves are expected to be converted already. Other embedded objects are
converted using a number of helper constructor methods.
"""
......@@ -96,8 +107,12 @@ class AASFromJsonDecoder(json.JSONDecoder):
Custom JSONDecoder class to use the `json` module for deserializing Asset Administration Shell data from the
official JSON format
The class contains a custom `object_hook` function to detect encoded AAS objects within the JSON data and convert
them to PyI40AAS objects while parsing. Typical usage:
The class contains a custom :meth:`~.AASFromJsonDecoder.object_hook` function to detect encoded AAS objects within
the JSON data and convert them to PyI40AAS objects while parsing.
Typical usage:
.. code-block:: python
data = json.loads(json_string, cls=AASFromJsonDecoder)
......@@ -114,6 +129,8 @@ class AASFromJsonDecoder(json.JSONDecoder):
tasks, (nearly) all the constructor methods take a parameter `object_type` defaulting to the normal PyI40AAS object
class, that can be overridden in a derived function:
.. code-block:: python
class EnhancedAsset(model.Asset):
pass
......@@ -122,11 +139,12 @@ class AASFromJsonDecoder(json.JSONDecoder):
def _construct_asset(cls, dct):
return super()._construct_asset(dct, object_class=EnhancedAsset)
:cvar failsafe: If True (the default), don't raise Exceptions for missing attributes and wrong types, but instead
:cvar failsafe: If `True` (the default), don't raise Exceptions for missing attributes and wrong types, but instead
skip defective objects and use logger to output warnings. Use StrictAASFromJsonDecoder for a
non-failsafe version.
:cvar stripped: If True, the JSON objects will be parsed in a stripped manner, excluding some attributes.
Defaults to False.
:cvar stripped: If `True`, the JSON objects will be parsed in a stripped manner, excluding some attributes.
Defaults to `False`.
See https://git.rwth-aachen.de/acplt/pyi40aas/-/issues/91
"""
failsafe = True
......@@ -695,7 +713,7 @@ class StrictAASFromJsonDecoder(AASFromJsonDecoder):
A strict version of the AASFromJsonDecoder class for deserializing Asset Administration Shell data from the
official JSON format
This version has set failsafe = False, which will lead to Exceptions raised for every missing attribute or wrong
This version has set `failsafe = False`, which will lead to Exceptions raised for every missing attribute or wrong
object type.
"""
failsafe = False
......@@ -746,19 +764,20 @@ def read_aas_json_file_into(object_store: model.AbstractObjectStore, file: IO, r
Read an Asset Administration Shell JSON file according to 'Details of the Asset Administration Shell', chapter 5.5
into a given object store.
:param object_store: The object store in which the identifiable objects should be stored
:param object_store: The :class:`ObjectStore <aas.model.provider.AbstractObjectStore>` in which the identifiable
objects should be stored
:param file: A file-like object to read the JSON-serialized data from
:param replace_existing: Whether to replace existing objects with the same identifier in the object store or not
:param ignore_existing: Whether to ignore existing objects (e.g. log a message) or raise an error.
This parameter is ignored if replace_existing is True.
:param failsafe: If true, the document is parsed in a failsafe way: missing attributes and elements are logged
This parameter is ignored if replace_existing is `True`.
:param failsafe: If `True`, the document is parsed in a failsafe way: Missing attributes and elements are logged
instead of causing exceptions. Defect objects are skipped.
This parameter is ignored if a decoder class is specified.
:param stripped: If true, stripped JSON objects are parsed.
:param stripped: If `True`, stripped JSON objects are parsed.
See https://git.rwth-aachen.de/acplt/pyi40aas/-/issues/91
This parameter is ignored if a decoder class is specified.
:param decoder: The decoder class used to decode the JSON objects
:return: A set of identifiers that were added to object_store
:return: A set of :class:`Identifiers <aas.model.base.Identifier>` that were added to object_store
"""
ret: Set[model.Identifier] = set()
decoder_ = _select_decoder(failsafe, stripped, decoder)
......@@ -816,12 +835,13 @@ def read_aas_json_file_into(object_store: model.AbstractObjectStore, file: IO, r
def read_aas_json_file(file: IO, **kwargs) -> model.DictObjectStore[model.Identifiable]:
"""
A wrapper of read_aas_json_file_into(), that reads all objects in an empty DictObjectStore. This function supports
the same keyword arguments as read_aas_json_file_into().
A wrapper of :meth:`~aas.adapter.json.json_deserialization.read_aas_json_file_into`, that reads all objects in an
empty :class:`~aas.model.provider.DictObjectStore`. This function supports the same keyword arguments as
:meth:`~aas.adapter.json.json_deserialization.read_aas_json_file_into`.
:param file: A filename or file-like object to read the JSON-serialized data from
:param kwargs: Keyword arguments passed to read_aas_json_file_into()
:return: A DictObjectStore containing all AAS objects from the JSON file
:param kwargs: Keyword arguments passed to :meth:`~aas.adapter.json.json_deserialization.read_aas_json_file_into`
:return: A :class:`~aas.model.provider.DictObjectStore` containing all AAS objects from the JSON file
"""
object_store: model.DictObjectStore[model.Identifiable] = model.DictObjectStore()
read_aas_json_file_into(object_store, file, **kwargs)
......
......@@ -9,19 +9,26 @@
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
# specific language governing permissions and limitations under the License.
"""
.. _adapter.json.json_serialization:
Module for serializing Asset Administration Shell objects to the official JSON format
The module provides an custom JSONEncoder class `AASToJsonEncoder` to be used with the Python standard `json` module.
It contains a custom `default` function which converts PyI40AAS objects to simple python types for an automatic
JSON serialization. Additionally, there's the `write_aas_json_file()` function, that takes a complete ObjectStore and
writes all contained AAS objects into a JSON file.
This job is performed in an iterative approach: The `default()` function gets called for every object and checks if an
object is an PyI40AAS object. In this case, it calls a special function for the respective PyI40AAS class which converts
the object (but not the contained objects) into a simple Python dict, which is serializable. Any contained
PyI40AAS objects are included into the dict as they are to be converted later on. The special helper function
`abstract_classes_to_json()` is called by most of the conversion functions to handle all the attributes of abstract base
classes.
The module provides an custom JSONEncoder classes :class:`~.AASToJsonEncoder` and :class:`~.AASToJsonEncoderStripped`
to be used with the Python standard `json` module. While the former serializes objects as defined in the specification,
the latter serializes stripped objects, excluding some attributes
(see https://git.rwth-aachen.de/acplt/pyi40aas/-/issues/91).
Each class contains a custom :meth:`~.AASToJsonEncoder.default` function which converts PyI40AAS objects to simple
python types for an automatic JSON serialization.
To simplify the usage of this module, the :meth:`~.write_aas_json_file` and :meth:`~.object_store_to_json` are provided.
The former is used to serialize a given :class:`~aas.model.provider.AbstractObjectStore` to a file, while the latter
serializes the object store to a string and returns it.
The serialization is performed in an iterative approach: The :meth:`~.AASToJsonEncoder.default` function gets called for
every object and checks if an object is an PyI40AAS object. In this case, it calls a special function for the respective
PyI40AAS class which converts the object (but not the contained objects) into a simple Python dict, which is
serializable. Any contained PyI40AAS objects are included into the dict as they are to be converted later on.
The special helper function :meth:`~.AASToJsonEncoder._abstract_classes_to_json` is called by most of the conversion
functions to handle all the attributes of abstract base classes.
"""
import base64
import inspect
......@@ -34,11 +41,15 @@ from .. import _generic
class AASToJsonEncoder(json.JSONEncoder):
"""
Custom JSONDecoder class to use the `json` module for serializing Asset Administration Shell data into the
Custom JSON Encoder class to use the `json` module for serializing Asset Administration Shell data into the
official JSON format
The class overrides the `default()` method to transform PyI40AAS objects into dicts that may be serialized by the
standard encode method. Typical usage:
The class overrides the :meth:`~.AASToJsonEncoder.default` method to transform PyI40AAS objects into dicts that may
be serialized by the standard encode method.
Typical usage:
.. code-block:: python
json_string = json.dumps(data, cls=AASToJsonEncoder)
......@@ -49,6 +60,12 @@ class AASToJsonEncoder(json.JSONEncoder):
stripped = False
def default(self, obj: object) -> object:
"""
The overwritten `default` method for `json.JSONEncoder`
:param obj: The object to serialize to json
:return: The serialized object
"""
if isinstance(obj, model.AssetAdministrationShell):
return self._asset_administration_shell_to_json(obj)
if isinstance(obj, model.Asset):
......@@ -747,13 +764,13 @@ def object_store_to_json(data: model.AbstractObjectStore, stripped: bool = False
Create a json serialization of a set of AAS objects according to 'Details of the Asset Administration Shell',
chapter 5.5
:param data: ObjectStore which contains different objects of the AAS meta model which should be serialized to a
JSON file
:param stripped: If true, objects are serialized to stripped json objects..
:param data: :class:`ObjectStore <aas.model.provider.AbstractObjectStore>` which contains different objects of the
AAS meta model which should be serialized to a JSON file
:param stripped: If true, objects are serialized to stripped json objects.
See https://git.rwth-aachen.de/acplt/pyi40aas/-/issues/91
This parameter is ignored if an encoder class is specified.
:param encoder: The encoder class used to encoder the JSON objects
:param kwargs: Additional keyword arguments to be passed to json.dump()
:param encoder: The encoder class used to encode the JSON objects
:param kwargs: Additional keyword arguments to be passed to `json.dumps()`
"""
encoder_ = _select_encoder(stripped, encoder)
# serialize object to json
......@@ -767,13 +784,13 @@ def write_aas_json_file(file: IO, data: model.AbstractObjectStore, stripped: boo
Administration Shell', chapter 5.5
:param file: A file-like object to write the JSON-serialized data to
:param data: ObjectStore which contains different objects of the AAS meta model which should be serialized to a
JSON file
:param stripped: If true, objects are serialized to stripped json objects..
:param data: :class:`ObjectStore <aas.model.provider.AbstractObjectStore>` which contains different objects of the
AAS meta model which should be serialized to a JSON file
:param stripped: If `True`, objects are serialized to stripped json objects.
See https://git.rwth-aachen.de/acplt/pyi40aas/-/issues/91
This parameter is ignored if an encoder class is specified.
:param encoder: The encoder class used to encoder the JSON objects
:param kwargs: Additional keyword arguments to be passed to json.dumps()
:param encoder: The encoder class used to encode the JSON objects
:param kwargs: Additional keyword arguments to be passed to `json.dump()`
"""
encoder_ = _select_encoder(stripped, encoder)
# serialize object to json
......
"""
.. _adapter.xml.__init__:
This package contains functionality for serialization and deserialization of PyI40AAS objects into/from XML.
xml_serialization:
The module offers a function to write an ObjectStore to a given file.
:ref:`xml_serialization <adapter.xml.xml_serialization>`: The module offers a function to write an
:class:`ObjectStore <aas.model.provider.AbstractObjectStore>` to a given file.
xml_deserialization.py
The module offers a function to create an ObjectStore from a given xml document.
:ref:`xml_deserialization <adapter.xml.xml_deserialization>`: The module offers a function to create an
:class:`ObjectStore <aas.model.provider.AbstractObjectStore>` from a given xml document.
"""
import os.path
......
......@@ -9,12 +9,18 @@
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
# specific language governing permissions and limitations under the License.
"""
.. _adapter.xml.xml_deserialization:
Module for deserializing Asset Administration Shell data from the official XML format
This module provides the following functions for parsing XML documents:
- read_aas_xml_element() constructs a single object from an XML document containing a single element
- read_aas_xml_file_into() constructs all elements of an XML document and stores them in a given object store
- read_aas_xml_file() constructs all elements of an XML document and returns them in a DictObjectStore
- :meth:`~aas.adapter.xml.xml_deserialization.read_aas_xml_element` constructs a single object from an XML document
containing a single element
- :meth:`~aas.adapter.xml.xml_deserialization.read_aas_xml_file_into` constructs all elements of an XML document and
stores them in a given :class:`ObjectStore <aas.model.provider.AbstractObjectStore>`
- :meth:`~aas.adapter.xml.xml_deserialization.read_aas_xml_file` constructs all elements of an XML document and returns
them in a :class:`~aas.model.provider.DictObjectStore`
These functions take a decoder class as keyword argument, which allows parsing in failsafe (default) or non-failsafe
mode. Parsing stripped elements - used in the HTTP adapter - is also possible. It is also possible to subclass the
......@@ -22,13 +28,16 @@ default decoder class and provide an own decoder.
In failsafe mode errors regarding missing attributes and elements or invalid values are caught and logged.
In non-failsafe mode any error would abort parsing.
Error handling is done only by _failsafe_construct() in this module. Nearly all constructor functions are called
by other constructor functions via _failsafe_construct(), so an error chain is constructed in the error case,
Error handling is done only by `_failsafe_construct()` in this module. Nearly all constructor functions are called
by other constructor functions via `_failsafe_construct()`, so an error chain is constructed in the error case,
which allows printing stacktrace-like error messages like the following in the error case (in failsafe mode of course):
KeyError: aas:identification on line 252 has no attribute with name idType!
-> Failed to construct aas:identification on line 252 using construct_identifier!
-> Failed to construct aas:conceptDescription on line 247 using construct_concept_description!
.. code-block:: python