# `importlib.metadata` 사용하기

버전 3.8에 추가.

버전 3.10에서 변경: `importlib.metadata` is no longer provisional.

Source code: Lib/importlib/metadata/__init__.py

`importlib.metadata`는 설치된 패키지 메타 데이터에 대한 액세스를 제공하는 라이브러리입니다. 파이썬의 임포트 시스템에 내장된 이 라이브러리는 `pkg_resources`의 진입 지점 API와 메타데이터 API에서 유사한 기능을 대체하려고 합니다. 파이썬 3.7 이상의 `importlib.resources`(이전 버전의 파이썬을 위해 importlib_resources로 역 이식되었습니다)와 함께, 오래되고 덜 효율적인 `pkg_resources` 패키지를 사용할 필요를 제거합니다.

“설치된 패키지”는 일반적으로 pip 와 같은 도구를 통해 파이썬의 `site-packages` 디렉터리에 설치된 제삼자 패키지를 의미합니다. 특히, 발견 가능한 `dist-info`나 `egg-info` 디렉터리와 PEP 566 또는 이전 명세로 정의된 메타 데이터가 있는 패키지를 의미합니다. 기본적으로, 패키지 메타 데이터는 파일 시스템이나 `sys.path`의 zip 저장소에서 살 수 있습니다. 확장 메커니즘을 통해, 메타 데이터는 거의 모든 곳에서 살아갈 수 있습니다.

## 개요

`pip`를 사용하여 설치한 패키지의 버전 문자열을 얻고 싶다고 가정해 봅시다. 우선 가상 환경을 만들고 그 안에 뭔가 설치합니다:

    $ python -m venv example
    $ source example/bin/activate
    (example) $ pip install wheel

다음을 실행하여 `wheel`에 대한 버전 문자열을 얻을 수 있습니다:

    (example) $ python
    >>> from importlib.metadata import version
    >>> version('wheel')
    '0.32.3'

`console_scripts`, `distutils.commands`와 다른 것들과 같은 그룹 키로 진입 지점 집합을 얻을 수도 있습니다. 각 그룹은 EntryPoint 객체의 시퀀스를 포함합니다.

여러분은 배포 메타데이터를 얻을 수 있습니다:

    >>> 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']

또한 배포의 버전 번호를 가져오고, 구성 파일을 나열하고, 배포의 요구사항 리스트를 얻을 수 있습니다.

## 기능적 API

이 패키지는 공용 API를 통해 다음과 같은 기능을 제공합니다.

### 진입 지점

The `entry_points()` function returns a collection of entry points. Entry points are represented by `EntryPoint` instances; each `EntryPoint` has a `.name`, `.group`, and `.value` attributes and a `.load()` method to resolve the value. There are also `.module`, `.attr`, and `.extras` attributes for getting the components of the `.value` attribute.

Query all entry points:

    >>> eps = entry_points()

The `entry_points()` function returns an `EntryPoints` object, a sequence of all `EntryPoint` objects with `names` and `groups` attributes for convenience:

    >>> sorted(eps.groups)
    ['console_scripts', 'distutils.commands', 'distutils.setup_keywords', 'egg_info.writers', 'setuptools.installation']

`EntryPoints` has a `select` method to select entry points matching specific properties. Select entry points in the `console_scripts` group:

    >>> scripts = eps.select(group='console_scripts')

Equivalently, since `entry_points` passes keyword arguments through to select:

    >>> scripts = entry_points(group='console_scripts')

Pick out a specific script named “wheel” (found in the wheel project):

    >>> 'wheel' in scripts.names
    True
    >>> wheel = scripts['wheel']

Equivalently, query for that entry point during selection:

    >>> (wheel,) = entry_points(group='console_scripts', name='wheel')
    >>> (wheel,) = entry_points().select(group='console_scripts', name='wheel')

Inspect the resolved entry point:

    >>> 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>

The `group` and `name` are arbitrary values defined by the package author and usually a client will wish to resolve all entry points for a particular group. Read the setuptools docs for more information on entry points, their definition, and usage.

Compatibility Note

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.

### 배포 메타데이터

모든 배포는 `metadata()` 함수를 사용하여 추출할 수 있는 몇 가지 메타 데이터가 포함되어 있습니다:

    >>> wheel_metadata = metadata('wheel')

The keys of the returned data structure, a `PackageMetadata`, name the metadata keywords, and the values are returned unparsed from the distribution metadata:

    >>> wheel_metadata['Requires-Python']
    '>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*'

`PackageMetadata` also presents a `json` attribute that returns all the metadata in a JSON-compatible form per PEP 566:

    >>> wheel_metadata.json['requires_python']
    '>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*'

버전 3.10에서 변경: The `Description` is now included in the metadata when presented through the payload. Line continuation characters have been removed.

버전 3.10에 추가: The `json` attribute was added.

### 배포 버전

`version()` 함수는 배포의 버전 번호를 문자열로 가져오는 가장 빠른 방법입니다:

    >>> version('wheel')
    '0.32.3'

### 배포 파일

You can also get the full set of files contained within a distribution. The `files()` function takes a distribution package name and returns all of the files installed by this distribution. Each file object returned is a `PackagePath`, a `pathlib.PurePath` derived object with additional `dist`, `size`, and `hash` properties as indicated by the metadata. For example:

    >>> 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>

일단 파일을 얻으면, 내용을 읽을 수도 있습니다:

    >>> print(util.read_text())
    import base64
    import sys
    ...
    def as_bytes(s):
        if isinstance(s, text_type):
            return s.encode('utf-8')
        return s

You can also use the `locate` method to get a the absolute path to the file:

    >>> util.locate()
    PosixPath('/home/gustav/example/lib/site-packages/wheel/util.py')

메타 데이터 파일 목록 파일(RECORD나 SOURCES.txt)이 누락된 경우, `files()`는 `None`을 반환합니다. 대상 배포에 메타 데이터가 있음이 알려지지 않았을 때, 이 조건에 대한 보호로 호출자는 `files()`에 대한 호출을 always_iterable이나 다른 것으로 감쌀 수 있습니다.

### 배포 요구 사항

배포의 전체 요구 사항을 얻으려면, `requires()` 함수를 사용하십시오:

    >>> requires('wheel')
    ["pytest (>=3.0.0) ; extra == 'test'", "pytest-cov ; extra == 'test'"]

### Package distributions

A convenience method to resolve the distribution or distributions (in the case of a namespace package) for top-level Python packages or modules:

    >>> packages_distributions()
    {'importlib_metadata': ['importlib-metadata'], 'yaml': ['PyYAML'], 'jaraco': ['jaraco.classes', 'jaraco.functools'], ...}

버전 3.10에 추가.

## 배포

위의 API가 가장 일반적이며 편리한 사용법이지만, `Distribution` 클래스에서 모든 정보를 얻을 수 있습니다. `Distribution`은 파이썬 패키지의 메타 데이터를 나타내는 추상 객체입니다. `Distribution` 인스턴스를 얻을 수 있습니다:

    >>> from importlib.metadata import distribution
    >>> dist = distribution('wheel')

따라서, 버전 번호를 얻는 다른 방법은 `Distribution` 인스턴스를 사용하는 것입니다:

    >>> dist.version
    '0.32.3'

`Distribution` 인스턴스에서 사용할 수 있는 모든 종류의 추가 메타 데이터가 있습니다:

    >>> dist.metadata['Requires-Python']
    '>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*'
    >>> dist.metadata['License']
    'MIT'

사용 가능한 메타 데이터의 전체 집합은 여기에서 설명하지 않습니다. 자세한 내용은 PEP 566을 참조하십시오.

## 검색 알고리즘 확장하기

패키지 메타 데이터는 `sys.path` 검색이나 패키지 로더를 통해 직접 사용할 수 없으므로, 패키지의 메타 데이터는 임포트 시스템 파인더를 통해 찾습니다. 배포 패키지의 메타 데이터를 찾기 위해, `importlib.metadata`는 `sys.meta_path`의 메타 경로 파인더의 리스트를 조회합니다.

파이썬의 기본 `PathFinder`에는 일반적인 파일 시스템 기반 경로에서 로드된 배포를 찾기 위해 `importlib.metadata.MetadataPathFinder`를 호출하는 훅이 포함되어 있습니다.

추상 클래스 `importlib.abc.MetaPathFinder`는 파이썬의 임포트 시스템에 의해 파인더가 기대하는 인터페이스를 정의합니다. `importlib.metadata`는 `sys.meta_path`의 파인더에서 선택적인 `find_distributions` 콜러블을 조회함으로써 이 프로토콜을 확장하고 이 확장된 인터페이스를 다음과 같은 추상 메서드를 정의하는 `DistributionFinder` 추상 베이스 클래스로 제공합니다:

    @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``.
        """

`DistributionFinder.Context` 객체는 검색할 경로와 일치할 이름을 가리키는 `.path`와 `.name` 프로퍼티를 제공하고 다른 관련 문맥을 제공할 수 있습니다.

이것이 실제로 의미하는 것은, 파일 시스템이 아닌 위치에서 배포 패키지 메타 데이터를 찾는 것을 지원하려면, `Distribution`을 서브 클래싱하고 추상 메서드를 구현해야 한다는 것입니다. 그런 다음 사용자 정의 파인더의 `find_distributions()` 메서드에서, 이 파생된 `Distribution`의 인스턴스를 반환하십시오.