←back to thread

421 points briankelly | 5 comments | | HN request time: 0s | source
Show context
necovek ◴[] No.43575664[source]
The premise might possibly be true, but as an actually seasoned Python developer, I've taken a look at one file: https://github.com/dx-tooling/platform-problem-monitoring-co...

All of it smells of a (lousy) junior software engineer: from configuring root logger at the top, module level (which relies on module import caching not to be reapplied), over not using a stdlib config file parser and building one themselves, to a raciness in load_json where it's checked for file existence with an if and then carrying on as if the file is certainly there...

In a nutshell, if the rest of it is like this, it simply sucks.

replies(23): >>43575714 #>>43575764 #>>43575953 #>>43576545 #>>43576732 #>>43576977 #>>43577008 #>>43577017 #>>43577193 #>>43577214 #>>43577226 #>>43577314 #>>43577850 #>>43578934 #>>43578952 #>>43578973 #>>43579760 #>>43581498 #>>43582065 #>>43583922 #>>43585046 #>>43585094 #>>43587376 #
byproxy ◴[] No.43577008[source]
As an actually unseasoned Python developer, would you be so kind as to explain why the problems you see are problems and their alternatives? Particularly the first two you note.
replies(1): >>43577346 #
1. saila ◴[] No.43577346[source]
The call to logging.basicConfig happens at import time, which could cause issues in certain scenarios. For a one-off script, it's probably fine, but for a production app, you'd probably want to set up logging during app startup from whatever your main entry point is.

The Python standard library has a configparser module, which should be used instead of custom code. It's safer and easier than manual parsing. The standard library also has a tomllib module, which would be an even better option IMO.

replies(1): >>43585513 #
2. cinntaile ◴[] No.43585513[source]
Regarding your first paragraph, we still don't understand what the issue actually is.
replies(1): >>43592648 #
3. necovek ◴[] No.43592648[source]
Logging configuration is done at import time for "utils" module.

Imagine code like this:

main.py:

  import logging
  logging.basicConfig(...)

  logging.info("foo") # uses above config
  
  if __name__ == "__main__":
      import utils # your config is overridden with the one in utils
      logging.info("bar") # uses utils configuration
      ...
Or two "commands", one importing utils and another not: they would non-obviously use different logging configuration.

It gets even crazier: you could import utils to set the configuration, override it, but a second import would not re-set it, as module imports are cached.

Basically, don't do it and no unexpected, confusing behaviour anywhere.

replies(1): >>43595240 #
4. bumblehean ◴[] No.43595240{3}[source]
As a non Python developer, what would be the use-case(s) for importing a module inside of the main function instead of importing it at the top of main.py with the others?
replies(1): >>43598011 #
5. necovek ◴[] No.43598011{4}[source]
Since the entire evaluation and running is dynamic, you don't need to import (and thus evaluate) a module in certain branches.

Eg. that `if __name__` trick is used to allow a module to be both a runnable script and importable module.

Top it off with plenty of common libraries being dog-slow to import because they are doing some of the anti-pattern stuff too, and you end up executing a lot of code when you just want to import a single module.

Eg. I've seen large Python projects that take 75s just importing all the modules because they are listing imports at the top, and many are executing code during import — imagine wanting to run a simple unit test, and your test runner takes 75s just to get to the point where it can run that 0.01s test for your "quick" TDD iteration.

You can also look at Instagram's approach to solving this over at their engineering blog.