Skip to content

Commit e3dd09f

Browse files
committed
✨ Enhance changelog handling in route configuration and update tests for deprecation logic
1 parent 97b69ef commit e3dd09f

File tree

2 files changed

+167
-105
lines changed

2 files changed

+167
-105
lines changed
Lines changed: 59 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
1+
from contextlib import suppress
12
from typing import Any, Final
23

4+
from packaging.version import Version
5+
6+
from ..._meta import API_VERSION
7+
38
#
49
# CHANGELOG formatted-messages for API routes
510
#
@@ -15,40 +20,42 @@
1520
# changes in given version with message
1621
FMSG_CHANGELOG_CHANGED_IN_VERSION: Final[str] = "Changed in *version {}*: {}\n"
1722

18-
# marked as deprecated and will be removed in given version
19-
FMSG_CHANGELOG_REMOVED_IN_VERSION: Final[str] = "Removed in *version {}*: {}\n"
20-
21-
FMSG_CHANGELOG_DEPRECATED: Final[str] = (
23+
# marked as deprecated
24+
FMSG_CHANGELOG_DEPRECATED_IN_VERSION: Final[str] = (
2225
"🚨 **Deprecated**: This endpoint is deprecated and will be removed in a future release.\n"
2326
"Please use `{}` instead.\n\n"
2427
)
2528

29+
# marked as deprecated and will be removed in given version
30+
FMSG_CHANGELOG_REMOVED_IN_VERSION: Final[str] = "Removed in *version {}*: {}\n"
31+
32+
2633
DEFAULT_MAX_STRING_LENGTH: Final[int] = 500
2734

2835

2936
def create_route_description(
3037
*,
3138
base: str = "",
32-
deprecated: bool = False,
33-
alternative: str | None = None, # alternative route to use
3439
changelog: list[str] | None = None,
40+
deprecated_in: str | None = None,
41+
alternative: str | None = None,
3542
) -> str:
3643
"""
3744
Builds a consistent route description with optional deprecation and changelog information.
3845
3946
Args:
4047
base (str): Main route description.
41-
deprecated (tuple): (retirement_date, alternative_route) if deprecated.
42-
changelog (List[str]): List of formatted changelog strings.
48+
changelog (list[str]): List of formatted changelog strings.
49+
deprecated_in (str, optional): Version when this endpoint was deprecated.
50+
alternative (str, optional): Alternative route to use if deprecated.
4351
4452
Returns:
4553
str: Final description string.
4654
"""
4755
parts = []
4856

49-
if deprecated:
50-
assert alternative, "If deprecated, alternative must be provided" # nosec
51-
parts.append(FMSG_CHANGELOG_DEPRECATED.format(alternative))
57+
if deprecated_in and alternative:
58+
parts.append(FMSG_CHANGELOG_DEPRECATED_IN_VERSION.format(alternative))
5259

5360
if base:
5461
parts.append(base)
@@ -62,63 +69,63 @@ def create_route_description(
6269
def create_route_config(
6370
base_description: str = "",
6471
*,
65-
to_be_released_in: str | None = None,
66-
to_be_removed_in: str | None = None,
67-
alternative: str | None = None,
6872
changelog: list[str] | None = None,
6973
) -> dict[str, Any]:
7074
"""
71-
Creates route configuration options including description.
75+
Creates route configuration options including description based on changelog history.
76+
77+
The function analyzes the changelog to determine if the endpoint:
78+
- Is not yet released (if the earliest entry is in a future version)
79+
- Is deprecated (if there's a removal notice in the changelog)
7280
7381
Args:
7482
base_description: Main route description
75-
to_be_released_in: Version where this route will be released (for upcoming features)
76-
to_be_removed_in: Version where this route will be removed (for deprecated endpoints)
77-
alternative: Alternative route to use (required if to_be_removed_in is provided)
78-
changelog: List of formatted changelog strings
83+
changelog: List of formatted changelog strings indicating version history
7984
8085
Returns:
8186
dict: Route configuration options that can be used as kwargs for route decorators
8287
"""
8388
route_options: dict[str, Any] = {}
84-
85-
# Build changelog
86-
if changelog is None:
87-
changelog = []
88-
89-
if to_be_released_in:
90-
# Add version information to the changelog if not already there
91-
version_note = FMSG_CHANGELOG_NEW_IN_VERSION.format(to_be_released_in)
92-
if not any(version_note in item for item in changelog):
93-
changelog.append(version_note)
94-
# Hide from schema until released
95-
route_options["include_in_schema"] = False
96-
97-
if to_be_removed_in:
98-
# Require an alternative route if this endpoint will be removed
99-
assert ( # nosec
100-
alternative
101-
), "If to_be_removed_in is provided, alternative must be provided" # nosec
102-
103-
# Add removal notice to the changelog if not already there
104-
removal_message = (
105-
"This endpoint is deprecated and will be removed in a future version"
106-
)
107-
removal_note = FMSG_CHANGELOG_REMOVED_IN_VERSION.format(
108-
to_be_removed_in, removal_message
109-
)
110-
if not any(removal_note in item for item in changelog):
111-
changelog.append(removal_note)
112-
113-
# Mark as deprecated
114-
route_options["deprecated"] = True
89+
changelog = changelog or []
90+
91+
# Parse changelog to determine endpoint state
92+
is_deprecated = False
93+
alternative = None
94+
is_released = False
95+
current_version = Version(API_VERSION)
96+
97+
for entry in changelog:
98+
# Check for deprecation/removal entries
99+
if FMSG_CHANGELOG_DEPRECATED_IN_VERSION.split("{")[0] in entry:
100+
is_deprecated = True
101+
# Extract alternative from deprecation message if possible
102+
with suppress(IndexError, AttributeError):
103+
alternative = entry.split("Please use `")[1].split("`")[0]
104+
105+
# Check for new version entries to determine if this is unreleased
106+
elif FMSG_CHANGELOG_NEW_IN_VERSION.split("{")[0] in entry:
107+
try:
108+
version_str = entry.split("New in *version ")[1].split("*")[0]
109+
entry_version = Version(version_str)
110+
# If the first/earliest entry version is greater than current API version,
111+
# this endpoint is not yet released
112+
if current_version < entry_version:
113+
is_released = True
114+
except (IndexError, ValueError, AttributeError):
115+
pass
116+
117+
# Set route options based on endpoint state
118+
route_options["include_in_schema"] = is_released
119+
route_options["deprecated"] = is_deprecated
115120

116121
# Create description
117122
route_options["description"] = create_route_description(
118123
base=base_description,
119-
deprecated=bool(to_be_removed_in),
120-
alternative=alternative,
121124
changelog=changelog,
125+
deprecated_in=(
126+
"Unknown" if is_deprecated else None
127+
), # We don't extract exact version
128+
alternative=alternative,
122129
)
123130

124131
return route_options

0 commit comments

Comments
 (0)