Elegí usar pickle (+ base64 + sockets TCP) para comunicar datos entre mi código de python3 y el código de python2 heredado, pero tengo problemas con los objetos de datetime
y datetime
:
El objeto PY3 se desintegra bien en PY2, pero a la inversa genera un TypeError
al llamar al constructor de fecha y hora, y luego a UnicodeEncodeError
en la función load_reduce.
Un progtwig de prueba corto y el registro, que incluye la salida de disección de los pepinillos PY2 y PY3, están disponibles en este resumen.
Estoy usando pickle.dumps(reply, protocol=2)
en PY2
luego pickle._loads(pickled, fix_imports=True, encoding='latin1')
en PY3
(Intentó Ninguno y utf-8 sin éxito)
La deencoding de loads
nativas de cPickle también falla, solo estoy usando _loads
de python’s _loads
para la depuración.
¿Es este un error de datetime
y datetime
? ¿Es posible que las datetime.__getstate__/__setstate__
no sean compatibles?
Cualquier comentario sobre el código es bienvenido …
Pepinillo PY-3.4.0:
0: \x80 PROTO 2 2: c GLOBAL 'datetime datetime' 21: q BINPUT 0 23: c GLOBAL '_codecs encode' 39: q BINPUT 1 41: X BINUNICODE u'\x07\xde\x07\x11\x0f\x06\x11\x05\n\x90' 58: q BINPUT 2 60: X BINUNICODE u'latin1' 71: q BINPUT 3 73: \x86 TUPLE2 74: q BINPUT 4 76: R REDUCE 77: q BINPUT 5 79: \x85 TUPLE1 80: q BINPUT 6 82: R REDUCE 83: q BINPUT 7 85: . STOP
Pepinillo PY-2.7.6:
0: \\x80 PROTO 2 2: c GLOBAL 'datetime datetime' 21: q BINPUT 0 23: U SHORT_BINSTRING '\\x07\xc3\x9e\\x07\\x11\\x0f\\x06\\x11\\x05\\n\\x90' 35: q BINPUT 1 37: \\x85 TUPLE1 38: q BINPUT 2 40: R REDUCE 41: q BINPUT 3 43: ] EMPTY_LIST 44: q BINPUT 4 46: N NONE 47: \\x87 TUPLE3 48: q BINPUT 5 50: . STOP
PY-3.4.0 pickle.load_reduce
:
def load_reduce(self): stack = self.stack args = stack.pop() func = stack[-1] try: value = func(*args) except: print(sys.exc_info()) print(func, args) raise stack[-1] = value dispatch[REDUCE[0]] = load_reduce
PY-3.4.0 datetime
soporte de pickle:
# Pickle support. def _getstate(self): yhi, ylo = divmod(self._year, 256) us2, us3 = divmod(self._microsecond, 256) us1, us2 = divmod(us2, 256) basestate = bytes([yhi, ylo, self._month, self._day, self._hour, self._minute, self._second, us1, us2, us3]) if self._tzinfo is None: return (basestate,) else: return (basestate, self._tzinfo) def __setstate(self, string, tzinfo): (yhi, ylo, self._month, self._day, self._hour, self._minute, self._second, us1, us2, us3) = string self._year = yhi * 256 + ylo self._microsecond = (((us1 << 8) | us2) << 8) | us3 if tzinfo is None or isinstance(tzinfo, _tzinfo_class): self._tzinfo = tzinfo else: raise TypeError("bad tzinfo state arg %r" % tzinfo) def __reduce__(self): return (self.__class__, self._getstate())
La solución es usar la encoding="bytes"
siguiente manera:
pickled_bytes = bytes(pickled_str, encoding='latin1') # If your input is a string(not my case) data = pickle.loads(pickled_bytes, encoding='bytes')
(Gracias a Tim Peters por la sugerencia)
El problema aún está abierto en http://bugs.python.org/issue22005 en cuanto a por qué se requiere esto.