core (XMLUI): small optimisation: introspection is done once at module loading instead of on each XMLUI instantiation

This commit is contained in:
Goffi 2019-01-11 09:48:17 +01:00
commit b33d1f66de

View file

@ -110,7 +110,6 @@ def _dataFormField2XMLUIData(field, read_only=False):
return widget_type, widget_args, widget_kwargs
def dataForm2Widgets(form_ui, form, read_only=False, prepend=None, filters=None):
"""Complete an existing XMLUI with widget converted from XEP-0004 data forms.
@ -280,7 +279,11 @@ def dataFormResult2XMLUI(
@param filters: same as for [dataForm2Widgets]
@return: XMLUI instance
"""
# we deepcopy the form because _dataFormField2XMLUIData can modify the value
# FIXME: check if it's really important, the only modified value seems to be
# the replacement of None by "" on fixed fields
form = deepcopy(result_form)
form = result_form
for name, field in form.fields.iteritems():
try:
base_field = base_form.fields[name]
@ -1300,7 +1303,6 @@ class XMLUI(object):
returned by frontends
@attribute named_widgets(dict): map from name to widget
"""
self._introspect() # FIXME: why doing that on each XMLUI ? should be done once
if panel_type not in [
C.XMLUI_WINDOW,
C.XMLUI_FORM,
@ -1336,50 +1338,63 @@ class XMLUI(object):
self.current_container = self.main_container
self.named_widgets = {}
def _introspect(self):
""" Introspect module to find Widgets and Containers """
self._containers = {}
self._widgets = {}
@staticmethod
def creatorWrapper(widget_cls, is_input):
# TODO: once moved to Python 3, use functools.partialmethod and
# remove the creatorWrapper
def createWidget(self, *args, **kwargs):
if self.type == C.XMLUI_DIALOG:
raise exceptions.InternalError(_(
"createWidget can't be used with dialogs"))
if "parent" not in kwargs:
kwargs["parent"] = self.current_container
if "name" not in kwargs and is_input:
# name can be given as first argument or in keyword
# arguments for InputWidgets
args = list(args)
kwargs["name"] = args.pop(0)
return widget_cls(self, *args, **kwargs)
return createWidget
@classmethod
def _introspect(cls):
""" Introspect module to find Widgets and Containers, and create addXXX methods"""
# FIXME: we can't log anything because this file is used
# in bin/sat script then evaluated
# bin/sat should be refactored
# log.debug(u'introspecting XMLUI widgets and containers')
cls._containers = {}
cls._widgets = {}
for obj in globals().values():
try:
if issubclass(obj, Widget):
if obj.__name__ == "Widget":
continue
self._widgets[obj.type] = obj
cls._widgets[obj.type] = obj
creator_name = u"add" + obj.__name__
if creator_name.endswith('Widget'):
creator_name = creator_name[:-6]
is_input = issubclass(obj, InputWidget)
# FIXME: cf. above comment
# log.debug(u"Adding {creator_name} creator (is_input={is_input}))"
# .format(creator_name=creator_name, is_input=is_input))
assert not hasattr(cls, creator_name)
# XXX: we need to use creatorWrapper because we are in a loop
# and Python 2 doesn't support default values in kwargs
# when using *args, **kwargs
setattr(cls, creator_name, cls.creatorWrapper(obj, is_input))
elif issubclass(obj, Container):
if obj.__name__ == "Container":
continue
self._containers[obj.type] = obj
cls._containers[obj.type] = obj
except TypeError:
pass
def __del__(self):
self.doc.unlink()
def __getattr__(self, name):
if name.startswith("add") and name not in (
"addWidget",
): # addWidgetName(...) create an instance of WidgetName
if self.type == C.XMLUI_DIALOG:
raise exceptions.InternalError(_("addXXX can't be used with dialogs"))
class_name = name[3:] + "Widget"
if class_name in globals():
cls = globals()[class_name]
if issubclass(cls, Widget):
def createWidget(*args, **kwargs):
if "parent" not in kwargs:
kwargs["parent"] = self.current_container
if "name" not in kwargs and issubclass(
cls, InputWidget
): # name can be given as first argument or in keyword arguments for InputWidgets
args = list(args)
kwargs["name"] = args.pop(0)
return cls(self, *args, **kwargs)
return createWidget
return object.__getattribute__(self, name)
@property
def submit_id(self):
top_element = self.doc.documentElement
@ -1480,11 +1495,12 @@ class XMLUI(object):
def addWidget(self, type_, *args, **kwargs):
"""Convenience method to add an element"""
if type_ not in self._widgets:
raise exceptions.DataError(_("Invalid type [%s]") % type_)
if "parent" not in kwargs:
kwargs["parent"] = self.current_container
cls = self._widgets[type_]
try:
cls = self._widgets[type_]
except KeyError:
raise exceptions.DataError(_("Invalid type [{type_}]").format(type_=type_))
return cls(self, *args, **kwargs)
def toXml(self):
@ -1492,6 +1508,10 @@ class XMLUI(object):
return self.doc.toxml()
# we call this to have automatic discovery of containers and widgets
XMLUI._introspect()
# Some sugar for XMLUI dialogs