What's an accurate way of checking whether an object can be atomically pickled? When I say "atomically pickled", I mean without considering other objects it may refer to. For example, this list:
l = [threading.Lock()]
is not a a pickleable object, because it refers to a Lock
which is not pickleable. But atomically, this list itself is pickleable.
So how do you check whether an object is atomically pickleable? (I'm guessing the check should be done on the class, but I'm not sure.)
I want it to behave like this:
>>> is_atomically_pickleable(3)
True
>>> is_atomically_pickleable(3.1)
True
>>> is_atomically_pickleable([1, 2, 3])
True
>>> is_atomically_pickleable(threading.Lock())
False
>>> is_atomically_pickleable(open('whatever', 'r'))
False
Etc.
Given that you're willing to break encapsulation, I think this is the best you can do:
from pickle import Pickler
import os
class AtomicPickler(Pickler):
def __init__(self, protocol):
# You may want to replace this with a fake file object that just
# discards writes.
blackhole = open(os.devnull, 'w')
Pickler.__init__(self, blackhole, protocol)
self.depth = 0
def save(self, o):
self.depth += 1
if self.depth == 1:
return Pickler.save(self, o)
self.depth -= 1
return
def is_atomically_pickleable(o, protocol=None):
pickler = AtomicPickler(protocol)
try:
pickler.dump(o)
return True
except:
# Hopefully this exception was actually caused by dump(), and not
# something like a KeyboardInterrupt
return False
In Python the only way you can tell if something will work is to try it. That's the nature of a language as dynamic as Python. The difficulty with your question is that you want to distinguish between failures at the "top level" and failures at deeper levels.
Pickler.save
is essentially the control-center for Python's pickling logic, so the above creates a modified Pickler
that ignores recursive calls to its save
method. Any exception raised while in the top-level save is treated as a pickling failure. You may want to add qualifiers to the except
statement. Unqualified excepts
in Python are generally a bad idea as exceptions are used not just for program errors but also for things like KeyboardInterrupt
and SystemExit
.
This can give what are arguably false negatives for types with odd custom pickling logic. For example, if you create a custom list-like class that instead of causing Pickler.save
to be recursively called it actually tried to pickle its elements on its own somehow, and then created an instance of this class that contained an element that its custom logic could not pickle, is_atomically_pickleable
would return False
for this instance even though removing the offending element would result in an object that was pickleable.
Also, note the protocol argument to is_atomically_pickleable
. Theoretically an object could behave differently when pickled with different protocols (though that would be pretty weird) so you should make this match the protocol argument you give to dump
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With