[Report] bone101: Python Integration Phase

8 views
Skip to first unread message

Amr Ragaey

unread,
Aug 16, 2016, 6:40:48 PM8/16/16
to BeagleBoard GSoC, Alex Hiam, Jason Kridner

2nd Phase: Python Integration


User Interface

Repository : https://github.com/amragaey/bone101/tree/python-integration


In bone101, I created a page to run python examples (#a867565).

In the page we have the ace-editor in bone101, was supporting Javascript syntax. I added support for Python syntax (#58de4a5).

The page contains three text areas; the script code (in Python) , standard input (if user waits for some input in the program), output (prints stdout if run successfully or stderr if anything went wrong), and the run and restore buttons that will be used to start and stop the execution of the python script.


The Python Runner Script

Repository: https://github.com/amragaey/bonescript/tree/python-runner



How is the python script executed on BeagleBone?

Let’s have a look into the Python Runner module the I wrote on bonescript.

https://github.com/amragaey/bonescript/blob/python-runner/src/python_runner.js



The scenario

1- User sends the code and standard input(if exists) to bonescript python runner.

3 - Server creates a temporary folder with random number on beaglebone to save the code and user inputs to it, and will contain the output file after execution complete.

2- Server create a new file called ‘script.py’ and saves the code into it, and saves the standard input into another file called ‘inputFile’.

‘Let’s assume a folder now called ‘8935582107aadd1a9f1d’ contains two files script.py and inputFile’

3 - The python file is executed on beaglebone terminal with proper arguments, and the execution result is written to output.text file.

‘The  folder ‘8935582107aadd1a9f1d’ contains now output.text that contains the execution result ’ .

4 - The output file contents is then sent back to the user.

5 - If user clicks on ‘reset’ button, the process terminate, and the temporary folder is removed.

*I used a temporary folder for as wrapper for each python script files to guarantee uniqueness of file names and avoid any overrides/or conflicts*



A look into the code

The design of the runner is based on main function pythonRunner and sub-functions attached to its prototype. The use of prototype here is to make the design more like to OOP design, the variables of main function is easily accessible to all sub functions, that makes the code easier to read and to scale.


  • The constructor

pythonRunner constructor takes five arguments (path, folder, file, code, stdin)

path: is the path used in which we create our temporary folder.

‘I assume it to be

folder: the name of the temporary folder that is chosen by a random function.

file : the file that will contain the python script. ‘Ex.script.py

code: the actual python code written by the user.

stdin: the standard input sent by the user (if exists).


  • pythonRunner.writeFiles(callback)

This method is responsible for creating the temporary folder inside the specified path, the folder is created using ‘child_process.exec()’ method, on the call back of exec(), the python code is written into a file ‘ex.script.py’ , and the stdin is written into ‘inputFile’, both files are in the temporary folder.


  • pythonRunner.executeScript(callback)

This method is responsible for the actual execution of the python script. The command used to run the script is:

‘Python script.py -<inputFile 2>&1 | tee -a output.text’

“inputFile and output.text used without their path here to simplify the command, they should be referred to temporary folder as seen in code”


The first argument ‘-< inputFile’ is responsible to pass the standard input to the python script during  execution (if available).

If the user writes for example python code: raw_input(“enter name: “), the inputFile should contain a name like ‘Amr’.


The second argument ‘ 2>&1 | tee -a output.text’ is responsible for returning the standard output or the standard error to a file called ‘output.text’, the file will be created after execution, and the contents of the file is returned in the callback of the exec() function to the user.

If the output file isn’t created for any reason, an error message will be printed to the JavaScript console.

The exec() function is assigned to variable called ‘c’. That will be used in killScript function to kill the process


  • pythonRunner.killScript(callback)

This method is responsible for killing the running python process, and removes the temporary folder with its contents.


Using ‘child_process.exec()’ to run the command ‘rm -rf /temporary folder’, and on the callback of the exec() the process is killed using c.kill(), a message will be returned in callback that “process is terminated”.



Why I did use exec() instead of spawn() ?

Running a python script in beaglebone terminal, I found two ways to do this in NodeJS using ‘child_process’.‘child_process’ has two methods that help in this situation, spawn() and exec(). Spawn method spawns the child process asynchronously, without blocking the Node.js event loop, and doesn’t take a callback. The exec method spawns a shell and runs a command within that shell, passing the stdout and stderr to a callback function when complete.

In beaglebone, our case, the user will write the python script and the standard input in textarea and send it to the server, waiting for a result which will be a callback of execution. I found exec() method also works more friendly with shell commands than spawn().



Integration to bonescript/Issues ?

I had some issues with my beaglebone, and hadn’t get an answer on the starting point for this phase. That leads me to save time and writing that module instead of single separate functions. I believe that separate function wouldn’t do the job as this do, but after discussion with Jason, I see that including the Python Runner in bonescript would require some steps in bonescript code. I’m not sure if I have the time to do it now. But Instead I used my runner with a simple NodeJS web application to test functions and make sure everything working fine.

I need to know if that would be good for you?



Testing

The Python Runner is tested with Express, a NodeJS web framework, just to make every function working fine and the output is returned as expected to the user.

The test is done with simple two API requests.

Post request with constructor attributes ‘written manually’.

Get request to kill the process from the client/browser side.

You can try it here : https://github.com/amragaey/python-runner


Features of Python Runner

  • Python runner is written similar to OOP programs even Javascript isn’t object oriented. The code could be extended easily, and any feature could be attached as a method to PythonRunner prototype.

  • Python Runner also provides a wrapper for the files which is the temporary folder to save scripts from conflicts or overrides.

  • PythonRunner could be used also to run Ruby scripts, just by changing the file name to ‘script.rb’ and let the argument of the execution being ‘ruby script.rb --args’ instead of ‘python script.py --args’. The language could be passed as an attribute to the constructor to make the pythonRunner more generic.


If there's anything I can do this week in developing regrading this phase I will be ready for it.. looking forward for your feedback.
Reply all
Reply to author
Forward
0 new messages