Created
July 30, 2016 17:05
-
-
Save cdent/de50cb05a7ab8219cd4f5b4ab3c181dd to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import inspect | |
import collections | |
LATEST = 5.0 | |
METHODS = collections.defaultdict(list) | |
# From twisted | |
# https://github.com/twisted/twisted/blob/trunk/twisted/python/deprecate.py | |
def _fullyQualifiedName(obj): | |
""" | |
Return the fully qualified name of a module, class, method or function. | |
Classes and functions need to be module level ones to be correctly | |
qualified. | |
@rtype: C{str}. | |
""" | |
try: | |
name = obj.__qualname__ | |
except AttributeError: | |
name = obj.__name__ | |
if inspect.isclass(obj) or inspect.isfunction(obj): | |
moduleName = obj.__module__ | |
return "%s.%s" % (moduleName, name) | |
elif inspect.ismethod(obj): | |
try: | |
cls = obj.im_class | |
except AttributeError: | |
# Python 3 eliminates im_class, substitutes __module__ and | |
# __qualname__ to provide similar information. | |
return "%s.%s" % (obj.__module__, obj.__qualname__) | |
else: | |
className = _fullyQualifiedName(cls) | |
return "%s.%s" % (className, name) | |
return name | |
def find_method(f, version_float): | |
"""Look in METHODS for method with right name matching version.""" | |
method_list = METHODS[f.__name__] | |
for min_version, max_version, func in method_list: | |
if min_version <= version_float <= max_version: | |
return func | |
# no match found we need to go boom | |
raise ValueError('that version sucks %s' % version_float) | |
def mdec(min_version_string, max_version_string=None): | |
"""Build a dictionary of METHODS. | |
The key is the fully qualified name of the method. | |
The value is a list, highest to lowest, of the versioned methods | |
that do this thing. | |
""" | |
def decorator(f): | |
min_version_float = float(min_version_string) | |
if max_version_string: | |
max_version_float = float(max_version_string) | |
else: | |
max_version_float = LATEST | |
qualified_name = _fullyQualifiedName(f) | |
METHODS[f.__name__].append((min_version_float, max_version_float, f)) | |
def decorated_func(req, *args, **kwargs): | |
version_float = float(req['version_string']) | |
return find_method(f, version_float)(req, *args, **kwargs) | |
# Sort highest min version to beginning of list. | |
METHODS[f.__name__].sort(key=lambda x: x[0], reverse=True) | |
return decorated_func | |
return decorator | |
@mdec('1.1') | |
def thing(req): | |
print 'in some' | |
@mdec('1.2') | |
def thing(req): | |
print 'in none' | |
@mdec('0.9') | |
def thing(req): | |
print 'in low' | |
@mdec('1.1') | |
def house(req): | |
print 'in dec house' | |
@mdec('1.2') | |
def house(req): | |
print 'in undec house' | |
if __name__ == '__main__': | |
req = {} | |
req['version_string'] = '1.1' | |
thing(req) | |
house(req) | |
req['version_string'] = '1.2' | |
thing(req) | |
house(req) | |
req['version_string'] = '1.9' | |
thing(req) | |
house(req) | |
req['version_string'] = '0.9' | |
try: | |
thing(req) | |
except ValueError as exc: | |
print 'thing', exc | |
try: | |
house(req) | |
except ValueError as exc: | |
print 'house', exc |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment