core (XMLUI): small optimisation: introspection is done once at module loading instead of on each XMLUI instantiation
This commit is contained in:
parent
169165e4ee
commit
b33d1f66de
1 changed files with 55 additions and 35 deletions
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue