26
26
MAKE_FUNCTION = opmap ['MAKE_FUNCTION' ]
27
27
MAKE_FUNCTION_FLAGS = ('defaults' , 'kwdefaults' , 'annotations' , 'closure' )
28
28
29
+ LOAD_CONST = opmap ['LOAD_CONST' ]
29
30
30
31
def _try_compile (source , name ):
31
32
"""Attempts to compile the given source, first as an expression and
@@ -317,19 +318,32 @@ def get_instructions(x, *, first_line=None):
317
318
co .co_names , co .co_consts ,
318
319
linestarts , line_offset , co_positions = co .co_positions ())
319
320
320
- def _get_const_info (const_index , const_list ):
321
+ def _get_const_value (op , arg , co_consts ):
322
+ """Helper to get the value of the const in a hasconst op.
323
+
324
+ Returns the dereferenced constant if this is possible.
325
+ Otherwise (if it is a LOAD_CONST and co_consts is not
326
+ provided) returns the dis.UNKNOWN sentinel.
327
+ """
328
+ assert op in hasconst
329
+
330
+ argval = UNKNOWN
331
+ if op == LOAD_CONST :
332
+ if co_consts is not None :
333
+ argval = co_consts [arg ]
334
+ return argval
335
+
336
+ def _get_const_info (op , arg , co_consts ):
321
337
"""Helper to get optional details about const references
322
338
323
- Returns the dereferenced constant and its repr if the constant
324
- list is defined .
339
+ Returns the dereferenced constant and its repr if the value
340
+ can be calculated .
325
341
Otherwise returns the sentinel value dis.UNKNOWN for the value
326
342
and an empty string for its repr.
327
343
"""
328
- if const_list is not None :
329
- argval = const_list [const_index ]
330
- return argval , repr (argval )
331
- else :
332
- return UNKNOWN , ''
344
+ argval = _get_const_value (op , arg , co_consts )
345
+ argrepr = repr (argval ) if argval is not UNKNOWN else ''
346
+ return argval , argrepr
333
347
334
348
def _get_name_info (name_index , get_name , ** extrainfo ):
335
349
"""Helper to get optional details about named references
@@ -371,14 +385,14 @@ def parse_exception_table(code):
371
385
return entries
372
386
373
387
def _get_instructions_bytes (code , varname_from_oparg = None ,
374
- names = None , constants = None ,
388
+ names = None , co_consts = None ,
375
389
linestarts = None , line_offset = 0 ,
376
390
exception_entries = (), co_positions = None ):
377
391
"""Iterate over the instructions in a bytecode string.
378
392
379
393
Generates a sequence of Instruction namedtuples giving the details of each
380
394
opcode. Additional information about the code's runtime environment
381
- (e.g. variable names, constants ) can be specified using optional
395
+ (e.g. variable names, co_consts ) can be specified using optional
382
396
arguments.
383
397
384
398
"""
@@ -408,7 +422,7 @@ def _get_instructions_bytes(code, varname_from_oparg=None,
408
422
# raw name index for LOAD_GLOBAL, LOAD_CONST, etc.
409
423
argval = arg
410
424
if op in hasconst :
411
- argval , argrepr = _get_const_info (arg , constants )
425
+ argval , argrepr = _get_const_info (op , arg , co_consts )
412
426
elif op in hasname :
413
427
argval , argrepr = _get_name_info (arg , get_name )
414
428
elif op in hasjabs :
@@ -457,7 +471,7 @@ def _disassemble_recursive(co, *, file=None, depth=None):
457
471
_disassemble_recursive (x , file = file , depth = depth )
458
472
459
473
def _disassemble_bytes (code , lasti = - 1 , varname_from_oparg = None ,
460
- names = None , constants = None , linestarts = None ,
474
+ names = None , co_consts = None , linestarts = None ,
461
475
* , file = None , line_offset = 0 , exception_entries = (),
462
476
co_positions = None ):
463
477
# Omit the line number column entirely if we have no line number info
@@ -476,7 +490,7 @@ def _disassemble_bytes(code, lasti=-1, varname_from_oparg=None,
476
490
else :
477
491
offset_width = 4
478
492
for instr in _get_instructions_bytes (code , varname_from_oparg , names ,
479
- constants , linestarts ,
493
+ co_consts , linestarts ,
480
494
line_offset = line_offset , exception_entries = exception_entries ,
481
495
co_positions = co_positions ):
482
496
new_source_line = (show_lineno and
@@ -557,11 +571,13 @@ def _find_imports(co):
557
571
opargs = [(op , arg ) for _ , op , arg in _unpack_opargs (co .co_code )
558
572
if op != EXTENDED_ARG ]
559
573
for i , (op , oparg ) in enumerate (opargs ):
560
- if (op == IMPORT_NAME and i >= 2
561
- and opargs [i - 1 ][0 ] == opargs [i - 2 ][0 ] == LOAD_CONST ):
562
- level = consts [opargs [i - 2 ][1 ]]
563
- fromlist = consts [opargs [i - 1 ][1 ]]
564
- yield (names [oparg ], level , fromlist )
574
+ if op == IMPORT_NAME and i >= 2 :
575
+ from_op = opargs [i - 1 ]
576
+ level_op = opargs [i - 2 ]
577
+ if (from_op [0 ] in hasconst and level_op [0 ] in hasconst ):
578
+ level = _get_const_value (level_op [0 ], level_op [1 ], consts )
579
+ fromlist = _get_const_value (from_op [0 ], from_op [1 ], consts )
580
+ yield (names [oparg ], level , fromlist )
565
581
566
582
def _find_store_names (co ):
567
583
"""Find names of variables which are written in the code
@@ -635,7 +651,7 @@ def dis(self):
635
651
with io .StringIO () as output :
636
652
_disassemble_bytes (co .co_code ,
637
653
varname_from_oparg = co ._varname_from_oparg ,
638
- names = co .co_names , constants = co .co_consts ,
654
+ names = co .co_names , co_consts = co .co_consts ,
639
655
linestarts = self ._linestarts ,
640
656
line_offset = self ._line_offset ,
641
657
file = output ,
0 commit comments