Upload csv for processing in PyScript - javascript

The following is my failed attempt at writing HTML/Javascript/PyScript code that allows a user to upload a csv (or excel) file, which is then available for use in PyScript (e.g., Pandas). As you might notice, I am not very experienced with Javascript.
<html>
<head>
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
<py-config>
packages = ["pandas"]
</py-config>
</head>
<body>
<input type="file" id="fileinput" accept=".csv, .xlsx"/>
<script>
var test = "test";
function assignFile(e) {
// Assign file to js variable
window.file = e.target.files[0];
console.log("File assigned")
}
</script>
<py-script>
import pandas as pd
import js
import pyodide
from js import test
js.console.log(test)
def get_file(e):
js.console.log("Attempting file upload: " + e.target.value)
# Assign file to a js variable
js.assignFile(e)
# Import variable to python
from js import file
display(pd.read_csv(file))
get_file_proxy = pyodide.ffi.create_proxy(get_file)
js.document.getElementById("fileinput").addEventListener("change", get_file_proxy)
</py-script>
</body>
</html>
Some notes to this code: I am aware that the part written in the script element could also be written in the py-script element, but decided not to. Furthermore, the line from js import file imports the variable created in Javascript, but when I try to use this variable with Pandas, it gives me the error in the console Invalid file path or buffer object type: <class 'pyodide.JsProxy'>. This is contrary to the properly functioning line from js import test. However, the specific error is unimportant to my question, which is:
What would be a simple way to allow a user to upload a csv (or xlsx) file for use in PyScript?

First, you need to use the event.target.files attribute of the FileEvent. This can be read using the common async JavaScript methods, like .text() or .arrayBuffer(). To read a CSV file from text with pandas you need to use an in-memory stream, like io.StringIO or io.BytesIO.
I adapted your PyScript code like this:
import pandas as pd
import pyodide
import io
import js
async def get_file(e):
files = e.target.files.to_py()
for file in files:
file_content = await file.text()
df = pd.read_csv(io.StringIO(file_content))
js.console.log(df)
get_file_proxy = pyodide.ffi.create_proxy(get_file)
js.document.getElementById("fileinput").addEventListener("change", get_file_proxy)
Keep in mind, that large files might be better read using a buffer, but I do not exactly know best practices for this in PyScript.

Related

How to import octokit in browser

tried to follow an example from this. To import octokit I first pasted the following lines into my html document as stated by adding the following lines:
<script type="module">
import { Octokit } from "https://cdn.skypack.dev/#octokit/core";
</script>
This just resulted in an Uncaught (in promise) ReferenceError: Octokit is not defined. Moving the line in script tags directly into the script.js file above the code just made one of the main functions appear as undefined (it handled a button click that authenticated a google account and then retrieved data from google sheets via the sheets API).
I then tried all this with new html and js files, adding that code directly to the html had the same result but this time adding it to the start of the js file gives a import declarations may only appear at top level of a module script.js:1
Don't really know what to do from here so any help would be appreciated. Did find this though but it just says the issue is fixed?
I think the best solution is to write your script logic in a separate javascript file, and then import that file in your html at the end of body element.
Here is an example of getting your repositories from GitHub:
repos.js
import { Octokit } from "https://cdn.skypack.dev/octokit";
import { config } from "./config.js";
const GIT_KEY = config.API_KEY;
export const octokit = new Octokit({
auth: GIT_KEY,
});
const repo = await octokit.request(
"GET /users/{username}/repos{?type,sort,direction,per_page,page}",
{
username: "your_username",
}
);
console.log(repo);
repos.html:
<body>
...
<script type="module" src="repos.js"></script>
</body>

require in Sapper preload function

I am trying to parse some markdown before a page loads, so I have the following code:
<script context="module">
var markdown = require( "markdown" ).markdown;
export async function preload(page, session) {
var someMakrdown = '# Title'
var html = markdown.toHTML(someMakrdown)
return {post : html}
}
</script>
This fails with a 500 and the message: require is not defined
I have also tried using import in the following way:
<script context="module">
import {markdown} from 'markdown';
export async function preload(page, session) {
var someMakrdown = '# Title'
var html = markdown.toHTML(someMakrdown)
return {post : html}
}
</script>
This also fails with a 500 and the message Error resolving module specifier: util
I have got this to work by moving the code into a [slug].json.js file and calling that from within the preload, but is there a better way to do this?
One of the things that I've enjoyed so far about Svelte is keeping the HTML, CSS and JS together for each component. It just doesn't feel right that I need to call a seperate JS file to create JSON that can then be used.
It appears that the markdown module imports util, making it unsuitable for client-side use. Since preload functions run both server-side and client-side, that's no good. My suggestion would be to use a different library instead (I can recommend marked) and/or raise an issue on the markdown bug tracker.
Just in case someone needs a complete answer, here's how it looks like using marked, as proposed by Rich.
<script context="module">
import marked from 'marked';
let elem = '';
export function preload({ params, query }) {
elem = marked('# Marked in the server or/and browser');
}
</script>
<div>{#html elem}</div>
It'll run in the server and then, for subsequent navigation, in the browser.

Is there a way to force after effects to import custom File Types through a .jsx Script?

Let's say i gave a custom file type for my AE project:
I changed it from character.aep to character.czip
i can easily import this file through AE's GUI ( File -> Import -> All Files Type -> character.czip )
I'd like to write a script that does the same, so i wrote:
var main_path = (String(new File($.fileName).parent));
var io = new ImportOptions(File (main_path+"/character.czip"));
var myFootage = app.project.importFile(io);
But this script keeps preventing me from importing the file, it gives the error:
After Effects error: FIle "character.czip" is not a valid file type for import.
Is there a way to bypass the file format check, as we do on ae's GUI?
Or at least, force the after effects to interpret the .czip file as .aep?

How do I get a global function recognized by my JS file loaded through AJAX?

I'm confused about scopes in Javascript and how to get a global function recognized. On my page I have
<script src="base64.js"></script>
defined. Then in another file, I have
var xhr = new XMLHttpRequest;
...
var full = location.protocol+'//'+location.hostname+(location.port ? ':'+location.port: '');
alert(Base64.decode("abc"));
xhr.open("get", full + "myotherfile.js", true);
xhr.send()
The alert executes without a problem. However in the "mytoherfile.js" references to the Base64 class result in a RerefernceError. So at the top of my myotherfile.js I tried
import {Base64} from 'base64';
but this results in a "Uncaught SyntaxError: Unexpected token {" error. What's the right way to include get my global function recognized in a JS file loaded through AJAX?
Edit: The remote loaded JS file is loaded using
this.worker = new Worker(xhrResponseText);
Scripts loaded in the main page are not available in web workers, you have to import them with importScripts not the import command
importScripts("base64.js");
In old-fashioned (non-module) javascript files, global variables are implied to be made on window. So in the first example, Base64.decode("abc") is the same as window.Base64.decode("abc"). In modules, however, this is not true. If you want to access a global variable on the window, it must be done explicitly.
In the module, try changing the reference to Base64 to window.Base64.
Sidenote: If the base64.js file works with a basic script tag import, then it will not work to import it as an es6 module like you have done (import {Base64} from 'base64';). You can read up more on how to import modules here!
Hope that helps!
Update
For clarity, here are a couple examples. Basically, what ever you put in the curly braces ({ Base64}) must be exported from the script being imported, not placed on the window.
<script src=".../base64.js"></script>
<script>
// both are accessible this way because this is NOT a module
// and global variables are assumed to be on the window.
console.log(Base64);
console.log(window.Base64);
</script>
<script type="module">
// Will not work:
// import { Base64 } from ".../base64.js
// import { window.Base64 } from ".../base64.js
// The same as importing view the script tag
// (not needed because the script tag already imported it)
// import ".../base64.js"
// the "global variable" is accessible on the window
console.log(window.Base64)
</script>
The issue is with the path you are referring to. Here are valid paths in type module.
// Supported:
import {foo} from 'https://jakearchibald.com/utils/bar.js';
import {foo} from '/utils/bar.js';
import {foo} from './bar.js';
import {foo} from '../bar.js';
// Not supported:
import {foo} from 'bar.js';
import {foo} from 'utils/bar.js';
Try referring to the path directly. something like this
import {addTextToBody} from '../../someFolder/someOtherfolder/utils.js';
here are valid pathName
Starts with ./ :- same folder
Starts with ../ :- Parent folder
Starts with ../../ :- above parentfolder

Calling XQuery using javascript

I want to call a XQuery function with JavaScript to retrieve data from a XML file. I'm able to call this simple function which doesn't read anything from any file:
<script type="text/javascript"
src="mxqueryjs/mxqueryjs.nocache.js"
></script>
<script type="application/xquery">
module namespace m = "http://www.xqib.org/module";
declare function m:GetNearestLocations($node as node()+) {
let $message := "Hello XQuery!"
return $message
};
</script>
With this JavaScript:
var output = xqib.call(
'http://www.xqib.org/module',
'GetNearestLocations',
center.lat());
The return output is as expected "Hello XQuery!".
Now I want to import a math module so that I can use some of its functions while reading data from a XML file.
Here's what I have but the math module doesn't import and causes XQST0059 error saying that there's no information location to load module with namespace "http://www.w3.org/2005/xpath-functions/math":
<script type="text/javascript"
src="mxqueryjs/mxqueryjs.nocache.js"
></script>
<script type="application/xquery">
module namespace m = "http://www.xqib.org/module";
import module namespace math
= "http://www.w3.org/2005/xpath-functions/math";
declare function m:GetNearestLocations($node as node()+) {
let $message := "Hello XQuery!"
return $message
};
</script>
What's is weird about this is that when I use Stylus Studio X15 Entreprise Suite to test the same function the import is working.
Important: I'm using the same JavaScript call when I import or not the Math module, so maybe my problem comes from there but, I don't know how I could fix this.
If you could also guide me a little on what could I set as parameter to m:GetNearestLocations so that I can pass it Integers or Strings
Thanks a lot.
Now I want to import a math module so that I can use some of its functions while reading data from a XML file.
That sounds reasonable. So your first task will be to find an implementation of the math module for namespace http://www.w3.org/2005/xpath-functions/math that XQiB / MXQuery can process, install it on your server, and point to it from the module import statement, as shown in the module import example on the XQiB web site.
Or alternatively, you may decide that you can work with the math functions in http://www.zorba-xquery.com/zorba/math-functions, which MXQuery (and thus XQiB) appear to support natively. (I see this in the MXQuery documentation but not in the XQiB documentation, so I guess there is the theoretical possibility that XQiB is using an older version of MXQuery -- but it's more likely that the development team just has better things to do with their time than document modules already documented elsewhere.)

Categories

Resources