Mercurial > libervia-backend
comparison sat/tools/xml_tools.py @ 2762:5a51c7fc74a5
core (XMLUI): small optimisation: introspection is done once at module loading instead of on each XMLUI instantiation
author | Goffi <goffi@goffi.org> |
---|---|
date | Fri, 11 Jan 2019 09:48:17 +0100 |
parents | 1797671827b9 |
children | 003b8b4b56a7 |
comparison
equal
deleted
inserted
replaced
2761:4b693ea24d5f | 2762:5a51c7fc74a5 |
---|---|
108 if field.var: | 108 if field.var: |
109 widget_kwargs["name"] = field.var | 109 widget_kwargs["name"] = field.var |
110 | 110 |
111 return widget_type, widget_args, widget_kwargs | 111 return widget_type, widget_args, widget_kwargs |
112 | 112 |
113 | |
114 def dataForm2Widgets(form_ui, form, read_only=False, prepend=None, filters=None): | 113 def dataForm2Widgets(form_ui, form, read_only=False, prepend=None, filters=None): |
115 """Complete an existing XMLUI with widget converted from XEP-0004 data forms. | 114 """Complete an existing XMLUI with widget converted from XEP-0004 data forms. |
116 | 115 |
117 @param form_ui (XMLUI): XMLUI instance | 116 @param form_ui (XMLUI): XMLUI instance |
118 @param form (data_form.Form): Wokkel's implementation of data form | 117 @param form (data_form.Form): Wokkel's implementation of data form |
278 @param session_id (unicode): session id to return with the data | 277 @param session_id (unicode): session id to return with the data |
279 @param prepend: same as for [dataForm2Widgets] | 278 @param prepend: same as for [dataForm2Widgets] |
280 @param filters: same as for [dataForm2Widgets] | 279 @param filters: same as for [dataForm2Widgets] |
281 @return: XMLUI instance | 280 @return: XMLUI instance |
282 """ | 281 """ |
282 # we deepcopy the form because _dataFormField2XMLUIData can modify the value | |
283 # FIXME: check if it's really important, the only modified value seems to be | |
284 # the replacement of None by "" on fixed fields | |
283 form = deepcopy(result_form) | 285 form = deepcopy(result_form) |
286 form = result_form | |
284 for name, field in form.fields.iteritems(): | 287 for name, field in form.fields.iteritems(): |
285 try: | 288 try: |
286 base_field = base_form.fields[name] | 289 base_field = base_form.fields[name] |
287 except KeyError: | 290 except KeyError: |
288 continue | 291 continue |
1298 dialog) | 1301 dialog) |
1299 @param session_id: use to keep a session attached to the dialog, must be | 1302 @param session_id: use to keep a session attached to the dialog, must be |
1300 returned by frontends | 1303 returned by frontends |
1301 @attribute named_widgets(dict): map from name to widget | 1304 @attribute named_widgets(dict): map from name to widget |
1302 """ | 1305 """ |
1303 self._introspect() # FIXME: why doing that on each XMLUI ? should be done once | |
1304 if panel_type not in [ | 1306 if panel_type not in [ |
1305 C.XMLUI_WINDOW, | 1307 C.XMLUI_WINDOW, |
1306 C.XMLUI_FORM, | 1308 C.XMLUI_FORM, |
1307 C.XMLUI_PARAM, | 1309 C.XMLUI_PARAM, |
1308 C.XMLUI_POPUP, | 1310 C.XMLUI_POPUP, |
1334 return | 1336 return |
1335 self.main_container = self._createContainer(container, TopElement(self)) | 1337 self.main_container = self._createContainer(container, TopElement(self)) |
1336 self.current_container = self.main_container | 1338 self.current_container = self.main_container |
1337 self.named_widgets = {} | 1339 self.named_widgets = {} |
1338 | 1340 |
1339 def _introspect(self): | 1341 @staticmethod |
1340 """ Introspect module to find Widgets and Containers """ | 1342 def creatorWrapper(widget_cls, is_input): |
1341 self._containers = {} | 1343 # TODO: once moved to Python 3, use functools.partialmethod and |
1342 self._widgets = {} | 1344 # remove the creatorWrapper |
1345 def createWidget(self, *args, **kwargs): | |
1346 if self.type == C.XMLUI_DIALOG: | |
1347 raise exceptions.InternalError(_( | |
1348 "createWidget can't be used with dialogs")) | |
1349 if "parent" not in kwargs: | |
1350 kwargs["parent"] = self.current_container | |
1351 if "name" not in kwargs and is_input: | |
1352 # name can be given as first argument or in keyword | |
1353 # arguments for InputWidgets | |
1354 args = list(args) | |
1355 kwargs["name"] = args.pop(0) | |
1356 return widget_cls(self, *args, **kwargs) | |
1357 return createWidget | |
1358 | |
1359 @classmethod | |
1360 def _introspect(cls): | |
1361 """ Introspect module to find Widgets and Containers, and create addXXX methods""" | |
1362 # FIXME: we can't log anything because this file is used | |
1363 # in bin/sat script then evaluated | |
1364 # bin/sat should be refactored | |
1365 # log.debug(u'introspecting XMLUI widgets and containers') | |
1366 cls._containers = {} | |
1367 cls._widgets = {} | |
1343 for obj in globals().values(): | 1368 for obj in globals().values(): |
1344 try: | 1369 try: |
1345 if issubclass(obj, Widget): | 1370 if issubclass(obj, Widget): |
1346 if obj.__name__ == "Widget": | 1371 if obj.__name__ == "Widget": |
1347 continue | 1372 continue |
1348 self._widgets[obj.type] = obj | 1373 cls._widgets[obj.type] = obj |
1374 creator_name = u"add" + obj.__name__ | |
1375 if creator_name.endswith('Widget'): | |
1376 creator_name = creator_name[:-6] | |
1377 is_input = issubclass(obj, InputWidget) | |
1378 # FIXME: cf. above comment | |
1379 # log.debug(u"Adding {creator_name} creator (is_input={is_input}))" | |
1380 # .format(creator_name=creator_name, is_input=is_input)) | |
1381 | |
1382 assert not hasattr(cls, creator_name) | |
1383 # XXX: we need to use creatorWrapper because we are in a loop | |
1384 # and Python 2 doesn't support default values in kwargs | |
1385 # when using *args, **kwargs | |
1386 setattr(cls, creator_name, cls.creatorWrapper(obj, is_input)) | |
1387 | |
1349 elif issubclass(obj, Container): | 1388 elif issubclass(obj, Container): |
1350 if obj.__name__ == "Container": | 1389 if obj.__name__ == "Container": |
1351 continue | 1390 continue |
1352 self._containers[obj.type] = obj | 1391 cls._containers[obj.type] = obj |
1353 except TypeError: | 1392 except TypeError: |
1354 pass | 1393 pass |
1355 | 1394 |
1356 def __del__(self): | 1395 def __del__(self): |
1357 self.doc.unlink() | 1396 self.doc.unlink() |
1358 | |
1359 def __getattr__(self, name): | |
1360 if name.startswith("add") and name not in ( | |
1361 "addWidget", | |
1362 ): # addWidgetName(...) create an instance of WidgetName | |
1363 if self.type == C.XMLUI_DIALOG: | |
1364 raise exceptions.InternalError(_("addXXX can't be used with dialogs")) | |
1365 class_name = name[3:] + "Widget" | |
1366 if class_name in globals(): | |
1367 cls = globals()[class_name] | |
1368 if issubclass(cls, Widget): | |
1369 | |
1370 def createWidget(*args, **kwargs): | |
1371 if "parent" not in kwargs: | |
1372 kwargs["parent"] = self.current_container | |
1373 if "name" not in kwargs and issubclass( | |
1374 cls, InputWidget | |
1375 ): # name can be given as first argument or in keyword arguments for InputWidgets | |
1376 args = list(args) | |
1377 kwargs["name"] = args.pop(0) | |
1378 return cls(self, *args, **kwargs) | |
1379 | |
1380 return createWidget | |
1381 return object.__getattribute__(self, name) | |
1382 | 1397 |
1383 @property | 1398 @property |
1384 def submit_id(self): | 1399 def submit_id(self): |
1385 top_element = self.doc.documentElement | 1400 top_element = self.doc.documentElement |
1386 if not top_element.hasAttribute("submit"): | 1401 if not top_element.hasAttribute("submit"): |
1478 assert isinstance(self.current_container, Container) | 1493 assert isinstance(self.current_container, Container) |
1479 return self.current_container | 1494 return self.current_container |
1480 | 1495 |
1481 def addWidget(self, type_, *args, **kwargs): | 1496 def addWidget(self, type_, *args, **kwargs): |
1482 """Convenience method to add an element""" | 1497 """Convenience method to add an element""" |
1483 if type_ not in self._widgets: | |
1484 raise exceptions.DataError(_("Invalid type [%s]") % type_) | |
1485 if "parent" not in kwargs: | 1498 if "parent" not in kwargs: |
1486 kwargs["parent"] = self.current_container | 1499 kwargs["parent"] = self.current_container |
1487 cls = self._widgets[type_] | 1500 try: |
1501 cls = self._widgets[type_] | |
1502 except KeyError: | |
1503 raise exceptions.DataError(_("Invalid type [{type_}]").format(type_=type_)) | |
1488 return cls(self, *args, **kwargs) | 1504 return cls(self, *args, **kwargs) |
1489 | 1505 |
1490 def toXml(self): | 1506 def toXml(self): |
1491 """return the XML representation of the panel""" | 1507 """return the XML representation of the panel""" |
1492 return self.doc.toxml() | 1508 return self.doc.toxml() |
1509 | |
1510 | |
1511 # we call this to have automatic discovery of containers and widgets | |
1512 XMLUI._introspect() | |
1493 | 1513 |
1494 | 1514 |
1495 # Some sugar for XMLUI dialogs | 1515 # Some sugar for XMLUI dialogs |
1496 | 1516 |
1497 | 1517 |