Table of Contents

To improve the usability of the API, the GroLink project includes a Python library, that links Python code to the running API server.

Requirements

GroPy installation

There are two ways to access the GroPy library, install it via pip or add the source file directly. Installing it with pip is much more handy on the long turn and is therefore recommended, yet the functionality is the same.

Installing with pip

A pip packed is included in the GroPy repository in the Package registry. This can be installed by the following pip command. Make sure pip is installed on your system.

This command works like all other pip commands, including –upgrade for updating to a new version or pip uninstall GroPy to remove the library.

Now GroPy can be imported to all your projects by from GroPy import GroPy

Adding the source directly

If for any reason the pip installation is not an option or not wanted it is also possible to just download the GroPy.py from the repository.

If this file is in the same directory as your Python file you can add it with import GroPy.

Tutorial

It is at any point necessary that GroIMP is running as the API server. How to start it is explained here.

Now in an empty python file (.py) we first import GroPy and create a link to the API server.

from GroPy import GroPy #if you did not use pip change the line to import GroPy
 
link = GroPy.GroLink("http://localhost:58081/api/") # if you started the API on a other port change it here as well

This link object by now did not interact with the server, it is only a collection of commands to create calls. These commands can be found here.

Create a new workbench reference

Each GroIMP project is always embedded in a workbench, which handles the interaction with the project. GroPy creates references to these workbenches (WBRef). For this tutorial a new empty RGG workbench is created, this is similar to the one created by 'new RGG' on the GUI.

wbCreateCall = link.createWB("newRGG") # create the API call object 
wbCreateCall.run() # execute the API call object
wb1 = wbCreateCall.read() # reading the results of the API call and create a WBRef object

The code above shows how GroPy handles calls. A call is created by the functions of the GroLink object 'link'. This call represents an API request but did not interact with the API yet. This happens when the run() function is executed. Afterwards, the response is stored in the call object and is interpreted when the read() function is executed.

This can be simplified by:

wb1 = link.createWB("newRGG").run().read() # a inline solution of the code above

The now-created WBRef object wb1 can execute a list of commands to create new calls. These commands can be found here

Find the first information

With the WBRef object 'wb1' it is now possible to get information about the workbench, for this tutorial: the project graph and the available RGG functions.

#print the Porject graph
print(wb1.getProjectGraph().run().read())
#get the list of RGG functions:
functions = wb1.listRGGFunctions().run().read()
for f in functions['data']: # reading all entries form the data entry
    print(f)

By default, each function that is defined with the return type 'JSON', returns a dictionary that always includes 'console' for the content of the XL console and 'log' for application information. Additionally, in most cases, the data that was requested is returned in 'data'. In some more complex results such as the ProjectGraph, the response is divided into several dictionary entries.

Executing RGG and XL

In the next step, the model will be manipulated by RGG functions and XL queries.

# create the call that counts all A nodes
countA = wb1.runXLQuery("count((*Model.A*));")
 
# create the call that executes the rgg command 'run'
execRun=wb1.runRGGFunction("run")
 
# executing the count and read the results
print(countA.run().read())
 
# execturing the run function 10 times without printing because the result is not needed
for i in range(10):
    execRun.run()
 
# executing the count and read the results a second time
print(countA.run().read())

XL queries as shown above work similarly to the XL console in the GUI(except for the usage of Variables), including the usage of rewriting rules. The main difference to the usage of XL in RGG is that Modules defined in the RGG code such as A must be referred to with Model.A.

The call created with runRGGFunction does the same thing as clicking on the button in the GUI.

Saving and closing the Workbench

At the final step of this small tutorial, the workbench is saved and closed.

If the workbench is not saved before closing the changes will be lost without additional questions.

The code below shows the two different ways to save a project:

# Saving the retuned data 
data=wb1.save().run().read() # recive the gsz file as binary data
f = open("result.gsz",'wb') # open a binary file
f.write(data) # save the file
f.close() # close the file 
 
# save to a path on the System
wb1.save(path="/home/tim/Dokumente/Uni/master/lab/py/test/eins.gs").run()

The two different ways exist for two different use cases: The first one does not require a shared file system between the API and the client. This means it is possible to run GroIMP on a different system such as a remote computer or a container(e.g. Docker). Therefore the first way also only supports .gsz files, since all information is returned as one file. The second way might be simpler in other use cases.

Finally closing the workbench is a simple last command:

# close the workbench
wb1.close().run().read()

Afterward, the API can be closed by crl+c in the console or with the command link.close().run();

The code of the Tutorial:

To simplify the testing and understanding here is the complete code of the tutorial:

from GroPy import GroPy #if you did not use pip change the line to import GroPy
 
link = GroPy.GroLink("http://localhost:58081/api/") # if you started the API on a other port change it here as well
 
wb1 = link.createWB("newRGG").run().read()
 
 
#print the Porject graph
print(wb1.getProjectGraph().run().read())
#get the list of RGG functions:
functions = wb1.listRGGFunctions().run().read()
for f in functions['data']: # reading all entries form the data entry
    print(f)
 
# create the call that counts all A nodes
countA = wb1.runXLQuery("count((*Model.A*));")
 
# create the call that executes the rgg command 'run'
execRun=wb1.runRGGFunction("run")
 
# executing the count and read the results
print(countA.run().read())
 
# execturing the run function 10 times without printing because the result is not needed
for i in range(10):
    execRun.run()
 
# executing the count and read the results a second time
print(countA.run().read())
 
# Saving the retuned data 
data=wb1.save().run().read() # recive the gsz file as binary data
f = open("result.gsz",'wb') # open a binary file
f.write(data) # save the file
f.close() # close the file 
 
#close
wb1.close().run().read()