importlib.metadata
– Tillgång till metadata för paket¶
Tillagd i version 3.8.
Ändrad i version 3.10: importlib.metadata
är inte längre provisorisk.
Källkod: Lib/importlib/metadata/__init__.py
importlib.metadata
är ett bibliotek som ger tillgång till metadata för ett installerat Distribution Package, såsom dess ingångspunkter eller dess toppnivånamn (Import Packages, moduler, om sådana finns). Det här biblioteket bygger delvis på Pythons importsystem och avser att ersätta liknande funktionalitet i entry point API och metadata API i pkg_resources
. Tillsammans med importlib.resources
kan detta paket eliminera behovet av att använda det äldre och mindre effektiva paketet pkg_resources
.
importlib.metadata
fungerar på tredjeparts distributionspaket som installeras i Pythons site-packages
-katalog via verktyg som pip. Specifikt fungerar det med distributioner med upptäckbara dist-info
eller egg-info
-kataloger och metadata som definieras av Core metadata specifications.
Viktigt
Dessa är inte nödvändigtvis likvärdiga med eller motsvarar 1:1 de importpaket-namn på toppnivå som kan importeras i Python-kod. Ett distributionspaket kan innehålla flera importpaket (och enstaka moduler), och ett importpaket på toppnivå kan mappa till flera distributionspaket om det är ett namnrymdspaket. Du kan använda packages_distributions() för att få en mappning mellan dem.
Som standard kan distributionsmetadata finnas i filsystemet eller i zip-arkiv på sys.path
. Genom en tilläggsmekanism kan metadata lagras nästan var som helst.
Se även
- https://importlib-metadata.readthedocs.io/
Dokumentationen för
importlib_metadata
, som tillhandahåller en backport avimportlib.metadata
. Detta inkluderar en API-referens för den här modulens klasser och funktioner, samt en migreringsguide för befintliga användare avpkg_resources
.
Översikt¶
Låt oss säga att du vill få fram versionssträngen för ett Distribution Package som du har installerat med hjälp av pip
. Vi börjar med att skapa en virtuell miljö och installerar något i den:
$ python -m venv example
$ source example/bin/activate
(exempel) $ python -m pip install wheel
Du kan få fram versionssträngen för wheel
genom att köra följande:
(example) $ python
>>> from importlib.metadata import version
>>> version('wheel')
'0.32.3'
Du kan också få en samling ingångspunkter som kan väljas genom egenskaper hos EntryPoint (vanligtvis ’group’ eller ’name’), t.ex. console_scripts
, distutils.commands
och andra. Varje grupp innehåller en samling av EntryPoint-objekt.
Du kan få metadata för en distribution:
>>> list(metadata('wheel'))
['Metadata-Version', 'Name', 'Version', 'Summary', 'Home-page', 'Author', 'Author-email', 'Maintainer', 'Maintainer-email', 'License', 'Project-URL', 'Project-URL', 'Project-URL', 'Keywords', 'Platform', 'Classifier', 'Classifier', 'Classifier', 'Classifier', 'Classifier', 'Classifier', 'Classifier', 'Classifier', 'Classifier', 'Classifier', 'Classifier', 'Classifier', 'Requires-Python', 'Provides-Extra', 'Requires-Dist', 'Requires-Dist']
Du kan också få en distributions versionsnummer, lista dess beståndsdelar och få en lista över distributionens Krav på distribution.
- exception importlib.metadata.PackageNotFoundError¶
Underklass till
ModuleNotFoundError
som orsakas av flera funktioner i denna modul när de frågar efter ett distributionspaket som inte är installerat i den aktuella Python-miljön.
Funktionellt API¶
Detta paket tillhandahåller följande funktionalitet via sitt publika API.
Ingångspunkter¶
- importlib.metadata.entry_points(**select_params)¶
Returnerar en
EntryPoints
-instans som beskriver entry points för den aktuella miljön. Eventuella nyckelordsparametrar skickas tillselect()
-metoden för jämförelse med attributen i de enskilda entry point-definitionerna.Obs: det är för närvarande inte möjligt att fråga efter entry points baserat på deras
EntryPoint.dist
-attribut (eftersom olikaDistribution
-instanser för närvarande inte jämförs lika, även om de har samma attribut)
- class importlib.metadata.EntryPoints¶
Detaljer om en samling installerade inmatningspunkter.
Innehåller även attributet
.groups
som rapporterar alla identifierade grupper av entrépunkter och attributet.names
som rapporterar alla identifierade namn på entrépunkter.
- class importlib.metadata.EntryPoint¶
Detaljer om en installerad ingångspunkt.
Varje
EntryPoint
-instans har attributen.name
,.group
och.value
och en.load()
-metod för att lösa upp värdet. Det finns också attributen.module
,.attr
och.extras
för att hämta komponenterna i attributet.value
och.dist
för att hämta information om det distributionspaket som tillhandahåller entrypointen.
Fråga alla inmatningspunkter:
>>> eps = entry_points()
Funktionen entry_points()
returnerar ett EntryPoints
-objekt, en samling av alla EntryPoint
-objekt med attributen names
och groups
för enkelhetens skull:
>>> sorted(eps.groups)
['console_scripts', 'distutils.commands', 'distutils.setup_keywords', 'egg_info.writers', 'setuptools.installation']
EntryPoints
har en select()
-metod för att välja entrypunkter som matchar specifika egenskaper. Välj ingångspunkter i gruppen console_scripts
:
>>> scripts = eps.select(group='console_scripts')
På motsvarande sätt, eftersom entry_points()
skickar nyckelordsargument vidare till select:
>>> scripts = entry_points(group='console_scripts')
Välj ut ett specifikt skript som heter ”wheel” (finns i wheel-projektet):
>>> 'wheel' in scripts.names
True
>>> wheel = scripts['wheel']
På motsvarande sätt, fråga efter den ingångspunkten under urvalet:
>>> (wheel,) = entry_points(group='console_scripts', name='wheel')
>>> (wheel,) = entry_points().select(group='console_scripts', name='wheel')
Inspektera den lösta ingångspunkten:
>>> wheel
EntryPoint(name='wheel', value='wheel.cli:main', group='console_scripts')
>>> wheel.module
'wheel.cli'
>>> wheel.attr
'main'
>>> wheel.extras
[]
>>> main = wheel.load()
>>> main
<function main at 0x103528488>
group
och name
är godtyckliga värden som definieras av paketets författare och vanligtvis kommer en klient att vilja lösa alla ingångspunkter för en viss grupp. Läs the setuptools docs för mer information om ingångspunkter, deras definition och användning.
Ändrad i version 3.12: De ”valbara” ingångspunkterna introducerades i importlib_metadata
3.6 och Python 3.10. Före dessa ändringar accepterade entry_points
inga parametrar och returnerade alltid en ordbok med ingångspunkter, med grupp som nyckel. Med importlib_metadata
5.0 och Python 3.12 returnerar entry_points
alltid ett EntryPoints
-objekt. Se backports.entry_points_selectable för kompatibilitetsalternativ.
Ändrad i version 3.13: EntryPoint
-objekt har inte längre ett tuple-liknande gränssnitt (__getitem__()
).
Metadata för distribution¶
- importlib.metadata.metadata(distribution_name)¶
Returnerar distributionsmetadata som motsvarar det angivna distributionspaketet som en instans av
PackageMetadata
.Utlöser
PackageNotFoundError
om det angivna distributionspaketet inte är installerat i den aktuella Python-miljön.
- class importlib.metadata.PackageMetadata¶
En konkret implementering av PackageMetadata-protokollet.
Förutom att tillhandahålla de definierade protokollmetoderna och -attributen, motsvarar subskription av instansen anrop av metoden
get()
.
Varje Distributionspaket innehåller en del metadata, som du kan extrahera med hjälp av funktionen metadata()
:
>>> wheel_metadata = metadata('wheel')
Nycklarna i den returnerade datastrukturen namnger nyckelorden i metadata och värdena returneras oanalyserade från distributionsmetadata:
>>> wheel_metadata['Requires-Python']
'>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*'
PackageMetadata
har också ett json
-attribut som returnerar alla metadata i JSON-kompatibel form enligt PEP 566:
>>> wheel_metadata.json['requires_python']
'>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*'
Den fullständiga uppsättningen tillgängliga metadata beskrivs inte här. Se PyPA:s Core metadata specification för ytterligare detaljer.
Ändrad i version 3.10: Description
ingår nu i metadata när den presenteras genom nyttolasten. Radernas fortsättningstecken har tagits bort.
Attributet json
har lagts till.
Distribution av versioner¶
- importlib.metadata.version(distribution_name)¶
Returnerar det installerade distributionspaketet version för det angivna distributionspaketet.
Utlöser
PackageNotFoundError
om det angivna distributionspaketet inte är installerat i den aktuella Python-miljön.
Funktionen version()
är det snabbaste sättet att få ett Distribution Package:s versionsnummer, som en sträng:
>>> version('wheel')
'0.32.3'
Distributionsfiler¶
- importlib.metadata.files(distribution_name)¶
Returnerar den fullständiga uppsättningen filer som ingår i det namngivna distributionspaketet.
Utlöser
PackageNotFoundError
om det angivna distributionspaketet inte är installerat i den aktuella Python-miljön.Returnerar
None
om distributionen hittas men installationsdatabasen rapporterar att de filer som är associerade med distributionspaketet saknas.
- class importlib.metadata.PackagePath¶
Ett
pathlib.PurePath
-deriverat objekt med ytterligaredist
-,size
- ochhash
-egenskaper som motsvarar distributionspaketets installationsmetadata för den filen.
Funktionen files()
tar ett namn på Distribution Package och returnerar alla filer som installerats av denna distribution. Varje fil rapporteras som en instans av PackagePath
. Till exempel:
>>> util = [p for p in files('wheel') if 'util.py' in str(p)][0]
>>> util
PackagePath('wheel/util.py')
>>> util.size
859
>>> util.dist
<importlib.metadata._hooks.PathDistribution object at 0x101e0cef0>
>>> util.hash
<FileHash mode: sha256 value: bYkw5oMccfazVCoYQwKkkemoVyMAFoR34mmKBx8R1NI>
När du har filen kan du också läsa dess innehåll:
>>> print(util.read_text())
import base64
import sys
...
def as_bytes(s):
if isinstance(s, text_type):
return s.encode('utf-8')
return s
Du kan också använda metoden locate()
för att få den absoluta sökvägen till filen:
>>> util.locate()
PosixPath('/home/gustav/example/lib/site-packages/wheel/util.py')
I fallet där metadatafilen som listar filer (RECORD
eller SOURCES.txt
) saknas, kommer files()
att returnera None
. Den som anropar kan vilja linda in anrop till files()
i always_iterable eller på annat sätt skydda sig mot detta villkor om det inte är känt att måldistributionen har metadata närvarande.
Krav på distribution¶
- importlib.metadata.requires(distribution_name)¶
Returnerar de deklarerade beroendespecifikationerna för det namngivna distributionspaketet.
Utlöser
PackageNotFoundError
om det angivna distributionspaketet inte är installerat i den aktuella Python-miljön.
För att få den fullständiga uppsättningen krav för ett Distributionspaket, använd funktionen requires()
:
>>> requires('wheel')
["pytest (>=3.0.0) ; extra == 'test'", "pytest-cov ; extra == 'test'"]
Mappning av import till distributionspaket¶
- importlib.metadata.packages_distributions()¶
Returnerar en mappning från toppnivåmodulen och importpaketnamnen som hittas via
sys.meta_path
till namnen på distributionspaketen (om sådana finns) som tillhandahåller motsvarande filer.För att möjliggöra namnrymdspaket (som kan ha medlemmar som tillhandahålls av flera distributionspaket) mappas varje importnamn på högsta nivån till en lista med distributionsnamn i stället för att mappas direkt till ett enda namn.
En bekvämlighetsmetod för att lösa Distribution Package-namnet (eller namnen, i fallet med ett namnrymdspaket) som tillhandahåller varje importerbar Python-modul på högsta nivån eller Import Package:
>>> packages_distributions()
{'importlib_metadata': ['importlib-metadata'], 'yaml': ['PyYAML'], 'jaraco': ['jaraco.classes', 'jaraco.functools'], ...}
Vissa redigerbara installationer, levererar inte toppnamn, och därför är denna funktion inte tillförlitlig med sådana installationer.
Tillagd i version 3.10.
Utdelningar¶
- importlib.metadata.distribution(distribution_name)¶
Returnerar en
Distribution
-instans som beskriver det namngivna distributionspaketet.Utlöser
PackageNotFoundError
om det angivna distributionspaketet inte är installerat i den aktuella Python-miljön.
- class importlib.metadata.Distribution¶
Detaljer om ett installerat distributionspaket.
Observera: olika
Distribution
-instanser jämförs för närvarande inte på samma sätt, även om de hänför sig till samma installerade distribution och därmed har samma attribut.
Även om API:et på modulnivå som beskrivs ovan är den vanligaste och mest praktiska användningen, kan du få all denna information från klassen Distribution
. Distribution
är ett abstrakt objekt som representerar metadata för ett Python Distribution Package. Du kan få den konkreta Distribution
-underklassinstansen för ett installerat distributionspaket genom att anropa distribution()
-funktionen:
>>> from importlib.metadata import distribution
>>> dist = distribution('wheel')
>>> type(dist)
<class 'importlib.metadata.PathDistribution'>
Ett alternativt sätt att få versionsnumret är alltså genom Distribution
-instansen:
>>> dist.version
'0.32.3'
Det finns alla typer av ytterligare metadata tillgängliga för Distribution
-instanser:
>>> dist.metadata['Requires-Python']
'>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*'
>>> dist.metadata['License']
'MIT'
För redigerbara paket kan en egenskap origin
presentera PEP 610 metadata:
>>> dist.origin.url
'file:///path/to/wheel-0.32.3.editable-py3-none-any.whl'
Den fullständiga uppsättningen tillgängliga metadata beskrivs inte här. Se PyPA:s Core metadata specification för ytterligare detaljer.
Tillagd i version 3.13: Egenskapen .origin
har lagts till.
Distribution Discovery¶
Som standard ger det här paketet inbyggt stöd för sökning av metadata för filsystem och zip-filer Distribution Packages. Denna metadatasökning använder som standard sys.path
, men skiljer sig något i hur den tolkar dessa värden från hur andra importmaskiner gör. I synnerhet:
importlib.metadata
respekterar intebytes
-objekt påsys.path
.importlib.metadata
kommer av en händelse att hedrapathlib.Path
-objekt påsys.path
även om sådana värden kommer att ignoreras för import.
Implementering av anpassade providers¶
importlib.metadata
adresserar två API-ytor, en för konsumenter och en annan för leverantörer. De flesta användare är konsumenter och konsumerar metadata som tillhandahålls av paketen. Det finns dock andra användningsfall där användare vill exponera metadata genom någon annan mekanism, t.ex. tillsammans med en anpassad importör. Ett sådant användningsfall kräver en custom provider.
Eftersom metadata för Distributionspaket inte är tillgängliga via sys.path
-sökningar eller paketladdare direkt, hittas metadata för en distribution via importsystemets finders. För att hitta metadata för ett distributionspaket frågar importlib.metadata
listan över meta path finders på sys.meta_path
.
Implementeringen har hooks integrerade i PathFinder
, som serverar metadata för distributionspaket som finns i filsystemet.
Den abstrakta klassen importlib.abc.MetaPathFinder
definierar det gränssnitt som Pythons importsystem förväntar sig av sökare. importlib.metadata
utökar detta protokoll genom att leta efter en valfri find_distributions
anropbar på sökarna från sys.meta_path
och presenterar detta utökade gränssnitt som den abstrakta basklassen DistributionFinder
, som definierar denna abstrakta metod:
@abc.abstractmethod
def find_distributions(context=DistributionFinder.Context()) -> Iterable[Distribution]:
"""Return an iterable of all Distribution instances capable of
loading the metadata for packages for the indicated ``context``.
"""
Objektet DistributionFinder.Context
tillhandahåller egenskaperna .path
och .name
som anger sökvägen som ska sökas och namnet som ska matchas och kan tillhandahålla annan relevant kontext som efterfrågas av konsumenten.
I praktiken, för att stödja sökning av metadata för distributionspaket på andra platser än filsystemet, kan du underordna dig Distribution
och implementera de abstrakta metoderna. Sedan från en anpassad sökare, returnera instanser av denna härledda Distribution
i metoden find_distributions()
.
Exempel¶
Tänk dig en anpassad sökare som laddar Python-moduler från en databas:
class DatabaseImporter(importlib.abc.MetaPathFinder):
def __init__(self, db):
self.db = db
def find_spec(self, fullname, target=None) -> ModuleSpec:
return self.db.spec_from_name(fullname)
sys.meta_path.append(DatabaseImporter(connect_db(...)))
Den importören tillhandahåller nu antagligen importerbara moduler från en databas, men den tillhandahåller inga metadata eller ingångspunkter. För att denna anpassade importör ska kunna tillhandahålla metadata skulle den också behöva implementera DistributionFinder
:
from importlib.metadata import DistributionFinder
class DatabaseImporter(DistributionFinder):
...
def find_distributions(self, context=DistributionFinder.Context()):
query = dict(name=context.name) if context.name else {}
for dist_record in self.db.query_distributions(query):
yield DatabaseDistribution(dist_record)
På detta sätt skulle query_distributions
returnera poster för varje distribution som betjänas av den databas som matchar frågan. Om till exempel requests-1.0
finns i databasen, skulle find_distributions
ge en DatabaseDistribution
för Context(name='requests')
eller Context(name=None)
.
För enkelhetens skull ignorerar detta exempel context.path
. Attributet path
är som standard sys.path
och är den uppsättning importvägar som ska beaktas i sökningen. En DatabaseImporter
skulle potentiellt kunna fungera utan att behöva ta hänsyn till någon sökväg. Om importören inte gör någon partitionering skulle ”path” vara irrelevant. För att illustrera syftet med path
skulle exemplet behöva illustrera en mer komplex DatabaseImporter
vars beteende varierar beroende på sys.path
/PYTHONPATH
. I det fallet bör find_distributions
respektera context.path
och endast ge Distribution
s som är relevanta för den sökvägen.
DatabaseDistribution
skulle då se ut ungefär som:
class DatabaseDistribution(importlib.metadata.Distribution):
def __init__(self, record):
self.record = record
def read_text(self, filename):
"""
Read a file like "METADATA" for the current distribution.
"""
if filename == "METADATA":
return f"""Name: {self.record.name}
Version: {self.record.version}
"""
if filename == "entry_points.txt":
return "\n".join(
f"""[{ep.group}]\n{ep.name}={ep.value}"""
for ep in self.record.entry_points)
def locate_file(self, path):
raise RuntimeError("This distribution has no file system")
Denna grundläggande implementering bör tillhandahålla metadata och ingångspunkter för paket som betjänas av DatabaseImporter
, förutsatt att record
tillhandahåller lämpliga attribut för .name
, .version
och .entry_points
.
DatabaseDistribution
kan också tillhandahålla andra metadatafiler, som RECORD
(krävs för Distribution.files
) eller åsidosätta implementeringen av Distribution.files
. Se källan för mer inspiration.