1

I have the following project structure:

xxx
├── xxx
|   ├── settings
|   └── tests
|   └── __init__.py
|   └── conf.py
|   └── xxx.py
|   └── utils.py

Those are the imports that I have in each file.

xxx.py

from xxx import utils, conf
from xxx.conf import BASE_DIR

conf.py

import os
import yaml

utils.py

import os
import shutil
from typing import List, Optional, Tuple, Dict, Union
import requests

When I run my app with

python3 xxx.py

I get the following error:

ImportError: cannot import name 'utils' from 'xxx' (/Users/yyyyy/workscpace/xxx/xxx/xxx.py)

When I run my test suite with pytest, I don't get any errors.

I have tried to change the import to (because those files are modules in my package):

import utils
import conf

In this case, I can run my app with no errors but I get the following error when trying to run pytest

ModuleNotFoundError: No module named 'utils'

What am I doing wrong?

Laurent S
  • 4,106
  • 3
  • 26
  • 50
shlomiLan
  • 659
  • 1
  • 9
  • 33

3 Answers3

1

Is your package's name xxx.py?

If those two have the same name, Python will import the xxx.py not the package xxx because Python looks for packages in sys.path sequentially, and the first entry is usually the current directory (of the project).

Otherwise, if you only have python xxx.py, sys.path will have current path in xxx package, but if you use pytest import xxx, the current not in xxx package, python will not find package or .py in xxx package and can't find utils.py and conf.py in this case you can try to write from . import * in _ init _.py or in xxx.py write from . import utils, conf

jbwang
  • 11
  • 3
  • Hi @jbwabg, could you please clarify your answer? I think you made a good point here, only it's a bit unclear... – toti08 Sep 28 '18 at 15:35
1

Your question is very similar to ModuleNotFoundError: No module named x

When you run python3 xxx.py, it becomes the main module, so it's looking for something like xxx/xxx/xxx/utils.py. When you run pytest, it is aware of the xxx package, and therefore picks up the utils and conf as you expect.

If you use absolute imports, the tests fail because python is now looking for utils on sys.path. But python3 xxx.py works because the local folder is added to your sys.path.

A clean solution would be to create a main.py one level up from utils.py and conf.py and import your code from there, like:

# main.py
from xxx import utils, conf

def main():
    # do stuff here

if __name__ == __main__:
    main()
Laurent S
  • 4,106
  • 3
  • 26
  • 50
1

When I run my app with

python3 xxx.py

This means that your current working directory is inside the xxx package. There is no xxx.conf to discover, because the top level seen to python is at conf, utils etc.

Run your app from the parent folder using the -m switch:

python3 -m xxx.xxx

Note that it is a good idea to avoid naming sub packages like the main package. This avoids confusion, especially when you or someone else has to maintain your package in the future.

Community
  • 1
  • 1
MisterMiyagi
  • 44,374
  • 10
  • 104
  • 119
  • I can run my app with `python -m xxx.xxx`, why is that? In "main package" are you referring to the top 'xxx' folder? this one is only the project (and repository) root, it's not a package. – shlomiLan Sep 28 '18 at 16:18