Ignore:
Timestamp:
03/19/12 12:14:20 (2 years ago)
Author:
markotoplak
Branch:
default
rebase_source:
92659cf777626f5bc411357989a821dd2083e466
Message:

Moved deprecation functions, progress bar support and environ into Orange.utils. Orange imports cleanly, although it is not tested yet.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • Orange/misc/__init__.py

    r10521 r10580  
    11""" 
    22.. index:: misc 
    3  
    4 Module Orange.misc contains common functions and classes which are used in other modules. 
    53 
    64.. index: CostMatrix 
     
    331329are :obj:`Orange.evaluation.testing` and :obj:`Orange.data.Table`. 
    332330 
    333 ------------------ 
    334 Reporting progress 
    335 ------------------ 
    336  
    337 .. autoclass:: Orange.misc.ConsoleProgressBar 
    338     :members: 
    339  
    340 ----------------------------- 
    341 Deprecation utility functions 
    342 ----------------------------- 
    343  
    344 .. autofunction:: Orange.misc.deprecation_warning 
    345  
    346 .. autofunction:: Orange.misc.deprecated_members 
    347  
    348 .. autofunction:: Orange.misc.deprecated_keywords 
    349  
    350 .. autofunction:: Orange.misc.deprecated_attribute 
    351  
    352 .. autofunction:: Orange.misc.deprecated_function_name  
    353  
    354331 
    355332---------------- 
     
    369346.. automodule:: Orange.misc.serverfiles 
    370347 
    371 .. automodule:: Orange.misc.environ 
    372  
    373348""" 
    374 import environ 
    375349import counters 
    376350import render 
    377  
     351from functools import wraps 
    378352from Orange.core import RandomGenerator as Random 
    379 from orange import SymMatrix 
    380 from orange import CostMatrix 
     353from Orange.core import SymMatrix 
     354from Orange.core import CostMatrix 
    381355 
    382356# addons is intentionally not imported; if it were, add-ons' directories would 
    383357# be added to the python path. If that sounds OK, this can be changed ... 
    384358 
    385 __all__ = ["counters", "selection", "render", "serverfiles", 
    386            "deprecated_members", "deprecated_keywords", 
    387            "deprecated_attribute", "deprecation_warning"] 
     359__all__ = ["counters", "selection", "render", "serverfiles" ] 
    388360 
    389361import random, types, sys 
     
    412384    else: 
    413385        return x, 0 
    414  
    415386 
    416387def frange(*argw): 
     
    443414    if len(verb) and verb[0] or verbose: 
    444415        print text 
    445  
    446  
    447 class ConsoleProgressBar(object): 
    448     """ A class to for printing progress bar reports in the console. 
    449      
    450     Example :: 
    451      
    452         >>> import sys, time 
    453         >>> progress = ConsoleProgressBar("Example", output=sys.stdout) 
    454         >>> for i in range(100): 
    455         ...    progress.advance() 
    456         ...    # Or progress.set_state(i) 
    457         ...    time.sleep(0.01) 
    458         ... 
    459         ... 
    460         Example ===================================>100% 
    461          
    462     """ 
    463     def __init__(self, title="", charwidth=40, step=1, output=None): 
    464         """ Initialize the progress bar. 
    465          
    466         :param title: The title for the progress bar. 
    467         :type title: str 
    468         :param charwidth: The maximum progress bar width in characters. 
    469          
    470             .. todo:: Get the console width from the ``output`` if the 
    471                 information can be retrieved.  
    472                  
    473         :type charwidth: int 
    474         :param step: A default step used if ``advance`` is called without 
    475             any  arguments 
    476          
    477         :type step: int 
    478         :param output: The output file. If None (default) then ``sys.stderr`` 
    479             is used. 
    480              
    481         :type output: An file like object to print the progress report to. 
    482           
    483         """ 
    484         self.title = title + " " 
    485         self.charwidth = charwidth 
    486         self.step = step 
    487         self.currstring = "" 
    488         self.state = 0 
    489         if output is None: 
    490             output = sys.stderr 
    491         self.output = output 
    492  
    493     def clear(self, i=-1): 
    494         """ Clear the current progress line indicator string. 
    495         """ 
    496         try: 
    497             if hasattr(self.output, "isatty") and self.output.isatty(): 
    498                 self.output.write("\b" * (i if i != -1 else len(self.currstring))) 
    499             else: 
    500                 self.output.seek(-i if i != -1 else -len(self.currstring), 2) 
    501         except Exception: ## If for some reason we failed  
    502             self.output.write("\n") 
    503  
    504     def getstring(self): 
    505         """ Return the progress indicator string. 
    506         """ 
    507         progchar = int(round(float(self.state) * (self.charwidth - 5) / 100.0)) 
    508         return self.title + "=" * (progchar) + ">" + " " * (self.charwidth\ 
    509             - 5 - progchar) + "%3i" % int(round(self.state)) + "%" 
    510  
    511     def printline(self, string): 
    512         """ Print the ``string`` to the output file. 
    513         """ 
    514         try: 
    515             self.clear() 
    516             self.output.write(string) 
    517             self.output.flush() 
    518         except Exception: 
    519             pass 
    520         self.currstring = string 
    521  
    522     def __call__(self, newstate=None): 
    523         """ Set the ``newstate`` as the current state of the progress bar. 
    524         ``newstate`` must be in the interval [0, 100]. 
    525          
    526         .. note:: ``set_state`` is the prefered way to set a new steate.  
    527          
    528         :param newstate: The new state of the progress bar. 
    529         :type newstate: float 
    530           
    531         """ 
    532         if newstate is None: 
    533             self.advance() 
    534         else: 
    535             self.set_state(newstate) 
    536              
    537     def set_state(self, newstate): 
    538         """ Set the ``newstate`` as the current state of the progress bar. 
    539         ``newstate`` must be in the interval [0, 100].  
    540          
    541         :param newstate: The new state of the progress bar. 
    542         :type newstate: float 
    543          
    544         """ 
    545         if int(newstate) != int(self.state): 
    546             self.state = newstate 
    547             self.printline(self.getstring()) 
    548         else: 
    549             self.state = newstate 
    550              
    551     def advance(self, step=None): 
    552         """ Advance the current state by ``step``. If ``step`` is None use 
    553         the default step as set at class initialization. 
    554            
    555         """ 
    556         if step is None: 
    557             step = self.step 
    558              
    559         newstate = self.state + step 
    560         self.set_state(newstate) 
    561  
    562     def finish(self): 
    563         """ Finish the progress bar (i.e. set the state to 100 and 
    564         print the final newline to the ``output`` file). 
    565         """ 
    566         self.__call__(100) 
    567         self.output.write("\n") 
    568  
    569 def progress_bar_milestones(count, iterations=100): 
    570     return set([int(i*count/float(iterations)) for i in range(iterations)]) 
    571416 
    572417def lru_cache(maxsize=100): 
     
    606451from contextlib import contextmanager 
    607452 
    608  
    609453@contextmanager 
    610454def member_set(obj, name, val): 
     
    632476        sys.setrecursionlimit(self.old_limit) 
    633477         
    634  
    635 import warnings 
    636 def deprecation_warning(old, new, stacklevel=-2): 
    637     """ Raise a deprecation warning of an obsolete attribute access. 
    638      
    639     :param old: Old attribute name (used in warning message). 
    640     :param new: New attribute name (used in warning message). 
    641      
    642     """ 
    643     warnings.warn("'%s' is deprecated. Use '%s' instead!" % (old, new), DeprecationWarning, stacklevel=stacklevel) 
    644     
    645 # We need to get the instancemethod type  
    646 class _Foo(): 
    647     def bar(self): 
    648         pass 
    649 instancemethod = type(_Foo.bar) 
    650 del _Foo 
    651  
    652 function = type(lambda: None) 
    653  
    654 class universal_set(set): 
    655     """ A universal set, pretends it contains everything. 
    656     """ 
    657     def __contains__(self, value): 
    658         return True 
    659      
    660 from functools import wraps 
    661  
    662 def deprecated_members(name_map, wrap_methods="all", in_place=True): 
    663     """ Decorate a class with properties for accessing attributes, and methods 
    664     with deprecated names. In addition methods from the `wrap_methods` list 
    665     will be wrapped to receive mapped keyword arguments. 
    666      
    667     :param name_map: A dictionary mapping old into new names. 
    668     :type name_map: dict 
    669      
    670     :param wrap_methods: A list of method names to wrap. Wrapped methods will 
    671         be called with mapped keyword arguments (by default all methods will 
    672         be wrapped). 
    673     :type wrap_methods: list 
    674      
    675     :param in_place: If True the class will be modified in place, otherwise 
    676         it will be subclassed (default True). 
    677     :type in_place: bool 
    678      
    679     Example :: 
    680              
    681         >>> class A(object): 
    682         ...     def __init__(self, foo_bar="bar"): 
    683         ...         self.set_foo_bar(foo_bar) 
    684         ...      
    685         ...     def set_foo_bar(self, foo_bar="bar"): 
    686         ...         self.foo_bar = foo_bar 
    687         ... 
    688         ... A = deprecated_members( 
    689         ... {"fooBar": "foo_bar",  
    690         ...  "setFooBar":"set_foo_bar"}, 
    691         ... wrap_methods=["set_foo_bar", "__init__"])(A) 
    692         ...  
    693         ... 
    694         >>> a = A(fooBar="foo") 
    695         __main__:1: DeprecationWarning: 'fooBar' is deprecated. Use 'foo_bar' instead! 
    696         >>> print a.fooBar, a.foo_bar 
    697         foo foo 
    698         >>> a.setFooBar("FooBar!") 
    699         __main__:1: DeprecationWarning: 'setFooBar' is deprecated. Use 'set_foo_bar' instead! 
    700          
    701     .. note:: This decorator does nothing if \ 
    702         :obj:`Orange.misc.environ.orange_no_deprecated_members` environment \ 
    703         variable is set to `True`. 
    704          
    705     """ 
    706     if environ.orange_no_deprecated_members: 
    707         return lambda cls: cls 
    708      
    709     def is_wrapped(method): 
    710         """ Is member method already wrapped. 
    711         """ 
    712         if getattr(method, "_deprecate_members_wrapped", False): 
    713             return True 
    714         elif hasattr(method, "im_func"): 
    715             im_func = method.im_func 
    716             return getattr(im_func, "_deprecate_members_wrapped", False) 
    717         else: 
    718             return False 
    719          
    720     if wrap_methods == "all": 
    721         wrap_methods = universal_set() 
    722     elif not wrap_methods: 
    723         wrap_methods = set() 
    724          
    725     def wrapper(cls): 
    726         cls_names = {} 
    727         # Create properties for accessing deprecated members 
    728         for old_name, new_name in name_map.items(): 
    729             cls_names[old_name] = deprecated_attribute(old_name, new_name) 
    730              
    731         # wrap member methods to map keyword arguments 
    732         for key, value in cls.__dict__.items(): 
    733             if isinstance(value, (instancemethod, function)) \ 
    734                 and not is_wrapped(value) and key in wrap_methods: 
    735                  
    736                 wrapped = deprecated_keywords(name_map)(value) 
    737                 wrapped._deprecate_members_wrapped = True # A flag indicating this function already maps keywords 
    738                 cls_names[key] = wrapped 
    739         if in_place: 
    740             for key, val in cls_names.items(): 
    741                 setattr(cls, key, val) 
    742             return cls 
    743         else: 
    744             return type(cls.__name__, (cls,), cls_names) 
    745          
    746     return wrapper 
    747  
    748 def deprecated_keywords(name_map): 
    749     """ Deprecates the keyword arguments of the function. 
    750      
    751     Example :: 
    752      
    753         >>> @deprecated_keywords({"myArg": "my_arg"}) 
    754         ... def my_func(my_arg=None): 
    755         ...     print my_arg 
    756         ... 
    757         ... 
    758         >>> my_func(myArg="Arg") 
    759         __main__:1: DeprecationWarning: 'myArg' is deprecated. Use 'my_arg' instead! 
    760         Arg 
    761          
    762     .. note:: This decorator does nothing if \ 
    763         :obj:`Orange.misc.environ.orange_no_deprecated_members` environment \ 
    764         variable is set to `True`. 
    765          
    766     """ 
    767     if environ.orange_no_deprecated_members: 
    768         return lambda func: func 
    769     for name in name_map.values(): 
    770         if name in name_map: 
    771             raise ValueError("Deprecation keys and values overlap; this could" 
    772                              " cause trouble!") 
    773      
    774     def decorator(func): 
    775         @wraps(func) 
    776         def wrap_call(*args, **kwargs): 
    777             kwargs = dict(kwargs) 
    778             for name in name_map: 
    779                 if name in kwargs: 
    780                     deprecation_warning(name, name_map[name], stacklevel=3) 
    781                     kwargs[name_map[name]] = kwargs[name] 
    782                     del kwargs[name] 
    783             return func(*args, **kwargs) 
    784         return wrap_call 
    785     return decorator 
    786  
    787 def deprecated_attribute(old_name, new_name): 
    788     """ Return a property object that accesses an attribute named `new_name` 
    789     and raises a deprecation warning when doing so. 
    790  
    791     .. 
    792  
    793         >>> sys.stderr = sys.stdout 
    794      
    795     Example :: 
    796      
    797         >>> class A(object): 
    798         ...     def __init__(self): 
    799         ...         self.my_attr = "123" 
    800         ...     myAttr = deprecated_attribute("myAttr", "my_attr") 
    801         ... 
    802         ... 
    803         >>> a = A() 
    804         >>> print a.myAttr 
    805         ...:1: DeprecationWarning: 'myAttr' is deprecated. Use 'my_attr' instead! 
    806         123 
    807          
    808     .. note:: This decorator does nothing and returns None if \ 
    809         :obj:`Orange.misc.environ.orange_no_deprecated_members` environment \ 
    810         variable is set to `True`. 
    811          
    812     """ 
    813     if environ.orange_no_deprecated_members: 
    814         return None 
    815      
    816     def fget(self): 
    817         deprecation_warning(old_name, new_name, stacklevel=3) 
    818         return getattr(self, new_name) 
    819      
    820     def fset(self, value): 
    821         deprecation_warning(old_name, new_name, stacklevel=3) 
    822         setattr(self, new_name, value) 
    823      
    824     def fdel(self): 
    825         deprecation_warning(old_name, new_name, stacklevel=3) 
    826         delattr(self, new_name) 
    827      
    828     prop = property(fget, fset, fdel, 
    829                     doc="A deprecated member '%s'. Use '%s' instead." % (old_name, new_name)) 
    830     return prop  
    831  
    832 class class_property(object): 
    833     def __init__(self, fget=None, fset=None, fdel=None, doc="class property"): 
    834         self.fget = fget 
    835         self.fset = fset 
    836         self.fdel = fdel 
    837         self.__doc__ = doc 
    838          
    839     def __get__(self, instance, owner): 
    840         if instance is None: 
    841             return self.fget(owner) 
    842         else: 
    843             return self.fget(instance)                 
    844              
    845 def deprecated_class_attribute(old_name, new_name): 
    846     """ Return a property object that accesses an class attribute 
    847     named `new_name` and raises a deprecation warning when doing so. 
    848      
    849     """ 
    850     if environ.orange_no_deprecated_members: 
    851         return None 
    852      
    853     def fget(self): 
    854         deprecation_warning(old_name, new_name, stacklevel=3) 
    855         return getattr(self, new_name) 
    856          
    857     prop = class_property(fget, 
    858                     doc="A deprecated class member '%s'. Use '%s' instead." % (old_name, new_name)) 
    859     return prop 
    860  
    861 def deprecated_function_name(func): 
    862     """ Return a wrapped function that raises an deprecation warning when 
    863     called. This should be used for deprecation of module level function names.  
    864      
    865     Example :: 
    866      
    867         >>> def func_a(arg): 
    868         ...    print "This is func_a  (used to be named funcA) called with", arg 
    869         ... 
    870         ... 
    871         >>> funcA = deprecated_function_name(func_a) 
    872         >>> funcA(None) 
    873            
    874      
    875     .. note:: This decorator does nothing and if \ 
    876         :obj:`Orange.misc.environ.orange_no_deprecated_members` environment \ 
    877         variable is set to `True`. 
    878          
    879     """ 
    880     if environ.orange_no_deprecated_members: 
    881         return func 
    882      
    883     @wraps(func) 
    884     def wrapped(*args, **kwargs): 
    885         warnings.warn("Deprecated function name. Use %r instead!" % func.__name__, 
    886                       DeprecationWarning, stacklevel=2) 
    887         return func(*args, **kwargs) 
    888     return wrapped 
    889      
    890  
    891478""" 
    892479Some utility functions common to Orange classes. 
     
    935522    return type(self), (), dict(self.__dict__) 
    936523 
     524from Orange.utils import deprecated_function_name 
    937525 
    938526demangleExamples = deprecated_function_name(demangle_examples) 
    939 progressBarMilestones = deprecated_function_name(progress_bar_milestones) 
    940527printVerbose = deprecated_function_name(print_verbose) 
    941528 
Note: See TracChangeset for help on using the changeset viewer.