TL;DR: I discovered the PYTHONSTARTUP environment variable, and therefore the possibilities of .pythonrc.py files.
Happy accident, and context
Iāve been using Python since some time around 2004-2006. At least I think so. I remember Django was definitely pre-1.0, and it was some time during the rise of Ruby On Rails. I was deep into PHP, and expanding to other languages.
I can hardly believe Iāve been using it so long and not remember seeing mention of or have utilized the PYTHONSTARTUP environment variable. Alas, today was a perfect storm, for a few reasons.
After giving a quick tutorial on some Django details, I was skimming the docs for the manage.py shell
command and the following block caught my eye:
ā¦Disables reading the startup script for the āplainā Python interpreter. By default, the script pointed to by the PYTHONSTARTUP environment variable or the ~/.pythonrc.py script is read.
Recently Iāve been setting up a new machine, so dotfiles of all kinds are fresh on my mind. Having been in and out of my .zshrc
several times today that .pythonrc.py
filename stuck out.
Some quick āgooglingā and I found this gist and Danās post from 2014. They both have some cool examples that immediately inspired me to put this to use. Itās funny to me that Dan also mentions being a Python developer for āaround 8 yearsā before discovering this feature. Somehow we have that in common.
It runs code when Python starts
The PYTHONSTARTUP
environment variable can be set to point at a file containing python code, and according to the 2.x docs:
ā¦ the Python commands in that file are executed before the first prompt is displayed in interactive mode.
This is great, and both examples I found use a global .pythonrc.py
in the userās home directory.
Iām a fan of things like autoenv, however, and tend to use .env
files in the base of most of my projects, to auto-activate a virtualenv, and other things. I wanted the same flexbility with my new found super powers.
autoenv + PYTHONSTARTUP = dynamic super powers
Iām definitely still a simpleton when it comes to bash/zsh scripting, but I was able to dynamically set a project-based startup file by adding this in my projectās .env
:
export PYTHONSTARTUP=`pwd`/.pythonrc.py
Now, whenever I enter the project directory, the PYTHONSTARTUP
environment variable is set to point at the .pythonrc.py
file in the same directory.
Hereās an example of what I added, when trying this out and getting started (āviewmasterā is the name of an app I work on):
# Filename: .pythonrc.py
import datetime
import os
import pdb
import sys
from pprint import pprint
print 'Imported the following items for your convenience:'
print 'sys, os, datetime, pdb, pprint.pprint as pprint'
if 'DJANGO_SETTINGS_MODULE' in os.environ:
from viewmaster import models as m
print "viewmaster.models imported as m"
Yes, this works with the Django shell
Back to where I started. Not only does invoking python
run this code, but the Django management shell command does as well ā as mentioned in the docs where I first noticed this.
This is incredibly handy. Iāve often been debugging or toying with something, and had to constantly kill/reload the Django shell. Each time, Iād have to re-import my models, etc.
Now, this is what I see when I run ./manage.py shell
in my projectās directory:
$ ./manage.py shell
Imported the following items for your convenience:
sys, os, datetime, pdb, pprint.pprint as pprint
viewmaster.models imported as m
Django settings imported as settings
imported Django 'django.utils.timezone' as timezone
Python 2.7.13 (default, Apr 4 2017, 08:47:57)
[GCC 4.2.1 Compatible Apple LLVM 8.1.0 (clang-802.0.38)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>>
ā¦ and I can immediately start using those things, as if I imported them myself! And that āmodels as mā shortcut allowed me to immediately start toying with a new model method I was testing.
Hereās the full output, from initial invocation, to show how convenient this is:
$ ./manage.py shell
Imported the following items for your convenience:
sys, os, datetime, pdb, pprint.pprint as pprint
viewmaster.models imported as m
Django settings imported as settings
imported Django 'django.utils.timezone' as timezone
Python 2.7.13 (default, Apr 4 2017, 08:47:57)
[GCC 4.2.1 Compatible Apple LLVM 8.1.0 (clang-802.0.38)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> i = m.Image.objects.first()
>>> i
<Image: Image #13; 2TI.1.9; Spanish (ES); TG!>
>>> timezone.now()
datetime.datetime(2017, 6, 3, 20, 38, 5, 705893, tzinfo=<UTC>)
Add some convenience to your life!
Because youāre doing awesome things, you deserve some convenience. Hereās some recommendations:
- Use something like autoenv,
- Set up a
.pythonrc.py
file with some convenient methods, imports, helpers for your project. - Use your env management to set PYTHONSTARTUP to point at your new Python startup stuff!
- ā¦ or use a global file and load it for everything. Do what you want!
- Profit! (All that extra time!)
Did you know about this?
Are you already using this for something cool? Have I overlooked something useful?
Maybe youāre like me, and just discovered this functionality?
Iād love to hear about itā¦ tweet at me!