Tutorial: Python PingPong Script¶
This tutorial explains how to write a Python assistant using PingPong protocol. You should start by setting up the general things explained in general tutorial.
Creating the Yaml Assistant¶
Since one of the points of PingPong is to avoid as much of the Yaml DSL as possible, this
will be very short (and self-explanatory, too!). This is what you should put in
~/programming/rstcreate/assistants/crt/rstcreate.yaml
:
fullname: RST Document
description: Create a simple reStructuredText document.
dependencies:
- rpm: [python3, python3-dapp]
args:
title:
flags: [-t, --title]
help: Title of the reStructuredText document.
required: True
files:
ppscript: &ppscript
source: ppscript.py
run:
- pingpong: python3 *ppscript
This is pretty much all you’ll need to write in the Yaml DSL everytime you’ll be writing assistants based on PingPong. A brief explanation follows (more detailed explanation of the DSL can be found at Tutorial: Creating Your Own Assistant in Yaml DSL):
fullname
anddescription
are “nice” attributes to show to users.dependencies
list packages that DevAssistant is supposed to install prior to invoking the PingPong script; you can add any dependencies that your PingPong script needs hereargs
are a Yaml mapping of arguments that the assistant will accept from user (be it on commandline or in GUI).files
is a Yaml mapping of files; each file must a have a unique name (ppscript
), should be referenced to by Yaml anchor (&ppscript
; shouldn’t be different fromppscript
because of issue 74) and has to havesource
argument that specifies filename. (Will be searched for in appropriatefiles
subdirectory.run
just runs the PingPong script the way it’s supposed to be run (thepython3 *ppscript
) is exactly what will get executed to execute the PingPong subprocess (of course after substituting*ppscript
with expanded path to the actual script fromfiles
).
Creating the PingPong Script¶
We’ll write the PingPong script in Python 3, using the dapp library. Note, that this tutorial uses version 0.3.0 of dapp; consult dapp documentation if your version is different (you can find a detailed documentation of this library at its Github project page).
This is the content of the ~/programming/rstcreate/files/crt/rstcreate/ppscript.py
file (see comments below for explanation):
#!/usr/bin/python3
import os
import dapp
class MyScript(dapp.DAPPClient):
def run(self, ctxt):
# call a DA command that replaces funny characters by underscores,
# so that we can use title as a filename
_, normalized = self.call_command(ctxt, 'normalize', ctxt['title'])
filename = normalized.lower() + '.rst'
# if file already exists, just fail
if os.path.exists(filename):
self.send_msg_failed(ctxt,
'File "{0}" already exists, cannot continue!'.format(filename))
self.call_command(ctxt, 'log_i', 'Creating file {0} ...'.format(filename))
with open(filename, 'w') as f:
# Issue a debug message that will show if DA is run with --debug
self.call_command(ctxt, 'log_d', 'Writing to file {0}'.format(filename))
f.write(ctxt['title'].capitalize())
f.write('\n')
f.write('=' * len(ctxt['title']))
# inform user that everything went fine and return
self.call_command(ctxt, 'log_i', 'File {0} was created.'.format(filename))
return (True, filename)
if __name__ == '__main__':
MyScript().pingpong()
- The PingPong script mustn’t write anything to
stdout
orstderr
. If you need to tell something to user, uselog_i
command (log_w
for warnings andlog_d
for debug output). - The whole PingPong script is just a Python 3 script that imports
dapp
library, subclasses thedapp.DAPPClient
class and runspingpong()
method when script is run (note: the implemented class has to implement run() method, but pingpong() has to be called!). - The
run
method takesctxt
as an argument, which is the Yaml DSL context. In short, it is a dictionary mapping DSL variables to their values. This context has to be passed as the first argument to all functions that interact with DevAssistant. Note, that all changes that you do toctxt
are permanent and will reflect in any subsequent Yaml DSL commands following the PingPong script invocation. See Variables and Context for more details on how context and variables work. - You can run DevAssistant commands by calling
self.call_command
method. It takes three parameters: Yaml DSL context, command type and command input (consult command_ref for details on command types and their input). This function returns 2-tuple, logical result (boolean) and result (type depends on command) (again, consult command_ref). - You can pass arbitrary dictionaries (== crafted to make commands see a different context)
to
call_command()
to achieve desired results. Doing this does not alter the Yaml DSL context in any way, the changes will be limited to the dictionary you pass. - Similarly, the called commands can change the context that you pass to them as argument (usually they don’t do this; if they do, they usually just add variables, not remove/change).
- The
run()
method has to return a 2-tuple, a logical result and result. This is exactly the same as what any DevAssistant command returns (sincepingpong
is in fact just a Yaml command). You can choose what you want to return as result as you wish - in this case, we return the name of the file created.
Wrap-up¶
That is it. Now you can run the assistant with:
da create rstcreate -t "My Article"
And that’s it. Enjoy!