Interactive Python interpreter for executing commands within Node.js

Overview

Python Interactive

CI Status Coverage Status Node

Interactive Python interpreter for executing commands within Node.js.

This module provides a means of using the Python interactive interpreter programmatically from within Node.js, allowing commands to be executed from code as if they were being run in a terminal.

Commands are executed asynchronously through the use of async/await, with results being returned via a Promise. This allows for interactions to be handled differently depending on whether the Python code ran successfully or returned an error.

Example

let {PythonInteractive} = require('python-interactive');
let python = new PythonInteractive();

let loopCmd = `
count = 0
while pi > 0:
  pi = pi / 2
  count += 1

print(count)
`;

// Start the Python process
python.start();

await (async () => {
  // Import packages and ignore any output
  await python.execute('from math import pi');

  // Print value of 'pi' and store the output
  let pi = await python.execute('print(pi)');

  // Execute multiline loop command and handle its output via Promise callbacks
  await python.execute(loopCmd)
    .then((data) => {
      // If the Python code executed successfully
      console.log(`${pi} was halved ${data} times before being less than or equal to 0`);
    })
    .catch((err) => {
      // If the Python code executed with an error
      console.log(`Failed to execute due to error:\n ${err}`);
    })
})();

// Stop the Python process
python.stop();
3.141592653589793 was halved 1077 times before being less than or equal to 0

Usage

Installing

NPM

Loading the Module

// ES6 module syntax
import {PythonInteractive} from 'python-interactive';

// CommonJS module syntax
let {PythonInteractive} = require('python-interactive');

Use ES6 import or CommonJS require to use the PythonInteractive class.

Creating an Instance

// Use default Python executable
let python = new PythonInteractive();

// Use specific Python executable
let python = new PythonInteractive('python3.9');

// Use specific Python executable with path
let python = new PythonInteractive('/path/to/python');

Create a new instance of PythonInteractive. By default, the Python interpreter will be spawned in interactive mode and is called using the python3 command on Unix systems or python on Windows. You must have Python in your PATH for this to work.

Each instance of PythonInteractive maintains a single isolated Python interpreter process. This allows you to have multiple Python processes running simultaneously whilst ensuring that they do not interfere with one another.

Optionally, you can initialise the Python interpreter using a specific Python executable. This can be done by passing in a path or command to the constructor.

Starting a Python Process

python.start();

To start the Python process, call the start() method. Attempting to execute commands before calling start() will result in an error being thrown. This method will not do anything if a process is already running.

Stopping a Python Process

python.stop();

To stop the Python process, call the stop() method. This will destroy all stdio streams, kill the Python process, then set it to null. When stop() is run, commands can no longer be executed until start() is called again. This method will not do anything if a process is not running.

Restarting a Python Process

python.restart();

To restart the Python process, call the restart() method. This method acts as a wrapper for calling stop() and then start(), and provides no additional functionality.

Executing Commands

Commands can be executed in multiple ways, but should always be done using async/await functionality as the result is returned via a Promise. Below are some examples of how commands can be executed. For more examples, take a look at the test suite.

Ignore Output

(async () => {
  await python.execute('x = 10');
})();

This will execute a command but do nothing with its output. However, in this example the x variable will still be assigned the value 10, and can be referenced in future command executions. Note that if a command is executed in this manner and causes an error, the error will be thrown (this can be handled using try/catch or the catch() function).

Retrieve Output

(async () => {
  let result = await python.execute('print(x)');
})();

This will execute a command and then save its output to the result variable. Since x was previously assigned the value 10, executing the command print(x) will give the output 10. This value is then saved to result. Note that if a command is executed in this manner and causes an error, the error will be thrown (this can be handled using try/catch or the catch() function).

Handle Output

(async () => {
  await python.execute('print(y)')
    .then((data) => {
      console.log(`Executed successfully with output:\n ${data}`);
    })
    .catch((err) => {
      console.log(`Failed to execute with error:\n ${err}`);
    })
})();

This will execute a command and then handle the output by attaching callbacks to the returned Promise. If the command executes without an error, the then() callback will handle the output. If the command returned an error, the catch() callback will handle the output. In this example, the catch() callback will be executed (as y has not been declared) and output the following:

", line 1, in NameError: name 'y' is not defined">
Failed to execute with error:
Traceback (most recent call last):
  File "
     
      ", line 1, in 
      
       
NameError: name 'y' is not defined

      
     

Multiline Command

let input = `
i = 0
while i < 3:
  print(i)
  i += 1

print(i*i)
`;

(async () => {
  let result = await python.execute(input);
  console.log(`"${result}"`);
})();

It is also possible to execute multiline commands, with any output being concatenated into a single string. For example, the above code will return the output:

"0
1
2
9"

Multiline constructs (e.g. loops, functions, classes) must be closed before the code can be executed - you cannot execute separate parts of a construct individually.

Interpreter Rules

Note that you must adhere to the rules of the Python interpreter when in interactive mode; indentation and line breaks must be used correctly to represent where constructs end. For example, this is valid Python code:

for i in range(a):
  print(i)

print(i * i)

This is not valid Python code and will return an IndentationError:

for i in range(a):
  print(i)
print(i * i)

API

PythonInteractive(pythonPath)

Initialises a new instance of PythonInteractive.

Each instance of PythonInteractive uses its own process, separate from all other instances. Note that the Python process is not spawned until the start() method is called.

Parameters

  • pythonPath (string): path to the Python interpreter. Defaults to python3 on Unix systems or python on Windows.

Properties

  • pythonPath (string): path to the Python interpreter.
  • process (ChildProcess): the current Python interpreter process.
  • history (Array ): all commands that have been executed for the current process.
  • lastCommand (string): the last command that was executed for the current process.

start()

Spawns a new Python process.

A new process is spawned using the Python interpreter as defined by the pythonPath property, though only if no process is currently running. To kill the current process, call stop(). Note that the history property is reset when calling this method.

The Python interpreter is always spawned with the -i, -u, and -q flags.

Parameters

  • args (string[]): Arguments to pass to the Python interpreter.
  • options (Object): Options to pass to the spawned process.

stop()

Kills the current Python process.

If no process is running, this method will do nothing. To spawn a new process, call the start() method.

restart()

Kills the current Python process and spawns a new one.

This method acts as a wrapper for executing stop() and then start(). It will only kill a process if there is a process currently running. If not, then only a new process is spawned. Note that the history property is reset when calling this method.

Parameters

  • args (string[]): Arguments to pass to the Python interpreter.
  • options (Object): Options to pass to the spawned process.

pythonVersion()

Returns the version of the Python interpreter via a Promise.

pythonBuild()

Returns information about the Python interpreter build via a Promise.

This method only works with Python 3.6 or greater.

execute(command)

Executes a string of Python code and returns the output.

Before commands can be executed, the Python process must be spawned using the start() method. An error will be thrown if the Python process has not been started.

Returns a Promise which will resolve with the output if the command executed successfully, or reject with an error message if the command failed.

Parameters

  • command (string): Python command to be executed. May be a single command or multiple commands separated by line breaks. If undefined, an empty line is executed.
You might also like...
commandpack - A package of modules for working with commands, command packages, files with command packages.
commandpack - A package of modules for working with commands, command packages, files with command packages.

commandpack Help the project financially: Donate: https://smartlegion.github.io/donate/ Yandex Money: https://yoomoney.ru/to/4100115206129186 PayPal:

Output Analyzer for you terminal commands
Output Analyzer for you terminal commands

Output analyzer (OZER) You can specify a few words inside config.yaml file and specify the color you want to be used. installing: Install command usin

A terminal tool for git. When we use git, do you feel very uncomfortable with too long commands
A terminal tool for git. When we use git, do you feel very uncomfortable with too long commands

PIGIT A terminal tool for git. When we use git, do you feel very uncomfortable with too long commands. For example: git status --short, this project c

⚙ A lightweight command line interface library for creating commands.
⚙ A lightweight command line interface library for creating commands.

⚙ A lightweight command line interface library for creating cli commands. About | Installation | Usage | Features | Contributors | License About Next:

tox-server is a command line tool which runs tox in a loop and calls it with commands from a remote CLI.

Tox Server tox-server is a command line tool which runs tox in a loop and calls it with commands from a remote CLI. It responds to commands via ZeroMQ

A CLI for advanced management of your notes with simple commands

PyNoteManager This is a CLI for advanced management of your notes with simple co

Message commands extension for discord-py-interactions

interactions-message-commands Message commands extension for discord-py-interactions README IS NOT FINISHED YET BUT IT IS A GOOD START Installation pi

A Multipurpose bot with many Commands made using Pycord

This repo has all of the commands you will ever need in a discord bot. a Multipurpose discord bot

A Bot Which Send Automatically Commands To Karuta Hub to Gain it's Currency

A Bot Which Send Automatically Commands To Karuta Hub to Gain it's Currency

Comments
  • Parallel instance commands tests throw '>>>'

    Parallel instance commands tests throw '>>>'

    Bug Description

    Quite rarely, tests involving parallel instanced commands will thrown >>> as an error.

    Steps to Reproduce Bug

    This can be most easily seen by repeatedly running the unit tests involving parallel instanced commands, and usually occurs with the Execute_ParallelInstancedMixedCommands_ReturnsErrorsAndOutputs test.

     Execute Python Commands › Async Commands › Execute_ParallelInstancedMixedCommands_ReturnsErrorsAndOutputs
        thrown: ">>>"
    

    Additional Information

    Jest will not exit when this error occurs, meaning that there are asynchronous operations that weren't stopped in the tests.

    System Information

    • Node.js Version: 16.6.1
    • Operating System: Arch Linux 5.13.9
    bug 
    opened by louislefevre 1
  • Incomplete error messages

    Incomplete error messages

    Bug Description

    Sometimes, errors output by the PythonShell are partially or entirely incomplete. As a result, unit tests related to testing errors are flaky and will sometimes arbitrarily fail.

    Steps to Reproduce Bug

    This can be most easily seen by repeatedly running the unit tests until one of the ones related to invalid commands/returning errors breaks.

    Expected Behaviour & Actual Behaviour

    Expected:

    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    NameError: name 'x' is not defined
    

    Actual:

    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    

    Additional Information

    This problem is due to the Python process stdout listener resolving its promise too fast. Only one stream, out of stdout and stderr, can be read at one time. The listener for stdout is where it is determined whether or not all the data has been received. If stdout is being read and completes, the promise will resolve with any information it currently has, even if not all information has been read from stderr. The solution to the problem is to implement a method for ensuring that both streams have been fully read in before resolving the promise.

    System Information

    • Node.js Version: 16.5.0
    • Operating System: Arch Linux 5.13.5
    bug 
    opened by louislefevre 0
Releases(v0.3.2)
  • v0.3.2(Sep 10, 2021)

    • c82a66e69f232bd16f9300dc83961bba60102b1b - Update dependencies to latest versions
    • b940f230dd59274fc01c1bd11606008201591521 - Add cross-spawn dependency for more reliable process spawning on Windows
    • 5d93333aa64f86210616a58debca4a14ea7ba209 - Update how prompts are handled; they are now removed when the process is spawned rather than filtered out from the output, fixing random >>> prompts sometimes being thrown as errors
    • 7c6db7b48daf7c8d4ea15215a670432a44d93183 - Remove ts-replace-all dependency
    Source code(tar.gz)
    Source code(zip)
  • v0.3.1(Aug 28, 2021)

    • b3bcc1f5c8037ed39b28c01d52d930d8e341c12a - Fix streams blocking execution when they unexpectedly end or return an error
    • 43039503cd16bd3c02a0ed813a16589fb71caa8c - Fix trailing arrows being returned (usually on Windows)
    Source code(tar.gz)
    Source code(zip)
  • v0.3.0(Aug 21, 2021)

  • v0.2.0(Aug 12, 2021)

    • d4e755495aec944d4eb81aa3193e5f5c26ea3912 - Compile to ECMAScript 2019 instead of ECMAScript 2015
    • 94ca5a6ec4e726fc5b17f7ccb713d995b9f61932 - Add lastCommand property
    • a739381cb903a58e5ceb02a13c64424a67b021ea - Add pythonVersion() method
    • 535cc5d4c08c0a595e13ed64cc64ee9f2e313e6f - Add pythonBuild() method
    • f225b9bb504e13c83df871c7305e76c31e116dfc - Remove async from start() and restart() methods so that they no longer return interpreter build information
    • ff5059ae67b15800d91304c11fd6390ffab6375c - Remove script property, add history property
    • d99803a3b1129ff69cf43ccb53646c2d377825a9 - Update documentation to be up-to-date
    Source code(tar.gz)
    Source code(zip)
  • v0.1.1(Aug 9, 2021)

    1f9d787ea35734081884369bbdadb23b3e936281 - Update README.md to include execute() function in API section e5bef7932a5a267e1520b1c34b2c8ee691a3af9f - Fix error messages not always being displayed in full (#1)

    Source code(tar.gz)
    Source code(zip)
  • v0.1.0(Aug 4, 2021)

A simple CLI application helps you to find giant files that are eating up your system storage

Large file finder Sometimes it's very hard to find if some giant files are eating up your system storage. We might need to hunt those down. This simpl

Rahul Baruri 5 Nov 18, 2022
An open source terminal project made in python

Calamity-Terminal An open source terminal project made in python. Calamity Terminal is a free and open source lightweight terminal. Its made 100% off

1 Mar 08, 2022
A Hikari command handler for people who love ducks.

duckari A Hikari command handler made with love by ducks. Currently Duckari is work in progress. Documentation is WIP. The wiki is no longer used as d

2 Oct 09, 2022
Play videos in the terminal.

Termvideo Play videos in the terminal (stdout). python main.py /path/to/video.mp4 Terminal size: -x output_width, -y output_height. Default autodetect

Patrick 11 Jun 13, 2022
spotifytools is a Python command line tool

spotifytools spotifytools is a Python command line tool Documentation The documentation is available on the following link Releases Instalation instru

0 Sep 28, 2021
A simple cli tool to commit Conventional Commits

convmoji A simple cli tool to commit Conventional Commits. Requirements Install pip install convmoji convmoji --help Examples A conventianal commit co

3 Jul 04, 2022
Konsave lets use save your KDE Plasma customizatios and restore them very easily!

Konsave (Save Plasma Customization) A CLI program that will let you save and apply your KDE Plasma customizations with just one command! Als

439 Jan 02, 2023
Set of scripts & tools for converting between numbers and major system encoded words.

major-system-converter Set of scripts & tools for converting between numbers and major system encoded words. Uses phonetics instead of letters to conv

4 Aug 09, 2022
An question and answer shell environment based on xonsh using ansible for setup

An question and answer shell environment based on xonsh using ansible for setup

Steven Hollingsworth 2 Jan 11, 2022
Python command line tool and python engine to label table fields and fields in data files.

Python command line tool and python engine to label table fields and fields in data files. It could help to find meaningful data in your tables and data files or to find Personal identifable informat

APICrafter 22 Dec 05, 2022
Tools hacking termux in the name ant-attack

Hello friends, I am ama.player0000. Web developer, software, Android command line (termux). (1)=Well, ant-attack tool is a tool to attack sites and disable them. (2)=You can use those CCTV servers, s

༺AMA.PLAYER༻ 1 Dec 17, 2021
An ZFS administration tool inspired on Midnight commander

ZC - ZFS Commander An ZFS administration tool inspired on Midnight commander Work in Progress Description ZFS Commander is a simple front-end for the

34 Dec 07, 2022
A command-line tool to upload local files and pastebin pastes to your mega account, without signing in anywhere

A command-line tool to upload local files and pastebin pastes to your mega account, without signing in anywhere

ADI 4 Nov 17, 2022
Get latest astronomy job and rumor news in your command line

astrojobs Tired of checking the AAS job register and astro rumor mill for job news? Get the latest updates in the command line! astrojobs automaticall

Philip Mocz 19 Jul 20, 2022
Un module simple pour demander l'accord de l'utilisateur dans une CLI.

Demande de confirmation utilisateur pour CLI Présentation ask_lib est un module pour le langage Python proposant une seule fonction; ask(). Le but pri

CallMePixelMan 7 May 09, 2022
Easy-to-use terminal program that can compile your code.

Description Easy-to-use terminal program that can compile your code. Installition 1. Cloning repository $ git clone https://github.com/DarkJoij/Compil

DarkJoij 1 Oct 21, 2021
Urial (URI Addition tooL) intelligently updates URIs stored in Finder comments of macOS files

Urial Urial (URI addition tool) is a simple but intelligent command-line tool to add or replace URIs found inside macOS Finder comments. Table of cont

Mike Hucka 3 Sep 14, 2022
Python-Stock-Info-CLI: Get stock info through CLI by passing stock ticker.

Python-Stock-Info-CLI Get stock info through CLI by passing stock ticker. Installation Use the following command to install the required modules at on

Ayush Soni 1 Nov 05, 2021
CLI helper to install Github releases on your system.

gh-release-install is a CLI helper to install Github releases on your system. It can be used for pretty much anything, to install a formatter in your CI, deploy some binary using an orcherstration to

Jonas L. 28 Nov 06, 2022
A simple yet powerful timer and time tracker from the command line.

Focus Phase Focus Phase (FP) is a simple yet powerful timer and time tracker. It is a command-line application written in Python and can be installed

Ammar Alyousfi 13 Jan 13, 2022