2 回答

TA貢獻1797條經驗 獲得超6個贊
使用( 或)packages_distributions()
中的函數。例如,在您的情況下, “導入包”的名稱是:importlib.metadata
importlib-metadata
serial
import?importlib.metadata??#?or:?`import?importlib_metadata` importlib.metadata.packages_distributions()['serial']
這應該返回一個包含 的列表,它是“分發包pyserial
”的名稱(應該用于pip?-install 的名稱)。
對于較舊的 Python 版本和/或較舊版本的importlib-metadata
...
我相信類似以下的內容應該有效:
#!/usr/bin/env python3
import importlib.util
import pathlib
import importlib_metadata
def get_distribution(file_name):
? ? result = None
? ? for distribution in importlib_metadata.distributions():
? ? ? ? try:
? ? ? ? ? ? relative = (
? ? ? ? ? ? ? ? pathlib.Path(file_name)
? ? ? ? ? ? ? ? .relative_to(distribution.locate_file(''))
? ? ? ? ? ? )
? ? ? ? except ValueError:
? ? ? ? ? ? pass
? ? ? ? else:
? ? ? ? ? ? if distribution.files and relative in distribution.files:
? ? ? ? ? ? ? ? result = distribution
? ? ? ? ? ? ? ? break
? ? return result
def alpha():
? ? file_name = importlib.util.find_spec('serial').origin
? ? distribution = get_distribution(file_name)
? ? print("alpha", distribution.metadata['Name'])
def bravo():
? ? import serial
? ? file_name = serial.__file__
? ? distribution = get_distribution(file_name)
? ? print("bravo", distribution.metadata['Name'])
if __name__ == '__main__':
? ? alpha()
? ? bravo()
這只是一個代碼示例,顯示如何獲取特定模塊所屬的已安裝項目的元數據。
重要的是函數get_distribution,它接受文件名作為參數。它可以是模塊或包數據的文件名。如果該文件名屬于環境中安裝的項目(pip install例如通過),則importlib.metadata.Distribution返回該對象。

TA貢獻1804條經驗 獲得超3個贊
此問題現已通過 importlib_metadata 庫解決。請參閱提供從“Python 包”到“分發包”的映射,特別是“注釋 2”處理這個確切的問題。因此,請參閱@sinoroc的評論,您可以使用如下內容找到該包(例如,提供模塊“serial”的包“pyserial”):
>>> import importlib_metadata
>>> print(importlib_metadata.packages_distributions()['serial'])
['pyserial']
我提出了以下代碼(合并了提到的 importlib.util.find_spec 方法,但對返回路徑中的 RECORD 文件進行基于 bash 的搜索)。
作為“python3 python_find-module-package.py -m [module-name-here] -d”運行,這也將打印調試。關閉“-d”開關即可僅返回包名稱(和錯誤)。
TLDR:github 上的代碼。
#!/usr/bin/python3
import sys
import os.path
import importlib.util
import importlib_metadata
import pathlib
import subprocess
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("-m", "--module", help="Find matching package for the specified Python module",
? ? ? ? ? ? ? ? ? ? ? ? ? ? type=str)
#parser.add_argument("-u", "--username", help="Database username",
#? ? ? ? ? ? ? ? ? ? ? ? ? ?type=str)
#parser.add_argument("-p", "--password", help="Database password",
#? ? ? ? ? ? ? ? ? ? ? ? ? ?type=str)
parser.add_argument("-d", "--debug", help="Debug messages are enabled",
? ? ? ? ? ? ? ? ? ? ? ? ? ? action="store_true")
args = parser.parse_args()
TESTMODULE='serial'
def debugPrint (message="Nothing"):
? ? if args.debug:
? ? ? ? print ("[DEBUG] %s" % str(message))
class application ():
? ? def __init__(self, argsPassed):
? ? ? ? self.argsPassed = argsPassed
? ? ? ? debugPrint("Got these arguments:\n%s" % (argsPassed))
? ? def run (self):
? ? ? ? #debugPrint("Running with args:\n%s" % (self.argsPassed))
? ? ? ? try:
? ? ? ? ? ? if self.argsPassed.module is not None:
? ? ? ? ? ? ? ? self.moduleName=self.argsPassed.module? #i.e. the module that you're trying to match with a package.
? ? ? ? ? ? else:
? ? ? ? ? ? ? ? self.moduleName=TESTMODULE
? ? ? ? ? ? ? ? print("[WARN] No module name supplied - defaulting to %s!" % (TESTMODULE))
? ? ? ? ? ? self.location=importlib.util.find_spec(self.moduleName).origin
? ? ? ? ? ? debugPrint(self.location)
? ? ? ? except:
? ? ? ? ? ? print("[ERROR] Parsing module name!")
? ? ? ? ? ? exit(1)
? ? ? ? try:
? ? ? ? ? ? self.getPackage()
? ? ? ? except Exception as e:
? ? ? ? ? ? print ("[ERROR] getPackage failed: %s" % str(e))
? ? ? ? try:
? ? ? ? ? ? distResult=self.getDistribution(self.location)
? ? ? ? ? ? self.packageStrDist=distResult.metadata['Name']
? ? ? ? ? ? print(self.packageStrDist)
? ? ? ? except Exception as e:
? ? ? ? ? ? print ("[ERROR] getDistribution failed: %s" % str(e))
? ? ? ? debugPrint("Parent package for \"%s\" is: \"%s\"" % (self.moduleName, self.packageStr))
? ? ? ? return self.packageStr
? ? def getPackage (self):
? ? ? ? locationStr=self.location.split("site-packages/",1)[1]
? ? ? ? debugPrint(locationStr)
? ? ? ? #serial/__init__.py
? ? ? ? locationDir=self.location.split(locationStr,1)[0]
? ? ? ? debugPrint(locationDir)
? ? ? ? #/usr/lib/python3.6/site-packages
? ? ? ? cmd='find \"' + locationDir + '\" -type f -iname \'RECORD\' -printf \'\"%p\"\\n\' | xargs grep \"' + locationStr + '\" -l -Z'
? ? ? ? debugPrint(cmd)
? ? ? ? #find "/usr/lib/python3.6/site-packages" -type f -iname 'RECORD' -printf '"%p"\n' | xargs grep "serial/__init__.py" -l -Z
? ? ? ? #return_code = os.system(cmd)
? ? ? ? #return_code = subprocess.run([cmd], stdout=subprocess.PIPE, universal_newlines=True, shell=False)
? ? ? ? #findResultAll = return_code.stdout
? ? ? ? findResultAll = subprocess.check_output(cmd, shell=True)? ? # Returns stdout as byte array, null terminated.
? ? ? ? findResult = str(findResultAll.decode('ascii').strip().strip('\x00'))
? ? ? ? debugPrint(findResult)
? ? ? ? #/usr/lib/python3.6/site-packages/pyserial-3.4.dist-info/RECORD
? ? ? ? findDir = os.path.split(findResult)
? ? ? ? self.packageStr=findDir[0].replace(locationDir,"")
? ? ? ? debugPrint(self.packageStr)
? ? def getDistribution(self, fileName=TESTMODULE):
? ? ? ? result = None
? ? ? ? for distribution in importlib_metadata.distributions():
? ? ? ? ? ? try:
? ? ? ? ? ? ? ? relative = (pathlib.Path(fileName).relative_to(distribution.locate_file('')))
? ? ? ? ? ? #except ValueError:
? ? ? ? ? ? #except AttributeError:
? ? ? ? ? ? except:
? ? ? ? ? ? ? ? pass
? ? ? ? ? ? else:
? ? ? ? ? ? ? ? if relative in distribution.files:
? ? ? ? ? ? ? ? ? ? result = distribution
? ? ? ? return result
if __name__ == '__main__':
? ? result=1
? ? try:
? ? ? ? prog = application(args)
? ? ? ? result = prog.run()
? ? except Exception as E:
? ? ? ? print ("[ERROR] Prog Exception: %s" % str(E))
? ? finally:
? ? ? ? sys.exit(result)
? ??
# exit the program if we haven't already
print ("Shouldn't get here.")
sys.exit(result)
添加回答
舉報