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

[Question] Cannot figure out how to inherit from Javascript object in Python code #1418

Closed redradist closed 4 years ago

redradist commented 4 years ago

Hi, I try to make adaptation for React for Brython, but I have faced with the issues ...

During rendering React search all attributes for object and cannot find appropriate props attribute, because this attribute is available on instance window.React.Component.new() ...

Test html:

<!doctype html>
<html>
    <head>
        <meta charset="utf-8">
        <script src="brython.js"></script>
        <script src="brython_modules.js"></script>
        <script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script>
        <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script>
    </head>

    <body onload="brython(1)">
        <script type="text/python" src="lib.py" precompiled></script>
        <div id="root"></div>
    </body>
</html>

I try to inherit from JS object something like this:

class MyComponent(window.React.Component):
    def __init__(self):
        super().__init__()

    def render(self):
        return window.React.createElement("button", {'onClick': on_click}, "Like")

I get an error:

Javascript error TypeError: Cannot read property '__name__' of undefined
    at Object.type.mro (brython.js:5815)
    at Object.$B.$class_constructor (brython.js:5639)
    at eval (eval at $B.loop (brython.js:5368), <anonymous>:196:43)
    at $B.loop (brython.js:5368)
    at $B.inImported (brython.js:5352)
    at Object.$B.loop (brython.js:5376)
    at $B.run_script (brython.js:5183)
    at $B.loop (brython.js:5376)
    at XMLHttpRequest.req.onreadystatechange (brython.js:5341)
brython.js:7908 test is js exc is recursion error TypeError: Cannot read property '__name__' of undefined
    at Object.type.mro (brython.js:5815)
    at Object.$B.$class_constructor (brython.js:5639)
    at eval (eval at $B.loop (brython.js:5368), <anonymous>:196:43)
    at $B.loop (brython.js:5368)
    at $B.inImported (brython.js:5352)
    at Object.$B.loop (brython.js:5376)
    at $B.run_script (brython.js:5183)
    at $B.loop (brython.js:5376)
    at XMLHttpRequest.req.onreadystatechange (brython.js:5341) TypeError: Cannot read property '__name__' of undefined

In current Brython it is line https://github.com/brython-dev/brython/blob/master/www/src/brython.js#L5748

Is there a proper way to inherit from JS object ?

I guess there is missed check if user tries to inherit from JS object by checking if __prototype__ property is available and if this property is available then inheritance should be done something like this:

...
    // Builds a basic class object
    var A;

    if (is_py_class(base)) {
        A = {
            __class__: _b_.type,
            __mro__: [base.__mro__, object],
            __name__: name,
            $is_class: true
        }
    } else {
        A = {
            __class__: _b_.type,
            __mro__: [base.prototype, object],
            __name__: name,
            $is_class: true
        }
    }

    A.$factory = factory

    return A
...

I have show example in pseudo code, but anyway idea should be clear, if base object is not class than instead of using its __mro__ in class hierarchy use __prototype__ property

It allows to implement wrappers for JavaScript libraries much easier !! ;)

redradist commented 4 years ago

@PierreQuentel I have found the issue in sources:

https://github.com/brython-dev/brython/blob/9ae0cd8d58cb4085e83fc571759644ffc86433ea/www/src/py_type.js#L677

But it is very strange because it seems like inheriting from JS is handling

redradist commented 4 years ago

@PierreQuentel Thanks !!