diff --git a/importlib_metadata/__init__.py b/importlib_metadata/__init__.py index 5e7e6ad7..f9984697 100644 --- a/importlib_metadata/__init__.py +++ b/importlib_metadata/__init__.py @@ -3,8 +3,10 @@ import abc import csv import sys +import json import zipp import email +import types import inspect import pathlib import operator @@ -625,6 +627,16 @@ def url_req_space(req): space = url_req_space(section.value) yield section.value + space + quoted_marker(section.name) + @property + def origin(self): + return self._load_json('direct_url.json') + + def _load_json(self, filename): + return pass_none(json.loads)( + self.read_text(filename), + object_hook=lambda data: types.SimpleNamespace(**data), + ) + class DistributionFinder(MetaPathFinder): """ diff --git a/newsfragments/404.feature.rst b/newsfragments/404.feature.rst new file mode 100644 index 00000000..47cf2447 --- /dev/null +++ b/newsfragments/404.feature.rst @@ -0,0 +1 @@ +Added ``Distribution.origin`` supplying the ``direct_url.json`` in a ``SimpleNamespace``. \ No newline at end of file diff --git a/tests/fixtures.py b/tests/fixtures.py index 8df0860c..b419d81c 100644 --- a/tests/fixtures.py +++ b/tests/fixtures.py @@ -1,6 +1,7 @@ import os import sys import copy +import json import shutil import pathlib import tempfile @@ -131,6 +132,27 @@ def make_uppercase(self): build_files(files, self.site_dir) +class DistInfoPkgEditable(DistInfoPkg): + """ + Package with a PEP 660 direct_url.json. + """ + + some_hash = '524127ce937f7cb65665130c695abd18ca386f60bb29687efb976faa1596fdcc' + files: FilesSpec = { + 'distinfo_pkg-1.0.0.dist-info': { + 'direct_url.json': json.dumps( + { + "archive_info": { + "hash": f"sha256={some_hash}", + "hashes": {"sha256": f"{some_hash}"}, + }, + "url": "file:///path/to/distinfo_pkg-1.0.0.editable-py3-none-any.whl", + } + ) + }, + } + + class DistInfoPkgWithDot(OnSysPath, SiteBuilder): files: FilesSpec = { "pkg_dot-1.0.0.dist-info": { diff --git a/tests/test_main.py b/tests/test_main.py index a0be5bae..dd6b51fa 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -457,3 +457,10 @@ def import_names_from_package(package_name): # sources_fallback-pkg has one import ('sources_fallback') inferred from # SOURCES.txt (top_level.txt and installed-files.txt is missing) assert import_names_from_package('sources_fallback-pkg') == {'sources_fallback'} + + +class EditableDistributionTest(fixtures.DistInfoPkgEditable, unittest.TestCase): + def test_origin(self): + dist = Distribution.from_name('distinfo-pkg') + assert dist.origin.url.endswith('.whl') + assert dist.origin.archive_info.hashes.sha256