I'm trying to run a function in python which returns me values from a PDF file, I upload the file into the controller written in nodejs, I call the python function with PythonShell. I'd like my controller to wait to solve my python function so I can return those values in the body so that I could consume these values in my View. My question is how I wait and how I withdraw the data from the function.

Inside the Python.stdout.on I can print the data in console.log, but i can't return data to outside the function

This function python is an example to the data since the return the function is a dataframe.

  async store({ request, response }) {
    try {
      if (!request.file("file")) return;

      const upload = request.file("file", { size: "2mb" });

      const fileName = `${Date.now()}.${upload.subtype}`;

      await upload.move(Helpers.tmpPath("uploads"), {
        name: fileName
      });

      if (!upload.moved()) {
        throw upload.error();
      }

      const resized = await path.resolve(
        __dirname,
        "..",
        "..",
        "..",
        "tmp",
        "uploads",
        fileName
      );

      let options = {
        mode: "text",
        pythonOptions: ["-u"],
        scriptPath: path.resolve(__dirname, "..", "Service"),
        args: [resized]
      };

      const Python = PythonShell.run("pdfRead.py", options, function(
        err,
        results
      ) {
        if (err) throw err;
        // results is an array consisting of messages collected during execution
        console.log("results: %j", results);
        const data = results;
        return data

      });

      const dataPython = await Python.stdout.on("data", data => {
        console.log(`data: ${data}`);
        const aux = [data];
        return aux        
      });

      return response.status(200).send(dataPython.data);

    } catch (error) {
      return response
        .status(error.status)
        .send({ error: { message: "Erro no upload de arquivo" } });
    }
  }

import sys
import pandas as pd

path = sys.argv[1]


def get_file(path):
    data = pd.read_csv(path)
    return data


print(get_file(path))
sys.stdout.flush()

1 Answers

0
Gean Feltrin On

I solved my problem, look the code :D I used promisify for transform the function PythonShell(callback) to promise.

async store({ request, response }) {
    try {
      if (!request.file("file")) return;

      const upload = request.file("file", { size: "30mb" });

      const fileName = `${Date.now()}.${upload.subtype}`;

      await upload.move(Helpers.tmpPath("uploads"), {
        name: fileName
      });

      if (!upload.moved()) {
        throw upload.error();
      }

      const resized = await path.resolve(
        __dirname,
        "..",
        "..",
        "..",
        "tmp",
        "uploads",
        fileName
      );

      let options = {
        mode: "text",
        pythonOptions: ["-u"],
        scriptPath: path.resolve(__dirname, "..", "Service"),
        args: [resized]
      };

      const readPdf = promisify(PythonShell.run);

      const pdf = await readPdf("extrator.py", options);

      const json = JSON.parse(pdf[0]);

      const file = await File.create({
        file: fileName,
        name: upload.clientName,
        type: upload.type,
        subtype: upload.subtype,
        data: json
      });

      return response.send(file.file);
    } catch (error) {
      return response
        .status(error.status)
        .send({ error: { message: "Erro no upload de arquivo" } });
    }