javascriptpythonnode.jspugpugjs

Node how to run python script when clicking button using pug and express node website


I'm trying to run a python script using the webpage I created in pug, express in node. I'm more familar with python than node. Using the below how can I run the python script? I have python shell included but not sure how to run the python script when I click the button on the pug webpage.

server.js

// require all dependencies
var express = require('express');
var app = express();
var PythonShell = require('python-shell');


// set up the template engine
app.set('views', './views');
app.set('view engine', 'pug');

var options = {
  mode: 'text',
  pythonOptions: ['-u'],
  scriptPath: '../hello.py',
  args: ['value1', 'value2', 'value3']
};



// GET response for '/'
app.get('/', function (req, res) {

    // render the 'index' template, and pass in a few variables
    res.render('index', { title: 'Hey', message: 'Hello' });

PythonShell.run('hello.py', options, function (err, results) {
    if (err) throw err;
    // results is an array consisting of messages collected during execution
    console.log('results: %j', results);
});

});

// start up the server
app.listen(3000, function () {
    console.log('Listening on http://localhost:3000');
});

index.pug

html
    head
        title= title
    body
        h1= message
        a(href="http://www.google.com"): button(type="button") Run python script

Solution

  • Create another route that you'll call when the button is clicked. Let's call is /foo. Now set up the handler for this route:

    const { spawn } = require('child_process')
    app.get('/foo', function(req, res) {
        // Call your python script here.
        // I prefer using spawn from the child process module instead of the Python shell
        const scriptPath = 'hello.py'
        const process = spawn('python', [scriptPath, arg1, arg2])
        process.stdout.on('data', (myData) => {
            // Do whatever you want with the returned data.
            // ...
            res.send("Done!")
        })
        process.stderr.on('data', (myErr) => {
            // If anything gets written to stderr, it'll be in the myErr variable
        })
    })
    

    Now on the frontend create the button using pug. And in your client side javascript, make an AJAX call to /foo when this button is clicked. For example,

    button(type="button", onclick="makeCallToFoo()") Run python script
    

    In your client side JS:

    function makeCallToFoo() {
        fetch('/foo').then(function(response) {
            // Use the response sent here
        })
    }
    

    EDIT: You can also use the shell module you're already using in a similar fashion. If you don't want the client side JS, you can enclose the button in a form with attributes: method="get" action="/foo". For example,

    form(method="get" action="/foo")
        button(type="submit") Run python script