|
17 | 17 | from email.policy import default
|
18 | 18 | from . import utils
|
19 | 19 |
|
20 |
| -from packaging.utils import canonicalize_name |
| 20 | +from packaging.utils import canonicalize_name, parse_wheel_filename, parse_sdist_filename |
21 | 21 |
|
22 | 22 | # Use tomllib if available (Python 3.11+), otherwise fall back to tomli
|
23 | 23 | try:
|
@@ -193,32 +193,64 @@ def get_pylock_wheels(wheelhouse: Path, lockfile: Path, wheelorigin: Optional[Pa
|
193 | 193 | print(f"\n\n*** We can't install {filename} ! ***\n\n")
|
194 | 194 |
|
195 | 195 | def extract_metadata_from_wheel(filepath: Path) -> Optional[Tuple[str, str, str]]:
|
196 |
| - "get metadata from a wheel package" |
| 196 | + "Extract package metadata from a .whl file and validate it matches the filename" |
| 197 | + wheel_name = filepath.name |
| 198 | + try: |
| 199 | + name, version, build, tags = parse_wheel_filename(wheel_name) |
| 200 | + filename_name = canonicalize_name(name) |
| 201 | + filename_version = str(version) |
| 202 | + except Exception as e: |
| 203 | + print(f"❌ Could not parse filename: {wheel_name}", e) |
| 204 | + return None |
| 205 | + |
197 | 206 | with zipfile.ZipFile(filepath, 'r') as z:
|
198 | 207 | # Locate *.dist-info/METADATA file inside but not in a vendored directory (flit-core)
|
199 | 208 | for name in z.namelist():
|
200 | 209 | if name.endswith(r'.dist-info/METADATA') and name.split("/")[1] == "METADATA":
|
201 | 210 | with z.open(name) as meta_file:
|
202 | 211 | metadata = BytesParser(policy=default).parse(meta_file)
|
203 |
| - name = canonicalize_name(str(metadata.get('Name', 'unknown'))) # Avoid Head type |
204 |
| - version = str(metadata.get('Version', 'unknown')) |
| 212 | + meta_name = canonicalize_name(str(metadata.get('Name', 'unknown'))) # Avoid Head type |
| 213 | + meta_version = str(metadata.get('Version', 'unknown')) |
205 | 214 | summary = utils.sum_up(str(metadata.get('Summary', '')))
|
206 |
| - return name, version, summary |
| 215 | + # Assert consistency |
| 216 | + if meta_name != filename_name or meta_version != filename_version: |
| 217 | + print(f"⚠️ Mismatch in {wheel_name}: filename says {filename_name}=={filename_version}, " |
| 218 | + f"but METADATA says {meta_name}=={meta_version}") |
| 219 | + return None |
| 220 | + return meta_name, meta_version , summary |
207 | 221 | return None
|
208 | 222 |
|
209 | 223 | def extract_metadata_from_sdist(filepath: Path) -> Optional[Tuple[str, str, str]]:
|
210 | 224 | "get metadata from a tar.gz or .zip package"
|
211 | 225 | open_func = tarfile.open if filepath.suffixes[-2:] == ['.tar', '.gz'] else zipfile.ZipFile
|
| 226 | + sdist_name = filepath.name |
| 227 | + try: |
| 228 | + name, version = parse_sdist_filename(sdist_name) |
| 229 | + filename_name = canonicalize_name(name) |
| 230 | + filename_version = str(version) |
| 231 | + except Exception as e: |
| 232 | + print(f"❌ Could not parse filename: {sdist_name}", e) |
| 233 | + return None |
| 234 | + |
212 | 235 | with open_func(filepath, 'r') as archive:
|
213 | 236 | namelist = archive.getnames() if isinstance(archive, tarfile.TarFile) else archive.namelist()
|
214 | 237 | for name in namelist:
|
215 | 238 | if name.endswith('PKG-INFO'):
|
216 |
| - content = archive.extractfile(name).read() if isinstance(archive, tarfile.TarFile) else archive.open(name).read() |
217 |
| - metadata = message_from_bytes(content) |
218 |
| - name = canonicalize_name(str(metadata.get('Name', 'unknown'))) # Avoid Head type |
219 |
| - version = str(metadata.get('Version', 'unknown')) |
220 |
| - summary = utils.sum_up(str(metadata.get('Summary', ''))) |
221 |
| - return name, version, summary |
| 239 | + if isinstance(archive, tarfile.TarFile): |
| 240 | + content = archive.extractfile(name) |
| 241 | + else: |
| 242 | + content = archive.open(name) |
| 243 | + if content: |
| 244 | + metadata = BytesParser(policy=default).parse(content) |
| 245 | + meta_name = canonicalize_name(str(metadata.get('Name', 'unknown'))) # Avoid Head type |
| 246 | + meta_version = str(metadata.get('Version', 'unknown')) |
| 247 | + summary = utils.sum_up(str(metadata.get('Summary', ''))) |
| 248 | + # Assert consistency |
| 249 | + if meta_name != filename_name or meta_version != filename_version: |
| 250 | + print(f"⚠️ Mismatch in {sdist_name}: filename says {filename_name}=={filename_version}, " |
| 251 | + f"but METADATA says {meta_name}=={meta_version}") |
| 252 | + return None |
| 253 | + return meta_name, meta_version, summary |
222 | 254 | return None
|
223 | 255 |
|
224 | 256 | def list_packages_with_metadata(directory: str) -> List[Tuple[str, str, str]]:
|
|
0 commit comments