You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					121 lines
				
				3.5 KiB
			
		
		
			
		
	
	
					121 lines
				
				3.5 KiB
			| 
								 
											3 years ago
										 
									 | 
							
								"""
							 | 
						||
| 
								 | 
							
								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  # NOTE: tests patch this name.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								DEPRECATION_MSG_PREFIX = "DEPRECATION: "
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class PipDeprecationWarning(Warning):
							 | 
						||
| 
								 | 
							
								    pass
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								_original_showwarning: Any = None
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								# Warnings <-> Logging Integration
							 | 
						||
| 
								 | 
							
								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):
							 | 
						||
| 
								 | 
							
								        # We use a specially named logger which will handle all of the
							 | 
						||
| 
								 | 
							
								        # deprecation messages for pip.
							 | 
						||
| 
								 | 
							
								        logger = logging.getLogger("pip._internal.deprecations")
							 | 
						||
| 
								 | 
							
								        logger.warning(message)
							 | 
						||
| 
								 | 
							
								    else:
							 | 
						||
| 
								 | 
							
								        _original_showwarning(message, category, filename, lineno, file, line)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def install_warning_logger() -> None:
							 | 
						||
| 
								 | 
							
								    # Enable our Deprecation Warnings
							 | 
						||
| 
								 | 
							
								    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.
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    # Determine whether or not the feature is already gone in this version.
							 | 
						||
| 
								 | 
							
								    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
							 | 
						||
| 
								 | 
							
								    )
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    # Raise as an error if this behaviour is deprecated.
							 | 
						||
| 
								 | 
							
								    if is_gone:
							 | 
						||
| 
								 | 
							
								        raise PipDeprecationWarning(message)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    warnings.warn(message, category=PipDeprecationWarning, stacklevel=2)
							 |