source: orange/Orange/OrangeCanvas/registry/base.py @ 11368:7de87de13b64

Revision 11368:7de87de13b64, 6.3 KB checked in by Ales Erjavec <ales.erjavec@…>, 14 months ago (diff)

Added rst documentation for the registry package.

Fixing docstrings in the process.

Line 
1"""
2WidgetRegistry Base
3
4"""
5
6import logging
7import bisect
8
9from operator import attrgetter
10
11from . import description
12
13log = logging.getLogger(__name__)
14
15# Registry hex version
16VERSION_HEX = 0x000102
17
18
19class WidgetRegistry(object):
20    """
21    A container for widget and category descriptions.
22
23    This class is most often used with WidgetDiscovery class but can
24    be used separately.
25
26    >>> reg = WidgetRegistry()
27    >>> file_desc = WidgetDescription.from_module(
28    ...     "Orange.OrangeWidgets.Data.OWFile"
29    ... )
30    ...
31    >>> reg.register_widget(file_desc)  # register the description
32    >>> print reg.widgets()
33    [...
34
35    Parameters
36    ----------
37    other : :class:`WidgetRegistry`, optional
38        If supplied the registry is initialized with the contents of `other`.
39
40    """
41
42    def __init__(self, other=None):
43        # A list of (category, widgets_list) tuples ordered by priority.
44        self.registry = []
45        # tuples from 'registry' indexed by name
46        self._categories_dict = {}
47        # WidgetDscriptions by qualified name
48        self._widgets_dict = {}
49
50        if other is not None:
51            if not isinstance(other, WidgetRegistry):
52                raise TypeError("Expected a 'WidgetRegistry' got %r." \
53                                % type(other).__name__)
54
55            self.registry = list(other.registry)
56            self._categories_dict = dict(other._categories_dict)
57            self._widgets_dict = dict(other._widgets_dict)
58
59    def categories(self):
60        """
61        Return a list all top level :class:`CategoryDescription` instances
62        ordered by priority.
63
64        """
65        return [c for c, _ in self.registry]
66
67    def category(self, name):
68        """
69        Find a :class:`CategoryDescription` by its `name`.
70
71        .. note:: Categories are identified by `name` attribute in contrast
72                  with widgets which are identified by `qualified_name`.
73
74        Parameters
75        ----------
76        name : str
77            Category name
78
79        """
80        return self._categories_dict[name][0]
81
82    def has_category(self, name):
83        """
84        Does a category with `name` exist in this registry.
85
86        Parameters
87        ----------
88        name : str
89            Category name
90
91        """
92        return name in self._categories_dict
93
94    def widgets(self, category=None):
95        """
96        Return a list of all widgets in the registry. If `category` is
97        specified return only widgets which belong to the category.
98
99        Parameters
100        ----------
101        category : :class:`CategoryDescription` or str, optional
102            Return only descriptions of widgets belonging to the category.
103
104        """
105        if category is None:
106            categories = self.categories()
107        elif isinstance(category, basestring):
108            categories = [self.category(category)]
109        else:
110            categories = [category]
111
112        widgets = []
113        for cat in categories:
114            if isinstance(cat, basestring):
115                cat = self.category(cat)
116            cat_widgets = self._categories_dict[cat.name][1]
117            widgets.extend(sorted(cat_widgets,
118                                  key=attrgetter("priority")))
119        return widgets
120
121    def widget(self, qualified_name):
122        """
123        Return a :class:`WidgetDescription` identified by `qualified_name`.
124
125        Raise :class:`KeyError` if the description does not exist.
126
127        Parameters
128        ----------
129        qualified_name : str
130            Widget description qualified name
131
132        See also
133        --------
134        WidgetDescription
135
136        """
137        return self._widgets_dict[qualified_name]
138
139    def has_widget(self, qualified_name):
140        """
141        Does the widget with `qualified_name` exist in this registry.
142        """
143        return qualified_name in self._widgets_dict
144
145    def register_widget(self, desc):
146        """
147        Register a :class:`WidgetDescription` instance.
148        """
149        if not isinstance(desc, description.WidgetDescription):
150            raise TypeError("Expected a 'WidgetDescription' got %r." \
151                            % type(desc).__name__)
152
153        if self.has_widget(desc.qualified_name):
154            raise ValueError("%r already exists in the registry." \
155                             % desc.qualified_name)
156
157        category = desc.category
158        if category is None:
159            category = "Unspecified"
160
161        if self.has_category(category):
162            cat_desc = self.category(category)
163        else:
164            log.warning("Creating a default category %r.", category)
165            cat_desc = description.CategoryDescription(name=category)
166            self.register_category(cat_desc)
167
168        self._insert_widget(cat_desc, desc)
169
170    def register_category(self, desc):
171        """
172        Register a :class:`CategoryDescription` instance.
173
174        .. note:: It is always best to register the category
175                  before the widgets belonging to it.
176
177        """
178        if not isinstance(desc, description.CategoryDescription):
179            raise TypeError("Expected a 'CategoryDescription' got %r." \
180                            % type(desc).__name__)
181
182        name = desc.name
183        if not name:
184            log.info("Creating a default category name.")
185            name = "default"
186
187        if any(name == c.name for c in self.categories()):
188            log.info("A category with %r name already exists" % name)
189            return
190
191        self._insert_category(desc)
192
193    def _insert_category(self, desc):
194        """
195        Insert category description into 'registry' list
196        """
197        priority = desc.priority
198        priorities = [c.priority for c, _ in self.registry]
199        insertion_i = bisect.bisect_right(priorities, priority)
200
201        item = (desc, [])
202        self.registry.insert(insertion_i, item)
203        self._categories_dict[desc.name] = item
204
205    def _insert_widget(self, category, desc):
206        """
207        Insert widget description `desc` into `category`.
208        """
209        assert(isinstance(category, description.CategoryDescription))
210        _, widgets = self._categories_dict[category.name]
211
212        priority = desc.priority
213        priorities = [w.priority for w in widgets]
214        insertion_i = bisect.bisect_right(priorities, priority)
215        widgets.insert(insertion_i, desc)
216        self._widgets_dict[desc.qualified_name] = desc
Note: See TracBrowser for help on using the repository browser.