Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: migration from 2.2 -> 3.2 -> 4.2 #2413

Closed
wants to merge 18 commits into from
Closed
Show file tree
Hide file tree
Changes from 2 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: 0 additions & 1 deletion banners/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +0,0 @@
default_app_config = 'banners.apps.BannersAppConfig'
22 changes: 11 additions & 11 deletions base-requirements.txt
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
dj-database-url==0.5.0
django-pipeline==2.0.6
django-sitetree==1.17.0
django-pipeline==3.0.0 # 3.0.0 is first version that supports Django 4.2
django-sitetree==1.18.0 # >=1.17.1 is (?) first version that supports Django 4.2
JacobCoffee marked this conversation as resolved.
Show resolved Hide resolved
django-apptemplates==1.5
django-admin-interface==0.24.2
django-translation-aliases==0.1.0
Django==2.2.28
Django==4.2.11
docutils==0.12
Markdown==3.3.4
cmarkgfm==0.6.0
Expand All @@ -22,32 +22,32 @@ chardet==4.0.0
celery[redis]==5.3.6
django-celery-beat==2.5.0
# TODO: We may drop 'django-imagekit' completely.
django-imagekit==4.0.2
django-imagekit==5.0 # 5.0 is first version that supports Django 4.2
django-haystack==3.2.1
elasticsearch>=7,<8
# TODO: 0.14.0 only supports Django 1.8 and 1.11.
django-tastypie==0.14.3
django-tastypie==0.14.6 # 0.14.6 is first version that supports Django 4.2

pytz==2021.1
python-dateutil==2.8.2

requests[security]>=2.26.0

django-honeypot==1.0.1
django-markupfield==2.0.0
django-markupfield-helpers==0.1.1
django-honeypot==1.0.4 # 1.0.4 is first version that supports Django 4.2
django-markupfield==2.0.1
# django-markupfield-helpers==0.1.1 # this hasnt been moved out of alpha and is last published 2018, we do import it
JacobCoffee marked this conversation as resolved.
Show resolved Hide resolved

django-allauth==0.41.0
django-allauth==0.61.1 # 0.55.0 is first version that supports Django 4.2
ewdurbin marked this conversation as resolved.
Show resolved Hide resolved

django-waffle==2.2.1

djangorestframework==3.12.2
djangorestframework==3.14.0 # 3.14.0 is first version that supports Django 4.1, 4.2 support hasnt been "released"
django-filter==2.4.0
django-ordered-model==3.4.3
django-widget-tweaks==1.4.8
django-countries==7.2.1
num2words==0.5.10
django-polymorphic==3.0.0
django-polymorphic==3.1.0 # 3.1.0 is first version that supports Django 4.0, unsure if it fully supports 4.2
sorl-thumbnail==12.7.0
django-extensions==3.1.4
django-import-export==2.7.1
Expand Down
1 change: 0 additions & 1 deletion blogs/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +0,0 @@
default_app_config = 'blogs.apps.BlogsAppConfig'
4 changes: 3 additions & 1 deletion blogs/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,13 @@ class BlogEntryAdmin(admin.ModelAdmin):
date_hierarchy = 'pub_date'
actions = ['sync_new_entries']

@admin.action(
description="Sync new blog entries"
)
def sync_new_entries(self, request, queryset):
call_command('update_blogs')
self.message_user(request, "Blog entries updated.")

sync_new_entries.short_description = "Sync new blog entries"


@admin.register(FeedAggregate)
Expand Down
4 changes: 2 additions & 2 deletions blogs/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

from django.conf import settings
from django.template.loader import render_to_string
from django.utils.timezone import make_aware, utc
from django.utils.timezone import make_aware

from boxes.models import Box
from .models import BlogEntry, Feed
Expand All @@ -16,7 +16,7 @@ def get_all_entries(feed_url):

for e in d['entries']:
published = make_aware(
datetime.datetime(*e['published_parsed'][:7]), timezone=utc
datetime.datetime(*e['published_parsed'][:7]), timezone=datetime.timezone.utc
)

entry = {
Expand Down
1 change: 0 additions & 1 deletion boxes/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +0,0 @@
default_app_config = 'boxes.apps.BoxesAppConfig'
1 change: 0 additions & 1 deletion cms/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +0,0 @@
default_app_config = 'cms.apps.CmsAppConfig'
1 change: 0 additions & 1 deletion codesamples/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +0,0 @@
default_app_config = 'codesamples.apps.CodesamplesAppConfig'
4 changes: 2 additions & 2 deletions codesamples/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ def setUp(self):
is_published=False)

def test_published(self):
self.assertQuerysetEqual(CodeSample.objects.published(),
self.assertQuerySetEqual(CodeSample.objects.published(),
['<CodeSample: Copy One>'])

def test_draft(self):
self.assertQuerysetEqual(CodeSample.objects.draft(),
self.assertQuerySetEqual(CodeSample.objects.draft(),
['<CodeSample: Copy Two>'])
1 change: 0 additions & 1 deletion community/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +0,0 @@
default_app_config = 'community.apps.CommunityAppConfig'
2 changes: 1 addition & 1 deletion community/models.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from django.contrib.postgres.fields import JSONField
from django.db.models import JSONField
from django.urls import reverse
from django.db import models
from django.utils.translation import gettext_lazy as _
Expand Down
6 changes: 3 additions & 3 deletions community/tests/test_managers.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,6 @@ def test_post_manager(self):
status=Post.STATUS_PUBLIC
)

self.assertQuerysetEqual(Post.objects.all(), [public_post, private_post], lambda x: x)
self.assertQuerysetEqual(Post.objects.public(), [public_post], lambda x: x)
self.assertQuerysetEqual(Post.objects.private(), [private_post], lambda x: x)
self.assertQuerySetEqual(Post.objects.all(), [public_post, private_post], lambda x: x)
self.assertQuerySetEqual(Post.objects.public(), [public_post], lambda x: x)
self.assertQuerySetEqual(Post.objects.private(), [private_post], lambda x: x)
1 change: 0 additions & 1 deletion companies/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +0,0 @@
default_app_config = 'companies.apps.CompaniesAppConfig'
15 changes: 14 additions & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,21 @@
version: "3.9"

services:
# postgres:
# image: postgres:10-bullseye
# ports:
# - "5433:5432"
# environment:
# POSTGRES_USER: pythondotorg
# POSTGRES_PASSWORD: pythondotorg
# POSTGRES_DB: pythondotorg
# POSTGRES_HOST_AUTH_METHOD: trust # never do this in production!
# healthcheck:
# test: ["CMD", "pg_isready", "-U", "pythondotorg", "-d", "pythondotorg"]
# interval: 1s

JacobCoffee marked this conversation as resolved.
Show resolved Hide resolved
postgres:
image: postgres:10-bullseye
image: postgres:12-bullseye # required for 4.2 upgrades
ewdurbin marked this conversation as resolved.
Show resolved Hide resolved
ports:
- "5433:5432"
environment:
Expand Down
1 change: 0 additions & 1 deletion downloads/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +0,0 @@
default_app_config = 'downloads.apps.DownloadsAppConfig'
14 changes: 7 additions & 7 deletions downloads/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ def test_invalid_token(self):
self.assertEqual(response.status_code, 401)

url = self.create_url('os')
response = self.client.get(url, HTTP_AUTHORIZATION=self.Authorization_invalid)
response = self.client.get(url, headers={"authorization": self.Authorization_invalid})
# TODO: API v1 returns 200 for a GET request even if token is invalid.
# 'StaffAuthorization.read_list` returns 'object_list' unconditionally,
# and 'StaffAuthorization.read_detail` returns 'True'.
Expand Down Expand Up @@ -222,7 +222,7 @@ def test_get_release(self):
self.assertEqual(len(content), 4)

# Login to get all releases.
response = self.client.get(url, HTTP_AUTHORIZATION=self.Authorization)
response = self.client.get(url, headers={"authorization": self.Authorization})
self.assertEqual(response.status_code, 200)
content = self.get_json(response)
self.assertEqual(len(content), 5)
Expand Down Expand Up @@ -258,7 +258,7 @@ def test_post_release(self):
response = self.client.get(new_url)
# TODO: API v1 returns 401; and API v2 returns 404.
self.assertIn(response.status_code, [401, 404])
response = self.client.get(new_url, HTTP_AUTHORIZATION=self.Authorization)
response = self.client.get(new_url, headers={"authorization": self.Authorization})
self.assertEqual(response.status_code, 200)
content = self.get_json(response)
self.assertEqual(content['name'], data['name'])
Expand Down Expand Up @@ -490,15 +490,15 @@ def test_throttling_anon(self):
)
def test_throttling_user(self):
url = self.create_url('os')
response = self.client.get(url, HTTP_AUTHORIZATION=self.Authorization)
response = self.client.get(url, headers={"authorization": self.Authorization})
self.assertEqual(response.status_code, 200)

# Second request should be okay for a user.
response = self.client.get(url, HTTP_AUTHORIZATION=self.Authorization)
response = self.client.get(url, headers={"authorization": self.Authorization})
self.assertEqual(response.status_code, 200)

# Third request should return '429 TOO MANY REQUESTS'.
response = self.client.get(url, HTTP_AUTHORIZATION=self.Authorization)
response = self.client.get(url, headers={"authorization": self.Authorization})
self.assertEqual(response.status_code, 429)

def test_filter_release_file_delete_by_release(self):
Expand Down Expand Up @@ -552,6 +552,6 @@ def test_filter_release_file_delete_by_release(self):
'release_file/delete_by_release',
filters={'release': self.release_275.pk},
),
HTTP_AUTHORIZATION=self.Authorization,
headers={"authorization": self.Authorization}
)
self.assertEqual(response.status_code, 405)
1 change: 0 additions & 1 deletion events/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +0,0 @@
default_app_config = 'events.apps.EventsAppConfig'
1 change: 0 additions & 1 deletion jobs/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +0,0 @@
default_app_config = 'jobs.apps.JobsAppConfig'
8 changes: 4 additions & 4 deletions jobs/signals.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
from django.dispatch import Signal

# Sent after job offer was submitted for review
job_was_submitted = Signal(providing_args=['job'])
job_was_submitted = Signal()
# Sent after job offer was approved
job_was_approved = Signal(providing_args=['approving_user', 'job'])
job_was_approved = Signal()
# Sent after job offer was rejected
job_was_rejected = Signal(providing_args=['rejecting_user', 'job'])
job_was_rejected = Signal()
# Sent after comment was posted
comment_was_posted = Signal(providing_args=['comment'])
comment_was_posted = Signal()
1 change: 0 additions & 1 deletion membership/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +0,0 @@
default_app_config = 'membership.apps.MembershipAppConfig'
1 change: 0 additions & 1 deletion minutes/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +0,0 @@
default_app_config = 'minutes.apps.MinutesAppConfig'
4 changes: 2 additions & 2 deletions minutes/tests/test_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,13 @@ def setUp(self):
)

def test_draft(self):
self.assertQuerysetEqual(
self.assertQuerySetEqual(
Minutes.objects.draft(),
['<Minutes: PSF Meeting Minutes January 01, 2013>']
)

def test_published(self):
self.assertQuerysetEqual(
self.assertQuerySetEqual(
Minutes.objects.published(),
['<Minutes: PSF Meeting Minutes January 01, 2012>']
)
Expand Down
1 change: 0 additions & 1 deletion nominations/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +0,0 @@
default_app_config = 'nominations.apps.NominationsAppConfig'
1 change: 0 additions & 1 deletion pages/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +0,0 @@
default_app_config = 'pages.apps.PagesAppConfig'
6 changes: 3 additions & 3 deletions pages/tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ def test_get_published_pages(self):
def test_get_all_pages(self):
# Login to get all pages.
url = self.create_url('page')
response = self.client.get(url, HTTP_AUTHORIZATION=self.Authorization)
response = self.client.get(url, headers={"authorization": self.Authorization})
self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.data), 3)

Expand All @@ -41,7 +41,7 @@ def test_filter_page(self):
self.assertEqual(len(response.data), 1)

# Login to filter all pages.
response = self.client.get(url, HTTP_AUTHORIZATION=self.Authorization)
response = self.client.get(url, headers={"authorization": self.Authorization})
self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.data), 2)

Expand All @@ -53,7 +53,7 @@ def test_filter_page(self):
self.assertEqual(len(response.data), 0)

# This should return only unpublished pages.
response = self.client.get(url, HTTP_AUTHORIZATION=self.Authorization)
response = self.client.get(url, headers={"authorization": self.Authorization})
self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.data), 1)

Expand Down
4 changes: 2 additions & 2 deletions pages/tests/test_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@

class PageModelTests(BasePageTests):
def test_published(self):
self.assertQuerysetEqual(Page.objects.published(), ['<Page: One>'])
self.assertQuerySetEqual(Page.objects.published(), ['<Page: One>'])

def test_draft(self):
self.assertQuerysetEqual(Page.objects.draft(), ['<Page: Two>'])
self.assertQuerySetEqual(Page.objects.draft(), ['<Page: Two>'])

def test_get_title(self):
one = Page.objects.get(path='one')
Expand Down
1 change: 0 additions & 1 deletion peps/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +0,0 @@
default_app_config = 'peps.apps.PepsAppConfig'
4 changes: 2 additions & 2 deletions prod-requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@ gunicorn==19.9.0
raven==6.10.0

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh that's an old one 😄 Not sure it supports Django 4.2, but maybe it's fine... Would be nice to see if we can switch to its successor, sentry-sdk.


# Heroku
Whitenoise==6.0.0 # 6.0.0 is latest version that supports Django 2.2
django-storages==1.12.3 # 1.12.3 is latest version that supports Django 2.2
Whitenoise==6.6.0 # 6.4.0 is first version that supports Django 4.2
django-storages==1.42.2 # 1.42.2 is first version that supports Django 4.2
boto3==1.26.165
11 changes: 9 additions & 2 deletions pydotorg/settings/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@
TIME_ZONE = 'UTC'
LANGUAGE_CODE = 'en-us'
USE_I18N = True
USE_L10N = True
USE_TZ = True

DATE_FORMAT = 'Y-m-d'
Expand All @@ -74,7 +73,14 @@
STATICFILES_DIRS = [
os.path.join(BASE, 'static'),
]
STATICFILES_STORAGE = 'pipeline.storage.PipelineStorage'
STORAGES = {
"default": {
"BACKEND": "django.core.files.storage.FileSystemStorage",
},
"staticfiles": {
"BACKEND": 'pipeline.storage.PipelineStorage',
},
}
STATICFILES_FINDERS = (
'django.contrib.staticfiles.finders.FileSystemFinder',
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
Expand Down Expand Up @@ -157,6 +163,7 @@
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'pages.middleware.PageFallbackMiddleware',
'django.contrib.redirects.middleware.RedirectFallbackMiddleware',
'allauth.account.middleware.AccountMiddleware',
JacobCoffee marked this conversation as resolved.
Show resolved Hide resolved
]

AUTH_USER_MODEL = 'users.User'
Expand Down
10 changes: 8 additions & 2 deletions pydotorg/settings/cabotage.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,14 @@
] + MIDDLEWARE

MEDIAFILES_LOCATION = 'media'
DEFAULT_FILE_STORAGE = 'custom_storages.storages.MediaStorage'
STATICFILES_STORAGE = 'custom_storages.storages.PipelineManifestStorage'
STORAGES = {
"default": {
"BACKEND": 'custom_storages.storages.MediaStorage',
},
"staticfiles": {
"BACKEND": 'custom_storages.storages.PipelineManifestStorage',
},
}

EMAIL_HOST = config('EMAIL_HOST')
EMAIL_HOST_USER = config('EMAIL_HOST_USER')
Expand Down
10 changes: 8 additions & 2 deletions pydotorg/settings/static.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,11 @@
] + MIDDLEWARE

MEDIAFILES_LOCATION = 'media'
DEFAULT_FILE_STORAGE = 'custom_storages.storages.MediaStorage'
STATICFILES_STORAGE = 'custom_storages.storages.PipelineManifestStorage'
STORAGES = {
"default": {
"BACKEND": 'custom_storages.storages.MediaStorage',
},
"staticfiles": {
"BACKEND": 'custom_storages.storages.PipelineManifestStorage',
},
}
3 changes: 2 additions & 1 deletion pydotorg/urls.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
from django.conf.urls import handler404, include
from django.conf.urls import handler404
from django.contrib import admin
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
from django.conf.urls.static import static
from django.urls import include
from django.urls import path, re_path
from django.views.generic.base import TemplateView
from django.conf import settings
Expand Down
6 changes: 3 additions & 3 deletions pydotorg/urls_api.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from django.conf.urls import url
from django.urls import re_path

from rest_framework import routers
from tastypie.api import Api
Expand All @@ -22,6 +22,6 @@
router.register(r'downloads/release_file', ReleaseFileViewSet)

urlpatterns = [
url(r'sponsors/logo-placement/', LogoPlacementeAPIList.as_view(), name="logo_placement_list"),
url(r'sponsors/sponsorship-assets/', SponsorshipAssetsAPIList.as_view(), name="assets_list"),
re_path(r'sponsors/logo-placement/', LogoPlacementeAPIList.as_view(), name="logo_placement_list"),
re_path(r'sponsors/sponsorship-assets/', SponsorshipAssetsAPIList.as_view(), name="assets_list"),
]
1 change: 0 additions & 1 deletion sponsors/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +0,0 @@
default_app_config = 'sponsors.apps.SponsorsAppConfig'
Loading