1. 17 Jul, 2024 16 commits
    • Kirill Smelkov's avatar
      Test under all py2_pickle{1,2,3} and py3_pickle3 ZODB kinds + fix discovered issues · f9d36ba7
      Kirill Smelkov authored
      Hello @jerome,
      
      For ZODB/go and WCFS, in order to support Python3 and Python2 with recent
      ZODB5, I need to extend generated test databases to cover all ZODB kinds
      instead of only ZODB/py2 + pickle protocol=2 we had before. This resulted in
      `run_with_all_zodb_pickle_kinds` utility inside gen_testdata.py and zodbtools
      also becoming well tested under all kinds of ZODB databases:
      
          py2: ZODB 4 and ZODB5 < 5.3     (pickle protocol 1)
          py2: ZODB 5.3                   (pickle protocol 2)
          py2: ZODB ≥ 5.4                 (pickle protocol 3)
          py3: ZODB4 and ZODB5            (pickle protocol 3)
      
      Please find the patches that do that for zodbtools attached. Some problems
      popped up due to extended testing coverage and they are fixed as well.
      
      Please see individual patches for details.
      
      Kirill
      
      /cc @vnmabus, @levin.zimmermann
      /reviewed-by @jerome
      /reviewed-on !29
      f9d36ba7
    • Kirill Smelkov's avatar
      *: Cosmetics · dbfea935
      Kirill Smelkov authored
      Fix noticed typos, remove shebang from py source not intended to be
      executed.
      dbfea935
    • Kirill Smelkov's avatar
      *: Fix pyflakes · 7f45f6da
      Kirill Smelkov authored
          (zdev+py39.env) kirr@deca:~/src/wendelin/z/zodbtools/zodbtools$ python3 -m pyflakes .
          ./test/test_dump.py:32:1: 'pytest.xfail' imported but unused
      
      Unused xfail import was there in test_dump.py from 425e6656 (dump,
      commit: Test for both non-empty and empty transaction extensions).
      7f45f6da
    • Kirill Smelkov's avatar
      commit: test: Use at0 instead of head to represent initial transaction ID · df9b1425
      Kirill Smelkov authored
      `head` name is a bit ambiguous because it might be perceived as
      referring to currently latest transaction ID, but in that test it
      refers to latest transaction ID when the test starts.
      
      Rename it to at0 for clarity.
      
      Just added test_zodbcommit_cmd already uses at0  to represent initial
      transaction ID (and at1 + at2 to represent follow-up transaction IDs).
      
      In general using atX naming comes from WCFS functional tests where it is
      used widely - see e.g.
      https://lab.nexedi.com/nexedi/wendelin.core/-/blob/07087ec8/wcfs/wcfs_test.py#L1539-1581
      df9b1425
    • Kirill Smelkov's avatar
      commit: Fix it wrt ZEO · 858c134c
      Kirill Smelkov authored
      Since 7ae5ff82 (Port zodbtools to py3) zodbtools/py3 requires
      pygolang!21 with which
      running `zodb commit` wrt ZEO, as demonstrates by added
      test_zodbcommit_cmd, yields:
      
          test/test_commit.py::test_zodbcommit_cmd[ZEO-!zext] Traceback (most recent call last):
            File "/usr/lib/python2.7/runpy.py", line 174, in _run_module_as_main
              "__main__", fname, loader, pkg_name)
            File "/usr/lib/python2.7/runpy.py", line 72, in _run_code
              exec code in run_globals
            File "/home/kirr/src/wendelin/z/zodbtools/zodbtools/zodb.py", line 133, in <module>
              main()
            File "/home/kirr/src/wendelin/z/zodbtools/zodbtools/zodb.py", line 129, in main
              return command_module.main(argv)
            File "<decorator-gen-4>", line 2, in main
            File "/home/kirr/src/tools/go/pygolang/golang/__init__.py", line 125, in _
              return f(*argv, **kw)
            File "/home/kirr/src/wendelin/z/zodbtools/zodbtools/zodbcommit.py", line 232, in main
              tid = zodbcommit(stor, at, txn)
            File "/home/kirr/src/wendelin/z/zodbtools/zodbtools/zodbcommit.py", line 131, in zodbcommit
              _()
            File "/home/kirr/src/wendelin/z/zodbtools/zodbtools/zodbcommit.py", line 128, in _
              stor.store(obj.oid, current_serial(obj.oid), data, '', txn)
            File "/home/kirr/src/wendelin/z/zodbtools/zodbtools/zodbcommit.py", line 87, in current_serial
              return _serial_at(stor, oid, at)
            File "/home/kirr/src/wendelin/z/zodbtools/zodbtools/zodbcommit.py", line 152, in _serial_at
              xdata = stor.loadBefore(oid, before)
            File "/home/kirr/src/wendelin/z/ZEO5/src/ZEO/ClientStorage.py", line 616, in loadBefore
              return self._server.load_before(oid, tid)
            File "/home/kirr/src/wendelin/z/ZEO5/src/ZEO/asyncio/client.py", line 935, in load_before
              return self.io_call(self.load_before_co(oid, tid, self.timeout))
            File "/home/kirr/src/wendelin/z/ZEO5/src/ZEO/asyncio/client.py", line 862, in io_call
              return future.result() if wait else future
            File "/home/kirr/src/wendelin/z/ZEO5/src/ZEO/asyncio/futures.py", line 230, in result
              return Future.result(self)
            File "/home/kirr/src/wendelin/z/ZEO5/src/ZEO/asyncio/futures.py", line 81, in result
              raise self._result
          ClientDisconnected: [Errno 104] Connection reset by peer
          FAILED()
          zeo.log:
      
          2024-07-16T21:13:45 ERROR ZEO.asyncio.server Can't deserialize message
          Traceback (most recent call last):
            File "/home/kirr/src/wendelin/z/ZEO5/src/ZEO/asyncio/server.py", line 100, in message_received
              message_id, async_, name, args = self.decode(message)
            File "/home/kirr/src/wendelin/z/ZEO5/src/ZEO/asyncio/marshal.py", line 119, in pickle_server_decode
              return unpickler.load()  # msgid, flags, name, args
            File "/home/kirr/src/wendelin/z/ZEO5/src/ZEO/asyncio/marshal.py", line 176, in server_find_global
              raise ImportError("Module not allowed: %s" % (module,))
          ImportError: Module not allowed: golang
      
      This happens because zodbcommit.main and zodbdump.DumpReader use bstr to
      handle binary data and further pass as IStorageTransactionInformation
      instance to ZEO via its RPC, but ZEO server explicitly checks safe to
      import modules and rejects golang.
      
      One way to fix would be to patch ZEO to allow golang imports, but in
      general it is better to follow the interface strictly and stay 100%
      compatible with its users. That's why the fix converts fields covered by
      IStorageTransactionInformation to exact types specified by that
      interface to stay 100% compatible with users of the interface because on
      py3 e.g. (b' ' == ' ') returns False and so we need to be careful to
      provide .status as exactly str instead bytes, and do the similar for
      other fields.
      858c134c
    • Kirill Smelkov's avatar
      commit: test: Verify it with both FileStorage and ZEO · 961066fe
      Kirill Smelkov authored
      There is currently one problem with `zodb commit` that exhibits it only
      with ZEO. And it could be triggered only via commandline.
      
      As a preparatory step for the fix add infrastructure to test zodbcommit
      with both FileStorage and ZEO via zsrv fixture.
      
      There is currently no breakage - test_commit continues to work ok. In
      the next patch we will add test for commandline handling of `zodb
      commit` and fix the issue.
      
      P.S. Support code for testing wrt ZEO is based on wendelin.core :
      
      https://lab.nexedi.com/nexedi/wendelin.core/-/blob/07087ec8/lib/testing.py#L230-308
      
      Maybe in the future it would be a good idea to switch wendelin.core to
      use zodbtools-provided ZSrv fixture.
      961066fe
    • Kirill Smelkov's avatar
      test/*: Add py3 + pickle protocol=3 ZODB kind to test matrix · 479c353d
      Kirill Smelkov authored
      Adjust conftest.py and gen_testdata to generate test data files from
      under ZODB/py3 . Adjust testutil to be able to open such databases from
      under py2. As seen in the appendix the most difference in generated data
      is that *UNICODE opcodes are used instead of *STRING. Adjust test_dump
      to normalize UNICODE and further BYTES so that zdump.zpickledis.ok
      golden files are handled ok under both py2 and py3.
      
      Appendix.
      
          (zdev+py39.env) kirr@deca:~/src/wendelin/z/zodbtools/zodbtools/test/testdata/1_!zext$ xdiff py2_pickle3/zdump.zpickledis.ok py3_pickle3/zdump.zpickledis.ok
          diff --git a/py2_pickle3/zdump.zpickledis.ok b/py3_pickle3/zdump.zpickledis.ok
          index cd9d7f5..b44cbc8 100644
          --- a/py2_pickle3/zdump.zpickledis.ok
          +++ b/py3_pickle3/zdump.zpickledis.ok
          @@ -2,16 +2,16 @@ txn 0285cbac70a3d733 "p"
           user "user0.12"
           description "step 0.12"
           extension ""
          -obj 0000000000000001 34 sha1:fc9e49cca756681a9f36c915c6b7b8ad79f17cbc
          +obj 0000000000000001 37 sha1:fb5c1963fc8207cbf2e9959ebb9a29eec5f56ae1
                 0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
          -     19: q    BINPUT     1
          +     19: q    BINPUT     0
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      3
          -     24: U    SHORT_BINSTRING 'f0.12'
          -     31: q    BINPUT     2
          -     33: .    STOP
          +     24: X    BINUNICODE 'f0.12'
          +     34: q    BINPUT     1
          +     36: .    STOP
             highest protocol among opcodes = 2
      
          @@ -19,16 +19,16 @@ txn 0285cbac7eb85219 "p"
           user "user0.15"
           description "step 0.15"
           extension ""
          -obj 0000000000000006 34 sha1:76a94af22a81cd970845aeb3536f428a96afcfc7
          +obj 0000000000000006 37 sha1:4baeb60acd0e085453e46bbeea395bf028652f28
                 0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
          -     19: q    BINPUT     1
          +     19: q    BINPUT     0
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      3
          -     24: U    SHORT_BINSTRING 'e0.15'
          -     31: q    BINPUT     2
          -     33: .    STOP
          +     24: X    BINUNICODE 'e0.15'
          +     34: q    BINPUT     1
          +     36: .    STOP
             highest protocol among opcodes = 2
      
          @@ -36,16 +36,16 @@ txn 0285cbac917e4b4c "p"
           user "user0.19"
           description "step 0.19"
           extension ""
          -obj 0000000000000005 34 sha1:4bd994052ba9a6b1f328c252d8766f13c53ae209
          +obj 0000000000000005 37 sha1:de7296cc2cea8492226a55e9b4f42daa4070f5af
                 0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
          -     19: q    BINPUT     1
          +     19: q    BINPUT     0
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      3
          -     24: U    SHORT_BINSTRING 'a0.19'
          -     31: q    BINPUT     2
          -     33: .    STOP
          +     24: X    BINUNICODE 'a0.19'
          +     34: q    BINPUT     1
          +     36: .    STOP
             highest protocol among opcodes = 2
      
          @@ -53,16 +53,16 @@ txn 0285cbac9ae147e6 "p"
           user "user0.21"
           description "step 0.21"
           extension ""
          -obj 0000000000000002 34 sha1:633b0e1e89447d452468367784717fb48b0b83b1
          +obj 0000000000000002 37 sha1:d9bd775ab8808616fc61abddd57f505c2e53e00e
                 0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
          -     19: q    BINPUT     1
          +     19: q    BINPUT     0
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      3
          -     24: U    SHORT_BINSTRING 'd0.21'
          -     31: q    BINPUT     2
          -     33: .    STOP
          +     24: X    BINUNICODE 'd0.21'
          +     34: q    BINPUT     1
          +     36: .    STOP
             highest protocol among opcodes = 2
      
          @@ -70,16 +70,16 @@ txn 0285cbacada74119 "p"
           user "root0.0\nYour\nMagesty "
           description "undo 0.0\nmore detailed description\n\nzzz ..."
           extension ""
          -obj 0000000000000007 34 sha1:b4bf7b467c62a1b51099ba1cc5b5aecd444d598d
          +obj 0000000000000007 37 sha1:2e9378511903201204cb5f08a4d6c52033a05545
                 0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
          -     19: q    BINPUT     1
          +     19: q    BINPUT     0
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      3
          -     24: U    SHORT_BINSTRING 'c0.22'
          -     31: q    BINPUT     2
          -     33: .    STOP
          +     24: X    BINUNICODE 'c0.22'
          +     34: q    BINPUT     1
          +     36: .    STOP
             highest protocol among opcodes = 2
      
          @@ -87,16 +87,16 @@ txn 0285cbacb258bf66 "p"
           user "root0.1\nYour\nMagesty "
           description "undo 0.1\nmore detailed description\n\nzzz ...\t"
           extension ""
          -obj 0000000000000003 34 sha1:3e5f02a2aa5f0ea3747a6c0ffeec090654091583
          +obj 0000000000000003 37 sha1:c83a8f07d208ea001abe540845e4ce75a7a32aee
                 0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
          -     19: q    BINPUT     1
          +     19: q    BINPUT     0
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      3
          -     24: U    SHORT_BINSTRING 'g0.11'
          -     31: q    BINPUT     2
          -     33: .    STOP
          +     24: X    BINUNICODE 'g0.11'
          +     34: q    BINPUT     1
          +     36: .    STOP
             highest protocol among opcodes = 2
      
          @@ -104,71 +104,92 @@ txn 0285cbacbbbbbc00 "p"
           user ""
           description "predelete 4"
           extension ""
          -obj 0000000000000000 199 sha1:d9c10b69422e9a8279e2f738d9c270b88ee49861
          +obj 0000000000000000 265 sha1:63708dd8f80d0b1f30f35f220f3d2207cb44e034
                 0: \x80 PROTO      3
                 2: c    GLOBAL     'persistent.mapping PersistentMapping'
          -     40: q    BINPUT     1
          +     40: q    BINPUT     0
                42: .    STOP
             highest protocol among opcodes = 2
                43: \x80 PROTO      3
                45: }    EMPTY_DICT
          -     46: q    BINPUT     2
          -     48: U    SHORT_BINSTRING 'data'
          -     54: q    BINPUT     3
          -     56: }    EMPTY_DICT
          -     57: q    BINPUT     4
          -     59: (    MARK
          -     60: U        SHORT_BINSTRING 'a'
          -     63: C        SHORT_BINBYTES '\x00\x00\x00\x00\x00\x00\x00\x05'
          -     73: c        GLOBAL     '__main__ Object'
          -     90: q        BINPUT     5
          -     92: \x86     TUPLE2
          -     93: Q        BINPERSID
          -     94: U        SHORT_BINSTRING 'c'
          -     97: C        SHORT_BINBYTES '\x00\x00\x00\x00\x00\x00\x00\x07'
          -    107: h        BINGET     5
          -    109: \x86     TUPLE2
          -    110: Q        BINPERSID
          -    111: U        SHORT_BINSTRING 'b'
          -    114: C        SHORT_BINBYTES '\x00\x00\x00\x00\x00\x00\x00\x08'
          -    124: h        BINGET     5
          -    126: \x86     TUPLE2
          -    127: Q        BINPERSID
          -    128: U        SHORT_BINSTRING 'e'
          -    131: C        SHORT_BINBYTES '\x00\x00\x00\x00\x00\x00\x00\x06'
          -    141: h        BINGET     5
          -    143: \x86     TUPLE2
          -    144: Q        BINPERSID
          -    145: U        SHORT_BINSTRING 'd'
          -    148: C        SHORT_BINBYTES '\x00\x00\x00\x00\x00\x00\x00\x02'
          -    158: h        BINGET     5
          -    160: \x86     TUPLE2
          -    161: Q        BINPERSID
          -    162: U        SHORT_BINSTRING 'g'
          -    165: C        SHORT_BINBYTES '\x00\x00\x00\x00\x00\x00\x00\x03'
          -    175: h        BINGET     5
          -    177: \x86     TUPLE2
          -    178: Q        BINPERSID
          -    179: U        SHORT_BINSTRING 'f'
          -    182: C        SHORT_BINBYTES '\x00\x00\x00\x00\x00\x00\x00\x01'
          -    192: h        BINGET     5
          -    194: \x86     TUPLE2
          -    195: Q        BINPERSID
          -    196: u        SETITEMS   (MARK at 59)
          -    197: s    SETITEM
          -    198: .    STOP
          +     46: q    BINPUT     1
          +     48: X    BINUNICODE 'data'
          +     57: q    BINPUT     2
          +     59: }    EMPTY_DICT
          +     60: q    BINPUT     3
          +     62: (    MARK
          +     63: X        BINUNICODE 'f'
          +     69: q        BINPUT     4
          +     71: C        SHORT_BINBYTES b'\x00\x00\x00\x00\x00\x00\x00\x01'
          +     81: q        BINPUT     5
          +     83: c        GLOBAL     '__main__ Object'
          +    100: q        BINPUT     6
          +    102: \x86     TUPLE2
          +    103: q        BINPUT     7
          +    105: Q        BINPERSID
          +    106: X        BINUNICODE 'd'
          +    112: q        BINPUT     8
          +    114: C        SHORT_BINBYTES b'\x00\x00\x00\x00\x00\x00\x00\x02'
          +    124: q        BINPUT     9
          +    126: h        BINGET     6
          +    128: \x86     TUPLE2
          +    129: q        BINPUT     10
          +    131: Q        BINPERSID
          +    132: X        BINUNICODE 'g'
          +    138: q        BINPUT     11
          +    140: C        SHORT_BINBYTES b'\x00\x00\x00\x00\x00\x00\x00\x03'
          +    150: q        BINPUT     12
          +    152: h        BINGET     6
          +    154: \x86     TUPLE2
          +    155: q        BINPUT     13
          +    157: Q        BINPERSID
          +    158: X        BINUNICODE 'b'
          +    164: q        BINPUT     14
          +    166: C        SHORT_BINBYTES b'\x00\x00\x00\x00\x00\x00\x00\x08'
          +    176: q        BINPUT     15
          +    178: h        BINGET     6
          +    180: \x86     TUPLE2
          +    181: q        BINPUT     16
          +    183: Q        BINPERSID
          +    184: X        BINUNICODE 'a'
          +    190: q        BINPUT     17
          +    192: C        SHORT_BINBYTES b'\x00\x00\x00\x00\x00\x00\x00\x05'
          +    202: q        BINPUT     18
          +    204: h        BINGET     6
          +    206: \x86     TUPLE2
          +    207: q        BINPUT     19
          +    209: Q        BINPERSID
          +    210: X        BINUNICODE 'e'
          +    216: q        BINPUT     20
          +    218: C        SHORT_BINBYTES b'\x00\x00\x00\x00\x00\x00\x00\x06'
          +    228: q        BINPUT     21
          +    230: h        BINGET     6
          +    232: \x86     TUPLE2
          +    233: q        BINPUT     22
          +    235: Q        BINPERSID
          +    236: X        BINUNICODE 'c'
          +    242: q        BINPUT     23
          +    244: C        SHORT_BINBYTES b'\x00\x00\x00\x00\x00\x00\x00\x07'
          +    254: q        BINPUT     24
          +    256: h        BINGET     6
          +    258: \x86     TUPLE2
          +    259: q        BINPUT     25
          +    261: Q        BINPERSID
          +    262: u        SETITEMS   (MARK at 62)
          +    263: s    SETITEM
          +    264: .    STOP
             highest protocol among opcodes = 3
      
          -obj 0000000000000008 32 sha1:dfe254b2f091cf0c9bc835713d53012d44e7e7ca
          +obj 0000000000000008 35 sha1:70dc33558d26431f1d6dbd576cf4b677032c97fd
                 0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
          -     19: q    BINPUT     1
          +     19: q    BINPUT     0
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      3
          -     24: U    SHORT_BINSTRING 'b0*'
          -     29: q    BINPUT     2
          -     31: .    STOP
          +     24: X    BINUNICODE 'b0*'
          +     32: q    BINPUT     1
          +     34: .    STOP
             highest protocol among opcodes = 2
      
          @@ -176,16 +197,16 @@ txn 0285cbad02222280 " "
           user "user1.0"
           description "step 1.0"
           extension ""
          -obj 0000000000000006 33 sha1:8f86d80dab366ac9780cdf9fd11aa622364397db
          +obj 0000000000000006 36 sha1:fc39de2e2d959f996fc80c1f8fa58fd8584e9bd6
                 0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
          -     19: q    BINPUT     1
          +     19: q    BINPUT     0
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      3
          -     24: U    SHORT_BINSTRING 'e1.0'
          -     30: q    BINPUT     2
          -     32: .    STOP
          +     24: X    BINUNICODE 'e1.0'
          +     33: q    BINPUT     1
          +     35: .    STOP
             highest protocol among opcodes = 2
      
          @@ -193,16 +214,16 @@ txn 0285cbad06d3a0cc " "
           user "user1.1"
           description "step 1.1"
           extension ""
          -obj 0000000000000008 33 sha1:3a63a76c25b677ada2cc1281f0fcbca823c2fde8
          +obj 0000000000000008 36 sha1:48ceba60e193e905cb25a4e452bacbfba1e6f54a
                 0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
          -     19: q    BINPUT     1
          +     19: q    BINPUT     0
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      3
          -     24: U    SHORT_BINSTRING 'b1.1'
          -     30: q    BINPUT     2
          -     32: .    STOP
          +     24: X    BINUNICODE 'b1.1'
          +     33: q    BINPUT     1
          +     35: .    STOP
             highest protocol among opcodes = 2
      
          @@ -210,16 +231,16 @@ txn 0285cbad0b851f19 " "
           user "user1.2"
           description "step 1.2"
           extension ""
          -obj 0000000000000003 33 sha1:c13b686e24c0b49869156feaafa5299a0be0db54
          +obj 0000000000000003 36 sha1:5484c69f420ce2bc74798fa0af92cad1fff46ac5
                 0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
          -     19: q    BINPUT     1
          +     19: q    BINPUT     0
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      3
          -     24: U    SHORT_BINSTRING 'g1.2'
          -     30: q    BINPUT     2
          -     32: .    STOP
          +     24: X    BINUNICODE 'g1.2'
          +     33: q    BINPUT     1
          +     35: .    STOP
             highest protocol among opcodes = 2
      
          @@ -227,16 +248,16 @@ txn 0285cbad10369d66 " "
           user "user1.3"
           description "step 1.3"
           extension ""
          -obj 0000000000000003 33 sha1:edbfe9c47fdfd3eeb89578d2b975196b72e04a47
          +obj 0000000000000003 36 sha1:c58b6020a7991c2b763ad922d1a9ae93f341883b
                 0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
          -     19: q    BINPUT     1
          +     19: q    BINPUT     0
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      3
          -     24: U    SHORT_BINSTRING 'g1.3'
          -     30: q    BINPUT     2
          -     32: .    STOP
          +     24: X    BINUNICODE 'g1.3'
          +     33: q    BINPUT     1
          +     35: .    STOP
             highest protocol among opcodes = 2
      
          @@ -244,16 +265,16 @@ txn 0285cbad14e81bb3 " "
           user "user1.4"
           description "step 1.4"
           extension ""
          -obj 0000000000000007 33 sha1:0ce3b56cc68602d8fcf9633527fc02d68d3c7963
          +obj 0000000000000007 36 sha1:a074839c67efb6d96e1d4400691bdb58e0b3ca43
                 0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
          -     19: q    BINPUT     1
          +     19: q    BINPUT     0
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      3
          -     24: U    SHORT_BINSTRING 'c1.4'
          -     30: q    BINPUT     2
          -     32: .    STOP
          +     24: X    BINUNICODE 'c1.4'
          +     33: q    BINPUT     1
          +     35: .    STOP
             highest protocol among opcodes = 2
      
          @@ -261,16 +282,16 @@ txn 0285cbad19999a00 " "
           user "user1.5"
           description "step 1.5"
           extension ""
          -obj 0000000000000001 33 sha1:9bb04c55d1990c274fcc9f6d71701456c999154d
          +obj 0000000000000001 36 sha1:6718431686e2413a926aa146c76ef3007de9d39b
                 0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
          -     19: q    BINPUT     1
          +     19: q    BINPUT     0
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      3
          -     24: U    SHORT_BINSTRING 'f1.5'
          -     30: q    BINPUT     2
          -     32: .    STOP
          +     24: X    BINUNICODE 'f1.5'
          +     33: q    BINPUT     1
          +     35: .    STOP
             highest protocol among opcodes = 2
      
          @@ -278,16 +299,16 @@ txn 0285cbad1e4b184c " "
           user "user1.6"
           description "step 1.6"
           extension ""
          -obj 0000000000000002 33 sha1:3856df32ef7c512e9fd2599772e431ce3a18b5f5
          +obj 0000000000000002 36 sha1:9cb878d16cc4c0968eb9942b45d7c7f84b2054ef
                 0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
          -     19: q    BINPUT     1
          +     19: q    BINPUT     0
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      3
          -     24: U    SHORT_BINSTRING 'd1.6'
          -     30: q    BINPUT     2
          -     32: .    STOP
          +     24: X    BINUNICODE 'd1.6'
          +     33: q    BINPUT     1
          +     35: .    STOP
             highest protocol among opcodes = 2
      
          @@ -295,16 +316,16 @@ txn 0285cbad22fc9699 " "
           user "user1.7"
           description "step 1.7"
           extension ""
          -obj 0000000000000007 33 sha1:3d9da3b8f59a10f15e7c6796023153089d58d969
          +obj 0000000000000007 36 sha1:bc53969fc907268a68ab4e9c601e114157a6b7ed
                 0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
          -     19: q    BINPUT     1
          +     19: q    BINPUT     0
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      3
          -     24: U    SHORT_BINSTRING 'c1.7'
          -     30: q    BINPUT     2
          -     32: .    STOP
          +     24: X    BINUNICODE 'c1.7'
          +     33: q    BINPUT     1
          +     35: .    STOP
             highest protocol among opcodes = 2
      
          @@ -312,16 +333,16 @@ txn 0285cbad27ae14e6 " "
           user "user1.8"
           description "step 1.8"
           extension ""
          -obj 0000000000000007 33 sha1:42c7e6fe473e6d99867b134c44c2d97813629b29
          +obj 0000000000000007 36 sha1:bb7b95b7f8cfcb61b5a19f646a9f54b05d445823
                 0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
          -     19: q    BINPUT     1
          +     19: q    BINPUT     0
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      3
          -     24: U    SHORT_BINSTRING 'c1.8'
          -     30: q    BINPUT     2
          -     32: .    STOP
          +     24: X    BINUNICODE 'c1.8'
          +     33: q    BINPUT     1
          +     35: .    STOP
             highest protocol among opcodes = 2
      
          @@ -329,16 +350,16 @@ txn 0285cbad2c5f9333 " "
           user "user1.9"
           description "step 1.9"
           extension ""
          -obj 0000000000000006 33 sha1:88921e4828cbbf11dc61ca6fbaf6595a88fe5076
          +obj 0000000000000006 36 sha1:e592ee7c81df854144e95f6a770786865a0d58d5
                 0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
          -     19: q    BINPUT     1
          +     19: q    BINPUT     0
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      3
          -     24: U    SHORT_BINSTRING 'e1.9'
          -     30: q    BINPUT     2
          -     32: .    STOP
          +     24: X    BINUNICODE 'e1.9'
          +     33: q    BINPUT     1
          +     35: .    STOP
             highest protocol among opcodes = 2
      
          @@ -346,16 +367,16 @@ txn 0285cbad31111180 " "
           user "user1.10"
           description "step 1.10"
           extension ""
          -obj 0000000000000005 34 sha1:70fe501d55fc4052b73f5e3473262a48555f375f
          +obj 0000000000000005 37 sha1:b2976e8cc01b2c9914b396cd6d3fdb49b0488856
                 0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
          -     19: q    BINPUT     1
          +     19: q    BINPUT     0
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      3
          -     24: U    SHORT_BINSTRING 'a1.10'
          -     31: q    BINPUT     2
          -     33: .    STOP
          +     24: X    BINUNICODE 'a1.10'
          +     34: q    BINPUT     1
          +     36: .    STOP
             highest protocol among opcodes = 2
      
          @@ -363,16 +384,16 @@ txn 0285cbad35c28fcc " "
           user "user1.11"
           description "step 1.11"
           extension ""
          -obj 0000000000000007 34 sha1:f1550b205f2cec40b8716673663fb6e446568772
          +obj 0000000000000007 37 sha1:6e4a4cf52bb36edaa083b1da4b59f3597ad6ea02
                 0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
          -     19: q    BINPUT     1
          +     19: q    BINPUT     0
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      3
          -     24: U    SHORT_BINSTRING 'c1.11'
          -     31: q    BINPUT     2
          -     33: .    STOP
          +     24: X    BINUNICODE 'c1.11'
          +     34: q    BINPUT     1
          +     36: .    STOP
             highest protocol among opcodes = 2
      
          @@ -380,16 +401,16 @@ txn 0285cbad3a740e19 " "
           user "user1.12"
           description "step 1.12"
           extension ""
          -obj 0000000000000006 34 sha1:e4587785ac67a316d288d89a2ecf5f7548804416
          +obj 0000000000000006 37 sha1:fad24b6d7758e671a255810ead8994459e9b0417
                 0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
          -     19: q    BINPUT     1
          +     19: q    BINPUT     0
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      3
          -     24: U    SHORT_BINSTRING 'e1.12'
          -     31: q    BINPUT     2
          -     33: .    STOP
          +     24: X    BINUNICODE 'e1.12'
          +     34: q    BINPUT     1
          +     36: .    STOP
             highest protocol among opcodes = 2
      
          @@ -397,16 +418,16 @@ txn 0285cbad3f258c66 " "
           user "user1.13"
           description "step 1.13"
           extension ""
          -obj 0000000000000003 34 sha1:c40d417ad5140d3c0a76b8119e1bc3f77924851f
          +obj 0000000000000003 37 sha1:be8b8aacb1e6b6e4661a96fe6f741ddc653acc41
                 0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
          -     19: q    BINPUT     1
          +     19: q    BINPUT     0
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      3
          -     24: U    SHORT_BINSTRING 'g1.13'
          -     31: q    BINPUT     2
          -     33: .    STOP
          +     24: X    BINUNICODE 'g1.13'
          +     34: q    BINPUT     1
          +     36: .    STOP
             highest protocol among opcodes = 2
      
          @@ -414,16 +435,16 @@ txn 0285cbad43d70ab3 " "
           user "user1.14"
           description "step 1.14"
           extension ""
          -obj 0000000000000003 34 sha1:141ee9a480f2e04c1c2b9fab6cab263010ab32cd
          +obj 0000000000000003 37 sha1:c65e91e03c291d0082a6ea58c9082e29b9f28c55
                 0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
          -     19: q    BINPUT     1
          +     19: q    BINPUT     0
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      3
          -     24: U    SHORT_BINSTRING 'g1.14'
          -     31: q    BINPUT     2
          -     33: .    STOP
          +     24: X    BINUNICODE 'g1.14'
          +     34: q    BINPUT     1
          +     36: .    STOP
             highest protocol among opcodes = 2
      
          @@ -431,16 +452,16 @@ txn 0285cbad48888900 " "
           user "user1.15"
           description "step 1.15"
           extension ""
          -obj 0000000000000002 34 sha1:ffd9e2447b4d6230d8e4c6584967ebd45bdb69cd
          +obj 0000000000000002 37 sha1:8b850edece74832eb6ff1e4be78b05f52ef5609c
                 0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
          -     19: q    BINPUT     1
          +     19: q    BINPUT     0
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      3
          -     24: U    SHORT_BINSTRING 'd1.15'
          -     31: q    BINPUT     2
          -     33: .    STOP
          +     24: X    BINUNICODE 'd1.15'
          +     34: q    BINPUT     1
          +     36: .    STOP
             highest protocol among opcodes = 2
      
          @@ -448,16 +469,16 @@ txn 0285cbad4d3a074c " "
           user "user1.16"
           description "step 1.16"
           extension ""
          -obj 0000000000000003 34 sha1:e320d84b1e6f9b5507665684c57938c97fb8707a
          +obj 0000000000000003 37 sha1:9480ee152fd13794009dd03d188cf82ec9fb4819
                 0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
          -     19: q    BINPUT     1
          +     19: q    BINPUT     0
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      3
          -     24: U    SHORT_BINSTRING 'g1.16'
          -     31: q    BINPUT     2
          -     33: .    STOP
          +     24: X    BINUNICODE 'g1.16'
          +     34: q    BINPUT     1
          +     36: .    STOP
             highest protocol among opcodes = 2
      
          @@ -465,16 +486,16 @@ txn 0285cbad51eb8599 " "
           user "user1.17"
           description "step 1.17"
           extension ""
          -obj 0000000000000001 34 sha1:a64a2fa4d8de13124ad15958bb44e93bb50be691
          +obj 0000000000000001 37 sha1:ee2d6c62270d71f460cfbe50c25c4558f2e4db96
                 0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
          -     19: q    BINPUT     1
          +     19: q    BINPUT     0
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      3
          -     24: U    SHORT_BINSTRING 'f1.17'
          -     31: q    BINPUT     2
          -     33: .    STOP
          +     24: X    BINUNICODE 'f1.17'
          +     34: q    BINPUT     1
          +     36: .    STOP
             highest protocol among opcodes = 2
      
          @@ -482,16 +503,16 @@ txn 0285cbad569d03e6 " "
           user "user1.18"
           description "step 1.18"
           extension ""
          -obj 0000000000000005 34 sha1:1a13c223b1e3c4336157bd9ea48bcebbf2bfeb83
          +obj 0000000000000005 37 sha1:aabc707728e1624e47e00b44c0536837c138f6e9
                 0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
          -     19: q    BINPUT     1
          +     19: q    BINPUT     0
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      3
          -     24: U    SHORT_BINSTRING 'a1.18'
          -     31: q    BINPUT     2
          -     33: .    STOP
          +     24: X    BINUNICODE 'a1.18'
          +     34: q    BINPUT     1
          +     36: .    STOP
             highest protocol among opcodes = 2
      
          @@ -499,16 +520,16 @@ txn 0285cbad5b4e8233 " "
           user "user1.19"
           description "step 1.19"
           extension ""
          -obj 0000000000000003 34 sha1:a0b9f323870e42230530e88c3d0df4d0ff53d169
          +obj 0000000000000003 37 sha1:ea6e91b0041c018c8c77ebe55596fb44593396a5
                 0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
          -     19: q    BINPUT     1
          +     19: q    BINPUT     0
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      3
          -     24: U    SHORT_BINSTRING 'g1.19'
          -     31: q    BINPUT     2
          -     33: .    STOP
          +     24: X    BINUNICODE 'g1.19'
          +     34: q    BINPUT     1
          +     36: .    STOP
             highest protocol among opcodes = 2
      
          @@ -516,16 +537,16 @@ txn 0285cbad60000080 " "
           user "user1.20"
           description "step 1.20"
           extension ""
          -obj 0000000000000003 34 sha1:9d877b2756905d307e10300aa81428ea05c630d2
          +obj 0000000000000003 37 sha1:2edb6e67e9c1d0c0dd7c4bf008c81ebcf16fe0b7
                 0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
          -     19: q    BINPUT     1
          +     19: q    BINPUT     0
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      3
          -     24: U    SHORT_BINSTRING 'g1.20'
          -     31: q    BINPUT     2
          -     33: .    STOP
          +     24: X    BINUNICODE 'g1.20'
          +     34: q    BINPUT     1
          +     36: .    STOP
             highest protocol among opcodes = 2
      
          @@ -533,16 +554,16 @@ txn 0285cbad64b17ecc " "
           user "user1.21"
           description "step 1.21"
           extension ""
          -obj 0000000000000006 34 sha1:4087f3ba62712e5c29b0d861d65bcc9904f0828e
          +obj 0000000000000006 37 sha1:39f276b08f1dbe1c10d8d78fbbb2b56a8adf47bc
                 0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
          -     19: q    BINPUT     1
          +     19: q    BINPUT     0
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      3
          -     24: U    SHORT_BINSTRING 'e1.21'
          -     31: q    BINPUT     2
          -     33: .    STOP
          +     24: X    BINUNICODE 'e1.21'
          +     34: q    BINPUT     1
          +     36: .    STOP
             highest protocol among opcodes = 2
      
          @@ -550,16 +571,16 @@ txn 0285cbad6962fd19 " "
           user "user1.22"
           description "step 1.22"
           extension ""
          -obj 0000000000000005 34 sha1:7f234b2ebf6c51bbc2acf55bc481b8ca0912b088
          +obj 0000000000000005 37 sha1:da8d342e0f80ea707724e47afc06640ab2d5a91b
                 0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
          -     19: q    BINPUT     1
          +     19: q    BINPUT     0
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      3
          -     24: U    SHORT_BINSTRING 'a1.22'
          -     31: q    BINPUT     2
          -     33: .    STOP
          +     24: X    BINUNICODE 'a1.22'
          +     34: q    BINPUT     1
          +     36: .    STOP
             highest protocol among opcodes = 2
      
          @@ -567,16 +588,16 @@ txn 0285cbad6e147b66 " "
           user "user1.23"
           description "step 1.23"
           extension ""
          -obj 0000000000000005 34 sha1:b54c8d6f9415eef59c5e4598d4ea459c7def7ae5
          +obj 0000000000000005 37 sha1:97ab286d00da92b84ccf43ead31cd607bf847e6d
                 0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
          -     19: q    BINPUT     1
          +     19: q    BINPUT     0
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      3
          -     24: U    SHORT_BINSTRING 'a1.23'
          -     31: q    BINPUT     2
          -     33: .    STOP
          +     24: X    BINUNICODE 'a1.23'
          +     34: q    BINPUT     1
          +     36: .    STOP
             highest protocol among opcodes = 2
      
          @@ -584,16 +605,16 @@ txn 0285cbad72c5f9b3 " "
           user "user1.24"
           description "step 1.24"
           extension ""
          -obj 0000000000000001 34 sha1:fc513f6a915be326a3d1212b12b389f284a329b2
          +obj 0000000000000001 37 sha1:fdb7cbf61232f415712183ed09075677d401141f
                 0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
          -     19: q    BINPUT     1
          +     19: q    BINPUT     0
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      3
          -     24: U    SHORT_BINSTRING 'f1.24'
          -     31: q    BINPUT     2
          -     33: .    STOP
          +     24: X    BINUNICODE 'f1.24'
          +     34: q    BINPUT     1
          +     36: .    STOP
             highest protocol among opcodes = 2
      
          @@ -613,18 +634,20 @@ txn 0285cbad80da7499 " "
           user "user"
           description "cyclic reference"
           extension ""
          -obj 0000000000000006 39 sha1:baf12eac4d077427f66ff902f64d44a2a141bfd6
          +obj 0000000000000006 43 sha1:983e0d4ef28b594823f7279d8c08d998930d1ff8
                 0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
          -     19: q    BINPUT     1
          +     19: q    BINPUT     0
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      3
          -     24: C    SHORT_BINBYTES '\x00\x00\x00\x00\x00\x00\x00\x06'
          -     34: h    BINGET     1
          -     36: \x86 TUPLE2
          -     37: Q    BINPERSID
          -     38: .    STOP
          +     24: C    SHORT_BINBYTES b'\x00\x00\x00\x00\x00\x00\x00\x06'
          +     34: q    BINPUT     1
          +     36: h    BINGET     0
          +     38: \x86 TUPLE2
          +     39: q    BINPUT     2
          +     41: Q    BINPERSID
          +     42: .    STOP
             highest protocol among opcodes = 3
      
          @@ -632,71 +655,92 @@ txn 0285cbad858bf2e6 " "
           user ""
           description "predelete 6"
           extension ""
          -obj 0000000000000000 199 sha1:eaa0f1b643468f33c6b87a875d67eb3b349be5dd
          +obj 0000000000000000 265 sha1:78b3f0aaef3a8674a55a61e9693b4b0443316bc9
                 0: \x80 PROTO      3
                 2: c    GLOBAL     'persistent.mapping PersistentMapping'
          -     40: q    BINPUT     1
          +     40: q    BINPUT     0
                42: .    STOP
             highest protocol among opcodes = 2
                43: \x80 PROTO      3
                45: }    EMPTY_DICT
          -     46: q    BINPUT     2
          -     48: U    SHORT_BINSTRING 'data'
          -     54: q    BINPUT     3
          -     56: }    EMPTY_DICT
          -     57: q    BINPUT     4
          -     59: (    MARK
          -     60: U        SHORT_BINSTRING 'a'
          -     63: C        SHORT_BINBYTES '\x00\x00\x00\x00\x00\x00\x00\x05'
          -     73: c        GLOBAL     '__main__ Object'
          -     90: q        BINPUT     5
          -     92: \x86     TUPLE2
          -     93: Q        BINPERSID
          -     94: U        SHORT_BINSTRING 'c'
          -     97: C        SHORT_BINBYTES '\x00\x00\x00\x00\x00\x00\x00\x07'
          -    107: h        BINGET     5
          -    109: \x86     TUPLE2
          -    110: Q        BINPERSID
          -    111: U        SHORT_BINSTRING 'b'
          -    114: C        SHORT_BINBYTES '\x00\x00\x00\x00\x00\x00\x00\x08'
          -    124: h        BINGET     5
          -    126: \x86     TUPLE2
          -    127: Q        BINPERSID
          -    128: U        SHORT_BINSTRING 'e'
          -    131: C        SHORT_BINBYTES '\x00\x00\x00\x00\x00\x00\x00\t'
          -    141: h        BINGET     5
          -    143: \x86     TUPLE2
          -    144: Q        BINPERSID
          -    145: U        SHORT_BINSTRING 'd'
          -    148: C        SHORT_BINBYTES '\x00\x00\x00\x00\x00\x00\x00\x02'
          -    158: h        BINGET     5
          -    160: \x86     TUPLE2
          -    161: Q        BINPERSID
          -    162: U        SHORT_BINSTRING 'g'
          -    165: C        SHORT_BINBYTES '\x00\x00\x00\x00\x00\x00\x00\x03'
          -    175: h        BINGET     5
          -    177: \x86     TUPLE2
          -    178: Q        BINPERSID
          -    179: U        SHORT_BINSTRING 'f'
          -    182: C        SHORT_BINBYTES '\x00\x00\x00\x00\x00\x00\x00\x01'
          -    192: h        BINGET     5
          -    194: \x86     TUPLE2
          -    195: Q        BINPERSID
          -    196: u        SETITEMS   (MARK at 59)
          -    197: s    SETITEM
          -    198: .    STOP
          +     46: q    BINPUT     1
          +     48: X    BINUNICODE 'data'
          +     57: q    BINPUT     2
          +     59: }    EMPTY_DICT
          +     60: q    BINPUT     3
          +     62: (    MARK
          +     63: X        BINUNICODE 'f'
          +     69: q        BINPUT     4
          +     71: C        SHORT_BINBYTES b'\x00\x00\x00\x00\x00\x00\x00\x01'
          +     81: q        BINPUT     5
          +     83: c        GLOBAL     '__main__ Object'
          +    100: q        BINPUT     6
          +    102: \x86     TUPLE2
          +    103: q        BINPUT     7
          +    105: Q        BINPERSID
          +    106: X        BINUNICODE 'd'
          +    112: q        BINPUT     8
          +    114: C        SHORT_BINBYTES b'\x00\x00\x00\x00\x00\x00\x00\x02'
          +    124: q        BINPUT     9
          +    126: h        BINGET     6
          +    128: \x86     TUPLE2
          +    129: q        BINPUT     10
          +    131: Q        BINPERSID
          +    132: X        BINUNICODE 'g'
          +    138: q        BINPUT     11
          +    140: C        SHORT_BINBYTES b'\x00\x00\x00\x00\x00\x00\x00\x03'
          +    150: q        BINPUT     12
          +    152: h        BINGET     6
          +    154: \x86     TUPLE2
          +    155: q        BINPUT     13
          +    157: Q        BINPERSID
          +    158: X        BINUNICODE 'b'
          +    164: q        BINPUT     14
          +    166: C        SHORT_BINBYTES b'\x00\x00\x00\x00\x00\x00\x00\x08'
          +    176: q        BINPUT     15
          +    178: h        BINGET     6
          +    180: \x86     TUPLE2
          +    181: q        BINPUT     16
          +    183: Q        BINPERSID
          +    184: X        BINUNICODE 'a'
          +    190: q        BINPUT     17
          +    192: C        SHORT_BINBYTES b'\x00\x00\x00\x00\x00\x00\x00\x05'
          +    202: q        BINPUT     18
          +    204: h        BINGET     6
          +    206: \x86     TUPLE2
          +    207: q        BINPUT     19
          +    209: Q        BINPERSID
          +    210: X        BINUNICODE 'e'
          +    216: q        BINPUT     20
          +    218: C        SHORT_BINBYTES b'\x00\x00\x00\x00\x00\x00\x00\t'
          +    228: q        BINPUT     21
          +    230: h        BINGET     6
          +    232: \x86     TUPLE2
          +    233: q        BINPUT     22
          +    235: Q        BINPERSID
          +    236: X        BINUNICODE 'c'
          +    242: q        BINPUT     23
          +    244: C        SHORT_BINBYTES b'\x00\x00\x00\x00\x00\x00\x00\x07'
          +    254: q        BINPUT     24
          +    256: h        BINGET     6
          +    258: \x86     TUPLE2
          +    259: q        BINPUT     25
          +    261: Q        BINPERSID
          +    262: u        SETITEMS   (MARK at 62)
          +    263: s    SETITEM
          +    264: .    STOP
             highest protocol among opcodes = 3
      
          -obj 0000000000000009 32 sha1:c10d44876cbf78e49f7cc633d985206f51ecc278
          +obj 0000000000000009 35 sha1:4b20bfd26d2807d81c4c52b56034203b96babe5d
                 0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
          -     19: q    BINPUT     1
          +     19: q    BINPUT     0
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      3
          -     24: U    SHORT_BINSTRING 'e1*'
          -     29: q    BINPUT     2
          -     31: .    STOP
          +     24: X    BINUNICODE 'e1*'
          +     32: q    BINPUT     1
          +     34: .    STOP
             highest protocol among opcodes = 2
      
          @@ -710,16 +754,16 @@ txn 0285cbadc740db19 " "
           user "user2.0"
           description "step 2.0"
           extension ""
          -obj 0000000000000001 33 sha1:118c46c51bb0f08ce76d8f4f3b5d923b81abdd46
          +obj 0000000000000001 36 sha1:4698f11fc85b9eadd355d8114ed6f55b71377024
                 0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
          -     19: q    BINPUT     1
          +     19: q    BINPUT     0
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      3
          -     24: U    SHORT_BINSTRING 'f2.0'
          -     30: q    BINPUT     2
          -     32: .    STOP
          +     24: X    BINUNICODE 'f2.0'
          +     33: q    BINPUT     1
          +     35: .    STOP
             highest protocol among opcodes = 2
      
          @@ -727,16 +771,16 @@ txn 0285cbadcbf25966 " "
           user "user2.1"
           description "step 2.1"
           extension ""
          -obj 0000000000000002 33 sha1:89ff5e4440585130863b518c044d35e0154daecc
          +obj 0000000000000002 36 sha1:e2f891ce328ae3ae117d22649af0da7cd0b1946d
                 0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
          -     19: q    BINPUT     1
          +     19: q    BINPUT     0
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      3
          -     24: U    SHORT_BINSTRING 'd2.1'
          -     30: q    BINPUT     2
          -     32: .    STOP
          +     24: X    BINUNICODE 'd2.1'
          +     33: q    BINPUT     1
          +     35: .    STOP
             highest protocol among opcodes = 2
      
          @@ -744,16 +788,16 @@ txn 0285cbadd0a3d7b3 " "
           user "user2.2"
           description "step 2.2"
           extension ""
          -obj 0000000000000003 33 sha1:e0470e3dee47625819f9bfe8085c1bce2a7a4a42
          +obj 0000000000000003 36 sha1:d1df41d00d4a274b872cc3a461c0e817a56891e8
                 0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
          -     19: q    BINPUT     1
          +     19: q    BINPUT     0
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      3
          -     24: U    SHORT_BINSTRING 'g2.2'
          -     30: q    BINPUT     2
          -     32: .    STOP
          +     24: X    BINUNICODE 'g2.2'
          +     33: q    BINPUT     1
          +     35: .    STOP
             highest protocol among opcodes = 2
      
          @@ -761,16 +805,16 @@ txn 0285cbadd5555600 " "
           user "user2.3"
           description "step 2.3"
           extension ""
          -obj 0000000000000003 33 sha1:b1a3740b05c6cae5f6c851b715c76dd7348228a9
          +obj 0000000000000003 36 sha1:94f3e65e39ff51d57f15d484211b9b14cc764dc9
                 0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
          -     19: q    BINPUT     1
          +     19: q    BINPUT     0
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      3
          -     24: U    SHORT_BINSTRING 'g2.3'
          -     30: q    BINPUT     2
          -     32: .    STOP
          +     24: X    BINUNICODE 'g2.3'
          +     33: q    BINPUT     1
          +     35: .    STOP
             highest protocol among opcodes = 2
      
          @@ -778,16 +822,16 @@ txn 0285cbadda06d44c " "
           user "user2.4"
           description "step 2.4"
           extension ""
          -obj 0000000000000009 33 sha1:d0368e87213747ab68d8e4f7a87ff1ea959ea579
          +obj 0000000000000009 36 sha1:ee33bb85a5d8eedd010f1353a12710f19164e039
                 0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
          -     19: q    BINPUT     1
          +     19: q    BINPUT     0
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      3
          -     24: U    SHORT_BINSTRING 'e2.4'
          -     30: q    BINPUT     2
          -     32: .    STOP
          +     24: X    BINUNICODE 'e2.4'
          +     33: q    BINPUT     1
          +     35: .    STOP
             highest protocol among opcodes = 2
      
          @@ -795,16 +839,16 @@ txn 0285cbaddeb85299 " "
           user "user2.5"
           description "step 2.5"
           extension ""
          -obj 0000000000000005 33 sha1:e5af7f0b8e157926739f657e729594908d188a3d
          +obj 0000000000000005 36 sha1:c772534529d247cfc1b9fdf5a6af0e6d209718f5
                 0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
          -     19: q    BINPUT     1
          +     19: q    BINPUT     0
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      3
          -     24: U    SHORT_BINSTRING 'a2.5'
          -     30: q    BINPUT     2
          -     32: .    STOP
          +     24: X    BINUNICODE 'a2.5'
          +     33: q    BINPUT     1
          +     35: .    STOP
             highest protocol among opcodes = 2
      
          @@ -812,16 +856,16 @@ txn 0285cbade369d0e6 " "
           user "user2.6"
           description "step 2.6"
           extension ""
          -obj 0000000000000008 33 sha1:dc70c3b1413c79d75bcfdcc50c3e803273f857ef
          +obj 0000000000000008 36 sha1:100e5baf3b5cf7276d7657e7ebe515e4444be00a
                 0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
          -     19: q    BINPUT     1
          +     19: q    BINPUT     0
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      3
          -     24: U    SHORT_BINSTRING 'b2.6'
          -     30: q    BINPUT     2
          -     32: .    STOP
          +     24: X    BINUNICODE 'b2.6'
          +     33: q    BINPUT     1
          +     35: .    STOP
             highest protocol among opcodes = 2
      
          @@ -829,16 +873,16 @@ txn 0285cbade81b4f33 " "
           user "user2.7"
           description "step 2.7"
           extension ""
          -obj 0000000000000003 33 sha1:35892bc2c71edb022b029aa1e4bf8201ccab4b0c
          +obj 0000000000000003 36 sha1:6982830f7f9ec7f5c71c2926dffc85003463365f
                 0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
          -     19: q    BINPUT     1
          +     19: q    BINPUT     0
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      3
          -     24: U    SHORT_BINSTRING 'g2.7'
          -     30: q    BINPUT     2
          -     32: .    STOP
          +     24: X    BINUNICODE 'g2.7'
          +     33: q    BINPUT     1
          +     35: .    STOP
             highest protocol among opcodes = 2
      
          @@ -846,16 +890,16 @@ txn 0285cbadeccccd80 " "
           user "user2.8"
           description "step 2.8"
           extension ""
          -obj 0000000000000002 33 sha1:b2da174266d0f0e0b58c214e6d79851f4a18b554
          +obj 0000000000000002 36 sha1:679994a2775668088af510d185f118a6de678e9b
                 0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
          -     19: q    BINPUT     1
          +     19: q    BINPUT     0
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      3
          -     24: U    SHORT_BINSTRING 'd2.8'
          -     30: q    BINPUT     2
          -     32: .    STOP
          +     24: X    BINUNICODE 'd2.8'
          +     33: q    BINPUT     1
          +     35: .    STOP
             highest protocol among opcodes = 2
      
          @@ -863,16 +907,16 @@ txn 0285cbadf17e4bcc " "
           user "user2.9"
           description "step 2.9"
           extension ""
          -obj 0000000000000009 33 sha1:92cf61eb5855d3b25fecbe7a458f1b21946f5ba3
          +obj 0000000000000009 36 sha1:7926589c9adf282a8de6ec2d2da7aeeb054db0e8
                 0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
          -     19: q    BINPUT     1
          +     19: q    BINPUT     0
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      3
          -     24: U    SHORT_BINSTRING 'e2.9'
          -     30: q    BINPUT     2
          -     32: .    STOP
          +     24: X    BINUNICODE 'e2.9'
          +     33: q    BINPUT     1
          +     35: .    STOP
             highest protocol among opcodes = 2
      
          @@ -880,16 +924,16 @@ txn 0285cbadf62fca19 " "
           user "user2.10"
           description "step 2.10"
           extension ""
          -obj 0000000000000007 34 sha1:f737655162c594cf8296b38f7c435a5e8e06d6d7
          +obj 0000000000000007 37 sha1:230ddb4fcd957487b06a9a6690d0085a5f4e447f
                 0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
          -     19: q    BINPUT     1
          +     19: q    BINPUT     0
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      3
          -     24: U    SHORT_BINSTRING 'c2.10'
          -     31: q    BINPUT     2
          -     33: .    STOP
          +     24: X    BINUNICODE 'c2.10'
          +     34: q    BINPUT     1
          +     36: .    STOP
             highest protocol among opcodes = 2
      
          @@ -897,16 +941,16 @@ txn 0285cbadfae14866 " "
           user "user2.11"
           description "step 2.11"
           extension ""
          -obj 0000000000000002 34 sha1:032d8305ea9de2ec785fc77c1743a37bb64553cd
          +obj 0000000000000002 37 sha1:c85a70f3ee80af026ffd7392402efd62e8dbd807
                 0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
          -     19: q    BINPUT     1
          +     19: q    BINPUT     0
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      3
          -     24: U    SHORT_BINSTRING 'd2.11'
          -     31: q    BINPUT     2
          -     33: .    STOP
          +     24: X    BINUNICODE 'd2.11'
          +     34: q    BINPUT     1
          +     36: .    STOP
             highest protocol among opcodes = 2
      
          @@ -914,16 +958,16 @@ txn 0285cbadff92c6b3 " "
           user "user2.12"
           description "step 2.12"
           extension ""
          -obj 0000000000000003 34 sha1:975fd7ef6350b6543495a800852969f1d7833c83
          +obj 0000000000000003 37 sha1:f447a42edf90ac9ef506f55e3f2af240f52d84d7
                 0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
          -     19: q    BINPUT     1
          +     19: q    BINPUT     0
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      3
          -     24: U    SHORT_BINSTRING 'g2.12'
          -     31: q    BINPUT     2
          -     33: .    STOP
          +     24: X    BINUNICODE 'g2.12'
          +     34: q    BINPUT     1
          +     36: .    STOP
             highest protocol among opcodes = 2
      
          @@ -931,16 +975,16 @@ txn 0285cbae04444500 " "
           user "user2.13"
           description "step 2.13"
           extension ""
          -obj 0000000000000002 34 sha1:d09e49d753b8183ba5e0fa042a239f103d54c873
          +obj 0000000000000002 37 sha1:92783aa30a97637bfa75bb74ee4188163e6599bb
                 0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
          -     19: q    BINPUT     1
          +     19: q    BINPUT     0
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      3
          -     24: U    SHORT_BINSTRING 'd2.13'
          -     31: q    BINPUT     2
          -     33: .    STOP
          +     24: X    BINUNICODE 'd2.13'
          +     34: q    BINPUT     1
          +     36: .    STOP
             highest protocol among opcodes = 2
      
          @@ -948,16 +992,16 @@ txn 0285cbae08f5c34c " "
           user "user2.14"
           description "step 2.14"
           extension ""
          -obj 0000000000000007 34 sha1:109581582c53bf400e56780c331410e5195d19e0
          +obj 0000000000000007 37 sha1:26e44812ce9f495bdc79426a987f86514576702b
                 0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
          -     19: q    BINPUT     1
          +     19: q    BINPUT     0
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      3
          -     24: U    SHORT_BINSTRING 'c2.14'
          -     31: q    BINPUT     2
          -     33: .    STOP
          +     24: X    BINUNICODE 'c2.14'
          +     34: q    BINPUT     1
          +     36: .    STOP
             highest protocol among opcodes = 2
      
          @@ -965,16 +1009,16 @@ txn 0285cbae0da74199 " "
           user "user2.15"
           description "step 2.15"
           extension ""
          -obj 0000000000000009 34 sha1:e67485cd99587ee9e98158db69ed668fb233093d
          +obj 0000000000000009 37 sha1:5036c79c841dfde65e56cf5ff9d5765ab025a8e8
                 0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
          -     19: q    BINPUT     1
          +     19: q    BINPUT     0
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      3
          -     24: U    SHORT_BINSTRING 'e2.15'
          -     31: q    BINPUT     2
          -     33: .    STOP
          +     24: X    BINUNICODE 'e2.15'
          +     34: q    BINPUT     1
          +     36: .    STOP
             highest protocol among opcodes = 2
      
          @@ -982,16 +1026,16 @@ txn 0285cbae1258bfe6 " "
           user "user2.16"
           description "step 2.16"
           extension ""
          -obj 0000000000000001 34 sha1:b9f373fb2097836edf1c9ffbf0ca55d1d2b2168f
          +obj 0000000000000001 37 sha1:a89f350d69c3f1ef8d7f2893d25ddbca59c72c1d
                 0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
          -     19: q    BINPUT     1
          +     19: q    BINPUT     0
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      3
          -     24: U    SHORT_BINSTRING 'f2.16'
          -     31: q    BINPUT     2
          -     33: .    STOP
          +     24: X    BINUNICODE 'f2.16'
          +     34: q    BINPUT     1
          +     36: .    STOP
             highest protocol among opcodes = 2
      
          @@ -999,16 +1043,16 @@ txn 0285cbae170a3e33 " "
           user "user2.17"
           description "step 2.17"
           extension ""
          -obj 0000000000000008 34 sha1:698e7a066839a9436339747fe7a85f475095af67
          +obj 0000000000000008 37 sha1:a442c267648c2cdcc7bd94e9343ae3c40bfd4aa1
                 0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
          -     19: q    BINPUT     1
          +     19: q    BINPUT     0
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      3
          -     24: U    SHORT_BINSTRING 'b2.17'
          -     31: q    BINPUT     2
          -     33: .    STOP
          +     24: X    BINUNICODE 'b2.17'
          +     34: q    BINPUT     1
          +     36: .    STOP
             highest protocol among opcodes = 2
      
          @@ -1016,16 +1060,16 @@ txn 0285cbae1bbbbc80 " "
           user "user2.18"
           description "step 2.18"
           extension ""
          -obj 0000000000000002 34 sha1:0d2f350bbfeb38c85466b05b336f9414b9e91f77
          +obj 0000000000000002 37 sha1:4751d47156d33d3029b1ac072978a0cd036d8407
                 0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
          -     19: q    BINPUT     1
          +     19: q    BINPUT     0
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      3
          -     24: U    SHORT_BINSTRING 'd2.18'
          -     31: q    BINPUT     2
          -     33: .    STOP
          +     24: X    BINUNICODE 'd2.18'
          +     34: q    BINPUT     1
          +     36: .    STOP
             highest protocol among opcodes = 2
      
          @@ -1033,16 +1077,16 @@ txn 0285cbae206d3acc " "
           user "user2.19"
           description "step 2.19"
           extension ""
          -obj 0000000000000009 34 sha1:471ca065c05720073421a0aeab549cb1e58cf99f
          +obj 0000000000000009 37 sha1:2c45fb767784e729381e26b159809465de6cc4a1
                 0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
          -     19: q    BINPUT     1
          +     19: q    BINPUT     0
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      3
          -     24: U    SHORT_BINSTRING 'e2.19'
          -     31: q    BINPUT     2
          -     33: .    STOP
          +     24: X    BINUNICODE 'e2.19'
          +     34: q    BINPUT     1
          +     36: .    STOP
             highest protocol among opcodes = 2
      
          @@ -1050,16 +1094,16 @@ txn 0285cbae251eb919 " "
           user "user2.20"
           description "step 2.20"
           extension ""
          -obj 0000000000000008 34 sha1:3b543565ce78028b7118f322a8d1faf2439d70e4
          +obj 0000000000000008 37 sha1:805076196578ebe4b4d399791a0841210348b7dd
                 0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
          -     19: q    BINPUT     1
          +     19: q    BINPUT     0
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      3
          -     24: U    SHORT_BINSTRING 'b2.20'
          -     31: q    BINPUT     2
          -     33: .    STOP
          +     24: X    BINUNICODE 'b2.20'
          +     34: q    BINPUT     1
          +     36: .    STOP
             highest protocol among opcodes = 2
      
          @@ -1067,16 +1111,16 @@ txn 0285cbae29d03766 " "
           user "user2.21"
           description "step 2.21"
           extension ""
          -obj 0000000000000009 34 sha1:79714405c7319c5800c2fe5f192a8a1e8a33d873
          +obj 0000000000000009 37 sha1:67fe19d4814705a72c5213d7b9827d60211f955e
                 0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
          -     19: q    BINPUT     1
          +     19: q    BINPUT     0
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      3
          -     24: U    SHORT_BINSTRING 'e2.21'
          -     31: q    BINPUT     2
          -     33: .    STOP
          +     24: X    BINUNICODE 'e2.21'
          +     34: q    BINPUT     1
          +     36: .    STOP
             highest protocol among opcodes = 2
      
          @@ -1084,16 +1128,16 @@ txn 0285cbae2e81b5b3 " "
           user "user2.22"
           description "step 2.22"
           extension ""
          -obj 0000000000000009 34 sha1:fb3f01b3470c5dcf9b4ce613bdd3821f2b9a3576
          +obj 0000000000000009 37 sha1:1467daccd50741b009135ca01fa4b1d5603cf52b
                 0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
          -     19: q    BINPUT     1
          +     19: q    BINPUT     0
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      3
          -     24: U    SHORT_BINSTRING 'e2.22'
          -     31: q    BINPUT     2
          -     33: .    STOP
          +     24: X    BINUNICODE 'e2.22'
          +     34: q    BINPUT     1
          +     36: .    STOP
             highest protocol among opcodes = 2
      
          @@ -1101,16 +1145,16 @@ txn 0285cbae33333400 " "
           user "user2.23"
           description "step 2.23"
           extension ""
          -obj 0000000000000002 34 sha1:2a646981c19fe36d62d89df7e1fd344eb648f9b8
          +obj 0000000000000002 37 sha1:414bbf42bc2c71670db19a00326a66ae81c95934
                 0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
          -     19: q    BINPUT     1
          +     19: q    BINPUT     0
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      3
          -     24: U    SHORT_BINSTRING 'd2.23'
          -     31: q    BINPUT     2
          -     33: .    STOP
          +     24: X    BINUNICODE 'd2.23'
          +     34: q    BINPUT     1
          +     36: .    STOP
             highest protocol among opcodes = 2
      
          @@ -1118,16 +1162,16 @@ txn 0285cbae37e4b24c " "
           user "user2.24"
           description "step 2.24"
           extension ""
          -obj 0000000000000009 34 sha1:8b769601aed2ebd9f3cc8fe1e63b2cd8975f9f2d
          +obj 0000000000000009 37 sha1:5bebc2493258962bc7b04ac95adf0753a48717c6
                 0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
          -     19: q    BINPUT     1
          +     19: q    BINPUT     0
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      3
          -     24: U    SHORT_BINSTRING 'e2.24'
          -     31: q    BINPUT     2
          -     33: .    STOP
          +     24: X    BINUNICODE 'e2.24'
          +     34: q    BINPUT     1
          +     36: .    STOP
             highest protocol among opcodes = 2
      
          @@ -1147,18 +1191,20 @@ txn 0285cbae45f92d33 " "
           user "user"
           description "cyclic reference"
           extension ""
          -obj 0000000000000002 39 sha1:f44b22761c7e1df86ed61823eb1404e463378a32
          +obj 0000000000000002 43 sha1:5dbee843010481bc9decea7a3fdc788af687a861
                 0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
          -     19: q    BINPUT     1
          +     19: q    BINPUT     0
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      3
          -     24: C    SHORT_BINBYTES '\x00\x00\x00\x00\x00\x00\x00\x02'
          -     34: h    BINGET     1
          -     36: \x86 TUPLE2
          -     37: Q    BINPERSID
          -     38: .    STOP
          +     24: C    SHORT_BINBYTES b'\x00\x00\x00\x00\x00\x00\x00\x02'
          +     34: q    BINPUT     1
          +     36: h    BINGET     0
          +     38: \x86 TUPLE2
          +     39: q    BINPUT     2
          +     41: Q    BINPERSID
          +     42: .    STOP
             highest protocol among opcodes = 3
      
          @@ -1166,71 +1212,92 @@ txn 0285cbae4aaaab80 " "
           user ""
           description "predelete 2"
           extension ""
          -obj 0000000000000000 199 sha1:a51d894c29856c2e8b8194e714cd84a0a23d03b8
          +obj 0000000000000000 265 sha1:7e206c9b8e345ec231a691fa8e5570059f715c42
                 0: \x80 PROTO      3
                 2: c    GLOBAL     'persistent.mapping PersistentMapping'
          -     40: q    BINPUT     1
          +     40: q    BINPUT     0
                42: .    STOP
             highest protocol among opcodes = 2
                43: \x80 PROTO      3
                45: }    EMPTY_DICT
          -     46: q    BINPUT     2
          -     48: U    SHORT_BINSTRING 'data'
          -     54: q    BINPUT     3
          -     56: }    EMPTY_DICT
          -     57: q    BINPUT     4
          -     59: (    MARK
          -     60: U        SHORT_BINSTRING 'a'
          -     63: C        SHORT_BINBYTES '\x00\x00\x00\x00\x00\x00\x00\x05'
          -     73: c        GLOBAL     '__main__ Object'
          -     90: q        BINPUT     5
          -     92: \x86     TUPLE2
          -     93: Q        BINPERSID
          -     94: U        SHORT_BINSTRING 'c'
          -     97: C        SHORT_BINBYTES '\x00\x00\x00\x00\x00\x00\x00\x07'
          -    107: h        BINGET     5
          -    109: \x86     TUPLE2
          -    110: Q        BINPERSID
          -    111: U        SHORT_BINSTRING 'b'
          -    114: C        SHORT_BINBYTES '\x00\x00\x00\x00\x00\x00\x00\x08'
          -    124: h        BINGET     5
          -    126: \x86     TUPLE2
          -    127: Q        BINPERSID
          -    128: U        SHORT_BINSTRING 'e'
          -    131: C        SHORT_BINBYTES '\x00\x00\x00\x00\x00\x00\x00\t'
          -    141: h        BINGET     5
          -    143: \x86     TUPLE2
          -    144: Q        BINPERSID
          -    145: U        SHORT_BINSTRING 'd'
          -    148: C        SHORT_BINBYTES '\x00\x00\x00\x00\x00\x00\x00\n'
          -    158: h        BINGET     5
          -    160: \x86     TUPLE2
          -    161: Q        BINPERSID
          -    162: U        SHORT_BINSTRING 'g'
          -    165: C        SHORT_BINBYTES '\x00\x00\x00\x00\x00\x00\x00\x03'
          -    175: h        BINGET     5
          -    177: \x86     TUPLE2
          -    178: Q        BINPERSID
          -    179: U        SHORT_BINSTRING 'f'
          -    182: C        SHORT_BINBYTES '\x00\x00\x00\x00\x00\x00\x00\x01'
          -    192: h        BINGET     5
          -    194: \x86     TUPLE2
          -    195: Q        BINPERSID
          -    196: u        SETITEMS   (MARK at 59)
          -    197: s    SETITEM
          -    198: .    STOP
          +     46: q    BINPUT     1
          +     48: X    BINUNICODE 'data'
          +     57: q    BINPUT     2
          +     59: }    EMPTY_DICT
          +     60: q    BINPUT     3
          +     62: (    MARK
          +     63: X        BINUNICODE 'f'
          +     69: q        BINPUT     4
          +     71: C        SHORT_BINBYTES b'\x00\x00\x00\x00\x00\x00\x00\x01'
          +     81: q        BINPUT     5
          +     83: c        GLOBAL     '__main__ Object'
          +    100: q        BINPUT     6
          +    102: \x86     TUPLE2
          +    103: q        BINPUT     7
          +    105: Q        BINPERSID
          +    106: X        BINUNICODE 'd'
          +    112: q        BINPUT     8
          +    114: C        SHORT_BINBYTES b'\x00\x00\x00\x00\x00\x00\x00\n'
          +    124: q        BINPUT     9
          +    126: h        BINGET     6
          +    128: \x86     TUPLE2
          +    129: q        BINPUT     10
          +    131: Q        BINPERSID
          +    132: X        BINUNICODE 'g'
          +    138: q        BINPUT     11
          +    140: C        SHORT_BINBYTES b'\x00\x00\x00\x00\x00\x00\x00\x03'
          +    150: q        BINPUT     12
          +    152: h        BINGET     6
          +    154: \x86     TUPLE2
          +    155: q        BINPUT     13
          +    157: Q        BINPERSID
          +    158: X        BINUNICODE 'b'
          +    164: q        BINPUT     14
          +    166: C        SHORT_BINBYTES b'\x00\x00\x00\x00\x00\x00\x00\x08'
          +    176: q        BINPUT     15
          +    178: h        BINGET     6
          +    180: \x86     TUPLE2
          +    181: q        BINPUT     16
          +    183: Q        BINPERSID
          +    184: X        BINUNICODE 'a'
          +    190: q        BINPUT     17
          +    192: C        SHORT_BINBYTES b'\x00\x00\x00\x00\x00\x00\x00\x05'
          +    202: q        BINPUT     18
          +    204: h        BINGET     6
          +    206: \x86     TUPLE2
          +    207: q        BINPUT     19
          +    209: Q        BINPERSID
          +    210: X        BINUNICODE 'e'
          +    216: q        BINPUT     20
          +    218: C        SHORT_BINBYTES b'\x00\x00\x00\x00\x00\x00\x00\t'
          +    228: q        BINPUT     21
          +    230: h        BINGET     6
          +    232: \x86     TUPLE2
          +    233: q        BINPUT     22
          +    235: Q        BINPERSID
          +    236: X        BINUNICODE 'c'
          +    242: q        BINPUT     23
          +    244: C        SHORT_BINBYTES b'\x00\x00\x00\x00\x00\x00\x00\x07'
          +    254: q        BINPUT     24
          +    256: h        BINGET     6
          +    258: \x86     TUPLE2
          +    259: q        BINPUT     25
          +    261: Q        BINPERSID
          +    262: u        SETITEMS   (MARK at 62)
          +    263: s    SETITEM
          +    264: .    STOP
             highest protocol among opcodes = 3
      
          -obj 000000000000000a 32 sha1:25364c8085cd5e554eb4756133186e5cf386032b
          +obj 000000000000000a 35 sha1:3c9779a0408ed164eca3ade755529246f25fe76c
                 0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
          -     19: q    BINPUT     1
          +     19: q    BINPUT     0
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      3
          -     24: U    SHORT_BINSTRING 'd2*'
          -     29: q    BINPUT     2
          -     31: .    STOP
          +     24: X    BINUNICODE 'd2*'
          +     32: q    BINPUT     1
          +     34: .    STOP
             highest protocol among opcodes = 2
      479c353d
    • Kirill Smelkov's avatar
      test: Add py2py3-venv to combine two virtual environments into one · fac2f190
      Kirill Smelkov authored
      Add script that can be used to combine python2 venv and python3 venv
      into one environment where python2 refers to python interpreter with
      access to eggs from py2 environment and python3 refers to python
      interpreter with access to eggs from py3 environment.
      
      In the next patch we will use this script to combine py2/py3 venvs into
      one environment to run `python2 gen_testdata.py` and `python3
      gen_testdata.py`. Though the script should be useful on its own to do
      any combined py2/py3 work or testing.
      fac2f190
    • Kirill Smelkov's avatar
      test/*: Add py2 + pickle protocol=3 ZODB kind to test matrix · 09d79332
      Kirill Smelkov authored
      This is the kind of databases that ZODB/py2 generates starting from ZODB
      5.4, more specifically from https://github.com/zopefoundation/ZODB/commit/12ee41c4
      done in 2018. In other words since 5-6 years ago this is the kind of
      databases that are generated by default. Which means we should have test
      coverage for this as well.
      
      And adding this test coverage automatically reveals one bug in zodbdump:
      its pretty=zpickledis mode used pickletools to dump content of pickles,
      but since on py2 standard pickletools knows nothing about protocol=3
      opcodes, that dump mode was failing on SHORT_BINBYTES ('C') opcode:
      
          kirr@deca:~/src/wendelin/z/zodbtools/zodbtools/test$ ./gen_testdata.py
          Traceback (most recent call last):
            File "./gen_testdata.py", line 392, in <module>
              main()
            File "./gen_testdata.py", line 388, in main
              run_with_all_zodb_pickle_kinds(_)
            File "./gen_testdata.py", line 190, in run_with_all_zodb_pickle_kinds
              _(3)
            File "./gen_testdata.py", line 187, in _
              f()
            File "./gen_testdata.py", line 376, in _
              zodbdump(stor, None, None, pretty=pretty, out=f)
            File "/home/kirr/src/wendelin/z/zodbtools/zodbtools/zodbdump.py", line 169, in zodbdump
              pickletools.dis(dataf, disf, memo) # state
            File "/usr/lib/python2.7/pickletools.py", line 1933, in dis
              for opcode, arg, pos in genops(pickle):
            File "/usr/lib/python2.7/pickletools.py", line 1847, in genops
              code))
          ValueError: at position 63, opcode 'C' unknown
      
      The fix is to use pickletools from zodbpickle instead of builtin
      pickletools, and the fix needs to go in this patch as well because
      otherwise it is not possible to generate the golden test files.
      
      Inspecting the diff in between py2_pickle2 and py2_pickle3 one can see
      that *BYTES opcodes start to be used for OIDs but otherwise test
      database stays logically the same:
      
          (zdev+py39.env) kirr@deca:~/src/wendelin/z/zodbtools/zodbtools/test/testdata/1_!zext$ xdiff py2_pickle2/zdump.zpickledis.ok py2_pickle3/zdump.zpickledis.ok
          diff --git a/py2_pickle2/zdump.zpickledis.ok b/py2_pickle3/zdump.zpickledis.ok
          index 8586d39..cd9d7f5 100644
          --- a/py2_pickle2/zdump.zpickledis.ok
          +++ b/py2_pickle3/zdump.zpickledis.ok
          @@ -2,13 +2,13 @@ txn 0285cbac70a3d733 "p"
           user "user0.12"
           description "step 0.12"
           extension ""
          -obj 0000000000000001 34 sha1:9fae782fe3e33273b520c954925704856ca90dc6
          -      0: \x80 PROTO      2
          +obj 0000000000000001 34 sha1:fc9e49cca756681a9f36c915c6b7b8ad79f17cbc
          +      0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
          -     22: \x80 PROTO      2
          +     22: \x80 PROTO      3
                24: U    SHORT_BINSTRING 'f0.12'
                31: q    BINPUT     2
                33: .    STOP
          @@ -19,13 +19,13 @@ txn 0285cbac7eb85219 "p"
           user "user0.15"
           description "step 0.15"
           extension ""
          -obj 0000000000000006 34 sha1:5dbf26359289e5a25f9755f832ea91cc8ee76686
          -      0: \x80 PROTO      2
          +obj 0000000000000006 34 sha1:76a94af22a81cd970845aeb3536f428a96afcfc7
          +      0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
          -     22: \x80 PROTO      2
          +     22: \x80 PROTO      3
                24: U    SHORT_BINSTRING 'e0.15'
                31: q    BINPUT     2
                33: .    STOP
          @@ -36,13 +36,13 @@ txn 0285cbac917e4b4c "p"
           user "user0.19"
           description "step 0.19"
           extension ""
          -obj 0000000000000005 34 sha1:9e0a8797eb8f60498563703b1961126fba35be9b
          -      0: \x80 PROTO      2
          +obj 0000000000000005 34 sha1:4bd994052ba9a6b1f328c252d8766f13c53ae209
          +      0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
          -     22: \x80 PROTO      2
          +     22: \x80 PROTO      3
                24: U    SHORT_BINSTRING 'a0.19'
                31: q    BINPUT     2
                33: .    STOP
          @@ -53,13 +53,13 @@ txn 0285cbac9ae147e6 "p"
           user "user0.21"
           description "step 0.21"
           extension ""
          -obj 0000000000000002 34 sha1:009174c1f01142f24495fa13738749ff528fd82c
          -      0: \x80 PROTO      2
          +obj 0000000000000002 34 sha1:633b0e1e89447d452468367784717fb48b0b83b1
          +      0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
          -     22: \x80 PROTO      2
          +     22: \x80 PROTO      3
                24: U    SHORT_BINSTRING 'd0.21'
                31: q    BINPUT     2
                33: .    STOP
          @@ -70,13 +70,13 @@ txn 0285cbacada74119 "p"
           user "root0.0\nYour\nMagesty "
           description "undo 0.0\nmore detailed description\n\nzzz ..."
           extension ""
          -obj 0000000000000007 34 sha1:688eb65eab5e4c5ee5242b027bb9bfa5e1087598
          -      0: \x80 PROTO      2
          +obj 0000000000000007 34 sha1:b4bf7b467c62a1b51099ba1cc5b5aecd444d598d
          +      0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
          -     22: \x80 PROTO      2
          +     22: \x80 PROTO      3
                24: U    SHORT_BINSTRING 'c0.22'
                31: q    BINPUT     2
                33: .    STOP
          @@ -87,13 +87,13 @@ txn 0285cbacb258bf66 "p"
           user "root0.1\nYour\nMagesty "
           description "undo 0.1\nmore detailed description\n\nzzz ...\t"
           extension ""
          -obj 0000000000000003 34 sha1:484358413b2746e8a05b1e3173051abedd28e1fa
          -      0: \x80 PROTO      2
          +obj 0000000000000003 34 sha1:3e5f02a2aa5f0ea3747a6c0ffeec090654091583
          +      0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
          -     22: \x80 PROTO      2
          +     22: \x80 PROTO      3
                24: U    SHORT_BINSTRING 'g0.11'
                31: q    BINPUT     2
                33: .    STOP
          @@ -104,13 +104,13 @@ txn 0285cbacbbbbbc00 "p"
           user ""
           description "predelete 4"
           extension ""
          -obj 0000000000000000 213 sha1:a6e70638fafd4619841032356ae93a4da7b539c5
          -      0: \x80 PROTO      2
          +obj 0000000000000000 199 sha1:d9c10b69422e9a8279e2f738d9c270b88ee49861
          +      0: \x80 PROTO      3
                 2: c    GLOBAL     'persistent.mapping PersistentMapping'
                40: q    BINPUT     1
                42: .    STOP
             highest protocol among opcodes = 2
          -     43: \x80 PROTO      2
          +     43: \x80 PROTO      3
                45: }    EMPTY_DICT
                46: q    BINPUT     2
                48: U    SHORT_BINSTRING 'data'
          @@ -119,60 +119,53 @@ obj 0000000000000000 213 sha1:a6e70638fafd4619841032356ae93a4da7b539c5
                57: q    BINPUT     4
                59: (    MARK
                60: U        SHORT_BINSTRING 'a'
          -     63: U        SHORT_BINSTRING '\x00\x00\x00\x00\x00\x00\x00\x05'
          -     73: q        BINPUT     5
          -     75: c        GLOBAL     '__main__ Object'
          -     92: q        BINPUT     6
          -     94: \x86     TUPLE2
          -     95: Q        BINPERSID
          -     96: U        SHORT_BINSTRING 'c'
          -     99: U        SHORT_BINSTRING '\x00\x00\x00\x00\x00\x00\x00\x07'
          -    109: q        BINPUT     7
          -    111: h        BINGET     6
          -    113: \x86     TUPLE2
          -    114: Q        BINPERSID
          -    115: U        SHORT_BINSTRING 'b'
          -    118: U        SHORT_BINSTRING '\x00\x00\x00\x00\x00\x00\x00\x08'
          -    128: q        BINPUT     8
          -    130: h        BINGET     6
          -    132: \x86     TUPLE2
          -    133: Q        BINPERSID
          -    134: U        SHORT_BINSTRING 'e'
          -    137: U        SHORT_BINSTRING '\x00\x00\x00\x00\x00\x00\x00\x06'
          -    147: q        BINPUT     9
          -    149: h        BINGET     6
          -    151: \x86     TUPLE2
          -    152: Q        BINPERSID
          -    153: U        SHORT_BINSTRING 'd'
          -    156: U        SHORT_BINSTRING '\x00\x00\x00\x00\x00\x00\x00\x02'
          -    166: q        BINPUT     10
          -    168: h        BINGET     6
          -    170: \x86     TUPLE2
          -    171: Q        BINPERSID
          -    172: U        SHORT_BINSTRING 'g'
          -    175: U        SHORT_BINSTRING '\x00\x00\x00\x00\x00\x00\x00\x03'
          -    185: q        BINPUT     11
          -    187: h        BINGET     6
          -    189: \x86     TUPLE2
          -    190: Q        BINPERSID
          -    191: U        SHORT_BINSTRING 'f'
          -    194: U        SHORT_BINSTRING '\x00\x00\x00\x00\x00\x00\x00\x01'
          -    204: q        BINPUT     12
          -    206: h        BINGET     6
          -    208: \x86     TUPLE2
          -    209: Q        BINPERSID
          -    210: u        SETITEMS   (MARK at 59)
          -    211: s    SETITEM
          -    212: .    STOP
          -  highest protocol among opcodes = 2
          -
          -obj 0000000000000008 32 sha1:936674657cf846998d27356363832827fa612092
          -      0: \x80 PROTO      2
          +     63: C        SHORT_BINBYTES '\x00\x00\x00\x00\x00\x00\x00\x05'
          +     73: c        GLOBAL     '__main__ Object'
          +     90: q        BINPUT     5
          +     92: \x86     TUPLE2
          +     93: Q        BINPERSID
          +     94: U        SHORT_BINSTRING 'c'
          +     97: C        SHORT_BINBYTES '\x00\x00\x00\x00\x00\x00\x00\x07'
          +    107: h        BINGET     5
          +    109: \x86     TUPLE2
          +    110: Q        BINPERSID
          +    111: U        SHORT_BINSTRING 'b'
          +    114: C        SHORT_BINBYTES '\x00\x00\x00\x00\x00\x00\x00\x08'
          +    124: h        BINGET     5
          +    126: \x86     TUPLE2
          +    127: Q        BINPERSID
          +    128: U        SHORT_BINSTRING 'e'
          +    131: C        SHORT_BINBYTES '\x00\x00\x00\x00\x00\x00\x00\x06'
          +    141: h        BINGET     5
          +    143: \x86     TUPLE2
          +    144: Q        BINPERSID
          +    145: U        SHORT_BINSTRING 'd'
          +    148: C        SHORT_BINBYTES '\x00\x00\x00\x00\x00\x00\x00\x02'
          +    158: h        BINGET     5
          +    160: \x86     TUPLE2
          +    161: Q        BINPERSID
          +    162: U        SHORT_BINSTRING 'g'
          +    165: C        SHORT_BINBYTES '\x00\x00\x00\x00\x00\x00\x00\x03'
          +    175: h        BINGET     5
          +    177: \x86     TUPLE2
          +    178: Q        BINPERSID
          +    179: U        SHORT_BINSTRING 'f'
          +    182: C        SHORT_BINBYTES '\x00\x00\x00\x00\x00\x00\x00\x01'
          +    192: h        BINGET     5
          +    194: \x86     TUPLE2
          +    195: Q        BINPERSID
          +    196: u        SETITEMS   (MARK at 59)
          +    197: s    SETITEM
          +    198: .    STOP
          +  highest protocol among opcodes = 3
          +
          +obj 0000000000000008 32 sha1:dfe254b2f091cf0c9bc835713d53012d44e7e7ca
          +      0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
          -     22: \x80 PROTO      2
          +     22: \x80 PROTO      3
                24: U    SHORT_BINSTRING 'b0*'
                29: q    BINPUT     2
                31: .    STOP
          @@ -183,13 +176,13 @@ txn 0285cbad02222280 " "
           user "user1.0"
           description "step 1.0"
           extension ""
          -obj 0000000000000006 33 sha1:f18e991b87b63cf1f9486d74d70020ff8d573eec
          -      0: \x80 PROTO      2
          +obj 0000000000000006 33 sha1:8f86d80dab366ac9780cdf9fd11aa622364397db
          +      0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
          -     22: \x80 PROTO      2
          +     22: \x80 PROTO      3
                24: U    SHORT_BINSTRING 'e1.0'
                30: q    BINPUT     2
                32: .    STOP
          @@ -200,13 +193,13 @@ txn 0285cbad06d3a0cc " "
           user "user1.1"
           description "step 1.1"
           extension ""
          -obj 0000000000000008 33 sha1:c37e1d2350c8fc4e18cdbc53b432dba50e5196ba
          -      0: \x80 PROTO      2
          +obj 0000000000000008 33 sha1:3a63a76c25b677ada2cc1281f0fcbca823c2fde8
          +      0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
          -     22: \x80 PROTO      2
          +     22: \x80 PROTO      3
                24: U    SHORT_BINSTRING 'b1.1'
                30: q    BINPUT     2
                32: .    STOP
          @@ -217,13 +210,13 @@ txn 0285cbad0b851f19 " "
           user "user1.2"
           description "step 1.2"
           extension ""
          -obj 0000000000000003 33 sha1:28e9880fc0f50a9fea5c4a9e861adc1fe44c9f5c
          -      0: \x80 PROTO      2
          +obj 0000000000000003 33 sha1:c13b686e24c0b49869156feaafa5299a0be0db54
          +      0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
          -     22: \x80 PROTO      2
          +     22: \x80 PROTO      3
                24: U    SHORT_BINSTRING 'g1.2'
                30: q    BINPUT     2
                32: .    STOP
          @@ -234,13 +227,13 @@ txn 0285cbad10369d66 " "
           user "user1.3"
           description "step 1.3"
           extension ""
          -obj 0000000000000003 33 sha1:5fb466e36ea6f847b73ad7976def8ad60e00e766
          -      0: \x80 PROTO      2
          +obj 0000000000000003 33 sha1:edbfe9c47fdfd3eeb89578d2b975196b72e04a47
          +      0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
          -     22: \x80 PROTO      2
          +     22: \x80 PROTO      3
                24: U    SHORT_BINSTRING 'g1.3'
                30: q    BINPUT     2
                32: .    STOP
          @@ -251,13 +244,13 @@ txn 0285cbad14e81bb3 " "
           user "user1.4"
           description "step 1.4"
           extension ""
          -obj 0000000000000007 33 sha1:90b0ffa657df9de708913a2cbbd454126fd9de15
          -      0: \x80 PROTO      2
          +obj 0000000000000007 33 sha1:0ce3b56cc68602d8fcf9633527fc02d68d3c7963
          +      0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
          -     22: \x80 PROTO      2
          +     22: \x80 PROTO      3
                24: U    SHORT_BINSTRING 'c1.4'
                30: q    BINPUT     2
                32: .    STOP
          @@ -268,13 +261,13 @@ txn 0285cbad19999a00 " "
           user "user1.5"
           description "step 1.5"
           extension ""
          -obj 0000000000000001 33 sha1:70b0a88b7652b82b82539800484dc7788277f32a
          -      0: \x80 PROTO      2
          +obj 0000000000000001 33 sha1:9bb04c55d1990c274fcc9f6d71701456c999154d
          +      0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
          -     22: \x80 PROTO      2
          +     22: \x80 PROTO      3
                24: U    SHORT_BINSTRING 'f1.5'
                30: q    BINPUT     2
                32: .    STOP
          @@ -285,13 +278,13 @@ txn 0285cbad1e4b184c " "
           user "user1.6"
           description "step 1.6"
           extension ""
          -obj 0000000000000002 33 sha1:e9018b0bc67c9de08becf1f1fe1a548ed263fb29
          -      0: \x80 PROTO      2
          +obj 0000000000000002 33 sha1:3856df32ef7c512e9fd2599772e431ce3a18b5f5
          +      0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
          -     22: \x80 PROTO      2
          +     22: \x80 PROTO      3
                24: U    SHORT_BINSTRING 'd1.6'
                30: q    BINPUT     2
                32: .    STOP
          @@ -302,13 +295,13 @@ txn 0285cbad22fc9699 " "
           user "user1.7"
           description "step 1.7"
           extension ""
          -obj 0000000000000007 33 sha1:0cd3f4b725517a5371429e2ef2f56ea54fe405fb
          -      0: \x80 PROTO      2
          +obj 0000000000000007 33 sha1:3d9da3b8f59a10f15e7c6796023153089d58d969
          +      0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
          -     22: \x80 PROTO      2
          +     22: \x80 PROTO      3
                24: U    SHORT_BINSTRING 'c1.7'
                30: q    BINPUT     2
                32: .    STOP
          @@ -319,13 +312,13 @@ txn 0285cbad27ae14e6 " "
           user "user1.8"
           description "step 1.8"
           extension ""
          -obj 0000000000000007 33 sha1:13e366fb1d15d36a62099e6b835638407718229f
          -      0: \x80 PROTO      2
          +obj 0000000000000007 33 sha1:42c7e6fe473e6d99867b134c44c2d97813629b29
          +      0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
          -     22: \x80 PROTO      2
          +     22: \x80 PROTO      3
                24: U    SHORT_BINSTRING 'c1.8'
                30: q    BINPUT     2
                32: .    STOP
          @@ -336,13 +329,13 @@ txn 0285cbad2c5f9333 " "
           user "user1.9"
           description "step 1.9"
           extension ""
          -obj 0000000000000006 33 sha1:3ac37991a56061c7407cc093ee2a71eef4379131
          -      0: \x80 PROTO      2
          +obj 0000000000000006 33 sha1:88921e4828cbbf11dc61ca6fbaf6595a88fe5076
          +      0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
          -     22: \x80 PROTO      2
          +     22: \x80 PROTO      3
                24: U    SHORT_BINSTRING 'e1.9'
                30: q    BINPUT     2
                32: .    STOP
          @@ -353,13 +346,13 @@ txn 0285cbad31111180 " "
           user "user1.10"
           description "step 1.10"
           extension ""
          -obj 0000000000000005 34 sha1:407cc5710a22f6c387df45aab613aa3673b221c6
          -      0: \x80 PROTO      2
          +obj 0000000000000005 34 sha1:70fe501d55fc4052b73f5e3473262a48555f375f
          +      0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
          -     22: \x80 PROTO      2
          +     22: \x80 PROTO      3
                24: U    SHORT_BINSTRING 'a1.10'
                31: q    BINPUT     2
                33: .    STOP
          @@ -370,13 +363,13 @@ txn 0285cbad35c28fcc " "
           user "user1.11"
           description "step 1.11"
           extension ""
          -obj 0000000000000007 34 sha1:88ab1add11652101077535c03b04e83fe4ddb88b
          -      0: \x80 PROTO      2
          +obj 0000000000000007 34 sha1:f1550b205f2cec40b8716673663fb6e446568772
          +      0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
          -     22: \x80 PROTO      2
          +     22: \x80 PROTO      3
                24: U    SHORT_BINSTRING 'c1.11'
                31: q    BINPUT     2
                33: .    STOP
          @@ -387,13 +380,13 @@ txn 0285cbad3a740e19 " "
           user "user1.12"
           description "step 1.12"
           extension ""
          -obj 0000000000000006 34 sha1:4808aef147f8ded08ffaae2ce04265506385e7f7
          -      0: \x80 PROTO      2
          +obj 0000000000000006 34 sha1:e4587785ac67a316d288d89a2ecf5f7548804416
          +      0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
          -     22: \x80 PROTO      2
          +     22: \x80 PROTO      3
                24: U    SHORT_BINSTRING 'e1.12'
                31: q    BINPUT     2
                33: .    STOP
          @@ -404,13 +397,13 @@ txn 0285cbad3f258c66 " "
           user "user1.13"
           description "step 1.13"
           extension ""
          -obj 0000000000000003 34 sha1:a9f47880096587b359fa7ea6a0fd213e800a24a4
          -      0: \x80 PROTO      2
          +obj 0000000000000003 34 sha1:c40d417ad5140d3c0a76b8119e1bc3f77924851f
          +      0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
          -     22: \x80 PROTO      2
          +     22: \x80 PROTO      3
                24: U    SHORT_BINSTRING 'g1.13'
                31: q    BINPUT     2
                33: .    STOP
          @@ -421,13 +414,13 @@ txn 0285cbad43d70ab3 " "
           user "user1.14"
           description "step 1.14"
           extension ""
          -obj 0000000000000003 34 sha1:e5b3820378e102a61be2b5998ded3182c106c7db
          -      0: \x80 PROTO      2
          +obj 0000000000000003 34 sha1:141ee9a480f2e04c1c2b9fab6cab263010ab32cd
          +      0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
          -     22: \x80 PROTO      2
          +     22: \x80 PROTO      3
                24: U    SHORT_BINSTRING 'g1.14'
                31: q    BINPUT     2
                33: .    STOP
          @@ -438,13 +431,13 @@ txn 0285cbad48888900 " "
           user "user1.15"
           description "step 1.15"
           extension ""
          -obj 0000000000000002 34 sha1:f136bac1befa0fbd1ebd50218f8d9afe00b9b0a5
          -      0: \x80 PROTO      2
          +obj 0000000000000002 34 sha1:ffd9e2447b4d6230d8e4c6584967ebd45bdb69cd
          +      0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
          -     22: \x80 PROTO      2
          +     22: \x80 PROTO      3
                24: U    SHORT_BINSTRING 'd1.15'
                31: q    BINPUT     2
                33: .    STOP
          @@ -455,13 +448,13 @@ txn 0285cbad4d3a074c " "
           user "user1.16"
           description "step 1.16"
           extension ""
          -obj 0000000000000003 34 sha1:778621ce5c5e97b65343b1ab0cc1a3ce5702fbc8
          -      0: \x80 PROTO      2
          +obj 0000000000000003 34 sha1:e320d84b1e6f9b5507665684c57938c97fb8707a
          +      0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
          -     22: \x80 PROTO      2
          +     22: \x80 PROTO      3
                24: U    SHORT_BINSTRING 'g1.16'
                31: q    BINPUT     2
                33: .    STOP
          @@ -472,13 +465,13 @@ txn 0285cbad51eb8599 " "
           user "user1.17"
           description "step 1.17"
           extension ""
          -obj 0000000000000001 34 sha1:eb6d2d192f3d8fe47a1b2e8119d390ed580c3fb4
          -      0: \x80 PROTO      2
          +obj 0000000000000001 34 sha1:a64a2fa4d8de13124ad15958bb44e93bb50be691
          +      0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
          -     22: \x80 PROTO      2
          +     22: \x80 PROTO      3
                24: U    SHORT_BINSTRING 'f1.17'
                31: q    BINPUT     2
                33: .    STOP
          @@ -489,13 +482,13 @@ txn 0285cbad569d03e6 " "
           user "user1.18"
           description "step 1.18"
           extension ""
          -obj 0000000000000005 34 sha1:921682b323eb62f109d052bc1dfd4ffe0dbf79db
          -      0: \x80 PROTO      2
          +obj 0000000000000005 34 sha1:1a13c223b1e3c4336157bd9ea48bcebbf2bfeb83
          +      0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
          -     22: \x80 PROTO      2
          +     22: \x80 PROTO      3
                24: U    SHORT_BINSTRING 'a1.18'
                31: q    BINPUT     2
                33: .    STOP
          @@ -506,13 +499,13 @@ txn 0285cbad5b4e8233 " "
           user "user1.19"
           description "step 1.19"
           extension ""
          -obj 0000000000000003 34 sha1:b0b31eb0b48548119153628eb3c6711d959e9f9b
          -      0: \x80 PROTO      2
          +obj 0000000000000003 34 sha1:a0b9f323870e42230530e88c3d0df4d0ff53d169
          +      0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
          -     22: \x80 PROTO      2
          +     22: \x80 PROTO      3
                24: U    SHORT_BINSTRING 'g1.19'
                31: q    BINPUT     2
                33: .    STOP
          @@ -523,13 +516,13 @@ txn 0285cbad60000080 " "
           user "user1.20"
           description "step 1.20"
           extension ""
          -obj 0000000000000003 34 sha1:6bfd3298d0bea74cfa3d1f01bb722e958e3f1520
          -      0: \x80 PROTO      2
          +obj 0000000000000003 34 sha1:9d877b2756905d307e10300aa81428ea05c630d2
          +      0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
          -     22: \x80 PROTO      2
          +     22: \x80 PROTO      3
                24: U    SHORT_BINSTRING 'g1.20'
                31: q    BINPUT     2
                33: .    STOP
          @@ -540,13 +533,13 @@ txn 0285cbad64b17ecc " "
           user "user1.21"
           description "step 1.21"
           extension ""
          -obj 0000000000000006 34 sha1:0d4b4837500e84b190ea2f92b16ab8ec0c486db5
          -      0: \x80 PROTO      2
          +obj 0000000000000006 34 sha1:4087f3ba62712e5c29b0d861d65bcc9904f0828e
          +      0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
          -     22: \x80 PROTO      2
          +     22: \x80 PROTO      3
                24: U    SHORT_BINSTRING 'e1.21'
                31: q    BINPUT     2
                33: .    STOP
          @@ -557,13 +550,13 @@ txn 0285cbad6962fd19 " "
           user "user1.22"
           description "step 1.22"
           extension ""
          -obj 0000000000000005 34 sha1:eacbd02d0d78eece9d784da7f3fd0b2738ca6ce0
          -      0: \x80 PROTO      2
          +obj 0000000000000005 34 sha1:7f234b2ebf6c51bbc2acf55bc481b8ca0912b088
          +      0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
          -     22: \x80 PROTO      2
          +     22: \x80 PROTO      3
                24: U    SHORT_BINSTRING 'a1.22'
                31: q    BINPUT     2
                33: .    STOP
          @@ -574,13 +567,13 @@ txn 0285cbad6e147b66 " "
           user "user1.23"
           description "step 1.23"
           extension ""
          -obj 0000000000000005 34 sha1:1b443228d5a434ddd9616ecb5aa90672c0ce9ba2
          -      0: \x80 PROTO      2
          +obj 0000000000000005 34 sha1:b54c8d6f9415eef59c5e4598d4ea459c7def7ae5
          +      0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
          -     22: \x80 PROTO      2
          +     22: \x80 PROTO      3
                24: U    SHORT_BINSTRING 'a1.23'
                31: q    BINPUT     2
                33: .    STOP
          @@ -591,13 +584,13 @@ txn 0285cbad72c5f9b3 " "
           user "user1.24"
           description "step 1.24"
           extension ""
          -obj 0000000000000001 34 sha1:b35a1826cc6cb71b9ddff043f0e8f88b4d90281f
          -      0: \x80 PROTO      2
          +obj 0000000000000001 34 sha1:fc513f6a915be326a3d1212b12b389f284a329b2
          +      0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
          -     22: \x80 PROTO      2
          +     22: \x80 PROTO      3
                24: U    SHORT_BINSTRING 'f1.24'
                31: q    BINPUT     2
                33: .    STOP
          @@ -620,33 +613,32 @@ txn 0285cbad80da7499 " "
           user "user"
           description "cyclic reference"
           extension ""
          -obj 0000000000000006 41 sha1:863d327e4b795efff7dff75bb73c0d20ea3981aa
          -      0: \x80 PROTO      2
          +obj 0000000000000006 39 sha1:baf12eac4d077427f66ff902f64d44a2a141bfd6
          +      0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
          -     22: \x80 PROTO      2
          -     24: U    SHORT_BINSTRING '\x00\x00\x00\x00\x00\x00\x00\x06'
          -     34: q    BINPUT     2
          -     36: h    BINGET     1
          -     38: \x86 TUPLE2
          -     39: Q    BINPERSID
          -     40: .    STOP
          -  highest protocol among opcodes = 2
          +     22: \x80 PROTO      3
          +     24: C    SHORT_BINBYTES '\x00\x00\x00\x00\x00\x00\x00\x06'
          +     34: h    BINGET     1
          +     36: \x86 TUPLE2
          +     37: Q    BINPERSID
          +     38: .    STOP
          +  highest protocol among opcodes = 3
      
           txn 0285cbad858bf2e6 " "
           user ""
           description "predelete 6"
           extension ""
          -obj 0000000000000000 213 sha1:7247042925f5c18f3695d860eeb2759b78109a55
          -      0: \x80 PROTO      2
          +obj 0000000000000000 199 sha1:eaa0f1b643468f33c6b87a875d67eb3b349be5dd
          +      0: \x80 PROTO      3
                 2: c    GLOBAL     'persistent.mapping PersistentMapping'
                40: q    BINPUT     1
                42: .    STOP
             highest protocol among opcodes = 2
          -     43: \x80 PROTO      2
          +     43: \x80 PROTO      3
                45: }    EMPTY_DICT
                46: q    BINPUT     2
                48: U    SHORT_BINSTRING 'data'
          @@ -655,60 +647,53 @@ obj 0000000000000000 213 sha1:7247042925f5c18f3695d860eeb2759b78109a55
                57: q    BINPUT     4
                59: (    MARK
                60: U        SHORT_BINSTRING 'a'
          -     63: U        SHORT_BINSTRING '\x00\x00\x00\x00\x00\x00\x00\x05'
          -     73: q        BINPUT     5
          -     75: c        GLOBAL     '__main__ Object'
          -     92: q        BINPUT     6
          -     94: \x86     TUPLE2
          -     95: Q        BINPERSID
          -     96: U        SHORT_BINSTRING 'c'
          -     99: U        SHORT_BINSTRING '\x00\x00\x00\x00\x00\x00\x00\x07'
          -    109: q        BINPUT     7
          -    111: h        BINGET     6
          -    113: \x86     TUPLE2
          -    114: Q        BINPERSID
          -    115: U        SHORT_BINSTRING 'b'
          -    118: U        SHORT_BINSTRING '\x00\x00\x00\x00\x00\x00\x00\x08'
          -    128: q        BINPUT     8
          -    130: h        BINGET     6
          -    132: \x86     TUPLE2
          -    133: Q        BINPERSID
          -    134: U        SHORT_BINSTRING 'e'
          -    137: U        SHORT_BINSTRING '\x00\x00\x00\x00\x00\x00\x00\t'
          -    147: q        BINPUT     9
          -    149: h        BINGET     6
          -    151: \x86     TUPLE2
          -    152: Q        BINPERSID
          -    153: U        SHORT_BINSTRING 'd'
          -    156: U        SHORT_BINSTRING '\x00\x00\x00\x00\x00\x00\x00\x02'
          -    166: q        BINPUT     10
          -    168: h        BINGET     6
          -    170: \x86     TUPLE2
          -    171: Q        BINPERSID
          -    172: U        SHORT_BINSTRING 'g'
          -    175: U        SHORT_BINSTRING '\x00\x00\x00\x00\x00\x00\x00\x03'
          -    185: q        BINPUT     11
          -    187: h        BINGET     6
          -    189: \x86     TUPLE2
          -    190: Q        BINPERSID
          -    191: U        SHORT_BINSTRING 'f'
          -    194: U        SHORT_BINSTRING '\x00\x00\x00\x00\x00\x00\x00\x01'
          -    204: q        BINPUT     12
          -    206: h        BINGET     6
          -    208: \x86     TUPLE2
          -    209: Q        BINPERSID
          -    210: u        SETITEMS   (MARK at 59)
          -    211: s    SETITEM
          -    212: .    STOP
          -  highest protocol among opcodes = 2
          -
          -obj 0000000000000009 32 sha1:1a43b55bc4a19245cce9eb5aa5ad411006f06afe
          -      0: \x80 PROTO      2
          +     63: C        SHORT_BINBYTES '\x00\x00\x00\x00\x00\x00\x00\x05'
          +     73: c        GLOBAL     '__main__ Object'
          +     90: q        BINPUT     5
          +     92: \x86     TUPLE2
          +     93: Q        BINPERSID
          +     94: U        SHORT_BINSTRING 'c'
          +     97: C        SHORT_BINBYTES '\x00\x00\x00\x00\x00\x00\x00\x07'
          +    107: h        BINGET     5
          +    109: \x86     TUPLE2
          +    110: Q        BINPERSID
          +    111: U        SHORT_BINSTRING 'b'
          +    114: C        SHORT_BINBYTES '\x00\x00\x00\x00\x00\x00\x00\x08'
          +    124: h        BINGET     5
          +    126: \x86     TUPLE2
          +    127: Q        BINPERSID
          +    128: U        SHORT_BINSTRING 'e'
          +    131: C        SHORT_BINBYTES '\x00\x00\x00\x00\x00\x00\x00\t'
          +    141: h        BINGET     5
          +    143: \x86     TUPLE2
          +    144: Q        BINPERSID
          +    145: U        SHORT_BINSTRING 'd'
          +    148: C        SHORT_BINBYTES '\x00\x00\x00\x00\x00\x00\x00\x02'
          +    158: h        BINGET     5
          +    160: \x86     TUPLE2
          +    161: Q        BINPERSID
          +    162: U        SHORT_BINSTRING 'g'
          +    165: C        SHORT_BINBYTES '\x00\x00\x00\x00\x00\x00\x00\x03'
          +    175: h        BINGET     5
          +    177: \x86     TUPLE2
          +    178: Q        BINPERSID
          +    179: U        SHORT_BINSTRING 'f'
          +    182: C        SHORT_BINBYTES '\x00\x00\x00\x00\x00\x00\x00\x01'
          +    192: h        BINGET     5
          +    194: \x86     TUPLE2
          +    195: Q        BINPERSID
          +    196: u        SETITEMS   (MARK at 59)
          +    197: s    SETITEM
          +    198: .    STOP
          +  highest protocol among opcodes = 3
          +
          +obj 0000000000000009 32 sha1:c10d44876cbf78e49f7cc633d985206f51ecc278
          +      0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
          -     22: \x80 PROTO      2
          +     22: \x80 PROTO      3
                24: U    SHORT_BINSTRING 'e1*'
                29: q    BINPUT     2
                31: .    STOP
          @@ -725,13 +710,13 @@ txn 0285cbadc740db19 " "
           user "user2.0"
           description "step 2.0"
           extension ""
          -obj 0000000000000001 33 sha1:7b5599bdbf192e2d33e2597b52c8a72a751ddd13
          -      0: \x80 PROTO      2
          +obj 0000000000000001 33 sha1:118c46c51bb0f08ce76d8f4f3b5d923b81abdd46
          +      0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
          -     22: \x80 PROTO      2
          +     22: \x80 PROTO      3
                24: U    SHORT_BINSTRING 'f2.0'
                30: q    BINPUT     2
                32: .    STOP
          @@ -742,13 +727,13 @@ txn 0285cbadcbf25966 " "
           user "user2.1"
           description "step 2.1"
           extension ""
          -obj 0000000000000002 33 sha1:50b0cf792f2fdc3fbfc5f47f148784924350e31c
          -      0: \x80 PROTO      2
          +obj 0000000000000002 33 sha1:89ff5e4440585130863b518c044d35e0154daecc
          +      0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
          -     22: \x80 PROTO      2
          +     22: \x80 PROTO      3
                24: U    SHORT_BINSTRING 'd2.1'
                30: q    BINPUT     2
                32: .    STOP
          @@ -759,13 +744,13 @@ txn 0285cbadd0a3d7b3 " "
           user "user2.2"
           description "step 2.2"
           extension ""
          -obj 0000000000000003 33 sha1:71f1255a9751e0f223f079552e182cf26b27c0a6
          -      0: \x80 PROTO      2
          +obj 0000000000000003 33 sha1:e0470e3dee47625819f9bfe8085c1bce2a7a4a42
          +      0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
          -     22: \x80 PROTO      2
          +     22: \x80 PROTO      3
                24: U    SHORT_BINSTRING 'g2.2'
                30: q    BINPUT     2
                32: .    STOP
          @@ -776,13 +761,13 @@ txn 0285cbadd5555600 " "
           user "user2.3"
           description "step 2.3"
           extension ""
          -obj 0000000000000003 33 sha1:e6236b8f0a4a2201c0c2375a8f360905108eff2d
          -      0: \x80 PROTO      2
          +obj 0000000000000003 33 sha1:b1a3740b05c6cae5f6c851b715c76dd7348228a9
          +      0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
          -     22: \x80 PROTO      2
          +     22: \x80 PROTO      3
                24: U    SHORT_BINSTRING 'g2.3'
                30: q    BINPUT     2
                32: .    STOP
          @@ -793,13 +778,13 @@ txn 0285cbadda06d44c " "
           user "user2.4"
           description "step 2.4"
           extension ""
          -obj 0000000000000009 33 sha1:55a37439e3dc66552d680833af332b8be83bfc2a
          -      0: \x80 PROTO      2
          +obj 0000000000000009 33 sha1:d0368e87213747ab68d8e4f7a87ff1ea959ea579
          +      0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
          -     22: \x80 PROTO      2
          +     22: \x80 PROTO      3
                24: U    SHORT_BINSTRING 'e2.4'
                30: q    BINPUT     2
                32: .    STOP
          @@ -810,13 +795,13 @@ txn 0285cbaddeb85299 " "
           user "user2.5"
           description "step 2.5"
           extension ""
          -obj 0000000000000005 33 sha1:6beb5d1ca083744ff1e8a13c0bee70c2df54a05c
          -      0: \x80 PROTO      2
          +obj 0000000000000005 33 sha1:e5af7f0b8e157926739f657e729594908d188a3d
          +      0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
          -     22: \x80 PROTO      2
          +     22: \x80 PROTO      3
                24: U    SHORT_BINSTRING 'a2.5'
                30: q    BINPUT     2
                32: .    STOP
          @@ -827,13 +812,13 @@ txn 0285cbade369d0e6 " "
           user "user2.6"
           description "step 2.6"
           extension ""
          -obj 0000000000000008 33 sha1:2a3221e27ac8fbf15ab75b38a9a65e727d237355
          -      0: \x80 PROTO      2
          +obj 0000000000000008 33 sha1:dc70c3b1413c79d75bcfdcc50c3e803273f857ef
          +      0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
          -     22: \x80 PROTO      2
          +     22: \x80 PROTO      3
                24: U    SHORT_BINSTRING 'b2.6'
                30: q    BINPUT     2
                32: .    STOP
          @@ -844,13 +829,13 @@ txn 0285cbade81b4f33 " "
           user "user2.7"
           description "step 2.7"
           extension ""
          -obj 0000000000000003 33 sha1:408fddc8c7255c5e2ed94c239ac57c211ab94b6d
          -      0: \x80 PROTO      2
          +obj 0000000000000003 33 sha1:35892bc2c71edb022b029aa1e4bf8201ccab4b0c
          +      0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
          -     22: \x80 PROTO      2
          +     22: \x80 PROTO      3
                24: U    SHORT_BINSTRING 'g2.7'
                30: q    BINPUT     2
                32: .    STOP
          @@ -861,13 +846,13 @@ txn 0285cbadeccccd80 " "
           user "user2.8"
           description "step 2.8"
           extension ""
          -obj 0000000000000002 33 sha1:72eda0cdae0addbec9472e28b5a9a91ecdf41bbf
          -      0: \x80 PROTO      2
          +obj 0000000000000002 33 sha1:b2da174266d0f0e0b58c214e6d79851f4a18b554
          +      0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
          -     22: \x80 PROTO      2
          +     22: \x80 PROTO      3
                24: U    SHORT_BINSTRING 'd2.8'
                30: q    BINPUT     2
                32: .    STOP
          @@ -878,13 +863,13 @@ txn 0285cbadf17e4bcc " "
           user "user2.9"
           description "step 2.9"
           extension ""
          -obj 0000000000000009 33 sha1:f1d87ba386f57291ecc925020a05df06caedb278
          -      0: \x80 PROTO      2
          +obj 0000000000000009 33 sha1:92cf61eb5855d3b25fecbe7a458f1b21946f5ba3
          +      0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
          -     22: \x80 PROTO      2
          +     22: \x80 PROTO      3
                24: U    SHORT_BINSTRING 'e2.9'
                30: q    BINPUT     2
                32: .    STOP
          @@ -895,13 +880,13 @@ txn 0285cbadf62fca19 " "
           user "user2.10"
           description "step 2.10"
           extension ""
          -obj 0000000000000007 34 sha1:6696fa0434fadb645687c74c8561f0f55fce1fd6
          -      0: \x80 PROTO      2
          +obj 0000000000000007 34 sha1:f737655162c594cf8296b38f7c435a5e8e06d6d7
          +      0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
          -     22: \x80 PROTO      2
          +     22: \x80 PROTO      3
                24: U    SHORT_BINSTRING 'c2.10'
                31: q    BINPUT     2
                33: .    STOP
          @@ -912,13 +897,13 @@ txn 0285cbadfae14866 " "
           user "user2.11"
           description "step 2.11"
           extension ""
          -obj 0000000000000002 34 sha1:14e8b27b3bc8bf5b4d86ca162cc1c912a29a1c05
          -      0: \x80 PROTO      2
          +obj 0000000000000002 34 sha1:032d8305ea9de2ec785fc77c1743a37bb64553cd
          +      0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
          -     22: \x80 PROTO      2
          +     22: \x80 PROTO      3
                24: U    SHORT_BINSTRING 'd2.11'
                31: q    BINPUT     2
                33: .    STOP
          @@ -929,13 +914,13 @@ txn 0285cbadff92c6b3 " "
           user "user2.12"
           description "step 2.12"
           extension ""
          -obj 0000000000000003 34 sha1:db269b90a0df33aa7d411c672f93fb7d86bbdb87
          -      0: \x80 PROTO      2
          +obj 0000000000000003 34 sha1:975fd7ef6350b6543495a800852969f1d7833c83
          +      0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
          -     22: \x80 PROTO      2
          +     22: \x80 PROTO      3
                24: U    SHORT_BINSTRING 'g2.12'
                31: q    BINPUT     2
                33: .    STOP
          @@ -946,13 +931,13 @@ txn 0285cbae04444500 " "
           user "user2.13"
           description "step 2.13"
           extension ""
          -obj 0000000000000002 34 sha1:4b28f9e97ff4f61f3dfba30b9f7aceb4913215ce
          -      0: \x80 PROTO      2
          +obj 0000000000000002 34 sha1:d09e49d753b8183ba5e0fa042a239f103d54c873
          +      0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
          -     22: \x80 PROTO      2
          +     22: \x80 PROTO      3
                24: U    SHORT_BINSTRING 'd2.13'
                31: q    BINPUT     2
                33: .    STOP
          @@ -963,13 +948,13 @@ txn 0285cbae08f5c34c " "
           user "user2.14"
           description "step 2.14"
           extension ""
          -obj 0000000000000007 34 sha1:c3eabecf360015b4b7555abc3a0dc0cea77fe7ed
          -      0: \x80 PROTO      2
          +obj 0000000000000007 34 sha1:109581582c53bf400e56780c331410e5195d19e0
          +      0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
          -     22: \x80 PROTO      2
          +     22: \x80 PROTO      3
                24: U    SHORT_BINSTRING 'c2.14'
                31: q    BINPUT     2
                33: .    STOP
          @@ -980,13 +965,13 @@ txn 0285cbae0da74199 " "
           user "user2.15"
           description "step 2.15"
           extension ""
          -obj 0000000000000009 34 sha1:25ffaeb6090581d72bce075a765d3cf4198af90f
          -      0: \x80 PROTO      2
          +obj 0000000000000009 34 sha1:e67485cd99587ee9e98158db69ed668fb233093d
          +      0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
          -     22: \x80 PROTO      2
          +     22: \x80 PROTO      3
                24: U    SHORT_BINSTRING 'e2.15'
                31: q    BINPUT     2
                33: .    STOP
          @@ -997,13 +982,13 @@ txn 0285cbae1258bfe6 " "
           user "user2.16"
           description "step 2.16"
           extension ""
          -obj 0000000000000001 34 sha1:e934438dede49d14ee2d1d2afa8fa18774547764
          -      0: \x80 PROTO      2
          +obj 0000000000000001 34 sha1:b9f373fb2097836edf1c9ffbf0ca55d1d2b2168f
          +      0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
          -     22: \x80 PROTO      2
          +     22: \x80 PROTO      3
                24: U    SHORT_BINSTRING 'f2.16'
                31: q    BINPUT     2
                33: .    STOP
          @@ -1014,13 +999,13 @@ txn 0285cbae170a3e33 " "
           user "user2.17"
           description "step 2.17"
           extension ""
          -obj 0000000000000008 34 sha1:9961f82b3f01204f80efbb3b62a2b98d9d3202fa
          -      0: \x80 PROTO      2
          +obj 0000000000000008 34 sha1:698e7a066839a9436339747fe7a85f475095af67
          +      0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
          -     22: \x80 PROTO      2
          +     22: \x80 PROTO      3
                24: U    SHORT_BINSTRING 'b2.17'
                31: q    BINPUT     2
                33: .    STOP
          @@ -1031,13 +1016,13 @@ txn 0285cbae1bbbbc80 " "
           user "user2.18"
           description "step 2.18"
           extension ""
          -obj 0000000000000002 34 sha1:5294513e1e00c7de532f4f90068b2147bf87f673
          -      0: \x80 PROTO      2
          +obj 0000000000000002 34 sha1:0d2f350bbfeb38c85466b05b336f9414b9e91f77
          +      0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
          -     22: \x80 PROTO      2
          +     22: \x80 PROTO      3
                24: U    SHORT_BINSTRING 'd2.18'
                31: q    BINPUT     2
                33: .    STOP
          @@ -1048,13 +1033,13 @@ txn 0285cbae206d3acc " "
           user "user2.19"
           description "step 2.19"
           extension ""
          -obj 0000000000000009 34 sha1:523ec17c6d74016e3464d52bb7c7b7baa4b82a20
          -      0: \x80 PROTO      2
          +obj 0000000000000009 34 sha1:471ca065c05720073421a0aeab549cb1e58cf99f
          +      0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
          -     22: \x80 PROTO      2
          +     22: \x80 PROTO      3
                24: U    SHORT_BINSTRING 'e2.19'
                31: q    BINPUT     2
                33: .    STOP
          @@ -1065,13 +1050,13 @@ txn 0285cbae251eb919 " "
           user "user2.20"
           description "step 2.20"
           extension ""
          -obj 0000000000000008 34 sha1:14b17f0e944432782cb270205b2e96948d112619
          -      0: \x80 PROTO      2
          +obj 0000000000000008 34 sha1:3b543565ce78028b7118f322a8d1faf2439d70e4
          +      0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
          -     22: \x80 PROTO      2
          +     22: \x80 PROTO      3
                24: U    SHORT_BINSTRING 'b2.20'
                31: q    BINPUT     2
                33: .    STOP
          @@ -1082,13 +1067,13 @@ txn 0285cbae29d03766 " "
           user "user2.21"
           description "step 2.21"
           extension ""
          -obj 0000000000000009 34 sha1:27744ea516240e0d00be75f26af9698f842bdda5
          -      0: \x80 PROTO      2
          +obj 0000000000000009 34 sha1:79714405c7319c5800c2fe5f192a8a1e8a33d873
          +      0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
          -     22: \x80 PROTO      2
          +     22: \x80 PROTO      3
                24: U    SHORT_BINSTRING 'e2.21'
                31: q    BINPUT     2
                33: .    STOP
          @@ -1099,13 +1084,13 @@ txn 0285cbae2e81b5b3 " "
           user "user2.22"
           description "step 2.22"
           extension ""
          -obj 0000000000000009 34 sha1:a3f303ddd4f2fb9369f6fbbb38ae8030f7f8188d
          -      0: \x80 PROTO      2
          +obj 0000000000000009 34 sha1:fb3f01b3470c5dcf9b4ce613bdd3821f2b9a3576
          +      0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
          -     22: \x80 PROTO      2
          +     22: \x80 PROTO      3
                24: U    SHORT_BINSTRING 'e2.22'
                31: q    BINPUT     2
                33: .    STOP
          @@ -1116,13 +1101,13 @@ txn 0285cbae33333400 " "
           user "user2.23"
           description "step 2.23"
           extension ""
          -obj 0000000000000002 34 sha1:343bed4b31f4fe69a92ee51d28fd7b9cfd6ecb8b
          -      0: \x80 PROTO      2
          +obj 0000000000000002 34 sha1:2a646981c19fe36d62d89df7e1fd344eb648f9b8
          +      0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
          -     22: \x80 PROTO      2
          +     22: \x80 PROTO      3
                24: U    SHORT_BINSTRING 'd2.23'
                31: q    BINPUT     2
                33: .    STOP
          @@ -1133,13 +1118,13 @@ txn 0285cbae37e4b24c " "
           user "user2.24"
           description "step 2.24"
           extension ""
          -obj 0000000000000009 34 sha1:8804c60dc27b2e2f6908e2a099a5c5d4b5abc843
          -      0: \x80 PROTO      2
          +obj 0000000000000009 34 sha1:8b769601aed2ebd9f3cc8fe1e63b2cd8975f9f2d
          +      0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
          -     22: \x80 PROTO      2
          +     22: \x80 PROTO      3
                24: U    SHORT_BINSTRING 'e2.24'
                31: q    BINPUT     2
                33: .    STOP
          @@ -1162,33 +1147,32 @@ txn 0285cbae45f92d33 " "
           user "user"
           description "cyclic reference"
           extension ""
          -obj 0000000000000002 41 sha1:1e2e3ac81badec749c2082a08d205c06c6bb5119
          -      0: \x80 PROTO      2
          +obj 0000000000000002 39 sha1:f44b22761c7e1df86ed61823eb1404e463378a32
          +      0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
          -     22: \x80 PROTO      2
          -     24: U    SHORT_BINSTRING '\x00\x00\x00\x00\x00\x00\x00\x02'
          -     34: q    BINPUT     2
          -     36: h    BINGET     1
          -     38: \x86 TUPLE2
          -     39: Q    BINPERSID
          -     40: .    STOP
          -  highest protocol among opcodes = 2
          +     22: \x80 PROTO      3
          +     24: C    SHORT_BINBYTES '\x00\x00\x00\x00\x00\x00\x00\x02'
          +     34: h    BINGET     1
          +     36: \x86 TUPLE2
          +     37: Q    BINPERSID
          +     38: .    STOP
          +  highest protocol among opcodes = 3
      
           txn 0285cbae4aaaab80 " "
           user ""
           description "predelete 2"
           extension ""
          -obj 0000000000000000 213 sha1:ee7932656b49c1a3f6271c9b58786f85a29179a2
          -      0: \x80 PROTO      2
          +obj 0000000000000000 199 sha1:a51d894c29856c2e8b8194e714cd84a0a23d03b8
          +      0: \x80 PROTO      3
                 2: c    GLOBAL     'persistent.mapping PersistentMapping'
                40: q    BINPUT     1
                42: .    STOP
             highest protocol among opcodes = 2
          -     43: \x80 PROTO      2
          +     43: \x80 PROTO      3
                45: }    EMPTY_DICT
                46: q    BINPUT     2
                48: U    SHORT_BINSTRING 'data'
          @@ -1197,60 +1181,53 @@ obj 0000000000000000 213 sha1:ee7932656b49c1a3f6271c9b58786f85a29179a2
                57: q    BINPUT     4
                59: (    MARK
                60: U        SHORT_BINSTRING 'a'
          -     63: U        SHORT_BINSTRING '\x00\x00\x00\x00\x00\x00\x00\x05'
          -     73: q        BINPUT     5
          -     75: c        GLOBAL     '__main__ Object'
          -     92: q        BINPUT     6
          -     94: \x86     TUPLE2
          -     95: Q        BINPERSID
          -     96: U        SHORT_BINSTRING 'c'
          -     99: U        SHORT_BINSTRING '\x00\x00\x00\x00\x00\x00\x00\x07'
          -    109: q        BINPUT     7
          -    111: h        BINGET     6
          -    113: \x86     TUPLE2
          -    114: Q        BINPERSID
          -    115: U        SHORT_BINSTRING 'b'
          -    118: U        SHORT_BINSTRING '\x00\x00\x00\x00\x00\x00\x00\x08'
          -    128: q        BINPUT     8
          -    130: h        BINGET     6
          -    132: \x86     TUPLE2
          -    133: Q        BINPERSID
          -    134: U        SHORT_BINSTRING 'e'
          -    137: U        SHORT_BINSTRING '\x00\x00\x00\x00\x00\x00\x00\t'
          -    147: q        BINPUT     9
          -    149: h        BINGET     6
          -    151: \x86     TUPLE2
          -    152: Q        BINPERSID
          -    153: U        SHORT_BINSTRING 'd'
          -    156: U        SHORT_BINSTRING '\x00\x00\x00\x00\x00\x00\x00\n'
          -    166: q        BINPUT     10
          -    168: h        BINGET     6
          -    170: \x86     TUPLE2
          -    171: Q        BINPERSID
          -    172: U        SHORT_BINSTRING 'g'
          -    175: U        SHORT_BINSTRING '\x00\x00\x00\x00\x00\x00\x00\x03'
          -    185: q        BINPUT     11
          -    187: h        BINGET     6
          -    189: \x86     TUPLE2
          -    190: Q        BINPERSID
          -    191: U        SHORT_BINSTRING 'f'
          -    194: U        SHORT_BINSTRING '\x00\x00\x00\x00\x00\x00\x00\x01'
          -    204: q        BINPUT     12
          -    206: h        BINGET     6
          -    208: \x86     TUPLE2
          -    209: Q        BINPERSID
          -    210: u        SETITEMS   (MARK at 59)
          -    211: s    SETITEM
          -    212: .    STOP
          -  highest protocol among opcodes = 2
          -
          -obj 000000000000000a 32 sha1:c9a667705323348a209f8f3b22c1977dbcd3f7e9
          -      0: \x80 PROTO      2
          +     63: C        SHORT_BINBYTES '\x00\x00\x00\x00\x00\x00\x00\x05'
          +     73: c        GLOBAL     '__main__ Object'
          +     90: q        BINPUT     5
          +     92: \x86     TUPLE2
          +     93: Q        BINPERSID
          +     94: U        SHORT_BINSTRING 'c'
          +     97: C        SHORT_BINBYTES '\x00\x00\x00\x00\x00\x00\x00\x07'
          +    107: h        BINGET     5
          +    109: \x86     TUPLE2
          +    110: Q        BINPERSID
          +    111: U        SHORT_BINSTRING 'b'
          +    114: C        SHORT_BINBYTES '\x00\x00\x00\x00\x00\x00\x00\x08'
          +    124: h        BINGET     5
          +    126: \x86     TUPLE2
          +    127: Q        BINPERSID
          +    128: U        SHORT_BINSTRING 'e'
          +    131: C        SHORT_BINBYTES '\x00\x00\x00\x00\x00\x00\x00\t'
          +    141: h        BINGET     5
          +    143: \x86     TUPLE2
          +    144: Q        BINPERSID
          +    145: U        SHORT_BINSTRING 'd'
          +    148: C        SHORT_BINBYTES '\x00\x00\x00\x00\x00\x00\x00\n'
          +    158: h        BINGET     5
          +    160: \x86     TUPLE2
          +    161: Q        BINPERSID
          +    162: U        SHORT_BINSTRING 'g'
          +    165: C        SHORT_BINBYTES '\x00\x00\x00\x00\x00\x00\x00\x03'
          +    175: h        BINGET     5
          +    177: \x86     TUPLE2
          +    178: Q        BINPERSID
          +    179: U        SHORT_BINSTRING 'f'
          +    182: C        SHORT_BINBYTES '\x00\x00\x00\x00\x00\x00\x00\x01'
          +    192: h        BINGET     5
          +    194: \x86     TUPLE2
          +    195: Q        BINPERSID
          +    196: u        SETITEMS   (MARK at 59)
          +    197: s    SETITEM
          +    198: .    STOP
          +  highest protocol among opcodes = 3
          +
          +obj 000000000000000a 32 sha1:25364c8085cd5e554eb4756133186e5cf386032b
          +      0: \x80 PROTO      3
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
          -     22: \x80 PROTO      2
          +     22: \x80 PROTO      3
                24: U    SHORT_BINSTRING 'd2*'
                29: q    BINPUT     2
                31: .    STOP
      09d79332
    • Kirill Smelkov's avatar
      test/*: Start testing zodbtools behaviour on ZODB databases of multiple kinds · bf772ce0
      Kirill Smelkov authored
      Since 0b6f99da (test/gen_testdata: Fix for ZODB5 > 5.5.1 + preserve
      database compatibility with ZODB3/py2) we are generating our test
      database with using pickle protocol=2. This was done in order to make
      sure the zodbtools works ok with data generated by e.g. ZODB4. However
      we still have lots of databases that are generated with pickle
      protocol=1, and we also have newer databases that are generated with
      pickle protocol=3. Note that it is not only data records who are
      affected by specified pickle protocol. For example for FileStorage the
      index is also saved via pickling and so used pickle protocol affects
      index format. For example ZODB/go currently cannot load FileStorage
      index if it was saved via protocol=3.
      
      Since zodbtools should work ok with any data it creates a need to test
      it against all kinds of ZODB databases: generated by either py2 or py3,
      and saved via pickle protocol 1,2 and 3.
      
      In this patch we add infrastructure for such testing and extend testdata
      coverage to cover not only py2_pickle2, but also py2_pickle1. We will
      add support for py2_pickle3 and py3_pickle3 in the follow-up patches.
      
      Testdata files are now located inside dedicated subdirectories - one for
      one ZODB kind. py2_pickle2/* is exactly the same compared to testdata
      files we had before. py2_pickle1/* is bit different. It is handy to see
      the difference via e.g.
      
          $ diff -u py2_pickle2/zdump.zpickledis.ok py2_pickle1/zdump.zpickledis.ok
      
      In tests particular kind of testdata is now accessed via ztestdata
      fixture. Please see changes in zodbtools/test/conftest.py and
      zodbtools/test/gen_testdata.py for details.
      bf772ce0
    • Kirill Smelkov's avatar
      zodbanalyze: tests: Verify CSV mode via golden output generated during gen_testdata · e66451c0
      Kirill Smelkov authored
      Instead of putting expected output into test code.
      
      The reason for this change is that soon, with many kinds of generated
      ZODB databases, analyze output will be different for each kind, and the
      only practical way to make sure that analyze works correctly is to have
      good expected output for each kind.
      
      We already do this way for zodbdump. Start doing the same for
      zodbanalyze as a preparatory step as well.
      e66451c0
    • Kirill Smelkov's avatar
      test/gen_testdata: Prevent object with OID=1 to be deleted · a2c660a7
      Kirill Smelkov authored
      Previously it was like this by luck, but recent changes shuffled
      generated output and one of delete selection started to point to OID 1:
      
          (zdev+py39.env) kirr@deca:~/src/wendelin/z/zodbtools/zodbtools/test/testdata$ grep '^obj .* delete' 1.zdump.zpickledis.ok
          obj 0000000000000001 delete
          obj 0000000000000002 delete
      
      However NEO/go tests depend on object with OID=1 to be present:
      
      https://lab.nexedi.com/kirr/neo/-/blob/1ad088c8/go/neo/neo_test.go#L216-219
      
      and it breaks there if here we let that object with OID=1 to be deleted.
      
      -> Prevent ZODB/go breakage by explicitly making sure that OID=1 stays
      present under any conditions.
      
      The actual places where gen_testdata.py from zodbtools is used in
      ZODB/go and Wendelin.core are e.g. here:
      
      https://lab.nexedi.com/kirr/neo/-/blob/f7776fc1/go/zodb/storage/fs1/py/gen-testdata
      https://lab.nexedi.com/nexedi/wendelin.core/-/blob/07087ec8/wcfs/internal/zdata/testdata/zblk_test_gen.py
      a2c660a7
    • Kirill Smelkov's avatar
      test/gen_testdata: Switch to random2 for PRNG · f38e7941
      Kirill Smelkov authored
      Python3 changed behaviour of random module compared to its previous
      behaviour under Python2:
      
          $ python2
          Python 2.7.18 (default, Jul 14 2021, 08:11:37)
          [GCC 10.2.1 20210110] on linux2
          Type "help", "copyright", "credits" or "license" for more information.
          >>> import random
          >>> random.seed(0)
          >>> for _ in range(5): print(random.randint(0,99))
          ...
          84
          75
          42
          25
          51
      
          $ python3
          Python 3.11.2 (main, Mar 13 2023, 12:18:29) [GCC 12.2.0] on linux
          Type "help", "copyright", "credits" or "license" for more information.
          >>> import random
          >>> random.seed(0)
          >>> for _ in range(5): print(random.randint(0,99))
          ...
          49
          97
          53
          5
          33
      
      Since gen_testdata.py uses PRNG heavily it means that with PRNG based on
      builtin random module of current python, generated output will differ
      strongly in between py2 and py3 versions.
      
      However we want generated outputs to be close to each other for py2 and
      py3 so that it is easier to analyze what is essential difference in
      generated databases.
      
      -> Make sure py2/py3 databases will be logically the same by explicitly
      using random2 and asserting that PRNG behaviour is stable independently
      of current python.
      
      No change in generated files as behaviour of random2 is by definition
      exactly the same as behaviour of builtin random on py2:
      
      https://pypi.org/project/random2/
      f38e7941
    • Kirill Smelkov's avatar
      test/gen_testdata: Retrieve object keys in predictable order independent of python version · 1118ba3a
      Kirill Smelkov authored
      gen_testdata.py picks up root keys randomly and shuffles extension dict
      keys also randomly. But even with predictable PRNG if the input to e.g.
      rand.choice is different, the result will be different as well.
      
      So far we were lucky: we were running gen_testdata.py only via py2 and
      the order of retrieved root keys was - by chance - the same each time.
      That's why generated testdata databases were the same after each
      gen_testdata.py run. But even on py2 there is no such guaranty and when
      runnning gen_testdata.py via py3 the order of keys is really different:
      
          $ python2
          Python 2.7.18 (default, Jul 14 2021, 08:11:37)
          [GCC 10.2.1 20210110] on linux2
          Type "help", "copyright", "credits" or "license" for more information.
          >>> d = {}
          >>> d['a'] = 1
          >>> d['b'] = 2
          >>> d['c'] = 3
          >>> d.keys()
          ['a', 'c', 'b']
      
          $ python3
          Python 3.11.2 (main, Mar 13 2023, 12:18:29) [GCC 12.2.0] on linux
          Type "help", "copyright", "credits" or "license" for more information.
          >>> d = {}
          >>> d['a'] = 1
          >>> d['b'] = 2
          >>> d['c'] = 3
          >>> list(d.keys())
          ['a', 'b', 'c']
      
      So let's prepare for py3 generation beforehand by making sure that
      keys input to PRNG is the same be it py2 or py3, thus, giving a chance
      for generated py2/py3 databases to be really close to each other.
      
      Since here we change the order of keys that are feed to PRNG, generated
      test databases are shuffled a bit.
      1118ba3a
    • Kirill Smelkov's avatar
      test/gen_testdata: Use our own PRNG instance · 667a0088
      Kirill Smelkov authored
      This protects us from ZODB and other third-party code from using
      global PRNG and thus affecting its state and gen_testdata.py output.
      
      Till now we were lucky that there was no such third-party user and so
      the output of gen_testdata.py remains exactly the same as before hereby
      patch. But better be robust and avoid even potential possibility of such
      situations.
      
      Using private PRNG will also help later when running gen_testdata.py via
      Python3 : in py3 they changed behaviour of builtin random and emitted
      numbers differ from the same random when run under py2. By using our own
      PRNG we will be able to level-out that and use essentially the same PRNG
      on both py2 and py3.
      667a0088
    • Kirill Smelkov's avatar
      test/gen_testdata: Start generating test files from clean empty state · 55769490
      Kirill Smelkov authored
      Previsouly we were generating e.g. 1.fs starting over existing 1.fs and
      due to that when FileStoraga was opening it, it was e.g. scanning
      existing 1.fs.index, thus doing some time() calls and so when the
      database was started to be generted the state of the timer was different
      compared to the situation if the database did not existed before
      gen_testdata.py run. In other words the result of gen_testdata.py run
      was different for the cases when it run after `rm testdata/1*` and
      without that rm.
      
      -> Make gen_testdata result to be stable irregardless of the start state
      when it runs by explicitly removing test databases fitst.
      
      As diff to *.zpickledis.ok shows, resulting changes are only in
      transaction IDs.
      55769490
  2. 16 Jul, 2024 1 commit
    • Kirill Smelkov's avatar
      test/gen_testdata: Make sure that "with zext" and "without zext" databases... · 395d8c27
      Kirill Smelkov authored
      test/gen_testdata: Make sure that "with zext" and "without zext" databases differ only in transaction extension
      
      Previously diff in between 1.zdump.zpickledis.ok and 1_!zext.zdump.zpickledis.ok
      indicated difference in many data records as demonstrated in the appendix.
      That was due to that !zext variant, while skipping generating
      transaction extension, contrary to zext variant, did not consumed PRNG
      output, and so when going further PRNG state for zext and !zext variants
      was diverging.
      
      -> Fix it via consuming PRNG output in !zext case exactly the same way
      as in zext case, but throwing out ext4subj output.
      
      After the patch the diff in between `1.zdump.zpickledis.ok
      1_\!zext.zdump.zpickledis.ok` shows only differences in between
      txn.extension fields:
      
          --- a/1.zdump.zpickledis.ok
          +++ b/1_!zext.zdump.zpickledis.ok
          @@ -1,19 +1,7 @@
           txn 0285cbac75555580 "p"
           user "user0.12"
           description "step 0.12"
          -extension
          -      0: \x80 PROTO      2
          -      2: }    EMPTY_DICT
          -      3: q    BINPUT     1
          -      5: (    MARK
          -      6: U        SHORT_BINSTRING 'x-cookie8'
          -     17: U        SHORT_BINSTRING '2MHMU'
          -     24: U        SHORT_BINSTRING 'x-generator'
          -     37: q        BINPUT     2
          -     39: U        SHORT_BINSTRING 'zodb/py2 (f)'
          -     53: u        SETITEMS   (MARK at 5)
          -     54: .    STOP
          -  highest protocol among opcodes = 2
          +extension ""
           obj 0000000000000001 34 sha1:9fae782fe3e33273b520c954925704856ca90dc6
                 0: \x80 PROTO      2
                 2: c    GLOBAL     '__main__ Object'
           ...
      
      Appendix. `1.zdump.zpickledis.ok 1_\!zext.zdump.zpickledis.ok` before this patch
      
          diff --git a/1.zdump.zpickledis.ok b/1_!zext.zdump.zpickledis.ok
          index 9385444..f80531d 100644
          --- a/1.zdump.zpickledis.ok
          +++ b/1_!zext.zdump.zpickledis.ok
          @@ -1,114 +1,49 @@
          -txn 0285cbac75555580 "p"
          -user "user0.12"
          -description "step 0.12"
          -extension
          -      0: \x80 PROTO      2
          -      2: }    EMPTY_DICT
          -      3: q    BINPUT     1
          -      5: (    MARK
          -      6: U        SHORT_BINSTRING 'x-cookie8'
          -     17: U        SHORT_BINSTRING '2MHMU'
          -     24: U        SHORT_BINSTRING 'x-generator'
          -     37: q        BINPUT     2
          -     39: U        SHORT_BINSTRING 'zodb/py2 (f)'
          -     53: u        SETITEMS   (MARK at 5)
          -     54: .    STOP
          -  highest protocol among opcodes = 2
          -obj 0000000000000001 34 sha1:9fae782fe3e33273b520c954925704856ca90dc6
          -      0: \x80 PROTO      2
          -      2: c    GLOBAL     '__main__ Object'
          -     19: q    BINPUT     1
          -     21: .    STOP
          -  highest protocol among opcodes = 2
          -     22: \x80 PROTO      2
          -     24: U    SHORT_BINSTRING 'f0.12'
          -     31: q    BINPUT     2
          -     33: .    STOP
          -  highest protocol among opcodes = 2
          -
          -
           txn 0285cbac8369d066 "p"
           user "user0.15"
           description "step 0.15"
          -extension
          -      0: \x80 PROTO      2
          -      2: }    EMPTY_DICT
          -      3: q    BINPUT     1
          -      5: (    MARK
          -      6: U        SHORT_BINSTRING 'x-cookieY'
          -     17: U        SHORT_BINSTRING 'EDZ10'
          -     24: U        SHORT_BINSTRING 'x-generator'
          -     37: q        BINPUT     2
          -     39: U        SHORT_BINSTRING 'zodb/py2 (e)'
          -     53: u        SETITEMS   (MARK at 5)
          -     54: .    STOP
          -  highest protocol among opcodes = 2
          -obj 0000000000000006 34 sha1:5dbf26359289e5a25f9755f832ea91cc8ee76686
          +extension ""
          +obj 0000000000000003 34 sha1:e616d80f35ea7aaaecdbc65e1e5838c25f4bf07a
                 0: \x80 PROTO      2
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      2
          -     24: U    SHORT_BINSTRING 'e0.15'
          +     24: U    SHORT_BINSTRING 'b0.15'
                31: q    BINPUT     2
                33: .    STOP
             highest protocol among opcodes = 2
      
          -txn 0285cbac962fc999 "p"
          -user "user0.19"
          -description "step 0.19"
          -extension
          -      0: \x80 PROTO      2
          -      2: }    EMPTY_DICT
          -      3: q    BINPUT     1
          -      5: (    MARK
          -      6: U        SHORT_BINSTRING 'x-cookieF'
          -     17: U        SHORT_BINSTRING 'OUC9L'
          -     24: U        SHORT_BINSTRING 'x-generator'
          -     37: q        BINPUT     2
          -     39: U        SHORT_BINSTRING 'zodb/py2 (a)'
          -     53: u        SETITEMS   (MARK at 5)
          -     54: .    STOP
          -  highest protocol among opcodes = 2
          -obj 0000000000000005 34 sha1:9e0a8797eb8f60498563703b1961126fba35be9b
          +txn 0285cbac9f92c633 "p"
          +user "user0.21"
          +description "step 0.21"
          +extension ""
          +obj 0000000000000001 34 sha1:025d34759b434419251b5a429f3ad78ce3c2fd98
                 0: \x80 PROTO      2
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      2
          -     24: U    SHORT_BINSTRING 'a0.19'
          +     24: U    SHORT_BINSTRING 'f0.21'
                31: q    BINPUT     2
                33: .    STOP
             highest protocol among opcodes = 2
      
          -txn 0285cbac9f92c633 "p"
          -user "user0.21"
          -description "step 0.21"
          -extension
          -      0: \x80 PROTO      2
          -      2: }    EMPTY_DICT
          -      3: q    BINPUT     1
          -      5: (    MARK
          -      6: U        SHORT_BINSTRING 'x-cookie8'
          -     17: U        SHORT_BINSTRING '0QC1A'
          -     24: U        SHORT_BINSTRING 'x-generator'
          -     37: q        BINPUT     2
          -     39: U        SHORT_BINSTRING 'zodb/py2 (d)'
          -     53: u        SETITEMS   (MARK at 5)
          -     54: .    STOP
          -  highest protocol among opcodes = 2
          -obj 0000000000000002 34 sha1:009174c1f01142f24495fa13738749ff528fd82c
          +txn 0285cbaca4444480 "p"
          +user "user0.22"
          +description "step 0.22"
          +extension ""
          +obj 0000000000000006 34 sha1:0734767857e69ab8bfd0007d4ca3f1a7fd69b677
                 0: \x80 PROTO      2
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      2
          -     24: U    SHORT_BINSTRING 'd0.21'
          +     24: U    SHORT_BINSTRING 'g0.22'
                31: q    BINPUT     2
                33: .    STOP
             highest protocol among opcodes = 2
          @@ -117,27 +52,15 @@ obj 0000000000000002 34 sha1:009174c1f01142f24495fa13738749ff528fd82c
           txn 0285cbacb70a3db3 "p"
           user "root0.1\nYour\nMagesty "
           description "undo 0.1\nmore detailed description\n\nzzz ...\t"
          -extension
          -      0: \x80 PROTO      2
          -      2: }    EMPTY_DICT
          -      3: q    BINPUT     1
          -      5: (    MARK
          -      6: U        SHORT_BINSTRING 'x-cookieV'
          -     17: U        SHORT_BINSTRING 'VHBGT'
          -     24: U        SHORT_BINSTRING 'x-generator'
          -     37: q        BINPUT     2
          -     39: U        SHORT_BINSTRING 'zodb/py2 (undo AoXLrK2nQRk=)'
          -     69: u        SETITEMS   (MARK at 5)
          -     70: .    STOP
          -  highest protocol among opcodes = 2
          -obj 0000000000000003 34 sha1:484358413b2746e8a05b1e3173051abedd28e1fa
          +extension ""
          +obj 0000000000000004 34 sha1:fe21381adc01e51965c3278c6debf52ebd63068c
                 0: \x80 PROTO      2
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      2
          -     24: U    SHORT_BINSTRING 'g0.11'
          +     24: U    SHORT_BINSTRING 'd0.11'
                31: q    BINPUT     2
                33: .    STOP
             highest protocol among opcodes = 2
          @@ -146,27 +69,15 @@ obj 0000000000000003 34 sha1:484358413b2746e8a05b1e3173051abedd28e1fa
           txn 0285cbacbbbbbc00 "p"
           user "user"
           description "cyclic reference"
          -extension
          -      0: \x80 PROTO      2
          -      2: }    EMPTY_DICT
          -      3: q    BINPUT     1
          -      5: (    MARK
          -      6: U        SHORT_BINSTRING 'x-cookieE'
          -     17: U        SHORT_BINSTRING 'ZM3QZ'
          -     24: U        SHORT_BINSTRING 'x-generator'
          -     37: q        BINPUT     2
          -     39: U        SHORT_BINSTRING 'zodb/py2 (cycle)'
          -     57: u        SETITEMS   (MARK at 5)
          -     58: .    STOP
          -  highest protocol among opcodes = 2
          -obj 0000000000000007 41 sha1:7108c96ccb9cbeaab1164d533174c300e51309f9
          +extension ""
          +obj 0000000000000002 41 sha1:1e2e3ac81badec749c2082a08d205c06c6bb5119
                 0: \x80 PROTO      2
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      2
          -     24: U    SHORT_BINSTRING '\x00\x00\x00\x00\x00\x00\x00\x07'
          +     24: U    SHORT_BINSTRING '\x00\x00\x00\x00\x00\x00\x00\x02'
                34: q    BINPUT     2
                36: h    BINGET     1
                38: \x86 TUPLE2
          @@ -177,9 +88,9 @@ obj 0000000000000007 41 sha1:7108c96ccb9cbeaab1164d533174c300e51309f9
      
           txn 0285cbacc06d3a4c "p"
           user ""
          -description "predelete 4"
          +description "predelete 5"
           extension ""
          -obj 0000000000000000 213 sha1:a6e70638fafd4619841032356ae93a4da7b539c5
          +obj 0000000000000000 194 sha1:4a9e413a4ff168a6a7f84be32b9168364048fd6d
                 0: \x80 PROTO      2
                 2: c    GLOBAL     'persistent.mapping PersistentMapping'
                40: q    BINPUT     1
          @@ -193,62 +104,56 @@ obj 0000000000000000 213 sha1:a6e70638fafd4619841032356ae93a4da7b539c5
                56: }    EMPTY_DICT
                57: q    BINPUT     4
                59: (    MARK
          -     60: U        SHORT_BINSTRING 'a'
          -     63: U        SHORT_BINSTRING '\x00\x00\x00\x00\x00\x00\x00\x05'
          +     60: U        SHORT_BINSTRING 'c'
          +     63: U        SHORT_BINSTRING '\x00\x00\x00\x00\x00\x00\x00\x02'
                73: q        BINPUT     5
                75: c        GLOBAL     '__main__ Object'
                92: q        BINPUT     6
                94: \x86     TUPLE2
                95: Q        BINPERSID
          -     96: U        SHORT_BINSTRING 'c'
          -     99: U        SHORT_BINSTRING '\x00\x00\x00\x00\x00\x00\x00\x07'
          +     96: U        SHORT_BINSTRING 'b'
          +     99: U        SHORT_BINSTRING '\x00\x00\x00\x00\x00\x00\x00\x03'
               109: q        BINPUT     7
               111: h        BINGET     6
               113: \x86     TUPLE2
               114: Q        BINPERSID
          -    115: U        SHORT_BINSTRING 'b'
          -    118: U        SHORT_BINSTRING '\x00\x00\x00\x00\x00\x00\x00\x08'
          +    115: U        SHORT_BINSTRING 'e'
          +    118: U        SHORT_BINSTRING '\x00\x00\x00\x00\x00\x00\x00\x07'
               128: q        BINPUT     8
               130: h        BINGET     6
               132: \x86     TUPLE2
               133: Q        BINPERSID
          -    134: U        SHORT_BINSTRING 'e'
          -    137: U        SHORT_BINSTRING '\x00\x00\x00\x00\x00\x00\x00\x06'
          +    134: U        SHORT_BINSTRING 'd'
          +    137: U        SHORT_BINSTRING '\x00\x00\x00\x00\x00\x00\x00\x04'
               147: q        BINPUT     9
               149: h        BINGET     6
               151: \x86     TUPLE2
               152: Q        BINPERSID
          -    153: U        SHORT_BINSTRING 'd'
          -    156: U        SHORT_BINSTRING '\x00\x00\x00\x00\x00\x00\x00\x02'
          +    153: U        SHORT_BINSTRING 'g'
          +    156: U        SHORT_BINSTRING '\x00\x00\x00\x00\x00\x00\x00\x06'
               166: q        BINPUT     10
               168: h        BINGET     6
               170: \x86     TUPLE2
               171: Q        BINPERSID
          -    172: U        SHORT_BINSTRING 'g'
          -    175: U        SHORT_BINSTRING '\x00\x00\x00\x00\x00\x00\x00\x03'
          +    172: U        SHORT_BINSTRING 'f'
          +    175: U        SHORT_BINSTRING '\x00\x00\x00\x00\x00\x00\x00\x01'
               185: q        BINPUT     11
               187: h        BINGET     6
               189: \x86     TUPLE2
               190: Q        BINPERSID
          -    191: U        SHORT_BINSTRING 'f'
          -    194: U        SHORT_BINSTRING '\x00\x00\x00\x00\x00\x00\x00\x01'
          -    204: q        BINPUT     12
          -    206: h        BINGET     6
          -    208: \x86     TUPLE2
          -    209: Q        BINPERSID
          -    210: u        SETITEMS   (MARK at 59)
          -    211: s    SETITEM
          -    212: .    STOP
          +    191: u        SETITEMS   (MARK at 59)
          +    192: s    SETITEM
          +    193: .    STOP
             highest protocol among opcodes = 2
      
          -obj 0000000000000008 32 sha1:936674657cf846998d27356363832827fa612092
          +obj 0000000000000007 32 sha1:b9d61167d2388ac320b1bc2940b43e7a8bad46ac
                 0: \x80 PROTO      2
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      2
          -     24: U    SHORT_BINSTRING 'b0*'
          +     24: U    SHORT_BINSTRING 'e0*'
                29: q    BINPUT     2
                31: .    STOP
             highest protocol among opcodes = 2
          @@ -257,20 +162,8 @@ obj 0000000000000008 32 sha1:936674657cf846998d27356363832827fa612092
           txn 0285cbad06d3a0cc " "
           user "user1.0"
           description "step 1.0"
          -extension
          -      0: \x80 PROTO      2
          -      2: }    EMPTY_DICT
          -      3: q    BINPUT     1
          -      5: (    MARK
          -      6: U        SHORT_BINSTRING 'x-cookieE'
          -     17: U        SHORT_BINSTRING 'VAZ3U'
          -     24: U        SHORT_BINSTRING 'x-generator'
          -     37: q        BINPUT     2
          -     39: U        SHORT_BINSTRING 'zodb/py2 (e)'
          -     53: u        SETITEMS   (MARK at 5)
          -     54: .    STOP
          -  highest protocol among opcodes = 2
          -obj 0000000000000006 33 sha1:f18e991b87b63cf1f9486d74d70020ff8d573eec
          +extension ""
          +obj 0000000000000007 33 sha1:f18e991b87b63cf1f9486d74d70020ff8d573eec
                 0: \x80 PROTO      2
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
          @@ -286,27 +179,15 @@ obj 0000000000000006 33 sha1:f18e991b87b63cf1f9486d74d70020ff8d573eec
           txn 0285cbad0b851f19 " "
           user "user1.1"
           description "step 1.1"
          -extension
          -      0: \x80 PROTO      2
          -      2: }    EMPTY_DICT
          -      3: q    BINPUT     1
          -      5: (    MARK
          -      6: U        SHORT_BINSTRING 'x-cookieN'
          -     17: U        SHORT_BINSTRING 'GSV4I'
          -     24: U        SHORT_BINSTRING 'x-generator'
          -     37: q        BINPUT     2
          -     39: U        SHORT_BINSTRING 'zodb/py2 (b)'
          -     53: u        SETITEMS   (MARK at 5)
          -     54: .    STOP
          -  highest protocol among opcodes = 2
          -obj 0000000000000008 33 sha1:c37e1d2350c8fc4e18cdbc53b432dba50e5196ba
          +extension ""
          +obj 0000000000000006 33 sha1:bf4f1be3d63bca5c7dccf98f7660f419597a0f3d
                 0: \x80 PROTO      2
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      2
          -     24: U    SHORT_BINSTRING 'b1.1'
          +     24: U    SHORT_BINSTRING 'g1.1'
                30: q    BINPUT     2
                32: .    STOP
             highest protocol among opcodes = 2
          @@ -315,20 +196,8 @@ obj 0000000000000008 33 sha1:c37e1d2350c8fc4e18cdbc53b432dba50e5196ba
           txn 0285cbad10369d66 " "
           user "user1.2"
           description "step 1.2"
          -extension
          -      0: \x80 PROTO      2
          -      2: }    EMPTY_DICT
          -      3: q    BINPUT     1
          -      5: (    MARK
          -      6: U        SHORT_BINSTRING 'x-cookieY'
          -     17: U        SHORT_BINSTRING 'A01OK'
          -     24: U        SHORT_BINSTRING 'x-generator'
          -     37: q        BINPUT     2
          -     39: U        SHORT_BINSTRING 'zodb/py2 (g)'
          -     53: u        SETITEMS   (MARK at 5)
          -     54: .    STOP
          -  highest protocol among opcodes = 2
          -obj 0000000000000003 33 sha1:28e9880fc0f50a9fea5c4a9e861adc1fe44c9f5c
          +extension ""
          +obj 0000000000000006 33 sha1:28e9880fc0f50a9fea5c4a9e861adc1fe44c9f5c
                 0: \x80 PROTO      2
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
          @@ -344,27 +213,15 @@ obj 0000000000000003 33 sha1:28e9880fc0f50a9fea5c4a9e861adc1fe44c9f5c
           txn 0285cbad14e81bb3 " "
           user "user1.3"
           description "step 1.3"
          -extension
          -      0: \x80 PROTO      2
          -      2: }    EMPTY_DICT
          -      3: q    BINPUT     1
          -      5: (    MARK
          -      6: U        SHORT_BINSTRING 'x-generator'
          -     19: q        BINPUT     2
          -     21: U        SHORT_BINSTRING 'zodb/py2 (g)'
          -     35: U        SHORT_BINSTRING 'x-cookieW'
          -     46: U        SHORT_BINSTRING '1QPNP'
          -     53: u        SETITEMS   (MARK at 5)
          -     54: .    STOP
          -  highest protocol among opcodes = 2
          -obj 0000000000000003 33 sha1:5fb466e36ea6f847b73ad7976def8ad60e00e766
          +extension ""
          +obj 0000000000000004 33 sha1:e8796affc44d563a09a2913907f91467a34498fc
                 0: \x80 PROTO      2
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      2
          -     24: U    SHORT_BINSTRING 'g1.3'
          +     24: U    SHORT_BINSTRING 'd1.3'
                30: q    BINPUT     2
                32: .    STOP
             highest protocol among opcodes = 2
          @@ -373,27 +230,15 @@ obj 0000000000000003 33 sha1:5fb466e36ea6f847b73ad7976def8ad60e00e766
           txn 0285cbad19999a00 " "
           user "user1.4"
           description "step 1.4"
          -extension
          -      0: \x80 PROTO      2
          -      2: }    EMPTY_DICT
          -      3: q    BINPUT     1
          -      5: (    MARK
          -      6: U        SHORT_BINSTRING 'x-cookieC'
          -     17: U        SHORT_BINSTRING 'J7L05'
          -     24: U        SHORT_BINSTRING 'x-generator'
          -     37: q        BINPUT     2
          -     39: U        SHORT_BINSTRING 'zodb/py2 (c)'
          -     53: u        SETITEMS   (MARK at 5)
          -     54: .    STOP
          -  highest protocol among opcodes = 2
          -obj 0000000000000007 33 sha1:90b0ffa657df9de708913a2cbbd454126fd9de15
          +extension ""
          +obj 0000000000000006 33 sha1:15a38343610d25057cd88521669671350eb0c0a8
                 0: \x80 PROTO      2
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      2
          -     24: U    SHORT_BINSTRING 'c1.4'
          +     24: U    SHORT_BINSTRING 'g1.4'
                30: q    BINPUT     2
                32: .    STOP
             highest protocol among opcodes = 2
          @@ -402,27 +247,15 @@ obj 0000000000000007 33 sha1:90b0ffa657df9de708913a2cbbd454126fd9de15
           txn 0285cbad1e4b184c " "
           user "user1.5"
           description "step 1.5"
          -extension
          -      0: \x80 PROTO      2
          -      2: }    EMPTY_DICT
          -      3: q    BINPUT     1
          -      5: (    MARK
          -      6: U        SHORT_BINSTRING 'x-cookieA'
          -     17: U        SHORT_BINSTRING 'CM15Z'
          -     24: U        SHORT_BINSTRING 'x-generator'
          -     37: q        BINPUT     2
          -     39: U        SHORT_BINSTRING 'zodb/py2 (f)'
          -     53: u        SETITEMS   (MARK at 5)
          -     54: .    STOP
          -  highest protocol among opcodes = 2
          -obj 0000000000000001 33 sha1:70b0a88b7652b82b82539800484dc7788277f32a
          +extension ""
          +obj 0000000000000003 33 sha1:0adf3b787e6814b6cc073bd51a42c3f18615a674
                 0: \x80 PROTO      2
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      2
          -     24: U    SHORT_BINSTRING 'f1.5'
          +     24: U    SHORT_BINSTRING 'b1.5'
                30: q    BINPUT     2
                32: .    STOP
             highest protocol among opcodes = 2
          @@ -431,27 +264,15 @@ obj 0000000000000001 33 sha1:70b0a88b7652b82b82539800484dc7788277f32a
           txn 0285cbad22fc9699 " "
           user "user1.6"
           description "step 1.6"
          -extension
          -      0: \x80 PROTO      2
          -      2: }    EMPTY_DICT
          -      3: q    BINPUT     1
          -      5: (    MARK
          -      6: U        SHORT_BINSTRING 'x-cookieI'
          -     17: U        SHORT_BINSTRING 'AH816'
          -     24: U        SHORT_BINSTRING 'x-generator'
          -     37: q        BINPUT     2
          -     39: U        SHORT_BINSTRING 'zodb/py2 (d)'
          -     53: u        SETITEMS   (MARK at 5)
          -     54: .    STOP
          -  highest protocol among opcodes = 2
          -obj 0000000000000002 33 sha1:e9018b0bc67c9de08becf1f1fe1a548ed263fb29
          +extension ""
          +obj 0000000000000001 33 sha1:4d811fcaaa707127f5f6f49dc368ffd2ebae1018
                 0: \x80 PROTO      2
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      2
          -     24: U    SHORT_BINSTRING 'd1.6'
          +     24: U    SHORT_BINSTRING 'f1.6'
                30: q    BINPUT     2
                32: .    STOP
             highest protocol among opcodes = 2
          @@ -460,27 +281,15 @@ obj 0000000000000002 33 sha1:e9018b0bc67c9de08becf1f1fe1a548ed263fb29
           txn 0285cbad27ae14e6 " "
           user "user1.7"
           description "step 1.7"
          -extension
          -      0: \x80 PROTO      2
          -      2: }    EMPTY_DICT
          -      3: q    BINPUT     1
          -      5: (    MARK
          -      6: U        SHORT_BINSTRING 'x-cookieU'
          -     17: U        SHORT_BINSTRING 'BE3WH'
          -     24: U        SHORT_BINSTRING 'x-generator'
          -     37: q        BINPUT     2
          -     39: U        SHORT_BINSTRING 'zodb/py2 (c)'
          -     53: u        SETITEMS   (MARK at 5)
          -     54: .    STOP
          -  highest protocol among opcodes = 2
          -obj 0000000000000007 33 sha1:0cd3f4b725517a5371429e2ef2f56ea54fe405fb
          +extension ""
          +obj 0000000000000004 33 sha1:4c3e1f41eebd1f56c0fef1f609d64e061a137f5a
                 0: \x80 PROTO      2
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      2
          -     24: U    SHORT_BINSTRING 'c1.7'
          +     24: U    SHORT_BINSTRING 'd1.7'
                30: q    BINPUT     2
                32: .    STOP
             highest protocol among opcodes = 2
          @@ -489,27 +298,77 @@ obj 0000000000000007 33 sha1:0cd3f4b725517a5371429e2ef2f56ea54fe405fb
           txn 0285cbad2c5f9333 " "
           user "user1.8"
           description "step 1.8"
          -extension
          +extension ""
          +obj 0000000000000000 213 sha1:8ccd62e915379b196be62bdb500c4019dfb7825f
                 0: \x80 PROTO      2
          -      2: }    EMPTY_DICT
          -      3: q    BINPUT     1
          -      5: (    MARK
          -      6: U        SHORT_BINSTRING 'x-generator'
          -     19: q        BINPUT     2
          -     21: U        SHORT_BINSTRING 'zodb/py2 (c)'
          -     35: U        SHORT_BINSTRING 'x-cookieW'
          -     46: U        SHORT_BINSTRING 'HPFAQ'
          -     53: u        SETITEMS   (MARK at 5)
          -     54: .    STOP
          +      2: c    GLOBAL     'persistent.mapping PersistentMapping'
          +     40: q    BINPUT     1
          +     42: .    STOP
          +  highest protocol among opcodes = 2
          +     43: \x80 PROTO      2
          +     45: }    EMPTY_DICT
          +     46: q    BINPUT     2
          +     48: U    SHORT_BINSTRING 'data'
          +     54: q    BINPUT     3
          +     56: }    EMPTY_DICT
          +     57: q    BINPUT     4
          +     59: (    MARK
          +     60: U        SHORT_BINSTRING 'a'
          +     63: U        SHORT_BINSTRING '\x00\x00\x00\x00\x00\x00\x00\x08'
          +     73: q        BINPUT     5
          +     75: c        GLOBAL     '__main__ Object'
          +     92: q        BINPUT     6
          +     94: \x86     TUPLE2
          +     95: Q        BINPERSID
          +     96: U        SHORT_BINSTRING 'c'
          +     99: U        SHORT_BINSTRING '\x00\x00\x00\x00\x00\x00\x00\x02'
          +    109: q        BINPUT     7
          +    111: h        BINGET     6
          +    113: \x86     TUPLE2
          +    114: Q        BINPERSID
          +    115: U        SHORT_BINSTRING 'b'
          +    118: U        SHORT_BINSTRING '\x00\x00\x00\x00\x00\x00\x00\x03'
          +    128: q        BINPUT     8
          +    130: h        BINGET     6
          +    132: \x86     TUPLE2
          +    133: Q        BINPERSID
          +    134: U        SHORT_BINSTRING 'e'
          +    137: U        SHORT_BINSTRING '\x00\x00\x00\x00\x00\x00\x00\x07'
          +    147: q        BINPUT     9
          +    149: h        BINGET     6
          +    151: \x86     TUPLE2
          +    152: Q        BINPERSID
          +    153: U        SHORT_BINSTRING 'd'
          +    156: U        SHORT_BINSTRING '\x00\x00\x00\x00\x00\x00\x00\x04'
          +    166: q        BINPUT     10
          +    168: h        BINGET     6
          +    170: \x86     TUPLE2
          +    171: Q        BINPERSID
          +    172: U        SHORT_BINSTRING 'g'
          +    175: U        SHORT_BINSTRING '\x00\x00\x00\x00\x00\x00\x00\x06'
          +    185: q        BINPUT     11
          +    187: h        BINGET     6
          +    189: \x86     TUPLE2
          +    190: Q        BINPERSID
          +    191: U        SHORT_BINSTRING 'f'
          +    194: U        SHORT_BINSTRING '\x00\x00\x00\x00\x00\x00\x00\x01'
          +    204: q        BINPUT     12
          +    206: h        BINGET     6
          +    208: \x86     TUPLE2
          +    209: Q        BINPERSID
          +    210: u        SETITEMS   (MARK at 59)
          +    211: s    SETITEM
          +    212: .    STOP
             highest protocol among opcodes = 2
          -obj 0000000000000007 33 sha1:13e366fb1d15d36a62099e6b835638407718229f
          +
          +obj 0000000000000008 33 sha1:7cffb67651540355d8467852ec6cabcb48d964aa
                 0: \x80 PROTO      2
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      2
          -     24: U    SHORT_BINSTRING 'c1.8'
          +     24: U    SHORT_BINSTRING 'a1.8'
                30: q    BINPUT     2
                32: .    STOP
             highest protocol among opcodes = 2
          @@ -518,27 +377,15 @@ obj 0000000000000007 33 sha1:13e366fb1d15d36a62099e6b835638407718229f
           txn 0285cbad31111180 " "
           user "user1.9"
           description "step 1.9"
          -extension
          -      0: \x80 PROTO      2
          -      2: }    EMPTY_DICT
          -      3: q    BINPUT     1
          -      5: (    MARK
          -      6: U        SHORT_BINSTRING 'x-cookieQ'
          -     17: U        SHORT_BINSTRING 'DZM23'
          -     24: U        SHORT_BINSTRING 'x-generator'
          -     37: q        BINPUT     2
          -     39: U        SHORT_BINSTRING 'zodb/py2 (e)'
          -     53: u        SETITEMS   (MARK at 5)
          -     54: .    STOP
          -  highest protocol among opcodes = 2
          -obj 0000000000000006 33 sha1:3ac37991a56061c7407cc093ee2a71eef4379131
          +extension ""
          +obj 0000000000000001 33 sha1:c32c4831eabc3a97810c4f925465c6093e4fb716
                 0: \x80 PROTO      2
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      2
          -     24: U    SHORT_BINSTRING 'e1.9'
          +     24: U    SHORT_BINSTRING 'f1.9'
                30: q    BINPUT     2
                32: .    STOP
             highest protocol among opcodes = 2
          @@ -547,27 +394,15 @@ obj 0000000000000006 33 sha1:3ac37991a56061c7407cc093ee2a71eef4379131
           txn 0285cbad35c28fcc " "
           user "user1.10"
           description "step 1.10"
          -extension
          -      0: \x80 PROTO      2
          -      2: }    EMPTY_DICT
          -      3: q    BINPUT     1
          -      5: (    MARK
          -      6: U        SHORT_BINSTRING 'x-cookieO'
          -     17: U        SHORT_BINSTRING 'EIGHL'
          -     24: U        SHORT_BINSTRING 'x-generator'
          -     37: q        BINPUT     2
          -     39: U        SHORT_BINSTRING 'zodb/py2 (a)'
          -     53: u        SETITEMS   (MARK at 5)
          -     54: .    STOP
          -  highest protocol among opcodes = 2
          -obj 0000000000000005 34 sha1:407cc5710a22f6c387df45aab613aa3673b221c6
          +extension ""
          +obj 0000000000000002 34 sha1:07fe4a745e127abf54f451d41fba5db7bd10ac9d
                 0: \x80 PROTO      2
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      2
          -     24: U    SHORT_BINSTRING 'a1.10'
          +     24: U    SHORT_BINSTRING 'c1.10'
                31: q    BINPUT     2
                33: .    STOP
             highest protocol among opcodes = 2
          @@ -576,27 +411,15 @@ obj 0000000000000005 34 sha1:407cc5710a22f6c387df45aab613aa3673b221c6
           txn 0285cbad3a740e19 " "
           user "user1.11"
           description "step 1.11"
          -extension
          -      0: \x80 PROTO      2
          -      2: }    EMPTY_DICT
          -      3: q    BINPUT     1
          -      5: (    MARK
          -      6: U        SHORT_BINSTRING 'x-cookie2'
          -     17: U        SHORT_BINSTRING 'Z9RFC'
          -     24: U        SHORT_BINSTRING 'x-generator'
          -     37: q        BINPUT     2
          -     39: U        SHORT_BINSTRING 'zodb/py2 (c)'
          -     53: u        SETITEMS   (MARK at 5)
          -     54: .    STOP
          -  highest protocol among opcodes = 2
          -obj 0000000000000007 34 sha1:88ab1add11652101077535c03b04e83fe4ddb88b
          +extension ""
          +obj 0000000000000001 34 sha1:2f0fc397cd9bdceb59cfb7e40b823ae3a81e2f7c
                 0: \x80 PROTO      2
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      2
          -     24: U    SHORT_BINSTRING 'c1.11'
          +     24: U    SHORT_BINSTRING 'f1.11'
                31: q    BINPUT     2
                33: .    STOP
             highest protocol among opcodes = 2
          @@ -605,20 +428,8 @@ obj 0000000000000007 34 sha1:88ab1add11652101077535c03b04e83fe4ddb88b
           txn 0285cbad3f258c66 " "
           user "user1.12"
           description "step 1.12"
          -extension
          -      0: \x80 PROTO      2
          -      2: }    EMPTY_DICT
          -      3: q    BINPUT     1
          -      5: (    MARK
          -      6: U        SHORT_BINSTRING 'x-cookie7'
          -     17: U        SHORT_BINSTRING 'WGO4E'
          -     24: U        SHORT_BINSTRING 'x-generator'
          -     37: q        BINPUT     2
          -     39: U        SHORT_BINSTRING 'zodb/py2 (e)'
          -     53: u        SETITEMS   (MARK at 5)
          -     54: .    STOP
          -  highest protocol among opcodes = 2
          -obj 0000000000000006 34 sha1:4808aef147f8ded08ffaae2ce04265506385e7f7
          +extension ""
          +obj 0000000000000007 34 sha1:4808aef147f8ded08ffaae2ce04265506385e7f7
                 0: \x80 PROTO      2
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
          @@ -634,27 +445,15 @@ obj 0000000000000006 34 sha1:4808aef147f8ded08ffaae2ce04265506385e7f7
           txn 0285cbad43d70ab3 " "
           user "user1.13"
           description "step 1.13"
          -extension
          -      0: \x80 PROTO      2
          -      2: }    EMPTY_DICT
          -      3: q    BINPUT     1
          -      5: (    MARK
          -      6: U        SHORT_BINSTRING 'x-cookie5'
          -     17: U        SHORT_BINSTRING '757DJ'
          -     24: U        SHORT_BINSTRING 'x-generator'
          -     37: q        BINPUT     2
          -     39: U        SHORT_BINSTRING 'zodb/py2 (g)'
          -     53: u        SETITEMS   (MARK at 5)
          -     54: .    STOP
          -  highest protocol among opcodes = 2
          -obj 0000000000000003 34 sha1:a9f47880096587b359fa7ea6a0fd213e800a24a4
          +extension ""
          +obj 0000000000000008 34 sha1:656d65291d6e34225fe2c8213c2241b390e7487a
                 0: \x80 PROTO      2
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      2
          -     24: U    SHORT_BINSTRING 'g1.13'
          +     24: U    SHORT_BINSTRING 'a1.13'
                31: q    BINPUT     2
                33: .    STOP
             highest protocol among opcodes = 2
          @@ -663,27 +462,15 @@ obj 0000000000000003 34 sha1:a9f47880096587b359fa7ea6a0fd213e800a24a4
           txn 0285cbad48888900 " "
           user "user1.14"
           description "step 1.14"
          -extension
          -      0: \x80 PROTO      2
          -      2: }    EMPTY_DICT
          -      3: q    BINPUT     1
          -      5: (    MARK
          -      6: U        SHORT_BINSTRING 'x-cookieX'
          -     17: U        SHORT_BINSTRING '5EOVH'
          -     24: U        SHORT_BINSTRING 'x-generator'
          -     37: q        BINPUT     2
          -     39: U        SHORT_BINSTRING 'zodb/py2 (g)'
          -     53: u        SETITEMS   (MARK at 5)
          -     54: .    STOP
          -  highest protocol among opcodes = 2
          -obj 0000000000000003 34 sha1:e5b3820378e102a61be2b5998ded3182c106c7db
          +extension ""
          +obj 0000000000000004 34 sha1:87a243d2e9bdd70a84129119894b7d25479f4abc
                 0: \x80 PROTO      2
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      2
          -     24: U    SHORT_BINSTRING 'g1.14'
          +     24: U    SHORT_BINSTRING 'd1.14'
                31: q    BINPUT     2
                33: .    STOP
             highest protocol among opcodes = 2
          @@ -692,27 +479,15 @@ obj 0000000000000003 34 sha1:e5b3820378e102a61be2b5998ded3182c106c7db
           txn 0285cbad4d3a074c " "
           user "user1.15"
           description "step 1.15"
          -extension
          -      0: \x80 PROTO      2
          -      2: }    EMPTY_DICT
          -      3: q    BINPUT     1
          -      5: (    MARK
          -      6: U        SHORT_BINSTRING 'x-cookieC'
          -     17: U        SHORT_BINSTRING 'HO7L7'
          -     24: U        SHORT_BINSTRING 'x-generator'
          -     37: q        BINPUT     2
          -     39: U        SHORT_BINSTRING 'zodb/py2 (d)'
          -     53: u        SETITEMS   (MARK at 5)
          -     54: .    STOP
          -  highest protocol among opcodes = 2
          -obj 0000000000000002 34 sha1:f136bac1befa0fbd1ebd50218f8d9afe00b9b0a5
          +extension ""
          +obj 0000000000000006 34 sha1:2e9ebc331bf53c095e9573de64a9b31f2b340b2f
                 0: \x80 PROTO      2
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      2
          -     24: U    SHORT_BINSTRING 'd1.15'
          +     24: U    SHORT_BINSTRING 'g1.15'
                31: q    BINPUT     2
                33: .    STOP
             highest protocol among opcodes = 2
          @@ -721,27 +496,15 @@ obj 0000000000000002 34 sha1:f136bac1befa0fbd1ebd50218f8d9afe00b9b0a5
           txn 0285cbad51eb8599 " "
           user "user1.16"
           description "step 1.16"
          -extension
          -      0: \x80 PROTO      2
          -      2: }    EMPTY_DICT
          -      3: q    BINPUT     1
          -      5: (    MARK
          -      6: U        SHORT_BINSTRING 'x-cookieU'
          -     17: U        SHORT_BINSTRING 'T159S'
          -     24: U        SHORT_BINSTRING 'x-generator'
          -     37: q        BINPUT     2
          -     39: U        SHORT_BINSTRING 'zodb/py2 (g)'
          -     53: u        SETITEMS   (MARK at 5)
          -     54: .    STOP
          -  highest protocol among opcodes = 2
          -obj 0000000000000003 34 sha1:778621ce5c5e97b65343b1ab0cc1a3ce5702fbc8
          +extension ""
          +obj 0000000000000003 34 sha1:86adb5f06801883ba2be7776f68bd8ab46b34dd8
                 0: \x80 PROTO      2
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      2
          -     24: U    SHORT_BINSTRING 'g1.16'
          +     24: U    SHORT_BINSTRING 'b1.16'
                31: q    BINPUT     2
                33: .    STOP
             highest protocol among opcodes = 2
          @@ -750,27 +513,15 @@ obj 0000000000000003 34 sha1:778621ce5c5e97b65343b1ab0cc1a3ce5702fbc8
           txn 0285cbad569d03e6 " "
           user "user1.17"
           description "step 1.17"
          -extension
          -      0: \x80 PROTO      2
          -      2: }    EMPTY_DICT
          -      3: q    BINPUT     1
          -      5: (    MARK
          -      6: U        SHORT_BINSTRING 'x-cookie8'
          -     17: U        SHORT_BINSTRING 'T23V1'
          -     24: U        SHORT_BINSTRING 'x-generator'
          -     37: q        BINPUT     2
          -     39: U        SHORT_BINSTRING 'zodb/py2 (f)'
          -     53: u        SETITEMS   (MARK at 5)
          -     54: .    STOP
          -  highest protocol among opcodes = 2
          -obj 0000000000000001 34 sha1:eb6d2d192f3d8fe47a1b2e8119d390ed580c3fb4
          +extension ""
          +obj 0000000000000002 34 sha1:033ab1c2cfacb42e1db63ec9fac8427c700cc3cb
                 0: \x80 PROTO      2
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      2
          -     24: U    SHORT_BINSTRING 'f1.17'
          +     24: U    SHORT_BINSTRING 'c1.17'
                31: q    BINPUT     2
                33: .    STOP
             highest protocol among opcodes = 2
          @@ -779,27 +530,15 @@ obj 0000000000000001 34 sha1:eb6d2d192f3d8fe47a1b2e8119d390ed580c3fb4
           txn 0285cbad5b4e8233 " "
           user "user1.18"
           description "step 1.18"
          -extension
          -      0: \x80 PROTO      2
          -      2: }    EMPTY_DICT
          -      3: q    BINPUT     1
          -      5: (    MARK
          -      6: U        SHORT_BINSTRING 'x-cookieY'
          -     17: U        SHORT_BINSTRING 'UB55N'
          -     24: U        SHORT_BINSTRING 'x-generator'
          -     37: q        BINPUT     2
          -     39: U        SHORT_BINSTRING 'zodb/py2 (a)'
          -     53: u        SETITEMS   (MARK at 5)
          -     54: .    STOP
          -  highest protocol among opcodes = 2
          -obj 0000000000000005 34 sha1:921682b323eb62f109d052bc1dfd4ffe0dbf79db
          +extension ""
          +obj 0000000000000006 34 sha1:11f0228fea479a8dacdda2351f2720d005c04b06
                 0: \x80 PROTO      2
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      2
          -     24: U    SHORT_BINSTRING 'a1.18'
          +     24: U    SHORT_BINSTRING 'g1.18'
                31: q    BINPUT     2
                33: .    STOP
             highest protocol among opcodes = 2
          @@ -808,27 +547,15 @@ obj 0000000000000005 34 sha1:921682b323eb62f109d052bc1dfd4ffe0dbf79db
           txn 0285cbad60000080 " "
           user "user1.19"
           description "step 1.19"
          -extension
          -      0: \x80 PROTO      2
          -      2: }    EMPTY_DICT
          -      3: q    BINPUT     1
          -      5: (    MARK
          -      6: U        SHORT_BINSTRING 'x-cookieZ'
          -     17: U        SHORT_BINSTRING 'IKOSR'
          -     24: U        SHORT_BINSTRING 'x-generator'
          -     37: q        BINPUT     2
          -     39: U        SHORT_BINSTRING 'zodb/py2 (g)'
          -     53: u        SETITEMS   (MARK at 5)
          -     54: .    STOP
          -  highest protocol among opcodes = 2
          -obj 0000000000000003 34 sha1:b0b31eb0b48548119153628eb3c6711d959e9f9b
          +extension ""
          +obj 0000000000000003 34 sha1:6f5ef8a80a64540885791a6b1e2d1a352ee91d1a
                 0: \x80 PROTO      2
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      2
          -     24: U    SHORT_BINSTRING 'g1.19'
          +     24: U    SHORT_BINSTRING 'b1.19'
                31: q    BINPUT     2
                33: .    STOP
             highest protocol among opcodes = 2
          @@ -837,27 +564,15 @@ obj 0000000000000003 34 sha1:b0b31eb0b48548119153628eb3c6711d959e9f9b
           txn 0285cbad64b17ecc " "
           user "user1.20"
           description "step 1.20"
          -extension
          -      0: \x80 PROTO      2
          -      2: }    EMPTY_DICT
          -      3: q    BINPUT     1
          -      5: (    MARK
          -      6: U        SHORT_BINSTRING 'x-cookieS'
          -     17: U        SHORT_BINSTRING '7JLTH'
          -     24: U        SHORT_BINSTRING 'x-generator'
          -     37: q        BINPUT     2
          -     39: U        SHORT_BINSTRING 'zodb/py2 (g)'
          -     53: u        SETITEMS   (MARK at 5)
          -     54: .    STOP
          -  highest protocol among opcodes = 2
          -obj 0000000000000003 34 sha1:6bfd3298d0bea74cfa3d1f01bb722e958e3f1520
          +extension ""
          +obj 0000000000000004 34 sha1:1c032191dab251d941e739b3703f42ed7e43b246
                 0: \x80 PROTO      2
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      2
          -     24: U    SHORT_BINSTRING 'g1.20'
          +     24: U    SHORT_BINSTRING 'd1.20'
                31: q    BINPUT     2
                33: .    STOP
             highest protocol among opcodes = 2
          @@ -866,27 +581,15 @@ obj 0000000000000003 34 sha1:6bfd3298d0bea74cfa3d1f01bb722e958e3f1520
           txn 0285cbad6962fd19 " "
           user "user1.21"
           description "step 1.21"
          -extension
          -      0: \x80 PROTO      2
          -      2: }    EMPTY_DICT
          -      3: q    BINPUT     1
          -      5: (    MARK
          -      6: U        SHORT_BINSTRING 'x-cookieI'
          -     17: U        SHORT_BINSTRING 'USN06'
          -     24: U        SHORT_BINSTRING 'x-generator'
          -     37: q        BINPUT     2
          -     39: U        SHORT_BINSTRING 'zodb/py2 (e)'
          -     53: u        SETITEMS   (MARK at 5)
          -     54: .    STOP
          -  highest protocol among opcodes = 2
          -obj 0000000000000006 34 sha1:0d4b4837500e84b190ea2f92b16ab8ec0c486db5
          +extension ""
          +obj 0000000000000003 34 sha1:d90118a669a7a9dbe6b779bcc61110df0cc97fd1
                 0: \x80 PROTO      2
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      2
          -     24: U    SHORT_BINSTRING 'e1.21'
          +     24: U    SHORT_BINSTRING 'b1.21'
                31: q    BINPUT     2
                33: .    STOP
             highest protocol among opcodes = 2
          @@ -895,27 +598,15 @@ obj 0000000000000006 34 sha1:0d4b4837500e84b190ea2f92b16ab8ec0c486db5
           txn 0285cbad6e147b66 " "
           user "user1.22"
           description "step 1.22"
          -extension
          -      0: \x80 PROTO      2
          -      2: }    EMPTY_DICT
          -      3: q    BINPUT     1
          -      5: (    MARK
          -      6: U        SHORT_BINSTRING 'x-cookie2'
          -     17: U        SHORT_BINSTRING 'UXAET'
          -     24: U        SHORT_BINSTRING 'x-generator'
          -     37: q        BINPUT     2
          -     39: U        SHORT_BINSTRING 'zodb/py2 (a)'
          -     53: u        SETITEMS   (MARK at 5)
          -     54: .    STOP
          -  highest protocol among opcodes = 2
          -obj 0000000000000005 34 sha1:eacbd02d0d78eece9d784da7f3fd0b2738ca6ce0
          +extension ""
          +obj 0000000000000006 34 sha1:cd7d6434b0aa8290342b60c85d7378cda0d19734
                 0: \x80 PROTO      2
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      2
          -     24: U    SHORT_BINSTRING 'a1.22'
          +     24: U    SHORT_BINSTRING 'g1.22'
                31: q    BINPUT     2
                33: .    STOP
             highest protocol among opcodes = 2
          @@ -924,27 +615,15 @@ obj 0000000000000005 34 sha1:eacbd02d0d78eece9d784da7f3fd0b2738ca6ce0
           txn 0285cbad72c5f9b3 " "
           user "user1.23"
           description "step 1.23"
          -extension
          -      0: \x80 PROTO      2
          -      2: }    EMPTY_DICT
          -      3: q    BINPUT     1
          -      5: (    MARK
          -      6: U        SHORT_BINSTRING 'x-cookieH'
          -     17: U        SHORT_BINSTRING 'AT11F'
          -     24: U        SHORT_BINSTRING 'x-generator'
          -     37: q        BINPUT     2
          -     39: U        SHORT_BINSTRING 'zodb/py2 (a)'
          -     53: u        SETITEMS   (MARK at 5)
          -     54: .    STOP
          -  highest protocol among opcodes = 2
          -obj 0000000000000005 34 sha1:1b443228d5a434ddd9616ecb5aa90672c0ce9ba2
          +extension ""
          +obj 0000000000000001 34 sha1:230c0adc97facea312cd09aeb825f9a6c953e029
                 0: \x80 PROTO      2
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      2
          -     24: U    SHORT_BINSTRING 'a1.23'
          +     24: U    SHORT_BINSTRING 'f1.23'
                31: q    BINPUT     2
                33: .    STOP
             highest protocol among opcodes = 2
          @@ -953,27 +632,15 @@ obj 0000000000000005 34 sha1:1b443228d5a434ddd9616ecb5aa90672c0ce9ba2
           txn 0285cbad77777800 " "
           user "user1.24"
           description "step 1.24"
          -extension
          -      0: \x80 PROTO      2
          -      2: }    EMPTY_DICT
          -      3: q    BINPUT     1
          -      5: (    MARK
          -      6: U        SHORT_BINSTRING 'x-cookieD'
          -     17: U        SHORT_BINSTRING 'O5ZEM'
          -     24: U        SHORT_BINSTRING 'x-generator'
          -     37: q        BINPUT     2
          -     39: U        SHORT_BINSTRING 'zodb/py2 (f)'
          -     53: u        SETITEMS   (MARK at 5)
          -     54: .    STOP
          -  highest protocol among opcodes = 2
          -obj 0000000000000001 34 sha1:b35a1826cc6cb71b9ddff043f0e8f88b4d90281f
          +extension ""
          +obj 0000000000000004 34 sha1:ec728760e33cbafcd21496354cbe752995dc02c4
                 0: \x80 PROTO      2
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      2
          -     24: U    SHORT_BINSTRING 'f1.24'
          +     24: U    SHORT_BINSTRING 'd1.24'
                31: q    BINPUT     2
                33: .    STOP
             highest protocol among opcodes = 2
          @@ -982,63 +649,27 @@ obj 0000000000000001 34 sha1:b35a1826cc6cb71b9ddff043f0e8f88b4d90281f
           txn 0285cbad7c28f64c " "
           user "root1.0\nYour\nMagesty "
           description "undo 1.0\nmore detailed description\n\nzzz ...\t"
          -extension
          -      0: \x80 PROTO      2
          -      2: }    EMPTY_DICT
          -      3: q    BINPUT     1
          -      5: (    MARK
          -      6: U        SHORT_BINSTRING 'x-cookie3'
          -     17: U        SHORT_BINSTRING 'G51MM'
          -     24: U        SHORT_BINSTRING 'x-generator'
          -     37: q        BINPUT     2
          -     39: U        SHORT_BINSTRING 'zodb/py2 (undo AoXLrXLF+bM=)'
          -     69: u        SETITEMS   (MARK at 5)
          -     70: .    STOP
          -  highest protocol among opcodes = 2
          -obj 0000000000000005 from 0285cbad6e147b66
          +extension ""
          +obj 0000000000000001 from 0285cbad3a740e19
      
           txn 0285cbad80da7499 " "
           user "root1.1\nYour\nMagesty "
           description "undo 1.1\nmore detailed description\n\nzzz ...\t\t"
          -extension
          -      0: \x80 PROTO      2
          -      2: }    EMPTY_DICT
          -      3: q    BINPUT     1
          -      5: (    MARK
          -      6: U        SHORT_BINSTRING 'x-cookieL'
          -     17: U        SHORT_BINSTRING 'CDRHV'
          -     24: U        SHORT_BINSTRING 'x-generator'
          -     37: q        BINPUT     2
          -     39: U        SHORT_BINSTRING 'zodb/py2 (undo AoXLrXd3eAA=)'
          -     69: u        SETITEMS   (MARK at 5)
          -     70: .    STOP
          -  highest protocol among opcodes = 2
          -obj 0000000000000001 from 0285cbad569d03e6
          +extension ""
          +obj 0000000000000004 from 0285cbad64b17ecc
      
           txn 0285cbad858bf2e6 " "
           user "user"
           description "cyclic reference"
          -extension
          -      0: \x80 PROTO      2
          -      2: }    EMPTY_DICT
          -      3: q    BINPUT     1
          -      5: (    MARK
          -      6: U        SHORT_BINSTRING 'x-cookie4'
          -     17: U        SHORT_BINSTRING 'C4OMS'
          -     24: U        SHORT_BINSTRING 'x-generator'
          -     37: q        BINPUT     2
          -     39: U        SHORT_BINSTRING 'zodb/py2 (cycle)'
          -     57: u        SETITEMS   (MARK at 5)
          -     58: .    STOP
          -  highest protocol among opcodes = 2
          -obj 0000000000000002 41 sha1:1e2e3ac81badec749c2082a08d205c06c6bb5119
          +extension ""
          +obj 0000000000000008 41 sha1:ecd78bff79e5e10c04d6a14c8277d3fd5baba3a2
                 0: \x80 PROTO      2
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      2
          -     24: U    SHORT_BINSTRING '\x00\x00\x00\x00\x00\x00\x00\x02'
          +     24: U    SHORT_BINSTRING '\x00\x00\x00\x00\x00\x00\x00\x08'
                34: q    BINPUT     2
                36: h    BINGET     1
                38: \x86 TUPLE2
          @@ -1051,7 +682,7 @@ txn 0285cbad8a3d7133 " "
           user ""
           description "predelete 3"
           extension ""
          -obj 0000000000000000 213 sha1:e278899979bad10d72962170790ea2a2f5865567
          +obj 0000000000000000 213 sha1:e8e6e66cf82c7cbff72efb7bed28826296e51a01
                 0: \x80 PROTO      2
                 2: c    GLOBAL     'persistent.mapping PersistentMapping'
                40: q    BINPUT     1
          @@ -1066,38 +697,38 @@ obj 0000000000000000 213 sha1:e278899979bad10d72962170790ea2a2f5865567
                57: q    BINPUT     4
                59: (    MARK
                60: U        SHORT_BINSTRING 'a'
          -     63: U        SHORT_BINSTRING '\x00\x00\x00\x00\x00\x00\x00\x05'
          +     63: U        SHORT_BINSTRING '\x00\x00\x00\x00\x00\x00\x00\x08'
                73: q        BINPUT     5
                75: c        GLOBAL     '__main__ Object'
                92: q        BINPUT     6
                94: \x86     TUPLE2
                95: Q        BINPERSID
                96: U        SHORT_BINSTRING 'c'
          -     99: U        SHORT_BINSTRING '\x00\x00\x00\x00\x00\x00\x00\x07'
          +     99: U        SHORT_BINSTRING '\x00\x00\x00\x00\x00\x00\x00\x02'
               109: q        BINPUT     7
               111: h        BINGET     6
               113: \x86     TUPLE2
               114: Q        BINPERSID
               115: U        SHORT_BINSTRING 'b'
          -    118: U        SHORT_BINSTRING '\x00\x00\x00\x00\x00\x00\x00\x08'
          +    118: U        SHORT_BINSTRING '\x00\x00\x00\x00\x00\x00\x00\t'
               128: q        BINPUT     8
               130: h        BINGET     6
               132: \x86     TUPLE2
               133: Q        BINPERSID
               134: U        SHORT_BINSTRING 'e'
          -    137: U        SHORT_BINSTRING '\x00\x00\x00\x00\x00\x00\x00\x06'
          +    137: U        SHORT_BINSTRING '\x00\x00\x00\x00\x00\x00\x00\x07'
               147: q        BINPUT     9
               149: h        BINGET     6
               151: \x86     TUPLE2
               152: Q        BINPERSID
               153: U        SHORT_BINSTRING 'd'
          -    156: U        SHORT_BINSTRING '\x00\x00\x00\x00\x00\x00\x00\x02'
          +    156: U        SHORT_BINSTRING '\x00\x00\x00\x00\x00\x00\x00\x04'
               166: q        BINPUT     10
               168: h        BINGET     6
               170: \x86     TUPLE2
               171: Q        BINPERSID
               172: U        SHORT_BINSTRING 'g'
          -    175: U        SHORT_BINSTRING '\x00\x00\x00\x00\x00\x00\x00\t'
          +    175: U        SHORT_BINSTRING '\x00\x00\x00\x00\x00\x00\x00\x06'
               185: q        BINPUT     11
               187: h        BINGET     6
               189: \x86     TUPLE2
          @@ -1113,14 +744,14 @@ obj 0000000000000000 213 sha1:e278899979bad10d72962170790ea2a2f5865567
               212: .    STOP
             highest protocol among opcodes = 2
      
          -obj 0000000000000009 32 sha1:38aaea7061f311a5ff41e144ea56df2c8f66435c
          +obj 0000000000000009 32 sha1:94f4c80027cdf77affb7dd9f26b634975b4619e4
                 0: \x80 PROTO      2
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      2
          -     24: U    SHORT_BINSTRING 'g1*'
          +     24: U    SHORT_BINSTRING 'b1*'
                29: q    BINPUT     2
                31: .    STOP
             highest protocol among opcodes = 2
          @@ -1129,45 +760,21 @@ obj 0000000000000009 32 sha1:38aaea7061f311a5ff41e144ea56df2c8f66435c
           txn 0285cbad8eeeef80 " "
           user "root1\nYour\nRoyal\nMagesty' \x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
           description "delete 1\nalpha beta gamma'delta\"lambda\n\nqqq ..."
          -extension
          -      0: \x80 PROTO      2
          -      2: }    EMPTY_DICT
          -      3: q    BINPUT     1
          -      5: (    MARK
          -      6: U        SHORT_BINSTRING 'x-cookieS'
          -     17: U        SHORT_BINSTRING 'XVOTI'
          -     24: U        SHORT_BINSTRING 'x-generator'
          -     37: q        BINPUT     2
          -     39: U        SHORT_BINSTRING 'zodb/py2 (delete 3)'
          -     60: u        SETITEMS   (MARK at 5)
          -     61: .    STOP
          -  highest protocol among opcodes = 2
          +extension ""
           obj 0000000000000003 delete
      
           txn 0285cbadcbf25966 " "
           user "user2.0"
           description "step 2.0"
          -extension
          -      0: \x80 PROTO      2
          -      2: }    EMPTY_DICT
          -      3: q    BINPUT     1
          -      5: (    MARK
          -      6: U        SHORT_BINSTRING 'x-cookie1'
          -     17: U        SHORT_BINSTRING 'GRGS2'
          -     24: U        SHORT_BINSTRING 'x-generator'
          -     37: q        BINPUT     2
          -     39: U        SHORT_BINSTRING 'zodb/py2 (f)'
          -     53: u        SETITEMS   (MARK at 5)
          -     54: .    STOP
          -  highest protocol among opcodes = 2
          -obj 0000000000000001 33 sha1:7b5599bdbf192e2d33e2597b52c8a72a751ddd13
          +extension ""
          +obj 0000000000000004 33 sha1:aff1248f33b29d65fe0b038d7dc11db007e2690d
                 0: \x80 PROTO      2
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      2
          -     24: U    SHORT_BINSTRING 'f2.0'
          +     24: U    SHORT_BINSTRING 'd2.0'
                30: q    BINPUT     2
                32: .    STOP
             highest protocol among opcodes = 2
          @@ -1176,27 +783,15 @@ obj 0000000000000001 33 sha1:7b5599bdbf192e2d33e2597b52c8a72a751ddd13
           txn 0285cbadd0a3d7b3 " "
           user "user2.1"
           description "step 2.1"
          -extension
          -      0: \x80 PROTO      2
          -      2: }    EMPTY_DICT
          -      3: q    BINPUT     1
          -      5: (    MARK
          -      6: U        SHORT_BINSTRING 'x-cookie3'
          -     17: U        SHORT_BINSTRING 'WYNK7'
          -     24: U        SHORT_BINSTRING 'x-generator'
          -     37: q        BINPUT     2
          -     39: U        SHORT_BINSTRING 'zodb/py2 (d)'
          -     53: u        SETITEMS   (MARK at 5)
          -     54: .    STOP
          -  highest protocol among opcodes = 2
          -obj 0000000000000002 33 sha1:50b0cf792f2fdc3fbfc5f47f148784924350e31c
          +extension ""
          +obj 0000000000000006 33 sha1:2a2f21f6f3480aef6afd1398bec7f6bffa43109c
                 0: \x80 PROTO      2
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      2
          -     24: U    SHORT_BINSTRING 'd2.1'
          +     24: U    SHORT_BINSTRING 'g2.1'
                30: q    BINPUT     2
                32: .    STOP
             highest protocol among opcodes = 2
          @@ -1205,27 +800,15 @@ obj 0000000000000002 33 sha1:50b0cf792f2fdc3fbfc5f47f148784924350e31c
           txn 0285cbadd5555600 " "
           user "user2.2"
           description "step 2.2"
          -extension
          -      0: \x80 PROTO      2
          -      2: }    EMPTY_DICT
          -      3: q    BINPUT     1
          -      5: (    MARK
          -      6: U        SHORT_BINSTRING 'x-cookieF'
          -     17: U        SHORT_BINSTRING 'SPFA4'
          -     24: U        SHORT_BINSTRING 'x-generator'
          -     37: q        BINPUT     2
          -     39: U        SHORT_BINSTRING 'zodb/py2 (g)'
          -     53: u        SETITEMS   (MARK at 5)
          -     54: .    STOP
          -  highest protocol among opcodes = 2
          -obj 0000000000000009 33 sha1:71f1255a9751e0f223f079552e182cf26b27c0a6
          +extension ""
          +obj 0000000000000008 33 sha1:07e79c0eb72eea524bbfbce530b0671a4f90f483
                 0: \x80 PROTO      2
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      2
          -     24: U    SHORT_BINSTRING 'g2.2'
          +     24: U    SHORT_BINSTRING 'a2.2'
                30: q    BINPUT     2
                32: .    STOP
             highest protocol among opcodes = 2
          @@ -1234,27 +817,15 @@ obj 0000000000000009 33 sha1:71f1255a9751e0f223f079552e182cf26b27c0a6
           txn 0285cbadda06d44c " "
           user "user2.3"
           description "step 2.3"
          -extension
          -      0: \x80 PROTO      2
          -      2: }    EMPTY_DICT
          -      3: q    BINPUT     1
          -      5: (    MARK
          -      6: U        SHORT_BINSTRING 'x-cookie1'
          -     17: U        SHORT_BINSTRING 'XE3RQ'
          -     24: U        SHORT_BINSTRING 'x-generator'
          -     37: q        BINPUT     2
          -     39: U        SHORT_BINSTRING 'zodb/py2 (g)'
          -     53: u        SETITEMS   (MARK at 5)
          -     54: .    STOP
          -  highest protocol among opcodes = 2
          -obj 0000000000000009 33 sha1:e6236b8f0a4a2201c0c2375a8f360905108eff2d
          +extension ""
          +obj 0000000000000004 33 sha1:9985268077ca849a615e15ed1b37634875749695
                 0: \x80 PROTO      2
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      2
          -     24: U    SHORT_BINSTRING 'g2.3'
          +     24: U    SHORT_BINSTRING 'd2.3'
                30: q    BINPUT     2
                32: .    STOP
             highest protocol among opcodes = 2
          @@ -1263,20 +834,8 @@ obj 0000000000000009 33 sha1:e6236b8f0a4a2201c0c2375a8f360905108eff2d
           txn 0285cbaddeb85299 " "
           user "user2.4"
           description "step 2.4"
          -extension
          -      0: \x80 PROTO      2
          -      2: }    EMPTY_DICT
          -      3: q    BINPUT     1
          -      5: (    MARK
          -      6: U        SHORT_BINSTRING 'x-cookie2'
          -     17: U        SHORT_BINSTRING '1XYQ2'
          -     24: U        SHORT_BINSTRING 'x-generator'
          -     37: q        BINPUT     2
          -     39: U        SHORT_BINSTRING 'zodb/py2 (e)'
          -     53: u        SETITEMS   (MARK at 5)
          -     54: .    STOP
          -  highest protocol among opcodes = 2
          -obj 0000000000000006 33 sha1:55a37439e3dc66552d680833af332b8be83bfc2a
          +extension ""
          +obj 0000000000000007 33 sha1:55a37439e3dc66552d680833af332b8be83bfc2a
                 0: \x80 PROTO      2
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
          @@ -1292,27 +851,15 @@ obj 0000000000000006 33 sha1:55a37439e3dc66552d680833af332b8be83bfc2a
           txn 0285cbade369d0e6 " "
           user "user2.5"
           description "step 2.5"
          -extension
          -      0: \x80 PROTO      2
          -      2: }    EMPTY_DICT
          -      3: q    BINPUT     1
          -      5: (    MARK
          -      6: U        SHORT_BINSTRING 'x-cookieW'
          -     17: U        SHORT_BINSTRING 'C0ZT2'
          -     24: U        SHORT_BINSTRING 'x-generator'
          -     37: q        BINPUT     2
          -     39: U        SHORT_BINSTRING 'zodb/py2 (a)'
          -     53: u        SETITEMS   (MARK at 5)
          -     54: .    STOP
          -  highest protocol among opcodes = 2
          -obj 0000000000000005 33 sha1:6beb5d1ca083744ff1e8a13c0bee70c2df54a05c
          +extension ""
          +obj 0000000000000004 33 sha1:2e472bec634f703fc24e5192114b0c61364d9273
                 0: \x80 PROTO      2
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      2
          -     24: U    SHORT_BINSTRING 'a2.5'
          +     24: U    SHORT_BINSTRING 'd2.5'
                30: q    BINPUT     2
                32: .    STOP
             highest protocol among opcodes = 2
          @@ -1321,27 +868,15 @@ obj 0000000000000005 33 sha1:6beb5d1ca083744ff1e8a13c0bee70c2df54a05c
           txn 0285cbade81b4f33 " "
           user "user2.6"
           description "step 2.6"
          -extension
          -      0: \x80 PROTO      2
          -      2: }    EMPTY_DICT
          -      3: q    BINPUT     1
          -      5: (    MARK
          -      6: U        SHORT_BINSTRING 'x-cookie0'
          -     17: U        SHORT_BINSTRING 'OX40D'
          -     24: U        SHORT_BINSTRING 'x-generator'
          -     37: q        BINPUT     2
          -     39: U        SHORT_BINSTRING 'zodb/py2 (b)'
          -     53: u        SETITEMS   (MARK at 5)
          -     54: .    STOP
          -  highest protocol among opcodes = 2
          -obj 0000000000000008 33 sha1:2a3221e27ac8fbf15ab75b38a9a65e727d237355
          +extension ""
          +obj 0000000000000001 33 sha1:e0148787fb3ffe52ef3ba85ad82b6b8afa47e20f
                 0: \x80 PROTO      2
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      2
          -     24: U    SHORT_BINSTRING 'b2.6'
          +     24: U    SHORT_BINSTRING 'f2.6'
                30: q    BINPUT     2
                32: .    STOP
             highest protocol among opcodes = 2
          @@ -1350,27 +885,15 @@ obj 0000000000000008 33 sha1:2a3221e27ac8fbf15ab75b38a9a65e727d237355
           txn 0285cbadeccccd80 " "
           user "user2.7"
           description "step 2.7"
          -extension
          -      0: \x80 PROTO      2
          -      2: }    EMPTY_DICT
          -      3: q    BINPUT     1
          -      5: (    MARK
          -      6: U        SHORT_BINSTRING 'x-cookieY'
          -     17: U        SHORT_BINSTRING '64CY4'
          -     24: U        SHORT_BINSTRING 'x-generator'
          -     37: q        BINPUT     2
          -     39: U        SHORT_BINSTRING 'zodb/py2 (g)'
          -     53: u        SETITEMS   (MARK at 5)
          -     54: .    STOP
          -  highest protocol among opcodes = 2
          -obj 0000000000000009 33 sha1:408fddc8c7255c5e2ed94c239ac57c211ab94b6d
          +extension ""
          +obj 0000000000000004 33 sha1:9472357211e402a8dfcda8b72f7ef98c2b8d8b20
                 0: \x80 PROTO      2
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      2
          -     24: U    SHORT_BINSTRING 'g2.7'
          +     24: U    SHORT_BINSTRING 'd2.7'
                30: q    BINPUT     2
                32: .    STOP
             highest protocol among opcodes = 2
          @@ -1379,27 +902,15 @@ obj 0000000000000009 33 sha1:408fddc8c7255c5e2ed94c239ac57c211ab94b6d
           txn 0285cbadf17e4bcc " "
           user "user2.8"
           description "step 2.8"
          -extension
          -      0: \x80 PROTO      2
          -      2: }    EMPTY_DICT
          -      3: q    BINPUT     1
          -      5: (    MARK
          -      6: U        SHORT_BINSTRING 'x-cookieZ'
          -     17: U        SHORT_BINSTRING 'AXYM6'
          -     24: U        SHORT_BINSTRING 'x-generator'
          -     37: q        BINPUT     2
          -     39: U        SHORT_BINSTRING 'zodb/py2 (d)'
          -     53: u        SETITEMS   (MARK at 5)
          -     54: .    STOP
          -  highest protocol among opcodes = 2
          -obj 0000000000000002 33 sha1:72eda0cdae0addbec9472e28b5a9a91ecdf41bbf
          +extension ""
          +obj 0000000000000006 33 sha1:d57709ac596de41959e36e1dd6902a853213267e
                 0: \x80 PROTO      2
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      2
          -     24: U    SHORT_BINSTRING 'd2.8'
          +     24: U    SHORT_BINSTRING 'g2.8'
                30: q    BINPUT     2
                32: .    STOP
             highest protocol among opcodes = 2
          @@ -1408,20 +919,8 @@ obj 0000000000000002 33 sha1:72eda0cdae0addbec9472e28b5a9a91ecdf41bbf
           txn 0285cbadf62fca19 " "
           user "user2.9"
           description "step 2.9"
          -extension
          -      0: \x80 PROTO      2
          -      2: }    EMPTY_DICT
          -      3: q    BINPUT     1
          -      5: (    MARK
          -      6: U        SHORT_BINSTRING 'x-cookie8'
          -     17: U        SHORT_BINSTRING '5WYSB'
          -     24: U        SHORT_BINSTRING 'x-generator'
          -     37: q        BINPUT     2
          -     39: U        SHORT_BINSTRING 'zodb/py2 (e)'
          -     53: u        SETITEMS   (MARK at 5)
          -     54: .    STOP
          -  highest protocol among opcodes = 2
          -obj 0000000000000006 33 sha1:f1d87ba386f57291ecc925020a05df06caedb278
          +extension ""
          +obj 0000000000000007 33 sha1:f1d87ba386f57291ecc925020a05df06caedb278
                 0: \x80 PROTO      2
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
          @@ -1437,27 +936,15 @@ obj 0000000000000006 33 sha1:f1d87ba386f57291ecc925020a05df06caedb278
           txn 0285cbadfae14866 " "
           user "user2.10"
           description "step 2.10"
          -extension
          -      0: \x80 PROTO      2
          -      2: }    EMPTY_DICT
          -      3: q    BINPUT     1
          -      5: (    MARK
          -      6: U        SHORT_BINSTRING 'x-cookie2'
          -     17: U        SHORT_BINSTRING 'F1402'
          -     24: U        SHORT_BINSTRING 'x-generator'
          -     37: q        BINPUT     2
          -     39: U        SHORT_BINSTRING 'zodb/py2 (c)'
          -     53: u        SETITEMS   (MARK at 5)
          -     54: .    STOP
          -  highest protocol among opcodes = 2
          -obj 0000000000000007 34 sha1:6696fa0434fadb645687c74c8561f0f55fce1fd6
          +extension ""
          +obj 0000000000000007 34 sha1:5118b5ada1ab6ce6852eef392212ea9300ac6f06
                 0: \x80 PROTO      2
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      2
          -     24: U    SHORT_BINSTRING 'c2.10'
          +     24: U    SHORT_BINSTRING 'e2.10'
                31: q    BINPUT     2
                33: .    STOP
             highest protocol among opcodes = 2
          @@ -1466,20 +953,8 @@ obj 0000000000000007 34 sha1:6696fa0434fadb645687c74c8561f0f55fce1fd6
           txn 0285cbadff92c6b3 " "
           user "user2.11"
           description "step 2.11"
          -extension
          -      0: \x80 PROTO      2
          -      2: }    EMPTY_DICT
          -      3: q    BINPUT     1
          -      5: (    MARK
          -      6: U        SHORT_BINSTRING 'x-cookieG'
          -     17: U        SHORT_BINSTRING 'Q5FM3'
          -     24: U        SHORT_BINSTRING 'x-generator'
          -     37: q        BINPUT     2
          -     39: U        SHORT_BINSTRING 'zodb/py2 (d)'
          -     53: u        SETITEMS   (MARK at 5)
          -     54: .    STOP
          -  highest protocol among opcodes = 2
          -obj 0000000000000002 34 sha1:14e8b27b3bc8bf5b4d86ca162cc1c912a29a1c05
          +extension ""
          +obj 0000000000000004 34 sha1:14e8b27b3bc8bf5b4d86ca162cc1c912a29a1c05
                 0: \x80 PROTO      2
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
          @@ -1495,27 +970,15 @@ obj 0000000000000002 34 sha1:14e8b27b3bc8bf5b4d86ca162cc1c912a29a1c05
           txn 0285cbae04444500 " "
           user "user2.12"
           description "step 2.12"
          -extension
          -      0: \x80 PROTO      2
          -      2: }    EMPTY_DICT
          -      3: q    BINPUT     1
          -      5: (    MARK
          -      6: U        SHORT_BINSTRING 'x-cookie7'
          -     17: U        SHORT_BINSTRING '2EFQB'
          -     24: U        SHORT_BINSTRING 'x-generator'
          -     37: q        BINPUT     2
          -     39: U        SHORT_BINSTRING 'zodb/py2 (g)'
          -     53: u        SETITEMS   (MARK at 5)
          -     54: .    STOP
          -  highest protocol among opcodes = 2
          -obj 0000000000000009 34 sha1:db269b90a0df33aa7d411c672f93fb7d86bbdb87
          +extension ""
          +obj 0000000000000007 34 sha1:60c6854b7737f5bbc7569c8b6a694910ed370ccc
                 0: \x80 PROTO      2
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      2
          -     24: U    SHORT_BINSTRING 'g2.12'
          +     24: U    SHORT_BINSTRING 'e2.12'
                31: q    BINPUT     2
                33: .    STOP
             highest protocol among opcodes = 2
          @@ -1524,27 +987,15 @@ obj 0000000000000009 34 sha1:db269b90a0df33aa7d411c672f93fb7d86bbdb87
           txn 0285cbae08f5c34c " "
           user "user2.13"
           description "step 2.13"
          -extension
          -      0: \x80 PROTO      2
          -      2: }    EMPTY_DICT
          -      3: q    BINPUT     1
          -      5: (    MARK
          -      6: U        SHORT_BINSTRING 'x-cookieS'
          -     17: U        SHORT_BINSTRING 'YS9KO'
          -     24: U        SHORT_BINSTRING 'x-generator'
          -     37: q        BINPUT     2
          -     39: U        SHORT_BINSTRING 'zodb/py2 (d)'
          -     53: u        SETITEMS   (MARK at 5)
          -     54: .    STOP
          -  highest protocol among opcodes = 2
          -obj 0000000000000002 34 sha1:4b28f9e97ff4f61f3dfba30b9f7aceb4913215ce
          +extension ""
          +obj 0000000000000002 34 sha1:5d89801d288c5238f605784e7c71b2d61598d362
                 0: \x80 PROTO      2
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      2
          -     24: U    SHORT_BINSTRING 'd2.13'
          +     24: U    SHORT_BINSTRING 'c2.13'
                31: q    BINPUT     2
                33: .    STOP
             highest protocol among opcodes = 2
          @@ -1553,27 +1004,15 @@ obj 0000000000000002 34 sha1:4b28f9e97ff4f61f3dfba30b9f7aceb4913215ce
           txn 0285cbae0da74199 " "
           user "user2.14"
           description "step 2.14"
          -extension
          -      0: \x80 PROTO      2
          -      2: }    EMPTY_DICT
          -      3: q    BINPUT     1
          -      5: (    MARK
          -      6: U        SHORT_BINSTRING 'x-cookie5'
          -     17: U        SHORT_BINSTRING 'RF8GX'
          -     24: U        SHORT_BINSTRING 'x-generator'
          -     37: q        BINPUT     2
          -     39: U        SHORT_BINSTRING 'zodb/py2 (c)'
          -     53: u        SETITEMS   (MARK at 5)
          -     54: .    STOP
          -  highest protocol among opcodes = 2
          -obj 0000000000000007 34 sha1:c3eabecf360015b4b7555abc3a0dc0cea77fe7ed
          +extension ""
          +obj 0000000000000007 34 sha1:0a27d685d77313b1a2b7c3478888a98798847077
                 0: \x80 PROTO      2
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      2
          -     24: U    SHORT_BINSTRING 'c2.14'
          +     24: U    SHORT_BINSTRING 'e2.14'
                31: q    BINPUT     2
                33: .    STOP
             highest protocol among opcodes = 2
          @@ -1582,27 +1021,15 @@ obj 0000000000000007 34 sha1:c3eabecf360015b4b7555abc3a0dc0cea77fe7ed
           txn 0285cbae1258bfe6 " "
           user "user2.15"
           description "step 2.15"
          -extension
          -      0: \x80 PROTO      2
          -      2: }    EMPTY_DICT
          -      3: q    BINPUT     1
          -      5: (    MARK
          -      6: U        SHORT_BINSTRING 'x-cookie0'
          -     17: U        SHORT_BINSTRING 'H70PM'
          -     24: U        SHORT_BINSTRING 'x-generator'
          -     37: q        BINPUT     2
          -     39: U        SHORT_BINSTRING 'zodb/py2 (e)'
          -     53: u        SETITEMS   (MARK at 5)
          -     54: .    STOP
          -  highest protocol among opcodes = 2
          -obj 0000000000000006 34 sha1:25ffaeb6090581d72bce075a765d3cf4198af90f
          +extension ""
          +obj 0000000000000002 34 sha1:ae3975f91e13b4ec60e6810006be027149642926
                 0: \x80 PROTO      2
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      2
          -     24: U    SHORT_BINSTRING 'e2.15'
          +     24: U    SHORT_BINSTRING 'c2.15'
                31: q    BINPUT     2
                33: .    STOP
             highest protocol among opcodes = 2
          @@ -1611,27 +1038,15 @@ obj 0000000000000006 34 sha1:25ffaeb6090581d72bce075a765d3cf4198af90f
           txn 0285cbae170a3e33 " "
           user "user2.16"
           description "step 2.16"
          -extension
          -      0: \x80 PROTO      2
          -      2: }    EMPTY_DICT
          -      3: q    BINPUT     1
          -      5: (    MARK
          -      6: U        SHORT_BINSTRING 'x-generator'
          -     19: q        BINPUT     2
          -     21: U        SHORT_BINSTRING 'zodb/py2 (f)'
          -     35: U        SHORT_BINSTRING 'x-cookieO'
          -     46: U        SHORT_BINSTRING 'MJ5PG'
          -     53: u        SETITEMS   (MARK at 5)
          -     54: .    STOP
          -  highest protocol among opcodes = 2
          -obj 0000000000000001 34 sha1:e934438dede49d14ee2d1d2afa8fa18774547764
          +extension ""
          +obj 0000000000000009 34 sha1:0f253572ebd02bdd419b287ac75113bc8213ef83
                 0: \x80 PROTO      2
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      2
          -     24: U    SHORT_BINSTRING 'f2.16'
          +     24: U    SHORT_BINSTRING 'b2.16'
                31: q    BINPUT     2
                33: .    STOP
             highest protocol among opcodes = 2
          @@ -1640,20 +1055,8 @@ obj 0000000000000001 34 sha1:e934438dede49d14ee2d1d2afa8fa18774547764
           txn 0285cbae1bbbbc80 " "
           user "user2.17"
           description "step 2.17"
          -extension
          -      0: \x80 PROTO      2
          -      2: }    EMPTY_DICT
          -      3: q    BINPUT     1
          -      5: (    MARK
          -      6: U        SHORT_BINSTRING 'x-cookie1'
          -     17: U        SHORT_BINSTRING 'RAZ4V'
          -     24: U        SHORT_BINSTRING 'x-generator'
          -     37: q        BINPUT     2
          -     39: U        SHORT_BINSTRING 'zodb/py2 (b)'
          -     53: u        SETITEMS   (MARK at 5)
          -     54: .    STOP
          -  highest protocol among opcodes = 2
          -obj 0000000000000008 34 sha1:9961f82b3f01204f80efbb3b62a2b98d9d3202fa
          +extension ""
          +obj 0000000000000009 34 sha1:9961f82b3f01204f80efbb3b62a2b98d9d3202fa
                 0: \x80 PROTO      2
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
          @@ -1669,27 +1072,15 @@ obj 0000000000000008 34 sha1:9961f82b3f01204f80efbb3b62a2b98d9d3202fa
           txn 0285cbae206d3acc " "
           user "user2.18"
           description "step 2.18"
          -extension
          -      0: \x80 PROTO      2
          -      2: }    EMPTY_DICT
          -      3: q    BINPUT     1
          -      5: (    MARK
          -      6: U        SHORT_BINSTRING 'x-cookieR'
          -     17: U        SHORT_BINSTRING 'KE39A'
          -     24: U        SHORT_BINSTRING 'x-generator'
          -     37: q        BINPUT     2
          -     39: U        SHORT_BINSTRING 'zodb/py2 (d)'
          -     53: u        SETITEMS   (MARK at 5)
          -     54: .    STOP
          -  highest protocol among opcodes = 2
          -obj 0000000000000002 34 sha1:5294513e1e00c7de532f4f90068b2147bf87f673
          +extension ""
          +obj 0000000000000007 34 sha1:00cce52a596916011d8935c4e53dcb04510af2d9
                 0: \x80 PROTO      2
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      2
          -     24: U    SHORT_BINSTRING 'd2.18'
          +     24: U    SHORT_BINSTRING 'e2.18'
                31: q    BINPUT     2
                33: .    STOP
             highest protocol among opcodes = 2
          @@ -1698,20 +1089,8 @@ obj 0000000000000002 34 sha1:5294513e1e00c7de532f4f90068b2147bf87f673
           txn 0285cbae251eb919 " "
           user "user2.19"
           description "step 2.19"
          -extension
          -      0: \x80 PROTO      2
          -      2: }    EMPTY_DICT
          -      3: q    BINPUT     1
          -      5: (    MARK
          -      6: U        SHORT_BINSTRING 'x-cookie8'
          -     17: U        SHORT_BINSTRING '1SBCJ'
          -     24: U        SHORT_BINSTRING 'x-generator'
          -     37: q        BINPUT     2
          -     39: U        SHORT_BINSTRING 'zodb/py2 (e)'
          -     53: u        SETITEMS   (MARK at 5)
          -     54: .    STOP
          -  highest protocol among opcodes = 2
          -obj 0000000000000006 34 sha1:523ec17c6d74016e3464d52bb7c7b7baa4b82a20
          +extension ""
          +obj 0000000000000007 34 sha1:523ec17c6d74016e3464d52bb7c7b7baa4b82a20
                 0: \x80 PROTO      2
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
          @@ -1727,27 +1106,15 @@ obj 0000000000000006 34 sha1:523ec17c6d74016e3464d52bb7c7b7baa4b82a20
           txn 0285cbae29d03766 " "
           user "user2.20"
           description "step 2.20"
          -extension
          -      0: \x80 PROTO      2
          -      2: }    EMPTY_DICT
          -      3: q    BINPUT     1
          -      5: (    MARK
          -      6: U        SHORT_BINSTRING 'x-cookieJ'
          -     17: U        SHORT_BINSTRING 'EAIKM'
          -     24: U        SHORT_BINSTRING 'x-generator'
          -     37: q        BINPUT     2
          -     39: U        SHORT_BINSTRING 'zodb/py2 (b)'
          -     53: u        SETITEMS   (MARK at 5)
          -     54: .    STOP
          -  highest protocol among opcodes = 2
          -obj 0000000000000008 34 sha1:14b17f0e944432782cb270205b2e96948d112619
          +extension ""
          +obj 0000000000000004 34 sha1:9cf3a2031b4e9af93e7fd40e58dbceedc753b7d6
                 0: \x80 PROTO      2
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      2
          -     24: U    SHORT_BINSTRING 'b2.20'
          +     24: U    SHORT_BINSTRING 'd2.20'
                31: q    BINPUT     2
                33: .    STOP
             highest protocol among opcodes = 2
          @@ -1756,27 +1123,15 @@ obj 0000000000000008 34 sha1:14b17f0e944432782cb270205b2e96948d112619
           txn 0285cbae2e81b5b3 " "
           user "user2.21"
           description "step 2.21"
          -extension
          -      0: \x80 PROTO      2
          -      2: }    EMPTY_DICT
          -      3: q    BINPUT     1
          -      5: (    MARK
          -      6: U        SHORT_BINSTRING 'x-cookieM'
          -     17: U        SHORT_BINSTRING 'ESSAD'
          -     24: U        SHORT_BINSTRING 'x-generator'
          -     37: q        BINPUT     2
          -     39: U        SHORT_BINSTRING 'zodb/py2 (e)'
          -     53: u        SETITEMS   (MARK at 5)
          -     54: .    STOP
          -  highest protocol among opcodes = 2
          -obj 0000000000000006 34 sha1:27744ea516240e0d00be75f26af9698f842bdda5
          +extension ""
          +obj 0000000000000008 34 sha1:330a069412b6cfb00a43da001b600b7f6b2380e6
                 0: \x80 PROTO      2
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      2
          -     24: U    SHORT_BINSTRING 'e2.21'
          +     24: U    SHORT_BINSTRING 'a2.21'
                31: q    BINPUT     2
                33: .    STOP
             highest protocol among opcodes = 2
          @@ -1785,27 +1140,15 @@ obj 0000000000000006 34 sha1:27744ea516240e0d00be75f26af9698f842bdda5
           txn 0285cbae33333400 " "
           user "user2.22"
           description "step 2.22"
          -extension
          -      0: \x80 PROTO      2
          -      2: }    EMPTY_DICT
          -      3: q    BINPUT     1
          -      5: (    MARK
          -      6: U        SHORT_BINSTRING 'x-cookieH'
          -     17: U        SHORT_BINSTRING 'DL5OC'
          -     24: U        SHORT_BINSTRING 'x-generator'
          -     37: q        BINPUT     2
          -     39: U        SHORT_BINSTRING 'zodb/py2 (e)'
          -     53: u        SETITEMS   (MARK at 5)
          -     54: .    STOP
          -  highest protocol among opcodes = 2
          -obj 0000000000000006 34 sha1:a3f303ddd4f2fb9369f6fbbb38ae8030f7f8188d
          +extension ""
          +obj 0000000000000001 34 sha1:bf2d0d8f4cd81e1592001eb3c265a22894cdb51b
                 0: \x80 PROTO      2
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      2
          -     24: U    SHORT_BINSTRING 'e2.22'
          +     24: U    SHORT_BINSTRING 'f2.22'
                31: q    BINPUT     2
                33: .    STOP
             highest protocol among opcodes = 2
          @@ -1814,27 +1157,15 @@ obj 0000000000000006 34 sha1:a3f303ddd4f2fb9369f6fbbb38ae8030f7f8188d
           txn 0285cbae37e4b24c " "
           user "user2.23"
           description "step 2.23"
          -extension
          -      0: \x80 PROTO      2
          -      2: }    EMPTY_DICT
          -      3: q    BINPUT     1
          -      5: (    MARK
          -      6: U        SHORT_BINSTRING 'x-cookieQ'
          -     17: U        SHORT_BINSTRING 'PBN2A'
          -     24: U        SHORT_BINSTRING 'x-generator'
          -     37: q        BINPUT     2
          -     39: U        SHORT_BINSTRING 'zodb/py2 (d)'
          -     53: u        SETITEMS   (MARK at 5)
          -     54: .    STOP
          -  highest protocol among opcodes = 2
          -obj 0000000000000002 34 sha1:343bed4b31f4fe69a92ee51d28fd7b9cfd6ecb8b
          +extension ""
          +obj 0000000000000006 34 sha1:c47e0f1415e14f41016809ac3a4323745ad79170
                 0: \x80 PROTO      2
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      2
          -     24: U    SHORT_BINSTRING 'd2.23'
          +     24: U    SHORT_BINSTRING 'g2.23'
                31: q    BINPUT     2
                33: .    STOP
             highest protocol among opcodes = 2
          @@ -1843,84 +1174,36 @@ obj 0000000000000002 34 sha1:343bed4b31f4fe69a92ee51d28fd7b9cfd6ecb8b
           txn 0285cbae3c963099 " "
           user "user2.24"
           description "step 2.24"
          -extension
          -      0: \x80 PROTO      2
          -      2: }    EMPTY_DICT
          -      3: q    BINPUT     1
          -      5: (    MARK
          -      6: U        SHORT_BINSTRING 'x-cookie2'
          -     17: U        SHORT_BINSTRING '0GV0I'
          -     24: U        SHORT_BINSTRING 'x-generator'
          -     37: q        BINPUT     2
          -     39: U        SHORT_BINSTRING 'zodb/py2 (e)'
          -     53: u        SETITEMS   (MARK at 5)
          -     54: .    STOP
          -  highest protocol among opcodes = 2
          -obj 0000000000000006 34 sha1:8804c60dc27b2e2f6908e2a099a5c5d4b5abc843
          +extension ""
          +obj 0000000000000006 34 sha1:2030a0ccc56595b70aac033e70c899060dbfb0f9
                 0: \x80 PROTO      2
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      2
          -     24: U    SHORT_BINSTRING 'e2.24'
          +     24: U    SHORT_BINSTRING 'g2.24'
                31: q    BINPUT     2
                33: .    STOP
             highest protocol among opcodes = 2
      
          -txn 0285cbae4147aee6 " "
          +txn 0285cbae45f92d33 " "
           user "root2.0\nYour\nMagesty "
           description "undo 2.0\nmore detailed description\n\nzzz ...\t\t"
          -extension
          -      0: \x80 PROTO      2
          -      2: }    EMPTY_DICT
          -      3: q    BINPUT     1
          -      5: (    MARK
          -      6: U        SHORT_BINSTRING 'x-cookieM'
          -     17: U        SHORT_BINSTRING 'OQO01'
          -     24: U        SHORT_BINSTRING 'x-generator'
          -     37: q        BINPUT     2
          -     39: U        SHORT_BINSTRING 'zodb/py2 (undo AoXLrjfkskw=)'
          -     69: u        SETITEMS   (MARK at 5)
          -     70: .    STOP
          -  highest protocol among opcodes = 2
          -obj 0000000000000002 from 0285cbae206d3acc
          +extension ""
          +obj 0000000000000001 from 0285cbade81b4f33
      
          -txn 0285cbae45f92d33 " "
          +txn 0285cbae4aaaab80 " "
           user "root2.1\nYour\nMagesty "
           description "undo 2.1\nmore detailed description\n\nzzz ...\t\t\t"
          -extension
          -      0: \x80 PROTO      2
          -      2: }    EMPTY_DICT
          -      3: q    BINPUT     1
          -      5: (    MARK
          -      6: U        SHORT_BINSTRING 'x-cookieA'
          -     17: U        SHORT_BINSTRING 'VPQ8R'
          -     24: U        SHORT_BINSTRING 'x-generator'
          -     37: q        BINPUT     2
          -     39: U        SHORT_BINSTRING 'zodb/py2 (undo AoXLrjyWMJk=)'
          -     69: u        SETITEMS   (MARK at 5)
          -     70: .    STOP
          -  highest protocol among opcodes = 2
          -obj 0000000000000006 from 0285cbae33333400
          +extension ""
          +obj 0000000000000006 from 0285cbae37e4b24c
      
          -txn 0285cbae4aaaab80 " "
          +txn 0285cbae4f5c29cc " "
           user "user"
           description "cyclic reference"
          -extension
          -      0: \x80 PROTO      2
          -      2: }    EMPTY_DICT
          -      3: q    BINPUT     1
          -      5: (    MARK
          -      6: U        SHORT_BINSTRING 'x-generator'
          -     19: q        BINPUT     2
          -     21: U        SHORT_BINSTRING 'zodb/py2 (cycle)'
          -     39: U        SHORT_BINSTRING 'x-cookieG'
          -     50: U        SHORT_BINSTRING 'B6FWF'
          -     57: u        SETITEMS   (MARK at 5)
          -     58: .    STOP
          -  highest protocol among opcodes = 2
          +extension ""
           obj 0000000000000006 41 sha1:863d327e4b795efff7dff75bb73c0d20ea3981aa
                 0: \x80 PROTO      2
                 2: c    GLOBAL     '__main__ Object'
          @@ -1937,11 +1220,11 @@ obj 0000000000000006 41 sha1:863d327e4b795efff7dff75bb73c0d20ea3981aa
             highest protocol among opcodes = 2
      
          -txn 0285cbae4f5c29cc " "
          +txn 0285cbae540da819 " "
           user ""
          -description "predelete 6"
          +description "predelete 1"
           extension ""
          -obj 0000000000000000 213 sha1:b44d53e1b6cc465c4ab3ba2a3384a80fbba4eb8a
          +obj 0000000000000000 213 sha1:ae6936a4e7c9f3f748d8ecf28186e259897651dd
                 0: \x80 PROTO      2
                 2: c    GLOBAL     'persistent.mapping PersistentMapping'
                40: q    BINPUT     1
          @@ -1956,44 +1239,44 @@ obj 0000000000000000 213 sha1:b44d53e1b6cc465c4ab3ba2a3384a80fbba4eb8a
                57: q    BINPUT     4
                59: (    MARK
                60: U        SHORT_BINSTRING 'a'
          -     63: U        SHORT_BINSTRING '\x00\x00\x00\x00\x00\x00\x00\x05'
          +     63: U        SHORT_BINSTRING '\x00\x00\x00\x00\x00\x00\x00\x08'
                73: q        BINPUT     5
                75: c        GLOBAL     '__main__ Object'
                92: q        BINPUT     6
                94: \x86     TUPLE2
                95: Q        BINPERSID
                96: U        SHORT_BINSTRING 'c'
          -     99: U        SHORT_BINSTRING '\x00\x00\x00\x00\x00\x00\x00\x07'
          +     99: U        SHORT_BINSTRING '\x00\x00\x00\x00\x00\x00\x00\x02'
               109: q        BINPUT     7
               111: h        BINGET     6
               113: \x86     TUPLE2
               114: Q        BINPERSID
               115: U        SHORT_BINSTRING 'b'
          -    118: U        SHORT_BINSTRING '\x00\x00\x00\x00\x00\x00\x00\x08'
          +    118: U        SHORT_BINSTRING '\x00\x00\x00\x00\x00\x00\x00\t'
               128: q        BINPUT     8
               130: h        BINGET     6
               132: \x86     TUPLE2
               133: Q        BINPERSID
               134: U        SHORT_BINSTRING 'e'
          -    137: U        SHORT_BINSTRING '\x00\x00\x00\x00\x00\x00\x00\n'
          +    137: U        SHORT_BINSTRING '\x00\x00\x00\x00\x00\x00\x00\x07'
               147: q        BINPUT     9
               149: h        BINGET     6
               151: \x86     TUPLE2
               152: Q        BINPERSID
               153: U        SHORT_BINSTRING 'd'
          -    156: U        SHORT_BINSTRING '\x00\x00\x00\x00\x00\x00\x00\x02'
          +    156: U        SHORT_BINSTRING '\x00\x00\x00\x00\x00\x00\x00\x04'
               166: q        BINPUT     10
               168: h        BINGET     6
               170: \x86     TUPLE2
               171: Q        BINPERSID
               172: U        SHORT_BINSTRING 'g'
          -    175: U        SHORT_BINSTRING '\x00\x00\x00\x00\x00\x00\x00\t'
          +    175: U        SHORT_BINSTRING '\x00\x00\x00\x00\x00\x00\x00\x06'
               185: q        BINPUT     11
               187: h        BINGET     6
               189: \x86     TUPLE2
               190: Q        BINPERSID
               191: U        SHORT_BINSTRING 'f'
          -    194: U        SHORT_BINSTRING '\x00\x00\x00\x00\x00\x00\x00\x01'
          +    194: U        SHORT_BINSTRING '\x00\x00\x00\x00\x00\x00\x00\n'
               204: q        BINPUT     12
               206: h        BINGET     6
               208: \x86     TUPLE2
          @@ -2003,34 +1286,22 @@ obj 0000000000000000 213 sha1:b44d53e1b6cc465c4ab3ba2a3384a80fbba4eb8a
               212: .    STOP
             highest protocol among opcodes = 2
      
          -obj 000000000000000a 32 sha1:35a18f6ce20260014618957689b770b74d7b3c78
          +obj 000000000000000a 32 sha1:da5c7f574b5e6a64d0d58314a6939ef761266d41
                 0: \x80 PROTO      2
                 2: c    GLOBAL     '__main__ Object'
                19: q    BINPUT     1
                21: .    STOP
             highest protocol among opcodes = 2
                22: \x80 PROTO      2
          -     24: U    SHORT_BINSTRING 'e2*'
          +     24: U    SHORT_BINSTRING 'f2*'
                29: q    BINPUT     2
                31: .    STOP
             highest protocol among opcodes = 2
      
          -txn 0285cbae540da819 " "
          +txn 0285cbae58bf2666 " "
           user "root2\nYour\nRoyal\nMagesty' \x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
           description "delete 2\nalpha beta gamma'delta\"lambda\n\nqqq ..."
          -extension
          -      0: \x80 PROTO      2
          -      2: }    EMPTY_DICT
          -      3: q    BINPUT     1
          -      5: (    MARK
          -      6: U        SHORT_BINSTRING 'x-cookieT'
          -     17: U        SHORT_BINSTRING '4WFSD'
          -     24: U        SHORT_BINSTRING 'x-generator'
          -     37: q        BINPUT     2
          -     39: U        SHORT_BINSTRING 'zodb/py2 (delete 6)'
          -     60: u        SETITEMS   (MARK at 5)
          -     61: .    STOP
          -  highest protocol among opcodes = 2
          -obj 0000000000000006 delete
          +extension ""
          +obj 0000000000000001 delete
      395d8c27
  3. 26 Jun, 2024 1 commit
    • Kirill Smelkov's avatar
      zodbdump: Fix pickle disassembly if state part of zpickle refers to class part · fbb2a3d9
      Kirill Smelkov authored
      I've tried to run `zodb dump --pretty=zpickledis` on wendelin.core test
      data in WCFS(*) and hit the following failure:
      
          (z-dev) kirr@deca:~/src/wendelin/wendelin.core/wcfs/internal/zdata/testdata$ zodb dump --pretty=zpickledis zblk.fs
          ...
          obj 0000000000000005 685 sha1:865171b709f575b355afd2cc9e1f32b9781c6510
          Traceback (most recent call last):
            File "/home/kirr/src/wendelin/venv/z-dev/bin/zodb", line 11, in <module>
              load_entry_point('zodbtools', 'console_scripts', 'zodb')()
            File "/home/kirr/src/wendelin/z/zodbtools/zodbtools/zodb.py", line 129, in main
              return command_module.main(argv)
            File "<decorator-gen-3>", line 2, in main
            File "/home/kirr/src/wendelin/venv/z-dev/lib/python2.7/site-packages/golang/__init__.py", line 103, in _
              return f(*argv, **kw)
            File "/home/kirr/src/wendelin/z/zodbtools/zodbtools/zodbdump.py", line 341, in main
              zodbdump(stor, tidmin, tidmax, hashonly, pretty)
            File "/home/kirr/src/wendelin/z/zodbtools/zodbtools/zodbdump.py", line 167, in zodbdump
              pickletools.dis(dataf, disf) # state
            File "/usr/lib/python2.7/pickletools.py", line 2005, in dis
              raise ValueError(errormsg)
          ValueError: memo key 1 has never been stored into
      
      The problem turned out to be due to that state part of zpickle is
      referring to another object with the same class as already saved
      in class part of zpickle, so that class was being referred to via GET
      matching corresponding PUT done in the class part, but our zpickledis
      handler did not shared the memo in between those two parts and so the
      GET became unmatched.
      
      In more details the problem is illustrated by the following zpickle that
      corresponds to Object.value referring to the same Object. The first part
      of zpickle contains class part and refers to __main__.Object global
      with putting it into memo[1]. The second part of zpickle contains state
      part and refers to that object by `(Object, 7) PERSID` where Object is
      retrieved via memo[1] GET:
      
          obj 0000000000000007 41 sha1:7108c96ccb9cbeaab1164d533174c300e51309f9
                0: \x80 PROTO      2
                2: c    GLOBAL     '__main__ Object'
               19: q    BINPUT     1                   <-- NOTE
               21: .    STOP
            highest protocol among opcodes = 2
               22: \x80 PROTO      2
               24: U    SHORT_BINSTRING '\x00\x00\x00\x00\x00\x00\x00\x07'
               34: q    BINPUT     2
               36: h    BINGET     1                   <-- NOTE
               38: \x86 TUPLE2
               39: Q    BINPERSID
               40: .    STOP
            highest protocol among opcodes = 2
      
      To handle such zpickles well we need to share the memo when dumping
      class and state disassemblies similarly to how ZODB does in its
      ObjectWriter._dump:
      
      https://github.com/zopefoundation/ZODB/blob/5.8.1-0-g72cebe6bc/src/ZODB/serialize.py#L436-L443
      
      Pickletools.dis has explicit support for using shared memo - originally
      added in https://github.com/python/cpython/commit/62235e701e37 and
      likely motivated by ZODB use-case.
      
      (*) https://lab.nexedi.com/nexedi/wendelin.core/-/blob/07087ec8/wcfs/internal/zdata/testdata/zblk.fs
          generated by wendelin.core@2c152d41
      
      /reviewed-by @jerome
      /reviewed-on !28
      fbb2a3d9
  4. 16 Feb, 2024 1 commit
  5. 01 Sep, 2023 3 commits
    • Jérome Perrin's avatar
      zodbcommit: include the status of transaction · a9853038
      Jérome Perrin authored
      even though the interface of IStorageRestorable.tpc_begin does not
      have a "status" argument, it is described in the notes below that the
      actual implementation uses it:
      
      https://github.com/zopefoundation/ZODB/blob/0632974d/src/ZODB/interfaces.py#L950-L956
      
      This is used by FileStorage:
      
      https://github.com/zopefoundation/ZODB/blob/0632974d/src/ZODB/FileStorage/format.py#L30-L39
      
      and the storage methods seem to accept this argument:
      
      https://github.com/zopefoundation/ZODB/blob/0632974d/src/ZODB/BaseStorage.py#L182
      https://github.com/zopefoundation/ZEO/blob/e5637818/src/ZEO/ClientStorage.py#L888
      https://lab.nexedi.com/nexedi/neoppod/blob/fd87e153/neo/client/app.py#L473
      
      Propagating the status fixes some cases where restoring commits did not
      recreate a storage that is byte-to-byte equivalent. This happened with
      a FileStorage that was packed and contained transactions with "p"
      status.
      Co-authored-by: Kirill Smelkov's avatarKirill Smelkov <kirr@nexedi.com>
      Reviewed-on: !24
      a9853038
    • Kirill Smelkov's avatar
      test/gen_testdata: Generate transactions with both " " and "p" status · 1b480c93
      Kirill Smelkov authored
      Until now we were generating only regular transactions with " " status
      and this does not cover e.g. restore case when it needs to replicate
      packed transaction: instead of recreating it bit-to-bit exactly as
      original with "p" status, restore recreates it with " " status, breaking
      restore promise.
      
      Adjusting testdata this way exposes that bug in restore:
      
          ======================================== FAILURES ========================================
          ________________________________________ test_zodbrestore[!zext] ________________________________________
      
          tmpdir = local('/tmp/pytest-of-kirr/pytest-17/test_zodbrestore__zext_0'), zext = <function _ at 0x7fd6b7a03750>
      
              @func
              def test_zodbrestore(tmpdir, zext):
                  zkind = '_!zext' if zext.disabled else ''
      
                  # restore from testdata/1.zdump.ok and verify it gives result that is
                  # bit-to-bit identical to testdata/1.fs
                  tdata = dirname(__file__) + "/testdata"
                  @func
                  def _():
                      zdump = open("%s/1%s.zdump.raw.ok" % (tdata, zkind), 'rb')
                      defer(zdump.close)
      
                      stor = storageFromURL('%s/2.fs' % tmpdir)
                      defer(stor.close)
      
                      zodbrestore(stor, zdump)
                  _()
      
                  zfs1 = readfile(fs1_testdata_py23(tmpdir, "%s/1%s.fs" % (tdata, zkind)))
                  zfs2 = readfile("%s/2.fs" % tmpdir)
          >       assert zfs1 == zfs2
          E       assert 'FS21\x02\x85...0\x00\x00\xb2' == 'FS21\x02\x85\...0\x00\x00\xb2'
          E         Skipping 49 identical leading characters in diff, use -v to show
          E         Skipping 22871 identical trailing characters in diff, use -v to show
          E         - 0\x00\x00tp\x00\x08\x00\t\x00\x00user0.15step 0.15\x00\x00\x00\x00\x00\x00\x00\x03\x02\x85\xcb\xac\x83i\xd0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00"\x80\x02c__main__
          E         ?           ^
          E         + 0\x00\x00t \x00\x08\x00\t\x00\x00user0.15step 0.15\x00\x00\x00\x00\x00\x00\x00\x03\x02\x85\xcb\xac\x83i\xd0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00...
          E
          E         ...Full output truncated (39 lines hidden), use '-vv' to show
      
          test_restore.py:53: AssertionError
      
      Having "p" transactions in the testdata will also make sure that all tools
      should handle such transactions well.
      
      The problem of restore not handling "p" status properly was reported by Jérome
      at nexedi/zodbtools!24.
      
      In the next patch we will fix that problem.
      
      /reviewed-by @jerome
      /reviewed-on nexedi/zodbtools!24
      1b480c93
    • Kirill Smelkov's avatar
      test/gen_testdata: Adjust it to match current testdata/ state · 37786d10
      Kirill Smelkov authored
      In 80559a94 ("zodbdump: support --pretty option with a format to show
      pickles disassembly") we added support for zodbdump --pretty and
      adjusted files in testdata/ to be named like 1.zdump.{raw,zpickledis}.ok
      instead of just 1.zdump.ok. However, that renaming and
      generation of 1.zdump.zpickledis.ok, it seems, were done by hand, because
      rerunning gen_testdata.py still regenerates old 1.zdump.ok. It seems
      that during nexedi/zodbtools!22 I
      missed that gen_testdata.py was not updated.
      
      -> Fix it.
      
      Running gen_testdata.py with py2 and ZODB 5.8.1 regenerates *.fs and
      *.ok files in testdata/ in exactly the same state they were.
      
      /reviewed-by @jerome
      /reviewed-on nexedi/zodbtools!24
      37786d10
  6. 08 Sep, 2022 1 commit
  7. 07 Sep, 2022 7 commits
    • Kirill Smelkov's avatar
      analyze: test: Fix tidmin thinko in "empty range" test · 65ebbe7b
      Kirill Smelkov authored
      Empty-range test added in b4824ad5 (analyze: fix ZeroDivisionErrors when
      report is empty) intended to use 0xffffffffffffffff TID, but used just
      'ffffffffffffffff' string instead. It was passing on py2 partly by luck,
      but on py3 it fails because tidmin type is mismatched:
      
          _______________________________ test_zodbanalyze _______________________________
      
          tmpdir = local('/tmp/pytest-of-kirr/pytest-30/test_zodbanalyze0')
          capsys = <_pytest.capture.CaptureFixture object at 0x7f7bb3f9a4f0>
      
              def test_zodbanalyze(tmpdir, capsys):
                  ...
      
                  # empty range
                  report(
          >           analyze(
                          tfs1,
                          use_dbm=False,
                          delta_fs=False,
                          tidmin="ffffffffffffffff",
                          tidmax=None,
                      ),
                      csv=False,
                  )
      
          zodbtools/test/test_analyze.py:68:
          _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
          ../../venv/py3.venv/lib/python3.9/site-packages/decorator.py:232: in fun
              return caller(func, *(extras + args), **kw)
          ../../../tools/go/pygolang/golang/__init__.py:103: in _
              return f(*argv, **kw)
          zodbtools/zodbanalyze.py:181: in analyze
              fsi = fs.iterator(tidmin, tidmax)
          ../ZODB/src/ZODB/FileStorage/FileStorage.py:1381: in iterator
              return FileIterator(self._file_name, start, stop)
          _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
      
          self = <ZODB.FileStorage.FileStorage.FileIterator object at 0x7f7bb348c6d0>
          filename = '/tmp/pytest-of-kirr/pytest-30/test_zodbanalyze0/1.fs'
          start = 'ffffffffffffffff', stop = None, pos = 4
      
              def __init__(self, filename, start=None, stop=None, pos=4):
                  assert isinstance(filename, STRING_TYPES)
                  file = open(filename, 'rb')
                  self._file = file
                  self._file_name = filename
                  if file.read(4) != packed_version:
                      raise FileStorageFormatError(file.name)
                  file.seek(0, 2)
                  self._file_size = file.tell()
                  if (pos < 4) or pos > self._file_size:
                      raise ValueError("Given position is greater than the file size",
                                       pos, self._file_size)
                  self._pos = pos
          >       assert start is None or isinstance(start, bytes)
          E       AssertionError
      
          ../ZODB/src/ZODB/FileStorage/FileStorage.py:1816: AssertionError
          ------------------------------ Captured log call -------------------------------
          ERROR    ZODB.FileStorage:FileStorage.py:480 loading index
          UnicodeDecodeError: 'ascii' codec can't decode byte 0xb7 in position 25: ordinal not in range(128)
      
          The above exception was the direct cause of the following exception:
      
          Traceback (most recent call last):
            File "/home/kirr/src/wendelin/z/ZODB/src/ZODB/FileStorage/FileStorage.py", line 478, in _restore_index
              info = fsIndex.load(index_name)
            File "/home/kirr/src/wendelin/z/ZODB/src/ZODB/fsIndex.py", line 138, in load
              v = unpickler.load()
          SystemError: <built-in method read of _io.BufferedReader object at 0x7f7bb3df03b0> returned a result with an error set
          ERROR    ZODB.FileStorage:FileStorage.py:480 loading index
          UnicodeDecodeError: 'ascii' codec can't decode byte 0xb7 in position 25: ordinal not in range(128)
      
          ...
      
      -> Fix it by preparing tidmin in the test a 8-bytes binary properly.
      65ebbe7b
    • Kirill Smelkov's avatar
      *: Fix working on py3 by using bstr bytestring instead of raw bytes · 9861c136
      Kirill Smelkov authored
      e.g. for ObjectData .hashfunc:
      
      In many contexts we need that .hashfunc to be like string, e.g. for
      accessing hashRegistry by keys. In many other contexts - e.g. when
      zodbdump input it parsed or emitted, it is more handy to handle it like
      raw bytes.
      
      If we let .hashfunc to be of type str - it breaks the second mode. If of
      type bytes - it breaks the first mode.
      
      And also in many places it is hard to constantly encode/decode str and
      bytes, especially in the places where an object is sometimes used in
      strings context, and sometimes in binary context.
      
      -> Fix it all in one go by using bytestring type from pygolang,
      which provides both unicode string and binary semantics simultaneously.
      
      This needs bstr from pygolang (see kirr/pygolang@c9648c44),
      but even if pygolang comes without bstr, with this patch zodbtools
      continues to work ok on py2 - it will be just py3 mode that won't work.
      
      The list of test failures before this patch is provided below:
      
          _______________________________ test_zodbanalyze _______________________________
      
          tmpdir = local('/tmp/pytest-of-kirr/pytest-22/test_zodbanalyze0')
          capsys = <_pytest.capture.CaptureFixture object at 0x7f3de6835c70>
      
              def test_zodbanalyze(tmpdir, capsys):
                  tfs1 = fs1_testdata_py23(tmpdir,
                                  os.path.join(os.path.dirname(__file__), "testdata", "1.fs"))
      
                  for use_dbm in (False, True):
          >           report(
                          analyze(
                              tfs1,
                              use_dbm=use_dbm,
                              delta_fs=False,
                              tidmin=None,
                              tidmax=None,
                          ),
                          csv=False,
                      )
      
          zodbtools/test/test_analyze.py:30:
          _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
      
          rep = <zodbtools.zodbanalyze.Report object at 0x7f3de5e16b20>, csv = False
      
              def report(rep, csv=False):
                  ...
                          print (fmtp % (t_display, rep.TYPEMAP[t], rep.TYPESIZE[t],
                                         pct, rep.TYPESIZE[t] * 1.0 / rep.TYPEMAP[t],
          >                              rep.COIDSMAP[t], rep.CBYTESMAP[t],
                                         rep.FOIDSMAP.get(t, 0), rep.FBYTESMAP.get(t, 0)))
          E               KeyError: b'persistent.mapping.PersistentMapping'
      
          zodbtools/zodbanalyze.py:147: KeyError
      
          ____________________________ test_zodbcommit[!zext] ____________________________
      
          zext = <function zext.<locals>._ at 0x7f3deb5c3e50>
      
              @func
              def test_zodbcommit(zext):
                  tmpd = mkdtemp('', 'zodbcommit.')
                  defer(lambda: rmtree(tmpd))
      
                  stor = storageFromURL('%s/2.fs' % tmpd)
                  defer(stor.close)
      
                  head = stor.lastTransaction()
      
                  # commit some transactions via zodbcommit and verify if storage dump gives
                  # what is expected.
                  t1 = Transaction(z64, ' ', b'user name', b'description ...', zext(dumps({'a': 'b'}, _protocol)), [
                      ObjectData(p64(1), b'data1', 'sha1', sha1(b'data1')),
                      ObjectData(p64(2), b'data2', 'sha1', sha1(b'data2'))])
      
                  t1.tid = zodbcommit(stor, head, t1)
      
                  t2 = Transaction(z64, ' ', b'user2', b'desc2', b'', [
                      ObjectDelete(p64(2))])
      
                  t2.tid = zodbcommit(stor, t1.tid, t2)
      
                  buf = BytesIO()
                  zodbdump(stor, p64(u64(head)+1), None, out=buf)
                  dumped = buf.getvalue()
      
          >       assert dumped == b''.join([_.zdump() for _ in (t1, t2)])
      
          zodbtools/test/test_commit.py:61:
          _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
          zodbtools/test/test_commit.py:61: in <listcomp>
              assert dumped == b''.join([_.zdump() for _ in (t1, t2)])
          zodbtools/zodbdump.py:521: in zdump
              z += obj.zdump()
          _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
      
          self = <zodbtools.zodbdump.ObjectData object at 0x7f3de5d26d90>
      
              def zdump(self):
                  data = self.data
                  hashonly = isinstance(data, HashOnly)
                  if hashonly:
                      size = data.size
                  else:
                      size = len(data)
          >       z = b'obj %s %d %s:%s' % (ashex(self.oid), size, self.hashfunc, ashex(self.hash_))
          E       TypeError: %b requires a bytes-like object, or an object that implements __bytes__, not 'str'
      
          zodbtools/zodbdump.py:569: TypeError
      
          _______________________________ test_dumpreader ________________________________
      
              def test_dumpreader():
                  in_ = b"""\
              txn 0123456789abcdef " "
              user "my name"
              description "o la-la..."
              extension "zzz123 def"
              obj 0000000000000001 delete
              obj 0000000000000002 from 0123456789abcdee
              obj 0000000000000003 54 adler32:01234567 -
              obj 0000000000000004 4 sha1:9865d483bc5a94f2e30056fc256ed3066af54d04
              ZZZZ
              obj 0000000000000005 9 crc32:52fdeac5
              ABC
      
              DEF!
      
              txn 0123456789abcdf0 " "
              user "author2"
              description "zzz"
              extension "qqq"
      
              """
      
                  r = DumpReader(BytesIO(in_))
          >       t1 = r.readtxn()
      
          zodbtools/test/test_dump.py:78:
          _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
          zodbtools/zodbdump.py:443: in readtxn
              self._badline('unknown hash function %s' % qq(hashfunc))
          _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
      
          self = <zodbtools.zodbdump.DumpReader object at 0x7f3de5d69cd0>
          msg = 'unknown hash function "adler32"'
      
              def _badline(self, msg):
          >       raise RuntimeError("%s+%d: invalid line: %s (%s)" % (_ioname(self._r), self.lineno, msg, qq(self._line)))
          E       RuntimeError: +7: invalid line: unknown hash function "adler32" ("obj 0000000000000003 54 adler32:01234567 -")
      
          zodbtools/zodbdump.py:382: RuntimeError
      
          ___________________________ test_zodbrestore[!zext] ____________________________
      
          tmpdir = local('/tmp/pytest-of-kirr/pytest-22/test_zodbrestore__zext_0')
          zext = <function zext.<locals>._ at 0x7f3de5d6ddc0>
      
              @func
              def test_zodbrestore(tmpdir, zext):
                  zkind = '_!zext' if zext.disabled else ''
      
                  # restore from testdata/1.zdump.ok and verify it gives result that is
                  # bit-to-bit identical to testdata/1.fs
                  tdata = dirname(__file__) + "/testdata"
                  @func
                  def _():
                      zdump = open("%s/1%s.zdump.raw.ok" % (tdata, zkind), 'rb')
                      defer(zdump.close)
      
                      stor = storageFromURL('%s/2.fs' % tmpdir)
                      defer(stor.close)
      
                      zodbrestore(stor, zdump)
          >       _()
      
          zodbtools/test/test_restore.py:49:
          _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
          ../../venv/py3.venv/lib/python3.9/site-packages/decorator.py:232: in fun
              return caller(func, *(extras + args), **kw)
          ../../../tools/go/pygolang/golang/__init__.py:103: in _
              return f(*argv, **kw)
          zodbtools/test/test_restore.py:48: in _
              zodbrestore(stor, zdump)
          zodbtools/zodbrestore.py:39: in zodbrestore
              txn = zr.readtxn()
          zodbtools/zodbdump.py:443: in readtxn
              self._badline('unknown hash function %s' % qq(hashfunc))
          _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
      
          self = <zodbtools.zodbdump.DumpReader object at 0x7f3de5d79e20>
          msg = 'unknown hash function "sha1"'
      
              def _badline(self, msg):
          >       raise RuntimeError("%s+%d: invalid line: %s (%s)" % (_ioname(self._r), self.lineno, msg, qq(self._line)))
          E       RuntimeError: /home/kirr/src/wendelin/z/zodbtools/zodbtools/test/testdata/1_!zext.zdump.raw.ok+5: invalid line: unknown hash function "sha1" ("obj 0000000000000000 61 sha1:664e6de0f153d8eaeda638d616a320c6e3c5feb1")
      
          zodbtools/zodbdump.py:382: RuntimeError
      9861c136
    • Kirill Smelkov's avatar
      zodbcommit: Fix stdin reading on py3 · b21fbe23
      Kirill Smelkov authored
      Zodbcommit reads input in zodbdump format from stdin and then uses
      zodbdump.DumpReader to parser that input. The parser works on binary
      data.
      
      However zodbcommit, was preparing that input data mixing bytes and
      strings, which is failing on py3:
      
          (py3.venv) kirr@deca:~/src/wendelin/z/zodbtools$ zodb commit 1.fs 00
          Ignoring index for /home/kirr/src/wendelin/z/zodbtools/1.fs
          aaa
          Traceback (most recent call last):
            File "/home/kirr/src/wendelin/venv/py3.venv/bin/zodb", line 33, in <module>
              sys.exit(load_entry_point('zodbtools', 'console_scripts', 'zodb')())
            File "/home/kirr/src/wendelin/z/zodbtools/zodbtools/zodb.py", line 129, in main
              return command_module.main(argv)
            File "/home/kirr/src/wendelin/venv/py3.venv/lib/python3.9/site-packages/decorator.py", line 232, in fun
              return caller(func, *(extras + args), **kw)
            File "/home/kirr/src/tools/go/pygolang/golang/__init__.py", line 103, in _
              return f(*argv, **kw)
            File "/home/kirr/src/wendelin/z/zodbtools/zodbtools/zodbcommit.py", line 222, in main
              zin += sys.stdin.read()
          TypeError: can't concat str to bytes
      
      -> Fix it by reading stdin in binary mode.
      
      No test currently as zodbcommit.main is not covered by tests (hopefully yet).
      b21fbe23
    • Kirill Smelkov's avatar
      zodbdump: Fix pickle disassembly on py3 · 69dc6de1
      Kirill Smelkov authored
      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"
      69dc6de1
    • Kirill Smelkov's avatar
      tests: Adjust testdata FileStorage for current Python on the fly · e825f80f
      Kirill Smelkov authored
      FileStorage/py2 uses `FS21` magic in file header, whereas
      FileStorage/py3 uses `FS30` magic:
      
          https://github.com/zopefoundation/ZODB/blob/0e72b8b13657/src/ZODB/_compat.py#L39
          https://github.com/zopefoundation/ZODB/blob/0e72b8b13657/src/ZODB/_compat.py#L74
      
      And if, upon opening the database, file magic does not match to what ZODB
      expects, open is rejected:
      
          https://github.com/zopefoundation/ZODB/blob/0e72b8b13657/src/ZODB/FileStorage/FileStorage.py#L88
          https://github.com/zopefoundation/ZODB/blob/0e72b8b13657/src/ZODB/FileStorage/FileStorage.py#L1625-L1630
      
      This is done with the idea for a database, that was written from
      Python2, to be rejected to be opened from Python3 and vice-versa because
      strings/bytes semantics changed in between py23.
      
      As the result, many zodbtools tests currently fail on py3 when they try
      to access prepared FileStorage database in testdata, because that
      database was originally prepared on py2. Here is, for example, how
      test_zodbdump fails:
      
          ___________________________ test_zodbdump[zext-raw] ____________________________
      
          zext = <function zext.<locals>._ at 0x7f28530bf9d0>, pretty = 'raw'
      
              @mark.parametrize('pretty', ('raw', 'zpickledis'))
              def test_zodbdump(zext, pretty):
                  tdir  = dirname(__file__)
                  zkind = '_!zext' if zext.disabled else ''
          >       stor  = FileStorage('%s/testdata/1%s.fs' % (tdir, zkind), read_only=True)
      
          zodbtools/test/test_dump.py:41:
          _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
          ../ZODB/src/ZODB/FileStorage/FileStorage.py:315: in __init__
              self._pos, self._oid, tid = read_index(
          _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
      
          file = <_io.BufferedReader name='/home/kirr/src/wendelin/z/zodbtools/zodbtools/test/testdata/1.fs'>
          name = '/home/kirr/src/wendelin/z/zodbtools/zodbtools/test/testdata/1.fs'
          index = <ZODB.fsIndex.fsIndex object at 0x7f2852fee2b0>, tindex = {}
          stop = b'\xff\xff\xff\xff\xff\xff\xff\xff'
          ltid = b'\x00\x00\x00\x00\x00\x00\x00\x00', start = 4
          maxoid = b'\x00\x00\x00\x00\x00\x00\x00\x00', recover = 0, read_only = True
      
              def read_index(file, name, index, tindex, stop=b'\377'*8,
                             ltid=z64, start=4, maxoid=z64, recover=0, read_only=0):
                  """Scan the file storage and update the index."""
                  ...
                  if file_size:
                      if file_size < start:
                          raise FileStorageFormatError(file.name)
                      seek(0)
                      if read(4) != packed_version:
          >               raise FileStorageFormatError(name)
          E               ZODB.FileStorage.FileStorage.FileStorageFormatError: /home/kirr/src/wendelin/z/zodbtools/zodbtools/test/testdata/1.fs
      
          ../ZODB/src/ZODB/FileStorage/FileStorage.py:1630: FileStorageFormatError
      
      Since zodbtools primarily work on raw data without decoding stored
      pickles, unlike Zope or ERP5, it should not be a problem for zodbtools
      to work on py3 with the database that was prepared on py2.
      
      -> Adjust all tests to use FileStorage data generated on the fly based
      on original files in testdata/ but with FileStorage header being
      rewritten to match current python.
      e825f80f
    • Kirill Smelkov's avatar
      util += writefile · 3cb93096
      Kirill Smelkov authored
      A counterpart to readfile - to write a file instead of reading it.
      We will need this function in the next patch.
      3cb93096
    • Kirill Smelkov's avatar
      util: Factor readfile function into here · adec18bd
      Kirill Smelkov authored
      Soon we will need to use it not only from test_restore.py
      adec18bd
  8. 29 Mar, 2022 1 commit
  9. 01 Apr, 2021 1 commit
    • Jérome Perrin's avatar
      zodbrestore: Mark restore-with-extension tests as xfail on ZODB4 · aa7e1966
      Jérome Perrin authored
      @kirr wrote (nexedi/zodbtools!19 (comment 129442))
      
          For the reference - contrary to ZODB5, restore tests on ZODB4 are currently
          [broken](https://nexedijs.erp5.net/#/test_result_module/20210317-B3AC205A/2).
          Restored file is not bit-to-bit identical to the original.
      
          The problem is that on commit/restore, we need to save
          user/description/extension. For extension `zodbdump.Transaction` provides
          .extension_bytes, which ZODB5 uses to save its raw copy. However ZODB4 goes
          through `.extension` and pickles it:
      
          https://lab.nexedi.com/nexedi/zodbtools/blob/129afa67/zodbtools/zodbdump.py#L425-453
          https://github.com/zopefoundation/ZODB/blob/4/src/ZODB/BaseStorage.py#L220-L240
      
          This leads to unpickle-repickle round-trip and different extension being committed on restore:
      
          ```diff
          diff --git a/1zdump b/2zdump
          index 5033bc1..a3a32aa 100644
          --- a/1zdump
          +++ b/2zdump
          @@ -10,7 +10,7 @@ q^A.
           txn 0285cbac3d0369e6 " "
           user "user0.0"
           description "step 0.0"
          -extension "\x80\x02}q\x01(U\tx-cookieSU\x05RF9IEU\vx-generatorq\x02U\fzodb/py2 (f)u."
          +extension "}q\x01(U\tx-cookieSU\x05RF9IEU\vx-generatorU\fzodb/py2 (f)u."
           obj 0000000000000000 98 sha1:eba252d1984f975ecb636bc1b3a89c953dd20527
          ...
          ```
      
          What might save us is to somehow in Transaction.extension returns a
          dict-subclass object that is somehow pickled to the exact bytes remembered when
          it was created. However, after briefly checking, I could not find a mechanism
          to do so yet...
      
      @jerome wrote (nexedi/zodbtools!19 (comment 129479))
      
          @kirr we already have pytest fixtures to test differently depending on whether
          the ZODB version has support for extension_bytes, so what about using it in the
          test and testing restoring the extension bytes version of the dump only for
          ZODB5 ?
      
      @kirr wrote (nexedi/zodbtools!19 (comment 129482))
      
          @jerome, yes we have this, but I believe we should actually fix zodbrestore to
          be reliable whatever ZODB is used. For ZODB5 it works. For ZODB4-wc2 we can
          adjust ZODB code to use extension_bytes similarly to how ZODB5 does. But
          unpatched ZODB4 is currently out of luck. As it was decided that Nexedi will
          use both ZODB4 and ZODB4-wc2, I think we should fix zodbrestore to work on all
          those versions to be reliable.
      
          /cc @tomo
      
      @kirr:
      
      -> No universal ZODB4 fix for now (this would require to monkey patch ZODB in
      several places), so mark "restore with extension" test as xfail similarly to
      how we already do for "dump with extension" test.
      
      This brings -ZODB4 and -ZODB4-wc2 tests back to PASS state.
      
      Even though on ZODB4 extension is restored not bit-to-bit exactly, it is
      restored to be the same dictionary equal to what was used to produce the
      dump. Not ideal, but still not loosing the information in practice.
      
      One more reason to switch to ZODB5...
      aa7e1966
  10. 16 Mar, 2021 2 commits
    • Kirill Smelkov's avatar
      zodbcommit: Provide full context when reporting errors · 129afa67
      Kirill Smelkov authored
      In the previous patch we taught object copy handler to report more
      details, but it was still incomplete - the error was missing details
      about which operation was run - commit, or restore of particular
      transaction.
      
      Noting that it can be also noted that other errors reported from that
      function lack such context.
      
      -> So fix it universally, at least for zodbcommit for now: set top-level
      runctx to topic of what we are doing, and use that runctx when
      generating errors. Runctx describes what we are running, and could be
      also later used for logging and tracing. That's why it is called runctx
      instead of just errctx for "error context".
      
      TODO currently it is only exceptions that we explicitly raise which get
      the context. If an exception is raised by something that we call - the
      context won't be added. It would be good to later rework error handling
      and append such context for any raised error. Defer and
      https://lab.nexedi.com/kirr/go123/blob/863c4602/xerr/__init__.py has
      something preliminary for this.
      
      The particular error when restoring a missing object copy becomes
      
          ValueError: /tmp/demo002868462/δ0285cbac75555580/δ.fs: restore 0285cbacb70a3db3 @0285cbacb258bf66: object 0000000000000003: copy from @0285cbac70a3d733: no data
      
      instead of older
      
          ValueError: /tmp/demo358030847/δ0285cbac75555580/δ.fs: object 0000000000000003: copy from @0285cbac70a3d733: no data
      
      /reviewed-by @jerome
      /reviewed-on !20
      129afa67
    • Kirill Smelkov's avatar
      zodbcommit: Robustify copy handling · fa00c283
      Kirill Smelkov authored
      When zodbdump input says to copy an object, we first load that object.
      However if object does not exist loadBefore raises POSKeyError, and when
      object at copied-from revision was deleted loadBefore returns None.
      
      -> Handle that explicitly to provide failure details to the user, so
      that instead of cryptic
      
          === RUN   TestLoad/δstart=0285cbac75555580
          Traceback (most recent call last):
            File "/usr/lib/python2.7/runpy.py", line 174, in _run_module_as_main
              "__main__", fname, loader, pkg_name)
            File "/usr/lib/python2.7/runpy.py", line 72, in _run_code
              exec code in run_globals
            File "/home/kirr/src/wendelin/z/zodbtools/zodbtools/zodb.py", line 133, in <module>
              main()
            File "/home/kirr/src/wendelin/z/zodbtools/zodbtools/zodb.py", line 129, in main
              return command_module.main(argv)
            File "<decorator-gen-6>", line 2, in main
            File "/home/kirr/src/tools/go/pygolang/golang/__init__.py", line 103, in _
              return f(*argv, **kw)
            File "/home/kirr/src/wendelin/z/zodbtools/zodbtools/zodbrestore.py", line 94, in main
              zodbrestore(stor, asbinstream(sys.stdin), _)
            File "/home/kirr/src/wendelin/z/zodbtools/zodbtools/zodbrestore.py", line 43, in zodbrestore
              zodbcommit(stor, at, txn)
            File "/home/kirr/src/wendelin/z/zodbtools/zodbtools/zodbcommit.py", line 122, in zodbcommit
              _()
            File "/home/kirr/src/wendelin/z/zodbtools/zodbtools/zodbcommit.py", line 91, in _
              data, _, _ = stor.loadBefore(obj.oid, p64(u64(obj.copy_from)+1))
          TypeError: 'NoneType' object is not iterable
              xtesting.go:483: /tmp/demo009767458/δ0285cbac75555580/δ.fs: zpyrestore: exit status 1
      
      it fails with something more understandable:
      
          === RUN   TestLoad/δstart=0285cbac75555580
          Traceback (most recent call last):
            File "/usr/lib/python2.7/runpy.py", line 174, in _run_module_as_main
              "__main__", fname, loader, pkg_name)
            File "/usr/lib/python2.7/runpy.py", line 72, in _run_code
              exec code in run_globals
            File "/home/kirr/src/wendelin/z/zodbtools/zodbtools/zodb.py", line 133, in <module>
              main()
            File "/home/kirr/src/wendelin/z/zodbtools/zodbtools/zodb.py", line 129, in main
              return command_module.main(argv)
            File "<decorator-gen-6>", line 2, in main
            File "/home/kirr/src/tools/go/pygolang/golang/__init__.py", line 103, in _
              return f(*argv, **kw)
            File "/home/kirr/src/wendelin/z/zodbtools/zodbtools/zodbrestore.py", line 94, in main
              zodbrestore(stor, asbinstream(sys.stdin), _)
            File "/home/kirr/src/wendelin/z/zodbtools/zodbtools/zodbrestore.py", line 43, in zodbrestore
              zodbcommit(stor, at, txn)
            File "/home/kirr/src/wendelin/z/zodbtools/zodbtools/zodbcommit.py", line 129, in zodbcommit
              _()
            File "/home/kirr/src/wendelin/z/zodbtools/zodbtools/zodbcommit.py", line 97, in _
              (stor.getName(), ashex(obj.oid), ashex(obj.copy_from)))
          ValueError: /tmp/demo358030847/δ0285cbac75555580/δ.fs: object 0000000000000003: copy from @0285cbac70a3d733: no data
              xtesting.go:483: /tmp/demo358030847/δ0285cbac75555580/δ.fs: zpyrestore: exit status 1
      
      For the implementation it would be easier to use loadAt
      (https://github.com/zopefoundation/ZODB/pull/323), but we don't have
      that yet.
      
      /reviewed-by @jerome
      /reviewed-on !20
      fa00c283
  11. 15 Mar, 2021 4 commits
  12. 10 Mar, 2021 2 commits
    • Kirill Smelkov's avatar
      Drop support for ZODB3 · c59a54ca
      Kirill Smelkov authored
      Nexedi stack is dropping support for that old ZODB version - see e.g.
      
      - slapos@70d05199
      - neoppod@3a8f6f03
      - wendelin.core@0802da2b
      
      Regarding test/gen_testdata.py: even though ZODB4 uses zodbpickle, and
      so should be able to load pickles encoded with protocol 3 even on
      python2, in practice it does not work so well: ZODB4 tests fail if I set
      
          --- a/src/ZODB/_compat.py
          +++ b/src/ZODB/_compat.py
          @@ -34,7 +34,7 @@
               HIGHEST_PROTOCOL = cPickle.HIGHEST_PROTOCOL
               IMPORT_MAPPING = {}
               NAME_MAPPING = {}
          -    _protocol = 1
          +    _protocol = 3
               FILESTORAGE_MAGIC = b"FS21"
           else:
               # Python 3.x: can't use stdlib's pickle because
      
      -> so continue to preserve protocol < 3 when generating the test
      database for compatibility - now with ZODB4/py2.
      
      /reviewed-by @jerome
      /reviewed-on !18
      c59a54ca
    • Kirill Smelkov's avatar
      tox: Don't run tests agains ZODB+PR183 anymore · 986baf02
      Kirill Smelkov authored
      The patch that provides raw-extension functionality was merged into ZODB 5.6:
      
      https://github.com/zopefoundation/ZODB/commit/2f8cc67a3ba3
      
      So when testing with ZODB5 >= 5.6 the tests will excercise code path
      that uses txn.extension_bytes, and when testing with ZODB4 the tests
      will excercise code path that work-arounds lack of txn.extension_bytes.
      
      /reviewed-by @jerome
      /reviewed-on !18
      986baf02