1
+ #!/usr/bin/env python3
2
+ """
3
+ packagemetadata.py - get metadata from designated place
4
+ """
5
+ import os
6
+ import re
7
+ import tarfile
8
+ import zipfile
9
+ import sys
10
+ from pathlib import Path
11
+ from collections import defaultdict
12
+ import shutil
13
+ import subprocess
14
+ from typing import Dict , List , Optional , Tuple
15
+ from . import utils
16
+
17
+ from packaging .utils import canonicalize_name , parse_wheel_filename , parse_sdist_filename
18
+ # --- Abstract metadata accessor ---
19
+
20
+ class PackageMetadata :
21
+ """A minimal abstraction for package metadata."""
22
+ def __init__ (self , name , version , requires , summary , description , metadata ):
23
+ self .name = name
24
+ self .version = version
25
+ self .requires = requires # List[str] of dependencies
26
+ self .summary = summary
27
+ self .description = description
28
+ self .metadata = metadata
29
+
30
+ def get_installed_metadata (path = None ) -> List [PackageMetadata ]:
31
+ # Use importlib.metadata or pkg_resources
32
+ import importlib .metadata
33
+ pkgs = []
34
+ distro = importlib .metadata .distributions (path = path ) if path else importlib .metadata .distributions ()
35
+ for dist in distro :
36
+ name = dist .metadata ['Name' ]
37
+ version = dist .version
38
+ summary = dist .metadata .get ("Summary" , "" ),
39
+ description = dist .metadata .get ("Description" , "" ),
40
+ requires = dist .requires or []
41
+ metadata = dist .metadata
42
+ pkgs .append (PackageMetadata (name , version , requires , summary , description , metadata ))
43
+ return pkgs
44
+
45
+ def get_directory_metadata (directory : str ) -> List [PackageMetadata ]:
46
+ # For each .whl/.tar.gz file in directory, extract metadata
47
+ pkgs = []
48
+ for fname in os .listdir (directory ):
49
+ if fname .endswith ('.whl' ):
50
+ # Extract METADATA from wheel
51
+ meta = extract_metadata_from_wheel (os .path .join (directory , fname ))
52
+ pkgs .append (meta )
53
+ elif fname .endswith ('.tar.gz' ):
54
+ # Extract PKG-INFO from sdist
55
+ meta = extract_metadata_from_sdist (os .path .join (directory , fname ))
56
+ pkgs .append (meta )
57
+ return pkgs
58
+
59
+ def extract_metadata_from_wheel (path : str ) -> PackageMetadata :
60
+ import zipfile
61
+ with zipfile .ZipFile (path ) as zf :
62
+ for name in zf .namelist ():
63
+ if name .endswith (r'.dist-info/METADATA' ) and name .split ("/" )[1 ] == "METADATA" :
64
+ with zf .open (name ) as f :
65
+ # Parse metadata (simple parsing for Name, Version, Requires-Dist)
66
+ return parse_metadata_file (f .read ().decode ())
67
+ raise ValueError (f"No METADATA found in { path } " )
68
+
69
+ def extract_metadata_from_sdist (path : str ) -> PackageMetadata :
70
+ import tarfile
71
+ with tarfile .open (path , "r:gz" ) as tf :
72
+ for member in tf .getmembers ():
73
+ if member .name .endswith ('PKG-INFO' ):
74
+ f = tf .extractfile (member )
75
+ return parse_metadata_file (f .read ().decode ())
76
+ raise ValueError (f"No PKG-INFO found in { path } " )
77
+
78
+ def parse_metadata_file (txt : str ) -> PackageMetadata :
79
+ name = version = summary = description = ""
80
+ requires = []
81
+ for line in txt .splitlines ():
82
+ if line .startswith ('Name: ' ):
83
+ name = line [6 :].strip ()
84
+ elif line .startswith ('Version: ' ):
85
+ version = line [9 :].strip ()
86
+ elif line .startswith ('Summary: ' ):
87
+ summary = description = line [9 :].strip ()
88
+ elif line .startswith ('Requires-Dist: ' ):
89
+ requires .append (line [14 :].strip ())
90
+ return PackageMetadata (name , version , requires , summary , description , {'Name' : name , "Summary" : summary , "Description" : description })
91
+
92
+ # --- Main dependency tree logic ---
93
+
94
+ def build_dependency_tree (pkgs : List [PackageMetadata ]):
95
+ # Existing logic, but using our PackageMetadata objects
96
+ pass
97
+
98
+ def main ():
99
+ if len (sys .argv ) > 1 :
100
+ # Directory mode
101
+ directory = sys .argv [1 ]
102
+ pkgs = get_directory_metadata (directory )
103
+ else :
104
+ # Installed packages mode
105
+ pkgs = get_installed_metadata ()
106
+ build_dependency_tree (pkgs )
107
+
108
+ if __name__ == "__main__" :
109
+ main ()
0 commit comments