Sorry I wasn't clear enough. The Singleton is a design pattern from the Gang of Four book that fits this situation well. It is a class that is meant to control access to the one and only instance of a global variable. I was just using that as a frame of reference, though; Zope has no such class for the Application object, or I wouldn't be writing this message.
Oh, ok, sorry, hard to tell intent from actual code. :-)
I just need some way of getting at the one and only Application object at run-time. Something like:
from Globals import app myOb = app.Control_Panel.Products.MyProduct.MyZClass('foo') ...
Given a reference to an object in the ZODB, I can do this via:
app = self.getPhysicalRoot() myOb = app.Control_Panel.Products.MyProduct.MyZClass('foo')
But, this does not work from methods like __init__, or __setstate__, where we do not have a physical location in the ZODB, yet.
Ah, I see the problem. I'm afraid I don't know the answer. I generally use the manage_afterAdd and manage_beforeDelete methods to do things like this. I suppose you could pass the root object into the constructor. __setstate__... well. Err... Anybody else?
Chris McDonough wrote:
Sorry I wasn't clear enough. The Singleton is a design pattern from the Gang of Four book that fits this situation well. It is a class that is meant to control access to the one and only instance of a global variable. I was just using that as a frame of reference, though; Zope has no such class for the Application object, or I wouldn't be writing this message.
Oh, ok, sorry, hard to tell intent from actual code. :-)
I just need some way of getting at the one and only Application object at run-time. Something like:
from Globals import app myOb = app.Control_Panel.Products.MyProduct.MyZClass('foo') ...
Given a reference to an object in the ZODB, I can do this via:
app = self.getPhysicalRoot() myOb = app.Control_Panel.Products.MyProduct.MyZClass('foo')
But, this does not work from methods like __init__, or __setstate__, where we do not have a physical location in the ZODB, yet.
Ah, I see the problem.
I'm afraid I don't know the answer.
I generally use the manage_afterAdd and manage_beforeDelete methods to do things like this.
I suppose you could pass the root object into the constructor. __setstate__... well. Err...
Anybody else?
The way to get the root application object is to open a connection to the ZODB and get the 'Application' object from the list of root objects. There is an easy shortcut: import Zope app = Zope.app() app now refers to a *copy* of the root Application object. When you're done modifying it and its descendants you have to commit or abort the transaction. get_transaction().commit() (or abort()) This gives you all kinds of benefits like undo and elimination of threading conflicts. You *must* remember to close the connection: app._p_jar.close() Shane
On Mon, 17 Jul 2000, Shane Hathaway wrote:
The way to get the root application object is to open a connection to the ZODB and get the 'Application' object from the list of root objects. There is an easy shortcut:
import Zope app = Zope.app()
app now refers to a *copy* of the root Application object.
Yeehaw, that worked! I was so close. :-)
When you're done modifying it and its descendants you have to commit or abort the transaction.
[snip] Do I need to commit or abort even if I don't make changes to the application object? The only thing I need it for is to get to the Control_Panel; I am instantiating ZClass instances in the constructor of a Python class, i.e.: class MyClass: def __init__(self, id, title=''): import Zope app = Zope.app() ob = app.Control_Panel.Products.MyProduct.MyZClass('newId') ob.id = 'newId' self._setObject('newId', ob) # Do I need a get_transaction().abort() here? Will that not abort # the wrong transaction? app._p_jar.close() ...
This gives you all kinds of benefits like undo and elimination of threading conflicts.
[snip] Good stuff. Thanks, Shane.
Shane
--Jeff --- Jeff K. Hoffman 704.849.0731 x108 Chief Technology Officer mailto:jeff.hoffman@goingv.com Going Virtual, L.L.C. http://www.goingv.com/
"Jeff K. Hoffman" wrote:
Do I need to commit or abort even if I don't make changes to the application object? The only thing I need it for is to get to the Control_Panel; I am instantiating ZClass instances in the constructor of a Python class, i.e.:
class MyClass:
def __init__(self, id, title=''): import Zope app = Zope.app()
ob = app.Control_Panel.Products.MyProduct.MyZClass('newId') ob.id = 'newId'
self._setObject('newId', ob)
# Do I need a get_transaction().abort() here? Will that not abort # the wrong transaction?
app._p_jar.close()
Hmm... you're creating an object in a separate connection (I would call get_transaction().abort() just to be on the safe side...) then copying that object over to the existing connection. This will probably work, but I wouldn't be surprised to see thorny bugs appear. If you could instead get a handle to the existing connection, you'd be following standard practice. You probably have a manage_addMyClass() method, don't you? The "self" argument provided to that method is already connected to the database. self.getPhysicalRoot() will give you the equivalent of the app object. Then just change your constructor this way:
def __init__(self, app, id, title=''): ob = app.Control_Panel.Products.MyProduct.MyZClass('newId') ob.id = 'newId'
self._setObject('newId', ob)
Best of luck! Shane
On Mon, 17 Jul 2000, Shane Hathaway wrote:
"Jeff K. Hoffman" wrote:
Do I need to commit or abort even if I don't make changes to the application object? The only thing I need it for is to get to the Control_Panel; I am instantiating ZClass instances in the constructor of a Python class, i.e.:
class MyClass:
def __init__(self, id, title=''): import Zope app = Zope.app()
ob = app.Control_Panel.Products.MyProduct.MyZClass('newId') ob.id = 'newId'
self._setObject('newId', ob)
# Do I need a get_transaction().abort() here? Will that not abort # the wrong transaction?
app._p_jar.close()
Hmm... you're creating an object in a separate connection (I would call get_transaction().abort() just to be on the safe side...) then copying that object over to the existing connection. This will probably work, but I wouldn't be surprised to see thorny bugs appear.
I have just hit one such thorny bug. Oh well. :-)
If you could instead get a handle to the existing connection, you'd be following standard practice. You probably have a manage_addMyClass() method, don't you? The "self" argument provided to that method is already connected to the database. self.getPhysicalRoot() will give you the equivalent of the app object. Then just change your constructor this way:
def __init__(self, app, id, title=''): ob = app.Control_Panel.Products.MyProduct.MyZClass('newId') ob.id = 'newId'
self._setObject('newId', ob)
Yeah, I was there, and that worked great. Then, I started implementing my __setstate__ method to "upgrade" old instances of my python class. I need to access the connection from here, too, and this is where the trouble begins. AFAICT, I cannot call self.getPhysicalRoot() from __setstate__, for the same reason I can't call it from __init__. I can get by the __init__ problem by passing app in as an argument from manage_addMyProduct(). I can find no such solution for __setstate__.
Best of luck!
Shane
All of my efforts are progressing towards one goal: How do I upgrade existing instances of a ZClass? Since I could find no __setstate__ method for ZClasses, I re-wrote the containing class as a Python class and figured I could leverage __setstate__ there, instantiating the subordinate ZClasses when required. No such luck. I am going to spend a little more time working on this. If I can't find a solution, I may drop ZClasses altogether and move all my code to Python. I had hoped not to do this, because my web guys can work with ZClasses but have no clue where to begin with a Python Product. I may just have to take total ownership of the code, as much as I dislike the idea, if I can find no other solution. --Jeff --- Jeff K. Hoffman 704.849.0731 x108 Chief Technology Officer mailto:jeff.hoffman@goingv.com Going Virtual, L.L.C. http://www.goingv.com/
"Jeff K. Hoffman" wrote:
All of my efforts are progressing towards one goal: How do I upgrade existing instances of a ZClass? Since I could find no __setstate__ method for ZClasses, I re-wrote the containing class as a Python class and figured I could leverage __setstate__ there, instantiating the subordinate ZClasses when required.
No such luck.
Okay, here's an interesting approach. I've been playing with __of__ a lot lately, so why not see what else it can do? :-) In your class that needs to be upgraded, add this method, modifying it as needed: def __of__(self, parent): if (self.isNotUpgraded()): self.performUpgrade() return MyClass.inheritedAttribute('__of__')(self, parent) When any user walks up to the object, you will have the opportunity to perform the upgrade. Shane
On Mon, 17 Jul 2000 12:50:27 -0400 Shane Hathaway <shane@digicool.com> wrote:
import Zope app = Zope.app()
get_transaction().commit()
I am doing just that in the next version of zzLocale (Zope interface internationalization product) I was about to release. I figured it out
from the "Zope Debugging" doc (http://www.zope.org/Documentation/Misc/DEBUGGING.txt), but:
You *must* remember to close the connection:
app._p_jar.close()
This is not mentionned in the above document, so I was doing without so far, and did not run into any problem. Now that I see it, I believe this is the Right Thing to Do and will include it in the release. But since you put an emphasis on its being required, can you tell us what evil things may happen if you don't close the connection? (Consuming ressources?) -- Yves-Eric Martin Digital Garage Inc. yemartin@garage.co.jp
Yves-Eric Martin wrote:
Shane Hathaway <shane@digicool.com> wrote:
You *must* remember to close the connection:
app._p_jar.close()
This is not mentionned in the above document, so I was doing without so far, and did not run into any problem. Now that I see it, I believe this is the Right Thing to Do and will include it in the release. But since you put an emphasis on its being required, can you tell us what evil things may happen if you don't close the connection? (Consuming ressources?)
That's correct. Only a certain number of connections are allowed at a time. Currently, as the "app" object falls out of scope it should close the connection automatically, but that may not always be the case IMHO. BTW if you're using this technique, be sure you're not opening two connections in one thread. It can prove hazardous. Shane
participants (4)
-
Chris McDonough -
Jeff K. Hoffman -
Shane Hathaway -
Yves-Eric Martin