【问题标题】:Node.js: Is it possible to make an adaptor for python interactive shell (REPL)?Node.js:是否可以为 python 交互式 shell (REPL) 制作适配器?
【发布时间】:2020-07-21 18:07:56
【问题描述】:

可以在Node.js中使用readline读取一行python代码,然后作为子进程发送到python交互shellspawned,然后接收输出?

我知道这是可能的:

import { spawn } from "child_process";

const py = spawn("python", ["-i"]);

py.stdout.on("data", (data) => {
  console.log(`stdout: ${data}`);
});

py.stdin.write('print("hello from python!")\n');

// will get 'stdout: hello from python!'

但是,这不起作用:

import { spawn } from "child_process";
import * as readline from "readline";

const py = spawn("python", ["-i"]);

py.stdout.on("data", (data) => {
  console.log(`stdout: ${data}`);
});

py.stdin.write('print("hello from python!")\n');

const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout,
});
rl.prompt();
rl.on("line", (line) => {
  py.stdin.write(line);
  rl.prompt();
}).on("close", () => {
  process.exit()
});

我想这样做是因为我想在 Node.js 中为 python 开发一个接口。通过spawn 执行独立的python 命令/文件很简单,但我想构建一个功能齐全的界面,它具有与R 中的Reticulate 类似的功能。

【问题讨论】:

    标签: javascript python node.js ffi read-eval-print-loop


    【解决方案1】:

    我有一个类似的应用程序,我设法让它运行得足以满足我的需要:a processToPromise function。 缺点是它总是必须在每个call 上注册新的事件监听器。基本上,它会在您的命令完成后等待交互式 Python shell 打印它的 >>>,并为您提供同时出现的输出。

    此外,您不能多次异步调用此函数而不会得到混乱的结果。 先尝试一些简单的 print 语句,看看是否得到了预期的结果。


    一些代码供参考:

    const child_process = require('child_process');
    
    class InteractiveProcessHandle {
        private process: any;
    
        public outputLog: string;
        public latestOutput: string;
    
        private processToPromise(process: any) {
            return new Promise<string>((resolve, reject) => {
                console.log("+++ creating promise");
                process.stdout.removeAllListeners();
                process.stderr.removeAllListeners();
                process.stdin.removeAllListeners();
    
                let lastString: string = '';
    
                process.stdout.on("data", (data: any) => {
                    data = data.toString().trim();
                    this.update(data);
                    if (data.endsWith('>>>')) {
                        resolve(lastString);
                    }
                    lastString = data;
                });
                process.stderr.on("data", (data: any) => {
                    data = data.toString().trim();
                    this.update(data);
                    if (data.endsWith('>>>')) {
                        resolve(lastString);
                    }
                    lastString = data;
                });
                process.stdin.on("error", () => {
                    console.log("Failure in stdin! ... error");
                    reject();
                });
                process.stdin.on("close", () => {
                    console.log("Failure in stdin! ... close");
                    reject();
                });
                process.stdin.on("end", () => {
                    console.log("Failure in stdin! ... end");
                    reject();
                });
                process.stdin.on("disconnect", () => {
                    console.log("Failure in stdin! ... disconnect");
                    reject();
                });
                process.stdout.on("error", () => {
                    console.log("Failure in stdout! ... error");
                    reject();
                });
                process.stdout.on("close", () => {
                    console.log("Failure in stdout! ... close");
                    reject();
                });
                process.stdout.on("end", () => {
                    console.log("Failure in stdout! ... end");
                    reject();
                });
                process.stderr.on("error", () => {
                    console.log("Failure in stderr! ... error");
                    reject();
                });
                process.stderr.on("close", () => {
                    console.log("Failure in stderr! ... close");
                    reject();
                });
                process.stderr.on("end", () => {
                    console.log("Failure in stderr! ... end");
                    reject();
                });
                console.log("+++ done creating promise");
            });
        }
    
        private update(data: any) {
            this.latestOutput = data;
            this.outputLog += data + "\n";
            console.log(`logging from update: "${data}"`);
        }
    
        public call(command: string): Promise<string> {
            console.log(`called: "${command.trim()}"`);
            let promise = this.processToPromise(this.process);
            this.process.stdin.write(command);
            return promise;
        }
    
        constructor(call: any, options: any) {
            this.latestOutput = "";
            this.outputLog = "";
    
            this.process = child_process.spawn(call, options, { shell: true });
            this.process.stdout.setEncoding('utf8');
            this.process.stderr.setEncoding('utf8');
        }
    };
    
    var interactive_python = new InteractiveProcessHandle('python', ['-i']);
    
    async () => {
        await interactive_python .call('');
        await interactive_python .call('x = 20');
        let x = await clang_build.call('print(x)\n');
        console.log('x = ', x);
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-04-16
      • 1970-01-01
      • 1970-01-01
      • 2016-09-22
      • 2022-01-05
      • 2011-03-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多