471,350 Members | 1,879 Online
Bytes | Software Development & Data Engineering Community
Post +

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 471,350 software developers and data experts.

unable to inherit

I've run into this issue a couple of times. I want to inherit from a class in order to extend it's functionality. The problem is that the class is defined in c in a shared library and doesn't seem to be designed so that it will allow inheritance (no __class__ defined, etc).
For example the Client object from pysvn.

Expand|Select|Wrap|Line Numbers
  1. import pysvn
  2. class MyClient(pysvn._pysvn._Client):
  3.     pass
  4.  
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: Error when calling the metaclass bases
cannot create 'builtin_function_or_method' instances


Is there already a soluion to this issue? My current thought is to create an Object Wrapper class as shown below to use in these situations. Any suggestions or better solutions?

Expand|Select|Wrap|Line Numbers
  1. import pysvn
  2.  
  3. class ObjectWrapper(object):
  4.     def __init__(self, obj):
  5.         self._obj = obj
  6.  
  7.     def __getattr__(self, name):
  8.         if not hasattr(self._obj, name):
  9.             raise AttributeError, ("'%s' has no attribute %s" %
  10.                                    (self.__class__.__name__, name))
  11.         else:
  12.             return getattr(self._obj, name)
  13.  
  14.     def __setattr__(self, name, value):
  15.         if (name == "_obj" or not hasattr(self, "_obj") or
  16.             not hasattr(self._obj, name) or name in dir(self)):
  17.             return super(ObjectWrapper, self).__setattr__(name, value)
  18.         else:
  19.             return setattr(self._obj, name, value)
  20.  
  21. class MyClient(ObjectWrapper):
  22.     def __init__(self, config_dir='', foo=''):
  23.         # pysvn.Client() method returns a Client object
  24.         super(MyClient, self).__init__(pysvn.Client(config_dir))
  25.         self.foo = foo
  26.  
  27.     def getFoo(self):
  28.         return self.foo
  29.  
  30. client = MyClient()
  31. # call pysvn.Client method 'is_url'
  32. client.is_url("file://test")
  33. # call MyClient method 'getFoo'
  34. client.getFoo()
  35.  
Oct 19 '07 #1
3 5841
bartonc
6,596 Expert 4TB
It may be more simple than that. I've used the following technique successfully for a while now:
Expand|Select|Wrap|Line Numbers
  1. class DBConnectionWrapper(object):
  2.     def __init__(self, servername, username="", password="", autocommit=1, database=""):
  3.         odbcstring = "DSN=%s;UID=%s;PWD=%s" %(servername, username, password)
  4.         self.dbConnection = connect(odbcstring, autocommit=autocommit)
  5.  
  6.     def __getattribute__(self, name):
  7.         """Redirect method calls to the connection 'object'."""
  8.         try:
  9.             return object.__getattribute__(self, name)
  10.         except AttributeError:
  11.             # __getattribute__() only work for subtypes of __builtin__.object.
  12. ##            return object.__getattribute__(self.dbConnection, name)
  13.             return eval("self.dbConnection.%s" %(name))
  14.  
Oct 19 '07 #2
Thanks for the reply.
The __setattr__ is necessary to set wrapped object attributes on the wrapped object rather than the object wrapper (when assigning an attr directly and not calling a set method). This probably wasn't a concern for your DBConnectionWrapper. Consider the following example:

Expand|Select|Wrap|Line Numbers
  1. class Foo(object):
  2.     def __init__(self, bar='default'):
  3.         self.bar = bar
  4.     def getUpperCaseBar(self):
  5.         return str(self.bar).upper()
  6.  
  7. class FooWrapper(ObjectWrapper):
  8.     def __init__(self, bar='default'):
  9.         ObjectWrapper.__init__(self, Foo(bar))
  10.  
  11.     def extendFooFunction(self):
  12.         return "my function to extend Foo"
  13.  
  14. fw = FooWrapper()
  15. fw.bar = "Hello"
  16. print fw.getUpperCaseBar()
  17.  
(Of course in this case we could just inherit from Foo rather than using a wrapper, this is just a simple example). This illustrates that without the ObjectWrapper __setattr__ you'll end up setting the bar attribute on the wrapper object rather than the wrapped object. Thus getUpperCaseBar() will print "DEFAULT" rather than "HELLO" because fw.bar is "Hello" but fw._obj.bar is still "default".

It's good to see that you approached the problem in a similar manner and that I'm not missing a more elegant solution. Cheers.
Oct 23 '07 #3
Here is an improvement to fix compatibility with objects that use the deprecated __methods__ and __members__ attributes.
Now it will show the expected result for dir(objectWrapperInstance), similar to what you would get if you had inherited from the wrapped object.

Expand|Select|Wrap|Line Numbers
  1. class ObjectWrapper(object):
  2.     """ObjectWrapper class redirects unhandled calls to wrapped object.
  3.  
  4.     Intended as an alternative when inheritance from the wrapped object is not
  5.     possible.  This is the case for some python objects implemented in c.
  6.  
  7.     """
  8.     def __init__(self, obj):
  9.         """Set the wrapped object."""
  10.         super(ObjectWrapper, self).__setattr__('_obj', obj)
  11.  
  12.         # __methods__ and __members__ are deprecated but still used by
  13.         # dir so we need to set them correctly here
  14.         methods = []
  15.         for nameValue in inspect.getmembers(obj, inspect.ismethod):
  16.             methods.append(nameValue[0])
  17.         super(ObjectWrapper, self).__setattr__('__methods__', methods)
  18.  
  19.         def isnotmethod(object_):
  20.             return not inspect.ismethod(object_)
  21.         members = []
  22.         for nameValue in inspect.getmembers(obj, isnotmethod):
  23.             members.append(nameValue[0])        
  24.         super(ObjectWrapper, self).__setattr__('__members__', members)
  25.  
  26.     def __getattr__(self, name):
  27.         """Redirect unhandled get attribute to self._obj."""
  28.         if not hasattr(self._obj, name):
  29.             raise AttributeError, ("'%s' has no attribute %s" %
  30.                                    (self.__class__.__name__, name))
  31.         else:
  32.             return getattr(self._obj, name)
  33.  
  34.     def __setattr__(self, name, value):
  35.         """Redirect set attribute to self._obj if necessary."""
  36.         # note that we don't want to call hasattr(self, name) or dir(self)
  37.         # we need to check if it is actually an attr on self directly
  38.         selfHasAttr = True
  39.         try:
  40.             super(ObjectWrapper, self).__getattribute__(name)
  41.         except AttributeError:
  42.             selfHasAttr = False
  43.  
  44.         if (name == "_obj" or not hasattr(self, "_obj") or
  45.             not hasattr(self._obj, name) or selfHasAttr):
  46.             return super(ObjectWrapper, self).__setattr__(name, value)
  47.         else:
  48.             return setattr(self._obj, name, value)
  49.  
Pete
Nov 26 '07 #4

Post your reply

Sign in to post your reply or Sign up for a free account.

Similar topics

7 posts views Thread by Fabian Neumann | last post: by
1 post views Thread by Jeff Schmidt | last post: by
7 posts views Thread by bobsled | last post: by
4 posts views Thread by Slavyan | last post: by
6 posts views Thread by Mohammad-Reza | last post: by
2 posts views Thread by ad | last post: by

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.