123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746 |
- Wrappers
- ========
- Several wrappers can be defined for the Modelverse, as the Modelverse is merely a service running externally.
- To communicate effectively, and automatically, a programming language wrapper is recommended.
- Nonetheless, it is possible to communicatie manually as well.
- These are some of the implemented wrappers.
- Prompt
- ------
- The simplest wrapper is the prompt wrapper, which merely sends the input and output directly to the user.
- This wrapper has almost no code, but requires users to manually decide which content to send next.
- It has no built-in integration with any model or action language compilers.
- Nonetheless, it is an easy way to test out the raw communication protocol manually.
- Python
- ------
- The first real wrapper is the Python-based wrapper.
- It provides a set of functions for use by Python code.
- These functions wrap not only the interface, but also provides simple error handling through the use of Python exceptions and contains the model and action language compilers.
- An overview of all functions and associatied exceptions is provided below.
- All operations happen *synchronously*, meaning that they block until the Modelverse has performed the requested operation.
- Note that some functions are only applicable in a certain *context*.
- In practice, this means that you should first issue the *init* and *login* operations, as otherwise your connection with the Modelverse will not have started up yet.
- For each function, we provide an example to indicate how this operation can be used.
- In these first examples, assume that all referenced elements are present, all permissions are granted, etc.
- 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.
- Initialization Function
- ^^^^^^^^^^^^^^^^^^^^^^^
- .. function:: init(address_param="http://127.0.0.1:8001", timeout=20.0)
- Start up the connection to the Modelverse, residing at *address_param*.
- This connection is an XML/HTTPRequest and will start up a new task at the Modelverse.
- Retries for *timeout* seconds until giving up.
- The timeout includes all HTTP errors, and will therefore keep retrying even on failed attempts.
- As this request is synchronous, like all others, it will block until a connection has been established.
- Examples:
- * To create a connection to a local Modelverse.
- >>> init()
- * To create a connection to the Modelverse running remotely.
- >>> init("http://modelverse.uantwerpen.be:8001")
- Authentication
- ^^^^^^^^^^^^^^
- .. function:: login(username, password)
- Explanation
- Logs in the currently active Modelverse connection to the specified *username* and *password*.
- If the user does not exist, it will create a new user with the specified password.
- If the user already exists, it will try to log in with the provided password.
- Examples:
- * To login as user user1, with the specified password.
- >>> 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)
- Add a new conformance relation between a model stored at *model_name* and a metamodel stored at *metamodel_name*.
- While this adds the conformance relation, it does not specify the type mapping model, meaning that it has to be subsequently resolved before use.
- Where possible, type mapping models can be automatically deduced (e.g., conformance bottom, traceability, and type mapping).
- If no type mapping can be deduced, an exception will be thrown during the execution of the first command that tries to open the model in this way.
- After the *conformance_add* operation, the relation can already be seen using *model_types*, as it is stored at the server.
- This is in contrast to *alter_context*, which is only stored locally in the client.
- Examples:
- * To consider a model *my_pn* as a conformance bottom model.
- >>> conformance_add("my_pn", "formalisms/Bottom")
- .. function:: conformance_delete(model_name, metamodel_name, type_mapping_name)
- Delete a conformance relation between a model stored at *model_name* and a metamodel stored at *metamodel_name*, using the type mapping model stored at *type_mapping_name*.
- The *type_mapping_name* can be left empty (empty string) if no type mapping model is defined yet.
- All matching conformance relations are removed.
- After the conformance relation is removed, it might be possible that the relation lingers in the context, meaning that a new attempt will be made to deduce a typing relation from scratch.
- Examples:
- * To remove the previously considered conformance bottom relation for model "my_pn", with type mapping model "type mappings/123".
- >>> conformance_delete("my_pn", "formalisms/Bottom", "type mappings/123")
- * To remove the previously considered conformance bottom relation for model "my_pn", without a constructed type mapping model.
- >>> conformance_delete("my_pn", "formalisms/Bottom", "")
- .. function:: model_add(model_name, metamodel_name, model_code=None)
- 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.
- When *model_code* is empty, an empty model is created.
- Examples:
- * To create a new model called PetriNets, conforming to SimpleClassDiagrams, and load the model stored in models/PetriNets.mvc.
- >>> model_add("formalisms/PetriNets", "formalisms/SimpleClassDiagrams", open("models/PetriNets.mvc", "r").read())
- * To create a minimal instance of the language afterwards, which only contains a single place (and no attributes).
- >>> model_add("models/my_pn", "formalisms/PetriNets", "Place p1 {}")
- * To create a less minimal instance of the language, stored in models/my_pn2.mvc.
- >>> model_add("models/my_pn2", "formalisms/PetriNets", open("models/my_pn2.mvc", "r").read())
- .. function:: upload_code(code)
- Upload a string of *code* in the Action Language formalism.
- This piece of code is compiled with the HUTN compiler and sent to the Modelverse directly.
- Makes the assumption that the **construct_function()** operation is currently running on the Modelverse, as otherwise the data will be misinterpreted.
- This is normally only useful in model transformations, where you want to upload a piece of code on-the-fly (e.g., adding a breakpoint in Action Language).
- Examples:
- * To upload the file models/code.alc.
- >>> upload_code(open("models/code.alc", "r").read())
- * To upload a code fragment inline.
- >>> upload_code("Void function a():\nreturn!")
- .. function:: model_delete(model_name)
- Delete the model referred to by name *model_name*.
- This is a non-cascading delete, with almost no checks: model transformations depending on this model will likely become corrupted.
- Examples:
- * To delete a previously created model.
- >>> model_delete("models/my_pn2")
- * Or to delete a metamodel, which is itself just a model.
- >>> model_delete("formalisms/PetriNets")
- * To delete a full folder.
- >>> model_delete("formalisms")
- .. function:: model_list(location)
- Returns a list of all models existing in the specified folder.
- Sub-folders can be recognized because they have a trailing forward slash in their name.
- Examples:
- * To get a list of all models in the formalisms directory.
- >>> model_list("formalisms")
- ["PetriNets", "SimpleClassDiagrams", "Bottom", "Tracability", ...]
- .. function:: model_list_full(location)
- Returns a detailed list of all models existing in the specified folder in the Modelverse.
- This list includes information on permissions, owner, and group.
- Examples:
- * To get a detailed list of all currently present models.
- >>> model_list_full("models")
- [("my_pn", "user1", "users", "200"), ("my_pn2", "user1", "users", "200"), ...]
- .. function:: verify(model_name, metamodel_name)
- Verify whether *model_name* conforms to *metammodel_name*, as both stored in the Modelverse.
- Returns either "OK" if the model conforms, or a string specifying the reason for non-conformance.
- Examples:
- * Verifying a conforming model.
- >>> verify("formalisms/PetriNets", "formalisms/SimpleClassDiagrams")
- OK
- * Or verify using the alternative conformance relation (conformance bottom).
-
- >>> verify("formalisms/PetriNets", "formalisms/Bottom")
- OK
- * Verifying a non-conforming model.
- >>> verify("models/my_pn")
- Lower cardinality violation for attribute "name" at Place p1.
- .. function:: model_overwrite(model_name, new_model_code=None)
- Overwrites the model previously known under the name *model_name* with the model code in *new_model_code*.
- This operation differs from first deleting the model and then recreating it, as all metadata of the model is kept, such as access permissions.
- The new model can be kept empty, in which case the model will be cleared.
- Examples:
- * To overwrite the PetriNets metamodel with a newer version, thereby also updating the metamodel of all existing instances ("my_pn" and "my_pn2").
- >>> model_overwrite("formalisms/PetriNets", open("models/PetriNets2.mvc", "r").read())
- * To overwrite an existing PetriNets instance.
- >>> model_overwrite("models/my_pn", """Place p2 {}""")
- Transformations
- ^^^^^^^^^^^^^^^
- .. function:: model_render(model_name, mapper_name)
- Render the model by name of *model_name* using the mapper by name of *mapper_name*.
- Both parameters have to be known models in the Modelverse.
- Outputs a JSON representation of the rendered model.
- This is basically just a shortcut for executing the specified operation and reading out the resulting model with a JSON representation.
- Examples:
- * To render the PetriNets instance using the PetriNetsMapper.
- >>> model_render("models/my_pn", "formalisms/PetriNetsMapper")
- [{"id": "__12345", "type": "Ellipse", "x": 100, "y": 150, "height": 20, "width: "20"}]
- .. function:: transformation_between(source, target)
- List all transformations that originate at *source* and end at *target*.
- Transformations can still be selected, even if they take more source models than those specified in the parameters.
- Examples:
- * To fetch all endogenous transformations on PetriNets, assuming that some were previously defined.
- >>> transformation_between("formalisms/PetriNets", "formalisms/PetriNets")
- ["PN_simulate", "PN_optimize"]
- * To fetch all transformations from a DSL to PetriNets, assuming that multiple people created different denotational semantics.
- >>> transformation_between("RPGame", "PetriNets")
- ["denotational1", "denotational_2", "denotational_3"]
- .. function:: transformation_add_MT(source_metamodels, target_metamodels, operation_name, code, callback=lambda: None)
- Create a new model transformation operation.
- The new transformation takes *source_metamodels* as input, and generates *target_metamodels* as output.
- Both parameters are dictionaries of the form {name: metamodel_name}.
- The name is used later on in the model transformation as a prefix to the type.
- A single metamodel_name can be used for multiple names.
- Note that the target metamodel names may overlap with the source metamodel names, but the metamodel type should be identical.
- The operation is henceforth known by *operation_name* and is provided as a model in the string *code*.
- Optionally, a callback is defined which performs some operations on the merged metamodel, for example to define tracability links between (previously unrelated) metamodels.
- In the background, this operation does all necessary RAMification and model merging.
- Examples:
- * To create a new model transformation for PetriNets simulation.
- >>> transformation_add_MT({"pn": "formalisms/PetriNets"}, {"pn": "formalisms/PetriNets"}, "models/pn_simulate", open("models/PN_simulate.mvc", "r").read())
- * To create a model transformation from a DSL to PetriNets, which requires tracability links.
- >>> def tracability_links():
- ... instantiate("Association", ID="Tile2Place", ("dsl/Tile", "pn/Place"))
- ... instantiate("Association", ID="Dirrection2Transition", ("dsl/Direction", "pn/Transition"))
- >>> transformation_add_MT({"dsl": "formalisms/RPGame"}, {"pn": "formalisms/PetriNets"}, "models/denotational_1", open("models/denotational_1.mvc", "r").read(), tracability_links)
- * To create a multi-input model transformation.
- >>> transformation_add_MT({"pn_1": "formalisms/PetriNets", "pn_2": "formalisms/PetriNets", "architecture: "formalisms/Architecture"}, {"result": "formalisms/PetriNets"}, "models/PN_merge", open("models/PN_merge.mvc", "r").read())
- .. function:: transformation_add_AL(source_metamodels, target_metamodels, operation_name, code, callback=lambda: None)
- Creates a new action language operation.
- Similar to *transformation_add_MT*, but now does not require RAMification.
- The *code* parameter also is not specified as a Modelverse model (.mvc), but as action language (.alc).
- Examples:
- * To create a new action language operation for PetriNets reachability analysis.
- >>> transformation_add_AL({"pn": "formalisms/PetriNets"}, {"graph": "formalisms/ReachabilityGraph"}, "models/pn_analyze", open("models/PN_reachability.alc", "r").read())
- * To create an action language operation from a Scheduling DSL to a list, which requires tracability links.
- >>> def tracability_links():
- ... instantiate("Association", ID="Task2Event", ("schedule/Task", "list/Event"))
- >>> transformation_add_AL({"schedule": "formalisms/SchedulingDSL"}, {"list": "formalisms/EventList"}, "models/sequentialize", open("models/sequentialize_schedule.alc", "r").read(), tracability_links)
- .. function:: transformation_add_MANUAL(source_metamodels, target_metamodels, operation_name, callback=lambda: None)
- Creates a new manual operation.
- Identical to *transformation_add_AL*, but does not take any code as content.
- Examples:
- * To create a manual refinement operation on PetriNets.
- >>> transformation_add_MANUAL({"pn": "formalisms/PetriNets"}, {"pn": "formalisms/PetriNets"}, "models/pn_refine")
- * To create a multi-input refinement operation on PetriNets.
- >>> transformation_add_MANUAL({"pn": "formalisms/PetriNets", "requirements": "formalisms/Requirements"}, {"pn": "formalisms/PetriNets"}, "models/pn_refine_req")
- .. function:: transformation_execute_AL(operation_name, input_models_dict, output_models_dict, statechart=None)
- Executes the Action Language model *operation_name* with *input_models_dict* as inputs and *output_models_dict* as outputs.
- For both dicts, the contents describe the mapping between the parameter names of the operation to the names in the Modelverse.
- Values in *input_models_dict* must be existing models, whereas values in *output_models_dict* can be non-existing upon invocation.
- A *statechart* tuple can be defined when the action language model requires user input or output.
- This is used to communicate with the executing code directly.
- For more information about this, refer to the execution of transformations.
- Examples:
- * To execute reachability analysis on an existing petri net.
- >>> transformation_execute_AL("models/pn_analyze", {"pn": "models/my_pn"}, {"graph": "models/my_pn_reachability"})
- .. function:: transformation_execute_MANUAL(operation_name, input_models_dict, output_models_dict, callback=lambda i: None)
- Executes the manual model operation *operation_name*.
- Furthermore, this is identical to *transformation_execute_AL*, with the exception of the *callback* function.
- In this case, the callback function can be just another series of Modelverse operations, though pertaining to a single model.
- As such, the *model_name* parameter of these operations **MUST** be set to *None*.
- Examples:
- * To execute a manual operation, which requires you to refine a PetriNets instance.
- >>> def callback():
- ... p1 = instantiate(None, "pn/Place")
- ... t1 = instantiate(None, "pn/Transition")
- ... instantiate(None, "pn/P2T", (p1, t1))
- >>> transformation_execute_MANUAL("models/pn_refine", {"pn": "models/my_pn"}, {"pn": "models/my_pn"}, callback)
- .. function:: transformation_execute_MT(operation_name, input_models_dict, output_models_dict, statechart=None)
- Executes the model transformation operation *operation_name*.
- Identical to *transformation_execute_AL*.
- Examples:
- * To execute a model transformation on a PetriNets instance, thereby putting the result in a different model.
- >>> transformation_execute_MT("models/pn_simulate", {"pn": "models/my_pn"}, {"pn": "models/my_simulated_pn"})
- .. 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*.
- 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, thereby binding the "requirements" model to the Modelverse location "models/requirements".
- >>> 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(model):
- ... # Do some operation on the architecture model here
- ... node1 = instantiate(model, "Node")
- ... node2 = instantiate(model, "Node")
- ... instantiate(None, "Connection", (node1, node2))
- >>> def refine_control(model):
- ... # Do some operation on the control model here
- ... 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(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)
-
- Fetch the process signature, specifying the list of all possible models and their metamodel.
- The returned dictionary works in two directions, as it is used for retrieving models and storing them again.
- All *Data* instances are listed here, with their *name* attribute as key and their *type* attribute as value.
- Examples:
- * To fetch all data artefacts from the process *pn_reachability*.
- >>> process_signature("pn_reachability")
- {"pn": "users/user/test/PetriNet", "reachability": "users/user/test/ReachabilityGraph"}
- User Access Control
- ^^^^^^^^^^^^^^^^^^^
- .. function:: read_permissions(model_name)
-
- Read the permissions of the current user for a specific model.
- In contrast to the *model_list_full* operation, which gives general permission information (e.g., owner and permissions for owner), this operation gives tailored information for this specific user (i.e., none, read, or write).
- As such, this operation does the necessary resolution of group membership and owning group deduction.
- The result is a string containing letters indicating permissions: "R" for read and "W" for write.
- If the model even cannot be read, the string is empty.
- Examples:
- * To determine the permissions for the *users/user/my_pn* model, which we own, for which we have read and write permissions.
- >>> read_permissions("user/user/my_pn")
- "RW"
- * To determine the permissions for the *formalisms/SimpleClassDiagrams* metamodel, for which we have read permissions, but no write permissions.
- >>> read_permissions("formalisms/SimpleClassDiagrams")
- "R"
- * To determine the permissions of the *administration/core* model, which we are not allowed to read or write.
- >>> read_permissions("administration/core")
- ""
- .. function:: permission_modify(model_name, permissions)
- Change the permissions of *model_name* to *permissions*.
- The permissions is a string of three characters, each between 0 and 2.
- The format is similar to the UNIX permission system: the leftmost character is the permission for the owning user, the middle character for members of the ownin group, and the rightmost character for all other users.
- Character 0 signifies no access, 1 read-only access, and 2 full read/write access.
- Note that changing permissions trickle down to the instances as well: if the metamodel is no longer readable to the user, all models conforming to it become unreadable in this specific context.
- Examples:
- * To modify the permissions of the PetriNets metamodel, allowing only the owner to read and write to it.
- >>> permission_modify("formalisms/PetriNets", "200")
- * To modify the permissions of a PetriNets model, granting everyone read/write access.
- >>> permission_modify("formalisms/PetriNets", "222")
- .. function:: permission_owner(model_name, owner)
- Change the owner of the model *model_name* to *owner*.
- Changing permissions trickles down to the instances as well: if the metamodel is no longer readable to the user, all models conforming to it become unreadable in this specific context.
- Examples:
- * To change the owning user of the PetriNets metamodel to user2.
- >>> permission_owner("formalisms/PetriNets", "user2")
- .. function:: permission_group(model_name, group)
- Change the owning group of the model *model_name* to *group*.
- The same remarks hold as for all other permission operations.
- Examples:
- * To change the owning group of the PetriNets metamodel to group1.
- >>> permission_group("formalisms/PetriNets", "group1")
- .. function:: group_create(group_name)
- Create a new group named *group_name*.
- You automatically become an administrator for this group.
- Examples:
- * To create a new group called group2.
- >>> group_create("group2")
- .. function:: group_delete(group_name)
- Delete the group named *group_name*.
- All users will automatically be kicked from the group, and all permissions previously granted by this group become void.
- Examples:
- * To delete the group group2.
- >>> group_delete("group2")
- .. function:: group_owner_add(group_name, user_name)
- Add user *user_name* as an owner of group *group_name*.
- This automatically makes the user join the specified group if this was not yet the case.
- Examples:
- * To add user user1 as a new owner, or group administrator, to group group1.
- >>> group_owner_add("group1", "user1")
- .. function:: group_owner_delete(group_name, user_name)
- Remove user *user_name* as an owner of group *group_name*.
- Examples:
- * To delete user1 as an owner, or group administrator, from group group1.
- >>> group_owner_delete("group1", "user1")
- .. function:: group_join(group_name, user_name)
- Have user *user_name* join the group *group_name* as an ordinary user.
- Examples:
-
- * To make user user1 join the group group1, of which the current user is an owner.
- >>> group_join("group1", "user1")
- .. function:: group_kick(group_name, user_name)
- Remove user *user_name* from the group *group_name*.
- If the user was an owner of the group, these permissions are also revoked.
- Examples:
- * To kick user user1 from group group1, of which the current user is an owner.
- >>> group_kick("group1, "user1")
- Administration
- ^^^^^^^^^^^^^^
- .. function:: admin_promote(user_name)
- Promote user *user_name* to admin status.
- Admin status grants users access to all operations, and provides all permission.
- Effectively, all groups and files have read/write access for the admin user, independent of the stored permissions.
- Examples:
- * To promote user1 to admin states.
- >>> admin_promote("user1")
- .. function:: admin_demote(user_name)
- Demote user *user_name* to ordinary user.
- Examples:
- * To demote user1 to a normal user.
- >>> 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*.
- This list can contain much more than only simple elements, but includes anonymous edges and attributes as well.
- It is therefore not recommended for general purpose use; use *element_list_nice* instead.
- Examples:
- * To get a list of all elements in the PetriNets metamodel.
- >>> element_list("formalisms/PetriNets")
- [("Place", "Class"), ("Transition", "Class"), ("P2T", "Association"), ("T2P", "Association"), ...]
- .. function:: types(model_name)
- Returns a list of all types usable in the model named *model_name*.
- This is similar to executing *element_list* on the metamodel of this model.
- It attempts to filter out most unusable elements.
- Examples:
- * To get a list of all types usable in the PetriNets metamodel (i.e., when altering the metamodel itself).
- >>> types("formalisms/PetriNets")
- ["Class", "Association", "SimpleAttribute", ...]
- .. function:: types_full(model_name)
- Returns a list of all types usable in the model named *model_name*.
- In contrast to *types*, this includes hidden elements as well (i.e., those starting with __)
- Examples:
- * To get a list of all types usable in the PetriNets metamodel (i.e., when altering the metamodel itself).
- >>> types("formalisms/PetriNets")
- ["Class", "Association", "SimpleAttribute", "__12345", ...]
- .. 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).
- Examples:
- * To read out the P2T link in the PetriNets metamodel.
- >>> read_info("formalisms/PetriNets", "P2T")
- ["Association", ("Place", "Transition")]
- * To read out the Place node in the PetriNets metamodel.
- >>> read_info("formalisms/PetriNets", "Place")
- ["Class", None]
- * To read out some P2T instance in a PetriNets model.
- >>> read_info("my_pn", "p1_to_t1")
- ["P2T", ("p1", "t1")]
- * To read out some Place instance in a PetriNets model.
- >>> read_info("my_pn", "p1")
- ["Place", None]
- .. function:: read_attrs(model_name, ID)
- Return a dictionary of all attributes of model element *ID* in model *model_name*, containing their values.
- All values in the Modelverse are primitive types, and as such, this is also the case in this operation.
- The value is *None* in case the attribute is not set.
- Examples:
- * To read out the attributes of the Place class.
- >>> read_attrs("formalisms/PetriNets", "Place")
- {"lower_cardinality": None, "upper_cardinality": None}
- * To read out the attributes of a Place instance.
- >>> read_attrs("models/my_pn", "p1")
- {"name": "critical_section", "tokens": 1}
- .. function:: instantiate(model_name, typename, edge=None, ID="")
- Instantiate a new instance of *typename* in the model *model_name*.
- If the instance is an edge, provide a tuple containing the source and target as *edge*.
- A preferred *ID* can be specified, though there is no guarantee that this name is actually used (e.g., if it is already taken by another element).
- This operation returns the actually assigned ID.
- It is this ID that is used for all other operations on the model.
- Examples:
- * To create a new Place instance in a PetriNets model.
- >>> instantiate("models/my_pn", "Place")
- "__12345"
- * To create a new Place instance with a preferred ID, which is granted.
- >>> instantiate("models/my_pn", "Place", ID="critical_section")
- "critical_section"
- * To create a new Place instance with a preferred ID, which is not granted.
- >>> instantiate("models/my_pn", "Place", ID="critical_section")
- critical_section_12345"
- * To create a new P2T instance in a PetriNets model.
- >>> instantiate("models/my_pn", "P2T", ("p1", "t1"))
- "__12345"
- * To create a new concept in the PetriNets metamodel, which can later on be used in all instances immediately.
- >>> instantiate("formalisms/PetriNets", "Association", ("Place", "Transition"), ID="InhibitorArc")
- "InhibitorArc"
- >>> instantiate("models/my_pn", "InhibitorArc", ("p1", "t1"))
- "__12345"
- .. function:: delete_element(model_name, ID)
- Delete the element *ID* in the model *model_name*.
- This is a recursive delete, and all incoming and outgoing edges will be removed (recursively) as well.
- Examples:
- * To delete an existing element in a PetriNets model.
- >>> delete_element("models/my_pn", "critical_section")
- * To delete an existing exdge in a PetriNets model.
- >>> delete_element("models/my_pn", "p1_to_t1")
- * When deleting an element "p1", the arc "p1_to_t1" is also removed automatically.
- >>> delete_element("models/my_pn", "p1")
- >>> delete_element("models/my_pn", "p1_to_t1")
- UnknownIdentifierException("p1_to_t1")
- Attribute Manipulation
- ^^^^^^^^^^^^^^^^^^^^^^
- .. function:: attribute_optional(model_name, node, attr_name, optionality)
- Alter the optionality of a defined attribute *attr_name* on a class *node* in the model *model_name* to *optionality*.
- The optionality has to be a boolean value.
- Examples:
- * To make the number of tokens in *formalisms/PetriNets* optional.
- >>> attribute_optional("formalisms/PetriNets", "Place", "tokens", True)
- * To make the number of tokens in *formalisms/PetriNets* mandatory.
- >>> attribute_optional("formalisms/PetriNets", "Place", "tokens", False)
- .. function:: attribute_name(model_name, node, attr_name, new_name)
- Change the name of a defined attribute *attr_name* on a class *node* in the model *model_name* to *new_name*.
- The new name has to be a string value, and no similarly named attribute should exist on that element yet.
- Examples:
- * To change the name of the *tokens* attribute to *nrTokens* in *formalisms/PetriNets*.
-
- >>> attribute_name("formalisms/PetriNets", "Place", "tokens", "nrTokens")
-
- .. function:: attribute_type(model_name, node, attr_name, new_type)
- Change the type of a defined attribute *attr_name* on a class *node* in the model *model_name* to *new_type*.
- The new type has to be a string value, refering to a type in the metamodel that defines the new type of the attribute.
- Examples:
- * To change the type of the *tokens* attribute *Integer* in *formalisms/PetriNets*, where *Integer* is defined as a *SimpleAttribute* instance.
-
- >>> attribute_name("formalisms/PetriNets", "Place", "tokens", "Integer")
-
- .. function:: read_defined_attrs(model_name, node)
- Retrieve a list of all defined attributes in class *node* in model *model_name*.
- The return value consists of a pair of dictionaries.
- The first dictionary containing all mandatory attributes, and the second dictionary containing all optional attributes.
- Both dictionaries are constructed the same way, consisting of the name of the attribute as key, and the name of the type as value.
- Examples:
- * To fetch all defined attributes of the *Place* class in *formalisms/PetriNets*, which has a mandatory name and number of tokens, with an optional capacity.
- >>> read_defined_attrs("formalisms/PetriNets", "Place")
- ({"name": "String", "tokens": "Natural"}, {"capacity": "Natural"})
- .. 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:: undefine_attribute(model_name, node, attr_name)
- Removes a defined attribute *attr_name* on *node* in model *model_name*.
- Upon removal, all information about the attribute is also removed, such as optionality, name, and typing information.
- Instances of the metamodel which make use of this attribute, will become non-conforming.
-
- Examples:
- * To undefine the *tokens* attribute in the *Place* class for *formalisms/PetriNets*.
- >>> undefine_attribute("formalisms/PetriNets", "Place", "tokens")
- .. 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*.
- If the attribute already has an assigned value, the previous value is removed first.
- Examples:
- * To assign some attributes to a Place instance.
- >>> attr_assign("models/my_pn", "p1", "name", "my first place")
- >>> attr_assign("models/my_pn", "p1", "tokens", 1)
- * To assign some attributes to the Place class itself.
- >>> attr_assign("formalisms/PetriNets", "Place", "upper_cardinality", 1)
- .. function:: attr_assign_code(model_name, ID, attr, code)
- Assign the code block *code* to the attribute named *attr* of the element *ID* in the model named *model_name*.
- If the attribute already has an assigned value, the previous value is removed first.
- The assigned code is compiled to Action Language by the HUTN compiler.
- Examples:
- * To assign a piece of action code to a Statecharts transition, loaded from file.
- >>> attr_assign_code("models/my_sc", "t1", "script", open("models/t1_script", "r").read())
- * To assign a piece of action code to a Statecharts transition, defined inline.
- >>> code = \
- ... """
- ... Void function action(attributes : Element):
- ... dict_overwrite(attributes, "counter", 1)
- ... return!
- ... """
- >>> attr_assign_code("models/my_sc", "t1", "script", code)
- .. function:: attr_delete(model_name, ID, attr)
- Unset the attribute *attr* of model element *ID* in the model *model_name*.
- This is not necessary when assigning a new value, as *attr_assign* automatically does this when required.
- As such, this only is useful when dealing with an optional attribute, or when you want to create a non-conforming model.
- Examples:
- * To unset the name attribute of a place.
- >>> 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*.
- Typename can be set to the empty string to indicate that all types must match.
- Note that this returns the association itself, **NOT** the destination.
- Examples:
- * To get all arcs starting in place p1.
- >>> read_outgoing("models/my_pn", "p1", "P2T")
- ["p1_to_t1"]
- * To get all allowed connections starting in a Place.
- >>> read_outgoing("formalisms/PetriNets", "Place", "Association")
- ["P2T", "InhibitorArc"]
- .. function:: read_incoming(model_name, ID, typename)
- Returns a list of all incoming associations of *ID*, typed by *typename*, in model *model_name*.
- Typename can be set to the empty string to indicate that all types must match.
- Note that this returns the association itself, **NOT** the source.
- Examples:
- * To get all arcs going to place p1.
- >>> read_incoming("models/my_pn", "p1", "T2P")
- ["t1_to_p1"]
- * To get all allowed connections going to a Place.
- >>> read_incoming("formalisms/PetriNets", "Place", "Association")
- ["T2P"]
- .. function:: read_association_source(model_name, ID)
- Returns the identifier of the source of association *ID* in model *model_name*.
- Examples:
- * To read out the source of the P2T link.
- >>> read_association_source("formalisms/PetriNets", "P2T")
- "Place"
- * To read out the source of an arc.
- >>> read_association_source("models/my_pn", "p1_to_t1")
- "p1"
- .. function:: read_association_destination(model_name, ID)
- Returns the identifier of the target of association *ID* in model *model_name*.
- Examples:
- * To read out the target of the P2T link.
- >>> read_association_destination("formalisms/PetriNets", "P2T")
- "Transition"
- * To read out the target of an arc.
- >>> 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.
- The specified *function* will be executed when users make a request to the service specified by *name*.
- This function will be executed on a different thread for each incoming request for a new instance of the service.
- If required, synchronization must be built in manually.
- After making this call, the thread should stay alive, but can do whatever other operation is required.
- Note that, upon termination, this client **MUST** call the *service_stop()* function, as otherwise the Modelverse is not notified of this service deregistering.
- The service is initially invoked with a Modelverse port to use for communication.
- This port must be used in all requests made to the Modelverse in the context of this service.
- The only two supported operations now are *service_set* (send data to the Modelverse) and *service_get* (fetch data from the Modelverse).
- Examples:
- * To register a Fibonacci service.
- >>> def fibonacci_service(port):
- ... def fibonacci(value):
- ... if value <= 2:
- ... return 1
- ... else:
- ... return fibonacci(value-1) + fibonacci(value-2)
- ... service_set(port, fibonacci, service_get(port))
- >>> service_register("fibonacci", fibonacci_service)
- .. function:: service_stop()
- Stops the current service from being available to the Modelverse.
- Existing connections will not be forcibly terminated, and these run on separate threads.
- Examples:
- * To stop the currently executing service.
- >>> service_stop()
- .. function:: service_get(port)
- When running a serivce, it is often necessary to request data from the Modelverse.
- This data can be sent whatever way in the Modelverse.
- Different Modelverse executions are identified by their differing *port*, which is received upon the client invoking the external service.
- Note that this call is blocking.
- That is, only when data is available, will this function return.
- Examples:
- * To get data from a currently executing Modelverse client.
- >>> service_get(port)
- 5
- .. function:: service_set(port, value)
- When running a service, it is often necessary to send data back to the Modelverse.
- This can be either for conversing with the user (e.g., prompting), or for sending the result back.
- Any primitive value can be sent to the Modelverse as a value.
- Examples:
- * To send the result back to the Modelverse.
- >>> service_set(port, 5)
- .. function:: service_poll(port)
- Polls whether there is any input for the service we are hosting for communication handle *port*.
- This returns either True or False, to get the actual data, a *service_get(port)* is required.
- This function does not block when there is not data to be read.
- Examples:
- * To check whether there is any data for our port, when there is none.
- >>> service_poll(port)
- False
- * To check whether there is any data for our port, when there is some.
- >>> service_poll(port)
- True
- Context Management
- ^^^^^^^^^^^^^^^^^^
- .. function:: alter_context(model_name, metamodel_name)
- Registers the model *model_name* to be interpreted in the context of *metamodel_name* as its metamodel.
- All future requests to the model will be made, using the assumption that the model is typed by the specified metamodel.
- When this is not the case, the request will throw an exception.
- Most of the time, this call must not be manually made, unless switching between metamodels, or when it is the first time using the model.
- The context is automatically deduced from the previous commands: adding the model with a specific metamodel, automatically puts the model in that context.
- When the model is opened for the first time, and it was not created by the client itself (e.g., by someone else, or through a model transformation), the metamodel needs to be specified.
- Examples:
- * To change the default metamodel of PetriNets to Bottom.
- >>> alter_context("formalisms/PetriNets", "formalisms/Bottom")
- .. function:: reset_context()
- 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
- ^^^^^^^^^^
- Below is a list of all exceptions that the wrappers can raise, together with a summary of the kind of error that occured.
- For each exception, its superclasses are also indicated after the colon.
- .. exception:: ModelverseException
- Generic Modelverse Exception, of which all others inherit.
- This should be the only type of exception that the wrapper can raise.
- General Python exceptions could theoretically still occur, though this likely is a bug in the wrapper.
- This exception itself will never occur: it is abstract.
- .. exception:: SuperclassAttribute : ModelverseException
- The attribute that is being modified, was defined in a superclass, even though it is also available for this class.
- To prevent unexpected changes, the change to the attribute is disallowed and should be invoked on the superclass that actually defines the attribute.
- Examples:
- * Modifying the type of the weight attribute is disallowed, as the attribute was defined on an abstract class for both the P2T and T2P associations.
- >>> attribute_type("formalisms/PetriNets", "P2T", "weight", "Integer")
- SuperclassAttribute()
- .. exception:: CallbackOnEmptySignature : ModelverseException
- An activity is being added which has an empty signature for input and output metamodels, while it still defines an operation on the merged metamodel.
- As there is no merged metamodel, since there are no models being manipulated, it is impossible to perform the specified operation
- Examples:
- * When adding a manual operation without signature, but providing an operation
- >>> def operation(model):
- ... pass
- >>> transformation_add_MANUAL({}, {}, "users/user/test/a", operation)
- CallbackOnEmptySignature()
- .. exception:: NotAModel : ModelverseException
- The requested location does not contain a model, but is instead a folder, while a model was expected.
- Examples:
- * When creating a new instance of a "folder" metamodel
- >>> model_add("my_new_model", "formalisms")
- NotAModel()
- .. exception:: UserNotInGroup : ModelverseException
- The specified user is not part of the group, whereas it should be a member of this group.
- Examples:
- * When kicking a user from a group, while the user is not even a member.
- >>> group_kick("group_A", "user_B")
- UserNotInGroup()
- .. exception:: IncorrectFormat : ModelverseException
- An incorrect format is specified for some input.
- Examples:
- * When setting the permissions of a model, this should be a string containing three characters representing either 0, 1, or 2.
- >>> permission_modify("formalisms", "003")
- IncorrectFormat()
- * When querying for all transformations satisfying an input and output signature, they cannot both be empty, as that would return all transformations in the Modelverse.
- >>> transformation_between({}, {})
- IncorrectFormat()
- .. exception:: SignatureMismatch : ModelverseException
- Generic exception for when the signature that is provided does not match the expected signature in the Modelverse.
- This is superclass for many more specific exceptions, but can also occur in its own right.
- Examples:
- * When executing a process with a model mapping that contains an entry that is not used by the process.
- >>> process_execute("users/user/test/empty_process", {"a": "models/a"})
- SignatureMismatch()
- .. exception:: EmptySignature : SignatureMismatch
- Adding a model transformation with an empty input and output signature is not allowed, as no metamodel can be determined for RAMification and future execution.
- Examples:
- * When adding an empty model transformation.
- >>> transformation_add_MT({}, {}, "users/user/test/a", "...")
- EmptySignature()
- .. exception:: SourceModelNotBound : SignatureMismatch
- Executing an activity with an incomplete input signature.
- Examples:
- * When executing a reachability analysis activity, without specifying the petri net model as input.
- >>> transformation_execute_AL("users/user/reachability_analyse", {}, {"reachability_graph": "users/user/reachability_graph"})
- SourceModelNotBound()
- .. exception:: TargetModelNotBound : SignatureMismatch
- Executing an activity with an over-specified output signature.
- Examples:
- * When executing a reachability analysis activity, a second (undefined) output key is specified in the invocation.
- >>> transformation_execute_AL("users/user/initialize_pn", {}, {"pn": "users/user/pn", "reachability": "users/user/reachability"})
- TargetModelNotBound()
- .. exception:: DifferingModelsForKey : SignatureMismatch
- When the input and output signature of an activity are in conflict, because a key has a different type in the output than the input.
- Examples:
- * If the key A switches type in the input and output signature of a to be created activity.
- >>> transformation_add_MANUAL({"A": "users/user/A"}, {"A": "users/user/B"}, "users/user/activity")
- DifferingModelsForKey()
- .. exception:: TypeMismatch : SignatureMismatch
- The type of a model in the input or output signature does not match with the expected type.
- Examples:
- * When executing an activity that took an instance of "formalisms/PetriNets" as input, gets an instance of "formalisms/ProcessModel" instead.
- >>> transformation_execute_AL("users/user/reachability_analyse", {"PN": "users/user/my_pm"}, {})
- TypeMismatch()
- .. exception:: UnknownError : ModelverseException
- Unknown exception has occured.
- This is likely something wrong with the connection, such as the Modelverse that suddenly disconnected, or the request timed out.
- Note that this exception cannot be raised during *init*, as then the connection is nicely wrapped in a *ConnectionError*.
- Examples:
- * When the Modelverse is suddenly killed during execution, while there was an outstanding request.
- >>> element_list("formalisms/PetriNets") # <-- Modelverse killed during execution
- UnknownError()
- .. exception:: UnknownM3 : ModelverseException
- The M3 level of the model could not be determined, indicating that the metametamodel is not recognized as such.
- Examples:
- * When instantiating a model at the M1 level again
- >>> model_add("M2", "formalisms/SimpleClassDiagrams")
- >>> model_add("M1", "M2")
- >>> model_add("wrong", "M1")
- UnknownM3()
- .. exception:: UnknownIdentifier : ModelverseException
- The specified element identifier could not be resolved in the specified model in the Modelverse.
- The exception contains the identifier causing the problem, as there might be multiple identifiers used in a single request.
- Examples:
- * When reading out a non-existing element in a PetriNets model.
- >>> read("models/my_pn", "p0")
- UnknownIdentifier("p0")
- * When reading out the allowed connections between two elements, of which neither exists.
- >>> connections_between("models/my_pn", "p0", "t0")
- UnknownIdentifier("p0")
- * When reading out the allowed connections between two elements, of which the target doesn't exists.
- >>> connections_between("models/my_pn", "p1", "t0")
- UnknownIdentifier("t0")
- * When instantiating a non-existing element in the meta-model.
- >>> instantiate("models/my_pn", "CapacityConstrainedPlace")
- UnknownIdentifier("CapacityConstrainedPlace")
- .. exception:: CompilationError : ModelverseException
- Error in the HUTN compiler during compilation.
- This is mostly caused by a malformed expression in the specified code.
- The compilation error is contained in the content of the exception.
- Examples:
- * When assigning a code block which cannot be parsed as action language.
- >>> attr_assign_code("models/my_pn", "p1", "tokens", "1")
- CompilationError("Parsing error at line 1: ...")
- .. exception:: NotAnActivity : ModelverseException
- An activity model was expected, but the provided model was not an executable activity.
- Examples:
- * When an ordinary model is passed to the transformation execution.
- >>> transformation_execute_AL("formalisms/PetriNets", {}, {})
- NotAnActivity()
- .. exception:: NotAProcess : ModelverseException
- A process model was expected, but the provided model was not typed as such.
- Examples:
- * When executing an ordinary model as if it were a process.
- >>> process_execute("formalisms/PetriNets", {})
- NotAProcess()
- .. exception:: NotAValidProcess : ModelverseException
- A process model was expected, and received, but it did not completely conform to the metamodel.
- For example, some constraints were not valid, no initial node was found, and so on.
- Examples:
- * When a process model is being executed that has not a single "Start" instance.
- >>> process_execute("models/my_empty_pm", {})
- NotAValidProcess()
- .. exception:: UnknownAttribute : UnknownIdentifier
- The specified attribute does not exist for this element.
- While the attribute might exist as a type for the lower meta-level, this only looks at the current level.
- Examples:
- * When assigning a non-existing attribute.
- >>> attr_assign("models/my_pn", "p1", "capacity", 2)
- UnknownAttribute("capacity")
- .. exception:: UnknownElement : UnknownIdentifier
- The specified model element is unknown in the model.
- Examples:
- * When instantiating an element of which the type element does not exist.
- >>> instantiate("models/my_pn", "CapacityConstrainedPlace")
- UnknownElement()
- .. exception:: UnknownModel : UnknownIdentifier
- The specified model can not be resolved in the Modelverse.
- While the model might technically exist, this exception merely indicates that it cannot be referred to with the specified identifier.
- Examples:
- * When trying to execute a non-existing transformation.
- >>> transformation_execute_MT("models/pn_optimize", {"pn": "models/my_pn"}, {"pn": "models/my_optimized_pn"})
- UnknownModel("pn_optimize")
- .. exception:: UnknownLocation : UnknownIdentifier
- The specified location could not be resolved, indicating that no element exists at that location.
- Note that there is no information as to the level at which the resolution goes wrong (e.g., a parent folder might already not exist).
- Examples:
- * When reading out the permissions of a non-existing location.
- >>> read_permissions("a/b/c/d/e/f/g")
- UnknownLocation()
- .. exception:: UnknownGroup : UnknownIdentifier
- The specified group does not exist.
- Examples:
- * When deleting a group that doesn't exist.
- >>> group_delete("no_such_group")
- UnknownGroup()
- .. exception:: UnknownUser : UnknownIdentifier
- The specified user does not exist.
- Examples:
- * When making a (non-existing) user join a group.
- >>> group_join("existing_group", "non_existing_user")
- UnknownUser()
- .. exception:: ConnectionError : ModelverseException
- Error during initialization of the connection to the Modelverse.
- The actual error is enclosed in the exception content.
- Despite possibly multiple errors, the *init* call will try for at least the amount of time specified in the timeout.
- This is done as the Modelverse might still be booting up and is not yet listening to incoming connections.
- Examples:
- * When trying to connect to a server which doesn't exist.
- >>> init("http://www.modelverse.be")
- ConnectionError()
- .. exception:: ExistsError : ModelverseException
- Abstract exception that indicates that a requested element to be created already exists.
- Never occurs on its own.
- .. exception:: AttributeExists : ExistsError
- A to-be-created attribute already exists, and could therefore not be created (or renamed to this).
- Examples:
- * Renaming an attribute to one that already exists.
- >>> attribute_name("formalisms/PetriNets", "Place", "tokens", "name")
- AttributeExists()
- .. exception:: ElementExists : ExistsError
- A to-be-created element already exists, and could therefore not be created.
- Examples:
- * Instantiating another element with ID Place, which already exists.
-
- >>> instantiate("formalisms/PetriNets", "Class", ID="Place")
- ElementExists()
- .. exception:: ModelExists : ExistsError
- The identifier to give to the newly created model already exists.
- Note that some operations, such as model transformation, will default to overwriting a model if it already exists, but still is used as a target.
- Of course, permissions of the overwritten model need to allow for this.
- Examples:
- * When the model "my_pn" already exists.
- >>> model_add("models/my_pn", "PetriNets")
- ModelExists("models/my_pn")
- .. exception:: FolderExists : ExistsError
- The folder you want to create already exists.
- Examples:
- * When creating a folder that already exists.
- >>> folder_create("formalisms")
- FolderExists()
- .. exception:: GroupExists : ExistsError
- The group already exists.
- Examples:
- * When creating a new group that already exists.
- >>> group_create("users")
- GroupExists()
- .. exception:: UserExists : ExistsError
- The user already exists or is already a member of the group.
- Examples:
- * When adding a user to a group, while the user is already in there.
- >>> group_join("users", "user")
- UserExists()
- .. exception:: PermissionDenied : ModelverseException
- Permission denied to a specific artefact.
- This is an abstract exception that is further subclassed by other exceptions.
- .. exception:: ReadPermissionDenied : PermissionDenied
- Current user has no permissions to read the specified model or folder.
- Examples:
- * When reading the administration model, for which we have no permission as it contains user password hashes.
- >>> element_list("administration/core")
- ReadPermissionDenied()
- * When instantiating a non-readable metamodel, as we require access to the enclosed information.
- >>> model_add("my_model", "non-readable-model")
- ReadPermissionDenied()
- * When listing a folder that we do not have read permissions for.
- >>> model_list("users/admin/")
- ReadPermissionDenied()
- .. exception:: WritePermissionDenied : PermissionDenied
- Current user has no permissions to write to the specified model or folder.
- Examples:
- * When writing changes to a core formalism, which ordinary users cannot modify.
- >>> instantiate("formalisms/SimpleClassDiagrams", "Class")
- WritePermissionDenied()
- * When creating a model in a non-writeable folder.
- >>> model_add("formalisms/abc", "formalisms/SimpleClassDiagrams")
- WritePermissionDenied()
- .. exception:: ExecutePermissionDenied : PermissionDenied
- Current user has no permissions to execute the specified activity or process.
- For now, execute permissions equal read permissions, although this is prone to change in the future.
- Examples:
- * When executing a model transformation that we are not allowed to execute.
- >>> transformation_execute_MT("users/admin/my_transformation", {}, {})
- ExecutePermissionDenied()
- .. exception:: UserPermissionDenied : PermissionDenied
- Current user has no permission to make changes to the specified user or to the permissions of models (which can only be modified by the owner).
- Examples:
- * When changing the password of another user.
- >>> user_password("admin", "other_one")
- UserPermissionDenied()
- * When modifying the permissions of a non-owned model.
- >>> permission_modify("formalisms/SimpleClassDiagrams", "222")
- UserPermissionDenied()
- .. exception:: GroupPermissionDenied : PermissionDenied
- Current user has no permission to modify properties of the specified group.
- Examples:
- * When adding a member to a group that we are not an administrator of.
- >>> group_join("some_group", "other_user")
- GroupPermissionDenied()
- .. exception:: AdminPermissionDenied : PermissionDenied
- Current user has no administrator privileges and cannot change the administrator level of another user.
- Examples:
- * When promoting another user as admin, while we are not an administrator ourselves.
- >>> admin_promote("other_user")
- AdminPermissionDenied()
- .. exception:: UnknownMetamodellingHierarchy : ModelverseException
- The requested metamodelling hierarchy could not be resolved.
- This is likely because no typing relation could be found between the specified model and metamodel, or if this typing relation is only a partial mapping that cannot be automatically resolved.
- Note that this exception should never occur when opening the model using *formalisms/Bottom*.
- Examples:
- * When opening an arbitrary model as a SimpleClassDiagrams model.
- >>> alter_context("models/my_pn", "formalisms/SimpleClassDiagrams")
- >>> element_list("models/my_pn")
- UnknownMetamodellingHierarchy()
- .. exception:: NotAnAssociation : ModelverseException
- The requested element is not an association or link, although it should be.
- Examples:
- * When instantiating an association with a type that is not an association.
- >>> instantiate("models/my_pn", "Place", edge=("p1", "p2"))
- NotAnAssociation
- SCCD
- ----
- An SCCD interface is created, which has exactly the same interface.
- Actually, the Python interface presented before is built using this SCCD interface.
- The operations are identical and have the same signature, although they are invoked differently.
- To make a request to the Modelverse, an event has to be raised called *action*.
- The first parameter of this event is the operation to invoke, as a string (*e.g.*, 'read_info').
- The second parameter specifies an ID that can be used in the response event to identify which event this is the response to.
- The third parameter is unused.
- The fourth parameter is a list of all the parameters to this function (*e.g.*, ["my_pn"]).
- For example::
- <raise event="action">
- <parameter expr="'read_info'"/>
- <parameter expr="None"/>
- <parameter expr="None"/>
- <parameter expr="['my_pn']"/>
- </raise>
- When this request is processed, the Modelverse will reply with the *mv_result* event, containing the result.
- The first parameter is the ID passed on in the original request.
- The second parameter contains the result.
- It is possible to wait on this event as follows::
- <transition event="mv_result" target=".">
- <parameter name="ID"/>
- <parameter name="result"/>
- <script>
- print("Response: " + str(result))
- </script>
- </transition>
- If something went wrong, the event *mv_exception* will be raised instead::
- <transition event="mv_exception" target=".">
- <parameter name="ID"/>
- <parameter name="exception_name"/>
- <parameter name="exception"/>
- <script>
- print("Exception: " + str(exception_name))
- print(exception)
- </script>
- </transition>
- The use of the SCCD interface is particularly interesting in case asynchronous communication is required.
- In contrast to the Python interface, requests don't block, making it possible to do additional computations in the background, or even work in a multi-threaded context.
- Note, however, that the SCCD interface is more difficult to use with callbacks and other statecharts, as you will have to manually make the linkage with ports.
- For this, we refer to the implementation.
- Custom
- ------
- Other wrappers can be made as desired, in whatever language required.
- This is due to the fact that the Modelverse communicates only through XML/HTTPRequests.
- As such, all languages that support this, can simply mimic the interface used by any of the implemented wrappers.
|