2

I have a python (3.6.3) project which has the following structure

setup.py
utils #python package
utils/constants.py
utils/name_reports.py
normalization #python package
normalization/resolve_name.py
categorization #python package
categorization/animal_categories.py

You can find the source code here on github - https://github.com/techmango-org/python-import-resolution

Here is the source code for utils/name_reports.py

import normalization.resolve_name as rn
import categorization.animal_categories as ac

test_name = 'DOGY'
resolved_name = rn.get_animal_name(test_name)

print('********ANIMAL CATEGORY IS:', ac.get_animal_score(resolved_name))

When I run python utils/name_reports.py I am getting the following exception

Traceback (most recent call last):
  File "utils/name_reports.py", line 1, in <module>
    import normalization.resolve_name as rn
ModuleNotFoundError: No module named 'normalization'

I have tried to solve this problem by installing the current package into virtual env site packages by running pip install . but that means for every local change I have to run pip install --upgrade . to move my local changes into site packages.

I have been using a hack -m unittest to get this problem solved. Check this screenshot

enter image description here

But I am unable to understand what difference does it create. Here are the exact questions -

  1. How to resolve python import issue in this situation?
  2. Is there a better approach to structure python code such that we do not face relative imports issue?
  3. What difference does -m unittest is creating which is solving this issue?
Sachin Jain
  • 21,353
  • 33
  • 103
  • 168
  • Did you look around? There are many solutions given in the past, for example: https://stackoverflow.com/questions/10272879/how-do-i-import-a-python-script-from-a-sibling-directory/10272919 – crazyGamer Jan 25 '19 at 08:42
  • 2
    Yeah! There are many SO posts related to this but most of the answers have been outdated and were very old and I do not want to use `sys.path` hack – Sachin Jain Jan 25 '19 at 08:46
  • You don't have to use the `sys.path` hack. using `..` relative imports is a better alternative. I have seen it being used in some large GitHub projects as well. Also make sure you have the `__init__.py` files in place so it is recognized as a package. – crazyGamer Jan 25 '19 at 08:47
  • No, It does not solve the problem and I get error - `ValueError: attempted relative import beyond top-level package`. – Sachin Jain Jan 25 '19 at 08:50
  • Let me add an answer. EDIT: Take a look at this: https://stackoverflow.com/questions/14886143/python-import-module-from-sibling-folder – crazyGamer Jan 25 '19 at 08:51
  • I tried adding __init__.py as mentioned as the answer in the question but it still doesn't work and complained `no module named normalization`. Do you think having one more hierarchy could help here? If you want to answer, you can refer the code on github – Sachin Jain Jan 25 '19 at 09:00

2 Answers2

10

Since there are already many answers on SO for this*, I will focus on question (2). About what is a better code organization:

|- setup.py
|- top_pkg_name
    |- __init__.py
    |- pkg1
        |- __init__.py
    |- pkg2
        |- __init__.py

The (relative) import is done as follows, from inside module_2:

from ..pkg1 import module1 as m1

Alternatively, you can use absolute imports, which refer to the top package name:

from top_pkg_name.pkg1 import module1 as m1

In such an organization, when you want to run any module as a script, you have to use the -m flag:

python -m top_pkg_name.pkg1.module1

For question (3), I'm not sure but it looks like the unittest module adds the folder to path, allowing the imports to happen directly.

*Refer:

  1. How do I import a Python script from a sibling directory?
  2. Python import module from sibling folder
crazyGamer
  • 1,119
  • 9
  • 16
  • You can check in my screenshot that Using `-m flag` code is running fine. Let me try to reorganize the code a/c to your suggestion and see if it fixes the problem. – Sachin Jain Jan 25 '19 at 09:03
  • Check out this branch - https://github.com/techmango-org/python-import-resolution/tree/added-one-more-hierarchy I added one more hierarchy in this branch and it still does not work and fails with `ValueError: attempted relative import beyond top-level package` error – Sachin Jain Jan 25 '19 at 09:12
  • I added some points on how you should be running the code. In your case, try the following in your new branch: `python -m src.utils.name_reports`. Also, note that instead of `src` you should use a name that describes the project or package itself. – crazyGamer Jan 25 '19 at 09:23
  • Thanks, you saved my day :)! I did not find the information regarding the -m flag anywhere! – thomasfermi Sep 23 '20 at 17:18
-1

Use Import statements:

from normalization import resolve_name
from categorization import animal_categories

Your Code:

from normalization import resolve_name as rn
from categorization import animal_categories as ac

test_name = 'DOGY'
resolved_name = rn.get_animal_name(test_name)

print('********ANIMAL CATEGORY IS:', ac.get_animal_score(resolved_name))
Anonymous
  • 659
  • 6
  • 16