diff options
-rw-r--r-- | sources/pyside2/PySide2/support/signature/loader.py | 40 | ||||
-rw-r--r-- | sources/pyside2/PySide2/support/signature/mapping.py | 102 | ||||
-rw-r--r-- | sources/pyside2/PySide2/support/signature/parser.py | 109 |
3 files changed, 97 insertions, 154 deletions
diff --git a/sources/pyside2/PySide2/support/signature/loader.py b/sources/pyside2/PySide2/support/signature/loader.py index f9c8b5c53..373cc8abe 100644 --- a/sources/pyside2/PySide2/support/signature/loader.py +++ b/sources/pyside2/PySide2/support/signature/loader.py @@ -51,40 +51,26 @@ This version does not use an embedded .zip file. import sys import os -import functools -from contextlib import contextmanager -from distutils import sysconfig - -@contextmanager -def add_path(path): - sys.path.insert(0, path) - yield - sys.path.pop(0) # Make sure that we always have the PySide containing package first. # This is crucial for the mapping during reload in the tests. package_dir = __file__ for _ in "four": package_dir = os.path.dirname(package_dir) -assured_site_packages = functools.partial(add_path, package_dir) - -with assured_site_packages(): - if sys.version_info >= (3,): - from PySide2.support.signature import inspect - from PySide2.support.signature import typing - else: - import inspect - namespace = inspect.__dict__ - from PySide2.support.signature import backport_inspect as inspect - inspect.__dict__.update(namespace) - from PySide2.support.signature import parser -# Note also that during the tests we have a different encodind that would -# break the Python license decorated files without an encoding line. - +sys.path.insert(0, package_dir) +if sys.version_info >= (3,): + from PySide2.support.signature import inspect + from PySide2.support.signature import typing +else: + import inspect + namespace = inspect.__dict__ + from PySide2.support.signature import backport_inspect as inspect + inspect.__dict__.update(namespace) # name used in signature.cpp -def pyside_type_init(*args, **kw): - with assured_site_packages(): - return parser.pyside_type_init(*args, **kw) +from PySide2.support.signature.parser import pyside_type_init +sys.path.pop(0) +# Note also that during the tests we have a different encoding that would +# break the Python license decorated files without an encoding line. # name used in signature.cpp def create_signature(props, sig_kind): diff --git a/sources/pyside2/PySide2/support/signature/mapping.py b/sources/pyside2/PySide2/support/signature/mapping.py index d18ee561b..f6ec9868d 100644 --- a/sources/pyside2/PySide2/support/signature/mapping.py +++ b/sources/pyside2/PySide2/support/signature/mapping.py @@ -55,15 +55,16 @@ See _resolve_value() in singature.py import sys import collections import struct +import PySide2 PY3 = sys.version_info >= (3,) if PY3: from . import typing - exec("ellipsis = ...") + ellipsis = eval("...") Char = typing.Union[str, int] # how do I model the limitation to 1 char? StringList = typing.List[str] Variant = typing.Union[str, int, float, Char, StringList, type(ellipsis)] - # much more, do we need that? + # Much more, do we need that? Do we better kill it? ModelIndexList = typing.List[int] QImageCleanupFunction = typing.Callable[[bytes], None] else: @@ -74,8 +75,8 @@ else: ModelIndexList = list QImageCleanupFunction = object Pair = collections.namedtuple('Pair', ['first', 'second']) -# ulong_max is the long size, which is only 32 bit on windows. -ulong_max = sys.maxsize if len(struct.pack("L", 1)) != 4 else 0xffffffff +# ulong_max is only 32 bit on windows. +ulong_max = 2*sys.maxsize+1 if len(struct.pack("L", 1)) != 4 else 0xffffffff ushort_max = 0xffff GL_COLOR_BUFFER_BIT = 0x00004000 @@ -97,28 +98,27 @@ class Missing(str): def __repr__(self): return "Missing({})".format(self) -TYPE_MAP_DOC = """ - The type_map variable is central for the signature module. - - PySide has a new function 'CppGenerator::writeSignatureInfo()' - that extracts the gathered information about the function arguments - and defaults as good as it can. But what PySide generates is still - very C-ish and has many constants that Python doesn't understand. - - The function 'try_to_guess()' below understands a lot of PySide's - peculiar way to assume local context. If it is able to do the guess, - then the result is inserted into the dict, so the search happens - not again. For everything that is not covered by these automatic - guesses, we provide an entry in 'type_map' that resolves it. - - In effect, 'type_map' maps text to real Python objects. -""" +class Reloader(object): + def __init__(self): + self.sys_module_count = 0 + self.uninitialized = PySide2.__all__[:] + + def update(self): + if self.sys_module_count == len(sys.modules): + return + self.sys_module_count = len(sys.modules) + for mod_name in self.uninitialized[:]: + if "PySide2." + mod_name in sys.modules: + self.uninitialized.remove(mod_name) + proc_name = "init_" + mod_name + if proc_name in globals(): + init_proc = globals()[proc_name] + globals().update(init_proc()) + +update_mapping = Reloader().update type_map = {} -loaded_modules = sys.modules - -# QtCore -if "PySide2.QtCore" in loaded_modules: +def init_QtCore(): import PySide2.QtCore from PySide2.QtCore import Qt, QUrl, QDir, QGenericArgument from PySide2.QtCore import QMarginsF # 5.9 @@ -169,7 +169,7 @@ if "PySide2.QtCore" in loaded_modules: "PyCallable": callable, "...": ellipsis, # no idea how this should be translated... maybe so? "PyTypeObject": type, - "PySequence": list, # could be more generic + "PySequence": list, # needs to be changed, QApplication for instance! "qptrdiff": int, "true": True, "Qt.HANDLE": int, # be more explicit with some consts? @@ -215,7 +215,6 @@ if "PySide2.QtCore" in loaded_modules: "QGenericArgument((0))": None, # 5.6, RHEL 6.6. Is that ok? "4294967295UL": 4294967295, # 5.6, RHEL 6.6 }) - try: type_map.update({ "PySide2.QtCore.QMetaObject.Connection": PySide2.QtCore.Connection, # wrong! @@ -223,9 +222,9 @@ if "PySide2.QtCore" in loaded_modules: except AttributeError: # this does not exist on 5.9 ATM. pass + return locals() -# QtGui -if "PySide2.QtGui" in loaded_modules: +def init_QtGui(): import PySide2.QtGui from PySide2.QtGui import QPageLayout, QPageSize # 5.9 type_map.update({ @@ -244,9 +243,9 @@ if "PySide2.QtGui" in loaded_modules: "QList< QTouchEvent.TouchPoint >()": list, "QPixmap()": lambda:QPixmap(), # we cannot create this without qApp }) + return locals() -# QtWidgets -if "PySide2.QtWidgets" in loaded_modules: +def init_QtWidgets(): import PySide2.QtWidgets from PySide2.QtWidgets import QWidget, QMessageBox, QStyleOption, QStyleHintReturn, QStyleOptionComplex type_map.update({ @@ -263,34 +262,34 @@ if "PySide2.QtWidgets" in loaded_modules: "SH_Default": QStyleHintReturn.SH_Default, "SO_Complex": QStyleOptionComplex.SO_Complex, }) + return locals() -# QtSql -if "PySide2.QtSql" in loaded_modules: +def init_QtSql(): import PySide2.QtSql from PySide2.QtSql import QSqlDatabase type_map.update({ "QLatin1String(defaultConnection)": QSqlDatabase.defaultConnection, "QVariant.Invalid": -1, # not sure what I should create, here... }) + return locals() -# QtNetwork -if "PySide2.QtNetwork" in loaded_modules: +def init_QtNetwork(): import PySide2.QtNetwork type_map.update({ "QMultiMap": typing.DefaultDict(list) if PY3 else {}, }) + return locals() -# QtXmlPatterns -if "PySide2.QtXmlPatterns" in loaded_modules: +def init_QtXmlPatterns(): import PySide2.QtXmlPatterns from PySide2.QtXmlPatterns import QXmlName type_map.update({ "QXmlName.PrefixCode": Missing("PySide2.QtXmlPatterns.QXmlName.PrefixCode"), "QXmlName.NamespaceCode": Missing("PySide2.QtXmlPatterns.QXmlName.NamespaceCode") }) + return locals() -# QtMultimedia -if "PySide2.QtMultimedia" in loaded_modules: +def init_QtMultimedia(): import PySide2.QtMultimedia import PySide2.QtMultimediaWidgets type_map.update({ @@ -298,9 +297,9 @@ if "PySide2.QtMultimedia" in loaded_modules: "QGraphicsVideoItem": PySide2.QtMultimediaWidgets.QGraphicsVideoItem, "QVideoWidget": PySide2.QtMultimediaWidgets.QVideoWidget, }) + return locals() -# QtOpenGL -if "PySide2.QtOpenGL" in loaded_modules: +def init_QtOpenGL(): import PySide2.QtOpenGL type_map.update({ "GLuint": int, @@ -311,9 +310,9 @@ if "PySide2.QtOpenGL" in loaded_modules: "PySide2.QtOpenGL.GLuint": int, "GLfloat": float, # 5.6, MSVC 15 }) + return locals() -# QtQml -if "PySide2.QtQml" in loaded_modules: +def init_QtQml(): import PySide2.QtQml type_map.update({ "QJSValueList()": [], @@ -321,43 +320,46 @@ if "PySide2.QtQml" in loaded_modules: # from 5.9 "QVariantHash()": {}, }) + return locals() -# QtQml -if "PySide2.QtQuick" in loaded_modules: +def init_QtQuick(): import PySide2.QtQuick type_map.update({ "PySide2.QtQuick.QSharedPointer": int, "PySide2.QtCore.uint": int, "T": int, }) + return locals() -# QtScript -if "PySide2.QtScript" in loaded_modules: +def init_QtScript(): import PySide2.QtScript type_map.update({ "QScriptValueList()": [], }) + return locals() -# QtTest -if "PySide2.QtTest" in loaded_modules: +def init_QtTest(): import PySide2.QtTest type_map.update({ "PySide2.QtTest.QTouchEventSequence": PySide2.QtTest.QTest.QTouchEventSequence, }) + return locals() # from 5.9 -if "PySide2.QtWebEngineWidgets" in loaded_modules: +def init_QtWebEngineWidgets(): import PySide2.QtWebEngineWidgets type_map.update({ "PySide2.QtTest.QTouchEventSequence": PySide2.QtTest.QTest.QTouchEventSequence, }) + return locals() # from 5.6, MSVC -if "PySide2.QtWinExtras" in loaded_modules: +def init_QtWinExtras(): import PySide2.QtWinExtras type_map.update({ "QList< QWinJumpListItem* >()": [], }) + return locals() # Here was testbinding, actually the source of all evil. diff --git a/sources/pyside2/PySide2/support/signature/parser.py b/sources/pyside2/PySide2/support/signature/parser.py index 224ea6be8..c944fe856 100644 --- a/sources/pyside2/PySide2/support/signature/parser.py +++ b/sources/pyside2/PySide2/support/signature/parser.py @@ -39,49 +39,33 @@ from __future__ import print_function, absolute_import -""" -signature.py - -This module is the python part of the PySide signature initialization. -It is not for common use and should be called by shiboken's signature.cpp. -It is initially written for Python 3, only. -Meanwhile people say it works with Python 2.7, too. ;-) -""" - import sys import re import warnings import types import keyword import functools - -PY3 = sys.version_info >= (3,) -if PY3: - try: - from importlib import reload - except ImportError: - from imp import reload +from .mapping import type_map, update_mapping, __dict__ as namespace _DEBUG = False _BREAK_ON_ERROR = False -class FakeMapping(object): - """ - We do not import the mapping module directly: +TYPE_MAP_DOC = """ + The type_map variable is central for the signature package. - It is not clear from where the mapping is imported. When for instance - the mapping is imported by a test from the source directory, reload - would now reload from the PySide directory. This is weird and - wasteful. We fake the module instead and load it later. - """ - def __init__(self): - self.type_map = {} + PySide has a new function 'CppGenerator::writeSignatureInfo()' + that extracts the gathered information about the function arguments + and defaults as good as it can. But what PySide generates is still + very C-ish and has many constants that Python doesn't understand. -mapping = FakeMapping() -namespace = mapping.__dict__ + The function 'try_to_guess()' below understands a lot of PySide's + peculiar way to assume local context. If it is able to do the guess, + then the result is inserted into the dict, so the search happens + not again. For everything that is not covered by these automatic + guesses, we provide an entry in 'type_map' that resolves it. -class _empty: - """ marks "no value found". We cannot use None here.""" + In effect, 'type_map' maps text to real Python objects. +""" def dprint(*args, **kw): if _DEBUG: @@ -138,17 +122,17 @@ def _resolve_number(thing): try: return eval(thing, namespace) except Exception: - return _empty + return None def try_to_guess(thing, valtype): res = _resolve_number(thing) - if res is not _empty: + if res is not None: return res if "." not in thing and "(" not in thing: text = "{}.{}".format(valtype, thing) try: return eval(text, namespace) - except Exception as e: + except Exception: pass typewords = valtype.split(".") valwords = thing.split(".") @@ -160,25 +144,23 @@ def try_to_guess(thing, valtype): text = ".".join(typewords[:idx] + valwords) try: return eval(text, namespace) - except Exception as e: + except Exception: pass - return _empty + return None -def _resolve_value_reloaded(thing, valtype, type_map, line, maybe_redo): +def _resolve_value(thing, valtype, line): if thing in type_map: return type_map[thing] try: res = eval(thing, namespace) type_map[thing] = res return res - except Exception as e: + except Exception: pass - res = try_to_guess(thing, valtype) if valtype else _empty - if res is not _empty: + res = try_to_guess(thing, valtype) if valtype else None + if res is not None: type_map[thing] = res return res - if maybe_redo: - return _empty warnings.warn("""pyside_type_init: UNRECOGNIZED: {!r} @@ -190,35 +172,10 @@ def _resolve_value_reloaded(thing, valtype, type_map, line, maybe_redo): raise RuntimeError return thing -def _resolve_value(thing, valtype, type_map, line): - """ - Load a value after eventually reloading. - - If an error occurs, there is maybe a new module imported that we - don't have, yet. Reload the mapping module and try again. - """ - try: - val = _resolve_value_reloaded(thing, valtype, type_map, line, True) - except Exception: - val = _empty - if val is not _empty: - return val - global mapping, namespace - if type(mapping) is not types.ModuleType: - # lazy import - from . import mapping - namespace = mapping.__dict__ - type_map.update(mapping.type_map) - return _resolve_value(thing, valtype, type_map, line) - reload(mapping) - dprint("Matrix reloaded") - type_map.update(mapping.type_map) - return _resolve_value_reloaded(thing, valtype, type_map, line, False) - -def _resolve_type(thing, type_map, line): - return _resolve_value(thing, None, type_map, line) +def _resolve_type(thing, line): + return _resolve_value(thing, None, line) -def calculate_props(line, type_map): +def calculate_props(line): line = line.strip() res = _parse_line(line) arglist = res["arglist"] @@ -226,14 +183,14 @@ def calculate_props(line, type_map): _defaults = [] for tup in arglist: name, ann = tup[:2] - annotations[name] = _resolve_type(ann, type_map, line) + annotations[name] = _resolve_type(ann, line) if len(tup) == 3: - default = _resolve_value(tup[2], ann, type_map, line) + default = _resolve_value(tup[2], ann, line) _defaults.append(default) defaults = tuple(_defaults) returntype = res["returntype"] if returntype is not None: - annotations["return"] = _resolve_type(returntype, type_map, line) + annotations["return"] = _resolve_type(returntype, line) props = {} props["defaults"] = defaults props["kwdefaults"] = {} @@ -246,17 +203,18 @@ def calculate_props(line, type_map): props["multi"] = res["multi"] return props -def pyside_type_init(typemod, sig_str, type_map): +def pyside_type_init(typemod, sig_str): dprint() if type(typemod) is types.ModuleType: dprint("Initialization of module '{}'".format(typemod.__name__)) else: dprint("Initialization of type '{}.{}'".format(typemod.__module__, typemod.__name__)) + update_mapping() ret = {} multi_props = [] for line in sig_str.strip().splitlines(): - props = calculate_props(line, type_map) + props = calculate_props(line) shortname = props["name"] multi = props["multi"] if multi is None: @@ -273,7 +231,4 @@ def pyside_type_init(typemod, sig_str, type_map): multi_props = [] return ret -pyside_type_init = functools.partial(pyside_type_init, - type_map=mapping.type_map) - # end of file |