Loading ...
Sorry, an error occurred while loading the content.
 

Re: [Cheetahtemplate-discuss] Cheetah template $name conflict

Expand Messages
  • Tavis Rudd
    Hi Huy, what version of Cheetah are you experiencing this with? It sounds like a bug as it s certainly not intentional. Can you post some code that
    Message 1 of 5 , Feb 13, 2003
      Hi Huy,
      what version of Cheetah are you experiencing this with? It sounds like a bug
      as it's certainly not intentional. Can you post some code that demonstrates
      it?
      Cheers,
      Tavis

      On February 12, 2003 10:35 pm, Huy Do wrote:
      > Hi,
      >
      > I was just checking to see if this is normal cheetah behaviour
      >
      > 1. I use the containment approach where servlet A creates template C which
      > extends template B.
      >
      > in Servlet A I have
      >
      > import module as name
      >
      > in template B i have a #def name
      >
      > when i say $name in template C, cheetah references the "import module as
      > name" in A instead of #def name in B as I would expect. The weird thing is
      > it only happens in some cases.
      >
      > Does this sound right ?


      -------------------------------------------------------
      This SF.NET email is sponsored by: FREE SSL Guide from Thawte
      are you planning your Web Server Security? Click here to get a FREE
      Thawte SSL guide and find the answers to all your SSL security issues.
      http://ads.sourceforge.net/cgi-bin/redirect.pl?thaw0026en
      _______________________________________________
      Cheetahtemplate-discuss mailing list
      Cheetahtemplate-discuss@...
      https://lists.sourceforge.net/lists/listinfo/cheetahtemplate-discuss
    • Tavis Rudd
      Hi Chuck, you re not the first to ask about this one. In fact, I don t think this is the first time you ve asked about it ;) I ve just looked through the
      Message 2 of 5 , Feb 13, 2003
        Hi Chuck,
        you're not the first to ask about this one. In fact, I don't think this is
        the first time you've asked about it ;)

        I've just looked through the error report that prompted you to send this
        request and I think there's actually two issues involved here. The first is
        the one you mention. The second, and more annoying, one is that when code is
        executed from a string rather than from a file Python can't give detailed
        tracebacks.

        Consider this example:

        --------------------------------
        tavis@lucy: ~/junk > cat test.tmpl
        #attr testAttr = {'var1':1, 'subDict':{'a':9, 'b':10} }


        #def test
        This is a test: $testAttr.var1, $testAttr.subDict.a, $testAttr.subDict.c,
        $bogusVar.sub1.sub2
        #end def


        $test
        tavis@lucy: ~/junk > cheetah -c test.tmpl
        Compiling test.tmpl -> test.py(backup test.py_bak)
        tavis@lucy: ~/junk > python test.py

        Traceback (most recent call last):
        File "test.py", line 167, in ?
        test().runAsMainProgram()
        File "/usr/lib/python2.2/site-packages/Cheetah/Template.py", line 340, in
        runAsMainProgram
        CmdLineIface(templateObj=self).run()
        File "/usr/lib/python2.2/site-packages/Cheetah/TemplateCmdLineIface.py",
        line 59, in run
        print self._template
        File "test.py", line 138, in respond
        write(filter(VFS(SL + [globals(), __builtin__],"test",1),
        rawExpr='$test')) # from line 9, col 1.
        File "test.py", line 94, in test
        write(filter(VFS(SL + [globals(), __builtin__],"testAttr.subDict.c",1),
        rawExpr='$testAttr.subDict.c')) # from line 5, col 54.
        NameMapper.NotFound: c
        --------------------------------

        As you can see, plenty of information is given in this case and debugging is
        dead simple. As I almost always compile the templates I'm using I've never
        cared about the first issue and haven't paid much attention to requests to
        'fix' it. More about this below ...

        The code you were running used a string instead of a compiled module. Here's
        the example above executed in a similar manner:

        --------------------------------
        tavis@lucy: ~/junk > python
        Python 2.2.2 (#1, Feb 7 2003, 14:36:51)
        [GCC 3.2.1 20021207 (Gentoo Linux 3.2.1-20021207)] on linux2
        Type "help", "copyright", "credits" or "license" for more information.
        Welcome to Lazy Python. Type "help LazyPython" for help.
        >>> from Cheetah.Template import Template
        >>> print Template(file='test.tmpl')

        Traceback (most recent call last):
        File "<stdin>", line 1, in ?
        File "<string>", line 33, in respond
        File "<string>", line 33, in test
        NameMapper.NotFound: c
        --------------------------------

        Not very useful!! I guess this is the reason you got annoyed with debugging
        the problem last night, rather than the NotFound issue. If the template had
        been compiled there would have been no problem. We should definitely include
        a note about this in the Users' Guide.

        Back to the NotFound issue ... It's rather tricky to implement what you and
        others are suggesting. I'll use the example from above to illustrate why.
        In the C version of NameMapper (src/_namemapper.c), there's a function called
        namemapper_valueFromSearchList:

        --------------------------------
        static PyObject *
        namemapper_valueFromSearchList(PyObject *self, PyObject *args, PyObject
        *keywds)
        {

        PyObject *searchList;
        char *name;
        int executeCallables = 0;

        char *nameCopy = NULL;
        char *tmpPntr1 = NULL;
        char *tmpPntr2 = NULL;
        char *nameChunks[MAXCHUNKS];
        int numChunks;

        PyObject *nameSpace = NULL;
        PyObject *theValue = NULL;
        int i;
        int listLen;

        static char *kwlist[] = {"searchList", "name", "executeCallables", NULL};

        if (!PyArg_ParseTupleAndKeywords(args, keywds, "Os|i", kwlist, &searchList,
        &name,
        &executeCallables)) {
        return NULL;
        }

        nameCopy = malloc(strlen(name) + 1);
        tmpPntr1 = name; tmpPntr2 = nameCopy;
        while ((*tmpPntr2++ = *tmpPntr1++));

        numChunks = getNameChunks(nameChunks, name, nameCopy);
        if (PyErr_Occurred()) { /* there might have been TooManyPeriods */
        free(nameCopy);
        return NULL;
        }
        listLen = PyList_Size(searchList);
        for (i=0; i < listLen; i++){
        nameSpace = PyList_GetItem(searchList, i);
        if ( hasKey(nameSpace, nameChunks[0]) ) {
        theValue = PyNamemapper_valueForName(nameSpace, nameChunks, numChunks,
        executeCallables);
        free(nameCopy);
        return theValue;
        }
        }
        free(nameCopy);
        notFound(name);
        }

        where
        #define notFound(message) { PyErr_SetString(NotFound, message); return NULL; }
        --------------------------------

        Here's the NameMapper logic flow for three $placeholders in the example.
        Branch 2a is for $test, branch 2b is for $bogusVar.sub1.sub2, and branch 2c
        is for $testAttr.subDict.c

        The function:
        1) parses the arguments from Python

        2) loops through the nameSpaces in the searchList and checks to see if the
        first chunk of the name exists in any of them

        2a) 'test' is found in the first nameSpace (i.e. self) and its value is
        retrieved by calling something like PyNamemapper_valueForName(~self~,
        ['test',], 1). Note that this is pseudocode.

        2b) 'bogusVar' isn't found in any nameSpace so the loop exits and
        PyErr_SetString(NotFound, 'bogusVar.sub1.sub2') is called and NULL is
        returned. Note that this is the only case in which the full $placeholder
        name is included in NotFound's value. Maybe it shouldn't be if this is an
        exception to the rule ...

        2c) 'testAttr' is also found in the first nameSpace and an attempt is made to
        retrieve its value by calling something like
        PyNamemapper_valueForName(~self~, ['testAttr','subDict','c'], 3). However,
        'c' is not found so PyNamemapper_valueForName calls PyErr_SetString(NotFound,
        'c') and returns NULL. The NULL value is then also returned by
        namemapper_valueFromSearchList, causing Python to become aware of the
        exception.

        Now, let's experiment with implementing your request for the full placeholder
        name to go in NotFound's exception value, using $testAttr.subDict.c and $test
        as our test cases.

        We extend namemapper_valueFromSearchList to check for NotFound exceptions
        being set by PyNamemapper_valueForName() and re-execute PyErr_SetString()
        with the full placeholder name:

        --------------------------------
        static PyObject *
        namemapper_valueFromSearchList(PyObject *self, PyObject *args, PyObject
        *keywds)
        {

        PyObject *searchList;
        char *name;
        int executeCallables = 0;

        char *nameCopy = NULL;
        char *tmpPntr1 = NULL;
        char *tmpPntr2 = NULL;
        char *nameChunks[MAXCHUNKS];
        int numChunks;

        PyObject *nameSpace = NULL;
        PyObject *theValue = NULL;
        int i;
        int listLen;

        static char *kwlist[] = {"searchList", "name", "executeCallables", NULL};

        if (!PyArg_ParseTupleAndKeywords(args, keywds, "Os|i", kwlist, &searchList,
        &name,
        &executeCallables)) {
        return NULL;
        }

        nameCopy = malloc(strlen(name) + 1);
        tmpPntr1 = name; tmpPntr2 = nameCopy;
        while ((*tmpPntr2++ = *tmpPntr1++));

        numChunks = getNameChunks(nameChunks, name, nameCopy);
        if (PyErr_Occurred()) { /* there might have been TooManyPeriods */
        free(nameCopy);
        return NULL;
        }
        listLen = PyList_Size(searchList);
        for (i=0; i < listLen; i++){
        nameSpace = PyList_GetItem(searchList, i);
        if ( hasKey(nameSpace, nameChunks[0]) ) {
        theValue = PyNamemapper_valueForName(nameSpace, nameChunks, numChunks,
        executeCallables);
        free(nameCopy);
        if (PyErr_Occurred() && PyErr_Occurred() == NotFound) {
        notFound(name);
        } else {
        return theValue;
        }
        }
        }
        free(nameCopy);
        notFound(name);
        }
        --------------------------------

        Now we call that one placeholder by itself to see if it works:

        --------------------------------
        >>> from Cheetah.Template import Template
        >>> print Template(file='test.tmpl').getVar('testAttr.subDict.c')
        Traceback (most recent call last):
        File "<stdin>", line 1, in ?
        File "/usr/lib/python2.2/site-packages/Cheetah/Template.py", line 300, in
        getVar
        return VFS(self.searchList(), varName.replace('$',''), autoCall)
        NameMapper.NotFound: testAttr.subDict.c
        --------------------------------

        So far so good. It worked. Now we have to try the other test case:

        --------------------------------
        >>> print Template(file='test.tmpl').getVar('test')
        Traceback (most recent call last):
        File "<stdin>", line 1, in ?
        File "/usr/lib/python2.2/site-packages/Cheetah/Template.py", line 300, in
        getVar
        return VFS(self.searchList(), varName.replace('$',''), autoCall)
        NameMapper.NotFound: test
        --------------------------------

        Hmm, that's not right! Let's try a different approach:

        --------------------------------
        tavis@lucy: ~/junk > python
        Python 2.2.2 (#1, Feb 7 2003, 14:36:51)
        [GCC 3.2.1 20021207 (Gentoo Linux 3.2.1-20021207)] on linux2
        Type "help", "copyright", "credits" or "license" for more information.
        Welcome to Lazy Python. Type "help LazyPython" for help.
        >>> from Cheetah.Template import Template
        >>> print Template(file='test.tmpl')

        Traceback (most recent call last):
        File "<stdin>", line 1, in ?
        File "<string>", line 33, in respond
        NameMapper.NotFound: test
        --------------------------------

        Still wrong! The reason why is that Cheetah's autocalling feature executes
        self.test() and results in a nested call to namemapper_valueFromSearchList
        for retrieving $testAttr.subDict.c. The nested call executes
        PyErr_SetString(NotFound, 'testAttr.subDict.c') and returns NULL. The
        'exception' eventually bubbles up to the first call of
        namemapper_valueFromSearchList, which then thinks that the NotFound exception
        resulted from $test.

        If this was written in Python code, I'd just set a flag on the exception to
        prevent it from being altered again by calls to
        namemapper_valueFromSearchList higher up the stack. However, I'm not sure
        how to do this using Python's C API. If anyone reading this does know how,
        please speak up.

        Note that the ImportHook I wrote for Cheetah .tmpl files resolves the second
        issue of incomplete tracebacks. Be warned, however, that it relies on Gordon
        MacMillan's ui.py and I believe there to be a few subtle bugs in that module.
        One example is that it won't work in situations where you are manipulating
        sys.path at run-time because it only checks sys.path at startup. In the
        meantime, I strongly suggest compiling your templates to file wherever
        possible.

        Cheers,
        Tavis

        On February 11, 2003 10:21 pm, Chuck Esterbrook wrote:
        > I'd like to suggest that instead of the sparse:
        > NotFound: bar
        >
        > for something like "$foo.bar", Cheetah instead report something like:
        >
        > NotFound: bar
        > type=<instance>
        > class=Baz
        > dir=name1, name2, name3
        >
        > The type, class and dir info is obviously for the $foo value that
        > Cheetah was searching bar for.
        >
        > This would be a *tremendous* help to me in debugging exceptions after
        > the fact. I have often received Cheetah barfs of that nature and
        > wondered what $foo was at the time.
        >
        > Opinions?
        >
        >
        > -Chuck
        >
        >
        > -------------------------------------------------------
        > This SF.NET email is sponsored by:
        > SourceForge Enterprise Edition + IBM + LinuxWorld = Something 2 See!
        > http://www.vasoftware.com
        > _______________________________________________
        > Cheetahtemplate-discuss mailing list
        > Cheetahtemplate-discuss@...
        > https://lists.sourceforge.net/lists/listinfo/cheetahtemplate-discuss


        -------------------------------------------------------
        This SF.NET email is sponsored by: FREE SSL Guide from Thawte
        are you planning your Web Server Security? Click here to get a FREE
        Thawte SSL guide and find the answers to all your SSL security issues.
        http://ads.sourceforge.net/cgi-bin/redirect.pl?thaw0026en
        _______________________________________________
        Cheetahtemplate-discuss mailing list
        Cheetahtemplate-discuss@...
        https://lists.sourceforge.net/lists/listinfo/cheetahtemplate-discuss
      Your message has been successfully submitted and would be delivered to recipients shortly.