Python on Electron framework
Asked Answered
C

6

61

I am trying to write a cross-platform desktop app using web technologies (HTML5, CSS, and JS). I took a look at some frameworks and decided to use the Electron framework.

I've already done the app in Python, so I want to know if is possible to write cross-platform desktop applications using Python on the Electron framework?

Cabrales answered 22/8, 2015 at 17:12 Comment(2)
Welcome to stackoverflow. Isn't the answer given right on the top of the electron page?Evita
Thank you. I didn't see it, but I'll check again. Sorry.Cabrales
H
53

It is possible to work with Electron but if you are looking for "webbish" UI capabilities, you can check Flexx - it allows you to code in pure Python but still use the styling and UI flexibility of web development tools.

If you insist on going on Electron you should follow the idea of this post.

First make sure you have everything installed:

pip install Flask
npm install electron-prebuilt -
npm install request-promise -g

Now create the directory where you want all the magic to happen and include following files

Create your hello.py:

from __future__ import print_function
import time
from flask import Flask

app = Flask(__name__)

@app.route("/")
def hello():
    return "Hello World! This is powered by Python backend."

if __name__ == "__main__":
   print('oh hello')
    #time.sleep(5)
    app.run(host='127.0.0.1', port=5000)

Create your basic package.json:

{
  "name"    : "your-app",
  "version" : "0.1.0",
  "main"    : "main.js",
  "dependencies": {
    "request-promise": "*",
    "electron-prebuilt": "*"
  }
}

Finally create your main.js:

const electron = require('electron');
const app = electron.app;
const BrowserWindow = electron.BrowserWindow;
electron.crashReporter.start();

var mainWindow = null;

app.on('window-all-closed', function() {
  //if (process.platform != 'darwin') {
    app.quit();
  //}
});

app.on('ready', function() {
  // call python?
  var subpy = require('child_process').spawn('python', ['./hello.py']);
  //var subpy = require('child_process').spawn('./dist/hello.exe');
  var rq = require('request-promise');
  var mainAddr = 'http://localhost:5000';

  var openWindow = function(){
    mainWindow = new BrowserWindow({width: 800, height: 600});
    // mainWindow.loadURL('file://' + __dirname + '/index.html');
    mainWindow.loadURL('http://localhost:5000');
    mainWindow.webContents.openDevTools();
    mainWindow.on('closed', function() {
      mainWindow = null;
      subpy.kill('SIGINT');
    });
  };

  var startUp = function(){
    rq(mainAddr)
      .then(function(htmlString){
        console.log('server started!');
        openWindow();
      })
      .catch(function(err){
        //console.log('waiting for the server start...');
        startUp();
      });
  };

  // fire!
  startUp();
});

Taken from the post itself - are the following notes

Notice that in main.js, we spawn a child process for a Python application. Then we check whether the server has been up or not using unlimited loop (well, bad practice! we should actually check the time required and break the loop after some seconds). After the server has been up, we build an actual electron window pointing to the new local website index page.

Hunt answered 23/8, 2016 at 20:49 Comment(3)
Are you assuming that the user has python installed on their system or you are packing it with the electron app (when distributing)?Corolla
I want the solution to that problem, how to package and deliver apps with python backend onto user machines?Higginbotham
Flexx appears to be about oldskool GUI coding style to display widgets in a normal browser. Not at all like Electron where web technologies are used for UI, the browser is built-in and where most importantly it allows for desktop-like access to local files etc.Sure
D
10

This is an update to the answer by @bluesummers that works for me on Jan 2, 2020.

  1. Install Node (https://nodejs.org/en/download/) and python 3.

  2. Install dependencies:

    pip install Flask
    npm install electron
    npm install request
    npm install request-promise
  1. Create a directory for your project and create the following files in that directory:

main.js

const electron = require( "electron" );
const app = electron.app;
const BrowserWindow = electron.BrowserWindow;
electron.crashReporter.start( { companyName: "my company", submitURL: "https://mycompany.com" } );

var mainWindow = null;

app.on(
    "window-all-closed",
    function()
    {
        // if ( process.platform != "darwin" )
        {
            app.quit();
        }
    }
);

app.on(
    "ready",
    function()
    {
        var subpy = require( "child_process" ).spawn( "python", [ "./hello.py" ] );
        // var subpy = require( "child_process" ).spawn( "./dist/hello.exe" );
        var rp = require( "request-promise" );
        var mainAddr = "http://localhost:5000";

        var OpenWindow = function()
        {
            mainWindow = new BrowserWindow( { width: 800, height: 600 } );
            // mainWindow.loadURL( "file://" + __dirname + "/index.html" );
            mainWindow.loadURL( "http://localhost:5000" );
            mainWindow.webContents.openDevTools();
            mainWindow.on(
                "closed",
                function()
                {
                    mainWindow = null;
                    subpy.kill( "SIGINT" );
                }
            );
        };

        var StartUp = function()
        {
            rp( mainAddr )
            .then(
                function( htmlString )
                {
                    console.log( "server started!" );
                    OpenWindow();
                }
            )
            .catch(
                function( err )
                {
                    console.log( "waiting for the server start..." );
                    // without tail call optimization this is a potential stack overflow
                    StartUp();
                }
            );
        };

        // fire!
        StartUp();
});

package.json

{
    "name": "your-app",
    "version": "0.1.0",
    "main": "main.js",
    "scripts":
    {
        "start": "electron ."
    },
    "dependencies":
    {
        "electron": "*",
        "request": "^2.88.0",
        "request-promise": "^4.2.5"
    }
}

hello.py

from __future__ import print_function
# import time
from flask import Flask

app = Flask( __name__ )

@app.route( "/" )
def hello():
    return "Hello World! This is powered by a Python backend."

if __name__ == "__main__":
    print( "oh hello" )
    #time.sleep(5)
    app.run( host = "127.0.0.1", port = 5000 )
  1. From within the project directory, run:
    npm start
Decompress answered 2/1, 2020 at 20:44 Comment(4)
Can you compile the electron project and run it in a computer which does not have python installed?Christianechristiania
@HeribertoJuárez Electron is a Node package in this context. The python part is just for running a server that the Electron browser communicates with. You need to have Python installed (or otherwise packaged with the application) to do this. But it's not necessary to use python as the server for electron. If you are asking how you can distribute this type of application without requiring python to be pre-installed on the user's system, see the "Packaging" section of medium.com/@abulka/electron-python-4e8c807bfa5eDecompress
I tried this solution but the server never starts. It just keeps saying "waiting for the server start...". Do you have to separately start the flask server manually?Epicanthus
@Rikudou, yes, the npm start just starts the Electron client application. The Python server has to be started separately with python hello.py.Decompress
H
5

You can use python-shell to communicate between Python and Node.js/Electron.

python-shell provides an easy way to run Python scripts from Node.js with basic and efficient inter-process communication and better error handling.

Using python-shell, you can:

  • spawn Python scripts in a child process;
  • switch between text, JSON and binary modes;
  • use custom parsers and formatters;
  • perform data transfers through stdin and stdout streams;
  • get stack traces when an error is thrown.

In your terminal, make sure you are inside the root folder of your project and run the following command to install python-shell from npm:

npm install --save python-shell 

You can then simply run a Python shell using:

var pyshell =  require('python-shell');

pyshell.run('hello.py',  function  (err, results)  {
 if  (err)  throw err;
 console.log('hello.py finished.');
 console.log('results', results);
});

See more information from this tutorial

Hanukkah answered 21/12, 2018 at 11:19 Comment(2)
This is a good approach, but how do we build an electron app that has a python dependency? for example I used python shell to run a python script that imports a pip library which worked in development, but then when I want to build my app for production I can't get the python dependencies to workPerdita
How about virtual enve?Err
G
3

With electron-django app I am developing I used pyinstaller to get my django app compiled, then just spawn its child process and it works, please notice pyinstaller may not recognize all modules or dist folder. there are plenty examples online on how to get a workaround for that filling the .specs file and amending the dist folder adding the files you may need. pyinstaller usually tells you what went wrong in the terminal. hope it helps

Greysun answered 2/6, 2020 at 12:28 Comment(0)
N
1

We have just released NiceGUI 1.2.0 which introduces “native” mode. This allows Electron-like capabilities by opening a native window on your desktop instead of a browser tab.

NiceGUI is an open-source Python library to write graphical user interfaces which run in the browser. It has a very gentle learning curve while still offering the option for advanced customizations. NiceGUI follows a backend-first philosophy: it handles all the web development details for you. You can focus on writing Python code.

python3 -m pip install nicegui
from nicegui import ui

ui.label('This is a Python desktop app')
ui.button('click me', on_click=lambda: ui.notify('a notification'))

ui.run(native=True)

Of course the app can also be packaged into an executable.

Nazario answered 20/3, 2023 at 16:5 Comment(0)
F
0

There is a way to convert Streamlit (Python) applications to Electron now: https://github.com/whitphx/stlite/blob/main/packages/desktop-cli/README.md

Caution, all the packages you use need to have Python 3 wheels available for micropip to build your app

Finland answered 5/12, 2022 at 18:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.