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

code.interact() does not work right #853

Closed
gilch opened this issue May 30, 2018 · 21 comments
Closed

code.interact() does not work right #853

gilch opened this issue May 30, 2018 · 21 comments

Comments

@gilch
Copy link

gilch commented May 30, 2018

And neither does import pdb; pdb.set_trace(), which is what I really wanted, but I get further with interact().

I put

import code
code.interact()

in the <script> tag. On page load, I get the expected >>> prompt (in a pop up, but OK, it's a web page). If I give it a simple input, like 1, I get another >>> prompt, as expected, but the 1 doesn't seem to have printed anywhere, not even in the browser developer tools' JS console, which is where you see the output of a print call, even though the interact banner printed to the console.

 Python 3.3.0 (default, 2018-04-17 08:26:29.400878) 
[Javascript 1.5] on Brython on brython
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)

However, entering print(1) at the pop-up prompt does produce output in the JS console.

Also, multi-line inputs completely crash. If I enter def foo(): I expect the next prompt to be ... so I can do the next line, but this just crashes. I don't get another prompt.

If Brython's aim is to be a drop-in replacement for client-side JavaScript, we need some kind of interactive console. Python's just not the same without it. It seems like this should be possible, considering that a bookmarklet like Firebug Lite could inject developer tools in the web page and we already have a demo console. It doesn't seem like much of a stretch to have something like IDLE embedded in a bookmarklet, but pdb.set_trace() didn't work right in the demo console either, so I don't know.

@gilch
Copy link
Author

gilch commented Mar 13, 2019

I've noticed some progress on this one. I get the first ... prompt when I try to def a function now. But this one always crashes with

AttributeError: 'SyntaxError' object has no attribute 'filename'

or

AttributeError: 'module' object has no attribute 'excepthook'

Depending on the input. Anything that raises an exception, even on one line, like 1/0 also generates this error and crashes the interact() session.

@PierreQuentel
Copy link
Contributor

This must win the award of the longest time ever to fix an issue in Brython ;-)

@gilch
Copy link
Author

gilch commented Dec 28, 2019

Cool! I tried using it. Still doesn't work right. My test page:

<script type="text/javascript"
    src="https://cdn.jsdelivr.net/gh/brython-dev/brython@master/www/src/brython.js">
</script>
<script type="text/javascript"
    src="https://cdn.jsdelivr.net/gh/brython-dev/brython@master/www/src/brython_stdlib.js">
</script>
<body onload="brython()">
<script type="text/python">
from code import interact
interact()
</script>
</body>

On Firefox (on Windows, after some load time. The prompts are in pop-up dialogs, and the outputs are in the javascript console.)

Python 3.8.0 (default, 2019-12-28 21:59:51.902843) 
[Javascript 1.5] on Brython on brython
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> 1  # Notice that no value is printed!
>>> print(1)  # But this works.
1
>>> def hi(name):
...   print('hi', name)
Javascript exception: TypeError: "line_info is undefined"
    brython master/www/src/brython.js:7686
    brython master/www/src/brython.js:6446
    brython master/www/src/brython.js line 9011 > Function:410
    brython master/www/src/brython.js line 9011 > Function:99
    brython master/www/src/brython.js line 9011 > Function:573
    brython master/www/src/brython.js line 9011 > Function:131
    brython master/www/src/brython.js line 9011 > Function:870
    brython master/www/src/brython.js line 9011 > Function:781
    brython master/www/src/brython.js line 9011 > Function:1030
    brython master/www/src/brython.js line 5240 > Function:16
    brython master/www/src/brython.js:5240
    brython master/www/src/brython.js:5171
    brython master/www/src/brython.js:5182

Array(5) [ "code_InteractiveInterpreter_2_runsource_4", {…}, "code", {…}, runsource1()
 ]
brython.js:7614:9

recursion error ? false brython.js:7615:9

This repeats several times, then.

print stack ok 
Array []
brython.js:7488:9
Traceback (most recent call last):
RuntimeError: TypeError: line_info is undefined brython.js:6120:9

What am I doing wrong?

@PierreQuentel PierreQuentel reopened this Dec 29, 2019
PierreQuentel pushed a commit that referenced this issue Dec 30, 2019
…f JS eval, the last evaluated value is returned by the function. Exceptions in exec have attribute $stack set to the part of frames_stack starting with the calling frame. eval(source) prints the result if source is a code object with filename = "<console>" and mode = "single", and the return value is not None. Changes required for issue #853.
@PierreQuentel
Copy link
Contributor

You did nothing wrong, it's the issue that was not really fixed...
The commit referenced above should give results more similar to the CPython module. If you find other bugs (which is likely ;-) please report them here.
Thanks !

@gilch
Copy link
Author

gilch commented Dec 31, 2019

Interact does show the repr of evaluated expressions now. But I still can't define functions of more than one line in the interactive session. It's the same traceback as before complaining about line_info is undefined.

I wonder if my test page is using the new version or caching the last one. I tried a force-refresh. I don't know how that interacts with the indexedDB though.

>> __BRYTHON__.compiled_date
"2019-12-30 22:24:19.377720"

That part looks right. But the stdlib is a separate file.

@PierreQuentel
Copy link
Contributor

I suspect that it's because the debug mode is 0, which happens if you call the function brython() without any parameter. If it is the case, I will change the default debug mode to 1 instead of 0.

There is nothing I can do for the multi-line input in the prompt box : unfortunately, with Javascript it is impossible to define a function that would have the same effect as input(), ie block the execution of the next instruction until the user has entered a value. The only blocking functions in Javascript are alert(), confirm() and prompt() ; Brython uses prompt() for input(), and prompt() doesn't support multiline entries.

It is possible to simulate the Python interactive interpreter in Brython (this is what the console does), but not with code.interact() which uses Python's input() function.

@gilch
Copy link
Author

gilch commented Dec 31, 2019

There is nothing I can do for the multi-line input in the prompt box

This seems like an unrelated issue, since code.interact() only takes single-line inputs to begin with. To enter a multi-line definition, you enter it one line at a time. If the first line entered, e.g.
>>> def hi(name):, is incomplete, then the next line prompts with ..., and indeed, Brython does this part correctly when using code.interact(). But then it crashes with RuntimeError: TypeError: line_info is undefined when I enter anything for the next line.

So, for example, in CPython's code.interact(), I can do

>>> def hi(name):
...     print('hi', name)
...
>>> hi('Bob')
hi Bob
>>>

Then the equivalent I expect from Brython would have five prompt()s, each with a single line of input:

>>>

def hi(name):

...

    print('hi', name)

[This is where it is crashing, currently.]

...

[empty]

>>>

hi('Bob')

[Prints "hi Bob" to js console.]

>>>

[end of example]

@gilch
Copy link
Author

gilch commented Dec 31, 2019

In fact, we can remove the input() from consideration altogether, and still demonstrate the same problem in Brython.

Take this example in CPython:

>>> from code import interact
>>> stream = iter("""
... def hi(name):
...     print('hi', name)
...
... hi('Bob')
... """.split('\n'))
>>> interact(readfunc=lambda _: next(stream))
Python 3.8.0 (tags/v3.8.0:fa919fd, Oct 14 2019, 19:37:50) [MSC v.1916 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
hi Bob
Traceback (most recent call last):
  ...
StopIteration
>>>

Note that it did print "hi Bob" before crashing when the input iterator ran out.

Let's try that in Brython:

<script type="text/javascript"
    src="https://cdn.jsdelivr.net/gh/brython-dev/brython@master/www/src/brython.js">
</script>
<script type="text/javascript"
    src="https://cdn.jsdelivr.net/gh/brython-dev/brython@master/www/src/brython_stdlib.js">
</script>
<body onload="brython(1)">
<script type="text/python">
from code import interact
stream = iter("""
def hi(name):
    print('hi', name)

hi('Bob')
""".split('\n'))

interact(readfunc=lambda _: next(stream))
</script>
</body>

It still crashes before the "hi Bob". input() has nothing to do with it.

using indexedDB for stdlib modules cache brython.js:5198:36
Python 3.8.0 (default, 2019-12-30 22:24:19.377720) 
[Javascript 1.5] on Brython on brython
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
brython.js:6120:9
Javascript exception: TypeError: "line_info is undefined"
    brython master/www/src/brython.js:7698
    brython master/www/src/brython.js:6447
    brython master/www/src/brython.js line 9023 > Function:410
    brython master/www/src/brython.js line 9023 > Function:99
    brython master/www/src/brython.js line 9023 > Function:573
    brython master/www/src/brython.js line 9023 > Function:131
    brython master/www/src/brython.js line 9023 > Function:870
    brython master/www/src/brython.js line 9023 > Function:781
    brython master/www/src/brython.js line 9023 > Function:1030
    brython master/www/src/brython.js line 5240 > Function:25
    brython master/www/src/brython.js:5240
    brython master/www/src/brython.js:5171
    brython master/www/src/brython.js:5182
brython.js:7625:32
Array(5) [ "codeop__maybe_compile_2", {…}, "codeop", {…}, _maybe_compile0()
 ]
brython.js:7626:9
recursion error ? false

[repeated 7 times]

print stack ok 
Array [ "__main__ line 9", "  interact(readfunc=lambda _:next(stream))" ]
brython.js:7500:9
Traceback (most recent call last):
  module __main__ line 9
    interact(readfunc=lambda _:next(stream))
RuntimeError: TypeError: line_info is undefined brython.js:6120:9
Error: brython.js line 7674 > eval:131:348
    $factory https://cdn.jsdelivr.net/gh/brython-dev/brython@master/www/src/brython.js line 7674 > eval:131
    loop https://cdn.jsdelivr.net/gh/brython-dev/brython@master/www/src/brython.js:5243
    idb_load https://cdn.jsdelivr.net/gh/brython-dev/brython@master/www/src/brython.js:5171
    onsuccess https://cdn.jsdelivr.net/gh/brython-dev/brython@master/www/src/brython.js:5182

@PierreQuentel
Copy link
Contributor

@gilch Thanks for the explanation, I think I understand what is going on.

I tried your example in Firefox, Edge and Chrome on Windows 10, and always got the expected result:

image

The page tests/test.html is

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<script type="text/javascript"
    src="https://cdn.jsdelivr.net/gh/brython-dev/brython@master/www/src/brython.js">
</script>
<script type="text/javascript"
    src="https://cdn.jsdelivr.net/gh/brython-dev/brython@master/www/src/brython_stdlib.js">
</script>

</head>

<body onload="brython(1)">
<script type="text/python">
from code import interact
stream = iter("""
def hi(name):
    print('hi', name)

hi('Bob')
""".split('\n'))

interact(readfunc=lambda _: next(stream))
</script>
</body>
</html>

But when I disable indexedDB cache and set debug mode to 0:

<body onload="brython({indexedDB: false, debug: 0})>

I get the same error message as you. So I think that you first ran the script with indexedDB cache enabled (this is the default) and debug mode not set (<body onload="brython()">), then ran it again with debug mode set to 1. Am I right ?

In this case, the stdlib modules stored in the indexedDB cache are not reset (caching only tests if it is the same version of brython_stdlib.js and brython.js, but not the debug mode), and when debug mode is not set the line numbers are not in the Javascript translation, which causes the error message "line_info is undefined"... It's a bug, obviously.

@gilch
Copy link
Author

gilch commented Jan 1, 2020

So I think that you first ran the script with indexedDB cache enabled (this is the default) and debug mode not set (), then ran it again with debug mode set to 1. Am I right ?

Yes.

@gilch
Copy link
Author

gilch commented Jan 1, 2020

By using

<body onload="brython({debug:1, indexedDB:false})">

I get the expected behavior as well. Both with the input iterator and directly typed in using the prompt()s. I found and cleared the indexedDB in Firefox's dev tools, and now it works with the fresh DB as well (onload="brython(1)").

PierreQuentel pushed a commit that referenced this issue Jan 1, 2020
@PierreQuentel
Copy link
Contributor

With the commit referenced above, the example should work now. Can you confirm ?

@gilch
Copy link
Author

gilch commented Jan 1, 2020

I'm still having issues when using

<body onload="brython()">

But,

>> __BRYTHON__.compiled_date
"2019-12-30 22:24:19.377720"

I'm not sure why I can't clear the caches.
I try, but Firefox says,

Database "brython-cache (default)" will be deleted after all connections are closed.

Then on reload,

create object store 1 brython.js:5190:9
upgrade needed brython.js:5192:43
InvalidStateError: A mutation operation was attempted on a database that did not allow mutations.

If I try a private window,

could not open indexedDB database brython.js:5212:35

@gilch
Copy link
Author

gilch commented Jan 1, 2020

Maybe it's not my cache. If I go directly to https://cdn.jsdelivr.net/gh/brython-dev/brython@master/www/src/brython.js and search for compiled_date it still shows last year.

@gilch
Copy link
Author

gilch commented Jan 2, 2020

It seems to be working now. Maybe the CDN caught up or maybe my cache timed out.

@PierreQuentel
Copy link
Contributor

Can we close the issue then ?

@gilch
Copy link
Author

gilch commented Jan 4, 2020

Next test: a try/finally statement

<script type="text/javascript"
    src="https://cdn.jsdelivr.net/gh/brython-dev/brython@master/www/src/brython.js">
</script>
<script type="text/javascript"
    src="https://cdn.jsdelivr.net/gh/brython-dev/brython@master/www/src/brython_stdlib.js">
</script>
<body onload="brython()">
<script type="text/python">
from code import interact
stream = iter("""
try:
    print('try')
finally:
    print('finally')

print('done')
""".split('\n'))

interact(readfunc=lambda _:next(stream))
</script>
</body>

The results:

using indexedDB for stdlib modules cache brython.js:5197:36
Python 3.8.0 (default, 2020-01-01 17:46:19.327656) 
[Javascript 1.5] on Brython on brython
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
brython.js:6119:9
  File "<string>", line 2
    print('try')
            ^
SyntaxError: invalid syntax
brython.js:6119:9
  File "<string>", line 1
    finally:
           ^
SyntaxError: invalid syntax
brython.js:6119:9
finally
brython.js:6119:9
done
brython.js:6119:9
Traceback (most recent call last):
  module __main__ line 11
    interact(readfunc=lambda _:next(stream))
  module code line 301, in interact
    console.interact(banner,exitmsg)
  module code line 227, in interact
    line=self.raw_input(prompt)
  module code line 261, in push
    return more
  module code line 71, in runsource
    return True
  module codeop line 168, in __call__
    return _maybe_compile(self.compiler,source,filename,symbol)
  module lambda2 line 12, in <lambda>
    
StopIteration: StopIteration

We expected the StopIteration, but the rest is still not working right.

The expected result (when run in CPython):

Python 3.8.0 (tags/v3.8.0:fa919fd, Oct 14 2019, 19:37:50) [MSC v.1916 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
try
finally
done
Traceback (most recent call last):
    ...
StopIteration

@gilch
Copy link
Author

gilch commented Jan 6, 2020

I'm also thinking input()s should be echoed to the js console (and probably their prompts as well). When you type input()s into the CPython console from the command line, you can see a history of them, and can copy from that history to re-enter things. But if you just type them into the prompt() boxes they disappear, so it's hard to tell what has been happening. (This wouldn't affect the output for the readfunc tests since those bypass input().)

@PierreQuentel
Copy link
Contributor

With the commit referenced above I think that the issue can be considered closed. If you disagree please reopen it.
Thanks again for the report and ideas :-)

@gilch
Copy link
Author

gilch commented Oct 21, 2023

Is this broken again or am I doing it wrong?

Test page:

<html>
<head>
<script src="https://raw.githack.com/brython-dev/brython/master/www/src/brython.js"
        crossorigin="anonymous">
</script>
<script src="https://raw.githack.com/brython-dev/brython/master/www/src/brython_stdlib.js"
        crossorigin="anonymous">
</script>
</head>

<body onload="brython({indexedDB: false, debug: 1})">
<script type="text/python">
import code
code.interact()
</script>
<p>Hello, World!</p>
</body>
</html>

Test input: (

Result in Edge console:

>>>  (
brython.js:584 braces ['(']
brython.js:584 braces ['(']
brython.js:584 braces ['(']
brython.js:15011  Python 3.12.0 (default, 2023-10-20 16:49:57.579466) 
[Javascript 1.5] on Brython on brython
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
Traceback (most recent call last):
  File "http://localhost:63342/hissp/examples/repl.html?_ijt=e5pm8ug00e07j68edf0mmopg1r&_ij_reload=RELOAD_ON_SAVE#__main__", line 2, in <module>
    code.interact()
  File "VFS.code.py", line 303, in interact
    console.interact(banner,exitmsg)
        ^^^^^^^^^^
  File "VFS.code.py", line 234, in interact
    more=self.push(line)
        ^^^^^^^^^^^^^^^^^^^^^^^^
  File "VFS.code.py", line 260, in push
    more=self.runsource(source,self.filename)
                 ^^^^^^^^^^
  File "VFS.code.py", line 66, in runsource
    self.showsyntaxerror(filename)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "VFS.code.py", line 109, in showsyntaxerror
    sys.last_exc=value
          ^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: can't set attribute. Did you mean: '__eq__'?

PierreQuentel pushed a commit that referenced this issue Oct 22, 2023
@PierreQuentel
Copy link
Contributor

Is this broken again or am I doing it wrong?

I'm afraid it was broken again, sorry...

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

2 participants