-
-
Notifications
You must be signed in to change notification settings - Fork 7.9k
FIX: Don't enable IPython integration if not entering REPL. #14979
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
FIX: Don't enable IPython integration if not entering REPL. #14979
Conversation
IPython can also be used to simply run files; when this is the case we are not going to be interactive; and we do not want to enable the eventloop integration. Otherwise someone doing: $ ipython script.py Will simply see a window blink, as IPython will exit immediately instead of showing the window and exit. I'm not quite sure how to test that are we basically _want_ something to block forever and wait for user input; so no test added Closes: ipython/ipython#11837
This is also related to #14950 so may not be a proper fix. |
lib/matplotlib/backend_bases.py
Outdated
try: | ||
mpl.rcParamsOrig["backend"] = mpl.rcParams["backend"] | ||
ip.enable_matplotlib() | ||
if is_non_interactive_terminal_ipython(ip): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you 1) make the function private (leading underscore) and 2) perhaps move the check a bit earlier, e.g. in line 1649 if not ip or _is_non_interactive...(ip)
?
thanks! just a minor nitpick. |
lib/matplotlib/backend_bases.py
Outdated
@@ -1553,6 +1553,20 @@ def _draw(renderer): raise Done(renderer) | |||
return figure._cachedRenderer | |||
|
|||
|
|||
def is_non_interactive_terminal_ipython(ip): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This does only check attributes of ip
, so I feel it should belong to the IPython object and should be implemented there as IPython.is_interactive
or similar.
Then one can do:
if ip.is_interactive:
ip.enable_matplotlib()
Or maybe even in enable_matplotlib()
def enable_matplotlib(self):
if not self.is_interactive:
warnings.warn('enable_matplotlib() called on a non-interactive IPython.'
'Matplotlib interactive mode is not enabled.'
'This will raise a RuntimeError in furture versions.')
return
...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But then we would only support versions of ipython>=whatever-implements-this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Which is the reason I did it this way, and also ip.is_interactive
make no-sens on non-TerminalInteractiveShell
. When running matplotlib in notebook, you will get a different type for ip
(ZmqInteractiveShell). And both are subclass of a base class which can be overridden by other implementations.
To be clearer this function test:
- is ip created by a terminal IPython.
- if 1; is it interactive.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm ok with the present approach for back-comatibility.
Can we just revert the commit that introduced the problem and then rethink this from scratch? I feel like matplotlib should provide the interface and attributes, such that IPython can query all the information it needs to decide what to do; not matplotlib deciding what IPython should do. |
@ImportanceOfBeingErnest In principle you are correct but we are constrained by some history (as we want IPython and Matplotlib to both work with future / old versions of the other) and the conflict between user expectations and lazyness. On one hand users want to be able to just import In the past people have had to remember to type The second to last commit changes to using the gentler The last commit simplifies it further and avoids monkey-patching IPython all together. |
Note that the above approach does not preclude to improve and expose more things in IPython; and we also likely want at some point to clear all the old code path. Matplotlib master is still amazingly workswith IPython 3.0 (released in 2015). I'm open to remove old compat layer though – maybe we should more carefully comment whcih code path are for older version of IPython :-) |
IIUC you want that people can get cairo plots in IPython by just updating matplotlib, without updating IPython? Isn't that a very special case? Like, if I know I need to update matplotlib anyways, I could just update IPython as well. |
Maybe you can but not everyboy can; but you can't assume that everyboy will think about this, take the time to do it or has the possibility to do it. IPython also oes have bugs, and we regularly have people that have to get to olde IPython version for some other unrelated bugs. And if you start this way, why not be always up to date will al the libraries ? Why isn't everyone using Python 3.8 two days after it is out ? This also mean that first we need to get the update in IPython; then release IPython, then release matplotlib. That also does not help with downstream packagers in Debian and Co. who now may also have to package IPython first. Packages that works with each other have to work with previous/next versions if you want to have any chance to a be a bit friendly with users. |
This will also be an issues with ipympl. |
I really feel I'm missing something here. So all of this is just for the one person on earth who wants to use a non-standard backend and cannot type |
What ipython needs to do is basically read the required_interactive_framework attribute (which is new in mpl3.0 and which I'm proposing, in #14521, to move to somewhere slightly more practical for third-party backend developers (basically they can mostly just ignore it if that PR gets merged)) and enable the correct event loop based on that. Note that this is not only for qt5cairo, but also for mplcairo and any other backend that may exist out there (of which there may admittedly not be that many). @ImportanceOfBeingErnest to be honest, it is not clear to me why you think this patch would better live in IPython's codebase rather than in Matplotlib's. For example, if #14521 goes in, IPython would need to carry more or less forever code to handle either location of required_interactive_framework, whereas by having the patch on Matplotlib's side, we can immediately update the IPython integration to use the new location. Also, the complexity of the patch is bascailly the same wherever it lives. |
Hopefully |
Hey, it's not because we have asingle bug report that there is a single person that have the issue. And note the reporter in the IPython issue never said they they couldn't type And it appear that the same piece of code also trigger issues with users that use Also sie note; I'm not a maintainer here and only swing by every now and then, but I'm not quite sure if I need to interprete your comments as a real genuine desire to understand, or a lack of empathy toward other user's needs. I have usually a tough skin and had to fight a lot with the language and cultural barrier when trying to express myself in international projects, but the way you present things can be extremely offputting to anyone reading this thread. New users may not distinguish a contributor from a maintainer; which can make feel like the project just does not care about their use case. Keep in mind that for every people commenting on a thread there might be dozens just lurking. |
I am extremely concerned about user's needs. And one of the highest goods is hence the stability of the code-base, i.e. not to break people's code from one version to the next. |
I don't disagree that we need stability; but whether or not we had release this in 3.1 or 4.0 it would have been broken; none of us design code to have bugs. Without the experience of this breakage; we would likely had never find this corner case anyway. And we are not going from one makeshift solution to another; we explore what is possible doing what we can; and cleaning up when possible to get better solutions. Remove the change is also a problem for the same stability reason you give us; if we remove it then user relying on some of those behavior in 3.1 would lose it in 3.2. That's not good either. In the end it's always a question a trade off; maybe reverting will be the solution, but maybe it's not. One thing for sure this is a relatively hard problem, and without experiments we won't get all things right. No plan survives contact with the enemy, and enemy is the rest of the folks that don't work on master. As usual there is an XKCD for this https://xkcd.com/1172/ |
I think this should be merged as-is and I will follow up with a PR that removes the |
Let's give a few days to @ImportanceOfBeingErnest to reply, unless you want to push 3.1.2 out tomorrow... |
Oh, I don't think I have anything more to add here. I've made the problem clear. And it seems it's being understood. |
ok, let's try this, then :) |
Owee, I'm MrMeeseeks, Look at me. There seem to be a conflict, please backport manually. Here are approximate instructions:
And apply the correct labels and milestones. Congratulation you did some good work ! Hopefully your backport PR will be tested by the continuous integration and merged soon! If these instruction are inaccurate, feel free to suggest an improvement. |
…f not entering REPL. FIX: Don't enable IPython integration if not entering REPL. (matplotlib#14979) FIX: Don't enable IPython integration if not entering REPL.
…-v3.1.x Backport PR #14979: FIX: Don't enable IPython integration if not ente…
IPython can also be used to simply run files; when this is the case we
are not going to be interactive; and we do not want to enable the
eventloop integration. Otherwise someone doing:
Will simply see a window blink, as IPython will exit immediately instead
of showing the window and exit.
I'm not quite sure how to test that are we basically want something to
block forever and wait for user input; so no test added
Closes: ipython/ipython#11837
PR Summary
PR Checklist