29

The following is my directory structure.

ankur
├── ankur1
│   ├── __init__.py
│   └── util.py
├── ankur2
│   └── main.py
└── __init__.py

In main.py, I am importing the following.

import ankur.ankur1.util

When I execute the code in Windows, it works perfectly fine. But in Linux, I get the following error.

ImportError: No module named ankur.ankur1.util

I also read the official python doc on Modules and Packages.

mkrieger1
  • 19,194
  • 5
  • 54
  • 65
Ankur Bhatia
  • 996
  • 3
  • 17
  • 29
  • 2
    Have you installed the package into the environment? – Busturdust Apr 18 '17 at 15:33
  • Thanks for the reply. I didn't get it. Do we need to install it separately. In my windows env it works fine. – Ankur Bhatia Apr 18 '17 at 15:35
  • I believe that it is probably a matter of `PYTHONPATH` issue which is properly configured on windows and not on linux, add the code base to the path, or install it so that it automaticaly locates itself tot he path – Busturdust Apr 18 '17 at 15:37
  • Thanks a lot. That was the issue. But how do we configure it to install it automatically. I want users to download the code and run it and not configure the PYTHONPATH. – Ankur Bhatia Apr 18 '17 at 15:50
  • 4
    create a `setup.py` users will be able to install the package using `python setup.py install` Look into writing a proper setup – Busturdust Apr 18 '17 at 15:51
  • Warning ! The "official python doc on Modules and Packages" mentioned at the end of the question refers to "Python 2". If you want to access python3 doc, click this [official python3 doc on Modules and Packages](https://docs.python.org/3/tutorial/modules.html#packages) – duthen Sep 26 '22 at 08:15

1 Answers1

28

Your package structure is OK. Your import statement is OK. The only thing missing is for the package to be visible in sys.path, a list of locations where import statements can be resolved.

Usually we do this by "installing" the package locally with pip, which copies your code into site-packages. This directory is one of the entries in sys.path, so when your code is installed in site-packages, the import statements can now be resolved as usual.

However, to install your code you'll need an installer (setup.py script) or a build system (pyproject.toml file) defined for the package. Your project doesn't appear to have any installer or build system, so you'll need to create one (see the Python Packaging User Guide for details about that) and then install the package with pip. If you don't want to learn Python packaging just yet, you'll need to find another way around.

It is possible to modify sys.path directly in main.py, which is subsequently enabling the statement import ankur.ankur1.util to be resolved. This is hacky and I recommend against that. It would add the restriction that executing main.py is the only entry point to the rest of the package, and so any other code wanting to import ankur will first need to know the path to main.py on the filesystem. That's a messy approach and should be avoided.

Another way around is to use the environment - there is an environment variable PYTHONPATH which can be used to augment the default search path for module files. In your shell:

export PYTHONPATH=/path/to/parent  # linux/macOS
SET PYTHONPATH=C:/path/to/parent   # Windows

Where parent is the directory containing ankur subdirectory.

The exact location of site-packages depends on your OS/platform, but you can check with import sysconfig; sysconfig.get_paths()["purelib"]

wim
  • 338,267
  • 99
  • 616
  • 750
  • 2
    Why should we not directly modify `sys.path` in code? [This highly upvoted answer](https://stackoverflow.com/a/4383597/4688119) directly modifies the python path from the program. – Box Box Box Box Jan 13 '19 at 15:21
  • 2
    It's messy, generally unnecessary, and it's not scaling well. Each entry in `sys.path` is searched on each import statement. So, if every library installed has decided to insert in `sys.path`, instead of just installing into site-packages dir as usual, then the import system becomes slow and unwieldy. Even a [comment from the answerer](https://stackoverflow.com/questions/4383571/importing-files-from-different-folder/4383597#comment53217573_4383597) warns this is not a good solution. Avoid to insert `sys.path` unless you really need a location to be searched first before the site-packages. – wim Jan 14 '19 at 00:22
  • I think when you are in the folder above ankur, type `pip install -e .`. I think this installs your package locally and you dont need any setup tools. In general, maybe it is worth to take a look on relative package imports https://docs.python.org/3/reference/import.html#package-relative-imports – Isi Oct 09 '20 at 12:14
  • `export` isn't available on all platforms, so using it is not always a viable workaround. – martineau Jun 07 '21 at 19:47
  • @martineau The Windows equivalent is SET – wim Jun 07 '21 at 19:54
  • Environment variables defined via `SET` on Windows are not permanent and disappear when that `cmd` shell exits — so I don't think it's quite equivalent. – martineau Jun 07 '21 at 19:59
  • @martineau The same is true of `export`. – wim Jan 16 '23 at 02:25
  • 1
    Hello. What would setup.py script look like? I am encountering similar issue as OP. – TechNewbie Mar 28 '23 at 02:43