unpickling derived LogRecord in python 2.7 from python2.6
Peter Otten
__peter__ at web.de
Wed Apr 27 12:41:02 EDT 2011
ivdneut at gmail.com wrote:
> I have a service that runs in python 2.6.4. This service sends
> LogRecords to a log monitoring app on my workstation running python
> 2.7. The LogRecord class is derived:
>
> class LogRecord(logging.LogRecord):
>
> def __init__(self, name, level, fn, lno, user, hostname, msg,
> args, exc_info, func=None):
>
> if sys.version_info[1] > 4:
> logging.LogRecord.__init__(self, name, level, fn, lno,
> msg, args, exc_info, func)
> else:
> logging.LogRecord.__init__(self, name, level, fn, lno,
> msg, args, exc_info)
>
> Now when I try to unpickle it:
>
> record = cPickle.loads(data)
>
> I get a TypeError exception:
>
> TypeError: ('__init__() takes at least 8 arguments (1 given)', <class
> '...gRecord'>, ())
>
> I've searched the web and this group, but most results are old. It
> worked when my workstation still ran python 2.6.
The Problem is that as of Python 2.7 logging.LogRecord has become a newstyle
class which is pickled/unpickled differently. I don't know if there is an
official way to do the conversion, but here's what I've hacked up.
The script can read pickles written with 2.6 in 2.7, but not the other way
round.
$ cat pickle_logrec.py
import sys
import pickle
import logging
class LogRecord(logging.LogRecord):
def __init__(self, name, level, fn, lno, user, hostname, msg, args,
exc_info, func=None):
if sys.version_info[1] > 4:
logging.LogRecord.__init__(self, name, level, fn, lno, msg,
args, exc_info, func)
else:
logging.LogRecord.__init__(self, name, level, fn, lno, msg,
args, exc_info)
def makeLogRecord():
return LogRecord(*[None]*9)
if issubclass(LogRecord, object):
print "LogRecord is a newstyle class"
class MyUnpickler(pickle.Unpickler):
def find_class(self, *args):
klass = pickle.Unpickler.find_class(self, *args)
if klass is LogRecord:
return makeLogRecord
return klass
else:
print "LogRecord is an oldstyle class"
MyUnpickler = pickle.Unpickler
if __name__ == "__main__":
if "--load" in sys.argv:
print "loading"
with open("tmp.pickle") as f:
restored = MyUnpickler(f).load()
print restored
else:
print "dumping"
with open("tmp.pickle", "w") as f:
f.write(pickle.dumps(LogRecord("yadda", *[None]*8)))
$ python2.6 pickle_logrec.py
LogRecord is an oldstyle class
dumping
$ python2.6 pickle_logrec.py --load
LogRecord is an oldstyle class
loading
<LogRecord: yadda, None, None, None, "None">
$ python2.7 pickle_logrec.py --load
LogRecord is a newstyle class
loading
<LogRecord: yadda, None, None, None, "None">
No warranty, use at your own risk.
More information about the Python-list
mailing list