更改enroll命名,添加了注释,向get_error_msg中添加了一些错误代码

This commit is contained in:
ygm1881
2022-05-05 22:59:35 +08:00
parent 51b5e374a3
commit ece69eaf57
4637 changed files with 7699 additions and 608140 deletions
@@ -16,6 +16,7 @@ from typing import Any, Dict, Optional, Set, Tuple, Union
from pip._vendor.packaging.markers import Marker
from pip._vendor.packaging.requirements import InvalidRequirement, Requirement
from pip._vendor.packaging.specifiers import Specifier
from pip._vendor.pkg_resources import RequirementParseError, parse_requirements
from pip._internal.exceptions import InstallationError
from pip._internal.models.index import PyPI, TestPyPI
@@ -112,56 +113,31 @@ def parse_editable(editable_req: str) -> Tuple[Optional[str], str, Set[str]]:
return package_name, url, set()
def check_first_requirement_in_file(filename: str) -> None:
"""Check if file is parsable as a requirements file.
This is heavily based on ``pkg_resources.parse_requirements``, but
simplified to just check the first meaningful line.
:raises InvalidRequirement: If the first meaningful line cannot be parsed
as an requirement.
"""
with open(filename, encoding="utf-8", errors="ignore") as f:
# Create a steppable iterator, so we can handle \-continuations.
lines = (
line
for line in (line.strip() for line in f)
if line and not line.startswith("#") # Skip blank lines/comments.
)
for line in lines:
# Drop comments -- a hash without a space may be in a URL.
if " #" in line:
line = line[: line.find(" #")]
# If there is a line continuation, drop it, and append the next line.
if line.endswith("\\"):
line = line[:-2].strip() + next(lines, "")
Requirement(line)
return
def deduce_helpful_msg(req: str) -> str:
"""Returns helpful msg in case requirements file does not exist,
or cannot be parsed.
:params req: Requirements file path
"""
if not os.path.exists(req):
return f" File '{req}' does not exist."
msg = " The path does exist. "
# Try to parse and check if it is a requirements file.
try:
check_first_requirement_in_file(req)
except InvalidRequirement:
logger.debug("Cannot parse '%s' as requirements file", req)
msg = ""
if os.path.exists(req):
msg = " The path does exist. "
# Try to parse and check if it is a requirements file.
try:
with open(req) as fp:
# parse first line only
next(parse_requirements(fp.read()))
msg += (
"The argument you provided "
"({}) appears to be a"
" requirements file. If that is the"
" case, use the '-r' flag to install"
" the packages specified within it."
).format(req)
except RequirementParseError:
logger.debug("Cannot parse '%s' as requirements file", req, exc_info=True)
else:
msg += (
f"The argument you provided "
f"({req}) appears to be a"
f" requirements file. If that is the"
f" case, use the '-r' flag to install"
f" the packages specified within it."
)
msg += f" File '{req}' does not exist."
return msg
@@ -10,6 +10,7 @@ import uuid
import zipfile
from typing import Any, Collection, Dict, Iterable, List, Optional, Sequence, Union
from pip._vendor import pkg_resources
from pip._vendor.packaging.markers import Marker
from pip._vendor.packaging.requirements import Requirement
from pip._vendor.packaging.specifiers import SpecifierSet
@@ -17,15 +18,11 @@ from pip._vendor.packaging.utils import canonicalize_name
from pip._vendor.packaging.version import Version
from pip._vendor.packaging.version import parse as parse_version
from pip._vendor.pep517.wrappers import Pep517HookCaller
from pip._vendor.pkg_resources import Distribution
from pip._internal.build_env import BuildEnvironment, NoOpBuildEnvironment
from pip._internal.exceptions import InstallationError, LegacyInstallFailure
from pip._internal.exceptions import InstallationError
from pip._internal.locations import get_scheme
from pip._internal.metadata import (
BaseDistribution,
get_default_environment,
get_directory_distribution,
)
from pip._internal.models.link import Link
from pip._internal.operations.build.metadata import generate_metadata
from pip._internal.operations.build.metadata_editable import generate_editable_metadata
@@ -35,6 +32,7 @@ from pip._internal.operations.build.metadata_legacy import (
from pip._internal.operations.install.editable_legacy import (
install_editable as install_editable_legacy,
)
from pip._internal.operations.install.legacy import LegacyInstallFailure
from pip._internal.operations.install.legacy import install as install_legacy
from pip._internal.operations.install.wheel import install_wheel
from pip._internal.pyproject import load_pyproject_toml, make_pyproject_path
@@ -49,10 +47,13 @@ from pip._internal.utils.misc import (
ask_path_exists,
backup_dir,
display_path,
dist_in_site_packages,
dist_in_usersite,
get_distribution,
hide_url,
redact_auth_from_url,
)
from pip._internal.utils.packaging import safe_extra
from pip._internal.utils.packaging import get_metadata
from pip._internal.utils.subprocess import runner_with_spinner_message
from pip._internal.utils.temp_dir import TempDirectory, tempdir_kinds
from pip._internal.utils.virtualenv import running_under_virtualenv
@@ -61,6 +62,32 @@ from pip._internal.vcs import vcs
logger = logging.getLogger(__name__)
def _get_dist(metadata_directory: str) -> Distribution:
"""Return a pkg_resources.Distribution for the provided
metadata directory.
"""
dist_dir = metadata_directory.rstrip(os.sep)
# Build a PathMetadata object, from path to metadata. :wink:
base_dir, dist_dir_name = os.path.split(dist_dir)
metadata = pkg_resources.PathMetadata(base_dir, dist_dir)
# Determine the correct Distribution object type.
if dist_dir.endswith(".egg-info"):
dist_cls = pkg_resources.Distribution
dist_name = os.path.splitext(dist_dir_name)[0]
else:
assert dist_dir.endswith(".dist-info")
dist_cls = pkg_resources.DistInfoDistribution
dist_name = os.path.splitext(dist_dir_name)[0].split("-")[0]
return dist_cls(
base_dir,
project_name=dist_name,
metadata=metadata,
)
class InstallRequirement:
"""
Represents something that may be installed later on, may have information
@@ -118,15 +145,16 @@ class InstallRequirement:
if extras:
self.extras = extras
elif req:
self.extras = {safe_extra(extra) for extra in req.extras}
self.extras = {pkg_resources.safe_extra(extra) for extra in req.extras}
else:
self.extras = set()
if markers is None and req:
markers = req.marker
self.markers = markers
# This holds the Distribution object if this requirement is already installed.
self.satisfied_by: Optional[BaseDistribution] = None
# This holds the pkg_resources.Distribution object if this requirement
# is already available:
self.satisfied_by: Optional[Distribution] = None
# Whether the installation process should try to uninstall an existing
# distribution before installing this requirement.
self.should_reinstall = False
@@ -214,7 +242,7 @@ class InstallRequirement:
def name(self) -> Optional[str]:
if self.req is None:
return None
return self.req.name
return pkg_resources.safe_name(self.req.name)
@functools.lru_cache() # use cached_property in python 3.8+
def supports_pyproject_editable(self) -> bool:
@@ -387,24 +415,32 @@ class InstallRequirement:
"""
if self.req is None:
return
existing_dist = get_default_environment().get_distribution(self.req.name)
existing_dist = get_distribution(self.req.name)
if not existing_dist:
return
version_compatible = self.req.specifier.contains(
existing_dist.version,
prereleases=True,
# pkg_resouces may contain a different copy of packaging.version from
# pip in if the downstream distributor does a poor job debundling pip.
# We avoid existing_dist.parsed_version and let SpecifierSet.contains
# parses the version instead.
existing_version = existing_dist.version
version_compatible = (
existing_version is not None
and self.req.specifier.contains(existing_version, prereleases=True)
)
if not version_compatible:
self.satisfied_by = None
if use_user_site:
if existing_dist.in_usersite:
if dist_in_usersite(existing_dist):
self.should_reinstall = True
elif running_under_virtualenv() and existing_dist.in_site_packages:
elif running_under_virtualenv() and dist_in_site_packages(
existing_dist
):
raise InstallationError(
f"Will not install to the user site because it will "
f"lack sys.path precedence to {existing_dist.raw_name} "
f"in {existing_dist.location}"
"Will not install to the user site because it will "
"lack sys.path precedence to {} in {}".format(
existing_dist.project_name, existing_dist.location
)
)
else:
self.should_reinstall = True
@@ -504,7 +540,6 @@ class InstallRequirement:
Under legacy processing, call setup.py egg-info.
"""
assert self.source_dir
details = self.name or f"from {self.link}"
if self.use_pep517:
assert self.pep517_backend is not None
@@ -516,13 +551,11 @@ class InstallRequirement:
self.metadata_directory = generate_editable_metadata(
build_env=self.build_env,
backend=self.pep517_backend,
details=details,
)
else:
self.metadata_directory = generate_metadata(
build_env=self.build_env,
backend=self.pep517_backend,
details=details,
)
else:
self.metadata_directory = generate_metadata_legacy(
@@ -530,7 +563,7 @@ class InstallRequirement:
setup_py_path=self.setup_py_path,
source_dir=self.unpacked_source_directory,
isolated=self.isolated,
details=details,
details=self.name or f"from {self.link}",
)
# Act on the newly generated metadata, based on the name and version.
@@ -544,12 +577,12 @@ class InstallRequirement:
@property
def metadata(self) -> Any:
if not hasattr(self, "_metadata"):
self._metadata = self.get_dist().metadata
self._metadata = get_metadata(self.get_dist())
return self._metadata
def get_dist(self) -> BaseDistribution:
return get_directory_distribution(self.metadata_directory)
def get_dist(self) -> Distribution:
return _get_dist(self.metadata_directory)
def assert_source_matches_version(self) -> None:
assert self.source_dir
@@ -609,7 +642,7 @@ class InstallRequirement:
# So here, if it's neither a path nor a valid VCS URL, it's a bug.
assert vcs_backend, f"Unsupported VCS URL {self.link.url}"
hidden_url = hide_url(self.link.url)
vcs_backend.obtain(self.source_dir, url=hidden_url, verbosity=0)
vcs_backend.obtain(self.source_dir, url=hidden_url)
# Top-level Actions
def uninstall(
@@ -628,7 +661,7 @@ class InstallRequirement:
"""
assert self.req
dist = get_default_environment().get_distribution(self.req.name)
dist = get_distribution(self.req.name)
if not dist:
logger.warning("Skipping %s as it is not installed.", self.name)
return None
@@ -808,7 +841,7 @@ class InstallRequirement:
)
except LegacyInstallFailure as exc:
self.install_succeeded = False
raise exc
raise exc.__cause__
except Exception:
self.install_succeeded = True
raise
@@ -1,3 +1,4 @@
import csv
import functools
import os
import sys
@@ -5,33 +6,47 @@ import sysconfig
from importlib.util import cache_from_source
from typing import Any, Callable, Dict, Iterable, Iterator, List, Optional, Set, Tuple
from pip._vendor import pkg_resources
from pip._vendor.pkg_resources import Distribution
from pip._internal.exceptions import UninstallationError
from pip._internal.locations import get_bin_prefix, get_bin_user
from pip._internal.metadata import BaseDistribution
from pip._internal.utils.compat import WINDOWS
from pip._internal.utils.egg_link import egg_link_path_from_location
from pip._internal.utils.logging import getLogger, indent_log
from pip._internal.utils.misc import ask, is_local, normalize_path, renames, rmtree
from pip._internal.utils.misc import (
ask,
dist_in_usersite,
dist_is_local,
is_local,
normalize_path,
renames,
rmtree,
)
from pip._internal.utils.temp_dir import AdjacentTempDirectory, TempDirectory
logger = getLogger(__name__)
def _script_names(bin_dir: str, script_name: str, is_gui: bool) -> Iterator[str]:
def _script_names(dist: Distribution, script_name: str, is_gui: bool) -> List[str]:
"""Create the fully qualified name of the files created by
{console,gui}_scripts for the given ``dist``.
Returns the list of file names
"""
exe_name = os.path.join(bin_dir, script_name)
yield exe_name
if not WINDOWS:
return
yield f"{exe_name}.exe"
yield f"{exe_name}.exe.manifest"
if is_gui:
yield f"{exe_name}-script.pyw"
if dist_in_usersite(dist):
bin_dir = get_bin_user()
else:
yield f"{exe_name}-script.py"
bin_dir = get_bin_prefix()
exe_name = os.path.join(bin_dir, script_name)
paths_to_remove = [exe_name]
if WINDOWS:
paths_to_remove.append(exe_name + ".exe")
paths_to_remove.append(exe_name + ".exe.manifest")
if is_gui:
paths_to_remove.append(exe_name + "-script.pyw")
else:
paths_to_remove.append(exe_name + "-script.py")
return paths_to_remove
def _unique(fn: Callable[..., Iterator[Any]]) -> Callable[..., Iterator[Any]]:
@@ -47,7 +62,7 @@ def _unique(fn: Callable[..., Iterator[Any]]) -> Callable[..., Iterator[Any]]:
@_unique
def uninstallation_paths(dist: BaseDistribution) -> Iterator[str]:
def uninstallation_paths(dist: Distribution) -> Iterator[str]:
"""
Yield all the uninstallation paths for dist based on RECORD-without-.py[co]
@@ -61,25 +76,25 @@ def uninstallation_paths(dist: BaseDistribution) -> Iterator[str]:
https://packaging.python.org/specifications/recording-installed-packages/
"""
location = dist.location
assert location is not None, "not installed"
entries = dist.iter_declared_entries()
if entries is None:
try:
r = csv.reader(dist.get_metadata_lines("RECORD"))
except FileNotFoundError as missing_record_exception:
msg = "Cannot uninstall {dist}, RECORD file not found.".format(dist=dist)
installer = dist.installer
if not installer or installer == "pip":
dep = "{}=={}".format(dist.raw_name, dist.version)
try:
installer = next(dist.get_metadata_lines("INSTALLER"))
if not installer or installer == "pip":
raise ValueError()
except (OSError, StopIteration, ValueError):
dep = "{}=={}".format(dist.project_name, dist.version)
msg += (
" You might be able to recover from this via: "
"'pip install --force-reinstall --no-deps {}'.".format(dep)
)
else:
msg += " Hint: The package was installed by {}.".format(installer)
raise UninstallationError(msg)
for entry in entries:
path = os.path.join(location, entry)
raise UninstallationError(msg) from missing_record_exception
for row in r:
path = os.path.join(dist.location, row[0])
yield path
if path.endswith(".py"):
dn, fn = os.path.split(path)
@@ -302,11 +317,11 @@ class UninstallPathSet:
"""A set of file paths to be removed in the uninstallation of a
requirement."""
def __init__(self, dist: BaseDistribution) -> None:
self._paths: Set[str] = set()
def __init__(self, dist: Distribution) -> None:
self.paths: Set[str] = set()
self._refuse: Set[str] = set()
self._pth: Dict[str, UninstallPthEntries] = {}
self._dist = dist
self.pth: Dict[str, UninstallPthEntries] = {}
self.dist = dist
self._moved_paths = StashedUninstallPathSet()
def _permitted(self, path: str) -> bool:
@@ -327,7 +342,7 @@ class UninstallPathSet:
if not os.path.exists(path):
return
if self._permitted(path):
self._paths.add(path)
self.paths.add(path)
else:
self._refuse.add(path)
@@ -339,37 +354,37 @@ class UninstallPathSet:
def add_pth(self, pth_file: str, entry: str) -> None:
pth_file = normalize_path(pth_file)
if self._permitted(pth_file):
if pth_file not in self._pth:
self._pth[pth_file] = UninstallPthEntries(pth_file)
self._pth[pth_file].add(entry)
if pth_file not in self.pth:
self.pth[pth_file] = UninstallPthEntries(pth_file)
self.pth[pth_file].add(entry)
else:
self._refuse.add(pth_file)
def remove(self, auto_confirm: bool = False, verbose: bool = False) -> None:
"""Remove paths in ``self._paths`` with confirmation (unless
"""Remove paths in ``self.paths`` with confirmation (unless
``auto_confirm`` is True)."""
if not self._paths:
if not self.paths:
logger.info(
"Can't uninstall '%s'. No files were found to uninstall.",
self._dist.raw_name,
self.dist.project_name,
)
return
dist_name_version = f"{self._dist.raw_name}-{self._dist.version}"
dist_name_version = self.dist.project_name + "-" + self.dist.version
logger.info("Uninstalling %s:", dist_name_version)
with indent_log():
if auto_confirm or self._allowed_to_proceed(verbose):
moved = self._moved_paths
for_rename = compress_for_rename(self._paths)
for_rename = compress_for_rename(self.paths)
for path in sorted(compact(for_rename)):
moved.stash(path)
logger.verbose("Removing file or directory %s", path)
for pth in self._pth.values():
for pth in self.pth.values():
pth.remove()
logger.info("Successfully uninstalled %s", dist_name_version)
@@ -387,18 +402,18 @@ class UninstallPathSet:
logger.info(path)
if not verbose:
will_remove, will_skip = compress_for_output_listing(self._paths)
will_remove, will_skip = compress_for_output_listing(self.paths)
else:
# In verbose mode, display all the files that are going to be
# deleted.
will_remove = set(self._paths)
will_remove = set(self.paths)
will_skip = set()
_display("Would remove:", will_remove)
_display("Would not remove (might be manually added):", will_skip)
_display("Would not remove (outside of prefix):", self._refuse)
if verbose:
_display("Will actually move:", compress_for_rename(self._paths))
_display("Will actually move:", compress_for_rename(self.paths))
return ask("Proceed (Y/n)? ", ("y", "n", "")) != "n"
@@ -407,12 +422,12 @@ class UninstallPathSet:
if not self._moved_paths.can_rollback:
logger.error(
"Can't roll back %s; was not uninstalled",
self._dist.raw_name,
self.dist.project_name,
)
return
logger.info("Rolling back uninstall of %s", self._dist.raw_name)
logger.info("Rolling back uninstall of %s", self.dist.project_name)
self._moved_paths.rollback()
for pth in self._pth.values():
for pth in self.pth.values():
pth.rollback()
def commit(self) -> None:
@@ -420,156 +435,141 @@ class UninstallPathSet:
self._moved_paths.commit()
@classmethod
def from_dist(cls, dist: BaseDistribution) -> "UninstallPathSet":
dist_location = dist.location
info_location = dist.info_location
if dist_location is None:
logger.info(
"Not uninstalling %s since it is not installed",
dist.canonical_name,
)
return cls(dist)
normalized_dist_location = normalize_path(dist_location)
if not dist.local:
def from_dist(cls, dist: Distribution) -> "UninstallPathSet":
dist_path = normalize_path(dist.location)
if not dist_is_local(dist):
logger.info(
"Not uninstalling %s at %s, outside environment %s",
dist.canonical_name,
normalized_dist_location,
dist.key,
dist_path,
sys.prefix,
)
return cls(dist)
if normalized_dist_location in {
if dist_path in {
p
for p in {sysconfig.get_path("stdlib"), sysconfig.get_path("platstdlib")}
if p
}:
logger.info(
"Not uninstalling %s at %s, as it is in the standard library.",
dist.canonical_name,
normalized_dist_location,
dist.key,
dist_path,
)
return cls(dist)
paths_to_remove = cls(dist)
develop_egg_link = egg_link_path_from_location(dist.raw_name)
# Distribution is installed with metadata in a "flat" .egg-info
# directory. This means it is not a modern .dist-info installation, an
# egg, or legacy editable.
setuptools_flat_installation = (
dist.installed_with_setuptools_egg_info
and info_location is not None
and os.path.exists(info_location)
# If dist is editable and the location points to a ``.egg-info``,
# we are in fact in the legacy editable case.
and not info_location.endswith(f"{dist.setuptools_filename}.egg-info")
develop_egg_link = egg_link_path_from_location(dist.project_name)
develop_egg_link_egg_info = "{}.egg-info".format(
pkg_resources.to_filename(dist.project_name)
)
egg_info_exists = dist.egg_info and os.path.exists(dist.egg_info)
# Special case for distutils installed package
distutils_egg_info = getattr(dist._provider, "path", None)
# Uninstall cases order do matter as in the case of 2 installs of the
# same package, pip needs to uninstall the currently detected version
if setuptools_flat_installation:
if info_location is not None:
paths_to_remove.add(info_location)
installed_files = dist.iter_declared_entries()
if installed_files is not None:
for installed_file in installed_files:
paths_to_remove.add(os.path.join(dist_location, installed_file))
if (
egg_info_exists
and dist.egg_info.endswith(".egg-info")
and not dist.egg_info.endswith(develop_egg_link_egg_info)
):
# if dist.egg_info.endswith(develop_egg_link_egg_info), we
# are in fact in the develop_egg_link case
paths_to_remove.add(dist.egg_info)
if dist.has_metadata("installed-files.txt"):
for installed_file in dist.get_metadata(
"installed-files.txt"
).splitlines():
path = os.path.normpath(os.path.join(dist.egg_info, installed_file))
paths_to_remove.add(path)
# FIXME: need a test for this elif block
# occurs with --single-version-externally-managed/--record outside
# of pip
elif dist.is_file("top_level.txt"):
try:
namespace_packages = dist.read_text("namespace_packages.txt")
except FileNotFoundError:
namespaces = []
elif dist.has_metadata("top_level.txt"):
if dist.has_metadata("namespace_packages.txt"):
namespaces = dist.get_metadata("namespace_packages.txt")
else:
namespaces = namespace_packages.splitlines(keepends=False)
namespaces = []
for top_level_pkg in [
p
for p in dist.read_text("top_level.txt").splitlines()
for p in dist.get_metadata("top_level.txt").splitlines()
if p and p not in namespaces
]:
path = os.path.join(dist_location, top_level_pkg)
path = os.path.join(dist.location, top_level_pkg)
paths_to_remove.add(path)
paths_to_remove.add(f"{path}.py")
paths_to_remove.add(f"{path}.pyc")
paths_to_remove.add(f"{path}.pyo")
paths_to_remove.add(path + ".py")
paths_to_remove.add(path + ".pyc")
paths_to_remove.add(path + ".pyo")
elif dist.installed_by_distutils:
elif distutils_egg_info:
raise UninstallationError(
"Cannot uninstall {!r}. It is a distutils installed project "
"and thus we cannot accurately determine which files belong "
"to it which would lead to only a partial uninstall.".format(
dist.raw_name,
dist.project_name,
)
)
elif dist.installed_as_egg:
elif dist.location.endswith(".egg"):
# package installed by easy_install
# We cannot match on dist.egg_name because it can slightly vary
# i.e. setuptools-0.6c11-py2.6.egg vs setuptools-0.6rc11-py2.6.egg
paths_to_remove.add(dist_location)
easy_install_egg = os.path.split(dist_location)[1]
paths_to_remove.add(dist.location)
easy_install_egg = os.path.split(dist.location)[1]
easy_install_pth = os.path.join(
os.path.dirname(dist_location),
"easy-install.pth",
os.path.dirname(dist.location), "easy-install.pth"
)
paths_to_remove.add_pth(easy_install_pth, "./" + easy_install_egg)
elif dist.installed_with_dist_info:
elif egg_info_exists and dist.egg_info.endswith(".dist-info"):
for path in uninstallation_paths(dist):
paths_to_remove.add(path)
elif develop_egg_link:
# PEP 660 modern editable is handled in the ``.dist-info`` case
# above, so this only covers the setuptools-style editable.
# develop egg
with open(develop_egg_link) as fh:
link_pointer = os.path.normcase(fh.readline().strip())
assert link_pointer == dist_location, (
f"Egg-link {link_pointer} does not match installed location of "
f"{dist.raw_name} (at {dist_location})"
assert (
link_pointer == dist.location
), "Egg-link {} does not match installed location of {} (at {})".format(
link_pointer, dist.project_name, dist.location
)
paths_to_remove.add(develop_egg_link)
easy_install_pth = os.path.join(
os.path.dirname(develop_egg_link), "easy-install.pth"
)
paths_to_remove.add_pth(easy_install_pth, dist_location)
paths_to_remove.add_pth(easy_install_pth, dist.location)
else:
logger.debug(
"Not sure how to uninstall: %s - Check: %s",
dist,
dist_location,
dist.location,
)
if dist.in_usersite:
bin_dir = get_bin_user()
else:
bin_dir = get_bin_prefix()
# find distutils scripts= scripts
try:
for script in dist.iterdir("scripts"):
paths_to_remove.add(os.path.join(bin_dir, script.name))
if dist.has_metadata("scripts") and dist.metadata_isdir("scripts"):
for script in dist.metadata_listdir("scripts"):
if dist_in_usersite(dist):
bin_dir = get_bin_user()
else:
bin_dir = get_bin_prefix()
paths_to_remove.add(os.path.join(bin_dir, script))
if WINDOWS:
paths_to_remove.add(os.path.join(bin_dir, f"{script.name}.bat"))
except (FileNotFoundError, NotADirectoryError):
pass
paths_to_remove.add(os.path.join(bin_dir, script) + ".bat")
# find console_scripts and gui_scripts
def iter_scripts_to_remove(
dist: BaseDistribution,
bin_dir: str,
) -> Iterator[str]:
for entry_point in dist.iter_entry_points():
if entry_point.group == "console_scripts":
yield from _script_names(bin_dir, entry_point.name, False)
elif entry_point.group == "gui_scripts":
yield from _script_names(bin_dir, entry_point.name, True)
# find console_scripts
_scripts_to_remove = []
console_scripts = dist.get_entry_map(group="console_scripts")
for name in console_scripts.keys():
_scripts_to_remove.extend(_script_names(dist, name, False))
# find gui_scripts
gui_scripts = dist.get_entry_map(group="gui_scripts")
for name in gui_scripts.keys():
_scripts_to_remove.extend(_script_names(dist, name, True))
for s in iter_scripts_to_remove(dist, bin_dir):
for s in _scripts_to_remove:
paths_to_remove.add(s)
return paths_to_remove