0

I have a library like this. wckg is the library name

wckg:
  __init__.py
  api/wckg_api.py

In __init__.py, I import the wckg_api scope and have an enum defined:

from wckg.api import wckg_api
class RelType(Enum):
   a = 1
   b = 2

WCKG = wckg_api.Wckg()

In api/wckg_api.py:

from wckg import RelType
   class Wckg(object):
     pass

As you can see, from wckg_api.py, it imports RelType from __init__, and at the same time it imports wckg_api from from wckg.api.py to create the Wckg object. This is circular and it reports an error:

ImportError: cannot import name 'RelType' from 'wckg' (/Users/comin/nlpc/wckg/wckg/init.py)

Is there a way to resolve this issue? init defined the interfaces and wckg_api.py is supposed to define the implementations of interfaces. I dont' want to define the constant RelType in wckg_api.py because I don't want users to import those constant types when users call a function from init. Those types can be immediately available to users. But since init also need to import something from wckg_api.py, it creates this circular import issue.

Is this a typical issue?

Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214
marlon
  • 6,029
  • 8
  • 42
  • 76
  • put `RelType` in a different file than `__init__.py` – Paul H Oct 26 '20 at 17:01
  • Does this answer your question? [Circular (or cyclic) imports in Python](https://stackoverflow.com/questions/744373/circular-or-cyclic-imports-in-python) – AlexisG Oct 26 '20 at 17:03
  • @PaulH, by defining it in __init__,py, uses don't have to import. Is that right? Is this good practice? – marlon Oct 26 '20 at 17:05
  • 1
    you import it into the `__init__.py` file from the other file – Paul H Oct 26 '20 at 17:05
  • here's a typical `__init__.py` file that i've written: https://github.com/phobson/paramnormal/blob/master/paramnormal/__init__.py – Paul H Oct 26 '20 at 17:07
  • @PaulH I will try that. – marlon Oct 26 '20 at 17:11
  • @PaulH, I tried defining the RelType in another file and then import it from __init__. However, when users call a function from __init__ that uses RelType as an argument type, RelType still has to be imported first. Ideally, I want users only need to import the interface library name 'wckg', without needing to import anything else. Is that possible? – marlon Oct 26 '20 at 17:27
  • yes. that's exactly what the `__init__.py` file is for. – Paul H Oct 26 '20 at 17:32

1 Answers1

1

I would fix this like that:

wckg:
  __init__.py
  api/wckg_api.py
  api/_rel_type.py

api/wckg_api.py:

from ._rel_type import RelType

class Wckg(object):
    pass

api/_rel_type.py:

class RelType(Enum):
   a = 1
   b = 2

and under __init__.py:

from wckg.api import wckg_api, RelType

WCKG = wckg_api.Wckg()
orlevii
  • 427
  • 4
  • 10
  • I tried. When user call a function that needs RelType as function argument, he still has to import RelType from _rel_type.py. Ideally, I only want users to import 'wckg' then he can start to use all functions defined in it. – marlon Oct 26 '20 at 17:22
  • The user can now import it from `wckg` directly. It's possible because the `__init__.py` imports it. – orlevii Oct 26 '20 at 17:28
  • I mean I tried, but found that users have to do "import wckg" and also do 'from rel_type import RelType'. Without the second import, it still complains the missing 'RelType'. Is this expcted? I dont' want users to import RelType from either __init__ or rel_type.py. I want it to be available automatically, so that users only need to 'import wckg'. Is that possible? – marlon Oct 26 '20 at 17:41
  • @marlon who are the users in this case? have they installed your package via a `setup.py` file (or a wheel or conda package) because that's what should be happening. It sounds like you're describing developers and that's exactly what should be happening – Paul H Oct 26 '20 at 17:55
  • @PaulH, I am talking about end users. not developers. Yes, they install through pip set.py and import the library name 'wckg', then I hope they can call any function defined in the __init__.py, without requiring them to import individually type like 'RelType'. Is that possible? – marlon Oct 26 '20 at 18:06
  • if you import `RelType` directly in your `__init__` file, it will be available to end users after they import your package (e.g., `import wckg; wckg.RelType`) – Paul H Oct 26 '20 at 18:11
  • OK。 I see, users also need to import wckg.RelType. I thought 'RelType' can be automatically available after users 'import wckg' only. That's why initially I tried to define RelType in __init__.py to hope the need of 'import RelType' can be eliminated. – marlon Oct 26 '20 at 18:21
  • no. if `RelType` is brought directly into `__init__.py`, importing the package will be enough – Paul H Oct 26 '20 at 18:22