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)

Wordle-textual - Play Wordle from the CLI, using Textual

Wordle, playable from the CLI This project seeks to emulate Wordle in your shell

PhenoM4n4n 3 Mar 29, 2022
A Simple Python CLI Lockpicking Tool

Cryptex a simple CLI lockpicking tool What can it do: Encode / Decode Hex Encode / Decode Base64 Break Randomly :D Requirements: Python3 Linux as your

Alex Kollar 23 Jul 04, 2022
Python3 library for multimedia functions at the command terminal

TERMINEDIA This is a Python library allowing using a text-terminal as a low-resolution graphics output, along with keyboard realtime reading, and a co

Joao S. O. Bueno 89 Dec 17, 2022
WazirX Portfolio Tracker on your Terminal!

If you have been investing in crypto in India, there is a very good chance that you are using WazirX. If you are using WazirX, then you definitely know that there is no P&L report, no green arrows no

Raunit 15 Jan 10, 2022
You'll never want to use cd again.

Jmp Description Have you ever used the cd command? You'll never touch that outdated thing again when you try jmp. Navigate your filesystem with unprec

Grant Holmes 21 Nov 03, 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
Custom 64 bit shellcode encoder that evades detection and removes some common badchars (\x00\x0a\x0d\x20)

x64-shellcode-encoder Custom 64 bit shellcode encoder that evades detection and removes some common badchars (\x00\x0a\x0d\x20) Usage Using a generato

Cole Houston 2 Jan 26, 2022
Kattis shell for getting examples, testing and submitting.

Kattis shell for getting examples, testing and submitting.

Simon Green Kristensen 15 Sep 30, 2022
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

Pogrammar 42 Dec 18, 2022
Play Wordle Bot - Wordle Bot written in python

Wordle Bot A Bot written in python with a CL Interface to guess adn solve Wordle

Prashant 1 Feb 25, 2022
Amazon Scraper: A command-line tool for scraping Amazon product data

Amazon Product Scraper: 2021 Description A command-line tool for scraping Amazon product data to CSV or JSON format(s). Requirements Python 3 pip3 Ins

49 Nov 15, 2021
Python and data science snippets on the command line

Python Snippet Tool A tool to get Python and data science snippets at Data Science Simplified on the command line. You can read my article to learn ho

Khuyen Tran 19 Dec 21, 2022
A small system that allow you to manage hosts stored in your .ssh/config file

A small system that allow you to manage hosts stored in your .ssh/config using simple commands.

Simone Ostini 1 Jan 24, 2022
A project designed to make taking notes easier than ever - by doing it all on command line

A project designed to make taking notes easier than ever - by doing it all on command line! Yes, all of your files are easily accessible through one command interface, and can be written to at any ti

1 Dec 10, 2021
Convert shellcode into :sparkles: different :sparkles: formats!

Bluffy Convert shellcode into ✨ different ✨ formats! Bluffy is a utility which was used in experiments to bypass Anti-Virus products (statically) by f

AD995 305 Dec 17, 2022
Terminal-based keyboard testing

kbdtest kbdtest is a simple Python program that tests keyboard input using an interactive, terminal-based, visual keyboard display. It was originally

Ruunyox 12 Jul 19, 2022
A python CLI app that converts a mp4 file into a gif with ASCII effect added.

Video2ASCIIgif This CLI app takes in a mp4 format video, converts it to a gif with ASCII effect applied. This also includes full control over: backgro

Sriram R 6 Dec 31, 2021
Professor Wordlist is a free open source command line tool written in python

Professor Wordlist is a free open source command line tool written in python, With the aim of generating custom wordlists with a variety of unique parameters and functions providing many possibilitie

オークO A K Z E H オーク 1 Oct 28, 2021
Chat with Rem in Terminal!

Chat with Rem in Terminal!

bariscodefx 1 Dec 19, 2021
Command line tool to keep track of your favorite playlists on YouTube and many other places.

Command line tool to keep track of your favorite playlists on YouTube and many other places.

Wolfgang Popp 144 Jan 05, 2023