22import datetime
33import logging
44import typing
5- from email .message import EmailMessage , Message
6- from email .parser import BytesParser
75from io import BytesIO
8- from typing import TYPE_CHECKING
96from zipfile import ZipFile
107
8+ from packaging .metadata import Metadata
119from packaging .requirements import Requirement
1210from packaging .utils import BuildTag , canonicalize_name
1311from packaging .version import Version
1412
13+ from . import dependencies
1514from .request_session import session
1615
1716logger = logging .getLogger (__name__ )
1817
19- # fix for runtime errors caused by inheriting classes that are generic in stubs but not runtime
20- # https://mypy.readthedocs.io/en/latest/runtime_troubles.html#using-classes-that-are-generic-in-stubs-but-not-at-runtime
21- if TYPE_CHECKING :
22- Metadata = Message [str , str ]
23- else :
24- Metadata = Message
25-
2618
2719@dataclasses .dataclass (frozen = True , order = True , slots = True , repr = False , kw_only = True )
2820class Candidate :
@@ -73,11 +65,10 @@ def metadata(self) -> Metadata:
7365 return self ._metadata
7466
7567 def _get_dependencies (self ) -> typing .Iterable [Requirement ]:
76- deps = self .metadata .get_all ( "Requires-Dist" , [])
68+ deps = self .metadata .requires_dist or []
7769 extras = self .extras if self .extras else ["" ]
7870
79- for d in deps :
80- r = Requirement (d )
71+ for r in deps :
8172 if r .marker is None :
8273 yield r
8374 else :
@@ -95,7 +86,8 @@ def dependencies(self) -> list[Requirement]:
9586
9687 @property
9788 def requires_python (self ) -> str | None :
98- return self .metadata .get ("Requires-Python" )
89+ spec = self .metadata .requires_python
90+ return str (spec ) if spec is not None else None
9991
10092
10193def get_metadata_for_wheel (url : str , metadata_url : str | None = None ) -> Metadata :
@@ -107,7 +99,7 @@ def get_metadata_for_wheel(url: str, metadata_url: str | None = None) -> Metadat
10799 metadata_url: Optional URL of the metadata file (PEP 658)
108100
109101 Returns:
110- Parsed metadata as a Message object
102+ Parsed metadata as a Metadata object
111103 """
112104 # Try PEP 658 metadata endpoint first if available
113105 if metadata_url :
@@ -119,8 +111,7 @@ def get_metadata_for_wheel(url: str, metadata_url: str | None = None) -> Metadat
119111 response .raise_for_status ()
120112
121113 # Parse metadata directly from the response content
122- p = BytesParser ()
123- metadata = p .parse (BytesIO (response .content ), headersonly = True )
114+ metadata = dependencies .parse_metadata (response .content )
124115 logger .debug (f"Successfully retrieved metadata via PEP 658 for { url } " )
125116 return metadata
126117
@@ -136,8 +127,8 @@ def get_metadata_for_wheel(url: str, metadata_url: str | None = None) -> Metadat
136127 with ZipFile (BytesIO (data )) as z :
137128 for n in z .namelist ():
138129 if n .endswith (".dist-info/METADATA" ):
139- p = BytesParser ( )
140- return p . parse ( z . open ( n ), headersonly = True )
130+ metadata_content = z . read ( n )
131+ return dependencies . parse_metadata ( metadata_content )
141132
142- # If we didn't find the metadata, return an empty dict
143- return EmailMessage ( )
133+ # If we didn't find the metadata, raise an error
134+ raise ValueError ( f"Could not find METADATA file in wheel: { url } " )
0 commit comments