12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700 |
- 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.
- Since it is relatively minimal and provides a complete implementation of a Modelverse Interface, it is considered as a reference implementation for the Modelverse protocol.
- 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, we assume that all referenced elements are present, all permissions are granted, etc.
- Afterwards, we provide an overview of all exceptions, together with an example.
- In these examples, the problem is often caused by an non-existing element or unsatisfied permissions.
- 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 take at least all elements in *source* as input, with an exact match in tags, and that generate at least all elements in *target*, again with the same tags.
- An empty dictionary means that there is no constraint on that part, but there must be at least one tag specified.
- Examples:
- * To fetch all endogenous transformations on PetriNets on the *PN* tag, assuming that some were previously defined.
- >>> transformation_between({"PN": "formalisms/PetriNets"}, {})
- ["PN_simulate", "PN_optimize", "PN_to_matrix"]
- * To fetch all endogenous transformations on PetriNets on the *PN* tag that modify the model in-place, assuming that some were previously defined.
- >>> transformation_between({"PN": "formalisms/PetriNets"}, {"PN": "formalisms/PetriNets"})
- ["PN_simulate", "PN_optimize"]
- .. 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, traceability_model="", fetch_output=True)
- 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.
- The *traceability* model can optionally be specified, which then loads in the selected model to create the traceability links between all models, and all changes are stored to this model as well.
- The *fetch_output* parameter ensures that the output thread is closed after this call. This is useful if the activity is forever running and no other communication has to happen with the MvI.
- 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, which is passed as a parameter.
- As such, the *model_name* parameter of these operations **MUST** be set to the parameter.
- Examples:
- * To execute a manual operation, which requires you to refine a PetriNets instance.
- >>> def callback(model):
- ... p1 = instantiate(model, "pn/Place")
- ... t1 = instantiate(model, "pn/Transition")
- ... instantiate(model, "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, traceability_model="", fetch_output=True)
- 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.
- 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:: 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")
- UnknownElement("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 identifier could not be resolved in the Modelverse.
- This is an abstract exception, for which several specializations exist.
- The exception always contains the identifier causing the problem, as there might be multiple identifiers used in a single request.
- .. 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:: 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, or set to *None*.
- The third 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="['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, or *None* if the ID was set to *None*.
- 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 (using the *ID* parameter).
- 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.
- We refer to the Python wrapper as the reference implementation.
|