├── pyblish_houdini ├── plugins │ ├── __init__.py │ └── collect_current_file.py ├── vendor │ ├── __init__.py │ └── Qt.py ├── __init__.py ├── houdini_path │ ├── python2.7libs │ │ └── pythonrc.py │ ├── python2.6libs │ │ └── pythonrc.py │ ├── python3.7libs │ │ └── pythonrc.py │ └── MainMenuCommon.xml ├── version.py └── lib.py ├── .gitignore ├── setup.cfg ├── .travis.yml ├── CHANGES ├── setup.py ├── README.md └── LICENSE /pyblish_houdini/plugins/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /pyblish_houdini/vendor/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | *.egg-info 3 | dist -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [metadata] 2 | # This includes the license file in the wheel. 3 | license_file = LICENSE 4 | 5 | [bdist_wheel] 6 | # This produces a "universal" (Py2+3) wheel. 7 | universal = 1 8 | -------------------------------------------------------------------------------- /pyblish_houdini/__init__.py: -------------------------------------------------------------------------------- 1 | from .version import * 2 | 3 | from .lib import ( 4 | show, 5 | setup, 6 | register_plugins, 7 | register_host, 8 | 9 | # Utility functions 10 | maintained_selection 11 | ) 12 | -------------------------------------------------------------------------------- /pyblish_houdini/houdini_path/python2.7libs/pythonrc.py: -------------------------------------------------------------------------------- 1 | try: 2 | __import__("pyblish_houdini") 3 | 4 | except ImportError as e: 5 | print "pyblish: Could not load integration: %s" % e 6 | 7 | else: 8 | import pyblish_houdini 9 | pyblish_houdini.setup() 10 | -------------------------------------------------------------------------------- /pyblish_houdini/houdini_path/python2.6libs/pythonrc.py: -------------------------------------------------------------------------------- 1 | try: 2 | __import__("pyblish_houdini") 3 | 4 | except ImportError as e: 5 | print("pyblish: Could not load integration: %s" % e) 6 | 7 | else: 8 | import pyblish_houdini 9 | pyblish_houdini.setup() 10 | -------------------------------------------------------------------------------- /pyblish_houdini/houdini_path/python3.7libs/pythonrc.py: -------------------------------------------------------------------------------- 1 | try: 2 | __import__("pyblish_houdini") 3 | 4 | except ImportError as e: 5 | print("pyblish: Could not load integration: %s" % e) 6 | 7 | else: 8 | import pyblish_houdini 9 | pyblish_houdini.setup() 10 | -------------------------------------------------------------------------------- /pyblish_houdini/version.py: -------------------------------------------------------------------------------- 1 | 2 | VERSION_MAJOR = 1 3 | VERSION_MINOR = 1 4 | VERSION_PATCH = 2 5 | 6 | version_info = (VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH) 7 | version = '%i.%i.%i' % version_info 8 | __version__ = version 9 | 10 | __all__ = ['version', 'version_info', '__version__'] 11 | -------------------------------------------------------------------------------- /pyblish_houdini/plugins/collect_current_file.py: -------------------------------------------------------------------------------- 1 | import pyblish.api 2 | 3 | import hou 4 | 5 | 6 | class CollectCurrentFile(pyblish.api.ContextPlugin): 7 | """Inject the current working file into context""" 8 | 9 | label = "Current File" 10 | hosts = ["houdini"] 11 | order = pyblish.api.CollectorOrder 12 | 13 | def process(self, context): 14 | """inject the current working file""" 15 | context.data["currentFile"] = hou.hipFile.path() 16 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | 3 | python: 4 | - 2.7 5 | 6 | script: 7 | - pip install file://$(pwd) 8 | 9 | deploy: 10 | provider: pypi 11 | user: mottosso 12 | distributions: "sdist bdist_wheel" 13 | password: 14 | secure: TeaVT5oKTkGTHAdkW0fjRIyxD8mbGDh5e7VwjVY/nAmASuX6J+W1IKsmF2lvgKETlbnhNsGl+Lk2YkT5bxRGY4ZI0Hnm4Dewn1Rfq0HdUbTT19gSq86dBHfjZTuq7C5DILIA0SjNfmIQvDsICdj08rkdye+r1fleCtedZAhgkMU= 15 | on: 16 | tags: true 17 | repo: pyblish/pyblish-houdini 18 | -------------------------------------------------------------------------------- /pyblish_houdini/houdini_path/MainMenuCommon.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | h.save_as 8 | 9 | 10 | 11 | file_menu 12 | 13 | pyblish_menu_sep 14 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /CHANGES: -------------------------------------------------------------------------------- 1 | pyblish-houdini Changelog 2 | ========================= 3 | 4 | Version 1.1.1 5 | ------------- 6 | 7 | - Add missing package_data to support Python 3 8 | 9 | Version 1.1.0 10 | ------------- 11 | 12 | - Port to Python 3 13 | 14 | Version 1.0.0 15 | ------------- 16 | 17 | - Updated to pyblish-base 1.4.1 18 | - Added support for register_gui() 19 | - DEPRECATED: port and console arguments of setup() 20 | 21 | Version 0.2.2 22 | ------------- 23 | 24 | - Added argument `port` to setup() 25 | 26 | Version 0.2.1 27 | ------------- 28 | 29 | - Exposed `register_host` 30 | 31 | Version 0.2.0 32 | ------------- 33 | 34 | - Added compatibility with Pyblish 1.1.3 35 | 36 | Version 0.1.1 37 | -------------- 38 | 39 | - Updated plug-ins to 1.1 40 | - Updated integration to Pyblish Integration -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | """This setup script packages pyblish_houdini""" 2 | 3 | import os 4 | import imp 5 | 6 | from setuptools import setup, find_packages 7 | 8 | version_file = os.path.abspath("pyblish_houdini/version.py") 9 | version_mod = imp.load_source("version", version_file) 10 | version = version_mod.version 11 | 12 | 13 | classifiers = [ 14 | "Development Status :: 5 - Production/Stable", 15 | "Intended Audience :: Developers", 16 | "License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3)", 17 | "Programming Language :: Python", 18 | "Programming Language :: Python :: 2", 19 | "Programming Language :: Python :: 2.6", 20 | "Programming Language :: Python :: 2.7", 21 | "Programming Language :: Python :: 3", 22 | "Programming Language :: Python :: 3.7", 23 | "Topic :: Software Development :: Libraries :: Python Modules", 24 | "Topic :: Utilities" 25 | ] 26 | 27 | 28 | setup( 29 | name="pyblish-houdini", 30 | version=version, 31 | packages=find_packages(), 32 | url="https://github.com/pyblish/pyblish-houdini", 33 | license="LGPL", 34 | author="Abstract Factory and Contributors", 35 | author_email="marcus@abstractfactory.io", 36 | description="Houdini Pyblish package", 37 | zip_safe=False, 38 | classifiers=classifiers, 39 | package_data={ 40 | "pyblish_houdini": [ 41 | "plugins/*.py", 42 | "houdini_path/*.xml", 43 | "houdini_path/python2.6libs/*.py", 44 | "houdini_path/python2.7libs/*.py", 45 | "houdini_path/python3.7libs/*.py", 46 | ] 47 | }, 48 | install_requires=[ 49 | "pyblish-base>=1.4" 50 | ], 51 | ) 52 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### ![](https://cloud.githubusercontent.com/assets/2152766/6998101/5c13946c-dbcd-11e4-968b-b357b7c60a06.png) 2 | 3 | [![Build Status](https://travis-ci.org/pyblish/pyblish-houdini.svg?branch=master)](https://travis-ci.org/pyblish/pyblish-houdini) 4 | 5 | Pyblish integration for SideFx Houdini 8-18.5. 6 | 7 |
8 |
9 |
10 | 11 | ### What is included? 12 | 13 | A set of common plug-ins and functions shared across other integrations - such as getting the current working file. It also visually integrates Pyblish into the File-menu for easy access. 14 | 15 | - Common [plug-ins](https://github.com/pyblish/pyblish-houdini/tree/master/pyblish_houdini/plugins) 16 | - Common [functionality](https://github.com/pyblish/pyblish-houdini/blob/master/pyblish_houdini/__init__.py) 17 | - File-menu shortcut 18 | 19 |
20 |
21 |
22 | 23 | ### Installation 24 | 25 | pyblish-houdini depends on [pyblish-base](https://github.com/pyblish/pyblish-base) and is available via PyPI. 26 | 27 | ```bash 28 | $ pip install pyblish-houdini 29 | ``` 30 | 31 | You may also want to consider a graphical user interface, such as [pyblish-qml](https://github.com/pyblish/pyblish-qml) or [pyblish-lite](https://github.com/pyblish/pyblish-lite). 32 | 33 |
34 |
35 |
36 | 37 | ### Usage 38 | 39 | To get started using pyblish-houdini, run `setup()` at startup of your application. 40 | 41 | ```python 42 | # 1. Register your favourite GUI 43 | import pyblish.api 44 | pyblish.api.register_gui("pyblish_lite") 45 | 46 | # 2. Set-up Pyblish for Houdini 47 | import pyblish_houdini 48 | pyblish_houdini.setup() 49 | ``` 50 | 51 |
52 |
53 |
54 | 55 | ### Persistence 56 | 57 | In order to have Pyblish become a permanent member of each Houdini session, you can add the supplied `houdini_path/` folder to your `HOUDINI_PATH` environment variable. 58 | 59 | Take care however, for this variable has an unexpected quirk on Windows platforms. 60 | 61 | ```bash 62 | $ set "HOUDINI_PATH=C:\pythonpath\pyblish_houdini\houdini_path;&" 63 | ``` 64 | 65 | Note the `&` sign, and the fact that the entire expression is wrapped in quotation marks. 66 | 67 | If you use batch script files on Windows to launch Houdini, you'll need to escape the "&" character with "^&". 68 | 69 | With this variable set, you should find a new File-menu item. 70 | 71 | **NOTE: If you use "HOUDINI_PATH" in houdini.env, make sure you setup the path here instead or inherit the environment with "$HOUDINI_PATH"** 72 | 73 | ![image](https://cloud.githubusercontent.com/assets/2152766/16362652/866de682-3bac-11e6-818a-cc711e04a1af.png) 74 | 75 |
76 |
77 |
78 | 79 | 80 | ### Documentation 81 | 82 | - [Under the hood](#under-the-hood) 83 | - [Manually show GUI](#manually-show-gui) 84 | - [Teardown pyblish-houdini](#teardown-pyblish-houdini) 85 | - [No GUI](#no-gui) 86 | 87 |
88 |
89 |
90 | 91 | ##### Under the hood 92 | 93 | The `setup()` command will: 94 | 95 | 1. Register Houdini related ["hosts"](http://api.pyblish.com/pages/Plugin.hosts.html), allowing plug-ins to be filtered accordingly. 96 | 3. Register a minimal set of plug-ins that are common across all integrations. 97 | 98 |
99 |
100 |
101 | 102 | ##### Manually show GUI 103 | 104 | The menu-button is set to run `show()`, which you may also manually call yourself, such as from a shelf-button. 105 | 106 | ```python 107 | import pyblish_houdini 108 | pyblish_houdini.show() 109 | ``` 110 | 111 |
112 |
113 |
114 | 115 | ##### Teardown pyblish-houdini 116 | 117 | To get rid of the menu, and completely remove any trace of pyblish-houdini from your Houdini session, run `teardown()`. 118 | 119 | ```python 120 | import pyblish_houdini 121 | pyblish_houdini.teardown() 122 | ``` 123 | 124 | This will do the opposite of `setup()` and clean things up for you. 125 | 126 |
127 |
128 |
129 | 130 | ##### No GUI 131 | 132 | In the event that no GUI is registered upon running `setup()`, the button will provide the *user* with this information on how they can get up and running on their own. 133 | 134 | ![image](https://cloud.githubusercontent.com/assets/2152766/16318872/d63b7f60-3988-11e6-9431-f64991aabef3.png) 135 | 136 | ![image](https://cloud.githubusercontent.com/assets/2152766/16318883/ddf159f0-3988-11e6-8ef5-af5fd8dde725.png) 137 | 138 | ![image](https://cloud.githubusercontent.com/assets/2152766/16318893/e7d4cc9a-3988-11e6-92e9-c16037e51fb7.png) 139 | -------------------------------------------------------------------------------- /pyblish_houdini/lib.py: -------------------------------------------------------------------------------- 1 | # Standard library 2 | import os 3 | import sys 4 | import contextlib 5 | 6 | # Pyblish libraries 7 | import pyblish.api 8 | 9 | # Host libraries 10 | import hou 11 | 12 | # Local libraries 13 | from . import plugins 14 | 15 | self = sys.modules[__name__] 16 | self._has_been_setup = False 17 | self._registered_gui = None 18 | 19 | 20 | def setup(console=False, port=None): 21 | """Setup integration 22 | 23 | Register plug-ins and integrate into the host 24 | 25 | Arguments: 26 | console (bool): DEPRECATED 27 | port (int, optional): DEPRECATED 28 | 29 | """ 30 | 31 | if self._has_been_setup: 32 | teardown() 33 | 34 | register_plugins() 35 | register_host() 36 | 37 | self._has_been_setup = True 38 | print("pyblish: Pyblish loaded successfully.") 39 | 40 | 41 | def show(): 42 | """Try showing the most desirable GUI 43 | 44 | This function cycles through the currently registered 45 | graphical user interfaces, if any, and presents it to 46 | the user. 47 | 48 | """ 49 | 50 | return (_discover_gui() or _show_no_gui)() 51 | 52 | 53 | def _discover_gui(): 54 | """Return the most desirable of the currently registered GUIs""" 55 | 56 | # Prefer last registered 57 | guis = reversed(pyblish.api.registered_guis()) 58 | 59 | for gui in guis: 60 | try: 61 | gui = __import__(gui).show 62 | except (ImportError, AttributeError): 63 | continue 64 | else: 65 | return gui 66 | 67 | 68 | def teardown(): 69 | """Remove integration""" 70 | if not self._has_been_setup: 71 | return 72 | 73 | deregister_plugins() 74 | deregister_host() 75 | 76 | self._has_been_setup = False 77 | print("pyblish: Integration torn down successfully") 78 | 79 | 80 | def register_host(): 81 | """Register supported hosts""" 82 | pyblish.api.register_host("hython") 83 | pyblish.api.register_host("hpython") 84 | pyblish.api.register_host("houdini") 85 | 86 | 87 | def register_plugins(): 88 | # Register accompanying plugins 89 | plugin_path = os.path.dirname(plugins.__file__) 90 | pyblish.api.register_plugin_path(plugin_path) 91 | 92 | 93 | def deregister_host(): 94 | pyblish.api.deregister_host("hpython") 95 | pyblish.api.deregister_host("houdini") 96 | 97 | 98 | def deregister_plugins(): 99 | plugin_path = os.path.dirname(plugins.__file__) 100 | pyblish.api.deregister_plugin_path(plugin_path) 101 | 102 | 103 | @contextlib.contextmanager 104 | def maintained_selection(): 105 | """Maintain selection during context 106 | 107 | Example: 108 | >>> with maintained_selection(): 109 | ... # Modify selection 110 | ... node.setSelected(on=False, clear_all_selected=True) 111 | >>> # Selection restored 112 | 113 | """ 114 | 115 | previous_selection = hou.selectedNodes() 116 | try: 117 | yield 118 | finally: 119 | if previous_selection: 120 | for node in previous_selection: 121 | node.setSelected(on=True) 122 | else: 123 | for node in previous_selection: 124 | node.setSelected(on=False) 125 | 126 | 127 | def _show_no_gui(): 128 | """Popup with information about how to register a new GUI 129 | 130 | In the event of no GUI being registered or available, 131 | this information dialog will appear to guide the user 132 | through how to get set up with one. 133 | 134 | """ 135 | 136 | try: 137 | from .vendor.Qt import QtWidgets, QtGui 138 | except ImportError: 139 | raise ImportError("Pyblish requires either PySide or PyQt bindings.") 140 | 141 | messagebox = QtWidgets.QMessageBox() 142 | messagebox.setIcon(messagebox.Warning) 143 | messagebox.setWindowIcon(QtGui.QIcon(os.path.join( 144 | os.path.dirname(pyblish.__file__), 145 | "icons", 146 | "logo-32x32.svg")) 147 | ) 148 | 149 | spacer = QtWidgets.QWidget() 150 | spacer.setMinimumSize(400, 0) 151 | spacer.setSizePolicy(QtWidgets.QSizePolicy.Minimum, 152 | QtWidgets.QSizePolicy.Expanding) 153 | 154 | layout = messagebox.layout() 155 | layout.addWidget(spacer, layout.rowCount(), 0, 1, layout.columnCount()) 156 | 157 | messagebox.setWindowTitle("Uh oh") 158 | messagebox.setText("No registered GUI found.") 159 | 160 | if not pyblish.api.registered_guis(): 161 | messagebox.setInformativeText( 162 | "In order to show you a GUI, one must first be registered. " 163 | "Press \"Show details...\" below for information on how to " 164 | "do that.") 165 | 166 | messagebox.setDetailedText( 167 | "Pyblish supports one or more graphical user interfaces " 168 | "to be registered at once, the next acting as a fallback to " 169 | "the previous." 170 | "\n" 171 | "\n" 172 | "For example, to use Pyblish Lite, first install it:" 173 | "\n" 174 | "\n" 175 | "$ pip install pyblish-lite" 176 | "\n" 177 | "\n" 178 | "Then register it, like so:" 179 | "\n" 180 | "\n" 181 | ">>> import pyblish.api\n" 182 | ">>> pyblish.api.register_gui(\"pyblish_lite\")" 183 | "\n" 184 | "\n" 185 | "The next time you try running this, Lite will appear." 186 | "\n" 187 | "See http://api.pyblish.com/register_gui.html for " 188 | "more information.") 189 | 190 | else: 191 | messagebox.setInformativeText( 192 | "None of the registered graphical user interfaces " 193 | "could be found." 194 | "\n" 195 | "\n" 196 | "Press \"Show details\" for more information.") 197 | 198 | messagebox.setDetailedText( 199 | "These interfaces are currently registered." 200 | "\n" 201 | "%s" % "\n".join(pyblish.api.registered_guis())) 202 | 203 | messagebox.setStandardButtons(messagebox.Ok) 204 | messagebox.exec_() 205 | -------------------------------------------------------------------------------- /pyblish_houdini/vendor/Qt.py: -------------------------------------------------------------------------------- 1 | """Map all bindings to PySide2 2 | 3 | This module replaces itself with the most desirable binding. 4 | 5 | Resolution order: 6 | - PySide2 7 | - PyQt5 8 | - PySide 9 | - PyQt4 10 | 11 | Usage: 12 | >>> import sys 13 | >>> from Qt import QtWidgets 14 | >>> app = QtWidgets.QApplication(sys.argv) 15 | >>> button = QtWidgets.QPushButton("Hello World") 16 | >>> button.show() 17 | >>> app.exec_() 18 | 19 | """ 20 | 21 | import os 22 | import sys 23 | 24 | __version__ = "0.3.2" 25 | 26 | 27 | def _pyqt5(): 28 | import PyQt5.Qt 29 | 30 | # Remap 31 | PyQt5.QtCore.Signal = PyQt5.QtCore.pyqtSignal 32 | PyQt5.QtCore.Slot = PyQt5.QtCore.pyqtSlot 33 | PyQt5.QtCore.Property = PyQt5.QtCore.pyqtProperty 34 | 35 | # Add 36 | PyQt5.__wrapper_version__ = __version__ 37 | PyQt5.__binding__ = "PyQt5" 38 | PyQt5.__binding_version__ = PyQt5.QtCore.PYQT_VERSION_STR 39 | PyQt5.__qt_version__ = PyQt5.QtCore.QT_VERSION_STR 40 | PyQt5.load_ui = pyqt5_load_ui 41 | 42 | return PyQt5 43 | 44 | 45 | def _pyqt4(): 46 | # Attempt to set sip API v2 (must be done prior to importing PyQt4) 47 | import sip 48 | try: 49 | sip.setapi("QString", 2) 50 | sip.setapi("QVariant", 2) 51 | sip.setapi("QDate", 2) 52 | sip.setapi("QDateTime", 2) 53 | sip.setapi("QTextStream", 2) 54 | sip.setapi("QTime", 2) 55 | sip.setapi("QUrl", 2) 56 | except AttributeError: 57 | raise ImportError 58 | # PyQt4 < v4.6 59 | except ValueError: 60 | # API version already set to v1 61 | raise ImportError 62 | 63 | import PyQt4.Qt 64 | 65 | # Remap 66 | PyQt4.QtWidgets = PyQt4.QtGui 67 | PyQt4.QtCore.Signal = PyQt4.QtCore.pyqtSignal 68 | PyQt4.QtCore.Slot = PyQt4.QtCore.pyqtSlot 69 | PyQt4.QtCore.Property = PyQt4.QtCore.pyqtProperty 70 | PyQt4.QtCore.QItemSelection = PyQt4.QtGui.QItemSelection 71 | PyQt4.QtCore.QItemSelectionModel = PyQt4.QtGui.QItemSelectionModel 72 | 73 | # Add 74 | PyQt4.__wrapper_version__ = __version__ 75 | PyQt4.__binding__ = "PyQt4" 76 | PyQt4.__binding_version__ = PyQt4.QtCore.PYQT_VERSION_STR 77 | PyQt4.__qt_version__ = PyQt4.QtCore.QT_VERSION_STR 78 | PyQt4.load_ui = pyqt4_load_ui 79 | 80 | return PyQt4 81 | 82 | 83 | def _pyside2(): 84 | import PySide2 85 | from PySide2 import QtGui, QtCore 86 | 87 | # Remap 88 | QtCore.QStringListModel = QtGui.QStringListModel 89 | 90 | # Add 91 | PySide2.__wrapper_version__ = __version__ 92 | PySide2.__binding__ = "PySide2" 93 | PySide2.__binding_version__ = PySide2.__version__ 94 | PySide2.__qt_version__ = PySide2.QtCore.qVersion() 95 | PySide2.load_ui = pyside2_load_ui 96 | 97 | return PySide2 98 | 99 | 100 | def _pyside(): 101 | import PySide 102 | from PySide import QtGui, QtCore 103 | 104 | # Remap 105 | PySide.QtWidgets = QtGui 106 | QtCore.QSortFilterProxyModel = QtGui.QSortFilterProxyModel 107 | QtCore.QStringListModel = QtGui.QStringListModel 108 | PySide.QtCore.QItemSelection = PySide.QtGui.QItemSelection 109 | PySide.QtCore.QItemSelectionModel = PySide.QtGui.QItemSelectionModel 110 | 111 | # Add 112 | PySide.__wrapper_version__ = __version__ 113 | PySide.__binding__ = "PySide" 114 | PySide.__binding_version__ = PySide.__version__ 115 | PySide.__qt_version__ = PySide.QtCore.qVersion() 116 | PySide.load_ui = pyside_load_ui 117 | 118 | return PySide 119 | 120 | 121 | def pyside_load_ui(fname): 122 | """Read Qt Designer .ui `fname` 123 | 124 | Args: 125 | fname (str): Absolute path to .ui file 126 | 127 | Usage: 128 | >> from Qt import load_ui 129 | >> class MyWindow(QtWidgets.QWidget): 130 | .. fname = 'my_ui.ui' 131 | .. self.ui = load_ui(fname) 132 | .. 133 | >> window = MyWindow() 134 | 135 | """ 136 | 137 | from PySide import QtUiTools 138 | return QtUiTools.QUiLoader().load(fname) 139 | 140 | 141 | def pyside2_load_ui(fname): 142 | """Read Qt Designer .ui `fname` 143 | 144 | Args: 145 | fname (str): Absolute path to .ui file 146 | 147 | """ 148 | 149 | from PySide2 import QtUiTools 150 | return QtUiTools.QUiLoader().load(fname) 151 | 152 | 153 | def pyqt4_load_ui(fname): 154 | """Read Qt Designer .ui `fname` 155 | 156 | Args: 157 | fname (str): Absolute path to .ui file 158 | 159 | """ 160 | 161 | from PyQt4 import uic 162 | return uic.loadUi(fname) 163 | 164 | 165 | def pyqt5_load_ui(fname): 166 | """Read Qt Designer .ui `fname` 167 | 168 | Args: 169 | fname (str): Absolute path to .ui file 170 | 171 | """ 172 | 173 | from PyQt5 import uic 174 | return uic.loadUi(fname) 175 | 176 | 177 | def _init(): 178 | """Try loading each binding in turn 179 | 180 | Please note: the entire Qt module is replaced with this code: 181 | sys.modules["Qt"] = binding() 182 | 183 | This means no functions or variables can be called after 184 | this has executed. 185 | 186 | """ 187 | 188 | preferred = os.getenv("QT_PREFERRED_BINDING") 189 | verbose = os.getenv("QT_VERBOSE") is not None 190 | 191 | if preferred: 192 | 193 | # Debug mode, used in installer 194 | if preferred == "None": 195 | sys.modules[__name__].__wrapper_version__ = __version__ 196 | return 197 | 198 | available = { 199 | "PySide2": _pyside2, 200 | "PySide": _pyside, 201 | "PyQt5": _pyqt5, 202 | "PyQt4": _pyqt4 203 | } 204 | 205 | if preferred not in available: 206 | raise ImportError("Preferred Qt binding \"%s\" " 207 | "not available" % preferred) 208 | 209 | binding = available[preferred] 210 | sys.modules[__name__] = binding() 211 | return 212 | 213 | else: 214 | for binding in (_pyside2, 215 | _pyqt5, 216 | _pyside, 217 | _pyqt4): 218 | 219 | if verbose: 220 | sys.stdout.write("Trying %s" % binding.__name__[1:]) 221 | 222 | try: 223 | sys.modules[__name__] = binding() 224 | return 225 | 226 | except ImportError as e: 227 | 228 | if verbose: 229 | sys.stdout.write(" - ImportError(\"%s\")\n" % e) 230 | 231 | continue 232 | 233 | # If not binding were found, throw this error 234 | raise ImportError("No Qt binding were found.") 235 | 236 | 237 | _init() 238 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | --------------------------------------------------------------------------------