Re: The problem with using KeyError for non-existing resources and traversal

1,350 views
Skip to first unread message

Whit Morriss

unread,
Mar 5, 2013, 9:43:11 PM3/5/13
to <pylons-discuss@googlegroups.com>


On Mar 5, 2013, at 12:45 PM, Peter Waller <peter....@gmail.com>
wrote:

> Hi All,
>
> First, I love Pyramid's design on the whole. Thanks very much for giving it to the world.
>
> I'm writing a pyramid application where one of the ideas is that it should be quite extensible by potential users of my project.
>
> One problem which concerns me a lot is that when writing code which gets called by MyResource.__getitem__ is that it must not raise KeyError, otherwise you get "resource not found", since those were the chosen semantics in Pyramid.
>
> The thing is, this can happen if you accidentally write erroneous code which tries to get a non-existing item from a dictionary, for example. There are many ways to get KeyError.
>
> How can I prevent this from appearing as "resource not found"? At the moment, the presence of a KeyError anywhere in the code is effectively masked by the the resource not found logic. To me this seems like a semi-fatal mistake in the design of Pyramid.
>
> I don't want such a scenario appear as "resource not found", I want it to be "hey, there is an error in your code here on this line".
>
> Thanks in advance for any input,
>

Hi Peter,

There should only really be a single way to get a key error, and that is passing a collection a bad key (of course python is for consenting adults and makes no promises here). As KeyError is the protocol for dictionaries and lists in python by default so I think it's a pretty reasonable design for most traversal use cases which are over hierarchies of dictionary-ish objects.

so my question is what are you doing (or expecting to happen) inside __getitem__ where you get unexpected key errors?

IIRC, if it's really critical to override the default behavior, you can register a custom traverser and use custom exceptions to create your own protocol. in my experience with traversal, keeping the structure and dispatch(i.e. __getitem__) simple saves a headaches. Factoring complex behavior out of __getitem__ to where you can test it thoroughly also helps a lot.

d. "whit" morriss
Platform Codemonkey
wh...@surveymonkey.com

Michael Merickel

unread,
Mar 5, 2013, 9:52:21 PM3/5/13
to Pylons

On Tue, Mar 5, 2013 at 12:45 PM, Peter Waller <peter....@gmail.com> wrote:
At the moment, the presence of a KeyError anywhere in the code is effectively masked by the the resource not found logic.

A KeyError in Pyramid is only special during traversal while it is performing __getitem__ lookups on your resource tree. If these happen, then the previous context in the tree will be used to lookup a view. Any other time in your code, other than when the traverser is waiting for a return value from a __getitem__ invocation, a KeyError will count as simply a regular old instance of Exception. Pyramid supports "exception views" for handling these various exceptions, but by default they should render a 500 internal server error message, not a "resource not found" (implying a 404). You should be able to write your own exception views and handle these errors.

As far as a KeyError within a __getitem__, you have full control over what happens here. You are responsible for whatever code is invoked within the __getitem__ and you may put a try:except: around that code and handle the KeyError however you see fit before returning/raising anything from within a __getitem__.

If this isn't making sense, you'll need to provide some clearer info on what you mean by "resource not found" and what exact behavior you're seeing in your app.

- Michael

Peter Waller

unread,
Mar 6, 2013, 4:50:04 AM3/6/13
to pylons-...@googlegroups.com, wh...@surveymonkey.com
On Wednesday, 6 March 2013 02:43:11 UTC, Whit Morriss wrote:
so my question is what are you doing (or expecting to happen) inside __getitem__ where you get  unexpected key errors?  

The problem is that I don't know, because I can't predict the future, nor can I predict what code *other* people might write.

Yes, dictionary lookups are the main way I've encountered this issue so far. But it is quite easy to write erroneous code which causes a KeyError, in fact, people messing with dictionaries when they develop their own resources is a very likely occurrence. The problem is that in complicated code, functions you call might call functions which raise KeyError somewhere, so you can't tell just by looking at the __getitem__ implementation whether it is KeyError safe. That means you have to always wrap your entire __getitem__ implementation to catch KeyError and rethrow it as a different exception, or something. (And of course, if you really mean KeyError->NoResource, you have to handle that case too). It's a mess.

On Wednesday, 6 March 2013 02:52:21 UTC, Michael Merickel wrote:
If this isn't making sense, you'll need to provide some clearer info on what you mean by "resource not found" and what exact behavior you're seeing in your app.

The __getitem__ is the place where most of my users might write their code. I don't get to choose whether they remember to write try/except around the entire function just in case there might be a latent bug anywhere inside any of the functions they call which allows a KeyError to propagate upwards.

To exacerbate this problem, I've developed something I call a MultiTraverser. Basically, it allows you to have wildcards in the URL fragments. This ends up with the traversal of a  cartesian-product of resources over URL fragments (i.e, a single URL can end up hitting a lot of resources). Having resources randomly not present in my case because they accidentally raised a KeyError is a pretty fatal problem for my use case. A resource might be just one component in some data analysis - a component randomly not being there (because it is buggy and raises a KeyError accidentally) could easily be missed by a user and lead to incorrect results.

It seems that if I want to make this reasonably fool-proof I have to invent my own traverser. Any advice on that front?

Thanks again,

- Peter

Arndt Droullier

unread,
Mar 6, 2013, 5:21:49 AM3/6/13
to Pyramid on google groups, wh...@surveymonkey.com
I don't think you need to implement a new traverser you just need to provide a 
customized __getitem__ to be used by your users and handle all issues you described there.
For example provide a decorator and introduce a NoRessource Exception and to be used 
instead of KeyError.

Though 'MultiTraverser' sounds like you already have replaced the default traverser?

Arndt.

To exacerbate this problem, I've developed something I call a MultiTraverser. Basically, it allows you to have wildcards in the URL fragments. This ends up with the traversal of a  cartesian-product of resources over URL fragments (i.e, a single URL can end up hitting a lot of resources). Having resources randomly not present in my case because they accidentally raised a KeyError is a pretty fatal problem for my use case. A resource might be just one component in some data analysis - a component randomly not being there (because it is buggy and raises a KeyError accidentally) could easily be missed by a user and lead to incorrect results.

It seems that if I want to make this reasonably fool-proof I have to invent my own traverser. Any advice on that front?


--
Arndt Droullier / Nive cms cms.nive.co

Peter Waller

unread,
Mar 6, 2013, 5:29:52 AM3/6/13
to pylons-...@googlegroups.com, wh...@surveymonkey.com
On 6 March 2013 10:21, Arndt Droullier <ar...@dvelectric.de> wrote:
I don't think you need to implement a new traverser you just need to provide a 
customized __getitem__ to be used by your users and handle all issues you described there.
For example provide a decorator and introduce a NoRessource Exception and to be used 
instead of KeyError.

Well, I want the users to write their own resources, and therefore (potentailly) implement their own __getitem__.
 
Though 'MultiTraverser' sounds like you already have replaced the default traverser?

I was going to say here that I use `pyramid.traversal.traverse`, then I realised that I do not.

My code currently suffers from the same problem. Because "KeyError" is the thing used to denote "no such resource", I can't tell the difference between a non-existing resource and a programmer error. I can't currently think of a way out of this, without changing pyramid's use of KeyError to indicate no such resource in general :(. I'm sure this is a sign of bad design on my part, but it does seem like KeyError to indicate no such resource is also slightly problematic in general.

I'm a little surprised I'm the first to raise this. Does anyone out there agree with my point, or is this truly just unique to me? I guess in most cases people are a) familiar with pyramid and that they have to be careful not to accidentally raise KeyError, b) if they find themselves in a no-such-resource situation it's obvious, c) if they find themselves in a no-such-resource situation they know that they have to check for unexpected KeyErrors.

Are a)+b)+c) reasonable expectations for all pyramid developers?

Arndt Droullier

unread,
Mar 6, 2013, 5:51:56 AM3/6/13
to Pyramid on google groups, wh...@surveymonkey.com
I thought about this point some time ago but I don't think it is a problem in general: 
- if you write a unit test you are likely to test your code without traverser so you will get plain Key errors
__getitem__ is not the place to put your application logic

If you want to extend pyramid or create a new framework on top you need to provide some code
to be used by users. Either as base classes, decorators or pyramid level replacements. This doesn't 
mean users cannot use __getitem__.



2013/3/6 Peter Waller <p...@pwaller.net>

Peter Waller

unread,
Mar 6, 2013, 6:01:05 AM3/6/13
to pylons-...@googlegroups.com, wh...@surveymonkey.com
On 6 March 2013 10:51, Arndt Droullier <ar...@dvelectric.de> wrote:
I thought about this point some time ago but I don't think it is a problem in general:  
- if you write a unit test you are likely to test your code without traverser so you will get plain Key errors

Since it's my users writing code I can't enforce that they write unit tests. I know that they won't, they're an inexperienced audience.
 
__getitem__ is not the place to put your application logic

.. I don't understand this statement at all. Then why have traversal at all?! The basic premise of my application is to give things URLs which currently do not, so I'm pretty heavily invested in using traversal for complex purposes.
 
If you want to extend pyramid or create a new framework on top you need to provide some code
to be used by users. Either as base classes, decorators or pyramid level replacements. This doesn't 
mean users cannot use __getitem__.

I already do this heavily. I have several decorators which allow you to modify the behaviour significantly.

The problem is that I want my users *to use pyramid*, i.e, I want to take advantage of the wonderful documentation and framework of Pyramid. That means that I want to build my application on top of it. The way I see it, there is a fundamental conflation of KeyError and "no resource" here which leads to an unresolvable decision - "is it an error, or a resource which doesn't exist?".

In my application it's not necessarily clear when a resource doesn't exist (which should, but there is an error), because it could just be one thing on a page of hundreds of things not showing up. This can lead to very problematic and hard to debug cases for the user.

This is very unfortunate for me, because other than this one horrible edge case (and user trap), I'm really pleased with the application and I want to share it (and pyramid) with the world.

Malthe Borch

unread,
Mar 6, 2013, 8:31:32 AM3/6/13
to pylons-...@googlegroups.com, wh...@surveymonkey.com
On 6 March 2013 12:01, Peter Waller <p...@pwaller.net> wrote:
> The problem is that I want my users *to use pyramid*, i.e, I want to take
> advantage of the wonderful documentation and framework of Pyramid. That
> means that I want to build my application on top of it. The way I see it,
> there is a fundamental conflation of KeyError and "no resource" here which
> leads to an unresolvable decision - "is it an error, or a resource which
> doesn't exist?".

You've got a point.

It's a fundamental problem with APIs that try to mimic the built-in
dict- and/or sequence types, what's sometimes called being "pythonic".
Another example is the `property` decorator (and descriptors in
general) – if you raise an `AttributeError`, then it's not obvious
what the error means.

But the solution is probably just awareness in this case. It's
unlikely that the interface will change. It's a "gotcha" :-).

\malthe

Peter Waller

unread,
Mar 6, 2013, 8:37:52 AM3/6/13
to pylons-...@googlegroups.com, wh...@surveymonkey.com
On 6 March 2013 13:31, Malthe Borch <mbo...@gmail.com> wrote:
But the solution is probably just awareness in this case. It's
unlikely that the interface will change. It's a "gotcha" :-).

:(

It's still not clear how (even with knowledge of this gotcha) I can easily debug it, actually. Since rather than throwing me to the console where I can look at a stack trace, I get a "not found".

Can I just mandate that all of my resources must return None if they don't have a sub-resource instead? And then treat KeyError as an ordinary exception. How might I do that?

It would mean I can't use a plain-old-dictionary, but I'm already waay past that point (of using something as simple as a dict) in my application anyway.

Peter Waller

unread,
Mar 6, 2013, 8:54:42 AM3/6/13
to pylons-...@googlegroups.com
On 6 March 2013 13:31, Malthe Borch <mbo...@gmail.com> wrote:
It's a fundamental problem with APIs that try to mimic the built-in
dict- and/or sequence types, what's sometimes called being "pythonic".

Just to add, I don't think this is terribly pythonic in this case, since the architecture is fail-unsafe. There could well be errors lurking out there that nobody knows about because they just appear to be 404s, not causing any error handling mechanism to kick in.

>>> import this
...
Errors should never pass silently.
...
In the face of ambiguity, refuse the temptation to guess.
...

Chris McDonough

unread,
Mar 6, 2013, 10:09:35 AM3/6/13
to pylons-...@googlegroups.com, wh...@surveymonkey.com
On Wed, 2013-03-06 at 13:37 +0000, Peter Waller wrote:
> On 6 March 2013 13:31, Malthe Borch <mbo...@gmail.com> wrote:
> But the solution is probably just awareness in this case. It's
> unlikely that the interface will change. It's a "gotcha" :-).
>
>
> :(
>
>
> It's still not clear how (even with knowledge of this gotcha) I can
> easily debug it, actually. Since rather than throwing me to the
> console where I can look at a stack trace, I get a "not found".
>
>
> Can I just mandate that all of my resources must return None if they
> don't have a sub-resource instead? And then treat KeyError as an
> ordinary exception. How might I do that?
>

You can replace the traverser.

http://docs.pylonsproject.org/projects/pyramid/en/1.4-branch/narr/hooks.html#changing-the-traverser

- C


>
> It would mean I can't use a plain-old-dictionary, but I'm already waay
> past that point (of using something as simple as a dict) in my
> application anyway.
>
> --
> 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 pylons-discus...@googlegroups.com.
> To post to this group, send email to pylons-...@googlegroups.com.
> Visit this group at
> http://groups.google.com/group/pylons-discuss?hl=en.
> For more options, visit https://groups.google.com/groups/opt_out.
>
>


Peter Waller

unread,
Mar 6, 2013, 10:39:38 AM3/6/13
to pylons-...@googlegroups.com, Whit Morriss
On 6 March 2013 15:23, Whit Morriss <wh...@surveymonkey.com> wrote:
you probably can choose where your users might write code. per suggestion above, maybe overriding __getitem__ isn't the best way for you?
 
I want my users to make their own pyramid resources, like any user of pyramid might. Plain old resources, which act and behave as any plain-old resource might. Then I want my code to "just work" with it.

do you have code or pseudo code you can share?  It might help understand exactly whether the issue is something that can be more simply handled a different way or whether you are trying something legitimately not easy to do with the framework as it is.  I'm guessing there is an easier/simpler way, but it's hard to be sure with more concrete examples of what you want to do.

Sorry, the code is awful and I don't think it's much use for the discussion, but here it is anyway. I want to know how to write this for-loop. The purpose is that it traverses many objects in one go. The problem is what to do with KeyErrors, since I don't know if they came from `context[key]` because the key is unavailable or from some function call inside context.__getitem__ which is actually an error. And if there is actually an error, I have nowhere to propagate it since the default traverser will catch it.


As Chris McDonough points out, I can write my own traverser. I'll give that a shot at some point.

Is the best thing to copy-paste the whole ResourceTreeTraverser yank the KeyError except clause, or does anyone have any brighter ideas? (found here)


--

I do still believe that the architecture is problematic and hides errors for everyone, it's just painfully obvious in my case. It's currently a landmine sitting in there for any users of mine. It's clear to me that it's a ridiculously big ask to suggest that Pyramid's architecture be changed, since such a change would cause a lot of conceptual and literal breakage.

It's still worth having this in mind though. I'm not sure all possibilities have been explored.

Steve Schmechel

unread,
Mar 6, 2013, 11:05:25 AM3/6/13
to pylons-...@googlegroups.com, wh...@surveymonkey.com
If architecture and designs are being critiqued, here are a few thoughts from 50,000 feet:

Pyramid bills itself as a "framework for building frameworks" and others have successfully done exactly that.

Traversal makes certain use cases easier (i.e. yours), but it is not a miracle solution that can auto-magically "give things URLs which currently do not".

In essence, you stated that you want to have "inexperienced users" writing "untested code" that simply works.  That is a very ambitious goal and you probably have a great deal of work to do beyond getting traversal to function, in order to have any hope of having system that can be stable and maintainable by inexperienced users. 

Are any exception messages going to be clear enough for them to know how to take corrective action to fix an unforeseen problem in their own code, without understanding the Pyramid internals?  You probably need a whole layer of code checking/introspection with custom feedback to guide the users - *before* they deploy their code into the live system.

I also think that handing them the Pyramid documentation, no matter how good it is, will not get you out of having to write your own custom documentation for your target audience.  The Pyramid documentation is very good but it is written to a particular audience (application developers - not code-slinging users). 

If someone wants to select the color of their car at a dealership, they don't hand them the manual for the painting robot at the assembly plant, even if it is "the best painting robot manual ever written".

If you don't handle all the possible problems in your code, it seems you are simply delaying the point where your users must become Pyramid developers, to when they experience their first bug and have to crack open the Pyramid documentation to figure out how to fix it.

For most people building stuff on top of Pyramid, the fact that it is simple, stable, and thoroughly tested is of greater importance then the ease of integrating it into every conceivable use case.  I really do not need or want a bunch of framework-specific exceptions thrust upon me to add to my learning curve.  And if I someday want some, I will override what I need to in order to add them.

I think that is probably what you are going too need to do.

Best of luck in your endeavor,
Steve


--

Peter Waller

unread,
Mar 6, 2013, 11:32:44 AM3/6/13
to pylons-...@googlegroups.com
Thanks Steve for your great reply!

In my use case, the "users" will (likely) not be using it as a platform as a service, but executing the pyramid application locally. My users will be comfortable with writing python and seeing stack traces.

You're right that I will have to write documentation and teach them caveats. A lot of this stuff does "just work" though. Many people will learn from example code, which won't teach them that you have to be certain you can't ever raise a KeyError in the wrong place. In addition, I'm not sure _as an experienced python developer_ how to write code which guarantees it doesn't raise a KeyError.

You've reminded me that I'm stuck at a microscopic level looking at one problem when there exist other things to worry about - especially once you throw other users writing code into the mix.

However, I complain about this one behaviour for a specific reason: it's hell to debug. It's silent error passing. It's "that's funny, why is my data subtly wrong?" and a violation of the assumption that "if it's an exception, I'll get a stack trace (or error e-mail, or whatever), like I always do whenever there is an exception". I've spent a lot of time going "that's funny, why does it give me resource not found, this should definitely exist.."

Brief thoughts inline.

On 6 March 2013 16:05, Steve Schmechel <shm...@gmail.com> wrote:
In essence, you stated that you want to have "inexperienced users" writing "untested code" that simply works.  That is a very ambitious goal and you probably have a great deal of work to do beyond getting traversal to function, in order to have any hope of having system that can be stable and maintainable by inexperienced users. 

Indeed. It's ambitious, it might not work, it might be stupid. It works really well so far except for this one thing which has been a recurring issue for me.

Are any exception messages going to be clear enough for them to know how to take corrective action to fix an unforeseen problem in their own code, without understanding the Pyramid internals?  You probably need a whole layer of code checking/introspection with custom feedback to guide the users - *before* they deploy their code into the live system.

In this case I'm worried about the user using a dictionary (something they're likely to do) and just fat fingering something such that they cause a KeyError somewhere in the traversal. A stack trace telling them exactly what dictionary had a KeyError, and what the missing key is would be extremely helpful. It would at least not mean hours of trying to figure out why traversal appears not to be working at all.
 
If someone wants to select the color of their car at a dealership, they don't hand them the manual for the painting robot at the assembly plant, even if it is "the best painting robot manual ever written".

:D, I like this analogy. I will use it as I hand them the pyramid manual.

If you don't handle all the possible problems in your code, it seems you are simply delaying the point where your users must become Pyramid developers, to when they experience their first bug and have to crack open the Pyramid documentation to figure out how to fix it.

Yup. Except that this caveat isn't really explained anywhere that I've seen, so becoming a Pyramid developer won't help, to first order. That's one of my biggest problems with this, that I see there might well be bugs lurking in existing applications, since I managed to write a lot of code before I encountered this problem. And then I managed to use my application and encounter weird issues for quite some time before I understood the root cause.
 
For most people building stuff on top of Pyramid, the fact that it is simple, stable, and thoroughly tested is of greater importance then the ease of integrating it into every conceivable use case.  I really do not need or want a bunch of framework-specific exceptions thrust upon me to add to my learning curve.  And if I someday want some, I will override what I need to in order to add them.
 
I think that is probably what you are going too need to do.

I very much appreciate this and I'm quite happy to be told "no changes to pyramid, go away". I haven't seen any other discussion on this matter though, so I thought it was worth having an exhaustive discussion.

I read what I've written and I hate the whiny tone, so I should probably stop talking now. If you read this far, thanks. Again, I love the way the project is and by no means am I saying "my way is right" (I don't even have a way..), I just would love to see a clean solution to this. Maybe copying the existing traverser and excising the catch is it.

Thomas G. Willis

unread,
Mar 6, 2013, 11:48:36 AM3/6/13
to pylons-...@googlegroups.com, p...@pwaller.net
this is just an idea, but you could catch KeyError s and log the stacktrace before re-raising, that might help.  something like

try:
    return whatevs()
except Exception:
    log.warning("error happened during traversal", exc_info=True)

Michael Merickel

unread,
Mar 6, 2013, 11:51:48 AM3/6/13
to Pylons

On Wed, Mar 6, 2013 at 10:32 AM, Peter Waller <p...@pwaller.net> wrote:
I'm not sure _as an experienced python developer_ how to write code which guarantees it doesn't raise a KeyError

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

There. Any KeyError raised within the code will be properly handled as a raw exception, and your contract with any code within __getitem__ that would be responsible for returning an invalid context should raise NoContext. Obviously this may not be ideal, but it's not like the framework is preventing you from having full control over what your code is doing.

Peter Waller

unread,
Mar 7, 2013, 5:04:39 AM3/7/13
to pylons-...@googlegroups.com
On 6 March 2013 16:48, Thomas G. Willis <tom.w...@gmail.com> 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 <mmer...@gmail.com> 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.

Sam Brauer

unread,
Mar 7, 2013, 9:02:57 AM3/7/13
to pylons-...@googlegroups.com, p...@pwaller.net
Here's yet another alternative that may be easier to swallow:
Stick with the default traverser and provide your users with a base resource class for them to subclass.
The base class has some new method for your users to override (in the example below I named it "getitem") which takes a name and should return an object or None.  If getitem raises a KeyError, a RuntimeError is raised that includes the KeyError's stacktrace.


import traceback

class BaseResource(object):

    def getitem(self, name):
        """ Return resource for ``name``, or ``None``. """
        return None

    def __getitem__(self, name):
        try:
            item = self.getitem(name)
        except KeyError as e:
            tb = traceback.format_exc()
            raise RuntimeError("getitem(%r) raised: %r\n\n%s" % (name, e, tb))
        if item is None:
            raise KeyError
        return item

Peter Waller

unread,
Mar 7, 2013, 9:10:25 AM3/7/13
to Sam Brauer, pylons-...@googlegroups.com
On 7 March 2013 14:02, Sam Brauer <sam.b...@gmail.com> wrote:
Here's yet another alternative that may be easier to swallow:

This.. is approaching a reasonable suggestion. I like it. The only problem that remains is that it treats KeyErrors as special, so you can't introspect the stack and get a console with the usual exception web interface, which is extremely useful.

It does ameleorate most of my concerns though. At least it prevents error hiding and tells you where the actual problem is.

Steve Schmechel

unread,
Mar 7, 2013, 9:43:02 AM3/7/13
to pylons-...@googlegroups.com
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

--

Peter Waller

unread,
Mar 7, 2013, 10:01:35 AM3/7/13
to pylons-...@googlegroups.com
On 7 March 2013 14:43, Steve Schmechel <shm...@gmail.com> wrote:
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.

I'm unhappy that there is a case where pyramid will swallow developer errors. They happen. Even with test driven development. I think everything else about my use case is not of much relevance.

However, my potential users are also developers. They currently write crappy code in python scripts, and I want them to put that code somewhere which suddenly it's available online. So I care about their experience, especially the edge cases which will hide their mistakes and give them incorrect results!

Whining aside, I think there exists at least one good solution for my (admittedly unusual) case, and I'm greatful for the input from this thread. That said, I'm still sad that the edge case exists for all other pyramid users. Sure, it's just one edge case and there are more where that come from, but it's the sort of thing which can burn hours of time and confuse newbies into not trusting their eyes.
Reply all
Reply to author
Forward
0 new messages