changed the way the target method name is passed to pli.pattern.proxy.utils.proxymeth...
[pli.git] / pli / pattern / proxy / utils.py
blobe84894aef9f0db47db03f40dac5ba415e52f94ec
1 #=======================================================================
3 __version__ = '''0.0.09'''
4 __sub_version__ = '''20080906224521'''
5 __copyright__ = '''(c) Alex A. Naanou 2003'''
8 #-----------------------------------------------------------------------
10 import types
11 import new
12 import sys
15 #-----------------------------------------------------------------------
16 #----------------------------------------createmethodwrappersinobject---
17 ##!!! REVISE (rewrite or remove) !!!##
18 def createmethodwrappersinobject(source_obj, method_list, wrapper, target_obj):
19 '''
20 this will attach methods mentioned in method_list to the target object
21 that will wrap methods of the source object.
23 WARNING: this will render the target object unpicklable...
24 NOTE: this can be used for classes...
25 '''
26 for meth in method_list:
27 if hasattr(source_obj, meth):
28 setattr(target_obj, meth, wrapper(getattr(source_dict, meth)))
29 return target_obj
32 #------------------------------------------------createmethodwrappers---
33 ##!!! REVISE (rewrite or remove) !!!##
34 def createmethodwrappers(source_dict, method_list, wrapper, target_dict=None):
35 '''
36 this will wrap methods mentioned in method_list from the source dict and
37 will return a dict containing the wrappers (will update and return target_dict
38 if given).
39 '''
40 if target_dict != None:
41 res = target_dict
42 else:
43 res = {}
44 for meth in method_list:
45 if meth in source_dict:
46 res[meth] = wrapper(source_dict[meth])
47 return res
51 #-----------------------------------------------------------------------
52 # XXX attempt to get the class name form the context...
53 ##!!! TEST !!!##
54 def superproxymethod(methodname, source_attr, class_name, exceptions=Exception, depth=1, decorators=()):
55 '''
56 create a proxy to the method name in the containing namespace.
58 this constructed proxy will attempt to call an existing method, and
59 in case it fails with exceptions, it will call the alternative from
60 the source_attr.
62 NOTE: this will add the method_name to the containing namespace.
63 NOTE: source_attr is to be used as the attr name referencing the source object.
64 '''
65 # text of the new function....
66 txt = '''\
67 def %(method_name)s(self, *p, **n):
68 """
69 this is the proxy to %(method_name)s method.
70 """
71 try:
72 return super(%(class_name)s, self).%(method_name)s(*p, **n)
73 except (%(exceptions)s):
74 return self.%(source_attr)s.%(method_name)s(*p, **n)
75 proxy = %(method_name)s'''
76 # execute the above code...
77 exec (txt % {
78 'method_name': method_name,
79 'source_attr': source_attr,
80 'class_name': class_name,
81 'exceptions': type(exceptions) in (tuple, list) \
82 and ', '.join([ e.__name__ for e in exceptions ]) \
83 or exceptions.__name__,
85 # run the decorators...
86 for d in decorators:
87 proxy = d(proxy)
88 # update the NS...
89 sys._getframe(depth).f_locals[method_name] = proxy
92 #---------------------------------------------------------proxymethod---
93 # NOTE: the interface changed, so if you used something like this:
94 # proxymethod('some_method', 'attr', target_method_name='method', ...)
95 # you should now do it like this:
96 # proxymethod(('some_method', 'method'), 'attr', ...)
97 # TODO create a version of this with super call...
98 # XXX as soon as we can construct a function in pure python this will
99 # need to be rewritten...
100 def proxymethod(method_name, source_attr, doc='', depth=1, decorators=(), explicit_self=False):
102 create a proxy to the method name in the containing namespace.
104 arguments:
105 method_name - the name of the method to proxy or a tuple of two strings first
106 is the name of the local method and the second is the name of the
107 target method.
108 source_attr - attribute to which to proxy the method call.
109 doc - the doc string to use for the constructed function.
110 decorators - sequence of decorators to apply to the constructed function.
111 explicit_self - if true, pass the self to the target explicitly.
113 depth - frame depth, used for name setting (use at your own risk).
115 NOTE: this will add the method_name to the containing namespace.
116 NOTE: source_attr is to be used as the attr name referencing the source object.
118 # text of the new function....
119 txt = '''\
120 def %(method_name)s(self, *p, **n):
121 """%(doc)s
122 this is a proxy to %(target_method_name)s method.
124 return self.%(source_attr)s.%(target_method_name)s(%(self_arg)s*p, **n)
126 # add the result to a predictable name in the NS.
127 proxy = %(method_name)s'''
129 # get the method name and target name...
130 if type(name) in (tuple, list):
131 if len(name) != 2:
132 raise TypeError, 'name must either be a string or a sequence of two (got: %s).' % name
133 name, target_method_name = name[0], name[-1]
134 # doc...
135 if doc == None:
136 doc = ''
137 else:
138 doc += '\n\n'
139 # explicit self passing...
140 if explicit_self is True:
141 self_arg = 'self, '
142 else:
143 self_arg = ''
144 # execute the above code...
145 exec (txt % {
146 'doc': doc,
147 'method_name': method_name,
148 'target_method_name': target_method_name,
149 'source_attr': source_attr,
150 'self_arg': self_arg})
151 # run the decorators...
152 for d in decorators:
153 proxy = d(proxy)
154 # update the NS...
155 sys._getframe(depth).f_locals[method_name] = proxy
158 #--------------------------------------------------------proxymethods---
159 def proxymethods(names, source_attr, decorators=(), explicit_self=False):
161 generate a direct proxy for each name.
163 for name in names:
164 proxymethod(name, source_attr, depth=2,
165 decorators=decorators, explicit_self=explicit_self)
169 #-----------------------------------------------------------------------
170 #-------------------------------------------------------proxyproperty---
171 def proxyproperty(name, source_attr, depth=1, local_attr_tpl='_%s'):
173 create a property that will fetch the attr name form an object
174 referenced by .source_attr of no local value is defined, otherwise
175 get the local data.
177 NOTE: this will shadow inherited or overwrite local existing attributes
178 by the same name.
179 NOTE: this supports local data stored in ._<name> attr (default)
180 NOTE: local_attr_tpl controls the attribute name to store the data
181 in the local namespace (must contain a string containing exactly
182 one '%s').
184 local_attr = local_attr_tpl % name
185 def getter(self):
186 return getattr(self, local_attr,
187 getattr(getattr(self, source_attr), name))
188 def setter(self, val):
189 setattr(self, local_attr, val)
190 def remover(self):
191 if hasattr(self, local_attr):
192 delattr(self, local_attr)
193 # define the prop...
194 sys._getframe(depth).f_locals[name] \
195 = property(
196 fget=getter,
197 fset=setter,
198 fdel=remover)
201 #-----------------------------------------------------proxyproperties---
202 def proxyproperties(names, source_attr, local_attr_tpl='_%s'):
204 shorthad for multiple proxyproperty use with the same source_attr.
206 for name in names:
207 proxyproperty(name, source_attr, depth=2, local_attr_tpl=local_attr_tpl)
211 #-----------------------------------------------------------------------
212 #------------------------------------------------------swapmethodself---
213 def swapmethodself(meth, wrapper, use_wrapper_as_class=True):
216 return new.instancemethod(meth.im_func,
217 wrapper,
218 use_wrapper_as_class and \
219 wrapper or meth.im_class)
222 #------------------------------------------------------wrapmethodself---
223 def wrapmethodself(meth, wrapper, use_wrapper_as_class=True):
226 return new.instancemethod(meth.im_func,
227 wrapper(meth.im_self),
228 use_wrapper_as_class and \
229 wrapper or meth.im_class)
233 #=======================================================================
234 # vim:set ts=4 sw=4 nowrap :