Python – Is there a way to check the incoming parameters from the __getattr__, or somehow redirect the call based on the passed parameters?

Is there a way to check the incoming parameters from the __getattr__, or somehow redirect the call based on the passed parameters?… here is a solution to the problem.

Is there a way to check the incoming parameters from the __getattr__, or somehow redirect the call based on the passed parameters?

Some background:
We have a trading system where we divide the traffic based on the country where the transaction bill is located. We have a logging table that exists in 2 instances, one database that logs transactions to the EU and the other to anywhere else. We also have a test library for managing and hiding the contents of the usage database, roughly speaking, each table is represented by a class. I have a class that represents the table, and the db session manager class has two members for each of the two instances of the class. What I want to do is create a generic “meta dao” class that will call it arbitrarily, check args, and dispatch the call to the correct db instance representing the class instance based on one of the input parameters. I initially considered overloading each method, but that was clunky and dirty.

I’m thinking about using __getattr__ to override the method lookup so I can call down the correct instance based on the name of the method __getattr__ receives, but as I understand it, I can’t check from __getattr__ passed in the method argument, so I can’t dispatch correctly from it in this case. Does anyone have any ideas for the different directions I can pursue, or is there any way to “check” parameters from __getattr__, not just the method name?

[edit] This is a generic version of what I’m saying:

class BarBase(object):
    def __init__(self, x):
        self.x = x
    def do_bar(self, i):
        return self.x * i

class FooBar(BarBase):
    def __init__(self, x):
        super(FooBar, self).__init__(x)
    def do_foo(self, i):
        return self.x + i

class MetaFoo(object):
    def __init__(self, bar_manager):
        self.foo_manager = bar_manager
    #something here that will take an arbitrary methodname and args as
    #long as args includes a value named i, inspect i, and call
    #bar_manager.fooa. [methodname] (args) if i < 10,
    #and bar_manager.foob. [methodname] (args) if i >= 10

class BarManager(object):
    def __init__(self):
        self.bar_list = {}
    def __get_fooa(self):
        if 'fooa' not in self.bar_list.keys():
            self.bar_list['fooa'] = FooBar('a')
        return self.bar_list['fooa']
    fooa = property(__get_fooa)
    def __get_foob(self):
        if 'foob' not in self.bar_list.keys():
            self.bar_list['foob'] = FooBar('b')
        return self.bar_list['foob']
    foob = property(__get_foob)
    def __get_foo(self):
        if 'foo' not in self.bar_list.keys():
            self.bar_list['foo'] = MetaFoo(self)
        return self.bar_list['foo']

Solution

It should work along these lines:

class ProxyCall(object):
   '''Class implementing the dispatch for a certain method call'''
   def __init__(self, proxy, methodname):
      self.proxy = proxy
      self.methodname = methodname

def __call__(self, *p, **kw):
      if p[0] == "EU": # or however you determine the destination
         return getattr(self.proxy.EU, self.methodname)(*p, **kw);
      else:
         return getattr(self.proxy.OTHER, self.methodname)(*p, **kw);

class Proxy(object):
   '''Class managing the different "equivalent" instances'''
   def __init__(self, EU, OTHER):
      self.EU = EU
      self. OTHER = OTHER

def __getattr__(self, name):
      if not hasattr(self.EU, name):
         # no such method
         raise AttributeError()
      else:
         # return object that supports __call__ and will make the dispatch
         return ProxyCall(self, name)

You will then create these two instances and combine them into a single proxy object:

eu = make_instance(...)
other = make_instance(...)
p = Proxy(eu, other)
p.somemethod(foo) 

Related Problems and Solutions