source: orange/Orange/OrangeCanvas/orngRegistry.py @ 10581:94a831b04ec3

Revision 10581:94a831b04ec3, 9.7 KB checked in by markotoplak, 2 years ago (diff)

Moved some other scripts from misc to utils and Orange imports and canvas not works, although not systematically tested.

Line 
1# Author: Gregor Leban (gregor.leban@fri.uni-lj.si)
2#
3
4import os, sys, re, glob, stat
5from orngSignalManager import OutputSignal, InputSignal
6from PyQt4.QtCore import *
7from PyQt4.QtGui import *
8import widgetParser
9
10orangeDir = os.path.split(os.path.split(os.path.abspath(__file__))[0])[0]
11if not orangeDir in sys.path:
12    sys.path.append(orangeDir)
13
14import orngEnviron, Orange.utils.addons
15
16class WidgetDescription:
17    def __init__(self, **attrs):
18        self.__dict__.update(attrs)
19
20    def docDir(self):
21        if not self.addOn:  # A built-in widget
22            dir, widgetDir = os.path.realpath(self.directory), os.path.realpath(orngEnviron.widgetDir)
23            subDir = os.path.relpath(dir, widgetDir) if "relpath" in os.path.__dict__ else dir.replace(widgetDir, "")
24            return os.path.join(orngEnviron.orangeDocDir, "widgets", subDir)
25        else:  # An add-on widget
26            addOnDocDir = self.addOn.directory_documentation()
27            return os.path.join(addOnDocDir, "widgets")
28
29
30class WidgetCategory(dict):
31    def __init__(self, name, widgets=None):
32        if widgets:
33            self.update(widgets)
34        self.name = name
35   
36def readCategories(silent=False):
37    try:
38        from Orange.version import version as orange_version
39    except ImportError:
40        # Orange.version module is writen by setup.py, what if orange was build
41        # using make
42        orange_version = "???"
43    # Add orange version to the cache version (because cache contains names
44    # of types inside the Orange hierarchy, if that changes the cache should be
45    # invalidated)
46    currentCacheVersion = (2, orange_version)
47   
48    global widgetsWithError, widgetsWithErrorPrototypes
49    widgetDirName = os.path.realpath(orngEnviron.directoryNames["widgetDir"])
50    canvasSettingsDir = os.path.realpath(orngEnviron.directoryNames["canvasSettingsDir"])
51    cacheFilename = os.path.join(canvasSettingsDir, "cachedWidgetDescriptions.pickle")
52
53    try:
54        import cPickle
55        cacheFile = file(cacheFilename, "rb")
56        cats = cPickle.load(cacheFile)
57        try:
58            version = cPickle.load(cacheFile)
59        except EOFError:
60            version = 0
61        if version == currentCacheVersion:
62            cachedWidgetDescriptions = dict([(w.fullName, w) for cat in cats.values() for w in cat.values()])
63        else:
64            cachedWidgetDescriptions = {}
65    except Exception:
66        cachedWidgetDescriptions = {} 
67
68    directories = [] # tuples (defaultCategory, dirName, plugin, isPrototype)
69    for dirName in os.listdir(widgetDirName):
70        directory = os.path.join(widgetDirName, dirName)
71        if os.path.isdir(directory):
72            directories.append((None, directory, None, "prototypes" in dirName.lower()))
73           
74    # read list of add-ons
75    for addOn in Orange.utils.addons.installed_addons.values() + Orange.utils.addons.registered_addons:
76        addOnWidgetsDir = os.path.join(addOn.directory, "widgets")
77        if os.path.isdir(addOnWidgetsDir):
78            directories.append((addOn.name, addOnWidgetsDir, addOn, False))
79        addOnWidgetsPrototypesDir = os.path.join(addOnWidgetsDir, "prototypes")
80        if os.path.isdir(addOnWidgetsPrototypesDir):
81            directories.append((None, addOnWidgetsPrototypesDir, addOn, True))
82
83    categories = {}     
84    for defCat, dirName, addOn, isPrototype in directories:
85        widgets = readWidgets(dirName, cachedWidgetDescriptions, isPrototype, silent=silent, addOn=addOn, defaultCategory=defCat)
86        for (wName, wInfo) in widgets:
87            catName = wInfo.category
88            if not catName in categories:
89                categories[catName] = WidgetCategory(catName)
90            if wName in categories[catName]:
91                print "Warning! A widget with duplicated name '%s' in category '%s' has been found! It will _not_ be available in the Canvas." % (wName, catName)
92            else:
93                categories[catName][wName] = wInfo
94
95    cacheFile = file(cacheFilename, "wb")
96    cPickle.dump(categories, cacheFile)
97    cPickle.dump(currentCacheVersion, cacheFile)
98    if splashWindow:
99        splashWindow.hide()
100
101    if not silent:
102        if widgetsWithError != []:
103            print "The following widgets could not be imported and will not be available: " + ", ".join(set(widgetsWithError)) + "."
104        if widgetsWithErrorPrototypes != []:
105            print "The following prototype widgets could not be imported and will not be available: " + ", ".join(set(widgetsWithErrorPrototypes)) + "."
106
107    return categories
108
109
110hasErrors = False
111splashWindow = None
112widgetsWithError = []
113widgetsWithErrorPrototypes = []
114
115def readWidgets(directory, cachedWidgetDescriptions, prototype=False, silent=False, addOn=None, defaultCategory=None):
116    import sys, imp
117    global hasErrors, splashWindow, widgetsWithError, widgetsWithErrorPrototypes
118   
119    widgets = []
120   
121    if not defaultCategory:
122        predir, defaultCategory = os.path.split(directory.strip(os.path.sep).strip(os.path.altsep))
123        if defaultCategory == "widgets":
124            defaultCategory = os.path.split(predir.strip(os.path.sep).strip(os.path.altsep))[1]
125   
126    if defaultCategory.lower() == "prototypes" or prototype:
127        defaultCategory = "Prototypes"
128   
129    for filename in glob.iglob(os.path.join(directory, "*.py")):
130        if os.path.isdir(filename):
131            continue
132       
133        datetime = str(os.stat(filename)[stat.ST_MTIME])
134        cachedDescription = cachedWidgetDescriptions.get(filename, None)
135        if cachedDescription and cachedDescription.time == datetime and hasattr(cachedDescription, "inputClasses"):
136            widgets.append((cachedDescription.name, cachedDescription))
137            continue
138       
139        data = file(filename).read()
140        try:
141            meta = widgetParser.WidgetMetaData(data, defaultCategory, enforceDefaultCategory=prototype)
142        except:   # Probably not an Orange widget module.
143            continue
144
145        dirname, fname = os.path.split(filename)
146        widgname = os.path.splitext(fname)[0]
147        try:
148            if not splashWindow:
149                import orngEnviron
150                logo = QPixmap(os.path.join(orngEnviron.directoryNames["canvasDir"], "icons", "splash.png"))
151                splashWindow = QSplashScreen(logo, Qt.WindowStaysOnTopHint)
152                splashWindow.setMask(logo.mask())
153                splashWindow.show()
154               
155            splashWindow.showMessage("Registering widget %s" % meta.name, Qt.AlignHCenter + Qt.AlignBottom)
156            qApp.processEvents()
157           
158            # We import modules using imp.load_source to avoid storing them in sys.modules,
159            # but we need to append the path to sys.path in case the module would want to load
160            # something
161            dirnameInPath = dirname in sys.path
162            if not dirnameInPath:
163                sys.path.append(dirname)
164            wmod = imp.load_source(widgname, filename)
165            if not dirnameInPath and dirname in sys.path: # I have no idea, why we need this, but it seems to disappear sometimes?!
166                sys.path.remove(dirname)
167            widgClass = wmod.__dict__[widgname]
168            inputClasses = set(eval(x[1], wmod.__dict__).__name__ for x in eval(meta.inputList))
169            outputClasses = set(y.__name__ for x in eval(meta.outputList) for y in eval(x[1], wmod.__dict__).mro())
170           
171            widgetInfo = WidgetDescription(
172                             name = meta.name,
173                             time = datetime,
174                             fileName = widgname,
175                             fullName = filename,
176                             directory = directory,
177                             addOn = addOn,
178                             inputList = meta.inputList, outputList = meta.outputList,
179                             inputClasses = inputClasses, outputClasses = outputClasses,
180                             tags=meta.tags
181                             )
182   
183            for attr in ["contact", "icon", "priority", "description", "category"]:
184                setattr(widgetInfo, attr, getattr(meta, attr))
185   
186            # build the tooltip
187            widgetInfo.inputs = [InputSignal(*signal) for signal in eval(widgetInfo.inputList)]
188            if len(widgetInfo.inputs) == 0:
189                formatedInList = "<b>Inputs:</b><br> &nbsp;&nbsp; None<br>"
190            else:
191                formatedInList = "<b>Inputs:</b><br>"
192                for signal in widgetInfo.inputs:
193                    formatedInList += " &nbsp;&nbsp; - " + signal.name + " (" + signal.type + ")<br>"
194   
195            widgetInfo.outputs = [OutputSignal(*signal) for signal in eval(widgetInfo.outputList)]
196            if len(widgetInfo.outputs) == 0:
197                formatedOutList = "<b>Outputs:</b><br> &nbsp; &nbsp; None<br>"
198            else:
199                formatedOutList = "<b>Outputs:</b><br>"
200                for signal in widgetInfo.outputs:
201                    formatedOutList += " &nbsp; &nbsp; - " + signal.name + " (" + signal.type + ")<br>"
202
203            addOnName = "" if not widgetInfo.addOn else " (from add-on %s)" % widgetInfo.addOn.name
204   
205            widgetInfo.tooltipText = "<b><b>&nbsp;%s</b></b>%s<hr><b>Description:</b><br>&nbsp;&nbsp;%s<hr>%s<hr>%s" % (meta.name, addOnName, widgetInfo.description, formatedInList[:-4], formatedOutList[:-4]) 
206            widgets.append((meta.name, widgetInfo))
207        except Exception, msg:
208            if not hasErrors and not silent:
209                print "There were problems importing the following widgets:"
210                hasErrors = True
211            if not silent:
212                print "   %s: %s" % (widgname, msg)
213
214            if not prototype:
215                widgetsWithError.append(widgname)
216            else:
217                widgetsWithErrorPrototypes.append(widgname)
218       
219    return widgets
Note: See TracBrowser for help on using the repository browser.