Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions pydotorg/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
path('getit/', include('downloads.urls', namespace='getit')),
path('downloads/', include('downloads.urls', namespace='download')),
path('doc/', views.DocumentationIndexView.as_view(), name='documentation'),
path('doc/versions2/', views.DocsByVersionView.as_view(), name='docs-versions'),
path('blogs/', include('blogs.urls')),
path('inner/', TemplateView.as_view(template_name="python/inner.html"), name='inner'),

Expand Down
114 changes: 114 additions & 0 deletions pydotorg/views.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import datetime as dt
import json
import os
import re
from collections import defaultdict

from django.conf import settings
from django.http import HttpResponse, JsonResponse
from django.views.generic.base import RedirectView, TemplateView
Expand Down Expand Up @@ -67,3 +71,113 @@ def get_redirect_url(self, *args, **kwargs):
settings.AWS_STORAGE_BUCKET_NAME,
image_path,
])


class DocsByVersionView(TemplateView):
template_name = "python/versions.html"

def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)

releases = Release.objects.filter(
is_published=True,
pre_release=False,
).order_by("-release_date")

# Some releases have no documentation
no_docs = {"2.3.6", "2.3.7", "2.4.5", "2.4.6", "2.5.5", "2.5.6"}

# We'll group releases by major.minor version
version_groups = defaultdict(list)

for release in releases:
# Extract version number from name ("Python 3.14.0" -> "3.14.0")
version_match = re.match(r"Python ([\d.]+)", release.name)
if version_match:
full_version = version_match.group(1)

if full_version in no_docs:
continue

# Get major.minor version ("3.14.0" -> "3.14")
version_parts = full_version.split(".")
major_minor = f"{version_parts[0]}.{version_parts[1]}"

# For 3.2.0 and earlier, use X.Y instead of X.Y.0
if len(version_parts) == 3:
major, minor, patch = map(int, version_parts)
# For versions <= 3.2.0 where patch is 0
if (major, minor, patch) <= (3, 2, 0) and patch == 0:
full_version = major_minor

release_data = {
"stage": full_version,
"date": release.release_date.replace(tzinfo=None),
}
version_groups[major_minor].append(release_data)

# Add legacy releases not in the database
legacy_releases_data = {
"2.2": [
{"stage": "2.2p1", "date": dt.datetime(2002, 3, 29)},
],
"2.1": [
{"stage": "2.1.2", "date": dt.datetime(2002, 1, 16)},
{"stage": "2.1.1", "date": dt.datetime(2001, 7, 20)},
{"stage": "2.1", "date": dt.datetime(2001, 4, 15)},
],
"2.0": [
{"stage": "2.0", "date": dt.datetime(2000, 10, 16)},
],
"1.6": [
{"stage": "1.6", "date": dt.datetime(2000, 9, 5)},
],
"1.5": [
{"stage": "1.5.2p2", "date": dt.datetime(2000, 3, 22)},
{"stage": "1.5.2p1", "date": dt.datetime(1999, 7, 6)},
{"stage": "1.5.2", "date": dt.datetime(1999, 4, 30)},
{"stage": "1.5.1p1", "date": dt.datetime(1998, 8, 6)},
{"stage": "1.5.1", "date": dt.datetime(1998, 4, 14)},
{"stage": "1.5", "date": dt.datetime(1998, 2, 17)},
],
"1.4": [
{"stage": "1.4", "date": dt.datetime(1996, 10, 25)},
],
}

# Merge legacy releases in
for version, items in legacy_releases_data.items():
version_groups[version].extend(items)

# Convert to list for template and sort releases within each version
version_list = []
for version, releases in version_groups.items():
# Sort x.y.z newest first
releases = sorted(
releases,
key=lambda x: x.get("date", dt.datetime.min),
reverse=True,
)
for release in releases:
release["date"] = release["date"].strftime("%-d %B %Y")

version_list.append(
{
"version": version,
"releases": releases,
}
)

# Sort x.y versions (newest first)
version_list.sort(
key=lambda x: [
int(n) if n.isdigit() else n for n in x["version"].split(".")
],
reverse=True,
)

context.update({
"version_list": version_list,
})

return context
58 changes: 58 additions & 0 deletions templates/python/versions.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
{% extends "base.html" %}
{% load boxes %}
{% load sitetree %}

{% block page_title %}Python documentation by version | {{ SITE_INFO.site_name }}{% endblock %}

{% block body_attributes %}class="python pages default-page"{% endblock %}

{% block breadcrumbs %}
{% sitetree_breadcrumbs from "main" %}
{% endblock breadcrumbs %}

{% block content_attributes %}with-left-sidebar{% endblock %}

{% block content %}
<article class="text">
<header class="article-header">
<h1 class="page-title">Python documentation by version</h1>
</header>

<p>Some previous versions of the documentation remain available online. Use the list below to select a version to view.</p>

<p>For unreleased (in development) documentation, see <a href="#in-development-versions">In development versions</a>.</p>

<h2>Release versions</h2>

{% for version_data in version_list %}
<h3>Python {{ version_data.version }}</h3>
<ul>
{% for release in version_data.releases %}
<li>
{% if release.stage %}
<a href="https://docs.python.org/release/{{ release.stage|cut:" " }}/">Python {{ release.stage }}</a>{% if release.date %}, released on {{ release.date }}{% endif %}
{% endif %}
</li>
{% endfor %}
</ul>
{% endfor %}

<h2 id="in-development-versions">In development versions</h2>
<p>The latest, and unreleased, documentation for versions of Python still under development:</p>
<ul>
<li><a href="https://docs.python.org/dev/">Development version</a></li>
<li><a href="https://docs.python.org/3/">Python 3.x</a></li>
</ul>

</article>
{% endblock content %}

{% block left_sidebar %}
<aside class="left-sidebar" role="secondary">
{% include "components/navigation-widget.html" %}

<div class="psf-sidebar-widget sidebar-widget">
{% box 'widget-sidebar-aboutpsf' %}
</div>
</aside>
{% endblock left_sidebar %}