Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add new interactivity mode for ast. #10598

Merged
merged 1 commit into from
Jun 1, 2017

Conversation

Carreau
Copy link
Member

@Carreau Carreau commented May 24, 2017

Allow to display the result of the last assignment of it has a unique
target.

meh, I should write tests for that.

@Carreau
Copy link
Member Author

Carreau commented May 24, 2017

@rgbkrk though on that ? I though about that because display() is long to type and I often do

df = some_operation(df)
df 

Just to display it.

Up until 6.0 the following code wouldn't show the value of the assigned
variable:

>>> var = "something"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My brain almost broke because it was in JS mode while reading this.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can change for let if you want ?

@rgbkrk
Copy link
Member

rgbkrk commented May 24, 2017

If this behavior exists, out of old Matlab habit I will append ; in hopes that it will not show the result by default.

I too do the operation then display it pretty often. I'd hate to have to figure out how to suppress output though.

@rgbkrk
Copy link
Member

rgbkrk commented May 24, 2017

Oh I see, this isn't the default setting, just a configurable. 🆒

@Carreau
Copy link
Member Author

Carreau commented May 24, 2017

yeah, of course it's not the default :-)

$ ipython --InteractiveShell.ast_node_interactivity='last_expr_or_assign'
Python 3.6.0 |Continuum Analytics, Inc.| (default, Dec 23 2016, 13:19:00)
Type 'copyright', 'credits' or 'license' for more information
IPython 6.1.0.dev -- An enhanced Interactive Python. Type '?' for help.

In [1]: a = 1;

In [2]: a = 1
Out[2]: 1

In [3]:

; works, you can also do a newline / pass or newline / None

@Carreau Carreau requested review from ivanov and takluyver May 24, 2017 20:55
if isinstance(nodelist[-1], ast.Assign):
asg = nodelist[-1]
if len(asg.targets) == 1:
nnode = ast.Expr(ast.Name(asg.targets[0].id, ast.Load()))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this will crash if you try to do a multiple assignment. When I parse something like (a, b) = (1, 2), I get an assignment with a length-1 list of targets whose only entry is an instance of ast.Tuple, which has no id:

In [5]: sys.version_info
Out[5]: sys.version_info(major=3, minor=5, micro=2, releaselevel='final', serial=0)

In [6]: %%ast
   ...: (a, b) = (1, 2)
   ...:
Module(
  body=[
    Assign(
      targets=[
        Tuple(
          elts=[
            Name(id='a', ctx=Store()),
            Name(id='b', ctx=Store()),
          ],
          ctx=Store(),
        ),
      ],
      value=Tuple(
        elts=[
          Num(1),
          Num(2),
        ],
        ctx=Load(),
      ),
    ),
  ],
)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(That %%ast magic comes from https://github.com/llllllllll/codetransformer/blob/master/codetransformer/__init__.py#L23-L35, btw. That might be relevant to your interests if you're working on ast stuff.)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, sweet. Thanks. Does it also define a pretty formatter for ast objects that are returned ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It doesn't at the moment, but that could be added pretty easily. The logic that does the actual formatting lives here: https://github.com/llllllllll/codetransformer/blob/master/codetransformer/utils/pretty.py#L31.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey ! ... it's not in the released version ! It's been merged a year ago, why no release?
1pns0e

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, TIL. @llllllllll we should probably do a codetransformer release...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Carreau Carreau force-pushed the ast-interactivity branch 2 times, most recently from 1f5d398 to 5260f5a Compare May 24, 2017 23:35
@Carreau
Copy link
Member Author

Carreau commented May 24, 2017

codetransformer 0.7.0 has been released

Thanks ! Though I'm on 3.6, so can't import it :-(

Pushed new commits that test the various behavior.

Copy link
Member

@takluyver takluyver left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work 👍

With the option ``InteractiveShell.ast_node_interactivity='last_expr_or_assign'``
you can now do::

>>> df = pandas.load_csv(...)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make this example match the others above? And use IPython prompts instead of >>>?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done.

@@ -2781,6 +2787,15 @@ def run_ast_nodes(self, nodelist, cell_name, interactivity='last_expr',
if not nodelist:
return

if interactivity == 'last_expr_or_assign':
if isinstance(nodelist[-1], ast.Assign):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is fine for getting this feature in and letting people experiment with it, but be aware that it won't catch a += 1 (which is an AugAssign node), or a : int = 1 (new in Python 3.6, AnnAssign node).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call. Fixed. It should work on all of these.

@Carreau Carreau force-pushed the ast-interactivity branch 2 times, most recently from 435916a to faaa345 Compare May 25, 2017 18:06
ip.run_cell('(u,v) = (41+1, 43-1)')

finally:
ip.run_cell('a = 1+1', store_history=True)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this in the finally block?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No reasons, bad copy past likely. Fixed.

@Carreau Carreau modified the milestone: 6.2 May 29, 2017
@Carreau
Copy link
Member Author

Carreau commented May 29, 2017

@fperez would prefer for this to not assign to Out[] and _.
I'm unsure about that. So I can rewrite the Ast to actually do display(ast_name).
I'll see what I can do.

@Carreau
Copy link
Member Author

Carreau commented May 29, 2017

Hum inject something at the end like that:

In [10]: %%ast
    ...: __import__('IPython').display.display(whatever)
Module(
  body=[
    Expr(
      value=Call(
        func=Attribute(
          value=Attribute(
            value=Call(
              func=Name(id='__import__', ctx=Load()),
              args=[
                Str(
                  s='IPython',
                ),
              ],
              keywords=[],
            ),
            attr='display',
            ctx=Load(),
          ),
          attr='display',
          ctx=Load(),
        ),
        args=[
          Name(id='whatever', ctx=Load()),
        ],
        keywords=[],
      ),
    ),
  ],
)

At the same time when the expression of a of a cell display something there is always an Out[], so I"m unsure.

@takluyver
Copy link
Member

If we're injecting display() into the builtins, that could be simpler. Although then I guess it would be susceptible to someone overriding display =.

Maybe there's a nicer way to do this - instead of modifying the AST, inspect it to find the target of the final assignment, and then record some information which says 'if this code completes successfully, print the value of foo'.

@Carreau
Copy link
Member Author

Carreau commented May 30, 2017

Maybe there's a nicer way to do this - instead of modifying the AST, inspect it to find the target of the final assignment, and then record some information which says 'if this code completes successfully, print the value of foo'

Well that's almost exactly what the above do. it calls display on the last assignment target.

Here is my argument against having it displayed and not triggerd as part of display hook.

One the the two below methods are doing

def load_something():
    display(...)

The other

def load_somethingelse():
    return ...
$ ipython
Python 3.6.0 |Continuum Analytics, Inc.| (default, Dec 23 2016, 13:19:00)
Type 'copyright', 'credits' or 'license' for more information
IPython 6.1.0.dev -- An enhanced Interactive Python. Type '?' for help.

In [1]: %config TerminalInteractiveShell.ast_node_interactivity='display_last_expr_or_assign'
In [2]: from dummymod import load_cars, load_iris

In [3]: a = load_iris()

=================
 Id    |  types
=================
1      |    A
2      |    B
3      |    A
None

In [4]: b = load_cars()

=================
 Id    |  types
=================
I      |    E
II     |    F
III    |    G

With the current implementation that would be disambiguated by having (or not) an Out:

In [6]: a = load_iris()

=================
 Id    |  types
=================
1      |    A
2      |    B
3      |    A

In [7]: b = load_cars()
Out[7]:

=================
 Id    |  types
=================
I      |    E
II     |    F
III    |    G

Well now both are implemented so I can push 2 options.

@rgbkrk
Copy link
Member

rgbkrk commented May 30, 2017

Ok I'm totally going to set this in my personal defaults.

@Carreau
Copy link
Member Author

Carreau commented May 30, 2017

Note, the current code will also not work if the LHS is an arbitrary assignment like a.b = 1

@Carreau
Copy link
Member Author

Carreau commented May 30, 2017

So @fperez agree with the original proposal. I'm going to revert ca387c8

you can now do::

In[2]: xyz = "something else"
"something else"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This example (and the second one above) should have an Out[2]: prompt, right?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes ! I s/>>>/In[1] stupidly.

Allow to display the result of the last assignment of it has a unique
target.
@Carreau
Copy link
Member Author

Carreau commented Jun 1, 2017

Now that 6.1 is released, I'm getting this in to play with it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants