How to import a Python module from a sibling folder? [duplicate]
Asked Answered
B

3

70

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
Bouillon answered 14/2, 2013 at 23:48 Comment(2)
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.Chromolithograph
Give this answer a try. It worked for mePeres
A
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.

Aerosphere answered 14/2, 2013 at 23:53 Comment(9)
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 suchBouillon
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".Aerosphere
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.Singlecross
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?Scoutmaster
@Scoutmaster 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).Heterogamy
While @DavidWolever is 100% right, the preferred style is to use a full import once you've done those __init__.py tricks. E.g., from <toplevel>.A import Account.Heterogamy
I created an __init__.py and I'm still getting the same error. I'm on Python 3.7. What gives?Franchot
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.Isopiestic
If nothing here is working for you, I recommend reading the accepted answer to this question: stackoverflow.com/questions/14132789/…. It explains how relative imports work and helped me understand at least why my imports weren't working.Bogy
G
17

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!")
Gobbet answered 27/5, 2021 at 16:27 Comment(3)
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.Metheglin
It does not working for me. But works with only a dot sys.path.append(".")Dallasdalli
Amazing that I had to search for hours for an answer to a very common problem that has frustrated so many people, when it should be easily found in the docs, and also that the solution is so relatively complicated for something that comes up so often. I thought simple is better than complex?Syndrome
D
2

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.

Durward answered 4/5, 2022 at 14:38 Comment(1)
This should be the accepted answer, and it does not requires calling sys.path.append("..") Misconceive

© 2022 - 2024 — McMap. All rights reserved.