ctdb-daemon: Use ctdb_parse_node_address() in ctdbd
[samba4-gss.git] / third_party / waf / waflib / extras / pyqt5.py
blob0c083a1247a1969583a1d6d42693f2e3ec97d574
1 #!/usr/bin/env python
2 # encoding: utf-8
3 # Federico Pellegrin, 2016-2022 (fedepell) adapted for Python
5 """
6 This tool helps with finding Python Qt5 tools and libraries,
7 and provides translation from QT5 files to Python code.
9 The following snippet illustrates the tool usage::
11 def options(opt):
12 opt.load('py pyqt5')
14 def configure(conf):
15 conf.load('py pyqt5')
17 def build(bld):
18 bld(
19 features = 'py pyqt5',
20 source = 'main.py textures.qrc aboutDialog.ui',
23 Here, the UI description and resource files will be processed
24 to generate code.
26 Usage
27 =====
29 Load the "pyqt5" tool.
31 Add into the sources list also the qrc resources files or ui5
32 definition files and they will be translated into python code
33 with the system tools (PyQt5, PySide2, PyQt4 are searched in this
34 order) and then compiled
35 """
37 try:
38 from xml.sax import make_parser
39 from xml.sax.handler import ContentHandler
40 except ImportError:
41 has_xml = False
42 ContentHandler = object
43 else:
44 has_xml = True
46 import os
47 from waflib.Tools import python
48 from waflib import Task, Options
49 from waflib.TaskGen import feature, extension
50 from waflib.Configure import conf
51 from waflib import Logs
53 EXT_RCC = ['.qrc']
54 """
55 File extension for the resource (.qrc) files
56 """
58 EXT_UI = ['.ui']
59 """
60 File extension for the user interface (.ui) files
61 """
64 class XMLHandler(ContentHandler):
65 """
66 Parses ``.qrc`` files
67 """
68 def __init__(self):
69 self.buf = []
70 self.files = []
71 def startElement(self, name, attrs):
72 if name == 'file':
73 self.buf = []
74 def endElement(self, name):
75 if name == 'file':
76 self.files.append(str(''.join(self.buf)))
77 def characters(self, cars):
78 self.buf.append(cars)
80 @extension(*EXT_RCC)
81 def create_pyrcc_task(self, node):
82 "Creates rcc and py task for ``.qrc`` files"
83 rcnode = node.change_ext('.py')
84 self.create_task('pyrcc', node, rcnode)
85 if getattr(self, 'install_from', None):
86 self.install_from = self.install_from.get_bld()
87 else:
88 self.install_from = self.path.get_bld()
89 self.install_path = getattr(self, 'install_path', '${PYTHONDIR}')
90 self.process_py(rcnode)
92 @extension(*EXT_UI)
93 def create_pyuic_task(self, node):
94 "Create uic tasks and py for user interface ``.ui`` definition files"
95 uinode = node.change_ext('.py')
96 self.create_task('ui5py', node, uinode)
97 if getattr(self, 'install_from', None):
98 self.install_from = self.install_from.get_bld()
99 else:
100 self.install_from = self.path.get_bld()
101 self.install_path = getattr(self, 'install_path', '${PYTHONDIR}')
102 self.process_py(uinode)
104 @extension('.ts')
105 def add_pylang(self, node):
106 """Adds all the .ts file into ``self.lang``"""
107 self.lang = self.to_list(getattr(self, 'lang', [])) + [node]
109 @feature('pyqt5')
110 def apply_pyqt5(self):
112 The additional parameters are:
114 :param lang: list of translation files (\\*.ts) to process
115 :type lang: list of :py:class:`waflib.Node.Node` or string without the .ts extension
116 :param langname: if given, transform the \\*.ts files into a .qrc files to include in the binary file
117 :type langname: :py:class:`waflib.Node.Node` or string without the .qrc extension
119 if getattr(self, 'lang', None):
120 qmtasks = []
121 for x in self.to_list(self.lang):
122 if isinstance(x, str):
123 x = self.path.find_resource(x + '.ts')
124 qmtasks.append(self.create_task('ts2qm', x, x.change_ext('.qm')))
127 if getattr(self, 'langname', None):
128 qmnodes = [k.outputs[0] for k in qmtasks]
129 rcnode = self.langname
130 if isinstance(rcnode, str):
131 rcnode = self.path.find_or_declare(rcnode + '.qrc')
132 t = self.create_task('qm2rcc', qmnodes, rcnode)
133 create_pyrcc_task(self, t.outputs[0])
135 class pyrcc(Task.Task):
137 Processes ``.qrc`` files
139 color = 'BLUE'
140 run_str = '${QT_PYRCC} ${QT_PYRCC_FLAGS} ${SRC} -o ${TGT}'
141 ext_out = ['.py']
143 def rcname(self):
144 return os.path.splitext(self.inputs[0].name)[0]
146 def scan(self):
147 """Parse the *.qrc* files"""
148 if not has_xml:
149 Logs.error('No xml.sax support was found, rcc dependencies will be incomplete!')
150 return ([], [])
152 parser = make_parser()
153 curHandler = XMLHandler()
154 parser.setContentHandler(curHandler)
155 fi = open(self.inputs[0].abspath(), 'r')
156 try:
157 parser.parse(fi)
158 finally:
159 fi.close()
161 nodes = []
162 names = []
163 root = self.inputs[0].parent
164 for x in curHandler.files:
165 nd = root.find_resource(x)
166 if nd:
167 nodes.append(nd)
168 else:
169 names.append(x)
170 return (nodes, names)
173 class ui5py(Task.Task):
175 Processes ``.ui`` files for python
177 color = 'BLUE'
178 run_str = '${QT_PYUIC} ${QT_PYUIC_FLAGS} ${SRC} -o ${TGT}'
179 ext_out = ['.py']
181 class ts2qm(Task.Task):
183 Generates ``.qm`` files from ``.ts`` files
185 color = 'BLUE'
186 run_str = '${QT_LRELEASE} ${QT_LRELEASE_FLAGS} ${SRC} -qm ${TGT}'
188 class qm2rcc(Task.Task):
190 Generates ``.qrc`` files from ``.qm`` files
192 color = 'BLUE'
193 after = 'ts2qm'
194 def run(self):
195 """Create a qrc file including the inputs"""
196 txt = '\n'.join(['<file>%s</file>' % k.path_from(self.outputs[0].parent) for k in self.inputs])
197 code = '<!DOCTYPE RCC><RCC version="1.0">\n<qresource>\n%s\n</qresource>\n</RCC>' % txt
198 self.outputs[0].write(code)
200 def configure(self):
201 self.find_pyqt5_binaries()
203 # warn about this during the configuration too
204 if not has_xml:
205 Logs.error('No xml.sax support was found, rcc dependencies will be incomplete!')
207 @conf
208 def find_pyqt5_binaries(self):
210 Detects PyQt5 or PySide2 programs such as pyuic5/pyside2-uic, pyrcc5/pyside2-rcc
212 env = self.env
214 if getattr(Options.options, 'want_pyqt5', True):
215 self.find_program(['pyuic5'], var='QT_PYUIC')
216 self.find_program(['pyrcc5'], var='QT_PYRCC')
217 self.find_program(['pylupdate5'], var='QT_PYLUPDATE')
218 elif getattr(Options.options, 'want_pyside2', True):
219 self.find_program(['pyside2-uic','uic-qt5'], var='QT_PYUIC')
220 self.find_program(['pyside2-rcc','rcc-qt5'], var='QT_PYRCC')
221 self.find_program(['pyside2-lupdate','lupdate-qt5'], var='QT_PYLUPDATE')
222 elif getattr(Options.options, 'want_pyqt4', True):
223 self.find_program(['pyuic4'], var='QT_PYUIC')
224 self.find_program(['pyrcc4'], var='QT_PYRCC')
225 self.find_program(['pylupdate4'], var='QT_PYLUPDATE')
226 else:
227 self.find_program(['pyuic5','pyside2-uic','pyuic4','uic-qt5'], var='QT_PYUIC')
228 self.find_program(['pyrcc5','pyside2-rcc','pyrcc4','rcc-qt5'], var='QT_PYRCC')
229 self.find_program(['pylupdate5', 'pyside2-lupdate','pylupdate4','lupdate-qt5'], var='QT_PYLUPDATE')
231 if not env.QT_PYUIC:
232 self.fatal('cannot find the uic compiler for python for qt5')
234 if not env.QT_PYRCC:
235 self.fatal('cannot find the rcc compiler for python for qt5')
237 self.find_program(['lrelease-qt5', 'lrelease'], var='QT_LRELEASE')
239 def options(opt):
241 Command-line options
243 pyqt5opt=opt.add_option_group("Python QT5 Options")
244 pyqt5opt.add_option('--pyqt5-pyqt5', action='store_true', default=False, dest='want_pyqt5', help='use PyQt5 bindings as python QT5 bindings (default PyQt5 is searched first, PySide2 after, PyQt4 last)')
245 pyqt5opt.add_option('--pyqt5-pyside2', action='store_true', default=False, dest='want_pyside2', help='use PySide2 bindings as python QT5 bindings (default PyQt5 is searched first, PySide2 after, PyQt4 last)')
246 pyqt5opt.add_option('--pyqt5-pyqt4', action='store_true', default=False, dest='want_pyqt4', help='use PyQt4 bindings as python QT5 bindings (default PyQt5 is searched first, PySide2 after, PyQt4 last)')