How to fix “Attempted relative import in non-package” even with __init__.py

后端 未结 19 2592
予麋鹿
予麋鹿 2020-11-21 21:51

I\'m trying to follow PEP 328, with the following directory structure:

pkg/
  __init__.py
  components/
    core.py
    __init__.py
  tests/
    core_test.py         


        
相关标签:
19条回答
  • 2020-11-21 22:39

    Here's one way which will piss off everyone but work pretty well. In tests run:

    ln -s ../components components
    

    Then just import components like you normally would.

    0 讨论(0)
  • 2020-11-21 22:40

    If someone is looking for a workaround, I stumbled upon one. Here's a bit of context. I wanted to test out one of the methods I've in a file. When I run it from within

    if __name__ == "__main__":
    

    it always complained of the relative imports. I tried to apply the above solutions, but failed to work, since there were many nested files, each with multiple imports.

    Here's what I did. I just created a launcher, an external program that would import necessary methods and call them. Though, not a great solution, it works.

    0 讨论(0)
  • 2020-11-21 22:41

    You can use from pkg.components.core import GameLoopEvents, for example I use pycharm, the below is my project structure image, I just import from the root package, then it works:

    0 讨论(0)
  • 2020-11-21 22:42

    It depends on how you want to launch your script.

    If you want to launch your UnitTest from the command line in a classic way, that is:

    python tests/core_test.py
    

    Then, since in this case 'components' and 'tests' are siblings folders, you can import the relative module either using the insert or the append method of the sys.path module. Something like:

    import sys
    from os import path
    sys.path.append( path.dirname( path.dirname( path.abspath(__file__) ) ) )
    from components.core import GameLoopEvents
    

    Otherwise, you can launch your script with the '-m' argument (note that in this case, we are talking about a package, and thus you must not give the '.py' extension), that is:

    python -m pkg.tests.core_test
    

    In such a case, you can simply use the relative import as you were doing:

    from ..components.core import GameLoopEvents
    

    You can finally mix the two approaches, so that your script will work no matter how it is called. For example:

    if __name__ == '__main__':
        if __package__ is None:
            import sys
            from os import path
            sys.path.append( path.dirname( path.dirname( path.abspath(__file__) ) ) )
            from components.core import GameLoopEvents
        else:
            from ..components.core import GameLoopEvents
    
    0 讨论(0)
  • 2020-11-21 22:42

    Because your code contains if __name__ == "__main__", which doesn't be imported as a package, you'd better use sys.path.append() to solve the problem.

    0 讨论(0)
  • 2020-11-21 22:43

    In core_test.py, do the following:

    import sys
    sys.path.append('../components')
    from core import GameLoopEvents
    
    0 讨论(0)
提交回复
热议问题