[Python-checkins] cpython (merge 3.5 -> default): Issue #26733: Disassembling a class now disassembles class and static methods.

serhiy.storchaka python-checkins at python.org
Sat Apr 23 02:24:49 EDT 2016


https://hg.python.org/cpython/rev/f96fec10cf25
changeset:   101096:f96fec10cf25
parent:      101094:103fb8be940b
parent:      101095:d14ea3964590
user:        Serhiy Storchaka <storchaka at gmail.com>
date:        Sat Apr 23 09:24:29 2016 +0300
summary:
  Issue #26733: Disassembling a class now disassembles class and static methods.
Patch by Xiang Zhang.

files:
  Doc/library/dis.rst  |  10 +++---
  Lib/dis.py           |   3 +-
  Lib/test/test_dis.py |  52 ++++++++++++++++++++++++++++++-
  Misc/NEWS            |   3 +
  4 files changed, 60 insertions(+), 8 deletions(-)


diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst
--- a/Doc/library/dis.rst
+++ b/Doc/library/dis.rst
@@ -139,11 +139,11 @@
    Disassemble the *x* object.  *x* can denote either a module, a class, a
    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.
+   For a class, it disassembles all methods (including class and static 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.
 
    The disassembly is written as text to the supplied *file* argument if
    provided and to ``sys.stdout`` otherwise.
diff --git a/Lib/dis.py b/Lib/dis.py
--- a/Lib/dis.py
+++ b/Lib/dis.py
@@ -13,7 +13,8 @@
            "get_instructions", "Instruction", "Bytecode"] + _opcodes_all
 del _opcodes_all
 
-_have_code = (types.MethodType, types.FunctionType, types.CodeType, type)
+_have_code = (types.MethodType, types.FunctionType, types.CodeType,
+              classmethod, staticmethod, type)
 
 def _try_compile(source, name):
     """Attempts to compile the given source, first as an expression and
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
@@ -30,6 +30,14 @@
     def __init__(self, x):
         self.x = x == 1
 
+    @staticmethod
+    def sm(x):
+        x = x == 1
+
+    @classmethod
+    def cm(cls, x):
+        cls.x = x == 1
+
 dis_c_instance_method = """\
 %3d           0 LOAD_FAST                1 (x)
               3 LOAD_CONST               1 (1)
@@ -50,6 +58,37 @@
          18 RETURN_VALUE
 """
 
+dis_c_class_method = """\
+%3d           0 LOAD_FAST                1 (x)
+              3 LOAD_CONST               1 (1)
+              6 COMPARE_OP               2 (==)
+              9 LOAD_FAST                0 (cls)
+             12 STORE_ATTR               0 (x)
+             15 LOAD_CONST               0 (None)
+             18 RETURN_VALUE
+""" % (_C.cm.__code__.co_firstlineno + 2,)
+
+dis_c_static_method = """\
+%3d           0 LOAD_FAST                0 (x)
+              3 LOAD_CONST               1 (1)
+              6 COMPARE_OP               2 (==)
+              9 STORE_FAST               0 (x)
+             12 LOAD_CONST               0 (None)
+             15 RETURN_VALUE
+""" % (_C.sm.__code__.co_firstlineno + 2,)
+
+# Class disassembling info has an extra newline at end.
+dis_c = """\
+Disassembly of %s:
+%s
+Disassembly of %s:
+%s
+Disassembly of %s:
+%s
+""" % (_C.__init__.__name__, dis_c_instance_method,
+       _C.cm.__name__, dis_c_class_method,
+       _C.sm.__name__, dis_c_static_method)
+
 def _f(a):
     print(a)
     return 1
@@ -311,13 +350,22 @@
     def test_disassemble_bytes(self):
         self.do_disassembly_test(_f.__code__.co_code, dis_f_co_code)
 
-    def test_disassemble_method(self):
+    def test_disassemble_class(self):
+        self.do_disassembly_test(_C, dis_c)
+
+    def test_disassemble_instance_method(self):
         self.do_disassembly_test(_C(1).__init__, dis_c_instance_method)
 
-    def test_disassemble_method_bytes(self):
+    def test_disassemble_instance_method_bytes(self):
         method_bytecode = _C(1).__init__.__code__.co_code
         self.do_disassembly_test(method_bytecode, dis_c_instance_method_bytes)
 
+    def test_disassemble_static_method(self):
+        self.do_disassembly_test(_C.sm, dis_c_static_method)
+
+    def test_disassemble_class_method(self):
+        self.do_disassembly_test(_C.cm, dis_c_class_method)
+
     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
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -256,6 +256,9 @@
 Library
 -------
 
+- Issue #26733: Disassembling a class now disassembles class and static methods.
+  Patch by Xiang Zhang.
+
 - Issue #26801: Fix error handling in :func:`shutil.get_terminal_size`, catch
   :exc:`AttributeError` instead of :exc:`NameError`. Patch written by Emanuel
   Barry.

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


More information about the Python-checkins mailing list