1# This is the PyQt5 build script. 2# 3# Copyright (c) 2021 Riverbank Computing Limited <info@riverbankcomputing.com> 4# 5# This file is part of PyQt5. 6# 7# This file may be used under the terms of the GNU General Public License 8# version 3.0 as published by the Free Software Foundation and appearing in 9# the file LICENSE included in the packaging of this file. Please review the 10# following information to ensure the GNU General Public License version 3.0 11# requirements will be met: http://www.gnu.org/copyleft/gpl.html. 12# 13# If you do not wish to use this file under the terms of the GPL version 3.0 14# then you may purchase a commercial license. For more information contact 15# info@riverbankcomputing.com. 16# 17# This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE 18# WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 19 20 21import glob 22import os 23import sys 24 25from pyqtbuild import PyQtBindings, PyQtProject, QmakeTargetInstallable 26from sipbuild import (Buildable, BuildableModule, Installable, Option, 27 UserException) 28 29 30class PyQt(PyQtProject): 31 """ The PyQt5 project. """ 32 33 def __init__(self): 34 """ Initialise the project. """ 35 36 super().__init__(dunder_init=True, tag_prefix='Qt', 37 console_scripts=[ 38 'pylupdate5 = PyQt5.pylupdate_main:main', 39 'pyrcc5 = PyQt5.pyrcc_main:main', 40 'pyuic5 = PyQt5.uic.pyuic:main']) 41 42 # Each set of bindings must appear after any set they depend on. 43 self.bindings_factories = [Qt, QtCore, QtNetwork, QtGui, QtWidgets, 44 QtQml, QAxContainer, QtAndroidExtras, QtBluetooth, QtDBus, 45 QtDesigner, Enginio, QtHelp, QtMacExtras, QtMultimedia, 46 QtMultimediaWidgets, QtNfc, QtOpenGL, QtPositioning, QtLocation, 47 QtPrintSupport, QtQuick, QtQuick3D, QtQuickWidgets, 48 QtRemoteObjects, QtSensors, QtSerialPort, QtSql, QtSvg, QtTest, 49 QtTextToSpeech, QtWebChannel, QtWebKit, QtWebKitWidgets, 50 QtWebSockets, QtWinExtras, QtX11Extras, QtXml, QtXmlPatterns, 51 _QOpenGLFunctions_2_0, _QOpenGLFunctions_2_1, 52 _QOpenGLFunctions_4_1_Core, _QOpenGLFunctions_ES2, pylupdate, 53 pyrcc] 54 55 def apply_user_defaults(self, tool): 56 """ Set default values where needed. """ 57 58 if self.license_dir is None: 59 self.license_dir = os.path.join(self.root_dir, 'sip') 60 else: 61 self.license_dir = os.path.abspath(self.license_dir) 62 63 super().apply_user_defaults(tool) 64 65 if not self.tools: 66 self.console_scripts = [] 67 68 def get_dunder_init(self): 69 """ Return the contents of the __init__.py file to install. """ 70 71 with open(os.path.join(self.root_dir, '__init__.py')) as f: 72 dunder_init = f.read() 73 74 if self.py_platform == 'win32': 75 dunder_init += """ 76 77def find_qt(): 78 import os, sys 79 80 qtcore_dll = '\\\\Qt5Core.dll' 81 82 dll_dir = os.path.dirname(sys.executable) 83 if not os.path.isfile(dll_dir + qtcore_dll): 84 path = os.environ['PATH'] 85 86 dll_dir = os.path.dirname(__file__) + '\\\\Qt5\\\\bin' 87 if os.path.isfile(dll_dir + qtcore_dll): 88 path = dll_dir + ';' + path 89 os.environ['PATH'] = path 90 else: 91 for dll_dir in path.split(';'): 92 if os.path.isfile(dll_dir + qtcore_dll): 93 break 94 else: 95 return 96 97 try: 98 os.add_dll_directory(dll_dir) 99 except AttributeError: 100 pass 101 102 103find_qt() 104del find_qt 105""" 106 107 return dunder_init 108 109 def get_options(self): 110 """ Return the sequence of configurable options. """ 111 112 # Get the standard options. 113 options = super().get_options() 114 115 # Add our new options. 116 options.append( 117 Option('confirm_license', option_type=bool, 118 help="confirm acceptance of the license")) 119 120 options.append( 121 Option('license_dir', option_type=str, 122 help="the license file can be found in DIR", 123 metavar="DIR")) 124 125 options.append( 126 Option('qt_shared', option_type=bool, 127 help="assume Qt has been built as shared libraries")) 128 129 options.append( 130 Option('designer_plugin', option_type=bool, inverted=True, 131 help="disable the building of the Python plugin for Qt Designer")) 132 133 options.append( 134 Option('qml_plugin', option_type=bool, inverted=True, 135 help="disable the building of the Python plugin for qmlscene")) 136 137 options.append( 138 Option('dbus', option_type=str, 139 help="the directory containing the dbus/dbus-python.h file", 140 metavar="DIR")) 141 142 options.append( 143 Option('dbus_python', option_type=bool, inverted=True, 144 help="disable the Qt support for the dbus-python package")) 145 146 options.append( 147 Option('tools', option_type=bool, inverted=True, 148 help="disable the building of pyuic5, pyrcc5 and pylupdate5")) 149 150 return options 151 152 def update(self, tool): 153 """ Update the configuration. """ 154 155 if tool not in Option.BUILD_TOOLS: 156 return 157 158 # Check we support the version of Qt. 159 if self.builder.qt_version >> 16 != 5: 160 raise UserException( 161 "Qt v5 is required, not v{0}".format( 162 self.builder.qt_version_str)) 163 164 # Automatically confirm the license if there might not be a command 165 # line option to do so. 166 if tool == 'pep517': 167 self.confirm_license = True 168 169 self._check_license() 170 171 # Handle the platform tag (allowing for win32-g++). 172 if self.py_platform.startswith('win32'): 173 plattag = 'WS_WIN' 174 elif self.py_platform == 'darwin': 175 plattag = 'WS_MACX' 176 else: 177 plattag = 'WS_X11' 178 179 self.bindings['QtCore'].tags.append(plattag) 180 181 # Make sure the bindings are buildable. 182 super().update(tool) 183 184 # PyQtWebEngine needs to know if QtWebChannel is available. 185 if 'QtWebChannel' not in self.bindings: 186 qtcore = self.bindings.get('QtCore') 187 if qtcore is not None: 188 qtcore.disabled_features.append('PyQt_WebChannel') 189 190 # Add the composite module. 191 if 'Qt' in self.bindings: 192 self._add_composite_module(tool) 193 194 # Always install the uic module. 195 installable = Installable('uic', target_subdir='PyQt5') 196 installable.files.append(os.path.join(self.root_dir, 'pyuic', 'uic')) 197 self.installables.append(installable) 198 199 # If any set of bindings is being built as a debug version then assume 200 # the plugins and DBus support should as well. 201 for bindings in self.bindings.values(): 202 if bindings.debug: 203 others_debug = True 204 break 205 else: 206 others_debug = self.py_debug 207 208 # Add the plugins. For the moment we don't include them in wheels. 209 # This may change when we improve the bundling of Qt. 210 if tool in ('build', 'install'): 211 if self.designer_plugin and 'QtDesigner' in self.bindings: 212 self._add_plugin('designer', "Qt Designer", 'pyqt5', 213 'designer', others_debug) 214 215 if self.qml_plugin and 'QtQml' in self.bindings: 216 self._add_plugin('qmlscene', "qmlscene", 'pyqt5qmlplugin', 217 'PyQt5', others_debug) 218 219 # Add the dbus-python support. 220 if self.dbus_python: 221 self._add_dbus(others_debug) 222 223 def _add_composite_module(self, tool): 224 """ Add the bindings for the composite module. """ 225 226 sip_file = os.path.join(self.build_dir, 'Qt.sip') 227 sip_f = self.open_for_writing(sip_file) 228 229 sip_f.write('''%CompositeModule PyQt5.Qt 230 231''') 232 233 for bindings in self.bindings.values(): 234 if not bindings.internal: 235 sip_f.write( 236 '%Include {}\n'.format( 237 bindings.sip_file.replace('\\', '/'))) 238 239 sip_f.close() 240 241 self.bindings['Qt'].sip_file = sip_file 242 243 def _add_dbus(self, debug): 244 """ Add the dbus-python support. """ 245 246 self.progress( 247 "Checking to see if the dbus-python support should be built") 248 249 # See if dbus-python is installed. 250 try: 251 import dbus.mainloop 252 except ImportError: 253 self.progress( 254 "The dbus-python package does not seem to be installed.") 255 return 256 257 dbus_module_dir = dbus.mainloop.__path__[0] 258 259 # Get the flags for the DBus library. 260 dbus_inc_dirs = [] 261 dbus_lib_dirs = [] 262 dbus_libs = [] 263 264 args = ['pkg-config', '--cflags-only-I', '--libs dbus-1'] 265 266 for line in self.read_command_pipe(args, fatal=False): 267 for flag in line.strip().split(): 268 if flag.startswith('-I'): 269 dbus_inc_dirs.append(flag[2:]) 270 elif flag.startswith('-L'): 271 dbus_lib_dirs.append(flag[2:]) 272 elif flag.startswith('-l'): 273 dbus_libs.append(flag[2:]) 274 275 if not any([dbus_inc_dirs, dbus_lib_dirs, dbus_libs]): 276 self.progress("DBus v1 does not seem to be installed.") 277 278 # Try and find dbus-python.h. The current PyPI package doesn't install 279 # it. We look where DBus itself is installed. 280 if self.dbus: 281 dbus_inc_dirs.append(self.dbus) 282 283 for d in dbus_inc_dirs: 284 if os.path.isfile(os.path.join(d, 'dbus', 'dbus-python.h')): 285 break 286 else: 287 self.progress( 288 "dbus/dbus-python.h could not be found and so the " 289 "dbus-python support module will be disabled. If " 290 "dbus-python is installed then use the --dbus argument to " 291 "explicitly specify the directory containing " 292 "dbus/dbus-python.h.") 293 return 294 295 # Create the buildable. 296 sources_dir = os.path.join(self.root_dir, 'dbus') 297 298 buildable = BuildableModule(self, 'dbus', 'dbus.mainloop.pyqt5', 299 uses_limited_api=True) 300 buildable.builder_settings.append('QT -= gui') 301 buildable.sources.extend(glob.glob(os.path.join(sources_dir, '*.cpp'))) 302 buildable.headers.extend(glob.glob(os.path.join(sources_dir, '*.h'))) 303 buildable.include_dirs.extend(dbus_inc_dirs) 304 buildable.library_dirs.extend(dbus_lib_dirs) 305 buildable.libraries.extend(dbus_libs) 306 buildable.debug = debug 307 308 self.buildables.append(buildable) 309 310 def _add_plugin(self, name, user_name, target_name, target_subdir, debug): 311 """ Add a plugin to the project buildables. """ 312 313 builder = self.builder 314 315 # Check we have a shared interpreter library. 316 if not self.py_pylib_shlib: 317 self.progress("The {0} plugin was disabled because a shared Python library couldn't be found.".format(user_name)) 318 return 319 320 # Where the plugin will (eventually) be installed. 321 target_plugin_dir = os.path.join( 322 builder.qt_configuration['QT_INSTALL_PLUGINS'], target_subdir) 323 324 # Create the buildable and add it to the builder. 325 buildable = Buildable(self, name) 326 self.buildables.append(buildable) 327 328 # The platform-specific name of the plugin file. 329 if self.py_platform == 'win32': 330 target_name = target_name + '.dll' 331 elif self.py_platform == 'darwin': 332 target_name = 'lib' + target_name + '.dylib' 333 else: 334 target_name = 'lib' + target_name + '.so' 335 336 # Create the corresponding installable. 337 installable = QmakeTargetInstallable(target_name, target_plugin_dir) 338 buildable.installables.append(installable) 339 340 # Create the .pro file. 341 self.progress( 342 "Generating the {0} plugin .pro file".format(user_name)) 343 344 root_plugin_dir = os.path.join(self.root_dir, name) 345 346 with open(os.path.join(root_plugin_dir, name + '.pro-in')) as f: 347 prj = f.read() 348 349 prj = prj.replace('@QTCONFIG@', 'debug' if debug else 'release') 350 prj = prj.replace('@PYINCDIR@', 351 builder.qmake_quote(self.py_include_dir)) 352 prj = prj.replace('@SIPINCDIR@', builder.qmake_quote(self.build_dir)) 353 prj = prj.replace('@PYLINK@', 354 '-L{} -l{}'.format(self.py_pylib_dir, self.py_pylib_lib)) 355 prj = prj.replace('@PYSHLIB@', self.py_pylib_shlib) 356 prj = prj.replace('@QTPLUGINDIR@', 357 builder.qmake_quote(target_plugin_dir)) 358 359 # Write the .pro file. 360 pro_path = os.path.join(buildable.build_dir, name + '.pro') 361 pro_f = self.open_for_writing(pro_path) 362 363 pro_f.write(prj) 364 365 pro_f.write(''' 366INCLUDEPATH += {} 367VPATH = {} 368'''.format(builder.qmake_quote(root_plugin_dir), builder.qmake_quote(root_plugin_dir))) 369 370 pro_f.write('\n'.join(builder.qmake_settings) + '\n') 371 372 pro_f.close() 373 374 def _check_license(self): 375 """ Handle the validation of the PyQt5 license. """ 376 377 # We read the license.py file as data. 378 license_py = os.path.join(self.root_dir, 'license.py') 379 380 if os.path.isfile(license_py): 381 ltype = lname = lfile = None 382 383 with open(license_py) as lf: 384 for line in lf: 385 parts = line.split('=') 386 if len(parts) == 2: 387 name, value = parts 388 389 name = name.strip() 390 value = value.strip()[1:-1] 391 392 if name == 'LicenseType': 393 ltype = value 394 elif name == 'LicenseName': 395 lname = value 396 elif name == 'LicenseFile': 397 lfile = value 398 399 if lname is None or lfile is None: 400 ltype = None 401 else: 402 ltype = None 403 404 # Default to the GPL. 405 if ltype is None: 406 ltype = 'GPL' 407 lname = "GNU General Public License" 408 lfile = 'pyqt-gpl.sip' 409 410 self.progress( 411 "This is the {0} version of PyQt {1} (licensed under the {2}) " 412 "for Python {3} on {4}.".format( 413 ltype, self.version_str, lname, 414 sys.version.split()[0], sys.platform)) 415 416 # Confirm the license if not already done. 417 if not self.confirm_license: 418 loptions = """ 419Type 'L' to view the license. 420""" 421 422 sys.stdout.write(loptions) 423 sys.stdout.write("""Type 'yes' to accept the terms of the license. 424Type 'no' to decline the terms of the license. 425 426""") 427 428 while True: 429 sys.stdout.write("Do you accept the terms of the license? ") 430 sys.stdout.flush() 431 432 try: 433 resp = sys.stdin.readline() 434 except KeyboardInterrupt: 435 raise SystemExit 436 except: 437 resp = "" 438 439 resp = resp.strip().lower() 440 441 if resp == "yes": 442 break 443 444 if resp == "no": 445 sys.exit() 446 447 if resp == 'l': 448 os.system('more LICENSE') 449 450 # Check that the license file exists and fix its syntax. 451 src_lfile = os.path.join(self.license_dir, lfile) 452 453 if os.path.isfile(src_lfile): 454 self.progress("Found the license file '{0}'.".format(lfile)) 455 self._fix_license(src_lfile, 456 os.path.join(self.build_dir, lfile + '5')) 457 458 # Make sure sip can find the license file. 459 self.sip_include_dirs.append(self.build_dir) 460 else: 461 raise UserException( 462 "Please copy the license file '{0}' to '{1}'".format(lfile, 463 self.license_dir)) 464 465 def _fix_license(self, src_lfile, dst_lfile): 466 """ Copy the license file and fix it so that it conforms to the SIP v5 467 syntax. 468 """ 469 470 with open(src_lfile) as f: 471 f5 = self.open_for_writing(dst_lfile) 472 473 for line in f: 474 if line.startswith('%License'): 475 anno_start = line.find('/') 476 anno_end = line.rfind('/') 477 478 if anno_start < 0 or anno_end < 0 or anno_start == anno_end: 479 f5.close() 480 481 raise UserException( 482 "'{0}' has missing annotations".format(name)) 483 484 annos = line[anno_start + 1:anno_end].split(', ') 485 annos5 = [anno[0].lower() + anno[1:] for anno in annos] 486 487 f5.write('%License(') 488 f5.write(', '.join(annos5)) 489 f5.write(')\n') 490 else: 491 f5.write(line) 492 493 f5.close() 494 495 496class OpenGLBindings(PyQtBindings): 497 """ Encapsulate internal OpenGL functions bindings. """ 498 499 def __init__(self, project, version): 500 """ Initialise the bindings. """ 501 502 super().__init__(project, '_QOpenGLFunctions_' + version, 503 test_headers=['qopenglfunctions_{}.h'.format(version.lower())], 504 test_statement='new QOpenGLFunctions_{}()'.format(version), 505 internal=True) 506 507 def is_buildable(self): 508 """ Return True if the bindings are buildable. """ 509 510 # Check that the QtGui bindings are being built. 511 qtgui = self.project.bindings.get('QtGui') 512 if qtgui is None: 513 return False 514 515 # Check if all OpenGL support is disabled. 516 if 'PyQt_OpenGL' in qtgui.disabled_features: 517 return False 518 519 # Check if OpenGL desktop support has been disabled. 520 if 'PyQt_Desktop_OpenGL' in qtgui.disabled_features: 521 if self.is_desktop_opengl(): 522 return False 523 else: 524 if not self.is_desktop_opengl(): 525 return False 526 527 # Run the standard configuration checks. 528 return super().is_buildable() 529 530 def is_desktop_opengl(self): 531 """ Return True if the bindings are for desktop OpenGL. """ 532 533 return True 534 535 536class Qt(PyQtBindings): 537 """ The Qt composite module. """ 538 539 def __init__(self, project): 540 """ Initialise the bindings. """ 541 542 # We specify 'internal' to avoid the generation of .api and .pyi files 543 # and the installation of the .sip files. 544 super().__init__(project, 'Qt', qmake_QT=['-core', '-gui'], 545 internal=True) 546 547 548class QAxContainer(PyQtBindings): 549 """ The QAxContainer bindings. """ 550 551 def __init__(self, project): 552 """ Initialise the bindings. """ 553 554 super().__init__(project, 'QAxContainer', qmake_QT=['axcontainer'], 555 test_headers=['qaxobject.h'], test_statement='new QAxObject()') 556 557 558class QtAndroidExtras(PyQtBindings): 559 """ The QtAndroidExtras bindings. """ 560 561 def __init__(self, project): 562 """ Initialise the bindings. """ 563 564 super().__init__(project, 'QtAndroidExtras', 565 qmake_QT=['androidextras'], test_headers=['QtAndroid'], 566 test_statement='QtAndroid::androidSdkVersion()') 567 568 569class QtBluetooth(PyQtBindings): 570 """ The QtBluetooth bindings. """ 571 572 def __init__(self, project): 573 """ Initialise the bindings. """ 574 575 super().__init__(project, 'QtBluetooth', qmake_QT=['bluetooth'], 576 test_headers=['qbluetoothaddress.h'], 577 test_statement='new QBluetoothAddress()') 578 579 580class QtCore(PyQtBindings): 581 """ The QtCore bindings. """ 582 583 def __init__(self, project): 584 """ Initialise the bindings. """ 585 586 super().__init__(project, 'QtCore', qmake_QT=['-gui']) 587 588 def generate(self): 589 """ Generate the bindings source code and return the corresponding 590 buildable. 591 """ 592 593 # This is re-implemented so that we can update the buildable to include 594 # the embedded sip flags. Note that this support is deprecated and can 595 # be removed once support for sip4 has been dropped. 596 597 project = self.project 598 599 # The embedded flags. 600 sip_flags = ['-n', project.sip_module] 601 602 if project.py_debug: 603 sip_flags.append('-D') 604 605 for tag in self.tags: 606 sip_flags.append('-t') 607 sip_flags.append(tag) 608 609 for bindings in project.bindings.values(): 610 for feature in bindings.disabled_features: 611 sip_flags.append('-x') 612 sip_flags.append(feature) 613 614 buildable = super().generate() 615 616 cpp = 'qpycore_post_init.cpp' 617 in_path = os.path.join(project.root_dir, 'qpy', 'QtCore', cpp + '.in') 618 out_path = os.path.join(buildable.build_dir, cpp) 619 620 out_f = project.open_for_writing(out_path) 621 622 with open(in_path) as in_f: 623 code = in_f.read() 624 code = code.replace('@@PYQT_SIP_FLAGS@@', ' '.join(sip_flags)) 625 out_f.write(code) 626 627 out_f.close() 628 629 buildable.sources.append(cpp) 630 631 return buildable 632 633 def handle_test_output(self, test_output): 634 """ Handle the output from the external test program and return True if 635 the bindings are buildable. 636 """ 637 638 project = self.project 639 640 if not project.qt_shared and test_output[0] == 'shared': 641 project.qt_shared = True 642 643 return super().handle_test_output(test_output[1:]) 644 645 646class QtDBus(PyQtBindings): 647 """ The QtDBus bindings. """ 648 649 def __init__(self, project): 650 """ Initialise the bindings. """ 651 652 super().__init__(project, 'QtDBus', qmake_QT=['dbus', '-gui'], 653 test_headers=['qdbusconnection.h'], 654 test_statement='QDBusConnection::systemBus()') 655 656 657class QtDesigner(PyQtBindings): 658 """ The QtDesigner bindings. """ 659 660 def __init__(self, project): 661 """ Initialise the bindings. """ 662 663 super().__init__(project, 'QtDesigner', qmake_QT=['designer'], 664 test_headers=['QExtensionFactory', 'customwidget.h'], 665 test_statement='new QExtensionFactory()') 666 667 def is_buildable(self): 668 """ Return True if the bindings are buildable. """ 669 670 project = self.project 671 672 if not project.qt_shared: 673 project.progress( 674 "The QtDesigner bindings are disabled with a static Qt " 675 "installation") 676 return False 677 678 return super().is_buildable() 679 680 681class Enginio(PyQtBindings): 682 """ The Enginio bindings. """ 683 684 def __init__(self, project): 685 """ Initialise the bindings. """ 686 687 super().__init__(project, 'Enginio', qmake_QT=['enginio'], 688 test_headers=['enginioclient.h'], 689 test_statement='new EnginioClient()') 690 691 692class QtGui(PyQtBindings): 693 """ The QtGui bindings. """ 694 695 def __init__(self, project): 696 """ Initialise the bindings. """ 697 698 super().__init__(project, 'QtGui') 699 700 701class QtHelp(PyQtBindings): 702 """ The QtHelp bindings. """ 703 704 def __init__(self, project): 705 """ Initialise the bindings. """ 706 707 super().__init__(project, 'QtHelp', qmake_QT=['help'], 708 test_headers=['qhelpengine.h'], 709 test_statement='new QHelpEngine("foo")') 710 711 712class QtLocation(PyQtBindings): 713 """ The QtLocation bindings. """ 714 715 def __init__(self, project): 716 """ Initialise the bindings. """ 717 718 super().__init__(project, 'QtLocation', qmake_QT=['location'], 719 test_headers=['qplace.h'], test_statement='new QPlace()') 720 721 722class QtMacExtras(PyQtBindings): 723 """ The QtMacExtras bindings. """ 724 725 def __init__(self, project): 726 """ Initialise the bindings. """ 727 728 super().__init__(project, 'QtMacExtras', qmake_QT=['macextras'], 729 test_headers=['qmacpasteboardmime.h'], 730 test_statement='class Foo : public QMacPasteboardMime {}') 731 732 733class QtMultimedia(PyQtBindings): 734 """ The QtMultimedia bindings. """ 735 736 def __init__(self, project): 737 """ Initialise the bindings. """ 738 739 super().__init__(project, 'QtMultimedia', qmake_QT=['multimedia'], 740 test_headers=['QAudioDeviceInfo'], 741 test_statement='new QAudioDeviceInfo()') 742 743 744class QtMultimediaWidgets(PyQtBindings): 745 """ The QtMultimediaWidgets bindings. """ 746 747 def __init__(self, project): 748 """ Initialise the bindings. """ 749 750 super().__init__(project, 'QtMultimediaWidgets', 751 qmake_QT=['multimediawidgets', 'multimedia'], 752 test_headers=['QVideoWidget'], 753 test_statement='new QVideoWidget()') 754 755 756class QtNetwork(PyQtBindings): 757 """ The QtNetwork bindings. """ 758 759 def __init__(self, project): 760 """ Initialise the bindings. """ 761 762 super().__init__(project, 'QtNetwork', qmake_QT=['network', '-gui']) 763 764 765class QtNfc(PyQtBindings): 766 """ The QtNfc bindings. """ 767 768 def __init__(self, project): 769 """ Initialise the bindings. """ 770 771 super().__init__(project, 'QtNfc', qmake_QT=['nfc', '-gui'], 772 test_headers=['qnearfieldmanager.h'], 773 test_statement='new QNearFieldManager()') 774 775 776class QtOpenGL(PyQtBindings): 777 """ The QtOpenGL bindings. """ 778 779 def __init__(self, project): 780 """ Initialise the bindings. """ 781 782 super().__init__(project, 'QtOpenGL', qmake_QT=['opengl'], 783 test_headers=['qgl.h'], test_statement='new QGLWidget()') 784 785 786class QtPositioning(PyQtBindings): 787 """ The QtPositioning bindings. """ 788 789 def __init__(self, project): 790 """ Initialise the bindings. """ 791 792 super().__init__(project, 'QtPositioning', qmake_QT=['positioning'], 793 test_headers=['qgeoaddress.h'], 794 test_statement='new QGeoAddress()') 795 796 797class QtPrintSupport(PyQtBindings): 798 """ The QtPrintSupport bindings. """ 799 800 def __init__(self, project): 801 """ Initialise the bindings. """ 802 803 super().__init__(project, 'QtPrintSupport', qmake_QT=['printsupport']) 804 805 806class QtQml(PyQtBindings): 807 """ The QtQml bindings. """ 808 809 def __init__(self, project): 810 """ Initialise the bindings. """ 811 812 super().__init__(project, 'QtQml', qmake_QT=['qml'], 813 test_headers=['qjsengine.h'], test_statement='new QJSEngine()') 814 815 816class QtQuick(PyQtBindings): 817 """ The QtQuick bindings. """ 818 819 def __init__(self, project): 820 """ Initialise the bindings. """ 821 822 super().__init__(project, 'QtQuick', qmake_QT=['quick'], 823 test_headers=['qquickwindow.h'], 824 test_statement='new QQuickWindow()') 825 826 827class QtQuick3D(PyQtBindings): 828 """ The QtQuick3D bindings. """ 829 830 def __init__(self, project): 831 """ Initialise the bindings. """ 832 833 super().__init__(project, 'QtQuick3D', qmake_QT=['quick3d'], 834 test_headers=['qquick3d.h'], 835 test_statement='QQuick3D::idealSurfaceFormat()') 836 837 838class QtQuickWidgets(PyQtBindings): 839 """ The QtQuickWidgets bindings. """ 840 841 def __init__(self, project): 842 """ Initialise the bindings. """ 843 844 super().__init__(project, 'QtQuickWidgets', qmake_QT=['quickwidgets'], 845 test_headers=['qquickwidget.h'], 846 test_statement='new QQuickWidget()') 847 848 849class QtRemoteObjects(PyQtBindings): 850 """ The QtRemoteObjects bindings. """ 851 852 def __init__(self, project): 853 """ Initialise the bindings. """ 854 855 super().__init__(project, 'QtRemoteObjects', 856 qmake_QT=['remoteobjects', '-gui'], 857 test_headers=['qtremoteobjectsversion.h'], 858 test_statement='const char *v = QTREMOTEOBJECTS_VERSION_STR') 859 860 861class QtSensors(PyQtBindings): 862 """ The QtSensors bindings. """ 863 864 def __init__(self, project): 865 """ Initialise the bindings. """ 866 867 super().__init__(project, 'QtSensors', qmake_QT=['sensors'], 868 test_headers=['qsensor.h'], 869 test_statement='new QSensor(QByteArray())') 870 871 872class QtSerialPort(PyQtBindings): 873 """ The QtSerialPort bindings. """ 874 875 def __init__(self, project): 876 """ Initialise the bindings. """ 877 878 super().__init__(project, 'QtSerialPort', qmake_QT=['serialport'], 879 test_headers=['qserialport.h'], 880 test_statement='new QSerialPort()') 881 882 883class QtSql(PyQtBindings): 884 """ The QtSql bindings. """ 885 886 def __init__(self, project): 887 """ Initialise the bindings. """ 888 889 super().__init__(project, 'QtSql', qmake_QT=['sql', 'widgets'], 890 test_headers=['qsqldatabase.h'], 891 test_statement='new QSqlDatabase()') 892 893 894class QtSvg(PyQtBindings): 895 """ The QtSvg bindings. """ 896 897 def __init__(self, project): 898 """ Initialise the bindings. """ 899 900 super().__init__(project, 'QtSvg', qmake_QT=['svg'], 901 test_headers=['qsvgwidget.h'], 902 test_statement='new QSvgWidget()') 903 904 905class QtTest(PyQtBindings): 906 """ The QtTest bindings. """ 907 908 def __init__(self, project): 909 """ Initialise the bindings. """ 910 911 super().__init__(project, 'QtTest', qmake_QT=['testlib', 'widgets'], 912 test_headers=['QtTest'], test_statement='QTest::qSleep(0)') 913 914 915class QtTextToSpeech(PyQtBindings): 916 """ The QtTextToSpeech bindings. """ 917 918 def __init__(self, project): 919 """ Initialise the bindings. """ 920 921 super().__init__(project, 'QtTextToSpeech', 922 qmake_QT=['texttospeech', '-gui'], 923 test_headers=['QTextToSpeech'], 924 test_statement='new QTextToSpeech()') 925 926 927class QtWebChannel(PyQtBindings): 928 """ The QtWebChannel bindings. """ 929 930 def __init__(self, project): 931 """ Initialise the bindings. """ 932 933 super().__init__(project, 'QtWebChannel', 934 qmake_QT=['webchannel', 'network', '-gui'], 935 test_headers=['qwebchannel.h'], 936 test_statement='new QWebChannel()') 937 938 939class QtWebKit(PyQtBindings): 940 """ The QtWebKit bindings. """ 941 942 def __init__(self, project): 943 """ Initialise the bindings. """ 944 945 super().__init__(project, 'QtWebKit', qmake_QT=['webkit', 'network'], 946 test_headers=['qwebkitglobal.h'], 947 test_statement='qWebKitVersion()') 948 949 950class QtWebKitWidgets(PyQtBindings): 951 """ The QtWebKitWidgets bindings. """ 952 953 def __init__(self, project): 954 """ Initialise the bindings. """ 955 956 super().__init__(project, 'QtWebKitWidgets', 957 qmake_QT=['webkitwidgets', 'printsupport'], 958 test_headers=['qwebpage.h'], test_statement='new QWebPage()') 959 960 961class QtWebSockets(PyQtBindings): 962 """ The QtWebSockets bindings. """ 963 964 def __init__(self, project): 965 """ Initialise the bindings. """ 966 967 super().__init__(project, 'QtWebSockets', 968 qmake_QT=['websockets', '-gui'], test_headers=['qwebsocket.h'], 969 test_statement='new QWebSocket()') 970 971 972class QtWidgets(PyQtBindings): 973 """ The QtWidgets bindings. """ 974 975 def __init__(self, project): 976 """ Initialise the bindings. """ 977 978 super().__init__(project, 'QtWidgets', qmake_QT=['widgets'], 979 test_headers=['qwidget.h'], test_statement='new QWidget()') 980 981 982class QtWinExtras(PyQtBindings): 983 """ The QtWinExtras bindings. """ 984 985 def __init__(self, project): 986 """ Initialise the bindings. """ 987 988 super().__init__(project, 'QtWinExtras', 989 qmake_QT=['winextras', 'widgets'], test_headers=['QtWin'], 990 test_statement='QtWin::isCompositionEnabled()') 991 992 993class QtX11Extras(PyQtBindings): 994 """ The QtX11Extras bindings. """ 995 996 def __init__(self, project): 997 """ Initialise the bindings. """ 998 999 super().__init__(project, 'QtX11Extras', qmake_QT=['x11extras'], 1000 test_headers=['QX11Info'], 1001 test_statement='QX11Info::display()') 1002 1003 1004class QtXml(PyQtBindings): 1005 """ The QtXml bindings. """ 1006 1007 def __init__(self, project): 1008 """ Initialise the bindings. """ 1009 1010 super().__init__(project, 'QtXml', qmake_QT=['xml', '-gui'], 1011 test_headers=['qdom.h'], test_statement='new QDomDocument()') 1012 1013 1014class QtXmlPatterns(PyQtBindings): 1015 """ The QtXmlPatterns bindings. """ 1016 1017 def __init__(self, project): 1018 """ Initialise the bindings. """ 1019 1020 super().__init__(project, 'QtXmlPatterns', 1021 qmake_QT=['xmlpatterns', '-gui', 'network'], 1022 test_headers=['qxmlname.h'], test_statement='new QXmlName()') 1023 1024 1025class _QOpenGLFunctions_2_0(OpenGLBindings): 1026 """ The _QOpenGLFunctions_2_0 bindings. """ 1027 1028 def __init__(self, project): 1029 """ Initialise the bindings. """ 1030 1031 super().__init__(project, '2_0') 1032 1033 1034class _QOpenGLFunctions_2_1(OpenGLBindings): 1035 """ The _QOpenGLFunctions_2_1 bindings. """ 1036 1037 def __init__(self, project): 1038 """ Initialise the bindings. """ 1039 1040 super().__init__(project, '2_1') 1041 1042 1043class _QOpenGLFunctions_4_1_Core(OpenGLBindings): 1044 """ The _QOpenGLFunctions_4_1_Core bindings. """ 1045 1046 def __init__(self, project): 1047 """ Initialise the bindings. """ 1048 1049 super().__init__(project, '4_1_Core') 1050 1051 1052class _QOpenGLFunctions_ES2(OpenGLBindings): 1053 """ The _QOpenGLFunctions_ES2 bindings. """ 1054 1055 def __init__(self, project): 1056 """ Initialise the bindings. """ 1057 1058 super().__init__(project, 'ES2') 1059 1060 def is_desktop_opengl(self): 1061 """ Return True if the bindings are for desktop OpenGL. """ 1062 1063 return False 1064 1065 1066class pylupdate(PyQtBindings): 1067 """ The pylupdate bindings. """ 1068 1069 def __init__(self, project): 1070 """ Initialise the bindings. """ 1071 1072 super().__init__(project, 'pylupdate', qmake_QT=['xml', '-gui'], 1073 internal=True) 1074 1075 def generate(self): 1076 """ Generate the bindings source code and return the corresponding 1077 buildable. 1078 """ 1079 1080 # This is re-implemented so that we can update the buildable to include 1081 # pylupdate_main.py. 1082 1083 project = self.project 1084 1085 buildable = super().generate() 1086 1087 installable = Installable('pylupdate_main', target_subdir='PyQt5') 1088 installable.files.append( 1089 os.path.join(project.root_dir, 'pylupdate', 1090 'pylupdate_main.py')) 1091 buildable.installables.append(installable) 1092 1093 return buildable 1094 1095 def is_buildable(self): 1096 """ Return True if the bindings are buildable. """ 1097 1098 return self.project.tools 1099 1100 1101class pyrcc(PyQtBindings): 1102 """ The pyrcc bindings. """ 1103 1104 def __init__(self, project): 1105 """ Initialise the bindings. """ 1106 1107 super().__init__(project, 'pyrcc', qmake_QT=['xml', '-gui'], 1108 internal=True) 1109 1110 def generate(self): 1111 """ Generate the bindings source code and return the corresponding 1112 buildable. 1113 """ 1114 1115 # This is re-implemented so that we can update the buildable to include 1116 # pyrcc_main.py. 1117 1118 project = self.project 1119 1120 buildable = super().generate() 1121 1122 installable = Installable('pyrcc_main', target_subdir='PyQt5') 1123 installable.files.append( 1124 os.path.join(project.root_dir, 'pyrcc', 'pyrcc_main.py')) 1125 buildable.installables.append(installable) 1126 1127 return buildable 1128 1129 def is_buildable(self): 1130 """ Return True if the bindings are buildable. """ 1131 1132 return self.project.tools 1133