0

My project structure looks like this:

project/
  main.py
  sub_a/
    class_a.py
    __init__.py
    utils/
      __init__.py
      util_a.py
  sub_b/
    class_b.py
    __init__.py
    utils/
      __init__.py
      util_b.py

And in each of class_a.py, class_b.py, there is an import like this:

from utils import util_a/b

My PYTHONPATH points to both sub_a and sub_b. When I try to

import class_b

in main.py, I get an ImportError:

ImportError: cannot import name util_b

I am using Python 2.7.

I understand that the error comes about because from utils import util_b is ambiguous, so Python chooses the first one on the path, but how can I rewrite the imports so that they work?

I don't think changing the PYTHONPATH is an option, since each of sub_a and sub_b assume they are part of the PYTHONPATH in their own internal imports. For instance, the from utils import util_b in class_b.py.

mwlon
  • 798
  • 5
  • 19
  • Where is the problematic import statement? Is it inside `main.py`? I started playing around with this in a repo: https://github.com/fireproofsocks/python_import . -- it's a work in progress but maybe one of the examples there will help clarify Python's behavior. – Everett Jun 14 '19 at 22:46

2 Answers2

1

Don't add both subdirectories to PYTHONPATH. Instead, add only project to it and import sub_a.utils.util_a and sub_b.utils.utils_b.
(In the packages themselves, you can use relative imports to import things from the same subtree. E.g. in sub_b/__init__.py: import .utils.utils_b)

As per isinstance fails for a type imported via package and from the same module directly , if you add the subdirectories, utils package gets associated with whichever is earlier on sys.path and only it will be searched whenever you try to import anything from utils.

ivan_pozdeev
  • 33,874
  • 19
  • 107
  • 152
  • I don't think this quite works, since each submodule depends on its own imports. For instance, files in `sub_b` call something like `from utils import util_b`. – mwlon Jun 14 '19 at 22:52
  • 1
    @mwlon use relative imports in this case: `from .utils import util_b`. – ivan_pozdeev Jun 14 '19 at 23:00
  • So there's no way to make it work without changing one or both of the submodules? Also, aren't relative imports frowned upon? – mwlon Jun 14 '19 at 23:09
  • 1
    @mwlon A relative import is syntax sugar. `from .utils import util_b` in `sub_b` is equivalent to `from sub_b.utils import util_b` but without hardcoding the current module name. They may have been frowned upon when they were new but now they are supported by all non-EOL versions. See https://realpython.com/absolute-vs-relative-python-imports/ for pros and cons. – ivan_pozdeev Jun 14 '19 at 23:25
0

What you looking for is 'Import As'

Good overview here: Answered in another thread from ... import OR import ... as for modules'

from project.sub_a import User as aUser

from project.sub_b import User as bUser

Alex R
  • 77
  • 5
  • I clarified the constraint that each submodule requires its own pythonpath to import from utils, which becomes ambiguous. How do I work around that? – mwlon Jun 14 '19 at 23:00