Import Script from a Parent Directory
Asked Answered
F

4

90

How do I import a module(python file) that resides in the parent directory?

Both directories have a __init__.py file in them but I still cannot import a file from the parent directory?

In this folder layout, Script B is attempting to import Script A:

Folder A:
   __init__.py
   Script A:
   Folder B:
     __init__.py
     Script B(attempting to import Script A)

The following code in Script B doesn't work:

import ../scriptA.py # I get a compile error saying the "." is invalid
Fultz answered 21/1, 2012 at 6:48 Comment(2)
Not exactly answering your question, but if you run init.py inside Folder A and try and import Folder B or Script B, Script A will be successfully imported inside Script B.Bravery
Possible duplicate of Importing modules from parent folderOchrea
A
84

You don't import scripts in Python you import modules. Some python modules are also scripts that you can run directly (they do some useful work at a module-level).

In general it is preferable to use absolute imports rather than relative imports.

toplevel_package/
├── __init__.py
├── moduleA.py
└── subpackage
    ├── __init__.py
    └── moduleB.py

In moduleB:

from toplevel_package import moduleA

If you'd like to run moduleB.py as a script then make sure that parent directory for toplevel_package is in your sys.path.

Aestival answered 21/1, 2012 at 8:4 Comment(10)
And why shouldn't sys path "hacks" be used in this case? Python makes it so hard to do what you want here without them. What exactly is the downside here?Lithomarge
@BT «sys.path.append(path_to_parent)» shouldn't be an answer to how to fix «"import ../scriptA.py # I get a compile error saying the "." is invalid"» question. There are cases where changing sys.path could be useful e.g., if python itself'd done it or a 3-party module that handles all corner cases correctly done it e.g., import autopath; autopath.add_toplevel_to_syspath() that automatically adds parent directory of toplevel_package to sys.path to allow a direct internal module execution as a script (or in a REPL) from any directory without proper PYTHONPATH or (virtualenv) install.Aestival
@J.F.Sebastian Is there some kind of proposal for a feature that allows us to explicit say what is the main folder or package of the whole project so that we don't have to care about adding parent directories to sys.path so that we can run submodules also as main files or scripts? I have a project where I really need to run scripts both as main or as modules, that is imported, but I need to do tons of hacks adding paths to sys.path to make them work in both cases. Would work in a virtualenv or using setuptools work somehow? I am really struggling with this...Haggai
@Haggai the feature is called pip install main-package. You can run "submodules" already (just use their absolute names e.g., python -ma.b.c). If it is unclear; askAestival
@Aestival So what you are suggesting is to add toplevel_package to PYTHONPATH whenever I start to work on new application?Womanizer
@Pietrko: The answer discusses how to import toplevel_package.moduleA from toplevel_package.subpackage.moduleB that is run as a script. I don't see what it has to do with "new applications"Aestival
"If you'd like to run moduleB.py as a script then make sure that parent directory for toplevel_package is in your sys.path." This sentence is gold. That solved all my problems, thank you.Fumikofumitory
This solution doesn't work for me. It raises: "ImportError: No module named toplevel_package"Hygienics
This solution works on my local fine but when I build it on docker it throws error. Instead of that I coppied the file to the other location too. Idk if you had error while deploying on docker but this is just a warning note in case you have the same problemForeshorten
What if moduleA.py is in a folder?Allegiance
J
37

From the docs:

from .. import scriptA

You can do this in packages, but not in scripts you run directly. From the link above:

Note that both explicit and implicit relative imports are based on the name of the current module. Since the name of the main module is always "__main__", modules intended for use as the main module of a Python application should always use absolute imports.

If you create a script that imports A.B.B, you won't receive the ValueError.

Juxtaposition answered 21/1, 2012 at 6:50 Comment(6)
ValueError: Attempted relative import in non-packageTso
@jgritty, that's because you're doing it in a script that you're running directly.Juxtaposition
Yes, you're right. It will work if you call a script that then imports Script B.Tso
@Tso sys.path.append("..") is what you're looking forIcken
Finally, 6 years later, the code snippet I've been looking for!Tso
@jgritty: "For every problem there is a solution that is simple, neat—and wrong." Mangling sys.path inside your script is the kind of solution that you grow to regret in time.Aestival
V
6

If you want to run the script directly, you can:

  1. Add the FolderA's path to the environment variable (PYTHONPATH).
  2. Add the path to sys.path in the your script.

Then:

import module_you_wanted
Vivanvivarium answered 21/1, 2012 at 7:46 Comment(0)
A
0

I struggled same kind of issue, and published syspend module on PyPI https://pypi.org/project/syspend/ This searches parent directories which have specific named file, and calls sys.path.append(directory: which has SYSPEND_ROOT file).

Folder A:
   __init__.py
   Script A:
   Folder B:
     __init__.py
     Script B(attempting to import Script A)
   SYSPEND_ROOT

In your case, please put SYSPEND_ROOT file. Empty file is OK. In your ScriptB.py

import syspend
import ScriptA

if __name__ == "__main__":
    ScriptA.method()
Azar answered 11/3, 2023 at 1:38 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.