Changeset 11745:21144138c193 in orange


Ignore:
Timestamp:
10/24/13 19:38:13 (6 months ago)
Author:
Ales Erjavec <ales.erjavec@…>
Branch:
default
Message:

Slight GUI and code style fixes for 'File' widget.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • Orange/OrangeWidgets/Data/OWFile.py

    r11719 r11745  
    77""" 
    88 
    9 # Don't move this - the line number of the call is important 
    10 def call(f,*args,**keyargs): 
    11     return f(*args, **keyargs) 
     9import os 
     10import sys 
     11import warnings 
     12 
     13import Orange 
    1214 
    1315from OWWidget import * 
    14 import OWGUI, string, os, sys, warnings 
    15 import orngIO 
     16import OWGUI 
    1617 
    1718NAME = "File" 
    18 ID = "orange.widgets.data.file" 
    1919 
    2020DESCRIPTION = """ 
     
    4040OUTPUTS = ( 
    4141    {"name": "Data", 
    42      "type": orange.ExampleTable, 
     42     "type": Orange.data.Table, 
    4343     "doc": "Attribute-valued data set read from the input file.", 
    44     }, 
     44     }, 
    4545) 
    4646 
    4747WIDGET_CLASS = "OWFile" 
    4848 
    49 # This is why the 'call''s line number is important. Actually you can 
    50 # move it but you need to make sure the following filter's lineno is updated 
    51 warnings.filterwarnings("error", ".*", orange.KernelWarning, "OWFile", 11) 
     49 
     50def call(f, *args, **kwargs): 
     51    return f(*args, **kwargs) 
     52 
     53# Make any KernelWarning raise an error if called through the 'call' function 
     54# defined above. 
     55warnings.filterwarnings( 
     56    "error", ".*", Orange.core.KernelWarning, 
     57    __name__, call.func_code.co_firstlineno + 1 
     58) 
    5259 
    5360 
     
    5966def addOrigin(examples, filename): 
    6067    vars = examples.domain.variables + examples.domain.getmetas().values() 
    61     strings = [var for var in vars if isinstance(var, orange.StringVariable)] 
     68    strings = [var for var in vars if isinstance(var, Orange.feature.String)] 
    6269    dirname, basename = os.path.split(filename) 
    6370    for var in strings: 
     
    6774 
    6875class OWFile(OWWidget): 
    69     settingsList=["recentFiles", "createNewOn", "showAdvanced"] 
     76    settingsList = ["recentFiles", "createNewOn", "showAdvanced"] 
    7077    contextHandlers = {"": FileNameContextHandler()} 
    7178 
    72     registeredFileTypes = [ft for ft in orange.getRegisteredFileTypes() if len(ft)>2 and ft[2]] 
    73     dlgFormats = 'Tab-delimited files (*.tab *.txt)\nC4.5 files (*.data)\nAssistant files (*.dat)\nRetis files (*.rda *.rdo)\nBasket files (*.basket)\n' \ 
    74                  + "\n".join("%s (%s)" % (ft[:2]) for ft in registeredFileTypes) \ 
    75                  + "\nAll files(*.*)" 
    76                   
    77     formats = {".tab": "Tab-delimited file", ".txt": "Tab-delimited file", ".data": "C4.5 file", 
    78                ".dat": "Assistant file", ".rda": "Retis file", ".rdo": "Retis file", 
    79                ".basket": "Basket file"} 
    80     formats.update(dict((ft[1][2:], ft[0]) for ft in registeredFileTypes)) 
    81       
    82     def __init__(self, parent=None, signalManager = None): 
    83         OWWidget.__init__(self, parent, signalManager, "File", wantMainArea = 0, resizingEnabled = 1) 
     79    registeredFileTypes = [ft[:2] for ft in Orange.core.getRegisteredFileTypes() 
     80                           if len(ft) > 2 and ft[2]] 
     81    dlgFormats = ( 
     82        'Tab-delimited files (*.tab *.txt)\n' 
     83        'C4.5 files (*.data)\n' 
     84        'Assistant files (*.dat)\n' 
     85        'Retis files (*.rda *.rdo)\n' 
     86        'Basket files (*.basket)\n' + 
     87        "\n".join("%s (%s)" % (ft[:2]) for ft in registeredFileTypes) + 
     88        "\nAll files(*.*)" 
     89    ) 
     90 
     91    formats = { 
     92        ".tab": "Tab-delimited file", 
     93        ".txt": "Tab-delimited file", 
     94        ".data": "C4.5 file", 
     95        ".dat": "Assistant file", 
     96        ".rda": "Retis file", 
     97        ".rdo": "Retis file", 
     98        ".basket": "Basket file" 
     99    } 
     100    formats.update(dict((ext.lstrip("*."), name) 
     101                        for name, ext in registeredFileTypes)) 
     102 
     103    def __init__(self, parent=None, signalManager=None): 
     104        OWWidget.__init__(self, parent, signalManager, "File", wantMainArea=0) 
    84105 
    85106        self.inputs = [] 
    86107        self.outputs = [("Data", ExampleTable)] 
    87108 
    88         self.recentFiles=["(none)"] 
     109        self.recentFiles = [] 
    89110        self.symbolDC = "?" 
    90111        self.symbolDK = "~" 
     
    95116        self.loadSettings() 
    96117 
    97         box = OWGUI.widgetBox(self.controlArea, "Data File", addSpace = True, orientation=0) 
     118        self.dataReport = None 
     119 
     120        box = OWGUI.widgetBox(self.controlArea, "Data File", addSpace=True, 
     121                              orientation="horizontal") 
    98122        self.filecombo = QComboBox(box) 
    99123        self.filecombo.setMinimumWidth(150) 
     124        self.filecombo.activated[int].connect(self.selectFile) 
     125 
    100126        box.layout().addWidget(self.filecombo) 
    101         button = OWGUI.button(box, self, '...', callback = self.browseFile, disabled=0) 
     127        button = OWGUI.button(box, self, '...', callback=self.browse) 
    102128        button.setIcon(self.style().standardIcon(QStyle.SP_DirOpenIcon)) 
    103129        button.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Fixed) 
    104          
    105         self.reloadBtn = OWGUI.button(box, self, "Reload", callback = self.reload, default=True) 
    106         self.reloadBtn.setIcon(self.style().standardIcon(QStyle.SP_BrowserReload)) 
     130 
     131        self.reloadBtn = OWGUI.button( 
     132            box, self, "Reload", callback=self.reload, default=True) 
     133 
     134        self.reloadBtn.setIcon( 
     135            self.style().standardIcon(QStyle.SP_BrowserReload) 
     136        ) 
    107137        self.reloadBtn.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) 
    108          
    109         box = OWGUI.widgetBox(self.controlArea, "Info", addSpace = True) 
     138 
     139        box = OWGUI.widgetBox(self.controlArea, "Info", addSpace=True) 
    110140        self.infoa = OWGUI.widgetLabel(box, 'No data loaded.') 
    111141        self.infob = OWGUI.widgetLabel(box, ' ') 
    112142        self.warnings = OWGUI.widgetLabel(box, ' ') 
    113          
     143 
    114144        #Set word wrap so long warnings won't expand the widget 
    115145        self.warnings.setWordWrap(True) 
    116         self.warnings.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.MinimumExpanding) 
    117          
    118         smallWidget = OWGUI.collapsableWidgetBox(self.controlArea, "Advanced settings", self, "showAdvanced", callback=self.adjustSize0) 
    119          
    120         box = OWGUI.widgetBox(smallWidget, "Missing Value Symbols") 
    121 #        OWGUI.widgetLabel(box, "Symbols for missing values in tab-delimited files (besides default ones)") 
    122          
    123         hbox = OWGUI.indentedBox(box) 
    124         OWGUI.lineEdit(hbox, self, "symbolDC", "Don't care:", labelWidth=80, orientation="horizontal", tooltip="Default values: '~' or '*'") 
    125         OWGUI.lineEdit(hbox, self, "symbolDK", "Don't know:", labelWidth=80, orientation="horizontal", tooltip="Default values: empty fields (space), '?' or 'NA'") 
    126  
     146        self.warnings.setSizePolicy(QSizePolicy.Ignored, 
     147                                    QSizePolicy.MinimumExpanding) 
     148 
     149        smallWidget = OWGUI.collapsableWidgetBox( 
     150            self.controlArea, "Advanced settings", self, "showAdvanced", 
     151            callback=self.adjustSize0) 
     152 
     153        box = QGroupBox("Missing Value Symbols") 
     154        form = QFormLayout(fieldGrowthPolicy=QFormLayout.AllNonFixedFieldsGrow) 
     155 
     156        form.addRow( 
     157            "Don't care:", 
     158            OWGUI.lineEdit(None, self, "symbolDC", 
     159                           tooltip="Default values: '~' or '*'") 
     160        ) 
     161        form.addRow( 
     162            "Don't know:", 
     163            OWGUI.lineEdit(None, self, "symbolDK", 
     164                           tooltip="Default values: empty fields (space), " 
     165                                   "'?' or 'NA'") 
     166        ) 
     167        box.setLayout(form) 
     168        smallWidget.layout().addWidget(box) 
    127169        smallWidget.layout().addSpacing(8) 
    128         OWGUI.radioButtonsInBox(smallWidget, self, "createNewOn", box="New Attributes", 
    129                        label = "Create a new attribute when existing attribute(s) ...", 
    130                        btnLabels = ["Have mismatching order of values", 
    131                                     "Have no common values with the new (recommended)", 
    132                                     "Miss some values of the new attribute", 
    133                                     "... Always create a new attribute" 
    134                                ]) 
    135          
     170 
     171        OWGUI.radioButtonsInBox( 
     172            smallWidget, self, "createNewOn", box="New Attributes", 
     173            label="Create a new attribute when existing attribute(s) ...", 
     174            btnLabels=["Have mismatching order of values", 
     175                       "Have no common values with the new (recommended)", 
     176                       "Miss some values of the new attribute", 
     177                       "... Always create a new attribute"] 
     178        ) 
     179 
    136180        OWGUI.rubber(smallWidget) 
    137181        smallWidget.updateControls() 
    138          
     182 
    139183        OWGUI.rubber(self.controlArea) 
    140          
     184 
    141185        # remove missing data set names 
    142186        def exists(path): 
     
    146190            else: 
    147191                return True 
     192 
    148193        self.recentFiles = filter(exists, self.recentFiles) 
    149194        self.setFileList() 
    150195 
    151196        if len(self.recentFiles) > 0 and exists(self.recentFiles[0]): 
    152             self.openFile(self.recentFiles[0], 0, self.symbolDK, self.symbolDC) 
    153  
    154         self.connect(self.filecombo, SIGNAL('activated(int)'), self.selectFile) 
     197            self.openFile(self.recentFiles[0]) 
    155198 
    156199    def adjustSize0(self): 
     
    160203    def setFileList(self): 
    161204        self.filecombo.clear() 
     205        model = self.filecombo.model() 
     206        iconprovider = QFileIconProvider() 
    162207        if not self.recentFiles: 
    163             self.filecombo.addItem("(none)") 
    164         for file in self.recentFiles: 
    165             if file == "(none)": 
    166                 self.filecombo.addItem("(none)") 
    167             else: 
    168                 self.filecombo.addItem(os.path.split(file)[1]) 
     208            item = QStandardItem("(none)") 
     209            item.setEnabled(False) 
     210            item.setSelectable(False) 
     211            model.appendRow([item]) 
     212        else: 
     213            for fname in self.recentFiles: 
     214                item = QStandardItem(os.path.basename(fname)) 
     215                item.setToolTip(fname) 
     216                item.setIcon(iconprovider.icon(QFileInfo(fname))) 
     217                model.appendRow(item) 
     218 
     219        self.filecombo.insertSeparator(self.filecombo.count()) 
    169220        self.filecombo.addItem("Browse documentation data sets...") 
    170          
     221        item = model.item(self.filecombo.count() - 1) 
     222        item.setEnabled(os.path.isdir(Orange.utils.environ.dataset_install_dir)) 
    171223 
    172224    def reload(self): 
    173225        if self.recentFiles: 
    174             return self.openFile(self.recentFiles[0], 1, self.symbolDK, self.symbolDC) 
    175  
     226            return self.openFile(self.recentFiles[0]) 
    176227 
    177228    def settingsFromWidgetCallback(self, handler, context): 
     
    183234 
    184235    def selectFile(self, n): 
    185         if n < len(self.recentFiles) : 
     236        if n < len(self.recentFiles): 
    186237            name = self.recentFiles[n] 
    187238            self.recentFiles.remove(name) 
    188239            self.recentFiles.insert(0, name) 
    189         elif n: 
    190             self.browseFile(1) 
     240        elif n >= 0: 
     241            self.browseDocDatasets() 
    191242 
    192243        if len(self.recentFiles) > 0: 
    193244            self.setFileList() 
    194             self.openFile(self.recentFiles[0], 0, self.symbolDK, self.symbolDC) 
    195  
    196     def browseFile(self, inDemos=0): 
    197         "Display a FileDialog and select a file" 
    198         if inDemos: 
    199             try: 
    200                 import orngConfiguration 
    201                 startfile = orngConfiguration.datasetsPath 
    202             except: 
    203                 startfile = "" 
    204                  
    205             if not startfile or not os.path.exists(startfile): 
    206                 try: 
    207                     import win32api, win32con 
    208                     t = win32api.RegOpenKey(win32con.HKEY_LOCAL_MACHINE, "SOFTWARE\\Python\\PythonCore\\%i.%i\\PythonPath\\Orange" % sys.version_info[:2], 0, win32con.KEY_READ) 
    209                     t = win32api.RegQueryValueEx(t, "")[0] 
    210                     startfile = t[:t.find("orange")] + "orange\\doc\\datasets" 
    211                 except: 
    212                     startfile = "" 
    213  
    214             if not startfile or not os.path.exists(startfile): 
    215                 widgetsdir = os.path.dirname(OWGUI.__file__) 
    216                 orangedir = os.path.dirname(widgetsdir) 
    217                 startfile = os.path.join(orangedir, "doc", "datasets") 
    218  
    219             if not startfile or not os.path.exists(startfile): 
    220                 d = os.getcwd() 
    221                 if os.path.basename(d) == "OrangeCanvas": 
    222                     startfile = os.path.join(os.path.dirname(d), "doc", "datasets") 
    223                 else: 
    224                     startfile = os.path.join(d, "doc", "datasets") 
    225  
    226             if not os.path.exists(startfile): 
    227                 QMessageBox.information( None, "File", "Cannot find the directory with example data sets", QMessageBox.Ok + QMessageBox.Default) 
    228                 return 
    229         else: 
     245            self.openFile(self.recentFiles[0]) 
     246 
     247    def browseDocDatasets(self): 
     248        """ 
     249        Display a FileDialog with the documentation datasets folder. 
     250        """ 
     251        self.browse(Orange.utils.environ.dataset_install_dir) 
     252 
     253    def browse(self, startpath=None): 
     254        """ 
     255        Display a FileDialog and select a file to open. 
     256        """ 
     257        if startpath is None: 
    230258            if len(self.recentFiles) == 0 or self.recentFiles[0] == "(none)": 
    231                 startfile = os.path.expanduser("~/") 
     259                startpath = os.path.expanduser("~/") 
    232260            else: 
    233                 startfile = self.recentFiles[0] 
    234  
    235         filename = QFileDialog.getOpenFileName(self, 'Open Orange Data File', startfile, self.dlgFormats) 
     261                startpath = self.recentFiles[0] 
     262 
     263        filename = QFileDialog.getOpenFileName( 
     264            self, 'Open Orange Data File', startpath, self.dlgFormats) 
     265 
    236266        filename = unicode(filename) 
    237          
     267 
    238268        if filename == "": 
    239269            return 
    240          
     270 
    241271        if filename in self.recentFiles: 
    242272            self.recentFiles.remove(filename) 
    243273        self.recentFiles.insert(0, filename) 
     274 
    244275        self.setFileList() 
    245276 
    246         self.openFile(self.recentFiles[0], 0, self.symbolDK, self.symbolDC) 
    247  
     277        self.openFile(filename) 
    248278 
    249279    # Open a file, create data from it and send it over the data channel 
    250     def openFile(self, fn, throughReload, DK=None, DC=None): 
    251         if self.processingHandler:  
    252             self.processingHandler(self, 1)    # focus on active widget 
     280    def openFile(self, fn): 
    253281        self.error() 
    254282        self.warning() 
    255283        self.information() 
    256          
     284 
    257285        if not os.path.exists(fn): 
    258             dirname, basename = os.path.split(fn) 
     286            basename = os.path.basename(fn) 
    259287            if os.path.exists(os.path.join("./", basename)): 
    260288                fn = os.path.join("./", basename) 
    261                 self.information("Loading '%s' from the current directory." % basename) 
     289                self.information("Loading '%s' from the current directory." % 
     290                                 basename) 
    262291 
    263292        self.closeContext() 
    264293        self.loadedFile = "" 
    265          
     294 
    266295        if fn == "(none)": 
    267296            self.send("Data", None) 
     
    270299            self.warnings.setText("") 
    271300            return 
    272              
    273         self.symbolDK = self.symbolDC = "" 
     301 
    274302        self.openContext("", fn) 
    275303 
    276304        self.loadedFile = "" 
    277305 
    278         argdict = {"createNewOn": 3-self.createNewOn} 
    279         if DK: 
    280             argdict["DK"] = str(DK) 
    281         if DC: 
    282             argdict["DC"] = str(DC) 
     306        argdict = {"createNewOn": 3 - self.createNewOn} 
     307        if self.symbolDK: 
     308            argdict["DK"] = str(self.symbolDK) 
     309        if self.symbolDC: 
     310            argdict["DC"] = str(self.symbolDC) 
    283311 
    284312        data = None 
    285313        try: 
    286             data = call(orange.ExampleTable, fn, **argdict) 
     314            data = call(Orange.data.Table, fn, **argdict) 
    287315            self.loadedFile = fn 
    288         except Exception, (errValue): 
    289             if "is being loaded as" in str(errValue): 
     316        except Exception as ex: 
     317            if "is being loaded as" in str(ex): 
    290318                try: 
    291                     data = orange.ExampleTable(fn, **argdict) 
    292                     self.warning(0, str(errValue)) 
     319                    data = Orange.data.Table(fn, **argdict) 
     320                    self.warning(0, str(ex)) 
    293321                except: 
    294322                    pass 
     323 
    295324            if data is None: 
    296                 self.error(str(errValue)) 
    297                 self.dataDomain = None 
     325                self.error(str(ex)) 
    298326                self.infoa.setText('Data was not loaded due to an error.') 
    299327                self.infob.setText('Error:') 
    300                 self.warnings.setText(str(errValue)) 
    301                 if self.processingHandler: self.processingHandler(self, 0)    # remove focus from this widget 
     328                self.warnings.setText(str(ex)) 
    302329                return 
    303                          
    304         self.dataDomain = data.domain 
    305  
    306         self.infoa.setText('%d example(s), ' % len(data) + '%d attribute(s), ' % len(data.domain.attributes) + '%d meta attribute(s).' % len(data.domain.getmetas())) 
    307         cl = data.domain.classVar 
    308         if cl: 
    309             if cl.varType == orange.VarTypes.Continuous: 
    310                     self.infob.setText('Regression; Numerical class.') 
    311             elif cl.varType == orange.VarTypes.Discrete: 
    312                     self.infob.setText('Classification; Discrete class with %d value(s).' % len(cl.values)) 
     330 
     331        self.infoa.setText('%d example(s), ' % len(data) + 
     332                           '%d attribute(s), ' % len(data.domain.attributes) + 
     333                           '%d meta attribute(s).' % len(data.domain.getmetas())) 
     334        cl = data.domain.class_var 
     335        if cl is not None: 
     336            if isinstance(cl, Orange.feature.Continuous): 
     337                self.infob.setText('Regression; Numerical class.') 
     338            elif isinstance(cl, Orange.feature.Discrete): 
     339                self.infob.setText( 
     340                    'Classification; Discrete class with %d value(s).' % 
     341                    len(cl.values) 
     342                ) 
    313343            else: 
    314344                self.infob.setText("Class is neither discrete nor continuous.") 
     
    316346            self.infob.setText("Data has no dependent variable.") 
    317347 
    318         warnings = "" 
    319         metas = data.domain.getmetas() 
    320         if hasattr(data, "attribute_load_status"):  # For some file formats, this is not populated 
    321             for status, messageUsed, messageNotUsed in [ 
    322                                     (orange.Variable.MakeStatus.Incompatible, 
    323                                      "", 
    324                                      "The following attributes already existed but had a different order of values, so new attributes needed to be created"), 
    325                                     (orange.Variable.MakeStatus.NoRecognizedValues, 
    326                                      "The following attributes were reused although they share no common values with the existing attribute of the same names", 
    327                                      "The following attributes were not reused since they share no common values with the existing attribute of the same names"), 
    328                                     (orange.Variable.MakeStatus.MissingValues, 
    329                                      "The following attribute(s) were reused although some values needed to be added", 
    330                                      "The following attribute(s) were not reused since they miss some values") 
    331                                     ]: 
    332                 if self.createNewOn > status: 
    333                     message = messageUsed 
    334                 else: 
    335                     message = messageNotUsed 
    336                 if not message: 
    337                     continue 
    338                 attrs = [attr.name for attr, stat in zip(data.domain, data.attributeLoadStatus) if stat == status] \ 
    339                       + [attr.name for id, attr in metas.items() if data.metaAttributeLoadStatus.get(id, -99) == status] 
    340                 if attrs: 
    341                     jattrs = ", ".join(attrs) 
    342                     if len(jattrs) > 80: 
    343                         jattrs = jattrs[:80] + "..." 
    344                     if len(jattrs) > 30:  
    345                         warnings += "<li>%s:<br/> %s</li>" % (message, jattrs) 
    346                     else: 
    347                         warnings += "<li>%s: %s</li>" % (message, jattrs) 
    348  
    349         self.warnings.setText(warnings) 
    350         #qApp.processEvents() 
    351         #self.adjustSize() 
     348        self.warnings.setText( 
     349            feature_load_status_report(data, self.createNewOn)) 
    352350 
    353351        addOrigin(data, fn) 
    354352        # make new data and send it 
    355         fName = os.path.split(fn)[1] 
    356         if "." in fName: 
    357             data.name = fName[:fName.rfind('.')] 
     353        name = os.path.basename(fn) 
     354        name, _ = os.path.splitext(name) 
     355        data.name = name 
     356 
     357        self.dataReport = self.prepareDataReport(data) 
     358 
     359        self.send("Data", data) 
     360 
     361    def sendReport(self): 
     362        if self.dataReport: 
     363            _, ext = os.path.splitext(self.loadedFile) 
     364            format = self.formats.get(ext, "unknown format") 
     365            self.reportSettings( 
     366                "File", [("File name", self.loadedFile), 
     367                         ("Format", format)]) 
     368            self.reportData(self.dataReport) 
     369 
     370 
     371def feature_load_status_report(data, create_new_on): 
     372    warnings = "" 
     373    metas = data.domain.getmetas() 
     374    attr_status = [] 
     375    meta_status = {} 
     376 
     377    if hasattr(data, "attribute_load_status"): 
     378        attr_status = data.attribute_load_status 
     379    elif hasattr(data, "attributeLoadStatus"): 
     380        attr_status = data.attributeLoadStatus 
     381 
     382    if hasattr(data, "meta_attribute_load_status"): 
     383        meta_status = data.meta_attribute_load_status 
     384    elif hasattr(data, "metaAttributeLoadStatus"): 
     385        meta_status = data.metaAttributeLoadStatus 
     386 
     387    for status, message_used, message_not_used in STATUS_MESASGES: 
     388        if create_new_on > status: 
     389            message = message_used 
    358390        else: 
    359             data.name = fName 
    360  
    361         self.dataReport = self.prepareDataReport(data) 
    362         self.send("Data", data) 
    363         if self.processingHandler: self.processingHandler(self, 0)    # remove focus from this widget 
    364  
    365     def sendReport(self): 
    366         if hasattr(self, "dataReport"): 
    367             self.reportSettings("File", 
    368                                 [("File name", self.loadedFile), 
    369                                  ("Format", self.formats.get(os.path.splitext(self.loadedFile)[1], "unknown format"))]) 
    370             self.reportData(self.dataReport) 
     391            message = message_not_used 
     392        if not message: 
     393            continue 
     394 
     395        attrs = [attr.name for attr, stat in zip(data.domain, attr_status) 
     396                 if stat == status] + \ 
     397                [attr.name for id, attr in metas.items() 
     398                 if meta_status.get(id, -99) == status] 
     399 
     400        if attrs: 
     401            jattrs = ", ".join(attrs) 
     402            if len(jattrs) > 80: 
     403                jattrs = jattrs[:80] + "..." 
     404            if len(jattrs) > 30: 
     405                warnings += "<li>%s:<br/> %s</li>" % (message, jattrs) 
     406            else: 
     407                warnings += "<li>%s: %s</li>" % (message, jattrs) 
     408    return warnings 
     409 
     410 
     411STATUS_MESASGES = [ 
     412    (Orange.feature.Descriptor.MakeStatus.Incompatible, 
     413     "", 
     414     "The following attributes already existed but had a different order " + 
     415     "of values, so new attributes needed to be created"), 
     416    (Orange.feature.Descriptor.MakeStatus.NoRecognizedValues, 
     417     "The following attributes were reused although they share no " + 
     418     "common values with the existing attribute of the same names", 
     419     "The following attributes were not reused since they share no " + 
     420     "common values with the existing attribute of the same names"), 
     421    (Orange.feature.Descriptor.MakeStatus.MissingValues, 
     422     "The following attribute(s) were reused although some values " + 
     423     "needed to be added", 
     424     "The following attribute(s) were not reused since they miss some values") 
     425] 
     426 
    371427 
    372428if __name__ == "__main__": 
Note: See TracChangeset for help on using the changeset viewer.