1154

I want to detect whether module has changed. Now, using inotify is simple, you just need to know the directory you want to get notifications from.

How do I retrieve a module's path in python?

8
  • 1
    Check out modulefinder: docs.python.org/library/modulefinder.html Commented Mar 8, 2012 at 6:19
  • 19
    If you are still looking on this site, please update the correct answer to this. It is way cleaner than the proposed solution and it works also in cases where __file__ is not set. Commented Dec 18, 2013 at 11:16
  • 3
    @erikb85: it is not only cleaner; inspect-based solution also works for execfile() case when __file__ produces wrong name silently. Commented Feb 21, 2014 at 13:49
  • 2
    related: How to properly determine current script directory in Python? Commented Nov 19, 2015 at 4:43
  • 4
    import pathlib, module; pathlib.Path(module.__file__).resolve().parent This is platformindependent Commented Mar 16, 2018 at 11:48

26 Answers 26

1358
import a_module print(a_module.__file__) 

Will actually give you the path to the .pyc file that was loaded, at least on Mac OS X. So I guess you can do:

import os path = os.path.abspath(a_module.__file__) 

You can also try:

path = os.path.dirname(a_module.__file__) 

To get the module's directory.

Sign up to request clarification or add additional context in comments.

11 Comments

this answers how to get the path of the module you import, but not of the module/script you are in (for the script you're running, __file__ is not a full path, it is relative). For the file I'm in I had to import another module from the same directory and do as shown here. Does anyone know a more convenient way?
@hbdgaf pretty sure there is no such thing as a built-in self.__file__
@BenBryant @hbdgaf os.path.dirname(__file__) works fine for me and returns the abs path of the module's directory.
I tried doing this and get the traceback: AttributeError: 'module' object has no attribute '__file__'
@DorianDore I was messing with modules a little and got to a solution path = module.__path__.__dict__["_path"][0], but I'm not sure if it's portable or if it doesn't differ between python versions either. It's working for me, unlike this answer which gives me the same error and inspect answer raises TypeError: <module 'module' (namespace)> is a built-in module...
|
397

There is inspect module in python.

Official documentation

The inspect module provides several useful functions to help get information about live objects such as modules, classes, methods, functions, tracebacks, frame objects, and code objects. For example, it can help you examine the contents of a class, retrieve the source code of a method, extract and format the argument list for a function, or get all the information you need to display a detailed traceback.

Example:

>>> import os >>> import inspect >>> inspect.getfile(os) '/usr/lib64/python2.7/os.pyc' >>> inspect.getfile(inspect) '/usr/lib64/python2.7/inspect.pyc' >>> os.path.dirname(inspect.getfile(inspect)) '/usr/lib64/python2.7' 

4 Comments

You can use inspect to get the name of the current file too; see stackoverflow.com/a/50905/320036
I googled this question many times and this is the most reasonable answer I have ever seen! Please update the information about inspect.currentframe()
the inspect.getfile() approach doesn't work with the module _io, but works with the module io.
Note that inspect.getfile can throw a TypeError for built-in modules.
83

As the other answers have said, the best way to do this is with __file__ (demonstrated again below). However, there is an important caveat, which is that __file__ does NOT exist if you are running the module on its own (i.e. as __main__).

For example, say you have two files (both of which are on your PYTHONPATH):

#/path1/foo.py import bar print(bar.__file__) 

and

#/path2/bar.py import os print(os.getcwd()) print(__file__) 

Running foo.py will give the output:

/path1 # "import bar" causes the line "print(os.getcwd())" to run /path2/bar.py # then "print(__file__)" runs /path2/bar.py # then the import statement finishes and "print(bar.__file__)" runs 

HOWEVER if you try to run bar.py on its own, you will get:

/path2 # "print(os.getcwd())" still works fine Traceback (most recent call last): # but __file__ doesn't exist if bar.py is running as main File "/path2/bar.py", line 3, in <module> print(__file__) NameError: name '__file__' is not defined 

Hope this helps. This caveat cost me a lot of time and confusion while testing the other solutions presented.

7 Comments

In this case, you can use sys.argv[0] in place of file.
Is that a version-specific caveat? In 2.6 and 2.7, I successfully rely on file, which works file when name__=='__main'. The only failure case I've seen is with "python -c 'print file'". I will add that sometimes file can be '<stdin>', which happens when IDEs like emacs execute the current buffer.
Note that leading-and-trailing "__" characters put a word in bold, so keep that in mind when reading the previous comments :-P
@PaulDuBois You can surround it w/ back tics: `__file__` becomes __file__
How do you get the NameError? @Paul Du Bois: I've tried Python 2.3-3.4 and __file__ is defined however I run Python file: python a.py, python -ma, ./a.py.
|
81

I will try tackling a few variations on this question as well:

  1. finding the path of the called script
  2. finding the path of the currently executing script
  3. finding the directory of the called script

(Some of these questions have been asked on SO, but have been closed as duplicates and redirected here.)

Caveats of Using __file__

For a module that you have imported:

import something something.__file__ 

will return the absolute path of the module. However, given the folowing script foo.py:

#foo.py print '__file__', __file__ 

Calling it with 'python foo.py' Will return simply 'foo.py'. If you add a shebang:

#!/usr/bin/python #foo.py print '__file__', __file__ 

and call it using ./foo.py, it will return './foo.py'. Calling it from a different directory, (eg put foo.py in directory bar), then calling either

python bar/foo.py 

or adding a shebang and executing the file directly:

bar/foo.py 

will return 'bar/foo.py' (the relative path).

Finding the directory

Now going from there to get the directory, os.path.dirname(__file__) can also be tricky. At least on my system, it returns an empty string if you call it from the same directory as the file. ex.

# foo.py import os print '__file__ is:', __file__ print 'os.path.dirname(__file__) is:', os.path.dirname(__file__) 

will output:

__file__ is: foo.py os.path.dirname(__file__) is: 

In other words, it returns an empty string, so this does not seem reliable if you want to use it for the current file (as opposed to the file of an imported module). To get around this, you can wrap it in a call to abspath:

# foo.py import os print 'os.path.abspath(__file__) is:', os.path.abspath(__file__) print 'os.path.dirname(os.path.abspath(__file__)) is:', os.path.dirname(os.path.abspath(__file__)) 

which outputs something like:

os.path.abspath(__file__) is: /home/user/bar/foo.py os.path.dirname(os.path.abspath(__file__)) is: /home/user/bar 

Note that abspath() does NOT resolve symlinks. If you want to do this, use realpath() instead. For example, making a symlink file_import_testing_link pointing to file_import_testing.py, with the following content:

import os print 'abspath(__file__)',os.path.abspath(__file__) print 'realpath(__file__)',os.path.realpath(__file__) 

executing will print absolute paths something like:

abspath(__file__) /home/user/file_test_link realpath(__file__) /home/user/file_test.py 

file_import_testing_link -> file_import_testing.py

Using inspect

@SummerBreeze mentions using the inspect module.

This seems to work well, and is quite concise, for imported modules:

import os import inspect print 'inspect.getfile(os) is:', inspect.getfile(os) 

obediently returns the absolute path. For finding the path of the currently executing script:

inspect.getfile(inspect.currentframe()) 

(thanks @jbochi)

inspect.getabsfile(inspect.currentframe()) 

gives the absolute path of currently executing script (thanks @Sadman_Sakib).

3 Comments

inspect.getfile(os) is the same as os.__file__ from the code: def getfile(object): """Work out which source or compiled file an object was defined in.""" if ismodule(object): if hasattr(object, 'file'): return object.__file__
This should be the accepted answer. Thank you for this exhaustive answer.
Adding here that inspect.getabsfile(inspect.currentframe()) gives the absolute path of currently executing script.
52

I don't get why no one is talking about this, but to me the simplest solution is using imp.find_module("modulename") (documentation here):

import imp imp.find_module("os") 

It gives a tuple with the path in second position:

(<open file '/usr/lib/python2.7/os.py', mode 'U' at 0x7f44528d7540>, '/usr/lib/python2.7/os.py', ('.py', 'U', 1)) 

The advantage of this method over the "inspect" one is that you don't need to import the module to make it work, and you can use a string in input. Useful when checking modules called in another script for example.

EDIT:

In python3, importlib module should do:

Doc of importlib.util.find_spec:

Return the spec for the specified module.

First, sys.modules is checked to see if the module was already imported. If so, then sys.modules[name].spec is returned. If that happens to be set to None, then ValueError is raised. If the module is not in sys.modules, then sys.meta_path is searched for a suitable spec with the value of 'path' given to the finders. None is returned if no spec could be found.

If the name is for submodule (contains a dot), the parent module is automatically imported.

The name and package arguments work the same as importlib.import_module(). In other words, relative module names (with leading dots) work.

5 Comments

imp is NOT depreciated in python 2 (current version 2.7.13). imp is depreciated in python 3 since 3.4. importlib shall be used in python 3 instead. I like this solution, because it even works when the actual import will fail (e.g. because 64bit module for a 32bit engine)
And REALLY nice when trying to find the path of 64 bit sqlite3 and import fails. Perfect.
importlib.machinery.PathFinder().find_module("os").get_filename() Shortest alternative to imp.find_module I've found in Python3+. If anyone is looking for the usage of importlib.util.find_spec.
This method works without importing the actual module, which is great as I am using this to figure out which version of a module is being imported from a shared computer.
DeprecationWarning: the imp module is deprecated in favour of importlib.. and "AttributeError: module 'importlib' has no attribute 'find_module"
22

This was trivial.

Each module has a __file__ variable that shows its relative path from where you are right now.

Therefore, getting a directory for the module to notify it is simple as:

os.path.dirname(__file__) 

2 Comments

Almost but not quite right -- file is not "relative to where you're at right now"; when it's relative (which it will be only when there are relative paths in sys.path), it's relative to where you were when the module was loaded.
Starting with Python 3.9 __file__ is always an absolute path.
22

If you want to retrieve the module path without loading it:

import importlib.util print(importlib.util.find_spec("requests").origin) 

Example output:

/usr/lib64/python3.9/site-packages/requests/__init__.py 

1 Comment

An underrated answer. Just what I was looking for. Caveat is the module is not imported. When you're programmatically running pytest for coverage, if you import the module you're testing before invoking pytest then all the imports, class/func definitions etc would be marked as not covered because it was already imported.
19
import os path = os.path.abspath(__file__) dir_path = os.path.dirname(path) 

1 Comment

doesn't work on my Linux python 2.6 since __file__ is just dir/test.py, abspath involves the cwd to complete the pathname which is not the desired result, but if you import a module then m.__file__ gives the desired result.
17
import module print module.__path__ 

Packages support one more special attribute, __path__. This is initialized to be a list containing the name of the directory holding the package’s __init__.py before the code in that file is executed. This variable can be modified; doing so affects future searches for modules and subpackages contained in the package.

While this feature is not often needed, it can be used to extend the set of modules found in a package.

Source

Comments

11

Command Line Utility

You can tweak it to a command line utility,

python-which <package name> 

enter image description here


Create /usr/local/bin/python-which

#!/usr/bin/env python import importlib import os import sys args = sys.argv[1:] if len(args) > 0: module = importlib.import_module(args[0]) print os.path.dirname(module.__file__) 

Make it executable

sudo chmod +x /usr/local/bin/python-which 

Comments

9

you can just import your module then hit its name and you'll get its full path

>>> import os >>> os <module 'os' from 'C:\\Users\\Hassan Ashraf\\AppData\\Local\\Programs\\Python\\Python36-32\\lib\\os.py'> >>> 

Comments

8

When you import a module, yo have access to plenty of information. Check out dir(a_module). As for the path, there is a dunder for that: a_module.__path__. You can also just print the module itself.

>>> import a_module >>> print(dir(a_module)) ['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__path__', '__spec__'] >>> print(a_module.__path__) ['/.../.../a_module'] >>> print(a_module) <module 'a_module' from '/.../.../a_module/__init__.py'> 

Comments

7

Er...

>>> import logging >>> print(logging) <module 'logging' from 'C:\\Users\\Mike\\AppData\\Local\\Programs\\Python\\Python39\\lib\\logging\\__init__.py'> 

Comments

6

So I spent a fair amount of time trying to do this with py2exe The problem was to get the base folder of the script whether it was being run as a python script or as a py2exe executable. Also to have it work whether it was being run from the current folder, another folder or (this was the hardest) from the system's path.

Eventually I used this approach, using sys.frozen as an indicator of running in py2exe:

import os,sys if hasattr(sys,'frozen'): # only when running in py2exe this exists base = sys.prefix else: # otherwise this is a regular python script base = os.path.dirname(os.path.realpath(__file__)) 

Comments

6

If you want to retrieve the package's root path from any of its modules, the following works (tested on Python 3.6):

from . import __path__ as ROOT_PATH print(ROOT_PATH) 

The main __init__.py path can also be referenced by using __file__ instead.

Hope this helps!

2 Comments

ImportError: attempted relative import with no known parent package
This code is intended to go in python packages. Make sure all folders have an __init__.py file. Googling that error shows other potential causes
6

If you installed it using pip, "pip show" works great ('Location')

$ pip show detectron2

Name: detectron2 Version: 0.1 Summary: Detectron2 is FAIR next-generation research platform for object detection and segmentation. Home-page: https://github.com/facebookresearch/detectron2 Author: FAIR Author-email: None License: UNKNOWN Location: /home/ubuntu/anaconda3/envs/pytorch_p36/lib/python3.6/site-packages Requires: yacs, tabulate, tqdm, pydot, tensorboard, Pillow, termcolor, future, cloudpickle, matplotlib, fvcore 

Update:

$ python -m pip show mymodule

(author: wisbucky)

1 Comment

Calling $ pip show mymodule is not reliable. You need to do $ python -m pip show mymodule. See stackoverflow.com/questions/247770/…
5

If you would like to know absolute path from your script you can use Path object:

from pathlib import Path print(Path().absolute()) print(Path().resolve('.')) print(Path().cwd()) 

cwd() method

Return a new path object representing the current directory (as returned by os.getcwd())

resolve() method

Make the path absolute, resolving any symlinks. A new path object is returned:

1 Comment

This will fail because it will only return the working directory, not the modules path
3

If the only caveat of using __file__ is when current, relative directory is blank (ie, when running as a script from the same directory where the script is), then a trivial solution is:

import os.path mydir = os.path.dirname(__file__) or '.' full = os.path.abspath(mydir) print __file__, mydir, full 

And the result:

$ python teste.py teste.py . /home/user/work/teste 

The trick is in or '.' after the dirname() call. It sets the dir as ., which means current directory and is a valid directory for any path-related function.

Thus, using abspath() is not truly needed. But if you use it anyway, the trick is not needed: abspath() accepts blank paths and properly interprets it as the current directory.

1 Comment

Better swap the order and just use os.path.dirname(os.path.abspath(__file__)) because then you don't have to worry about relative paths at all. One less opportunity for bugs.
3

I'd like to contribute with one common scenario (in Python 3) and explore a few approaches to it.

The built-in function open() accepts either relative or absolute path as its first argument. The relative path is treated as relative to the current working directory though so it is recommended to pass the absolute path to the file.

Simply said, if you run a script file with the following code, it is not guaranteed that the example.txt file will be created in the same directory where the script file is located:

with open('example.txt', 'w'): pass 

To fix this code we need to get the path to the script and make it absolute. To ensure the path to be absolute we simply use the os.path.realpath() function. To get the path to the script there are several common functions that return various path results:

  • os.getcwd()
  • os.path.realpath('example.txt')
  • sys.argv[0]
  • __file__

Both functions os.getcwd() and os.path.realpath() return path results based on the current working directory. Generally not what we want. The first element of the sys.argv list is the path of the root script (the script you run) regardless of whether you call the list in the root script itself or in any of its modules. It might come handy in some situations. The __file__ variable contains path of the module from which it has been called.


The following code correctly creates a file example.txt in the same directory where the script is located:

filedir = os.path.dirname(os.path.realpath(__file__)) filepath = os.path.join(filedir, 'example.txt') with open(filepath, 'w'): pass 

Comments

3

A modern (Python >= 3.7) solution to this problem is importlib.resources.files()

from importlib import resources resources.files(package_name) # => WindowsPath("C:\Path\to\your\package\") 

2 Comments

AttributeError: module 'importlib.resources' has no attribute 'files'
So Sorry! Fixed it. Copy pasted the wrong version of my code the first time.
2

If your import is a site-package (e.g. pandas) I recommend this to get its directory (does not work if import is a module, like e.g. pathlib):

from importlib import resources # part of core Python import pandas as pd package_dir = resources.path(package=pd, resource="").__enter__() 

In general importlib.resources can be considered when a task is about accessing paths/resources of a site package.

Comments

1

From within modules of a python package I had to refer to a file that resided in the same directory as package. Ex.

some_dir/ maincli.py top_package/ __init__.py level_one_a/ __init__.py my_lib_a.py level_two/ __init__.py hello_world.py level_one_b/ __init__.py my_lib_b.py 

So in above I had to call maincli.py from my_lib_a.py module knowing that top_package and maincli.py are in the same directory. Here's how I get the path to maincli.py:

import sys import os import imp class ConfigurationException(Exception): pass # inside of my_lib_a.py def get_maincli_path(): maincli_path = os.path.abspath(imp.find_module('maincli')[1]) # top_package = __package__.split('.')[0] # mod = sys.modules.get(top_package) # modfile = mod.__file__ # pkg_in_dir = os.path.dirname(os.path.dirname(os.path.abspath(modfile))) # maincli_path = os.path.join(pkg_in_dir, 'maincli.py') if not os.path.exists(maincli_path): err_msg = 'This script expects that "maincli.py" be installed to the '\ 'same directory: "{0}"'.format(maincli_path) raise ConfigurationException(err_msg) return maincli_path 

Based on posting by PlasmaBinturong I modified the code.

Comments

1

If you wish to do this dynamically in a "program" try this code:
My point is, you may not know the exact name of the module to "hardcode" it. It may be selected from a list or may not be currently running to use __file__.

(I know, it will not work in Python 3)

global modpath modname = 'os' #This can be any module name on the fly #Create a file called "modname.py" f=open("modname.py","w") f.write("import "+modname+"\n") f.write("modpath = "+modname+"\n") f.close() #Call the file with execfile() execfile('modname.py') print modpath <module 'os' from 'C:\Python27\lib\os.pyc'> 

I tried to get rid of the "global" issue but found cases where it did not work I think "execfile()" can be emulated in Python 3 Since this is in a program, it can easily be put in a method or module for reuse.

Comments

1

Here is a quick bash script in case it's useful to anyone. I just want to be able to set an environment variable so that I can pushd to the code.

#!/bin/bash module=${1:?"I need a module name"} python << EOI import $module import os print os.path.dirname($module.__file__) EOI 

Shell example:

[root@sri-4625-0004 ~]# export LXML=$(get_python_path.sh lxml) [root@sri-4625-0004 ~]# echo $LXML /usr/lib64/python2.7/site-packages/lxml [root@sri-4625-0004 ~]# 

Comments

1

If you used pip, then you can call pip show, but you must call it using the specific version of python that you are using. For example, these could all give different results:

$ python -m pip show numpy $ python2.7 -m pip show numpy $ python3 -m pip show numpy Location: /System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python 

Don't simply run $ pip show numpy, because there is no guarantee that it will be the same pip that different python versions are calling.

Comments

1

Here im printing cProfile package path:-

import cProfile import os path = os.path.abspath(cProfile.__file__) print(path) 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.