"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"의 인스턴스
를 반환하십시오.
