Commit 69dc6de1 authored by Kirill Smelkov's avatar Kirill Smelkov

zodbdump: Fix pickle disassembly on py3

pickletools.dis, which is used to handle --pretty=zpickledis (*),
expects output stream be text-like, not binary. We were passing a binary
stream to it. As the result pickle disassembly was failing on py3:

    _______________________ test_zodbdump[!zext-zpickledis] ________________________

    tmpdir = local('/tmp/pytest-of-kirr/pytest-11/test_zodbdump__zext_zpickledis0')
    zext = <function zext.<locals>._ at 0x7f538b508670>, pretty = 'zpickledis'

        @mark.parametrize('pretty', ('raw', 'zpickledis'))
        def test_zodbdump(tmpdir, zext, pretty):
            tdir  = dirname(__file__)
            zkind = '_!zext' if zext.disabled else ''
            tfs1  = fs1_testdata_py23(tmpdir, '%s/testdata/1%s.fs' % (tdir, zkind))
            stor  = FileStorage(tfs1, read_only=True)

            with open('%s/testdata/1%s.zdump.%s.ok' % (tdir, zkind, pretty), 'rb') as f:
                dumpok = f.read()

            out = BytesIO()
    >       zodbdump(stor, None, None, pretty=pretty, out=out)

    zodbtools/test/test_dump.py:48:
    _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
    zodbtools/zodbdump.py:165: in zodbdump
        pickletools.dis(dataf, disf) # class
    _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

    pickle = <_io.BytesIO object at 0x7f538b577130>
    out = <_io.BytesIO object at 0x7f538b49f8b0>, memo = {}, indentlevel = 4
    annotate = 0

        def dis(pickle, out=None, memo=None, indentlevel=4, annotate=0):
            """Produce a symbolic disassembly of a pickle..."""
            ...
            for opcode, arg, pos in genops(pickle):
                if pos is not None:
    >               print("%5d:" % pos, end=' ', file=out)
    E               TypeError: a bytes-like object is required, not 'str'

    /usr/lib/python3.9/pickletools.py:2450: TypeError

-> Fix it by letting pickletools.dis to emit its output to StringIO instead of BytesIO.

(*) see 80559a94 "zodbdump: support --pretty option with a format to show
    pickles disassembly"
parent e825f80f
...@@ -76,6 +76,7 @@ import logging as log ...@@ -76,6 +76,7 @@ import logging as log
import re import re
from golang.gcompat import qq from golang.gcompat import qq
from golang import func, defer, strconv, b from golang import func, defer, strconv, b
from six import StringIO # io.StringIO does not accept non-unicode strings on py2
# txn_raw_extension returns raw extension from txn metadata # txn_raw_extension returns raw extension from txn metadata
def txn_raw_extension(stor, txn): def txn_raw_extension(stor, txn):
...@@ -122,9 +123,9 @@ def zodbdump(stor, tidmin, tidmax, hashonly=False, pretty='raw', out=asbinstream ...@@ -122,9 +123,9 @@ def zodbdump(stor, tidmin, tidmax, hashonly=False, pretty='raw', out=asbinstream
else: else:
out.write(b"extension\n") out.write(b"extension\n")
extf = BytesIO(rawext) extf = BytesIO(rawext)
disf = BytesIO() disf = StringIO()
pickletools.dis(extf, disf) pickletools.dis(extf, disf)
out.write(indent(disf.getvalue(), " ")) out.write(b(indent(disf.getvalue(), " ")))
extra = extf.read() extra = extf.read()
if len(extra) > 0: if len(extra) > 0:
out.write(b" + extra data %s\n" % qq(extra)) out.write(b" + extra data %s\n" % qq(extra))
...@@ -161,10 +162,10 @@ def zodbdump(stor, tidmin, tidmax, hashonly=False, pretty='raw', out=asbinstream ...@@ -161,10 +162,10 @@ def zodbdump(stor, tidmin, tidmax, hashonly=False, pretty='raw', out=asbinstream
elif pretty == 'zpickledis': elif pretty == 'zpickledis':
# https://github.com/zopefoundation/ZODB/blob/5.6.0-55-g1226c9d35/src/ZODB/serialize.py#L24-L29 # https://github.com/zopefoundation/ZODB/blob/5.6.0-55-g1226c9d35/src/ZODB/serialize.py#L24-L29
dataf = BytesIO(obj.data) dataf = BytesIO(obj.data)
disf = BytesIO() disf = StringIO()
pickletools.dis(dataf, disf) # class pickletools.dis(dataf, disf) # class
pickletools.dis(dataf, disf) # state pickletools.dis(dataf, disf) # state
out.write(indent(disf.getvalue(), " ")) out.write(b(indent(disf.getvalue(), " ")))
extra = dataf.read() extra = dataf.read()
if len(extra) > 0: if len(extra) > 0:
out.write(b" + extra data %s\n" % qq(extra)) out.write(b" + extra data %s\n" % qq(extra))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment