]> granicus.if.org Git - python/commitdiff
Issue #21947: handle generator-iterator objects in dis
authorNick Coghlan <ncoghlan@gmail.com>
Fri, 25 Jul 2014 13:02:56 +0000 (23:02 +1000)
committerNick Coghlan <ncoghlan@gmail.com>
Fri, 25 Jul 2014 13:02:56 +0000 (23:02 +1000)
Patch by Clement Rouault.

Doc/library/dis.rst
Lib/dis.py
Lib/test/test_dis.py
Misc/ACKS
Misc/NEWS

index fbabe357724c04c499797291fc89908b43f2107d..8653da765bf651032d98264a019e69af6548b540 100644 (file)
@@ -48,8 +48,8 @@ compiled code.
 
 .. 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 @@ object isn't useful:
 .. 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 @@ object isn't useful:
 .. 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.
 
index 81cbe7f4f993ff6d3ced3be158c5101d516ef13a..d215bc59e4a833d6e91945ba805ce427926aaaf8 100644 (file)
@@ -29,7 +29,7 @@ def _try_compile(source, name):
     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 @@ def dis(x=None, *, file=None):
         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 @@ def pretty_flags(flags):
     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
index d1229fba6dbe65355f9e97988aeb2a5f87c9b243..f04f12ca821dd3b010417f7cd969b54aa921ae6c 100644 (file)
@@ -229,6 +229,9 @@ dis_traceback = """\
        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 @@ class DisTests(unittest.TestCase):
         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
index d9fed8a2a718cb1e7d26304377ba6c627c9b96b7..4a68015cdd4de7a5bfafcdce04d1a20b8dec3cbf 100644 (file)
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -1145,6 +1145,7 @@ Guido van Rossum
 Just van Rossum
 Hugo van Rossum
 Saskia van Rossum
+Clement Rouault
 Donald Wallace Rouse II
 Liam Routt
 Todd Rovito
index 515978aed6f47dbae2d2ce7ab29927717934bff9..3f49d9c9ac1bdcaaf9b433d125f53329719855fa 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -108,6 +108,9 @@ Core and Builtins
 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.