I'm looking for a simple and fast way to find the root of the package and the full module name from a path to .py file.
I want the user to choose a .py and import it without breaking. Importing a module if it's part of the package will likely break. Thus I want to automatically append the directory wherein the root of the package resides to sys.path (if not already in there) and then import the module with its full module name.
I'm not running anywhere from the same directory or from that script, so I can't use __file__
and that kind of thing. Also I don't have the module imported yet, so I can't (as far as I know) inspect the module object, because there is none.
This is a working version, yet I'm interested in finding easier/faster solutions.
def splitPathFull(path):
folders=[]
while 1:
path,folder=os.path.split(path)
if folder!="":
folders.append(folder)
else:
if path!="":
folders.append(path)
break
folders.reverse()
return folders
def getPackageRootAndModuleNameFromFilePath(filePath):
"""
It recursively looks up until it finds a folder without __init__.py and uses that as the root of the package
the root of the package.
"""
folder = os.path.dirname(filePath)
if not os.path.exists( folder ):
raise RuntimeError( "Location does not exist: {0}".format(folder) )
if not filePath.endswith(".py"):
return None
moduleName = os.path.splitext( os.path.basename(filePath) )[0] # filename without extension
#
# If there's a __init__.py in the folder:
# Find the root module folder by recursively going up until there's no more __init__.py
# Else:
# It's a standalone module/python script.
#
foundScriptRoot = False
fullModuleName = None
rootPackagePath = None
if not os.path.exists( os.path.join(folder, "__init__.py" ) ):
rootPackagePath = folder
fullModuleName = moduleName
foundScriptRoot = True
# It's not in a Python package but a seperate ".py" script
# Thus append it's directory name to sys path (if not in there) and import the .py as a module
else:
startFolder = folder
moduleList = []
if moduleName != "__init__":
moduleList.append(moduleName)
amountUp = 0
while os.path.exists( folder ) and foundScriptRoot == False:
moduleList.append ( os.path.basename(folder) )
folder = os.path.dirname(folder)
amountUp += 1
if not os.path.exists( os.path.join(folder, "__init__.py" ) ):
foundScriptRoot = True
splitPath = splitPathFull(startFolder)
rootPackagePath = os.path.join( *splitPath[:-amountUp] )
moduleList.reverse()
fullModuleName = ".".join(moduleList)
if fullModuleName == None or rootPackagePath == None or foundScriptRoot == False:
raise RuntimeError( "Couldn't resolve python package root python path and full module name for: {0}".format(filePath) )
return [rootPackagePath, fullModuleName]
def importModuleFromFilepath(filePath, reloadModule=True):
"""
Imports a module by it's filePath.
It adds the root folder to sys.path if it's not already in there.
Then it imports the module with the full package/module name and returns the imported module as object.
"""
rootPythonPath, fullModuleName = getPackageRootAndModuleNameFromFilePath(filePath)
# Append rootPythonPath to sys.path if not in sys.path
if rootPythonPath not in sys.path:
sys.path.append(rootPythonPath)
# Import full (module.module.package) name
mod = __import__( fullModuleName, {}, {}, [fullModuleName] )
if reloadModule:
reload(mod)
return mod
This is impossible due to namespace packages - there is simply no way to decide whether the correct package for baz.py
is foo.bar
or just bar
with the following file structure:
foo/
bar/
__init__.py
baz.py
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.