ipython not reloading modules - python

I'm running IPython in an emacs shell using:
;; Set IPython interpreter in my init.el
(defvar python-shell-interpreter "ipython")
(defvar python-shell-interpreter-args "-i")
Then:
Start IPython with M-x run-python
Run a program within IPython with %run myprog.py. myprog.py imports a module called mymodule.
I make changes to mymodule but when I run %run myprog.py again, it runs the original mymodule, not the changed code.
FWIW, I'm using emacs 24.5 prelude, on Windows 10 with Anaconda and Python 3.5.

It turns out that IPython's %run command does not reload modules.
My current workaround is:
Add the code below to ~/.ipython/profile_default/ipython_config.py
Use $run myprog.py args
.
# this code in `~/.ipython/profile_default/ipython_config.py`
# get_config() is injected into the global namespace whilst
# config files are loaded
c = get_config()
# Autoreload modules
c.InteractiveShellApp.extensions = ['autoreload']
c.InteractiveShellApp.exec_lines = ['%autoreload 2']
I didn't realise that %run does not reload modules because I'm used to using Spyder's runfile command, which does. It's nuts that %run doesn't and I'd like to submit a patch to fix it at some point.
On Windows, the HOME environment variable must be set so that the run-python command in emacs can read the IPython profile. If HOME is not set, you can add this to your init.el:
(add-hook 'inferior-python-mode-hook (lambda ()
(progn
(python-shell-send-string-no-output "%load_ext autoreload")
(python-shell-send-string-no-output "%autoreload 2"))))

Related

IPython - running a script with %run command - saved to which folder?

I'm in IPython and want to run a simple python script that I've saved in a file called "test.py".
I'd like to use the %run test.py command to execute it inside IPython, but I don't know to which folder I need to save my test.py.
Also, how can I change that default folder to something else, for example C:\Users\user\foldername ?
I tried with the .ipython folder (original installation folder) but that's not working.
I found the answer:
import os
filepath = 'C:\\Users\\user\\foldername'
os.chdir(filepath)
%run test.py
%run myprogram works for Python scripts/programs.
To run any arbitrary programs, use ! as a prefix, e.g. !myprogram.
Many common shell commands/programs (cd, ls, less, ...) are also registered as IPython magic commands (run via %cd, %ls, ...), and also have registered aliases, so you can directly run them without any prefix, just as cd, ls, less, ...

Launch Python Shell with Predefined Imports and Settings

I am trying to set up a shell-launch script like this:
./practice.py
I intend to debug commands using various modules which can be tedious to import, set up oauth settings, etc.
How do I set example practice.py to launch with this sort of preset:
import module_x
import module_y
from module_z import something
a = something.settings(var_1='123', var_1='456')
>> #start doing stuff
You can use the PYTHONSTARTUP environmental variable. Quoting the documentation:
PYTHONSTARTUP
If this is the name of a readable file, the Python commands in
that file are executed before the first prompt is displayed in
interactive mode. The file is executed in the same namespace where
interactive commands are executed so that objects defined or imported
in it can be used without qualification in the interactive session.
You can also change the prompts sys.ps1 and sys.ps2 and the hook
sys.__interactivehook__ in this file.
How you set environmental variables depends on the OS.
Put a shebang at first line with interactive mode switch:
#!/usr/bin/env python -i
import module_x
import module_y
from module_z import something
a = something.settings(var_1='123', var_1='456')
Then make sure it is executable:
chmod +x practice.py
Then you can run it like this:
./practice.py
python (and the more comfortable ipython) support -i somefile.py as option to execute the contents of a file before opening the interactive prompt.
on Linux/Unix/OS X you could simply set that as the interpreter of your script like this
#! /usr/bin/python -i
import module_x
# other preloaded settings
On Windows you need to create a batch file or similar to wrap it.

How do I import a py module into the command line

I am using the Anaconda command prompt, with Python - in Windows 8.
I have a py file containing containing a number of "Helper Functions".
How do I import this file in to the command prompt I am using so future operation will recognize the function calls and execute them appropriately?
If by command prompt, you mean that the python interactive shell and you want to import the module every time you start the interactive shell, you can use the .pystartup file to import the relevant modules so that they are always available when you start the interpreter.
On Linux, you can edit the file /home/username/.pystartup to add:
import mod1
import mod2
Have an environment variable which points to the ~/.pystartup file
$ export PYTHONSTARTUP=~/.pystartup
And then use the python interactive shell use the modules loaded in ~/.pystartup
$ python
>> mod1.something
On Windows, you can do the same by adding the environment variable PYTHONSTARTUP with value some_windows_path (I keep mine in C:\python27\pystartup.py) via Computer->Advanced Settings->Environment variables.

Launch configured cmd from Python

I'm on Windows. I am trying to write a Python 2.x script (let's call it setup.py) which would enable the following scenario:
User runs cmd to open a console window
In that console window, user runs setup.py
User finds themselves in the same console window, but now the cmd running there has had its environment (env. variables) modified by setup.py
setup.py modifies the environment by adding a new environment variable FOO with value foo, and by preneding something to PATH.
On Linux, I would simply use os.exec*e to replace the Python process with a shell with the environment configured.
I tried the same approach on Windows (like os.exec*e(os.environ['ComSpec'])), but it doesn't work, the environment of the newly executed cmd is messed up like this:
Running just set doesn't list FOO and doesn't show the effect on PATH. Running set FOO, however, shows FOO=foo, and echo %FOO% echoes foo.
Running set PATH or echo %PATH% shows the modified PATH variable. Running set path or echo %path% shows the value without the modification (even though env. vars are normally case insensitive on Windows).
If I type exit, the conole remains hanging in some state not accepting input, until I hit Ctrl+C. After that, it apparently returns to the cmd which originally called setup.py.
So clearly, os.exec*e doesn't work for this scenario on Windows. Is there a different way to achieve what I want? Is there a combination of subprocess.Popen() flags which would enable me to exit the calling Python process and leave the called cmd runnig, ideally in the same console? Or would accessing CreateProcess through ctypes help?
If necessary, I would settle for launching a new console window and closing the old one, but I certainly can't afford having the old console window hang in frozen state, waiting for a newly created one to close.
There's a much simpler solution if it's acceptable to use a Windows batch file in addition to your script, since the batch file runs in the calling process, and can therefore modify its environment.
Given a file setup.bat, which looks like this...
#echo off
for /f "tokens=*" %%a in ('python setup.py') do %%a
...and a file setup.py which looks like this...
import os
print 'set FOO=foo'
print 'set PATH=%s;%s' % ('C:\\my_path_dir', os.environ['PATH'])
...and assuming python.exe in in the PATH, then calling setup.bat from the command line will set the environment variables in the calling process, while still allowing you to make the setup.py script as complicated as you like, as long as it prints the commands you want to execute to stdout.
Update based on comments
If your setup.py has multiple modes of operation, you could make the setup.bat a generic wrapper for it. Suppose instead setup.bat looks like this...
#echo off
if "%1" == "setenv" (
for /f "tokens=*" %%a in ('python setup.py %1') do %%a
) else (
python setup.py %*
)
...and setup.py looks like this...
import sys
import os
if len(sys.argv) > 1 and sys.argv[1] == 'setenv':
print 'set FOO=foo'
print 'set PATH=%s;%s' % ('C:\\my_path_dir', os.environ['PATH'])
else:
print "I'm gonna do something else with argv=%r" % sys.argv
...would that not suffice?

Running profile startup files in an embedded IPython instance

I want to use an embedded IPython shell with a user_ns dictionary and a my profile configuration (ipython_config.py and the startup files). The purpose is to run a Django shell with models imported on startup. django-extensions implements a command called shell_plus that does this:
https://github.com/django-extensions/django-extensions/blob/master/django_extensions/management/commands/shell_plus.py
from IPython import embed
embed(user_ns=imported_objects)
The problem is that this does not load my startup files. embed() calls load_default_config() which I figure loads ipython_config.py.
How do I make the embedded IPython instance run my profile startup files?
I used the following workaround to run my own IPython startup script but still take advantage of shell_plus:
Create a file called shell_plus_startup.py in the same directory as manage.py. For example:
# File: shell_plus_startup.py
# Extra python code to run after shell_plus starts an embedded IPython shell.
# Run this file from IPython using '%run shell_plus_startup.py'
# Common imports
from datetime import date
# Common variables
tod = date.today()
Launch shell plus (which launches an embedded IPython shell).
python manage.py shell_plus
Manually run the startup script.
In [1]: %run shell_plus_startup.py
Then you can use variables you've defined, modules you've imported, etc.
In [2]: tod
Out[2]: datetime.date(2012, 7, 14)
Also see this answer: scripting ipython through django's shell_plus
I found a way that works if you are using django-extensions-shell_plus. It is a bit hacky, but with this way your startup file is loaded fully automatically and you don't have to type any run-command at the beginning of your ipython-session.
Therefore I edited the file shells.py from the django_extensions dir, which is in my case located in /usr/local/lib/python2.7/dist-packages/django_extensions/management/shells.py. I added these lines inside the function import_objects(options, style):, so it imports the content of the file startup.py defined by the environment param PYTHONSTARTUP.
def import_objects(options, style):
# (...)
import os, sys, pkgutil
if 'PYTHONSTARTUP' in os.environ:
try:
sys.path.append(os.environ['PYTHONSTARTUP'])
import startup
content = [element for element in dir(startup) if not element.startswith('__')]
for element in content:
imported_objects[element] = getattr(startup, element)
except Exception, ex:
sys.exit("Could not import startup module content, Error:\n%s" % ex)
Now when I launch the shell_plus-shell, I give it the environment variable to my startup python script. My bash script to launch the shell with everything in place looks like this:
#!/bin/bash
export PYTHONSTARTUP=/home/ifischer/src/myproject/startup.py # tells shell_plus to load this file
python /home/ifischer/src/myproject/manage.py shell_plus --ipython
Now I have access to all methods and variables defined in startup.py from the beginning of the ipython session.
So you can reuse that and have custom startup files for every project, pre-loading different aspects.
Maybe there is a cleaner way where to include the lines I added to the shells.py? But this approach works fine for me for now.
It does automatically load your ipython configuration starting from django-extensions==1.5.6. You can also pass additional arguments to ipython via IPYTHON_ARGUMENTS. Docs:
http://django-extensions.readthedocs.org/en/latest/shell_plus.html#configuration
Another way is using a class that derives from InteractiveShellEmbed and InteractiveShellApp. Sample, incomplete code:
from IPython.terminal.embed import InteractiveShellEmbed
from IPython.terminal.ipapp import InteractiveShellApp
class ISE(InteractiveShellEmbed, InteractiveShellApp):
def init_shell(self):
self.shell = self.instance()
self.extra_args = []
ise = ISE()
ise.init_path()
ise.init_shell()
ise.init_code()
ise.shell()

Categories