I need to:
- Enable the user to select a plain text file from the user's filesystem.
- Make it available to Pyodide.
- Read its contents line-by-line in Pyodide (in the Python code).
The code to read currently replaced by dummy code: inp_str = 'ACGTACGT'
. The actual use case involves complicated processing of the text file, but the minimal working example simply converts the input to lowercase.
<!doctype html>
<html>
<head>
<script src="https://cdn.jsdelivr.net/pyodide/v0.22.1/full/pyodide.js"></script>
</head>
<body>
Analyze input <br>
<script type="text/javascript">
async function main(){
let pyodide = await loadPyodide();
let txt = pyodide.runPython(`
# Need to replace the line below with code for the user to select
# the file from the user's filesystem and read
# its contents line-by-line:
inp_str = 'ACGTACGT'
out_str = inp_str.lower()
with open('/out.txt', 'w') as fh:
print(out_str, file=fh)
with open('/out.txt', 'rt') as fh:
out = fh.read()
out
`);
const blob = new Blob([txt], {type : 'application/text'});
let url = window.URL.createObjectURL(blob);
var downloadLink = document.createElement("a");
downloadLink.href = url;
downloadLink.text = "Download output";
downloadLink.download = "out.txt";
document.body.appendChild(downloadLink);
}
main();
</script>
</body>
</html>
We have external users that may not be advanced computer users. We can specify they need to use Google Chrome browser, but not specific releases like Chrome Canary. We cannot ask them to manually enable the File System API.
Based on the suggestion by TachyonicBytes, I tried the code below. Now I got the error below. I also cannot see something like select file button, or any obvious code for it:
Uncaught (in promise) DOMException: Failed to execute 'showDirectoryPicker' on 'Window': Must be handling a user gesture to show a file picker.
at main (file:///Users/foo/bar/upload_nativefs.html:10:35)
at file:///Users/foo/bar/upload_nativefs.html:26:7
This is line 10 referred to in the error message:
const dirHandle = await showDirectoryPicker();
And the full page is pasted below:
<!doctype html>
<html>
<head>
<script src="https://cdn.jsdelivr.net/pyodide/v0.22.1/full/pyodide.js"></script>
</head>
<body>
Analyze input <br>
<script type="text/javascript">
async function main(){
const dirHandle = await showDirectoryPicker();
if ((await dirHandle.queryPermission({ mode: "readwrite" })) !== "granted") {
if (
(await dirHandle.requestPermission({ mode: "readwrite" })) !== "granted"
) {
throw Error("Unable to read and write directory");
}
}
let pyodide = await loadPyodide();
const nativefs = await pyodide.mountNativeFS("/mount_dir", dirHandle);
pyodide.runPython(`
import os
print(os.listdir('/mount_dir'))
`);
}
main();
</script>
</body>
</html>