|
| 1 | +import datetime as dt |
1 | 2 | import json |
2 | 3 | import os |
| 4 | +import re |
| 5 | +from collections import defaultdict |
| 6 | + |
3 | 7 | from django.conf import settings |
4 | 8 | from django.http import HttpResponse, JsonResponse |
5 | 9 | from django.views.generic.base import RedirectView, TemplateView |
@@ -67,3 +71,113 @@ def get_redirect_url(self, *args, **kwargs): |
67 | 71 | settings.AWS_STORAGE_BUCKET_NAME, |
68 | 72 | image_path, |
69 | 73 | ]) |
| 74 | + |
| 75 | + |
| 76 | +class DocsByVersionView(TemplateView): |
| 77 | + template_name = "python/versions.html" |
| 78 | + |
| 79 | + def get_context_data(self, **kwargs): |
| 80 | + context = super().get_context_data(**kwargs) |
| 81 | + |
| 82 | + releases = Release.objects.filter( |
| 83 | + is_published=True, |
| 84 | + pre_release=False, |
| 85 | + ).order_by("-release_date") |
| 86 | + |
| 87 | + # Some releases have no documentation |
| 88 | + no_docs = {"2.3.6", "2.3.7", "2.4.5", "2.4.6", "2.5.5", "2.5.6"} |
| 89 | + |
| 90 | + # We'll group releases by major.minor version |
| 91 | + version_groups = defaultdict(list) |
| 92 | + |
| 93 | + for release in releases: |
| 94 | + # Extract version number from name ("Python 3.14.0" -> "3.14.0") |
| 95 | + version_match = re.match(r"Python ([\d.]+)", release.name) |
| 96 | + if version_match: |
| 97 | + full_version = version_match.group(1) |
| 98 | + |
| 99 | + if full_version in no_docs: |
| 100 | + continue |
| 101 | + |
| 102 | + # Get major.minor version ("3.14.0" -> "3.14") |
| 103 | + version_parts = full_version.split(".") |
| 104 | + major_minor = f"{version_parts[0]}.{version_parts[1]}" |
| 105 | + |
| 106 | + # For 3.2.0 and earlier, use X.Y instead of X.Y.0 |
| 107 | + if len(version_parts) == 3: |
| 108 | + major, minor, patch = map(int, version_parts) |
| 109 | + # For versions <= 3.2.0 where patch is 0 |
| 110 | + if (major, minor, patch) <= (3, 2, 0) and patch == 0: |
| 111 | + full_version = major_minor |
| 112 | + |
| 113 | + release_data = { |
| 114 | + "stage": full_version, |
| 115 | + "date": release.release_date.replace(tzinfo=None), |
| 116 | + } |
| 117 | + version_groups[major_minor].append(release_data) |
| 118 | + |
| 119 | + # Add legacy releases not in the database |
| 120 | + legacy_releases_data = { |
| 121 | + "2.2": [ |
| 122 | + {"stage": "2.2p1", "date": dt.datetime(2002, 3, 29)}, |
| 123 | + ], |
| 124 | + "2.1": [ |
| 125 | + {"stage": "2.1.2", "date": dt.datetime(2002, 1, 16)}, |
| 126 | + {"stage": "2.1.1", "date": dt.datetime(2001, 7, 20)}, |
| 127 | + {"stage": "2.1", "date": dt.datetime(2001, 4, 15)}, |
| 128 | + ], |
| 129 | + "2.0": [ |
| 130 | + {"stage": "2.0", "date": dt.datetime(2000, 10, 16)}, |
| 131 | + ], |
| 132 | + "1.6": [ |
| 133 | + {"stage": "1.6", "date": dt.datetime(2000, 9, 5)}, |
| 134 | + ], |
| 135 | + "1.5": [ |
| 136 | + {"stage": "1.5.2p2", "date": dt.datetime(2000, 3, 22)}, |
| 137 | + {"stage": "1.5.2p1", "date": dt.datetime(1999, 7, 6)}, |
| 138 | + {"stage": "1.5.2", "date": dt.datetime(1999, 4, 30)}, |
| 139 | + {"stage": "1.5.1p1", "date": dt.datetime(1998, 8, 6)}, |
| 140 | + {"stage": "1.5.1", "date": dt.datetime(1998, 4, 14)}, |
| 141 | + {"stage": "1.5", "date": dt.datetime(1998, 2, 17)}, |
| 142 | + ], |
| 143 | + "1.4": [ |
| 144 | + {"stage": "1.4", "date": dt.datetime(1996, 10, 25)}, |
| 145 | + ], |
| 146 | + } |
| 147 | + |
| 148 | + # Merge legacy releases in |
| 149 | + for version, items in legacy_releases_data.items(): |
| 150 | + version_groups[version].extend(items) |
| 151 | + |
| 152 | + # Convert to list for template and sort releases within each version |
| 153 | + version_list = [] |
| 154 | + for version, releases in version_groups.items(): |
| 155 | + # Sort x.y.z newest first |
| 156 | + releases = sorted( |
| 157 | + releases, |
| 158 | + key=lambda x: x.get("date", dt.datetime.min), |
| 159 | + reverse=True, |
| 160 | + ) |
| 161 | + for release in releases: |
| 162 | + release["date"] = release["date"].strftime("%-d %B %Y") |
| 163 | + |
| 164 | + version_list.append( |
| 165 | + { |
| 166 | + "version": version, |
| 167 | + "releases": releases, |
| 168 | + } |
| 169 | + ) |
| 170 | + |
| 171 | + # Sort x.y versions (newest first) |
| 172 | + version_list.sort( |
| 173 | + key=lambda x: [ |
| 174 | + int(n) if n.isdigit() else n for n in x["version"].split(".") |
| 175 | + ], |
| 176 | + reverse=True, |
| 177 | + ) |
| 178 | + |
| 179 | + context.update({ |
| 180 | + "version_list": version_list, |
| 181 | + }) |
| 182 | + |
| 183 | + return context |
0 commit comments