def analyze_dists(root: Path, dist_dir: str) -> Optional[DistInfo]: if not dist_dir: return None name = None version = None tarball_path = None dists = root / dist_dir for dist in dists.iterdir(): if ".tar" in dist.suffixes: tmp_path = Path(tempfile.mkdtemp(suffix="tarfile")) shutil.unpack_archive(dist, tmp_path) tarball_path = tmp_path / dist.name # drop '.tar.gz' suffix tarball_path = tarball_path.with_suffix("").with_suffix("") assert tarball_path.is_dir() nam, ver = parse_sdist_filename(dist.name) else: nam, ver, build, tags = parse_wheel_filename(dist.name) if name is not None: assert name == nam, f"{nam} != {name} for {dist}" else: name = nam if version is not None: assert version == ver, f"{ver} != {version} for {dist}" else: version = ver assert version is not None assert name is not None assert tarball_path is not None return DistInfo(str(version), name, tarball_path)
def from_url(url: str) -> "WheelInfo": """Parse wheels URL and extract available metadata See https://www.python.org/dev/peps/pep-0427/#file-name-convention """ file_name = Path(url).name name, version, build, tags = parse_wheel_filename(file_name) return WheelInfo( name=name, version=version, filename=file_name, build=build, tags=tags, url=url, )
def find_compatible_wheel(wheels: Sequence[T], identifier: str) -> T | None: """ Finds a wheel with an abi3 or a none ABI tag in `wheels` compatible with the Python interpreter specified by `identifier` that is previously built. """ interpreter, platform = identifier.split("-") for wheel in wheels: _, _, _, tags = parse_wheel_filename(wheel.name) for tag in tags: if tag.abi == "abi3": # ABI3 wheels must start with cp3 for impl and tag if not (interpreter.startswith("cp3") and tag.interpreter.startswith("cp3")): continue elif tag.abi == "none": # CPythonless wheels must include py3 tag if tag.interpreter[:3] != "py3": continue else: # Other types of wheels are not detected, this is looking for previously built wheels. continue if tag.interpreter != "py3" and int(tag.interpreter[3:]) > int( interpreter[3:]): # If a minor version number is given, it has to be lower than the current one. continue if platform.startswith(("manylinux", "musllinux", "macosx")): # Linux, macOS require the beginning and ending match (macos/manylinux version doesn't need to) os_, arch = platform.split("_", 1) if not tag.platform.startswith(os_): continue if not tag.platform.endswith(f"_{arch}"): continue else: # Windows should exactly match if not tag.platform == platform: continue # If all the filters above pass, then the wheel is a previously built compatible wheel. return wheel return None
def find_matching_wheels(wheel_paths: Iterable[Path]) -> Iterator[Path]: """ Returns the sequence wheels whose tags match the Pyodide interpreter. Parameters ---------- wheel_paths A list of paths to wheels Returns ------- The subset of wheel_paths that have tags that match the Pyodide interpreter. """ wheel_paths = list(wheel_paths) wheel_tags_list: list[frozenset[Tag]] = [] for wheel in wheel_paths: _, _, _, tags = parse_wheel_filename(wheel.name) wheel_tags_list.append(tags) for supported_tag in pyodide_tags(): for wheel_path, wheel_tags in zip(wheel_paths, wheel_tags_list): if supported_tag in wheel_tags: yield wheel_path
def test_parse_wheel_filename(filename, name, version, build, tags): assert parse_wheel_filename(filename) == (name, version, build, tags)
def test_parse_wheel_invalid_filename(filename): with pytest.raises(InvalidWheelFilename): parse_wheel_filename(filename)
def add_platforms( in_wheel: str, platforms: Iterable[str], out_path: Optional[str] = None, clobber: bool = False, ) -> Optional[str]: """Add platform tags `platforms` to `in_wheel` filename and WHEEL tags Add any platform tags in `platforms` that are missing from `in_wheel` filename. Add any platform tags in `platforms` that are missing from `in_wheel` ``WHEEL`` file. Parameters ---------- in_wheel : str Filename of wheel to which to add platform tags platforms : iterable platform tags to add to wheel filename and WHEEL tags - e.g. ``('macosx_10_9_intel', 'macosx_10_9_x86_64') out_path : None or str, optional Directory to which to write new wheel. Default is directory containing `in_wheel` clobber : bool, optional If True, overwrite existing output filename, otherwise raise error Returns ------- out_wheel : None or str Absolute path of wheel file written, or None if no wheel file written. """ in_wheel = abspath(in_wheel) out_path = dirname(in_wheel) if out_path is None else abspath(out_path) name, version, _, tags = parse_wheel_filename(basename(in_wheel)) info_fname = f"{name}-{version}.dist-info/WHEEL" # Check what tags we have platform_tags = {tag.platform for tag in tags} extra_fname_tags = [tag for tag in platforms if tag not in platform_tags] in_wheel_base, ext = splitext(basename(in_wheel)) out_wheel_base = ".".join([in_wheel_base] + extra_fname_tags) out_wheel = pjoin(out_path, out_wheel_base + ext) if exists(out_wheel) and not clobber: raise WheelToolsError( "Not overwriting {0}; set clobber=True to overwrite".format( out_wheel)) with InWheelCtx(in_wheel) as ctx: info = read_pkg_info(info_fname) if info["Root-Is-Purelib"] == "true": raise WheelToolsError("Cannot add platforms to pure wheel") in_info_tags = [tag for name, tag in info.items() if name == "Tag"] # Python version, C-API version combinations pyc_apis = ["-".join(tag.split("-")[:2]) for tag in in_info_tags] # unique Python version, C-API version combinations pyc_apis = unique_by_index(pyc_apis) # Add new platform tags for each Python version, C-API combination required_tags = ["-".join(tup) for tup in product(pyc_apis, platforms)] needs_write = False for req_tag in required_tags: if req_tag in in_info_tags: continue needs_write = True info.add_header("Tag", req_tag) if needs_write: write_pkg_info(info_fname, info) # Tell context manager to write wheel on exit by setting filename ctx.out_wheel = out_wheel return ctx.out_wheel
def get_info(wheel_path: str) -> Message: name, version, _, _ = parse_wheel_filename(basename(wheel_path)) with ZipFile(wheel_path) as zip_file: return read_pkg_info_bytes( zip_file.read(f"{name}-{version}.dist-info/WHEEL") )