2013-02-12 55 views
3

我正在尋找一種簡單而快速的方法來查找軟件包的根目錄以及完整模塊名稱從.py文件的路徑。從.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 
+0

只是一個問題;爲什麼?什麼是最終目標?這只是一個excersize? – placeybordeaux 2013-02-12 15:36:20

+0

我正在嘗試創建一個允許在程序的python包之外設計插件/附加類的API。這將用於創建將定義新對象類型的新類。我希望用戶說'將這個文件/文件夾包含在對象類型清單中'。然而,這個文件/文件夾可能是另一個項目/軟件包的一部分,當它自行導入時可能會破壞一些代碼。 (對吧?)我需要導入文件來獲取類,但也檢查它是否是一個有效的新類。最終導致類似。進口包; package.addPluginPath(「filepath」) – 2013-02-12 15:41:59

+0

@RoyNieterau你應該只需要'嘗試:除了:'加載模塊來處理無效導入的情況。我不確定任何插件架構是否100%安全...... Python中有太多內省工具可以讓任何插件混淆正在運行的解釋器。 – 2013-02-12 15:47:46

回答

0

這是不可能的,因爲namespace packages - 根本就沒有辦法來決定正確的封裝baz.pyfoo.bar或只是下面的文件結構bar

foo/ 
    bar/ 
     __init__.py 
     baz.py 
+0

這將如何與命名空間包一起工作? sys.path中應該有什麼路徑,以及要導入的模塊是什麼。你會如何定義foo.bar會是正確的路徑?會在'baz.py'中編碼嗎?我一直在閱讀PEP420,但無法看到這是如何工作的。此外,這隻會是一個問題與Python 3.2 +? – 2013-02-12 20:57:39

+0

PEP420非常簡單:它開始導入常規包和模塊,並捕獲所有名稱空間包的候選*。如果它找不到任何東西,它會從候選列表中創建一個名稱空間包。是的,如果你的目標是Python <3。3,你不必擔心這一點。 – phihag 2013-02-12 21:17:25

相關問題