Interactively run script blocs in IPython - ipython

Working with terminals only, is there a way to select script blocs by line ranges and run them in IPython?
Something like %run -r 35-48 thescript.py?
I understand that ipython -i, %edit and %loadpy offer ways to run scripts interactively, but I'd like to progress through the script without loading it upfront, in other words, have the namespace built as I progress through the script, bloc by bloc.
For example, I'd have one terminal with the script open in vim & set number, tweak & save as needed, and on the other terminal I'd run ipython from which I'd select line ranges to run (and build the namespace as I go along).

Seems like the answer to the question is "No":
http://mail.scipy.org/pipermail/ipython-user/2011-December/008796.html

Related

Editing WSL2 instance of Ubuntu Crontab using Windows VSCode

My question is whether it is possible to edit the crontab of a WSL2-based instance of Ubuntu with my Windows VSCode that is connected via WSL remote SSH.
If I type export EDITOR=code inside my WSL instance and then crontab -e, I am able to see a /tmp/crontab.sygFAU file load inside my VSCode instance.
The problem is that once I make edits to this file, it will save the file to /tmp/crontab.sysFAU but it doesn't actually take the next step of replacing the the real crontab file in /var/spool/cron/crontabs.
So once I re-open the crontab, it will just show what I had previously, and not my saved edits.
It would be nice to know if this is not possible or if there are any alternative ways to run a GUI editor because using nano is a pain!
An interesting question that I haven't considered before, myself. Here's what's happening:
You set your editor to code
You crontab -e, which properly loads VSCode with the temporary crontab.
However, because this is a Windows GUI application, it returns control to the parent Linux application (crontab) immediately after starting VSCode. You can see the same result if you just start notepad.exe from your shell in WSL -- Once Notepad starts (rather than exits) control is returned to the shell.
If you switch back to your terminal at this point, you'll see that crontab detected that the editor that it launched exited (returned), and so it has already tried to copy the temporary file to the permanent location.
However, since the temporary files doesn't yet have any changes, crontab decides there's nothing to do.
Editing the file in VSCode and saving it has no effect, other than to leave a dangling /tmp/... file hanging around (since crontab isn't there to clean up).
So what's the solution? We need a way to launch a Windows GUI application and prevent it from returning control to crontab until you are done editing.
I originally thought something from this question might work, but the problem is that the actual command that launches the Windows process is embedded in a shell script, which you can see with less "$(which code)" (or code "$(which code)"), but it's probably not a great idea to edit this.
So the next-best thing I came up with is a simple "wrapper" script around the (already-a-wrapper) code command. Create ~/.local/bin/code_no_fork.sh (could be anywhere) with:
#!/usr/bin/env bash
code $* > /dev/null
echo Press Spacebar to continue
read -r -s -d ' '
Credit: This answer for the Spacebar approach
Then:
EDITOR=~/.local/bin/code_no_fork crontab -e
After you make your edits in VSCode, simply press Space to allow the script to continue/exit, at which point crontab will (assuming no errors were detected) install the new Crontab.
Alternatives
This is should typically only be a problem with Windows GUI applications, so the other possible avenue is to simply use any Linux editor that doesn't fork. If you want a GUI editor, that's entirely possible as long as you are running a WSL release that includes WSLg support (now available for Windows 10 and 11).
I won't offer any individual editor suggestions since that would get into "opinion" and "software recommendation" territory, which is off-topic here.

In Jupyter Notebooks on Google Colab, what's the difference between using % and ! to run a shell command?

Question is in the title.
I know that % usually denotes a "magic variable" in IPython. That's not a concept I'm terribly familiar with yet, but I have read about it.
However, today I saw a tutorial where someone was using it to run a shell command. Normally I have seen and used !.
Is there a difference? Both seem to be doing the same thing when I try them.
The difference is this:
When you run a command with !, it directly executes a bash command in a subshell.
When you run a command with %, it executes one of the magic commands defined in IPython.
Some of the magic commands defined by IPython deliberately mirror bash commands, but they differ in the implementation details.
For example, running the !cd bash command does not persistently change your directory, because it runs in a temporary subshell. However, running the %cd magic command will persistently change your directory:
!pwd
# /content
!cd sample_data/
!pwd
# /content
%cd sample_data/
!pwd
# /content/sample_data
Read more in IPython: Built-in Magic Commands.

ipython magic/macro/alias guidance for invoking shell and dispatching result

(Note: I have plenty of python and unix shell experience, but fairly new to ipython -- using 7.5)
I'm trying to replicate a UNIX shell function that I use all the time, so that it works in the ipython shell.
The requirement is that I want to type something like to myproj, and then have ipython process the resulting text by doing a cd to the directory that comes back from to. (This is a quick-directory-change utility I use in unix)
The way it works in unix is that a shell function invokes an external command, that command prints its result to stdout, and the shell function then invokes the internal cd to the target dir.
I've been trying to wrap my head around %magic and macros and aliases in ipython, but so far I don't see how to get this done. Any ideas?

IPython: run script starting from a specific line

I am writing my script interactively with IPython. This is what I currently do:
write a chunk of code,
run in ipython with "run -i file_name.py".
make changes and repeat 2 until I think it is OK .
comment out the entire previous chunk.
write new chunk of code that is based on the previous one.
go back to step 2.
......
Is there more efficient way? Can I start a script from a specific line while using all the variables in current namespace?
Use ipdb ("pip install ipdb" on the command line to install it).
Suppose you want to run script "foo.py" from line 18 to 23.
You'll want to start like this:
ipdb foo.py
Now, let's jump to line 18 (i.e., ignore all the lines before the 18th):
ipdb> j 18
Next, we set a breakpoint at line 23 (we don't want to go further):
ipdb> b 23
Finally, let's execute:
ipdb> c
Job done :)
I'd personally also use the ipython notebook, but you call also use you favorite text editor and always copy out the chunk of code you want to run and use the magic command %paste to run that chunk in the ipython shell. It will take care of indentation for you.
Use the magic of %edit stuff.py (first use) and %ed -p (after the first use) and it will invoke your $EDITOR from inside of ipython. Upon exiting from the editor ipython will run the script (unless you called %ed -x). That is by far the fastest way I found to work in CLI-ipython. The notebooks are nice, but I like having a real editor for code.
(Based on lev's answer)
From the interactive shell:
%run -i -d foo.py
should then enter the debugger, and proceed with:
j <line_number>
c
etc.
EDIT: unfortunately, this seems to sort of break ipython's magic %debug command.
An IPython Notebook allows you to interactively run scripts line by line. It comes with IPython, just run:
ipython notebook
from the terminal to launch it. Its a web interface to IPython, where you can save the notebooks to *.py files by clicking save as in the settings.
Here's some more info from this video.
For something fast as well as flexible use http://qtconsole.readthedocs.io/en/stable/
It is similar to the Jupyter notebook based on your browsers (as pointed out by #agonti and #magellan88, but presumably much faster. It also has emacs style keybindings.
I use ipdb, ipython, comupled with tmux and vim and get almost IDE like features and much faster.

Interacting with IPython kernel from a Bash script

Is it possible to interact with an IPython interactive session (or with a kernel) from a Bash script? Ideally, I'd like to do something like this, within a shell script (I'm aware that the send subcommand probably doesn't exist like this):
# do stuff in Bash ...
# start a kernel and get its Id
KERNEL=`ipython init --command="print(__KERNELID__)"`
# do something inside the kernel
ipython send --kernel=KERNELID --command="mylist = [0,1,2]"
Then, ideally, the command
ipython send --kernel=KERNELID --command="print(mylist)"
would output
[0, 1, 2]
In the end, I would need to destroy the kernel somehow:
ipython --kernel=KERNELID --command="sys.exit()"
Probably, there is already a mechanism to do what I'd like,
right? Unfortunately, I wasn't able to find it ...
There are quite a number of ways around this problem. Since you are having to use python you might as well use python for the whole thing. Python programs can take command line arguments like mylist and do whatever you want with them.
Since you are sending commands to be evaluated make sure you are the one controlling the inputs. Don't let someone start typing "import os" and "os.unlink([your hard drive here])" for example.
For other options: Check out expect for your interactive needs http://expect.sourceforge.net/
or just the python version check out the pexpect module http://pexpect.sourceforge.net/pexpect.html