Storing references in objects accross requests - bad or OK?
hello, I am am worrying a problem here, where I need to store references to objects in my own objects, while at the same time needing to store and retreive my objects later. Here is an example of what I need to do: in a product BooTool for Zope I have: ---- class Foo: def __init__(self, data, ref_a): self.data = data self.a_handle = ref_a self.stuff = [] def bar(self): # do something with self.stuff cool = self.a_handle('one') self.stuff.append(cool) return self.stuff def getStuff(data, ref_a): """ his method is available to Zope from the tool boo_tool """ return Foo(data, ref_a) ---- in a python script I have a pythonscript: ---- my_ob = context.boo_tool.getStuff('123', container.my_script) return my_ob ---- so my_ob contains a reference to the my_script Pythonscript/ZSQL Method. What happens if I store my_ob in a session storage for instance and later retrieve it and do my_ob.bar() ? What bad things can happen? Thanks for any input. /dario -- -- ------------------------------------------------------------------- Dario Lopez-Kästen, IT Systems & Services Chalmers University of Tech.
Dario Lopez-Kästen wrote at 2004-6-13 12:43 +0200:
I am am worrying a problem here, where I need to store references to objects in my own objects, while at the same time needing to store and retreive my objects later.
Your problem can be summarized by "storing acquisition wrappers (of persistent objects) across requests". This is very difficult! You have a very good chance to get burned. You cannot store them in the ZODB as acquisition wrappers cannot be stored there. Currently, the ZODB silently unmantles acquisition wrappers. They may be rebound on access -- but this will not give you the original acquisition context and behaviour can be drastically different. You cannot store them via module global data structures as the values (indirectly) reference persitent objects. You must never put persistent objects outside the scope of its ZODB connection as this will give nasty (non deterministic) persistency bugs. You could store such values as volatile attributes ("_v_") of persistent objects. However, volatile attributes are not completely reliable (as the name suggests). And they are (ZODB) connection local -- another connection does not see them. You may put such objects into attributes of the ZODB connection itself. Again, they will be connection local. Urgent recommendation: avoid storing acquisition wrapped objects across requests, store paths instead and locate the objects by means of the paths. -- Dieter
Dieter Maurer wrote:
Urgent recommendation: avoid storing acquisition wrapped objects across requests, store paths instead and locate the objects by means of the paths.
Thank you Dieter and others that have helped me. It seems the best way is either to rethink the way I am doing things, or to store only strings or lists to where the objects are. Thank you for your assistance. /dario -- -- ------------------------------------------------------------------- Dario Lopez-Kästen, IT Systems & Services Chalmers University of Tech.
Dieter Maurer wrote:
Your problem can be summarized by "storing acquisition wrappers (of persistent objects) across requests".
<...>
You cannot store them in the ZODB as acquisition wrappers cannot be stored there. Currently, the ZODB silently unmantles acquisition wrappers. They may be rebound on access -- but this will not give you the original acquisition context and behaviour can be drastically different.
hello, again, I have rearranged in my product now, so that I pass along dictionaries to populate the classes and using a cmf-tool to provide the interface for the various methods of the classes. I am returning objects wrapped in __of__(self), ie. class Person(Acquisition.Implicit): def __init__(self data): ... PersonObject = Person(data).__of__(self) return PersonObject If I want to pickle, store and later reuse PersonObject, I suspect that this also creates a similar to my original one, where I wanted to store ZODB-references in the PersonObject. So should I, when pickling and storing the PersonObject, store PersonObject.aq_base rather than just PersonObject? Thanks, /dario -- -- ------------------------------------------------------------------- Dario Lopez-Kästen, IT Systems & Services Chalmers University of Tech.
[ resend - never got to the list ] Dieter Maurer wrote:
Your problem can be summarized by "storing acquisition wrappers (of persistent objects) across requests".
<...>
You cannot store them in the ZODB as acquisition wrappers cannot be stored there. Currently, the ZODB silently unmantles acquisition wrappers. They may be rebound on access -- but this will not give you the original acquisition context and behaviour can be drastically different.
hello, again, I have rearranged in my product now, so that I pass along dictionaries to populate the classes and using a cmf-tool to provide the interface for the various methods of the classes. I am returning objects wrapped in __of__(self), ie. class Person(Acquisition.Implicit): def __init__(self data): ... PersonObject = Person(data).__of__(self) return PersonObject If I want to pickle, store and later reuse PersonObject, I suspect that this also creates a similar to my original one, where I wanted to store ZODB-references in the PersonObject. So should I, when pickling and storing the PersonObject, store PersonObject.aq_base rather than just PersonObject? Thanks, /dario -- -- ------------------------------------------------------------------- Dario Lopez-Kästen, IT Systems & Services Chalmers University of Tech.
* Dario Lopez-Kästen <dario@ita.chalmers.se> [2004-06-17 19:55]:
[ resend - never got to the list ]
Dieter Maurer wrote:
Your problem can be summarized by "storing acquisition wrappers (of persistent objects) across requests".
<...>
You cannot store them in the ZODB as acquisition wrappers cannot be stored there. Currently, the ZODB silently unmantles acquisition wrappers. They may be rebound on access -- but this will not give you the original acquisition context and behaviour can be drastically different.
hello, again,
I have rearranged in my product now, so that I pass along dictionaries to populate the classes and using a cmf-tool to provide the interface for the various methods of the classes.
I am returning objects wrapped in __of__(self), ie.
class Person(Acquisition.Implicit): def __init__(self data): ...
PersonObject = Person(data).__of__(self) return PersonObject
If I want to pickle, store and later reuse PersonObject, I suspect that this also creates a similar to my original one, where I wanted to store ZODB-references in the PersonObject.
So should I, when pickling and storing the PersonObject, store
PersonObject.aq_base
rather than just PersonObject?
No, because the ZODB already strips acquisition wrappers - like Dieter pointed out above. You only have to make sure that you wrap objects in the original acquisition context when you retrieve them. -- Roché Compaan Upfront Systems http://www.upfrontsystems.co.za
Dario Lopez-Kästen wrote at 2004-6-17 11:01 +0200:
[ resend - never got to the list ]
Zope's mailing lists currently seem to have problems... Traffic volume is down to a trickle, at least as seen from here...
... class Person(Acquisition.Implicit): def __init__(self data): ...
PersonObject = Person(data).__of__(self) return PersonObject
If I want to pickle, store and later reuse PersonObject, I suspect that this also creates a similar to my original one, where I wanted to store ZODB-references in the PersonObject.
So should I, when pickling and storing the PersonObject, store
PersonObject.aq_base
rather than just PersonObject?
You cannot pickle acquisition wrappers, it simply will not work. The current ZODB code allows you to store wrapped objects as attributes of persistent objects. It catches the resulting pickling exception, unwraps the object and tries again. Whether or not you unwrap yourself or let the ZODB do it: you loose the acquisition context. Later when you access your object again (load it), you must rewrap the object. When the object is stored as an attribute of a persistent object this rewrapping happens automatically -- but usually not with the original context! -- Dieter
Dieter Maurer wrote:
Whether or not you unwrap yourself or let the ZODB do it: you loose the acquisition context. Later when you access your object again (load it), you must rewrap the object. When the object is stored as an attribute of a persistent object this rewrapping happens automatically -- but usually not with the original context!
Thak you again, Dieter. this ie s eaxctly what I needed. The loss of the acquisition context is not a problem in this particuklar context, since the context will always be a specific path in the ZODB (the path to the instance of a cmf-tool). Thanks again. /dario -- -- ------------------------------------------------------------------- Dario Lopez-Kästen, IT Systems & Services Chalmers University of Tech.
participants (3)
-
Dario Lopez-Kästen -
Dieter Maurer -
Roché Compaan