subscription table shows more than one app
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -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
|
||||
|
@@ -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()
|
@@ -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"
|
||||
|
@@ -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
|
||||
|
@@ -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)),
|
||||
|
@@ -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):
|
||||
|
@@ -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
|
||||
|
Reference in New Issue
Block a user