forked from winpython/winpython
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpackagemetadata.py
More file actions
92 lines (84 loc) · 3.41 KB
/
packagemetadata.py
File metadata and controls
92 lines (84 loc) · 3.41 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# -*- coding: utf-8 -*-
"""
packagemetadata.py - get metadata from designated place
"""
import os
import re
import tarfile
import zipfile
import sys
from pathlib import Path
from typing import Dict, List, Optional, Tuple
from . import utils
import importlib.metadata
import email
#from packaging.utils import canonicalize_name
# --- Abstract metadata accessor ---
class PackageMetadata:
"""A minimal abstraction for package metadata."""
def __init__(self, name, version, requires, summary, description, metadata):
self.name = name
self.version = version
self.requires = requires # List[str] of dependencies
self.summary = summary
self.description = description
self.metadata = metadata
def get_installed_metadata(path = None) -> List[PackageMetadata]:
# Use importlib.metadata or pkg_resources
pkgs = []
distro = importlib.metadata.distributions(path = path) if path else importlib.metadata.distributions()
for dist in distro:
name = utils.canonicalize_name(dist.metadata['Name'])
version = dist.version
summary = dist.metadata.get("Summary", ""),
description = dist.metadata.get("Description", ""),
requires = dist.requires or []
metadata = dist.metadata
pkgs.append(PackageMetadata(name, version, requires, summary, description, metadata))
return pkgs
def get_directory_metadata(directory: str) -> List[PackageMetadata]:
# For each .whl/.tar.gz file in directory, extract metadata
pkgs = []
for fname in os.listdir(directory):
if fname.endswith('.whl'):
# Extract METADATA from wheel
meta = extract_metadata_from_wheel(os.path.join(directory, fname))
pkgs.append(meta)
elif fname.endswith('.tar.gz'):
# Extract PKG-INFO from sdist
meta = extract_metadata_from_sdist(os.path.join(directory, fname))
pkgs.append(meta)
return pkgs
def extract_metadata_from_wheel(path: str) -> PackageMetadata:
with zipfile.ZipFile(path) as zf:
for name in zf.namelist():
if name.endswith(r'.dist-info/METADATA') and name.split("/")[1] == "METADATA":
with zf.open(name) as f:
# Parse metadata (simple parsing for Name, Version, Requires-Dist)
return parse_metadata_file(f.read().decode())
raise ValueError(f"No METADATA found in {path}")
def extract_metadata_from_sdist(path: str) -> PackageMetadata:
with tarfile.open(path, "r:gz") as tf:
for member in tf.getmembers():
if member.name.endswith('PKG-INFO'):
f = tf.extractfile(member)
return parse_metadata_file(f.read().decode())
raise ValueError(f"No PKG-INFO found in {path}")
def parse_metadata_file(txt: str) -> PackageMetadata:
meta = email.message_from_string(txt)
name = utils.canonicalize_name(meta.get('Name', ''))
version = meta.get('Version', '')
summary = meta.get('Summary', '')
description = meta.get('Description', '')
requires = meta.get_all('Requires-Dist') or []
return PackageMetadata(name, version, requires, summary, description, dict(meta.items()))
def main():
if len(sys.argv) > 1:
# Directory mode
directory = sys.argv[1]
pkgs = get_directory_metadata(directory)
else:
# Installed packages mode
pkgs = get_installed_metadata()
if __name__ == "__main__":
main()