def canSerialize(obj): result = False container_type_tuple = (list, tuple, dict, set, frozenset) # if object is a container, we need to check its elements for presence of # objects that cannot be put inside the zodb if isinstance(obj, container_type_tuple): if isinstance(obj, dict): result_list = [] for key, value in obj.iteritems(): result_list.append(canSerialize(key)) result_list.append(canSerialize(value)) else: result_list = [canSerialize(element) for element in obj] return all(result_list) # if obj is an object and implements __getstate__, ZODB.serialize can check # if we can store it elif isinstance(obj, object) and hasattr(obj, '__getstate__'): # Need to unwrap the variable, otherwise we get a TypeError, because # objects cannot be pickled while inside an acquisition wrapper. unwrapped_obj = Acquisition.aq_base(obj) writer = ObjectWriter(unwrapped_obj) for obj in writer: try: writer.serialize(obj) # Because writer.serialize(obj) relies on the implementation of __getstate__ # of obj, all errors can happen, so the "except all" is necessary here. except: return False return True else: # If cannot serialize object with ZODB.serialize, try with cPickle # Only a dump of the object is not enough. Dumping and trying to # load it will properly raise errors in all possible situations, # for example: if the user defines a dict with an object of a class # that he created the dump will stil work, but the load will fail. try: cPickle.loads(cPickle.dumps(obj)) # By unknowing reasons, trying to catch cPickle.PicklingError in the "normal" # way isn't working. This issue might be related to some weirdness in # pickle/cPickle that is reported in this issue: http://bugs.python.org/issue1457119. # # So, as a temporary fix, we're investigating the exception's class name as # string to be able to identify them. # # Even though the issue seems complicated, this quickfix should be # properly rewritten in a better way as soon as possible. except Exception as e: if type(e).__name__ in ('PicklingError', 'TypeError', 'NameError', 'AttributeError'): return False else: raise e else: return True
def canSerialize(obj): result = False container_type_tuple = (list, tuple, dict, set, frozenset) # if object is a container, we need to check its elements for presence of # objects that cannot be put inside the zodb if isinstance(obj, container_type_tuple): if isinstance(obj, dict): result_list = [] for key, value in obj.iteritems(): result_list.append(canSerialize(key)) result_list.append(canSerialize(value)) else: result_list = [canSerialize(element) for element in obj] return all(result_list) # if obj is an object and implements __getstate__, ZODB.serialize can check # if we can store it elif isinstance(obj, object) and hasattr(obj, '__getstate__') and hasattr( obj, '_p_jar'): # Need to unwrap the variable, otherwise we get a TypeError, because # objects cannot be pickled while inside an acquisition wrapper. unwrapped_obj = Acquisition.aq_base(obj) writer = ObjectWriter(unwrapped_obj) for obj in writer: try: writer.serialize(obj) # Because writer.serialize(obj) relies on the implementation of __getstate__ # of obj, all errors can happen, so the "except all" is necessary here. except: return False return True else: # If cannot serialize object with ZODB.serialize, try with cPickle # Only a dump of the object is not enough. Dumping and trying to # load it will properly raise errors in all possible situations, # for example: if the user defines a dict with an object of a class # that he created the dump will stil work, but the load will fail. try: cPickle.loads(cPickle.dumps(obj)) # By unknowing reasons, trying to catch cPickle.PicklingError in the "normal" # way isn't working. This issue might be related to some weirdness in # pickle/cPickle that is reported in this issue: http://bugs.python.org/issue1457119. # # So, as a temporary fix, we're investigating the exception's class name as # string to be able to identify them. # # Even though the issue seems complicated, this quickfix should be # properly rewritten in a better way as soon as possible. except (cPickle.PicklingError, TypeError, NameError, AttributeError) as e: return False else: return True
def register(self, obj): """ Serialize early to inspect PicklingErrors Raise any PicklingErrors when the object is added to the transaction as opposed to when the transaction is committed. Under pdb, for example, this allows inspecting the code that made the change resulting in the PicklingError. Requires either zope.testrunner or zope.testing which can be included using the 'zodb' or 'zodb-testing' extras respectively. """ orig_register(self, obj) writer = ObjectWriter(obj) # Replace the pickler so that it doesn't set oids import cPickle as pickle writer._p = pickle.Pickler(writer._file, 1) # Try to serialize to raise piclkling errors early writer.serialize(obj)