Skip to content
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

Qt namespace is littered with service functions #463

Open
StSav012 opened this issue Oct 25, 2023 · 2 comments · May be fixed by #465
Open

Qt namespace is littered with service functions #463

StSav012 opened this issue Oct 25, 2023 · 2 comments · May be fixed by #465

Comments

@StSav012
Copy link
Contributor

StSav012 commented Oct 25, 2023

The following piece of code shows all the extra stuff QtPy adds to the PyQt/PySide modules:

# coding=utf-8
import importlib
import os
import re
import warnings
from types import ModuleType

warnings.filterwarnings("error")


def bright(text: str) -> str:
    return "\033[97m" + text + "\033[39m"


def italic(text: str) -> str:
    return "\033[3m" + text + "\033[23m"


api: str = 'PyQt5'

os.environ["FORCE_QT_API"] = "1"
os.environ["QT_API"] = api

try:
    import qtpy
except qtpy.PythonQtWarning as ex:
    print(bright(api), italic(str(ex)), sep=": ")

for module_name in [
    "Qsci",
    "Qt3DAnimation",
    "Qt3DCore",
    "Qt3DExtras",
    "Qt3DInput",
    "Qt3DLogic",
    "Qt3DRender",
    "QtAxContainer",
    "QtBluetooth",
    "QtCharts",
    "QtConcurrent",
    "QtCore",
    "QtDataVisualization",
    "QtDBus",
    "QtDesigner",
    "QtGui",
    "QtHelp",
    "QtLocation",
    "QtMacExtras",
    "QtMultimedia",
    "QtMultimediaWidgets",
    "QtNetwork",
    "QtNetworkAuth",
    "QtNfc",
    "QtOpenGL",
    "QtOpenGLWidgets",
    "QtPdf",
    "QtPdfWidgets",
    "QtPositioning",
    "QtPrintSupport",
    "QtPurchasing",
    "QtQml",
    "QtQuick",
    "QtQuick3D",
    "QtQuickControls2",
    "QtQuickWidgets",
    "QtRemoteObjects",
    "QtScxml",
    "QtSensors",
    "QtSerialPort",
    "QtSql",
    "QtStateMachine",
    "QtSvg",
    "QtSvgWidgets",
    "QtTest",
    "QtTextToSpeech",
    "QtUiTools",
    "QtWebChannel",
    "QtWebEngine",
    "QtWebEngineCore",
    "QtWebEngineQuick",
    "QtWebEngineWidgets",
    "QtWebSockets",
    "QtWidgets",
    "QtWinExtras",
    "QtX11Extras",
    "QtXml",
    "QtXmlPatterns",
]:
    try:
        original_module: ModuleType = importlib.import_module(
            f"{qtpy.API_NAME}.{module_name}"
        )
    except ModuleNotFoundError:
        # print(f"{module_name} not loaded from {API_NAME}")
        continue

    try:
        qtpy_module: ModuleType = importlib.import_module(f"qtpy.{module_name}")
    except (qtpy.QtBindingMissingModuleError, qtpy.QtModuleNotInQtVersionError) as ex:
        print(italic(str(ex)).replace(module_name, bright(module_name)))
        continue

    try:
        extra_members: frozenset[str] = (
            frozenset(dir(qtpy_module))
            - frozenset(dir(original_module))
            - frozenset(
                # To test if we are using WebEngine or WebKit
                # NOTE: This constant is imported by other projects
                # (e.g. Spyder), so please don't remove it.
                [
                    "WEBENGINE",
                ]
            )
            - frozenset(
                # These are for the compatibility b/w PySide and PyQt:
                [
                    "ClassInfo",
                    "ListProperty",
                    "MetaFunction",
                    "MetaSignal",
                    "Property",
                    "PyClassProperty",
                    "SIGNAL",
                    "SLOT",
                    "Signal",
                    "SignalInstance",
                    "Slot",
                    "VolatileBool",
                    "qjsEngine",
                    "qmlAttachedPropertiesObject",
                    "qmlClearTypeRegistrations",
                    "qmlRegisterRevision",
                    "qmlRegisterSingletonType",
                    "qmlRegisterUncreatableType",
                    "qmlTypeId",
                    "qtTrId",
                ]
            )
            - frozenset(
                # These are mostly harmless:
                [
                    "PYQT5",
                    "PYQT6",
                    "PYSIDE2",
                    "PYSIDE6",
                ]
            )
        )
    except Exception as ex:
        print(bright(f"{api}.{module_name}"), italic(str(ex)), sep=": ")
    else:
        neither_qt_nor_builtins: list[str] = sorted(
            filter(
                lambda d: re.match("(^(Q|q[A-Z]).+$|(^__[a-z_]+__$))", d) is None,
                extra_members,
            ),
        )
        if neither_qt_nor_builtins:
            print(
                bright(f"{api}.{module_name}"),
                ", ".join(neither_qt_nor_builtins),
                sep=": ",
            )

(It might be better to test the APIs one by one.)

For most of the modules, it's just PYQT5, PYQT6, PYSIDE2, and PYSIDE6. This can easily be cured with

del PYQT5, PYQT6, PYSIDE2, PYSIDE6

appended to the files. So, I've excluded them from the results for now. Still, I've got the following:

PyQt5.QtCore: TYPE_CHECKING, _qt_version, contextlib, parse, possibly_static_exec, possibly_static_exec_
PyQt5.QtDBus: sys
PyQt5.QtGui: _QAction, _QTOPENGL_NAMES, __QPointF, _action_set_shortcut, _action_set_shortcuts, _missing_optional_names, _qt_version, getattr_missing_optional_dep, parse, partialmethod, possibly_static_exec, set_shortcut, set_shortcuts
PyQt5.QtOpenGL: contextlib
PyQt5.QtWidgets: _QMenu, _QToolBar, _menu_add_action, _missing_optional_names, _qt_version, _toolbar_add_action, add_action, getattr_missing_optional_dep, parse, partialmethod, possibly_static_exec, static_method_kwargs_wrapper
PyQt5.QtX11Extras: sys

PySide2.QtCore: PySide2, TYPE_CHECKING, _qt_version, contextlib, parse, possibly_static_exec, possibly_static_exec_
PySide2.QtGui: _QAction, _QTOPENGL_NAMES, __QPointF, _action_set_shortcut, _action_set_shortcuts, _missing_optional_names, _qt_version, getattr_missing_optional_dep, movePosition, movePositionPatched, parse, partialmethod, possibly_static_exec, set_shortcut, set_shortcuts
PySide2.QtOpenGL: contextlib
PySide2.QtWidgets: _QMenu, _QToolBar, _menu_add_action, _missing_optional_names, _qt_version, _toolbar_add_action, add_action, getattr_missing_optional_dep, parse, partialmethod, possibly_static_exec, static_method_kwargs_wrapper
PySide2.QtX11Extras: sys

PyQt6.QtCore: TYPE_CHECKING, _qt_version, contextlib, parse, possibly_static_exec, possibly_static_exec_, promote_enums
PyQt6.QtDBus: sys
PyQt6.QtGui: _QTOPENGL_NAMES, _class, _missing_optional_names, _obsolete_function, _qt_version, getattr_missing_optional_dep, parse, partialmethod, possibly_static_exec, promote_enums, set_shortcut, set_shortcuts
PyQt6.QtOpenGL: contextlib
PyQt6.QtTest: promote_enums
PyQt6.QtWidgets: _missing_optional_names, _qt_version, add_action, getattr_missing_optional_dep, parse, partialmethod, possibly_static_exec, promote_enums, static_method_kwargs_wrapper

PySide6.QtCore: PySide6, TYPE_CHECKING, _qt_version, contextlib, parse, possibly_static_exec, possibly_static_exec_
PySide6.QtDBus: sys
PySide6.QtGui: _QTOPENGL_NAMES, _class, _missing_optional_names, _obsolete_function, _qt_version, getattr_missing_optional_dep, movePosition, movePositionPatched, parse, partialmethod, possibly_static_exec, set_shortcut, set_shortcuts
PySide6.QtOpenGL: contextlib
PySide6.QtWidgets: _missing_optional_names, _qt_version, add_action, getattr_missing_optional_dep, parse, partialmethod, possibly_static_exec, static_method_kwargs_wrapper

That's a lot, and most of this is what I've brought. 😢

@ccordoba12
Copy link
Member

I thought about a suggestion that could minimize the current changes you did in PR #465 to clear our names, and the future required ones: what if we import the _utils module instead of individual elements of it?

That way we'd only need to remove that module instead.

@StSav012
Copy link
Contributor Author

StSav012 commented Nov 1, 2023

what if we import the _utils module instead of individual elements of it?

Done. Thank you for the suggestion! The code might have become just a bit slower, but also a bit clearer to read.

@dalthviz dalthviz modified the milestones: v2.4.2, v2.5.0 Nov 1, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants