brython-dev / brython

Brython (Browser Python) is an implementation of Python 3 running in the browser
BSD 3-Clause "New" or "Revised" License
6.39k stars 511 forks source link

Problems trying to use either f.write() or json.dump() to save data to a local file... #1250

Closed vonschappler closed 4 years ago

vonschappler commented 4 years ago

I am trying to save some data into a local file "which has to be ACCESSED" on the fly in a code to update a DataTable that reads the info inside the file.

The code I am using is the listed below (this is just for writing to file test purpose):

async def saveFile(f, data):
    with codecs.open(f, mode="w+") as output:
        print("f is: " + str(type(f)))
        print("output is: " + str(type(output)))
        console.log("Info: ", "File opened for saving...")
        json.dump(data, output, ensure_ascii=False, indent=2, sort_keys=True)
        console.log("Success:", "File saved!")

But I get this error message from debug level 2 - set as <body style="max-height: viewport" onload="brython(2)"> on the index.html page:

Traceback (most recent call last):
__main__ line 61
  aio.run(readFile())
__main__ line 61
  aio.run(readFile())
__main__ line 79
  json.dump(data, output, ensure_ascii=False, indent=2, sort_keys=True)
AttributeError: '_io.TextIOWrapper' object has no attribute 'write'

On the other hand, IF I change my code to:

async def saveFile(f, data):
    with codecs.open(f, mode="w+") as output:
        print("f is: " + str(type(f)))
        print("output is: " + str(type(output)))
        console.log("Info: ", "File opened for saving...")
        #json.dump(data, output, ensure_ascii=False, indent=2, sort_keys=True)
        txt = json.dumps(data, ensure_ascii=False, indent=2, sort_keys=True)
        console.log(txt)
        console.log("Success:", "File saved!")

This is what my log prints:

Info:  File opened for saving...
{
  data_ as_string
}
Success: File saved!

Could someone either tell me what I am doing wrong or could the dev implement this feature please? Or if that's not the case, could someone guide me on how to make my own version of the write() or json.dump() ?

NOTE: the only reason I am using this tool is to generate this file without the need of a framework as node.js or any database / php code because that file will be read also by a chatbot app - so creating it "online" and forcing a download from a database with php is a NO-GO.

PierreQuentel commented 4 years ago

For security reasons, browsers don't have write access to the file system, at least not without an explicit consent of the user.

But it is possible to ask the user if he want to save content in a local file. Unfortunately the API is not very simple (it uses Data URLs), but you can test the example below:

<!doctype html>
<html>

<head>
<meta charset="utf-8">
<script type="text/javascript" src="/src/brython.js"></script>
<script type="text/javascript" src="/src/brython_stdlib.js"></script>
</head>

<body onLoad="brython(1)">

<script type="text/python">
import json
import base64

from browser import document, html

data = {"a": [1, 2]}

content = json.dumps(data)
b64 = base64.b64encode(content.encode("utf-8")).decode("utf-8")

document <= html.A("Export to local file",
                href="data:text/plain;charset=utf-8;base64," + b64,
                download="test.json")

</script>
</body>
</html>
vonschappler commented 4 years ago

Well, ty for the answer, but "asking" for a download via a tag it out of the purpose of the app I'm trying to code because the file needs to be autosaved in order for the chatbot script to work...

Also, if we take a look at FileAPI, this seems to allow the save the way I want/need... I am just having issues to implement it, and so it was why I tried Bryton, because the way to write files with python is FAR was simple than try to understand the whole API.

Also, to be honest, IF the hosting service I use would allow using any framework as noje.js* - I would be using node because noje.js ALSO allows local recording directly from the browser...

I think that I/we really just need a way to make Bryton work with this FileAPI from MDN...

PierreQuentel commented 4 years ago

node.js is Javascript executed on the server side, not the client side (the browser). And, as the documentation explains, the FileAPI is done for files that are selected by the user from the file explorer, ie with an explicit user permission.

Allowing a client-side program to read from or write on disk without asking permission would be a massive security and privacy issue.