Opened 17 years ago
Last modified 17 years ago
#179 new defect
Ambiguos py:match scoping rules (combined with xi:include and py:with)
Reported by: | michele | Owned by: | cmlenz |
---|---|---|---|
Priority: | minor | Milestone: | |
Component: | Expression evaluation | Version: | 0.4.4 |
Keywords: | Cc: | michele.cella@… |
Description
I'm experiencing some problems with py:match, particularly when including another template using xi:include and py:with to parametrize the include (and/or the match).
ATM it seems as there are some inconsistency in the scope py:match sees, that's what genshi is doing now (quoting an irc discussion with cmlenz):
feb 06 12:35:29 <cmlenz> right, when the match is applied the context is that of where it matched, not where it's defined… what you'd need would basically be lexical scoping feb 06 12:42:25 <cmlenz> so one question that needs to be asked… would it ever make sense for a match template to have access to the context of where it's applied feb 06 12:42:40 <cmlenz> instead of just the context of where it's defined feb 06 12:42:48 <cmlenz> I'm not really sure myself feb 06 12:43:22 <cmlenz> python does lexical scoping (i.e. the latter), but what about e.g. xslt? feb 06 12:43:25 <mcella> atm match has access to the context of where it's applied right? feb 06 12:43:51 <cmlenz> yeah feb 06 12:44:09 <mcella> mm, but it seems backward to me feb 06 12:44:41 <cmlenz> yeah, I think I agree with you feb 06 12:44:50 <cmlenz> I just want to make sure we're not overlooking something
I've cooked up some small example to show what happens in different situations, all examples are including this template:
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:py="http://genshi.edgewall.org/" py:strip="True"> <?python bar = 'bar' ?> <div py:content="str(globals()['data'])"/> <py:match path="test"> <?python foo = 'foo' ?> <div py:content="str(globals()['data'])"/> </py:match> </html>
1)
<html xmlns:xi="http://www.w3.org/2001/XInclude" xmlns:py="http://genshi.edgewall.org/"> <xi:include href="included.html"/> <test/> </html>
outputs:
[{'defined': <function defined at 0x8b2156c>, 'value_of': <function value_of at 0x8b2148c>, 'bar': 'bar'}] [{'select': <function select at 0x8b214fc>}, {'defined': <function defined at 0x8b2156c>, 'value_of': <function value_of at 0x8b2148c>, 'bar': 'bar'}]
2)
<html xmlns:xi="http://www.w3.org/2001/XInclude" xmlns:py="http://genshi.edgewall.org/"> <xi:include py:with="" href="included.html"/> <test/> </html>
outputs:
[{'bar': 'bar'}, {'defined': <function defined at 0x8b2117c>, 'value_of': <function value_of at 0x8b214fc>}] [{'select': <function select at 0x8b21994>}, {'defined': <function defined at 0x8b2117c>, 'value_of': <function value_of at 0x8b214fc>}]
3)
<html xmlns:xi="http://www.w3.org/2001/XInclude" xmlns:py="http://genshi.edgewall.org/"> <xi:include py:with="var='var'" href="included.html"/> <test/> </html>
outputs:
[{'var': 'var', 'bar': 'bar'}, {'defined': <function defined at 0x8b21a3c>, 'value_of': <function value_of at 0x8b21a74>}] [{'select': <function select at 0x8b21ae4>}, {'defined': <function defined at 0x8b21a3c>, 'value_of': <function value_of at 0x8b21a74>}]
4)
<html xmlns:xi="http://www.w3.org/2001/XInclude" xmlns:py="http://genshi.edgewall.org/"> <xi:include href="included.html"/> <test py:with="var='var'"/> </html>
outputs:
[{'defined': <function defined at 0x8b21aac>, 'value_of': <function value_of at 0x8b21ae4>, 'bar': 'bar'}] [{'select': <function select at 0x8b21b8c>}, {'var': 'var'}, {'defined': <function defined at 0x8b21aac>, 'value_of': <function value_of at 0x8b21ae4>, 'bar': 'bar'}]
5)
<html xmlns:xi="http://www.w3.org/2001/XInclude" xmlns:py="http://genshi.edgewall.org/"> <xi:include py:with="" href="included.html"/> <test py:with="var='var'"/> </html>
outputs:
[{'bar': 'bar'}, {'defined': <function defined at 0x8b21b1c>, 'value_of': <function value_of at 0x8b21b8c>}] [{'select': <function select at 0x8b21c34>}, {'var': 'var'}, {'defined': <function defined at 0x8b21b1c>, 'value_of': <function value_of at 0x8b21b8c>}]
I'm sure these examples are not exercising every possible behavior, if someone wants to add other examples feel free to do so.
Basically it seems as using py:with introduces a different scope in the stack, this scope is then popped out once hitting py:match, in the first example the variable bar it's there since it's defined inside the template scope, but when you use py:with the template scope changes and bar ends up in a different scope that's then popped out inside py:match (examples 2, 3 and 5). Examples 4 and 5 show that as cmlenz said py:match has access to the variables defined in the matching scope.
Now, what's the proper behavior? I'm not sure, ATM I'm using the solution presented in the fourth example and it works but I do think that introducing a totally different scope when using py:with it's a bug since it breaks the global scope of the included template.
Regarding cmlenz question ("so one question that needs to be asked… would it ever make sense for a match template to have access to the context of where it's applied"), I'm not sure myself, I've said it sounds backward but I don't have a strong opinion, maybe it's right... anyone that can add to the discussion? example 4 works now and it doesn't look bad at all, on the contrary it looks pretty explicit to me...
Finally, am I wrong or it seems as python code blocks inside py:match are not being evaluated (look for the variable foo that's never appearing)? is this a bug or a feature?