minor bugfix...
[pli.git] / pli / pattern / proxy / utils.py
blobf54d74068b3d8cf868e411823738db365ac80969
1 #=======================================================================
3 __version__ = '''0.0.09'''
4 __sub_version__ = '''20080907044938'''
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 the 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 self.%(source_attr)s.%(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(method_name) in (tuple, list):
131 if len(method_name) != 2:
132 raise TypeError, 'name must either be a string or a sequence of two (got: %s).' % method_name
133 name, target_method_name = method_name[0], method_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, depth=1):
161 generate a direct proxy for each name.
163 for more details see docs for proxymethod(...)
165 for name in names:
166 proxymethod(name, source_attr, depth=depth+1,
167 decorators=decorators, explicit_self=explicit_self)
171 #-----------------------------------------------------------------------
172 #-------------------------------------------------------proxyproperty---
173 def proxyproperty(name, source_attr, depth=1, local_attr_tpl='_%s'):
175 create a property that will fetch the attr name form an object
176 referenced by .source_attr if no local value is defined, otherwise
177 get the local data.
179 NOTE: this will shadow inherited or overwrite local existing attributes
180 by the same name.
181 NOTE: this supports local data stored in ._<name> attr (default)
182 NOTE: local_attr_tpl controls the attribute name to store the data
183 in the local namespace (must contain a string containing exactly
184 one '%s').
186 local_attr = local_attr_tpl % name
187 def getter(self):
188 if hasattr(self, local_attr):
189 return getattr(self, local_attr)
190 return getattr(getattr(self, source_attr), name)
191 def setter(self, val):
192 setattr(self, local_attr, val)
193 def remover(self):
194 if hasattr(self, local_attr):
195 delattr(self, local_attr)
196 # define the prop...
197 sys._getframe(depth).f_locals[name] \
198 = property(
199 fget=getter,
200 fset=setter,
201 fdel=remover)
204 #-----------------------------------------------------proxyproperties---
205 def proxyproperties(names, source_attr, local_attr_tpl='_%s'):
207 shorthad for multiple proxyproperty use with the same source_attr.
209 for name in names:
210 proxyproperty(name, source_attr, depth=2, local_attr_tpl=local_attr_tpl)
214 #-----------------------------------------------------------------------
215 #------------------------------------------------------swapmethodself---
216 def swapmethodself(meth, wrapper, use_wrapper_as_class=True):
219 return new.instancemethod(meth.im_func,
220 wrapper,
221 use_wrapper_as_class and \
222 wrapper or meth.im_class)
225 #------------------------------------------------------wrapmethodself---
226 def wrapmethodself(meth, wrapper, use_wrapper_as_class=True):
229 return new.instancemethod(meth.im_func,
230 wrapper(meth.im_self),
231 use_wrapper_as_class and \
232 wrapper or meth.im_class)
236 #=======================================================================
237 # vim:set ts=4 sw=4 nowrap :