importlib.metadata
– Acessando metadados do pacote¶
Novo na versão 3.8.
Alterado na versão 3.10: importlib.metadata
não é mais provisório.
Código-fonte: Lib/importlib/metadata/__init__.py
importlib.metadata
é uma biblioteca que fornece acesso aos metadados de um Pacote de Distribuição instalado, como seus pontos de entrada ou seus nomes de nível superior (Pacotes de Importação, módulos, se houver). Construída em parte no sistema de importação do Python, esta biblioteca pretende substituir funcionalidades semelhantes na API de ponto de entrada e API de metadados de pkg_resources
. Junto com importlib.resources
, este pacote pode eliminar a necessidade de usar o pacote pkg_resources
mais antigo e menos eficiente.
importlib.metadata
operates on third-party distribution packages
installed into Python’s site-packages
directory via tools such as
pip.
Specifically, it works with distributions with discoverable
dist-info
or egg-info
directories,
and metadata defined by the Core metadata specifications.
Importante
Eles não são necessariamente equivalentes ou correspondem 1:1 aos nomes de pacotes de importação de nível superior que podem ser importados dentro do código Python. Um pacote de distribuição pode conter vários pacotes de importação (e módulos únicos), e um pacote de importação de nível superior pode mapear para vários pacotes de distribuição se for um pacote de espaço de nomes. Você pode usar package_distributions() para obter um mapeamento entre eles.
Por padrão, os metadados de distribuição podem residir no sistema de arquivos ou em arquivos zip em sys.path
. Através de um mecanismo de extensão, os metadados podem residir em praticamente qualquer lugar.
Ver também
- https://importlib-metadata.readthedocs.io/
A documentação para
importlib_metadata
, que fornece um backport deimportlib.metadata
. Isso inclui uma referência de API para as classes e funções deste módulo, bem como um guia de migração para usuários existentes depkg_resources
.
Visão Geral¶
Digamos que você queira obter a string da versão de um Pacote de Distribuição que você instalou usando pip
. Começamos criando um ambiente virtual e instalando algo nele:
$ python -m venv example
$ source example/bin/activate
(example) $ python -m pip install wheel
Você pode obter a string de versão para wheel
executando o seguinte:
(example) $ python
>>> from importlib.metadata import version
>>> version('wheel')
'0.32.3'
Você também pode obter uma coleção de pontos de entrada selecionáveis pelas propriedades do EntryPoint (normalmente ‘group’ ou ‘name’), como console_scripts
, distutils.commands
e outros. Cada grupo contém uma coleção de objetos EntryPoint.
Você pode obter os metadados para uma distribuição:
>>> 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']
Você também pode obter uma número da versão da distribuição, listar seus arquivos constituintes e obter uma lista dos Requisitos de distribuição da distribuição.
API funcional¶
Este pacote fornece a seguinte funcionalidade por meio de sua API pública.
Pontos de entrada¶
A função entry_points()
retorna uma coleção de pontos de entrada. Os pontos de entrada são representados por instâncias EntryPoint
; cada EntryPoint
tem atributos .name
, .group
e .value
e um método .load()
para resolver o valor. Existem também atributos .module
, .attr
e .extras
para obter os componentes do atributo .value
.
Consultar todos os pontos de entrada:
>>> eps = entry_points()
A função entry_points()
retorna um objeto EntryPoints
, uma coleção de todos os objetos EntryPoint
com atributos names
e groups
por conveniência:
>>> sorted(eps.groups)
['console_scripts', 'distutils.commands', 'distutils.setup_keywords', 'egg_info.writers', 'setuptools.installation']
EntryPoints
possui um método select
para selecionar pontos de entrada que correspondam a propriedades específicas. Selecione pontos de entrada no grupo console_scripts
:
>>> scripts = eps.select(group='console_scripts')
Equivalentemente, já que entry_points
passa argumento nomeado para seleção:
>>> scripts = entry_points(group='console_scripts')
Escolha um script específico chamado “wheel” (encontrado no projeto wheel):
>>> 'wheel' in scripts.names
True
>>> wheel = scripts['wheel']
De forma equivalente, consulte esse ponto de entrada durante a seleção:
>>> (wheel,) = entry_points(group='console_scripts', name='wheel')
>>> (wheel,) = entry_points().select(group='console_scripts', name='wheel')
Inspecione o ponto de entrada resolvido:
>>> 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>
O group
e name
são valores arbitrários definidos pelo autor do pacote e normalmente um cliente desejará resolver todos os pontos de entrada para um grupo específico. Leia a documentação do setuptools para obter mais informações sobre pontos de entrada, sua definição e uso.
Notas de compatibilidade
The “selectable” entry points were introduced in importlib_metadata
3.6 and Python 3.10. Prior to those changes, entry_points
accepted
no parameters and always returned a dictionary of entry points, keyed
by group. For compatibility, if no parameters are passed to entry_points,
a SelectableGroups
object is returned, implementing that dict
interface. In the future, calling entry_points
with no parameters
will return an EntryPoints
object. Users should rely on the selection
interface to retrieve entry points by group.
Metadados de distribuição¶
Cada Pacote de Distribuição inclui alguns metadados, que você pode extrair usando a função metadata()
:
>>> wheel_metadata = metadata('wheel')
As chaves da estrutura de dados retornada, um PackageMetadata
, nomeiam as palavras reservadas dos metadados, e os valores são retornados sem análise dos metadados de distribuição:
>>> wheel_metadata['Requires-Python']
'>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*'
PackageMetadata
também apresenta um atributo json
que retorna todos os metadados em um formato compatível com JSON pela PEP 566:
>>> wheel_metadata.json['requires_python']
'>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*'
Nota
O tipo real do objeto retornado por metadata()
é um detalhe de implementação e deve ser acessado somente através da interface descrita pelo protocolo PackageMetadata.
Alterado na versão 3.10: A Description
agora é incluída nos metadados quando apresentada através do payload. Os caracteres de continuação de linha foram removidos.
O atributo json
foi adicionado.
Versões de distribuição¶
A função version()
é a maneira mais rápida de obter o número de versão de um Pacote de Distribuição, como uma string:
>>> version('wheel')
'0.32.3'
Arquivos de distribuição¶
Você também pode obter o conjunto completo de arquivos contidos em uma distribuição. A função files()
pega um nome Pacote de Distribuição e retorna todos os arquivos instalados por este distribuição. Cada objeto de arquivo retornado é um PackagePath
, um objeto derivado de pathlib.PurePath
com propriedades adicionais dist
, size
e hash
conforme indicado pelos metadados. Por exemplo:
>>> 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>
Uma vez que tenha o arquivo, você também pode ler seu conteúdo:
>>> print(util.read_text())
import base64
import sys
...
def as_bytes(s):
if isinstance(s, text_type):
return s.encode('utf-8')
return s
Você também pode usar o método locate
para obter o caminho absoluto para o arquivo:
>>> util.locate()
PosixPath('/home/gustav/example/lib/site-packages/wheel/util.py')
No caso em que o arquivo de metadados que lista os arquivos (RECORD ou SOURCES.txt) estiver faltando, files()
retornará None
. O chamador pode querer agrupar chamadas para files()
em always_iterable ou de outra forma se proteger contra isso condição se a distribuição de destino não for conhecida por ter os metadados presentes.
Requisitos de distribuição¶
Para obter o conjunto completo de requisitos para um Pacote de Distribuição, use a função requires()
:
>>> requires('wheel')
["pytest (>=3.0.0) ; extra == 'test'", "pytest-cov ; extra == 'test'"]
Mapeando importação pra pacotes de distribuição¶
Um método conveniente para resolver o nome do Pacote de Distribuição (ou nomes, no caso de um pacote de espaço de nomes) que fornece cada módulo Python de nível superior importável ou Pacote de Importação:
>>> packages_distributions()
{'importlib_metadata': ['importlib-metadata'], 'yaml': ['PyYAML'], 'jaraco': ['jaraco.classes', 'jaraco.functools'], ...}
Novo na versão 3.10.
Distribuições¶
Embora a API acima seja o uso mais comum e conveniente, você pode obter todas essas informações na classe Distribution
. Uma Distribution
é um objeto abstrato que representa os metadados de um Pacote de Distribuição do Python. Você pode obter a instância Distribution
:
>>> from importlib.metadata import distribution
>>> dist = distribution('wheel')
Assim, uma forma alternativa de obter o número da versão é através da instância Distribution
:
>>> dist.version
'0.32.3'
Existem todos os tipos de metadados adicionais disponíveis na instância Distribution
:
>>> dist.metadata['Requires-Python']
'>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*'
>>> dist.metadata['License']
'MIT'
O conjunto completo de metadados disponíveis não é descrito aqui. Consulte as Especificações de metadados principais para obter detalhes adicionais.
Descoberta de distribuição¶
Por padrão, este pacote fornece suporte embutido para descoberta de metadados para sistema de arquivos e arquivo zip Pacotes de Distribuição. Esta pesquisa do localizador de metadados tem como padrão sys.path
, mas varia um pouco na maneira como ela interpreta esses valores em relação a outras mecanismo de importação. Em particular:
importlib.metadata
não honra objetosbytes
emsys.path
.importlib.metadata
irá incidentalmente honrar objetospathlib.Path
emsys.path
mesmo que tais valores sejam ignorados para importações.
Estendendo o algoritmo de pesquisa¶
Because Distribution Package metadata
is not available through sys.path
searches, or
package loaders directly,
the metadata for a distribution is found through import
system finders. To find a distribution package’s metadata,
importlib.metadata
queries the list of meta path finders on
sys.meta_path
.
Por padrão importlib.metadata
instala um localizador para pacotes de distribuição encontrados no sistema de arquivos. Na verdade, esse localizador não encontra nenhuma distribuição, mas pode encontrar seus metadados.
A classe abstrata importlib.abc.MetaPathFinder
define a interface esperada dos localizadores pelo sistema de importação do Python. importlib.metadata
estende este protocolo procurando por um chamável find_distributions
opcional nos localizadores de sys.meta_path
e apresenta esta interface estendida como a classe base abstrata DistributionFinder
, que define este método abstrato:
@abc.abstractmethod
def find_distributions(context=DistributionFinder.Context()):
"""Return an iterable of all Distribution instances capable of
loading the metadata for packages for the indicated ``context``.
"""
O objeto DistributionFinder.Context
fornece propriedades .path
e .name
indicando o caminho para pesquisar e o nome a ser correspondido e pode fornecer outro contexto relevante.
O que isso significa na prática é que para prover suporte à localização de metadados de pacotes de distribuição em outros locais fora do sistema de arquivos, crie uma subclasse Distribution
e implemente os métodos abstratos. Então, a partir de um localizador personalizado, retorne instâncias deste derivado de Distribution
no método find_distributions()
.