Hi Henning, This branch is a nice improvement. It's always good to shrink files. I have a few comments below, but I also would like this change made, which isn't actually part of your diff. In PersonRoles.__getattr__ please add info to the exception you raise so that it matches the error python gives you for its default types such as: AttributeError: 'int' object has no attribute 'foo' merge-conditional -Edwin >=== added file 'lib/canonical/launchpad/doc/personroles.txt' >--- lib/canonical/launchpad/doc/personroles.txt 1970-01-01 00:00:00 +0000 >+++ lib/canonical/launchpad/doc/personroles.txt 2010-01-13 16:45:40 +0000 >@@ -0,0 +1,131 @@ >+= PersonRoles = >+ >+To make the checking for certain roles that a person can have more convenient This makes it a little easier to read: "To make it more convenient to check which roles a person has," >+the IPersonRoles adapter is provided. It's main use is to easily check if a >+person is the member of a celebrity team or is a celebrity person. In >+addition, methods for common checks are provided, too. >+ >+The IPersonRoles interface is closely tight to the ILaunchpadCelebrities >+interface. Any addition or removal of a person celebrity must be reflected in >+adding or removing the corresponding property in IPersonRoles. Luckily the >+celbrities.txt doctest includes a check for this and will give a useful >+information of which attribute needs to be added or removed. Both interfaces s/celbrities.txt/celebrities.txt/ s/give a useful/give useful/ s/information of/information on/ >+are found in the same file. There is no need to adapt the implementation >+class PersonRoles, though (thanks to __getattr__). >+ >+PersonRoles is most prominent in AuthenticationBase in security.py. The user >+parameter to checkAuthenticated is a PersonRoles object (used to be a Person >+object). s/used to be/was/ or "this used to be" to differentiate it from "this is used to be". Otherwise, it's not clear if "this" or "this is" was dropped until you get to the middle of the sentence. >+== The person object and the adapter == >+ >+PersonRoles is registered as an unnamed adapter for IPersonRoles. >+ >+ >>> from canonical.launchpad.interfaces.launchpad import IPersonRoles >+ >>> person = factory.makePerson() >+ >>> print IPersonRoles(person) >+ >+ >+The original Person object can be reached through the person attribute. >+ >+ >>> roles = IPersonRoles(person) >+ >>> print roles.person is person >+ True >+ >+ >+== Celebrity persons == >+ >+There are a number of celebrity persons defined in ILaunchpadCelebrities. >+PersonRoles has a corresponding attribute of the same name prefixed with >+"in_" to check if the person in question is a member of this celebrity or is >+this celebrity. The following tests are identical. >+ >+ >>> from canonical.launchpad.interfaces.launchpad import ( >+ ... ILaunchpadCelebrities) >+ >>> rosetta_experts = getUtility(ILaunchpadCelebrities).rosetta_experts >+ >>> print person.inTeam(rosetta_experts) >+ False >+ >+ >>> print roles.in_rosetta_experts >+ False >+ >+The test will succeed once we make person a member of the team. Need to be an >+admin to do that. >+ >+ >>> login("