I’m laughing as I type this, since this is the third post about Parsenvy I’ve written in the last six weeks. First I wrote a draft of an introduction much like this one, long overdue. Throughout the process, I started questioning the point of the library in the first place, especially as I don’t really use it much myself any more, so I wrote one wondering about its future.
I didn’t get around to finishing up either one of those before PyCascades, where a few people ended up sprinting on it (check out the sweet docs!), which got me to finish up v3. So now you get this third version.
I’m actually mildly shocked I never wrote this post, since Parsenvy has been around for a while—the first commit landed on March 16, 2017, and the first release was installable on July 31, 2017.
It’s a Python library for reading environment variables and typecasting them into some of the built-in types—namely the “simple” ones: numerics, sequences, and mappings.
The various tools in the standard library’s os
module always return strings (unless a default of a different type is specified), so if you need an integer, you have to do something like this:
from os import getenv
DEFAULT_PAGE_LENGTH = int(getenv("DEFAULT_PAGE_LENGTH", 10))
If you omit the int()
call, you’ll get a string—e.g., "7"
—instead of integer—e.g., 7
—from the environment, if the variable is defined.
This is hardly groundbreaking, but it can read a bit clumsy if you need a lot of it.
With Parsenvy it reads a little better:
import parsenvy
DEFAULT_PAGE_LENGTH = parsenvy.int("DEFAULT_PAGE_LENGTH", 10)
But it improves if there’s a block of these:
from os import getenv
DEBUG = bool(getenv("DEBUG", False))
DEFAULT_PAGE_LENGTH = int(getenv("DEFAULT_PAGE_LENGTH", 10))
HOSTNAME = getenv("HOSTNAME")
# versus
import parsenvy
DEBUG = parsenvy.bool("DEBUG", False)
DEFAULT_PAGE_LENGTH = parsenvy.int("DEFAULT_PAGE_LENGTH", 10)
HOSTNAME = parsenvy.str("HOSTNAME")
Parsenvy supports some of the most commonly used built-in types:
bool
int
float
list
tuple
set
str
(yes, redundant, but provided for completeness)Here’s the example section of the README:
>>> import parsenvy
# DEBUG_ENABLED=True
>>> parsenvy.bool("DEBUG_ENABLED")
True
# POSTS_PER_PAGE=13
>>> parsenvy.int("POSTS_PER_PAGE")
13
# EXCHANGE_RATE=42.911
>>> parsenvy.float("EXCHANGE_RATE")
42.911
# INVALID_USERNAMES=admin,superuser,user,webmaster
>>> parsenvy.list("INVALID_USERNAMES")
["admin", "superuser", "user", "webmaster"]
# SAMPLE_GREETING=Hello,world!
>>> parsenvy.tuple("SAMPLE_GREETING")
("Hello", "world!")
# ALLOWED_CATEGORIES=python,vim,git
>>> parsenvy.set("ALLOWED_CATEGORIES")
{"python", "vim", "git"}
# DB_PREFIX=dj_
>>> parsenvy.str("DB_PREFIX")
"dj_"
Short answer: some combination of “I haven’t needed them yet”, “couldn’t come up with good syntax”, and “just plain forgot about them”.
There’s an issue to add support for range
already, and bytes
, bytearray
, dict
, memoryview
, and frozenset
are under consideration in another.
There’s also the possibility of adding support for shell data structures, but that’s enough of a change to warrant a new major version, and I’m in no rush.
Feedback is welcome on any of the above issues, any other ones, or even new ones. After all, it’s a community project now. ;)
Thanks for reading! You can keep up with my writing via the feed or newsletter, or you can get in touch via email or Mastodon.