@@ -2680,6 +2680,7 @@ def test_specialized_code(self):
26802680 for flag in ['-S' , '--specialized' ]:
26812681 self .check_output (source , expect , flag )
26822682
2683+
26832684@force_colorized_test_class
26842685class DisColoredTests (unittest .TestCase ):
26852686 def get_colored_output (self , func ):
@@ -2690,55 +2691,132 @@ def get_colored_output(self, func):
26902691
26912692 return output .getvalue ()
26922693
2693- def assertOpColored (self , output , opname , color ):
2694- self .assertIn (
2695- f"{ color } { opname } " , output ,
2696- f"{ opname } should be colored with { color !r} "
2697- )
2694+ def _check_colored (self , output , opname , color , as_not_colored ):
2695+ # allow spaces, ANSI colors etc.
2696+ inter_word_pattern = r"(?:\s|\x1b\[[0-9;]*m)*"
26982697
2699- def test_load_ops_colored (self ):
2700- def f (a ):
2701- return a
2702- out = self .get_colored_output (f )
2703- self .assertOpColored (out , "LOAD_FAST" , theme .op_load )
2698+ tokens = opname .split ()
2699+ escaped_tokens = [re .escape (token ) for token in tokens ]
2700+ joined_opname = inter_word_pattern .join (escaped_tokens )
27042701
2705- def test_call_return_ops_colored (self ):
2706- def f ():
2707- return 1
2708- out = self .get_colored_output (f )
2709- self .assertOpColored (out , "RETURN_VALUE" , theme .op_call_return )
2710- self .assertOpColored (out , "RESUME" , theme .op_call_return )
2702+ pattern = re .escape (color ) + inter_word_pattern + joined_opname
2703+
2704+ if as_not_colored :
2705+ self .assertNotRegex (
2706+ output ,
2707+ pattern ,
2708+ f"{ opname } should NOT be colored with { color !r} " ,
2709+ )
2710+ else :
2711+ self .assertRegex (
2712+ output , pattern , f"{ opname } should be colored with { color !r} "
2713+ )
27112714
2712- def test_pop_ops_colored (self ):
2715+ def assertOpColoredAs (self , output , opname , color ):
2716+ self ._check_colored (output , opname , color , as_not_colored = False )
2717+
2718+ def assertOpNotColoredAs (self , output , opname , wrong_color ):
2719+ self ._check_colored (output , opname , wrong_color , as_not_colored = True )
2720+
2721+ def test_opname_and_arg_colored (self ):
27132722 def f (a ):
2714- print (a )
2723+ return a
2724+
27152725 out = self .get_colored_output (f )
2716- self .assertOpColored (out , "POP_TOP" , theme .op_pop )
2726+ self .assertOpColoredAs (out , "LOAD_FAST_BORROW" , theme .opname )
2727+ self .assertOpColoredAs (out , "RETURN_VALUE" , theme .opname )
2728+ self .assertOpColoredAs (out , "0" , theme .arg )
27172729
27182730 def test_control_flow_ops_colored (self ):
27192731 def f (a ):
27202732 for _ in a :
27212733 pass
2734+
27222735 out = self .get_colored_output (f )
2723- self .assertOpColored (out , "FOR_ITER" , theme .op_control_flow )
2724- self .assertOpColored (out , "JUMP_BACKWARD" , theme .op_control_flow )
27252736
2726- def test_argrepr_colored (self ):
2737+ self .assertOpNotColoredAs (out , "FOR_ITER" , theme .opname )
2738+ self .assertOpNotColoredAs (out , "END_FOR" , theme .opname )
2739+
2740+ self .assertOpColoredAs (out , "FOR_ITER" , theme .opname_with_label )
2741+ self .assertOpColoredAs (out , "END_FOR" , theme .opname_with_label )
2742+
2743+ opnames = (
2744+ "RESUME" ,
2745+ "LOAD_FAST" ,
2746+ "GET_ITER" ,
2747+ "STORE_FAST" ,
2748+ "JUMP_BACKWARD" ,
2749+ "POP_ITER" ,
2750+ "LOAD_COMMON_CONSTANT" ,
2751+ "RETURN_VALUE" ,
2752+ )
2753+
2754+ for opname in opnames :
2755+ self .assertOpColoredAs (out , opname , theme .opname )
2756+
2757+ def test_jump_targets_colored (self ):
2758+ # sample code from:
2759+ # https://github.com/python/cpython/pull/144208#issuecomment-5375286176
2760+ def f (a , c ):
2761+ _t2 .d if (
2762+ _t2 := (
2763+ _t1
2764+ if (_t1 := a .b if a is not None else None ) is not None
2765+ else c
2766+ )
2767+ ) is not None else None
2768+
2769+ out = self .get_colored_output (f )
2770+
2771+ for n in range (1 , 6 ):
2772+ self .assertOpColoredAs (out , f"L{ n } :" , theme .jump_target )
2773+ self .assertIn (f"(to { theme .jump_target } L{ n } { theme .reset } )" , out )
2774+
2775+ cases = (
2776+ "L1: LOAD_COMMON_CONSTANT" ,
2777+ "L2: COPY" ,
2778+ "L3: LOAD_FAST" ,
2779+ "L4: COPY" ,
2780+ "L5: LOAD_COMMON_CONSTANT" ,
2781+ )
2782+
2783+ for part in cases :
2784+ self .assertOpColoredAs (out , part , theme .jump_target )
2785+
2786+ def test_exception_table_colored (self ):
27272787 def f (a ):
2728- print (a )
2788+ try :
2789+ a
2790+ except Exception :
2791+ pass
2792+ else :
2793+ return a
2794+
27292795 out = self .get_colored_output (f )
2730- self .assertIn (f"{ theme .argument_detail } (" , out )
2731-
2732- def test_color_by_opname_coverage (self ):
2733- self .assertEqual (theme .color_by_opname ("LOAD_FAST" ), theme .op_load )
2734- self .assertEqual (theme .color_by_opname ("LOAD_GLOBAL" ), theme .op_load )
2735- self .assertEqual (theme .color_by_opname ("POP_TOP" ), theme .op_pop )
2736- self .assertEqual (theme .color_by_opname ("CALL" ), theme .op_call_return )
2737- self .assertEqual (theme .color_by_opname ("RETURN_VALUE" ), theme .op_call_return )
2738- self .assertEqual (theme .color_by_opname ("RESUME" ), theme .op_call_return )
2739- self .assertEqual (theme .color_by_opname ("FOR_ITER" ), theme .op_control_flow )
2740- self .assertEqual (theme .color_by_opname ("JUMP_BACKWARD" ), theme .op_control_flow )
2741- self .assertEqual (theme .color_by_opname ("BINARY_OP" ), theme .reset ) # uncolored
2796+
2797+ cases = (
2798+ ("L1" , "L2" , "L3" ),
2799+ ("L3" , "L4" , "L8" ),
2800+ ("L5" , "L6" , "L8" ),
2801+ ("L7" , "L8" , "L8" ),
2802+ )
2803+
2804+ def assertExceptionTableRow (pairs , out ):
2805+ p1 , p2 , p3 = pairs
2806+ part = f"{ theme .jump_target } { p1 } { theme .reset } to { theme .jump_target } { p2 } { theme .reset } -> { theme .jump_target } { p3 } { theme .reset } "
2807+ self .assertIn (part , out )
2808+
2809+ for pairs in cases :
2810+ assertExceptionTableRow (pairs , out )
2811+
2812+ cases = (
2813+ "L3: PUSH_EXC_INFO" ,
2814+ "L6: POP_EXCEPT" ,
2815+ "L7: RERAISE" ,
2816+ )
2817+
2818+ for part in cases :
2819+ self .assertOpColoredAs (out , part , theme .jump_target )
27422820
27432821if __name__ == "__main__" :
27442822 unittest .main ()
0 commit comments