-
Notifications
You must be signed in to change notification settings - Fork 2k
/
maintain.py
89 lines (71 loc) · 3.45 KB
/
maintain.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
''' This module contains code that helps in maintaining the Ckan codebase. '''
import logging
import re
log = logging.getLogger(__name__)
def deprecated(message=''):
''' This is a decorator used to mark functions as deprecated.
It logs a warning when the function is called. If a message is
passed it is also logged, this can be useful to indicate for example
that a different function should be used instead.
Additionally an exception is raised if the functions docstring does
not contain the word `deprecated`.'''
def decorator(fn):
# When decorating a function check that the docstring is correct.
if not fn.__doc__ or not re.search(r'\bdeprecated\b',
fn.__doc__, re.IGNORECASE):
raise Exception('Function %s() in module %s has been deprecated '
'but this is not mentioned in the docstring. '
'Please update the docstring for the function. '
'It must include the word `deprecated`.'
% (fn.__name__, fn.__module__))
# Log deprecated functions
log.info('Function %s() in module %s has been deprecated. %s'
% (fn.__name__, fn.__module__, message))
def wrapped(*args, **kw):
log.warning('Function %s() in module %s has been deprecated '
'and will be removed in a later release of ckan. %s'
% (fn.__name__, fn.__module__, message))
return fn(*args, **kw)
return wrapped
return decorator
def deprecate_context_item(item_name, message=''):
''' Deprecate a named item in the global context object.
It logs a warning when the item is accessed. If a mesage is passed, it is
also logged. This can be useful to indicate for example that a different
function should be used instead.
No warnings are given when an attempt to change or delete the named item
from the context object.
Example usage:
>>> c.facets = "Foobar"
>>> deprecate_context_item('facets', 'Use `c.search_facets` instead')
>>> print c.facets
2012-07-12 13:27:06,294 WARNI [ckan.lib.maintain] c.facets has been deprecated [...]
Foobar
This function works by attaching a property to the underlying
`pylons.util.AttribSafeContextObj` object which provides the storage of the
context object. ie - it adds a class-level attribute to the
`pylons.util.AttribSafeContextObj` at runtime.
'''
# prevent a circular import
from ckan.lib.base import c
class Fake(object):
def __init__(self, obj):
self._obj = obj
def __getattribute__(self,name):
obj = object.__getattribute__(self, '_obj')
if name == '_obj':
return obj
return getattr(obj, name)
# store the value in a fake object
setattr(c, item_name, Fake(getattr(c, item_name)))
# we need to store the origional __getattr__ and replace with our own one
if not hasattr(c.__class__, '__old_getattr__'):
def fake_attr(self, name):
obj = self.__class__.__dict__['__old_getattr__'](self, name)
if isinstance(obj, Fake):
return obj._obj
else:
return obj
get_attr = getattr(c.__class__, '__getattr__')
setattr(c.__class__, '__old_getattr__', get_attr)
setattr(c.__class__, '__getattr__', fake_attr)