Repository: ipython/ipython (Python)

Issue:
IPython 7.6 problem with %%time
In IPython 7.6, the `%%time` magic is messing with the workspace. Looks like the last variable is never assigned in the workspace. This is a pretty serious error.

IPython 7.5.0 worked fine, so I assume it's related to https://github.com/ipython/ipython/pull/11716/. Also works fine when there's exactly one statement inside the cell.

```
In [1]:
%%time
a = 1
b = 2
c = 3
```

Wall time: 0 ns

```
In [2]:
a, b, c
```

```
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-2-6fd489e9d195> in <module>
----> 1 a, b, c

NameError: name 'c' is not defined
```


Discussion:
Thanks for the report (this an previous issue), 
I'll try to get a fix and a minor release soon.
Do you mind trying #11812 ? If it fixes it; I'll try to make a release before Friday.
7.6.1 should now be released with a fix.
Thanks. It's working fine now.



Patch:
diff --git a/IPython/core/magics/execution.py b/IPython/core/magics/execution.py
index 0a7ea0ef548..9031e470c32 100644
--- a/IPython/core/magics/execution.py
+++ b/IPython/core/magics/execution.py
@@ -1281,13 +1281,11 @@ def time(self,line='', cell=None, local_ns=None):
             mode = 'exec'
             source = '<timed exec>'
             # multi-line %%time case
-            if len(expr_ast.body) > 1 :
-                expr_val=expr_ast.body[-1]
-                code_val = self.shell.compile(ast.Expression(expr_val.value)
-                                                , '<timed eval>'
-                                                , 'eval')
-                expr_ast=expr_ast.body[:-1]
+            if len(expr_ast.body) > 1 and isinstance(expr_ast.body[-1], ast.Expr):
+                expr_val= expr_ast.body[-1]
+                expr_ast = expr_ast.body[:-1]
                 expr_ast = Module(expr_ast, [])
+                expr_val = ast.Expression(expr_val.value)
 
         t0 = clock()
         code = self.shell.compile(expr_ast, source, mode)
@@ -1312,8 +1310,9 @@ def time(self,line='', cell=None, local_ns=None):
                 exec(code, glob, local_ns)
                 out=None
                 # multi-line %%time case
-                if expr_val and isinstance(expr_val, ast.Expr):
-                    out = eval(code_val, glob, local_ns)  
+                if expr_val is not None:
+                    code_2 = self.shell.compile(expr_val, source, 'eval')
+                    out = eval(code_2, glob, local_ns)
             except:
                 self.shell.showtraceback()
                 return
diff --git a/docs/source/whatsnew/version7.rst b/docs/source/whatsnew/version7.rst
index 8924d859b1a..938bd45cea7 100644
--- a/docs/source/whatsnew/version7.rst
+++ b/docs/source/whatsnew/version7.rst
@@ -2,6 +2,15 @@
  7.x Series
 ============
 
+.. _version761:
+
+IPython 7.6.1
+=============
+
+IPython 7.6.1 contain a critical bugfix in the ``%timeit`` magic, which would
+crash on some inputs as a side effect of :ghpull:`11716`. See :ghpull:`11812`
+
+
 .. _whatsnew760:
 
 IPython 7.6.0
@@ -24,7 +33,7 @@ Python 3.8.
      should decrease startup time. :ghpull:`11693`
    - Autoreload now update the types of reloaded objects; this for example allow
      pickling of reloaded objects. :ghpull:`11644`
-   - Fix a big where ``%%time`` magic would suppress cell output. :ghpull:`11716`
+   - Fix a bug where ``%%time`` magic would suppress cell output. :ghpull:`11716`
 
 
 Prepare migration to pytest (instead of nose) for testing


Test patch:
diff --git a/IPython/core/tests/test_magic.py b/IPython/core/tests/test_magic.py
index e137c931179..3206b19a2e5 100644
--- a/IPython/core/tests/test_magic.py
+++ b/IPython/core/tests/test_magic.py
@@ -400,6 +400,15 @@ def test_time():
         with tt.AssertPrints("hihi", suppress=False):
             ip.run_cell("f('hi')")
 
+def test_time_last_not_expression():
+    ip.run_cell("%%time\n"
+                "var_1 = 1\n"
+                "var_2 = 2\n")
+    assert ip.user_ns['var_1'] == 1
+    del ip.user_ns['var_1']
+    assert ip.user_ns['var_2'] == 2
+    del ip.user_ns['var_2']
+    
 
 @dec.skip_win32
 def test_time2():