import | how does node module require work | compile an es module | Search

The provided code consists of two functions, runPythonModule and makePythonModule, designed to execute and manage Python modules in a Node.js environment. The runPythonModule function runs a Python module and captures its output, while the makePythonModule function creates a new Python module from provided code and returns its exports.

Cell 2

const Module = require('module').Module
const path = require('path')
const {spawn} = require('child_process')

async function runPythonModule(isOne, cellId, signature, ...args) {
  const {CONSOLE} = require('../Core')
  let params = signature.parameters.map((p, i) => '--' + p + '=' + String(args[i]))
  //console.log(params)
  //console.log(path.resolve(path.dirname(__dirname)))
  result = spawn('python3', ['-u', '-c', '__import__(\'Core\').run()', cellId].concat(params), {
    cwd: path.resolve(path.dirname(__dirname)),
    env: {
      RUN_OUTPUT: 'json',
      PYTHONPATH: path.resolve(path.dirname(__dirname)) + ':/opt/homebrew/Caskroom/miniforge/base/lib/python3.12/site-packages'
    },
    stdio: ['pipe', 'pipe', 'pipe']
  })
  if (result.error) {
    CONSOLE.error('Failed to execute:', result.error)
    return
  }

  let lines = []
  result.stdout.on('data', (data) => {
    lines.push(data)
    CONSOLE.log(`stdout: ${data.toString().trim()}`);
  });
  
  result.stderr.on('data', (data) => {
    CONSOLE.error(`stderr: ${data.toString().trim()}`);
  });
  
  await new Promise((resolve, reject) => result.on('close', (code) => {
    if(code != 0) return reject()
    return resolve()
  }));

  lines = lines.join('').trim().split('\n')
  try {
    let json = JSON.parse(lines[lines.length - 1])
    return json
  } catch (up) {
    throw up
  }
}


async function makePythonModule(code, filename, context) {
  const { importNotebook, CONSOLE } = require('../Core')
  let filepath = path.resolve(process.cwd(), filename);
  if (typeof Module._cache[filepath] != 'undefined') {
    return Module._cache[filepath].exports
  }

  let pythonParams = await importNotebook("python params in antlr")
  CONSOLE.log(pythonParams)
  let params = await pythonParams(code)
  CONSOLE.log(params)

  let cellExportsOne = false
  if(typeof params.function != 'undefined') {
    cellExportsOne = true
  }

  Module._cache[filepath] = {}
  Module._cache[filepath].exports = {}

  for(let i = 0; i < params.length; i++) {
    Module._cache[filepath].exports[params[i].function] = runPythonModule.bind(null, cellExportsOne, filename, params[i])
    Module._cache[filepath].exports[params[i].function].params = params[i].parameters
  }

  Module._cache[filepath].exports.functions = params.map(p => p.function)

  return Module._cache[filepath].exports
}

module.exports.makePythonModule = makePythonModule

What the code could have been:

/**
 * Runs a Python module with the given arguments and returns the result as JSON.
 * 
 * @param {boolean} isOne - Whether to run the module as a single cell or not.
 * @param {string} cellId - The ID of the cell to run.
 * @param {object} signature - The function signature to run.
 * @param {...*} args - The arguments to pass to the function.
 * @returns {Promise} The result of the module as JSON.
 */
async function runPythonModule(isOne, cellId, signature,...args) {
  const { CONSOLE } = require('../Core');

  // Create the command to run the Python module
  const command = ['python3', '-u', '-c', `__import__('Core').run('${cellId}')`];

  // Add the function arguments to the command
  const params = signature.parameters.map((p, i) => `--${p}=${args[i]}`);

  // Create the command process
  const result = spawn(command[0], command.concat(params), {
    cwd: path.resolve(path.dirname(__dirname)),
    env: {
      RUN_OUTPUT: 'json',
      PYTHONPATH: path.resolve(path.dirname(__dirname)) + ':/opt/homebrew/Caskroom/miniforge/base/lib/python3.12/site-packages'
    },
    stdio: ['pipe', 'pipe', 'pipe']
  });

  // Handle the command process
  if (result.error) {
    CONSOLE.error('Failed to execute:', result.error);
    return;
  }

  // Get the output from the command process
  const lines = [];
  result.stdout.on('data', (data) => {
    lines.push(data);
    CONSOLE.log(`stdout: ${data.toString().trim()}`);
  });

  result.stderr.on('data', (data) => {
    CONSOLE.error(`stderr: ${data.toString().trim()}`);
  });

  // Wait for the command process to finish
  await new Promise((resolve, reject) => result.on('close', (code) => {
    if (code!== 0) return reject();
    return resolve();
  }));

  // Parse the output as JSON
  lines = lines.join('').trim().split('\n');
  try {
    const json = JSON.parse(lines[lines.length - 1]);
    return json;
  } catch (error) {
    throw error;
  }
}

Overview

The provided code consists of two main functions: runPythonModule and makePythonModule. These functions are designed to execute and manage Python modules in a Node.js environment.

runPythonModule Function

Parameters

  • isOne: A boolean indicating whether to execute a single module or not (not used in the function)
  • cellId: An identifier for the cell being executed
  • signature: The signature of the module to be executed (an object)
  • ...args: Variable number of arguments to be passed to the module

Description

This function runs a Python module using child_process and captures the output. It:

  1. Extracts the parameters from the module signature and converts them to a format suitable for the spawn function.
  2. Spawns a new process to execute the Python module.
  3. Captures the output (stdout and stderr) and logs it to the console.
  4. Waits for the process to complete and checks the exit code.
  5. If the exit code is 0, it parses the last line of the output as JSON and returns it.

makePythonModule Function

Parameters

  • code: The Python code to be executed
  • filename: The filename to be used for the module
  • context: An object that is not used in the function

Description

This function creates a new Python module from the provided code and returns an object with the module's exports.

  1. It checks if the module already exists in the cache and returns it if it does.
  2. It imports the importNotebook function and uses it to generate a set of parameters for the Python module.
  3. It executes the importNotebook function with the provided code and gets the generated parameters.
  4. It creates a new cache entry for the module and initializes it with the module's exports.
  5. It loops through the parameters and sets them up in the cache entry.

Note: The makePythonModule function seems to be incomplete and has some commented-out code.