[Zope-dev] Why is TemplateDict so opaque? -and- Have youseen this problem?

Jim Fulton jim@digicool.com
Thu, 16 Dec 1999 21:47:04 +0000


Dave Parker wrote:
> 
> "Phillip J. Eby" wrote:
> > Try this:
> >
> > <!--#var standard_html_header-->
> > Depth: <dtml-var "methodA(_.None,_,counter=counter+1)">
> > <!--#var standard_html_footer-->
> 
> Andrew Duncan suggested this one as well more or less as well - thanks.
> BUT! (read on...)
> 
> > Horrible workarounds?  Not really. Just make sure that if you're going to
> > call any kind of DTML-ish thing with parameters, the first two positional
> > parameters should be _.None and _ so that the current namespace is passed
> > through.
> 
> Well, yes they were horrible; minus knowing that to descend more than
> two levels deep in evaluated method calls I must start passing these
> things, the workarounds *are* extremely ugly.  So I'm glad I have this
> tidbit in my head now, but I've made a *lot* of compromises since :(

You are making this more mysterious than it really is.
The rule doesn;t depend on the evaluation level. If you call a 
DTML method or document in an expression, then you must pass the
namespace if you want it to be used.  This arises from the fact
that the expression syntax uses Python. This gives you more power
at the cost of more work, a tradeoff.

> And I continue to maintain that this is a *BUG* - here's why:
> 
> (slightly modified version of the original example - emphasises bug
> issue)
> 
> This version blows up:
> methodA:
>         Depth: <dtml-var counter>
>         <dtml-if "counter < 2">
>         <dtml-var "methodA(counter=counter+1)">
> 
> The error:
> 
> Error type:  KeyError
> Error value: counter
> 
> This one works fine:
> methodA:
>         Depth: <dtml-var counter>
>         <dtml-if "counter < 1">
>         <dtml-var "methodA(counter=counter+1)">
> 
> Output is:
> 
> Depth: 0 Depth: 1
> 
> I strongly believe this is a bug in that if it's the case that my
> namespace goes away minus passing in the namespace as a parameter, the
> second example *should not have worked*.

Your analysis is flawed. Here's why.  The method gets called 
recursively. The first time it is called, the namespace *is* passed
in, by Zope.  When it calls itself the second time, the namespace
isn't there, because the method doesn't pass it.  Lets work through this:

In your second example, the method gets called. I assume that
you arranged for counter to be initialized to zero. (I'm 
coming in at the tail end of this conversation. :)

- On the first call, "Depth: 0" is output."
  The counter is < 1 so we enter the if block
  and call methodA. This succeeds because methodA
  is in the namespace.

- On the second call, "Depth: 1" is output."
  Because counter is not <1, we never execute the
  'if' and we're done. It doesn't matter that methodA
  is not in the namespace, because we never call it.

Not consider your first example:

- On the first call, "Depth: 0" is output."
  The counter is < 2 so we enter the if block
  and call methodA. This succeeds because methodA
  is in the namespace.

- On the second call, "Depth: 1" is output."
  Because counter is < 2, we try to execute the 
  if block.  This fails (with a name error on methodA)
  because methodA is not in the namespace, because we
  never passed in the namespace.


>  It strikes me that someone
> went to the effort to ensure that namespace gets passed down for me to
> *some* extent,

That's right.  When a method is called by Zope or when you insert
it with the name attribute of the var tag:

  <dtml-var name=methodA>  (aka <dtml-var methodA>)

The namespace is passed in for you.

> becuase I'm getting "Depth: 1".  That it should fail at
> the next level appears entirely arbitrary.

It may appear that way, but it's not. :)
 
> If this is really really not a bug, then we are going to have a piece of
> documentation that says:
> 
> "If you want to call your methods within an expression context where
> you're calling depth is greater than two, you must pass in the namespace
> as (_.None,_[,...])"
> 
> I would personally be embarassed to have such a note in there.

Right, that's why the documentation should say:

 "If you want to call your methods within an expression, 
  you must pass in the namespace as (_.None,_[,...])"
 
> Sorry, but this one has frustrated me way too many times. Please tell me
> why I'm wrong.

Hopefully, the explanation above helps.

Jim

--
Jim Fulton           mailto:jim@digicool.com
Technical Director   (888) 344-4332              Python Powered!
Digital Creations    http://www.digicool.com     http://www.python.org

Under US Code Title 47, Sec.227(b)(1)(C), Sec.227(a)(2)(B) This email
address may not be added to any commercial mail list with out my
permission.  Violation of my privacy with advertising or SPAM will
result in a suit for a MINIMUM of $500 damages/incident, $1500 for
repeats.