Skip to content

Commit 4adc1b3

Browse files
authored
Merge pull request #10229 from pradyunsg/deprecation-cleanups
Give some TLC to the `deprecated` helper
2 parents 9cb23c9 + 10c0f0d commit 4adc1b3

File tree

4 files changed

+83
-58
lines changed

4 files changed

+83
-58
lines changed

src/pip/_internal/locations/__init__.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -315,10 +315,12 @@ def get_scheme(
315315
)
316316
if any(default_old[k] != getattr(old, k) for k in SCHEME_KEYS):
317317
deprecated(
318-
"Configuring installation scheme with distutils config files "
319-
"is deprecated and will no longer work in the near future. If you "
320-
"are using a Homebrew or Linuxbrew Python, please see discussion "
321-
"at https://github.com/Homebrew/homebrew-core/issues/76621",
318+
reason=(
319+
"Configuring installation scheme with distutils config files "
320+
"is deprecated and will no longer work in the near future. If you "
321+
"are using a Homebrew or Linuxbrew Python, please see discussion "
322+
"at https://github.com/Homebrew/homebrew-core/issues/76621"
323+
),
322324
replacement=None,
323325
gone_in=None,
324326
)

src/pip/_internal/utils/deprecation.py

Lines changed: 35 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,9 @@
88

99
from pip._vendor.packaging.version import parse
1010

11-
from pip import __version__ as current_version
11+
from pip import __version__ as current_version # NOTE: tests patch this name.
1212

1313
DEPRECATION_MSG_PREFIX = "DEPRECATION: "
14-
DEPRECATION_MESSAGE = DEPRECATION_MSG_PREFIX + "{reason}"
15-
GONE_IN_MESSAGE_FUTURE = "pip {gone_in} will enforce this behavior change."
16-
GONE_IN_MESSAGE_PAST = "This behavior change has been enforced since pip {gone_in}."
17-
REPLACEMENT_MESSAGE = "A possible replacement is {replacement}."
18-
FEATURE_FLAG_MESSAGE = (
19-
"You can temporarily use the flag --use-feature={feature_flag} "
20-
"to test the upcoming behavior."
21-
)
22-
ISSUE_MESSAGE = "Discussion can be found at https://github.com/pypa/pip/issues/{issue}."
2314

2415

2516
class PipDeprecationWarning(Warning):
@@ -62,6 +53,7 @@ def install_warning_logger() -> None:
6253

6354

6455
def deprecated(
56+
*,
6557
reason: str,
6658
replacement: Optional[str],
6759
gone_in: Optional[str],
@@ -86,42 +78,43 @@ def deprecated(
8678
issue:
8779
Issue number on the tracker that would serve as a useful place for
8880
users to find related discussion and provide feedback.
89-
90-
Always pass replacement, gone_in and issue as keyword arguments for clarity
91-
at the call site.
9281
"""
82+
9383
# Determine whether or not the feature is already gone in this version.
9484
is_gone = gone_in is not None and parse(current_version) >= parse(gone_in)
95-
# Allow variable substitutions within the "reason" variable.
96-
formatted_reason = reason.format(gone_in=gone_in)
97-
# Construct a nice message.
98-
# This is eagerly formatted as we want it to get logged as if someone
99-
# typed this entire message out.
100-
formatted_deprecation_message = DEPRECATION_MESSAGE.format(reason=formatted_reason)
101-
gone_in_message = GONE_IN_MESSAGE_PAST if is_gone else GONE_IN_MESSAGE_FUTURE
102-
formatted_gone_in_message = (
103-
gone_in_message.format(gone_in=gone_in) if gone_in else None
104-
)
105-
formatted_replacement_message = (
106-
REPLACEMENT_MESSAGE.format(replacement=replacement) if replacement else None
107-
)
108-
formatted_feature_flag_message = (
109-
None
110-
if is_gone or not feature_flag
111-
else FEATURE_FLAG_MESSAGE.format(feature_flag=feature_flag)
112-
)
113-
formatted_issue_message = ISSUE_MESSAGE.format(issue=issue) if issue else None
114-
sentences = [
115-
formatted_deprecation_message,
116-
formatted_gone_in_message,
117-
formatted_replacement_message,
118-
formatted_feature_flag_message,
119-
formatted_issue_message,
85+
86+
message_parts = [
87+
(reason, f"{DEPRECATION_MSG_PREFIX}{{}}"),
88+
(
89+
gone_in,
90+
"pip {} will enforce this behaviour change."
91+
if not is_gone
92+
else "Since pip {}, this is no longer supported.",
93+
),
94+
(
95+
replacement,
96+
"A possible replacement is {}.",
97+
),
98+
(
99+
feature_flag,
100+
"You can use the flag --use-feature={} to test the upcoming behaviour."
101+
if not is_gone
102+
else None,
103+
),
104+
(
105+
issue,
106+
"Discussion can be found at https://github.com/pypa/pip/issues/{}",
107+
),
120108
]
121-
message = " ".join(sentence for sentence in sentences if sentence)
122109

123-
# Raise as an error if the functionality is gone.
110+
message = " ".join(
111+
format_str.format(value)
112+
for value, format_str in message_parts
113+
if format_str is not None and value is not None
114+
)
115+
116+
# Raise as an error if this behaviour is deprecated.
124117
if is_gone:
125118
raise PipDeprecationWarning(message)
126-
else:
127-
warnings.warn(message, category=PipDeprecationWarning, stacklevel=2)
119+
120+
warnings.warn(message, category=PipDeprecationWarning, stacklevel=2)

tests/functional/test_warning.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ def warnings_demo(tmpdir):
1414
deprecation.install_warning_logger()
1515
basicConfig()
1616
17-
deprecation.deprecated("deprecated!", replacement=None, gone_in=None)
17+
deprecation.deprecated(reason="deprecated!", replacement=None, gone_in=None)
1818
'''))
1919
return demo
2020

tests/unit/test_utils.py

Lines changed: 41 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -879,12 +879,16 @@ def patch_deprecation_check_version():
879879
@pytest.mark.parametrize("replacement", [None, "a magic 8 ball"])
880880
@pytest.mark.parametrize("gone_in", [None, "2.0"])
881881
@pytest.mark.parametrize("issue", [None, 988])
882-
def test_deprecated_message_contains_information(gone_in, replacement, issue):
882+
@pytest.mark.parametrize("feature_flag", [None, "magic-8-ball"])
883+
def test_deprecated_message_contains_information(
884+
gone_in, replacement, issue, feature_flag
885+
):
883886
with pytest.warns(PipDeprecationWarning) as record:
884887
deprecated(
885-
"Stop doing this!",
888+
reason="Stop doing this!",
886889
replacement=replacement,
887890
gone_in=gone_in,
891+
feature_flag=feature_flag,
888892
issue=issue,
889893
)
890894

@@ -893,51 +897,77 @@ def test_deprecated_message_contains_information(gone_in, replacement, issue):
893897

894898
assert "DEPRECATION: Stop doing this!" in message
895899
# Ensure non-None values are mentioned.
896-
for item in [gone_in, replacement, issue]:
900+
for item in [gone_in, replacement, issue, feature_flag]:
897901
if item is not None:
898902
assert str(item) in message
899903

900904

901905
@pytest.mark.usefixtures("patch_deprecation_check_version")
902906
@pytest.mark.parametrize("replacement", [None, "a magic 8 ball"])
903907
@pytest.mark.parametrize("issue", [None, 988])
904-
def test_deprecated_raises_error_if_too_old(replacement, issue):
908+
@pytest.mark.parametrize("feature_flag", [None, "magic-8-ball"])
909+
def test_deprecated_raises_error_if_too_old(replacement, issue, feature_flag):
905910
with pytest.raises(PipDeprecationWarning) as exception:
906911
deprecated(
907-
"Stop doing this!",
912+
reason="Stop doing this!",
908913
gone_in="1.0", # this matches the patched version.
909914
replacement=replacement,
915+
feature_flag=feature_flag,
910916
issue=issue,
911917
)
912918

913919
message = exception.value.args[0]
914920

915921
assert "DEPRECATION: Stop doing this!" in message
916922
assert "1.0" in message
923+
assert str(feature_flag) not in message
917924
# Ensure non-None values are mentioned.
918925
for item in [replacement, issue]:
919926
if item is not None:
920927
assert str(item) in message
921928

922929

923930
@pytest.mark.usefixtures("patch_deprecation_check_version")
924-
def test_deprecated_message_reads_well():
931+
def test_deprecated_message_reads_well_past():
925932
with pytest.raises(PipDeprecationWarning) as exception:
926933
deprecated(
927-
"Stop doing this!",
934+
reason="Stop doing this!",
928935
gone_in="1.0", # this matches the patched version.
929936
replacement="to be nicer",
930-
issue="100000", # I hope we never reach this number.
937+
feature_flag="magic-8-ball",
938+
issue="100000",
931939
)
932940

933941
message = exception.value.args[0]
934942

935943
assert message == (
936944
"DEPRECATION: Stop doing this! "
937-
"This behavior change has been enforced since pip 1.0. "
945+
"Since pip 1.0, this is no longer supported. "
946+
"A possible replacement is to be nicer. "
947+
"Discussion can be found at https://github.com/pypa/pip/issues/100000"
948+
)
949+
950+
951+
@pytest.mark.usefixtures("patch_deprecation_check_version")
952+
def test_deprecated_message_reads_well_future():
953+
with pytest.warns(PipDeprecationWarning) as record:
954+
deprecated(
955+
reason="Stop doing this!",
956+
gone_in="2.0", # this is greater than the patched version.
957+
replacement="to be nicer",
958+
feature_flag="crisis",
959+
issue="100000",
960+
)
961+
962+
assert len(record) == 1
963+
message = record[0].message.args[0]
964+
965+
assert message == (
966+
"DEPRECATION: Stop doing this! "
967+
"pip 2.0 will enforce this behaviour change. "
938968
"A possible replacement is to be nicer. "
939-
"Discussion can be found at "
940-
"https://github.com/pypa/pip/issues/100000."
969+
"You can use the flag --use-feature=crisis to test the upcoming behaviour. "
970+
"Discussion can be found at https://github.com/pypa/pip/issues/100000"
941971
)
942972

943973

0 commit comments

Comments
 (0)