Pyodide is a Python distribution for the browser that’s based on WebAssembly.
I’ve been meaning to try it for a while, so I gave it whirl when I wanted to create a simple site that given a JSON file with nested objects would flatten the data and output a CSV file.
The flattener that I made can be found here: https://flattener.netlify.app/.
And here’s the index.html that drives everything:
<!doctype html>
<html>
<head>
<script src="https://cdn.jsdelivr.net/pyodide/v0.22.1/full/pyodide.js"></script>
</head>
<body>
<div>
<h1>JSON Flattener</h1>
<div>
Provide a JSON file. The File will be processed, all in your browser,
into a CSV file that can be loaded.
<br />
<br />
Keys in the json file will be flattened with two underscores, "__", as
the separator.
<br />
<br />
For example:
<br />
JSON Input: [{"foo1": 3, "foo2": {"bar": "meow"}]
<br />
CSV Output Columns: "foo1" and "foo2__bar"
</div>
<div>
<br />
JSON file:
<button>Select file</button>
</div>
<br />
<br />
</div>
<script type="text/javascript">
async function main() {
// Get the file contents into JS
const [fileHandle] = await showOpenFilePicker();
const fileData = await fileHandle.getFile();
const contents = await fileData.text();
// Create the Python convert toy function
let pyodide = await loadPyodide();
await pyodide.loadPackage("pandas");
let process = pyodide.runPython(`
from pyodide.ffi import to_js
import json
import pandas as pd
def process(contents):
print(contents)
deserialized = json.loads(contents)
print(deserialized)
df = pd.json_normalize(deserialized, sep="__")
csv_str = df.to_csv(index=False)
return to_js(csv_str)
process
`);
let result = process(contents);
console.log(result);
const blob = new Blob([result], { type: "text/csv" });
let url = window.URL.createObjectURL(blob);
var downloadLink = document.createElement("a");
downloadLink.href = url;
downloadLink.text = "Download CSV";
downloadLink.download = "out.csv";
document.body.appendChild(downloadLink);
}
const button = document.querySelector("button");
button.addEventListener("click", main);
</script>
</body>
</html>