subscription table shows more than one app

This commit is contained in:
2025-02-03 13:10:12 -05:00
parent ef5f57e678
commit d3d0806d5a
1841 changed files with 2390 additions and 3359 deletions

View File

@@ -15,24 +15,31 @@ __all__ = [
]
def _egg_link_name(raw_name: str) -> str:
def _egg_link_names(raw_name: str) -> List[str]:
"""
Convert a Name metadata value to a .egg-link name, by applying
the same substitution as pkg_resources's safe_name function.
Note: we cannot use canonicalize_name because it has a different logic.
We also look for the raw name (without normalization) as setuptools 69 changed
the way it names .egg-link files (https://github.com/pypa/setuptools/issues/4167).
"""
return re.sub("[^A-Za-z0-9.]+", "-", raw_name) + ".egg-link"
return [
re.sub("[^A-Za-z0-9.]+", "-", raw_name) + ".egg-link",
f"{raw_name}.egg-link",
]
def egg_link_path_from_sys_path(raw_name: str) -> Optional[str]:
"""
Look for a .egg-link file for project name, by walking sys.path.
"""
egg_link_name = _egg_link_name(raw_name)
egg_link_names = _egg_link_names(raw_name)
for path_item in sys.path:
egg_link = os.path.join(path_item, egg_link_name)
if os.path.isfile(egg_link):
return egg_link
for egg_link_name in egg_link_names:
egg_link = os.path.join(path_item, egg_link_name)
if os.path.isfile(egg_link):
return egg_link
return None
@@ -64,9 +71,10 @@ def egg_link_path_from_location(raw_name: str) -> Optional[str]:
sites.append(user_site)
sites.append(site_packages)
egg_link_name = _egg_link_name(raw_name)
egg_link_names = _egg_link_names(raw_name)
for site in sites:
egglink = os.path.join(site, egg_link_name)
if os.path.isfile(egglink):
return egglink
for egg_link_name in egg_link_names:
egglink = os.path.join(site, egg_link_name)
if os.path.isfile(egglink):
return egglink
return None

View File

@@ -1,35 +0,0 @@
"""A helper module that injects SecureTransport, on import.
The import should be done as early as possible, to ensure all requests and
sessions (or whatever) are created after injecting SecureTransport.
Note that we only do the injection on macOS, when the linked OpenSSL is too
old to handle TLSv1.2.
"""
import sys
def inject_securetransport() -> None:
# Only relevant on macOS
if sys.platform != "darwin":
return
try:
import ssl
except ImportError:
return
# Checks for OpenSSL 1.0.1
if ssl.OPENSSL_VERSION_NUMBER >= 0x1000100F:
return
try:
from pip._vendor.urllib3.contrib import securetransport
except (ImportError, OSError):
return
securetransport.inject_into_urllib3()
inject_securetransport()

View File

@@ -155,8 +155,8 @@ class RichPipStreamHandler(RichHandler):
# If we are given a diagnostic error to present, present it with indentation.
assert isinstance(record.args, tuple)
if record.msg == "[present-rich] %s" and len(record.args) == 1:
rich_renderable = record.args[0]
if getattr(record, "rich", False):
(rich_renderable,) = record.args
assert isinstance(
rich_renderable, (ConsoleRenderable, RichCast, str)
), f"{rich_renderable} is not rich-console-renderable"

View File

@@ -11,9 +11,11 @@ import stat
import sys
import sysconfig
import urllib.parse
from functools import partial
from io import StringIO
from itertools import filterfalse, tee, zip_longest
from types import TracebackType
from pathlib import Path
from types import FunctionType, TracebackType
from typing import (
Any,
BinaryIO,
@@ -33,6 +35,7 @@ from typing import (
cast,
)
from pip._vendor.packaging.requirements import Requirement
from pip._vendor.pyproject_hooks import BuildBackendHookCaller
from pip._vendor.tenacity import retry, stop_after_delay, wait_fixed
@@ -66,17 +69,15 @@ T = TypeVar("T")
ExcInfo = Tuple[Type[BaseException], BaseException, TracebackType]
VersionInfo = Tuple[int, int, int]
NetlocTuple = Tuple[str, Tuple[Optional[str], Optional[str]]]
OnExc = Callable[[FunctionType, Path, BaseException], Any]
OnErr = Callable[[FunctionType, Path, ExcInfo], Any]
def get_pip_version() -> str:
pip_pkg_dir = os.path.join(os.path.dirname(__file__), "..", "..")
pip_pkg_dir = os.path.abspath(pip_pkg_dir)
return "pip {} from {} (python {})".format(
__version__,
pip_pkg_dir,
get_major_minor_version(),
)
return f"pip {__version__} from {pip_pkg_dir} (python {get_major_minor_version()})"
def normalize_version_info(py_version_info: Tuple[int, ...]) -> Tuple[int, int, int]:
@@ -123,33 +124,75 @@ def get_prog() -> str:
# Retry every half second for up to 3 seconds
# Tenacity raises RetryError by default, explicitly raise the original exception
@retry(reraise=True, stop=stop_after_delay(3), wait=wait_fixed(0.5))
def rmtree(dir: str, ignore_errors: bool = False) -> None:
def rmtree(
dir: str,
ignore_errors: bool = False,
onexc: Optional[OnExc] = None,
) -> None:
if ignore_errors:
onexc = _onerror_ignore
if onexc is None:
onexc = _onerror_reraise
handler: OnErr = partial(
# `[func, path, Union[ExcInfo, BaseException]] -> Any` is equivalent to
# `Union[([func, path, ExcInfo] -> Any), ([func, path, BaseException] -> Any)]`.
cast(Union[OnExc, OnErr], rmtree_errorhandler),
onexc=onexc,
)
if sys.version_info >= (3, 12):
shutil.rmtree(dir, ignore_errors=ignore_errors, onexc=rmtree_errorhandler)
# See https://docs.python.org/3.12/whatsnew/3.12.html#shutil.
shutil.rmtree(dir, onexc=handler) # type: ignore
else:
shutil.rmtree(dir, ignore_errors=ignore_errors, onerror=rmtree_errorhandler)
shutil.rmtree(dir, onerror=handler) # type: ignore
def _onerror_ignore(*_args: Any) -> None:
pass
def _onerror_reraise(*_args: Any) -> None:
raise
def rmtree_errorhandler(
func: Callable[..., Any], path: str, exc_info: Union[ExcInfo, BaseException]
func: FunctionType,
path: Path,
exc_info: Union[ExcInfo, BaseException],
*,
onexc: OnExc = _onerror_reraise,
) -> None:
"""On Windows, the files in .svn are read-only, so when rmtree() tries to
remove them, an exception is thrown. We catch that here, remove the
read-only attribute, and hopefully continue without problems."""
"""
`rmtree` error handler to 'force' a file remove (i.e. like `rm -f`).
* If a file is readonly then it's write flag is set and operation is
retried.
* `onerror` is the original callback from `rmtree(... onerror=onerror)`
that is chained at the end if the "rm -f" still fails.
"""
try:
has_attr_readonly = not (os.stat(path).st_mode & stat.S_IWRITE)
st_mode = os.stat(path).st_mode
except OSError:
# it's equivalent to os.path.exists
return
if has_attr_readonly:
if not st_mode & stat.S_IWRITE:
# convert to read/write
os.chmod(path, stat.S_IWRITE)
# use the original function to repeat the operation
func(path)
return
else:
raise
try:
os.chmod(path, st_mode | stat.S_IWRITE)
except OSError:
pass
else:
# use the original function to repeat the operation
try:
func(path)
return
except OSError:
pass
if not isinstance(exc_info, BaseException):
_, exc_info, _ = exc_info
onexc(func, path, exc_info)
def display_path(path: str) -> str:
@@ -232,13 +275,13 @@ def strtobool(val: str) -> int:
def format_size(bytes: float) -> str:
if bytes > 1000 * 1000:
return "{:.1f} MB".format(bytes / 1000.0 / 1000)
return f"{bytes / 1000.0 / 1000:.1f} MB"
elif bytes > 10 * 1000:
return "{} kB".format(int(bytes / 1000))
return f"{int(bytes / 1000)} kB"
elif bytes > 1000:
return "{:.1f} kB".format(bytes / 1000.0)
return f"{bytes / 1000.0:.1f} kB"
else:
return "{} bytes".format(int(bytes))
return f"{int(bytes)} bytes"
def tabulate(rows: Iterable[Iterable[Any]]) -> Tuple[List[str], List[int]]:
@@ -475,9 +518,7 @@ def redact_netloc(netloc: str) -> str:
else:
user = urllib.parse.quote(user)
password = ":****"
return "{user}{password}@{netloc}".format(
user=user, password=password, netloc=netloc
)
return f"{user}{password}@{netloc}"
def _transform_url(
@@ -532,13 +573,20 @@ def redact_auth_from_url(url: str) -> str:
return _transform_url(url, _redact_netloc)[0]
def redact_auth_from_requirement(req: Requirement) -> str:
"""Replace the password in a given requirement url with ****."""
if not req.url:
return str(req)
return str(req).replace(req.url, redact_auth_from_url(req.url))
class HiddenText:
def __init__(self, secret: str, redacted: str) -> None:
self.secret = secret
self.redacted = redacted
def __repr__(self) -> str:
return "<HiddenText {!r}>".format(str(self))
return f"<HiddenText {str(self)!r}>"
def __str__(self) -> str:
return self.redacted

View File

@@ -209,7 +209,7 @@ def call_subprocess(
output_lines=all_output if not showing_subprocess else None,
)
if log_failed_cmd:
subprocess_logger.error("[present-rich] %s", error)
subprocess_logger.error("%s", error, extra={"rich": True})
subprocess_logger.verbose(
"[bold magenta]full command[/]: [blue]%s[/]",
escape(format_command_args(cmd)),

View File

@@ -3,8 +3,19 @@ import itertools
import logging
import os.path
import tempfile
import traceback
from contextlib import ExitStack, contextmanager
from typing import Any, Dict, Generator, Optional, TypeVar, Union
from pathlib import Path
from typing import (
Any,
Callable,
Dict,
Generator,
List,
Optional,
TypeVar,
Union,
)
from pip._internal.utils.misc import enum, rmtree
@@ -106,6 +117,7 @@ class TempDirectory:
delete: Union[bool, None, _Default] = _default,
kind: str = "temp",
globally_managed: bool = False,
ignore_cleanup_errors: bool = True,
):
super().__init__()
@@ -128,6 +140,7 @@ class TempDirectory:
self._deleted = False
self.delete = delete
self.kind = kind
self.ignore_cleanup_errors = ignore_cleanup_errors
if globally_managed:
assert _tempdir_manager is not None
@@ -170,7 +183,44 @@ class TempDirectory:
self._deleted = True
if not os.path.exists(self._path):
return
rmtree(self._path)
errors: List[BaseException] = []
def onerror(
func: Callable[..., Any],
path: Path,
exc_val: BaseException,
) -> None:
"""Log a warning for a `rmtree` error and continue"""
formatted_exc = "\n".join(
traceback.format_exception_only(type(exc_val), exc_val)
)
formatted_exc = formatted_exc.rstrip() # remove trailing new line
if func in (os.unlink, os.remove, os.rmdir):
logger.debug(
"Failed to remove a temporary file '%s' due to %s.\n",
path,
formatted_exc,
)
else:
logger.debug("%s failed with %s.", func.__qualname__, formatted_exc)
errors.append(exc_val)
if self.ignore_cleanup_errors:
try:
# first try with tenacity; retrying to handle ephemeral errors
rmtree(self._path, ignore_errors=False)
except OSError:
# last pass ignore/log all errors
rmtree(self._path, onexc=onerror)
if errors:
logger.warning(
"Failed to remove contents in a temporary directory '%s'.\n"
"You can safely remove it manually.",
self._path,
)
else:
rmtree(self._path)
class AdjacentTempDirectory(TempDirectory):

View File

@@ -28,7 +28,7 @@ def parse_wheel(wheel_zip: ZipFile, name: str) -> Tuple[str, Message]:
metadata = wheel_metadata(wheel_zip, info_dir)
version = wheel_version(metadata)
except UnsupportedWheel as e:
raise UnsupportedWheel("{} has an invalid wheel, {}".format(name, str(e)))
raise UnsupportedWheel(f"{name} has an invalid wheel, {str(e)}")
check_compatibility(version, name)
@@ -60,9 +60,7 @@ def wheel_dist_info_dir(source: ZipFile, name: str) -> str:
canonical_name = canonicalize_name(name)
if not info_dir_name.startswith(canonical_name):
raise UnsupportedWheel(
".dist-info directory {!r} does not start with {!r}".format(
info_dir, canonical_name
)
f".dist-info directory {info_dir!r} does not start with {canonical_name!r}"
)
return info_dir