source: orange/Orange/orng/widgetParser.py @ 10827:8527a7511c4f

Revision 10827:8527a7511c4f, 3.5 KB checked in by mitar, 2 years ago (diff)

Support for widgets loading from modules, registered through entry point.

Line 
1import xml.dom.minidom
2import re, os
3from fileutil import xml_text_of
4from fileutil import create_text_element
5from fileutil import _zip_open
6
7re_inputs = re.compile(r'[ \t]+self.inputs\s*=\s*(?P<signals>\[[^]]*\])', re.DOTALL)
8re_outputs = re.compile(r'[ \t]+self.outputs\s*=\s*(?P<signals>\[[^]]*\])', re.DOTALL)
9re_tuple = re.compile(r"\(([^)]+)\)")
10
11def _getSignalList(regex, data):
12    inmo = regex.search(data)
13    if inmo:
14        return str([tuple([y[0] in "'\"" and y[1:-1] or str(y) for y in (x.strip() for x in ttext.group(1).split(","))])
15               for ttext in re_tuple.finditer(inmo.group("signals"))])
16    else:
17        return "[]"
18
19class WidgetMetaData:
20    xmlAttrs = ["name", "description", "contact", "category", "icon", "hasDoc", "prototype"]
21   
22    def __init__(self, data, defaultCategory="Prototypes", enforceDefaultCategory=False, filename=None, hasDoc="0"):  # data can either be a string with module (.py file) contents or an xml.dom.Element
23        if not filename and data.__class__ is xml.dom.minidom.Element:  # XML (as returned by toXml())
24            self.name=""
25            self.icon=""
26            self.priority=""
27            self.description=""
28            self.category=""
29            self.tags=""
30            self.prototype="0"
31            self.filename=None
32            self.hasDoc = hasDoc
33            for attr in self.xmlAttrs:
34                nodes = data.getElementsByTagName(attr)
35                if nodes:
36                    setattr(self, attr, xml_text_of(nodes[0]))
37            if data.hasAttribute("filename"):
38                self.filename = data.getAttribute("filename")
39        else:   # python module
40            setattr(self, "filename", filename)
41            for attr, deflt in (("name", None), ("contact", "") , ("icon", "icons/Unknown.png"), ("priority", "5000"), ("description", ""), ("category", defaultCategory), ("tags", ""), ("prototype", "0")):
42                istart, iend = data.find("<"+attr+">"), data.find("</"+attr+">")
43                setattr(self, attr, istart >= 0 and iend >= 0 and data[istart+2+len(attr):iend].strip() or deflt)
44            if enforceDefaultCategory:
45                self.category = defaultCategory
46            if not self.name:
47                raise Exception("Not an Orange widget module.")
48            self.hasDoc = hasDoc
49            self.inputList = _getSignalList(re_inputs, data)
50            self.outputList = _getSignalList(re_outputs, data)
51
52    def clone(self):
53        return WidgetMetaData(self.toXml())
54   
55    def toXml(self):
56        widgetTag = xml.dom.minidom.Element("widget")
57        for attr in self.xmlAttrs:
58            if hasattr(self, attr):
59                widgetTag.appendChild(create_text_element(attr, getattr(self, attr)))
60        if "filename" in self.__dict__ and self.filename:
61            widgetTag.setAttribute("filename", self.filename)
62        return widgetTag
63
64_widgetModuleName = re.compile(r"widgets/(prototypes/|)[^/]*\.py$")
65def widgetsXml(oaoZip):
66    files = oaoZip.namelist()
67    widgetsTag = xml.dom.minidom.Element("widgets")
68    for file in files:
69        if re.match(_widgetModuleName, file):
70            try:
71                filename = file[8:]
72                meta = WidgetMetaData(_zip_open(oaoZip, file).read(), "None", filename=filename, hasDoc="1" if ("doc/widgets/%s.htm" % (os.path.splitext(filename)[0][2:]) in files) else "0")
73            except:
74                continue   # Probably not an Orange widget module
75            widgetsTag.appendChild(meta.toXml())
76    return widgetsTag
Note: See TracBrowser for help on using the repository browser.