Changeset 11252:e50ca88b9854 in orange


Ignore:
Timestamp:
01/08/13 12:26:33 (16 months ago)
Author:
Ales Erjavec <ales.erjavec@…>
Branch:
default
Message:

Changes to widget descriptors for better documentation/help.

Location:
Orange
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • Orange/OrangeCanvas/registry/base.py

    r11157 r11252  
    1414 
    1515# Registry hex version 
    16 VERSION_HEX = 0x001001 
     16VERSION_HEX = 0x000101 
    1717 
    1818 
  • Orange/OrangeCanvas/registry/description.py

    r11171 r11252  
    66import os 
    77import sys 
    8  
     8import warnings 
    99 
    1010# Exceptions 
     11 
    1112 
    1213class DescriptionError(Exception): 
     
    2627 
    2728 
    28 ############## 
    29 # Signal flags 
    30 ############## 
     29############### 
     30# Channel flags 
     31############### 
    3132 
    3233# A single signal 
     
    6162    handler : str 
    6263        Name of the handler method for the signal. 
    63     parameters : int 
    64         Parameter flags. 
     64    flags : int, optional 
     65        Channel flags. 
     66    id : str 
     67        A unique id of the input signal. 
     68    doc : str, optional 
     69        A docstring documenting the channel. 
    6570 
    6671    """ 
    67     def __init__(self, name, type, handler, parameters=Single + NonDefault): 
     72    def __init__(self, name, type, handler, flags=Single + NonDefault, 
     73                 id=None, doc=None): 
    6874        self.name = name 
    6975        self.type = type 
    7076        self.handler = handler 
    71  
    72         if isinstance(parameters, basestring): 
    73             # parameters are stored as strings 
    74             parameters = eval(parameters) 
    75  
    76         if not (parameters & Single or parameters & Multiple): 
    77             parameters += Single 
    78  
    79         if not (parameters & Default or parameters & NonDefault): 
    80             parameters += NonDefault 
    81  
    82         self.single = parameters & Single 
    83         self.default = parameters & Default 
    84         self.explicit = parameters & Explicit 
     77        self.id = id 
     78        self.doc = doc 
     79 
     80        if isinstance(flags, basestring): 
     81            # flags are stored as strings 
     82            warnings.warn("Passing 'flags' as string is deprecated, use " 
     83                          "integer constants instead", 
     84                          PendingDeprecationWarning) 
     85            flags = eval(flags) 
     86 
     87        if not (flags & Single or flags & Multiple): 
     88            flags += Single 
     89 
     90        if not (flags & Default or flags & NonDefault): 
     91            flags += NonDefault 
     92 
     93        self.single = flags & Single 
     94        self.default = flags & Default 
     95        self.explicit = flags & Explicit 
     96        self.flags = flags 
     97 
     98 
     99def input_channel_from_args(args): 
     100    if isinstance(args, tuple): 
     101        return InputSignal(*args) 
     102    elif isinstance(args, dict): 
     103        return InputSignal(**args) 
     104    elif isinstance(args, InputSignal): 
     105        return args 
     106    else: 
     107        raise TypeError 
    85108 
    86109 
     
    94117    type : str or `type` 
    95118        Type of the output signals. 
    96     parameters : int 
    97         Parameter flags. 
     119    flags : int, optional 
     120        Channel flags. 
     121    id : str 
     122        A unique id of the output signal. 
     123    doc : str, optional 
     124        A docstring documenting the channel. 
    98125 
    99126    """ 
    100     def __init__(self, name, type, parameters=Single + NonDefault): 
     127    def __init__(self, name, type, flags=Single + NonDefault, 
     128                 id=None, doc=None): 
    101129        self.name = name 
    102130        self.type = type 
    103  
    104         if isinstance(parameters, basestring): 
    105             # parameters are stored as strings 
    106             parameters = eval(parameters) 
    107  
    108         if not (parameters & Single or parameters & Multiple): 
    109             parameters += Single 
    110  
    111         if not (parameters & Default or parameters & NonDefault): 
    112             parameters += NonDefault 
    113  
    114         self.single = parameters & Single 
    115         self.default = parameters & Default 
    116         self.explicit = parameters & Explicit 
    117  
    118         self.dynamic = parameters & Dynamic 
     131        self.id = id 
     132        self.doc = doc 
     133 
     134        if isinstance(flags, basestring): 
     135            # flags are stored as strings 
     136            warnings.warn("Passing 'flags' as string is deprecated, use " 
     137                          "integer constants instead", 
     138                          PendingDeprecationWarning) 
     139            flags = eval(flags) 
     140 
     141        if not (flags & Single or flags & Multiple): 
     142            flags += Single 
     143 
     144        if not (flags & Default or flags & NonDefault): 
     145            flags += NonDefault 
     146 
     147        self.single = flags & Single 
     148        self.default = flags & Default 
     149        self.explicit = flags & Explicit 
     150        self.dynamic = flags & Dynamic 
     151        self.flags = flags 
     152 
    119153        if self.dynamic and not self.single: 
    120154            raise SignalSpecificationError( 
     
    123157 
    124158 
     159def output_channel_from_args(args): 
     160    if isinstance(args, tuple): 
     161        return OutputSignal(*args) 
     162    elif isinstance(args, dict): 
     163        return OutputSignal(**args) 
     164    elif isinstance(args, InputSignal): 
     165        return args 
     166    else: 
     167        raise TypeError 
     168 
     169 
    125170class WidgetDescription(object): 
    126171    """Description of a widget. 
    127172 
    128173    Parameters 
    129     ========== 
     174    ---------- 
    130175    name : str 
    131         A human readable name of the widget (required). 
    132     category : str 
    133         A name of the category in which this widget belongs (optional). 
    134     version : str 
    135         Version of the widget (optional). 
    136     description : str 
    137         A short description of the widget, suitable for a tool tip (optional). 
    138     long_description : str 
    139         A longer description of the widget (optional). 
    140     quialified_name : str 
    141         A qualified name (import name) of the class implementation (required). 
    142     package : str 
    143         A package name where the widget is implemented (optional). 
    144     project_name : str 
    145         The distribution name that provides the widget (optional) 
    146     inputs : list of `InputSignal` 
     176        A human readable name of the widget. 
     177    id : str 
     178        A unique identifier of the widget (in most situations this should 
     179        be the full module name). 
     180    category : str, optional 
     181        A name of the category in which this widget belongs. 
     182    version : str, optional 
     183        Version of the widget. By default the widget inherits the project 
     184        version. 
     185    description : str, optional 
     186        A short description of the widget, suitable for a tool tip. 
     187    long_description : str, optional 
     188        A longer description of the widget, suitable for a 'what's this?' 
     189        role. 
     190    qualified_name : str 
     191        A qualified name (import name) of the class implementing the widget. 
     192    package : str, optional 
     193        A package name where the widget is implemented. 
     194    project_name : str, optional 
     195        The distribution name that provides the widget. 
     196    inputs : list of `InputSignal`, optional 
    147197        A list of input channels provided by the widget. 
    148     outputs : list of `OutputSignal` 
    149         A list of output channels provided the widget. 
    150     help : str 
    151         URL or an URL scheme of a detailed widget help page. 
    152     author : str 
     198    outputs : list of `OutputSignal`, optional 
     199        A list of output channels provided by the widget. 
     200    help : str, optional 
     201        URL or an Resource template of a detailed widget help page. 
     202    author : str, optional 
    153203        Author name. 
    154     author_email : str 
     204    author_email : str, optional 
    155205        Author email address. 
    156     maintainer : str 
     206    maintainer : str, optional 
    157207        Maintainer name 
    158     maintainer_email : str 
     208    maintainer_email : str, optional 
    159209        Maintainer email address. 
    160     keywords : str 
    161         A comma separated list of keyword phrases. 
    162     priority : int 
     210    keywords : list-of-str, optional 
     211        A list of keyword phrases. 
     212    priority : int, optional 
    163213        Widget priority (the order of the widgets in a GUI presentation). 
    164     icon : str 
     214    icon : str, optional 
    165215        A filename of the widget icon (in relation to the package). 
    166     background : str 
     216    background : str, optional 
    167217        Widget's background color (in the canvas GUI). 
     218    replaces: list-of-str, optional 
     219        A list of `id`s this widget replaces (optional). 
    168220 
    169221    """ 
    170     def __init__(self, name=None, category=None, version=None, 
     222    def __init__(self, name, id, category=None, version=None, 
    171223                 description=None, long_description=None, 
    172224                 qualified_name=None, package=None, project_name=None, 
    173                  inputs=[], outputs=[], help=None, 
     225                 inputs=[], outputs=[], 
    174226                 author=None, author_email=None, 
    175227                 maintainer=None, maintainer_email=None, 
    176                  url=None, keywords=None, priority=sys.maxint, 
     228                 help=None, url=None, keywords=None, 
     229                 priority=sys.maxint, 
    177230                 icon=None, background=None, 
     231                 replaces=None, 
    178232                 ): 
    179233 
     
    183237 
    184238        self.name = name 
     239        self.id = id 
    185240        self.category = category 
    186241        self.version = version 
     
    202257        self.icon = icon 
    203258        self.background = background 
     259        self.replaces = replaces 
    204260 
    205261    def __str__(self): 
    206         return "WidgetDescription(name=%(name)r, category=%(category)r, ...)" \ 
    207                 % self.__dict__ 
     262        return ("WidgetDescription(name=%(name)r, id=%(id)r), " 
     263                "category=%(category)r, ...)") % self.__dict__ 
    208264 
    209265    def __repr__(self): 
     
    242298        wmod = __import__(import_name, fromlist=[""]) 
    243299 
     300        qualified_name = "%s.%s" % (import_name, widget_name) 
     301 
    244302        inputs = eval(meta.inputList) 
    245303        outputs = eval(meta.outputList) 
    246304 
    247         inputs = [InputSignal(*input) for input in inputs] 
    248         outputs = [OutputSignal(*output) for output in outputs] 
     305        inputs = map(input_channel_from_args, inputs) 
     306 
     307        outputs = map(output_channel_from_args, outputs) 
    249308 
    250309        # Resolve signal type names into concrete type instances 
     
    263322        desc = WidgetDescription( 
    264323             name=meta.name, 
     324             id=qualified_name, 
    265325             category=meta.category, 
    266326             description=meta.description, 
    267              qualified_name="%s.%s" % (import_name, widget_name), 
     327             qualified_name=qualified_name, 
    268328             package=wmod.__package__, 
    269329             keywords=meta.tags, 
     
    312372            raise WidgetSpecificationError 
    313373 
     374        qualified_name = "%s.%s" % (module.__name__, widget_class.__name__) 
     375 
     376        id = getattr(module, "ID", module_name) 
    314377        inputs = getattr(module, "INPUTS", []) 
    315378        outputs = getattr(module, "OUTPUTS", []) 
    316379        category = getattr(module, "CATEGORY", default_cat_name) 
     380        version = getattr(module, "VERSION", None) 
    317381        description = getattr(module, "DESCRIPTION", name) 
    318  
    319         qualified_name = "%s.%s" % (module.__name__, widget_class.__name__) 
     382        long_description = getattr(module, "LONG_DESCRIPTION", None) 
     383        author = getattr(module, "AUTHOR", None) 
     384        author_email = getattr(module, "AUTHOR_EMAIL", None) 
     385        maintainer = getattr(module, "MAINTAINER", None) 
     386        maintainer_email = getattr(module, "MAINTAINER_EMAIL", None) 
     387        help = getattr(module, "HELP", None) 
     388        url = getattr(module, "URL", None) 
    320389 
    321390        icon = getattr(module, "ICON", None) 
    322391        priority = getattr(module, "PRIORITY", sys.maxint) 
    323392        keywords = getattr(module, "KEYWORDS", None) 
    324  
    325         inputs = [InputSignal(*t) for t in inputs] 
    326         outputs = [OutputSignal(*t) for t in outputs] 
     393        background = getattr(module, "BACKGROUND", None) 
     394        replaces = getattr(module, "REPLACES", None) 
     395 
     396        inputs = map(input_channel_from_args, inputs) 
     397        outputs = map(output_channel_from_args, outputs) 
    327398 
    328399        # Convert all signal types into qualified names. 
     
    335406        return WidgetDescription( 
    336407            name=name, 
     408            id=id, 
    337409            category=category, 
     410            version=version, 
    338411            description=description, 
     412            long_description=long_description, 
    339413            qualified_name=qualified_name, 
    340414            package=module.__package__, 
    341415            inputs=inputs, 
    342416            outputs=outputs, 
     417            author=author, 
     418            author_email=author_email, 
     419            maintainer=maintainer, 
     420            maintainer_email=maintainer_email, 
     421            help=help, 
     422            url=url, 
     423            keywords=keywords, 
     424            priority=priority, 
    343425            icon=icon, 
    344             priority=priority, 
    345             keywords=keywords) 
     426            background=background, 
     427            replaces=replaces) 
    346428 
    347429 
     
    350432 
    351433    Parameters 
    352     ========== 
     434    ---------- 
    353435 
    354436    name : str 
     
    376458                 description=None, long_description=None, 
    377459                 qualified_name=None, package=None, 
    378                  project_name=None, help=None, 
    379                  author=None, author_email=None, 
     460                 project_name=None, author=None, author_email=None, 
    380461                 maintainer=None, maintainer_email=None, 
    381                  url=None, keywords=None, 
     462                 url=None, help=None, keywords=None, 
    382463                 widgets=None, priority=sys.maxint, 
    383464                 icon=None, background=None 
     
    391472        self.package = package 
    392473        self.project_name = project_name 
    393         self.help = help 
    394474        self.author = author 
    395475        self.author_email = author_email 
     
    397477        self.maintainer_email = maintainer_email 
    398478        self.url = url 
     479        self.help = help 
    399480        self.keywords = keywords 
    400481        self.widgets = widgets or [] 
     
    428509        description = getattr(package, "DESCRIPTION", None) 
    429510        long_description = getattr(package, "LONG_DESCRIPTION", None) 
    430         help = getattr(package, "HELP", None) 
    431511        author = getattr(package, "AUTHOR", None) 
    432512        author_email = getattr(package, "AUTHOR_EMAIL", None) 
     
    434514        maintainer_email = getattr(package, "MAINTAINER_MAIL", None) 
    435515        url = getattr(package, "URL", None) 
     516        help = getattr(package, "HELP", None) 
    436517        keywords = getattr(package, "KEYWORDS", None) 
    437518        widgets = getattr(package, "WIDGETS", None) 
  • Orange/OrangeCanvas/registry/qt.py

    r11243 r11252  
    66 
    77from xml.sax.saxutils import escape 
     8from urllib import urlencode 
    89 
    910from PyQt4.QtGui import ( 
     
    203204        else: 
    204205            icon = "icons/default-category.svg" 
     206 
    205207        icon = icon_loader.from_description(desc).get(icon) 
    206208        item.setIcon(icon) 
     
    217219 
    218220        tooltip = desc.description if desc.description else desc.name 
     221 
    219222        item.setToolTip(tooltip) 
    220223        item.setFlags(Qt.ItemIsEnabled) 
     
    315318    title = desc.name 
    316319    help_url = desc.help 
     320 
     321    if not help_url: 
     322        help_url = "help://search?" + urlencode({"id": desc.id}) 
     323 
    317324    description = desc.description 
    318  
    319     template = "<h3>{title}</h3>" + \ 
    320                "<p>{description}</p>" + \ 
    321                ("<a href='{url}'>more...</a>" if help_url else "") 
    322     help_text = template.format(title=title, description=description, 
    323                                 url=help_url) 
    324     return help_text 
     325    long_description = desc.long_description 
     326 
     327    template = ["<h3>{0}</h3>".format(escape(title))] 
     328 
     329    if description: 
     330        template.append("<p>{0}</p>".format(escape(description))) 
     331 
     332    if long_description: 
     333        template.append("<p>{0}</p>".format(escape(long_description[:100]))) 
     334 
     335    if help_url: 
     336        template.append("<a href='{0}'>more...</a>".format(escape(help_url))) 
     337 
     338    return "\n".join(template) 
    325339 
    326340 
  • Orange/OrangeWidgets/Data/OWFile.py

    r11096 r11252  
    3232 
    3333NAME = "File" 
    34 DESCRIPTION = "Reads a data table from a file." 
    35  
    36 LONG_DESCRIPTION = """Read a data table from a supported file format on 
    37 the the filesystem and send it to the the output.""" 
     34ID = "orange.widgets.data.file" 
     35 
     36DESCRIPTION = """ 
     37Read a data table from a supported file format on the the file system and 
     38send it to the the output. 
     39""" 
     40 
     41LONG_DESCRIPTION = """ 
     42This is the widget you will probably use at the start of every schema to read 
     43the input data file (data table with examples). The widget maintains a 
     44history of most recently used data files. For convenience, the history 
     45also includes a directory with the sample data sets that come with Orange. 
     46""" 
    3847 
    3948ICON = "icons/File.svg" 
     
    4251PRIORITY = 10 
    4352CATEGORY = "Data" 
    44 HELP = "docs/html/data/file.html" 
    45  
    46 OUTPUTS = [("Data", orange.ExampleTable,)] 
     53 
     54KEYWORDS = ["data", "file", "load", "read"] 
     55 
     56OUTPUTS = [{"name": "Data", 
     57            "type": orange.ExampleTable, 
     58            "doc": "Attribute-valued data set read from the input file."}] 
    4759 
    4860WIDGET_CLASS = "OWFile" 
  • Orange/OrangeWidgets/Data/__init__.py

    r11095 r11252  
    99NAME = "Data" 
    1010 
     11ID = "orange.widgets.data" 
     12 
    1113DESCRIPTION = """Widgets for data manipulation""" 
    1214 
    13 LONG_DESRIPTION = """\ 
    14 This category contains widgets for data manipulation. 
    15 This includes loading, importing, saving, preprocessing, 
    16 selection, etc. 
     15LONG_DESRIPTION = """ 
     16This category contains widgets for data manipulation. This includes 
     17loading, importing, saving, preprocessing, selection, etc. 
    1718 
    1819""" 
Note: See TracChangeset for help on using the changeset viewer.