From b13dfcd68498044dfef020082dd5bab2d256868e Mon Sep 17 00:00:00 2001 From: Marcus Ottosson Date: Mon, 29 Aug 2016 14:13:04 +0100 Subject: [PATCH 1/9] Implement #105 --- Dockerfile-py2.7 | 1 + Dockerfile-py3.5 | 1 + 2 files changed, 2 insertions(+) diff --git a/Dockerfile-py2.7 b/Dockerfile-py2.7 index a8e59fda..512908d1 100644 --- a/Dockerfile-py2.7 +++ b/Dockerfile-py2.7 @@ -26,6 +26,7 @@ ENV DISPLAY :99 WORKDIR /workspace/Qt.py ENTRYPOINT cp -r /Qt.py /workspace && \ python build_caveats_tests.py && \ + python build_membership_tests.py && \ Xvfb :99 -screen 0 1024x768x16 2>/dev/null & \ sleep 3 && \ nosetests \ diff --git a/Dockerfile-py3.5 b/Dockerfile-py3.5 index 89bedfa4..6be3b9b7 100644 --- a/Dockerfile-py3.5 +++ b/Dockerfile-py3.5 @@ -26,6 +26,7 @@ ENV DISPLAY :99 WORKDIR /workspace/Qt.py ENTRYPOINT cp -r /Qt.py /workspace && \ python3 build_caveats_tests.py && \ + python build_membership_tests.py && \ Xvfb :99 -screen 0 1024x768x16 2>/dev/null & \ sleep 3 && \ nosetests \ From 8f95c5d943734c66da411e7ec9a12e1b09f7f9b2 Mon Sep 17 00:00:00 2001 From: Marcus Ottosson Date: Mon, 29 Aug 2016 14:23:53 +0100 Subject: [PATCH 2/9] Implement #105 --- build_membership_tests.py | 77 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 build_membership_tests.py diff --git a/build_membership_tests.py b/build_membership_tests.py new file mode 100644 index 00000000..c119d4a5 --- /dev/null +++ b/build_membership_tests.py @@ -0,0 +1,77 @@ +import json + +# Safe-guard against incomplete API +from PySide2 import __all__ +__all__.remove("QtOpenGL") +__all__.remove("QtSql") +__all__.remove("QtSvg") + +from PySide2 import * + +# Serialise members +members = {} +for name, module in locals().items(): + if name.startswith("_"): + continue + + if name in ("json", "members"): + continue + + members[name] = dir(module) + +# Write to disk +with open("reference_members.json", "w") as f: + json.dump(members, f, indent=4) + + +def build_test(): + boilerplate = """\ +import os +import json + +with open("reference_members.json") as f: + reference_members = json.load(f) + + +""" + + test = """\ +def test_{binding}_members(): + os.environ["QT_PREFERRED_BINDING"] = "{binding}" + + target_members = dict() + for name, module in locals().items(): + if name.startswith("_"): + continue + + target_members[name] = dir(module) + + missing = dict() + for module, members in reference_members.items(): + for member in members: + if member not in target_members.get(module, []): + if module not in missing: + missing[module] = [] + missing[module].append(member) + + message = "" + for module, members in missing.items(): + message += "\\n%s: \\n - %s" % (module, "\\n - ".join(members)) + + assert not missing, "{binding} is missing members: %s" % message + +""" + + tests = list(test.format(binding=binding) + for binding in ["PyQt5", + "PyQt4", + "PySide"]) + + with open("test_membership.py", "w") as f: + contents = boilerplate + "\n".join(tests) + print(contents) # Preview content during tests + f.write(contents) + + +if __name__ == '__main__': + build_test() From 1fe8bdaec4f3d2608689b7992d1cf6a64e5226dd Mon Sep 17 00:00:00 2001 From: Marcus Ottosson Date: Mon, 29 Aug 2016 14:25:23 +0100 Subject: [PATCH 3/9] Fix Dockerfile for Python 3.5 --- Dockerfile-py3.5 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile-py3.5 b/Dockerfile-py3.5 index 6be3b9b7..845d6661 100644 --- a/Dockerfile-py3.5 +++ b/Dockerfile-py3.5 @@ -26,7 +26,7 @@ ENV DISPLAY :99 WORKDIR /workspace/Qt.py ENTRYPOINT cp -r /Qt.py /workspace && \ python3 build_caveats_tests.py && \ - python build_membership_tests.py && \ + python3 build_membership_tests.py && \ Xvfb :99 -screen 0 1024x768x16 2>/dev/null & \ sleep 3 && \ nosetests \ From b591fd5635d82395f4802821020c10093f8fad2b Mon Sep 17 00:00:00 2001 From: Marcus Ottosson Date: Mon, 29 Aug 2016 15:00:56 +0100 Subject: [PATCH 4/9] Do not run under Python 3 I also renamed the builders, because they were getting run during testing due to their name containing the magic word "test". --- Dockerfile-py2.7 | 4 ++-- Dockerfile-py3.5 | 3 +-- build_caveats_tests.py => build_caveats.py | 0 build_membership_tests.py => build_membership.py | 11 +++++++---- 4 files changed, 10 insertions(+), 8 deletions(-) rename build_caveats_tests.py => build_caveats.py (100%) mode change 100755 => 100644 rename build_membership_tests.py => build_membership.py (89%) diff --git a/Dockerfile-py2.7 b/Dockerfile-py2.7 index 512908d1..e76ca1b2 100644 --- a/Dockerfile-py2.7 +++ b/Dockerfile-py2.7 @@ -25,8 +25,8 @@ ENV DISPLAY :99 WORKDIR /workspace/Qt.py ENTRYPOINT cp -r /Qt.py /workspace && \ - python build_caveats_tests.py && \ - python build_membership_tests.py && \ + python build_caveats.py && \ + python build_membership.py && \ Xvfb :99 -screen 0 1024x768x16 2>/dev/null & \ sleep 3 && \ nosetests \ diff --git a/Dockerfile-py3.5 b/Dockerfile-py3.5 index 845d6661..daade117 100644 --- a/Dockerfile-py3.5 +++ b/Dockerfile-py3.5 @@ -25,8 +25,7 @@ ENV DISPLAY :99 WORKDIR /workspace/Qt.py ENTRYPOINT cp -r /Qt.py /workspace && \ - python3 build_caveats_tests.py && \ - python3 build_membership_tests.py && \ + python3 build_caveats.py && \ Xvfb :99 -screen 0 1024x768x16 2>/dev/null & \ sleep 3 && \ nosetests \ diff --git a/build_caveats_tests.py b/build_caveats.py old mode 100755 new mode 100644 similarity index 100% rename from build_caveats_tests.py rename to build_caveats.py diff --git a/build_membership_tests.py b/build_membership.py similarity index 89% rename from build_membership_tests.py rename to build_membership.py index c119d4a5..7423cf21 100644 --- a/build_membership_tests.py +++ b/build_membership.py @@ -10,7 +10,7 @@ # Serialise members members = {} -for name, module in locals().items(): +for name, module in locals().copy().items(): if name.startswith("_"): continue @@ -25,8 +25,9 @@ def build_test(): - boilerplate = """\ + header = """\ import os +import sys import json with open("reference_members.json") as f: @@ -39,8 +40,10 @@ def build_test(): def test_{binding}_members(): os.environ["QT_PREFERRED_BINDING"] = "{binding}" + from Qt import * + target_members = dict() - for name, module in locals().items(): + for name, module in locals().copy().items(): if name.startswith("_"): continue @@ -68,7 +71,7 @@ def test_{binding}_members(): "PySide"]) with open("test_membership.py", "w") as f: - contents = boilerplate + "\n".join(tests) + contents = header + "\n".join(tests) print(contents) # Preview content during tests f.write(contents) From 7474ce1ff5d4f4e8b573298ad64708c9827ee87a Mon Sep 17 00:00:00 2001 From: Marcus Ottosson Date: Mon, 29 Aug 2016 15:33:22 +0100 Subject: [PATCH 5/9] Add missing members, exclude PySide2-only members --- Qt.py | 2 + build_membership.py | 193 ++++++++++++++++++++++++++++++++++++++------ 2 files changed, 172 insertions(+), 23 deletions(-) diff --git a/Qt.py b/Qt.py index 6c6cda13..9d9483cd 100644 --- a/Qt.py +++ b/Qt.py @@ -69,6 +69,7 @@ def _pyqt4(): PyQt4.QtCore.Property = PyQt4.QtCore.pyqtProperty PyQt4.QtCore.QItemSelection = PyQt4.QtGui.QItemSelection PyQt4.QtCore.QItemSelectionModel = PyQt4.QtGui.QItemSelectionModel + PyQt4.QtCore.QAbstractProxyModel = PyQt4.QtGui.QAbstractProxyModel try: from PyQt4 import QtWebKit @@ -115,6 +116,7 @@ def _pyside(): PySide.QtCore.QStringListModel = PySide.QtGui.QStringListModel PySide.QtCore.QItemSelection = PySide.QtGui.QItemSelection PySide.QtCore.QItemSelectionModel = PySide.QtGui.QItemSelectionModel + PySide.QtCore.QAbstractProxyModel = PySide.QtGui.QAbstractProxyModel try: from PySide import QtWebKit diff --git a/build_membership.py b/build_membership.py index 7423cf21..e6562245 100644 --- a/build_membership.py +++ b/build_membership.py @@ -1,30 +1,47 @@ -import json -# Safe-guard against incomplete API -from PySide2 import __all__ -__all__.remove("QtOpenGL") -__all__.remove("QtSql") -__all__.remove("QtSvg") -from PySide2 import * +def build_membership(): + """Generate a .json file with all members of PySide2""" + + # NOTE: PySide2, as of this writing, is incomplete. + # In it's __all__ module is a module, `QtOpenGL` + # that does no exists. This causes `import *` to fail. + + import json + from PySide2 import __all__ + __all__.remove("QtOpenGL") + + # These modules do not exist pre-Qt 5, + # so do not bother testing for them. + __all__.remove("QtSql") + __all__.remove("QtSvg") + + from PySide2 import * + + # Serialise members + members = {} + for name, module in locals().copy().items(): + if name.startswith("_"): + continue + + if name in ("json", "members"): + continue -# Serialise members -members = {} -for name, module in locals().copy().items(): - if name.startswith("_"): - continue + members[name] = dir(module) - if name in ("json", "members"): - continue + # Write to disk + with open("reference_members.json", "w") as f: + json.dump(members, f, indent=4) - members[name] = dir(module) -# Write to disk -with open("reference_members.json", "w") as f: - json.dump(members, f, indent=4) +def build_tests(): + """Build membership tests + Members only available in Qt 5 are excluded, along with member + exclusive to a paricular binding. + + """ -def build_test(): header = """\ import os import sys @@ -33,12 +50,136 @@ def build_test(): with open("reference_members.json") as f: reference_members = json.load(f) +excluded = { + + "QtCore": [ + # + # From PySide + # + "Connection", + "QBasicMutex", + "QFileDevice", + "QItemSelectionRange", + "QJsonArray", + "QJsonDocument", + "QJsonParseError", + "QJsonValue", + "QMessageLogContext", + "QtInfoMsg", + "qInstallMessageHandler", + + # + # From PyQt4 + # + "ClassInfo", + "MetaFunction", + "QFactoryInterface", + "QSortFilterProxyModel", + "QStringListModel", + "QT_TRANSLATE_NOOP3", + "QT_TRANSLATE_NOOP_UTF8", + "__moduleShutdown", + "__version__", + "__version_info__", + "qAcos", + "qAsin", + "qAtan", + "qAtan2", + "qExp", + "qFabs", + "qFastCos", + "qFastSin", + "qFuzzyIsNull", + "qTan", + "qtTrId", + + # + # From PyQt5 + # + "SIGNAL", + "SLOT", + ], + + "QtGui": [ + # + # From PySide + # + "QGuiApplication", + "QPagedPaintDevice", + "QSurface", + "QSurfaceFormat", + "QTouchDevice", + "QWindow", + + # + # From PyQt4 + # + "QAccessibleEvent", + "QToolBarChangeEvent", + + # + # From PyQt5 + # + "QMatrix", + "QPyTextObject", + "QStringListModel", + ], + + "QtWebKit": [ + # + # From PyQt4 + # + "WebCore", + + # + # From PyQt5 + # + "__doc__", + "__file__", + "__name__", + "__package__", + ], + + "QtScript": [ + # + # From PyQt4 + # + "QScriptExtensionInterface", + "QScriptExtensionPlugin", + "QScriptProgram", + "QScriptable", + + # + # From PyQt5 + # + "QScriptClass", + "QScriptClassPropertyIterator", + "QScriptContext", + "QScriptContextInfo", + "QScriptEngine", + "QScriptEngineAgent", + "QScriptString", + "QScriptValue", + "QScriptValueIterator", + "__doc__", + "__file__", + "__name__", + "__package__", + ], + + "QtNetwork": [ + # + # PyQt4 + # + "QIPv6Address", + ], +} """ test = """\ def test_{binding}_members(): - os.environ["QT_PREFERRED_BINDING"] = "{binding}" + os.environ["QT_PREFERRED_BINDING"] = "{Binding}" from Qt import * @@ -52,6 +193,11 @@ def test_{binding}_members(): missing = dict() for module, members in reference_members.items(): for member in members: + + # Ignore those that have no Qt 4-equivalent. + if member in excluded.get(module, []): + continue + if member not in target_members.get(module, []): if module not in missing: missing[module] = [] @@ -61,11 +207,11 @@ def test_{binding}_members(): for module, members in missing.items(): message += "\\n%s: \\n - %s" % (module, "\\n - ".join(members)) - assert not missing, "{binding} is missing members: %s" % message + assert not missing, "{Binding} is missing members: %s" % message """ - tests = list(test.format(binding=binding) + tests = list(test.format(Binding=binding, binding=binding.lower()) for binding in ["PyQt5", "PyQt4", "PySide"]) @@ -77,4 +223,5 @@ def test_{binding}_members(): if __name__ == '__main__': - build_test() + build_membership() + build_tests() From 00039695af7f81462c82561a48fe38fa0e5b7a31 Mon Sep 17 00:00:00 2001 From: Marcus Ottosson Date: Mon, 29 Aug 2016 16:10:37 +0100 Subject: [PATCH 6/9] Explicitly run test files Without these lines, tests may look within any Python file and throw errors unrelated to tests (in this case, SyntaxError in Python 3 for file(s) produced by build_membership.py). --- Dockerfile-py2.7 | 5 ++++- Dockerfile-py3.5 | 4 +++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/Dockerfile-py2.7 b/Dockerfile-py2.7 index e76ca1b2..92144ea2 100644 --- a/Dockerfile-py2.7 +++ b/Dockerfile-py2.7 @@ -33,4 +33,7 @@ ENTRYPOINT cp -r /Qt.py /workspace && \ --verbose \ --with-process-isolation \ --with-doctest \ - --exe + --exe \ + test_membership.py \ + test_caveats.py \ + tests.py diff --git a/Dockerfile-py3.5 b/Dockerfile-py3.5 index daade117..46c5b510 100644 --- a/Dockerfile-py3.5 +++ b/Dockerfile-py3.5 @@ -32,4 +32,6 @@ ENTRYPOINT cp -r /Qt.py /workspace && \ --verbose \ --with-process-isolation \ --with-doctest \ - --exe + --exe \ + test_caveats.py \ + tests.py From cf7140ae9a5922ce713415d9b88659fb727cc892 Mon Sep 17 00:00:00 2001 From: Marcus Ottosson Date: Tue, 30 Aug 2016 07:01:33 +0100 Subject: [PATCH 7/9] Refine membership build --- build_membership.py | 164 ++++++++++++++++++++++---------------------- 1 file changed, 81 insertions(+), 83 deletions(-) diff --git a/build_membership.py b/build_membership.py index e6562245..188e876f 100644 --- a/build_membership.py +++ b/build_membership.py @@ -1,3 +1,4 @@ +import json def build_membership(): @@ -7,7 +8,6 @@ def build_membership(): # In it's __all__ module is a module, `QtOpenGL` # that does no exists. This causes `import *` to fail. - import json from PySide2 import __all__ __all__.remove("QtOpenGL") @@ -50,12 +50,77 @@ def build_tests(): with open("reference_members.json") as f: reference_members = json.load(f) -excluded = { +excluded = {excluded} + +""".format(excluded=json.dumps(excluded, indent=4)) + + test = """\ +def test_{binding}_members(): + os.environ["QT_PREFERRED_BINDING"] = "{Binding}" + + if "PyQt" in "{Binding}": + # PyQt4 and 5 performs some magic here + # that must take place before attempting + # to import with wildcard. + from Qt import Qt as _ + + if "PySide2" == "{Binding}": + # PySide2, as of this writing, doesn't include + # these modules in it's __all__ list; leaving + # the wildcard import below untrue. + from Qt import __all__ + for missing in ("QtWidgets", + "QtXml", + "QtHelp", + "QtPrintSupport"): + __all__.append(missing) + + from Qt import * + + target_members = dict() + for name, module in locals().copy().items(): + if name.startswith("_"): + continue + + target_members[name] = dir(module) + + missing = dict() + for module, members in reference_members.items(): + for member in members: + + # Ignore those that have no Qt 4-equivalent. + if member in excluded.get(module, []): + continue + if member not in target_members.get(module, []): + if module not in missing: + missing[module] = [] + missing[module].append(member) + + message = "" + for module, members in missing.items(): + message += "\\n%s: \\n - %s" % (module, "\\n - ".join(members)) + + assert not missing, "{Binding} is missing members: %s" % message + +""" + + tests = list(test.format(Binding=binding, + binding=binding.lower()) + for binding in ["PyQt5", + "PyQt4", + "PySide"]) + + with open("test_membership.py", "w") as f: + contents = header + "\n".join(tests) + print(contents) # Preview content during tests + f.write(contents) + + +# Don't consider these members +excluded = { "QtCore": [ - # - # From PySide - # + # PySide "Connection", "QBasicMutex", "QFileDevice", @@ -68,9 +133,7 @@ def build_tests(): "QtInfoMsg", "qInstallMessageHandler", - # - # From PyQt4 - # + # PyQt4 "ClassInfo", "MetaFunction", "QFactoryInterface", @@ -93,47 +156,35 @@ def build_tests(): "qTan", "qtTrId", - # - # From PyQt5 - # + # PyQt5 "SIGNAL", "SLOT", ], "QtGui": [ - # - # From PySide - # - "QGuiApplication", + # PySide + "QGuiApplication", # Qt 5-only "QPagedPaintDevice", "QSurface", "QSurfaceFormat", "QTouchDevice", - "QWindow", + "QWindow", # Qt 5-only - # - # From PyQt4 - # + # PyQt4 "QAccessibleEvent", "QToolBarChangeEvent", - # - # From PyQt5 - # + # PyQt5 "QMatrix", "QPyTextObject", "QStringListModel", ], "QtWebKit": [ - # - # From PyQt4 - # + # PyQt4 "WebCore", - # - # From PyQt5 - # + # PyQt5 "__doc__", "__file__", "__name__", @@ -141,17 +192,13 @@ def build_tests(): ], "QtScript": [ - # - # From PyQt4 - # + # PyQt4 "QScriptExtensionInterface", "QScriptExtensionPlugin", "QScriptProgram", "QScriptable", - # - # From PyQt5 - # + # PyQt5 "QScriptClass", "QScriptClassPropertyIterator", "QScriptContext", @@ -168,60 +215,11 @@ def build_tests(): ], "QtNetwork": [ - # # PyQt4 - # "QIPv6Address", ], } -""" - - test = """\ -def test_{binding}_members(): - os.environ["QT_PREFERRED_BINDING"] = "{Binding}" - - from Qt import * - - target_members = dict() - for name, module in locals().copy().items(): - if name.startswith("_"): - continue - - target_members[name] = dir(module) - - missing = dict() - for module, members in reference_members.items(): - for member in members: - - # Ignore those that have no Qt 4-equivalent. - if member in excluded.get(module, []): - continue - - if member not in target_members.get(module, []): - if module not in missing: - missing[module] = [] - missing[module].append(member) - - message = "" - for module, members in missing.items(): - message += "\\n%s: \\n - %s" % (module, "\\n - ".join(members)) - - assert not missing, "{Binding} is missing members: %s" % message - -""" - - tests = list(test.format(Binding=binding, binding=binding.lower()) - for binding in ["PyQt5", - "PyQt4", - "PySide"]) - - with open("test_membership.py", "w") as f: - contents = header + "\n".join(tests) - print(contents) # Preview content during tests - f.write(contents) - - if __name__ == '__main__': build_membership() build_tests() From bcb22a0133f7b6796127830f3630e7a02507732d Mon Sep 17 00:00:00 2001 From: Marcus Ottosson Date: Tue, 30 Aug 2016 07:49:11 +0100 Subject: [PATCH 8/9] Add descriptions to membership test --- build_membership.py | 44 ++++++++++++++++++++++++++++---------------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/build_membership.py b/build_membership.py index 188e876f..32bcb4e8 100644 --- a/build_membership.py +++ b/build_membership.py @@ -43,6 +43,10 @@ def build_tests(): """ header = """\ +# +# AUTOMATICALLY GENERATED MEMBERSHIP TEST, DO NOT MODIFY +# + import os import sys import json @@ -117,10 +121,18 @@ def test_{binding}_members(): f.write(contents) -# Don't consider these members +# Don't consider these members. +# +# Some of these are either: +# 1. Unique to a particular binding +# 2. Unique to Qt 5 +# 3. Not yet included in PySide2 +# +# TODO: Clearly mark which are which. (3) should +# eventually be removed from this dictionary. excluded = { "QtCore": [ - # PySide + # missing from PySide "Connection", "QBasicMutex", "QFileDevice", @@ -133,7 +145,7 @@ def test_{binding}_members(): "QtInfoMsg", "qInstallMessageHandler", - # PyQt4 + # missing from PyQt4 "ClassInfo", "MetaFunction", "QFactoryInterface", @@ -142,8 +154,8 @@ def test_{binding}_members(): "QT_TRANSLATE_NOOP3", "QT_TRANSLATE_NOOP_UTF8", "__moduleShutdown", - "__version__", - "__version_info__", + "__version__", # unique to PyQt + "__version_info__", # unique to PyQt "qAcos", "qAsin", "qAtan", @@ -156,35 +168,35 @@ def test_{binding}_members(): "qTan", "qtTrId", - # PyQt5 + # missing from PyQt5 "SIGNAL", "SLOT", ], "QtGui": [ - # PySide - "QGuiApplication", # Qt 5-only + # missing from PySide + "QGuiApplication", # unique to Qt 5 "QPagedPaintDevice", "QSurface", "QSurfaceFormat", "QTouchDevice", - "QWindow", # Qt 5-only + "QWindow", # unique to Qt 5 - # PyQt4 + # missing from PyQt4 "QAccessibleEvent", "QToolBarChangeEvent", - # PyQt5 + # missing from PyQt5 "QMatrix", "QPyTextObject", "QStringListModel", ], "QtWebKit": [ - # PyQt4 + # missing from PyQt4 "WebCore", - # PyQt5 + # missing from PyQt5 "__doc__", "__file__", "__name__", @@ -192,13 +204,13 @@ def test_{binding}_members(): ], "QtScript": [ - # PyQt4 + # missing from PyQt4 "QScriptExtensionInterface", "QScriptExtensionPlugin", "QScriptProgram", "QScriptable", - # PyQt5 + # missing from PyQt5 "QScriptClass", "QScriptClassPropertyIterator", "QScriptContext", @@ -215,7 +227,7 @@ def test_{binding}_members(): ], "QtNetwork": [ - # PyQt4 + # missing from PyQt4 "QIPv6Address", ], } From 1f7791e26d4bfeba1fd7020213c669e7c8f47059 Mon Sep 17 00:00:00 2001 From: Marcus Ottosson Date: Tue, 30 Aug 2016 08:06:38 +0100 Subject: [PATCH 9/9] Improve membership test, and augment documentation. --- build_membership.py | 112 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 104 insertions(+), 8 deletions(-) diff --git a/build_membership.py b/build_membership.py index 32bcb4e8..b10b81d2 100644 --- a/build_membership.py +++ b/build_membership.py @@ -16,6 +16,23 @@ def build_membership(): __all__.remove("QtSql") __all__.remove("QtSvg") + # These should be present in PySide2, + # but are not as of this writing. + for missing in ("QtWidgets", + "QtXml", + "QtHelp", + "QtPrintSupport"): + __all__.append(missing) + + # Why `import *`? + # + # PySide, and PyQt, perform magic that triggers via Python's + # import mechanism. If we try and sidestep it in any way, say + # by using `imp.load_module` or `__import__`, the mechanism + # will not trigger and the compiled libraries will not get loaded. + # + # Wildcard was the only way I could think of to import everything, + # without hardcoding the members, such as QtCore into the function. from PySide2 import * # Serialise members @@ -24,10 +41,11 @@ def build_membership(): if name.startswith("_"): continue - if name in ("json", "members"): + if name in ("json", "members", "missing"): continue - members[name] = dir(module) + members[name] = list(member for member in dir(module) + if not member.startswith("_")) # Write to disk with open("reference_members.json", "w") as f: @@ -48,7 +66,6 @@ def build_tests(): # import os -import sys import json with open("reference_members.json") as f: @@ -81,6 +98,13 @@ def test_{binding}_members(): from Qt import * + if "PySide" == "{Binding}": + # Qt 4 bindings do not include QtWidgets + # in their __all__ list. And who knows what else. + # + # TODO: This needs a more robust implementation. + from Qt import QtWidgets + target_members = dict() for name, module in locals().copy().items(): if name.startswith("_"): @@ -121,7 +145,7 @@ def test_{binding}_members(): f.write(contents) -# Don't consider these members. +# Do not consider these members. # # Some of these are either: # 1. Unique to a particular binding @@ -154,8 +178,8 @@ def test_{binding}_members(): "QT_TRANSLATE_NOOP3", "QT_TRANSLATE_NOOP_UTF8", "__moduleShutdown", - "__version__", # unique to PyQt - "__version_info__", # unique to PyQt + "__version__", # (2) unique to PyQt + "__version_info__", # (2) unique to PyQt "qAcos", "qAsin", "qAtan", @@ -175,12 +199,12 @@ def test_{binding}_members(): "QtGui": [ # missing from PySide - "QGuiApplication", # unique to Qt 5 + "QGuiApplication", # (2) unique to Qt 5 "QPagedPaintDevice", "QSurface", "QSurfaceFormat", "QTouchDevice", - "QWindow", # unique to Qt 5 + "QWindow", # (2) unique to Qt 5 # missing from PyQt4 "QAccessibleEvent", @@ -230,6 +254,78 @@ def test_{binding}_members(): # missing from PyQt4 "QIPv6Address", ], + + "QtPrintSupport": [ + # PyQt4 + "QAbstractPrintDialog", + "QPageSetupDialog", + "QPrintDialog", + "QPrintEngine", + "QPrintPreviewDialog", + "QPrintPreviewWidget", + "QPrinter", + "QPrinterInfo", + ], + + "QtWidgets": [ + # PyQt4 + "QTileRules", + + # PyQt5 + "QGraphicsItemAnimation", + "QTileRules", + ], + + "QtHelp": [ + # PySide + "QHelpContentItem", + "QHelpContentModel", + "QHelpContentWidget", + "QHelpEngine", + "QHelpEngineCore", + "QHelpIndexModel", + "QHelpIndexWidget", + "QHelpSearchEngine", + "QHelpSearchQuery", + "QHelpSearchQueryWidget", + "QHelpSearchResultWidget", + ], + + "QtXml": [ + # PySide + "QDomAttr", + "QDomCDATASection", + "QDomCharacterData", + "QDomComment", + "QDomDocument", + "QDomDocumentFragment", + "QDomDocumentType", + "QDomElement", + "QDomEntity", + "QDomEntityReference", + "QDomImplementation", + "QDomNamedNodeMap", + "QDomNode", + "QDomNodeList", + "QDomNotation", + "QDomProcessingInstruction", + "QDomText", + "QXmlAttributes", + "QXmlContentHandler", + "QXmlDTDHandler", + "QXmlDeclHandler", + "QXmlDefaultHandler", + "QXmlEntityResolver", + "QXmlErrorHandler", + "QXmlInputSource", + "QXmlLexicalHandler", + "QXmlLocator", + "QXmlNamespaceSupport", + "QXmlParseException", + "QXmlReader", + "QXmlSimpleReader", + ], + } if __name__ == '__main__':