CSV to Markdown with the browser Python framework, PyScript.

PyScript has popped up on the scene recently. It looks like a lot of fun to play with and i’m excited to see where it goes in the future. I decided to throw together a quick toy CSV to Markdown converter app, just to get a feel for it at this early stage.

The Tech

PyScript is a framework powered by Pyodide and WebAssembly (WASM) that brings the rich Python language and community to HTML. Not as a server-side scripting language but fully integrated into your client-side HTML. At the time of writing, PyScript is in early development. The PyScript website describes it as “very alpha” and they do not recommend using it for production.

If you’re up-to-date with web technologies you will have heard of WASM. But what’s Pyodide? Pyodide is a port of CPython to WASM/Emscripten. It’s intended to be a Python distribution for the browser and Node.js.

Setup

For a quick start, just throw the js and css into any HTML page and you can start scripting inside the <py-script> tags:

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

    </head>
    <body>
        <body> <py-script> print('PyScript FTW') </py-script> </body>
    </body>
</html>

CSV to MD

Now I could start writing my own csv parser and transformer but that wouldn’t be in the spirit of Python. Much like JavaScript, there’s such a feature rich community of packages. And PyScript can take full advantage. We’ll be using pandas and it also requires tabulate. Tabulate doesn’t seem to be in the Pyodide library of default packages but it was painless to retrieve the whl file and add it to the project.

So we include these dependencies into the <py-env> tag in the document <head>:

<head>
    <link rel="stylesheet" href="https://pyscript.net/alpha/pyscript.css" />
    <script defer src="https://pyscript.net/alpha/pyscript.js"></script>
    <py-env>
        - pandas
        - '/tabulate-0.8.9-py3-none-any.whl'
    </py-env>
</head>

We’re able to take full advantage of HTML, so lets draft up a quick form so the user can choose the delimiter, paste the CSV input and view the output after processing:

<label> Delimiter:
    <select id="delimiter-in">
        <option value=',' selected>Comma</option>
        <option value='\t'>Tab</option>
    </select>
</label>
<label> Input:
    <textarea id="csv-in"></textarea>
</label>
<button id="new-task-btn" 
    class="p-2 text-white bg-green-600 border border-green-600 rounded"
    type="submit"
>
    Convert!
</button>

<output>
    <pre id="md-out">
    </pre>
</output>

Then we can draft up our simple script. We’re able to get data from the page as we normally would in JavaScript, document.getElementById, and PyScript provides an API to write out into elements too, pyscript.write().

<py-script>
    import html
    import pandas as pd
    from io import StringIO

    def get_text():
        textarea = document.getElementById("csv-in")
        text = textarea.value
        return text

    def get_delimiter():
        select = document.getElementById("delimiter-in")
        delimiter = select.value
        return delimiter

    def convert_handler(event):
        text = get_text()
        delimiter = get_delimiter();
        df = pd.read_csv(StringIO(text),sep=delimiter,header=(0))
        pyscript.write('md-out',  html.escape(df.to_markdown()))
</py-script>

The last thing to do is connect the script to the onClick event with a PyScript attribute for our button:

<button id="new-task-btn" 
    class="p-2 text-white bg-green-600 border border-green-600 rounded"
    type="submit"
    pys-onClick="convert_handler"
>
    Convert!
</button>

The demo is live here. Now remember, i’m not doing any processing or visualisation of the data here. There’s scope to use all the capabilities of panda and numpy and the host of other libraries. Amazing. It’s well worth checking out some the examples PyScript showcase.

Final Thoughts

Even in early development you can see the potential to mock up expressive interfaces for Python scripts. For offline applications the chance to work with HTML + CSS will fill many developers hearts with glee.

As you may imagine, there are some snags. For instance, the payload required for hosted applications is massive. I’m seeing around 30 MB on the network graph when I load the page. That should make most web developers think twice. That said, it’s on Pyodide’s radar.

We shouldn’t view this as a replacement for JavaScript. But it’s early days and there’s an opportunity for innovation that can’t be ignored.