How to copy / download file created in Pyodide in browser? - python

I managed to run Pyodide in browser. I created hello.txt file. But how can I access it.
Pyodide https://github.com/iodide-project/pyodide/blob/master/docs/using_pyodide_from_javascript.md
pyodide.runPython('open("hello.txt", "w")')
What I tried in chrome devtools?
pyodide.runPython('os.chdir("../")')
pyodide.runPython('os.listdir()')
pyodide.runPython('os.path.realpath("hello.txt")')
Output for listdir
["hello.txt", "lib", "proc", "dev", "home", "tmp"]
Output for realpath
"/hello.txt"
Also,
pyodide.runPython('import platform')
pyodide.runPython('platform.platform()')
Output
"Emscripten-1.0-x86-JS-32bit"
All outputs in chrome devtools console.
It is created in root folder. But how it can be accessed in file explorer or anyway to copy file to Download folder?
Thanks

Indeed pyodide operates in an in-memory (MEMFS) filesystem created by Emscripten. You can't directly write files to disk from pyodide since it's executed in the browser sandbox.
You can however, pass your file to JavaScript, create a Blob out of it and then download it. For instance, using,
let txt = pyodide.runPython(`
with open('/test.txt', 'rt') as fh:
txt = fh.read()
txt
`);
const blob = new Blob([txt], {type : 'application/text'});
let url = window.URL.createObjectURL(blob);
window.location.assign(url);
It should have been also possible to do all of this from the Python side, using the type conversions included in pyodide, i.e.
from js import Blob, document
from js import window
with open('/test.txt', 'rt') as fh:
txt = fh.read()
blob = Blob.new([txt], {type : 'application/text'})
url = window.URL.createObjectURL(blob)
window.location.assign(url)
however at present, this unfortunately doesn't work, as it depends on pyodide#788 being resolved first.

I have modified the answer by rth. It will download file with the name of file.
let txt = pyodide.runPython(`
with open('/test.txt', 'rt') as fh:
txt = fh.read()
txt
`);
const blob = new Blob([txt], {type : 'application/text'});
let url = window.URL.createObjectURL(blob);
var downloadLink = document.createElement("a");
downloadLink.href = url;
downloadLink.download = "test.txt";
document.body.appendChild(downloadLink);
downloadLink.click();

Related

Downloading binary data generated by a pyscript script

I need to download a binary file that is created by a pyscript script.
Pressing the "Download" button should result in downloading a file containing the binary data generated by the pyscript. However the result is a plaintext .txt file , with a single line inside it:
<gzip _io.BufferedWriter name='file_test.dat' 0xdce348>
Here's the code I use to create the "Download" button (the code is inside an async python function that is
called after a "start the program" button is clicked)
f_in = open('datafile','rb') // the file is opened. The file itself is stored in /home/pyodide/
//the contents of the file are written into a gzip.GzipFile
f = open('file_test.dat','wb')
gz = gzip.GzipFile('', 'wb', 8, f, 0.)
for ln in f_in:
gz.write(ln)
print(ln) // printing the file contents line by line results in correct data, so Im fairly certain that
// the script itself generates data properly
//a blob object is created that is then attached to a new <a> tag
blob = Blob.new([gz], {type: "application/gzip"})
downloadDoc = document.createElement('a')
downloadDoc.href = window.URL.createObjectURL(blob)
//then the <a> tag is appended to a <div> inside the main html file, and a download button is created
downloadButton = document.createElement('button')
downloadButton.innerHTML = "Download"
downloadDoc.appendChild(downloadButton)
document.getElementById("download-div").appendChild(downloadDoc)
I'm fairly new to web development (in fact this is my first web project), so there may be some obvious
thing I'm missing.
Thanks in advance!
UPDATE - SOLUTION
Closing all the files and passing the 'file_test.dat' file
to the pyodide.to_js() function before creating a Blob solves the problem. Here's the complete working code:
f_in = open('datafile','rb')
f = open('file_test.dat','wb')
gz = gzip.GzipFile('', 'wb', 8, f, 0.)
for ln in f_in:
gz.write(ln)
gz.close()
f_in.close()
f.close()
//reopening the file and then passing it into pyodide.to_js() function solved the issue
f2 = open('file_test.dat',"rb")
content = to_js(f2.read())
blob = Blob.new([content], {type: ""})
downloadDoc = document.createElement('a')
downloadDoc.href = window.URL.createObjectURL(blob)
downloadButton = document.createElement('button')
downloadButton.innerHTML = "Download"
downloadDoc.appendChild(downloadButton)
document.getElementById("download-div").appendChild(downloadDoc)

file upload from container using webdav results into empty file upload

I'm attempting to wrap my brain around this because the identical code generates two different sets of outcomes, implying that there must be a fundamental difference between the settings in which the code is performed.
This is the code I use:
from webdav3.client import Client
if __name__ == "__main__":
client = Client(
{
"webdav_hostname": "http://some_address"
+ "project"
+ "/",
"webdav_login": "somelogin",
"webdav_password": "somepass",
}
)
ci = "someci"
version = "someversion"
directory = f'release-{ci.replace("/", "-")}-{version}'
client.webdav.disable_check = (
True # Need to be disabled as the check can not be performed on the root
)
f = "a.rst"
with open(f, "r") as fh:
contents = fh.read()
print(contents)
evaluated = contents.replace("#PIPELINE_URL#", "DUMMY PIPELINE URL")
with open(f, "w") as fh:
fh.write(evaluated)
print(contents)
client.upload(local_path=f, remote_path=f)
The file a.rst contains some text like:
Please follow instruction link below
#####################################
`Click here for instructions <https://some_website>`_
When I execute this code from macOS, a file with the same contents of a.rst appears on my website.
When I execute this script from within a container with a base image of Python 3.9 and the webdav dependencies, it creates a file on my website, but the content is always empty. I'm not sure why, but it could have something to do with the fact that I'm running it from within a Docker container that on top of it can't handle the special characters in the file (plain text seems to work though)?
Anyone have any ideas as to why this is happening and how to fix it?
EDIT:
It seems that the character ":" is creating the problem..

Download a file without name using Python

I want to download a file, there is a hyper link in html page which does not include the file name and extension. How can I download the file using python?
For example the link is http://1.1.1.1:8080/tank-20/a/at_download/file,
but whenever I click on it the file will download and open with browser.
Use python requests to get the body of the response and write to file, this is essentially what the browser is doing when you click the link.
Try the below:
import requests
# define variables
request_url = "http://1.1.1.1:8080/tank-20/a/at_download/file"
output_file = "output.txt"
# send get request
response = requests.get(request_url)
# use 'with' to write to file
with open(output_file, 'w') as fh:
fh.write(response.content)
fh.close()

creating and using a preferences file in python

Brand new to stack and python; hopefully someone wiser than myself can help. I have searched up and down and can't seem to find an actual answer to this, apologies if there is an exact answer and I've missed it :( (the few that I've found are either old or don't seem to work).
Closest I've found is
Best way to retrieve variable values from a text file?
Alas, imp seems to be depreciated and tried figuring out importlib but little above my current brain to figure out how to adapt it as errors throw up left and right on me.
This is very close to what I want and could potentially work if someone can help update with new methods, alas still doesn't have how to overwrite the old variable.
= - - Scenario - - =
I would like to create a preferences file (let's call it settings.txt or settings.py: doesn't need to be cross-compatible with other languages, but some reason I'd prefer txt - any preference/standards coders can impart would be appreciated?).
\\\ settings.txt\
water_type = "Fresh"\
measurement = "Metric"\
colour = "Blue"\
location = "Bottom"\
...
I am creating a script main_menu.py which will read variables in settings.txt and write to this file if changes are 'saved'
ie.
"select water type:"
Fresh
Salt
if water_type is the same as settings.txt, do nothing,
if water_type different, overwrite the variable in the settings.txt file
Other scripts down the line will also read and write to this settings file.
I've seen:
from settings import *
Which seems to work for reading the file if I go the settings.py path but still leaves me on how do I overwrite this.
also open to any better/standard/ideas you guys can think of.
Appreciate any help on this!
Here are some suggestions that may help you:
Use a json file:
settings.json
{
"water_type": "Fresh",
"measurement": "Metric",
"colour": "Blue",
"location": "Bottom",
...
}
then in python:
import json
# Load data from the json file
with open("settings.json", "r") as f:
x = json.load(f) # x is a python dictionary in this case
# Change water_type in x
x["water_type"] = "Salt"
# Save changes
with open("settings.json", "w") as f:
json.dump(x, f, indent=4)
Use a yaml file: (edit: you will need to install pyyaml)
settings.yaml
water_type: Fresh
measurement: Metric
colour: Blue
location: Bottom
...
then in python:
import yaml
# Load data from the yaml file
with open("settings.yaml", "r") as f:
x = yaml.load(f, Loader=yaml.FullLoader) # x is a python dictionary in this case
# Change water_type in x
x["water_type"] = "Salt"
# Save changes
with open("settings.yaml", "w") as f:
yaml.dump(x, f)
Use a INI file:
settings.ini
[Preferences]
water_type=Fresh
measurement=Metric
colour=Blue
location=Bottom
...
then in python:
import configparser
# Load data from the ini file
config = configparser.ConfigParser()
config.read('settings.ini')
# Change water_type in config
config["Preferences"]["water_type"] = "Salt"
# Save changes
with open("settings.ini", "w") as f:
config.write(f)
For .py config files, it's usually static options or settings.
Ex.
# config.py
STRINGTOWRITE01 = "Hello, "
STRINGTOWRITE02 = "World!"
LINEENDING = "\n"
It would be hard to save changes made to the settings in such a format.
I'd recommend a JSON file.
Ex. settings.json
{
"MainSettings": {
"StringToWrite": "Hello, World!"
}
}
To read the settings from this file into a Python Dictionary, you can use this bit of code.
import json # Import pythons JSON library
JSON_FILE = open('settings.json','r').read() # Open the file with read permissions, then read it.
JSON_DATA = json.loads(JSON_FILE) # load the raw text from the file into a json object or dictionary
print(JSON_DATA["MainSettings"]["StringToWrite"]) # Access the 'StringToWrite' variable, just as you would with a dictionary.
To write to the settings.json file you can use this bit of code
import json # import pythons json lib
JSON_FILE = open('settings.json','r').read() # Open the file with read permissions, then read it.
JSON_DATA = json.loads(JSON_FILE) # load the data into a json object or dictionary
print(JSON_DATA["MainSettings"]["StringToWrite"]) # Print out the StringToWrite "variable"
JSON_DATA["MainSettings"]["StringToWrite"] = "Goodnight!" # Change the StringToWrite
JSON_DUMP = json.dumps(JSON_DATA) # Turn the json object or dictionary back into a regular string
JSON_FILE = open('settings.json','w') # Reopen the file, this time with read and write permissions
JSON_FILE.write(JSON_DUMP) # Update our settings file, by overwriting our previous settings
Now, I've written this so that it is as easy as possible to understand what's going on. There are better ways to do this with Python Functions.
You guys are fast! I'm away from the computer for the weekend but had to log in just to say thanks.
I'll look into these more next week when I'm back at it and have some time to give it the attention needed. A quick glance could be a bit of fun to implement and learn a bit more.
Had to answer as adding comment only is on one of your guys solutions and wanted to give a blanket thanks to all!
Cheers
Here's a python library if you choose to do it this way.
If not this is also a good resource.
Creating a preferences file example
Writing preferences to file from python file
import json
# Data to be written
dictionary ={
"name" : "sathiyajith",
"rollno" : 56,
"cgpa" : 8.6,
"phonenumber" : "9976770500"
}
# Serializing json
json_object = json.dumps(dictionary, indent = 4)
# Writing to sample.json
with open("sample.json", "w") as outfile:
outfile.write(json_object)
Reading preferences from .json file in Python
import json
# open and read file content
with open('sample.json') as json_file:
data = json.load(json_file)
# print json file
print(data)

Reading and returning jpg file in Python, ASP.NET?

I have an image.asp file, using Python, in which I am attempting to open a JPEG image and write it to the response so that it can be retrieved from the relevant link. What I have currently:
<%# LANGUAGE = Python%>
<%
path = "path/to/image.jpg"
with open(path, 'rb') as f:
jpg = f.read()
Response.ContentType = "image/jpeg"
Response.WriteBinary(jpg)
%>
In a browser, this returns the following error:
The image "url/to/image.asp" cannot be displayed because it contains errors.
I suspect the issue is that I am just not writing contents of the jpg file correctly. What do I need to fix?
Your issue is here:
with open(url, 'rb') as f:
Your variable, that contains path is named path, not url.
Make it as:
with open(path, 'rb') as f:
and it will work better.

Categories

Resources