1import os 2import re 3import zipfile 4from typing import Optional 5 6from pkginfo import distribution 7 8from twine import exceptions 9 10wininst_file_re = re.compile(r".*py(?P<pyver>\d+\.\d+)\.exe$") 11 12 13class WinInst(distribution.Distribution): 14 def __init__(self, filename: str, metadata_version: Optional[str] = None) -> None: 15 self.filename = filename 16 self.metadata_version = metadata_version 17 self.extractMetadata() 18 19 @property 20 def py_version(self) -> str: 21 m = wininst_file_re.match(self.filename) 22 if m is None: 23 return "any" 24 else: 25 return m.group("pyver") 26 27 def read(self) -> bytes: 28 fqn = os.path.abspath(os.path.normpath(self.filename)) 29 if not os.path.exists(fqn): 30 raise exceptions.InvalidDistribution("No such file: %s" % fqn) 31 32 if fqn.endswith(".exe"): 33 archive = zipfile.ZipFile(fqn) 34 names = archive.namelist() 35 36 def read_file(name: str) -> bytes: 37 return archive.read(name) 38 39 else: 40 raise exceptions.InvalidDistribution( 41 "Not a known archive format for file: %s" % fqn 42 ) 43 44 try: 45 tuples = [ 46 x.split("/") 47 for x in names 48 if x.endswith(".egg-info") or x.endswith("PKG-INFO") 49 ] 50 schwarz = sorted([(len(x), x) for x in tuples]) 51 for path in [x[1] for x in schwarz]: 52 candidate = "/".join(path) 53 data = read_file(candidate) 54 if b"Metadata-Version" in data: 55 return data 56 finally: 57 archive.close() 58 59 raise exceptions.InvalidDistribution( 60 "No PKG-INFO/.egg-info in archive: %s" % fqn 61 ) 62