[Python-checkins] cpython: Issue #21947: handle generator-iterator objects in dis

nick.coghlan python-checkins at python.org
Fri Jul 25 15:04:51 CEST 2014


http://hg.python.org/cpython/rev/2ae5709692ef
changeset:   91858:2ae5709692ef
user:        Nick Coghlan <ncoghlan at gmail.com>
date:        Fri Jul 25 23:02:56 2014 +1000
summary:
  Issue #21947: handle generator-iterator objects in dis

Patch by Clement Rouault.

files:
  Doc/library/dis.rst  |  16 ++++++++--------
  Lib/dis.py           |   8 ++++++--
  Lib/test/test_dis.py |   8 ++++++++
  Misc/ACKS            |   1 +
  Misc/NEWS            |   3 +++
  5 files changed, 26 insertions(+), 10 deletions(-)


diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst
--- a/Doc/library/dis.rst
+++ b/Doc/library/dis.rst
@@ -48,8 +48,8 @@
 
 .. class:: Bytecode(x, *, first_line=None, current_offset=None)
 
-   Analyse the bytecode corresponding to a function, method, string of
-   source code, or a code object (as returned by :func:`compile`).
+   Analyse the bytecode corresponding to a function, generator, method,
+   string of source code, or a code object (as returned by :func:`compile`).
 
    This is a convenience wrapper around many of the functions listed below,
    most notably :func:`get_instructions`, as iterating over a
@@ -112,7 +112,7 @@
 .. function:: code_info(x)
 
    Return a formatted multi-line string with detailed code object information
-   for the supplied function, method, source code string or code object.
+   for the supplied function, generator, method, source code string or code object.
 
    Note that the exact contents of code info strings are highly implementation
    dependent and they may change arbitrarily across Python VMs or Python
@@ -139,11 +139,11 @@
 .. function:: dis(x=None, *, file=None)
 
    Disassemble the *x* object.  *x* can denote either a module, a class, a
-   method, a function, a code object, a string of source code or a byte sequence
-   of raw bytecode.  For a module, it disassembles all functions.  For a class,
-   it disassembles all methods.  For a code object or sequence of raw bytecode,
-   it prints one line per bytecode instruction.  Strings are first compiled to
-   code objects with the :func:`compile` built-in function before being
+   method, a function, a generator, a code object, a string of source code or
+   a byte sequence of raw bytecode.  For a module, it disassembles all functions.
+   For a class, it disassembles all methods.  For a code object or sequence of
+   raw bytecode, it prints one line per bytecode instruction.  Strings are first
+   compiled to code objects with the :func:`compile` built-in function before being
    disassembled.  If no object is provided, this function disassembles the last
    traceback.
 
diff --git a/Lib/dis.py b/Lib/dis.py
--- a/Lib/dis.py
+++ b/Lib/dis.py
@@ -29,7 +29,7 @@
     return c
 
 def dis(x=None, *, file=None):
-    """Disassemble classes, methods, functions, or code.
+    """Disassemble classes, methods, functions, generators, or code.
 
     With no argument, disassemble the last traceback.
 
@@ -41,6 +41,8 @@
         x = x.__func__
     if hasattr(x, '__code__'):  # Function
         x = x.__code__
+    if hasattr(x, 'gi_code'):  # Generator
+        x = x.gi_code
     if hasattr(x, '__dict__'):  # Class or module
         items = sorted(x.__dict__.items())
         for name, x1 in items:
@@ -99,11 +101,13 @@
     return ", ".join(names)
 
 def _get_code_object(x):
-    """Helper to handle methods, functions, strings and raw code objects"""
+    """Helper to handle methods, functions, generators, strings and raw code objects"""
     if hasattr(x, '__func__'): # Method
         x = x.__func__
     if hasattr(x, '__code__'): # Function
         x = x.__code__
+    if hasattr(x, 'gi_code'):  # Generator
+        x = x.gi_code
     if isinstance(x, str):     # Source code
         x = _try_compile(x, "<disassembly>")
     if hasattr(x, 'co_code'):  # Code object
diff --git a/Lib/test/test_dis.py b/Lib/test/test_dis.py
--- a/Lib/test/test_dis.py
+++ b/Lib/test/test_dis.py
@@ -229,6 +229,9 @@
        TRACEBACK_CODE.co_firstlineno + 4,
        TRACEBACK_CODE.co_firstlineno + 5)
 
+def _g(x):
+    yield x
+
 class DisTests(unittest.TestCase):
 
     def get_disassembly(self, func, lasti=-1, wrapper=True):
@@ -314,6 +317,11 @@
         method_bytecode = _C(1).__init__.__code__.co_code
         self.do_disassembly_test(method_bytecode, dis_c_instance_method_bytes)
 
+    def test_disassemble_generator(self):
+        gen_func_disas = self.get_disassembly(_g)  # Disassemble generator function
+        gen_disas = self.get_disassembly(_g(1))  # Disassemble generator itself
+        self.assertEqual(gen_disas, gen_func_disas)
+
     def test_dis_none(self):
         try:
             del sys.last_traceback
diff --git a/Misc/ACKS b/Misc/ACKS
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -1145,6 +1145,7 @@
 Just van Rossum
 Hugo van Rossum
 Saskia van Rossum
+Clement Rouault
 Donald Wallace Rouse II
 Liam Routt
 Todd Rovito
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -108,6 +108,9 @@
 Library
 -------
 
+- Issue #21947: The dis module can now disassemble generator-iterator
+  objects based on their gi_code attribute. Patch by Clement Rouault.
+
 - Issue #16133: The asynchat.async_chat.handle_read() method now ignores
   BlockingIOError exceptions.
 

-- 
Repository URL: http://hg.python.org/cpython


More information about the Python-checkins mailing list