[Tres Seaver]
The 'iteritems' method of a dictionary returns an object of type 'dictionary-iterator'; AccessControl.ZopeGuards makes no container assertions about that type, although it *does* permit calling the 'iteritems' method which returns an instance of it.
I find it interesting that that module wraps 'iterkeys' and 'itervalues' in its 'get_iter' checker, but allows unrestricted access to 'iteritems'.
[Jamie Heilman]
Yeah I saw that, which is why I asked about it, I couldn't decide if it was left sort of half-baked on purpose or not. I assume not, but I wanted to make sure.
It was deliberate. iterkeys() and itervalues() reveal objects held by the dict directly, and so require security checks before handing those objects out. iteritems() returns 2-tuples, though, and there's no security implication there until you do something to extract the contained keys and values from the 2-tuples. The security checks in the iteritems() case occur in all the ways of picking apart the 2-tuples.
The following patch will make your use case work (it would need to be prettied up for Python < 2.3):
[a patch that inserted ContainerAssertions[type({}.iteritems())] = 1 ] Unfortunately, type({}.iteritems()) is type({}.iterkeys()) is type({}.itervalues()) They all return a dictionary-iterator object. The .next() method of a dictionary-iterator object is safe to hand out for the iteritems flavor (again because it returns 2-tuples), but the .next() methods of the others aren't safe (again because they reveal contained objects directly).
OK, but really I'm more interested in having this supported in Zope proper,
Sure -- I'm sure Tres was just trying to get you unstuck in a hurry.
I can always use .items() instead of .iteritems() and soak the associated costs if I have to. Surely making iteritems use a guarded interator is the Right thing, yes?
The thing going wrong here is subtler than that. For example, change iteritems() to itervalues() in your original example, and I bet it still won't work. OTOH, if you use list(yourdict.iterkeys()) instead, I bet it will work.