|
1 | 1 | """Utility class to inspect an extracted wheel directory"""
|
2 |
| -import email |
| 2 | +import configparser |
3 | 3 | import glob
|
4 | 4 | import os
|
5 | 5 | import stat
|
6 | 6 | import zipfile
|
7 | 7 | from typing import Dict, Optional, Set
|
8 | 8 |
|
9 |
| -import installer |
10 | 9 | import pkg_resources
|
| 10 | +import pkginfo |
11 | 11 |
|
12 | 12 |
|
13 | 13 | def current_umask() -> int:
|
@@ -37,46 +37,57 @@ def path(self) -> str:
|
37 | 37 |
|
38 | 38 | @property
|
39 | 39 | def name(self) -> str:
|
40 |
| - # TODO Also available as installer.sources.WheelSource.distribution |
41 |
| - return str(self.metadata['Name']) |
| 40 | + return str(self.metadata.name) |
42 | 41 |
|
43 | 42 | @property
|
44 |
| - def metadata(self) -> email.message.Message: |
45 |
| - with installer.sources.WheelFile.open(self.path) as wheel_source: |
46 |
| - metadata_contents = wheel_source.read_dist_info("METADATA") |
47 |
| - metadata = installer.utils.parse_metadata_file(metadata_contents) |
48 |
| - return metadata |
| 43 | + def metadata(self) -> pkginfo.Wheel: |
| 44 | + return pkginfo.get_metadata(self.path) |
49 | 45 |
|
50 |
| - @property |
51 |
| - def version(self) -> str: |
52 |
| - # TODO Also available as installer.sources.WheelSource.version |
53 |
| - return str(self.metadata["Version"]) |
54 |
| - |
55 |
| - def entry_points(self) -> Dict[str, tuple[str, str]]: |
| 46 | + def entry_points(self) -> Dict[str, str]: |
56 | 47 | """Returns the entrypoints defined in the current wheel
|
57 | 48 |
|
58 | 49 | See https://packaging.python.org/specifications/entry-points/ for more info
|
59 | 50 |
|
60 | 51 | Returns:
|
61 |
| - Dict[str, Tuple[str, str]]: A mapping of the entry point's name to it's module and attribute |
| 52 | + Dict[str, str]: A mappying of the entry point's name to it's method |
62 | 53 | """
|
63 |
| - with installer.sources.WheelFile.open(self.path) as wheel_source: |
64 |
| - if "entry_points.txt" not in wheel_source.dist_info_filenames: |
| 54 | + with zipfile.ZipFile(self.path, "r") as whl: |
| 55 | + # Calculate the location of the entry_points.txt file |
| 56 | + metadata = self.metadata |
| 57 | + name = "{}-{}".format(metadata.name.replace("-", "_"), metadata.version) |
| 58 | + |
| 59 | + # Note that the zipfile module always uses the forward slash as |
| 60 | + # directory separator, even on Windows, so don't use os.path.join |
| 61 | + # here. Reference for Python 3.10: |
| 62 | + # https://github.com/python/cpython/blob/3.10/Lib/zipfile.py#L355. |
| 63 | + # TODO: use zipfile.Path once 3.8 is our minimum supported version |
| 64 | + entry_points_path = "{}.dist-info/entry_points.txt".format(name) |
| 65 | + |
| 66 | + # If this file does not exist in the wheel, there are no entry points |
| 67 | + if entry_points_path not in whl.namelist(): |
65 | 68 | return dict()
|
66 | 69 |
|
67 |
| - entry_points_mapping = dict() |
68 |
| - entry_points_contents = wheel_source.read_dist_info("entry_points.txt") |
69 |
| - entry_points = installer.utils.parse_entrypoints(entry_points_contents) |
70 |
| - for script, module, attribute, script_section in entry_points: |
71 |
| - if script_section == "console": |
72 |
| - entry_points_mapping[script] = (module, attribute) |
| 70 | + # Parse the avaialble entry points |
| 71 | + config = configparser.ConfigParser() |
| 72 | + try: |
| 73 | + config.read_string(whl.read(entry_points_path).decode("utf-8")) |
| 74 | + if "console_scripts" in config.sections(): |
| 75 | + return dict(config["console_scripts"]) |
| 76 | + |
| 77 | + # TODO: It's unclear what to do in a situation with duplicate sections or options. |
| 78 | + # For now, we treat the config file as though it contains no scripts. For more |
| 79 | + # details on the config parser, see: |
| 80 | + # https://docs.python.org/3.7/library/configparser.html#configparser.ConfigParser |
| 81 | + # https://docs.python.org/3.7/library/configparser.html#configparser.Error |
| 82 | + except configparser.Error: |
| 83 | + pass |
73 | 84 |
|
74 |
| - return entry_points_mapping |
| 85 | + return dict() |
75 | 86 |
|
76 | 87 | def dependencies(self, extras_requested: Optional[Set[str]] = None) -> Set[str]:
|
77 | 88 | dependency_set = set()
|
78 | 89 |
|
79 |
| - for wheel_req in self.metadata.get_all('Requires-Dist', []): |
| 90 | + for wheel_req in self.metadata.requires_dist: |
80 | 91 | req = pkg_resources.Requirement(wheel_req) # type: ignore
|
81 | 92 |
|
82 | 93 | if req.marker is None or any(
|
|
0 commit comments