Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

When extending JS classes, the super class' constructor isn't called + an exception is raised when calling super() in the subclass #2393

Open
denis-migdal opened this issue Mar 10, 2024 · 4 comments

Comments

@denis-migdal
Copy link
Contributor

denis-migdal commented Mar 10, 2024

It seems Brython doesn't call the constructor of the super class when inheriting a JS class.

The JS class:

function BLISS() {
    return class {
        constructor() {
            console.log("called");
        }

        foo() {
            console.log("foo");
        }

        faa = 43;

        set fii(a: number) {
            console.log("fii");
        }

        get fuu() {
            console.log("fuu");
            return 43;
        }
    }
}

The Brython class:

import BLISS

class X( BLISS() ):
    def __init__(self):
        print(self)
        print("?", dir(self) )
        print( self.foo() )
        print( self.faa )
        self.fii(43)
        print( self.fuu )

It prints:

<Javascript object: [object Object]>
? []
foo
<Javascript undefined> # should be 43

Uncaught (in promise) TypeError: $B.frame_obj is null
    set_exception_offsets http://127.0.0.1:5500/brython/www/src/brython.js:4075
    call http://127.0.0.1:5500/brython/www/src/brython.js:1604
    PyClass http://127.0.0.1:5500/index.js:36
    init http://127.0.0.1:5500/LISS/index.js:243
    connectedCallback http://127.0.0.1:5500/LISS/index.js:194
    define http://127.0.0.1:5500/LISS/index.js:332
    test http://127.0.0.1:5500/index.js:40
    res http://127.0.0.1:5500/brython/www/src/brython.js:9555
    call http://127.0.0.1:5500/brython/www/src/brython.js:1603
    anonymous http://127.0.0.1:5500/brython/www/src/brython.js line 1117 > Function:89
    loop http://127.0.0.1:5500/brython/www/src/brython.js:1117
    run_script http://127.0.0.1:5500/brython/www/src/brython.js:963
    loop http://127.0.0.1:5500/brython/www/src/brython.js:1133
    onreadystatechange http://127.0.0.1:5500/brython/www/src/brython.js:1086
    ajax_load_script http://127.0.0.1:5500/brython/www/src/brython.js:1082
    loop http://127.0.0.1:5500/brython/www/src/brython.js:1133
    run_scripts http://127.0.0.1:5500/brython/www/src/brython.js:945
    brython http://127.0.0.1:5500/brython/www/src/brython.js:891
    onload http://127.0.0.1:5500/brython/www/src/brython.js:842
    EventHandlerNonNull* http://127.0.0.1:5500/brython/www/src/brython.js:842
    EventListener.handleEvent* http://127.0.0.1:5500/brython/www/src/brython.js:840
    <anonymous> http://127.0.0.1:5500/brython/www/src/brython.js:964
@denis-migdal
Copy link
Contributor Author

denis-migdal commented Mar 10, 2024

Hum, it seems calling super() in the subclass raises an error.

I'll have to check more in depth the error as I currently have TypeError: $B.frame_obj is null.

@denis-migdal
Copy link
Contributor Author

It seems when calling super(), the error is here :

Uncaught (in promise) Error: 
    exc_class http://127.0.0.1:5500/brython/www/src/brython.js:4220
    super http://127.0.0.1:5500/brython/www/src/brython.js:3448
    call http://127.0.0.1:5500/brython/www/src/brython.js:1603
    __init__4 http://127.0.0.1:5500/brython/www/src/brython.js line 1117 > Function:54
    anonymous http://127.0.0.1:5500/brython/www/src/brython.js line 9866 > Function:11
    instance_creator http://127.0.0.1:5500/brython/www/src/brython.js:2445
    call http://127.0.0.1:5500/brython/www/src/brython.js:1603
    PyClass http://127.0.0.1:5500/index.js:48
    init http://127.0.0.1:5500/LISS/index.js:243
    connectedCallback http://127.0.0.1:5500/LISS/index.js:194
    define http://127.0.0.1:5500/LISS/index.js:332
    test http://127.0.0.1:5500/index.js:52
    res http://127.0.0.1:5500/brython/www/src/brython.js:9555
    call http://127.0.0.1:5500/brython/www/src/brython.js:1603
    anonymous http://127.0.0.1:5500/brython/www/src/brython.js line 1117 > Function:83
    loop http://127.0.0.1:5500/brython/www/src/brython.js:1117
    run_script http://127.0.0.1:5500/brython/www/src/brython.js:963
    loop http://127.0.0.1:5500/brython/www/src/brython.js:1133
    onreadystatechange http://127.0.0.1:5500/brython/www/src/brython.js:1086
    ajax_load_script http://127.0.0.1:5500/brython/www/src/brython.js:1082
    loop http://127.0.0.1:5500/brython/www/src/brython.js:1133
    run_scripts http://127.0.0.1:5500/brython/www/src/brython.js:945
    brython http://127.0.0.1:5500/brython/www/src/brython.js:891
    onload http://127.0.0.1:5500/brython/www/src/brython.js:842
    EventHandlerNonNull* http://127.0.0.1:5500/brython/www/src/brython.js:842
    EventListener.handleEvent* http://127.0.0.1:5500/brython/www/src/brython.js:840
    <anonymous> http://127.0.0.1:5500/brython/www/src/brython.js:964
brython.js:4220:57
    init http://127.0.0.1:5500/LISS/index.js:253
    connectedCallback http://127.0.0.1:5500/LISS/index.js:194
    define http://127.0.0.1:5500/LISS/index.js:332
    InterpretGeneratorResume self-hosted:1465
    AsyncFunctionNext self-hosted:852
    (Asynchrone : async)
    test http://127.0.0.1:5500/index.js:52
    res http://127.0.0.1:5500/brython/www/src/brython.js:9555
    call http://127.0.0.1:5500/brython/www/src/brython.js:1603
    anonymous http://127.0.0.1:5500/brython/www/src/brython.js line 1117 > Function:83
    loop http://127.0.0.1:5500/brython/www/src/brython.js:1117
    run_script http://127.0.0.1:5500/brython/www/src/brython.js:963
    loop http://127.0.0.1:5500/brython/www/src/brython.js:1133
    onreadystatechange http://127.0.0.1:5500/brython/www/src/brython.js:1086
    (Asynchrone : EventHandlerNonNull)
    ajax_load_script http://127.0.0.1:5500/brython/www/src/brython.js:1082
    loop http://127.0.0.1:5500/brython/www/src/brython.js:1133
    run_scripts http://127.0.0.1:5500/brython/www/src/brython.js:945
    brython http://127.0.0.1:5500/brython/www/src/brython.js:891
    onload http://127.0.0.1:5500/brython/www/src/brython.js:842
    (Asynchrone : EventHandlerNonNull)
    <anonyme> http://127.0.0.1:5500/brython/www/src/brython.js:842
    (Asynchrone : EventListener.handleEvent)
    <anonyme> http://127.0.0.1:5500/brython/www/src/brython.js:840
    <anonyme> http://127.0.0.1:5500/brython/www/src/brython.js:964

@denis-migdal denis-migdal changed the title When extending a JS classes, Brython gets the methods but not the attributes, getter, and setters. When extending a JS classes, the super class' constructor isn't called + an exception is raised when calling super() in the subclass Mar 10, 2024
@denis-migdal denis-migdal changed the title When extending a JS classes, the super class' constructor isn't called + an exception is raised when calling super() in the subclass When extending JS classes, the super class' constructor isn't called + an exception is raised when calling super() in the subclass Mar 10, 2024
@denis-migdal
Copy link
Contributor Author

denis-migdal commented Mar 10, 2024

Proposal:

When extending a JS class:

  1. Make super() returning {__init__: function(){ ... }}.
  2. The subclass must call super().__init__(...).
  3. super().__init__(*args) will construct a new instance of the inherited JS class : new SuperClass(...args).
  4. Then, consecutive calls to super() will return the built instance.
  5. When accessing self.foo, if not in the subclass, search it in the built instance.

@denis-migdal
Copy link
Contributor Author

denis-migdal commented Mar 11, 2024

Alternative Proposal:

When doing : class PyClass(JSClass), do not directly inherit JSClass, but instead inherit an ad hoc python class wrapping the JS class :

class Wrapper:
    def __init__(self, *args):
        self.__js = JSClass.new(*args)

    def foo(self):
        self.__js.foo()

class PyClass(Wrapper):
    pass

This could be implemented in two ways :

  1. internally, i.e. when Brython detects we inherit a JS class, automatically build the wrapper (more secure).

  2. explicitly with an helper : PyClass(BuildWrapper(JSClass)) (can be implemented directly in Brython) + raise an exception when trying to directly inherit a JS class.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant