0

//fileSaver is used to save the code to a file and download it 
const fileSaver = require('file-saver');
// Setup ace variables and the output pane for pyodide
var editor = ace.edit("editor");
var output_pane;
// manual file paths for testing
var filePath = '/_static/test_files/main.py';
var testFilePath = '/_static/test_files/test.py';


loadPyodide().then((pyodide) => {
    // pyodide is now ready to use...
    globalThis.pyodide = pyodide;
    appendOutput('Python ready.\n');
});

function appendOutput(msg) {
    // used to add program output to the textarea
    output_pane.value = output_pane.value + '\n' + msg;
    output_pane.scrollTop = output_pane.scrollHeight;
}

function configEditor(){
    // configure the ace editor to make it usable
    editor = ace.edit("editor");
    editor.setTheme("ace/theme/xcode");
    editor.session.setMode("ace/mode/python");
    editor.setShowPrintMargin(false);
    editor.setBehavioursEnabled(true);
    editor.setFontSize(13);
    openCode(filePath);
}

function openCode(filePathToUse) {
    getCode(filePathToUse)
      .then(code => {
        var modelist = ace.require("ace/ext/modelist");
        var modeName = modelist.getModeForPath(filePathToUse).mode;
        editor.session.setMode(modeName);
        editor.session.setValue(code);
      })
      .catch(error => {
        console.error('Error occurred while opening the code:', error);
      });
  }

async function runCode(code_to_run) {
    // run the code from the editor and display the output in the textarea
    console.logs = [];

    let promise = new Promise((resolve, reject) => {
        window.pyodide.runPython(code_to_run)
        resolve(true)
    }).catch(err => {
        console.log(err);
        appendOutput(console.logs.join('\n')); 
    });

    let result = await promise;
    if (result) { 
        appendOutput(console.logs.join('\n')); 
    }
}

function saveCode(code) {
    var blob = new Blob([code], { type: "text/plain;charset=utf-8" });
    window.saveAs(blob, filePath);
}

//make a function getCode that takes in a file path and returns the code in that file as a string to use in ace
async function getCode(codeToGet) {
    try {
      const response = await fetch(codeToGet);
      const data = await response.text();
      return data;
    } catch (error) {
      console.error('Error occurred while opening the code:', error);
    }
  }


//codeToSwitch will be a file path
function switchFile(codeToSwitch) {
    getCode(codeToSwitch)
    .then(code => {
        var EditSession = ace.require("ace/edit_session").EditSession;
        var oldSession = editor.getSession();
        //change to new file
        var newSession = new EditSession(code, "ace/mode/python");
        editor.setSession(newSession);
    })
    .catch(error => {
      console.error('Error occurred while opening the code:', error);
    });

}

document.addEventListener('DOMContentLoaded', (event) => {

    output_pane = document.getElementById("output");
    // Add event listeners for downloading code
    document.getElementById("downloadButton").addEventListener('click', function () {
        saveCode(editor.getValue());
    });

    // Add event listeners for switching files
    document.getElementById("switchButton").addEventListener('click', function () {
        switchFile(testFilePath);
    });

    // Add event listeners for running code
    document.getElementById("run_code").addEventListener('click', function () {
        //Run the getcode function to get the code from the editor
        getCode(testFilePath)
        .then(code => {
            runCode(code);
        }) 
        .catch(error => {
            console.error('Error occurred while opening the code:', error);
        });
    });

    // Capture the output from Pyodide and add it to an array
    console.stdlog = console.log.bind(console);
    console.logs = [];
    console.log = function(){
        console.logs.push(Array.from(arguments));
        console.stdlog.apply(console, arguments);
    }
    
    configEditor();
});

The problem is that whenever I run the test script it will tell me that the module main is not defined, meaning Pyodide cant use it. I understand Pyodide cant really use local files for security reasons however I am not really sure how else to have test scripts to run, the main.py and test.py files I inputted manually have code in them already that will pass all the tests. I just want to see if it will work with pyodide so I can be sure that test scripts can be successfully run and move on to serving files on a server and actually be able to save files that users type into and run test scripts off that. How can I be a be to load local packages into pyodide, specifically in a folder such as the test_files folder I have in the code above? And use its files?

Cr3 D
  • 153
  • 6

1 Answers1

0

See the documentation section on loading custom Python code in Pyodide.

In particular, once you download the code you need to write it to the MEMFS file system so that Python would get access to it. For instance, by passing the code string from JS to Python and writing it with Python.

To upload a folder, the easiest is to either put it in a .tar.gz or a Python wheel (if it's a package) and Pyodide provides tools such as pyodide.unpackArchive for the former, and micropip.install for the latter to make it easier. See the documentation above for more complete examples.

rth
  • 10,680
  • 7
  • 53
  • 77