Best way to disconnect from ldap?

Discussion in 'Python' started by John Gordon, Mar 21, 2012.

  1. John Gordon

    John Gordon Guest

    I'm writing an application that interacts with ldap, and I'm looking
    for advice on how to handle the connection. Specifically, how to
    close the ldap connection when the application is done.

    I wrote a class to wrap an LDAP connection, similar to this:

    import ldap
    import ConfigParser

    class MyLDAPWrapper(object):

    def __init__(self):

    config = ConfigParser.SafeConfigParser()
    config.read('sample.conf')

    uri = config.get('LDAP', 'uri')
    user = config.get('LDAP', 'user')
    password = config.get('LDAP', 'password')

    self.ldapClient = ldap.initialize(uri)
    self.ldapClient.simple_bind_s(user, password)

    My question is this: what is the best way to ensure the ldap connection
    gets closed when it should? I could write an explicit close() method,
    but that seems a bit messy; there would end up being lots of calls to
    close() scattered around in my code (primarily inside exception handlers.)

    Or I could write a __del__ method:

    def __del__(self):
    self.ldapClient.unbind_s()

    This seems like a much cleaner solution, as I don't ever have to worry
    about closing the connection; it gets done automatically.

    I haven't ever used __del__ before. Are there any 'gotchas' I need to
    worry about?

    Thanks!

    --
    John Gordon A is for Amy, who fell down the stairs
    B is for Basil, assaulted by bears
    -- Edward Gorey, "The Gashlycrumb Tinies"
     
    John Gordon, Mar 21, 2012
    #1
    1. Advertising

  2. Write a context manager.

    Then you just do

    with MyLDAPWrapper() as ldap
    ldap.this()
    ldap.that()

    and when you leave the scope of the with statement, your ldap __exit__
    method will get called regardless of how you left.

    Cheers,
    Cliff


    On Wed, 2012-03-21 at 19:30 +0000, John Gordon wrote:
    > I'm writing an application that interacts with ldap, and I'm looking
    > for advice on how to handle the connection. Specifically, how to
    > close the ldap connection when the application is done.
    >
    > I wrote a class to wrap an LDAP connection, similar to this:LDAP
    >
    > import ldap
    > import ConfigParser
    >
    > class MyLDAPWrapper(object):
    >
    > def __init__(self):
    >
    > config = ConfigParser.SafeConfigParser()
    > config.read('sample.conf')
    >
    > uri = config.get('LDAP', 'uri')
    > user = config.get('LDAP', 'user')
    > password = config.get('LDAP', 'password')
    >
    > self.ldapClient = ldap.initialize(uri)
    > self.ldapClient.simple_bind_s(user, password)
    >
    > My question is this: what is the best way to ensure the ldap connection
    > gets closed when it should? I could write an explicit close() method,
    > but that seems a bit messy; there would end up being lots of calls to
    > close() scattered around in my code (primarily inside exception handlers.)
    >
    > Or I could write a __del__ method:
    >
    > def __del__(self):
    > self.ldapClient.unbind_s()
    >
    > This seems like a much cleaner solution, as I don't ever have to worry
    > about closing the connection; it gets done automatically.
    >
    > I haven't ever used __del__ before. Are there any 'gotchas' I need to
    > worry about?
    >
    > Thanks!
    >
    > --
    > John Gordon A is for Amy, who fell down the stairs
    > B is for Basil, assaulted by bears
    > -- Edward Gorey, "The Gashlycrumb Tinies"
    >
     
    J. Cliff Dyer, Mar 21, 2012
    #2
    1. Advertising

  3. John Gordon

    Chris Rebert Guest

    On Wed, Mar 21, 2012 at 12:30 PM, John Gordon <> wrote:
    > I'm writing an application that interacts with ldap, and I'm looking
    > for advice on how to handle the connection.  Specifically, how to
    > close the ldap connection when the application is done.
    >
    > I wrote a class to wrap an LDAP connection, similar to this:
    >
    >    import ldap
    >    import ConfigParser
    >
    >    class MyLDAPWrapper(object):
    >
    >        def __init__(self):
    >
    >            config = ConfigParser.SafeConfigParser()
    >            config.read('sample.conf')
    >
    >            uri = config.get('LDAP', 'uri')
    >            user = config.get('LDAP', 'user')
    >            password = config.get('LDAP', 'password')
    >
    >            self.ldapClient = ldap.initialize(uri)
    >            self.ldapClient.simple_bind_s(user, password)
    >
    > My question is this: what is the best way to ensure the ldap connection
    > gets closed when it should?  I could write an explicit close() method,
    > but that seems a bit messy; there would end up being lots of calls to
    > close() scattered around in my code (primarily inside exception handlers.)
    >
    > Or I could write a __del__ method:
    >
    >        def __del__(self):
    >            self.ldapClient.unbind_s()
    >
    > This seems like a much cleaner solution, as I don't ever have to worry
    > about closing the connection; it gets done automatically.


    Yes, but not necessarily in a timely manner. Since its uses reference
    counting, CPython /just so happens/ to finalize
    non-cyclically-referenced objects promptly when they go out of scope,
    but Python-the-language makes no such guarantee, and indeed some of
    the other Python implementations explicitly disclaim that there may be
    a significant delay before finalization is performed.

    > I haven't ever used __del__ before.  Are there any 'gotchas' I need to
    > worry about?


    In addition to the aforementioned problem regarding portability to
    other Python implementations, see also the Warning box under:
    http://docs.python.org/reference/datamodel.html#object.__del__

    I concur with J.'s context manager suggestion.

    Cheers,
    Chris
     
    Chris Rebert, Mar 21, 2012
    #3
  4. John Gordon

    Chris Kaynor Guest

    On Wed, Mar 21, 2012 at 1:34 PM, Chris Rebert <> wrote:
    >
    > On Wed, Mar 21, 2012 at 12:30 PM, John Gordon <> wrote:
    > > I'm writing an application that interacts with ldap, and I'm looking
    > > for advice on how to handle the connection.  Specifically, how to
    > > close the ldap connection when the application is done.
    > >
    > > I wrote a class to wrap an LDAP connection, similar to this:
    > >
    > >    import ldap
    > >    import ConfigParser
    > >
    > >    class MyLDAPWrapper(object):
    > >
    > >        def __init__(self):
    > >
    > >            config = ConfigParser.SafeConfigParser()
    > >            config.read('sample.conf')
    > >
    > >            uri = config.get('LDAP', 'uri')
    > >            user = config.get('LDAP', 'user')
    > >            password = config.get('LDAP', 'password')
    > >
    > >            self.ldapClient = ldap.initialize(uri)
    > >            self.ldapClient.simple_bind_s(user, password)
    > >
    > > My question is this: what is the best way to ensure the ldap connection
    > > gets closed when it should?  I could write an explicit close() method,
    > > but that seems a bit messy; there would end up being lots of calls to
    > > close() scattered around in my code (primarily inside exception handlers.)
    > >
    > > Or I could write a __del__ method:
    > >
    > >        def __del__(self):
    > >            self.ldapClient.unbind_s()
    > >
    > > This seems like a much cleaner solution, as I don't ever have to worry
    > > about closing the connection; it gets done automatically.

    >
    > Yes, but not necessarily in a timely manner. Since its uses reference
    > counting, CPython /just so happens/ to finalize
    > non-cyclically-referenced objects promptly when they go out of scope,
    > but Python-the-language makes no such guarantee, and indeed some of
    > the other Python implementations explicitly disclaim that there may be
    > a significant delay before finalization is performed.
    >
    > > I haven't ever used __del__ before.  Are there any 'gotchas' I need to
    > > worry about?

    >
    > In addition to the aforementioned problem regarding portability to
    > other Python implementations, see also the Warning box under:
    > http://docs.python.org/reference/datamodel.html#object.__del__
    >
    > I concur with J.'s context manager suggestion.


    Personally, I would combine both methods (and maybe throw in a close
    option as well). The standard interface would be to use the with
    context, however in cases where that is not possible, an explicit
    close is useful, and just in-case that is forgotten or missed, the
    __del__ is there as a final backup.

    The main case that context managers fail is when you need to break the
    creation and teardown into separate methods, such as when writing a
    more complex context manager.

    As Chris Rebert pointed out, there is no guarantee as to when the
    __del__ method is called. CPython will generally call it immediately,
    however if there are reference cycles it may never call it:

    class O(object):
    def __del__(self):
    print 'del'

    a = O()
    b = O()
    a.obj = b
    b.obj = a
    del a
    del b # After this, all references should be gone. Netiher a nor b are
    accessable anymore, right?
    # Yet del was never printed. Maybe a full garbage collection will help?
    import gc
    gc.collect()
    # Nope...



    Also, if the object exists and an exception is thrown, the object may
    be held onto for extended periods of time, or may never get cleaned
    up. A quick example of this issue:

    >>> class O(object):

    .... def __del__(self):
    .... print 'del'
    ....
    >>> def F():

    .... o = O()
    .... raise RuntimeError()
    ....
    >>> F() # o is not garbage collected as sys.exc_info holds a reference to it still in the traceback object.

    RuntimeError
    Traceback (most recent call last):
    File "<stdin-inspect>", line 1, in <module>
    File "<stdin-inspect>", line 3, in F
    RuntimeError
    >>> raise ValueError() # When another exception got thrown, it will get cleaned up....

    del
    ValueError
    Traceback (most recent call last):
    File "<stdin-inspect>", line 1, in <module>
    ValueError

    In any case, it still makes a decent fall-back in case the user of
    your code fails to properly clean-up. It will cover many of the common
    cases, though you do need to be careful to never get into a reference
    cycle if you have __del__ methods, or you get memory leaks.

    >
    >
    > Cheers,
    > Chris
    > --
    > http://mail.python.org/mailman/listinfo/python-list
     
    Chris Kaynor, Mar 21, 2012
    #4
  5. On Wed, Mar 21, 2012 at 04:49:54PM -0500, Tim Chase wrote:
    > On 03/21/12 15:54, Chris Kaynor wrote:
    > >As Chris Rebert pointed out, there is no guarantee as to when the
    > >__del__ method is called. CPython will generally call it immediately,
    > >however if there are reference cycles it may never call it

    >
    > And more maddeningly, modules/objects used/called from within the
    > __del__ may have already gone out of scope, producing
    > head-scratching errors. I've been bitten by this enough times that
    > I just stopped using __del__ completely.


    I've had similar experiences. In fact, in light of all this - why does
    __del__ exist at all? Novice python users may (reasonably) assume it
    behaves similarly to a C++ destructor (even though the docs warn
    otherwise).

    Given that you can't trust __del__, is there a legitimate use case for
    it?

    \t
     
    Tycho Andersen, Mar 22, 2012
    #5
  6. John Gordon

    Chris Rebert Guest

    On Thu, Mar 22, 2012 at 6:14 AM, Tycho Andersen <> wrote:
    > On Wed, Mar 21, 2012 at 04:49:54PM -0500, Tim Chase wrote:
    >> On 03/21/12 15:54, Chris Kaynor wrote:
    >> >As Chris Rebert pointed out, there is no guarantee as to when the
    >> >__del__ method is called. CPython will generally call it immediately,
    >> >however if there are reference cycles it may never call it

    >>
    >> And more maddeningly, modules/objects used/called from within the
    >> __del__ may have already gone out of scope, producing
    >> head-scratching errors.  I've been bitten by this enough times that
    >> I just stopped using __del__ completely.

    >
    > I've had similar experiences. In fact, in light of all this - why does
    > __del__ exist at all? Novice python users may (reasonably) assume it
    > behaves similarly to a C++ destructor (even though the docs warn
    > otherwise).
    >
    > Given that you can't trust __del__, is there a legitimate use case for
    > it?


    Writing resource classes (like `file`) in C? Their __del__()s
    typically involve little/less Python-level stuff and thus less
    paranoia need be exercised.
    There is somewhat of a perverse incentive in having such last-ditch
    clean-up mechanisms though. "This code seems to work fine without
    `with`, so why bother changing it?"

    Cheers,
    Chris
     
    Chris Rebert, Mar 22, 2012
    #6
  7. On Thu, Mar 22, 2012 at 06:27:45AM -0700, Chris Rebert wrote:
    > On Thu, Mar 22, 2012 at 6:14 AM, Tycho Andersen <> wrote:
    > > On Wed, Mar 21, 2012 at 04:49:54PM -0500, Tim Chase wrote:
    > >> On 03/21/12 15:54, Chris Kaynor wrote:
    > >> >As Chris Rebert pointed out, there is no guarantee as to when the
    > >> >__del__ method is called. CPython will generally call it immediately,
    > >> >however if there are reference cycles it may never call it
    > >>
    > >> And more maddeningly, modules/objects used/called from within the
    > >> __del__ may have already gone out of scope, producing
    > >> head-scratching errors.  I've been bitten by this enough times that
    > >> I just stopped using __del__ completely.

    > >
    > > I've had similar experiences. In fact, in light of all this - why does
    > > __del__ exist at all? Novice python users may (reasonably) assume it
    > > behaves similarly to a C++ destructor (even though the docs warn
    > > otherwise).
    > >
    > > Given that you can't trust __del__, is there a legitimate use case for
    > > it?

    >
    > Writing resource classes (like `file`) in C? Their __del__()s
    > typically involve little/less Python-level stuff and thus less
    > paranoia need be exercised.


    Sure, but you still have no guarantee that __del__ will ever be
    called, so it's a bad idea to rely on it to clean up anything.

    > There is somewhat of a perverse incentive in having such last-ditch
    > clean-up mechanisms though. "This code seems to work fine without
    > `with`, so why bother changing it?"


    Yeah, I guess I can see doing something like:
    __del__ = __exit__
    but anything beyond that seems risky...

    \t
     
    Tycho Andersen, Mar 22, 2012
    #7
  8. On Thu, 22 Mar 2012 08:14:47 -0500, Tycho Andersen wrote:

    > I've had similar experiences. In fact, in light of all this - why does
    > __del__ exist at all? Novice python users may (reasonably) assume it
    > behaves similarly to a C++ destructor (even though the docs warn
    > otherwise).


    What makes you think that novice Python users will be familiar with C++
    destructors?

    Be careful about assuming that idioms in <INSERT FAVOURITE LANGUAGE HERE>
    will be shared by all Python programmers, novice or expert.


    > Given that you can't trust __del__, is there a legitimate use case for
    > it?


    I've never found the need to write one.



    --
    Steven
     
    Steven D'Aprano, Mar 22, 2012
    #8
  9. John Gordon

    Tim Chase Guest

    On 03/22/12 12:26, Steven D'Aprano wrote:
    > On Thu, 22 Mar 2012 08:14:47 -0500, Tycho Andersen wrote:
    >> Given that you can't trust __del__, is there a legitimate
    >> use case for it?

    >
    > I've never found the need to write one.


    I've found the need to write them...then been frustrated by
    things falling out of namespace reach, and found that context
    managers do a much more reliable/understandable job, saving what
    little sanity I had left. ;-)

    So I'd say that __del__ was really only useful (for some sick,
    sick definition of "useful") in versions of Python before
    context-managers were readily available.

    -tkc
     
    Tim Chase, Mar 22, 2012
    #9
  10. John Gordon

    Terry Reedy Guest

    On 3/22/2012 1:54 PM, Tim Chase wrote:
    > On 03/22/12 12:26, Steven D'Aprano wrote:
    >> On Thu, 22 Mar 2012 08:14:47 -0500, Tycho Andersen wrote:
    >>> Given that you can't trust __del__, is there a legitimate
    >>> use case for it?


    It is part of original or early Python and pretty well superceded by
    cyclic gc (which does not work for object with __del__ *because* of the
    unreliability), explicit close methods, and now context managers.
    >>
    >> I've never found the need to write one.

    >
    > I've found the need to write them...then been frustrated by things
    > falling out of namespace reach, and found that context managers do a
    > much more reliable/understandable job, saving what little sanity I had
    > left. ;-)


    Which is one reason they were added ;-).

    > So I'd say that __del__ was really only useful (for some sick, sick
    > definition of "useful") in versions of Python before context-managers
    > were readily available.


    And before cyclic gc, which does a better job of ordering deletions.

    --
    Terry Jan Reedy
     
    Terry Reedy, Mar 22, 2012
    #10
  11. On Thu, Mar 22, 2012 at 05:26:11PM +0000, Steven D'Aprano wrote:
    > On Thu, 22 Mar 2012 08:14:47 -0500, Tycho Andersen wrote:
    >
    > > I've had similar experiences. In fact, in light of all this - why does
    > > __del__ exist at all? Novice python users may (reasonably) assume it
    > > behaves similarly to a C++ destructor (even though the docs warn
    > > otherwise).

    >
    > What makes you think that novice Python users will be familiar with C++
    > destructors?


    I don't, really. It's just natural to assume that __del__ is the
    "opposite" of __init__, when it's really not (i.e. every object is
    __init__ed, but not every object is destructed and thus __del__'d).
    Novice programmers may make this assumption (indeed, many experienced
    programmers do as well).

    > Be careful about assuming that idioms in <INSERT FAVOURITE LANGUAGE HERE>
    > will be shared by all Python programmers, novice or expert.


    Yeah, C++ was the first language which has destructors that came to
    mind. It's certainly not my favorite ;-)

    \t
     
    Tycho Andersen, Mar 22, 2012
    #11
  12. John Gordon

    John Gordon Guest

    In <jkda88$mrk$> John Gordon <> writes:

    > I'm writing an application that interacts with ldap, and I'm looking
    > for advice on how to handle the connection. Specifically, how to
    > close the ldap connection when the application is done.


    > I wrote a class to wrap an LDAP connection, similar to this:


    > import ldap
    > import ConfigParser


    > class MyLDAPWrapper(object):


    > def __init__(self):


    > config = ConfigParser.SafeConfigParser()
    > config.read('sample.conf')
    >
    > uri = config.get('LDAP', 'uri')
    > user = config.get('LDAP', 'user')
    > password = config.get('LDAP', 'password')


    > self.ldapClient = ldap.initialize(uri)
    > self.ldapClient.simple_bind_s(user, password)


    > My question is this: what is the best way to ensure the ldap connection
    > gets closed when it should? I could write an explicit close() method,
    > but that seems a bit messy; there would end up being lots of calls to
    > close() scattered around in my code (primarily inside exception handlers.)


    > Or I could write a __del__ method:


    > def __del__(self):
    > self.ldapClient.unbind_s()


    Thanks everyone for your input. I learned a lot!

    However, I just ran across this bit of documentation on python-ldap.org:

    class ldap.LDAPObject
    Instances of LDAPObject are returned by initialize() and open()
    (deprecated). The connection is automatically unbound and closed
    when the LDAP object is deleted.

    So, given that, do I need to do anything at all?

    --
    John Gordon A is for Amy, who fell down the stairs
    B is for Basil, assaulted by bears
    -- Edward Gorey, "The Gashlycrumb Tinies"
     
    John Gordon, Apr 5, 2012
    #12
  13. John Gordon wrote:
    > class ldap.LDAPObject
    > Instances of LDAPObject are returned by initialize() and open()
    > (deprecated). The connection is automatically unbound and closed
    > when the LDAP object is deleted.
    >
    > So, given that, do I need to do anything at all?


    Hmm, maybe the author of this statement (have to check who) did not know about
    the caveats with __del__() when this was written ages ago. IIRC first
    python-ldap release was for Python 1.4 back in '98. See use of dealloc() in
    Modules/LDAPObject.c.

    So I'd recommend to use the modern with-statement to make sure
    LDAPObject.unbind_s() is really called. Being old-fashioned I used
    try-finally-blocks until now.

    Ciao, Michael.
     
    Michael Ströder, Apr 5, 2012
    #13
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Replies:
    1
    Views:
    533
    Raymond DeCampo
    Feb 21, 2006
  2. rcmn
    Replies:
    1
    Views:
    339
    =?ISO-8859-1?Q?Michael_Str=F6der?=
    Nov 6, 2006
  3. Jason Wold

    using LDAP Controls in ruby-ldap

    Jason Wold, Nov 4, 2004, in forum: Ruby
    Replies:
    5
    Views:
    252
  4. Ian Macdonald
    Replies:
    0
    Views:
    218
    Ian Macdonald
    Mar 15, 2005
  5. James Hughes
    Replies:
    4
    Views:
    330
    James Hughes
    Dec 13, 2005
Loading...

Share This Page