# Copyright 2013 Donald Stufft## Licensed under the Apache License, Version 2.0 (the "License");# you may not use this file except in compliance with the License.# You may obtain a copy of the License at## https://www.apache.org/licenses/LICENSE-2.0## Unless required by applicable law or agreed to in writing, software# distributed under the License is distributed on an "AS IS" BASIS,# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.# See the License for the specific language governing permissions and# limitations under the License.importioimportosimportreimportzipfilefromtypingimportList,Optionalfromtypingimportcastastype_castfrompkginfoimportdistributionfromtwineimportexceptions# Monkeypatch Metadata 2.0 supportdistribution.HEADER_ATTRS_2_0=distribution.HEADER_ATTRS_1_2distribution.HEADER_ATTRS.update({"2.0":distribution.HEADER_ATTRS_2_0})wheel_file_re=re.compile(r"""^(?P<namever>(?P<name>.+?)(-(?P<ver>\d.+?))?) ((-(?P<build>\d.*?))?-(?P<pyver>.+?)-(?P<abi>.+?)-(?P<plat>.+?) \.whl|\.dist-info)$""",re.VERBOSE,)
[docs]@staticmethoddeffind_candidate_metadata_files(names:List[str])->List[List[str]]:"""Filter files that may be METADATA files."""tuples=[x.split("/")forxinnamesif"METADATA"inx]return[x[1]forxinsorted((len(x),x)forxintuples)]
[docs]defread(self)->bytes:fqn=os.path.abspath(os.path.normpath(self.filename))ifnotos.path.exists(fqn):raiseexceptions.InvalidDistribution("No such file: %s"%fqn)iffqn.endswith(".whl"):archive=zipfile.ZipFile(fqn)names=archive.namelist()defread_file(name:str)->bytes:returnarchive.read(name)else:raiseexceptions.InvalidDistribution("Not a known archive format for file: %s"%fqn)try:forpathinself.find_candidate_metadata_files(names):candidate="/".join(path)data=read_file(candidate)ifb"Metadata-Version"indata:returndatafinally:archive.close()raiseexceptions.InvalidDistribution("No METADATA in archive: %s"%fqn)
[docs]defparse(self,data:bytes)->None:super().parse(data)fp=io.StringIO(data.decode("utf-8",errors="replace"))# msg is ``email.message.Message`` which is a legacy API documented# here: https://docs.python.org/3/library/email.compat32-message.htmlmsg=distribution.parse(fp)self.description=type_cast(str,msg.get_payload())