Skip to content

adding ipython interpreter option for developers#20329

Merged
scheibelp merged 10 commits intospack:developfrom
vsoch:add/ipython
Jan 6, 2021
Merged

adding ipython interpreter option for developers#20329
scheibelp merged 10 commits intospack:developfrom
vsoch:add/ipython

Conversation

@vsoch
Copy link
Copy Markdown
Member

@vsoch vsoch commented Dec 10, 2020

This is a small pull request to add an option to use an ipython interpreter for developers, which is my preference (and maybe others too?) Basically, you can specify it like this:

$ spack python -i ipython
Python 3.8.3 (default, May 19 2020, 18:47:26) 
Type 'copyright', 'credits' or 'license' for more information
IPython 7.17.0 -- An enhanced Interactive Python. Type '?' for help.


Spack version 0.16.0
Python 3.8.3, Linux x86_64

In [1]:

I replaced the console.runsource with a simple exec, since embed() essentially includes all the locals anyway. For running commands/files I force the user to use python, because while it works to use ipython, it doesn't make sense for a non-interactive use case.

This is my first PR in a long time so I suspect the formatting will be wrong, I'll follow up with fixes when the CI tells me I'm a wet noodle.

@alalazo alalazo added feature A feature is missing in Spack proposal labels Dec 11, 2020
Copy link
Copy Markdown
Member

@adamjstewart adamjstewart left a comment

Choose a reason for hiding this comment

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

This is great! I imagine a lot of other users will like this. Since it adds a new feature, let's get at least one more core developer to review. Also pinging some heavy Python users: @trws @skosukhin

@scheibelp scheibelp self-assigned this Jan 4, 2021
Copy link
Copy Markdown
Member

@scheibelp scheibelp left a comment

Choose a reason for hiding this comment

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

I have a few requests relating to default behavior.

Also, is there an IPython executable? I'm wondering if we could get more flexibility by specifying the executable as an argument, modifying e.g. PYTHONPATH, and then launching the executable (vs. importing the relevant interpreter library) - that would allow supporting other interpreter options without modifying Spack.

@adamjstewart
Copy link
Copy Markdown
Member

Also, is there an IPython executable?

Yes, it's called ipython.

@vsoch
Copy link
Copy Markdown
Member Author

vsoch commented Jan 4, 2021

Also, is there an IPython executable? I'm wondering if we could get more flexibility by specifying the executable as an argument, modifying e.g. PYTHONPATH, and then launching the executable (vs. importing the relevant interpreter library) - that would allow supporting other interpreter options without modifying Spack.

This would definitely make sense for something that we cannot interact with via Python, but for these interpreters that's not the case so I'm not sure it's warranted yet. Also, we would need to be able to still provide the local environment with spack ready to go, which would be more challenging allowing for the user to specify any old executable. It's a cool idea, but maybe we should consider it when there is evidence that users want to use their own custom interpreter executables?

@vsoch
Copy link
Copy Markdown
Member Author

vsoch commented Jan 4, 2021

okay! I've updated the PR to more explicitly exit with an error message for the user when a combination of args is invalid (e.g., a command and anything other than ipython) or if ipython cannot be imported. See a691e9a.

the client should exit if the user provides an argument/command paired with
anything other than python, as it is not really logical. We also exit if
ipython is not able to be imported, vs. we previously switched over to
python instead and issued a warning.

Signed-off-by: vsoch <[email protected]>
@scheibelp
Copy link
Copy Markdown
Member

scheibelp commented Jan 5, 2021

(EDIT: this was already addressed by #20329 (comment))

Also, is there an IPython executable? I'm wondering if we could get more flexibility by specifying the executable as an argument, modifying e.g. PYTHONPATH, and then launching the executable (vs. importing the relevant interpreter library) - that would allow supporting other interpreter options without modifying Spack.

This would definitely make sense for something that we cannot interact with via Python, but for these interpreters that's not the case so I'm not sure it's warranted yet

This makes sense but are there interpreters other than IPython or the default Python which are available as imports? If not, I think -i should be a flag option rather than a user-specified option. -i would be a bit too succinct though so IMO the flag should be called --ipython

@vsoch
Copy link
Copy Markdown
Member Author

vsoch commented Jan 5, 2021

Yes, all the ones that I mentioned are available to be called interactively. If it's a Python library that gets called from the command line, logically there is a way to bypass the client and do from within Python. Here are a few examples for the ones I mentioned:

I think we should take this approach, the simplest one, until there is strong reason (user demand) to do otherwise.

@trws
Copy link
Copy Markdown
Contributor

trws commented Jan 5, 2021

This seems somewhat overfit to ipython to me personally, I think largely because of the fact the spack python command reuses the existing interpreter rather than executing a new one with the correct PYTHONPATH (which was on my list of things to try and fix actually). This would be ok with me if it's documented that the only supported interpreters for now are something like "current" and "ipython", so we can expand it out to take a generic path later for things like pypy, iron python etc. later.

Copy link
Copy Markdown
Member

@scheibelp scheibelp left a comment

Choose a reason for hiding this comment

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

I think the only thing needed here is updating the documentation in line with the updated error behavior.


just like you would with the normal ``python`` command.
just like you would with the normal ``python`` command. Note that for both
commands and files, the default will always be the python interpreter,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

With new edits, -i ipython will through an error so I think comment can be updated accordingly.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

My bad, totally forgot about updating the docs! I'll do that now.

@scheibelp
Copy link
Copy Markdown
Member

scheibelp commented Jan 5, 2021

This would be ok with me if it's documented that the only supported interpreters for now are something like "current" and "ipython", so we can expand it out to take a generic path later for things like pypy, iron python etc. later.

@trws IMO the documentation added here was clear that only ipython was supported as an alternative. Is there a wording tweak you would suggest?

I also felt that this solution wouldn't get in the way of a set-PYTHONPATH-and-invoke-interpreter-executable-based solution, but let me know if you disagree.

to explicitly state that the options are 1) current python (default)
or 2) ipython. And show that commands/args must be done with python

Signed-off-by: vsoch <[email protected]>
@vsoch
Copy link
Copy Markdown
Member Author

vsoch commented Jan 5, 2021

I updated the docs to be consistent with the current implementation, and (hopefully) did a better job to address @trws about explicitly stating the two options. 849b4c5. I also used more consistent capitalization for Python and IPython.


Strange! GitHub links the commit to the repository here (with a message that the commit doesn't belong) but it should be linked to my fork, vsoch@849b4c5.

@trws
Copy link
Copy Markdown
Contributor

trws commented Jan 5, 2021

It probably won't get in the way. The docs seem to have some remaining issues though, in that spack python still runs an interactive repl with or without the flag (and thus is most definitely interactive capable), and line 417 seems to imply that spack python -i python results in IPython?

@vsoch
Copy link
Copy Markdown
Member Author

vsoch commented Jan 5, 2021

That was a typo, and having the redundancy is probably confusing. Fixed in c4ca219. The very first part of the section does mention that spack python is interactive, but for the script / command use case you wouldn't want it interactive, which is what I was trying to say, maybe I didn't do a good job? @trws is there a better way we could say this?

@vsoch
Copy link
Copy Markdown
Member Author

vsoch commented Jan 5, 2021

As a possible solution, I just removed the extra "clarification" (which wasn't very good, my bad!) about why we would only allow python for commands and scripts. It now just directly states the options without trying to explain them, which sounds much better I think.

Signed-off-by: vsoch <[email protected]>
@trws
Copy link
Copy Markdown
Contributor

trws commented Jan 5, 2021

The doc updates look good. 👍

The thing I'm contemplating now though is that while I occasionally use ipython, I almost never use it interactively. I normally use it to get better errors, or turn on its pdb integration and use it as a debugger, things like this:

❯ ipython ~/scripts/broken-script.py
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
~/scripts/at-home.py in <module>
      8 host = check_output("hostname", shell=True)
      9
---> 10 if 'hurricane' in host or 'gale' in host:
     11     sys.exit(0)
     12 if "typhoon" in host or "storm" in host or "bolt" in host:

TypeError: a bytes-like object is required, not 'str'

Why prevent this use?

@vsoch
Copy link
Copy Markdown
Member Author

vsoch commented Jan 5, 2021

The thing I'm contemplating now though is that while I occasionally use ipython, I almost never use it interactively. I normally use it to get better errors, or turn on its pdb integration and use it as a debugger, things like this:

Oh, interesting, I've never used it like that before! I typically just embed it everywhere to get an interactive session to develop and debug. @trws if I understand correctly, we should allow using ipython for the script use case (and string arguments as well?) and remove the checks that don't allow it?

@trws
Copy link
Copy Markdown
Contributor

trws commented Jan 5, 2021

If possible? I actually use embedding too, but usually by adding an embed() call into the script to break at that point. I may just be strange like that, but if it wouldn't impose a significant amount of extra work it would be really nice, especially for debugging spack itself come to think of it.

@vsoch
Copy link
Copy Markdown
Member Author

vsoch commented Jan 5, 2021

@trws I gave it a shot! 8fa2064. One thing I'm wondering about is if it should be allowed to run a command and a script. It seems to functionally work for python (and I tested for ipython but it's not included in the PR here) but I'm not sure it's working in practice. For example, let's say I have a script that prints the current working directory, but doesn't have the os import:

# script.py
print(os.getcwd())

If I run the script with the python interpreter, this is what I'd expect:

$ bin/spack python script.py 
Traceback (most recent call last):
  File "script.py", line 2, in <module>
    print(os.getcwd())
NameError: name 'os' is not defined

Arguably since the console command is run before the script, I should be able to add it, and then see the printing:

$ bin/spack python -c "import os" script.py
# nothing printed

It's not an issue of the import working, because I can change to sys (and I'd expect to see the error message again) but I don't:

$ bin/spack python -c "import sys" script.py
# nothing printed

The only thing that "works" at least to run and still produce the output is to have the -c argument handed as a python arg instead of to the spack argparser:

$ bin/spack python script.py -c "import os"
Traceback (most recent call last):
  File "script.py", line 2, in <module>
    print(os.getcwd())
NameError: name 'os' is not defined

But the import is still not done in context of the script.

So if this is a bug, while it's present we should check that both are defined in the parent function and cut out early if this is the case. If the user wants to run a command alongside a script, arguably it's just easiest to write it into the script. Let me know what you think!

@trws
Copy link
Copy Markdown
Contributor

trws commented Jan 5, 2021

Wow, I had not thought of that at all. So, doing a bit of similar testing with python the executable, it seems as though if you specify -c then the positional arguments are treated as arguments to the command rather than executed as scripts, so I suppose I would do that? Just looked at the documentation, it looks like -c terminates the argument list, so yeah probably simplify that way. Really interesting question, and I like the thought of being able to inject something like that too, but for this probably go for consistency.

@vsoch
Copy link
Copy Markdown
Member Author

vsoch commented Jan 5, 2021

So just to clarify, you think that we shouldn’t allow specifying both (the spack -c, not a -c to go to Python) and exit early if this is the case? This is my suggestion because having both doesn’t seem to work! And of course the user is free to test specifying -c after a command so it’s handed off to Python or IPython.

@vsoch
Copy link
Copy Markdown
Member Author

vsoch commented Jan 5, 2021

I just pushed a fix 75e5c83 to cut out early if both are specified. So this won't work:

$ spack python -c "import sys" script.py
==> Error: You can only specify a command OR script, but not both.

But this will, and the user is free to do whatever they like! Likely a separate command could be run first, independent of the script, but not something you expect to hand off to the script like an IPython embed.

$ bin/spack python script.py -c "import os"
Traceback (most recent call last):
  File "script.py", line 2, in <module>
    print(os.getcwd())
NameError: name 'os' is not defined

@scheibelp scheibelp merged commit 67ce193 into spack:develop Jan 6, 2021
@scheibelp
Copy link
Copy Markdown
Member

Thanks!

@vsoch
Copy link
Copy Markdown
Member Author

vsoch commented Jan 6, 2021

Wooo merged! Thanks y'all! :D

@trws
Copy link
Copy Markdown
Contributor

trws commented Jan 7, 2021

Thank you, good addition, and thanks for working through the feedback.

bollig pushed a commit to bollig/spack that referenced this pull request Jan 12, 2021
This adds a -i option to "spack python" which allows use of the
IPython interpreter; it can be used with "spack python -i ipython".
This assumes it is available in the Python instance used to run
Spack (i.e. that you can "import IPython").
loulawrence pushed a commit to loulawrence/spack that referenced this pull request Jan 19, 2021
This adds a -i option to "spack python" which allows use of the
IPython interpreter; it can be used with "spack python -i ipython".
This assumes it is available in the Python instance used to run
Spack (i.e. that you can "import IPython").
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

commands feature A feature is missing in Spack

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants