fixed a typo...
[pli.git] / pli / pattern / proxy / utils.py
blob7e5c9d667c9ba755cf7c84f09b556420f468f0fe
1 #=======================================================================
3 __version__ = '''0.0.09'''
4 __sub_version__ = '''20081027154102'''
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: method name can either be a string or a touple of two strings, a source
63 and target method names.
64 NOTE: this will add the method_name to the containing namespace.
65 NOTE: source_attr is to be used as the attr name referencing the source object.
66 '''
67 # text of the new function....
68 txt = '''\
69 def %(method_name)s(self, *p, **n):
70 """
71 this is the proxy to %(method_name)s method.
72 """
73 try:
74 return super(%(class_name)s, self).%(method_name)s(*p, **n)
75 except (%(exceptions)s):
76 return self.%(source_attr)s.%(target_method_name)s(*p, **n)
77 proxy = %(method_name)s'''
79 # get the method name and target name...
80 if type(method_name) in (tuple, list):
81 if len(method_name) != 2:
82 raise TypeError, 'name must either be a string or a sequence of two (got: %s).' % method_name
83 method_name, target_method_name = method_name[0], method_name[-1]
84 else:
85 target_method_name = method_name
86 # execute the above code...
87 exec (txt % {
88 'method_name': method_name,
89 'target_method_name': target_method_name,
90 'source_attr': source_attr,
91 'class_name': class_name,
92 'exceptions': type(exceptions) in (tuple, list) \
93 and ', '.join([ e.__name__ for e in exceptions ]) \
94 or exceptions.__name__,
96 # run the decorators...
97 for d in decorators:
98 proxy = d(proxy)
99 # update the NS...
100 sys._getframe(depth).f_locals[method_name] = proxy
103 #---------------------------------------------------------proxymethod---
104 # NOTE: the interface changed, so if you used something like this:
105 # proxymethod('some_method', 'attr', target_method_name='method', ...)
106 # you should now do it like this:
107 # proxymethod(('some_method', 'method'), 'attr', ...)
108 # TODO create a version of this with super call...
109 # TODO move depth to the end of the args...
110 # XXX as soon as we can construct a function in pure python this will
111 # need to be rewritten...
112 def proxymethod(method_name, source_attr, doc='', depth=1, decorators=(), explicit_self=False):
114 create a proxy to the method name in the containing namespace.
116 arguments:
117 method_name - the name of the method to proxy or a tuple of two strings first
118 is the name of the local method and the second is the name of the
119 target method.
120 source_attr - attribute to which to proxy the method call. if this is set to
121 None the the method will be called directly to the current object.
122 doc - the doc string to use for the constructed function.
123 decorators - sequence of decorators to apply to the constructed function.
124 explicit_self - if true, pass the self to the target explicitly.
126 depth - frame depth, used for name setting (use at your own risk).
128 NOTE: this will add the method_name to the containing namespace.
129 NOTE: source_attr is to be used as the attr name referencing the source object.
131 # text of the new function....
132 txt = '''\
133 def %(method_name)s(self, *p, **n):
134 """%(doc)s
135 this is a proxy to self.%(source_attr)s.%(target_method_name)s method.
137 return self.%(source_attr)s%(target_method_name)s(%(self_arg)s*p, **n)
139 # add the result to a predictable name in the NS.
140 proxy = %(method_name)s'''
142 # get the method name and target name...
143 if type(method_name) in (tuple, list):
144 if len(method_name) != 2:
145 raise TypeError, 'name must either be a string or a sequence of two (got: %s).' % method_name
146 method_name, target_method_name = method_name[0], method_name[-1]
147 else:
148 target_method_name = method_name
149 # prepare the source attr...
150 if source_attr == None:
151 source_attr = ''
152 else:
153 source_attr += '.'
154 # doc...
155 if doc == None:
156 doc = ''
157 else:
158 doc += '\n\n'
159 # explicit self passing...
160 if explicit_self is True:
161 self_arg = 'self, '
162 else:
163 self_arg = ''
164 # execute the above code...
165 exec (txt % {
166 'doc': doc,
167 'method_name': method_name,
168 'target_method_name': target_method_name,
169 'source_attr': source_attr,
170 'self_arg': self_arg})
171 # run the decorators...
172 for d in decorators:
173 proxy = d(proxy)
174 # update the NS...
175 sys._getframe(depth).f_locals[method_name] = proxy
178 #--------------------------------------------------------proxymethods---
179 def proxymethods(names, source_attr, decorators=(), explicit_self=False, depth=1):
181 generate a direct proxy for each name.
183 for more details see docs for proxymethod(...)
185 for name in names:
186 proxymethod(name, source_attr, depth=depth+1,
187 decorators=decorators, explicit_self=explicit_self)
191 #-----------------------------------------------------------------------
192 #-------------------------------------------------------proxyproperty---
193 def proxyproperty(name, source_attr, depth=1, local_attr_tpl='_%s'):
195 create a property that will fetch the attr name form an object
196 referenced by .source_attr if no local value is defined, otherwise
197 get the local data.
199 NOTE: this will shadow inherited or overwrite local existing attributes
200 by the same name.
201 NOTE: this supports local data stored in ._<name> attr (default)
202 NOTE: local_attr_tpl controls the attribute name to store the data
203 in the local namespace (must contain a string containing exactly
204 one '%s').
206 local_attr = local_attr_tpl % name
207 def getter(self):
208 if hasattr(self, local_attr):
209 return getattr(self, local_attr)
210 return getattr(getattr(self, source_attr), name)
211 def setter(self, val):
212 setattr(self, local_attr, val)
213 def remover(self):
214 if hasattr(self, local_attr):
215 delattr(self, local_attr)
216 # define the prop...
217 sys._getframe(depth).f_locals[name] \
218 = property(
219 fget=getter,
220 fset=setter,
221 fdel=remover)
224 #-----------------------------------------------------proxyproperties---
225 def proxyproperties(names, source_attr, local_attr_tpl='_%s'):
227 shorthad for multiple proxyproperty use with the same source_attr.
229 for name in names:
230 proxyproperty(name, source_attr, depth=2, local_attr_tpl=local_attr_tpl)
234 #-----------------------------------------------------------------------
235 #------------------------------------------------------swapmethodself---
236 def swapmethodself(meth, wrapper, use_wrapper_as_class=True):
239 return new.instancemethod(meth.im_func,
240 wrapper,
241 use_wrapper_as_class and \
242 wrapper or meth.im_class)
245 #------------------------------------------------------wrapmethodself---
246 def wrapmethodself(meth, wrapper, use_wrapper_as_class=True):
249 return new.instancemethod(meth.im_func,
250 wrapper(meth.im_self),
251 use_wrapper_as_class and \
252 wrapper or meth.im_class)
256 #=======================================================================
257 # vim:set ts=4 sw=4 nowrap :