1919import re
2020import subprocess
2121import sys
22- from typing import Any , Dict , List , NamedTuple , Optional , Sequence , Tuple , Union , cast
22+ import warnings
23+ from typing import (
24+ Any ,
25+ Dict ,
26+ Iterable ,
27+ List ,
28+ NamedTuple ,
29+ Optional ,
30+ Sequence ,
31+ Tuple ,
32+ Union ,
33+ cast ,
34+ )
2335
2436if sys .version_info >= (3 , 10 ):
2537 import importlib .metadata as importlib_metadata
2638else :
2739 import importlib_metadata
2840
41+ import packaging .version
2942import pkginfo
3043from rich import print
3144
@@ -65,12 +78,19 @@ def _safe_name(name: str) -> str:
6578 return re .sub ("[^A-Za-z0-9.]+" , "-" , name )
6679
6780
81+ class CheckedDistribution (pkginfo .Distribution ):
82+ """A Distribution whose name and version are confirmed to be defined."""
83+
84+ name : str
85+ version : str
86+
87+
6888class PackageFile :
6989 def __init__ (
7090 self ,
7191 filename : str ,
7292 comment : Optional [str ],
73- metadata : pkginfo . Distribution ,
93+ metadata : CheckedDistribution ,
7494 python_version : Optional [str ],
7595 filetype : Optional [str ],
7696 ) -> None :
@@ -100,7 +120,8 @@ def from_filename(cls, filename: str, comment: Optional[str]) -> "PackageFile":
100120 for ext , dtype in DIST_EXTENSIONS .items ():
101121 if filename .endswith (ext ):
102122 try :
103- meta = DIST_TYPES [dtype ](filename )
123+ with warnings .catch_warnings (record = True ) as captured :
124+ meta = DIST_TYPES [dtype ](filename )
104125 except EOFError :
105126 raise exceptions .InvalidDistribution (
106127 "Invalid distribution file: '%s'" % os .path .basename (filename )
@@ -112,22 +133,29 @@ def from_filename(cls, filename: str, comment: Optional[str]) -> "PackageFile":
112133 "Unknown distribution format: '%s'" % os .path .basename (filename )
113134 )
114135
115- # If pkginfo encounters a metadata version it doesn't support, it may give us
136+ supported_metadata = list (pkginfo .distribution .HEADER_ATTRS )
137+ if cls ._is_unknown_metadata_version (captured ):
138+ raise exceptions .InvalidDistribution (
139+ "Make sure the distribution is using a supported Metadata-Version: "
140+ f"{ ', ' .join (supported_metadata )} ."
141+ )
142+ # If pkginfo <1.11 encounters a metadata version it doesn't support, it may give
116143 # back empty metadata. At the very least, we should have a name and version,
117144 # which could also be empty if, for example, a MANIFEST.in doesn't include
118145 # setup.cfg.
119146 missing_fields = [
120147 f .capitalize () for f in ["name" , "version" ] if not getattr (meta , f )
121148 ]
122149 if missing_fields :
123- supported_metadata = list (pkginfo .distribution .HEADER_ATTRS )
124- raise exceptions .InvalidDistribution (
125- "Metadata is missing required fields: "
126- f"{ ', ' .join (missing_fields )} .\n "
127- "Make sure the distribution includes the files where those fields "
128- "are specified, and is using a supported Metadata-Version: "
129- f"{ ', ' .join (supported_metadata )} ."
130- )
150+ msg = f"Metadata is missing required fields: { ', ' .join (missing_fields )} ."
151+ if cls ._pkginfo_before_1_11 ():
152+ msg += (
153+ "\n "
154+ "Make sure the distribution includes the files where those fields "
155+ "are specified, and is using a supported Metadata-Version: "
156+ f"{ ', ' .join (supported_metadata )} ."
157+ )
158+ raise exceptions .InvalidDistribution (msg )
131159
132160 py_version : Optional [str ]
133161 if dtype == "bdist_egg" :
@@ -140,7 +168,21 @@ def from_filename(cls, filename: str, comment: Optional[str]) -> "PackageFile":
140168 else :
141169 py_version = None
142170
143- return cls (filename , comment , meta , py_version , dtype )
171+ return cls (
172+ filename , comment , cast (CheckedDistribution , meta ), py_version , dtype
173+ )
174+
175+ @staticmethod
176+ def _is_unknown_metadata_version (
177+ captured : Iterable [warnings .WarningMessage ],
178+ ) -> bool :
179+ NMV = getattr (pkginfo .distribution , "NewMetadataVersion" , None )
180+ return any (warning .category is NMV for warning in captured )
181+
182+ @staticmethod
183+ def _pkginfo_before_1_11 () -> bool :
184+ ver = packaging .version .Version (importlib_metadata .version ("pkginfo" ))
185+ return ver < packaging .version .Version ("1.11" )
144186
145187 def metadata_dictionary (self ) -> Dict [str , MetadataValue ]:
146188 """Merge multiple sources of metadata into a single dictionary.
0 commit comments