1

I am creating a Python package with multiple modules. I want to make sure that when I import modules within the package that they are importing only from the package and not something outside the package that has the same name.

Is the correct way of doing this is to use relative imports? Will this interfere when I move my package to a different location on my machine (or gets installed wherever on a customer's machine)?

jlconlin
  • 14,206
  • 22
  • 72
  • 105

2 Answers2

3

Modern relative imports (here's a reference) are package-relative and package-specific, so as long as the internal structure of your package does not change you can move the package as a whole around wherever you want.

While Joran Beasley's answer should work as well (though does not seem necessary in those older versions of Python where absolute imports aren't the default, as the old style of importing checked within the package's directory first), I personally don't really like modifying the import path like that when you don't have to, especially if you need to load some of those other packages or modules that your modules or packages now shadow.

A warning, however: these do require that the module in question is loaded as part of a package, or at least have their __name__ set to indicate a location in a package. Relative imports won't work for a module when __name__ == '__main__', so if you're writing a simple/casual script that utilizes another module in the same directory as it (and want to make sure the script will refer to the proper directory, things won't work right if the current working directory is not set to the script's), you could do something like import os, sys; sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) (with thanks to https://stackoverflow.com/a/1432949/138772 for the idea). As noted in S.Lott's answer to the same question, this probably isn't something you'd want to do professionally or as part of a team project, but for something personal where you're just doing some menial task automation or the like it should be fine.

Community
  • 1
  • 1
JAB
  • 20,783
  • 6
  • 71
  • 80
  • I agree that he probably shouldn't modify it in the method I gave as an example ... I tried to make that clear :P – Joran Beasley Jan 17 '14 at 20:35
  • @JoranBeasley I was mainly referring to the first part of your answer, though the second one is less dangerous than you might think (built-in packages and modules still seem be available, even when you do `sys.path = []`, and you could always switch over any necessary imports to use the underlying `__import__` function, which does allow path specification iirc). – JAB Jan 17 '14 at 20:44
  • I did just realize that your version might not work right if the current working directory is changed during execution, though. Something like what http://stackoverflow.com/a/1432949/138772 does would fix that, though. – JAB Jan 17 '14 at 20:49
  • When creating/debugging my modules, I often use the `if __name__ == '__main__':` feature. From your comment, it seems that I can't do this if I'm using relative imports. Correct? – jlconlin Jan 17 '14 at 20:55
  • @Jeremy Unfortunately not, but there are ways you can get around that (using a mock package, setting up `__init__.py` to do things, etc.), and you could always use absolute imports within the conditional. The simplest way might be to set `__name__` to what it would actually be when the module is imported for package usage for any modules imported into `__main__`, which might let you get away with some of that. That's how I'd probably do it if it became an issue, at least. – JAB Jan 17 '14 at 20:58
2

the sys.path tells python where to look for imports

add

import sys
sys.path.insert(0,".")

to the top of your main python script this will ensure local packages are imported BEFORE builtin packages (although tbh I think this happens automagically)

if you really want to import only packages in your folder do

import sys
sys.path = ["."]

however I do not recommend this at all as it will probably break lots of your stuff ...

most IDE's (eclipse/pycharm/etc) provide mechanisms to set up the environment a project uses including its paths

really the best option is not to name packages the same as builtin packages or 3rd party modules that are installed on your system

also the best option is to distribute it via a correctly bundled package, this should more than suffice

Joran Beasley
  • 110,522
  • 12
  • 160
  • 179
  • I agree it's a bad idea to name packages the same as 3rd party or built-in packages, but that's nearly impossible. For example: I don't know what packages will be on someone else's machine. – jlconlin Jan 17 '14 at 20:25
  • its not nearly impossible it should be relatively easy to avoid naming conflicts (at least with builtins and most 3rd party modules)... and every developer does it with very little problem ... class names can be the same just use unique filenames `from Myapp_Users import User` for example – Joran Beasley Jan 17 '14 at 20:28