2

I tried reading other similar questions but the answers didn't work for me, like Python submodule imports using __init__.py and module has no attribute

I have a folder structure like so:

python_scripts
├── lib
│   ├── __init__.py      # import lib.talk
│   └── talk.py          # def sayhello(x): print(x)
│   
├── src
│   ├── __init__.py      # import lib.talk
│   └── data
│       ├── __init__.py  # import lib.talk
│       └── main.py      # from lib.talk import sayhello
│                          sayhello('hi')
│
└── __init__.py          # import lib.talk

This throws an error:

Traceback (most recent call last):
  File "main.py", line 1, in <module>
    from lib.talk import sayhello
ModuleNotFoundError: No module named 'lib.talk'

The strange thing is if I simply 'import lib' in main.py there is no error. How should I solve this?

I am using Windows and I would highly prefer to avoid using the sys.path method because we don't want to hardcode the path in (this may be used by other teams in the future).

yl_low
  • 1,209
  • 2
  • 17
  • 26

2 Answers2

4

In your main.py file, add following on the top.

import sys
path = r'{path_to_python_scripts}'

if path not in sys.path:
    sys.path.append(path)

# Now import
import lib

or

import sys, os
path = os.path.abspath('../..')

if path not in sys.path:
    sys.path.append(path)

# Now import
import lib

or How to import a module given the full path?

Oli
  • 1,313
  • 14
  • 31
0

Use from ...lib import talk. Your import lib.talk doesn't work since lib is a package because of __init__.py inside lib dictionary. You can also use path appending way, but you need to get it something like this:

import os, sys
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', 'libs')))

This way you will always append path to libs dynamically no matter where your Python code is stored.

maQ
  • 496
  • 3
  • 8
  • Hi, thanks for your reply. I tried both methods unfortunately it still throws an error: ImportError: cannot import name 'talk' – yl_low Apr 11 '18 at 01:27
  • My bad. I didn't take a proper look at your directory tree. I have modified my answer. My small suggestion for you: when you build something like this `main.py` should be in the main directory, so all imports from subdirectory/subpackage will be relative to this script. At your solution, you need to go up over your directory tree and also other people will have a problem to find `main.py`. – maQ Apr 11 '18 at 07:34
  • thanks for your suggestion. i wanted this main.py to be the script to pull all the data (hence inside the data folder). there would be another app.py at the main directory for the actual app. maybe i should move main.py to the main directory and rename it pull_data.py – yl_low Apr 11 '18 at 07:43
  • 1
    Separate data file and logic. `data` folder should be only for storing data. No Python files inside. Data parser should be inside `lib` and `main.py` should in the main directory. This way when you import parser from lib directory into main, path to data directory still be relative to main.py. It's easier to maintain. – maQ Apr 11 '18 at 07:46