68

I have gone through many Python relative import questions but I can't understand the issue/get it to work.

My directory structure is:

Driver.py

A/
      Account.py
      __init__.py

B/
      Test.py
      __init__.py

Driver.py

from B import Test

Account.py

class Account:
def __init__(self):
    self.money = 0

Test.py

from ..A import Account

When I try to run:

python Driver.py

I get the error

Traceback (most recent call last):

from B import Test

File "B/Test.py", line 1, in <module> from ..A import Account

ValueError: Attempted relative import beyond toplevel package
double-beep
  • 5,031
  • 17
  • 33
  • 41
Joshua
  • 1,516
  • 2
  • 22
  • 31
  • 5
    You really should mention your Python version when asking about features which have changed radically between versions (relative imports, Unicode, and a few others). Sometimes people will be able to guess based on the specific error you got, or how you wrote your code, but you shouldn't count on people guessing right. – abarnert Feb 15 '13 at 00:42
  • Give this [answer](https://stackoverflow.com/questions/70395407/import-module-from-a-sibling-directory-in-python3-10/73081295#73081295) a try. It worked for me – Hadi F Jul 22 '22 at 13:45

3 Answers3

39

This is happening because A and B are independent, unrelated, packages as far as Python is concerned.

Create a __init__.py in the same directory as Driver.py and everything should work as expected.

David Wolever
  • 148,955
  • 89
  • 346
  • 502
  • 1
    Thanks! Can you explain the __init__.py files a little bit? I have not understood explanations found online. I come from a c++ background, so I am used to just giving the path for includes and such – Joshua Feb 15 '13 at 14:04
  • 15
    It's a bit hand-wavy, but basically: putting a `__init__.py` file in a directory means "in this directory, all of the `.py` files, and all of the subdirectories which contain a `__init__.py` file, are part of the same package". – David Wolever Feb 15 '13 at 15:56
  • All he needs if from A import Account in driver.py. Adding the extra init.py and using a relative import is a bit awkward and pollutes the toplevel. – Wyrmwood Nov 10 '14 at 19:49
  • 2
    This solution doesn't work for me using Python 2.7.14. I assume the solution is for Python 3.x? Is there a python2 solution for those forced to work in legacy systems? – retsigam Apr 14 '18 at 23:40
  • @retsigam This works for both Python 2 & Python 3. In fact, this syntax was created for Python 2.3 or 2.4 or something like that (I forget the release time). – Mike Williamson Jun 27 '18 at 00:58
  • While @DavidWolever is 100% right, the [preferred style](https://www.python.org/dev/peps/pep-0008/?#imports) is to use a full import once you've done those `__init__.py` tricks. E.g., `from .A import Account`. – Mike Williamson Jun 27 '18 at 01:02
  • 53
    I created an `__init__.py` and I'm still getting the same error. I'm on Python 3.7. What gives? – Jared Nielsen Feb 01 '19 at 02:44
  • I use 3.6.8 and I need `Test.py` to read `from A import account`. Then, I can call `Driver.py` from its containing directory. – smcs Nov 05 '19 at 18:18
  • If nothing here is working for you, I recommend reading the accepted answer to this question: https://stackoverflow.com/questions/14132789/relative-imports-for-the-billionth-time. It explains how relative imports work and helped me understand at least why my imports weren't working. – Rob Streeting Feb 17 '21 at 11:01
14

In my case adding __init__.py was not enough. You also have to append the path of the parent directory if you get module not found error.

root :
 |
 |__SiblingA:
 |    \__A.py
 |     
 |__SiblingB:
 |      \_ __init__.py
 |      \__B.py
 |

To import B.py from A.py, you have to do the following

import sys
  
# append the path of the parent directory
sys.path.append("..")

from SiblingB import B
print("B is successfully imported!")
Shekhar
  • 347
  • 3
  • 13
  • 2
    This worked best for me in August 2022. This should be the accepted answer! The accepted answer does not provide the full directory structure and code for this to work. – Rich Lysakowski PhD Aug 11 '22 at 21:55
  • It does not working for me. But works with only a dot `sys.path.append(".")` – alfredo Dec 15 '22 at 05:17
0

The reason for

ValueError: Attempted relative import beyond toplevel package

is that A is the same directory level as Driver.py. Hence, ..A in from ..A import Account is beyond top-level package.

You can solve this by create a new folder named AandB together with __init__py in this new folder, and then move A and B folders into AandB folder. The directory structure is as following:

The directory structure

Correspondingly, the content in Driver.py should be modified as from AandB.B import Test.