In this post, we’ll introduce Electron for Python developers, a great tool if you want to build GUIs for your Python apps with modern web technologies based on HTML, CSS and JavaScript. We’ll also see different ways to connect Python and Electron such as child_process, python-shell and an HTTP (Flask) server.
Prerequisites
This tutorial is designed for Python developers that want to build desktop applications and GUIs with modern web technologies, HTML, CSS, and JS and related frameworks.
To be able to follow this tutorial comfortably, you will need to have a few prerequisites:
- Knowledge of Python is a must.
- You should be comfortable working with web technologies like JavaScript, HTML, and CSS.
- You should also be familiar with installing and using Node.js packages from npm.
Step 1 - Setting up a Development Environment
In this section, we’ll set up a development environment for running our examples. We need to have Node.js together with NPM and Python 3 installed on our machine.
Installing Node.js and NPM
There are various ways that you can follow to install Node.js and NPM on your development machine, such as using:
- the official binaries for your target operating system
- the official package manager for your system
- NVM (Node Version Manager) for installing and managing multiple versions of Node.js in the same machine
Let’s keep it simple, simply go to the official website and download the binaries for your target operating system then follow the instructions to install Node.js and NPM on your system.
Setting Up a Python Virtual Environment
There is a big chance that you already have Python 3 installed on your development machine. In case it’s not installed, the simplest way is to go to the official website and grab the binaries for your target system.
You can make sure you have Python 3 installed on your system by opening a command-line interface and running the following command:
$ python --version
Python 3.7.0
Now, let’s set up a virtual environment.
Creating a Virtual Environment
In this section, you’ll use venv
to create an isolated virtual environment for running your example and install the required packages.
A virtual environment allows you to create an environment for isolating the dependencies of your current project. This will allow you to avoid conflicts between the same packages that have different versions.
In Python 3, you can make use of the venv
module to create a virtual environment.
Now, head over to your terminal and run the following command to create a virtual environment:
$ python -m venv env
Next, you need to activate the environment using the following command:
$ source env/bin/activate
On Windows, you can activate the virtual environment using the Scripts\activate.bat file as follows:
$ env\Scripts\activate.bat
That’s it. You now have your virtual environment activated, and you can install the packages for your example.
Step 4 - Creating a Node.js Application
Now that we have setup our development environment for Python and Electron development by installing Node.js together with npm and creating a Python virtual environment, let’s proceed to create our Electron application.
Let’s start by creating a folder for our project and create a package.json file inside it using the following commands:
$ mkdir python-nodejs-example
$ cd python-nodejs-example
$ npm init -y
The init
command of npm will generate a package.json file with the following default values:
{
"name": "python-nodejs-example",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}
You can customize the values in this file as you see fit in your project and you can also simply go with the default values for this simple example.
Next, we need to create two files inside the project’s folder, index.html and index.js:
$ touch index.js
$ touch index.html
How to Communicate Between Electron and Python
In this section, we’ll see the various available ways that you can use to achieve communications between Electron and Python processes.
What is IPC?
According to Wikipedia:
In computer science, inter-process communication or interprocess communication (IPC) refers specifically to the mechanisms an operating system provides to allow the processes to manage shared data. Typically, applications can use IPC, categorized as clients and servers, where the client requests data and the server responds to client requests.
IPC refers to a set of mechanisms supported by operating systems to enable different, local or remote, processes to communicate with each other. For example, in our case, we want to allow communications between the Electron process and the Python process.
Let’s see some ways to achieve IPC.
Spawning a Python Process Using child_process
Node.js provides the {child_process
] (https://nodejs.org/api/child_process.html) module which allows you to spawn child processes.
Let’s use it to spawn a Python process and run a simple calc.py script.
We’ll make use of simplecalculator to do simple calculations in Python, so we first run the following command to install it:
$ sudo pip install simplecalculator
First, inside your project’s folder, create a py folder and create a calc.py file inside of it:
$ mkdir py & cd py
$ touch calc.py
Open the calc.py file and add the following Python code which performs a calculation and prints the result to the standard output:
from sys import argv
from calculator.simple import SimpleCalculator
def calc(text)
try:
c = SimpleCalculator()
c.run(text)
return c.log[-1]
except Exception as e:
print(e)
return 0.0
if __name__ == '__main__':
print(calc(argv[1]))
Next, create a renderer.js file, and add the following code to spawn a Python process and execute the py/calc.py script:
function sendToPython() {
var python = require('child_process').spawn('python', ['./py/calc.py', input.value]);
python.stdout.on('data', function (data) {
console.log("Python response: ", data.toString('utf8'));
result.textContent = data.toString('utf8');
});
python.stderr.on('data', (data) => {
console.error(`stderr: ${data}`);
});
python.on('close', (code) => {
console.log(`child process exited with code ${code}`);
});
}
btn.addEventListener('click', () => {
sendToPython();
});
btn.dispatchEvent(new Event('click'));
Next, open the index.html file and update it as follows:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Calling Python from Electron!</title>
</head>
<body>
<h1>Simple Python Calculator!</h1>
<p>Input something like <code>1 + 1</code>.</p>
<input id="input" value="1 + 1"></input>
<input id="btn" type="button" value="Send to Python!"></input>
</br>
Got <span id="result"></span>
<script src="./renderer.js"></script>
</body>
</html>
Using python-shell
After seeing how to use child_process
to do communication between Electron and Python, let’s now see how to use python-shell
.
python-shell
is an npm package that provides an easy way to run Python scripts from Node.js with basic and efficient inter-process communication and error handling.
You can use python-shell
for:
- spawning Python scripts
- switching between text, JSON and binary modes
- doing data transfers through
stdin
and stdout
streams - getting stack traces in case of errors
Go to your terminal, and run the following command to install python-shell
from npm:
$ npm install --save python-shell
As the time of this writing, python-shell v1.0.8
is installed in our project.
Next, open the renderer.js file and update the sendToPython()
function as follows:
function sendToPython() {
var { PythonShell } = require('python-shell');
let options = {
mode: 'text',
args: [input.value]
};
PythonShell.run('./py/calc.py', options, function (err, results) {
if (err) throw err;
console.log('results: ', results);
result.textContent = results[0];
});
}
Using Client-Server Communication
Let’s now see another way to achieve communication betweeen Python and Electron using an HTTP server.
Head back to your terminal and run the following command to install Flask and Flask-Cors:
$ pip install flask
$ pip install Flask-Cors
Next, in the py folder of your project, create a server.py file and add the following code to run a Flask server that simply performs a calculation and returns the result as an HTTP response:
import sys
from flask import Flask
from flask_cors import cross_origin
from calculator.simple import SimpleCalculator
def calcOp(text)
try:
c = SimpleCalculator()
c.run(text)
return c.log[-1]
except Exception as e:
print(e)
return 0.0
app = Flask(__name__)
@app.route("/<input>")
@cross_origin()
def calc(input):
return calcOp(input)
if __name__ == "__main__":
app.run(host='127.0.0.1', port=5001)
Next, open the renderer.js file and add the following code to spawn Python and run the server.py file:
let input = document.querySelector('#input')
let result = document.querySelector('#result')
let btn = document.querySelector('#btn')
function sendToPython() {
var { PythonShell } = require('python-shell');
let options = {
mode: 'text'
};
PythonShell.run('./py/server.py', options, function (err, results) {
if (err) throw err;
console.log('response: ', results);
});
}
function onclick(){
fetch(`http://127.0.0.1:5001/${input.value}`).then((data)=>{
return data.text();
}).then((text)=>{
console.log("data: ", text);
result.textContent = text;
}).catch(e=>{
console.log(e);
})
}
sendToPython();
btn.addEventListener('click', () => {
onclick();
});
btn.dispatchEvent(new Event('click'))
Recap
In this tutorial, we’ve introduced Electron for Python developers which can be a great tool if they want to build GUIs for their Python apps with modern web technologies based on HTML, CSS and JavaScript. We’ve also seen different ways to connect Python and Electron such as child_process
, python-shell
and an HTTP (Flask) server.