
Folks,
Please indulge a python virgin. Barry has advised someone to 'overload the Load & Save function' in extend.py . Would someone help me with a little sample? It doesn't need to do anything useful, just replace the original function.
Martin Whinnery Assistant Network Manager South Birmingham College

On 30 October 2002, Martin Whinnery said:
Huh? There's no file called extend.py in the Mailman source tree. Just what are you trying to accomplish?
Greg
-- Greg Ward <gward@python.net> http://www.gerg.ca/ Question authority!

On Wed, 30 Oct 2002, Greg Ward wrote:
And I quote (From NEWS 2.36)
"
- Membership Adaptors
o Internally, mailing list memberships are accessed through a
MemberAdaptor interface. This would allow for integrating
membership databases with external sources (e.g. Zope or
LDAP), although the only MemberAdaptor currently implemented
is a "classic" adaptor which stores the membership
information on the MailList object.
...
- List Extensibility
o A framework has been added which can be used to specialize
and extend specific mailing lists. If there is a file
called lists/<yourlist>/extend.py, it is execfile()'d after
the MailList object is instantiated. The file should
contain a function extend() which will be called with the
MailList instance...
"
Now after a little more digging (And I take your point about not hacking the actual source, I don't know what I was thinking. Probably why I'm 'just the assistant') it appears that what I need to do is implement new Load() and Save() functions ( orginally defined in MailList.py ), which cause membership information to be read into the mlist structure from LDAP rather than from config.pck, and which fail to write that information back to config.pck.
I appreciate that this will leave membership options unable to be changed, but that's what we want. A later version might be able to write that info back to LDAP, but there's authentication issues and the matter of schema definitions, and I don't need to go there just yet.
Here, look. This code is in file
/usr/local/mailman/lists/ldaplist/extend.py
# Extension mechanism for a list. # This ought to cause a lists membership info to read from LDAP
from ldap import * from Mailman.ldap_cfg import * from Mailman.LDAPMemberships import * ## Note that the file LDAPMemberships.py is identical to ## OldStyleMembership.py except that names the class LDAPMemberships. ## All the methods are currently identical
class LDAPMailList: def __init__(self,oldfunc): self.oldfunc = oldfunc
def Save(self):
myldap = initialize(LDAP_URL)
myldap.simple_bind("dummy","")
return
def Load(self):
"""Load method which ought to overload that defined in MailList"""
myldap = initialize(LDAP_URL)
myldap.simple_bind("","")
# Populate membership
filter = "(&(objectclass=" + LDAP_LIST_CLASS + ")(" +
LDAP_LIST_RDN_ATTR + "=" + mlist.real_name + "))" blah blah blah LDAP stuff blah blah blah return
def extend(mlist): mlist = LDAPMailList(mlist) mlist.__memberadaptor = LDAPMemberships(mlist)
----- snip ----------
Now, what I want is for the Load() and Save() functions defined in MailList.py to be overridden for this list with my own versions.
I just don't understand Python/Mailman well enough.
I suspect that I'm trying to do one thing two ways, and that I should forget the LDAPMemberships / MemberAdaptor stuff for the moment.
Any examples, flames, advice or witticisms will be revered in a darkened room.
Thanks in advance (I like the desperate sound that makes when I say it)
Martin Whinnery "Just the" Assistant Network Manager South Birmingham College

On 30 October 2002, Martin Whinnery <martin.whinnery@sbirmc.ac.uk> said:
It's pretty clear to me that you don't really understand how Python passes function parameters around; you definitely need to go do some homework. Although it's a bit out-of-date, I recommend *Learning Python* by Mark Lutz and David Ascher. It worked for me.
Now, what I want is for the Load() and Save() functions defined in MailList.py to be overridden for this list with my own versions.
Right, the rest of your code makes sense. The problem is that by the time Mailman passes the mlist object to your extend() function, it has already instantiated MailList to create mlist. You *might* be able to get away with a noxious and vile hack like this:
def extend(mlist): mlist.__class__ = LDAPMailList
but don't tell anyone *I* said you could do that.
Unfortunately, I don't know enough about Mailman's internals to tell you what the Right Way to do it is. Sorry.
Greg
-- Greg Ward <gward@python.net> http://www.gerg.ca/ I haven't lost my mind; I know exactly where I left it.

"MW" == Martin Whinnery <martin.whinnery@sbc.ac.uk> writes:
MW> Please indulge a python virgin. Barry has advised someone to
MW> 'overload the Load & Save function' in extend.py . Would
MW> someone help me with a little sample? It doesn't need to do
MW> anything useful, just replace the original function.
Understand that this stuff is a kludge that should make /some/ radical customization of Mailman easier. The specific use case I had in mind was the ability to create different MemberAdaptor implementations, which I think is pretty close to what you're trying to do.
Note that you may or may not need to overload MailList.Load() and MailList.Save() unless you also want to customize how list attributes are stored. If all you care about is getting member information out of LDAP, you might only need to set the MailList object's _memberadaptor attribute to something other than an OldStyleMemberships instance.
--------- My efforts so far -------------
# /usr/local/mailman/lists/ldaplist/extend.py
def extend(mlist):
mlist.OldSave = mlist.Save
def MySave(self):
print "WOOKIE" # So I can see it in withlist
mlist.__class__.Save(self)
mlist.Save = MySave
-------- snip snip ----------------------
I think this is pretty close to what I had in mind, although I'm not sure why you want to call the original Save function in MySave(), and why you wouldn't just call mlist.OldSave() if you really wanted to do that.
But when I try m.Save(m) from within "withlist ldaplist", I get a
'NotLocked' error:
NotLockedError: <LockFile
137391332: /usr/local/mailman/locks/ldaplist.lock [unlocked: 18000sec]
pid=9172>: None
Did you use the -l option to withlist? Or did you explicit call m.Lock()? If not, getting this exception probably has little to do with extend.py (the list has to be locked in order to Save it).
But as I said, I'm not sure you'll need to override Load() and Save() -- unless you're going to allow the writeable methods in the MemberAdaptor interface to be called through Mailman.
You'll definitely want to write an implementation of MemberAdaptor that gets its data through LDAP, and then in your extend.py file, do something like
-------------------- snip snip -------------------- # extend.py
def extend(mlist): # You might want to key off of something other than the list's # internal name. listid = mlist.internal_name() # Get all member info from LDAP mlist._memberadaptor = LDAPMemberAdaptor(listid) -------------------- snip snip --------------------
HTH, -Barry

On 30 October 2002, Martin Whinnery said:
Huh? There's no file called extend.py in the Mailman source tree. Just what are you trying to accomplish?
Greg
-- Greg Ward <gward@python.net> http://www.gerg.ca/ Question authority!

On Wed, 30 Oct 2002, Greg Ward wrote:
And I quote (From NEWS 2.36)
"
- Membership Adaptors
o Internally, mailing list memberships are accessed through a
MemberAdaptor interface. This would allow for integrating
membership databases with external sources (e.g. Zope or
LDAP), although the only MemberAdaptor currently implemented
is a "classic" adaptor which stores the membership
information on the MailList object.
...
- List Extensibility
o A framework has been added which can be used to specialize
and extend specific mailing lists. If there is a file
called lists/<yourlist>/extend.py, it is execfile()'d after
the MailList object is instantiated. The file should
contain a function extend() which will be called with the
MailList instance...
"
Now after a little more digging (And I take your point about not hacking the actual source, I don't know what I was thinking. Probably why I'm 'just the assistant') it appears that what I need to do is implement new Load() and Save() functions ( orginally defined in MailList.py ), which cause membership information to be read into the mlist structure from LDAP rather than from config.pck, and which fail to write that information back to config.pck.
I appreciate that this will leave membership options unable to be changed, but that's what we want. A later version might be able to write that info back to LDAP, but there's authentication issues and the matter of schema definitions, and I don't need to go there just yet.
Here, look. This code is in file
/usr/local/mailman/lists/ldaplist/extend.py
# Extension mechanism for a list. # This ought to cause a lists membership info to read from LDAP
from ldap import * from Mailman.ldap_cfg import * from Mailman.LDAPMemberships import * ## Note that the file LDAPMemberships.py is identical to ## OldStyleMembership.py except that names the class LDAPMemberships. ## All the methods are currently identical
class LDAPMailList: def __init__(self,oldfunc): self.oldfunc = oldfunc
def Save(self):
myldap = initialize(LDAP_URL)
myldap.simple_bind("dummy","")
return
def Load(self):
"""Load method which ought to overload that defined in MailList"""
myldap = initialize(LDAP_URL)
myldap.simple_bind("","")
# Populate membership
filter = "(&(objectclass=" + LDAP_LIST_CLASS + ")(" +
LDAP_LIST_RDN_ATTR + "=" + mlist.real_name + "))" blah blah blah LDAP stuff blah blah blah return
def extend(mlist): mlist = LDAPMailList(mlist) mlist.__memberadaptor = LDAPMemberships(mlist)
----- snip ----------
Now, what I want is for the Load() and Save() functions defined in MailList.py to be overridden for this list with my own versions.
I just don't understand Python/Mailman well enough.
I suspect that I'm trying to do one thing two ways, and that I should forget the LDAPMemberships / MemberAdaptor stuff for the moment.
Any examples, flames, advice or witticisms will be revered in a darkened room.
Thanks in advance (I like the desperate sound that makes when I say it)
Martin Whinnery "Just the" Assistant Network Manager South Birmingham College

On 30 October 2002, Martin Whinnery <martin.whinnery@sbirmc.ac.uk> said:
It's pretty clear to me that you don't really understand how Python passes function parameters around; you definitely need to go do some homework. Although it's a bit out-of-date, I recommend *Learning Python* by Mark Lutz and David Ascher. It worked for me.
Now, what I want is for the Load() and Save() functions defined in MailList.py to be overridden for this list with my own versions.
Right, the rest of your code makes sense. The problem is that by the time Mailman passes the mlist object to your extend() function, it has already instantiated MailList to create mlist. You *might* be able to get away with a noxious and vile hack like this:
def extend(mlist): mlist.__class__ = LDAPMailList
but don't tell anyone *I* said you could do that.
Unfortunately, I don't know enough about Mailman's internals to tell you what the Right Way to do it is. Sorry.
Greg
-- Greg Ward <gward@python.net> http://www.gerg.ca/ I haven't lost my mind; I know exactly where I left it.

"MW" == Martin Whinnery <martin.whinnery@sbc.ac.uk> writes:
MW> Please indulge a python virgin. Barry has advised someone to
MW> 'overload the Load & Save function' in extend.py . Would
MW> someone help me with a little sample? It doesn't need to do
MW> anything useful, just replace the original function.
Understand that this stuff is a kludge that should make /some/ radical customization of Mailman easier. The specific use case I had in mind was the ability to create different MemberAdaptor implementations, which I think is pretty close to what you're trying to do.
Note that you may or may not need to overload MailList.Load() and MailList.Save() unless you also want to customize how list attributes are stored. If all you care about is getting member information out of LDAP, you might only need to set the MailList object's _memberadaptor attribute to something other than an OldStyleMemberships instance.
--------- My efforts so far -------------
# /usr/local/mailman/lists/ldaplist/extend.py
def extend(mlist):
mlist.OldSave = mlist.Save
def MySave(self):
print "WOOKIE" # So I can see it in withlist
mlist.__class__.Save(self)
mlist.Save = MySave
-------- snip snip ----------------------
I think this is pretty close to what I had in mind, although I'm not sure why you want to call the original Save function in MySave(), and why you wouldn't just call mlist.OldSave() if you really wanted to do that.
But when I try m.Save(m) from within "withlist ldaplist", I get a
'NotLocked' error:
NotLockedError: <LockFile
137391332: /usr/local/mailman/locks/ldaplist.lock [unlocked: 18000sec]
pid=9172>: None
Did you use the -l option to withlist? Or did you explicit call m.Lock()? If not, getting this exception probably has little to do with extend.py (the list has to be locked in order to Save it).
But as I said, I'm not sure you'll need to override Load() and Save() -- unless you're going to allow the writeable methods in the MemberAdaptor interface to be called through Mailman.
You'll definitely want to write an implementation of MemberAdaptor that gets its data through LDAP, and then in your extend.py file, do something like
-------------------- snip snip -------------------- # extend.py
def extend(mlist): # You might want to key off of something other than the list's # internal name. listid = mlist.internal_name() # Get all member info from LDAP mlist._memberadaptor = LDAPMemberAdaptor(listid) -------------------- snip snip --------------------
HTH, -Barry
participants (4)
-
barry@python.org
-
Greg Ward
-
Martin Whinnery
-
Martin Whinnery <martin.whinnery@sbirmc.ac.uk>