Bug with External Methods and default params?
(First a little excuse: I've got an extreme lack of time right now, otherwise I would try to isolate the problem -- but maybe it's a bug already known) There seems to be a problem calling external methods with default parameters from DTML docs. I've got an external method (original signature): def pfadleiste(self, pfadleisten_info, cut_last_entry): "..." calling it via <!--#var "pfadleiste(self, info, 0)"--> is no problem at all, but if I change the signature to def pfadleiste(self, pfadleisten_info, cut_last_entry=1): calling the same page in an identical context gives one of these darned screwed-up "TypeError: read-only buffer, class" error that unluckily hide the original exception (a permanent pain when debugging -- if this changes with the new Zope version it would be a reason for me to upgrade even my existing system). Stefan
Stefan Franke wrote:
There seems to be a problem calling external methods with default parameters from DTML docs. I've got an external method (original signature):
def pfadleiste(self, pfadleisten_info, cut_last_entry): "..."
calling it via
<!--#var "pfadleiste(self, info, 0)"-->
is no problem at all, but if I change the signature to
def pfadleiste(self, pfadleisten_info, cut_last_entry=1):
calling the same page in an identical context gives one of these darned screwed-up "TypeError: read-only buffer, class" error that unluckily hide the original exception (a permanent pain when debugging -- if this changes with the new Zope version it would be a reason for me to upgrade even my existing system).
I've seen the same symptoms. See an earlier post of mine (titled: Re: [Zope] external methods and REQUEST) I think the default parameter bug is the culprit there too. (goes to check the bugs database) Regards, Martijn
Martijn Faassen wrote:
Stefan Franke wrote:
[description of weird behavior/bug with default parameters in external methods]
I've seen the same symptoms. See an earlier post of mine (titled: Re: [Zope] external methods and REQUEST)
I think the default parameter bug is the culprit there too.
(goes to check the bugs database)
I didn't find anything in the bugs database, and all weekend I anticipated wise and enlightening responses to this thread; if it is a bug then it seems to be a fairly serious one (it can thoroughly flabbergast people, see an earlier thread involving weird REQUEST behavior for an example). But no responses yet. Did I miss something? Did anybody confirm this bug? Explain where we went wrong? It is fixed in Zope 1.10? Regards, Martijn
Martijn Faassen wrote:
Martijn Faassen wrote:
Stefan Franke wrote:
[description of weird behavior/bug with default parameters in external methods]
I've seen the same symptoms. See an earlier post of mine (titled: Re: [Zope] external methods and REQUEST)
I think the default parameter bug is the culprit there too.
(goes to check the bugs database)
I didn't find anything in the bugs database, and all weekend I anticipated wise and enlightening responses to this thread; if it is a bug then it seems to be a fairly serious one (it can thoroughly flabbergast people, see an earlier thread involving weird REQUEST behavior for an example).
But no responses yet. Did I miss something? Did anybody confirm this bug? Explain where we went wrong? It is fixed in Zope 1.10?
Sorry for the late response. We'll look into it today. --Paul
Paul Everitt wrote:
Martijn Faassen wrote:
[bug report]
But no responses yet. Did I miss something? Did anybody confirm this bug? Explain where we went wrong? It is fixed in Zope 1.10?
Sorry for the late response. We'll look into it today.
No problem at all, I suppose it shows how high an impression I have of your general responsiveness that I started to complain so quickly. :) Thanks! Martijn
Paul Everitt wrote:
Martijn Faassen wrote:
Martijn Faassen wrote:
Stefan Franke wrote:
[description of weird behavior/bug with default parameters in external methods]
I believe your questions are: 1. Why is it tricky to call External Methods with variable expressions from DTML? 2. Why do some REQUESTs have AUTHENTICATED_USERs and some don't? The answer to question 1 is that External Methods are slightly weird methods which when called from variable expressions in DTML need to explicitly be passed the self argument if they define one. For example: def myMethod(self, foo, bar): "blah blah" ... will not work correctly is called like so: <!--#var "myMethod('foo','bar')"--> because this assigns 'foo' to self and 'bar' to foo and nothing to 'bar'. Instead you should do this: <!--#var "myMethod(foo='foo',bar='bar')"--> Or if you really want to pass self, you can choose a Zope object to pass (such as the parent Folder in the case of DTML methods or 'this()' in the case of other Zope objects.) For example here's one way to explicitly pass the self argument: <!--#var "myMethod(this(),'foo','bar')"--> The answer to question 2 is that AUTHENTICATED_USER object is only present in the REQUEST object when the ORB puts it there. The ORB only puts it there when it has to perform authentication to publish the requested object. So if you are publishing a Document that is publicly viewable, the AUTHENTICATED_USER will not be set. As for the identity of the REQUEST as passed by the ORB when publishing a method, versus the acquired request (self.REQUEST) versus the REQUEST available in DTML, they should all be the same. I hope this clears things up a bit. -Amos
amos wrote:
Paul Everitt wrote:
Martijn Faassen wrote:
Martijn Faassen wrote:
Stefan Franke wrote:
[description of weird behavior/bug with default parameters in external methods]
I believe your questions are:
1. Why is it tricky to call External Methods with variable expressions from DTML?
It's definitely tricky, but I'm not quite sure what I don't understand. :)
2. Why do some REQUESTs have AUTHENTICATED_USERs and some don't?
No, this wasn't my question, but this did come up in a thread somewhere involving REQUEST, to which I replied.
The answer to question 1 is that External Methods are slightly weird methods which when called from variable expressions in DTML need to explicitly be passed the self argument if they define one. For example:
def myMethod(self, foo, bar): "blah blah" ...
will not work correctly is called like so:
<!--#var "myMethod('foo','bar')"-->
because this assigns 'foo' to self and 'bar' to foo and nothing to 'bar'.
Are you sure? The external method: def test4(self, foo, bar): return "%s %s" % (foo, bar) Returns 'one two' when I call it like this: <!--#var "test4('one', 'two')"--> Also, this one: def test1(self, foo): return "%s %s" % (self.REQUEST, foo) when called with: <!--#var "test1('bar')"--> Returns a whole slew of REQUEST info, and then 'bar'. I'm now even more confused. :) However: def test0(self, foo="foo"): return "%s %s" % (self.REQUEST, foo) Gives an error when called like that. The page won't load at all: <!-- Error type: Error value: read-only buffer, class -->
Instead you should do this:
<!--#var "myMethod(foo='foo',bar='bar')"-->
Okay, this explains at least something, though I'm even more confused why the previous *did* work as expected (except in the default argument case): <!--#var "test0()"--> gives me a mess of REQUEST data and 'foo'. while: <!--#var "test0(foo="bar")--> gives me the same and then 'bar'. But 'self' is still definitely being passed, right?
Or if you really want to pass self, you can choose a Zope object to pass (such as the parent Folder in the case of DTML methods or 'this()' in the case of other Zope objects.) For example here's one way to explicitly pass the self argument:
<!--#var "myMethod(this(),'foo','bar')"-->
But self was already passed just fine automatically, I thought...
From my (limited) perspective it still looks as if all works just as expected (in the Python sense), *except* when I use default parameters in the external methods, and only then when I don't use the explicit "foo='bar'" method of parameter passing. Am I wrong in expecting it should all work in a Pythonic way?
The answer to question 2 is that AUTHENTICATED_USER object is only present in the REQUEST object when the ORB puts it there. The ORB only puts it there when it has to perform authentication to publish the requested object. So if you are publishing a Document that is publicly viewable, the AUTHENTICATED_USER will not be set. As for the identity of the REQUEST as passed by the ORB when publishing a method, versus the acquired request (self.REQUEST) versus the REQUEST available in DTML, they should all be the same.
I *thought* this didn't confuse me, but now I am..Is AUTHENTICATED_USER never set by documents that are publicly viewable? But, this trick seems to work in publicly viewable docs: <!--#call "REQUEST.set('isManager',AUTHENTICATED_USER.hasRole(_.None,['Manager']))"--> When one views (public) docs after having logged in as a manager now, one can make the doc respond differently, such as: <!--#if "isManager"--> <p>I know you're the manager!</p> <!--#/if--> Does this mean AUTHENTICATED_USER is just not set in the *REQUEST* object, but it is in the document itself?
I hope this clears things up a bit.
Thank you for your reply, but no, it doesn't, really... I'm far more confused now. :) Perhaps I'm just bothered by my Python induced sense of how it *ought* to work, but my tests seem to partially contradict what you explained.. (or at least show there is more going on than your explanation indicates) In any case, my 'typical user confusion' will hopefully enable you guys to improve the documentation. :) Regards, Martijn
amos wrote: I did some research and also installed Zope 1.10; the DTML Documents that support properties have my special interest here. So, another reply:
The answer to question 1 is that External Methods are slightly weird methods which when called from variable expressions in DTML need to explicitly be passed the self argument if they define one. For example:
def myMethod(self, foo, bar): "blah blah" ...
will not work correctly is called like so:
<!--#var "myMethod('foo','bar')"--> because this assigns 'foo' to self and 'bar' to foo and nothing to 'bar'.
This doesn't appear to be the case? See below.
Instead you should do this:
<!--#var "myMethod(foo='foo',bar='bar')"-->
Or if you really want to pass self, you can choose a Zope object to pass (such as the parent Folder in the case of DTML methods or 'this()' in the case of other Zope objects.) For example here's one way to explicitly pass the self argument:
<!--#var "myMethod(this(),'foo','bar')"-->
I did some research with the following external method: def blah(self, id): if hasattr(self, id): return "We know %s" % id else: return "We don't know %s" % id Is this use of hasattr allowed, or discouraged? It seemed to work at first, but now it's starting to confuse me to now end. I made a folder. I defined the property 'prop_in_folder' in it. Then I put a DTML method in it: <!--#var standard_html_header--> <p><!--#var "blah('prop_in_folder')"--></p> <p><!--#var "blah(this(), 'prop_in_folder')"--></p> <!--#var standard_html_footer--> The output of this DTML method is this: We know prop_in_folder We know prop_in_folder My analysis: 'self' appears to be passed automatically; 'prop_in_folder' is not assigned to 'self'. Alternatively passing this() works fine too. Both ways pass as self the containing folder. Then I made a DTML Document (as opposed to DTML method) in the same folder. I also defined a property in the document, called 'prop_in_doc'. The DTML of the DTML Document is the following: <!--#var standard_html_header--> <p><!--#var "blah('prop_in_doc')"--></p> <p><!--#var "blah('prop_in_folder')"--></p> <p><!--#var "blah(this(), 'prop_in_doc')"--></p> <p><!--#var "blah(this(), 'prop_in_folder')"--></p> <!--#var standard_html_footer--> It gives the following output: We don't know prop_in_doc We know prop_in_folder We know prop_in_doc We don't know prop_in_folder This is where confusion starts to get me. Apparently in the first cases (when 'this()' is not passed, the self that is passed is the surrounding Folder. In the second case, this() seems to pass the Document itself, but somehow the Folder's property is not seen. This is odd, as folder properties do propagate to DTML methods as well as subfolders (I just tested this, yup, they do, both with and without passing this()). But apparently properties in surrounding folders *are* seen by DTML Documents, as evidenced by this: <p><!--#var prop_in_folder--></p> This works in a DTML document and gives me the (string) value of 'prop_in_folder'. An added complication: If I use explicit parameter naming in the DTML that calls blah(), like this: <!--#var "blah('id=prop_in_doc')"--> it results in an error message. Yet another complication is the use of default parameters in the external method (as mentioned earlier). It would be useful if there was some explanation for all this behavior. It is confusing me a lot. :) The behavior I think I expect is (I'm not sure if I *want* this behavior; there are probably caveats which make it impossible?): If the external method has as first parameter 'self', then, pass 'self' (either the document or the surrounding folder) silently and automatically. For both documents and folders, this 'self' should propagate properties etc the same way. In summary, it all works the same way as Python methods do, and documents and folders are in the equivalent of an inheritance tree so that 'self' always shares the attributes of its containing folders. If the external method doesn't use the parameter 'self', then treat it as a Python function. Anyway, I'm waiting eagerly for explanations. Even a "Martijn, you missed the blindingly obvious, and the obvious is X and X explains everything like thus!" is welcome. :) Regards, Martijn
participants (4)
-
amos -
Martijn Faassen -
Paul Everitt -
Stefan Franke