67

I've seen several approaches for finding the path of a module by first importing it. Is there a way to do this without importing the module?

3
  • 1
    Why? Why don't you want to import it? Commented Jan 14, 2011 at 16:53
  • 10
    Because importing is useless at the point in the program where the paths are needed and can cause circular dependencies and other issues. Import occurs at a more opportune time later down the road. Commented Jan 14, 2011 at 17:00
  • 1
    Also you may want to just look at the source code without actually running any code in the module. Commented Feb 27, 2017 at 20:45

5 Answers 5

72

Using pkgutil module:

>>> import pkgutil
>>> package = pkgutil.get_loader("pip")
>>> package.filename
'/usr/local/lib/python2.6/dist-packages/pip-0.7.1-py2.6.egg/pip'
>>> package = pkgutil.get_loader("threading")
>>> package.filename
'/usr/lib/python2.6/threading.py'
>>> package = pkgutil.get_loader("sqlalchemy.orm")
>>> package.filename
'/usr/lib/pymodules/python2.6/sqlalchemy/orm'

In Python 3, use pkgutil.get_loader("module name").get_filename() instead.

Using imp module:

>>> import imp
>>> imp.find_module('sqlalchemy')
(None, '/usr/lib/pymodules/python2.6/sqlalchemy', ('', '', 5))
>>> imp.find_module('pip')
(None, '/usr/local/lib/python2.6/dist-packages/pip-0.7.1-py2.6.egg/pip', ('', '', 5))
>>> imp.find_module('threading')
(<open file '/usr/lib/python2.6/threading.py', mode 'U' at 0x7fb708573db0>, '/usr/lib/python2.6/threading.py', ('.py', 'U', 1))

N.B: with imp module you can't do something like imp.find_module('sqlalchmy.orm')

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

6 Comments

@cgohlke : actually their is no pkutil package, it should be pkgutil, it was a typo mistake , thanks for pointing it out :)
@mouad I'm actually looking for the same thing. The above implementation with pkgutil doesn't do what is requested in all cases. pkgutil.get_laoder("sqlalchemy.orm") wll execute sqlalchemy/__init__.py, tho it won't execute sqlalchemy/orm.py.
@Prody: Yes that's true in case of a package it will execute the __init__.py package as the documentation (docs.python.org/release/3.1.5/library/…) say If the named module is not already imported, its containing package (if any) is imported, in order to establish the package _path_ which make total sense :)
I found [in Python 3.5.1] that package.filename didn't exist, but package.get_filename() did.
pkgutil.get_loader is deprecated, one should use importlib.util.find_spec instead
|
21

For python3 imp is deprecated. Use pkgutil (as seen above) or for Python 3.4+ use importlib.util.find_spec:

>>> import importlib
>>> spec = importlib.util.find_spec("threading")
>>> spec.origin
'/usr/lib64/python3.6/threading.py'

5 Comments

spec.origin attribute do not exist for a module folder which contains an __init__.py. Use instead : python >>> spec.submodule_search_locations[0]
unfortunately find_spec might try importing the module github.com/python/cpython/blob/…
This will only work if find_spec is not used to find submodules: find_spec("foo") will not import anything but find_spec("foo.bar") will import foo (thereby evaluating foo.__init__.py)
In Python3.11, spec.origin of "os" module returns "frozen"
@tamuhey that means the module was compiled into byte code and included in an a standalone python interpreter. i.e. it has no location
2

For most use-cases, you actually don't need help from third parties. importlib.util.find_spec has been around since python3.4, and solves the issue for top-level imports:

>>> import importlib.util
>>> spec = importlib.util.find_spec("foo")
>>> spec.origin
/home/me/my_venv/python3.11/site-packages/foo/__init__.py

And for a portable variant that gets the parent folder:

[...]
>>> from pathlib import Path
>>> Path(spec.origin).parent
/home/me/my_venv/python3.11/site-packages/foo

Notes:

  • For sub-packages (e.g. foo.bar), parent packages will be actually imported. Due to the dynamic nature of python, including how imports may resolve, there is no correct solution which does not do an actual import (try to find the location of os.path without importing os for a real-world-example).
  • If the package doesn't exist, spec will be None.
  • If the package is actually a namespace, spec.origin will be None

Comments

0
import importlib.util 
import os

this_module='numpy'

origin=importlib.util.find_spec(this_module).origin
print(origin)

path_to_this_module=os.path.dirname(origin)
print(path_to_this_module)

Output on windows:

...\site-packages\numpy\__init__.py
...\site-packages\numpy

Output on linux:

/home/.../site-packages/numpy/__init__.py
/home/.../site-packages/numpy

Comments

-1

You might want to try running this in your interpreter:

>>> import sys
>>> sys.modules['codecs'].__file__ # codecs is just an example
'/usr/lib/python2.7/codecs.pyc'

4 Comments

+1 I would have suggested a DFS or something using os.system. But this is awesome - didn't know this could be done
This doesn't work except with some modules from the stdlib. Try it with SQLAlchemy. Thanks for the response, though.
this will not work for package which wasn't already been loaded.
The question explicitly asks "without importing it".

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.