Last active
September 4, 2018 02:58
-
-
Save kdart/652ddd73fa0afe226457 to your computer and use it in GitHub Desktop.
Python 3 script that can tell you where a module is coming from when imported.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3.7 | |
""" | |
Uses the import machinery to locate a module and report what it found, such as | |
where the source file is. | |
""" | |
import sys | |
import os | |
import importlib | |
import importlib.util | |
import getopt | |
def module_from_path(fname): | |
"""Find and return the module name given a full path name. | |
Return None if file name not in the package path. | |
""" | |
if not os.path.exists(fname): | |
print("Warning: given path name does not exist.", file=sys.stderr) | |
dirname, basename = os.path.split(fname) | |
for p in sys.path: | |
if fname.startswith(p): | |
pkgname = ".".join(dirname[len(p)+1:].split("/")) | |
if pkgname: | |
return pkgname + "." + os.path.splitext(basename)[0] | |
else: | |
return os.path.splitext(basename)[0] | |
return None | |
def getmod(args): | |
for fname in args: | |
modname = module_from_path(fname) | |
if modname: | |
print(modname) | |
def pyfiles(args): | |
for modname in args: | |
spec = importlib.util.find_spec(modname) | |
if spec: | |
if spec.has_location: | |
if spec.loader.is_package(modname): | |
mod = importlib.import_module(spec.name) | |
for p in mod.__path__: | |
print(p) | |
else: | |
print(spec.origin) | |
else: | |
print(spec.cached) | |
else: | |
print("{} not found.".format(modname)) | |
def pywhich(args): | |
for modname in args: | |
try: | |
spec = importlib.util.find_spec(modname) | |
except ValueError: | |
mod = sys.modules[modname] | |
for p in mod.__path__: | |
print(" {}".format(p)) | |
return | |
if spec: | |
if spec.has_location: | |
if spec.loader.is_package(modname): | |
print("{} is a package -> {}\nPaths:".format(spec.name, spec.origin)) | |
mod = importlib.import_module(spec.name) | |
for p in mod.__path__: | |
print(" {}".format(p)) | |
else: | |
cached = "(cached)" if spec.cached else "" | |
print("{} -> {} {}".format(spec.name, spec.origin, cached)) | |
else: | |
print("No source location.") | |
else: | |
print("Not found.") | |
def main(argv): | |
"""pywhich [-fr] <modname> | |
Tell you which actual file is being used by an import. The module name | |
should be a full module path (e.g. pycopia.OS.rtc). | |
If the `-f` option is given then give the full path name to the source | |
file, if available. If it's a package then the package search paths are printed. | |
Use -r for a reverse mapping. Given a file, find the module name used to | |
import it. | |
""" | |
do_file = False | |
do_reverse = False | |
try: | |
opts, args = getopt.getopt(sys.argv[1:], "h?fr", ["help", "file", | |
"reverse"]) | |
except getopt.GetoptError as err: | |
print(str(err)) | |
print(main.__doc__) | |
return 1 | |
for option, argument in opts: | |
if option in ("-h", "--help"): | |
print(main.__doc__) | |
return 2 | |
elif option in ("-f", "--file"): | |
do_file = True | |
elif option in ("-r", "--reverse"): | |
do_reverse = True | |
if not args: | |
print(main.__doc__) | |
return 1 | |
if do_reverse: | |
return getmod(args) | |
elif do_file: | |
return pyfiles(args) | |
else: | |
return pywhich(args) | |
sys.exit(main(sys.argv)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment