Is there a way in Python to detect, within a process, where that process is being executed? I have some code that includes the getpass.getpass() function, which is broken in Spyder, and it's annoying to go back and forth between the command line and the IDE all the time. It would be useful if I could add code like:
if not being run from Spyder:
use getpass
else:
use alternative
Here is the solution I ended up using. After reading Markus's answer, I noticed that Spyder adds half a dozen or so environment variables to os.environ with names like SPYDER_ENCODING, SPYDER_SHELL_ID, etc. Detecting the presence of any of these seems relatively unambiguous, compared to detecting the absence of a variable with as generic a name as 'PYTHONSTARTUP'. The code is simple, and works independently of Spyder's startup script (as far as I can tell):
if any('SPYDER' in name for name in os.environ)
# use alternative
else:
# use getpass
Since the string is at the beginning of each environment variable name, you could also use str.startswith, but it's less flexible, and a little bit slower (I was curious):
>>> import timeit
>>> s = timeit.Timer("[name.startswith('SPYDER') for name in os.environ]", "import os")
>>> i = timeit.Timer("['SPYDER' in name for name in os.environ]", "import os")
>>> s.timeit()
16.18333065883474
>>> i.timeit()
6.156869294143846
The sys.executable method may or may not be useful depending on your installation. I have a couple WinPython installations and a separate Python 2.7 installation, so I was able to check the condition sys.executable.find('WinPy') == -1 to detect a folder name in the path of the executable Spyder uses. Since the warning that shows in IDLE when you try to use getpass is less "loud" than it could be, in my opinion, I ended up also checking the condition sys.executable.find('pythonw.exe') == -1 to make it slightly louder. Using sys.executable only, that method looks like:
if sys.executable.find('pythonw.exe') == sys.executable.find('WinPy') == -1:
# use getpass
else:
# use alternative
But since I want this to work on other machines, and it's much more likely that another user would modify their WinPython installation folder name than that they would rename their IDLE executable, my final code uses sys.executable to detect IDLE and os.environ to detect Spyder, providing a "louder" warning in either case and keeping the code from breaking in the latter.
if any('SPYDER' in name for name in os.environ) \
or 'pythonw.exe' in sys.executable:
password = raw_input('WARNING: PASSWORD WILL BE SHOWN ON SCREEN\n\n' * 3
+ 'Please enter your password: ')
else:
password = getpass.getpass("Please enter your password: ")
By default, Spyder uses a startup scrip, see Preferences -> Console -> Adanced setting. This option is usually set to the scientific_startup.py file that loads pylab et al.
The easiest solution is to just add a global variable to the file and then use that in your if statement, e.g. add this line at the end of scientific_startup.py:
SPYDER_IDE_ACTIVE = True
In your script:
if not 'SPYDER_IDE_ACTIVE' in globals():
use getpass
else:
use alternative
This will work without throwing an error. You can also use exceptions if you like that more.
A second solution would be (if you cannot modify that file for some reason) to just check if the environment variable PYTHONSTARTUP is set. On my machine (using the Anaconda Python stack), it is not set for a regular Python shell. You could do
import os
if not 'PYTHONSTARTUP' in os.environ:
use getpass
else:
use alternative
Spyder provides the option of executing the current editor script in a native system terminal. This would produce identical behavior as if you were running from the command line. To set this up, open the Run Settings dialog by hitting F6. Then select the radio button "Execute in an external System terminal". Now run the script as usual by hitting F5. You should be able to use getpass in the normal fashion with this approach.
You could add env variable when running in Spyder and check it in code.
How can I embed an IPython shell in my code and have it automatically display the line number and function in which it was invoked?
I currently have the following setup to embed IPython shells in my code:
from IPython.frontend.terminal.embed import InteractiveShellEmbed
from IPython.config.loader import Config
# Configure the prompt so that I know I am in a nested (embedded) shell
cfg = Config()
prompt_config = cfg.PromptManager
prompt_config.in_template = 'N.In <\\#>: '
prompt_config.in2_template = ' .\\D.: '
prompt_config.out_template = 'N.Out<\\#>: '
# Messages displayed when I drop into and exit the shell.
banner_msg = ("\n**Nested Interpreter:\n"
"Hit Ctrl-D to exit interpreter and continue program.\n"
"Note that if you use %kill_embedded, you can fully deactivate\n"
"This embedded instance so it will never turn on again")
exit_msg = '**Leaving Nested interpreter'
# Put ipshell() anywhere in your code where you want it to open.
ipshell = InteractiveShellEmbed(config=cfg, banner1=banner_msg, exit_msg=exit_msg)
This allows me to start a full IPython shell anywhere in my code by just using ipshell(). For example, the following code:
a = 2
b = a
ipshell()
starts an IPython shell in the scope of the caller that allows me inspect the values of a and b.
What I would like to do is to automatically run the following code whenever I call ipshell():
frameinfo = getframeinfo(currentframe())
print 'Stopped at: ' + frameinfo.filename + ' ' + str(frameinfo.lineno)
This would always show the context where the IPython shell starts so that I know what file/function, etc. I am debugging.
Perhaps I could do this with a decorator, but all my attemps so far have failed, since I need ipshell() to run within the original context (so that I have access to a and b from the IPython shell).
How can I accomplish this?
You can call ipshell() from within another user-defined function, e.g. ipsh()
from inspect import currentframe
def ipsh():
frame = currentframe().f_back
msg = 'Stopped at {0.f_code.co_filename} and line {0.f_lineno}'.format(frame)
ipshell(msg,stack_depth=2) # Go back one level!
Then use ipsh() whenever you want to drop into the IPython shell.
Explanation:
stack_depth=2 asks ipshell to go up one level when retrieving the namespace for the new IPython shell (the default is 1).
currentframe().f_back() retrieves the previous frame so that you can print the line number and file of the location where ipsh() is called.
It would be useful to save the session variables which could be loaded easily into memory at a later stage.
In [23]: %logstart /tmp/session.log
Activating auto-logging. Current session state plus future input saved.
Filename : /tmp/session.log
Mode : backup
Output logging : False
Raw input log : False
Timestamping : False
State : active
In [24]: x = 1
In [25]: %logstop
In [26]: quit()
Do you really want to exit ([y]/n)? y
Then we can restore the session with:
% ipython -log /tmp/session.log
Activating auto-logging. Current session state plus future input saved.
Filename : ipython_log.py
...
In [1]: x
Out[1]: 1
For more on "Session logging and restoring" see the docs.
Note that this merely stores the commands run by IPython. It does not save the
state of the IPython session. Restoring the session requires re-execution of
the commands.
If you set the PYTHONSTARTUP environment variable to point at a file called, say, startup.py:
PYTHONSTARTUP=/path/to/startup.py
then put the following in /path/to/startup.py:
try:
# https://stackoverflow.com/a/5377051/190597 (Tom Dunham)
__IPYTHON__
except NameError:
pass
else:
# https://stackoverflow.com/a/15898875/190597 (user2261139)
from IPython import get_ipython
ipython = get_ipython()
ipython.magic("%logstart /tmp/session.log")
then IPython will call %logstart automatically whenever you start an interactive session.
Looking for something similar I came across save_ipython_variables:
save-ipython-variables lets you ... save your global IPython
variables to disk easily, and load them back into the global
namespace when you need them again, even in a whole new IPython
session.
I haven't had much chance to use it yet, but looks promising.
I haven't tried this yet, but starting from AE Drew's answer, I found a possible alternative. Looks like IPython has a built in magic command that does this called %store:
%store magic for lightweight persistence. Stores variables, aliases and macros in IPython’s database. To automatically restore stored variables at startup, add this to your ipython_config.py file:
c.StoreMagic.autorestore = True
There is also a magic command, history, that can be used to write all the commands/statements given by user.
Syntax : %history -f file_name.
Also %save file_name start_line-end_line, where star_line is the starting line number and end_line is ending line number. Useful in case of selective save.
%run can be used to execute the commands in the saved file
Not my solution, but this seems to be the closest solution, if you are using ipython: https://stackoverflow.com/a/28552465/4752883
I'm trying to save myself just a few keystrokes for a command I type fairly regularly in Python.
In my python startup script, I define a function called load which is similar to import, but adds some functionality. It takes a single string:
def load(s):
# Do some stuff
return something
In order to call this function I have to type
>>> load('something')
I would rather be able to simply type:
>>> load something
I am running Python with readline support, so I know there exists some programmability there, but I don't know if this sort of thing is possible using it.
I attempted to get around this by using the InteractivConsole and creating an instance of it in my startup file, like so:
import code, re, traceback
class LoadingInteractiveConsole(code.InteractiveConsole):
def raw_input(self, prompt = ""):
s = raw_input(prompt)
match = re.match('^load\s+(.+)', s)
if match:
module = match.group(1)
try:
load(module)
print "Loaded " + module
except ImportError:
traceback.print_exc()
return ''
else:
return s
console = LoadingInteractiveConsole()
console.interact("")
This works with the caveat that I have to hit Ctrl-D twice to exit the python interpreter: once to get out of my custom console, once to get out of the real one.
Is there a way to do this without writing a custom C program and embedding the interpreter into it?
Edit
Out of channel, I had the suggestion of appending this to the end of my startup file:
import sys
sys.exit()
It works well enough, but I'm still interested in alternative solutions.
You could try ipython - which gives a python shell which does allow many things including automatic parentheses which gives you the function call as you requested.
I think you want the cmd module.
See a tutorial here:
http://wiki.python.org/moin/CmdModule
Hate to answer my own question, but there hasn't been an answer that works for all the versions of Python I use. Aside from the solution I posted in my question edit (which is what I'm now using), here's another:
Edit .bashrc to contain the following lines:
alias python3='python3 ~/py/shellreplace.py'
alias python='python ~/py/shellreplace.py'
alias python27='python27 ~/py/shellreplace.py'
Then simply move all of the LoadingInteractiveConsole code into the file ~/py/shellreplace.py Once the script finishes executing, python will cease executing, and the improved interactive session will be seamless.
I find myself frequently using Python's interpreter to work with databases, files, etc -- basically a lot of manual formatting of semi-structured data. I don't properly save and clean up the useful bits as often as I would like. Is there a way to save my input into the shell (db connections, variable assignments, little for loops and bits of logic) -- some history of the interactive session? If I use something like script I get too much stdout noise. I don't really need to pickle all the objects -- though if there is a solution that does that, it would be OK. Ideally I would just be left with a script that ran as the one I created interactively, and I could just delete the bits I didn't need. Is there a package that does this, or a DIY approach?
IPython is extremely useful if you like using interactive sessions. For example for your use-case there is the %save magic command, you just input %save my_useful_session 10-20 23 to save input lines 10 to 20 and 23 to my_useful_session.py (to help with this, every line is prefixed by its number).
Furthermore, the documentation states:
This function uses the same syntax as %history for input ranges, then saves the lines to the filename you specify.
This allows for example, to reference older sessions, such as
%save current_session ~0/
%save previous_session ~1/
Look at the videos on the presentation page to get a quick overview of the features.
From Andrew Jones's website (archived):
import readline
readline.write_history_file('/home/ahj/history')
There is a way to do it. Store the file in ~/.pystartup...
# Add auto-completion and a stored history file of commands to your Python
# interactive interpreter. Requires Python 2.0+, readline. Autocomplete is
# bound to the Esc key by default (you can change it - see readline docs).
#
# Store the file in ~/.pystartup, and set an environment variable to point
# to it: "export PYTHONSTARTUP=/home/user/.pystartup" in bash.
#
# Note that PYTHONSTARTUP does *not* expand "~", so you have to put in the
# full path to your home directory.
import atexit
import os
import readline
import rlcompleter
historyPath = os.path.expanduser("~/.pyhistory")
def save_history(historyPath=historyPath):
import readline
readline.write_history_file(historyPath)
if os.path.exists(historyPath):
readline.read_history_file(historyPath)
atexit.register(save_history)
del os, atexit, readline, rlcompleter, save_history, historyPath
and then set the environment variable PYTHONSTARTUP in your shell (e.g. in ~/.bashrc):
export PYTHONSTARTUP=$HOME/.pystartup
You can also add this to get autocomplete for free:
readline.parse_and_bind('tab: complete')
Please note that this will only work on *nix systems. As readline is only available in Unix platform.
If you are using IPython you can save to a file all your previous commands using the magic function %history with the -f parameter, p.e:
%history -f /tmp/history.py
After installing Ipython, and opening an Ipython session by running the command:
ipython
from your command line, just run the following Ipython 'magic' command to automatically log your entire Ipython session:
%logstart
This will create a uniquely named .py file and store your session for later use as an interactive Ipython session or for use in the script(s) of your choosing.
Also, reinteract gives you a notebook-like interface to a Python session.
In addition to IPython, a similar utility bpython has a "save the code you've entered to a file" feature
I had to struggle to find an answer, I was very new to iPython environment.
This will work
If your iPython session looks like this
In [1] : import numpy as np
....
In [135]: counter=collections.Counter(mapusercluster[3])
In [136]: counter
Out[136]: Counter({2: 700, 0: 351, 1: 233})
You want to save lines from 1 till 135 then on the same ipython session use this command
In [137]: %save test.py 1-135
This will save all your python statements in test.py file in your current directory ( where you initiated the ipython).
There is %history magic for printing and saving the input history (and optionally the output).
To store your current session to a file named my_history.py:
>>> %hist -f my_history.py
History IPython stores both the commands you enter, and the results it produces. You can easily go through previous commands with the up- and down-arrow keys, or access your history in more sophisticated ways.
You can use the %history magic function to examine past input and output. Input history from previous sessions is saved in a database, and IPython can be configured to save output history.
Several other magic functions can use your input history, including %edit, %rerun, %recall, %macro, %save and %pastebin. You can use a standard format to refer to lines:
%pastebin 3 18-20 ~1/1-5
This will take line 3 and lines 18 to 20 from the current session, and lines 1-5 from the previous session.
See %history? for the Docstring and more examples.
Also, be sure to explore the capabilities of %store magic for lightweight persistence of variables in IPython.
Stores variables, aliases and macros in IPython’s database.
d = {'a': 1, 'b': 2}
%store d # stores the variable
del d
%store -r d # Refresh the variable from IPython's database.
>>> d
{'a': 1, 'b': 2}
To autorestore stored variables on startup, specifyc.StoreMagic.autorestore = True in ipython_config.py.
The %history command is awesome, but unfortunately it won't let you save things that were %paste 'd into the sesh. To do that I think you have to do %logstart at the beginning (although I haven't confirmed this works).
What I like to do is
%history -o -n -p -f filename.txt
which will save the output, line numbers, and '>>>' before each input (o, n, and p options). See the docs for %history here.
Just putting another suggesting in the bowl:
Spyder
It has History log and Variable explorer. If you have worked with MatLab, then you'll see the similarities.
As far as Linux goes, one can use script command to record the whole session. It is part of util-linux package so should be on most Linux systems . You can create and alias or function that will call script -c python and that will be saved to a typescript file. For instance, here's a reprint of one such file.
$ cat typescript
Script started on Sat 14 May 2016 08:30:08 AM MDT
Python 2.7.6 (default, Jun 22 2015, 17:58:13)
[GCC 4.8.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> print 'Hello Pythonic World'
Hello Pythonic World
>>>
Script done on Sat 14 May 2016 08:30:42 AM MDT
Small disadvantage here is that the script records everything , even line-feeds, whenever you hit backspaces , etc. So you may want to use col to clean up the output (see this post on Unix&Linux Stackexchange) .
there is another option --- pyslice.
in the "wxpython 2.8 docs demos and tools", there is a open source program named "pyslices".
you can use it like a editor, and it also support using like a console ---- executing each line like a interactive interpreter with immediate echo.
of course, all the blocks of codes and results of each block will be recorded into a txt file automatically.
the results are logged just behind the corresponding block of code. very convenient.
In IPython, I first use
In [2]: %hist
to view my past code. I select the chunk I want to save and then paste it into file my_file.py using the %%file magic (short for %%writefile)
In [3]: %%file my_file.py
...: # paste code here
...:
...:
hitting return two times in the end.
To append to file use the option -a: %%file -a my_file.py.
If needed, I can list, edit, etc. the file in the underlying command line using the exclamation mark
In [5]: !ls -l my_file.py
In [6]: !vi my_file.py
Some comments were asking how to save all of the IPython inputs at once. For %save magic in IPython, you can save all of the commands programmatically as shown below, to avoid the prompt message and also to avoid specifying the input numbers.
currentLine = len(In)-1
%save -f my_session 1-$currentLine
The -f option is used for forcing file replacement and the len(IN)-1 shows the current input prompt in IPython, allowing you to save the whole session programmatically.
For those using spacemacs, and ipython that comes with python-layer, save magic creates a lot of unwanted output, because of the constant auto-completion command working in the backround such as:
len(all_suffixes)
';'.join(__PYTHON_EL_get_completions('''len'''))
';'.join(__PYTHON_EL_get_completions('''all_substa'''))
len(all_substantives_w_suffixes)
';'.join(__PYTHON_EL_get_completions('''len'''))
';'.join(__PYTHON_EL_get_completions('''all'''))
';'.join(__PYTHON_EL_get_completions('''all_'''))
';'.join(__PYTHON_EL_get_completions('''all_w'''))
';'.join(__PYTHON_EL_get_completions('''all_wo'''))
';'.join(__PYTHON_EL_get_completions('''all_wor'''))
';'.join(__PYTHON_EL_get_completions('''all_word'''))
';'.join(__PYTHON_EL_get_completions('''all_words'''))
len(all_words_w_logograms)
len(all_verbs)
To avoid this just save the ipython buffer like you normally save any other: spc f s
If you use bpython, all your command history is by default saved to ~/.pythonhist.
To save the commands for later reusage you can copy them to a python script file:
$ cp ~/.pythonhist mycommands.py
Then edit that file to clean it up and put it under Python path (global or virtual environment's site-packages, current directory, mentioning in *.pth, or some other way).
To include the commands into your shell, just import them from the saved file:
>>> from mycommands import *
I'd like to suggest another way to maintain python session through tmux on linux. you run tmux, attach your self to the session you opened (if not attached after opening it directly). execute python and do whatever you are doing on it. then detach from session. detaching from a tmux session does not close the session. the session remains open.
pros of this method:
you can attach to this session from any other device (in case you can ssh your pc)
cons of this method:
this method does not relinquish the resources used by the opened python session until you actually exist the python interpreter.
To save input and output on XUbuntu:
In XWindows, run iPython from the Xfce terminal app
click Terminal in the top menu bar and look for save contents in the dropdown
I find this saves the input and output, going all the way back to when I opened the terminal. This is not ipython specific, and would work with ssh sessions or other tasks run from the terminal window.
You can use built-in function open: I use it in all of my
programs in which I need to store some history (Including Calculator, etc.)
for example:
#gk-test.py or anything else would do
try: # use the try loop only if you haven't created the history file outside program
username = open("history.txt").readline().strip("\n")
user_age = open("history.txt").readlines()[1].strip("\n")
except FileNotFoundError:
username = input("Enter Username: ")
user_age = input("Enter User's Age: ")
open("history.txt", "w").write(f"{username}\n{user_age}")
#Rest of the code is secret! try it your own!
I would thank to all of them who liked my comments! Thank you for reading this!