source: orange/orange/Orange/misc/__init__.py @ 7777:8c5acaad0dc1

Revision 7777:8c5acaad0dc1, 12.1 KB checked in by ales_erjavec <ales.erjavec@…>, 3 years ago (diff)

Restored serverfiles import. My last commit overwrote it.

Line 
1"""
2
3.. index:: misc
4
5Module Orange.misc contains common functions and classes which are used in other modules.
6
7==================
8Counters
9==================
10
11.. index:: misc
12.. index::
13   single: misc; counters
14
15.. automodule:: Orange.misc.counters
16  :members:
17
18==================
19Render
20==================
21
22.. index:: misc
23.. index::
24   single: misc; render
25
26.. automodule:: Orange.misc.render
27  :members:
28
29==================
30Selection
31==================
32
33.. index:: selection
34.. index::
35   single: misc; selection
36
37Many machine learning techniques generate a set different solutions or have to
38choose, as for instance in classification tree induction, between different
39features. The most trivial solution is to iterate through the candidates,
40compare them and remember the optimal one. The problem occurs, however, when
41there are multiple candidates that are equally good, and the naive approaches
42would select the first or the last one, depending upon the formulation of
43the if-statement.
44
45:class:`Orange.misc.selection` provides a class that makes a random choice
46in such cases. Each new candidate is compared with the currently optimal
47one; it replaces the optimal if it is better, while if they are equal,
48one is chosen by random. The number of competing optimal candidates is stored,
49so in this random choice the probability to select the new candidate (over the
50current one) is 1/w, where w is the current number of equal candidates,
51including the present one. One can easily verify that this gives equal
52chances to all candidates, independent of the order in which they are presented.
53
54.. automodule:: Orange.misc.selection
55  :members:
56
57Example
58--------
59
60The following snippet loads the data set lymphography and prints out the
61feature with the highest information gain.
62
63part of `misc-selection-bestonthefly.py`_ (uses `lymphography.tab`_)
64
65.. literalinclude:: code/misc-selection-bestonthefly.py
66  :lines: 7-16
67
68Our candidates are tuples gain ratios and features, so we set
69:obj:`callCompareOn1st` to make the compare function compare the first element
70(gain ratios). We could achieve the same by initializing the object like this:
71
72part of `misc-selection-bestonthefly.py`_ (uses `lymphography.tab`_)
73
74.. literalinclude:: code/misc-selection-bestonthefly.py
75  :lines: 18-18
76
77
78The other way to do it is through indices.
79
80`misc-selection-bestonthefly.py`_ (uses `lymphography.tab`_)
81
82.. literalinclude:: code/misc-selection-bestonthefly.py
83  :lines: 25-
84
85.. _misc-selection-bestonthefly.py: code/misc-selection-bestonthefly.py.py
86.. _lymphography.tab: code/lymphography.tab
87
88Here we only give gain ratios to :obj:`bestOnTheFly`, so we don't have to specify a
89special compare operator. After checking all features we get the index of the
90optimal one by calling :obj:`winnerIndex`.
91
92==================
93Server files
94==================
95
96.. index:: server files
97
98.. automodule:: Orange.misc.serverfiles
99
100"""
101
102import counters
103import selection
104import render
105import serverfiles
106
107__all__ = ["counters", "selection", "render", "serverfiles",
108           "deprecated_members", "deprecated_keywords",
109           "deprecated_attribute", "deprecation_warning"]
110
111import random, types, sys
112import time
113
114def getobjectname(x, default=""):
115    if type(x)==types.StringType:
116        return x
117     
118    for i in ["name", "shortDescription", "description", "func_doc", "func_name"]:
119        if getattr(x, i, ""):
120            return getattr(x, i)
121
122    if hasattr(x, "__class__"):
123        r = repr(x.__class__)
124        if r[1:5]=="type":
125            return str(x.__class__)[7:-2]
126        elif r[1:6]=="class":
127            return str(x.__class__)[8:-2]
128    return default
129
130
131def demangleExamples(x):
132    if type(x)==types.TupleType:
133        return x
134    else:
135        return x, 0
136
137
138def frange(*argw):
139    start, stop, step = 0.0, 1.0, 0.1
140    if len(argw)==1:
141        start=step=argw[0]
142    elif len(argw)==2:
143        stop, step = argw
144    elif len(argw)==3:
145        start, stop, step = argw
146    elif len(argw)>3:
147        raise AttributeError, "1-3 arguments expected"
148
149    stop+=1e-10
150    i=0
151    res=[]
152    while 1:
153        f=start+i*step
154        if f>stop:
155            break
156        res.append(f)
157        i+=1
158    return res
159
160verbose = 0
161
162def printVerbose(text, *verb):
163    if len(verb) and verb[0] or verbose:
164        print text
165
166class ConsoleProgressBar(object):
167    def __init__(self, title="", charwidth=40, step=1, output=sys.stderr):
168        self.title = title + " "
169        self.charwidth = charwidth
170        self.step = step
171        self.currstring = ""
172        self.state = 0
173        self.output = output
174
175    def clear(self, i=-1):
176        try:
177            if hasattr(self.output, "isatty") and self.output.isatty():
178                self.output.write("\b" * (i if i != -1 else len(self.currstring)))
179            else:
180                self.output.seek(-i if i != -1 else -len(self.currstring), 2)
181        except Exception: ## If for some reason we failed
182            self.output.write("\n")
183
184    def getstring(self):
185        progchar = int(round(float(self.state) * (self.charwidth - 5) / 100.0))
186        return self.title + "=" * (progchar) + ">" + " " * (self.charwidth\
187            - 5 - progchar) + "%3i" % int(round(self.state)) + "%"
188
189    def printline(self, string):
190        try:
191            self.clear()
192            self.output.write(string)
193            self.output.flush()
194        except Exception:
195            pass
196        self.currstring = string
197
198    def __call__(self, newstate=None):
199        if newstate == None:
200            newstate = self.state + self.step
201        if int(newstate) != int(self.state):
202            self.state = newstate
203            self.printline(self.getstring())
204        else:
205            self.state = newstate
206
207    def finish(self):
208        self.__call__(100)
209        self.output.write("\n")
210
211def progressBarMilestones(count, iterations=100):
212    return set([int(i*count/float(iterations)) for i in range(iterations)])
213
214def lru_cache(maxsize=100):
215    """ A least recently used cache function decorator.
216    (Similar to the functools.lru_cache in python 3.2)
217    """
218   
219    def decorating_function(func):
220        import functools
221        cache = {}
222       
223        functools.wraps(func)
224        def wrapped(*args, **kwargs):
225            key = args + tuple(sorted(kwargs.items()))
226            if key not in cache:
227                res = func(*args, **kwargs)
228                cache[key] = (time.time(), res)
229                if len(cache) > maxsize:
230                    key, (_, _) = min(cache.iteritems(), key=lambda item: item[1][0])
231                    del cache[key]
232            else:
233                _, res = cache[key]
234                cache[key] = (time.time(), res) # update the time
235               
236            return res
237       
238        def clear():
239            cache.clear()
240       
241        wrapped.clear = clear
242       
243        return wrapped
244    return decorating_function
245
246
247"""\
248Deprecation utility functions.
249
250"""
251
252import warnings
253def deprecation_warning(old, new, stacklevel=-2):
254    warnings.warn("'%s' is deprecated. Use '%s' instead!" % (old, new), DeprecationWarning, stacklevel=stacklevel)
255   
256# We need to get the instancemethod type
257class _Foo():
258    def bar(self):
259        pass
260instancemethod = type(_Foo.bar)
261del _Foo
262
263function = type(lambda: None)
264
265class universal_set(set):
266    """ A universal set, pretends it contains everything.
267    """
268    def __contains__(self, value):
269        return True
270   
271from functools import wraps
272
273def deprecated_members(name_map, wrap_methods="all", in_place=True):
274    """ Decorate a class with properties for accessing attributes, and methods
275    with deprecated names. In addition methods from the `wrap_methods` list
276    will be wrapped to receive mapped keyword arguments.
277   
278    :param name_map: A dictionary mapping old into new names.
279    :type name_map: dict
280   
281    :param wrap_methods: A list of method names to wrap. Wrapped methods will
282        be called with mapped keyword arguments (by default all methods will
283        be wrapped).
284    :type wrap_methods: list
285   
286    Example ::
287           
288        >>> @deprecated_members({"fooBar": "foo_bar", "setFooBar":"set_foo_bar"},
289        ...                    wrap_methods=["set_foo_bar", "__init__"])
290        ... class A(object):
291        ...     def __init__(self, foo_bar="bar"):
292        ...         self.set_foo_bar(foo_bar)
293        ...     
294        ...     def set_foo_bar(self, foo_bar="bar"):
295        ...         self.foo_bar = foo_bar
296        ...         
297        ...
298        >>> a = A(fooBar="foo")
299        __main__:1: DeprecationWarning: 'fooBar' is deprecated. Use 'foo_bar' instead!
300        >>> print a.fooBar, a.foo_bar
301        foo foo
302        >>> a.setFooBar("FooBar!")
303        __main__:1: DeprecationWarning: 'setFooBar' is deprecated. Use 'set_foo_bar' instead!
304       
305    """
306    def is_wrapped(method):
307        """ Is member method already wrapped.
308        """
309        if getattr(method, "_deprecate_members_wrapped", False):
310            return True
311        elif hasattr(method, "im_func"):
312            im_func = method.im_func
313            return getattr(im_func, "_deprecate_members_wrapped", False)
314        else:
315            return False
316       
317    if wrap_methods == "all":
318        wrap_methods = universal_set()
319    elif not wrap_methods:
320        wrap_methods = set()
321       
322    def wrapper(cls):
323        cls_names = {}
324        # Create properties for accessing deprecated members
325        for old_name, new_name in name_map.items():
326            cls_names[old_name] = deprecated_attribute(old_name, new_name)
327           
328        # wrap member methods to map keyword arguments
329        for key, value in cls.__dict__.items():
330            if isinstance(value, (instancemethod, function)) \
331                and not is_wrapped(value) and key in wrap_methods:
332               
333                wrapped = deprecated_keywords(name_map)(value)
334                wrapped._deprecate_members_wrapped = True # A flag indicating this function already maps keywords
335                cls_names[key] = wrapped
336        if in_place:
337            for key, val in cls_names.items():
338                setattr(cls, key, val)
339            return cls
340        else:
341            return type(cls.__name__, (cls,), cls_names)
342       
343    return wrapper
344
345def deprecated_keywords(name_map):
346    """ Deprecates the keyword arguments of the function.
347   
348    Example ::
349   
350        >>> @deprecated_keywords({"myArg": "my_arg"})
351        ... def my_func(my_arg=None):
352        ...     print my_arg
353        ...
354        ...
355        >>> my_func(myArg="Arg")
356        __main__:1: DeprecationWarning: 'myArg' is deprecated. Use 'my_arg' instead!
357        Arg
358       
359    """
360    def decorator(func):
361        @wraps(func)
362        def wrap_call(*args, **kwargs):
363            kwargs = dict(kwargs)
364            for name in name_map:
365                if name in kwargs:
366                    deprecation_warning(name, name_map[name], stacklevel=3)
367                    kwargs[name_map[name]] = kwargs[name]
368                    del kwargs[name]
369            return func(*args, **kwargs)
370        return wrap_call
371    return decorator
372
373def deprecated_attribute(old_name, new_name):
374    """ Return a property object that accesses an attribute named `new_name`
375    and raises a deprecation warning when doing so.
376   
377    Example ::
378   
379        >>> class A(object):
380        ...     def __init__(self):
381        ...         self.my_attr = "123"
382        ...     myAttr = deprecated_attribute("myAttr", "my_attr")
383        ...
384        ...
385        >>> a = A()
386        >>> print a.myAttr
387        __main__:1: DeprecationWarning: 'myAttr' is deprecated. Use 'my_attr' instead!
388        123
389       
390    """
391    def fget(self):
392        deprecation_warning(old_name, new_name, stacklevel=3)
393        return getattr(self, new_name)
394   
395    def fset(self, value):
396        deprecation_warning(old_name, new_name, stacklevel=3)
397        setattr(self, new_name, value)
398   
399    def fdel(self):
400        deprecation_warning(old_name, new_name, stacklevel=3)
401        delattr(self, new_name)
402   
403    prop = property(fget, fset, fdel,
404                    doc="A deprecated member '%s'. Use '%s' instead." % (old_name, new_name))
405    return prop
406   
407def _test():
408    import doctest
409    doctest.testmod()
410   
411if __name__ == "__main__":
412    _test()
Note: See TracBrowser for help on using the repository browser.