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 | from logging import error |
|
79 | from logging import error | |
80 | import IPython.core.hooks |
|
80 | import IPython.core.hooks | |
81 |
|
81 | |||
|
82 | from typing import List as ListType | |||
|
83 | from ast import AST | |||
|
84 | ||||
82 | # NoOpContext is deprecated, but ipykernel imports it from here. |
|
85 | # NoOpContext is deprecated, but ipykernel imports it from here. | |
83 | # See https://github.com/ipython/ipykernel/issues/157 |
|
86 | # See https://github.com/ipython/ipykernel/issues/157 | |
84 | from IPython.utils.contexts import NoOpContext |
|
87 | from IPython.utils.contexts import NoOpContext | |
@@ -102,6 +105,13 b' class ProvisionalWarning(DeprecationWarning):' | |||||
102 | """ |
|
105 | """ | |
103 | pass |
|
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 | # Globals |
|
116 | # Globals | |
107 | #----------------------------------------------------------------------------- |
|
117 | #----------------------------------------------------------------------------- | |
@@ -376,11 +386,12 b' class InteractiveShell(SingletonConfigurable):' | |||||
376 | """ |
|
386 | """ | |
377 | ).tag(config=True) |
|
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 | default_value='last_expr', |
|
390 | default_value='last_expr', | |
381 | help=""" |
|
391 | help=""" | |
382 |
'all', 'last', 'last_expr' or 'none', specifying |
|
392 | 'all', 'last', 'last_expr' or 'none', 'last_expr_or_assign' specifying | |
383 |
run interactively (displaying output from expressions). |
|
393 | which nodes should be run interactively (displaying output from expressions). | |
|
394 | """ | |||
384 | ).tag(config=True) |
|
395 | ).tag(config=True) | |
385 |
|
396 | |||
386 | # TODO: this part of prompt management should be moved to the frontends. |
|
397 | # TODO: this part of prompt management should be moved to the frontends. | |
@@ -2749,7 +2760,7 b' class InteractiveShell(SingletonConfigurable):' | |||||
2749 | return node |
|
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 | compiler=compile, result=None): |
|
2764 | compiler=compile, result=None): | |
2754 | """Run a sequence of AST nodes. The execution mode depends on the |
|
2765 | """Run a sequence of AST nodes. The execution mode depends on the | |
2755 | interactivity parameter. |
|
2766 | interactivity parameter. | |
@@ -2762,11 +2773,13 b' class InteractiveShell(SingletonConfigurable):' | |||||
2762 | Will be passed to the compiler as the filename of the cell. Typically |
|
2773 | Will be passed to the compiler as the filename of the cell. Typically | |
2763 | the value returned by ip.compile.cache(cell). |
|
2774 | the value returned by ip.compile.cache(cell). | |
2764 | interactivity : str |
|
2775 | interactivity : str | |
2765 |
'all', 'last', 'last_expr' |
|
2776 | 'all', 'last', 'last_expr' , 'last_expr_or_assign' or 'none', | |
2766 | run interactively (displaying output from expressions). 'last_expr' |
|
2777 | specifying which nodes should be run interactively (displaying output | |
2767 | will run the last node interactively only if it is an expression (i.e. |
|
2778 | from expressions). 'last_expr' will run the last node interactively | |
2768 | expressions in loops or other blocks are not displayed. Other values |
|
2779 | only if it is an expression (i.e. expressions in loops or other blocks | |
2769 | for this parameter will raise a ValueError. |
|
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 | compiler : callable |
|
2783 | compiler : callable | |
2771 | A function with the same interface as the built-in compile(), to turn |
|
2784 | A function with the same interface as the built-in compile(), to turn | |
2772 | the AST nodes into code objects. Default is the built-in compile(). |
|
2785 | the AST nodes into code objects. Default is the built-in compile(). | |
@@ -2781,6 +2794,21 b' class InteractiveShell(SingletonConfigurable):' | |||||
2781 | if not nodelist: |
|
2794 | if not nodelist: | |
2782 | return |
|
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 | if interactivity == 'last_expr': |
|
2812 | if interactivity == 'last_expr': | |
2785 | if isinstance(nodelist[-1], ast.Expr): |
|
2813 | if isinstance(nodelist[-1], ast.Expr): | |
2786 | interactivity = "last" |
|
2814 | interactivity = "last" |
@@ -53,3 +53,51 b' def test_underscore_no_overrite_builtins():' | |||||
53 | ip.run_cell('print(_)', store_history=True) |
|
53 | ip.run_cell('print(_)', store_history=True) | |
54 | ip.run_cell('import builtins; del builtins._') |
|
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