Mr SZ a écrit :
Hi,

I'm writing an LDAP plugin for my TG2 application. In this I wrote a small 
class based decorator with args to set up a connection and call the necessary
functionality but I'm having problems with it. Here's my code:

(snip code)

class LdapPlugin(Plugin):
    ...
    def __init__(self, **kw):
        Plugin.__init__(self)
@getConnection(self._settings, self.__cred__)

<ot>
Don't use '__name__', they are reserved for the implementation. And FWIW, don't use '__name' unless you have a really compelling reason to do so.
</ot>

    def search(self, **kw):
        print 'Searching'
        ...


This can't work, and it's a FAQ FWIW - but since there's no official c.l.py FAQ, we won't hold it against you !-)

def and class are both *executable* statements (yes, classes and functions creation - like almost anything in Python - are run-time operations).

The first one creates a function object - *wherever* it happens - and bind the function object to the function's name in the current namespace. Think of it as an equivalent of the following javascript snippet:

   var func_name = function(arg) { /* function's body */ };

The second statement - class - builds a class object from the names defined in the class statement's body (that is, names defined in the class statement's body will become attributes of the class object).

Now about the 'methods' and 'self' stuff...

First understand that there's *nothing* magical with 'self'. It's *not* a keyword. It's only a naming convention, and you could use any legal Python identified instead.

The reason we have to explicitly mention it as first argument of the function is that it's the only way the function's body can get access to the current instance. What happens is (overly simplified) that during attribute resolution, when the found attribute happens to be a function, this function is wrapped - together with the instance on which the attribute was looked up and it's class - into a callable method object. Then when you call this method object, it inserts the instance as first argument to the function call, and returns the result of the function call (if you want to read more about this and how computed attributes are implemented in Python, google for 'descriptor protocol').

IOW, and to make a long story short, calling instance.method is the same as calling Class.method(instance).


Ok, now to the point: when you call getConnection within the class statement's body, there's no magical "self" keyword poiting to an instance, and since the class itself doesn't yet exists, so there's *no* way you could get at an instance of it anyway !-)

There are many ways to solve your problem, the simplest bing probably to write another decorator calling on the first one, ie:


def connected_method(func):
    def connected(self, *args, **kw):
        wrapped = getConnection(self.__this, self.__that)(func)
        return wrapped(*args, **kw)

    return connected


Note that this may not be that efficient - you'll have quite a few function calls involved here.


While we're at it, a couple comments on your code... First, please read pep08 (naming and coding conventions) on python.org. Conventions are very important in Python.

wrt/ error handling:

            try:
                if tls:
                    connection.start_tls_s()
                if anon:
                    con.simple_bind_s()
                else:
                    con.simple_bind_s(dn, pw)

            except ldap.LDAPError, e:
                print e.message['info']


This kind of "error handling" is more than useless - it's worse than no error handling at all. If you cannot handle the problem (I really mean *handle*, you know, like do something to fix it), just let the exception propagate - you'll get a nice traceback with all the necessary debugging informations. Users of your package can always add a top-level "catch-all" exception handler that will log tracebacks, send alert mails to the team, and present the end-user with a nicely formatted error message (and even possibly a way to handle the problem - like providing appropriate connection data (credentials, url, whatever) !-)

Also note that sys.stdout is for *normal* program outputs. Error messages belongs to sys.stderr.


            else:
                kw['conn'] = connection
                try:
                    f(*args, **kw)
                except Exception, e:
                    print 'Exception in Plugin execution: %s' % e

Same as above : if you can't handle the exception, leave it alone.

HTH


--
http://mail.python.org/mailman/listinfo/python-list

Reply via email to