簡體   English   中英

從.py文件中獲取包根和完整模塊名稱以進行導入

[英]Get package root and full module name from .py file for importing

我正在尋找一種簡單快速的方法來查找包的根目錄和從.py文件的路徑中找到完整的模塊名稱。

我希望用戶選擇.py並導入它而不會中斷。 導入模塊如果它是包的一部分可能會中斷。 因此,我想自動將包的根所在的目錄附加到sys.path(如果尚未存在),然后導入模塊及其完整的模塊名稱。

我沒有從同一目錄或該腳本運行任何地方,所以我不能使用__file__這樣的事情。 此外我還沒有導入模塊,所以我不能(據我所知)檢查模塊對象,因為沒有。

這是一個工作版本,但我有興趣找到更容易/更快的解決方案。

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

這是不可能的,因為命名空間包 - 沒有辦法確定baz.py的正確包是foo.bar還是只是具有以下文件結構的bar

foo/
    bar/
        __init__.py
        baz.py

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM