source: orange/Orange/misc/__init__.py @ 9698:968c27701d5a

Revision 9698:968c27701d5a, 18.1 KB checked in by anze <anze.staric@…>, 2 years ago (diff)

Removed import from orngMisc.

Line 
1"""
2.. index:: misc
3
4Module Orange.misc contains common functions and classes which are used in other modules.
5
6.. index: Random number generator
7
8-----------------------
9Random number generator
10-----------------------
11
12:obj:`Random` uses the
13`Mersenne twister <http://en.wikipedia.org/wiki/Mersenne_twister>`_ algorithm
14to generate random numbers.
15
16::
17
18    >>> import Orange
19    >>> rg = Orange.misc.Random(42)
20    >>> rg(10)
21    4
22    >>> rg(10)
23    7
24    >>> rg.uses  # We called rg two times.
25    2
26    >>> rg.reset()
27    >>> rg(10)
28    4
29    >>> rg(10)
30    7
31    >>> rg.uses
32    2
33
34
35.. class:: Random(initseed)
36
37    :param initseed: Seed used for initializing the random generator.
38    :type initseed: int
39
40    .. method:: __call__(n)
41
42        Return a random integer R such that 0 <= R < n.
43
44        :type n: int
45
46    .. method:: reset([initseed])
47
48        Reinitialize the random generator with `initseed`. If `initseed`
49        is not given use the existing value of attribute `initseed`.
50
51    .. attribute:: uses
52       
53        The number of times the generator was called after
54        initialization/reset.
55   
56    .. attribute:: initseed
57
58        Random seed.
59
60Two examples or random number generator uses found in the documentation
61are :obj:`Orange.evaluation.testing` and :obj:`Orange.data.Table`.
62
63.. automodule:: Orange.misc.counters
64  :members:
65
66.. automodule:: Orange.misc.render
67  :members:
68
69.. automodule:: Orange.misc.selection
70
71.. automodule:: Orange.misc.addons
72
73.. automodule:: Orange.misc.serverfiles
74
75.. automodule:: Orange.misc.environ
76
77.. automodule:: Orange.misc.r
78
79
80"""
81import environ
82import counters
83import render
84
85from Orange.core import RandomGenerator as Random
86
87# addons is intentionally not imported; if it were, add-ons' directories would
88# be added to the python path. If that sounds OK, this can be changed ...
89
90__all__ = ["counters", "selection", "render", "serverfiles",
91           "deprecated_members", "deprecated_keywords",
92           "deprecated_attribute", "deprecation_warning"]
93
94import random, types, sys
95import time
96
97def getobjectname(x, default=""):
98    if type(x)==types.StringType:
99        return x
100     
101    for i in ["name", "shortDescription", "description", "func_doc", "func_name"]:
102        if getattr(x, i, ""):
103            return getattr(x, i)
104
105    if hasattr(x, "__class__"):
106        r = repr(x.__class__)
107        if r[1:5]=="type":
108            return str(x.__class__)[7:-2]
109        elif r[1:6]=="class":
110            return str(x.__class__)[8:-2]
111    return default
112
113
114def demangle_examples(x):
115    if type(x)==types.TupleType:
116        return x
117    else:
118        return x, 0
119
120
121def frange(*argw):
122    """ Like builtin `range` but works with floats
123    """
124    start, stop, step = 0.0, 1.0, 0.1
125    if len(argw)==1:
126        start=step=argw[0]
127    elif len(argw)==2:
128        stop, step = argw
129    elif len(argw)==3:
130        start, stop, step = argw
131    elif len(argw)>3:
132        raise AttributeError, "1-3 arguments expected"
133
134    stop+=1e-10
135    i=0
136    res=[]
137    while 1:
138        f=start+i*step
139        if f>stop:
140            break
141        res.append(f)
142        i+=1
143    return res
144
145verbose = 0
146
147def print_verbose(text, *verb):
148    if len(verb) and verb[0] or verbose:
149        print text
150
151__doc__ += """\
152------------------
153Reporting progress
154------------------
155
156.. autoclass:: Orange.misc.ConsoleProgressBar
157    :members:
158
159"""
160
161class ConsoleProgressBar(object):
162    """ A class to for printing progress bar reports in the console.
163   
164    Example ::
165   
166        >>> import sys, time
167        >>> progress = ConsoleProgressBar("Example", output=sys.stdout)
168        >>> for i in range(100):
169        ...    progress.advance()
170        ...    # Or
171        ...    progress.set_state(i)
172        ...    time.sleep(0.01)
173        ...
174        ...
175        Example ===================================>100%
176       
177    """
178    def __init__(self, title="", charwidth=40, step=1, output=None):
179        """ Initialize the progress bar.
180       
181        :param title: The title for the progress bar.
182        :type title: str
183        :param charwidth: The maximum progress bar width in characters.
184       
185            .. todo:: Get the console width from the ``output`` if the
186                information can be retrieved.
187               
188        :type charwidth: int
189        :param step: A default step used if ``advance`` is called without
190            any  arguments
191       
192        :type step: int
193        :param output: The output file. If None (default) then ``sys.stderr``
194            is used.
195           
196        :type output: An file like object to print the progress report to.
197         
198        """
199        self.title = title + " "
200        self.charwidth = charwidth
201        self.step = step
202        self.currstring = ""
203        self.state = 0
204        if output is None:
205            output = sys.stderr
206        self.output = output
207
208    def clear(self, i=-1):
209        """ Clear the current progress line indicator string.
210        """
211        try:
212            if hasattr(self.output, "isatty") and self.output.isatty():
213                self.output.write("\b" * (i if i != -1 else len(self.currstring)))
214            else:
215                self.output.seek(-i if i != -1 else -len(self.currstring), 2)
216        except Exception: ## If for some reason we failed
217            self.output.write("\n")
218
219    def getstring(self):
220        """ Return the progress indicator string.
221        """
222        progchar = int(round(float(self.state) * (self.charwidth - 5) / 100.0))
223        return self.title + "=" * (progchar) + ">" + " " * (self.charwidth\
224            - 5 - progchar) + "%3i" % int(round(self.state)) + "%"
225
226    def printline(self, string):
227        """ Print the ``string`` to the output file.
228        """
229        try:
230            self.clear()
231            self.output.write(string)
232            self.output.flush()
233        except Exception:
234            pass
235        self.currstring = string
236
237    def __call__(self, newstate=None):
238        """ Set the ``newstate`` as the current state of the progress bar.
239        ``newstate`` must be in the interval [0, 100].
240       
241        .. note:: ``set_state`` is the prefered way to set a new steate.
242       
243        :param newstate: The new state of the progress bar.
244        :type newstate: float
245         
246        """
247        if newstate is None:
248            self.advance()
249        else:
250            self.set_state(newstate)
251           
252    def set_state(self, newstate):
253        """ Set the ``newstate`` as the current state of the progress bar.
254        ``newstate`` must be in the interval [0, 100].
255       
256        :param newstate: The new state of the progress bar.
257        :type newstate: float
258       
259        """
260        if int(newstate) != int(self.state):
261            self.state = newstate
262            self.printline(self.getstring())
263        else:
264            self.state = newstate
265           
266    def advance(self, step=None):
267        """ Advance the current state by ``step``. If ``step`` is None use
268        the default step as set at class initialization.
269         
270        """
271        if step is None:
272            step = self.step
273           
274        newstate = self.state + step
275        self.set_state(newstate)
276
277    def finish(self):
278        """ Finish the progress bar (i.e. set the state to 100 and
279        print the final newline to the ``output`` file).
280        """
281        self.__call__(100)
282        self.output.write("\n")
283
284def progress_bar_milestones(count, iterations=100):
285    return set([int(i*count/float(iterations)) for i in range(iterations)])
286
287def lru_cache(maxsize=100):
288    """ A least recently used cache function decorator.
289    (Similar to the functools.lru_cache in python 3.2)
290    """
291   
292    def decorating_function(func):
293        import functools
294        cache = {}
295       
296        @functools.wraps(func)
297        def wrapped(*args, **kwargs):
298            key = args + tuple(sorted(kwargs.items()))
299            if key not in cache:
300                res = func(*args, **kwargs)
301                cache[key] = (time.time(), res)
302                if len(cache) > maxsize:
303                    key, (_, _) = min(cache.iteritems(), key=lambda item: item[1][0])
304                    del cache[key]
305            else:
306                _, res = cache[key]
307                cache[key] = (time.time(), res) # update the time
308               
309            return res
310       
311        def clear():
312            cache.clear()
313       
314        wrapped.clear = clear
315        wrapped._cache = cache
316       
317        return wrapped
318    return decorating_function
319
320#from Orange.misc.render import contextmanager
321from contextlib import contextmanager
322
323
324@contextmanager
325def member_set(obj, name, val):
326    """ A context manager that sets member ``name`` on ``obj`` to ``val``
327    and restores the previous value on exit.
328    """
329    old_val = getattr(obj, name, val)
330    setattr(obj, name, val)
331    yield
332    setattr(obj, name, old_val)
333   
334   
335class recursion_limit(object):
336    """ A context manager that sets a new recursion limit.
337   
338    """
339    def __init__(self, limit=1000):
340        self.limit = limit
341       
342    def __enter__(self):
343        self.old_limit = sys.getrecursionlimit()
344        sys.setrecursionlimit(self.limit)
345   
346    def __exit__(self, exc_type, exc_val, exc_tb):
347        sys.setrecursionlimit(self.old_limit)
348
349
350__doc__ += """\
351-----------------------------
352Deprecation utility functions
353-----------------------------
354
355.. autofunction:: Orange.misc.deprecation_warning
356
357.. autofunction:: Orange.misc.deprecated_members
358
359.. autofunction:: Orange.misc.deprecated_keywords
360
361.. autofunction:: Orange.misc.deprecated_attribute
362
363.. autofunction:: Orange.misc.deprecated_function_name
364
365"""
366
367import warnings
368def deprecation_warning(old, new, stacklevel=-2):
369    """ Raise a deprecation warning of an obsolete attribute access.
370   
371    :param old: Old attribute name (used in warning message).
372    :param new: New attribute name (used in warning message).
373   
374    """
375    warnings.warn("'%s' is deprecated. Use '%s' instead!" % (old, new), DeprecationWarning, stacklevel=stacklevel)
376   
377# We need to get the instancemethod type
378class _Foo():
379    def bar(self):
380        pass
381instancemethod = type(_Foo.bar)
382del _Foo
383
384function = type(lambda: None)
385
386class universal_set(set):
387    """ A universal set, pretends it contains everything.
388    """
389    def __contains__(self, value):
390        return True
391   
392from functools import wraps
393
394def deprecated_members(name_map, wrap_methods="all", in_place=True):
395    """ Decorate a class with properties for accessing attributes, and methods
396    with deprecated names. In addition methods from the `wrap_methods` list
397    will be wrapped to receive mapped keyword arguments.
398   
399    :param name_map: A dictionary mapping old into new names.
400    :type name_map: dict
401   
402    :param wrap_methods: A list of method names to wrap. Wrapped methods will
403        be called with mapped keyword arguments (by default all methods will
404        be wrapped).
405    :type wrap_methods: list
406   
407    :param in_place: If True the class will be modified in place, otherwise
408        it will be subclassed (default True).
409    :type in_place: bool
410   
411    Example ::
412           
413        >>> class A(object):
414        ...     def __init__(self, foo_bar="bar"):
415        ...         self.set_foo_bar(foo_bar)
416        ...     
417        ...     def set_foo_bar(self, foo_bar="bar"):
418        ...         self.foo_bar = foo_bar
419        ...
420        ... A = deprecated_members(
421        ... {"fooBar": "foo_bar",
422        ...  "setFooBar":"set_foo_bar"},
423        ... wrap_methods=["set_foo_bar", "__init__"])(A)
424        ...
425        ...
426        >>> a = A(fooBar="foo")
427        __main__:1: DeprecationWarning: 'fooBar' is deprecated. Use 'foo_bar' instead!
428        >>> print a.fooBar, a.foo_bar
429        foo foo
430        >>> a.setFooBar("FooBar!")
431        __main__:1: DeprecationWarning: 'setFooBar' is deprecated. Use 'set_foo_bar' instead!
432       
433    .. note:: This decorator does nothing if \
434        :obj:`Orange.misc.environ.orange_no_deprecated_members` environment \
435        variable is set to `True`.
436       
437    """
438    if environ.orange_no_deprecated_members:
439        return lambda cls: cls
440   
441    def is_wrapped(method):
442        """ Is member method already wrapped.
443        """
444        if getattr(method, "_deprecate_members_wrapped", False):
445            return True
446        elif hasattr(method, "im_func"):
447            im_func = method.im_func
448            return getattr(im_func, "_deprecate_members_wrapped", False)
449        else:
450            return False
451       
452    if wrap_methods == "all":
453        wrap_methods = universal_set()
454    elif not wrap_methods:
455        wrap_methods = set()
456       
457    def wrapper(cls):
458        cls_names = {}
459        # Create properties for accessing deprecated members
460        for old_name, new_name in name_map.items():
461            cls_names[old_name] = deprecated_attribute(old_name, new_name)
462           
463        # wrap member methods to map keyword arguments
464        for key, value in cls.__dict__.items():
465            if isinstance(value, (instancemethod, function)) \
466                and not is_wrapped(value) and key in wrap_methods:
467               
468                wrapped = deprecated_keywords(name_map)(value)
469                wrapped._deprecate_members_wrapped = True # A flag indicating this function already maps keywords
470                cls_names[key] = wrapped
471        if in_place:
472            for key, val in cls_names.items():
473                setattr(cls, key, val)
474            return cls
475        else:
476            return type(cls.__name__, (cls,), cls_names)
477       
478    return wrapper
479
480def deprecated_keywords(name_map):
481    """ Deprecates the keyword arguments of the function.
482   
483    Example ::
484   
485        >>> @deprecated_keywords({"myArg": "my_arg"})
486        ... def my_func(my_arg=None):
487        ...     print my_arg
488        ...
489        ...
490        >>> my_func(myArg="Arg")
491        __main__:1: DeprecationWarning: 'myArg' is deprecated. Use 'my_arg' instead!
492        Arg
493       
494    .. note:: This decorator does nothing if \
495        :obj:`Orange.misc.environ.orange_no_deprecated_members` environment \
496        variable is set to `True`.
497       
498    """
499    if environ.orange_no_deprecated_members:
500        return lambda func: func
501   
502    def decorator(func):
503        @wraps(func)
504        def wrap_call(*args, **kwargs):
505            kwargs = dict(kwargs)
506            for name in name_map:
507                if name in kwargs:
508                    deprecation_warning(name, name_map[name], stacklevel=3)
509                    kwargs[name_map[name]] = kwargs[name]
510                    del kwargs[name]
511            return func(*args, **kwargs)
512        return wrap_call
513    return decorator
514
515def deprecated_attribute(old_name, new_name):
516    """ Return a property object that accesses an attribute named `new_name`
517    and raises a deprecation warning when doing so.
518   
519    Example ::
520   
521        >>> class A(object):
522        ...     def __init__(self):
523        ...         self.my_attr = "123"
524        ...     myAttr = deprecated_attribute("myAttr", "my_attr")
525        ...
526        ...
527        >>> a = A()
528        >>> print a.myAttr
529        __main__:1: DeprecationWarning: 'myAttr' is deprecated. Use 'my_attr' instead!
530        123
531       
532    .. note:: This decorator does nothing and returns None if \
533        :obj:`Orange.misc.environ.orange_no_deprecated_members` environment \
534        variable is set to `True`.
535       
536    """
537    if environ.orange_no_deprecated_members:
538        return None
539   
540    def fget(self):
541        deprecation_warning(old_name, new_name, stacklevel=3)
542        return getattr(self, new_name)
543   
544    def fset(self, value):
545        deprecation_warning(old_name, new_name, stacklevel=3)
546        setattr(self, new_name, value)
547   
548    def fdel(self):
549        deprecation_warning(old_name, new_name, stacklevel=3)
550        delattr(self, new_name)
551   
552    prop = property(fget, fset, fdel,
553                    doc="A deprecated member '%s'. Use '%s' instead." % (old_name, new_name))
554    return prop
555
556
557def deprecated_function_name(func):
558    """ Return a wrapped function that raises an deprecation warning when
559    called. This should be used for deprecation of module level function names.
560   
561    Example ::
562   
563        >>> def func_a(arg):
564        ...    print "This is func_a  (used to be named funcA) called with", arg
565        ...
566        ...
567        >>> funcA = deprecated_function_name(func_a)
568        >>> funcA(None)
569         
570   
571    .. note:: This decorator does nothing and if \
572        :obj:`Orange.misc.environ.orange_no_deprecated_members` environment \
573        variable is set to `True`.
574       
575    """
576    if environ.orange_no_deprecated_members:
577        return func
578   
579    @wraps(func)
580    def wrapped(*args, **kwargs):
581        warnings.warn("Deprecated function name. Use %r instead!" % func.__name__,
582                      DeprecationWarning, stacklevel=2)
583        return func(*args, **kwargs)
584    return wrapped
585   
586
587"""
588Some utility functions common to Orange classes.
589 
590"""
591
592def _orange__new__(base=None):
593    """ Return an orange 'schizofrenic' __new__ class method.
594   
595    :param base: base orange class (default orange.Learner)
596    :type base: type
597         
598    Example::
599        class NewOrangeLearner(orange.Learner):
600            __new__ = _orange__new(orange.Learner)
601       
602    """
603    if base is None:
604        import Orange
605        base = Orange.core.Learner
606       
607    @wraps(base.__new__)
608    def _orange__new_wrapped(cls, data=None, **kwargs):
609        self = base.__new__(cls, **kwargs)
610        if data:
611            self.__init__(**kwargs)
612            return self.__call__(data)
613        else:
614            return self
615    return _orange__new_wrapped
616
617
618def _orange__reduce__(self):
619    """ A default __reduce__ method for orange types. Assumes the object
620    can be reconstructed with the call `constructor(__dict__)` where __dict__
621    if the stored (pickled) __dict__ attribute.
622   
623    Example::
624        class NewOrangeType(orange.Learner):
625            __reduce__ = _orange__reduce()
626    """ 
627    return type(self), (), dict(self.__dict__)
628
629
630demangleExamples = deprecated_function_name(demangle_examples)
631progressBarMilestones = deprecated_function_name(progress_bar_milestones)
632printVerbose = deprecated_function_name(print_verbose)
633
634# Must be imported after deprecation function definitions
635import selection
Note: See TracBrowser for help on using the repository browser.