Hello, friends. It may be that I am misunderstanding something fundamental. I have code that does essentially the following: (1) Defines an external method for processing form data: # In module MyModule: def myExtMethod(req): global Request Request = req action = getFormData("action") #...process request... # And a utility function to help out - this is not an # external method, but is used by myExtMethod. def getFormData(key): return Request.get(key) (2) Defines a DTML document that just passes its input along to myExtMethod(): ... <dtml-var expr="myExtMethod(REQUEST)"> ... The point of this is that myExtMethod() is a wrapper around some old CGI code; I want the state of MyModule to be preserved between invocations of myExtMethod(), for performance reasons. I've been working with Zope for only a very short time (days), so I don't know if this is the "right" way to do this; I'd appreciate any advice on this matter. Now the problem. This code works most of the time. However, apparently at random, when executing a request, I will get an exception from getFormData(): "global name Request does not exist." This is very strange, because /every/ invocation of getFormData() is called from myExtMethod(), so there's simply no way the Request global can be unset, as far as I can see. Can anyone explain what is happening here? A pointer to relevant documentation would be sufficient; I've got "The Zope Book" and "The Book of Zope", neither of which have been much help about this particular issue (though quite helpful in many other ways). Many thanks, -- Joe "I should like to close this book by sticking out any part of my neck which is not yet exposed, and making a few predictions about how the problem of quantum gravity will in the end be solved." --- Physicist Lee Smolin, "Three Roads to Quantum Gravity"
You need to declare "global Request' in the definition of getFormData(), too. If it's defined in another module, remember that "global" means "global withing the module", not "global within all the Python code". I'm not clear why it works sometimes, though. I'd suggest passing the request explictly; it wouldn't affect your maintaining the state of the module: def getFormData(key,Request): return Request.get(key) #Don't need the "global" Cheers Tom P [Joseph A Knapka]
It may be that I am misunderstanding something fundamental. I have code that does essentially the following:
(1) Defines an external method for processing form data:
# In module MyModule: def myExtMethod(req):
global Request Request = req
action = getFormData("action") #...process request...
# And a utility function to help out - this is not an # external method, but is used by myExtMethod. def getFormData(key): return Request.get(key)
(2) Defines a DTML document that just passes its input along to myExtMethod():
...
<dtml-var expr="myExtMethod(REQUEST)"> ...
The point of this is that myExtMethod() is a wrapper around some old CGI code; I want the state of MyModule to be preserved between invocations of myExtMethod(), for performance reasons. I've been working with Zope for only a very short time (days), so I don't know if this is the "right" way to do this; I'd appreciate any advice on this matter.
Now the problem. This code works most of the time. However, apparently at random, when executing a request, I will get an exception from getFormData(): "global name Request does not exist." This is very strange, because /every/ invocation of getFormData() is called from myExtMethod(), so there's simply no way the Request global can be unset, as far as I can see.
"Thomas B. Passin" wrote:
You need to declare "global Request' in the definition of getFormData(), too.
No. In Python, the rule is "any variable not assigned in the body of a function is presumed to be a module global" (though this may change in the presence of nested scopes in Python 2.2). It appears that global state in Zope is just not handled the way I, as a Python programmer, expect. For example: # In module xtest: myVar = 0 # External method: def getAndIncMyVar(): global myVar myVar = myVar + 1 return "The value of myVar is now %d"%myVar # In DTML document myVarTest: <standard_html_header> <dtml-var expr="getAndIncMyVar()"> <standard_html_footer> If you go to the /myVarTest URL and hit "Refresh Page" a couple of dozen times, you will see the reported value of myVar jump around. It will increase for a while, then jump backward an apparently random number. The violates my (Python-centered) expectations most horribly, and I'd really like to understand it. Are external-method modules automaically reloaded periodically, or something like that? Thanks, -- Joe "I should like to close this book by sticking out any part of my neck which is not yet exposed, and making a few predictions about how the problem of quantum gravity will in the end be solved." --- Physicist Lee Smolin, "Three Roads to Quantum Gravity"
[Joseph A Knapka]
"Thomas B. Passin" wrote:
You need to declare "global Request' in the definition of getFormData(), too.
No. In Python, the rule is "any variable not assigned in the body of a function is presumed to be a module global" (though this may change in the presence of nested scopes in Python 2.2).
Yes, I overlooked the fact that you only referred to the Request and didn't assign to it.
It appears that global state in Zope is just not handled the way I, as a Python programmer, expect. For example:
# In module xtest: myVar = 0
# External method: def getAndIncMyVar(): global myVar myVar = myVar + 1 return "The value of myVar is now %d"%myVar
# In DTML document myVarTest: <standard_html_header> <dtml-var expr="getAndIncMyVar()"> <standard_html_footer>
If you go to the /myVarTest URL and hit "Refresh Page" a couple of dozen times, you will see the reported value of myVar jump around. It will increase for a while, then jump backward an apparently random number. The violates my (Python-centered) expectations most horribly, and I'd really like to understand it.
I just did it 110 times and it incremented normally each time. This is on Windows 2000, IE5.5, Zope 2.3.3. Then I loaded it into Netscape 4.73 and it picked up where it had left off, and it incremented for another 20 tries. So it seems to work as expected on my system.
Are external-method modules automaically reloaded periodically, or something like that?
They would if your service died and restarted. You'd think it would reset to zero, though. Could there be some caching shenanigans going on instead? Cheers, Tom P
"Thomas B. Passin" wrote:
If you go to the /myVarTest URL and hit "Refresh Page" a couple of dozen times, you will see the reported value of myVar jump around. It will increase for a while, then jump backward an apparently random number. The violates my (Python-centered) expectations most horribly, and I'd really like to understand it.
I just did it 110 times and it incremented normally each time. This is on Windows 2000, IE5.5, Zope 2.3.3. Then I loaded it into Netscape 4.73 and it picked up where it had left off, and it incremented for another 20 tries. So it seems to work as expected on my system.
Mine is Zope 2.5.0 on WinNT4, IE6, Navigator4.77. And now that I try it again, I cannot reproduce this behavior myself, though I definitely saw it earlier. I must have been doing something differently in the script. Also, I rewrote my original code (the CGI app wrapper mentioned in my original message) to always pass REQUEST as a parameter to all code that uses it, rather than assigning it to a global; that code worked flawlessly. Then I rewrote it again to store REQUEST as a global, and that, too, is working fine now. So apparently this is all a case of pilot error. If I find out any further information, such as exactly what stupid thing I was doing to cause the problems I saw, I'll post a message :0-/ (Hmm, can I use Zope to do version-control on my Python extension files? I think so...) Cheers, -- Joe "I should like to close this book by sticking out any part of my neck which is not yet exposed, and making a few predictions about how the problem of quantum gravity will in the end be solved." --- Physicist Lee Smolin, "Three Roads to Quantum Gravity"
Joseph A Knapka wrote:
Mine is Zope 2.5.0 on WinNT4, IE6, Navigator4.77. And now that I try it again, I cannot reproduce this behavior myself, though I definitely saw it earlier. I must have been doing something differently in the script.
Also, I rewrote my original code (the CGI app wrapper mentioned in my original message) to always pass REQUEST as a parameter to all code that uses it, rather than assigning it to a global; that code worked flawlessly. Then I rewrote it again to store REQUEST as a global, and that, too, is working fine now. So apparently this is all a case of pilot error. If I find out any further information, such as exactly what stupid thing I was doing to cause the problems I saw, I'll post a message :0-/
OK, I lied, Zope wasn't using the re-globalfied version, which still breaks. However, I've managed to narrow the problem down: The problem with global data being "missing" only happens when the DTML doc that calls my external method is invoked from a particular other DTML document. Also, I discovered that if I create an empty module called "myGlobals", and explicitly place all my global data there, everything works. Still confused, trying to build a simple case that breaks the same way as my original code. Cheers, -- Joe "I should like to close this book by sticking out any part of my neck which is not yet exposed, and making a few predictions about how the problem of quantum gravity will in the end be solved." --- Physicist Lee Smolin, "Three Roads to Quantum Gravity"
[Joseph A Knapka]
OK, I lied, Zope wasn't using the re-globalfied version, which still breaks. However, I've managed to narrow the problem down: The problem with global data being "missing" only happens when the DTML doc that calls my external method is invoked from a particular other DTML document.
Also, I discovered that if I create an empty module called "myGlobals", and explicitly place all my global data there, everything works. Still confused, trying to build a simple case that breaks the same way as my original code.
Well, in Python you can invoke any function with your own context (globals and locals). Zope may supply its own globals when it calls an external method , and maybe in some cases that would prevent yours from being known. It's an area I don't know much about. I'd still prefer to pass everything as explicit parameters, but I can see cases where it would be useful to use various global variables. How are you making use of your myGlobals module? Just importing * from it? Cheers, Tom P
"Thomas B. Passin" wrote:
[Joseph A Knapka]
OK, I lied, Zope wasn't using the re-globalfied version, which still breaks. However, I've managed to narrow the problem down: The problem with global data being "missing" only happens when the DTML doc that calls my external method is invoked from a particular other DTML document.
Also, I discovered that if I create an empty module called "myGlobals", and explicitly place all my global data there, everything works. Still confused, trying to build a simple case that breaks the same way as my original code.
Well, in Python you can invoke any function with your own context (globals and locals). Zope may supply its own globals when it calls an external method , and maybe in some cases that would prevent yours from being known.
I thought of that, but it's still bizarre, because my code says: def myExtMethod(REQUEST): global req_data req_data = REQUEST ... and then later in code called from myExtMethod(), it's *req_data* that can't be found in the global namespace. Since it's being assigned at a place which every single call to this code passes through, I'm quite mystified. But it does seem to be an animal of the general nature you suggest.
It's an area I don't know much about. I'd still prefer to pass everything as explicit parameters, but I can see cases where it would be useful to use various global variables.
Sometimes globals are good. Sometimes even "goto" is good :)
How are you making use of your myGlobals module? Just importing * from it?
import myGlobals def myExtMethod(REQUEST): myGlobals.req_data = REQUEST ... ... then use "myGlobals.req_data" instead of just "req_data" everywhere else in the file. The problem definitely smells of some weird interaction between Zope and the Python namespace mechanism. I may just tear the hood off of Zope some time soon and poke around a bit. Cheers, -- Joe "I should like to close this book by sticking out any part of my neck which is not yet exposed, and making a few predictions about how the problem of quantum gravity will in the end be solved." --- Physicist Lee Smolin, "Three Roads to Quantum Gravity"
[Joseph A Knapka]
How are you making use of your myGlobals module? Just importing * from
it?
import myGlobals def myExtMethod(REQUEST): myGlobals.req_data = REQUEST ...
... then use "myGlobals.req_data" instead of just "req_data" everywhere else in the file.
I do the same kind of thing to let a module find the root of its directory subtree. The modules are in a package, and in the __init__.py I get the root location from __file__. I import it where I want to use it with external methods and it lets me put things into the right locations. That way I don't have to hard-code the root location. Cheers, Tom P
Joseph A Knapka writes:
... (1) Defines an external method for processing form data:
# In module MyModule: def myExtMethod(req):
global Request Request = req
action = getFormData("action") #...process request... ... Now the problem. This code works most of the time. However, apparently at random, when executing a request, I will get an exception from getFormData(): "global name Request does not exist." This is very strange, because /every/ invocation of getFormData() is called from myExtMethod(), so there's simply no way the Request global can be unset, as far as I can see. In earlier Zope versions (may no longer be true for very new Zope versions (i.e. above 2,4,3)), the source files of External Methods have not been Python modules. Their data was thread private. I.e. each of the Zope threads had its own copy of this data (and of your global variable "REQUEST"). When a new thread processes the request, it may not see the global variable defined in a previous request.
Move such data into a true Python module, define your function there. Make you External Method a one liner: from myTruePythonMethod import myFunction Dieter
Dieter Maurer wrote:
Joseph A Knapka writes:
... (1) Defines an external method for processing form data:
# In module MyModule: def myExtMethod(req):
global Request Request = req
action = getFormData("action") #...process request... ... Now the problem. This code works most of the time. However, apparently at random, when executing a request, I will get an exception from getFormData(): "global name Request does not exist." This is very strange, because /every/ invocation of getFormData() is called from myExtMethod(), so there's simply no way the Request global can be unset, as far as I can see. In earlier Zope versions (may no longer be true for very new Zope versions (i.e. above 2,4,3)), the source files of External Methods have not been Python modules. Their data was thread private. I.e. each of the Zope threads had its own copy of this data (and of your global variable "REQUEST"). When a new thread processes the request, it may not see the global variable defined in a previous request.
Move such data into a true Python module, define your function there. Make you External Method a one liner:
from myTruePythonMethod import myFunction
Dieter
Hmm... I think my external method is already a Python module, since I had to tell it the module name and function when I did "Add->External Method." This is under Zope 2.5.0 on Windows (NT development system, production server will be Win98 -- Yes, I know, but I'm stuck with it.) I'll try your suggestion and see if it helps. Thanks, -- Joe "I should like to close this book by sticking out any part of my neck which is not yet exposed, and making a few predictions about how the problem of quantum gravity will in the end be solved." --- Physicist Lee Smolin, "Three Roads to Quantum Gravity"
Joseph A Knapka writes:
Hmm... I think my external method is already a Python module, since I had to tell it the module name and function when I did "Add->External Method." This is under Zope 2.5.0 on Windows (NT development system, production server will be Win98 -- Yes, I know, but I'm stuck with it.) It's probably not a module in Python's sense.
Dieter
participants (3)
-
Dieter Maurer -
Joseph A Knapka -
Thomas B. Passin