##// 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:

r28487:820b4807
r28842:e5d1a069 merge
Show More
test_text.py
268 lines | 7.6 KiB | text/x-python | PythonLexer
# encoding: utf-8
"""Tests for IPython.utils.text"""
#-----------------------------------------------------------------------------
# Copyright (C) 2011 The IPython Development Team
#
# Distributed under the terms of the BSD License. The full license is in
# the file COPYING, distributed as part of this software.
#-----------------------------------------------------------------------------
#-----------------------------------------------------------------------------
# Imports
#-----------------------------------------------------------------------------
import os
import math
import random
from pathlib import Path
import pytest
from IPython.utils import text
#-----------------------------------------------------------------------------
# Globals
#-----------------------------------------------------------------------------
@pytest.mark.parametrize(
"expected, width, row_first, spread",
(
(
"aaaaa bbbbb ccccc ddddd\n",
80,
False,
False,
),
(
"aaaaa ccccc\nbbbbb ddddd\n",
25,
False,
False,
),
(
"aaaaa ccccc\nbbbbb ddddd\n",
12,
False,
False,
),
(
"aaaaa\nbbbbb\nccccc\nddddd\n",
10,
False,
False,
),
(
"aaaaa bbbbb ccccc ddddd\n",
80,
True,
False,
),
(
"aaaaa bbbbb\nccccc ddddd\n",
25,
True,
False,
),
(
"aaaaa bbbbb\nccccc ddddd\n",
12,
True,
False,
),
(
"aaaaa\nbbbbb\nccccc\nddddd\n",
10,
True,
False,
),
(
"aaaaa bbbbb ccccc ddddd\n",
40,
False,
True,
),
(
"aaaaa ccccc\nbbbbb ddddd\n",
20,
False,
True,
),
(
"aaaaa ccccc\nbbbbb ddddd\n",
12,
False,
True,
),
(
"aaaaa\nbbbbb\nccccc\nddddd\n",
10,
False,
True,
),
),
)
def test_columnize(expected, width, row_first, spread):
"""Basic columnize tests."""
size = 5
items = [l*size for l in 'abcd']
with pytest.warns(PendingDeprecationWarning):
out = text.columnize(
items, displaywidth=width, row_first=row_first, spread=spread
)
assert out == expected
def test_columnize_random():
"""Test with random input to hopefully catch edge case """
for row_first in [True, False]:
for nitems in [random.randint(2,70) for i in range(2,20)]:
displaywidth = random.randint(20,200)
rand_len = [random.randint(2,displaywidth) for i in range(nitems)]
items = ['x'*l for l in rand_len]
with pytest.warns(PendingDeprecationWarning):
out = text.columnize(
items, row_first=row_first, displaywidth=displaywidth
)
longer_line = max([len(x) for x in out.split("\n")])
longer_element = max(rand_len)
assert longer_line <= displaywidth, (
f"Columnize displayed something lager than displaywidth : {longer_line}\n"
f"longer element : {longer_element}\n"
f"displaywidth : {displaywidth}\n"
f"number of element : {nitems}\n"
f"size of each element : {rand_len}\n"
f"row_first={row_first}\n"
)
@pytest.mark.parametrize("row_first", [True, False])
def test_columnize_medium(row_first):
"""Test with inputs than shouldn't be wider than 80"""
size = 40
items = [l*size for l in 'abc']
with pytest.warns(PendingDeprecationWarning):
out = text.columnize(items, row_first=row_first, displaywidth=80)
assert out == "\n".join(items + [""]), "row_first={0}".format(row_first)
@pytest.mark.parametrize("row_first", [True, False])
def test_columnize_long(row_first):
"""Test columnize with inputs longer than the display window"""
size = 11
items = [l*size for l in 'abc']
with pytest.warns(PendingDeprecationWarning):
out = text.columnize(items, row_first=row_first, displaywidth=size - 1)
assert out == "\n".join(items + [""]), "row_first={0}".format(row_first)
def eval_formatter_check(f):
ns = dict(n=12, pi=math.pi, stuff='hello there', os=os, u=u"café", b="café")
s = f.format("{n} {n//4} {stuff.split()[0]}", **ns)
assert s == "12 3 hello"
s = f.format(" ".join(["{n//%i}" % i for i in range(1, 8)]), **ns)
assert s == "12 6 4 3 2 2 1"
s = f.format("{[n//i for i in range(1,8)]}", **ns)
assert s == "[12, 6, 4, 3, 2, 2, 1]"
s = f.format("{stuff!s}", **ns)
assert s == ns["stuff"]
s = f.format("{stuff!r}", **ns)
assert s == repr(ns["stuff"])
# Check with unicode:
s = f.format("{u}", **ns)
assert s == ns["u"]
# This decodes in a platform dependent manner, but it shouldn't error out
s = f.format("{b}", **ns)
pytest.raises(NameError, f.format, "{dne}", **ns)
def eval_formatter_slicing_check(f):
ns = dict(n=12, pi=math.pi, stuff='hello there', os=os)
s = f.format(" {stuff.split()[:]} ", **ns)
assert s == " ['hello', 'there'] "
s = f.format(" {stuff.split()[::-1]} ", **ns)
assert s == " ['there', 'hello'] "
s = f.format("{stuff[::2]}", **ns)
assert s == ns["stuff"][::2]
pytest.raises(SyntaxError, f.format, "{n:x}", **ns)
def eval_formatter_no_slicing_check(f):
ns = dict(n=12, pi=math.pi, stuff="hello there", os=os)
s = f.format("{n:x} {pi**2:+f}", **ns)
assert s == "c +9.869604"
s = f.format("{stuff[slice(1,4)]}", **ns)
assert s == "ell"
s = f.format("{a[:]}", a=[1, 2])
assert s == "[1, 2]"
def test_eval_formatter():
f = text.EvalFormatter()
eval_formatter_check(f)
eval_formatter_no_slicing_check(f)
def test_full_eval_formatter():
f = text.FullEvalFormatter()
eval_formatter_check(f)
eval_formatter_slicing_check(f)
def test_dollar_formatter():
f = text.DollarFormatter()
eval_formatter_check(f)
eval_formatter_slicing_check(f)
ns = dict(n=12, pi=math.pi, stuff='hello there', os=os)
s = f.format("$n", **ns)
assert s == "12"
s = f.format("$n.real", **ns)
assert s == "12"
s = f.format("$n/{stuff[:5]}", **ns)
assert s == "12/hello"
s = f.format("$n $$HOME", **ns)
assert s == "12 $HOME"
s = f.format("${foo}", foo="HOME")
assert s == "$HOME"
def test_strip_email():
src = """\
>> >>> def f(x):
>> ... return x+1
>> ...
>> >>> zz = f(2.5)"""
cln = """\
>>> def f(x):
... return x+1
...
>>> zz = f(2.5)"""
assert text.strip_email_quotes(src) == cln
def test_strip_email2():
src = "> > > list()"
cln = "list()"
assert text.strip_email_quotes(src) == cln
def test_LSString():
lss = text.LSString("abc\ndef")
assert lss.l == ["abc", "def"]
assert lss.s == "abc def"
lss = text.LSString(os.getcwd())
assert isinstance(lss.p[0], Path)
def test_SList():
sl = text.SList(["a 11", "b 1", "a 2"])
assert sl.n == "a 11\nb 1\na 2"
assert sl.s == "a 11 b 1 a 2"
assert sl.grep(lambda x: x.startswith("a")) == text.SList(["a 11", "a 2"])
assert sl.fields(0) == text.SList(["a", "b", "a"])
assert sl.sort(field=1, nums=True) == text.SList(["b 1", "a 2", "a 11"])