[Python-checkins] python/nondist/sandbox/pickletools pickletools.py,1.25,1.26

tim_one@users.sourceforge.net tim_one@users.sourceforge.net
Sun, 26 Jan 2003 16:19:52 -0800


Update of /cvsroot/python/python/nondist/sandbox/pickletools
In directory sc8-pr-cvs1:/tmp/cvs-serv11749

Modified Files:
	pickletools.py 
Log Message:
Got rid of the Walker base class and the Dis disassembler class.  There's
now a genops(pickle) generator instead, and a dis() function.  The code is
simpler, faster, and clearer this way.


Index: pickletools.py
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/pickletools/pickletools.py,v
retrieving revision 1.25
retrieving revision 1.26
diff -C2 -d -r1.25 -r1.26
*** pickletools.py	26 Jan 2003 20:04:35 -0000	1.25
--- pickletools.py	27 Jan 2003 00:19:50 -0000	1.26
***************
*** 6,10 ****
  #   descriptors.
  #
! # - A symbolic pickle disassembler.
  #
  # - A pickle verifier:  read a pickle and check it exhaustively for
--- 6,10 ----
  #   descriptors.
  #
! # - A symbolic pickle disassembler (done -- see function dis()).
  #
  # - A pickle verifier:  read a pickle and check it exhaustively for
***************
*** 1365,1449 ****
  
  ##############################################################################
! # A pickle walker base clase.
! 
! class Walker:
!     def __init__(self, pickle):
!         """pickle is a file-like object containing a pickle bytestream.
! 
!         Invoking walk() traverses the pickle, calling visit() for each
!         opcode encountered, then calling done() once at the end.  Subclasses
!         will want to override visit(), and possibly done().  The default
!         implementations do nothing.
!         """
  
!         self.pickle = pickle
  
!         if hasattr(pickle, 'tell'):
!             def position():
!                 return pickle.tell()
!         else:
!             def position():
!                 return None
  
!         self.position = position
  
!     def walk(self):
!         """"Run" the pickle, from the current position, until a STOP opcode.
  
!         For each opcode encountered, calls
  
!             self.visit(opcode, arg, pos)
  
!         opcode is an OpcodeInfo record, describing the current opcode.
  
!         If the opcode has an argument embedded in the pickle, arg contains
!         its decoded value, as a Python object.  If the opcode doesn't have
!         an argument, arg is None.
  
!         If the pickle has a tell() method, pos was the value of pickle.tell()
!         before reading the current opcode.  Else pos is None.
  
!         After a STOP opcode triggers a visit() call, self.done() is called
!         once.
!         """
  
!         pickle = self.pickle
!         position = self.position
!         while True:
!             pos = position()
!             code = pickle.read(1)
!             opcode = code2op.get(code)
!             if opcode is None:
!                 if code == "":
!                     raise ValueError("pickle exhausted before seeing STOP")
!                 else:
!                     raise ValueError("at position %s, opcode %r unknown" % (
!                                      pos is None and "<unknown>" or pos,
!                                      code))
!             if opcode.arg is None:
!                 arg = None
              else:
!                 arg = opcode.arg.reader(pickle)
!             self.visit(opcode, arg, pos)
!             if code == '.':
!                 assert opcode.name == 'STOP'
!                 break
!         self.done()
  
!     def visit(self, opcode, arg, pos):
!         "Called once per opcode.  See the walk() docs for argument details."
!         pass
  
!     def done(self):
!         "Called after STOP is passed to visit()."
!         pass
  
! class Dis(Walker):
!     def __init__(self, pickle, out=None):
!         Walker.__init__(self, pickle)
!         self.out = out
  
!     def visit(self, opcode, arg, pos):
!         out = self.out
          if pos is not None:
              print >> out, "%5d:" % pos,
--- 1365,1439 ----
  
  ##############################################################################
! # A pickle opcode generator.
  
! def genops(pickle):
!     """"Generate all the opcodes in a pickle.
  
!     'pickle' is a file-like object, or string, containing the pickle.
  
!     Each opcode in the pickle is generated, from the current pickle position,
!     stopping after a STOP opcode is delivered.  A triple is generated for
!     each opcode:
  
!         opcode, arg, pos
  
!     opcode is an OpcodeInfo record, describing the current opcode.
  
!     If the opcode has an argument embedded in the pickle, arg is its decoded
!     value, as a Python object.  If the opcode doesn't have an argument, arg
!     is None.
  
!     If the pickle has a tell() method, pos was the value of pickle.tell()
!     before reading the current opcode.  If the pickle is a string object,
!     it's wrapped in a StringIO object, and the latter's tell() result is
!     used.  Else (the pickle doesn't have a tell(), and it's not obvious how
!     to query its current position) pos is None.
!     """
  
!     import cStringIO as StringIO
  
!     if isinstance(pickle, str):
!         pickle = StringIO.StringIO(pickle)
  
!     if hasattr(pickle, "tell"):
!         getpos = pickle.tell
!     else:
!         getpos = lambda: None
  
!     while True:
!         pos = getpos()
!         code = pickle.read(1)
!         opcode = code2op.get(code)
!         if opcode is None:
!             if code == "":
!                 raise ValueError("pickle exhausted before seeing STOP")
              else:
!                 raise ValueError("at position %s, opcode %r unknown" % (
!                                  pos is None and "<unknown>" or pos,
!                                  code))
!         if opcode.arg is None:
!             arg = None
!         else:
!             arg = opcode.arg.reader(pickle)
!         yield opcode, arg, pos
!         if code == '.':
!             assert opcode.name == 'STOP'
!             break
  
! ##############################################################################
! # A symbolic pickle disassembler.
  
! def dis(pickle, out=None):
!     """Produce a symbolic disassembly of a pickle.
  
!     'pickle' is file-like object, or string, containing a (at least one)
!     pickle.  The pickle is disassembled from the current position, through
!     the first STOP opcode encountered.
  
!     Optional arg 'out' is a file-like object to which the disassembly is
!     printed.  It defaults to sys.stdout.
!     """
! 
!     for opcode, arg, pos in genops(pickle):
          if pos is not None:
              print >> out, "%5d:" % pos,
***************
*** 1455,1465 ****
  
  _disassembler_test = """
- >>> from StringIO import StringIO
  >>> import pickle
  >>> x = [1, 2, (3, 4), {'abc': u"def"}]
  >>> pik = pickle.dumps(x)
! >>> stream = StringIO(pik)
! >>> d = Dis(stream)
! >>> d.walk()
      0: ( MARK
      1: l LIST
--- 1445,1452 ----
  
  _disassembler_test = """
  >>> import pickle
  >>> x = [1, 2, (3, 4), {'abc': u"def"}]
  >>> pik = pickle.dumps(x)
! >>> dis(pik)
      0: ( MARK
      1: l LIST
***************
*** 1487,1494 ****
  
  Try again with a "binary" pickle.
  >>> pik = pickle.dumps(x, 1)
! >>> stream = StringIO(pik)
! >>> d = Dis(stream)
! >>> d.walk()
      0: ] EMPTY_LIST
      1: q BINPUT     0
--- 1474,1480 ----
  
  Try again with a "binary" pickle.
+ 
  >>> pik = pickle.dumps(x, 1)
! >>> dis(pik)
      0: ] EMPTY_LIST
      1: q BINPUT     0