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.
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.
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
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"
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>)
Because you're doing awesome things, you deserve some convenience. Here's some recommendations:
.pythonrc.pyfile with some convenient methods, imports, helpers for your project.
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!