Browse Source

Updates to documentation

Yentl Van Tendeloo 3 years ago
parent
commit
fff5085207
4 changed files with 252 additions and 206 deletions
  1. 3 3
      doc/conf.py
  2. 1 1
      doc/interaction.rst
  3. 1 1
      doc/transformations.rst
  4. 247 201
      doc/wrappers.rst

+ 3 - 3
doc/conf.py

@@ -49,7 +49,7 @@ master_doc = 'index'
 
 # General information about the project.
 project = u'Modelverse'
-copyright = u'2017, Yentl Van Tendeloo'
+copyright = u'2018, Yentl Van Tendeloo'
 author = u'Yentl Van Tendeloo'
 
 # The version info for the project you're documenting, acts as replacement for
@@ -57,9 +57,9 @@ author = u'Yentl Van Tendeloo'
 # built documents.
 #
 # The short X.Y version.
-version = u'0.7'
+version = u'1.0'
 # The full version, including alpha/beta/rc tags.
-release = u'0.7.1'
+release = u'1.0.0'
 
 # The language for content autogenerated by Sphinx. Refer to documentation
 # for a list of supported languages.

+ 1 - 1
doc/interaction.rst

@@ -63,7 +63,7 @@ The SCCDXML wrapper is asynchronous and perfectly suited for use in GUIs.
 
 The wrapper provides all necessary (meta-)modelling operations that can be used by the MvI.
 As the Modelverse is independent of its (visual/textual) user interface, we only discuss the Modelverse wrapper in this documentation.
-For an example use of the wrappers, we refer to the tests of the Modelverse (using all functionality of the wrapper) and the `Modelverse prototype GUI<https://msdl.uantwerpen.be/git/yentl/modelverse_GUI.git>`_.
+For an example use of the wrappers, we refer to the tests of the Modelverse (using all functionality of the wrapper) and the `Modelverse prototype GUI <https://msdl.uantwerpen.be/git/yentl/modelverse_GUI.git>`_.
 The wrapper functions are explained further in this documentation through the use of examples, in a tutorial-like fashion.
 A full overview of all Python wrapper functions is provided at the end of the documentation.
 

+ 1 - 1
doc/transformations.rst

@@ -42,7 +42,7 @@ To support model transformation, the Modelverse makes use of RAMification.
 In RAMification, the original metamodel is Relaxed, Augmented, and Modified.
 As such, the new metamodel can be used to define model transformation rules.
 
-This consists of the following three phases::
+This consists of the following three phases:
 
 1. The metamodel is **Relaxed**, such that lower cardinalities are no longer applied. Similarly, constraints are removed, and abstract entities can be instantiated. This is done because in model transformations, we only use a specific part of the metamodel.
 2. The metamodel is **Augmented**, such that new attributes and concepts are added. These new attributes are *label* and *constraint* in the LHS, and *label* and *action* in the right hand side. New concepts that are added, are the LHS and RHS entity. These are the containers for all elements of the LHS and the RHS, respectively.

+ 247 - 201
doc/wrappers.rst

@@ -32,8 +32,8 @@ For each exception, then, we provide an example where it can occur.
 In these examples, the problem is often caused by an non-existing element or unsatisfied permissions.
 From the example, it should be clear what the problem is.
 
-Functions
-^^^^^^^^^
+Initialization Function
+^^^^^^^^^^^^^^^^^^^^^^^
 
 .. function:: init(address_param="http://127.0.0.1:8001", timeout=20.0)
 
@@ -53,6 +53,9 @@ Functions
 
      >>> init("http://modelverse.uantwerpen.be:8001")
 
+Authentication
+^^^^^^^^^^^^^^
+
 .. function:: login(username, password)
 
    Explanation
@@ -66,9 +69,102 @@ Functions
 
      >>> login("user1", "my_password")
 
+.. function:: user_logout()
+
+   Logs out the current user, thereby closing the task.
+   Subsequent operations will no longer have any effect, as the task was terminated.
+   To log in as a different user, the *init* operation has to be executed again.
+
+   Examples:
+
+   * To log out the current user and allow future logins by this user.
+
+     >>> user_logout()
+
+.. function:: user_name(user, username)
+
+   Changes the username of user *user* to *username*.
+   From this point on, the user has been renamed, and all old permissions are inherited.
+   Similar to password management, users can only alter their own username.
+   The administrator can also alter the username of all users.
+   Active logins do not need to be refreshed, as the new username will automatically be used everywhere.
+   From the next login, however, the new username has to be used, as the old one has been renamed.
+
+   Examples:
+
+   * To change the username of user1 to user2.
+
+     >>> user_name("user1", "user2")
+
+.. function:: user_password(user, password)
+
+   Changes the password of user *user* to *password*.
+   Permissions on this operation are of course rather strict:
+   users can only modify their own password.
+   Of course, an administrator can modify the password of every user.
+   Active logins do not need to be refreshed, as the new username will automatically be used everywhere.
+   From the next login, however, the new username has to be used, as the old one has been renamed.
+
+   Examples:
+
+   * To change the password of user *user1* to *my_password*.
+
+     >>> user_password("user1", "my_password")
+
+Model Management
+^^^^^^^^^^^^^^^^
+
+.. function:: folder_create(folder_name)
+   
+   Create a folder with the specified name.
+   If necessary, this operation recursively creates all parent folders as well.
+   All created folders are owned by the creating users and permissions are set accordingly.
+
+   Examples:
+
+   * To create a folder *my_folder* in your user folder.
+
+     >>> folder_create("users/user/my_folder")
+
+   * To create a folder *my_subfolder* in the folder *parent_subfolder*, in your user folder.
+
+     >>> folder_create("users/user/parent_subfolder/my_subfolder")
+
+.. function:: model_types(model_name)
+
+   Returns typing information of the model.
+   This information consists of a set of tuples, each tuple containing the metamodel, the type mapping model, and the conformance checking function used.
+   Multiple entries might have the same metamodel or type mapping model, as there might be multiple ways in which a model conforms to a metamodel.
+   Note that this only queries for existing typing relations, and does not consider potential relations.
+   For example, all models will conform to *formalisms/Bottom*, but this will only be an entry in *model_types* if the relation was explicitly created (e.g., by opening the model as such).
+   The type mapping model might be empty (i.e., *None*), in which case the type mapping model has to be dynamically constructed.
+   If the conformance semantics is set to None, this means that the internal Modelverse semantics is used.
+
+   Examples:
+   
+   * To query for the metamodels of model *my_pn*.
+
+     >>> model_types("my_pn")
+     set([("formalisms/PetriNets", "type mappings/1", None)])
+
+   * To query for the metamodels of model *my_pn*, after it has been opened using *formalisms/Bottom*.
+
+     >>> model_types("my_pn")
+     set([("formalisms/PetriNets", "type mappings/1", None), ("formalisms/Bottom", "type mappings/20", None)])
+
+   * To query for the metamodel of a metamodel *formalisms/PetriNets*.
+
+     >>> model_types("formalisms/PetriNets")
+     set([("formalisms/SimpleClassDiagrams", "type mappings/2", None)])
+
+.. function:: conformance_add(model_name, metamodel_name)
+   TODO
+
+.. function:: conformance_delete(model_name, metamodel_name, type_mapping_name)
+   TODO
+
 .. function:: model_add(model_name, metamodel_name, model_code=None)
 
-   Explanation
    Upload a new model that can later be referred to as *model_name*, conforming to *metamodel_name*.
    The model itself is stored in the string *model_code*.
    This string is parsed using the HUTN compiler and subsequently sent to the Modelverse.
@@ -186,30 +282,8 @@ Functions
 
      >>> model_overwrite("models/my_pn", """Place p2 {}""")
 
-.. function:: user_logout()
-
-   Logs out the current user, thereby closing the task.
-   Subsequent operations will no longer have any effect, as the task was terminated.
-   To log in as a different user, the *init* operation has to be executed again.
-
-   Examples:
-
-   * To log out the current user and allow future logins by this user.
-
-     >>> user_logout()
-
-.. function:: user_delete()
-
-   Delete the current user and thereafter log out.
-   This removes the current user, making it impossible to log in as this user again.
-   Existing models tied to this user, such as those the user is an owner of, remain bound to the (removed) user.
-   While it is possible to recreate a new user with the same name, model permissions will not be inherited to this new user with the same name.
-
-   Examples:
-
-   * To delete the current user, and make all owned models owner-less.
-
-     >>> user_delete()
+Transformations
+^^^^^^^^^^^^^^^
 
 .. function:: model_render(model_name, mapper_name)
 
@@ -347,38 +421,64 @@ Functions
 
      >>> transformation_execute_MT("models/pn_simulate", {"pn": "models/my_pn"}, {"pn": "models/my_simulated_pn"})
 
-.. function:: process_execute(process_name, prefix, callbacks)
+.. function:: transformation_read_signature(transformation)
+
+   Returns the signature of the transformation *transformation*.
+   The signature consists of two dictionaries: the first specifies the input signature, and the second one specifies the output signature.
+   Both dictionaries have the same structure: the keys represent the names of the model while invoking the operation, and the values represent the expected type of the model.
+
+   Examples:
+
+   * To read out the signature of the "plant_refine" operation.
+
+     >>> transformation_read_signature("models/plant_refine")
+     ({"req": "formalisms/Requirements", "plant": "formalisms/Plant"}, {"plant": "formalisms/Plant"})
+
+Processes
+^^^^^^^^^
+
+.. function:: process_execute(process_name, model_mapping, callbacks={})
 
    Execute the process model stored as *process_name*.
-   All models are stored with their names prefixed with *prefix* to allow for multiple executions of the same model.
-   Note that this applies to the resolution of input models as well.
+   Models are retrieved and stored in the Modelverse based on the names stored in the process model.
+   When a name is present in the *model_mapping*, the dictionary value is used as the location where the model is retrieved or stored.
+   If the name is not present in the mapping, the model is considered to be anonymous.
    Optionally, a dictionary of *callbacks* can be defined with as key the operation that is being executed, and value the actual callback.
    The callbacks must be similarly defined just like how they were defined in the individual *transformation_execute* operations.
    This means that the callback might very well be a tuple for a statechart instance.
 
    Examples:
 
-   * To execute a process model for the power window example.
+   * To execute a process model for the power window example, thereby binding the "requirements" model to the Modelverse location "models/requirements".
 
-     >>> process_execute("models/pm_powerwindow", "pw_")
+     >>> process_execute("models/pm_powerwindow", {"requirements": "models/requirements"})
 
    * To execute a process model for the power window example, which requires user input for some operations.
 
-     >>> def refine_architecture():
+     >>> def refine_architecture(model):
      ...     # Do some operation on the architecture model here
-     ...     node1 = instantiate(None, "Node")
-     ...     node2 = instantiate(None, "Node")
+     ...     node1 = instantiate(model, "Node")
+     ...     node2 = instantiate(model, "Node")
      ...     instantiate(None, "Connection", (node1, node2))
-     >>> def refine_control():
+     >>> def refine_control(model):
      ...     # Do some operation on the control model here
-     ...     s1 = instantiate(None, "State")
-     ...     s2 = instantiate(None, "State")
-     ...     instantiate(None, "Transition", (s1, s2))
-     >>> def refine_query():
+     ...     s1 = instantiate(model, "State")
+     ...     s2 = instantiate(model, "State")
+     ...     instantiate(model, "Transition", (s1, s2))
+     >>> def refine_query(model):
      ...     # Do some operation on the safety query model here
-     ...     p1 = instantiate(None, "Place")
-     ...     attr_assign(None, p1, "tokens", 2)
-     >>> process_execute("models/pm_powerwindow", "pw_", {"models/refine_plant": refine_plant, "models/refine_control": refine_control, "models/refine_query": refine_query})
+     ...     p1 = instantiate(model, "Place")
+     ...     attr_assign(model, p1, "tokens", 2)
+     >>> process_execute("models/pm_powerwindow", {}, {"models/refine_plant": refine_plant, "models/refine_control": refine_control, "models/refine_query": refine_query})
+
+.. function:: process_signature(process_name)
+   TODO
+
+User Access Control
+^^^^^^^^^^^^^^^^^^^
+
+.. function:: read_permissions(model_name)
+   TODO
 
 .. function:: permission_modify(model_name, permissions)
 
@@ -484,6 +584,9 @@ Functions
 
      >>> group_kick("group1, "user1")
 
+Administration
+^^^^^^^^^^^^^^
+
 .. function:: admin_promote(user_name)
 
    Promote user *user_name* to admin status.
@@ -506,6 +609,22 @@ Functions
 
      >>> admin_demote("user1")
 
+Modelling
+^^^^^^^^^
+
+.. function:: element_list_nice(model_name)
+
+   Returns a complete representation of a model in a compact dicationary-like representation.
+   This is basically a list of dictionaries, each dictionary containing the values usually obtained with *read_attrs*.
+   Additionally, some special keys are added: *id* (the identifier returned upon instantiation), *__source* (the source of the association, if it was an association), and *__target* (the target of the association, if it was an association).
+
+   Examples:
+
+   * To read out a list of a PetriNets instance model.
+
+     >>> element_list_nice("models/my_pn")
+     [{"id": "p1", "name": "a place", "tokens": 1}, {"id": "t1", "name": "a transition"}, {"id": "p1_to_t1", "name": "transition", "__source": "p1", "__target": "t1", "weight": 1}]
+
 .. function:: element_list(model_name)
 
    Returns a list of all elements and their type specified in the model named *model_name*.
@@ -544,7 +663,7 @@ Functions
      >>> types("formalisms/PetriNets")
      ["Class", "Association", "SimpleAttribute", "__12345", ...]
 
-.. function:: read(model_name, ID)
+.. function:: read_info(model_name, ID)
 
    Read the content of model element *ID* in model *model_name*.
    This returns the type of the element, and the set of source and destination if the element is an edge (*None* otherwise).
@@ -553,22 +672,22 @@ Functions
 
    * To read out the P2T link in the PetriNets metamodel.
 
-     >>> read("formalisms/PetriNets", "P2T")
+     >>> read_info("formalisms/PetriNets", "P2T")
      ["Association", ("Place", "Transition")]
 
    * To read out the Place node in the PetriNets metamodel.
 
-     >>> read("formalisms/PetriNets", "Place")
+     >>> read_info("formalisms/PetriNets", "Place")
      ["Class", None]
 
    * To read out some P2T instance in a PetriNets model.
 
-     >>> read("my_pn", "p1_to_t1")
+     >>> read_info("my_pn", "p1_to_t1")
      ["P2T", ("p1", "t1")]
 
    * To read out some Place instance in a PetriNets model.
 
-     >>> read("my_pn", "p1")
+     >>> read_info("my_pn", "p1")
      ["Place", None]
 
 .. function:: read_attrs(model_name, ID)
@@ -607,7 +726,7 @@ Functions
    * To create a new Place instance with a preferred ID, which is granted.
 
      >>> instantiate("models/my_pn", "Place", ID="critical_section")
-    "critical_section"
+     "critical_section"
 
    * To create a new Place instance with a preferred ID, which is not granted.
 
@@ -647,6 +766,38 @@ Functions
      >>> delete_element("models/my_pn", "p1_to_t1")
      UnknownIdentifierException("p1_to_t1")
 
+Attribute Manipulation
+^^^^^^^^^^^^^^^^^^^^^^
+
+.. function:: attribute_optional(model_name, node, attr_name, optionality)
+   TODO
+
+.. function:: undefine_attribute(model_name, node, attr_name)
+   TODO
+
+.. function:: attribute_name(model_name, node, attr_name, new_name)
+   TODO
+
+.. function:: attribute_type(model_name, node, attr_name, new_type)
+   TODO
+
+.. function:: read_defined_attrs(model_name, node)
+   TODO
+
+.. function:: define_attribute(model_name, node, attr_name, attr_type)
+
+   Defines a new attribute on the element *node* in the metamodel identified by *model_name*.
+   The attribute is named *attr_name* and must conform to *attr_type*.
+   Note that, while there are other ways of creating attributes than this function, this function is by far the most user friendly.
+   The type being assigned needs to be specified in the metamodel as well, by instantiating the *SimpleAttribute* node.
+   As models are updated immediately, without any recompilation step inbetween, all instances can immediately make use of this new attribute.
+
+   Examples:
+
+   * To define a new attribute "tokens" on a PetriNet Place, which is of a Natural type.
+
+     >>> define_attribute("formalisms/PetriNets", "Place", "tokens", Natural)
+
 .. function:: attr_assign(model_name, ID, attr, value)
 
    Assign the value *value* to the attribute named *attr* of the element *ID* in the model named *model_name*.
@@ -697,6 +848,43 @@ Functions
 
      >>> attr_delete("models/my_pn", "p1", "name")
 
+Model Query
+^^^^^^^^^^^
+
+.. function:: all_instances(model_name, type_name)
+
+   Returns a list of all instances of type *type_name* in the model *model_name*.
+   This includes indirect instances, which are only typed by type_name through inheritance.
+
+   Examples:
+
+   * To get all places in a PetriNet model.
+
+     >>> all_instances("models/my_pn", "Place")
+     ["p1", "__12345"]
+
+   * To get all nodes that can be instantiated directly for PetriNets.
+
+     >>> all_instances("formalisms/PetriNets", "Class")
+     ["Place", "Transition", "P2T", "T2P"]
+
+.. function:: connections_between(model_name, source_element, target_element)
+
+   Returns a list of all allowed connection types between *source_element* and *target_element* in a specified model.
+   Both elements need to be part of the same model, as otherwise a merged model should be created beforehand.
+
+   Examples:
+
+   * To read out the allowed connections between elements "p1" and "t1".
+
+     >>> connections_between("models/my_pn", "p1", "t1")
+     ["P2T"]
+
+   * To read out the allowed connections from the Place class to itself.
+
+     >>> connections_between("formalisms/PetriNets", "Place", "Place")
+     ["Association", "Inheritance"]
+
 .. function:: read_outgoing(model_name, ID, typename)
 
    Returns a list of all outgoing associations of *ID*, typed by *typename*, in model *model_name*.
@@ -765,6 +953,9 @@ Functions
      >>> read_association_destination("models/my_pn", "p1_to_t1")
      "t1"
 
+Service Management
+^^^^^^^^^^^^^^^^^^
+
 .. function:: service_register(name, function)
 
    Registers the current client-side thread as a service in the Modelverse.
@@ -829,95 +1020,6 @@ Functions
 
      >>> service_set(port, 5)
 
-.. function:: user_password(user, password)
-
-   Changes the password of user *user* to *password*.
-   Permissions on this operation are of course rather strict:
-   users can only modify their own password.
-   Of course, an administrator can modify the password of every user.
-   Active logins do not need to be refreshed, as the new username will automatically be used everywhere.
-   From the next login, however, the new username has to be used, as the old one has been renamed.
-
-   Examples:
-
-   * To change the password of user *user1* to *my_password*.
-
-     >>> user_password("user1", "my_password")
-
-.. function:: transformation_read_signature(transformation)
-
-   Returns the signature of the transformation *transformation*.
-   The signature consists of two dictionaries: the first specifies the input signature, and the second one specifies the output signature.
-   Both dictionaries have the same structure: the keys represent the names of the model while invoking the operation, and the values represent the expected type of the model.
-
-   Examples:
-
-   * To read out the signature of the "plant_refine" operation.
-
-     >>> transformation_read_signature("models/plant_refine")
-     ({"req": "formalisms/Requirements", "plant": "formalisms/Plant"}, {"plant": "formalisms/Plant"})
-
-.. function:: element_list_nice(model_name)
-
-   Returns a complete representation of a model in a compact dicationary-like representation.
-   This is basically a list of dictionaries, each dictionary containing the values usually obtained with *read_attrs*.
-   Additionally, some special keys are added: *id* (the identifier returned upon instantiation), *__source* (the source of the association, if it was an association), and *__target* (the target of the association, if it was an association).
-
-   Examples:
-
-   * To read out a list of a PetriNets instance model.
-
-     >>> element_list_nice("models/my_pn")
-     [{"id": "p1", "name": "a place", "tokens": 1}, {"id": "t1", "name": "a transition"}, {"id": "p1_to_t1", "name": "transition", "__source": "p1", "__target": "t1", "weight": 1}]
-
-.. function:: connections_between(model_name, source_element, target_element)
-
-   Returns a list of all allowed connection types between *source_element* and *target_element* in a specified model.
-   Both elements need to be part of the same model, as otherwise a merged model should be created beforehand.
-
-   Examples:
-
-   * To read out the allowed connections between elements "p1" and "t1".
-
-     >>> connections_between("models/my_pn", "p1", "t1")
-     ["P2T"]
-
-   * To read out the allowed connections from the Place class to itself.
-
-     >>> connections_between("formalisms/PetriNets", "Place", "Place")
-     ["Association", "Inheritance"]
-
-.. function:: define_attribute(model_name, node, attr_name, attr_type)
-
-   Defines a new attribute on the element *node* in the metamodel identified by *model_name*.
-   The attribute is named *attr_name* and must conform to *attr_type*.
-   Note that, while there are other ways of creating attributes than this function, this function is by far the most user friendly.
-   The type being assigned needs to be specified in the metamodel as well, by instantiating the *SimpleAttribute* node.
-   As models are updated immediately, without any recompilation step inbetween, all instances can immediately make use of this new attribute.
-
-   Examples:
-
-   * To define a new attribute "tokens" on a PetriNet Place, which is of a Natural type.
-
-     >>> define_attribute("formalisms/PetriNets", "Place", "tokens", Natural)
-
-.. function:: all_instances(model_name, type_name)
-
-   Returns a list of all instances of type *type_name* in the model *model_name*.
-   This includes indirect instances, which are only typed by type_name through inheritance.
-
-   Examples:
-
-   * To get all places in a PetriNet model.
-
-     >>> all_instances("models/my_pn", "Place")
-     ["p1", "__12345"]
-
-   * To get all nodes that can be instantiated directly for PetriNets.
-
-     >>> all_instances("formalisms/PetriNets", "Class")
-     ["Place", "Transition", "P2T", "T2P"]
-
 .. function:: service_poll(port)
 
    Polls whether there is any input for the service we are hosting for communication handle *port*.
@@ -936,20 +1038,8 @@ Functions
      >>> service_poll(port)
      True
 
-.. function:: user_name(user, username)
-
-   Changes the username of user *user* to *username*.
-   From this point on, the user has been renamed, and all old permissions are inherited.
-   Similar to password management, users can only alter their own username.
-   The administrator can also alter the username of all users.
-   Active logins do not need to be refreshed, as the new username will automatically be used everywhere.
-   From the next login, however, the new username has to be used, as the old one has been renamed.
-
-   Examples:
-
-   * To change the username of user1 to user2.
-
-     >>> user_name("user1", "user2")
+Context Management
+^^^^^^^^^^^^^^^^^^
 
 .. function:: alter_context(model_name, metamodel_name)
 
@@ -966,56 +1056,12 @@ Functions
 
      >>> alter_context("formalisms/PetriNets", "formalisms/Bottom")
 
-.. function:: allowed_metamodels(model_name)
-
-   Fetch a set of all metamodels that are registered for *model_name*.
-   This reads out the data in the Modelverse, and will not try to resolve new relations.
-   It is possible for this list to be empty, in case the relation to *Bottom* was removed previously.
-   Otherwise, every model will conform to at least *Bottom*.
-   Other metamodels are optional.
-
-   Examples:
-
-   * To fetch the metamodels to which a PetriNet model conforms, where it is explicitly set that it also conforms to PetriNets which use inhibitor arcs.
-
-     >>> allowed_metamodels("models/my_pn")
-     ["formalisms/PetriNets", "formalisms/Bottom", "formalisms/PetriNets_Inhibitor"]
-
-   * When all typing relations were explicitly removed.
-
-     >>> allowed_metamodels("models/my_pn")
-     []
-
-   * Usual situation when there is no metamodel specified.
-
-     >>> allowed_metamodels("models/my_pn")
-     ["Bottom"]
-
-.. function:: remove_metamodel(model_name, metamodel_name)
-
-   Explicitly removes the conformance relation between *model_name* and *metamodel_name*.
-   It will prevent future uses of this model in the context of this metamodel, though does not prevent future operations from recreating this relation.
-
-   Examples:
-
-   * To remove the PetriNets_Inhibitor metamodel for my_pn.
-
-     >>> remove_metamodel("models/my_pn", "formalisms/PetriNets_Inhibitor")
-
-.. function:: add_metamodel(model_name, metamodel_name, partial_type_mapping=None)
-
-   Explicitly add the conformance relation between *model_name* and *metamodel_name*.
-   It creates the relation, and will try to find a type mapping between them automatically.
-   A *partial_type_mapping* can be passed, which will be used as a starting point when searching for a conformance relation.
-   Multiple possible relations might be found, in which case an arbitrary type mapping is taken.
-
-   TODO: allow for the partial type mapping
-   
-   Examples:
-
-   * To try and make my_pn conform to PetriNets_Inhibitor again; this results in multiple options!
+.. function:: reset_context()
 
-     >>> add_metamodel("models/my_pn", "formalisms/PetriNets_Inhibitor")
+   Clears all previously registered context models.
+   This is useful for when a model is removed automatically, without the knowledge of the client.
+   When the context is reset, no metamodel is stored, and opening a model will then cause searching for the registered metamodel.
+   Note that if a model still has an old metamodel registered, this might cause exceptions when opening the model, since the old metamodel is tried.
 
 Exceptions
 ^^^^^^^^^^