Skip to content

Commit

Permalink
bpo-45168: change dis output to omit missing values rather than repla…
Browse files Browse the repository at this point in the history
…cing them by their index (GH-28313)
  • Loading branch information
iritkatriel committed Sep 14, 2021
1 parent c2f1e95 commit c99fc4e
Show file tree
Hide file tree
Showing 4 changed files with 28 additions and 19 deletions.
5 changes: 3 additions & 2 deletions Doc/library/dis.rst
Expand Up @@ -293,12 +293,13 @@ details of bytecode instructions as :class:`Instruction` instances:

.. data:: argval

resolved arg value (if known), otherwise same as arg
resolved arg value (if any), otherwise ``None``


.. data:: argrepr

human readable description of operation argument
human readable description of operation argument (if any),
otherwise an empty string.


.. data:: offset
Expand Down
25 changes: 16 additions & 9 deletions Lib/dis.py
Expand Up @@ -125,6 +125,13 @@ def pretty_flags(flags):
names.append(hex(flags))
return ", ".join(names)

class _Unknown:
def __repr__(self):
return "<unknown>"

# Sentinel to represent values that cannot be calculated
UNKNOWN = _Unknown()

def _get_code_object(x):
"""Helper to handle methods, compiled or raw code objects, and strings."""
# Extract functions from methods.
Expand Down Expand Up @@ -315,28 +322,28 @@ def _get_const_info(const_index, const_list):
Returns the dereferenced constant and its repr if the constant
list is defined.
Otherwise returns the constant index and its repr().
Otherwise returns the sentinel value dis.UNKNOWN for the value
and an empty string for its repr.
"""
argval = const_index
if const_list is not None:
argval = const_list[const_index]
return argval, repr(argval)
return argval, repr(argval)
else:
return UNKNOWN, ''

def _get_name_info(name_index, get_name, **extrainfo):
"""Helper to get optional details about named references
Returns the dereferenced name as both value and repr if the name
list is defined.
Otherwise returns the name index and its repr().
Otherwise returns the sentinel value dis.UNKNOWN for the value
and an empty string for its repr.
"""
argval = name_index
if get_name is not None:
argval = get_name(name_index, **extrainfo)
argrepr = argval
return argval, argval
else:
argrepr = repr(argval)
return argval, argrepr

return UNKNOWN, ''

def parse_varint(iterator):
b = next(iterator)
Expand Down
16 changes: 8 additions & 8 deletions Lib/test/test_dis.py
Expand Up @@ -48,12 +48,12 @@ def cm(cls, x):
""" % (_C.__init__.__code__.co_firstlineno + 1,)

dis_c_instance_method_bytes = """\
0 LOAD_FAST 1 (1)
2 LOAD_CONST 1 (1)
0 LOAD_FAST 1
2 LOAD_CONST 1
4 COMPARE_OP 2 (==)
6 LOAD_FAST 0 (0)
8 STORE_ATTR 0 (0)
10 LOAD_CONST 0 (0)
6 LOAD_FAST 0
8 STORE_ATTR 0
10 LOAD_CONST 0
12 RETURN_VALUE
"""

Expand Down Expand Up @@ -105,11 +105,11 @@ def _f(a):


dis_f_co_code = """\
0 LOAD_GLOBAL 0 (0)
2 LOAD_FAST 0 (0)
0 LOAD_GLOBAL 0
2 LOAD_FAST 0
4 CALL_FUNCTION 1
6 POP_TOP
8 LOAD_CONST 1 (1)
8 LOAD_CONST 1
10 RETURN_VALUE
"""

Expand Down
@@ -0,0 +1 @@
Change :func:`dis.dis` output to omit op arg values that cannot be resolved due to ``co_consts``, ``co_names`` etc not being provided. Previously the oparg itself was repeated in the value field, which is not useful and can be confusing.

0 comments on commit c99fc4e

Please sign in to comment.