Search code examples
pythonhtmlcsspyscript

How do I use pyscript in my HTML code and return output


I am trying to call my python function created. But not getting any output and no resource how to achieve.

Code :

<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="https://pyscript.net/alpha/pyscript.css" />
<script defer src="https://pyscript.net/alpha/pyscript.js"></script>
</head>
<body>

<p>Click on the "Choose File" button to upload a file:</p>

<form>
  <input  type="file" id="myFile" name="filename">
  <input type="submit" onClick="readfile(filename)" name="SUBMIT">
</form>

<py-script>

def readfile(filename):
    with open(filename) as mfile:
        head = [next(mfile) for x in range(1,5)]
        print(head)

</py-script>

</body>
</html>

It would be great helpful if some one provide input like …

How to pass selected file to my function and python will be executed & return output on screen.


Solution

  • When writing Python in the browser, you must rethink how actions are performed. Typically, Python programs are procedural. Browser-based applications are asynchronous.

    The first step is to enable asynchronous features:

    import asyncio
    

    Browser based programs cannot directly access the local file system. Your code is not doing what you think it is.

    def readfile(filename):
        with open(filename) as mfile:
            head = [next(mfile) for x in range(1,5)]
            print(head)
    

    Your code is reading from the browser virtual file system which is allowed. You are trying to process the event from the ` element but trying to access a different location.

    Note: I do not know what the file contents of "filename" are, so I did not incorporate your code after the file is read.

    Your code cannot read files. You must ask the browser to read a file for your application. This is performed with the FileReader class.

    Example:

    async def process_file(event):
            # Currently, PyScript print() does not work in this 
            # type of code (async callbacks)
            # use console.log() to debug output
    
            fileList = event.target.files.to_py()
    
            for f in fileList:
                    data = await f.text()
                    document.getElementById("content").innerHTML = data
                    # Add your own code to process the "data" variable
                    # which contains the content of the selected file
    

    Another problem is that you are passing a Python function as a callback. That will not work. Instead, you must call create_proxy() to create a callback proxy for the Python function. The browser will call the proxy which then calls your Python function.

    Example:

    # Create a Python proxy for the callback function
    # process_file() is your function to process events from FileReader
    file_event = create_proxy(process_file)
    
    # Set the listener to the callback
    document.getElementById("myfile").addEventListener("change", file_event, False)
    

    I put a copy of this solution on my website. You can right-click on the page to download the source code.

    File Example Demo

    Complete solution:

    <!DOCTYPE html>
    <html>
    <head>
    <link rel="stylesheet" href="https://pyscript.net/alpha/pyscript.css" />
    <script defer src="https://pyscript.net/alpha/pyscript.js"></script>
    <title>File Example</title>
    </head>
    <body>
    
    <p>This example shows how to read a file from the local file system and display its contents</p>
    <br />
    <p>Warning: Not every file type will display. PyScript removes content with tags such as XML, HTML, PHP, etc. Normal text files will work.</p>
    <br />
    <p>No content type checking is performed to detect images, executables, etc.</p>
    <br />
    <label for="myfile">Select a file:</label>
    <input type="file" id="myfile" name="myfile">
    <br />
    <br />
    <div id="print_output"></div>
    <br />
    <p>File Content:</p>
    <div style="border:2px inset #AAA;cursor:text;height:120px;overflow:auto;width:600px; resize:both">
      <div id="content">
      </div>
    </div>
    
    <py-script output="print_output">
    import asyncio
    from js import document, FileReader
    from pyodide import create_proxy
    
    async def process_file(event):
        fileList = event.target.files.to_py()
    
        for f in fileList:
            data = await f.text()
            document.getElementById("content").innerHTML = data
    
    def main():
        # Create a Python proxy for the callback function
        # process_file() is your function to process events from FileReader
        file_event = create_proxy(process_file)
    
        # Set the listener to the callback
        e = document.getElementById("myfile")
        e.addEventListener("change", file_event, False)
    
    main()
    </py-script>
    
    </body>
    </html>