##// END OF EJS Templates
Fix use of pyside6 >= 6.7.0 (#14510)...
Fix use of pyside6 >= 6.7.0 (#14510) Fixes #14463. Using `pyside6 >= 6.7.0` as the `qt6` gui loop gives the following error: ``` In [1]: %gui qt6 In [2]: Traceback (most recent call last): File "/Users/iant/micromamba/envs/temp/bin/ipython", line 8, in <module> sys.exit(start_ipython()) ^^^^^^^^^^^^^^^ File "/Users/iant/github/ipython/IPython/__init__.py", line 130, in start_ipython return launch_new_instance(argv=argv, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/Users/iant/micromamba/envs/temp/lib/python3.12/site-packages/traitlets/config/application.py", line 1075, in launch_instance app.start() File "/Users/iant/github/ipython/IPython/terminal/ipapp.py", line 317, in start self.shell.mainloop() File "/Users/iant/github/ipython/IPython/terminal/interactiveshell.py", line 917, in mainloop self.interact() File "/Users/iant/github/ipython/IPython/terminal/interactiveshell.py", line 902, in interact code = self.prompt_for_code() ^^^^^^^^^^^^^^^^^^^^^^ File "/Users/iant/github/ipython/IPython/terminal/interactiveshell.py", line 845, in prompt_for_code text = self.pt_app.prompt( ^^^^^^^^^^^^^^^^^^^ File "/Users/iant/micromamba/envs/temp/lib/python3.12/site-packages/prompt_toolkit/shortcuts/prompt.py", line 1035, in prompt return self.app.run( ^^^^^^^^^^^^^ File "/Users/iant/micromamba/envs/temp/lib/python3.12/site-packages/prompt_toolkit/application/application.py", line 978, in run result = loop.run_until_complete(coro) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/Users/iant/micromamba/envs/temp/lib/python3.12/asyncio/base_events.py", line 674, in run_until_complete self.run_forever() File "/Users/iant/micromamba/envs/temp/lib/python3.12/asyncio/base_events.py", line 641, in run_forever self._run_once() File "/Users/iant/micromamba/envs/temp/lib/python3.12/asyncio/base_events.py", line 1948, in _run_once event_list = self._selector.select(timeout) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/Users/iant/micromamba/envs/temp/lib/python3.12/site-packages/prompt_toolkit/eventloop/inputhook.py", line 150, in select self.inputhook(InputHookContext(self._r, input_is_ready)) File "/Users/iant/github/ipython/IPython/terminal/pt_inputhooks/qt.py", line 50, in inputhook _appref = app = QtGui.QApplication([" "]) ^^^^^^^^^^^^^^^^^^ AttributeError: module 'PySide6.QtPrintSupport' has no attribute 'QApplication' If you suspect this is an IPython 8.28.0.dev bug, please report it at: https://github.com/ipython/ipython/issues or send an email to the mailing list at ipython-dev@python.org You can print a more detailed traceback right now with "%tb", or use "%debug" to interactively debug it. Extra-detailed tracebacks for bug-reporting purposes can be enabled via: %config Application.verbose_crash=True ``` This is because we use the imported module's `__dict__` to get the classes and functions available in the module here: https://github.com/ipython/ipython/blob/9b8cd4a397e5894ffeadad52477bb53e0fb664fc/IPython/external/qt_loaders.py#L309-L311 This no longer works as not all the classes and functions are in the `__dict__`. The solution in this PR is to use `dir(module)` instead. I have tested this locally using `pyside6` 6.6.3.1, 6.7.0, 6.7.1 and 6.7.2 and it works for me. It also successfully creates Matplotlib plots using for example ``` In [1]: %matplotlib qt6 In [2]: import matplotlib.pyplot as plt In [3]: plt.plot([1,3,2]) ``` It would be good to get independent confirmation that this fixes other downstream libraries as I tend to work directly with IPython and IPyKernel.

File last commit:

r26591:a5bdebad
r28842:e5d1a069 merge
Show More
auto.py
144 lines | 4.7 KiB | text/x-python | PythonLexer
"""Implementation of magic functions that control various automatic behaviors.
"""
#-----------------------------------------------------------------------------
# Copyright (c) 2012 The IPython Development Team.
#
# Distributed under the terms of the Modified BSD License.
#
# The full license is in the file COPYING.txt, distributed with this software.
#-----------------------------------------------------------------------------
#-----------------------------------------------------------------------------
# Imports
#-----------------------------------------------------------------------------
# Our own packages
from IPython.core.magic import Bunch, Magics, magics_class, line_magic
from IPython.testing.skipdoctest import skip_doctest
from logging import error
#-----------------------------------------------------------------------------
# Magic implementation classes
#-----------------------------------------------------------------------------
@magics_class
class AutoMagics(Magics):
"""Magics that control various autoX behaviors."""
def __init__(self, shell):
super(AutoMagics, self).__init__(shell)
# namespace for holding state we may need
self._magic_state = Bunch()
@line_magic
def automagic(self, parameter_s=''):
"""Make magic functions callable without having to type the initial %.
Without arguments toggles on/off (when off, you must call it as
%automagic, of course). With arguments it sets the value, and you can
use any of (case insensitive):
- on, 1, True: to activate
- off, 0, False: to deactivate.
Note that magic functions have lowest priority, so if there's a
variable whose name collides with that of a magic fn, automagic won't
work for that function (you get the variable instead). However, if you
delete the variable (del var), the previously shadowed magic function
becomes visible to automagic again."""
arg = parameter_s.lower()
mman = self.shell.magics_manager
if arg in ('on', '1', 'true'):
val = True
elif arg in ('off', '0', 'false'):
val = False
else:
val = not mman.auto_magic
mman.auto_magic = val
print('\n' + self.shell.magics_manager.auto_status())
@skip_doctest
@line_magic
def autocall(self, parameter_s=''):
"""Make functions callable without having to type parentheses.
Usage:
%autocall [mode]
The mode can be one of: 0->Off, 1->Smart, 2->Full. If not given, the
value is toggled on and off (remembering the previous state).
In more detail, these values mean:
0 -> fully disabled
1 -> active, but do not apply if there are no arguments on the line.
In this mode, you get::
In [1]: callable
Out[1]: <built-in function callable>
In [2]: callable 'hello'
------> callable('hello')
Out[2]: False
2 -> Active always. Even if no arguments are present, the callable
object is called::
In [2]: float
------> float()
Out[2]: 0.0
Note that even with autocall off, you can still use '/' at the start of
a line to treat the first argument on the command line as a function
and add parentheses to it::
In [8]: /str 43
------> str(43)
Out[8]: '43'
# all-random (note for auto-testing)
"""
valid_modes = {
0: "Off",
1: "Smart",
2: "Full",
}
def errorMessage() -> str:
error = "Valid modes: "
for k, v in valid_modes.items():
error += str(k) + "->" + v + ", "
error = error[:-2] # remove tailing `, ` after last element
return error
if parameter_s:
if not parameter_s in map(str, valid_modes.keys()):
error(errorMessage())
return
arg = int(parameter_s)
else:
arg = 'toggle'
if not arg in (*list(valid_modes.keys()), "toggle"):
error(errorMessage())
return
if arg in (valid_modes.keys()):
self.shell.autocall = arg
else: # toggle
if self.shell.autocall:
self._magic_state.autocall_save = self.shell.autocall
self.shell.autocall = 0
else:
try:
self.shell.autocall = self._magic_state.autocall_save
except AttributeError:
self.shell.autocall = self._magic_state.autocall_save = 1
print("Automatic calling is:", list(valid_modes.values())[self.shell.autocall])