1############################################################################# 2## 3## Copyright (C) 2019 The Qt Company Ltd. 4## Contact: https://www.qt.io/licensing/ 5## 6## This file is part of Qt for Python. 7## 8## $QT_BEGIN_LICENSE:LGPL$ 9## Commercial License Usage 10## Licensees holding valid commercial Qt licenses may use this file in 11## accordance with the commercial license agreement provided with the 12## Software or, alternatively, in accordance with the terms contained in 13## a written agreement between you and The Qt Company. For licensing terms 14## and conditions see https://www.qt.io/terms-conditions. For further 15## information use the contact form at https://www.qt.io/contact-us. 16## 17## GNU Lesser General Public License Usage 18## Alternatively, this file may be used under the terms of the GNU Lesser 19## General Public License version 3 as published by the Free Software 20## Foundation and appearing in the file LICENSE.LGPL3 included in the 21## packaging of this file. Please review the following information to 22## ensure the GNU Lesser General Public License version 3 requirements 23## will be met: https://www.gnu.org/licenses/lgpl-3.0.html. 24## 25## GNU General Public License Usage 26## Alternatively, this file may be used under the terms of the GNU 27## General Public License version 2.0 or (at your option) the GNU General 28## Public license version 3 or any later version approved by the KDE Free 29## Qt Foundation. The licenses are as published by the Free Software 30## Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 31## included in the packaging of this file. Please review the following 32## information to ensure the GNU General Public License requirements will 33## be met: https://www.gnu.org/licenses/gpl-2.0.html and 34## https://www.gnu.org/licenses/gpl-3.0.html. 35## 36## $QT_END_LICENSE$ 37## 38############################################################################# 39 40from __future__ import print_function, absolute_import 41 42""" 43mapping.py 44 45This module has the mapping from the pyside C-modules view of signatures 46to the Python representation. 47 48The PySide modules are not loaded in advance, but only after they appear 49in sys.modules. This minimizes the loading overhead. 50""" 51 52import sys 53import struct 54import os 55 56from shibokensupport.signature import typing 57from shibokensupport.signature.typing import TypeVar, Generic 58from shibokensupport.signature.lib.tool import with_metaclass 59 60class ellipsis(object): 61 def __repr__(self): 62 return "..." 63 64ellipsis = ellipsis() 65Point = typing.Tuple[float, float] 66Variant = typing.Any 67ModelIndexList = typing.List[int] 68QImageCleanupFunction = typing.Callable 69 70# unfortunately, typing.Optional[t] expands to typing.Union[t, NoneType] 71# Until we can force it to create Optional[t] again, we use this. 72NoneType = type(None) 73 74_S = TypeVar("_S") 75 76MultiMap = typing.DefaultDict[str, typing.List[str]] 77 78# ulong_max is only 32 bit on windows. 79ulong_max = 2*sys.maxsize+1 if len(struct.pack("L", 1)) != 4 else 0xffffffff 80ushort_max = 0xffff 81 82GL_COLOR_BUFFER_BIT = 0x00004000 83GL_NEAREST = 0x2600 84 85WId = int 86 87# from 5.9 88GL_TEXTURE_2D = 0x0DE1 89GL_RGBA = 0x1908 90 91 92class _NotCalled(str): 93 """ 94 Wrap some text with semantics 95 96 This class is wrapped around text in order to avoid calling it. 97 There are three reasons for this: 98 99 - some instances cannot be created since they are abstract, 100 - some can only be created after qApp was created, 101 - some have an ugly __repr__ with angle brackets in it. 102 103 By using derived classes, good looking instances can be created 104 which can be used to generate source code or .pyi files. When the 105 real object is needed, the wrapper can simply be called. 106 """ 107 def __repr__(self): 108 return "{}({})".format(type(self).__name__, self) 109 110 def __call__(self): 111 from shibokensupport.signature.mapping import __dict__ as namespace 112 text = self if self.endswith(")") else self + "()" 113 return eval(text, namespace) 114 115USE_PEP563 = False 116# Note: we cannot know if this feature has been imported. 117# Otherwise it would be "sys.version_info[:2] >= (3, 7)". 118# We *can* eventually inspect sys.modules and look if 119# the calling module has this future statement set, 120# but should we do that? 121 122 123# Some types are abstract. They just show their name. 124class Virtual(_NotCalled): 125 pass 126 127# Other types I simply could not find. 128class Missing(_NotCalled): 129 # The string must be quoted, because the object does not exist. 130 def __repr__(self): 131 if USE_PEP563: 132 return _NotCalled.__repr__(self) 133 return '{}("{}")'.format(type(self).__name__, self) 134 135 136class Invalid(_NotCalled): 137 pass 138 139# Helper types 140class Default(_NotCalled): 141 pass 142 143 144class Instance(_NotCalled): 145 pass 146 147# Parameterized primitive variables 148class _Parameterized(object): 149 def __init__(self, type): 150 self.type = type 151 self.__name__ = self.__class__.__name__ 152 153 def __repr__(self): 154 return "{}({})".format( 155 type(self).__name__, self.type.__name__) 156 157# Mark the primitive variables to be moved into the result. 158class ResultVariable(_Parameterized): 159 pass 160 161# Mark the primitive variables to become Sequence, Iterable or List 162# (decided in the parser). 163class ArrayLikeVariable(_Parameterized): 164 pass 165 166StringList = ArrayLikeVariable(str) 167 168 169class Reloader(object): 170 """ 171 Reloder class 172 173 This is a singleton class which provides the update function for the 174 shiboken and PySide classes. 175 """ 176 def __init__(self): 177 self.sys_module_count = 0 178 179 @staticmethod 180 def module_valid(mod): 181 if getattr(mod, "__file__", None) and not os.path.isdir(mod.__file__): 182 ending = os.path.splitext(mod.__file__)[-1] 183 return ending not in (".py", ".pyc", ".pyo", ".pyi") 184 return False 185 186 def update(self): 187 """ 188 'update' imports all binary modules which are already in sys.modules. 189 The reason is to follow all user imports without introducing new ones. 190 This function is called by pyside_type_init to adapt imports 191 when the number of imported modules has changed. 192 """ 193 if self.sys_module_count == len(sys.modules): 194 return 195 self.sys_module_count = len(sys.modules) 196 g = globals() 197 # PYSIDE-1009: Try to recognize unknown modules in errorhandler.py 198 candidates = list(mod_name for mod_name in sys.modules.copy() 199 if self.module_valid(sys.modules[mod_name])) 200 for mod_name in candidates: 201 # 'top' is PySide2 when we do 'import PySide.QtCore' 202 # or Shiboken if we do 'import Shiboken'. 203 # Convince yourself that these two lines below have the same 204 # global effect as "import Shiboken" or "import PySide2.QtCore". 205 top = __import__(mod_name) 206 g[top.__name__] = top 207 proc_name = "init_" + mod_name.replace(".", "_") 208 if proc_name in g: 209 # Modules are in place, we can update the type_map. 210 g.update(g.pop(proc_name)()) 211 212 213def check_module(mod): 214 # During a build, there exist the modules already as directories, 215 # although the '*.so' was not yet created. This causes a problem 216 # in Python 3, because it accepts folders as namespace modules 217 # without enforcing an '__init__.py'. 218 if not Reloader.module_valid(mod): 219 mod_name = mod.__name__ 220 raise ImportError("Module '{mod_name}' is not a binary module!" 221 .format(**locals())) 222 223update_mapping = Reloader().update 224type_map = {} 225namespace = globals() # our module's __dict__ 226 227type_map.update({ 228 "...": ellipsis, 229 "bool": bool, 230 "char": int, 231 "char*": str, 232 "char*const": str, 233 "double": float, 234 "float": float, 235 "int": int, 236 "List": ArrayLikeVariable, 237 "long": int, 238 "PyCallable": typing.Callable, 239 "PyObject": object, 240 "PySequence": typing.Iterable, # important for numpy 241 "PyTypeObject": type, 242 "QChar": str, 243 "QHash": typing.Dict, 244 "qint16": int, 245 "qint32": int, 246 "qint64": int, 247 "qint8": int, 248 "qintptr": int, 249 "QList": ArrayLikeVariable, 250 "qlonglong": int, 251 "QMap": typing.Dict, 252 "QPair": typing.Tuple, 253 "qptrdiff": int, 254 "qreal": float, 255 "QSet": typing.Set, 256 "QString": str, 257 "QStringList": StringList, 258 "quint16": int, 259 "quint32": int, 260 "quint32": int, 261 "quint64": int, 262 "quint8": int, 263 "quintptr": int, 264 "qulonglong": int, 265 "QVariant": Variant, 266 "QVector": typing.List, 267 "QSharedPointer": typing.Tuple, 268 "real": float, 269 "short": int, 270 "signed char": int, 271 "signed long": int, 272 "std.list": typing.List, 273 "std.map": typing.Dict, 274 "std.pair": typing.Tuple, 275 "std.vector": typing.List, 276 "str": str, 277 "true": True, 278 "Tuple": typing.Tuple, 279 "uchar": int, 280 "uchar*": str, 281 "uint": int, 282 "ulong": int, 283 "ULONG_MAX": ulong_max, 284 "unsigned char": int, # 5.9 285 "unsigned char*": str, 286 "unsigned int": int, 287 "unsigned long int": int, # 5.6, RHEL 6.6 288 "unsigned long long": int, 289 "unsigned long": int, 290 "unsigned short int": int, # 5.6, RHEL 6.6 291 "unsigned short": int, 292 "Unspecified": None, 293 "ushort": int, 294 "void": int, # be more specific? 295 "WId": WId, 296 "zero(bytes)": b"", 297 "zero(Char)": 0, 298 "zero(float)": 0, 299 "zero(int)": 0, 300 "zero(object)": None, 301 "zero(str)": "", 302 "zero(typing.Any)": None, 303 }) 304 305type_map.update({ 306 # Handling variables declared as array: 307 "array double*" : ArrayLikeVariable(float), 308 "array float*" : ArrayLikeVariable(float), 309 "array GLint*" : ArrayLikeVariable(int), 310 "array GLuint*" : ArrayLikeVariable(int), 311 "array int*" : ArrayLikeVariable(int), 312 "array long long*" : ArrayLikeVariable(int), 313 "array long*" : ArrayLikeVariable(int), 314 "array short*" : ArrayLikeVariable(int), 315 "array signed char*" : bytes, 316 "array unsigned char*" : bytes, 317 "array unsigned int*" : ArrayLikeVariable(int), 318 "array unsigned short*" : ArrayLikeVariable(int), 319 }) 320 321type_map.update({ 322 # Special cases: 323 "char*" : bytes, 324 "QChar*" : bytes, 325 "quint32*" : int, # only for QRandomGenerator 326 "quint8*" : bytearray, # only for QCborStreamReader and QCborValue 327 "uchar*" : bytes, 328 "unsigned char*": bytes, 329 }) 330 331type_map.update({ 332 # Handling variables that are returned, eventually as Tuples: 333 "bool*" : ResultVariable(bool), 334 "float*" : ResultVariable(float), 335 "int*" : ResultVariable(int), 336 "long long*" : ResultVariable(int), 337 "long*" : ResultVariable(int), 338 "PStr*" : ResultVariable(str), # module sample 339 "qint32*" : ResultVariable(int), 340 "qint64*" : ResultVariable(int), 341 "qreal*" : ResultVariable(float), 342 "QString*" : ResultVariable(str), 343 "quint16*" : ResultVariable(int), 344 "uint*" : ResultVariable(int), 345 "unsigned int*" : ResultVariable(int), 346 "QStringList*" : ResultVariable(StringList), 347 }) 348 349# PYSIDE-1328: We need to handle "self" explicitly. 350type_map.update({ 351 "self" : "self", 352 }) 353 354 355# The Shiboken Part 356def init_Shiboken(): 357 type_map.update({ 358 "PyType": type, 359 "shiboken2.bool": bool, 360 "size_t": int, 361 }) 362 return locals() 363 364 365def init_minimal(): 366 type_map.update({ 367 "MinBool": bool, 368 }) 369 return locals() 370 371 372def init_sample(): 373 import datetime 374 type_map.update({ 375 "char": int, 376 "char**": typing.List[str], 377 "Complex": complex, 378 "double": float, 379 "Foo.HANDLE": int, 380 "HANDLE": int, 381 "Null": None, 382 "nullptr": None, 383 "ObjectType.Identifier": Missing("sample.ObjectType.Identifier"), 384 "OddBool": bool, 385 "PStr": str, 386 "PyDate": datetime.date, 387 "sample.bool": bool, 388 "sample.char": int, 389 "sample.double": float, 390 "sample.int": int, 391 "sample.ObjectType": object, 392 "sample.OddBool": bool, 393 "sample.Photon.TemplateBase[Photon.DuplicatorType]": sample.Photon.ValueDuplicator, 394 "sample.Photon.TemplateBase[Photon.IdentityType]": sample.Photon.ValueIdentity, 395 "sample.Point": Point, 396 "sample.PStr": str, 397 "sample.unsigned char": int, 398 "std.size_t": int, 399 "std.string": str, 400 "ZeroIn": 0, 401 'Str("<unk")': "<unk", 402 'Str("<unknown>")': "<unknown>", 403 'Str("nown>")': "nown>", 404 }) 405 return locals() 406 407 408def init_other(): 409 import numbers 410 type_map.update({ 411 "other.ExtendsNoImplicitConversion": Missing("other.ExtendsNoImplicitConversion"), 412 "other.Number": numbers.Number, 413 }) 414 return locals() 415 416 417def init_smart(): 418 # This missing type should be defined in module smart. We cannot set it to Missing() 419 # because it is a container type. Therefore, we supply a surrogate: 420 global SharedPtr 421 class SharedPtr(Generic[_S]): 422 __module__ = "smart" 423 smart.SharedPtr = SharedPtr 424 type_map.update({ 425 "smart.Smart.Integer2": int, 426 }) 427 return locals() 428 429 430# The PySide Part 431def init_PySide2_QtCore(): 432 from PySide2.QtCore import Qt, QUrl, QDir 433 from PySide2.QtCore import QRect, QSize, QPoint, QLocale, QByteArray 434 from PySide2.QtCore import QMarginsF # 5.9 435 try: 436 # seems to be not generated by 5.9 ATM. 437 from PySide2.QtCore import Connection 438 except ImportError: 439 pass 440 type_map.update({ 441 "' '": " ", 442 "'%'": "%", 443 "'g'": "g", 444 "4294967295UL": 4294967295, # 5.6, RHEL 6.6 445 "CheckIndexOption.NoOption": Instance( 446 "PySide2.QtCore.QAbstractItemModel.CheckIndexOptions.NoOption"), # 5.11 447 "DescriptorType(-1)": int, # Native handle of QSocketDescriptor 448 "false": False, 449 "list of QAbstractAnimation": typing.List[PySide2.QtCore.QAbstractAnimation], 450 "list of QAbstractState": typing.List[PySide2.QtCore.QAbstractState], 451 "long long": int, 452 "NULL": None, # 5.6, MSVC 453 "nullptr": None, # 5.9 454 "PyByteArray": bytearray, 455 "PyBytes": bytes, 456 "QDeadlineTimer(QDeadlineTimer.Forever)": Instance("PySide2.QtCore.QDeadlineTimer"), 457 "PySide2.QtCore.QUrl.ComponentFormattingOptions": 458 PySide2.QtCore.QUrl.ComponentFormattingOption, # mismatch option/enum, why??? 459 "PyUnicode": typing.Text, 460 "Q_NULLPTR": None, 461 "QDir.Filters(AllEntries | NoDotAndDotDot)": Instance( 462 "QDir.Filters(QDir.AllEntries | QDir.NoDotAndDotDot)"), 463 "QDir.SortFlags(Name | IgnoreCase)": Instance( 464 "QDir.SortFlags(QDir.Name | QDir.IgnoreCase)"), 465 "QGenericArgument((0))": ellipsis, # 5.6, RHEL 6.6. Is that ok? 466 "QGenericArgument()": ellipsis, 467 "QGenericArgument(0)": ellipsis, 468 "QGenericArgument(NULL)": ellipsis, # 5.6, MSVC 469 "QGenericArgument(nullptr)": ellipsis, # 5.10 470 "QGenericArgument(Q_NULLPTR)": ellipsis, 471 "QJsonObject": typing.Dict[str, PySide2.QtCore.QJsonValue], 472 "QModelIndex()": Invalid("PySide2.QtCore.QModelIndex"), # repr is btw. very wrong, fix it?! 473 "QModelIndexList": ModelIndexList, 474 "QModelIndexList": ModelIndexList, 475 "QString()": "", 476 "QStringList()": [], 477 "QStringRef": str, 478 "QStringRef": str, 479 "Qt.HANDLE": int, # be more explicit with some constants? 480 "QUrl.FormattingOptions(PrettyDecoded)": Instance( 481 "QUrl.FormattingOptions(QUrl.PrettyDecoded)"), 482 "QVariant()": Invalid(Variant), 483 "QVariant.Type": type, # not so sure here... 484 "QVariantMap": typing.Dict[str, Variant], 485 "QVariantMap": typing.Dict[str, Variant], 486 }) 487 try: 488 type_map.update({ 489 "PySide2.QtCore.QMetaObject.Connection": PySide2.QtCore.Connection, # wrong! 490 }) 491 except AttributeError: 492 # this does not exist on 5.9 ATM. 493 pass 494 return locals() 495 496 497def init_PySide2_QtConcurrent(): 498 type_map.update({ 499 "PySide2.QtCore.QFuture[QString]": 500 PySide2.QtConcurrent.QFutureQString, 501 "PySide2.QtCore.QFuture[void]": 502 PySide2.QtConcurrent.QFutureVoid, 503 }) 504 return locals() 505 506 507def init_PySide2_QtGui(): 508 from PySide2.QtGui import QPageLayout, QPageSize # 5.12 macOS 509 type_map.update({ 510 "0.0f": 0.0, 511 "1.0f": 1.0, 512 "GL_COLOR_BUFFER_BIT": GL_COLOR_BUFFER_BIT, 513 "GL_NEAREST": GL_NEAREST, 514 "int32_t": int, 515 "QPixmap()": Default("PySide2.QtGui.QPixmap"), # can't create without qApp 516 "QPlatformSurface*": int, # a handle 517 "QVector< QTextLayout.FormatRange >()": [], # do we need more structure? 518 "uint32_t": int, 519 "uint8_t": int, 520 "USHRT_MAX": ushort_max, 521 }) 522 return locals() 523 524 525def init_PySide2_QtWidgets(): 526 from PySide2.QtWidgets import QWidget, QMessageBox, QStyleOption, QStyleHintReturn, QStyleOptionComplex 527 from PySide2.QtWidgets import QGraphicsItem, QStyleOptionGraphicsItem # 5.9 528 type_map.update({ 529 "QMessageBox.StandardButtons(Yes | No)": Instance( 530 "QMessageBox.StandardButtons(QMessageBox.Yes | QMessageBox.No)"), 531 "QWidget.RenderFlags(DrawWindowBackground | DrawChildren)": Instance( 532 "QWidget.RenderFlags(QWidget.DrawWindowBackground | QWidget.DrawChildren)"), 533 "SH_Default": QStyleHintReturn.SH_Default, 534 "SO_Complex": QStyleOptionComplex.SO_Complex, 535 "SO_Default": QStyleOption.SO_Default, 536 "static_cast<Qt.MatchFlags>(Qt.MatchExactly|Qt.MatchCaseSensitive)": Instance( 537 "Qt.MatchFlags(Qt.MatchExactly | Qt.MatchCaseSensitive)"), 538 "Type": PySide2.QtWidgets.QListWidgetItem.Type, 539 }) 540 return locals() 541 542 543def init_PySide2_QtSql(): 544 from PySide2.QtSql import QSqlDatabase 545 type_map.update({ 546 "QLatin1String(defaultConnection)": QSqlDatabase.defaultConnection, 547 "QVariant.Invalid": Invalid("Variant"), # not sure what I should create, here... 548 }) 549 return locals() 550 551 552def init_PySide2_QtNetwork(): 553 from PySide2.QtNetwork import QNetworkRequest 554 best_structure = typing.OrderedDict if getattr(typing, "OrderedDict", None) else typing.Dict 555 type_map.update({ 556 "QMultiMap[PySide2.QtNetwork.QSsl.AlternativeNameEntryType, QString]": 557 best_structure[PySide2.QtNetwork.QSsl.AlternativeNameEntryType, typing.List[str]], 558 "DefaultTransferTimeoutConstant": 559 QNetworkRequest.TransferTimeoutConstant, 560 "QNetworkRequest.DefaultTransferTimeoutConstant": 561 QNetworkRequest.TransferTimeoutConstant, 562 }) 563 del best_structure 564 return locals() 565 566 567def init_PySide2_QtXmlPatterns(): 568 from PySide2.QtXmlPatterns import QXmlName 569 type_map.update({ 570 "QXmlName.NamespaceCode": Missing("PySide2.QtXmlPatterns.QXmlName.NamespaceCode"), 571 "QXmlName.PrefixCode": Missing("PySide2.QtXmlPatterns.QXmlName.PrefixCode"), 572 }) 573 return locals() 574 575 576def init_PySide2_QtMultimedia(): 577 import PySide2.QtMultimediaWidgets 578 # Check if foreign import is valid. See mapping.py in shiboken2. 579 check_module(PySide2.QtMultimediaWidgets) 580 type_map.update({ 581 "QGraphicsVideoItem": PySide2.QtMultimediaWidgets.QGraphicsVideoItem, 582 "qint64": int, 583 "QVideoWidget": PySide2.QtMultimediaWidgets.QVideoWidget, 584 }) 585 return locals() 586 587 588def init_PySide2_QtOpenGL(): 589 type_map.update({ 590 "GLbitfield": int, 591 "GLenum": int, 592 "GLfloat": float, # 5.6, MSVC 15 593 "GLint": int, 594 "GLuint": int, 595 }) 596 return locals() 597 598 599def init_PySide2_QtQml(): 600 type_map.update({ 601 "QJSValueList()": [], 602 "QVariantHash()": typing.Dict[str, Variant], # from 5.9 603 }) 604 return locals() 605 606 607def init_PySide2_QtQuick(): 608 type_map.update({ 609 "PySide2.QtQuick.QSharedPointer[PySide2.QtQuick.QQuickItemGrabResult]": 610 PySide2.QtQuick.QQuickItemGrabResult, 611 "UnsignedShortType": int, 612 }) 613 return locals() 614 615 616def init_PySide2_QtScript(): 617 type_map.update({ 618 "QScriptValueList()": [], 619 }) 620 return locals() 621 622 623def init_PySide2_QtTest(): 624 type_map.update({ 625 "PySide2.QtTest.QTest.PySideQTouchEventSequence": PySide2.QtTest.QTest.QTouchEventSequence, 626 "PySide2.QtTest.QTouchEventSequence": PySide2.QtTest.QTest.QTouchEventSequence, 627 }) 628 return locals() 629 630# from 5.6, MSVC 631def init_PySide2_QtWinExtras(): 632 type_map.update({ 633 "QList< QWinJumpListItem* >()": [], 634 }) 635 return locals() 636 637# from 5.12, macOS 638def init_PySide2_QtDataVisualization(): 639 from PySide2.QtDataVisualization import QtDataVisualization 640 QtDataVisualization.QBarDataRow = typing.List[QtDataVisualization.QBarDataItem] 641 QtDataVisualization.QBarDataArray = typing.List[QtDataVisualization.QBarDataRow] 642 QtDataVisualization.QSurfaceDataRow = typing.List[QtDataVisualization.QSurfaceDataItem] 643 QtDataVisualization.QSurfaceDataArray = typing.List[QtDataVisualization.QSurfaceDataRow] 644 type_map.update({ 645 "100.0f": 100.0, 646 "QtDataVisualization.QBarDataArray": QtDataVisualization.QBarDataArray, 647 "QtDataVisualization.QBarDataArray*": QtDataVisualization.QBarDataArray, 648 "QtDataVisualization.QSurfaceDataArray": QtDataVisualization.QSurfaceDataArray, 649 "QtDataVisualization.QSurfaceDataArray*": QtDataVisualization.QSurfaceDataArray, 650 }) 651 return locals() 652 653 654def init_testbinding(): 655 type_map.update({ 656 "testbinding.PySideCPP2.TestObjectWithoutNamespace": testbinding.TestObjectWithoutNamespace, 657 }) 658 return locals() 659 660# end of file 661