Peter, This still seems to come down to "fuzzy" requirement definitions. What is your distinction between "users" and "developers"? What functionality do you expect to control vs. other developers/users controlling? There is a range of answers for both questions that are workable, but you seem to be talking about several points on each one at the same time.
If you really want users to be able to extend or change the behavior of the system without knowledge of the under-workings, you need to provide a safe, controlled environment for them to work. That could mean defining the "object access code" in some external module, file, or database. Then your traverser finds and applies that code. A big example might be the old Zope2-based Plone with "through the web" based programming. (OK. Maybe that doesn't make the point about not needing to know the inner workings, but it does point out how difficult it can be to have users accomplish this.) If you want developers to extend upon your work you either provide libraries of code that they import into their code, or you build a framework to run their code. Frameworks are essentially pre-coded boilerplate. Everyone that runs Pyramid is using the same boilerplate code to get their code to work. The better the framework, the less boilerplate in your code, but there are limits. (i.e. in Pyramid with traversal you need __getitem__). If other developers are directly modifying __getitem__ in the actual objects being traversed, you have already seceded *all control*. Unless they follow the boilerplate of "returning an object from a dictionary-like structure" they can do whatever they want. They could stop traversal and run any code they desire. Boiler plate is already part of their lives, you are just resisting the idea of adding more of your own. So you either need to modify the framework as others have suggested (custom traverser, etc.) to minimize the boiler plate, or consider forcing them to have their objects inherit from an object you provide. That would ensure that the boilerplate is applied as you desire and you can handle exceptions in one spot. Forced inheritance is not a great idea for a framework like Pyramid in general, but it seems that you have (hopefully) a defined scope on "who" would be working with your solution and that it would be new (non-legacy) code. If your scope is actually "users = developers world-wide", they you may need to start working on following in the footsteps Jim Fulton, Chris McDonough, etc. and develop the next, great way to "publish Python objects". http://en.wikipedia.org/wiki/Zope Best regards, Steve On Thu, Mar 7, 2013 at 4:04 AM, Peter Waller <[email protected]> wrote: > On 6 March 2013 16:48, Thomas G. Willis <[email protected]> wrote: > >> this is just an idea, but you could catch KeyError s and log the >> stacktrace before re-raising, that might help. >> > > On 6 March 2013 16:51, Michael Merickel <[email protected]> wrote: > >> Inside of your __getitem__ you have total control over what that method >> will return. You only want a KeyError to be raised if you are sure that the >> goal is to exit with no context. Thus, define what you mean by no context >> as "class NoContext(Exception): pass" . >> >> def __getitem__(self, key): >> try: >> # stuff to find context >> return context >> except NoContext: >> raise KeyError >> except KeyError: >> raise SomeOtherExceptionThatIsNotKeyError >> > > The point I've been trying to make is that I also don't control the > `__getitem__` because I want other people to write them. These people may > never share their code with me. > > In addition, IMO this isn't a pythonic solution. The try/except would have > to go in every resource written which is silly boilerplate. This is because > except for the most trivial implementations I can't guarantee that code > won't unintentionally cause a KeyError. Re-raising the true KeyError as a > different exception loses information about the nature (the key, the stack > trace) of the original exception. It makes KeyError special. It changes the > semantics that a KeyError is used to denote a non-existing resource. None > of the above is ideal, but maybe I should get over it. > > In my mind, the traversal *structure* is awesome for my use case and I > still love it. I'm beginning to think that in my replacement traverser I > should lose the idea that resources should pretend to be dictionaries and > instead use a different protocol. For example, instead of `__getitem__` I > could call it `child`, then I could have my own exception for resources > which don't exist, or a convention that it returns None. > > -- > You received this message because you are subscribed to the Google Groups > "pylons-discuss" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to [email protected]. > To post to this group, send email to [email protected]. > Visit this group at http://groups.google.com/group/pylons-discuss?hl=en. > For more options, visit https://groups.google.com/groups/opt_out. > > > -- You received this message because you are subscribed to the Google Groups "pylons-discuss" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. To post to this group, send email to [email protected]. Visit this group at http://groups.google.com/group/pylons-discuss?hl=en. For more options, visit https://groups.google.com/groups/opt_out.
