Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 07454ed

Browse filesBrowse files
nedbatencukouhugovk
authored
"Status of Python versions" page: more details in charts, more descriptive text (#1531)
* Python version status: show when bugfix releases become security releases * Make them look all the same * Show EOL ones as red * Two graphs * Remove unacceptable newline * Join an unacceptably split line * Hide the starts of EOL versions * Special-case 2.7 * Remove 3.5 * Format * Put labels on top, if the mask doesn't work * simplify the svg paths * Add more explanation to the Python versions Status key * clarify what a feature fix is. * Update _tools/generate_release_cycle.py Co-authored-by: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> * Update _tools/generate_release_cycle.py Co-authored-by: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> * Update _tools/generate_release_cycle.py Co-authored-by: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> * Update _tools/generate_release_cycle.py Co-authored-by: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> * Update _tools/generate_release_cycle.py Co-authored-by: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> * 3.13 gets two years of bug fixes, earlier gets 1.5 years * last changes from the review * use a consistent anchor for the full chart * more tweaking of the phase descriptions * Use `height` consistently * Clean up the path code * Remove the "shade" rectangle, keep left+right+border or a single rect * Use the same radius everywhere * Rearrange comments/assignments * No mask for active branches * Restore bold red color * Update _tools/release_cycle_template.svg.jinja --------- Co-authored-by: Petr Viktorin <encukou@gmail.com> Co-authored-by: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com>
1 parent 85eda4a commit 07454ed
Copy full SHA for 07454ed

7 files changed

+280
-86
lines changed

‎.gitignore

Copy file name to clipboardExpand all lines: .gitignore
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,3 +91,4 @@ celerybeat-schedule
9191
include/branches.csv
9292
include/end-of-life.csv
9393
include/release-cycle.svg
94+
include/release-cycle-all.svg

‎Makefile

Copy file name to clipboardExpand all lines: Makefile
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ REQUIREMENTS = requirements.txt
2222
_ALL_SPHINX_OPTS = --jobs $(JOBS) $(SPHINXOPTS)
2323
_RELEASE_CYCLE = include/branches.csv \
2424
include/end-of-life.csv \
25+
include/release-cycle-all.svg \
2526
include/release-cycle.svg
2627

2728
.PHONY: help

‎_static/devguide_overrides.css

Copy file name to clipboardExpand all lines: _static/devguide_overrides.css
+39-17Lines changed: 39 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -48,35 +48,57 @@
4848
fill: white;
4949
}
5050

51-
.release-cycle-chart .release-cycle-blob-label.release-cycle-blob-security,
52-
.release-cycle-chart .release-cycle-blob-label.release-cycle-blob-bugfix {
51+
.release-cycle-chart .release-cycle-blob-label.release-cycle-status-security,
52+
.release-cycle-chart .release-cycle-blob-label.release-cycle-status-bugfix {
5353
/* but use black to improve contrast for lighter backgrounds */
5454
fill: black;
5555
}
5656

57-
.release-cycle-chart .release-cycle-blob.release-cycle-blob-end-of-life {
58-
fill: #DD2200;
59-
stroke: #FF8888;
57+
.release-cycle-chart .release-cycle-blob-label.release-cycle-status-end-of-life,
58+
.release-cycle-chart .release-cycle-blob-label.release-cycle-status-feature {
59+
/* and FG when it's not in a blob */
60+
fill: var(--color-foreground-primary);
61+
}
62+
63+
.release-cycle-chart .release-cycle-status-end-of-life {
64+
--status-bg-color: #DD2200;
65+
--status-border-color: #FF8888;
6066
}
6167

62-
.release-cycle-chart .release-cycle-blob.release-cycle-blob-security {
63-
fill: #FFDD44;
64-
stroke: #FF8800;
68+
.release-cycle-chart .release-cycle-status-security {
69+
--status-bg-color: #FFDD44;
70+
--status-border-color: #FF8800;
6571
}
6672

67-
.release-cycle-chart .release-cycle-blob.release-cycle-blob-bugfix {
68-
fill: #00DD22;
69-
stroke: #008844;
73+
.release-cycle-chart .release-cycle-status-bugfix {
74+
--status-bg-color: #00DD22;
75+
--status-border-color: #008844;
7076
}
7177

72-
.release-cycle-chart .release-cycle-blob.release-cycle-blob-prerelease {
73-
fill: teal;
74-
stroke: darkgreen;
78+
.release-cycle-chart .release-cycle-status-prerelease {
79+
--status-bg-color: teal;
80+
--status-border-color: darkgreen;
7581
}
7682

77-
.release-cycle-chart .release-cycle-blob.release-cycle-blob-feature {
78-
fill: #2222EE;
79-
stroke: #008888;
83+
.release-cycle-chart .release-cycle-status-feature {
84+
--status-bg-color: #2222EE;
85+
--status-border-color: #008888;
86+
}
87+
88+
.release-cycle-chart .release-cycle-blob {
89+
fill: var(--status-bg-color);
90+
stroke: transparent;
91+
}
92+
93+
.release-cycle-chart .release-cycle-blob-full {
94+
fill: var(--status-bg-color);
95+
stroke: var(--status-border-color);
96+
}
97+
98+
.release-cycle-chart .release-cycle-border {
99+
fill: transparent;
100+
stroke: var(--status-border-color);
101+
stroke-width: 1.6px;
80102
}
81103

82104
.good pre {

‎_tools/generate_release_cycle.py

Copy file name to clipboardExpand all lines: _tools/generate_release_cycle.py
+60-13Lines changed: 60 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -25,24 +25,64 @@ def parse_date(date_str: str) -> dt.date:
2525
return dt.date.fromisoformat(date_str)
2626

2727

28+
def parse_version(ver: str) -> list[int]:
29+
return [int(i) for i in ver["key"].split(".")]
30+
31+
2832
class Versions:
2933
"""For converting JSON to CSV and SVG."""
3034

31-
def __init__(self) -> None:
35+
def __init__(self, *, limit_to_active=False, special_py27=False) -> None:
3236
with open("include/release-cycle.json", encoding="UTF-8") as in_file:
3337
self.versions = json.load(in_file)
3438

3539
# Generate a few additional fields
3640
for key, version in self.versions.items():
3741
version["key"] = key
38-
version["first_release_date"] = parse_date(version["first_release"])
42+
ver_info = parse_version(version)
43+
if ver_info >= [3, 13]:
44+
full_years = 2
45+
else:
46+
full_years = 1.5
47+
version["first_release_date"] = r1 = parse_date(version["first_release"])
48+
version["start_security_date"] = r1 + dt.timedelta(days=full_years * 365)
3949
version["end_of_life_date"] = parse_date(version["end_of_life"])
50+
51+
self.cutoff = min(ver["first_release_date"] for ver in self.versions.values())
52+
53+
if limit_to_active:
54+
self.cutoff = min(
55+
version["first_release_date"]
56+
for version in self.versions.values()
57+
if version["status"] != "end-of-life"
58+
)
59+
self.versions = {
60+
key: version
61+
for key, version in self.versions.items()
62+
if version["end_of_life_date"] >= self.cutoff
63+
or (special_py27 and key == "2.7")
64+
}
65+
if special_py27:
66+
self.cutoff = min(self.cutoff, dt.date(2019, 8, 1))
67+
self.id_key = "active"
68+
else:
69+
self.id_key = "all"
70+
4071
self.sorted_versions = sorted(
4172
self.versions.values(),
42-
key=lambda v: [int(i) for i in v["key"].split(".")],
73+
key=parse_version,
4374
reverse=True,
4475
)
4576

77+
# Set the row (Y coordinate) for the chart, to allow a gap between 2.7
78+
# and the rest
79+
y = len(self.sorted_versions) + (1 if special_py27 else 0)
80+
for version in self.sorted_versions:
81+
if special_py27 and version["key"] == "2.7":
82+
y -= 1
83+
version["y"] = y
84+
y -= 1
85+
4686
def write_csv(self) -> None:
4787
"""Output CSV files."""
4888
now_str = str(dt.datetime.now(dt.timezone.utc))
@@ -68,7 +108,7 @@ def write_csv(self) -> None:
68108
csv_file.writeheader()
69109
csv_file.writerows(versions.values())
70110

71-
def write_svg(self, today: str) -> None:
111+
def write_svg(self, today: str, out_path: str) -> None:
72112
"""Output SVG file."""
73113
env = jinja2.Environment(
74114
loader=jinja2.FileSystemLoader("_tools/"),
@@ -85,6 +125,8 @@ def write_svg(self, today: str) -> None:
85125
# CSS.
86126
# (Ideally we'd actually use `em` units, but SVG viewBox doesn't take
87127
# those.)
128+
129+
# Uppercase sizes are un-scaled
88130
SCALE = 18
89131

90132
# Width of the drawing and main parts
@@ -96,7 +138,7 @@ def write_svg(self, today: str) -> None:
96138
# some positioning numbers in the template as well.
97139
LINE_HEIGHT = 1.5
98140

99-
first_date = min(ver["first_release_date"] for ver in self.sorted_versions)
141+
first_date = self.cutoff
100142
last_date = max(ver["end_of_life_date"] for ver in self.sorted_versions)
101143

102144
def date_to_x(date: dt.date) -> float:
@@ -105,7 +147,7 @@ def date_to_x(date: dt.date) -> float:
105147
total_days = (last_date - first_date).days
106148
ratio = num_days / total_days
107149
x = ratio * (DIAGRAM_WIDTH - LEGEND_WIDTH - RIGHT_MARGIN)
108-
return x + LEGEND_WIDTH
150+
return (x + LEGEND_WIDTH) * SCALE
109151

110152
def year_to_x(year: int) -> float:
111153
"""Convert year number to an SVG X coordinate of 1st January"""
@@ -115,20 +157,21 @@ def format_year(year: int) -> str:
115157
"""Format year number for display"""
116158
return f"'{year % 100:02}"
117159

118-
with open(
119-
"include/release-cycle.svg", "w", encoding="UTF-8", newline="\n"
120-
) as f:
160+
with open(out_path, "w", encoding="UTF-8", newline="\n") as f:
121161
template.stream(
122162
SCALE=SCALE,
123-
diagram_width=DIAGRAM_WIDTH,
124-
diagram_height=(len(self.sorted_versions) + 2) * LINE_HEIGHT,
163+
diagram_width=DIAGRAM_WIDTH * SCALE,
164+
diagram_height=(self.sorted_versions[0]["y"] + 2) * LINE_HEIGHT * SCALE,
125165
years=range(first_date.year, last_date.year + 1),
126-
LINE_HEIGHT=LINE_HEIGHT,
166+
line_height=LINE_HEIGHT * SCALE,
167+
legend_width=LEGEND_WIDTH * SCALE,
168+
right_margin=RIGHT_MARGIN * SCALE,
127169
versions=list(reversed(self.sorted_versions)),
128170
today=dt.datetime.strptime(today, "%Y-%m-%d").date(),
129171
year_to_x=year_to_x,
130172
date_to_x=date_to_x,
131173
format_year=format_year,
174+
id_key=self.id_key,
132175
).dump(f)
133176

134177

@@ -145,8 +188,12 @@ def main() -> None:
145188
args = parser.parse_args()
146189

147190
versions = Versions()
191+
assert len(versions.versions) > 10
148192
versions.write_csv()
149-
versions.write_svg(args.today)
193+
versions.write_svg(args.today, "include/release-cycle-all.svg")
194+
195+
versions = Versions(limit_to_active=True, special_py27=True)
196+
versions.write_svg(args.today, "include/release-cycle.svg")
150197

151198

152199
if __name__ == "__main__":

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.