Force Python to update command history file from command line? - python

I use Python without a GUI/IDE by issuing Python from the Bash command line. I use it within a Cygwin environment, which behaves like a Linux system in many respects.
The file used for the history of commands issued at the Python command line is stored in ~/.python_history. I can easily scoot in and yank content for manipulation using vim's Buffer Explorer. It's also easy to yank manipulated content into the system clipboard for pasting at the Python command line. (For more tactical revisions of commands, on the other hand, I just use readline to vim previous commands and a single-line basis.)
I have found that ~/.python_history doesn't update after each command. I'm not sure how often it is updated, but it's clear that exiting Python causes it to update. Putting into the background with Ctrl+Z does not.
(Is there a quick and convenient way from the Python command line to force an update to ~/.python_history?
Since my original posting of this question, I've had occasion to figure out Linux (Ubuntu) as a VirtualBox virtual machine. However, it seems very excessive to fire up an entire guest operating system just to be able to access the command history as a palette as opposed to one line at a time using the Up-Arrow key (or equivalently, k if one's command line editor is set to Vim). I'd even be happy with a Python counterpart to Bash's "fix command" (fc) command, even though I would have to erase all the lines that I don't want to execute.
Various things tried
As per the responses, I tried importing readline.write_history_file, but it isn't recognized, even though readline itself is:
$python
Python 3.8.10 (default, May 20 2021, 11:41:59)
[GCC 10.2.0] on cygwin
Type "help", "copyright", "credits" or "license" for more information.
# Show modules
>>> import sys
>>> modulenames = set(sys.modules) & set(globals())
>>> allmodules = [sys.modules[name] for name in modulenames]
>>> print(allmodules)
[<module 'sys' (built-in)>]
# Fail to import readline.write_history_file
>>> import readline.write_history_file as whf
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ModuleNotFoundError: No module named 'readline.write_history_file'; 'readline' is not a package
# However, readline itself imports
>>> import readline
>>> readline.get_history_item(2)
'version'
readline does appear to be explicitly part of the Cygwin repository, so I didn't try pip install readline:
Search Cygwin packages for readline (followed by browser search for the string python)
The one result that appears to be most relevant shows dll,py, and pyc files with readline[s] in the file name, but I'm not sure what that says about the form taken by the readline module itself. I welcome clarifications/explanations about this.
In fact, I'm reluctant to try installing anything outside of the Cygwin package manager using pip for fear of creating inconsistencies.

Reading through this module, I found out readline.write_history_file(path) may be what you are searching for:
Save the history list to a readline history file, overwriting any existing file.
The default filename is ~/.history
First thing in the interactive interpreter, do
import readline.write_history_file as whf # write history file
Then you can do whf() or whf("path/to/.historyfile"), and your python history gets saved to disk immediately.
EDIT:
I'm not sure how often it is updated
It is only updated when you exit the interpreter. If you kill it, the history won't get saved, and Ctrl+Z just causes the interpreter to be suspended. If you then unsuspend it (by executing fg or bg, for example) and exit it normally, the history file will get written.

Related

Can't change sys.ps1 in IDLE

I've recently heard that you can change the prompt in python by changing variable sys.ps1. So I've decided to open IDLE, and write something like that:
>>> import sys
>>> sys.ps1 = ":::"
However, that created a new variable and nothing changed (prompt was still ">>>") - I rebooted IDLE and checked is this variable read by python... Nope:
>>> sys.ps1
Traceback (most recent call last):
File "<pyshell#1>", line 1, in <module>
sys.ps1
AttributeError: module 'sys' has no attribute 'ps1'
So, how do I change the prompt in python?
NOTE: The other functions/variables of sys module were read properly.
See issue #13657, "IDLE doesn't recognize resetting sys.ps1", on the Python bug tracker. It was opened in 2011 and is still unresolved (as of this writing). So it is not possible to change the prompt from within IDLE's Python shell simply because IDLE does not support that.
Update (less than 24 hours later): The issue is now closed. In the upcoming version of IDLE, to be released with Python 3.10, prompts will be displayed differently. See comment by IDLE developer Terry Jan Reedy above. A setting to change the prompt may be added in the future.
In the current and earlier Python/IDLE releases, the prompt can be customized before starting IDLE, but not while running it. You'd need a little start-up script that does this:
import sys
sys.ps1 = '::: '
import idlelib.idle
The reason you get that error message (module 'sys' has no attribute 'ps1') is because the Python shell that IDLE presents to you is not actually in "interactive" mode. And only then is sys.ps1 defined. You'd see the same error message if you tried to access sys.ps1 in any other Python program that is directly executed. In this case, that Python program is IDLE itself.
The prompt strings specifying the primary and secondary prompt (their initial values in this case are >>> and ... ) of the interpreter are only defined if the interpreter is in interactive mode and IDLE is more or less an integrated development environment for Python
Python interactive mode:
sys.ps1 doc

How to Pre-load Python Modules in Python IDLE on Startup?

I am on Windows 7. When I launch Python IDLE, I want it to pre-load: pandas, numpy and matplotlib without me having to type out the import statements. I import them very frequently.
I have waded through several posts:
This one has to do with iPython, not IDLE-specific
This one has to do with running a script in IDLE
This one talks about PYTHONSTARTUP for interactive sessions
From these posts, I have determined that there is a distinct difference between Windows command-prompt python interactive shell and IDLE's interactive shell.
For example, I created defaultimports.py and put it in this location:
C:\Python34\Lib\site-packages\jaradspythonstartup
That script contains the following:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
print('pd, np and plt imported')
Next, on my machine, I went to Start > Computer > right-clicked Properties > Advanced system settings > environment variables > clicked New... and added a new variable named PYTHONSTARTUP, then put my path C:\Python34\Lib\site-packages\jaradspythonstartup\defaultimports.py
However, this seems to only work in Windows Command prompt when I open command prompt and type python. I do see it loads my print statement.
When I launch IDLE, I don't see the message: pd, np, and plt imported print statement. While in IDLE, if I import os and os.environ['PYTHONSTARTUP'], I do see my environment variable defined but don't know if that's important to note or not.
Python 3.4.2 (v3.4.2:ab2c023a9432, Oct 6 2014, 22:15:05) [MSC v.1600 32 bit (Intel)] on win32
Type "copyright", "credits" or "license()" for more information.
>>> import os
>>> os.environ['PYTHONSTARTUP']
'C:\\Python34\\Lib\\site-packages\\jaradspythonstartup\\defaultimports.py'
>>>
My Question
How can I pre-load modules in IDLE on startup?
python -m idlelib -h on a command line, where python runs recent 3.x, will display startup commands for IDLE; use idlelib.idle for 2.x. It says that
idle idlelib -s "runs $IDLESTARTUP or $PYTHONSTARTUP before anything else".
If that does not work, try python -m idlelib -s.
Currently, when you restart the shell, which happens when you run a file from the editor, ....STARTUP does not get re-run. I hope to fix that.
EDIT: How to start IDLE with arguments from the desktop instead of command line.
Make a properly labelled IDLE desktop icon. Go to Start Menu > Python x.y > IDLE... and copy to Desktop. Control-Left Mouse Button drag or (Win 7, at least) Right click, Send to > Desktop (create shortcut). If for Python before 3.4, right click icon, select Rename, and label with the version number. (We recently got complaint "I installed 3.5 and (pre-existing) desktop icon opens 2.7.).
Make icon open IDLE with arguments. Right-click icon, select properties, click end (you may or may not have to click box first). Cursor should be at end of line with ...pythonw.exe...idlew.py. Space and add arguments. I tried -c "print('hello')" to test. Add -s for ...STARTUP. Consider renaming to indicate addition, such as IDLE 3.5 64 bit STARTUP, in case you want another IDLE desktop icon.

Problems when showing Interpreter (IPython) after running Program in PyCharm

I have PyCharm Professional Edition 3.5 5.0 configured to
use IPython when possible
and in my Run/Debug Configurations I set
show interpreter afterwards
I use the interactive Interpreter a lot and I really like IPython, but there are some things that I don't like about the way this is handled in PyCharm:
any input() in my programs return empty strings.
Additionally, when an error occurs I can't interact with the Program anymore. (you can when you run a Python program with the -i flag)
There is a lot of space between the last line in the Console and the current line
In IPython the ...: prompt in a code block isn't indented 2 spaces and therefore not aligned to the In [?]: prompt.
When an error occurs I get something like this:
Traceback (most recent call last):
File "C:\Program Files (x86)\PyCharm\helpers\pydev\pydev_run_in_console.py", line 69, in <module>
globals = run_file(file, None, None)
File "C:\Program Files (x86)\PyCharm\helpers\pydev\pydev_run_in_console.py", line 29, in run_file
pydev_imports.execfile(file, globals, locals) # execute the script
File "C:\Program Files (x86)\PyCharm\helpers\pydev\_pydev_imps\_pydev_execfile.py", line 18, in execfile
exec(compile(contents+"\n", file, 'exec'), glob, loc)
File "C:/Users/ca/Python/Bundeswettbewerb Informatik/Aufgabe2/Ameisen.py", line 133, in <module>
function_that_caused_error()
I don't need/want to see the traceback from the internals.
When running a file IPython needs to be started which takes some seconds even if I'm not going use the interpreted afterwards. I would like PyCharm to start IPython after the program has ended or when I start debugging (you can start IPython in an interactive console by doing import IPython; IPython.start_ipython()
There are some other minor things that I don't like:
When IPython is started it prints a lot of text to the console. I don't want to see any of it except maybe the version number (you can usually do this with the --no-banner option, but adding it to the interpreter options doesn't work)
when you type something and press Up it replaces what I have written with the last item of my history instead of replacing it with the last item of my history that start with what I have typed. Plain IPython does this.
I would like to have automatic code completion without having to press Ctrl + Space in the console
The "problems" are ordered by importance. Does anybody know how to change some of them? I could stop using IPython which would solve the second , the third and the fourth problem, but the other ones would still persist. All of this behavior (excluding the IPython stuff) is implemented very well in PyScripter.
EDIT:
I have found solutions to the first two problems and the problem with the IPython banner. The source for the PyDev interactive interpreter (which is used by PyCharm) is located, on Windows, in C:\Program Files (x86)\PyCharm\helpers\PyDev (path my vary of course).
So the first problem can be solved by editing the file _pydev_imps/_pydev_execfile.py. Wrap line 18 (exec(compile(contents+"\n", file, 'exec'), glob, loc)) in a try ... except block with the following code as the exception handler import traceback; traceback.print_exc(). This will terminate your Python program if there is an error while letting you interact with the variable afterwards.
Problem 2 can be solved by editing the fire pydev_run_in_console.py. Add this import at the beginning of the file: from pydev_console_utils import StdIn and insert sys.stdin = StdIn(interpreter, host, client_port) after what was line 61 before adding the import.
In order to solve the problem with the banner you have to download the most recent version of the PyDev source here and replace the files pydev_ipython_console and pydev_ipython_console_011 by their newer versions. In the newer version of the first file the __init__ method in line 22 has a argument called show_banner with the default value True. Change this to False.
This is probably not the answer you are searching for, but based on my experience using IPython on InteliJ products ( PyCharm, Ultimate), I don't recommend using their version of IPython. It's full of bugs, outdated and you'll lose precious time fixing problems instead of coding.
Have you tried jupyter notebook? If you installed python with anaconda, it's already installed. To run it, open the terminal and type:
jupyter notebook
If your browser doesn't open automagically, head to http://localhost:8888
Note:
You can automate this process by creating bat or sh script containing the code above inside your project directory, this way it doesn't start on you home dir, which it does by default.
Resources:
How to Install and Use IPython
nbopen project: Open a Jupyter notebook in the best available server
In all honesty, have you simply tried running a newer version of PyCharm and importing your settings? 3.5 is fairly outdated (I'm on 4.5.3 myself, newest version is 5.0) and I believe more support is offered for IPython in the newer versions. https://www.jetbrains.com/pycharm/help/ipython.html. Especially if you are a student, it might not hurt to give it a shot. I know older versions of PyCharm were more buggy than recent releases.

Opening Files using Python in Prompt

After invoking Python from within Windows Powershell, I am unable to open files in the current working directory.
PS C:\python27> python
Python 2.7.9 (default, Dec 10 2014, 12:24:55) [MSC v.1500 32 bit (Intel
Type "help", "copyright", "credits" or "license" for more information.
After that, I type:
x = open(ex15_sample.txt)
With the idea of calling the open function on the filename parameter of the text file I would like to open in Python. The idea is that I can then run the following code in Windows Powershell and open that file in Python through Powershell:
print x.read()
However I can't get to this step, because after I typed
x = open(ex15_sample.txt)
Powershell outputs the following:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'ex15_sample' is not defined
In order to open the file "ex15_sample.txt" in Python via Powershell I also typed:
import ex15_sample.txt
After reading online that this can work, but Powershell outputted the following:
File "<stdin>", line 1, in <module>
ImportError: No module named ex15_sample.txt
How can I open the file "ex15_sample.txt" from within Python via the Powershell Command Line Interface?
You need to supply open() with a string.
"ex15_sample.txt" is a string literal, but ex15_sample.txt is the name of a variable you haven't defined yet.
So, you would need to type
open("ex15_sample.txt")
This is a pretty basic programming concept, and certainly not specific to Python. When you pass a value to a function like open, it can either be a variable containing a data, or a literal string. In this case, you want a string, and in most languages (including Python) strings must be surrounded by quotes:
x = open('ex15_sample.txt')
You've misunderstood what you've read about import: that's for loading other Python modules only.
Also note that none of this has anything to do with Powershell at all.
Think like this, when you run something, all the words in in it are commands (variables, functions, whatever), python will try to interpret all those things, when you try this:
open(ex15_sample.txt)
Python will effectively search for a command open (it will find, as it is a built-in function), and then it will search for another command ex15_sample that doesn't exist in python, so it will throw an error.
What you want to do is pass a text containing the name of the file to python, the way to do that is surrounding it with single or double quotes, either 'ex15_sample.txt' or "ex15_sample.txt", that way python interpret it as text instead of trying to understand it as a command, so
open('ex15_sample.txt')
is what you really want

Improved IDE'ish Python command line including code completion?

For writing Python I currently use the excellent PyCharm IDE. I love the way it has code completion so that you often only need to type the first 2 letters and then hit enter.
For easy testing I am of course also often on the command line. The only thing is that I miss the convenient features of the IDE on the command line. Why is there no code completion on the command line? And when I fire up a new Python interactive interpreter, why doesn't it remember commands I inserted earlier (like for example sqlite3 does)?
So I searched around, but I can't find anything like it, or I'm simply not searching for the right words.
So my question; does anybody know of an improved and more convenient version of the Python interactive command line interpreter? All tips are welcome!
bpython is one of the many choices for alternative interactive Python interpreters that sports both of the features you mentioned (tab completion and persistent readline history).
Another very commonly used one would by IPython, though I personally don't like it very much (just a personal preference, many people are very fond of it).
Last but not least you can also enable those features for the standard Python interpreter:
Tab completion: See the docs on the rlcompleter module.
Create a file ~/.pythonrc in your home directory containing this script:
try:
import readline
except ImportError:
print "Module readline not available."
else:
import rlcompleter
readline.parse_and_bind("tab: complete")
This will try to import the readline module, and bind its default completion function to the tab key. In order to execute this script every time you start a Python interpreter, set the environment variable PYTHONSTARTUP to contain the path to this script. How you do this depends on your operating system - on Linux you could do it in your ~/.bashrc for example:
export PYTHONSTARTUP="/home/lukas/.pythonrc"
(The file doesn't need to be called .pythonrc or even be in your home directory - all that matters is that it's the same path you set in PYTHONSTARTUP)
Persistent history: See the .pythonrc file in Marius Gedminas's dotfiles. The concept is the same as above: You add the code that saves and loads the history to your ~/.pythonrc, and configure the PYTHONSTARTUP environment variable to contain the path to that script, so it gets executed every time you start a Python interpreter.
His script already contains the tab completion part. So since you want both, you could save his script called python to ~/.python and add the contents of his bashrc.python to your ~/.bashrc.

Categories

Resources