9 ms·
Just a small note on the code in the linked script: API_KEY = os.environ.get("YOUTUBE_API_KEY") CHANNEL_ID = os.environ.get("YOUTUBE_CHANNEL_ID")
by Mawr 1y ago
Just a small note on the code in the linked script:
API_KEY = os.environ.get("YOUTUBE_API_KEY")
CHANNEL_ID = os.environ.get("YOUTUBE_CHANNEL_ID")
if not API_KEY or not CHANNEL_ID:
print("Missing YOUTUBE_API_KEY or YOUTUBE_CHANNEL_ID.")
exit(1)
Presenting the user with "Missing X OR Y" when there's no reason that OR has to be there massively frustrates the user for the near zero benefit of having one fewer if statement.
if not API_KEY:
print("Missing YOUTUBE_API_KEY.")
exit(1)
if not CHANNEL_ID:
print("Missing YOUTUBE_CHANNEL_ID.")
exit(1)
Way better user experience, 0.00001% slower dev time.
- casper14 1y ago[flagged]
- deleted 1y ago[deleted]
- johnisgood 1y ago[flagged]
- wiseowise 1y agoI hope you’ll be stuck debugging “error happened” without stuck trace and “x, y or z” are missing forever.
- 20k 1y agoMy forever favourite error message is iverilog encountering a problem and simply printing: I give up
- nyarlathotep_ 1y ago>> long running batch job 'process exited with status 1'
- franktankbank 1y agoYou must be eternally frustrating junior.
- Centigonal 1y agothoughtful programming tips? on my HN??
- Twirrim 1y agoGlad I'm not working with you if you consider that kind of PR comment to be worthy of a negative comment.
- CamperBob2 1y agoI would have just replied with "Oops, something went wrong." If it hadn't already been flagged, that is.
- johnisgood 1y agoWhich is unfortunately very commonplace.
- johnisgood 1y agoFunny how statements like these get upvoted and not flagged, but my "Lmao" did. I should be more toxic it seems. Which I thought is worse than an "Lmao" but hey, HN knows best. ("Lmao" is useless, but definitely not worse than some other responses.)
- niux 1y agoWhy not add a boolean flag and use a single exit(1) at the end? That way the user can see all the environment variables that have not been set.
- gvalkov 1y agoThis is nitpicking, but this is a good usecase for the := operator: if not (API_KEY := os.getenv("API_KEY")): ... For internal tools I just let os.environ["API_KEY"] raise a KeyError. It's descriptive enough.
- arthurcolle 1y agoI always forget this syntax exists. When was this introduced?
- gvalkov 1y agoIn Python 3.8 - https://peps.python.org/pep-0572/ https://peps.python.org/pep-0572/
- DangitBobby 1y agoOctober 2019 in Python 3.8 https://docs.python.org/3/whatsnew/3.8.html https://docs.python.org/3/whatsnew/3.8.html
- cranium 1y agoThe Walrus operator! Introduced in Python 3.8 according to the PEP 572. Really nice to combine 1) checking if something exists and 2) act on it
- deleted 1y ago[deleted]
- indymike 1y agoYou forgot to end with "goo goo g'joob" or the less correct Simon and Garfunkel version "coo coo ca choo".
- Iwan-Zotow 1y agoAnd for lambdas
- tyrust 1y ago
- wcrossbow 1y agoEven better is to try to fetch all the env variables and then report on all of the missing ones.
- pyuser583 1y agoIt would be better to do both: print out the detailed string or strings, then exit if either are printed.
- danielrico 1y agoEven better, check all the conditions and report all the errors. Don't make me add the first variable, run it again and get another error. Sometimes that's inevitable, bit noisy of the time it isn't.
- taeric 1y agoI'm surprised there isn't an argparse like thing for documenting expected environment variables.
- icedchai 1y agoThat's basically pydantic settings: https://docs.pydantic.dev/latest/concepts/pydantic_settings/ https://docs.pydantic.dev/latest/concepts/pydantic_settings/
- paisawalla 1y agoTaking ephemeral arguments like channel ID from the environment is more offensive to observability and user comfort
- conductr 1y agoI feel like use case and audience matters when making these decisions. In this case, the user is probably someone interacting with a python script they're running in a console (I assume by print), then I really don't think it matters - the user will check that both things are set. Should you also give them some documentation about setting env vars? Should you customize that documentation to the OS they're running? etc. If the user is a typical consumer using a typical consumer interface, then yes you want to handhold them a bit more.
- bjourne 1y agoNeophytes take notice. Attention to details like this is what separates truly great programmers from merely good ones. That said, for scripts reusable by others you should use command line arguments . Environment variables in lieu of command line arguments is a huge code smell.
- shakna 1y agoYou don't generally want API keys accidentally recorded into someone's bash history.
- deleted 1y ago[deleted]
- zahlman 1y agoWhat exactly is your threat model, where the attacker can read ~/.bash_history but can't execute (or capture output from) /usr/bin/env?
- pastage 1y agoYou do NOT save passwords in shell history, it is insanely insecure. Lets begin with the passwords being readable by everything that can list tasks. You can protect passwords in a password manager. You do not need to keep the passwords in env and I do not.
- zahlman 1y ago> Lets begin with the passwords being readable by everything that can list tasks. Why are processes running that can do this, that I don't already fully trust? > You can protect passwords in a password manager. What's your plan for supplying the password to the program, given that people will want to automate use of the program?
- dapperdrake 1y agoThreat model: shell scripts
- JohnKemeny 1y agoexit("Missing ...") This prints the message and exits with code 1.
- cristoperb 1y agoEven slightly better is to first check both if not API_KEY and not CHANNEL_ID: print("Missing both YOUTUBE_API_KEY and YOUTUBE_CHANNEL_ID.") exit(1) if not API_KEY: print("Missing YOUTUBE_API_KEY.") exit(1) if not CHANNEL_ID: print("Missing YOUTUBE_CHANNEL_ID.") exit(1) That way you don't end up fixing one just come back and be told you're also missing another requirement
- delusional 1y agoEven better would be to only check each once and buffer the decision: valid = True if not API_KEY: print("Missing YOUTUBE_API_KEY.") valid = False if not CHANNEL_ID: print("Missing YOUTUBE_CHANNEL_ID.") valid = False if not valid: exit(1) This way you only check each value once (because your logic might be more complicated than just checking it's not set, maybe it can be wrongly formatted) and you still get to do whatever logic you want. It also removed the combinatorial problems. This is a pretty general principle of separating decision from action.
- pinoy420 1y ago[dead]
- make3 1y agowhy print then exit(1) instead of raising an exception?
- mdaniel 1y agoOh, I know this one: $ python3 -c "print('clear messaging'); exit(1)" clear messaging $ python3 -c "raise ValueError('text that matters')" Traceback (most recent call last): File "<string>", line 1, in <module> ValueError: text that matters and that story gets _a lot_ worse when some programs raise from within a "helper" module and you end up with 8 lines of Python junk to the one line of actual signal
- deleted 1y ago[deleted]
- stana 1y agoOr API_KEY = os.environ.get("YOUTUBE_API_KEY") CHANNEL_ID = os.environ.get("YOUTUBE_CHANNEL_ID") assert(API_KEY, "Missing YOUTUBE_API_KEY") assert(CHANNEL_ID, "Missing CHANNEL_ID")
- Tempest1981 1y agoDo you use parens with assert? In Python, the assert statement is not a function, right? That bit me before... it created a tuple which evaluated as true.
- IshKebab 1y agoAssertions are disabled via `python -O` so they probably shouldn't be used like this.
- rcarmo 1y agoI usually go through an array of settings that must be defined and list any missing ones, to avoid repeated attempts from the user/deployer.
- Suppafly 1y agoThank you. I see something like this all the time on one of the sites I use for work. If you fail the 2-factor, it'll tell you your password was wrong and reset the whole thing instead of telling you the 2-factor code was wrong or expired.
- Perepiska 1y agoJust use if not API_KEY: sys.exit("Missing YOUTUBE_API_KEY.") It will print message to sys.stderr and do system exit with code 1. P.S. exit() is just an alias to sys.exit(), I prefer longer form.