Repository: spyder-ide/qtpy (language: python)

Issue:
Make `QtWidgets` and `QtGui` modules compatible with `PySide6`/`PyQt6` import locations for `PySide2`/`PyQt5`
Hello, everyone,

Recently, I found that `QAction` is in `QtGui` of `PySide6`, but in `QtWidgets` of `PyQt5`. Therefore, when I do `from qtpy.QtGui import QAction` having `PySide6` available, it's OK, but with `PyQt5`, I get an import error.

So, isn't it reasonable to add
```python
from PyQt5.QtWidgets import QAction
```
line into the `if PYQT5` section of `qtpy/QtGui.py` to make `QAction` available from both `QtGui` and `QtWidgets`? This would make the code more flexible. That's not the only difference between Qt5 and Qt6 modules' locations.

I see that `QtPy` tends to adhere to the `PyQt5` syntax, but this leads to such minor lacks in the universality.

Anyway, thanks for the superb tool!


Discussion / hints:
Hi @StSav012 thank you for the feedback! That sounds good :+1: I think probably other classes should be added too like `QActionGroup`, `QShortcut`, `QFileSystemModel` and `QUndoCommand` (we already make those available from `qtpy.QtWidgets` for Qt6 bindings and are missing from `qtpy.QtGui` when using Qt5 bindings as well).

I would say then that we should do what you suggest, so adding the import in `qtpy.QtGui ` `QAction` in the Qt5 related sections (`if PYQT5` and probably for `if PYSIDE2`) as well for the other classes that changed from `QtWidgets` to `QtGui` on Qt6 (at least `QAction`, `QActionGroup`, `QShortcut`, `QFileSystemModel` and `QUndoCommand`).

Let us know If you want to help with this @StSav012 !
Closed by https://github.com/spyder-ide/qtpy/pull/403/commits/20628845291ee37226789e61b24ad22ad8e86fac
Since your PR hasn't been merged, this needs to remain open. Github will close the issue automatically when it is merged.

Fix patch:
diff --git a/qtpy/QtGui.py b/qtpy/QtGui.py
index 86502fd2..35a83eab 100644
--- a/qtpy/QtGui.py
+++ b/qtpy/QtGui.py
@@ -12,6 +12,9 @@
 
 if PYQT5:
     from PyQt5.QtGui import *
+
+    # Backport items moved to QtGui in Qt6
+    from PyQt5.QtWidgets import QAction, QActionGroup, QFileSystemModel, QShortcut, QUndoCommand
 elif PYQT6:
     from PyQt6 import QtGui
     from PyQt6.QtGui import *
@@ -30,12 +33,20 @@
     del QtGui
 elif PYSIDE2:
     from PySide2.QtGui import *
+
+    # Backport items moved to QtGui in Qt6
+    from PySide2.QtWidgets import QAction, QActionGroup, QFileSystemModel, QShortcut, QUndoCommand
+
     if hasattr(QFontMetrics, 'horizontalAdvance'):
         # Needed to prevent raising a DeprecationWarning when using QFontMetrics.width
         QFontMetrics.width = lambda self, *args, **kwargs: self.horizontalAdvance(*args, **kwargs)
 elif PYSIDE6:
     from PySide6.QtGui import *
     from PySide6.QtOpenGL import *
+
+    # Backport `QFileSystemModel` moved to QtGui in Qt6
+    from PySide6.QtWidgets import QFileSystemModel
+
     QFontMetrics.width = lambda self, *args, **kwargs: self.horizontalAdvance(*args, **kwargs)
     QFontMetricsF.width = lambda self, *args, **kwargs: self.horizontalAdvance(*args, **kwargs)
 


Test patch:
diff --git a/qtpy/tests/test_qtgui.py b/qtpy/tests/test_qtgui.py
index d16f08a2..787d7dba 100644
--- a/qtpy/tests/test_qtgui.py
+++ b/qtpy/tests/test_qtgui.py
@@ -39,6 +39,15 @@ def test_qguiapplication_functions():
     assert QtGui.QGuiApplication.exec_ is not None
 
 
+def test_what_moved_to_qtgui_in_qt6():
+    """Test what has been moved to QtGui in Qt6"""
+    assert QtGui.QAction is not None
+    assert QtGui.QActionGroup is not None
+    assert QtGui.QFileSystemModel is not None
+    assert QtGui.QShortcut is not None
+    assert QtGui.QUndoCommand is not None
+
+
 @pytest.mark.skipif(
     sys.platform.startswith('linux') and not_using_conda(),
     reason="Segmentation fault/Aborted on Linux CI when not using conda")
diff --git a/qtpy/tests/test_qtwidgets.py b/qtpy/tests/test_qtwidgets.py
index a04e662d..8670fdf6 100644
--- a/qtpy/tests/test_qtwidgets.py
+++ b/qtpy/tests/test_qtwidgets.py
@@ -29,9 +29,13 @@ def test_qlineedit_functions():
     assert QtWidgets.QLineEdit.getTextMargins
 
 
-def test_qundocommand_object():
-    """Test object aliasing for QUndoCommand"""
-    assert QtWidgets.QUndoCommand
+def test_what_moved_to_qtgui_in_qt6():
+    """Test that we move back what has been moved to QtGui in Qt6"""
+    assert QtWidgets.QAction is not None
+    assert QtWidgets.QActionGroup is not None
+    assert QtWidgets.QFileSystemModel is not None
+    assert QtWidgets.QShortcut is not None
+    assert QtWidgets.QUndoCommand is not None
 
 
 @pytest.mark.skipif(