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

Nothing works in embedded mode after moving from 8.10 to 8.11 #13966

Closed
akhileshraju opened this issue Mar 7, 2023 · 7 comments
Closed

Nothing works in embedded mode after moving from 8.10 to 8.11 #13966

akhileshraju opened this issue Mar 7, 2023 · 7 comments
Labels

Comments

@akhileshraju
Copy link

Issue

I am embedding IPython in my command line application. v8.5 to v8.10 work fine but after upgrading to v8.11 nothing works.
The command line starts up, but every command results in Exception 'NoneType' object has no attribute 'check_complete'

Simple act of starting up the application and pressing 'Enter' also throws the error.

Exception

***************************
 <Banner>
***************************


Unhandled exception in event loop:
  File "/home/user1/.pyenv/versions/3.11.1/lib/python3.11/asyncio/events.py", line 80, in _run
    self._context.run(self._callback, *self._args)
  File "/home/user1/dev/cli/.venv/lib/python3.11/site-packages/prompt_toolkit/input/vt100.py", line 173, in callback_wrapper
    callback()
  File "/home/user1/dev/cli/.venv/lib/python3.11/site-packages/prompt_toolkit/application/application.py", line 707, in read_from_input
    self.key_processor.process_keys()
  File "/home/user1/dev/cli/.venv/lib/python3.11/site-packages/prompt_toolkit/key_binding/key_processor.py", line 270, in process_keys
    self._process_coroutine.send(key_press)
  File "/home/user1/dev/cli/.venv/lib/python3.11/site-packages/prompt_toolkit/key_binding/key_processor.py", line 185, in _process
    self._call_handler(matches[-1], key_sequence=buffer[:])
  File "/home/user1/dev/cli/.venv/lib/python3.11/site-packages/prompt_toolkit/key_binding/key_processor.py", line 320, in _call_handler
    handler.call(event)
  File "/home/user1/dev/cli/.venv/lib/python3.11/site-packages/prompt_toolkit/key_binding/key_bindings.py", line 124, in call
    result = self.handler(event)
             ^^^^^^^^^^^^^^^^^^^
  File "/home/user1/dev/cli/.venv/lib/python3.11/site-packages/IPython/terminal/shortcuts/__init__.py", line 374, in handle_return_or_newline_or_execute
    return newline_or_execute_outer(shell)(event)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/user1/dev/cli/.venv/lib/python3.11/site-packages/IPython/terminal/shortcuts/__init__.py", line 397, in newline_or_execute
    status, indent = shell.check_complete(check_text)
                     ^^^^^^^^^^^^^^^^^^^^

Exception 'NoneType' object has no attribute 'check_complete'
Press ENTER to continue...

Application script

import os
import tempfile
from pathlib import Path
import argparse

from traitlets.config.loader import Config
from IPython.terminal.embed import InteractiveShellEmbed


parser = argparse.ArgumentParser()
parser.add_argument("-s", "--source", help="source the python script file", type=str)
args = parser.parse_args()

cfg = Config()

ipshell = InteractiveShellEmbed(
    config=cfg,
    banner1="\n***************************\n <Banner> \n***************************\n",
    exit_msg="\nExiting...",
)

banner = (
    "#####################################################################\n"
    "# Dummy banner \n"
    "#####################################################################\n"
)

if os.access(Path.cwd(), os.W_OK):
    log_path = Path.cwd()
else:
    log_path = Path(tempfile.gettempdir())

ipshell.logger.logstart(
    loghead=banner,
    logfname=str(log_path.joinpath("log.py")),
    logmode="over",
    log_output=True,
)

ipshell()

@krassowski krassowski added the bug label Mar 10, 2023
@krassowski
Copy link
Member

Thank you for the report, apologies for the regression. I can reproduce the problem with your script. This likely has to do with get_ipython not returning the shell correctly.

When I tried to create a smaller minimal reproducible example with:

from IPython.terminal.embed import embed; embed()

It appears to work just fine, so it seems to be specific to the direct use of InteractiveShellEmbed rather than the embed mode provided by embed() function.

This works:

from traitlets.config.loader import Config
from IPython.terminal.embed import embed

cfg = Config()

embed(
    config=cfg,
    banner1="\n***************************\n <Banner> \n***************************\n",
    exit_msg="\nExiting...",
)

This does not:

from traitlets.config.loader import Config
from IPython.terminal.embed import InteractiveShellEmbed

cfg = Config()

InteractiveShellEmbed(
    config=cfg,
    banner1="\n***************************\n <Banner> \n***************************\n",
    exit_msg="\nExiting...",
)()

It is not obvious to me what causes this difference.

@samuelsadok
Copy link

samuelsadok commented Mar 17, 2023

Minimal reproducable example:

import IPython; console = IPython.terminal.embed.InteractiveShellEmbed(); console()

The error can be seen in a fresh virtual environment:

python -m venv venv
source venv/bin/activate
pip install ipython
python -c "import IPython; console = IPython.terminal.embed.InteractiveShellEmbed(); console()"
# [press enter]

As mentioned by the OP, a downgrade (e.g. pip install "ipython<=8.10") fixes the issue.

In our application we do a bunch of additional setup on the InteractiveShellEmbed object before launching the console, so I think we can't use embed() directly.

Update

After digging a bit deeper, the issue seems to be introduced by 875ff23 by adding a dependency to IPython.core.getipython.get_ipython() via handle_return_or_newline_or_execute(). However when instantiating InteractiveShellEmbed manually, it is not automatically set as the current shell instance.

To fix this, instead of calling InteractiveShellEmbed(...), one can call InteractiveShellEmbed.instance(...) (which is what embed() does).

So this works fine for me, but in terms of suggested fixes to IPython maybe it would be cleaner/safer to have the instance be set automatically when launching (rather than instantiating) the console?

Update 2

Seems the suggested workaround doesn't actually work on Windows (or generally when starting the script with ipython instead of python). So we need to guard the workaround behind an if:

if IPython.core.getipython.get_ipython() is None:
    console = IPython.terminal.embed.InteractiveShellEmbed.instance()
else:
    console = IPython.terminal.embed.InteractiveShellEmbed()

@akhileshraju
Copy link
Author

@samuelsadok thanks for the detailed analysis and workaround.

@krassowski is there a plan to fix this in a newer version of IPython? I imagine this is fix-worthy since it's a regression.

@krassowski
Copy link
Member

Yes, I think it should be fixed because current examples are broken. After some thinking, I would say instance() should be set in __call__ method of InteractiveShellEmbed as this is intended to activate the shell. More generally I feel like it should override the current instance if there is one, and on exit it should restore it (so basically we should maintain a stack of instances to allow nested embedding, while enforcing that the currently active instance is bound to the singleton tracking the current instance).

def __call__(

Any thoughts on such a solution?

antoinevg pushed a commit to greatscottgadgets/greatfet that referenced this issue May 5, 2023
IPython.terminal broke the greatfet shell such that any attempt to use it resulted in an exception ending in:
Exception 'NoneType' object has no attribute 'check_complete'

This was traced to a change in IPython, version 8.11 and has broken other projects as well, refer to this issue in the IPython project: ipython/ipython#13966

This PR fixes the problem, as suggested in the issue report (linked above). It should be compatible with IPython v8.11 and later, and also backwards compatible for earlier versions of the library as well (as per the above issues last comment).

I tested the raw Python script (greatefet_shell.py) but have not managed to generate an install (.egg ?) using the README instructions. The .py file, when run directly, no longer creates an exception and the shell runs normally.
luispedro added a commit to luispedro/jug that referenced this issue May 11, 2023
Jug shell fails in newer versions of IPython, see ipython/ipython#13966
luispedro added a commit to luispedro/jug that referenced this issue May 11, 2023
Jug shell fails in newer versions of IPython, see ipython/ipython#13966
luispedro added a commit to luispedro/jug that referenced this issue May 26, 2023
Jug shell fails in newer versions of IPython, see ipython/ipython#13966
@shayneoneill
Copy link

note, I get this same bug just by using the ipython command line.

On all my machines.

claudiodsf added a commit to SeismicSource/sourcespec that referenced this issue Jul 11, 2023
@akhileshraju
Copy link
Author

akhileshraju commented Jul 11, 2023

Hi @krassowski any updates on the fix for this issue? I didn't reply to your earlier question since I am not really an expert on the internals of IPython and didn't want to give any incorrect answers.

@akhileshraju
Copy link
Author

Since there doesn't seem to be any movement on this, I am assuming this won't be fixed.
Closing this since the workaround SeismicSource/sourcespec@8bde65c works for me

@akhileshraju akhileshraju closed this as not planned Won't fix, can't repro, duplicate, stale Aug 28, 2023
ankush added a commit to frappe/frappe that referenced this issue Sep 3, 2023
mainland added a commit to drexelwireless/dragonradio that referenced this issue Apr 11, 2024
mainland added a commit to drexelwireless/dragonradio that referenced this issue Apr 11, 2024
mainland added a commit to drexelwireless/dragonradio that referenced this issue Apr 17, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants