[Zope-dev] Re: Creating a namespace

Michael Halle halazar@media.mit.edu
Sun, 28 Jan 2001 17:38:42 -0500


Stephan Richter <srichter@cbu.edu> writes: 

> I want to make my own name space with the following situation:
> class X:
>     attributes = {'foo': 'bar'}
> x = X()
> Then I want to use it like that:
> <dtml-with x>
>       <dtml-var foo>
> </dtml-with>

I puzzled through a related problem a little, but for (I think) a
different reason.  I have an External Method that takes a significant
amount of time to run, and returns a collection of data. I didn't want
to have to push the names of all the subvariables returned onto the
stack; that pollutes the name space.  What I wanted to do was the
following:

<dtml-let x="MyExternalMethod(arg1, arg2)">
	Variable 1: <dtml-var expr="x.variable1"> <br>
	Variable 2: <dtml-var expr="x.variable2"> <br>
</dtml-let>

(But, as in your case, I could also have done:

     <dtml-with expr="MyExternalMethod(arg1, arg2)">
	    Variable 1: <dtml-var expr="variable1"> <br>
	    Variable 2: <dtml-var expr="variable2"> <br>
     </dtml-let> )


To me, this first example seemed like a pretty common and obvious
thing to to.  I didn't need "x" to be persistent, I didn't need or
want acqusition, I just wanted to keep my variables containerized in a
structure.  For this purpose, FunctionTemplate, InstanceDict, and
TemplateDict all seemed either inappropriate, too complex, or too
heavyweight.

So, I wrote the simple container class at the end of this message that
contains a grab-bag of methods that can be used for my application as
well as with a variety of others that use <dtml-with> and <dtml-in>.
It essentially provides all that "_.namespace()" does, plus some extra
introspection.  It's concocted from various pieces of Zope and the
HowTos.

Now, philosophical Zope questions:

* To those in the know, is there any problems returning non-persistent
structures?

* Next, it there a reason that there's no sanctioned class for this
purpose?

* Can you return a populated namespace from a DTML Method or a Python Script
using existing mechanisms?

* Why can't you set values in "_.namespace()" in DTML after a
namespace has been created?

* To me, it would make so much more sense to be able create a namespace
with temporary variables (as shown in one of the HowTos) rather than
forcing people to hack them using REQUEST.set().  The namespace
could be used directly as a structure (eg, "ns.x") or as a scope 
(eg, <dtml-with ns> <dtml-var x> </dtml-with> ).  Is there a deep
reason it doesn't exist?

Anyway, here's my "no-guarantee" class.  Notice the magic member
"__allow_access_to_unprotected_subobjects__", which the documentation
(read, code) says can also be set to a list of members that you want
to be publicly accessible and unprotected.  Use this code as a guide;
you can trim it down to get what you want.  An instance of this class
can be used directly as an argument to <dtml-with>; to use with
<dtml-in>, use either the "getItems" or "getMap()" methods.


-------------------------------------

class StructureInstance:
    """A simple, non-persistent, class-based dictionary
    that's useful for returning arguments to Zope"""

    __allow_access_to_unprotected_subobjects__ = 1

    def __init__(self, dict={}):
        self.__d=dict

    def __getattr__(self, name):
        try: return self.__d[name]
        except KeyError: raise AttributeError, name

    def __getitem__(self, name):
        try: return self.__d[name]
        except KeyError: raise KeyError, name

    def __setitem__(self, name, value):
        self.__d[name] = value

    def update(self, dict):
        self.__d.update(dict)

    def getKeys(self, spec=None):
        if spec is None:
            return self.__d.keys()
        
        return filter((lambda x, spec=spec: x in spec), self.__d.keys())

    def getValues(self, spec=None):
        if spec is None:        
            return self.__d.values()

        return map(lambda y: y[1],
                      filter((lambda x, spec=spec: x[0] in spec),
                             self.__d.keys()))

    def getItems(self, spec=None):
        if spec is None:
            return self.__d.items()

        return filter((lambda x, spec=spec: x[0] in spec), self.__d.items())

    def getMap(self, spec=None):
        items = self.getItems(spec)
        dict = {}
        for (i, j) in items:
            dict[i] = j
        return dict
        
    def set(self, **args):
        self.update(args)
    
    setitem=__setitem__


-----------------------------------------------
Michael Halle
mhalle@media.mit.edu