diff --git a/news/10165.trivial.rst b/news/10165.trivial.rst new file mode 100644 index 00000000000..45d40200c5b --- /dev/null +++ b/news/10165.trivial.rst @@ -0,0 +1,4 @@ +Add a ``feature_flag`` optional kwarg to the ``deprecated()`` function +``pip._internal.utils.deprecation:deprecated``. Also formulate a corresponding canned +message which suggests using the ``--use-feature={feature_flag}`` to test upcoming +behavior. diff --git a/src/pip/_internal/utils/deprecation.py b/src/pip/_internal/utils/deprecation.py index 57dbdbdca4e..a163395c4e5 100644 --- a/src/pip/_internal/utils/deprecation.py +++ b/src/pip/_internal/utils/deprecation.py @@ -11,6 +11,15 @@ from pip import __version__ as current_version DEPRECATION_MSG_PREFIX = "DEPRECATION: " +DEPRECATION_MESSAGE = DEPRECATION_MSG_PREFIX + "{reason}" +GONE_IN_MESSAGE_FUTURE = "pip {gone_in} will enforce this behavior change." +GONE_IN_MESSAGE_PAST = "This behavior change has been enforced since pip {gone_in}." +REPLACEMENT_MESSAGE = "A possible replacement is {replacement}." +FEATURE_FLAG_MESSAGE = ( + "You can temporarily use the flag --use-feature={feature_flag} " + "to test the upcoming behavior." +) +ISSUE_MESSAGE = "Discussion can be found at https://github.com/pypa/pip/issues/{issue}." class PipDeprecationWarning(Warning): @@ -56,20 +65,24 @@ 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. + 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 errors if pip's current version is greater than or equal to + 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. @@ -77,28 +90,38 @@ def deprecated( Always pass replacement, gone_in and issue as keyword arguments for clarity at the call site. """ - + # 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) + # Allow variable substitutions within the "reason" variable. + formatted_reason = reason.format(gone_in=gone_in) # Construct a nice message. # This is eagerly formatted as we want it to get logged as if someone # typed this entire message out. + formatted_deprecation_message = DEPRECATION_MESSAGE.format(reason=formatted_reason) + gone_in_message = GONE_IN_MESSAGE_PAST if is_gone else GONE_IN_MESSAGE_FUTURE + formatted_gone_in_message = ( + gone_in_message.format(gone_in=gone_in) if gone_in else None + ) + formatted_replacement_message = ( + REPLACEMENT_MESSAGE.format(replacement=replacement) if replacement else None + ) + formatted_feature_flag_message = ( + None + if is_gone or not feature_flag + else FEATURE_FLAG_MESSAGE.format(feature_flag=feature_flag) + ) + formatted_issue_message = ISSUE_MESSAGE.format(issue=issue) if issue else None sentences = [ - (reason, DEPRECATION_MSG_PREFIX + "{}"), - (gone_in, "pip {} will remove support for this functionality."), - (replacement, "A possible replacement is {}."), - ( - issue, - ( - "You can find discussion regarding this at " - "https://github.com/pypa/pip/issues/{}." - ), - ), + formatted_deprecation_message, + formatted_gone_in_message, + formatted_replacement_message, + formatted_feature_flag_message, + formatted_issue_message, ] - message = " ".join( - template.format(val) for val, template in sentences if val is not None - ) + message = " ".join(sentence for sentence in sentences if sentence) - # Raise as an error if it has to be removed. - if gone_in is not None and parse(current_version) >= parse(gone_in): + # Raise as an error if the functionality is gone. + if is_gone: raise PipDeprecationWarning(message) - - warnings.warn(message, category=PipDeprecationWarning, stacklevel=2) + else: + warnings.warn(message, category=PipDeprecationWarning, stacklevel=2) diff --git a/tests/unit/test_utils.py b/tests/unit/test_utils.py index ebccd666011..4e5bba2e1e4 100644 --- a/tests/unit/test_utils.py +++ b/tests/unit/test_utils.py @@ -934,9 +934,9 @@ def test_deprecated_message_reads_well(): assert message == ( "DEPRECATION: Stop doing this! " - "pip 1.0 will remove support for this functionality. " + "This behavior change has been enforced since pip 1.0. " "A possible replacement is to be nicer. " - "You can find discussion regarding this at " + "Discussion can be found at " "https://github.com/pypa/pip/issues/100000." )