|
7 | 7 | import getpass
|
8 | 8 | import hashlib
|
9 | 9 | import io
|
10 |
| -import locale |
11 |
| -import logging |
12 | 10 | import os
|
13 | 11 | import posixpath
|
14 | 12 | import shutil
|
|
41 | 39 | from pip._vendor.tenacity import retry, stop_after_delay, wait_fixed
|
42 | 40 |
|
43 | 41 | from pip import __version__
|
44 |
| -from pip._internal.exceptions import CommandError |
| 42 | +from pip._internal.exceptions import CommandError, ExternallyManagedEnvironment |
45 | 43 | from pip._internal.locations import get_major_minor_version
|
| 44 | +from pip._internal.utils._log import VERBOSE, getLogger |
46 | 45 | from pip._internal.utils.compat import WINDOWS
|
47 | 46 | from pip._internal.utils.virtualenv import running_under_virtualenv
|
48 | 47 |
|
|
60 | 59 | "captured_stdout",
|
61 | 60 | "ensure_dir",
|
62 | 61 | "remove_auth_from_url",
|
63 |
| - "get_externally_managed_error", |
| 62 | + "check_externally_managed", |
64 | 63 | "ConfiguredBuildBackendHookCaller",
|
65 | 64 | ]
|
66 | 65 |
|
67 | 66 |
|
68 |
| -logger = logging.getLogger(__name__) |
| 67 | +logger = getLogger(__name__) |
69 | 68 |
|
70 | 69 | T = TypeVar("T")
|
71 | 70 | ExcInfo = Tuple[Type[BaseException], BaseException, TracebackType]
|
@@ -585,56 +584,25 @@ def protect_pip_from_modification_on_windows(modifying_pip: bool) -> None:
|
585 | 584 | )
|
586 | 585 |
|
587 | 586 |
|
588 |
| -_DEFAULT_EXTERNALLY_MANAGED_ERROR = f"""\ |
589 |
| -The Python environment under {sys.prefix} is managed externally, and may not be |
590 |
| -manipulated by the user. Please use specific tooling from the distributor of |
591 |
| -the Python installation to interact with this environment instead. |
592 |
| -""" |
| 587 | +def check_externally_managed() -> None: |
| 588 | + """Check whether the current environment is externally managed. |
593 | 589 |
|
594 |
| - |
595 |
| -def _iter_externally_managed_error_keys() -> Iterator[str]: |
596 |
| - lang, _ = locale.getlocale(locale.LC_MESSAGES) |
597 |
| - if lang is not None: |
598 |
| - yield f"Error-{lang}" |
599 |
| - for sep in ("-", "_"): |
600 |
| - before, found, _ = lang.partition(sep) |
601 |
| - if not found: |
602 |
| - continue |
603 |
| - yield f"Error-{before}" |
604 |
| - yield "Error" |
605 |
| - |
606 |
| - |
607 |
| -def get_externally_managed_error() -> Optional[str]: |
608 |
| - """Get an error message from the EXTERNALLY-MANAGED config file. |
609 |
| -
|
610 |
| - This checks whether the current environment pip is running in is externally |
611 |
| - managed. If the EXTERNALLY-MANAGED file is found, the vendor-provided error |
612 |
| - message is read and returned (if available; a default message is used |
613 |
| - otherwise), as specified in `PEP 668`_. |
614 |
| -
|
615 |
| - If the current environment is *not* externally managed, *None* is returned. |
616 |
| -
|
617 |
| - .. _`PEP 668`: https://peps.python.org/pep-0668/ |
| 590 | + If the ``EXTERNALLY-MANAGED`` config file is found, the current environment |
| 591 | + is considered externally managed, and an ExternallyManagedEnvironment is |
| 592 | + raised. |
618 | 593 | """
|
619 | 594 | if running_under_virtualenv():
|
620 | 595 | return None
|
621 | 596 | marker = os.path.join(sysconfig.get_path("stdlib"), "EXTERNALLY-MANAGED")
|
622 | 597 | if not os.path.isfile(marker):
|
623 |
| - return None |
| 598 | + return |
| 599 | + parser = configparser.ConfigParser(interpolation=None) |
624 | 600 | try:
|
625 |
| - parser = configparser.ConfigParser(interpolation=None) |
626 | 601 | parser.read(marker, encoding="utf-8")
|
627 |
| - except (OSError, UnicodeDecodeError) as e: |
628 |
| - logger.warning("Ignoring %s due to error %s", marker, e) |
629 |
| - return _DEFAULT_EXTERNALLY_MANAGED_ERROR |
630 |
| - try: |
631 |
| - section = parser["externally-managed"] |
632 |
| - except KeyError: |
633 |
| - return _DEFAULT_EXTERNALLY_MANAGED_ERROR |
634 |
| - for key in _iter_externally_managed_error_keys(): |
635 |
| - with contextlib.suppress(KeyError): |
636 |
| - return section[key] |
637 |
| - return _DEFAULT_EXTERNALLY_MANAGED_ERROR |
| 602 | + except (OSError, UnicodeDecodeError): |
| 603 | + exc_info = logger.isEnabledFor(VERBOSE) |
| 604 | + logger.warning("Failed to read %s", marker, exc_info=exc_info) |
| 605 | + raise ExternallyManagedEnvironment.from_config(parser) |
638 | 606 |
|
639 | 607 |
|
640 | 608 | def is_console_interactive() -> bool:
|
|
0 commit comments