[Zope] Argument passing and DTMLFile methods

Terry Hancock hancock@anansispaceworks.com
Sat, 29 Jun 2002 09:18:17 -0700

Hi all,

First of all, thanks to Dieter Maurer, Charles Riemann,
Michel Bencur, and Joachim Werner for help on the last
couple of headaches on this project! I am getting really
close to releasing this sucker, but ... ;-)

Next up is how to properly pass implicit arguments to
a class-method created by DTMLFile. This probably requires
some explanation, though ...

I'm converting a prototype of the product which I developed
through the web. The presentation layer is fairly large.

In it, I have a few instances of explicit DTMLMethod calls,
like this:

<dtml-var expr="mydtmlmethod(_.None, _, explicitarg=explicitval)">

This syntax is based on the note in the back of the
Zope Book on the equivalent explicit call to a DTMLMethod.

E.g., it claims that:

<dtml-var expr="mydtmlmethod(_.None, _)">

is equivalent to

<dtml-var mydtmlmethod>

And, in the "through-the-web" prototype, this is apparently
true. (That is, I have verified it experimentally).

However, I am now trying to make the prototype into
a product, and I want these DTML methods to act similarly
to their Python method counterparts (NOT python scripts --
I have converted the scripts to product class methods, 
which become object methods when an instance of the object
is created in Zope). 

So far, I've used SQL(), ImageFile(), and DTMLFile() to
successfully convert ZSQL methods, images, and DTML methods
over to the same sort of usage as I have with Python:

from Globals import ImageFile
from Globals import DTMLFile
from Products.ZSQLMethods.SQL import SQL

dbc = database_connection_object	# Defined elsewhere

class MyClass(Folder):
	meta_type = "my_class"

	def python_method(self, ...):
		#... python code adapted from python script ...
		# container/context converted to self, etc.
		# Naturally, this works just fine, as this
		# this is the stuff that's well-documented

	zsql_method = SQL('zsql_method', '', dbc, args, zsql_code)
		# Works perfectly

	dtml_method = DTMLFile('dtml/mydtmlmethod', 
			globals(), document_id='mydtmlmethod')
		# Works great for implicit DTML usages. Variables,
		# acquisition, etc, all seem to work.

	image_data  = ImageFile('www/myimage', globals())
		# A little weird, because this is the actual
		# image data, not the Zope image object, but
		# still very usable.  Basically, I can't
		# use "tag" or "absolute_url", but I can
		# access it via a URL.

I wasn't certain this would work, since this is different from
containing these objects within the folder (which can be done
either by manage_addMyClass() or MyClass.__init__()).  However,
so far, it works pretty well -- DTML methods are able to find
each other and include subsets, pass implicit variables, etc.

They can be accessed by URL:


and acquisition works on them as expected.

They exist for all instances of the object, and if the methods
are altered, I only have to restart Zope to propagate the
change to all instances. (I.e. I don't have to delete and
re-add the instances).

Furthermore, they are hidden from the management interface,
and are thus "read-only". Great! This is all exactly what
I want -- I'm freezing the prototype into a fixed product.
Changes now have to be made to the product source code to
take effect. This greatly reduces the hazard of accidently
screwing up the product when you're trying to administrate
it. The idea is that only objects which the administrator
would need to alter are made available through the web.

In short, they have all the properties of ordinary python
class methods.

So I'm not sure if this meets "best practice standards",
but it seems like a very natural solution.

I was beginning to be really happy about how smooth this
was all going -- I could even get the correct context in
included DTML methods. "Wow!" I thought, "this Zope thing is
really coming together..." (and "I might actually make
that July 1st date")

EXCEPT... :-(

This only works if I use *implicit* dtml-var substitutions,

<dtml-var mydtml_submethod>

If I try to use the explicit form mentioned above,

<dtml-var expr="mydtml_submethod(_.None, _)">

I lose my context!  I can see variables passed by keywords,
but not the implicit ones. They were visible in the implicit
form, but not the explicit one.  Ack!

Ironic, isn't it?  You'd think I might have to be *more*
explicit in this situation. My guess is that I've somehow
chosen the wrong thing to pass to this method (perhaps "_"
doesn't mean anything in this context?).  Presumeably,
Zope is doing the right thing for implicit references,
but I can't figure out what that is. (This is *after*
"reading the source". Some of the source is quite readable,
but the DTML publishing parts are pretty hairy stuff!).

For one thing, I'm not exactly sure what the difference
is between my DTMLFile object and a DTML Method or
DTML Document (it seems like it can't actually be either
of those, but something related).

I have the frustrating feeling that a simple answer exists
for this, but that I'm just not seeing it, so I'm hoping
this will seem obvious to somebody.

If there's no other way around it, I can probably work-around
this with dtml-let and passing all variables implicitly,
or by sticking huge lists of variables in as keywords, but
these are ugly solutions, and it seems like they ought
to be unnecessary.

Thanks in advance for any ideas.  We *are* very close to
release if this conversion process can be made to work
(the prototype, while basically working, is not up to
production use for a lot of reasons -- we think it will
significantly benefit from being converted into a Product).
I suspect "July 1st" is out the question at this point,
but maybe *next* Monday at this rate. ;-D

I have some screenshots of my prototype version on our
website, for the curious:


Naturally, Narya will be open source (GPL), but I do feel
it should have at least minimal functionality before trying
to release it.


Terry Hancock
Anansi Spaceworks                 
P.O. Box 60583                     
Pasadena, CA 91116-6583