enthought / pyface

pyface: traits-capable windowing framework
Other
105 stars 55 forks source link

Bug: 'import pyface.tasks.api' fails with latest PySide6 #1163

Closed mdickinson closed 1 year ago

mdickinson commented 1 year ago

Environment

OS: Mac Python version: 3.8 Toolkit: Qt Qt API: PySide6

Description

Importing pyface.tasks.api fails with the latest Pyface (7.4.2) from PyPI and the latest PySide6 (6.4.0).

Steps to Reproduce

  1. Create a new Python 3.8 venv, and activate it
  2. Execute pip install pyface PySide6
  3. Start Python and import pyface.tasks.api.

The result of the import is a traceback with tail end:

  File "/Users/mdickinson/.venvs/testing/lib/python3.8/site-packages/pyface/ui/qt4/tasks/dock_pane.py", line 31, in <genexpr>
    INVERSE_AREA_MAP = dict((int(v), k) for k, v in AREA_MAP.items())
TypeError: int() argument must be a string, a bytes-like object or a number, not 'DockWidgetArea'

Here's the full session:

mdickinson@mirzakhani ~ % python3.8 -m venv --clear ~/.venvs/testing && source ~/.venvs/testing/bin/activate
(testing) mdickinson@mirzakhani ~ % pip install pyface PySide6
Collecting pyface
  Using cached pyface-7.4.2-py3-none-any.whl (1.3 MB)
Collecting PySide6
  Downloading PySide6-6.4.0-cp36-abi3-macosx_10_9_universal2.whl (6.9 kB)
Collecting traits>=6.2
  Using cached traits-6.4.1-cp38-cp38-macosx_10_9_x86_64.whl (5.0 MB)
Collecting importlib-resources>=1.1.0
  Downloading importlib_resources-5.10.0-py3-none-any.whl (34 kB)
Collecting PySide6-Addons==6.4.0
  Downloading PySide6_Addons-6.4.0-cp36-abi3-macosx_10_9_universal2.whl (218.3 MB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 218.3/218.3 MB 5.1 MB/s eta 0:00:00
Collecting shiboken6==6.4.0
  Downloading shiboken6-6.4.0-cp36-abi3-macosx_10_9_universal2.whl (346 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 347.0/347.0 KB 12.3 MB/s eta 0:00:00
Collecting PySide6-Essentials==6.4.0
  Downloading PySide6_Essentials-6.4.0-cp36-abi3-macosx_10_9_universal2.whl (139.2 MB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 139.2/139.2 MB 9.8 MB/s eta 0:00:00
Collecting zipp>=3.1.0
  Downloading zipp-3.9.0-py3-none-any.whl (5.8 kB)
Installing collected packages: zipp, traits, shiboken6, PySide6-Essentials, importlib-resources, PySide6-Addons, pyface, PySide6
Successfully installed PySide6-6.4.0 PySide6-Addons-6.4.0 PySide6-Essentials-6.4.0 importlib-resources-5.10.0 pyface-7.4.2 shiboken6-6.4.0 traits-6.4.1 zipp-3.9.0
WARNING: You are using pip version 22.0.4; however, version 22.3 is available.
You should consider upgrading via the '/Users/mdickinson/.venvs/testing/bin/python3.8 -m pip install --upgrade pip' command.
(testing) mdickinson@mirzakhani ~ % python        
Python 3.8.15 (default, Oct 12 2022, 04:23:30) 
[Clang 13.0.0 (clang-1300.0.29.30)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import pyface
>>> import pyface.tasks.api
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/mdickinson/.venvs/testing/lib/python3.8/site-packages/pyface/tasks/api.py", line 60, in <module>
    from .advanced_editor_area_pane import AdvancedEditorAreaPane
  File "/Users/mdickinson/.venvs/testing/lib/python3.8/site-packages/pyface/tasks/advanced_editor_area_pane.py", line 17, in <module>
    AdvancedEditorAreaPane = toolkit_object(
  File "/Users/mdickinson/.venvs/testing/lib/python3.8/site-packages/pyface/base_toolkit.py", line 127, in __call__
    module = import_module(mname, package)
  File "/opt/local/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/importlib/__init__.py", line 127, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "/Users/mdickinson/.venvs/testing/lib/python3.8/site-packages/pyface/ui/qt4/tasks/advanced_editor_area_pane.py", line 25, in <module>
    from .main_window_layout import MainWindowLayout, PaneItem
  File "/Users/mdickinson/.venvs/testing/lib/python3.8/site-packages/pyface/ui/qt4/tasks/main_window_layout.py", line 29, in <module>
    from .dock_pane import AREA_MAP
  File "/Users/mdickinson/.venvs/testing/lib/python3.8/site-packages/pyface/ui/qt4/tasks/dock_pane.py", line 31, in <module>
    INVERSE_AREA_MAP = dict((int(v), k) for k, v in AREA_MAP.items())
  File "/Users/mdickinson/.venvs/testing/lib/python3.8/site-packages/pyface/ui/qt4/tasks/dock_pane.py", line 31, in <genexpr>
    INVERSE_AREA_MAP = dict((int(v), k) for k, v in AREA_MAP.items())
TypeError: int() argument must be a string, a bytes-like object or a number, not 'DockWidgetArea'
>>> 
mdickinson commented 1 year ago

Using .value instead of int seems to work for this particular version of PySide6. (But it probably fails for other versions.)

>>> from pyface.qt import QtCore
>>> QtCore.Qt.DockWidgetArea.LeftDockWidgetArea
<DockWidgetArea.LeftDockWidgetArea: 1>
>>> int(QtCore.Qt.DockWidgetArea.LeftDockWidgetArea)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: int() argument must be a string, a bytes-like object or a number, not 'DockWidgetArea'
>>> type(QtCore.Qt.DockWidgetArea.LeftDockWidgetArea).__mro__
(<enum 'DockWidgetArea'>, <enum 'Flag'>, <enum 'Enum'>, <class 'object'>)
>>> QtCore.Qt.DockWidgetArea.LeftDockWidgetArea.value
1
mdickinson commented 1 year ago

And this is indeed new with PySide6 6.4.0. With 6.3.2, I get:

>>> from pyface.qt import QtCore
>>> int(QtCore.Qt.DockWidgetArea.LeftDockWidgetArea)
1
>>> QtCore.Qt.DockWidgetArea.LeftDockWidgetArea.value
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'PySide6.QtCore.Qt.DockWidgetArea' object has no attribute 'value'
>>> 
mdickinson commented 1 year ago

Looks like matplotlib ran into this too: https://github.com/matplotlib/matplotlib/issues/24155 (fix in https://github.com/matplotlib/matplotlib/pull/24158)

corranwebster commented 1 year ago

This also begs the question about why we were casting to int in the first place in the above code.

A bit of digging shows it was to work around a PySide 1.0 bug: https://github.com/enthought/pyface/pull/11

We can possibly remove all of the int(...) casts introduced by that PR?

mdickinson commented 1 year ago

We can possibly remove all of the int(...) casts introduced by that PR?

Yes, a solution that just treats all Qt Enum values as black-box immutable value objects and doesn't try to interpret them in any way sounds like the ideal fix. (But I could see situations where that wouldn't work - e.g., if we need to serialise and deserialise enum values for some reason.)

corranwebster commented 1 year ago

The immediate issue is resolved by pinning in #1169

I am going to close this in favour of #1164, with a reference back to the discussion here.