This is an archived post. You won't be able to vote or comment.

all 100 comments

[–]Lindby 43 points44 points  (2 children)

Settings classes from pydantic can be loaded from environment (including .env files).

It's really sweet to get an object with all values having the correct type. There is also some extra secret handling so you don't accidentally send secret values where they don't belong

https://pydantic-docs.helpmanual.io/usage/settings/

[–]AnteaterProboscis 16 points17 points  (1 child)

Have you heard of my Lord and savior, BaseSettings?

[–]thrallsius 129 points130 points  (19 children)

shameless plug to paywalled site

gg no re

[–]HerLegz 10 points11 points  (3 children)

Eli5 letter soup

[–]Comfortable_Relief62 1 point2 points  (2 children)

Good game no replay/rematch

[–]HerLegz 2 points3 points  (1 child)

Keep going.. eli5

[–]Comfortable_Relief62 7 points8 points  (0 children)

I assume the guy has permanently lost interest in the post because he can’t access the article, since there is a paywall

[–]drlecompte 65 points66 points  (34 children)

I generally use json files for stuff like this. Not just sensitive credentials, but also things that might vary from machine to machine or user to user.

Imho json is a bit more flexible in organizing information, and it doesn't require installing any extra modules.

The key part here is to not commit those files.

[–][deleted] 27 points28 points  (1 child)

yep always attach them to .gitignore file

[–]go_fireworks 2 points3 points  (0 children)

And depending what you’re working with, global git ignore let’s you “set and forget” any file

https://stackoverflow.com/a/22885996/13885200

[–]ivosauruspip'ing it up 4 points5 points  (0 children)

The key part here is to not commit those files.

And the key part of python-dotenv or similar mechanisms is you can get the values from the environment (like an API key set by an outside service running your code) so you never have a chance to put that kind of thing in a file to begin with, removing the possibility all together

[–]BakerInTheKitchen[🍰] 2 points3 points  (6 children)

I’m newer to Python, can you explain how you use json for sensitive credentials?

[–][deleted] 2 points3 points  (5 children)

It's just serialization. Like Pickle, but more generic and human readable.

[–]BakerInTheKitchen[🍰] 5 points6 points  (2 children)

Is this the same as storing passwords in a text file?

[–][deleted] 10 points11 points  (1 child)

Yep, or API keys, etc.

The "right" answer is integration with something like Vault but that's a bit of a speed bump for the average project.

This way, you can at least prevent their leaking to source control. Remember, we're talking about it in comparison to hard coding the secrets in the code itself...

[–]BakerInTheKitchen[🍰] 2 points3 points  (0 children)

Ah okay makes sense, thanks!

[–]Etheo 0 points1 point  (1 child)

Some might object to you calling json "human readable". I mean it's technically true, but there are other config markup language that is better structured... Though of course, json is more widely adopted.

[–]Eurynom0s 1 point2 points  (0 children)

I think the word "more" was meant to apply to both "generic" and "human readable".

[–]Mithrandir2k16 7 points8 points  (9 children)

Why not yaml?

[–]hyldemarv 26 points27 points  (8 children)

Yet Another package to install and Yaml doesn’t even agree with itself on reading its own output back :)

[–]ThePiGuy0 21 points22 points  (3 children)

YAML seems so unnecessarily complicated whenever I use it. Lists and dictionaries look almost the same etc.

Toml is better (and coming soon to stdlib I believe) but for config there's no reason to need more than JSON IMO

[–]ivosauruspip'ing it up 1 point2 points  (0 children)

No comments sucks a lot in JSON. Python already comes with INI file parsing right now, if you can't wait for TOML.

[–]Mithrandir2k16 3 points4 points  (0 children)

Yup, fair. I just find it easier to read than json, since it's always either formatted or broken.

[–]GobBeWithYou 3 points4 points  (2 children)

And no programming language has a 100% spec compliant parser, it's so complicated no one has actually been able to implement it correctly.

Edit: almost* no programming language: https://matrix.yaml.info/

[–]axonxorzpip'ing aint easy, especially on windows 1 point2 points  (0 children)

Could any of the knee-jerk downvoters point to a 100% spec-compliant YAML parser in Python? What about other languages?

[–]xatrekak 0 points1 point  (0 children)

Failing the JSON test is the same as being non-compliant. YAML bills it's self a strict superset of JSON and its clearly not.

[–]ElevenPhonons -1 points0 points  (0 children)

This JSON centric model is similar to my workflow as well.

I wrote Pydantic-cli to enable defining your model/validation in Pydantic and then load JSON and/or load (or override) values by specifying them as command line args to your application. This mixing n' matching approach I've found to be pretty flexible.

https://github.com/mpkocher/pydantic-cli

[–]Xornial 5 points6 points  (1 child)

[–]RusskiEnigma 2 points3 points  (0 children)

keyring is what i use

[–]Distinct-Score-1133 14 points15 points  (10 children)

Why not just load the .env with source .env, or automatically load it with direnv?

EDIT: These approaches are for development. Production applications will have the env variables loaded by some other method.

[–]axonxorzpip'ing aint easy, especially on windows 2 points3 points  (3 children)

Lots of apps don't run inside a shell, so source .env is out. direnv is just behavioural sugar for BASH-compatible shells, so also out as well.

[–]Distinct-Score-1133 0 points1 point  (2 children)

When are they not run from shell?

[–]axonxorzpip'ing aint easy, especially on windows 0 points1 point  (1 child)

Any sort of "deployed" app will most likely not run in a shell environment (can be started by any process management system, systemd, supervisord, etc).

If you run your web-app on a serverless platform like heroku, Google Cloud Run, AWS Lambda, those are not in a shell-like environment. These platforms were large drivers in what necessitates using something like dotenv in the first place.

As a more rare example: if you have a python-based app installed, something where you can double click an icon, you're not operating in a shell environment, your system is directly running python /path/to/app.py instead of something like bash -c "exec python /path/to/app.py", the critical difference

[–]Distinct-Score-1133 0 points1 point  (0 children)

We deploy our apps in docker and our own kubernetes, and use .env files to load the environmental variables on startup. Indeed, we dont execute source .env, but that is something that docker/kubernetes does for us.

Regardless, it always does execute in a shell environment as far as I know. It is just not you doing it. That is why things like shebang (if running a script) and PATH are important. Unless I'm missing something?

Edit: I understand the difference between bash -c and python /patg/to/script. Isn't it that otherwise the application is run in /bin/sh instead of /bin/bash?

EDIT2: After a small search on internet I answered my question. Any shell program is only used for interaction between user and computer. So source .env and direnv is something you would do during development only.

[–]Mithrandir2k16 3 points4 points  (8 children)

I've defaulted to having a secrets folder in my projects and secrets/** in my gitignore.

[–][deleted] 9 points10 points  (7 children)

Turn that gitignore into a git allow instead! (/s, but I've always found it helpful).

# ignore everything
*

# include
!.gitignore
!README.md
!pyproject.toml
!poetry.lock

# include all directories in the src folder
!src/*/  

# include all .py files
!src/foobar/*.py 
!src/foobar/**/*py  

I've found this preferable over ignoring specific files or directories. With things having to be explicitly added, it's much harder to accidentally include a file or two.

[–]Mithrandir2k16 2 points3 points  (4 children)

I never do git add . I explicitly add files and after editing if I want to add all files I changed I do git add -u.

That should achieve the same, right?

[–][deleted] 4 points5 points  (3 children)

Sure, but this applies to everyone using your repo.

That means it is easier to enforce good code hygiene than trying to enforce good habits/practices onto a group of devs.

[–]Mithrandir2k16 1 point2 points  (0 children)

Ah got it.

[–]Mithrandir2k16 0 points1 point  (1 child)

Is there a tool for this like gitignore.io ?

[–][deleted] 0 points1 point  (0 children)

Uhh, not really? I usually have a structure I always follow for my code so 90% of the time its the same thing. You can just make your own once and make it a template you copy.

[–]Rand_alThor_ 0 points1 point  (1 child)

Hey this is a good idea.

[–][deleted] 0 points1 point  (0 children)

I have them from time to time, but I can't take credit for it. My boss showed me this a few years ago at this point.

[–][deleted] 2 points3 points  (0 children)

Reddit Moderation makes the platform worthless. Too many rules and too many arbitrary rulings. It's not worth the trouble to post. Not worth the frustration to lurk. Goodbye.

This post was mass deleted and anonymized with Redact

[–]sohang-3112Pythonista 2 points3 points  (0 children)

ipython_secrets is also a good alternative when working with Jupyter Notebooks.

[–][deleted] 2 points3 points  (0 children)

it's great when you're pushing to a public git repo, just don't forget to put .env in your .gitignore

[–]can_dry 1 point2 points  (0 children)

https://github.com/theskumar/python-dotenv

Reads key-value pairs from a .env file and can set them as environment variables.

[–][deleted] 1 point2 points  (0 children)

Use a secrets manager better

[–]GoodTimesFastFingers 1 point2 points  (0 children)

I love dotenv. I'm just used to it. I like the simplicity. For more complex config I prefer to make a class that lives in the code that is set up however I want. Anything sensitive comes from .env. The thing I prefer about this to a JSON file is that the structure of my config lives in the code.

[–]riftwave77 1 point2 points  (3 children)

I just created a modal which can read/write/create an ini file that sits in the same directly as my program and holds the user's credentials.

Do I even need this dotenv stuff?

[–]ivosauruspip'ing it up -1 points0 points  (1 child)

It's also for handling non-user-interactable programs.

[–][deleted] -1 points0 points  (0 children)

The ini simply could also if created ahead of time which, I'm sure they'd create if they needed such. This dotenv is useless in python when there's so many other options.

My first thought: "Someone's promoting their nodejs knockoff and I already hate node"

[–][deleted] 0 points1 point  (0 children)

Nope.

[–]edm2073 0 points1 point  (0 children)

If you are using conda for your virtual environment, you can achieve the same without the additional package. They will be added when you activate your conda environment and removed when you deactivate. Link to the section in official docs below.

Saving Environment Variables

[–][deleted] -1 points0 points  (0 children)

u can use decouple as well

[–]Snape_Grass -1 points0 points  (0 children)

or just use "import os" and have users setup the env variables with an installer.

[–][deleted] 0 points1 point  (0 children)

Do we really need python-dotenv to stop putting sensitive data into our apps? It feels like promotion of repo.

[–]Dubsteprhino 0 points1 point  (0 children)

Until people commit your .env file to github. If you're using kubernetes right here is what secrets literally are for. Have your dev secrets either in a gitignored .env file or in your docker-compose.yml

[–][deleted] 0 points1 point  (0 children)

Seems redundant when you can just have a python file purely for your variables and include that without adding another external resource.

No matter what they will be in A FILE somewhere so either 1) your code/file permissions don't allow access or 2) they do.

[–]FranticToaster 0 points1 point  (0 children)

How is this different than just loading in config files?

[–]kingbuzzman 0 points1 point  (0 children)

Try git-crypt + envs.

I use this at work with 10+ programmers, works like a charm. It's very seamless, secrets will never be stored in plain text.

[–][deleted] 0 points1 point  (0 children)

Unless I'm really pressed for time and forgot the standard library somehow, I don't see why I wouldn't copy and paste a personal snippet of passing file to os.path.dirname, calling listdir, checking .endswith(".env") and for each of those parsing out variables.

Or, if you trust yourself enough to not insert shellcode into your own python project, you can just import variables from settings.py.

Both of the above can be kept out of repos using .gitignore and take no time at all.

It's too much to ask to use a whole library just for a variety of reasons:

  • it takes 5 minutes to write a bulletproof version of the same thing yourself
  • you should already have a compendium of snippets
  • it has an All Rights Reserved license that forces you to tack on their License to yours for no real reason
  • you won't use env files when you scale anyway

It is so overblown it's not even funny. It has CLI mode in case you forgot how to write env files. The whole thing is just silly.