##// END OF EJS Templates
Add new interactivity mode for ast....
Matthias Bussonnier -
Show More
@@ -0,0 +1,22 b''
1 IPython can now trigger the display hook on last assignment of cells.
2 Up until 6.0 the following code wouldn't show the value of the assigned
3 variable::
4
5 In[1]: xyz = "something"
6 # nothing shown
7
8 You would have to actually make it the last statement::
9
10 In [2]: xyz = "something else"
11 ... : xyz
12 Out[2]: "something else"
13
14 With the option ``InteractiveShell.ast_node_interactivity='last_expr_or_assign'``
15 you can now do::
16
17 In [2]: xyz = "something else"
18 Out[2]: "something else"
19
20 This option can be toggled at runtime with the ``%config`` magic, and will
21 trigger on assignment ``a = 1``, augmented assignment ``+=``, ``-=``, ``|=`` ...
22 as well as type annotated assignments: ``a:int = 2``.
@@ -79,6 +79,9 b' from warnings import warn'
79 79 from logging import error
80 80 import IPython.core.hooks
81 81
82 from typing import List as ListType
83 from ast import AST
84
82 85 # NoOpContext is deprecated, but ipykernel imports it from here.
83 86 # See https://github.com/ipython/ipykernel/issues/157
84 87 from IPython.utils.contexts import NoOpContext
@@ -102,6 +105,13 b' class ProvisionalWarning(DeprecationWarning):'
102 105 """
103 106 pass
104 107
108 if sys.version_info > (3,6):
109 _assign_nodes = (ast.AugAssign, ast.AnnAssign, ast.Assign)
110 _single_targets_nodes = (ast.AugAssign, ast.AnnAssign)
111 else:
112 _assign_nodes = (ast.AugAssign, ast.Assign )
113 _single_targets_nodes = (ast.AugAssign, )
114
105 115 #-----------------------------------------------------------------------------
106 116 # Globals
107 117 #-----------------------------------------------------------------------------
@@ -376,11 +386,12 b' class InteractiveShell(SingletonConfigurable):'
376 386 """
377 387 ).tag(config=True)
378 388
379 ast_node_interactivity = Enum(['all', 'last', 'last_expr', 'none'],
389 ast_node_interactivity = Enum(['all', 'last', 'last_expr', 'none', 'last_expr_or_assign'],
380 390 default_value='last_expr',
381 391 help="""
382 'all', 'last', 'last_expr' or 'none', specifying which nodes should be
383 run interactively (displaying output from expressions)."""
392 'all', 'last', 'last_expr' or 'none', 'last_expr_or_assign' specifying
393 which nodes should be run interactively (displaying output from expressions).
394 """
384 395 ).tag(config=True)
385 396
386 397 # TODO: this part of prompt management should be moved to the frontends.
@@ -2749,7 +2760,7 b' class InteractiveShell(SingletonConfigurable):'
2749 2760 return node
2750 2761
2751 2762
2752 def run_ast_nodes(self, nodelist, cell_name, interactivity='last_expr',
2763 def run_ast_nodes(self, nodelist:ListType[AST], cell_name:str, interactivity='last_expr',
2753 2764 compiler=compile, result=None):
2754 2765 """Run a sequence of AST nodes. The execution mode depends on the
2755 2766 interactivity parameter.
@@ -2762,11 +2773,13 b' class InteractiveShell(SingletonConfigurable):'
2762 2773 Will be passed to the compiler as the filename of the cell. Typically
2763 2774 the value returned by ip.compile.cache(cell).
2764 2775 interactivity : str
2765 'all', 'last', 'last_expr' or 'none', specifying which nodes should be
2766 run interactively (displaying output from expressions). 'last_expr'
2767 will run the last node interactively only if it is an expression (i.e.
2768 expressions in loops or other blocks are not displayed. Other values
2769 for this parameter will raise a ValueError.
2776 'all', 'last', 'last_expr' , 'last_expr_or_assign' or 'none',
2777 specifying which nodes should be run interactively (displaying output
2778 from expressions). 'last_expr' will run the last node interactively
2779 only if it is an expression (i.e. expressions in loops or other blocks
2780 are not displayed) 'last_expr_or_assign' will run the last expression
2781 or the last assignment. Other values for this parameter will raise a
2782 ValueError.
2770 2783 compiler : callable
2771 2784 A function with the same interface as the built-in compile(), to turn
2772 2785 the AST nodes into code objects. Default is the built-in compile().
@@ -2781,6 +2794,21 b' class InteractiveShell(SingletonConfigurable):'
2781 2794 if not nodelist:
2782 2795 return
2783 2796
2797 if interactivity == 'last_expr_or_assign':
2798 if isinstance(nodelist[-1], _assign_nodes):
2799 asg = nodelist[-1]
2800 if isinstance(asg, ast.Assign) and len(asg.targets) == 1:
2801 target = asg.targets[0]
2802 elif isinstance(asg, _single_targets_nodes):
2803 target = asg.target
2804 else:
2805 target = None
2806 if isinstance(target, ast.Name):
2807 nnode = ast.Expr(ast.Name(target.id, ast.Load()))
2808 ast.fix_missing_locations(nnode)
2809 nodelist.append(nnode)
2810 interactivity = 'last_expr'
2811
2784 2812 if interactivity == 'last_expr':
2785 2813 if isinstance(nodelist[-1], ast.Expr):
2786 2814 interactivity = "last"
@@ -2924,7 +2952,7 b' class InteractiveShell(SingletonConfigurable):'
2924 2952 self.pylab_gui_select = gui
2925 2953 # Otherwise if they are different
2926 2954 elif gui != self.pylab_gui_select:
2927 print ('Warning: Cannot change to a different GUI toolkit: %s.'
2955 print('Warning: Cannot change to a different GUI toolkit: %s.'
2928 2956 ' Using %s instead.' % (gui, self.pylab_gui_select))
2929 2957 gui, backend = pt.find_gui_and_backend(self.pylab_gui_select)
2930 2958
@@ -53,3 +53,51 b' def test_underscore_no_overrite_builtins():'
53 53 ip.run_cell('print(_)', store_history=True)
54 54 ip.run_cell('import builtins; del builtins._')
55 55
56
57 def test_interactivehooks_ast_modes():
58 """
59 Test that ast nodes can be triggerd with different modes
60 """
61 saved_mode = ip.ast_node_interactivity
62 ip.ast_node_interactivity = 'last_expr_or_assign'
63
64 try:
65 with AssertPrints('2'):
66 ip.run_cell('a = 1+1', store_history=True)
67
68 with AssertPrints('9'):
69 ip.run_cell('b = 1+8 # comment with a semicolon;', store_history=False)
70
71 with AssertPrints('7'):
72 ip.run_cell('c = 1+6\n#commented_out_function();', store_history=True)
73
74 ip.run_cell('d = 11', store_history=True)
75 with AssertPrints('12'):
76 ip.run_cell('d += 1', store_history=True)
77
78 with AssertNotPrints('42'):
79 ip.run_cell('(u,v) = (41+1, 43-1)')
80
81 finally:
82 ip.ast_node_interactivity = saved_mode
83
84 def test_interactivehooks_ast_modes_semi_supress():
85 """
86 Test that ast nodes can be triggerd with different modes and supressed
87 by semicolon
88 """
89 saved_mode = ip.ast_node_interactivity
90 ip.ast_node_interactivity = 'last_expr_or_assign'
91
92 try:
93 with AssertNotPrints('2'):
94 ip.run_cell('x = 1+1;', store_history=True)
95
96 with AssertNotPrints('7'):
97 ip.run_cell('y = 1+6; # comment with a semicolon', store_history=True)
98
99 with AssertNotPrints('9'):
100 ip.run_cell('z = 1+8;\n#commented_out_function()', store_history=True)
101
102 finally:
103 ip.ast_node_interactivity = saved_mode
General Comments 0
You need to be logged in to leave comments. Login now