4 ms·
Wake me up when we can import a module by relative file path.
by IshKebab 1y ago
Wake me up when we can import a module by relative file path.
- Spivak 1y agoYou… can? I mean in the strictest sense you're technically not importing by file path but if you make your folder a module by slapping an __init__.py in there then your relative imports will follow the directory tree. I think as of Python 3.3 the init file is optional so it will do it by default but I can't remember if there are still some cases where it's required. The only thing you can't do is go "up" to a higher directory than the root module. Also if that doesn't strike your fancy all of the importlib machinery is at your disposal and it's really not very much work to write an import_path() function. It's one of the patterns plug-in systems use and so is stable and expected to be used by end users. No arcane magic required.
- zahlman 1y ago> if you make your folder a module by slapping an __init__.py in there then your relative imports will follow the directory tree. `__init__.py` has nothing to do with making this work. It is neither necessary (as of 3.3, yes, you got it right: see https://peps.python.org/pep-0420/ https://peps.python.org/pep-0420/) nor sufficient (careless use of sys.path and absolute imports could make it so that the current folder hasn't been imported yet, so you can't even go "up into" it). The folder will already be represented by a module object. What `__init__.py` does is: 1. Prevents relative imports from also potentially checking in other paths. 2. Provides a space for code that runs before sub-modules, for example to set useful package attributes such as `__all__` (which controls star-imports).
- IshKebab 1y ago> if you make your folder a module by slapping an __init__.py in there then your relative imports will follow the directory tree haha no > all of the importlib machinery is at your disposal This breaks all tooling. Awful option.
- zahlman 1y agoRelative imports have been supported for approximately forever (https://stackoverflow.com/questions/72852 https://stackoverflow.com/questions/72852). If you mean "by explicitly specifying a path string" (as opposed to a symbolic name), that has also been supported for approximately forever (https://stackoverflow.com/questions/67631 https://stackoverflow.com/questions/67631). Today, the `importlib` standard library exposes all the steps of the import process — including figuring out where the source code is, checking the `sys.modules` cache etc. — and lets you hook into everything (in particular, you can bypass the entire "finder" process and turn a file path into a dummy "spec" which is fed to a "loader"). The flexibility of this system also entails that you can in effect define a completely new programming language, describe the process of creating Python bytecode from your custom source, and have clients transparently `import` source in the other language as a result. Or you can define an import process that grabs code from the Internet (not that it would be a good idea...). If you mean "by explicitly specifying a relative path, and having it be interpreted according to the path of the current module's source code", well first you have to consider that the current module isn't required to have source code. But if it does, then generally it will have been loaded with the default mechanism, which means the module object will have a `__file__` attribute with an absolute path, and you just set your path relative to that.
- IshKebab 1y agoNope. Relative imports work by relative package path, which is not at all the same. Often when you run Python you don't even have a package path. Using `importlib` is a horrible hack that breaks basically all tooling. You very very obviously are not supposed to do that.
- zahlman 1y ago> Relative imports work by relative package path, which is not at all the same. Exactly. This gives you the flexibility to distribute a complex package across multiple locations. > Often when you run Python you don't even have a package path. Any time you successfully import foo.bar, you necessarily have imported foo (because bar is an attribute of that object!), and therefore bar can `from . import` its siblings. > Using `importlib` is a horrible hack that breaks basically all tooling. You very very obviously are not supposed to do that. It is exactly as obvious (and true) that you are not "supposed to", in the exact same sense, directly specify where on disk the source code file you want to import is. After all, this constrains the import process to use a source code file. (Similarly if you specify a .pyc directly.) Your relative path doesn't necessarily make any sense after you have packaged and distributed your code and someone else has installed it. It definitely doesn't make any sense if you pack all your modules into a zipapp.