Transcrypt icon indicating copy to clipboard operation
Transcrypt copied to clipboard

enumerate on list: py_enumerate is not defined error

Open warrenchopin opened this issue 9 months ago • 14 comments

I reinstalled Transcrypt today, and I encountered a weird error.

source:

def test_enumerate():
    print('in test_enumerate()')
    l= [1,2,3,4,5]
    for i, v in enumerate(l):
        print(f'{i}: {v}')

output:

in test_enumerate()
tests.enumerate.py:4 Uncaught ReferenceError: py_enumerate is not defined
    at test_enumerate (tests.enumerate.py:4:1)
    at main (tests.enumerate.py:24:1)

Python version: 3.9.20 Transcrypt version: 3.9.4 Web Browser: Chromium Version 137.0.7151.68 (Official Build) (64-bit), Firefox 139.04

it is so weird because enumerate() is a primitive function, and almost all Python code would not be able to be executed without it. But, I installed from the standard library:

python3.9 -m pip install transcrypt

I uninstalled Transcrypt, and reinstalled it, but the result was the same.

Was there a new update of Transcrypt recently? If not, I am afraid that something was messed up in my working environment. If you have any idea about how to fix, please leave a comment.

Thanks in advance.

warrenchopin avatar Jun 15 '25 15:06 warrenchopin

Yes, there was an update to Transcrypt a few weeks ago, and there were some changes to enumerate. I will look into this and see if I can reproduce the issue.

JennaSys avatar Jun 15 '25 16:06 JennaSys

In version 3.9.4, I did introduce (perhaps unnecessarily) a py_enumerate alias for enumerate to be consistent with other Python functions in the runtime. But so far, I am not able to reproduce this behavior, even with the test function you provided.

Are you rebuilding completely from scratch (i.e. deleting the __target__ folder)? Were you calling the Python enumerate function directly from JS code (not transcrypt'd)?

JennaSys avatar Jun 15 '25 18:06 JennaSys

Are you rebuilding completely from scratch (i.e. deleting the __target__ folder)? Were you calling the Python enumerate function directly from JS code (not transcrypt'd)?

There were some libraries included. I will remove them and rebuild completely from scratch after deleting the target directory, and let you know. I called the function from transcrypted code not from JS() code.

warrenchopin avatar Jun 16 '25 02:06 warrenchopin

I found that enumerate() raises the error when used in a sub module (NOT in a top module). I made an example code:

./main_test.py:

if __name__ == '__main__':
    from tests.enumerate import main
    main()

./tests/enumerate.y:

def main():
    print('in tests/enumerate.py')
    l = [1, 2, 3, 4, 5]
    for i, v in enumerate(l):
        print(f'{i}: {v}')
if __name__ == 'tests.enumerate':
    main()

compilation:

$ transcrypt -m -n ./main_test.py

Note that 'enumerate' is imported (NOT 'py_enumerate') in the compiled code below (in the second line import {...}) . This is why the error was raised.

compiled code (enumerate.js):

// Transcrypt'ed from Python, 2025-06-16 14:25:15
import {AssertionError, ..., divmod, enumerate, filter, float, getattr, hasattr, input, int, isinstance, issubclass, len, list, map, max, min, object, ord, pow, print, property, py_TypeError, py_iter, py_metatype, py_next, py_reversed, py_typeof, range, repr, round, set, setattr, sorted, str, sum, tuple, zip} from './org.transcrypt.__runtime__.js';
var __name__ = 'tests.enumerate';
export var main = function() {
    print('in tests/enumerate.py');
    var l = [1, 2, 3, 4, 5];
    for (var [i,v] of py_enumerate(l)) {
        print('{}: {}'.format(i, v));
    }
};
if (__name__ == 'tests.enumerate') {
    main();
}

//# sourceMappingURL=tests.enumerate.map

webpage (./main_frontend.html):

<!doctype html>
<html>
    <head>
        <meta charset="utf-8">
        <title>Enumerate Test</title>
        <script type="module" src="./__target__/main_test.js"></script>
    </head>
</html>

output:

Loading tests.enumerate...
org.transcrypt.__runtime__.py:272 in tests/enumerate.py
tests.enumerate.py:4 Uncaught ReferenceError: py_enumerate is not defined
    at main (tests.enumerate.py:4:1)
    at tests.enumerate.py:9:1

warrenchopin avatar Jun 16 '25 08:06 warrenchopin

Thank you for the additional info, I'll check this use case.

FWIW, I will likely drop the py_enumerate alias in the next version (3.13.0) as I don't think it is necessary since there should be no conflict with enumerate in JS anyway.

JennaSys avatar Jun 16 '25 08:06 JennaSys

I tested your example and it still worked for me:

in tests/enumerate.py
0: 1
1: 2
2: 3
3: 4
4: 5
in tests/enumerate.py
0: 1
1: 2
2: 3
3: 4
4: 5

And the transpiled file has the correct import:

// Transcrypt'ed from Python, 2025-06-16 01:31:33
import {AssertionError, ..., divmod, filter, float, getattr, hasattr, hex, input, int, isinstance, issubclass, len, list, map, max, min, object, oct, ord, pow, print, property, py_TypeError, py_enumerate, py_iter, py_metatype, py_next, py_reversed, py_typeof, range, repr, round, set, setattr, sorted, str, sum, tuple, zip} from './org.transcrypt.__runtime__.js';
var __name__ = 'tests.enumerate';
export var main = function() {
    print('in tests/enumerate.py');
    var l = [1, 2, 3, 4, 5];
    for (var [i,v] of py_enumerate(l)) {
        print('{}: {}'.format(i, v));
    }
};
if (__name__ == 'tests.enumerate') {
    main();
}

//# sourceMappingURL=tests.enumerate.map

I'm using Python 3.9.23 but that shouldn't matter compared to 3.9.20 that you are using. I've only tried it on Linux though. I can try it on Windows tomorrow and see if it behaves any differently. Off the top of my head, I can not think of why the import would have the non-aliased name unless there is some kind of cache issue somewhere. I will try to replicate the issue a bit more though.

JennaSys avatar Jun 16 '25 08:06 JennaSys

Hm, weird. However, I reverted to the previous Transcrypt version, and the error disappeared as before.

By the way, my working environment is Debian Linux (Termux_XFCE).

warrenchopin avatar Jun 16 '25 10:06 warrenchopin

The only thing I can think of that would cause this situation (where the code gets aliased but the import does not) is if the org.transcrypt.runtime.js file that it is using was compiled with the previous version instead of being re-compiled with the current version. If you look in the non-minified org.transcrypt.__runtime__.js file compiled with 3.9.4, you should see a line: export var py_enumerate = __enumerate__;

If instead you see: export function enumerate(iterable, start = 0) { then the runtime was compiled with 3.9.3

JennaSys avatar Jun 16 '25 17:06 JennaSys

I checked org.transcrypt.__runtime__.js, and searched 'enumerate', and only one was found as following:

export function enumerate (iterable) {
    return zip (range (len (iterable)), iterable);
}

I don't know how it was compiled with 3.9.3. I had erased __target__ directory, and compiled again from scratch before, but the result was not different when using 3.9.4.

warrenchopin avatar Jun 17 '25 01:06 warrenchopin

I found that I used some copied sources for org.transcrypt to import __pragma__ and primitive functions from transcrypt. It was from JdeH`s code implementing async/await (https://github.com/TranscryptOrg/Transcrypt/issues/131#issuecomment-313639193):

from org.transcrypt.stubs.browser import __pragma__, __envir__
...
__pragma__('js', '{}', '''
...
''')

to import __pragma__, I remember that I had to copy required source code from transcrypt directory installed. That is why the old version (3.9.3) was included raising the error in 3.9.4.

So, I erased the copied source code, I installed the newest Transcrypt (v3.9.4) and tried to compile. But, I encountered an error __pragma__ not found.

How can I import __pragma__, __envir__ in Transcrypt(3.9.4)? Should I copy the source code again from the installed directory?

warrenchopin avatar Jun 17 '25 02:06 warrenchopin

I assume you mean 3.9.3 and not 3.4.3? In any case, you definitely shouldn't mix code compiled with one version of Transcrypt with a runtime compiled from a different version.

I think I ran into the org import issue myself early on and started just using the comment style of __pragma__ to avoid having to import the stubs. That said, there could be an issue in Transcrypt's __main__ where the search paths are set up. I'll need to test that aspect further.

JennaSys avatar Jun 18 '25 00:06 JennaSys

Yes, I mean 3.9.3. Sorry for typo.

When ___pragma___ has multiple lines, I cannot use it in comment unless I collapse them into a single line. It is problematic because some has pretty long lines using 'JS'.

Moreover, ___envir___ is used in the middle of python source line (https://github.com/TranscryptOrg/Transcrypt/issues/131#issuecomment-313639193). How can I use it without copying org.transcrypt.stubs and importing?

warrenchopin avatar Jun 18 '25 02:06 warrenchopin

I found that I could replace the multi line string with a string variable, then I can use #__pragma__

Also, I found that I could erase source including ___envir___ which was not necessary.

Then, I think that I can erase org.trascrypt.stubs, and compile using Transcrypt 3.9.4. I will try this and leave a comment about the result.

warrenchopin avatar Jun 18 '25 06:06 warrenchopin

I tried, but Transcrypt didn't recognize a variable in a commented line. Is there a way to do it? Or is there a way to use a multi line string in #___pragma___()?

If not, It is problematic to collapse multi line JS code into a single line. JS code in a single line is almost not readable and debugging becomes very difficult. How do you manage multi line JS code in #___pragma___()?

warrenchopin avatar Jun 18 '25 08:06 warrenchopin