On May 11, 9:01 pm, Carl Banks <pavlovevide...@gmail.com> wrote: > On May 11, 11:16 am, samwyse <samw...@gmail.com> wrote: > > > Should I use a class decorator, or a metaclass? > > Here's the thing: unless you have advance knowledge of the methods > defined by self.blog, you can't get the attr_list at class definition > time, which means neither the metaclass nor the decorator would be a > good approach. If that's the case, you should define newPost, > editPost, and whatever other methods of self.blog as ordinary > attributes of self, within the init function. boilerplate would be > the same except you would pass self to it and allow template to use it > from its nested scope (it would no longer be an instance method since > it's an ordinary attribute). > > If you do know what the methods of self.blog will be, then that's > where you get attr_list from. So, for instance, if blogHandler always > returns an object of type Blog, then you could inspect Blog's type > dict to see what methods are defined in it; in fact you probably want > to check the whole MRO for Blog, like this (untested): > > attr_list = [] > for cls in Blog.__mro__: > for value in cls.__dict__: > if is_wrapped_method(value): > attr_list.append(value) > > A metaclass is probably overkill to assign the wrapped blog methods. > I probably wouldn't even bother with the decorator, and just write the > loop after the class definition. Then you can use MetaBlog directly > for klass. > > class MetaBlog(object): > ... > > for what in attr_list: > setattr(MetaBlog, what, boilerplate(what)) > > If it were the kind of thing I found myself doing often I'd refactor > into a decorator.
Unfortunately, 'boilerplate()' uses the handlers that I provide when MetaBlog is instantiated. I tried the following, but it didn't work (for reasons that were obvious in retrospect). def instantiate_template(m_name, instance): isAuthorised = instance.security.isAuthorised method_to_wrap = getattr(instance.blog, m_name) def template(self, which, username, password, *args): if not isAuthorised(username, password, which, m_name): raise Exception('Unauthorised access') return method_to_wrap(which, *args) template.__name__ = method_to_wrap.__name__ template.__doc__ = method_to_wrap.__doc__ return template class MetaWeblog(object): def __init__(self, securityHandler=SimpleSecurityHandler, blogHandler=SimpleBlogHandler): self.security = securityHandler() self.blog = blogHandler() # from http://www.xmlrpc.com/metaWeblogApi m_prefix = 'metaWeblog.' m_list = ('newPost', 'editPost', 'getPost', 'newMediaObject', 'getCategories', 'getRecentPosts', ) # Here's where things fell apart for m_name in m_list: dotted_name = m_prefix + m_name method = instantiate_template(m_name, self) setattr(self, dotted_name, method) So, I replaced that last for-loop with this: # Since we're about to monkey-patch the class, we should # make certain that all instances use the same handlers. handlers = (self.security, self.blog) try: assert getattr(self.__class__, '_handlers') == handlers except AttributeError: for m_name in m_list: dotted_name = m_prefix + m_name method = instantiate_template(m_name, self) setattr(self.__class__, dotted_name, method) setattr(self.__class__, '_handlers', handlers) This is good enough for now, since I can't conceive of a reason why MetaBlog would be instantiated more than once. If it were, on the other hand, it would probably be because you wanted to use different handlers. In that case, I think I'd want to use a class factory, something like this: server.register_instance( MetaWeblogFactory(securityHandler, blogHandler)() ) Anyway, thanks for getting me over a conceptual hump. -- http://mail.python.org/mailman/listinfo/python-list