Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 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
6 changes: 6 additions & 0 deletions downloads/managers.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ def latest_python3(self, minor_version: int | None = None):
pattern = rf"^Python 3\.{minor_version}\."
return self.python3().filter(name__regex=pattern).order_by("-release_date")

def latest_prerelease(self):
return self.python3().filter(pre_release=True).order_by("-release_date")

def latest_pymanager(self):
return self.pymanager().filter(is_latest=True)

Expand All @@ -52,5 +55,8 @@ def latest_python2(self):
def latest_python3(self, minor_version: int | None = None):
return self.get_queryset().latest_python3(minor_version).first()

def latest_prerelease(self):
return self.get_queryset().latest_prerelease().first()

def latest_pymanager(self):
return self.get_queryset().latest_pymanager().first()
1 change: 1 addition & 0 deletions downloads/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,7 @@ def purge_fastly_download_pages(sender, instance, **kwargs):
match = re.match(r'^3\.(\d+)', version)
if match:
purge_url(f'/downloads/latest/python3.{match.group(1)}/')
purge_url('/downloads/latest/prerelease/')
purge_url('/downloads/latest/pymanager/')
purge_url('/downloads/macos/')
purge_url('/downloads/source/')
Expand Down
40 changes: 40 additions & 0 deletions downloads/tests/test_models.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import datetime as dt

from ..models import Release, ReleaseFile
from .base import BaseDownloadTests

Expand Down Expand Up @@ -56,6 +58,44 @@ def test_python3(self):
self.assertIn(self.hidden_release, versions)
self.assertIn(self.pre_release, versions)

def test_latest_python3(self):
latest_3 = Release.objects.latest_python3()
self.assertEqual(latest_3, self.python_3)
self.assertNotEqual(latest_3, self.python_3_10_18)

latest_3_10 = Release.objects.latest_python3(minor_version=10)
self.assertEqual(latest_3_10, self.python_3)
self.assertNotEqual(latest_3_10, self.python_3_10_18)

latest_3_8 = Release.objects.latest_python3(minor_version=8)
self.assertEqual(latest_3_8, self.python_3_8_20)
self.assertNotEqual(latest_3_8, self.python_3_8_19)

latest_3_99 = Release.objects.latest_python3(minor_version=99)
self.assertIsNone(latest_3_99)

def test_latest_prerelease(self):
latest_prerelease = Release.objects.latest_prerelease()
self.assertEqual(latest_prerelease, self.pre_release)

# Create a newer prerelease with a future date
newer_prerelease = Release.objects.create(
version=Release.PYTHON3,
name="Python 3.9.99",
is_published=True,
pre_release=True,
release_date=self.pre_release.release_date + dt.timedelta(days=1),
)
latest_prerelease = Release.objects.latest_prerelease()
self.assertEqual(latest_prerelease, newer_prerelease)
self.assertNotEqual(latest_prerelease, self.pre_release)

def test_latest_prerelease_when_no_prerelease(self):
# Delete the prerelease
self.pre_release.delete()
latest_prerelease = Release.objects.latest_prerelease()
self.assertIsNone(latest_prerelease)

def test_get_version(self):
self.assertEqual(self.release_275.name, 'Python 2.7.5')
self.assertEqual(self.release_275.get_version(), '2.7.5')
Expand Down
25 changes: 25 additions & 0 deletions downloads/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,31 @@ def test_latest_redirects(self):
response = self.client.get(url)
self.assertRedirects(response, latest_python3.get_absolute_url())

def test_latest_python3x_redirects(self):
url = reverse("download:download_latest_python3x", kwargs={"minor": "10"})
response = self.client.get(url)
self.assertRedirects(response, self.python_3.get_absolute_url())

url = reverse("download:download_latest_python3x", kwargs={"minor": "8"})
response = self.client.get(url)
self.assertRedirects(response, self.python_3_8_20.get_absolute_url())

url = reverse("download:download_latest_python3x", kwargs={"minor": "99"})
response = self.client.get(url)
self.assertRedirects(response, reverse("download:download"))

def test_latest_prerelease_redirect(self):
url = reverse("download:download_latest_prerelease")
response = self.client.get(url)
self.assertRedirects(response, self.pre_release.get_absolute_url())

def test_latest_prerelease_redirect_when_no_prerelease(self):
# Delete the prerelease to test fallback
self.pre_release.delete()
url = reverse("download:download_latest_prerelease")
response = self.client.get(url)
self.assertRedirects(response, reverse("download:download"))

def test_redirect_page_object_to_release_detail_page(self):
self.release_275.release_page = None
self.release_275.save()
Expand Down
1 change: 1 addition & 0 deletions downloads/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
re_path(r'latest/python2/?$', views.DownloadLatestPython2.as_view(), name='download_latest_python2'),
re_path(r'latest/python3/?$', views.DownloadLatestPython3.as_view(), name='download_latest_python3'),
re_path(r'latest/python3\.(?P<minor>\d+)/?$', views.DownloadLatestPython3x.as_view(), name='download_latest_python3x'),
re_path(r'latest/prerelease/?$', views.DownloadLatestPrerelease.as_view(), name='download_latest_prerelease'),
re_path(r'latest/pymanager/?$', views.DownloadLatestPyManager.as_view(), name='download_latest_pymanager'),
re_path(r'latest/?$', views.DownloadLatestPython3.as_view(), name='download_latest_python3'),
path('operating-systems/', views.DownloadFullOSList.as_view(), name='download_full_os_list'),
Expand Down
17 changes: 17 additions & 0 deletions downloads/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,23 @@ def get_redirect_url(self, **kwargs):
return reverse('downloads:download')


class DownloadLatestPrerelease(RedirectView):
"""Redirect to latest Python 3 prerelease"""

permanent = False

def get_redirect_url(self, **kwargs):
try:
latest_prerelease = Release.objects.latest_prerelease()
except Release.DoesNotExist:
latest_prerelease = None

if latest_prerelease:
return latest_prerelease.get_absolute_url()
else:
return reverse("downloads:download")


class DownloadLatestPyManager(RedirectView):
""" Redirect to latest Python install manager release """
permanent = False
Expand Down
Loading