> What problem are you having with imports?
This is a Python function I wrote some years ago to import a module when given a path:
def module_from_path( name, path ):
### thx to https://stackoverflow.com/a/50395128/7568091 ###
### thx to https://stackoverflow.com/a/67692/7568091 ###
import importlib
import importlib.util
spec = importlib.util.spec_from_file_location( name, path )
module = importlib.util.module_from_spec( spec )
sys.modules[ spec.name ] = module
spec.loader.exec_module( module )
return importlib.import_module( name )
There are so many conspicuous things about it but to put it short, I should be able to just give a relative or absolute file path, call one method, and be done. Damn all those intermediate steps, and why do I have to name it?The dynamic module:
» cat sub/test_module.py
def hello(name):
print(f'Hello {name}')
The main script: » cat test_script.py
from importlib import import_module
full_module_path = 'sub.test_module' # no ".py"
module = import_module(full_module_path)
# optional, if you want to use across the project:
import sys
sys.modules[full_module_path] = module
print(sys.modules[full_module_path])
# end optional
# try it:
module.hello('there!')
To run it: » python3 test_script.py
<module 'sub.test_module' from '/home/foo/sub/test_module.py'>
Hello there!
Stack overflow has its uses. But you shouldn't rely on it if things have changed, a lot of their advice is outdated and written by non-experts. The importlib module docs explain this concisely.https://docs.python.org/3/library/importlib.html#importlib.i...
In general, I don't see the intrinsic complexity being reduced much more than this:
from importlib import import_module
module = import_module('sub.test_module')> In general, I don't see the intrinsic complexity being reduced much more than this
you know in NodeJS I do `const tm = require('sub/test_module');` which I for a number of reasons do find inherently less complex.
I used to work at a company where they had a custom import system and it was a nightmare.
https://stackoverflow.com/questions/14132789/relative-import...
And you need (maybe used to?) an __init__.py file in each package.
But once you know that, it's straightforward, no? Certainly not, "only a few people in the world know this..." level. Don't think I'm some kinda level-10 genius here.
Yes because referring to the filesystem is logical and intuitive and referring to some abstract "package" that changes depending on how you invoke Python is insane.
> But once you know that, it's straightforward, no?
I wish!
from foo.bar import Baz
And there's a foo/__init__.py file it gets executed merely from path traversal.And because of how Django's settings work (import django.settings and all your stuff is magically there), people in my company have gotten into the habit of putting code in settings/__init__.py to do the things they need, like retrieve secrets from AWS.
Which I don't want to have happen when I'm trying to import settings.bla_module to use a type in a unit test.
Yes, and it needs to—to find the variables there, which may/not be other packages.
> how Django's settings work
Right. Django is great and popular, and so I think many folks don't realize how downright clunky it is in a number of places. Many parts of it are over-engineered like this one. It has improved over time but some things are set in stone due to history. I'd like their settings redesigned myself.
> __init__.py to do the things they need, like retrieve secrets from AWS
No, no, no, no... NO! ;-)
Imports should only create variables, define functions, and/or alias a package. They should never, ever run lengthy computations or access the network. That's basic software design 101, unfortunately not taught everywhere.
I don't see this one as a clear flaw of Python. "Dumb" coding can happen anywhere. I suppose it could prohibit this kind of stuff, but that might prohibit other cool things that might be reasonable in limited situations. It is a "consenting adults" design, with those trade offs.