| """ |
| A module that implements tooling to enable easy warnings about deprecations. |
| """ |
|
|
| import logging |
| import warnings |
| from typing import Any, Optional, TextIO, Type, Union |
|
|
| from pip._vendor.packaging.version import parse |
|
|
| from pip import __version__ as current_version |
|
|
| DEPRECATION_MSG_PREFIX = "DEPRECATION: " |
|
|
|
|
| class PipDeprecationWarning(Warning): |
| pass |
|
|
|
|
| _original_showwarning: Any = None |
|
|
|
|
| |
| def _showwarning( |
| message: Union[Warning, str], |
| category: Type[Warning], |
| filename: str, |
| lineno: int, |
| file: Optional[TextIO] = None, |
| line: Optional[str] = None, |
| ) -> None: |
| if file is not None: |
| if _original_showwarning is not None: |
| _original_showwarning(message, category, filename, lineno, file, line) |
| elif issubclass(category, PipDeprecationWarning): |
| |
| |
| logger = logging.getLogger("pip._internal.deprecations") |
| logger.warning(message) |
| else: |
| _original_showwarning(message, category, filename, lineno, file, line) |
|
|
|
|
| def install_warning_logger() -> None: |
| |
| warnings.simplefilter("default", PipDeprecationWarning, append=True) |
|
|
| global _original_showwarning |
|
|
| if _original_showwarning is None: |
| _original_showwarning = warnings.showwarning |
| warnings.showwarning = _showwarning |
|
|
|
|
| def deprecated( |
| *, |
| reason: str, |
| replacement: Optional[str], |
| gone_in: Optional[str], |
| feature_flag: Optional[str] = None, |
| issue: Optional[int] = None, |
| ) -> None: |
| """Helper to deprecate existing functionality. |
| |
| reason: |
| Textual reason shown to the user about why this functionality has |
| been deprecated. Should be a complete sentence. |
| replacement: |
| Textual suggestion shown to the user about what alternative |
| functionality they can use. |
| gone_in: |
| The version of pip does this functionality should get removed in. |
| Raises an error if pip's current version is greater than or equal to |
| this. |
| feature_flag: |
| Command-line flag of the form --use-feature={feature_flag} for testing |
| upcoming functionality. |
| issue: |
| Issue number on the tracker that would serve as a useful place for |
| users to find related discussion and provide feedback. |
| """ |
|
|
| |
| is_gone = gone_in is not None and parse(current_version) >= parse(gone_in) |
|
|
| message_parts = [ |
| (reason, f"{DEPRECATION_MSG_PREFIX}{{}}"), |
| ( |
| gone_in, |
| ( |
| "pip {} will enforce this behaviour change." |
| if not is_gone |
| else "Since pip {}, this is no longer supported." |
| ), |
| ), |
| ( |
| replacement, |
| "A possible replacement is {}.", |
| ), |
| ( |
| feature_flag, |
| ( |
| "You can use the flag --use-feature={} to test the upcoming behaviour." |
| if not is_gone |
| else None |
| ), |
| ), |
| ( |
| issue, |
| "Discussion can be found at https://github.com/pypa/pip/issues/{}", |
| ), |
| ] |
|
|
| message = " ".join( |
| format_str.format(value) |
| for value, format_str in message_parts |
| if format_str is not None and value is not None |
| ) |
|
|
| |
| if is_gone: |
| raise PipDeprecationWarning(message) |
|
|
| warnings.warn(message, category=PipDeprecationWarning, stacklevel=2) |
|
|