Ivan
Ivan

Reputation: 30999

Importing files from different folder

I have this folder structure:

application
├── app
│   └── folder
│       └── file.py
└── app2
    └── some_folder
        └── some_file.py

How can I import a function from file.py, from within some_file.py? I tried:

from application.app.folder.file import func_name

but it doesn't work.

Upvotes: 2624

Views: 3769844

Answers (30)

Markus Hirsimäki
Markus Hirsimäki

Reputation: 685

There are plenty of other solutions already but here is my two cents. Let's say you don't want to do any of these:

  • add __init__.py files
  • run with python -m mymodule
  • edit __package__
  • add if check in __main__
  • edit sys.path by hand
  • edit PYTHONPATH
  • restructure the project

You can instead use a tool that will that will add a given absolute/relative path to sys.path while making sure the path is valid and in the correct format.

$ pip install importmonkey [github] [pip]

# Example structure
├─ src
│   └─ project
│       ├─ __init__.py
│       └─ module.py
└─ test
    └─ test.py
# Example solution using the tool, in test.py

from importmonkey import add_path
add_path("../src")  # relative to current __file__
import project

# You can add as many paths as needed, absolute or relative, in any file.
# Relative paths start from the current __file__ directory.
# Normal unix path conventions work so you can use '..' and '.' and so on.
# The paths you try to add are checked for validity etc. help(add_path) for details.

Disclosure of affiliation: I made importmonkey.

Upvotes: 8

Cameron
Cameron

Reputation: 98736

Note: This answer was intended for a very specific question. For most programmers coming here from a search engine, this is not the answer you are looking for. Typically you would structure your files into packages (see other answers) instead of modifying the search path.


By default, you can't. When importing a file, Python only searches the directory that the entry-point script is running from and sys.path which includes locations such as the package installation directory (it's actually a little more complex than this, but this covers most cases).

However, you can add to the Python path at runtime:

# some_file.py
import sys
# caution: path[0] is reserved for script path (or '' in REPL)
sys.path.insert(1, '/path/to/application/app/folder')

import file

Upvotes: 2328

helloworld
helloworld

Reputation: 673

There are many awesome answers, but I think it is import to note the PATHONPATH. (Below is excerpted from various online resource. Credit to Internet!)

If you have a function in a Python file in another directory, you can still import it by modifying the Python import path or using a relative import.

Here's how you can do it:

Let's assume you have the following directory structure:

my_project/
│
├── main.py
│
└── my_module/
    ├── __init__.py
    └── my_functions.py

Your my_functions.py defined a function named my_function and you want to use it in main.py.

Here is how you can do it:

from my_module.my_functions import my_function

my_function()  # Outputs: Hello, World!

This assumes that my_project is in your Python path. If you're running main.py from the my_project directory, then Python will add my_project to the Python path automatically and it should be able to find my_module.

If my_project is not in your Python path, you must add it manually at the start of main.py:

import sys
sys.path.insert(0, '/path/to/my_project')

from my_module.my_functions import my_function

my_function()  # Outputs: Hello, World!

Replace '/path/to/my_project' with the actual path to my_project.

The __init__.py file in my_module is necessary for Python to recognize my_module as a package that can be imported. If my_module doesn't contain __init__.py, simply create an empty file with that name.

Above answers this question post:

Importing files from different folder

For additional reference, if one needs to import functions defined in different files in the same module, here is the example on how to import functions from one file to another file ( under the same module).

Suppose you have the following directory structure:

src/
    __init__.py
    file1.py
    file2.py

Let's say file1.py contains a function function1(), and you want to use this function in file2.py.

In file2.py, you can import the function from file1.py using the following line:

from .file1 import function1

You can then call function1() in file2.py as if it was defined in the same file.

The . before file1 in the import statement is a relative import, which means "import from the same package". In this case, it's saying "import from the same directory".

Note: This will only work if your script is run as a module (i.e., using the -m flag with Python, like python -m src.file2), not if you run the Python file directly (python file2.py). If you're running the file directly and the other file is in the same directory, you can just do from file1 import function1.

If you are running the file directly and the import is not working, make sure your src folder (the root folder of this module) is in the Python path. The Python path is a list of directories that Python checks when it's looking for the module you're trying to import. You can add the src folder to the Python path by adding it to the PYTHONPATH environment variable, or by adding an empty file named __init__.py in your src directory to make it a package.

Upvotes: 4

Timothy C. Quinn
Timothy C. Quinn

Reputation: 4475

If the purpose of loading a module from a specific path is to assist you during the development of a custom module, you can create a symbolic link in the same folder of the test script that points to the root of the custom module. This module reference will take precedence over any other modules installed of the same name for any script run in that folder.

I tested this on Linux but it should work in any modern OS that supports symbolic links.

One advantage to this approach is that you can you can point to a module that's sitting in your own local software version control branch working copy which can greatly simplify the development cycle time and reduce failure modes of managing different versions of the module.

Upvotes: 6

Mustafa Kareem
Mustafa Kareem

Reputation: 59

Just use the change directory function from the os module:

os.chdir("Here new director")

Then you can import normally.

More information

Upvotes: -4

ChandanK
ChandanK

Reputation: 597

Considering application as the root directory for your Python project, create an empty __init__.py file in the application, app and folder folders. Then in your some_file.py, make changes as follows to get the definition of func_name:

import sys
sys.path.insert(0, r'/from/root/directory/application')

from application.app.folder.file import func_name ## You can also use '*' wildcard to import all the functions in file.py file.
func_name()

Upvotes: 28

joey
joey

Reputation: 14322

There is nothing wrong with:

from application.app.folder.file import func_name

Just make sure folder also contains an __init__.py. This allows it to be included as a package. I am not sure why the other answers talk about PYTHONPATH.

Upvotes: 1394

Ax3l
Ax3l

Reputation: 1529

I think an ad hoc way would be to use the environment variable PYTHONPATH as described in the documentation: Python2, Python3

# Linux and OS X
export PYTHONPATH=$HOME/dirWithScripts/:$PYTHONPATH

# Windows
set PYTHONPATH=C:\path\to\dirWithScripts\;%PYTHONPATH%

Upvotes: 76

Nermin
Nermin

Reputation: 935

2023 Python 3.10+ solution

Out of all the answers here, only martin36's solution hidden in the comments worked for me to enable relative imports.

import sys
sys.path.append('')

(But using append instead of insert)

from application.app.folder.file import func_name

Upvotes: 4

Adilet Usonov
Adilet Usonov

Reputation: 136

This problem may be due to PyCharm

I had the same problem while using PyCharm. I had this project structure

skylake\
   backend\
      apps\
          example.py
      configuration\
          settings.py
   frontend\
      ...some_stuff

and code from configuration import settings in example.py raised an import error.

The problem was that when I opened PyCharm, it considered that skylake is the root path and ran this code.

sys.path.extend(['D:\\projects\\skylake', 'D:/projects/skylake'])

To fix this I just marked backend directory as the source root.

Enter image description here

And it's fixed my problem.

Upvotes: 5

Daniel N.
Daniel N.

Reputation: 374

In case you only want to run the script instead of actually importing it, the exec command will do the work

exec(open('/full/or/relative/path').read())

Upvotes: 3

yerty
yerty

Reputation: 343

The following worked for me:

OS: Windows 10

Python: v3.10.0

Note: Since I am Python v3.10.0, I am not using __init__.py files, which did not work for me anyway.

application
├── app
│   └── folder
│       └── file.py
└── app2
    └── some_folder
        └── some_file.py

WY Hsu's first solution worked for me. I have reposted it with an absolute file reference for clarity:

import sys
sys.path.insert(1, 'C:\\Users\\<Your Username>\\application')
import app2.some_folder.some_file

some_file.hello_world()

Alternative Solution: However, this also worked for me:

import sys
sys.path.append( '.' )
import app2.some_folder.some_file

some_file.hello_world()

Although, I do not understand why it works. I thought the dot is a reference to the current directory. However, when printing out the paths to the current folder, the current directory is already listed at the top:

for path in sys.path:
    print(path)

Upvotes: 9

Md Shafiul Islam
Md Shafiul Islam

Reputation: 1659

This worked for me.

Python adds the folder containing the script you launch to the PYTHONPATH, so if you run

python application/app2/some_folder/some_file.py

Only the folder application/app2/some_folder is added to the path (not the base directory that you're executing the command in). Instead, run your file as a module and add a __init__.py in your some_folder directory.

python -m application.app2.some_folder.some_file

This will add the base directory to the path to executable python, and then classes will be accessible via a non-relative import.

Upvotes: 6

Neinstein
Neinstein

Reputation: 1033

The code below imports the Python script given by its path, no matter where it is located, in a Python version-safe way:

def import_module_by_path(path):
    name = os.path.splitext(os.path.basename(path))[0]
    if sys.version_info[0] == 2:
        # Python 2
        import imp
        return imp.load_source(name, path)
    elif sys.version_info[:2] <= (3, 4):
        # Python 3, version <= 3.4
        from importlib.machinery import SourceFileLoader
        return SourceFileLoader(name, path).load_module()
    else:
        # Python 3, after 3.4
        import importlib.util
        spec = importlib.util.spec_from_file_location(name, path)
        mod = importlib.util.module_from_spec(spec)
        spec.loader.exec_module(mod)
        return mod

I found this in the codebase of psutils, at line 1042 in psutils.test.__init__.py (most recent commit as of 09.10.2020).

Usage example:

script = "/home/username/Documents/some_script.py"
some_module = import_module_by_path(script)
print(some_module.foo())

Important caveat: The module will be treated as top-level; any relative imports from parent packages in it will fail.

Upvotes: 6

IOstream
IOstream

Reputation: 113

You can refresh the Python shell by pressing F5, or go to RunRun Module. This way you don't have to change the directory to read something from the file. Python will automatically change the directory. But if you want to work with different files from different directory in the Python shell, then you can change the directory in sys, as Cameron said earlier.

Upvotes: 1

herve-guerin
herve-guerin

Reputation: 3101

I'm quite special: I use Python with Windows!

I just complete information: for both Windows and Linux, both relative and absolute paths work into sys.path (I need relative paths because I use my scripts on the several PCs and under different main directories).

And when using Windows, both \ and / can be used as a separator for file names and of course you must double \ into Python strings. Here are some valid examples:

sys.path.append('c:\\tools\\mydir')
sys.path.append('..\\mytools')
sys.path.append('c:/tools/mydir')
sys.path.append('../mytools')

(Note: I think that / is more convenient than \, even if it is less 'Windows-native', because it is Linux-compatible and simpler to write and copy to Windows Explorer)

Upvotes: 10

dsg38
dsg38

Reputation: 554

This worked for me in Python 3 on Linux:

import sys
sys.path.append(pathToFolderContainingScripts)
from scriptName import functionName #scriptName without .py extension

Upvotes: 32

Emeeus
Emeeus

Reputation: 5250

This works for me on Windows:

# some_file.py on mainApp/app2
import sys
sys.path.insert(0, sys.path[0]+'\\app2')

import some_file

Upvotes: 13

Sergiusz
Sergiusz

Reputation: 112

My solution for people who have all the necessary __init__.py in the package, but import still doesn't work.

import sys
import os
sys.path.insert(0, os.getcwd())

import application.app.folder.file as file

Upvotes: 7

danday74
danday74

Reputation: 56936

Given a folder structure like

├── main.py
└── myfolder
    └── myfile.py

Where myfile.py contains

def myfunc():
    print('hello')

To call myfunc from main.py, use:

from myfolder.myfile import myfunc
myfunc()

Upvotes: 53

CianB
CianB

Reputation: 945

The issue is that Python is looking in the wrong directory for the file. To solve this, try using relative import. Change

from application.app.folder.file import func_name

to:

from .application.app.folder.file import func_name

Adding the dot instructs Python to look for the application folder within the current folder, instead of in the Python install folder.

Upvotes: 64

Mohsen Haddadi
Mohsen Haddadi

Reputation: 1366

One way is to create a package and use absolute import to access other modules from the package. Start the program from a script at the root of the package. This structure allows using and accessing sub-packages, parent package, and sibling packages and modules.

As an example, try creating the following folder structure:

package/
├── __init__.py
├── main_module.py
├── module_0.py
├── subpackage_1/
|   ├── __init__.py
|   ├── module_1.py
|   └── sub_subpackage_3/
|       ├── __init__.py
|       └── module_3.py
└── subpackage_2/
    ├── __init__.py
    └── module_2.py

Contents of main_module.py:

import subpackage_1.module_1

Contents of module_0.py:

print('module_0 at parent directory, is imported')

Contents of module_1.py:

print('importing other modules from module_1...')
import module_0
import subpackage_2.module_2
import subpackage_1.sub_subpackage_3.module_3

Contents of module_2.py:

print('module_2 at same level directory, is imported')

Contents of module_3.py:

print('module_3 at sub directory, is imported')

Leave all __init__.py files empty.

Now run main_module.py; the output will be

importing other modules from module_1...
module_0 at parent directory, is imported
module_2 at same level directory, is imported
module_3 at sub directory, is imported

Upvotes: 23

winsett
winsett

Reputation: 101

Just in case anyone still needs a solution and hasn't found one in the answers above. This worked for me:

I have this folder structure:

a
└── b
    ├── c1
    |   └── d
    |       └── a_script.py
    └── c2
        └── a_lib.py

And I needed the a_lib.py to be included in the a_script.py. This is how I resolved the error that c2 is not recognized:

import sys
from pathlib import Path
path_scripts = Path(__file__).resolve().parents[2]
sys.path.append(str(path_scripts))
from c2 import a_lib

Upvotes: 2

KSHMR
KSHMR

Reputation: 809

You can use pip's pip install -e . command. You must create a file called setup.py in the root of the project's directory which contains the following:

from setuptools import find_packages, setup

setup(
    name='src',
    packages=find_packages(),
    version='0.1.0',
    description='my_project',
    author='author',
    license='MIT',
)

Afterwards, enter pip install -e . while in your project's root directory. This will enable all directories to be called with their name as a module. For example, if your root directory contains the subdirectories module1 and module2, each with scripts inside them, you will be able to access them from any subdirectories with the following command, for module1:

import module1.script1 as script1

Upvotes: 5

Milovan Tomašević
Milovan Tomašević

Reputation: 8663

├───root
│   ├───dir_a
│   │   ├───file_a.py
│   │   └───file_xx.py
│   ├───dir_b
│   │   ├───file_b.py
│   │   └───file_yy.py
│   ├───dir_c
│   └───dir_n

You can add the parent directory to PYTHONPATH, in order to achieve that, you can use OS depending path in the "module search path" which is listed in sys.path. So you can easily add the parent directory like following:

# file_b.py

import sys
sys.path.insert(0, '..')

from dir_a.file_a import func_name

Upvotes: 22

Nagev
Nagev

Reputation: 13197

Using sys.path.append with an absolute path is not ideal when moving the application to other environments. Using a relative path won't always work because the current working directory depends on how the script was invoked.

Since the application folder structure is fixed, we can use os.path to get the full path of the module we wish to import. For example, if this is the structure:

/home/me/application/app2/some_folder/vanilla.py
/home/me/application/app2/another_folder/mango.py

And let's say that you want to import the mango module. You could do the following in vanilla.py:

import sys, os.path
mango_dir = (os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
+ '/another_folder/')
sys.path.append(mango_dir)
import mango

Of course, you don't need the mango_dir variable.

To understand how this works look at this interactive session example:

>>> import os
>>> mydir = '/home/me/application/app2/some_folder'
>>> newdir = os.path.abspath(os.path.join(mydir, '..'))
>>> newdir
    '/home/me/application/app2'
>>> newdir = os.path.abspath(os.path.join(mydir, '..')) + '/another_folder'
>>> 
>>> newdir
'/home/me/application/app2/another_folder'
>>> 

And check the os.path documentation.

Also worth noting that dealing with multiple folders is made easier when using packages, as one can use dotted module names.

Upvotes: 41

kepy97
kepy97

Reputation: 1074

If you have multiple folders and sub folders, you can always import any class or module from the main directory.

For example: Tree structure of the project

Project 
├── main.py
├── .gitignore
|
├── src
     ├────model
     |    └── user_model.py
     |────controller
          └── user_controller.py

Now, if you want to import "UserModel" class from user_model.py in main.py file, you can do that using:

from src.model.user_model.py import UserModel

Also, you can import same class in user_controller.py file using same line:

from src.model.user_model.py import UserModel

Overall, you can give reference of main project directory to import classes and files in any python file inside Project directory.

Upvotes: 2

picmate 涅
picmate 涅

Reputation: 4249

I usually create a symlink to the module I want to import. The symlink makes sure Python interpreter can locate the module inside the current directory (the script you are importing the other module into); later on when your work is over, you can remove the symlink. Also, you should ignore symlinks in .gitignore, so that, you wouldn't accidentally commit symlinked modules to your repo. This approach lets you even successfully work with modules that are located parallel to the script you are executing.

ln -s ~/path/to/original/module/my_module ~/symlink/inside/the/destination/directory/my_module

Upvotes: 4

user12058827
user12058827

Reputation:

Instead of just doing an import ..., do this :

from <MySubFolder> import <MyFile>

MyFile is inside the MySubFolder.

Upvotes: 8

B Furtado
B Furtado

Reputation: 1500

I've had these problems a number of times. I've come to this same page a lot. In my last problem I had to run the server from a fixed directory, but whenever debugging I wanted to run from different sub-directories.

import sys
sys.insert(1, /path) 

did NOT work for me because at different modules I had to read different *.csv files which were all in the same directory.

In the end, what worked for me was not pythonic, I guess, but:

I used a if __main__ on top of the module I wanted to debug, that is run from a different than usual path.

So:

# On top of the module, instead of on the bottom
import os
if __name__ == '__main__':
    os.chdir('/path/for/the/regularly/run/directory')

Upvotes: 2

Related Questions