From 81a1f8afa8a861042bb7c50fb7973722be22afde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leon=20M=C3=B6ller?= Date: Sat, 23 Dec 2023 01:28:28 +0100 Subject: [PATCH] massive docstring overhaul This fixes missing references, improves the layout, removes outdated information in some places, and more. --- basyx/aas/adapter/aasx.py | 100 +++---- basyx/aas/adapter/json/__init__.py | 17 +- .../aas/adapter/json/json_deserialization.py | 90 +++--- basyx/aas/adapter/json/json_serialization.py | 43 +-- basyx/aas/adapter/xml/__init__.py | 4 +- basyx/aas/adapter/xml/xml_deserialization.py | 41 ++- basyx/aas/adapter/xml/xml_serialization.py | 216 +++++++------- basyx/aas/backend/backends.py | 78 ++--- basyx/aas/backend/couchdb.py | 43 +-- basyx/aas/backend/local_file.py | 4 +- .../compliance_tool/compliance_check_aasx.py | 35 +-- .../compliance_tool/compliance_check_json.py | 42 +-- .../compliance_tool/compliance_check_xml.py | 44 ++- basyx/aas/compliance_tool/state_manager.py | 43 +-- basyx/aas/examples/data/_helper.py | 23 +- basyx/aas/examples/data/example_aas.py | 4 +- .../data/example_aas_mandatory_attributes.py | 12 +- .../data/example_submodel_template.py | 4 +- basyx/aas/examples/tutorial_aasx.py | 6 +- basyx/aas/model/__init__.py | 23 +- basyx/aas/model/_string_constraints.py | 43 +-- basyx/aas/model/aas.py | 30 +- basyx/aas/model/base.py | 276 ++++++++++-------- basyx/aas/model/concept.py | 9 +- basyx/aas/model/datatypes.py | 10 +- basyx/aas/model/provider.py | 6 +- basyx/aas/model/submodel.py | 89 +++--- basyx/aas/util/__init__.py | 4 +- basyx/aas/util/identification.py | 2 +- docs/source/model/index.rst | 7 +- test/_helper/setup_testdb.py | 6 +- 31 files changed, 678 insertions(+), 676 deletions(-) diff --git a/basyx/aas/adapter/aasx.py b/basyx/aas/adapter/aasx.py index 1f69046b7..37eee7b88 100644 --- a/basyx/aas/adapter/aasx.py +++ b/basyx/aas/adapter/aasx.py @@ -10,13 +10,13 @@ Functionality for reading and writing AASX files according to "Details of the Asset Administration Shell Part 1 V2.0", section 7. -The AASX file format is built upon the Open Packaging Conventions (OPC; ECMA 376-2). We use the `pyecma376_2` library +The AASX file format is built upon the Open Packaging Conventions (OPC; ECMA 376-2). We use the ``pyecma376_2`` library 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 :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 `. +included AAS objects into/form :class:`ObjectStores `. For handling of embedded supplementary files, this module provides the :class:`~.AbstractSupplementaryFileContainer` class interface and the :class:`~.DictSupplementaryFileContainer` implementation. @@ -64,7 +64,7 @@ def __init__(self, file: Union[os.PathLike, str, IO]): """ Open an AASX reader for the given filename or file handle - The given file is opened as OPC ZIP package. Make sure to call `AASXReader.close()` after reading the file + The given file is opened as OPC ZIP package. Make sure to call ``AASXReader.close()`` after reading the file contents to close the underlying ZIP file reader. You may also use the AASXReader as a context manager to ensure closing under any circumstances. @@ -92,7 +92,7 @@ def get_thumbnail(self) -> Optional[bytes]: Retrieve the packages thumbnail image 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`: + for further processing or conversion, e.g. ``pillow``: .. code-block:: python @@ -115,21 +115,21 @@ def read_into(self, object_store: model.AbstractObjectStore, override_existing: bool = False, **kwargs) -> Set[model.Identifier]: """ Read the contents of the AASX package and add them into a given - :class:`ObjectStore ` + :class:`ObjectStore ` 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 :class:`Submodels ` + ``object_store``. While doing so, it searches all parsed :class:`Submodels ` for :class:`~basyx.aas.model.submodel.File` objects to extract the supplementary files. The referenced - supplementary files are added to the given `file_store` and the :class:`~basyx.aas.model.submodel.File` + supplementary files are added to the given ``file_store`` and the :class:`~basyx.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. + file within the ``file_store`` later. - :param object_store: An :class:`ObjectStore ` to add the AAS objects - from the AASX file to + :param object_store: An :class:`ObjectStore ` 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 + :param override_existing: If ``True``, existing objects in the object store are overridden with objects from the AASX that have the same :class:`~basyx.aas.model.base.Identifier`. Default behavior is to skip those objects from the AASX. :return: A set of the :class:`Identifiers ` of all @@ -178,8 +178,8 @@ def _read_aas_part_into(self, part_name: str, """ Helper function for :meth:`read_into()` to read and process the contents of an AAS-spec part of the AASX file. - This method primarily checks for duplicate objects. It uses `_parse_aas_parse()` to do the actual parsing and - `_collect_supplementary_files()` for supplementary file processing of non-duplicate objects. + This method primarily checks for duplicate objects. It uses ``_parse_aas_parse()`` to do the actual parsing and + ``_collect_supplementary_files()`` for supplementary file processing of non-duplicate objects. :param part_name: The OPC part name to read :param object_store: An ObjectStore to add the AAS objects from the AASX file to @@ -292,7 +292,7 @@ def __init__(self, file: Union[os.PathLike, str, IO]): """ Create a new AASX package in the given file and open the AASXWriter to add contents to the package. - Make sure to call `AASXWriter.close()` after writing all contents to write the aas-spec relationships for all + Make sure to call ``AASXWriter.close()`` after writing all contents to write the aas-spec relationships for all AAS parts to the file and close the underlying ZIP file writer. You may also use the AASXWriter as a context manager to ensure closing under any circumstances. @@ -325,38 +325,38 @@ def write_aas(self, :class:`AssetAdministrationShells ` with all included and referenced objects to the AASX package according to the part name conventions from DotAAS. - This method takes the AASs' :class:`Identifiers ` (as `aas_ids`) to retrieve - the AASs from the given object_store. + This method takes the AASs' :class:`Identifiers ` (as ``aas_ids``) to retrieve + the AASs from the given ``object_store``. :class:`References ` to :class:`Submodels ` and :class:`ConceptDescriptions ` (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 + 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 :class:`~basyx.aas.model.submodel.File` object in any of the :class:`Submodels ` are also added to the AASX package. - This method uses `write_all_aas_objects()` to write the AASX part. + This method uses :meth:`write_all_aas_objects` to write the AASX part. .. 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 + 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 problems when reading the package. 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. + a list of AAS Identifiers to the ``aas_ids`` parameter. :param aas_ids: :class:`~basyx.aas.model.base.Identifier` or Iterable of :class:`Identifiers ` of the AAS(s) to be written to the AASX file - :param object_store: :class:`ObjectStore ` to retrieve the + :param object_store: :class:`ObjectStore ` to retrieve the :class:`~basyx.aas.model.base.Identifiable` AAS objects (:class:`~basyx.aas.model.aas.AssetAdministrationShell`, :class:`~basyx.aas.model.concept.ConceptDescription` and :class:`~basyx.aas.model.submodel.Submodel`) from - :param file_store: :class:`SupplementaryFileContainer <~.AbstractSupplementaryFileContainer>` to retrieve + :param file_store: :class:`SupplementaryFileContainer ` to retrieve supplementary files from, which are referenced by :class:`~basyx.aas.model.submodel.File` objects - :param write_json: If `True`, JSON parts are created for the AAS and each + :param write_json: If ``True``, JSON parts are created for the AAS and each :class:`~basyx.aas.model.submodel.Submodel` in the AASX package file instead of XML parts. - Defaults to `False`. + Defaults to ``False``. :raises KeyError: If one of the AAS could not be retrieved from the object store (unresolvable :class:`Submodels ` and :class:`ConceptDescriptions ` are skipped, logging a @@ -428,29 +428,31 @@ def write_aas_objects(self, """ A thin wrapper around :meth:`write_all_aas_objects` to ensure downwards compatibility - This method takes the AAS's :class:`~basyx.aas.model.base.Identifier` (as `aas_id`) to retrieve it - from the given object_store. If the list of written objects includes :class:`aas.model.submodel.Submodel` + This method takes the AAS's :class:`~basyx.aas.model.base.Identifier` (as ``aas_id``) to retrieve it + from the given object_store. If the list of written objects includes :class:`~basyx.aas.model.submodel.Submodel` objects, Supplementary files which are referenced by :class:`~basyx.aas.model.submodel.File` objects within those submodels, are also added to the AASX package. .. attention:: - You must make sure to call this method or `write_all_aas_objects` only once per unique `part_name` on a - single package instance. + You must make sure to call this method or :meth:`write_all_aas_objects` only once per unique ``part_name`` + on a single package instance. :param part_name: Name of the Part within the AASX package to write the files to. Must be a valid ECMA376-2 part name and unique within the package. The extension of the part should match the data format (i.e. - '.json' if `write_json` else '.xml'). + '.json' if ``write_json`` else '.xml'). :param object_ids: A list of :class:`Identifiers ` of the objects to be written to the AASX package. Only these :class:`~basyx.aas.model.base.Identifiable` objects (and included :class:`~basyx.aas.model.base.Referable` objects) are written to the package. :param object_store: The objects store to retrieve the :class:`~basyx.aas.model.base.Identifiable` objects from - :param file_store: The :class:`SupplementaryFileContainer ` + :param file_store: The + :class:`SupplementaryFileContainer ` to retrieve supplementary files from (if there are any :class:`~basyx.aas.model.submodel.File` objects within the written objects. - :param write_json: If `True`, the part is written as a JSON file instead of an XML file. Defaults to `False`. - :param split_part: If `True`, no aas-spec relationship is added from the aasx-origin to this part. You must make - sure to reference it via a aas-spec-split relationship from another aas-spec part + :param write_json: If ``True``, the part is written as a JSON file instead of an XML file. Defaults to + ``False``. + :param split_part: If ``True``, no aas-spec relationship is added from the aasx-origin to this part. You must + make sure to reference it via a aas-spec-split relationship from another aas-spec part :param additional_relationships: Optional OPC/ECMA376 relationships which should originate at the AAS object part to be written, in addition to the aas-suppl relationships which are created automatically. """ @@ -479,26 +481,26 @@ def write_all_aas_objects(self, split_part: bool = False, additional_relationships: Iterable[pyecma376_2.OPCRelationship] = ()) -> None: """ - Write all AAS objects in a given :class:`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 ` to an XML + or JSON part in the AASX package and add the referenced supplementary files to the package. - This method takes an :class:`ObjectStore ` 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:`~basyx.aas.model.submodel.File` objects - within those Submodels, are fetched from the `file_store` and added to the AASX package. + This method takes an :class:`ObjectStore ` and writes all + contained objects into an ``aas_env`` part in the AASX package. If the ObjectStore includes + :class:`~basyx.aas.model.submodel.Submodel` objects, supplementary files which are referenced by + :class:`~basyx.aas.model.submodel.File` objects within those Submodels, are fetched from the ``file_store`` + and added to the AASX package. .. attention:: - You must make sure to call this method only once per unique `part_name` on a single package instance. + You must make sure to call this method only once per unique ``part_name`` on a single package instance. :param part_name: Name of the Part within the AASX package to write the files to. Must be a valid ECMA376-2 part name and unique within the package. The extension of the part should match the data format (i.e. - '.json' if `write_json` else '.xml'). + '.json' if ``write_json`` else '.xml'). :param objects: The objects to be written to the AASX package. Only these Identifiable objects (and included Referable objects) are written to the package. - :param file_store: The SupplementaryFileContainer to retrieve supplementary files from (if there are any `File` - objects within the written objects. + :param file_store: The SupplementaryFileContainer to retrieve supplementary files from (if there are any + ``File`` objects within the written objects. :param write_json: If True, the part is written as a JSON file instead of an XML file. Defaults to False. :param split_part: If True, no aas-spec relationship is added from the aasx-origin to this part. You must make sure to reference it via a aas-spec-split relationship from another aas-spec part @@ -616,7 +618,7 @@ def _write_aasx_origin_relationships(self): """ Helper function to write aas-spec relationships of the aasx-origin part. - This method uses the list of aas-spec parts in `_aas_part_names`. It should be called just before closing the + This method uses the list of aas-spec parts in ``_aas_part_names``. It should be called just before closing the file to make sure all aas-spec parts of the package have already been written. """ # Add relationships from AASX-origin part to AAS parts @@ -731,8 +733,8 @@ def add_file(self, name: str, file: IO[bytes], content_type: str) -> str: :param name: The file's proposed name. Should start with a '/'. Should not contain URI-encoded '/' or '\' :param file: A binary file-like opened for reading the file contents :param content_type: The file's content_type - :return: The file name as stored in the SupplementaryFileContainer. Typically `name` or a modified version of - `name` to resolve conflicts. + :return: The file name as stored in the SupplementaryFileContainer. Typically ``name`` or a modified version of + ``name`` to resolve conflicts. """ pass # pragma: no cover diff --git a/basyx/aas/adapter/json/__init__.py b/basyx/aas/adapter/json/__init__.py index d469468aa..740b0fbf4 100644 --- a/basyx/aas/adapter/json/__init__.py +++ b/basyx/aas/adapter/json/__init__.py @@ -4,16 +4,17 @@ This package contains functionality for serialization and deserialization of BaSyx Python SDK objects into/from JSON. :ref:`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 BaSyx Python SDK objects and their attributes by converting them into standard python -objects. +given file and therefore defines the custom JSONEncoder +:class:`~basyx.aas.adapter.json.json_serialization.AASToJsonEncoder` which handles encoding of all BaSyx Python SDK +objects and their attributes by converting them into standard python objects. :ref:`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 BaSyx Python SDK 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 BaSyx Python SDK objectstore. +:class:`~basyx.aas.adapter.json.json_deserialization.AASFromJsonDecoder` and +:class:`~basyx.aas.adapter.json.json_deserialization.StrictAASFromJsonDecoder`, that — when used with Python's +:mod:`json` module — detect AAS objects in the parsed JSON and convert them into the corresponding BaSyx Python SDK +object. A function :meth:`~basyx.aas.adapter.json.json_deserialization.read_aas_json_file` is provided to read all +AAS objects within a JSON file and return them as BaSyx Python SDK +:class:`ObjectStore `. """ import os.path diff --git a/basyx/aas/adapter/json/json_deserialization.py b/basyx/aas/adapter/json/json_deserialization.py index 436a6e567..1e3aecbd1 100644 --- a/basyx/aas/adapter/json/json_deserialization.py +++ b/basyx/aas/adapter/json/json_deserialization.py @@ -10,24 +10,24 @@ Module for deserializing Asset Administration Shell data from the official JSON format 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 BaSyx Python SDK 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`, +be used with the Python standard :mod:`json` module. + +Furthermore it provides two classes :class:`~basyx.aas.adapter.json.json_deserialization.StrippedAASFromJsonDecoder` and +:class:`~basyx.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:`~basyx.aas.adapter.json.json_deserialization.AASFromJsonDecoder.object_hook` +function to detect encoded AAS objects within the JSON data and convert them to BaSyx Python SDK objects while parsing. +Additionally, there's the :meth:`~basyx.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:`~basyx.aas.model.provider.AbstractObjectStore`. :meth:`read_aas_json_file` is a wrapper for this function. +Instead of storing the objects in a given :class:`~basyx.aas.model.provider.AbstractObjectStore`, it returns a :class:`~basyx.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. +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. """ import base64 import json @@ -101,7 +101,7 @@ def _expect_type(object_: object, type_: Type, context: str, failsafe: bool) -> class AASFromJsonDecoder(json.JSONDecoder): """ - Custom JSONDecoder class to use the `json` module for deserializing Asset Administration Shell data from the + Custom JSONDecoder class to use the :mod:`json` module for deserializing Asset Administration Shell data from the official JSON format The class contains a custom :meth:`~.AASFromJsonDecoder.object_hook` function to detect encoded AAS objects within @@ -113,17 +113,17 @@ class AASFromJsonDecoder(json.JSONDecoder): data = json.loads(json_string, cls=AASFromJsonDecoder) - The `object_hook` function uses a set of `_construct_*()` methods, one for each + The ``object_hook`` function uses a set of ``_construct_*()`` methods, one for each AAS object type to transform the JSON objects in to BaSyx Python SDK objects. These constructor methods are divided - into two parts: "Helper Constructor Methods", that are used to construct AAS object types without a `modelType` + into two parts: "Helper Constructor Methods", that are used to construct AAS object types without a ``modelType`` attribute as embedded objects within other AAS objects, and "Direct Constructor Methods" for AAS object types *with* - `modelType` attribute. The former are called from other constructor methods or utility methods based on the expected - type of an attribute, the latter are called directly from the `object_hook()` function based on the `modelType` - attribute. + ``modelType`` attribute. The former are called from other constructor methods or utility methods based on the + expected type of an attribute, the latter are called directly from the ``object_hook()`` function based on the + ``modelType`` attribute. This class may be subclassed to override some of the constructor functions, e.g. to construct objects of specialized - subclasses of the BaSyx Python SDK object classes instead of these normal classes from the `model` package. To - simplify this tasks, (nearly) all the constructor methods take a parameter `object_type` defaulting to the normal + subclasses of the BaSyx Python SDK object classes instead of these normal classes from the ``model`` package. To + simplify this tasks, (nearly) all the constructor methods take a parameter ``object_type`` defaulting to the normal BaSyx Python SDK object class, that can be overridden in a derived function: .. code-block:: python @@ -139,11 +139,11 @@ def _construct_submodel(cls, dct, object_class=EnhancedSubmodel): return super()._construct_submodel(dct, object_class=object_class) - :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 + :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 @@ -160,10 +160,10 @@ def object_hook(cls, dct: Dict[str, object]) -> object: return dct # The following dict specifies a constructor method for all AAS classes that may be identified using the - # `modelType` attribute in their JSON representation. Each of those constructor functions takes the JSON + # ``modelType`` attribute in their JSON representation. Each of those constructor functions takes the JSON # representation of an object and tries to construct a Python object from it. Embedded objects that have a # modelType themselves are expected to be converted to the correct PythonType already. Additionally, each - # function takes a bool parameter `failsafe`, which indicates weather to log errors and skip defective objects + # function takes a bool parameter ``failsafe``, which indicates weather to log errors and skip defective objects # instead of raising an Exception. AAS_CLASS_PARSERS: Dict[str, Callable[[Dict[str, object]], object]] = { 'AssetAdministrationShell': cls._construct_asset_administration_shell, @@ -281,7 +281,7 @@ def _get_kind(cls, dct: Dict[str, object]) -> model.ModellingKind: Utility method to get the kind of an HasKind object from its JSON representation. :param dct: The object's dict representation from JSON - :return: The object's `kind` value + :return: The object's ``kind`` value """ return MODELLING_KIND_INVERSE[_get_ts(dct, "kind", str)] if 'kind' in dct else model.ModellingKind.INSTANCE @@ -366,8 +366,8 @@ def _construct_administrative_information( @classmethod def _construct_operation_variable(cls, dct: Dict[str, object]) -> model.SubmodelElement: """ - Since we don't implement `OperationVariable`, this constructor discards the wrapping `OperationVariable` object - and just returns the contained :class:`~basyx.aas.model.submodel.SubmodelElement`. + Since we don't implement ``OperationVariable``, this constructor discards the wrapping ``OperationVariable`` + object and just returns the contained :class:`~basyx.aas.model.submodel.SubmodelElement`. """ # TODO: remove the following type: ignore comments when mypy supports abstract types for Type[T] # see https://github.com/python/mypy/issues/5374 @@ -750,7 +750,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 @@ -776,8 +776,8 @@ def _select_decoder(failsafe: bool, stripped: bool, decoder: Optional[Type[AASFr Returns the correct decoder based on the parameters failsafe and stripped. If a decoder class is given, failsafe and stripped are ignored. - :param failsafe: If `True`, a failsafe decoder is selected. Ignored if a decoder class is specified. - :param stripped: If `True`, a decoder for parsing stripped JSON objects is selected. Ignored if a decoder class is + :param failsafe: If ``True``, a failsafe decoder is selected. Ignored if a decoder class is specified. + :param stripped: If ``True``, a decoder for parsing stripped JSON objects is selected. Ignored if a decoder class is specified. :param decoder: Is returned, if specified. :return: An :class:`~.AASFromJsonDecoder` (sub)class. @@ -801,16 +801,16 @@ 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 :class:`ObjectStore ` in which the identifiable - objects should be stored + :param object_store: The :class:`ObjectStore ` 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 @@ -866,12 +866,12 @@ 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 :meth:`~aas.adapter.json.json_deserialization.read_aas_json_file_into`, that reads all objects in an - empty :class:`~basyx.aas.model.provider.DictObjectStore`. This function supports the same keyword arguments as - :meth:`~aas.adapter.json.json_deserialization.read_aas_json_file_into`. + A wrapper of :meth:`~basyx.aas.adapter.json.json_deserialization.read_aas_json_file_into`, that reads all objects + in an empty :class:`~basyx.aas.model.provider.DictObjectStore`. This function supports the same keyword arguments as + :meth:`~basyx.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 :meth:`~aas.adapter.json.json_deserialization.read_aas_json_file_into` + :param kwargs: Keyword arguments passed to :meth:`read_aas_json_file_into` :return: A :class:`~basyx.aas.model.provider.DictObjectStore` containing all AAS objects from the JSON file """ object_store: model.DictObjectStore[model.Identifiable] = model.DictObjectStore() diff --git a/basyx/aas/adapter/json/json_serialization.py b/basyx/aas/adapter/json/json_serialization.py index 09dace4aa..2faadb82b 100644 --- a/basyx/aas/adapter/json/json_serialization.py +++ b/basyx/aas/adapter/json/json_serialization.py @@ -9,21 +9,21 @@ Module for serializing Asset Administration Shell objects to the official JSON format -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 +The module provides an custom JSONEncoder classes :class:`AASToJsonEncoder` and :class:`StrippedAASToJsonEncoder` +to be used with the Python standard :mod:`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 BaSyx Python SDK 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. +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:`~basyx.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 BaSyx Python SDK object. In this case, it calls a special function for the respective BaSyx Python SDK class which converts the object (but not the contained objects) into a simple Python dict, which is serializable. Any contained BaSyx Python SDK 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 +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. """ import base64 @@ -37,10 +37,10 @@ class AASToJsonEncoder(json.JSONEncoder): """ - Custom JSON Encoder class to use the `json` module for serializing Asset Administration Shell data into the + Custom JSON Encoder class to use the :mod:`json` module for serializing Asset Administration Shell data into the official JSON format - The class overrides the `default()` method to transform BaSyx Python SDK objects into dicts that may be serialized + The class overrides the ``default()`` method to transform BaSyx Python SDK objects into dicts that may be serialized by the standard encode method. Typical usage: @@ -50,14 +50,14 @@ class AASToJsonEncoder(json.JSONEncoder): json_string = json.dumps(data, cls=AASToJsonEncoder) :cvar stripped: If True, the JSON objects will be serialized in a stripped manner, excluding some attributes. - Defaults to `False`. + Defaults to ``False``. See https://git.rwth-aachen.de/acplt/pyi40aas/-/issues/91 """ stripped = False def default(self, obj: object) -> object: """ - The overwritten `default` method for `json.JSONEncoder` + The overwritten ``default`` method for :class:`json.JSONEncoder` :param obj: The object to serialize to json :return: The serialized object @@ -578,12 +578,13 @@ def _annotated_relationship_element_to_json(cls, obj: model.AnnotatedRelationshi def _operation_variable_to_json(cls, obj: model.SubmodelElement) -> Dict[str, object]: """ serialization of an object from class SubmodelElement to a json OperationVariable representation - Since we don't implement the `OperationVariable` class, which is just a wrapper for a single - :class:`~basyx.aas.model.submodel.SubmodelElement`, elements are serialized as the `value` attribute of an - `operationVariable` object. + Since we don't implement the ``OperationVariable`` class, which is just a wrapper for a single + :class:`~basyx.aas.model.submodel.SubmodelElement`, elements are serialized as the ``value`` attribute of an + ``operationVariable`` object. - :param obj: object of class `SubmodelElement` - :return: `OperationVariable` wrapper containing the serialized `SubmodelElement` + :param obj: object of class :class:`~basyx.aas.model.submodel.SubmodelElement` + :return: ``OperationVariable`` wrapper containing the serialized + :class:`~basyx.aas.model.submodel.SubmodelElement` """ return {'value': obj} @@ -718,13 +719,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: :class:`ObjectStore ` which contains different objects of the - AAS meta model which should be serialized to a JSON file + :param data: :class:`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. 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 encode the JSON objects - :param kwargs: Additional keyword arguments to be passed to `json.dumps()` + :param kwargs: Additional keyword arguments to be passed to :func:`json.dumps` """ encoder_ = _select_encoder(stripped, encoder) # serialize object to json @@ -738,8 +739,8 @@ 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: :class:`ObjectStore ` which contains different objects of the - AAS meta model which should be serialized to a JSON file + :param data: :class:`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. See https://git.rwth-aachen.de/acplt/pyi40aas/-/issues/91 This parameter is ignored if an encoder class is specified. diff --git a/basyx/aas/adapter/xml/__init__.py b/basyx/aas/adapter/xml/__init__.py index 43e333cb6..714c80663 100644 --- a/basyx/aas/adapter/xml/__init__.py +++ b/basyx/aas/adapter/xml/__init__.py @@ -4,10 +4,10 @@ This package contains functionality for serialization and deserialization of BaSyx Python SDK objects into/from XML. :ref:`xml_serialization `: The module offers a function to write an -:class:`ObjectStore ` to a given file. +:class:`ObjectStore ` to a given file. :ref:`xml_deserialization `: The module offers a function to create an -:class:`ObjectStore ` from a given xml document. +:class:`ObjectStore ` from a given xml document. """ import os.path diff --git a/basyx/aas/adapter/xml/xml_deserialization.py b/basyx/aas/adapter/xml/xml_deserialization.py index fa78706fe..31b5012fb 100644 --- a/basyx/aas/adapter/xml/xml_deserialization.py +++ b/basyx/aas/adapter/xml/xml_deserialization.py @@ -11,12 +11,11 @@ This module provides the following functions for parsing XML documents: -- :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 ` -- :meth:`~aas.adapter.xml.xml_deserialization.read_aas_xml_file` constructs all elements of an XML document and returns - them in a :class:`~basyx.aas.model.provider.DictObjectStore` +- :func:`read_aas_xml_element` constructs a single object from an XML document containing a single element +- :func:`read_aas_xml_file_into` constructs all elements of an XML document and stores them in a given + :class:`ObjectStore ` +- :func:`read_aas_xml_file` constructs all elements of an XML document and returns them in a + :class:`~basyx.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 @@ -24,8 +23,8 @@ 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): @@ -65,13 +64,13 @@ def _str_to_bool(string: str) -> bool: """ - XML only allows "false" and "true" (case-sensitive) as valid values for a boolean. + XML only allows ``false`` and ``true`` (case-sensitive) as valid values for a boolean. - This function checks the string and raises a ValueError if the string is neither "true" nor "false". + This function checks the string and raises a ValueError if the string is neither ``true`` nor ``false``. - :param string: String representation of a boolean. ("true" or "false") + :param string: String representation of a boolean. (``true`` or ``false``) :return: The respective boolean value. - :raises ValueError: If string is neither "true" nor "false". + :raises ValueError: If string is neither ``true`` nor ``false``. """ if string not in ("true", "false"): raise ValueError(f"{string} is not a valid boolean! Only true and false are allowed.") @@ -424,7 +423,7 @@ class AASFromXmlDecoder: It parses XML documents in a failsafe manner, meaning any errors encountered will be logged and invalid XML elements will be skipped. - Most member functions support the `object_class` parameter. It was introduced so they can be overwritten + Most member functions support the ``object_class`` parameter. It was introduced so they can be overwritten in subclasses, which allows constructing instances of subtypes. """ failsafe = True @@ -542,7 +541,7 @@ def _construct_referable_reference(cls, element: etree.Element, **kwargs: Any) \ @classmethod def _construct_operation_variable(cls, element: etree.Element, **kwargs: Any) -> model.SubmodelElement: """ - Since we don't implement `OperationVariable`, this constructor discards the wrapping `aas:operationVariable` + Since we don't implement ``OperationVariable``, this constructor discards the wrapping `aas:operationVariable` and `aas:value` and just returns the contained :class:`~basyx.aas.model.submodel.SubmodelElement`. """ value = _get_child_mandatory(element, NS_AAS + "value") @@ -1404,18 +1403,18 @@ def read_aas_xml_file_into(object_store: model.AbstractObjectStore[model.Identif **parser_kwargs: Any) -> Set[model.Identifier]: """ Read an Asset Administration Shell XML file according to 'Details of the Asset Administration Shell', chapter 5.4 - into a given :class:`ObjectStore `. + into a given :class:`ObjectStore `. - :param object_store: The :class:`ObjectStore ` in which the + :param object_store: The :class:`ObjectStore ` in which the :class:`~basyx.aas.model.base.Identifiable` objects should be stored :param file: A filename or file-like object to read the XML-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 + :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 XML elements are parsed. + :param stripped: If ``True``, stripped XML elements 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 XML elements @@ -1473,12 +1472,12 @@ def read_aas_xml_file_into(object_store: model.AbstractObjectStore[model.Identif def read_aas_xml_file(file: IO, **kwargs: Any) -> model.DictObjectStore[model.Identifiable]: """ - A wrapper of :meth:`~aas.adapter.xml.xml_deserialization.read_aas_xml_file_into`, that reads all objects in an + A wrapper of :meth:`~basyx.aas.adapter.xml.xml_deserialization.read_aas_xml_file_into`, that reads all objects in an empty :class:`~basyx.aas.model.provider.DictObjectStore`. This function supports - the same keyword arguments as :meth:`~aas.adapter.xml.xml_deserialization.read_aas_xml_file_into`. + the same keyword arguments as :meth:`~basyx.aas.adapter.xml.xml_deserialization.read_aas_xml_file_into`. :param file: A filename or file-like object to read the XML-serialized data from - :param kwargs: Keyword arguments passed to :meth:`~aas.adapter.xml.xml_deserialization.read_aas_xml_file_into` + :param kwargs: Keyword arguments passed to :meth:`~basyx.aas.adapter.xml.xml_deserialization.read_aas_xml_file_into` :return: A :class:`~basyx.aas.model.provider.DictObjectStore` containing all AAS objects from the XML file """ object_store: model.DictObjectStore[model.Identifiable] = model.DictObjectStore() diff --git a/basyx/aas/adapter/xml/xml_serialization.py b/basyx/aas/adapter/xml/xml_serialization.py index 0376b6290..c6eb2be1c 100644 --- a/basyx/aas/adapter/xml/xml_serialization.py +++ b/basyx/aas/adapter/xml/xml_serialization.py @@ -11,11 +11,11 @@ How to use: -- For generating an XML-File from a :class:`~aas.model.provider.AbstractObjectStore`, check out the function - :meth:`~aas.adapter.xml.xml_serialization.write_aas_xml_file`. +- For generating an XML-File from a :class:`~basyx.aas.model.provider.AbstractObjectStore`, check out the function + :func:`write_aas_xml_file`. - For serializing any object to an XML fragment, that fits the XML specification from 'Details of the - Asset Administration Shell', chapter 5.4, check out `_to_xml()`. These functions return - an :class:`xml.etree.ElementTree.Element` object to be serialized into XML. + Asset Administration Shell', chapter 5.4, check out ``_to_xml()``. These functions return + an :class:`~lxml.etree.Element` object to be serialized into XML. """ from lxml import etree # type: ignore @@ -36,12 +36,12 @@ def _generate_element(name: str, text: Optional[str] = None, attributes: Optional[Dict] = None) -> etree.Element: """ - generate an ElementTree.Element object + generate an :class:`~lxml.etree.Element` object :param name: namespace+tag_name of the element :param text: Text of the element. Default is None - :param attributes: Attributes of the elements in form of a dict {"attribute_name": "attribute_content"} - :return: ElementTree.Element object + :param attributes: Attributes of the elements in form of a dict ``{"attribute_name": "attribute_content"}`` + :return: :class:`~lxml.etree.Element` object """ et_element = etree.Element(name) if text: @@ -56,8 +56,8 @@ def boolean_to_xml(obj: bool) -> str: """ Serialize a boolean to XML - :param obj: Boolean (`True`, `False`) - :return: String in the XML accepted form (`'true'`, `'false'`) + :param obj: Boolean (``True``, ``False``) + :return: String in the XML accepted form (``true``, ``false``) """ if obj: return "true" @@ -72,7 +72,7 @@ def boolean_to_xml(obj: bool) -> str: def abstract_classes_to_xml(tag: str, obj: object) -> etree.Element: """ - Generates an XML element and adds attributes of abstract base classes of `obj`. + Generates an XML element and adds attributes of abstract base classes of ``obj``. If the object obj is inheriting from any abstract AAS class, this function adds all the serialized information of those abstract classes to the generated element. @@ -140,12 +140,12 @@ def _value_to_xml(value: model.ValueDataType, value_type: model.DataTypeDefXsd, tag: str = NS_AAS+"value") -> etree.Element: """ - Serialization of objects of class ValueDataType to XML + Serialization of objects of :class:`~basyx.aas.model.base.ValueDataType` to XML - :param value: model.ValueDataType object - :param value_type: Corresponding model.DataTypeDefXsd - :param tag: tag of the serialized ValueDataType object - :return: Serialized ElementTree.Element object + :param value: :class:`~basyx.aas.model.base.ValueDataType` object + :param value_type: Corresponding :class:`~basyx.aas.model.base.DataTypeDefXsd` + :param tag: tag of the serialized :class:`~basyx.aas.model.base.ValueDataType` object + :return: Serialized :class:`~lxml.etree.Element` object """ # todo: add "{NS_XSI+"type": "xs:"+model.datatypes.XSD_TYPE_NAMES[value_type]}" as attribute, if the schema allows # it @@ -156,11 +156,11 @@ def _value_to_xml(value: model.ValueDataType, def lang_string_set_to_xml(obj: model.LangStringSet, tag: str) -> etree.Element: """ - Serialization of objects of class :class:`~aas.model.base.LangStringSet` to XML + Serialization of objects of class :class:`~basyx.aas.model.base.LangStringSet` to XML - :param obj: Object of class :class:`~aas.model.base.LangStringSet` + :param obj: Object of class :class:`~basyx.aas.model.base.LangStringSet` :param tag: Namespace+Tag name of the returned XML element. - :return: Serialized ElementTree object + :return: Serialized :class:`~lxml.etree.Element` object """ LANG_STRING_SET_TAGS: Dict[Type[model.LangStringSet], str] = {k: NS_AAS + v for k, v in { model.MultiLanguageNameType: "langStringNameType", @@ -184,8 +184,8 @@ def administrative_information_to_xml(obj: model.AdministrativeInformation, Serialization of objects of class :class:`~basyx.aas.model.base.AdministrativeInformation` to XML :param obj: Object of class :class:`~basyx.aas.model.base.AdministrativeInformation` - :param tag: Namespace+Tag of the serialized element. Default is "aas:administration" - :return: Serialized ElementTree object + :param tag: Namespace+Tag of the serialized element. Default is ``aas:administration`` + :return: Serialized :class:`~lxml.etree.Element` object """ et_administration = abstract_classes_to_xml(tag, obj) if obj.version: @@ -204,7 +204,7 @@ def data_element_to_xml(obj: model.DataElement) -> etree.Element: Serialization of objects of class :class:`~basyx.aas.model.submodel.DataElement` to XML :param obj: Object of class :class:`~basyx.aas.model.submodel.DataElement` - :return: Serialized ElementTree element + :return: Serialized :class:`~lxml.etree.Element` object """ if isinstance(obj, model.MultiLanguageProperty): return multi_language_property_to_xml(obj) @@ -225,8 +225,8 @@ def reference_to_xml(obj: model.Reference, tag: str = NS_AAS+"reference") -> etr Serialization of objects of class :class:`~basyx.aas.model.base.Reference` to XML :param obj: Object of class :class:`~basyx.aas.model.base.Reference` - :param tag: Namespace+Tag of the returned element. Default is "aas:reference" - :return: Serialized ElementTree + :param tag: Namespace+Tag of the returned element. Default is ``aas:reference`` + :return: Serialized :class:`~lxml.etree.Element` object """ et_reference = _generate_element(tag) et_reference.append(_generate_element(NS_AAS + "type", text=_generic.REFERENCE_TYPES[obj.__class__])) @@ -245,11 +245,11 @@ def reference_to_xml(obj: model.Reference, tag: str = NS_AAS+"reference") -> etr def qualifier_to_xml(obj: model.Qualifier, tag: str = NS_AAS+"qualifier") -> etree.Element: """ - Serialization of objects of class :class:`~aas.model.base.Qualifier` to XML + Serialization of objects of class :class:`~basyx.aas.model.base.Qualifier` to XML - :param obj: Object of class :class:`~aas.model.base.Qualifier` - :param tag: Namespace+Tag of the serialized ElementTree object. Default is "aas:qualifier" - :return: Serialized ElementTreeObject + :param obj: Object of class :class:`~basyx.aas.model.base.Qualifier` + :param tag: Namespace+Tag of the serialized ElementTree object. Default is ``aas:qualifier`` + :return: Serialized :class:`~lxml.etree.Element` object """ et_qualifier = abstract_classes_to_xml(tag, obj) et_qualifier.append(_generate_element(NS_AAS + "kind", text=_generic.QUALIFIER_KIND[obj.kind])) @@ -264,11 +264,11 @@ def qualifier_to_xml(obj: model.Qualifier, tag: str = NS_AAS+"qualifier") -> etr def extension_to_xml(obj: model.Extension, tag: str = NS_AAS+"extension") -> etree.Element: """ - Serialization of objects of class :class:`~aas.model.base.Extension` to XML + Serialization of objects of class :class:`~basyx.aas.model.base.Extension` to XML - :param obj: Object of class :class:`~aas.model.base.Extension` - :param tag: Namespace+Tag of the serialized ElementTree object. Default is "aas:extension" - :return: Serialized ElementTreeObject + :param obj: Object of class :class:`~basyx.aas.model.base.Extension` + :param tag: Namespace+Tag of the serialized ElementTree object. Default is ``aas:extension`` + :return: Serialized :class:`~lxml.etree.Element` object """ et_extension = abstract_classes_to_xml(tag, obj) et_extension.append(_generate_element(NS_AAS + "name", text=obj.name)) @@ -288,14 +288,11 @@ def extension_to_xml(obj: model.Extension, tag: str = NS_AAS+"extension") -> etr def value_reference_pair_to_xml(obj: model.ValueReferencePair, tag: str = NS_AAS+"valueReferencePair") -> etree.Element: """ - Serialization of objects of class :class:`~aas.model.base.ValueReferencePair` to XML + Serialization of objects of class :class:`~basyx.aas.model.base.ValueReferencePair` to XML - todo: couldn't find it in the official schema, so guessing how to implement serialization - check namespace, tag and correct serialization - - :param obj: Object of class :class:`~aas.model.base.ValueReferencePair` - :param tag: Namespace+Tag of the serialized element. Default is "aas:valueReferencePair" - :return: Serialized ElementTree object + :param obj: Object of class :class:`~basyx.aas.model.base.ValueReferencePair` + :param tag: Namespace+Tag of the serialized element. Default is ``aas:valueReferencePair`` + :return: Serialized :class:`~lxml.etree.Element` object """ et_vrp = _generate_element(tag) # TODO: value_type isn't used at all by _value_to_xml(), thus we can ignore the type here for now @@ -307,13 +304,13 @@ def value_reference_pair_to_xml(obj: model.ValueReferencePair, def value_list_to_xml(obj: model.ValueList, tag: str = NS_AAS+"valueList") -> etree.Element: """ - Serialization of objects of class :class:`~aas.model.base.ValueList` to XML + Serialization of objects of class :class:`~basyx.aas.model.base.ValueList` to XML todo: couldn't find it in the official schema, so guessing how to implement serialization - :param obj: Object of class :class:`~aas.model.base.ValueList` - :param tag: Namespace+Tag of the serialized element. Default is "aas:valueList" - :return: Serialized ElementTree object + :param obj: Object of class :class:`~basyx.aas.model.base.ValueList` + :param tag: Namespace+Tag of the serialized element. Default is ``aas:valueList`` + :return: Serialized :class:`~lxml.etree.Element` object """ et_value_list = _generate_element(tag) et_value_reference_pairs = _generate_element(NS_AAS+"valueReferencePairs") @@ -334,8 +331,8 @@ def specific_asset_id_to_xml(obj: model.SpecificAssetId, tag: str = NS_AAS + "sp Serialization of objects of class :class:`~basyx.aas.model.base.SpecificAssetId` to XML :param obj: Object of class :class:`~basyx.aas.model.base.SpecificAssetId` - :param tag: Namespace+Tag of the ElementTree object. Default is "aas:identifierKeyValuePair" - :return: Serialized ElementTree object + :param tag: Namespace+Tag of the ElementTree object. Default is ``aas:identifierKeyValuePair`` + :return: Serialized :class:`~lxml.etree.Element` object """ et_asset_information = abstract_classes_to_xml(tag, obj) et_asset_information.append(_generate_element(name=NS_AAS + "name", text=obj.name)) @@ -348,11 +345,11 @@ def specific_asset_id_to_xml(obj: model.SpecificAssetId, tag: str = NS_AAS + "sp def asset_information_to_xml(obj: model.AssetInformation, tag: str = NS_AAS+"assetInformation") -> etree.Element: """ - Serialization of objects of class :class:`~aas.model.aas.AssetInformation` to XML + Serialization of objects of class :class:`~basyx.aas.model.aas.AssetInformation` to XML - :param obj: Object of class :class:`~aas.model.aas.AssetInformation` - :param tag: Namespace+Tag of the ElementTree object. Default is "aas:assetInformation" - :return: Serialized ElementTree object + :param obj: Object of class :class:`~basyx.aas.model.aas.AssetInformation` + :param tag: Namespace+Tag of the ElementTree object. Default is ``aas:assetInformation`` + :return: Serialized :class:`~lxml.etree.Element` object """ et_asset_information = abstract_classes_to_xml(tag, obj) et_asset_information.append(_generate_element(name=NS_AAS + "assetKind", text=_generic.ASSET_KIND[obj.asset_kind])) @@ -377,8 +374,8 @@ def concept_description_to_xml(obj: model.ConceptDescription, Serialization of objects of class :class:`~basyx.aas.model.concept.ConceptDescription` to XML :param obj: Object of class :class:`~basyx.aas.model.concept.ConceptDescription` - :param tag: Namespace+Tag of the ElementTree object. Default is "aas:conceptDescription" - :return: Serialized ElementTree object + :param tag: Namespace+Tag of the ElementTree object. Default is ``aas:conceptDescription`` + :return: Serialized :class:`~lxml.etree.Element` object """ et_concept_description = abstract_classes_to_xml(tag, obj) if obj.is_case_of: @@ -392,11 +389,11 @@ def concept_description_to_xml(obj: model.ConceptDescription, def embedded_data_specification_to_xml(obj: model.EmbeddedDataSpecification, tag: str = NS_AAS+"embeddedDataSpecification") -> etree.Element: """ - Serialization of objects of class :class:`~aas.model.base.EmbeddedDataSpecification` to XML + Serialization of objects of class :class:`~basyx.aas.model.base.EmbeddedDataSpecification` to XML - :param obj: Object of class :class:`~aas.model.base.EmbeddedDataSpecification` - :param tag: Namespace+Tag of the ElementTree object. Default is "aas:embeddedDataSpecification" - :return: Serialized ElementTree object + :param obj: Object of class :class:`~basyx.aas.model.base.EmbeddedDataSpecification` + :param tag: Namespace+Tag of the ElementTree object. Default is ``aas:embeddedDataSpecification`` + :return: Serialized :class:`~lxml.etree.Element` object """ et_embedded_data_specification = abstract_classes_to_xml(tag, obj) et_embedded_data_specification.append(reference_to_xml(obj.data_specification, tag=NS_AAS + "dataSpecification")) @@ -407,11 +404,11 @@ def embedded_data_specification_to_xml(obj: model.EmbeddedDataSpecification, def data_specification_content_to_xml(obj: model.DataSpecificationContent, tag: str = NS_AAS+"dataSpecificationContent") -> etree.Element: """ - Serialization of objects of class :class:`~aas.model.base.DataSpecificationContent` to XML + Serialization of objects of class :class:`~basyx.aas.model.base.DataSpecificationContent` to XML - :param obj: Object of class :class:`~aas.model.base.DataSpecificationContent` - :param tag: Namespace+Tag of the ElementTree object. Default is "aas:dataSpecificationContent" - :return: Serialized ElementTree object + :param obj: Object of class :class:`~basyx.aas.model.base.DataSpecificationContent` + :param tag: Namespace+Tag of the ElementTree object. Default is ``aas:dataSpecificationContent`` + :return: Serialized :class:`~lxml.etree.Element` object """ et_data_specification_content = abstract_classes_to_xml(tag, obj) if isinstance(obj, model.DataSpecificationIEC61360): @@ -424,11 +421,11 @@ def data_specification_content_to_xml(obj: model.DataSpecificationContent, def data_specification_iec61360_to_xml(obj: model.DataSpecificationIEC61360, tag: str = NS_AAS+"dataSpecificationIec61360") -> etree.Element: """ - Serialization of objects of class :class:`~aas.model.base.DataSpecificationIEC61360` to XML + Serialization of objects of class :class:`~basyx.aas.model.base.DataSpecificationIEC61360` to XML - :param obj: Object of class :class:`~aas.model.base.DataSpecificationIEC61360` - :param tag: Namespace+Tag of the ElementTree object. Default is "aas:dataSpecificationIec61360" - :return: Serialized ElementTree object + :param obj: Object of class :class:`~basyx.aas.model.base.DataSpecificationIEC61360` + :param tag: Namespace+Tag of the ElementTree object. Default is ``aas:dataSpecificationIec61360`` + :return: Serialized :class:`~lxml.etree.Element` object """ et_data_specification_iec61360 = abstract_classes_to_xml(tag, obj) et_data_specification_iec61360.append(lang_string_set_to_xml(obj.preferred_name, NS_AAS + "preferredName")) @@ -471,8 +468,8 @@ def asset_administration_shell_to_xml(obj: model.AssetAdministrationShell, Serialization of objects of class :class:`~basyx.aas.model.aas.AssetAdministrationShell` to XML :param obj: Object of class :class:`~basyx.aas.model.aas.AssetAdministrationShell` - :param tag: Namespace+Tag of the ElementTree object. Default is "aas:assetAdministrationShell" - :return: Serialized ElementTree object + :param tag: Namespace+Tag of the ElementTree object. Default is ``aas:assetAdministrationShell`` + :return: Serialized :class:`~lxml.etree.Element` object """ et_aas = abstract_classes_to_xml(tag, obj) if obj.derived_from: @@ -496,7 +493,7 @@ def submodel_element_to_xml(obj: model.SubmodelElement) -> etree.Element: Serialization of objects of class :class:`~basyx.aas.model.submodel.SubmodelElement` to XML :param obj: Object of class :class:`~basyx.aas.model.submodel.SubmodelElement` - :return: Serialized ElementTree object + :return: Serialized :class:`~lxml.etree.Element` object """ if isinstance(obj, model.DataElement): return data_element_to_xml(obj) @@ -524,8 +521,8 @@ def submodel_to_xml(obj: model.Submodel, Serialization of objects of class :class:`~basyx.aas.model.submodel.Submodel` to XML :param obj: Object of class :class:`~basyx.aas.model.submodel.Submodel` - :param tag: Namespace+Tag of the serialized element (optional). Default is "aas:submodel" - :return: Serialized ElementTree object + :param tag: Namespace+Tag of the serialized element (optional). Default is ``aas:submodel`` + :return: Serialized :class:`~lxml.etree.Element` object """ et_submodel = abstract_classes_to_xml(tag, obj) if obj.submodel_element: @@ -542,8 +539,8 @@ def property_to_xml(obj: model.Property, Serialization of objects of class :class:`~basyx.aas.model.submodel.Property` to XML :param obj: Object of class :class:`~basyx.aas.model.submodel.Property` - :param tag: Namespace+Tag of the serialized element (optional). Default is "aas:property" - :return: Serialized ElementTree object + :param tag: Namespace+Tag of the serialized element (optional). Default is ``aas:property`` + :return: Serialized :class:`~lxml.etree.Element` object """ et_property = abstract_classes_to_xml(tag, obj) et_property.append(_generate_element(NS_AAS + "valueType", text=model.datatypes.XSD_TYPE_NAMES[obj.value_type])) @@ -560,8 +557,8 @@ def multi_language_property_to_xml(obj: model.MultiLanguageProperty, Serialization of objects of class :class:`~basyx.aas.model.submodel.MultiLanguageProperty` to XML :param obj: Object of class :class:`~basyx.aas.model.submodel.MultiLanguageProperty` - :param tag: Namespace+Tag of the serialized element (optional). Default is "aas:multiLanguageProperty" - :return: Serialized ElementTree object + :param tag: Namespace+Tag of the serialized element (optional). Default is ``aas:multiLanguageProperty`` + :return: Serialized :class:`~lxml.etree.Element` object """ et_multi_language_property = abstract_classes_to_xml(tag, obj) if obj.value: @@ -577,8 +574,8 @@ def range_to_xml(obj: model.Range, Serialization of objects of class :class:`~basyx.aas.model.submodel.Range` to XML :param obj: Object of class :class:`~basyx.aas.model.submodel.Range` - :param tag: Namespace+Tag of the serialized element (optional). Default is "aas:range" - :return: Serialized ElementTree object + :param tag: Namespace+Tag of the serialized element (optional). Default is ``aas:range`` + :return: Serialized :class:`~lxml.etree.Element` object """ et_range = abstract_classes_to_xml(tag, obj) et_range.append(_generate_element(name=NS_AAS + "valueType", @@ -596,8 +593,8 @@ def blob_to_xml(obj: model.Blob, Serialization of objects of class :class:`~basyx.aas.model.submodel.Blob` to XML :param obj: Object of class :class:`~basyx.aas.model.submodel.Blob` - :param tag: Namespace+Tag of the serialized element. Default is "blob" - :return: Serialized ElementTree object + :param tag: Namespace+Tag of the serialized element. Default is ``aas:blob`` + :return: Serialized :class:`~lxml.etree.Element` object """ et_blob = abstract_classes_to_xml(tag, obj) et_value = etree.Element(NS_AAS + "value") @@ -614,8 +611,8 @@ def file_to_xml(obj: model.File, Serialization of objects of class :class:`~basyx.aas.model.submodel.File` to XML :param obj: Object of class :class:`~basyx.aas.model.submodel.File` - :param tag: Namespace+Tag of the serialized element. Default is "aas:file" - :return: Serialized ElementTree object + :param tag: Namespace+Tag of the serialized element. Default is ``aas:file`` + :return: Serialized :class:`~lxml.etree.Element` object """ et_file = abstract_classes_to_xml(tag, obj) if obj.value: @@ -627,11 +624,11 @@ def file_to_xml(obj: model.File, def resource_to_xml(obj: model.Resource, tag: str = NS_AAS+"resource") -> etree.Element: """ - Serialization of objects of class :class:`~aas.model.base.Resource` to XML + Serialization of objects of class :class:`~basyx.aas.model.base.Resource` to XML - :param obj: Object of class :class:`~aas.model.base.Resource` - :param tag: Namespace+Tag of the serialized element. Default is "aas:resource" - :return: Serialized ElementTree object + :param obj: Object of class :class:`~basyx.aas.model.base.Resource` + :param tag: Namespace+Tag of the serialized element. Default is ``aas:resource`` + :return: Serialized :class:`~lxml.etree.Element` object """ et_resource = abstract_classes_to_xml(tag, obj) et_resource.append(_generate_element(NS_AAS + "path", text=obj.path)) @@ -646,8 +643,8 @@ def reference_element_to_xml(obj: model.ReferenceElement, Serialization of objects of class :class:`~basyx.aas.model.submodel.ReferenceElement` to XMl :param obj: Object of class :class:`~basyx.aas.model.submodel.ReferenceElement` - :param tag: Namespace+Tag of the serialized element (optional). Default is "aas:referenceElement" - :return: Serialized ElementTree object + :param tag: Namespace+Tag of the serialized element (optional). Default is ``aas:referenceElement`` + :return: Serialized :class:`~lxml.etree.Element` object """ et_reference_element = abstract_classes_to_xml(tag, obj) if obj.value: @@ -660,11 +657,9 @@ def submodel_element_collection_to_xml(obj: model.SubmodelElementCollection, """ Serialization of objects of class :class:`~basyx.aas.model.submodel.SubmodelElementCollection` to XML - Note that we do not have parameter "allowDuplicates" in out implementation - :param obj: Object of class :class:`~basyx.aas.model.submodel.SubmodelElementCollection` - :param tag: Namespace+Tag of the serialized element (optional). Default is "aas:submodelElementCollection" - :return: Serialized ElementTree object + :param tag: Namespace+Tag of the serialized element (optional). Default is ``aas:submodelElementCollection`` + :return: Serialized :class:`~lxml.etree.Element` object """ et_submodel_element_collection = abstract_classes_to_xml(tag, obj) if obj.value: @@ -677,6 +672,13 @@ def submodel_element_collection_to_xml(obj: model.SubmodelElementCollection, def submodel_element_list_to_xml(obj: model.SubmodelElementList, tag: str = NS_AAS+"submodelElementList") -> etree.Element: + """ + Serialization of objects of class :class:`~basyx.aas.model.submodel.SubmodelElementList` to XML + + :param obj: Object of class :class:`~basyx.aas.model.submodel.SubmodelElementList` + :param tag: Namespace+Tag of the serialized element (optional). Default is ``aas:submodelElementList`` + :return: Serialized :class:`~lxml.etree.Element` object + """ et_submodel_element_list = abstract_classes_to_xml(tag, obj) et_submodel_element_list.append(_generate_element(NS_AAS + "orderRelevant", boolean_to_xml(obj.order_relevant))) if obj.semantic_id_list_element is not None: @@ -701,8 +703,8 @@ def relationship_element_to_xml(obj: model.RelationshipElement, Serialization of objects of class :class:`~basyx.aas.model.submodel.RelationshipElement` to XML :param obj: Object of class :class:`~basyx.aas.model.submodel.RelationshipElement` - :param tag: Namespace+Tag of the serialized element (optional). Default is "aas:relationshipElement" - :return: Serialized ELementTree object + :param tag: Namespace+Tag of the serialized element (optional). Default is ``aas:relationshipElement`` + :return: Serialized :class:`~lxml.etree.Element` object """ et_relationship_element = abstract_classes_to_xml(tag, obj) et_relationship_element.append(reference_to_xml(obj.first, NS_AAS+"first")) @@ -716,8 +718,8 @@ def annotated_relationship_element_to_xml(obj: model.AnnotatedRelationshipElemen Serialization of objects of class :class:`~basyx.aas.model.submodel.AnnotatedRelationshipElement` to XML :param obj: Object of class :class:`~basyx.aas.model.submodel.AnnotatedRelationshipElement` - :param tag: Namespace+Tag of the serialized element (optional): Default is "aas:annotatedRelationshipElement" - :return: Serialized ElementTree object + :param tag: Namespace+Tag of the serialized element (optional): Default is ``aas:annotatedRelationshipElement`` + :return: Serialized :class:`~lxml.etree.Element` object """ et_annotated_relationship_element = relationship_element_to_xml(obj, tag) if obj.annotation: @@ -731,13 +733,13 @@ def annotated_relationship_element_to_xml(obj: model.AnnotatedRelationshipElemen def operation_variable_to_xml(obj: model.SubmodelElement, tag: str = NS_AAS+"operationVariable") -> etree.Element: """ Serialization of :class:`~basyx.aas.model.submodel.SubmodelElement` to the XML OperationVariable representation - Since we don't implement the `OperationVariable` class, which is just a wrapper for a single - :class:`~basyx.aas.model.submodel.SubmodelElement`, elements are serialized as the `aas:value` child of an - `aas:operationVariable` element. + Since we don't implement the ``OperationVariable`` class, which is just a wrapper for a single + :class:`~basyx.aas.model.submodel.SubmodelElement`, elements are serialized as the ``aas:value`` child of an + ``aas:operationVariable`` element. :param obj: Object of class :class:`~basyx.aas.model.submodel.SubmodelElement` - :param tag: Namespace+Tag of the serialized element (optional). Default is "aas:operationVariable" - :return: Serialized ElementTree object + :param tag: Namespace+Tag of the serialized element (optional). Default is ``aas:operationVariable`` + :return: Serialized :class:`~lxml.etree.Element` object """ et_operation_variable = _generate_element(tag) et_value = _generate_element(NS_AAS+"value") @@ -752,8 +754,8 @@ def operation_to_xml(obj: model.Operation, Serialization of objects of class :class:`~basyx.aas.model.submodel.Operation` to XML :param obj: Object of class :class:`~basyx.aas.model.submodel.Operation` - :param tag: Namespace+Tag of the serialized element (optional). Default is "aas:operation" - :return: Serialized ElementTree object + :param tag: Namespace+Tag of the serialized element (optional). Default is ``aas:operation`` + :return: Serialized :class:`~lxml.etree.Element` object """ et_operation = abstract_classes_to_xml(tag, obj) for tag, nss in ((NS_AAS+"inputVariables", obj.input_variable), @@ -773,8 +775,8 @@ def capability_to_xml(obj: model.Capability, Serialization of objects of class :class:`~basyx.aas.model.submodel.Capability` to XML :param obj: Object of class :class:`~basyx.aas.model.submodel.Capability` - :param tag: Namespace+Tag of the serialized element, default is "aas:capability" - :return: Serialized ElementTree object + :param tag: Namespace+Tag of the serialized element, default is ``aas:capability`` + :return: Serialized :class:`~lxml.etree.Element` object """ return abstract_classes_to_xml(tag, obj) @@ -785,8 +787,8 @@ def entity_to_xml(obj: model.Entity, Serialization of objects of class :class:`~basyx.aas.model.submodel.Entity` to XML :param obj: Object of class :class:`~basyx.aas.model.submodel.Entity` - :param tag: Namespace+Tag of the serialized element (optional). Default is "aas:entity" - :return: Serialized ElementTree object + :param tag: Namespace+Tag of the serialized element (optional). Default is ``aas:entity`` + :return: Serialized :class:`~lxml.etree.Element` object """ et_entity = abstract_classes_to_xml(tag, obj) if obj.statement: @@ -810,8 +812,8 @@ def basic_event_element_to_xml(obj: model.BasicEventElement, tag: str = NS_AAS+" Serialization of objects of class :class:`~basyx.aas.model.submodel.BasicEventElement` to XML :param obj: Object of class :class:`~basyx.aas.model.submodel.BasicEventElement` - :param tag: Namespace+Tag of the serialized element (optional). Default is "aas:basicEventElement" - :return: Serialized ElementTree object + :param tag: Namespace+Tag of the serialized element (optional). Default is ``aas:basicEventElement`` + :return: Serialized :class:`~lxml.etree.Element` object """ et_basic_event_element = abstract_classes_to_xml(tag, obj) et_basic_event_element.append(reference_to_xml(obj.observed, NS_AAS+"observed")) @@ -846,9 +848,9 @@ def write_aas_xml_file(file: IO, Administration Shell', chapter 5.4 :param file: A file-like object to write the XML-serialized data to - :param data: :class:`ObjectStore ` which contains different objects of the - AAS meta model which should be serialized to an XML file - :param kwargs: Additional keyword arguments to be passed to `tree.write()` + :param data: :class:`ObjectStore ` which contains different objects of + the AAS meta model which should be serialized to an XML file + :param kwargs: Additional keyword arguments to be passed to :meth:`~lxml.etree.ElementTree.write` """ # separate different kind of objects asset_administration_shells = [] diff --git a/basyx/aas/backend/backends.py b/basyx/aas/backend/backends.py index 55bc1e337..c5a987a96 100644 --- a/basyx/aas/backend/backends.py +++ b/basyx/aas/backend/backends.py @@ -9,16 +9,15 @@ synchronize Referable AAS objects or their included data with external data sources such as a remote API or a local source for real time data. Each backend provides access to one kind of data source. -The data source of an individual object is specified as an URI in its :attr:`~basyx.aas.model.base.Referable.source` -attribute. The schema part of that URI defines the type of data source and, in consequence, the backend class to use -for synchronizing this object. +The data source of an individual object is specified as an URI in its ``source`` attribute. The schema part of that URI +defines the type of data source and, in consequence, the backend class to use for synchronizing this object. -Custom backends for additional types of data sources can be implemented by subclassing the `Backend` class and +Custom backends for additional types of data sources can be implemented by subclassing :class:`Backend` and implementing the :meth:`~.Backend.commit_object` and :meth:`~.Backend.update_object` class methods. These are used internally by the objects' :meth:`~basyx.aas.model.base.Referable.update` and :meth:`~basyx.aas.model.base.Referable.commit` methods when the backend is applicable for the relevant source URI. Then, the Backend class needs to be registered to handle update/commit requests for a specific URI schema, using -:meth:`~aas.backend.backends.register_backend`. +:meth:`~basyx.aas.backend.backends.register_backend`. """ import abc import re @@ -34,7 +33,7 @@ class Backend(metaclass=abc.ABCMeta): Each Backend class is typically capable of synchronizing (updating/committing) objects with a type of external data source, identified by one or more source URI schemas. Custom backends for custom source URI schemas should inherit - from this class and be registered via :meth:`~aas.backend.backends.register_backend`. to be used by Referable + from this class and be registered via :meth:`~basyx.aas.backend.backends.register_backend`. to be used by Referable object's :meth:`~basyx.aas.model.base.Referable.update` and :meth:`~basyx.aas.model.base.Referable.commit` methods when required. """ @@ -53,25 +52,26 @@ def commit_object(cls, URI of the object or the source URI one of its ancestors in the AAS object containment hierarchy include an URI schema for which this backend has been registered. Both of the objects are passed to this function: the one which shall be committed - (`committed_object`) and its ancestor with the relevant source URI (`store_object`). They may be the same, the - committed object has a source with the relevant schema itself. Additionally, the `relative_path` from the - `store_object` down to the `committed_object` is provided. + (``committed_object``) and its ancestor with the relevant source URI (``store_object``). They may be the same, + the committed object has a source with the relevant schema itself. Additionally, the ``relative_path`` from the + ``store_object`` down to the ``committed_object`` is provided. - The backend MUST ensure to commit all local changes of at least the `committed_object` and all objects contained - within it (if any) to the data source. It MAY additionally commit changes to other objects (i.e. the - `store_object` and any additional contained object). + The backend MUST ensure to commit all local changes of at least the ``committed_object`` and all objects + contained within it (if any) to the data source. It MAY additionally commit changes to other objects (i.e. the + ``store_object`` and any additional contained object). - For this purpose a concrete implementation of this method would typically use the `source` attribute of the - `store_object` to identify the data source. If the data source supports fine-grained access to contained - objects, the `relative_path` may become handy to compose the committed object's address within the data source's - interface. + For this purpose a concrete implementation of this method would typically use the ``source`` attribute of the + ``store_object`` to identify the data source. If the data source supports fine-grained access to contained + objects, the ``relative_path`` may become handy to compose the committed object's address within the data + source's interface. :param committed_object: The object which shall be synced to the external data source :param store_object: The object which originates from the relevant data source (i.e. has the relevant source - attribute). It may be the `committed_object` or one of its ancestors in the AAS object hierarchy. - :param relative_path: List of idShort strings to resolve the `committed_object` starting at the `store_object`, - such that `obj = store_object; for i in relative_path: obj = obj.get_referable(i)` resolves to the - `committed_object`. In case that `store_object is committed_object`, it is an empty list. + attribute). It may be the ``committed_object`` or one of its ancestors in the AAS object hierarchy. + :param relative_path: List of idShort strings to resolve the ``committed_object`` starting at the + ``store_object``, such that `obj = store_object; for i in relative_path: obj = obj.get_referable(i)` + resolves to the ``committed_object``. In case that ``store_object is committed_object``, it is an empty + list. :raises BackendNotAvailableException: when the external data source cannot be reached """ pass @@ -89,26 +89,26 @@ def update_object(cls, It is automatically called by the :meth:`~basyx.aas.model.base.Referable.update` implementation, when the source URI of the object or the source URI one of its ancestors in the AAS object containment hierarchy include an URI schema for which this backend has been registered. Both of the objects are passed - to this function: the one which shall be update (`updated_object`) and its ancestor with - the relevant source URI (`store_object`). They may be the same, the updated object has a source with - the relevant schema itself. Additionally, the `relative_path` from the `store_object` down to - the `updated_object` is provided. - - The backend MUST ensure to update at least the `updated_object` and all objects contained within it (if any) - with any changes from the data source. It MAY additionally update other objects (i.e. the `store_object` and any - additional contained object). - - For this purpose a concrete implementation of this method would typically use the `source` attribute of the - `store_object` to identify the data source. If the data source supports fine-grained access to contained - objects, the `relative_path` may become handy to compose the updated object's address within the data source's + to this function: the one which shall be update (``updated_object``) and its ancestor with + the relevant source URI (``store_object``). They may be the same, the updated object has a source with + the relevant schema itself. Additionally, the ``relative_path`` from the ``store_object`` down to + the ``updated_object`` is provided. + + The backend MUST ensure to update at least the ``updated_object`` and all objects contained within it (if any) + with any changes from the data source. It MAY additionally update other objects (i.e. the ``store_object`` and + any additional contained object). + + For this purpose a concrete implementation of this method would typically use the ``source`` attribute of the + ``store_object`` to identify the data source. If the data source supports fine-grained access to contained + objects, the ``relative_path`` may become handy to compose the updated object's address within the data source's interface. :param updated_object: The object which shall be synced from the external data source :param store_object: The object which originates from the relevant data source (i.e. has the relevant source - attribute). It may be the `committed_object` or one of its ancestors in the AAS object hierarchy. - :param relative_path: List of idShort strings to resolve the `updated_object` starting at the `store_object`, - such that `obj = store_object; for i in relative_path: obj = obj.get_referable(i)` resolves to the - `updated_object`. In case that `store_object is updated_object`, it is an empty list. + attribute). It may be the ``committed_object`` or one of its ancestors in the AAS object hierarchy. + :param relative_path: List of idShort strings to resolve the ``updated_object`` starting at the + ``store_object``, such that `obj = store_object; for i in relative_path: obj = obj.get_referable(i)` + resolves to the ``updated_object``. In case that ``store_object is updated_object``, it is an empty list. :raises BackendNotAvailableException: when the external data source cannot be reached """ pass @@ -129,7 +129,7 @@ def register_backend(scheme: str, backend_class: Type[Backend]) -> None: :param scheme: The URI schema of source URIs to be handled with Backend class, without trailing colon and slashes. E.g. 'http', 'https', 'couchdb', etc. - :param backend_class: The Backend implementation class. Should be inheriting from `Backend`. + :param backend_class: The Backend implementation class. Should inherit from :class:`Backend`. """ # TODO handle multiple backends per scheme _backends_map[scheme] = backend_class @@ -140,8 +140,8 @@ def register_backend(scheme: str, backend_class: Type[Backend]) -> None: def get_backend(url: str) -> Type[Backend]: """ - Internal function to retrieve the Backend implementation for the external data source identified by the given `url` - via the url's schema. + Internal function to retrieve the Backend implementation for the external data source identified by the given + ``url`` via the url's schema. :param url: External data source URI to find an appropriate Backend implementation for :return: A Backend class, capable of updating/committing from/to the external data source diff --git a/basyx/aas/backend/couchdb.py b/basyx/aas/backend/couchdb.py index 7c23e77fb..b59186d97 100644 --- a/basyx/aas/backend/couchdb.py +++ b/basyx/aas/backend/couchdb.py @@ -33,7 +33,7 @@ class CouchDBBackend(backends.Backend): """ This Backend stores each Identifiable object as a single JSON document in the configured CouchDB database. Each - document's id is build from the object's identifier. The document's contents comprise a single property "data", + document's id is build from the object's identifier. The document's contents comprise a single property ``data``, containing the JSON serialization of the BaSyx Python SDK object. The :ref:`adapter.json ` package is used for serialization and deserialization of objects. """ @@ -117,7 +117,7 @@ def do_request(cls, url: str, method: str = "GET", additional_headers: Dict[str, :param additional_headers: Additional headers to insert into the request. The default headers include 'connection: keep-alive', 'accept-encoding: ...', 'authorization: basic ...', 'Accept: ...'. :param body: Request body for POST, PUT, and PATCH requests - :return: The parsed JSON data if the request `method` is other than 'HEAD' or the response headers for 'HEAD' + :return: The parsed JSON data if the request ``method`` is other than 'HEAD' or the response headers for 'HEAD' requests """ url_parts = urllib.parse.urlparse(url) @@ -235,9 +235,9 @@ class CouchDBObjectStore(model.AbstractObjectStore): An ObjectStore implementation for :class:`~basyx.aas.model.base.Identifiable` BaSyx Python SDK objects backed by a CouchDB database server. - All methods of the `CouchDBObjectStore` are blocking, i.e. they stop the current thread's execution until they - receive a response from the CouchDB server (or encounter a timeout). However, the `CouchDBObjectStore` objects are - thread-safe, as long as no CouchDB credentials are added (via `register_credentials()`) during transactions. + All methods of the ``CouchDBObjectStore`` are blocking, i.e. they stop the current thread's execution until they + receive a response from the CouchDB server (or encounter a timeout). However, the ``CouchDBObjectStore`` objects are + thread-safe, as long as no CouchDB credentials are added (via ``register_credentials()``) during transactions. """ def __init__(self, url: str, database: str): """ @@ -264,7 +264,8 @@ def check_database(self, create=False): Check if the database exists and created it if not (and requested to do so) :param create: If True and the database does not exist, try to create it - :raises CouchDBError: If error occur during the request to the CouchDB server (see `_do_request()` for details) + :raises CouchDBError: If error occur during the request to the CouchDB server + (see ``_do_request()`` for details) """ try: @@ -287,7 +288,8 @@ def get_identifiable_by_couchdb_id(self, couchdb_id: str) -> model.Identifiable: Retrieve an AAS object from the CouchDB by its couchdb-ID-string :raises KeyError: If no such object is stored in the database - :raises CouchDBError: If error occur during the request to the CouchDB server (see `_do_request()` for details) + :raises CouchDBError: If error occur during the request to the CouchDB server + (see ``_do_request()`` for details) """ # Create and issue HTTP request (raises HTTPError on status != 200) @@ -327,7 +329,8 @@ def get_identifiable(self, identifier: model.Identifier) -> model.Identifiable: Retrieve an AAS object from the CouchDB by its :class:`~basyx.aas.model.base.Identifier` :raises KeyError: If no such object is stored in the database - :raises CouchDBError: If error occur during the request to the CouchDB server (see `_do_request()` for details) + :raises CouchDBError: If error occur during the request to the CouchDB server + (see ``_do_request()`` for details) """ try: return self.get_identifiable_by_couchdb_id(self._transform_id(identifier, False)) @@ -339,7 +342,8 @@ def add(self, x: model.Identifiable) -> None: Add an object to the store :raises KeyError: If an object with the same id exists already in the database - :raises CouchDBError: If error occur during the request to the CouchDB server (see `_do_request()` for details) + :raises CouchDBError: If error occur during the request to the CouchDB server + (see ``_do_request()`` for details) """ logger.debug("Adding object %s to CouchDB database ...", repr(x)) # Serialize data @@ -368,13 +372,14 @@ def discard(self, x: model.Identifiable, safe_delete=False) -> None: Delete an :class:`~basyx.aas.model.base.Identifiable` AAS object from the CouchDB database :param x: The object to be deleted - :param safe_delete: If `True`, only delete the object if it has not been modified in the database in comparison - to the provided revision. This uses the CouchDB revision token and thus only works with - CouchDBIdentifiable objects retrieved from this database. + :param safe_delete: If ``True``, only delete the object if it has not been modified in the database in + comparison to the provided revision. This uses the CouchDB revision token and thus only + works with CouchDBIdentifiable objects retrieved from this database. :raises KeyError: If the object does not exist in the database - :raises CouchDBConflictError: If safe_delete is `True` and the object has been modified or deleted in the + :raises CouchDBConflictError: If safe_delete is ``True`` and the object has been modified or deleted in the database - :raises CouchDBError: If error occur during the request to the CouchDB server (see `_do_request()` for details) + :raises CouchDBError: If error occur during the request to the CouchDB server + (see ``_do_request()`` for details) """ logger.debug("Deleting object %s from CouchDB database ...", repr(x)) rev = get_couchdb_revision("{}/{}/{}".format(self.url, @@ -424,8 +429,9 @@ def __contains__(self, x: object) -> bool: :param x: AAS object :class:`~basyx.aas.model.base.Identifier` or :class:`~basyx.aas.model.base.Identifiable` AAS object - :return: `True` if such an object exists in the database, `False` otherwise - :raises CouchDBError: If error occur during the request to the CouchDB server (see `_do_request()` for details) + :return: ``True`` if such an object exists in the database, ``False`` otherwise + :raises CouchDBError: If error occur during the request to the CouchDB server + (see ``_do_request()`` for details) """ if isinstance(x, model.Identifier): identifier = x @@ -449,7 +455,8 @@ def __len__(self) -> int: Retrieve the number of objects in the CouchDB database :return: The number of objects (determined from the number of documents) - :raises CouchDBError: If error occur during the request to the CouchDB server (see `_do_request()` for details) + :raises CouchDBError: If error occur during the request to the CouchDB server + (see ``_do_request()`` for details) """ logger.debug("Fetching number of documents from database ...") data = CouchDBBackend.do_request("{}/{}".format(self.url, self.database_name)) @@ -463,7 +470,7 @@ def __iter__(self) -> Iterator[model.Identifiable]: the identifiable objects on the fly. :raises CouchDBError: If error occur during fetching the list of objects from the CouchDB server (see - `_do_request()` for details) + ``_do_request()`` for details) """ # Iterator class storing the list of ids and fetching Identifiable objects on the fly class CouchDBIdentifiableIterator(Iterator[model.Identifiable]): diff --git a/basyx/aas/backend/local_file.py b/basyx/aas/backend/local_file.py index 82a8169c4..f5176dbc7 100644 --- a/basyx/aas/backend/local_file.py +++ b/basyx/aas/backend/local_file.py @@ -31,7 +31,7 @@ class LocalFileBackend(backends.Backend): """ This Backend stores each Identifiable object as a single JSON document as a local file in a directory. Each document's id is build from the object's identifier using a SHA256 sum of its identifiable; the document's - contents comprise a single property "data", containing the JSON serialization of the BaSyx Python SDK object. The + contents comprise a single property ``data``, containing the JSON serialization of the BaSyx Python SDK object. The :ref:`adapter.json ` package is used for serialization and deserialization of objects. """ @@ -178,7 +178,7 @@ def __contains__(self, x: object) -> bool: :param x: AAS object :class:`~basyx.aas.model.base.Identifier` or :class:`~basyx.aas.model.base.Identifiable` AAS object - :return: `True` if such an object exists in the database, `False` otherwise + :return: ``True`` if such an object exists in the database, ``False`` otherwise """ if isinstance(x, model.Identifier): identifier = x diff --git a/basyx/aas/compliance_tool/compliance_check_aasx.py b/basyx/aas/compliance_tool/compliance_check_aasx.py index bb3993150..3317d6ad8 100644 --- a/basyx/aas/compliance_tool/compliance_check_aasx.py +++ b/basyx/aas/compliance_tool/compliance_check_aasx.py @@ -7,16 +7,9 @@ """ Module which offers functions to use in a confirmation tool related to AASX files -:meth:`~aas.compliance_tool.compliance_check_aasx.check_deserialization`: Checks if a AASX file can be deserialized - -:meth:`~aas.compliance_tool.compliance_check_aasx.check_aas_example`: Checks if a AASX file consist the data of the -example data defined in aas.examples.data.example_aas.py - -:meth:`~aas.compliance_tool.compliance_check_aasx.check_aasx_files_equivalence`: Checks if two AASX files have the same -data regardless of their order - -All functions reports any issues using the given :class:`~aas.compliance_tool.state_manager.ComplianceToolStateManager` -by adding new steps and associated LogRecords +All functions reports any issues using the given +:class:`~basyx.aas.compliance_tool.state_manager.ComplianceToolStateManager` by adding new steps and associated +:class:`LogRecords ` """ import datetime import logging @@ -41,7 +34,7 @@ def check_deserialization(file_path: str, state_manager: ComplianceToolStateMana -> Tuple[model.DictObjectStore, aasx.DictSupplementaryFileContainer, pyecma376_2.OPCCoreProperties]: """ Read a AASX file and reports any issues using the given - :class:`~aas.compliance_tool.state_manager.ComplianceToolStateManager` + :class:`~basyx.aas.compliance_tool.state_manager.ComplianceToolStateManager` Add the steps: `Open {} file' and 'Read {} file` @@ -98,7 +91,7 @@ def check_deserialization(file_path: str, state_manager: ComplianceToolStateMana def check_schema(file_path: str, state_manager: ComplianceToolStateManager) -> None: """ Checks a given file against the official json schema and reports any issues using the given - :class:`~aas.compliance_tool.state_manager.ComplianceToolStateManager` + :class:`~basyx.aas.compliance_tool.state_manager.ComplianceToolStateManager` Opens the file and checks if the data inside is stored in XML or JSON. Then calls the respective compliance tool schema check @@ -161,14 +154,14 @@ def check_schema(file_path: str, state_manager: ComplianceToolStateManager) -> N def check_aas_example(file_path: str, state_manager: ComplianceToolStateManager, **kwargs) -> None: """ Checks if a file contains all elements of the aas example and reports any issues using the given - :class:`~aas.compliance_tool.state_manager.ComplianceToolStateManager` + :class:`~basyx.aas.compliance_tool.state_manager.ComplianceToolStateManager` - Calls the :meth:`~aas.compliance_tool.compliance_check_aasx.check_deserialization` and add the steps: + Calls the :meth:`~basyx.aas.compliance_tool.compliance_check_aasx.check_deserialization` and add the steps: `Check if data is equal to example data` :param file_path: Given file which should be checked - :param state_manager: :class:`~aas.compliance_tool.state_manager.ComplianceToolStateManager` to log the steps - :param kwargs: Additional arguments to pass to :class:`~aas.examples.data._helper.AASDataChecker` + :param state_manager: :class:`~basyx.aas.compliance_tool.state_manager.ComplianceToolStateManager` to log the steps + :param kwargs: Additional arguments to pass to :class:`~basyx.aas.examples.data._helper.AASDataChecker` """ logger = logging.getLogger('compliance_check') logger.addHandler(state_manager) @@ -272,15 +265,15 @@ def check_aasx_files_equivalence(file_path_1: str, file_path_2: str, state_manag **kwargs) -> None: """ Checks if two aasx files contain the same elements in any order and reports any issues using the given - :class:`~aas.compliance_tool.state_manager.ComplianceToolStateManager` + :class:`~basyx.aas.compliance_tool.state_manager.ComplianceToolStateManager` - calls the :meth:`~aas.compliance_tool.compliance_check_aasx.check_deserialization` for each file and add the steps: - `Check if data in files are equal` + calls the :meth:`~basyx.aas.compliance_tool.compliance_check_aasx.check_deserialization` for each file and add the + steps: `Check if data in files are equal` :param file_path_1: Given first file which should be checked :param file_path_2: Given second file which should be checked - :param state_manager: :class:`~aas.compliance_tool.state_manager.ComplianceToolStateManager` to log the steps - :param kwargs: Additional arguments to pass to :class:`~aas.examples.data._helper.AASDataChecker` + :param state_manager: :class:`~basyx.aas.compliance_tool.state_manager.ComplianceToolStateManager` to log the steps + :param kwargs: Additional arguments to pass to :class:`~basyx.aas.examples.data._helper.AASDataChecker` """ logger = logging.getLogger('compliance_check') logger.addHandler(state_manager) diff --git a/basyx/aas/compliance_tool/compliance_check_json.py b/basyx/aas/compliance_tool/compliance_check_json.py index 53b37f14a..d6b7a1ef2 100644 --- a/basyx/aas/compliance_tool/compliance_check_json.py +++ b/basyx/aas/compliance_tool/compliance_check_json.py @@ -7,19 +7,9 @@ """ Module which offers functions to use in a confirmation tool related to json files -:meth:`~aas.compliance_tool.compliance_check_json.check_schema`: Checks if a json file is conform to official JSON -schema as defined in the 'Details of the Asset Administration Shell' specification of Plattform Industrie 4.0 - -:meth:`~aas.compliance_tool.compliance_check_json.check_deserialization`: Checks if a json file can be deserialized - -:meth:`~aas.compliance_tool.compliance_check_json.check_aas_example`: Checks if a json file consist the data of the -example data defined in aas.examples.data.example_aas.py - -:meth:`~aas.compliance_tool.compliance_check_json.check_json_files_equivalence`: Checks if two json files have the -same data regardless of their order - -All functions reports any issues using the given :class:`~aas.compliance_tool.state_manager.ComplianceToolStateManager` -by adding new steps and associated LogRecords +All functions reports any issues using the given +:class:`~basyx.aas.compliance_tool.state_manager.ComplianceToolStateManager` by adding new steps and associated +:class:`LogRecords ` """ import json import logging @@ -35,13 +25,13 @@ def check_schema(file_path: str, state_manager: ComplianceToolStateManager) -> None: """ Checks a given file against the official json schema and reports any issues using the given - :class:`~aas.compliance_tool.state_manager.ComplianceToolStateManager` + :class:`~basyx.aas.compliance_tool.state_manager.ComplianceToolStateManager` Add the steps: `Open file`, `Read file and check if it is conform to the json syntax` and `Validate file against official json schema` :param file_path: Path to the file which should be checked - :param state_manager: :class:`~aas.compliance_tool.state_manager.ComplianceToolStateManager` to log the steps + :param state_manager: :class:`~basyx.aas.compliance_tool.state_manager.ComplianceToolStateManager` to log the steps """ logger = logging.getLogger('compliance_check') logger.addHandler(state_manager) @@ -111,12 +101,12 @@ def check_deserialization(file_path: str, state_manager: ComplianceToolStateMana file_info: Optional[str] = None) -> model.DictObjectStore: """ Deserializes a JSON AAS file and reports any issues using the given - :class:`~aas.compliance_tool.state_manager.ComplianceToolStateManager` + :class:`~basyx.aas.compliance_tool.state_manager.ComplianceToolStateManager` Add the steps: `Open {} file` and `Read {} file` and `check if it is conform to the json schema` :param file_path: Given file which should be deserialized - :param state_manager: :class:`~aas.compliance_tool.state_manager.ComplianceToolStateManager` to log the steps + :param state_manager: :class:`~basyx.aas.compliance_tool.state_manager.ComplianceToolStateManager` to log the steps :param file_info: Additional information about the file for name of the steps :return: The deserialized :class:`~basyx.aas.model.provider.DictObjectStore` """ @@ -165,14 +155,14 @@ def check_deserialization(file_path: str, state_manager: ComplianceToolStateMana def check_aas_example(file_path: str, state_manager: ComplianceToolStateManager, **kwargs) -> None: """ Checks if a file contains all elements of the aas example and reports any issues using the given - :class:`~aas.compliance_tool.state_manager.ComplianceToolStateManager` + :class:`~basyx.aas.compliance_tool.state_manager.ComplianceToolStateManager` - Calls the :meth:`~aas.compliance_tool.compliance_check_json.check_deserialization` and add the steps: + Calls the :meth:`~basyx.aas.compliance_tool.compliance_check_json.check_deserialization` and add the steps: `Check if data is equal to example data` :param file_path: Given file which should be checked - :param state_manager: :class:`~aas.compliance_tool.state_manager.ComplianceToolStateManager` to log the steps - :param kwargs: Additional arguments to pass to :class:`~aas.examples.data._helper.AASDataChecker` + :param state_manager: :class:`~basyx.aas.compliance_tool.state_manager.ComplianceToolStateManager` to log the steps + :param kwargs: Additional arguments to pass to :class:`~basyx.aas.examples.data._helper.AASDataChecker` """ # create handler to get logger info logger_example = logging.getLogger(example_aas.__name__) @@ -199,15 +189,15 @@ def check_json_files_equivalence(file_path_1: str, file_path_2: str, state_manag **kwargs) -> None: """ Checks if two json files contain the same elements in any order and reports any issues using the given - :class:`~aas.compliance_tool.state_manager.ComplianceToolStateManager` + :class:`~basyx.aas.compliance_tool.state_manager.ComplianceToolStateManager` - Calls the :meth:`~aas.compliance_tool.compliance_check_json.check_deserialization` for ech file and add the steps: - `Check if data in files are equal` + Calls the :meth:`~basyx.aas.compliance_tool.compliance_check_json.check_deserialization` for ech file and add the + steps: `Check if data in files are equal` :param file_path_1: Given first file which should be checked :param file_path_2: Given second file which should be checked - :param state_manager: :class:`~aas.compliance_tool.state_manager.ComplianceToolStateManager` to log the steps - :param kwargs: Additional arguments to pass to :class:`~aas.examples.data._helper.AASDataChecker` + :param state_manager: :class:`~basyx.aas.compliance_tool.state_manager.ComplianceToolStateManager` to log the steps + :param kwargs: Additional arguments to pass to :class:`~basyx.aas.examples.data._helper.AASDataChecker` """ logger = logging.getLogger('compliance_check') logger.addHandler(state_manager) diff --git a/basyx/aas/compliance_tool/compliance_check_xml.py b/basyx/aas/compliance_tool/compliance_check_xml.py index 2c5fdf0e6..9791011af 100644 --- a/basyx/aas/compliance_tool/compliance_check_xml.py +++ b/basyx/aas/compliance_tool/compliance_check_xml.py @@ -7,19 +7,9 @@ """ Module which offers functions to use in a confirmation tool related to xml files -:meth:`~aas.compliance_tool.compliance_check_xml.check_schema`: Checks if a xml file is conform to official JSON schema -as defined in the 'Details of the Asset Administration Shell' specification of Plattform Industrie 4.0 - -:meth:`~aas.compliance_tool.compliance_check_xml.check_deserialization`: Checks if a xml file can be deserialized - -:meth:`~aas.compliance_tool.compliance_check_xml.check_aas_example`: Checks if a xml file consist the data of the -example data defined in aas.examples.data.example_aas.py - -:meth:`~aas.compliance_tool.compliance_check_xml.check_xml_files_equivalence`: Checks if two xml files have the same -data regardless of their order - -All functions reports any issues using the given :class:`~aas.compliance_tool.state_manager.ComplianceToolStateManager` -by adding new steps and associated LogRecords +All functions reports any issues using the given +:class:`~basyx.aas.compliance_tool.state_manager.ComplianceToolStateManager` by adding new steps and associated +:class:`LogRecords ` """ from lxml import etree # type: ignore @@ -36,13 +26,13 @@ def check_schema(file_path: str, state_manager: ComplianceToolStateManager) -> None: """ Checks a given file against the official xml schema and reports any issues using the given - :class:`~aas.compliance_tool.state_manager.ComplianceToolStateManager` + :class:`~basyx.aas.compliance_tool.state_manager.ComplianceToolStateManager` Add the steps: `Open file`, `Read file`, `Check if it is conform to the xml syntax` and `Validate file against official xml schema` :param file_path: Path to the file which should be checked - :param state_manager: :class:`~aas.compliance_tool.state_manager.ComplianceToolStateManager` to log the steps + :param state_manager: :class:`~basyx.aas.compliance_tool.state_manager.ComplianceToolStateManager` to log the steps """ logger = logging.getLogger('compliance_check') logger.addHandler(state_manager) @@ -111,12 +101,12 @@ def check_deserialization(file_path: str, state_manager: ComplianceToolStateMana file_info: Optional[str] = None) -> model.DictObjectStore: """ Deserializes a XML AAS file and reports any issues using the given - :class:`~aas.compliance_tool.state_manager.ComplianceToolStateManager` + :class:`~basyx.aas.compliance_tool.state_manager.ComplianceToolStateManager` Add the steps: `Open {} file` and `Read {} file` and `Check if it is conform to the xml schema` :param file_path: Given file which should be deserialized - :param state_manager: :class:`~aas.compliance_tool.state_manager.ComplianceToolStateManager` to log the steps + :param state_manager: :class:`~basyx.aas.compliance_tool.state_manager.ComplianceToolStateManager` to log the steps :param file_info: Additional information about the file for name of the steps :return: The deserialized object store """ @@ -165,14 +155,14 @@ def check_deserialization(file_path: str, state_manager: ComplianceToolStateMana def check_aas_example(file_path: str, state_manager: ComplianceToolStateManager, **kwargs) -> None: """ Checks if a file contains all elements of the aas example and reports any issues using the given - :class:`~aas.compliance_tool.state_manager.ComplianceToolStateManager` + :class:`~basyx.aas.compliance_tool.state_manager.ComplianceToolStateManager` - Calls the :meth:`~aas.compliance_tool.compliance_check_xml.check_deserialization` and add the steps: `Check if data - is equal to example data` + Calls the :meth:`~basyx.aas.compliance_tool.compliance_check_xml.check_deserialization` and add the steps: + `Check if data is equal to example data` :param file_path: Given file which should be checked - :param state_manager: :class:`~aas.compliance_tool.state_manager.ComplianceToolStateManager` to log the steps - :param kwargs: Additional arguments to pass to :class:`~aas.examples.data._helper.AASDataChecker` + :param state_manager: :class:`~basyx.aas.compliance_tool.state_manager.ComplianceToolStateManager` to log the steps + :param kwargs: Additional arguments to pass to :class:`~basyx.aas.examples.data._helper.AASDataChecker` """ # create handler to get logger info logger_example = logging.getLogger(example_aas.__name__) @@ -199,15 +189,15 @@ def check_xml_files_equivalence(file_path_1: str, file_path_2: str, state_manage **kwargs) -> None: """ Checks if two xml files contain the same elements in any order and reports any issues using the given - :class:`~aas.compliance_tool.state_manager.ComplianceToolStateManager` + :class:`~basyx.aas.compliance_tool.state_manager.ComplianceToolStateManager` - Calls the :meth:`~aas.compliance_tool.compliance_check_xml.check_deserialization` for each file and add the steps: - `Check if data in files are equal` + Calls the :meth:`~basyx.aas.compliance_tool.compliance_check_xml.check_deserialization` for each file and add the + steps: `Check if data in files are equal` :param file_path_1: Given first file which should be checked :param file_path_2: Given second file which should be checked - :param state_manager: :class:`~aas.compliance_tool.state_manager.ComplianceToolStateManager` to log the steps - :param kwargs: Additional arguments to pass to :class:`~aas.examples.data._helper.AASDataChecker` + :param state_manager: :class:`~basyx.aas.compliance_tool.state_manager.ComplianceToolStateManager` to log the steps + :param kwargs: Additional arguments to pass to :class:`~basyx.aas.examples.data._helper.AASDataChecker` """ logger = logging.getLogger('compliance_check') logger.addHandler(state_manager) diff --git a/basyx/aas/compliance_tool/state_manager.py b/basyx/aas/compliance_tool/state_manager.py index a8093a4b3..3116fe150 100644 --- a/basyx/aas/compliance_tool/state_manager.py +++ b/basyx/aas/compliance_tool/state_manager.py @@ -5,8 +5,8 @@ # # SPDX-License-Identifier: MIT """ -This module defines a :class:`~.ComplianceToolStateManager` to store `logging.LogRecords` for single steps in a -compliance check of the compliance tool +This module defines a :class:`~.ComplianceToolStateManager` to store :class:`LogRecords ` +for single steps in a compliance check of the compliance tool """ import logging import enum @@ -36,8 +36,8 @@ class Step: A step represents a single test stage in a test protocol of a :class:`~.ComplianceToolStateManager` :ivar name: Name of the step - :ivar ~.status: Status of the step from type Status - :ivar log_list: List of `logging.LogRecords` which belong to this step + :ivar status: Status of the step from type Status + :ivar log_list: List of :class:`LogRecords ` which belong to this step """ def __init__(self, name: str, status: Status, log_list: List[logging.LogRecord]): self.name = name @@ -55,7 +55,7 @@ class ComplianceToolStateManager(logging.Handler): - Set the step status from log - Add logs to a step by hand - Add logs to a step from a data checker - - Be used as a `logging.Handler` which adds logs to the current step + - Be used as a :class:`logging.Handler` which adds logs to the current step Example of a ComplianceTest for a schema check: @@ -101,9 +101,9 @@ def add_step(self, name: str) -> None: def add_log_record(self, record: logging.LogRecord) -> None: """ - Adds a `logging.LogRecord` to the log list of the actual :class:`~.Step` + Adds a :class:`~logging.LogRecord` to the log list of the actual :class:`~.Step` - :param record: `logging.LogRecord` which should be added to the current :class:`~.Step` + :param record: :class:`~logging.LogRecord` which should be added to the current :class:`~.Step` """ self.steps[-1].log_list.append(record) @@ -123,13 +123,13 @@ def set_step_status_from_log(self) -> None: def add_log_records_from_data_checker(self, data_checker: DataChecker) -> None: """ - Sets the status of the current :class:`~.Step` and convert the checks to `logging.LogRecords` and adds these to - the current :class:`~.Step` + Sets the status of the current :class:`~.Step` and convert the checks to + :class:`LogRecords ` and adds these to the current :class:`~.Step` - :class:`~.Step`: FAILED if the :class:`~aas.examples.data._helper.DataChecker` consist at least one failed + :class:`~.Step`: FAILED if the :class:`~basyx.aas.examples.data._helper.DataChecker` consist at least one failed check otherwise SUCCESS - :param data_checker: :class:`~aas.examples.data._helper.DataChecker` which checks should be added to the + :param data_checker: :class:`~basyx.aas.examples.data._helper.DataChecker` which checks should be added to the current :class:`~.Step` """ self.steps[-1].status = Status.SUCCESS if not any(True for _ in data_checker.failed_checks) else Status.FAILED @@ -149,22 +149,24 @@ def add_log_records_from_data_checker(self, data_checker: DataChecker) -> None: def get_error_logs_from_step(self, index: int) -> List[logging.LogRecord]: """ - Returns a list of `logging.LogRecords` of a step where the log level is `logging.ERROR` or `logging.WARNING` + Returns a list of :class:`LogRecords ` of a step where the log level + is :data:`~logging.ERROR` or :data:`~logging.WARNING` :param index: Step index in the Step list of the manager - :return: List of LogRecords with log level `logging.ERROR` or `logging.WARNING` + :return: List of LogRecords with log level :data:`~logging.ERROR` or :data:`~logging.WARNING` """ return [x for x in self.steps[index].log_list if x.levelno >= logging.WARNING] def format_step(self, index: int, verbose_level: int = 0) -> str: """ - Creates a string for the step containing the status, the step name and the `logging.LogRecords` if wanted + Creates a string for the step containing the status, the step name and + the :class:`LogRecords ` if wanted :param index: Step index in the step list of the manager :param verbose_level: Decision which kind of LogRecords should be in the string - 0: No LogRecords - - 1: Only LogRecords with log level >= logging.WARNING + - 1: Only LogRecords with log level >= :data:`~logging.WARNING` - 2: All LogRecords :return: formatted string of the step @@ -190,13 +192,13 @@ def format_step(self, index: int, verbose_level: int = 0) -> str: def format_state_manager(self, verbose_level: int = 0) -> str: """ - Creates a report with all executed steps: Containing the status, the step name and the `logging.LogRecords` if - wanted + Creates a report with all executed steps: Containing the status, the step name and + the :class:`LogRecords ` if wanted :param verbose_level: Decision which kind of LogRecords should be in the string - 0: No LogRecords - - 1: Only LogRecords with log level >= logging.WARNING + - 1: Only LogRecords with log level >= :data:`~logging.WARNING` - 2: All LogRecords :return: formatted report @@ -207,8 +209,9 @@ def format_state_manager(self, verbose_level: int = 0) -> str: def emit(self, record: logging.LogRecord): """ - `logging.Handler` function for adding `logging.LogRecords` from a `logger` to the current :class:`~.Step` + :class:`~logging.Handler` function for adding :class:`LogRecords ` from a ``logger`` + to the current :class:`~.Step` - :param record: `logging.LogRecord` which should be added + :param record: :class:`~logging.LogRecord` which should be added """ self.steps[-1].log_list.append(record) diff --git a/basyx/aas/examples/data/_helper.py b/basyx/aas/examples/data/_helper.py index 11db36330..2b19a304d 100644 --- a/basyx/aas/examples/data/_helper.py +++ b/basyx/aas/examples/data/_helper.py @@ -6,6 +6,9 @@ # SPDX-License-Identifier: MIT """ Helper classes for checking two objects for completeness and correctness and reporting the check results. + +.. warning:: + This module is intended for internal use only. """ import pprint from typing import List, NamedTuple, Iterator, Dict, Any, Type, Union, Set, Iterable, TypeVar @@ -34,6 +37,8 @@ class DataChecker: Typical usage: + .. code-block:: python + data = {'a': 1, 'b': 2} dc = DataChecker() dc.check(len(data) > 0, "data is not empty") @@ -55,7 +60,7 @@ def __init__(self, raise_immediately: bool = False): def check(self, expression: bool, expectation: str, **kwargs) -> bool: """ - Checks if `expression` is True and adds / stores the check result for later analysis. + Checks if ``expression`` is True and adds / stores the check result for later analysis. :param expression: The boolean to be checked for :param expectation: A string describing, what the data was expected to look like (for later listing of @@ -969,7 +974,7 @@ def check_object_store(self, obj_store_1: model.DictObjectStore, obj_store_2: mo def check_attribute_equal(self, object_: object, attribute_name: str, expected_value: object, **kwargs) -> bool: """ - Checks if the value of the attribute in object_ is the same as expected_value and adds / stores the + Checks if the value of the attribute in ``object_`` is the same as ``expected_value`` and adds / stores the check result for later analysis. :param object_: The object of which the attribute shall be checked @@ -995,13 +1000,12 @@ def check_attribute_equal(self, object_: object, attribute_name: str, expected_v def check_element_in(self, object_: model.Referable, parent: object, **kwargs) -> bool: """ - Checks if object_ exist in parent and adds / stores the check result for later analysis. + Checks if ``object_`` exist in ``parent`` and adds / stores the check result for later analysis. :param object_: The object which shall be in parent - :param parent: The parent in which object_ shall be exist + :param parent: The parent in which ``object_`` shall be exist :param kwargs: Relevant values to add to the check result for further analysis (e.g. the compared values) :return: The value of expression to be used in control statements - Existence check: must exist in () """ return self.check(object_.parent == parent, "{} must exist in {}s".format(repr(object_), repr(parent)), @@ -1010,7 +1014,7 @@ def check_element_in(self, object_: model.Referable, parent: object, **kwargs) - def check_contained_element_length(self, object_: object, attribute_name: str, class_name: Type, length: int, **kwargs) -> bool: """ - Checks if the object_ has elements of class in attribute and + Checks if the ``object_`` has ``lenght`` elements of class ``class_name`` in attribute ``attribute_name`` and adds / stores the check result for later analysis. :param object_: The object of which the attribute shall be checked @@ -1032,10 +1036,10 @@ def check_contained_element_length(self, object_: object, attribute_name: str, c def check_is_instance(self, object_: object, class_name: Type, **kwargs) -> bool: """ - Checks if the value of the attribute in object_ is None and adds / stores the check result for later analysis. + Checks if ``object_`` is of type ``class_name`` and adds / stores the check result for later analysis. :param object_: The object of which the attribute shall be checked - :param class_name: The class name which the object_ shall be + :param class_name: The class name which the ``object_`` shall be :param kwargs: Relevant values to add to the check result for further analysis (e.g. the compared values) :return: The value of expression to be used in control statements """ @@ -1046,7 +1050,8 @@ def check_is_instance(self, object_: object, class_name: Type, **kwargs) -> bool def check_attribute_is_none(self, object_: object, attribute_name: str, **kwargs) -> bool: """ - Checks if the value of the attribute in object_ is None and adds / stores the check result for later analysis. + Checks if the value of the attribute in ``object_`` is :class:`None` and adds / stores the check result for + later analysis. :param object_: The object of which the attribute shall be checked :param attribute_name: The name of the attribute in the given object which shall be checked diff --git a/basyx/aas/examples/data/example_aas.py b/basyx/aas/examples/data/example_aas.py index b5dd86405..b4c6e1f8f 100644 --- a/basyx/aas/examples/data/example_aas.py +++ b/basyx/aas/examples/data/example_aas.py @@ -8,7 +8,7 @@ Module for the creation of an :class:`ObjectStore ` with an example asset administration shell and example submodels and an example concept description -To get this object store use the function :meth:`~aas.examples.data.example_aas.create_full_example`. +To get this object store use the function :meth:`~basyx.aas.examples.data.example_aas.create_full_example`. If you want to get single example objects or want to get more information use the other functions. """ import datetime @@ -792,7 +792,7 @@ def create_example_asset_administration_shell() -> \ model.AssetAdministrationShell: """ Creates an :class:`~basyx.aas.model.aas.AssetAdministrationShell` with references to an example - :class:`~aas.model.submodel.Submodel`. + :class:`~basyx.aas.model.submodel.Submodel`. :return: example :class:`~basyx.aas.model.aas.AssetAdministrationShell` """ diff --git a/basyx/aas/examples/data/example_aas_mandatory_attributes.py b/basyx/aas/examples/data/example_aas_mandatory_attributes.py index 3485c13b8..e91b1dfa4 100644 --- a/basyx/aas/examples/data/example_aas_mandatory_attributes.py +++ b/basyx/aas/examples/data/example_aas_mandatory_attributes.py @@ -6,13 +6,11 @@ # SPDX-License-Identifier: MIT """ Module for the creation of an :class:`ObjectStore ` with an example -:class:`~basyx.aas.model.aas.AssetAdministrationShell` and example -:class:`Submodels ` and a :class:`~aas.model.concept.ConceptDictionary` containing an -example :class:`~basyx.aas.model.concept.ConceptDescription`. All objects only contain mandatory -attributes. +:class:`~basyx.aas.model.aas.AssetAdministrationShell`, example :class:`Submodels ` +and an example :class:`~basyx.aas.model.concept.ConceptDescription`. All objects only contain mandatory attributes. To get this object store use the function -:meth:`~aas.examples.data.example_aas_mandatory_attributes.create_full_example`. If you want to get single example +:meth:`~basyx.aas.examples.data.example_aas_mandatory_attributes.create_full_example`. If you want to get single example objects or want to get more information use the other functions. """ import logging @@ -196,9 +194,9 @@ def create_example_asset_administration_shell() -> \ def create_example_empty_asset_administration_shell() -> model.AssetAdministrationShell: """ Creates an example empty :class:`~basyx.aas.model.aas.AssetAdministrationShell` with just - an empty :class:`~aas.model.aas.AssetInformation` and an :class:`~basyx.aas.model.base.Identifier` + an empty :class:`~basyx.aas.model.aas.AssetInformation` and an :class:`~basyx.aas.model.base.Identifier` - :return: example asset administration shell + :return: example :class:`~basyx.aas.model.aas.AssetAdministrationShell` """ asset_administration_shell = model.AssetAdministrationShell( asset_information=model.AssetInformation( diff --git a/basyx/aas/examples/data/example_submodel_template.py b/basyx/aas/examples/data/example_submodel_template.py index 75ec7e357..ee572143c 100644 --- a/basyx/aas/examples/data/example_submodel_template.py +++ b/basyx/aas/examples/data/example_submodel_template.py @@ -7,7 +7,7 @@ """ Module for the creation of an example :class:`~basyx.aas.model.submodel.Submodel` template containing all kind of :class:`SubmodelElements ` where the kind is -always `TEMPLATE`. +always ``TEMPLATE``. """ import datetime import logging @@ -22,7 +22,7 @@ def create_example_submodel_template() -> model.Submodel: """ Creates an example :class:`~basyx.aas.model.submodel.Submodel` template containing all kind of :class:`~basyx.aas.model.submodel.SubmodelElement` objects where the kind is always - `TEMPLATE` + ``TEMPLATE`` :return: example submodel """ diff --git a/basyx/aas/examples/tutorial_aasx.py b/basyx/aas/examples/tutorial_aasx.py index 1125b56ab..41e4fe509 100755 --- a/basyx/aas/examples/tutorial_aasx.py +++ b/basyx/aas/examples/tutorial_aasx.py @@ -3,12 +3,12 @@ # See http://creativecommons.org/publicdomain/zero/1.0/ for more information. """ Tutorial for exporting Asset Administration Shells with related objects and auxiliary files to AASX package files, using -the aas.adapter.aasx module from the Eclipse BaSyx Python SDK. +the :mod:`~basyx.aas.adapter.aasx` module from the Eclipse BaSyx Python SDK. -.. warning: +.. warning:: This tutorial is only valid for the current main branch of the Eclipse BaSyx Python SDK. With version 3.0 of *Details of the Asset Administration Shell* some specifications of AASX files will change, resulting in changes of - the `AASXWriter` interface. + the :class:`~basyx.aas.adapter.aasx.AASXWriter` interface. """ import datetime from pathlib import Path # Used for easier handling of auxiliary file's local path diff --git a/basyx/aas/model/__init__.py b/basyx/aas/model/__init__.py index 634e34c6c..fed5a7097 100644 --- a/basyx/aas/model/__init__.py +++ b/basyx/aas/model/__init__.py @@ -5,28 +5,7 @@ .. code-block:: python - from aas.model import AssetAdministrationShell, Submodel, Property - -The different modules are: - -aas.py - The main module, implementing high-level structures, such as AssetAdministrationShell and ConceptDictionary. - -base.py - Basic structures of the model, including all abstract classes and enumerations. This provides inheritance for the - higher level structures. - -concept.py - :class:`~basyx.aas.model.concept.ConceptDescription` from the AAS meta model - as well as specialized :class:`ConceptDescriptions ` like - :class:`~aas.model.concept.IEC61360ConceptDescription` - -provider.py - Providers for AAS objects, in order to store and retrieve :class:`~basyx.aas.model.base.Identifiable` objects by - their :class:`~basyx.aas.model.base.Identifier`. - -submodel.py - Meta-model of the submodels and events. + from basyx.aas.model import AssetAdministrationShell, Submodel, Property """ from .aas import * diff --git a/basyx/aas/model/_string_constraints.py b/basyx/aas/model/_string_constraints.py index d471201f4..88582a81c 100644 --- a/basyx/aas/model/_string_constraints.py +++ b/basyx/aas/model/_string_constraints.py @@ -5,19 +5,26 @@ # # SPDX-License-Identifier: MIT """ -This module implements constraint functions for the listed constrained string types and is meant for internal use only. +This module implements constraint functions for the listed constrained string types. All types are constrained in length (min and max), RevisionType and VersionType are additionally constrained -by a regular expression. The following types aliased in the base module are constrained: -- ContentType -- Identifier -- LabelType -- MessageTopicType -- NameType -- PathType -- RevisionType -- ShortNameType -- QualifierType -- VersionType +by a regular expression. + +.. warning:: + This module is intended for internal use only. + +The following types aliased in the :mod:`~basyx.aas.model.base` module are constrained: + +- :class:`~basyx.aas.model.base.ContentType` +- :class:`~basyx.aas.model.base.Identifier` +- :class:`~basyx.aas.model.base.LabelType` +- :class:`~basyx.aas.model.base.MessageTopicType` +- :class:`~basyx.aas.model.base.NameType` +- :class:`~basyx.aas.model.base.PathType` +- :class:`~basyx.aas.model.base.RevisionType` +- :class:`~basyx.aas.model.base.ShortNameType` +- :class:`~basyx.aas.model.base.QualifierType` +- :class:`~basyx.aas.model.base.VersionType` +- :class:`~basyx.aas.model.base.ValueTypeIEC61360` """ import re @@ -103,14 +110,14 @@ def check_version_type(value: str, type_name: str = "VersionType") -> None: def create_check_function(min_length: int = 0, max_length: Optional[int] = None, pattern: Optional[re.Pattern] = None) \ -> Callable[[str, str], None]: """ - Returns a new `check_type` function with mandatory `type_name` for the given min_length, max_length and pattern + Returns a new ``check_type`` function with mandatory ``type_name`` for the given min_length, max_length and pattern constraints. - This is the type-independent alternative to :func:`~.check_content_type`, :func:`~.check_identifier`, etc. - It is used for the definition of the :class:`ConstrainedLangStringSets `, - as a "Basic" constrained string type only exists for :class:`~aas.model.base.MultiLanguageNameType`, where all - values are :class:`ShortNames `. All other - :class:`:class:`ConstrainedLangStringSets ` use custom constraints. + This is the type-independent alternative to :func:`~.check_content_type`, :func:`~.check_identifier`, etc. It is + used for the definition of the :class:`ConstrainedLangStringSets `, + as a "Basic" constrained string type only exists for :class:`~basyx.aas.model.base.MultiLanguageNameType`, where all + values are :class:`ShortNames `. All other + :class:`:class:`ConstrainedLangStringSets ` use custom constraints. """ def check_fn(value: str, type_name: str) -> None: return check(value, type_name, min_length, max_length, pattern) diff --git a/basyx/aas/model/aas.py b/basyx/aas/model/aas.py index f9e31ff42..97eb160fc 100644 --- a/basyx/aas/model/aas.py +++ b/basyx/aas/model/aas.py @@ -7,10 +7,6 @@ """ The main module of the AAS meta-model. It is used to define the class structures of high level elements such as AssetAdministrationShell. - -This module contains the following classes from an up-to-down-level: - - :class:`~.AssetAdministrationShell` - - :class:`~.AssetInformation` """ from typing import Optional, Set, Iterable, List @@ -27,27 +23,29 @@ class AssetInformation: The asset may either represent an asset type or an asset instance. The asset has a globally unique identifier plus – if needed – additional domain specific (proprietary) identifiers. However, to support the corner case of very first phase of lifecycle where a stabilised/constant - global asset identifier does not already exist, the corresponding attribute “globalAssetId” is optional. + global asset identifier does not already exist, the corresponding attribute ``globalAssetId`` is optional. - *Constraint AASd-131*: The globalAssetId or at least one specificAssetId shall be defined for AssetInformation. + **Constraint AASd-131:** The globalAssetId or at least one specificAssetId shall be defined for AssetInformation. - :ivar asset_kind: Denotes whether the Asset is of :class:`~basyx.aas.model.base.AssetKind` "TYPE" or "INSTANCE". - Default is "INSTANCE". + :ivar asset_kind: Denotes whether the Asset is of :class:`~basyx.aas.model.base.AssetKind` ``TYPE`` or ``INSTANCE``. + Default is ``INSTANCE``. :ivar global_asset_id: :class:`~basyx.aas.model.base.Identifier` modelling the identifier of the asset the AAS is representing. This attribute is required as soon as the AAS is exchanged via partners in the life cycle of the asset. In a first phase of the life cycle the asset might not yet have a global id but already an internal identifier. The internal identifier would be modelled via - :attr:`~.specificAssetId`. + :attr:`~.specific_asset_id`. :ivar specific_asset_id: Additional domain specific, typically proprietary Identifier (Set of :class:`SpecificAssetIds ` for the asset like e.g. serial number etc. :ivar asset_type: In case AssetInformation/assetKind is applicable the AssetInformation/assetType is the asset ID of the type asset of the asset under consideration as identified by AssetInformation/globalAssetId. - *Note:* In case AssetInformation/assetKind is "Instance" then the AssetInformation/assetType - denotes which "Type" the asset is of. But it is also possible to have - an AssetInformation/assetType of an asset of kind "Type". + + .. note:: + In case AssetInformation/assetKind is ``Instance`` then the AssetInformation/assetType + denotes which ``Type`` the asset is of. But it is also possible to have + an AssetInformation/assetType of an asset of kind ``Type``. :ivar default_thumbnail: Thumbnail of the asset represented by the asset administration shell. Used as default. """ @@ -125,7 +123,7 @@ class AssetAdministrationShell(base.Identifiable, base.UniqueIdShortNamespace, b An Asset Administration Shell :ivar asset_information: :class:`~.AssetInformation` of the asset this AssetAdministrationShell is representing - :ivar ~.id: The globally unique id (:class:`~basyx.aas.model.base.Identifier`) of the element. + :ivar id: The globally unique id (:class:`~basyx.aas.model.base.Identifier`) of the element. (inherited from :class:`~basyx.aas.model.base.Identifiable`) :ivar id_short: Identifying string of the element within its name space. (inherited from :class:`~basyx.aas.model.base.Referable`) @@ -139,12 +137,12 @@ class AssetAdministrationShell(base.Identifiable, base.UniqueIdShortNamespace, b :ivar administration: :class:`~basyx.aas.model.base.AdministrativeInformation` of an :class:`~.basyx.aas.model.base.Identifiable` element. (inherited from :class:`~basyx.aas.model.base.Identifiable`) - :ivar ~.submodel: Unordered list of :class:`submodels ` to describe typically - the asset of an AAS. (Initialization-parameter: `submodel_`) + :ivar submodel: Unordered list of :class:`~basyx.aas.model.base.ModelReference` to + :class:`~basyx.aas.model.submodel.Submodel` to describe typically the asset of an AAS. :ivar derived_from: The :class:`reference ` to the AAS the AAs was derived from :ivar embedded_data_specifications: List of Embedded data specification. :ivar extension: An extension of the element. - (from :class:`~basyx.aas.model.base.HasExtensions`) + (from :class:`~basyx.aas.model.base.HasExtension`) """ def __init__(self, asset_information: AssetInformation, diff --git a/basyx/aas/model/base.py b/basyx/aas/model/base.py index 01701b61f..513c64758 100644 --- a/basyx/aas/model/base.py +++ b/basyx/aas/model/base.py @@ -57,12 +57,14 @@ class KeyTypes(Enum): **ReferableElements starting from 1000** - *Note:* DataElement is abstract, i. e. if a key uses :attr:`~.KeyTypes.DATA_ELEMENT` the reference may be - :class:`~basyx.aas.model.submodel.Property`, :class:`~basyx.aas.model.submodel.File` etc. + .. note:: + DataElement is abstract, i. e. if a key uses :attr:`~.KeyTypes.DATA_ELEMENT` the reference may be + :class:`~basyx.aas.model.submodel.Property`, :class:`~basyx.aas.model.submodel.File` etc. - *Note:* SubmodelElement is abstract, i.e. if a key uses :attr:`~.KeyTypes.SUBMODEL_ELEMENT` - the reference may be a :class:`~basyx.aas.model.submodel.Property`, a - :class:`~basyx.aas.model.submodel.SubmodelElementCollection`, an :class:`~basyx.aas.model.submodel.Operation` etc. + .. note:: + SubmodelElement is abstract, i.e. if a key uses :attr:`~.KeyTypes.SUBMODEL_ELEMENT` the reference may be a + :class:`~basyx.aas.model.submodel.Property`, a :class:`~basyx.aas.model.submodel.SubmodelElementCollection`, + an :class:`~basyx.aas.model.submodel.Operation` etc. :cvar ANNOTATED_RELATIONSHIP_ELEMENT: :class:`~basyx.aas.model.submodel.AnnotatedRelationshipElement` :cvar BASIC_EVENT_ELEMENT: :class:`~basyx.aas.model.submodel.BasicEventElement` @@ -194,16 +196,23 @@ class EntityType(Enum): class ModellingKind(Enum): """ Enumeration for denoting whether an element is a type or an instance. - *Note:* An :attr:`~.ModellingKind.INSTANCE` becomes an individual entity of a template, for example a device model, - by defining specific property values. - *Note:* In an object-oriented view, an instance denotes an object of a template (class). + .. note:: + An ``INSTANCE`` becomes an individual entity of a template, for example a device model, + by defining specific property values. + + .. note:: + In an object-oriented view, an instance denotes an object of a template (class). :cvar TEMPLATE: Software element which specifies the common attributes shared by all instances of the template :cvar INSTANCE: concrete, clearly identifiable component of a certain template. - *Note:* It becomes an individual entity of a template, for example a device model, by defining + + .. note:: + It becomes an individual entity of a template, for example a device model, by defining specific property values. - *Note:* In an object-oriented view, an instance denotes an object of a template (class). + + .. note:: + In an object-oriented view, an instance denotes an object of a template (class). """ TEMPLATE = 0 @@ -215,10 +224,13 @@ class AssetKind(Enum): """ Enumeration for denoting whether an asset is a type asset or an instance asset or whether this kind of classification is not applicable. - *Note:* :attr:`~.AssetKind.INSTANCE` becomes an individual entity of a type, for example a device, by defining - specific property values. - *Note:* In an object oriented view, an instance denotes an object of a class (of a type) + .. note:: + :attr:`~.AssetKind.INSTANCE` becomes an individual entity of a type, for example a device, by defining + specific property values. + + .. note:: + In an object oriented view, an instance denotes an object of a class (of a type) :cvar TYPE: Type asset :cvar INSTANCE: Instance asset @@ -236,9 +248,9 @@ class QualifierKind(Enum): :cvar CONCEPT_QUALIFIER: qualifies the semantic definition the element is referring to (HasSemantics/semanticId) :cvar TEMPLATE_QUALIFIER: qualifies the elements within a specific submodel on concept level. Template qualifiers - are only applicable to elements with kind="Template" + are only applicable to elements with kind=``Template`` :cvar VALUE_QUALIFIER: qualifies the value of the element and can change during run-time. Value qualifiers are only - applicable to elements with kind="Instance" + applicable to elements with kind=``Instance`` """ CONCEPT_QUALIFIER = 0 @@ -320,7 +332,7 @@ def clear(self) -> None: class ConstrainedLangStringSet(LangStringSet, metaclass=abc.ABCMeta): """ - A :class:`~.LangStringSet` with constrained values. + A :class:`LangStringSet` with constrained values. """ @abc.abstractmethod def __init__(self, dict_: Dict[str, str], constraint_check_fn: Callable[[str, str], None]): @@ -342,8 +354,8 @@ def __setitem__(self, key: str, value: str) -> None: class MultiLanguageNameType(ConstrainedLangStringSet): """ - A :class:`~.ConstrainedLangStringSet` where each value is a :class:`~.ShortNameType`. - See also: :func:`~aas.model._string_constraints.check_short_name_type` + A :class:`~.ConstrainedLangStringSet` where each value is a :class:`ShortNameType`. + See also: :func:`basyx.aas.model._string_constraints.check_short_name_type` """ def __init__(self, dict_: Dict[str, str]): super().__init__(dict_, _string_constraints.check_short_name_type) @@ -385,9 +397,9 @@ class Key: """ A key is a reference to an element by its id. - :ivar type_: Denote which kind of entity is referenced. In case type = :attr:`~.KeyTypes.GLOBAL_REFERENCE` then - the element is a global unique id. In all other cases the key references a model element of the same or - of another AAS. The name of the model element is explicitly listed. + :ivar type: Denote which kind of entity is referenced. In case type = :attr:`~.KeyTypes.GLOBAL_REFERENCE` then + the element is a global unique id. In all other cases the key references a model element of the same or + of another AAS. The name of the model element is explicitly listed. :ivar value: The key value, for example an IRDI or IRI """ @@ -422,11 +434,11 @@ def __eq__(self, other: object) -> bool: def __hash__(self): return hash((self.value, self.type)) - def get_identifier(self) -> Optional["Identifier"]: + def get_identifier(self) -> Optional[Identifier]: """ - Get an :class:`~.Identifier` object corresponding to this key, if it is an identifiable key. + Get an :class:`Identifier` object corresponding to this key, if it is an identifiable key. - :return: None if this is no identifiable key, otherwise a corresponding :class:`~.Identifier` string. + :return: None if this is no identifiable key, otherwise a corresponding :class:`Identifier` string. """ if not self.type.is_aas_identifiable: return None @@ -529,14 +541,10 @@ class HasExtension(Namespace, metaclass=abc.ABCMeta): <> - *Constraint AASd-077:* The name of an extension within HasExtensions needs to be unique. - - TODO: This constraint is not yet implemented, a new Class for CustomSets should be implemented + **Constraint AASd-077:** The name of an Extension within HasExtensions needs to be unique. :ivar namespace_element_sets: List of :class:`NamespaceSets ` :ivar extension: A :class:`~.NamespaceSet` of :class:`Extensions <.Extension>` of the element. - :ivar _MEMBER_OBJ_TYPE: :class:`_NSO ` - :ivar _ATTRIBUTE_NAME: Specific attribute name `. """ @abc.abstractmethod def __init__(self) -> None: @@ -578,15 +586,18 @@ class Referable(HasExtension, metaclass=abc.ABCMeta): <> - *Constraint AASd-001:* In case of a referable element not being an identifiable element the - idShort is mandatory and used for referring to the element in its name space. - *Constraint AASd-002:* idShort shall only feature letters, digits, underscore ("_"); starting - mandatory with a letter. - *Constraint AASd-004:* Add parent in case of non identifiable elements. - *Constraint AASd-022:* idShort of non-identifiable referables shall be unique in its namespace (case-sensitive) + **Constraint AASd-001:** In case of a referable element not being an identifiable element the + idShort is mandatory and used for referring to the element in its name space. + + **Constraint AASd-002:** idShort shall only feature letters, digits, underscore (``_``); starting + mandatory with a letter. + + **Constraint AASd-004:** Add parent in case of non identifiable elements. + + **Constraint AASd-022:** idShort of non-identifiable referables shall be unique in its namespace (case-sensitive) :ivar _id_short: Identifying string of the element within its name space - :ivar ~.category: The category is a value that gives further meta information w.r.t. to the class of the element. + :ivar category: The category is a value that gives further meta information w.r.t. to the class of the element. It affects the expected existence of attributes and the applicability of constraints. :ivar description: Description or comments on the element. :ivar parent: Reference (in form of a :class:`~.UniqueIdShortNamespace`) to the next referable parent element @@ -654,9 +665,11 @@ def _set_id_short(self, id_short: Optional[NameType]): """ Check the input string - Constraint AASd-002: idShort of Referables shall only feature letters, digits, underscore ("_"); starting - mandatory with a letter. I.e. [a-zA-Z][a-zA-Z0-9_]+ - Constraint AASd-022: idShort of non-identifiable referables shall be unique in its namespace (case-sensitive) + **Constraint AASd-002:** idShort of Referables shall only feature letters, digits, underscore (``_``); starting + mandatory with a letter. I.e. ``[a-zA-Z][a-zA-Z0-9_]+`` + + **Constraint AASd-022:** idShort of non-identifiable referables shall be unique in its namespace + (case-sensitive) :param id_short: Identifying string of the element within its name space :raises ValueError: if the constraint is not fulfilled @@ -714,7 +727,7 @@ def update(self, If there is no source in any ancestor, this function will do nothing :param max_age: Maximum age of the local data in seconds. This method may return early, if the previous update - of the object has been performed less than `max_age` seconds ago. + of the object has been performed less than ``max_age`` seconds ago. :param recursive: Also call update on all children of this object. Default is True :param _indirect_source: Internal parameter to avoid duplicate updating. :raises backends.BackendError: If no appropriate backend or the data source is not available @@ -775,7 +788,7 @@ def update_from(self, other: "Referable", update_source: bool = False): Internal function to updates the object's attributes from another object of a similar type. This function should not be used directly. It is typically used by backend implementations (database adapters, - protocol clients, etc.) to update the object's data, after `update()` has been called. + protocol clients, etc.) to update the object's data, after ``update()`` has been called. :param other: The object to update from :param update_source: Update the source attribute with the other's source attribute. This is not propagated @@ -859,8 +872,8 @@ class Reference(metaclass=abc.ABCMeta): <> - *Constraint AASd-121:* For References the value of Key/type of the first key of Reference/keys shall be one of - GloballyIdentifiables. + **Constraint AASd-121:** For References the value of Key/type of the first key of Reference/keys shall be one of + GloballyIdentifiables. :ivar key: Ordered list of unique reference in its name space, each key referencing an element. The complete list of keys may for example be concatenated to a path that then gives unique access to an element @@ -903,11 +916,12 @@ class ExternalReference(Reference): A reference is an ordered list of keys, each key referencing an element. The complete list of keys may for example be concatenated to a path that then gives unique access to an element or entity. - *Constraint AASd-122:* For external references, i.e. References with Reference/type = ExternalReference, - the value of Key/type of the first key of Reference/keys shall be one of GenericGloballyIdentifiables. - *Constraint AASd-124:* For external references, i.e. References with Reference/type = ExternalReference, - the last key of Reference/keys shall be either one of GenericGloballyIdentifiables - or one of GenericFragmentKeys. + **Constraint AASd-122:** For external references, i.e. References with Reference/type = ExternalReference, + the value of Key/type of the first key of Reference/keys shall be one of GenericGloballyIdentifiables. + + **Constraint AASd-124:** For external references, i.e. References with Reference/type = ExternalReference, + the last key of Reference/keys shall be either one of GenericGloballyIdentifiables + or one of GenericFragmentKeys. :ivar key: Ordered list of unique reference in its name space, each key referencing an element. The complete list of keys may for example be concatenated to a path that then gives unique access to an element @@ -936,27 +950,31 @@ class ModelReference(Reference, Generic[_RT]): This is a special construct of the implementation to allow typed references and de-referencing. - *Constraint AASd-123:* For model references, i.e. References with Reference/type = ModelReference, - the value of Key/type of the first key of Reference/keys shall be one of AasIdentifiables. - *Constraint AASd-125:* For model references, i.e. References with Reference/type = ModelReference with more than - one key in Reference/keys, the value of Key/type of each of the keys following the first key of Reference/keys - shall be one of FragmentKeys. - *Constraint AASd-126:* For model references, i.e. References with Reference/type = ModelReference with more than - one key in Reference/keys, the value of Key/type of the last Key in the reference key chain may be one of - GenericFragmentKeys, or no key at all shall have a value out of GenericFragmentKeys. - *Constraint AASd-127:* For model references, i.e. References with Reference/type = ModelReference with more than - one key in Reference/keys, a key with Key/type FragmentReference shall be preceded by a key with Key/type - File or Blob. All other AAS fragments, i.e. Key/type values out of AasSubmodelElements, - do not support fragments. - *Constraint AASd-128:* For model references the Key/value of a Key preceded by a Key with - Key/type=SubmodelElementList is an integer number denoting the position in the array of the - submodel element list. + **Constraint AASd-123:** For model references, i.e. References with Reference/type = ModelReference, + the value of Key/type of the first key of Reference/keys shall be one of AasIdentifiables. + + **Constraint AASd-125:** For model references, i.e. References with Reference/type = ModelReference with more than + one key in Reference/keys, the value of Key/type of each of the keys following the first key of Reference/keys + shall be one of FragmentKeys. + + **Constraint AASd-126:** For model references, i.e. References with Reference/type = ModelReference with more than + one key in Reference/keys, the value of Key/type of the last Key in the reference key chain may be one of + GenericFragmentKeys, or no key at all shall have a value out of GenericFragmentKeys. + + **Constraint AASd-127:** For model references, i.e. References with Reference/type = ModelReference with more than + one key in Reference/keys, a key with Key/type FragmentReference shall be preceded by a key with Key/type + File or Blob. All other AAS fragments, i.e. Key/type values out of AasSubmodelElements, + do not support fragments. + + **Constraint AASd-128:** For model references the Key/value of a Key preceded by a Key with + Key/type=SubmodelElementList is an integer number denoting the position in the array of the + submodel element list. :ivar key: Ordered list of unique :class:`Keys <.Key>` in its name space, each key referencing an element. The complete list of keys may for example be concatenated to a path that then gives unique access to an element or entity. - :ivar ~.type: The type of the referenced object (additional parameter, not from the AAS Metamodel) - *Initialization parameter:* `type_` + :ivar type: The type of the referenced object (additional parameter, not from the AAS Metamodel) + *Initialization parameter:* ``type_`` :ivar referred_semantic_id: SemanticId of the referenced model element. For external references there typically is no semantic id. """ @@ -996,7 +1014,7 @@ def resolve(self, provider_: "provider.AbstractObjectProvider") -> _RT: :raises TypeError: If one of the intermediate objects on the path is not a :class:`~basyx.aas.model.base.Namespace` :raises UnexpectedTypeError: If the retrieved object is not of the expected type (or one of its subclasses). The - object is stored in the `value` attribute of the exception + object is stored in the ``value`` attribute of the exception :raises KeyError: If the reference could not be resolved """ @@ -1045,10 +1063,10 @@ def resolve(self, provider_: "provider.AbstractObjectProvider") -> _RT: def get_identifier(self) -> Identifier: """ - Retrieve the :class:`~.Identifier` of the :class:`~.Identifiable` object, which is referenced or in which the + Retrieve the :class:`Identifier` of the :class:`~.Identifiable` object, which is referenced or in which the referenced :class:`~.Referable` is contained. - :returns: :class:`~.Identifier` + :returns: :class:`Identifier` :raises ValueError: If this :class:`~.ModelReference` does not include a Key of AasIdentifiable type """ try: @@ -1123,12 +1141,10 @@ class DataSpecificationContent: which additional attributes shall be added to the element instance that references the data specification template and meta information about the template itself. - *Constraint AASc-3a-050:* If the `Data_specification_IEC_61360` is used - for an element, the value of `Has_data_specification.embedded_data_specifications` - shall contain the external reference to the IRI of the corresponding data specification - template - https://admin-shell.io/DataSpecificationTemplates/DataSpecificationIEC61360/3/0 - + **Constraint AASc-3a-050:** If the ``Data_specification_IEC_61360`` is used + for an element, the value of ``HasDataSpecification.embedded_data_specifications`` + shall contain the external reference to the IRI of the corresponding data specification + template ``https://admin-shell.io/DataSpecificationTemplates/DataSpecificationIEC61360/3/0`` """ @abc.abstractmethod def __init__(self): @@ -1162,7 +1178,8 @@ class HasDataSpecification(metaclass=abc.ABCMeta): element may or shall have. The data specifications used are explicitly specified with their global ID. - *Note:* Please consider, that we have not implemented DataSpecification template class + .. warning:: + Please consider, that we do not implement the DataSpecification template class. :ivar embedded_data_specifications: List of :class:`~.EmbeddedDataSpecification`. """ @@ -1180,26 +1197,28 @@ class AdministrativeInformation(HasDataSpecification): """ Administrative meta-information for an element like version information. - *Constraint AASd-005:* If AdministrativeInformation/version is not specified then also - AdministrativeInformation/revision shall be unspecified. This means, a revision - requires a version. if there is no version there is no revision neither. Revision is - optional. + **Constraint AASd-005:** If AdministrativeInformation/version is not specified then also + AdministrativeInformation/revision shall be unspecified. This means, a revision + requires a version. if there is no version there is no revision neither. Revision is + optional. :ivar version: Version of the element. :ivar revision: Revision of the element. :ivar creator: The subject ID of the subject responsible for making the element :ivar template_id: Identifier of the template that guided the creation of the element + :ivar embedded_data_specifications: List of Embedded data specification. + used by the element. - *Note:* In case of a submodel, the template ID is the identifier of the submodel template that guided the - creation of the submodel. - - *Note:* The submodel template ID is not relevant for validation. Here, the Submodel/semanticId shall be used + .. note:: + In case of a submodel, the template ID is the identifier of the submodel template that guided the + creation of the submodel. - *Note:* Usage of the template ID is not restricted to submodel instances. - The creation of submodel templates can also be guided by another submodel template. + .. note:: + The submodel template ID is not relevant for validation. Here, the Submodel/semanticId shall be used - :ivar embedded_data_specifications: List of Embedded data specification. - used by the element. + .. note:: + Usage of the template ID is not restricted to submodel instances. + The creation of submodel templates can also be guided by another submodel template. """ def __init__(self, @@ -1252,12 +1271,12 @@ def __repr__(self) -> str: @_string_constraints.constrain_identifier("id") class Identifiable(Referable, metaclass=abc.ABCMeta): """ - An element that has a globally unique :class:`~.Identifier`. + An element that has a globally unique :class:`Identifier`. <> :ivar administration: :class:`~.AdministrativeInformation` of an identifiable element. - :ivar ~.id: The globally unique id of the element. + :ivar id: The globally unique id of the element. """ @abc.abstractmethod def __init__(self) -> None: @@ -1276,19 +1295,19 @@ def __repr__(self) -> str: class ConstrainedList(MutableSequence[_T], Generic[_T]): """ A type of list that can be constrained by hooks, useful when implementing AASd constraints. This list can be - initialized with an `item_add_hook`, `item_set_hook` and an `item_del_hook`. + initialized with an ``item_add_hook``, ``item_set_hook`` and an ``item_del_hook``. The item_add_hook is called every time an item is added to the list. It is passed the item that is added and all items currently contained in the list. - The `item_set_hook` is called every time one or multiple items are overwritten with one or multiple new items, à la - `list[i] = new_item` or `list[i:j] = new_items`. It is passed the item(s) about to replaced, the new item(s) and all - items currently contained in the list. - Note that this can also be used to clear the list, e.g. `list[:] = []`. Thus, to ensure that a list is never empty, - `item_set_hook` must be used in addition to `item_del_hook`. + The ``item_set_hook`` is called every time one or multiple items are overwritten with one or multiple new items, + à la ``list[i] = new_item`` or ``list[i:j] = new_items``. It is passed the item(s) about to replaced, the new + item(s) and all items currently contained in the list. + Note that this can also be used to clear the list, e.g. ``list[:] = []``. Thus, to ensure that a list is never + empty, ``item_set_hook`` must be used in addition to ``item_del_hook``. - Finally, `item_del_hook` is called whenever an item is removed from the list, (e.g. via `.remove()`, `.pop()` or - `del list[i]`. It is passed the item about to be deleted and the current list elements. + Finally, ``item_del_hook`` is called whenever an item is removed from the list, (e.g. via ``.remove()``, ``.pop()`` + or ``del list[i]``. It is passed the item about to be deleted and the current list elements. """ def __init__(self, items: Iterable[_T], item_add_hook: Optional[Callable[[_T, List[_T]], None]] = None, @@ -1383,8 +1402,8 @@ class HasSemantics(metaclass=abc.ABCMeta): <> - *Constraint AASd-118:* If a supplemental semantic ID (HasSemantics/supplementalSemanticId) is defined, - there shall also be a main semantic ID (HasSemantics/semanticId). + **Constraint AASd-118:** If a supplemental semantic ID (HasSemantics/supplementalSemanticId) is defined, + there shall also be a main semantic ID (HasSemantics/semanticId). :ivar semantic_id: Identifier of the semantic definition of the element. It is called semantic id of the element. The semantic id may either reference an external global id or it may reference a referable model @@ -1445,8 +1464,8 @@ class Extension(HasSemantics): Single extension of an element :ivar name: An extension of the element. - :ivar value_type: Type (:class:`~.DataTypeDefXsd`) of the value of the extension. Default: xsd:string - :ivar value: Value (:class:`~.ValueDataType`) of the extension + :ivar value_type: Type (:class:`DataTypeDefXsd`) of the value of the extension. Default: xsd:string + :ivar value: Value (:class:`ValueDataType`) of the extension :ivar refers_to: An iterable of :class:`~.ModelReference` to elements the extension refers to :ivar semantic_id: The semantic_id defined in the :class:`~.HasSemantics` class. :ivar supplemental_semantic_id: Identifier of a supplemental semantic definition of the element. It is called @@ -1533,14 +1552,14 @@ def kind(self): class Qualifiable(Namespace, metaclass=abc.ABCMeta): """ - Abstract baseclass for all objects which form a Namespace to hold :class:`~.Qualifier` objects and resolve them by + Abstract baseclass for all objects which form a Namespace to hold :class:`Qualifier` objects and resolve them by their type. <> :ivar namespace_element_sets: A list of all :class:`NamespaceSets <.NamespaceSet>` of this Namespace - :ivar qualifier: Unordered list of :class:`Qualifiers <~.Qualifier>` that gives additional qualification of a - qualifiable element. + :ivar qualifier: Unordered list of :class:`Qualifiers ` that gives additional qualification of a + qualifiable element. """ @abc.abstractmethod def __init__(self) -> None: @@ -1579,14 +1598,15 @@ class Qualifier(HasSemantics): """ A qualifier is a type-value pair that makes additional statements w.r.t. the value of the element. - *Constraint AASd-006:* If both, the value and the valueId of a Qualifier are present, the value needs - to be identical to the value of the referenced coded value in Qualifier/valueId. - *Constraint AASd-020:* The value of Qualifier/value shall be consistent with the - data type as defined in Qualifier/valueType. + **Constraint AASd-006:** If both, the value and the valueId of a Qualifier are present, the value needs + to be identical to the value of the referenced coded value in Qualifier/valueId. + + **Constraint AASd-020:** The value of Qualifier/value shall be consistent with the + data type as defined in Qualifier/valueType. - :ivar type: The type (:class:`~.QualifierType`) of the qualifier that is applied to the element. - :ivar value_type: Data type (:class:`~.DataTypeDefXsd`) of the qualifier value - :ivar value: The value (:class:`~.ValueDataType`) of the qualifier. + :ivar type: The type (:class:`QualifierType`) of the qualifier that is applied to the element. + :ivar value_type: Data type (:class:`DataTypeDefXsd`) of the qualifier value + :ivar value: The value (:class:`ValueDataType`) of the qualifier. :ivar value_id: :class:`~.Reference` to the global unique id of a coded value. :ivar semantic_id: The semantic_id defined in :class:`~.HasSemantics`. :ivar supplemental_semantic_id: Identifier of a supplemental semantic definition of the element. It is called @@ -1685,7 +1705,7 @@ class UniqueIdShortNamespace(Namespace, metaclass=abc.ABCMeta): Abstract baseclass for all objects which form a Namespace to hold :class:`~.Referable` objects and resolve them by their id_short. - A Namespace can contain multiple :class:`NamespaceSets <~.NamespaceSet>`, which contain :class:`~.Referable` objects + A Namespace can contain multiple :class:`NamespaceSets `, which contain :class:`~.Referable` objects of different types. However, the id_short of each object must be unique across all NamespaceSets of one Namespace. @@ -1719,7 +1739,7 @@ def add_referable(self, referable: Referable) -> None: def remove_referable(self, id_short: NameType) -> None: """ - Remove a :class:`~.Referable` from this Namespace by its `id_short` + Remove a :class:`~.Referable` from this Namespace by its ``id_short`` :param id_short: id_short :raises KeyError: If no such :class:`~.Referable` can be found @@ -1785,13 +1805,13 @@ class NamespaceSet(MutableSet[_NSO], Generic[_NSO]): Helper class for storing AAS objects of a given type in a Namespace and find them by their unique attribute. This class behaves much like a set of AAS objects of a defined type, but uses dicts internally to rapidly - find those objects by their unique attribute. Additionally, it manages the `parent` attribute of the stored + find those objects by their unique attribute. Additionally, it manages the ``parent`` attribute of the stored AAS objects and ensures the uniqueness of their attribute within the Namespace. - Use `add()`, `remove()`, `pop()`, `discard()`, `clear()`, `len()`, `x in` checks and iteration just like on a - normal set of AAS objects. To get an AAS object by its attribute, use `get_object()` or `get()` (the latter one - allows a default argument and returns None instead of raising a KeyError). As a bonus, the `x in` check supports - checking for existence of attribute *or* a concrete AAS object. + Use ``add()``, ``remove()``, ``pop()``, ``discard()``, ``clear()``, ``len()``, ``x in`` checks and iteration just + like on a normal set of AAS objects. To get an AAS object by its attribute, use ``get_object()`` or ``get()`` + (the latter one allows a default argument and returns None instead of raising a KeyError). As a bonus, the ``x in`` + check supports checking for existence of attribute *or* a concrete AAS object. :ivar parent: The Namespace this set belongs to @@ -1802,7 +1822,7 @@ class NamespaceSet(MutableSet[_NSO], Generic[_NSO]): indicates if the attribute should be matched case-sensitive (true) or case-insensitive (false) :param items: A given list of AAS items to be added to the set - :raises KeyError: When `items` contains multiple objects with same unique attribute + :raises KeyError: When ``items`` contains multiple objects with same unique attribute """ def __init__(self, parent: Union[UniqueIdShortNamespace, UniqueSemanticIdNamespace, Qualifiable, HasExtension], attribute_names: List[Tuple[str, bool]], items: Iterable[_NSO] = (), @@ -1812,7 +1832,7 @@ def __init__(self, parent: Union[UniqueIdShortNamespace, UniqueSemanticIdNamespa """ Initialize a new NamespaceSet. - This initializer automatically takes care of adding this set to the `namespace_element_sets` list of the + This initializer automatically takes care of adding this set to the ``namespace_element_sets`` list of the Namespace. :param parent: The Namespace this set belongs to @@ -1827,7 +1847,7 @@ def __init__(self, parent: Union[UniqueIdShortNamespace, UniqueSemanticIdNamespa :param item_id_del_hook: A function that is called for each item removed from this NamespaceSet. Used in SubmodelElementList to unset id_shorts on removal. Should not be used for constraint checking, as the hook is called after removal. - :raises AASConstraintViolation: When `items` contains multiple objects with same unique attribute or when an + :raises AASConstraintViolation: When ``items`` contains multiple objects with same unique attribute or when an item doesn't has an identifying attribute """ self.parent = parent @@ -1989,7 +2009,7 @@ def get(self, attribute_name: str, attribute_value: str, default: Optional[_NSO] :param attribute_name: name of the attribute to search for :param attribute_value: value of the attribute to search for :param default: An object to be returned, if no object with the given attribute is found - :return: The AAS object with the given attribute in the set. Otherwise the `default` object or None, if + :return: The AAS object with the given attribute in the set. Otherwise the ``default`` object or None, if none is given. """ backend, case_sensitive = self._backend[attribute_name] @@ -2056,7 +2076,7 @@ def __init__(self, parent: Union[UniqueIdShortNamespace, UniqueSemanticIdNamespa """ Initialize a new OrderedNamespaceSet. - This initializer automatically takes care of adding this set to the `namespace_element_sets` list of the + This initializer automatically takes care of adding this set to the ``namespace_element_sets`` list of the Namespace. :param parent: The Namespace this set belongs to @@ -2071,7 +2091,7 @@ def __init__(self, parent: Union[UniqueIdShortNamespace, UniqueSemanticIdNamespa :param item_id_del_hook: A function that is called for each item removed from this NamespaceSet. Used in SubmodelElementList to unset id_shorts on removal. Should not be used for constraint checking, as the hook is called after removal. - :raises AASConstraintViolation: When `items` contains multiple objects with same unique attribute or when an + :raises AASConstraintViolation: When ``items`` contains multiple objects with same unique attribute or when an item doesn't has an identifying attribute """ self._order: List[_NSO] = [] @@ -2163,8 +2183,8 @@ class SpecificAssetId(HasSemantics): A specific asset ID describes a generic supplementary identifying attribute of the asset. The specific asset ID is not necessarily globally unique. - *Constraint AASd-133:* SpecificAssetId/externalSubjectId shall be a global reference, - i.e. Reference/type = ExternalReference + **Constraint AASd-133:** SpecificAssetId/externalSubjectId shall be a global reference, + i.e. Reference/type = ExternalReference :ivar name: Key of the identifier :ivar value: The value of the identifier with the corresponding key. @@ -2245,7 +2265,7 @@ def __init__(self, constraint_id: int, message: str): @unique class DataTypeIEC61360(Enum): """ - Data types for data_type in :class:`DataSpecificationIEC61360 <.IEC61360ConceptDescription>` + Data types for data_type in :class:`DataSpecificationIEC61360` The data types are: :cvar DATE: @@ -2292,7 +2312,7 @@ class DataTypeIEC61360(Enum): @unique class IEC61360LevelType(Enum): """ - Level types for the level_type in :class:`DataSpecificationIEC61360 <.IEC61360ConceptDescription>` + Level types for the level_type in :class:`DataSpecificationIEC61360` The level types are: :cvar MIN: diff --git a/basyx/aas/model/concept.py b/basyx/aas/model/concept.py index d875667d7..3f3029b23 100644 --- a/basyx/aas/model/concept.py +++ b/basyx/aas/model/concept.py @@ -5,8 +5,7 @@ # # SPDX-License-Identifier: MIT """ -This module contains the class :class:`~.ConceptDescription` from the AAS meta model -as well as specialized :class:`ConceptDescriptions <.ConceptDescription>` like :class:`~.IEC61360ConceptDescription`. +This module contains the class :class:`~.ConceptDescription` from the AAS meta model. """ from typing import Optional, Set, Iterable, List @@ -35,10 +34,10 @@ class ConceptDescription(base.Identifiable, base.HasDataSpecification): The description of the concept should follow a standardized schema (realized as data specification template). - *Note:* Compare :attr:`~.ConceptDescription.is_case_of` to is-case-of relationship in ISO 13584-32 & IEC EN 61360 + .. note:: + Compare ``is_case_of`` to is-case-of relationship in ISO 13584-32 & IEC EN 61360 - :ivar ~.id: The globally unique id of the element. (inherited from - :class:`~basyx.aas.model.base.Identifiable`) + :ivar id: The globally unique id of the element. (inherited from :class:`~basyx.aas.model.base.Identifiable`) :ivar is_case_of: Unordered list of global :class:`References ` to external definitions the concept is compatible to or was derived from. :ivar id_short: Identifying string of the element within its name space. (inherited from diff --git a/basyx/aas/model/datatypes.py b/basyx/aas/model/datatypes.py index 2782bcc4b..a52e288d3 100644 --- a/basyx/aas/model/datatypes.py +++ b/basyx/aas/model/datatypes.py @@ -9,13 +9,13 @@ them from/into their lexical XML representation. See https://www.w3.org/TR/xmlschema-2/#built-in-datatypes for the XSD simple type hierarchy and more information on the -datatypes. All types from this type hierarchy (except for `token` and its descendants) are implemented or aliased in +datatypes. All types from this type hierarchy (except for ``token`` and its descendants) are implemented or aliased in this module using their pythonized: Duration, DateTime, GMonthDay, String, Integer, Decimal, Short …. These types are meant to be used directly for data values in the context of Asset Administration Shells. There are three conversion functions for usage in BaSyx Python SDK's model and adapters: -* :meth:`~aas.model.datatypes.xsd_repr` serializes any XSD type from this module into it's lexical representation +* :meth:`~basyx.aas.model.datatypes.xsd_repr` serializes any XSD type from this module into its lexical representation * :meth:`~basyx.aas.model.datatypes.from_xsd` parses an XSD type from its lexical representation (its required to name the type for unambiguous conversion) * :meth:`~basyx.aas.model.datatypes.trivial_cast` type-cast a python value into an XSD type, @@ -404,9 +404,9 @@ def trivial_cast(value, type_: Type[AnyXSDType]) -> AnyXSDType: # workaround. W However, we want to stay strongly typed, so we only allow this type-cast if it is trivial to do, i.e. does not change the value's semantics. Examples, where this holds true: - * int → :class:`basyx.aas.model.datatypes.Int` (if the value is in the expected range) - * bytes → :class:`basyx.aas.model.datatypes.Base64Binary` - * datetime.date → :class:`aas.model.datatypes.Date` + * int → :class:`~basyx.aas.model.datatypes.Int` (if the value is in the expected range) + * bytes → :class:`~basyx.aas.model.datatypes.Base64Binary` + * datetime.date → :class:`~basyx.aas.model.datatypes.Date` Yet, it is not allowed to cast float → :class:`basyx.aas.model.datatypes.Int`. diff --git a/basyx/aas/model/provider.py b/basyx/aas/model/provider.py index 1cc831281..c1bc4bdb8 100644 --- a/basyx/aas/model/provider.py +++ b/basyx/aas/model/provider.py @@ -47,7 +47,7 @@ def get(self, identifier: Identifier, default: Optional[Identifiable] = None) -> :param default: An object to be returned, if no object with the given :class:`id ` is found :return: The :class:`~basyx.aas.model.base.Identifiable` object with the given - :class:`id ` in the provider. Otherwise the `default` object + :class:`id ` in the provider. Otherwise the ``default`` object or None, if none is given. """ try: @@ -68,8 +68,8 @@ class AbstractObjectStore(AbstractObjectProvider, MutableSet[_IT], Generic[_IT], This includes local object stores (like :class:`~.DictObjectStore`) and database :class:`Backends `. - The AbstractObjectStore inherits from the `MutableSet` abstract collections class and therefore implements all the - functions of this class. + The AbstractObjectStore inherits from the :class:`~collections.abc.MutableSet` abstract collections class and + therefore implements all the functions of this class. """ @abc.abstractmethod def __init__(self): diff --git a/basyx/aas/model/submodel.py b/basyx/aas/model/submodel.py index 2a674c37c..6e7cc5022 100644 --- a/basyx/aas/model/submodel.py +++ b/basyx/aas/model/submodel.py @@ -22,11 +22,12 @@ class SubmodelElement(base.Referable, base.Qualifiable, base.HasSemantics, """ A submodel element is an element suitable for the description and differentiation of assets. - *Note:* The concept of type and instance applies to submodel elements. :class:`Properties <.Property>` are special - submodel elements. The property types are defined in dictionaries (like the IEC Common Data Dictionary or eCl\\@ss), - they do not have a value. The property type (`kind=Type`) is also called data element type in some standards. - The property instances (`kind=Instance`) typically have a value. A property instance is also called - property-value pair in certain standards. + .. note:: + The concept of type and instance applies to submodel elements. :class:`Properties <.Property>` are special + submodel elements. The property types are defined in dictionaries (like the IEC Common Data Dictionary or + eCl\\@ss), they do not have a value. The property type (``kind=Type``) is also called data element type in some + standards. The property instances (``kind=Instance``) typically have a value. A property instance is also called + property-value pair in certain standards. :ivar id_short: Identifying string of the element within its name space. (inherited from :class:`~basyx.aas.model.base.Referable`) @@ -89,8 +90,7 @@ class Submodel(base.Identifiable, base.HasSemantics, base.HasKind, base.Qualifia into distinguishable parts. Each submodel refers to a well-defined domain or subject matter. Submodels can become standardized and thus become submodel types. Submodels can have different life-cycles. - :ivar ~.id: The globally unique id of the element. - (inherited from :class:`~basyx.aas.model.base.Identifiable`) + :ivar id: The globally unique id of the element. (inherited from :class:`~basyx.aas.model.base.Identifiable`) :ivar submodel_element: Unordered list of :class:`SubmodelElements <.SubmodelElement>` :ivar id_short: Identifying string of the element within its name space. (inherited from :class:`~basyx.aas.model.base.Referable`) @@ -109,8 +109,8 @@ class Submodel(base.Identifiable, base.HasSemantics, base.HasKind, base.Qualifia (inherited from :class:`~basyx.aas.model.base.HasSemantics`) :ivar qualifier: Unordered list of Qualifiers that gives additional qualification of a qualifiable element. (from :class:`~basyx.aas.model.base.Qualifiable`) - :ivar kind: Kind of the element: Either `TYPE` or `INSTANCE`. Default is `INSTANCE`. (inherited from - :class:`aas.model.base.HasKind`) + :ivar kind: Kind of the element: Either ``TYPE`` or ``INSTANCE``. Default is ``INSTANCE``. (inherited from + :class:`~basyx.aas.model.base.HasKind`) :ivar extension: An extension of the element. (inherited from :class:`basyx.aas.model.base.HasExtension`) :ivar supplemental_semantic_id: Identifier of a supplemental semantic definition of the element. It is called @@ -225,8 +225,8 @@ class Property(DataElement): """ A property is a :class:`DataElement` that has a single value. - *Constraint AASd-007:* If both, the value and the valueId of a Qualifier are present, - the value needs to be identical to the value of the referenced coded value in Qualifier/valueId. + **Constraint AASd-007:** If both, the value and the valueId of a Qualifier are present, + the value needs to be identical to the value of the referenced coded value in Qualifier/valueId. :ivar id_short: Identifying string of the element within its name space. (inherited from :class:`~basyx.aas.model.base.Referable`) @@ -295,9 +295,9 @@ class MultiLanguageProperty(DataElement): """ A multi language property is a :class:`~.DataElement` that has a multi language value. - *Constraint AASd-012*: if both the MultiLanguageProperty/value and the MultiLanguageProperty/valueId are present, - the meaning must be the same for each string in a specific language, - as specified inMultiLanguageProperty/valueId. + **Constraint AASd-012:** if both the MultiLanguageProperty/value and the MultiLanguageProperty/valueId are present, + the meaning must be the same for each string in a specific language, + as specified inMultiLanguageProperty/valueId. :ivar id_short: Identifying string of the element within its name space. (inherited from :class:`~basyx.aas.model.base.Referable`) @@ -351,8 +351,8 @@ class Range(DataElement): """ A range is a :class:`~.DataElement` that has a range value. - *Constraint AASd-013:* In case of a range with `kind=Instance` either the min or the max value or both - need to be defined + **Constraint AASd-013:** In case of a range with ``kind=Instance`` either the min or the max value or both + need to be defined :ivar id_short: Identifying string of the element within its name space. (inherited from :class:`~basyx.aas.model.base.Referable`) @@ -434,7 +434,8 @@ class Blob(DataElement): A BLOB is a :class:`~.DataElement` that represents a file that is contained with its source code in the value attribute. - *Note:* In contrast to the file property the file content is stored directly as value in the Blob data element. + .. note:: + In contrast to the file property the file content is stored directly as value in the Blob data element. :ivar id_short: Identifying string of the element within its name space. (inherited from :class:`~basyx.aas.model.base.Referable`) @@ -646,17 +647,21 @@ class SubmodelElementList(SubmodelElement, base.UniqueIdShortNamespace, Generic[ A submodel element list is an ordered list of :class:`SubmodelElements <.SubmodelElement>`. The numbering starts with Zero (0). - *Constraint AASd-107:* If a first level child element in a :class:`SubmodelElementList` has a semanticId it shall be - identical to SubmodelElementList/semanticIdListElement. - *Constraint AASd-114:* If two first level child elements in a :class:`SubmodelElementList` have a semanticId then - they shall be identical. - *Constraint AASd-115:* If a first level child element in a :class:`SubmodelElementList` does not specify a - semanticId, the value is assumed to be identical to SubmodelElementList/semanticIdListElement. - *Constraint AASd-108:* All first level child elements in a :class:`SubmodelElementList` shall have the same - submodel element type as specified in SubmodelElementList/typeValueListElement. - *Constraint AASd-109:* If SubmodelElementList/typeValueListElement is equal to Property or Range, - SubmodelElementList/valueTypeListElement shall be set and all first level child elements in the - :class:`SubmodelElementList` shall have the value type as specified in SubmodelElementList/valueTypeListElement. + **Constraint AASd-107:** If a first level child element in a :class:`SubmodelElementList` has a semanticId it shall + be identical to SubmodelElementList/semanticIdListElement. + + **Constraint AASd-114:** If two first level child elements in a :class:`SubmodelElementList` have a semanticId then + they shall be identical. + + **Constraint AASd-115:** If a first level child element in a :class:`SubmodelElementList` does not specify a + semanticId, the value is assumed to be identical to SubmodelElementList/semanticIdListElement. + + **Constraint AASd-108:** All first level child elements in a :class:`SubmodelElementList` shall have the same + submodel element type as specified in SubmodelElementList/typeValueListElement. + + **Constraint AASd-109:** If SubmodelElementList/typeValueListElement is equal to Property or Range, + SubmodelElementList/valueTypeListElement shall be set and all first level child elements in the + :class:`SubmodelElementList` shall have the value type as specified in SubmodelElementList/valueTypeListElement. :ivar id_short: Identifying string of the element within its name space. (inherited from :class:`~basyx.aas.model.base.Referable`) @@ -939,13 +944,13 @@ class Operation(SubmodelElement, base.UniqueIdShortNamespace): An operation is a :class:`~.SubmodelElement` with input and output variables. In- and output variables are implemented as :class:`SubmodelElements <.SubmodelElement>` directly without the - wrapping `OperationVariable`. This makes implementing *Constraint AASd-134* much easier since we can just use normal - :class:`NamespaceSets <~basyx.aas.model.base.NamespaceSet>`. Furthermore, an `OperationVariable` contains nothing - besides a single :class:`~.SubmodelElement` anyway, so implementing it would just make using `Operations` more - tedious for no reason. + wrapping ``OperationVariable``. This makes implementing *Constraint AASd-134* much easier since we can just + use normal :class:`NamespaceSets `. Furthermore, an ``OperationVariable`` + contains nothing besides a single :class:`~.SubmodelElement` anyway, so implementing it would just make using + ``Operations`` more tedious for no reason. - *Constraint AASd-134:* For an Operation, the idShort of all inputVariable/value, outputVariable/value, - and inoutputVariable/value shall be unique. + **Constraint AASd-134:** For an Operation, the idShort of all inputVariable/value, outputVariable/value, + and inoutputVariable/value shall be unique. :ivar id_short: Identifying string of the element within its name space. (inherited from :class:`~basyx.aas.model.base.Referable`) @@ -1049,8 +1054,8 @@ class Entity(SubmodelElement, base.UniqueIdShortNamespace): """ An entity is a :class:`~.SubmodelElement` that is used to model entities - *Constraint AASd-014:* global_asset_id or specific_asset_id must be set if :attr:`~.entity_type` is set to - :attr:`~.EntityType.SELF_MANAGED_ENTITY`. They must be empty otherwise. + **Constraint AASd-014:** global_asset_id or specific_asset_id must be set if ``entity_type`` is set to + :attr:`~basyx.aas.model.base.EntityType.SELF_MANAGED_ENTITY`. They must be empty otherwise. :ivar id_short: Identifying string of the element within its name space. (inherited from :class:`~basyx.aas.model.base.Referable`) @@ -1060,7 +1065,7 @@ class Entity(SubmodelElement, base.UniqueIdShortNamespace): :ivar global_asset_id: Global :class:`~basyx.aas.model.base.Identifier` of the asset the entity is representing. :ivar specific_asset_id: :class:`~basyx.aas.model.base.Reference` to an identifier key value pair representing a specific identifier of the asset represented by the asset administration shell. - See Constraint AASd-014 + See *Constraint AASd-014* :ivar display_name: Can be provided in several languages. (inherited from :class:`~basyx.aas.model.base.Referable`) :ivar category: The category is a value that gives further meta information w.r.t. to the class of the element. It affects the expected existence of attributes and the applicability of constraints. @@ -1239,10 +1244,12 @@ class BasicEventElement(EventElement): Refers to a :class:`~basyx.aas.model.submodel.SubmodelElement`, :class:`~basyx.aas.model.submodel.SubmodelElementList`, :class:`~basyx.aas.model.submodel.SubmodelElementCollection` or - :class:`~basyx.aas.model.submodel.Entity`, which contains DataElements describing the - proprietary specification for the message broker. - Note: for different message infrastructure, e.g. OPC UA or MQTT or AMQP, this proprietary - specification could be standardized by having respective Submodels. + :class:`~basyx.aas.model.submodel.Entity`, which contains DataElements describing + the proprietary specification for the message broker. + + .. note:: + For different message infrastructure, e.g. OPC UA or MQTT or AMQP, this proprietary + specification could be standardized by having respective Submodels. :ivar last_update: Timestamp in UTC, when the last event was received (input direction) or sent (output direction). :ivar min_interval: For input direction, reports on the maximum frequency, the software entity behind the respective Referable can handle input events. For output events, specifies the maximum frequency of diff --git a/basyx/aas/util/__init__.py b/basyx/aas/util/__init__.py index 834214561..1b85151c2 100644 --- a/basyx/aas/util/__init__.py +++ b/basyx/aas/util/__init__.py @@ -1,9 +1,9 @@ """ This package provides helpful utilities for working with a python based AAS model. -`identification.py`: +:mod:`.identification`: Generate :class:`Identifiers ` -`traversal.py`: +:mod:`.traversal`: A module with helper functions for traversing AAS object structures. """ diff --git a/basyx/aas/util/identification.py b/basyx/aas/util/identification.py index 50c2565e9..71aa2b386 100644 --- a/basyx/aas/util/identification.py +++ b/basyx/aas/util/identification.py @@ -67,7 +67,7 @@ class NamespaceIRIGenerator(AbstractIdentifierGenerator): :ivar namespace: The IRI Namespace to generate Identifiers in. It must be a valid IRI (starting with a scheme) and end on either #, /, or = to form a reasonable namespace. - :ivar ~.provider: An :class:`~basyx.aas.model.provider.AbstractObjectProvider` to check existence of + :ivar provider: An :class:`~basyx.aas.model.provider.AbstractObjectProvider` to check existence of :class:`Identifiers ` """ def __init__(self, namespace: str, provider: model.AbstractObjectProvider): diff --git a/docs/source/model/index.rst b/docs/source/model/index.rst index d58300ccc..fbd52b7d3 100644 --- a/docs/source/model/index.rst +++ b/docs/source/model/index.rst @@ -3,9 +3,10 @@ basyx.aas.model - Python Model of the AssetAdministrationShell Metamodel .. automodule:: basyx.aas.model -*Note:* Since the Class-Attributes usually have the same names as the `__init__`-constructor -parameters, you can assume that you can use the attribute names listed in the documentation for -initiating the class. If there is discrepancy between the two, it should be stated so. +.. note:: + Since the Class-Attributes usually have the same names as the ``__init__``-constructor + parameters, you can assume that you can use the attribute names listed in the documentation for + initiating the class. If there is discrepancy between the two, it should be stated so. .. toctree:: :maxdepth: 2 diff --git a/test/_helper/setup_testdb.py b/test/_helper/setup_testdb.py index 07c7388b1..ba5c98095 100755 --- a/test/_helper/setup_testdb.py +++ b/test/_helper/setup_testdb.py @@ -8,13 +8,13 @@ """ Small helper script to setup a blank CouchDB server with a test database and a test user (e.g. for use in CI) -This script uses the `test/test_config.ini` and `test/test_config.default.ini` files to setup the CouchDB server the way -the tests will expect it. The admin user and password used to do the setup may be configured via command line: +This script uses the ``test/test_config.ini`` and ``test/test_config.default.ini`` files to setup the CouchDB server +the way the tests will expect it. The admin user and password used to do the setup may be configured via command line: setup_testdb.py -u admin -p admin_password If no CouchDB server at the configured URL, the script will exit with exit code 1. To avoid the error exit code (for use -in CI), provide the `--failsafe` option. +in CI), provide the ``--failsafe`` option. """ import base64 import configparser