===== Getting started with GroLink and GroPy =====
To improve the usability of the API, the GroLink project includes a [[https://gitlab.com/grogra/groimp-utils/pythonapilibrary|Python library]], that links Python code to the running API server.
==== Requirements ====
* A GroIMP version including the API plugin is needed, the first version including the API is 2.1.
* Python >=3.7 is needed
==== 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 [[https://gitlab.com/grogra/groimp-utils/pythonapilibrary/-/packages|Package registry]]. This can be installed by the following pip command. Make sure pip is installed on your system.
> pip install GroPy --index-url https://gitlab.com/api/v4/projects/50527255/packages/pypi/simple
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 [[https://gitlab.com/grogra/groimp-utils/pythonapilibrary/-/blob/075ff476e5b3a734f549b23a71a094bb87f1db03/src/GroPy/GroPy.py|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 ====
=== Starting API and creating the link ===
It is at any point necessary that GroIMP is running as the API server. How to start it is explained [[:groimp-platform:interfaces:api|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 [[https://gitlab.com/grogra/groimp-utils/pythonapilibrary/-/tree/main?ref_type=heads#grolink|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 [[https://gitlab.com/grogra/groimp-utils/pythonapilibrary/-/tree/main?ref_type=heads#wbref|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()