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 510 forks source link

Importing a Brython module that is implemented in pure JavaScript #1568

Closed moepnse closed 1 year ago

moepnse commented 3 years ago

I hope you had a wonderful Christmas 🎄 🎅 🤶 🎁

I have the special case that I have a Brython module in pure JavaScript and want to import it using the import statement without making it accessible via a script tag beforehand.

Thanks in advance.

lovasb commented 3 years ago
Brython module in pure JavaScript

What does it mean? The Brython module is compiled to Javascript? Or it's developed originaly in Javascript?

moepnse commented 3 years ago

The module is developed in JavaScript and not compiled to JavaScript. To be precise, I forked an existing one.

I have adapted the _webcomponent module and want to use it so that I don't have to build the whole stdlib. I suspect that I can achieve this with the importlib.

PierreQuentel commented 3 years ago

@moepnse The standard way of adding a new importing process is to add a new loader to sys.meta_path. The loader loads the module at a specified location (here, with a blocking Ajax call), executes it (here, with Javascript's window.eval()) and import the module name in the importer namespace.

Do you think you can develop this loader ? Otherwise I will try, it's something that would be worth including in Brython, with a documentation.

moepnse commented 3 years ago

@PierreQuentel I'm already working on it.

PierreQuentel commented 3 years ago

@moepnse Cool !

moepnse commented 3 years ago

My first attempt using the importlib failed.

I then looked at py_import.js. Apparently only line 747 needs to be adjusted.

The exec_module method in line 811 can already distinguish between Python and JavaScript modules.

Seems to work: brython_js_modules

I'll look over it again tomorrow to be sure that it really works and write a test for it. Is there somewhere documented how to write tests for Brython?

PierreQuentel commented 3 years ago

I don't think it's a good idea to change the standard Brython import mechanism in py_import.js, because it would add the search for JS modules (hence an Ajax call) for all imports. At the moment, only the JS modules in the Brython stdlib, in folder libs, can be imported.

My idea was more to develop a specific loader, that would only be added to sys.meta_path for the (rare) case when a user-specific JS module, at a specific location, needs to be imported.

In issue #1182 I had provided an example of a loader written in Python, maybe you can start from this example for a Javascript module loader.

moepnse commented 3 years ago

I understand your concerns.

But maybe I can change your mind.

The importlib uses a list of possible source code file suffixes: https://docs.python.org/3/library/importlib.html#importlib.machinery.SOURCE_SUFFIXES

What do you think of adopting this concept and making it configurable as an option, like in the attached patch? If you do not agree with the patch, then I will implement it as a separate loader, based on the importlib, or your example loader, as suggested by you.

    <body onload="brython({debug: 1, 
        pythonpath: ['/py/', '/bry/'],
        source_suffixes: ['.py', '.js']});">

Apart from that, your sample loader should be part of the documentation or gallery.

moepnse commented 3 years ago

Writing a WebSocket or WAMP capable loader would be interesting.

kikocorreoso commented 3 years ago

@moepnse

I made this example: https://gist.github.com/kikocorreoso/3ac16c87777a91461900d19543b7c612

It is working here: https://gist.githack.com/kikocorreoso/3ac16c87777a91461900d19543b7c612/raw/b69007b10bb5c162f4b08e6de7d1547308f981dc/test.html

Would it be a correct approach for your use case??

NovaAndrom3da commented 2 years ago

Perhaps do something like: JS file:

function my_function(argument) {
  return "some value "+argument
}

Python File:

from browser import window
window.my_function("test")
PierreQuentel commented 2 years ago

In commit 8e8d0a59edd925acabda4a09fccda6deff2334fb I have added a function import_js(url, name) in module javascript that makes it possible to import a module written in Javascript. This module must define a name $module, used to build the module namespace, with the usual Javascript -> Python conversions.

If Javascript script at _jstest.js is

var $module = { x: 1 }

then a Python script can use it this way:

import javascript

javascript.import_js("js_test.js", "js_module") 
import js_module 
assert js_module.x == 1
PierreQuentel commented 1 year ago

Reviewing this old issue: I recently added a function import_modules in the javascript module to import Javascript modules that use the export keyword. It is described in the documentation.

Because such JS modules are loaded asynchronously, the use of Python import, which is blocking, is unfortunately not possible.

I close the issue but if you have other suggestions, just comment and I will reopen it.