diff --git a/README.md b/README.md index 52ad0a8f0a7e4ce1fb520d7842bde6b7f098a4c8..0c1cd424734ce2206458c63297430da76813a748 100644 --- a/README.md +++ b/README.md @@ -100,13 +100,14 @@ with open('Simple_Submodel.xml', 'w', encoding='utf-8') as f: For further examples and tutorials, check out the `aas.examples`-package. Here is a quick overview: -* `examples.tutorial_create_simple_aas`: Create an Asset Administration Shell, containing an asset reference and a -submodel reference -* `examples.tutorial_serialization_deserialization_json`: Tutorial for the serialization and deserialization of asset -administration shells, submodels and assets -* `examples.tutorial_storage`: Tutorial for storing asset administration shells, submodels and assets -* `examples.tutorial_dynamic_model`: Tutorial about creating a submodel with elements that update dynamically from a - custom data source +* `aas.examples.tutorial_create_simple_aas`: Create an Asset Administration Shell, including an Asset object and a + Submodel +* `aas.examples.tutorial_storage`: Manage a larger number of Asset Administration Shells in an ObjectStore and resolve + references +* `aas.examples.tutorial_serialization_deserialization`: Use the JSON and XML serialization/deserialization for + single objects or full standard-compliant files +* `aas.examples.tutorial_dynamic_model`: Create a submodel with elements that are dynamically updated from a custom data + source ## Contributing diff --git a/aas/examples/tutorial_create_simple_aas.py b/aas/examples/tutorial_create_simple_aas.py index e6918bd05dfa76b318273c1a84133086bcb012cf..51d92f6f46752622d819c8013e09eccfd1385f02 100755 --- a/aas/examples/tutorial_create_simple_aas.py +++ b/aas/examples/tutorial_create_simple_aas.py @@ -2,76 +2,85 @@ # This work is licensed under a Creative Commons CCZero 1.0 Universal License. # See http://creativecommons.org/publicdomain/zero/1.0/ for more information. """ -Tutorial for the creation of an simple asset administration shell containing a asset reference and a submodel +Tutorial for the creation of an simple Asset Administration Shell, containing an Asset reference and a Submodel reference """ # Import all PyI40AAS classes from model package from aas import model -# In this tutorial, you get a step by step guide on how to create an asset administration shell and its required -# objects. First, you need an asset for which you want to create an asset administration shell. So, first, you will -# learn how to create an Asset object. After that, you learn how to create an Asset Administration Shell (AAS) -# containing a reference to the Asset. Now, it is possible to add Submodels to the AAS. Therefore, you learn how to -# create a Submodel and how to add the reference to it to the AAS. The Submodel can contain Submodel Elements. -# Therefore, you will also learn how to create a Submodel Element and how to add it to the Submodel. -# Step by step guide: -# step 1: create a simple asset -# step 2: create a simple asset administration shell containing a reference to the asset -# step 3: create a simple submodel -# step 4: create a simple property and add it to the submodel - -################################## -# step 1: create a simple asset # -################################## -# step 1.1: create an identifier for the asset -# chose the type of the identifier which are defined in the enumeration "IdentifierType", here we use an IRI -id_type = model.IdentifierType.IRI -# define the IRI of the asset -id_ = 'https://acplt.org/Simple_Asset' -# create the identifier -identifier = model.Identifier(id_, id_type) -# step 1.2: create the simple asset +# In this tutorial, you'll get a step by step guide on how to create an Asset Administration Shell (AAS) and all +# required objects within. First, you need an asset for which you want to create an AAS, represented by an Asset object. +# After that, an Asset Administration Shell can be created, containing a reference to that Asset. Then, it's possible to +# add Submodels to the AAS. The Submodels can contain SubmodelElements. +# +# Step by Step Guide: +# step 1: create a simple Asset object +# step 2: create a simple Asset Administration Shell, containing a reference to the Asset +# step 3: create a simple Submodel +# step 4: create a simple Property and add it to the Submodel + + +################################# +# Step 1: Create a Simple Asset # +################################# + +# step 1.1: create an identifier for the Asset +# Here we use an IRI identifier +identifier = model.Identifier(id_='https://acplt.org/Simple_Asset', + id_type=model.IdentifierType.IRI) + +# step 1.2: create the Asset object asset = model.Asset( - kind=model.AssetKind.INSTANCE, # define that the asset is of kind instance + kind=model.AssetKind.INSTANCE, # define that the Asset is of kind instance identification=identifier # set identifier ) + ########################################################################################## -# step 2: create a simple asset administration shell containing a reference to the asset # +# Step 2: Create a Simple Asset Administration Shell Containing a Reference to the Asset # ########################################################################################## -# step 2.1: create the asset administration shell + +# step 2.1: create the Asset Administration Shell identifier = model.Identifier('https://acplt.org/Simple_AAS', model.IdentifierType.IRI) aas = model.AssetAdministrationShell( identification=identifier, # set identifier - asset=model.AASReference.from_referable(asset) # generate a Reference object to the asset (from its identifier) + asset=model.AASReference.from_referable(asset) # generate a Reference object to the Asset (using its identifier) ) -############################################################### -# step 3: create a simple submodel with zero submodel element # -############################################################### -# step 3.1: create the identifier of the submodel + +############################################################# +# step 3: Create a Simple Submodel Without SubmodelElements # +############################################################# + +# step 3.1: create the Submodel object identifier = model.Identifier('https://acplt.org/Simple_Submodel', model.IdentifierType.IRI) submodel = model.Submodel( identification=identifier ) -# step 3.2: add a reference to the submodel to the asset administration shell + +# step 3.2: create a reference to that Submodel and add it to the Asset Administration Shell's `submodel` set aas.submodel.add(model.AASReference.from_referable(submodel)) -# step 2 and 3 can also be done in one step -# submodel = model.Submodel( -# identification=model.Identifier('https://acplt.org/Simple_Submodel', model.IdentifierType.IRI) -# ) -# aas = model.AssetAdministrationShell( -# identification= model.Identifier('https://acplt.org/Simple_AAS', model.IdentifierType.IRI), -# asset=model.AASReference.from_referable(asset), -# submodel_={model.AASReference.from_referable(submodel)} -# ) + +# =============================================================== +# ALTERNATIVE: step 2 and 3 can alternatively be done in one step +# In this version, the Submodel reference is passed to the Asset Administration Shell's constructor. +submodel = model.Submodel( + identification=model.Identifier('https://acplt.org/Simple_Submodel', model.IdentifierType.IRI) +) +aas = model.AssetAdministrationShell( + identification=model.Identifier('https://acplt.org/Simple_AAS', model.IdentifierType.IRI), + asset=model.AASReference.from_referable(asset), + submodel_={model.AASReference.from_referable(submodel)} +) + ############################################################### -# step 4: create a simple property and add it to the submodel # +# step 4: Create a Simple Property and Add it to the Submodel # ############################################################### -# step 4.1: create a global reference to a semantic description of the property + +# step 4.1: create a global reference to a semantic description of the Property # A global reference consist of one key which points to the address where the semantic description is stored semantic_reference = model.Reference( (model.Key( @@ -81,32 +90,37 @@ semantic_reference = model.Reference( id_type=model.KeyType.IRI ),) ) -# step 4.2: create the simple property -property = model.Property( - id_short='ExampleProperty', # Identifying string of the element within the submodel namespace + +# step 4.2: create the simple Property +property_ = model.Property( + id_short='ExampleProperty', # Identifying string of the element within the Submodel namespace value_type=model.datatypes.String, # Data type of the value - value='exampleValue', # Value of the property + value='exampleValue', # Value of the Property semantic_id=semantic_reference # set the semantic reference ) -# step 4.3: add the property to the submodel -submodel.submodel_element.add(property) - -# step 3 and 4 can also be done in one step -# submodel = model.Submodel( -# identification=model.Identifier('https://acplt.org/Simple_Submodel', model.IdentifierType.IRI), -# submodel_element={ -# model.Property( -# id_short='ExampleProperty', -# value_type=model.datatypes.String, -# value='exampleValue', -# semantic_id=model.Reference( -# (model.Key( -# type_=model.KeyElements.GLOBAL_REFERENCE, -# local=False, -# value='http://acplt.org/Properties/SimpleProperty', -# id_type=model.KeyType.IRI -# ),) -# ) -# ) -# } -# ) + +# step 4.3: add the Property to the Submodel +submodel.submodel_element.add(property_) + + +# ===================================================================== +# ALTERNATIVE: step 3 and 4 can also be combined in a single statement: +# Again, we pass the Property to the Submodel's constructor instead of adding it afterwards. +submodel = model.Submodel( + identification=model.Identifier('https://acplt.org/Simple_Submodel', model.IdentifierType.IRI), + submodel_element={ + model.Property( + id_short='ExampleProperty', + value_type=model.datatypes.String, + value='exampleValue', + semantic_id=model.Reference( + (model.Key( + type_=model.KeyElements.GLOBAL_REFERENCE, + local=False, + value='http://acplt.org/Properties/SimpleProperty', + id_type=model.KeyType.IRI + ),) + ) + ) + } +) diff --git a/aas/examples/tutorial_serialization_deserialization.py b/aas/examples/tutorial_serialization_deserialization.py new file mode 100755 index 0000000000000000000000000000000000000000..981b6e20ab1edaf401e686b3df4d47229927c6ac --- /dev/null +++ b/aas/examples/tutorial_serialization_deserialization.py @@ -0,0 +1,159 @@ +#!/usr/bin/env python3 +# This work is licensed under a Creative Commons CCZero 1.0 Universal License. +# See http://creativecommons.org/publicdomain/zero/1.0/ for more information. +""" +Tutorial for the serialization and deserialization of Asset Administration Shells, Submodels and Assets into/from JSON +and XML files. +""" + +import json + +from aas import model +import aas.adapter.json +import aas.adapter.xml + +# 'Details of the Asset Administration Shell' specifies multiple official serialization formats for AAS data. In this +# tutorial, we show, how the PyI40AAS library can be used to serialize AAS objects into JSON or XML and to create +# JSON/XML files according to the standardized format. It is also demonstrated, how these files can be parsed to +# restore the AAS objects as Python objects. +# +# Step by Step Guide: +# step 1: creating Asset, Submodel and Asset Administration Shell objects +# step 2: serializing single objects to JSON +# step 3: parsing single objects or custom data structures from JSON +# step 4: writing multiple identifiable objects to a (standard-compliant) JSON/XML file +# Step 5: reading the serialized aas objects from JSON/XML files + + +########################################################################### +# Step 1: Creating Asset, Submodel and Asset Administration Shell Objects # +########################################################################### + +# For more details, take a look at `tutorial_create_simple_aas.py` + +asset = model.Asset( + kind=model.AssetKind.INSTANCE, + identification=model.Identifier('https://acplt.org/Simple_Asset', model.IdentifierType.IRI) +) +submodel = model.Submodel( + identification=model.Identifier('https://acplt.org/Simple_Submodel', model.IdentifierType.IRI), + submodel_element={ + model.Property( + id_short='ExampleProperty', + value_type=model.datatypes.String, + value='exampleValue', + semantic_id=model.Reference( + (model.Key( + type_=model.KeyElements.GLOBAL_REFERENCE, + local=False, + value='http://acplt.org/Properties/SimpleProperty', + id_type=model.KeyType.IRI + ),) + ) + )} +) +aashell = model.AssetAdministrationShell( + identification=model.Identifier('https://acplt.org/Simple_AAS', model.IdentifierType.IRI), + asset=model.AASReference.from_referable(asset), + submodel_={model.AASReference.from_referable(submodel)} +) + + +############################################## +# Step 2: Serializing Single Objects to JSON # +############################################## + +# Before serializing the data, we should make sure, it's up to data. This is irrelevant for the static AAS objects in +# this tutorial, but may be important when dealing with dynamic data. +# See `tutorial_dynamic_model.py` for more information on that topic. +aashell.update() + +# `AASToJsonEncoder` from the `aas.adapter.json` module is a custom JSONEncoder class for serializing +# Asset Administration Shell data into the official JSON format according to +# 'Details of the Asset Administration Shell', chapter 5.5, using Python's built-in JSON library. When provided to the +# the `json.dump()` and `json.dumps()` methods, these methods are enabled to correctly handle AAS objects within the +# dumped data structure. +aashell_json_string = json.dumps(aashell, cls=aas.adapter.json.AASToJsonEncoder) + +property_json_string = json.dumps(submodel.submodel_element.get_referable('ExampleProperty'), + cls=aas.adapter.json.AASToJsonEncoder) + +# Using this technique, we can also serialize Python dict and list data structures with nested AAS objects: +json_string = json.dumps({'the_submodel': submodel, + 'the_aas': aashell + }, + cls=aas.adapter.json.AASToJsonEncoder) + + +###################################################################### +# Step 3: Parsing Single Objects or Custom Data Structures from JSON # +###################################################################### + +# JSON deserialization works in a similar way to JSON serialization: The `aas.adapter.json` module provides a +# JSONDecoder class, called `AASFromJSONDecoder` which can be passed to `json.load()` or `json.loads()` to ensure that +# AAS objects contained in the JSON data are transformed into their PyI40AAS Python object representation instead of +# simple Python dicts: +submodel_and_aas = json.loads(json_string, cls=aas.adapter.json.AASFromJsonDecoder) + +# Alternatively, one can use the `StrictAASFromJsonDecoder` which works in just the same way, but enforces the format +# specification more strictly. While `AASFromJSONDecoder` will tolerate some semantic errors by simple skipping the +# broken object and issuing a log message, `StrictAASFromJsonDecoder` will raise an Exception in these cases. + + +######################################################################################### +# Step 4: Writing Multiple Identifiable Objects to a (Standard-compliant) JSON/XML File # +######################################################################################### + +# step 4.1: creating an ObjectStore containing the objects to be serialized +# For more information, take a look into `tutorial_storage.py` +obj_store: model.DictObjectStore[model.Identifiable] = model.DictObjectStore() +obj_store.add(asset) +obj_store.add(submodel) +obj_store.add(aashell) + +# step 4.2: Again, make sure that the data is up to date +asset.update() +submodel.update() +aashell.update() + +# step 4.3: writing the contents of the ObjectStore to a JSON file +# Heads up! It is important to open the file in text-mode with utf-8 encoding! +with open('data.json', 'w', encoding='utf-8') as json_file: + aas.adapter.json.write_aas_json_file(json_file, obj_store) + +# We can pass the additional keyword argument `indent=4` to `write_aas_json_file()` to format the JSON file in a more +# human-readable (but much more space-consuming) manner. + +# step 4.4: writing the contents of the ObjectStore to an XML file +# Heads up! For writing XML files -- in contrast to writing JSON --, the file must be opened in binary mode! The XML +# writer will handle character encoding internally. +with open('data.xml', 'wb') as xml_file: + aas.adapter.xml.write_aas_xml_file(xml_file, obj_store) + + +################################################################## +# Step 5: Reading the Serialized AAS Objects From JSON/XML Files # +################################################################## + +# step 5.1: reading contents of the JSON file as an ObjectStore +# Heads up! It is important to open the file in text-mode with utf-8 encoding! Using 'utf-8-sig' is recommended to +# handle unicode Byte Order Marks (BOM) correctly. +with open('data.json', encoding='utf-8-sig') as json_file: + json_file_data = aas.adapter.json.read_aas_json_file(json_file) + +# By passing the `failsafe=False` argument to `read_aas_json_file()`, we can switch to the `StrictAASFromJsonDecoder` +# (see step 3) for a stricter error reporting. + +# step 5.2: reading contents of the XML file as an ObjectStore +# Heads up! For reading XML files -- in contrast to reading JSON --, the file must be opened in binary mode! The XML +# writer will handle character encoding internally. +with open('data.xml', 'rb') as xml_file: + xml_file_data = aas.adapter.xml.read_aas_xml_file(xml_file) + +# Again, we can use `failsafe=False` for switching on stricter error reporting in the parser. + +# step 5.3: Retrieving the objects from the ObjectStore +# For more information on the availiable techniques, see `tutorial_storage.py`. +submodel_from_xml = xml_file_data.get_identifiable(model.Identifier('https://acplt.org/Simple_Submodel', + model.IdentifierType.IRI)) +assert(isinstance(submodel_from_xml, model.Submodel)) diff --git a/aas/examples/tutorial_serialization_deserialization_json.py b/aas/examples/tutorial_serialization_deserialization_json.py deleted file mode 100755 index 37c3be14cc966d1dc9561e17fd5a0ca009531bee..0000000000000000000000000000000000000000 --- a/aas/examples/tutorial_serialization_deserialization_json.py +++ /dev/null @@ -1,110 +0,0 @@ -#!/usr/bin/env python3 -# This work is licensed under a Creative Commons CCZero 1.0 Universal License. -# See http://creativecommons.org/publicdomain/zero/1.0/ for more information. -""" -Tutorial for the serialization and deserialization of asset administration shells, submodels and assets -""" - -import io -import json - -# Import all PyI40AAS classes from model package -from aas import model -from aas.adapter.json import AASToJsonEncoder, read_aas_json_file, write_aas_json_file, object_store_to_json -from aas.model import Asset, AssetAdministrationShell, Submodel - -# In this tutorial you get a step by step guide how to serialize objects of the meta model according to -# 'Details of the Asset Administration Shell'. Therefore, you will learn how to serialize one object and an object -# store to json data. You also will learn how to write this json data to a json file. This tutorial close with a -# demonstration of how to deserialize json data from a json file. -# Step by step guide: -# step 1: create asset, submodel and asset administration shell, for more details look at -# 'tutorial_create_simple_aas.py' -# step 2: serialize an object to json and write it to file -# step 3: serialize an object store to json and write it to file -# step 4: # read a json string from file and deserialize it into an object store of AAS objects - -################################################################# -# step 1: create asset, submodel and asset administration shell # -################################################################# -asset = Asset( - kind=model.AssetKind.INSTANCE, - identification=model.Identifier('https://acplt.org/Simple_Asset', model.IdentifierType.IRI) -) -submodel = Submodel( - identification=model.Identifier('https://acplt.org/Simple_Submodel', model.IdentifierType.IRI), - submodel_element={ - model.Property( - id_short='ExampleProperty', - value_type=model.datatypes.String, - value='exampleValue', - semantic_id=model.Reference( - (model.Key( - type_=model.KeyElements.GLOBAL_REFERENCE, - local=False, - value='http://acplt.org/Properties/SimpleProperty', - id_type=model.KeyType.IRI - ),) - ) - )} -) -aas = AssetAdministrationShell( - identification=model.Identifier('https://acplt.org/Simple_AAS', model.IdentifierType.IRI), - asset=model.AASReference.from_referable(asset), - submodel_={model.AASReference.from_referable(submodel)} -) - -############################################################ -# step 2: serialize an object to json and write it to file # -############################################################ -# step 2.1: serialize an object to json -# AASToJsonEncoder is a custom JSONDecoder class for serializing Asset Administration Shell data -# into the official JSON format according to 'Details of the Asset Administration Shell', chapter 5.5 -# serialize an asset administration shell -json_data_object = json.loads(json.dumps(aas, cls=AASToJsonEncoder)) -# serialize a property -json_data_object = json.loads(json.dumps(submodel.submodel_element.get_referable('ExampleProperty'), - cls=AASToJsonEncoder)) -# step 2.2: write json data to file -# define a file stream, here an internal file stream is used. For an external file stream use -# 'open('tutorial.json', 'w', encoding='utf-8')' for opening a json-File to write json data inside -file_object = io.StringIO() -# write json_data to file -json.dump(json_data_object, file_object) - -################################################################## -# step 3: serialize an object store to json and write it to file # -################################################################## -# step 2.1: serialize an object store to json -# create an object store containing the asset administration shell, the asset and submodel, defined above, for more -# detail look at 'tutorial_storage.py' -obj_store: model.DictObjectStore[model.Identifiable] = model.DictObjectStore() -obj_store.add(asset) -obj_store.add(submodel) -obj_store.add(aas) -# serialize the store using the function 'object_store_to_json' of the 'json' module -json_data_store = object_store_to_json(obj_store) -# step 2.2: write json data to file -# define a file stream, here an internal file stream is used. For an external file stream use -# 'open('tutorial.json', 'w', encoding='utf-8')' for opening a json-File to write json data inside -file_store = io.StringIO() -# write json_data to file -json.dump(json_data_store, file_store) - -# serialize an object store and write it to a file can be done in one step using the function 'write_aas_json_file' -file_store_2 = io.StringIO() -write_aas_json_file(file=file_store_2, data=obj_store) - -################################################################################################# -# step 4: # read a json string from file and deserialize it into an object store of AAS objects # -################################################################################################# -# define a file stream, here the internal file stream from above is used. For an external file stream use -# 'open('tutorial.json', 'r', encoding='utf-8-sig')' for opening a json-File to read json data inside -# we have to set the file pointer to the beginning cause we are using the same file stream. Normally, you do not need -# to do this. -file_store_2.seek(0) -json_object_store = read_aas_json_file(file_store_2, failsafe=False) - -# take a submodel out of the object store, for more details look at 'tutorial_storage.py' -tmp_submodel: Submodel = json_object_store.get_identifiable( # type: ignore - model.Identifier('https://acplt.org/Simple_Submodel', model.IdentifierType.IRI)) diff --git a/aas/examples/tutorial_storage.py b/aas/examples/tutorial_storage.py index 08325027607b594208b51d482257b91832c293c5..763fb03abba40e86cac93d74a79ed55f6384f9c4 100755 --- a/aas/examples/tutorial_storage.py +++ b/aas/examples/tutorial_storage.py @@ -2,49 +2,53 @@ # This work is licensed under a Creative Commons CCZero 1.0 Universal License. # See http://creativecommons.org/publicdomain/zero/1.0/ for more information. """ -Tutorial for storing asset administration shells, submodels and assets +Tutorial for storing Asset Administration Shells, Submodels and Assets in an ObjectStore and using it for fetching these +objects by identification and resolving references. """ -# Import all PyI40AAS classes from model package +# For managing a larger number of Identifiable AAS objects (AssetAdministrationShells, Assets, Submodels, +# ConceptDescriptions), the PyI40AAS library provides the `ObjectStore` functionality. This tutorial shows the basic +# features of an ObjectStore and how to use them. This includes usage of the built-in `resolve()` method of Reference +# objects, which can be used to easily get the Submodel objects, which are referenced by the +# `AssetAdministrationShell.submodel` set, etc. +# +# Step by Step Guide: +# step 1: creating Asset, Submodel and Asset Administration Shell objects +# step 2: storing the data in an ObjectStore for easier handling +# step 3: retrieving objects from the store by their identifier +# step 4: using the ObjectStore to resolve a reference + + from aas import model from aas.model import Asset, AssetAdministrationShell, Submodel -# In this tutorial you get a step by step guide how to store an asset administration shell and its needed objects. For -# storing an asset administration shell including the asset and submodels you need an object store. In an object -# store you can store as many identifiable objects (assets, asset administration shells and submodels) as you want. -# First you will learn how to create an object store and how to add objects to it. After that you will learn how to get -# the objects out of the store using their identifier. At the end you learn how to resolve a reference using the object -# store. -# Step by step guide: -# step 1: create asset, submodel and asset administration shell, for more details look at -# 'tutorial_create_simple_aas.py' -# step 2: store the data in an object store for easier handling -# step 3: get data of objects out of the store using their identifier -# step 4: use the object store for resolving a reference - -######################################################################### -# step 1: create example asset, submodel and asset administration shell # -######################################################################### + +########################################################################### +# Step 1: Creating Asset, Submodel and Asset Administration Shell objects # +########################################################################### + +# For more details, take a look at `tutorial_create_simple_aas.py` + asset = Asset( kind=model.AssetKind.INSTANCE, identification=model.Identifier('https://acplt.org/Simple_Asset', model.IdentifierType.IRI) ) +prop = model.Property( + id_short='ExampleProperty', + value_type=model.datatypes.String, + value='exampleValue', + semantic_id=model.Reference( + (model.Key( + type_=model.KeyElements.GLOBAL_REFERENCE, + local=False, + value='http://acplt.org/Properties/SimpleProperty', + id_type=model.KeyType.IRI + ),) + ) +) submodel = Submodel( identification=model.Identifier('https://acplt.org/Simple_Submodel', model.IdentifierType.IRI), - submodel_element={ - model.Property( - id_short='ExampleProperty', - value_type=model.datatypes.String, - value='exampleValue', - semantic_id=model.Reference( - (model.Key( - type_=model.KeyElements.GLOBAL_REFERENCE, - local=False, - value='http://acplt.org/Properties/SimpleProperty', - id_type=model.KeyType.IRI - ),) - ) - )} + submodel_element={prop} ) aas = AssetAdministrationShell( identification=model.Identifier('https://acplt.org/Simple_AAS', model.IdentifierType.IRI), @@ -52,53 +56,70 @@ aas = AssetAdministrationShell( submodel_={model.AASReference.from_referable(submodel)} ) -################################################################# -# step 2: store the data in an object store for easier handling # -################################################################# -# step 2.1: create an object store for identifiable objects (asset administration shell, asset and submodel) + +################################################################## +# step 2: Storing the Data in an ObjectStore for Easier Handling # +################################################################## + +# step 2.1: create an ObjectStore for identifiable objects +# +# In this tutorial, we use a `DictObjectStore`, which is a simple in-memory store: It just keeps track of the Python +# objects using a dict. +# This may not be a suitable solution, if you need to manage large numbers of objects or objects must kept in a +# persistent memory (i.e. on hard disk). In this case, you may chose the `CouchDBObjectStore` from +# `aas.adapter.couchdb` to use a CouchDB database server as persistent storage. Both ObjectStore implementations provide +# the same interface. Therefore, all the methods shown in this tutorial, can be realized with a CouchDBObjectStore as +# well. obj_store: model.DictObjectStore[model.Identifiable] = model.DictObjectStore() + # step 2.2: add asset, submodel and asset administration shell to store obj_store.add(asset) obj_store.add(submodel) obj_store.add(aas) -####################################################################### -# step 3: get data of objects out of the store using their identifier # -####################################################################### -tmp_submodel: Submodel = obj_store.get_identifiable( # type: ignore + +################################################################# +# step 3: Retrieving Objects From the Store by Their Identifier # +################################################################# + +tmp_submodel = obj_store.get_identifiable( model.Identifier('https://acplt.org/Simple_Submodel', model.IdentifierType.IRI)) -assert(submodel == tmp_submodel) -########################################################## -# step 4: use the object store for resolving a reference # -########################################################## -# create a reference to the submodel -submodel_reference = model.AASReference( - (model.Key( - type_=model.KeyElements.SUBMODEL, - local=True, - value='https://acplt.org/Simple_Submodel', - id_type=model.KeyType.IRI - ),), - type_=model.Submodel -) -tmp_submodel = submodel_reference.resolve(obj_store) -assert(submodel == tmp_submodel) +assert(submodel is tmp_submodel) + + +######################################################## +# step 4: Using the ObjectStore to Resolve a Reference # +######################################################## -# create a reference to the property +# The `aas` object already contains a reference to the submodel. +# Let's create a list of all submodels, to which the AAS has references, by resolving each of the submodel references: +submodels = [reference.resolve(obj_store) + for reference in aas.submodel] + +# The first (and only) element of this list should be our example submodel: +assert(submodel is tmp_submodel) + +# Now, let's manually create a reference to the Property within the submodel. The reference uses two keys, the first one +# identifying the submodel by its identification, the second one resolving to the Property within the submodel by its +# idShort. property_reference = model.AASReference( (model.Key( type_=model.KeyElements.SUBMODEL, local=True, value='https://acplt.org/Simple_Submodel', - id_type=model.KeyType.IRI - ), + id_type=model.KeyType.IRI), model.Key( type_=model.KeyElements.PROPERTY, local=True, value='ExampleProperty', - id_type=model.KeyType.IDSHORT - ),), + id_type=model.KeyType.IDSHORT), + ), type_=model.Property ) + +# Now, we can resolve this new reference. +# The `resolve()` method will fetch the Submodel object from the ObjectStore, traverse down to the included Property +# object and return this object. tmp_property = property_reference.resolve(obj_store) +assert(prop is tmp_property) diff --git a/test/examples/test_tutorials.py b/test/examples/test_tutorials.py index 3a1569ddf43856e8cd104928a8ba3398014f5984..209c61d0630faa3cf3725e9fc4d308adda3c4460 100644 --- a/test/examples/test_tutorials.py +++ b/test/examples/test_tutorials.py @@ -26,12 +26,18 @@ from aas.adapter.json import read_aas_json_file class TutorialTest(unittest.TestCase): def test_tutorial_create_simple_aas(self): from aas.examples import tutorial_create_simple_aas + self.assertEqual(tutorial_create_simple_aas.submodel.get_referable('ExampleProperty').value, 'exampleValue') + store = model.DictObjectStore({tutorial_create_simple_aas.submodel}) + next(iter(tutorial_create_simple_aas.aas.submodel)).resolve(store) def test_tutorial_storage(self): from aas.examples import tutorial_storage + # The tutorial already includes assert statements for the relevant points. So no further checks are required. def test_tutorial_serialization_deserialization_json(self): - from aas.examples import tutorial_serialization_deserialization_json + with temporary_workingdirectory(): + from aas.examples import tutorial_serialization_deserialization + # The tutorial already includes assert statements for the relevant points. So no further checks are required. def test_tutorial_dynamic_model(self) -> None: with temporary_workingdirectory():