#190 Upgrade from Python 2 to Python 3
Merged 9 months ago by bt0dotninja. Opened 9 months ago by shraddhaag.
fedora-commops/ shraddhaag/fedora-happiness-packets change-py2-to-py3  into  master

file modified
+2 -1

@@ -1,4 +1,5 @@ 

- FROM python:2-alpine

+ #Issue with celery=4.2.1 with Py3.7 hence Py3.6.8 used

+ FROM python:3.6.8-alpine

  

  # Set current working directory

  WORKDIR /app

@@ -8,7 +8,7 @@ 

  from crispy_forms.layout import Submit, Layout, Fieldset, HTML

  from django import forms

  from django.conf import settings

- from django.core.urlresolvers import reverse

+ from django.urls import reverse

  from django.db.models import Q

  from django.utils import timezone

  

@@ -4,7 +4,7 @@ 

  import logging

  import re

  

- from django.core.urlresolvers import reverse

+ from django.urls import reverse

  from django.db import models

  from django.template.loader import render_to_string

  from django.utils.crypto import salted_hmac

@@ -4,7 +4,7 @@ 

  from django.conf import settings

  from django.core import mail

  from django.contrib.auth.models import User

- from django.core.urlresolvers import reverse

+ from django.urls import reverse

  from django.test import TestCase

  from django.utils.crypto import salted_hmac

  from haystack.management.commands import update_index

@@ -1,23 +1,25 @@ 

  from __future__ import unicode_literals

  

- from django.conf.urls import url

+ from django.urls import re_path

  

  from .views import (StartView, MessageSearchView, MessageSendView, MessageSenderConfirmationSentView, MessageSenderConfirmationView,

                      MessageSenderConfirmedView, MessageRecipientMessageUpdate, FaqView, ArchiveView, InspirationView,

                      BlacklistEmailView, ReceivedMessagesView, SentMessagesView)

  

+ app_name = 'messaging'

+ 

  urlpatterns = [

-     url(r'^$', StartView.as_view(), name='start'),

-     url(r'^faq/$', FaqView.as_view(), name='faq'),

-     url(r'^archive/$', ArchiveView.as_view(), name='archive'),

-     url(r'^inspiration/$', InspirationView.as_view(), name='inspiration'),

-     url(r'^received-messages/$', ReceivedMessagesView.as_view(), name='received_messages'),

-     url(r'^sent-messages/$', SentMessagesView.as_view(), name='sent_messages'),

-     url(r'^blacklist-email/(?P<email>[\w\.@\+-]+)/(?P<digest>\w+)/$', BlacklistEmailView.as_view(), name='blacklist_email'),

-     url(r'^send/$', MessageSendView.as_view(), name='send'),

-     url(r'^send/confirmation-sent/$', MessageSenderConfirmationSentView.as_view(), name='sender_confirmation_sent'),

-     url(r'^send/confirmation/(?P<identifier>[\w-]+)/(?P<token>[\w-]+)/$', MessageSenderConfirmationView.as_view(), name='sender_confirm'),

-     url(r'^send/confirmed/$', MessageSenderConfirmedView.as_view(), name='sender_confirmed'),

-     url(r'^recipient/(?P<identifier>[\w-]+)/(?P<token>[\w-]+)/$', MessageRecipientMessageUpdate.as_view(), name='recipient_message_update'),

-     url(r'^search/?$', MessageSearchView.as_view(), name='search'),

+     re_path(r'^$', StartView.as_view(), name='start'),

+     re_path(r'^faq/$', FaqView.as_view(), name='faq'),

+     re_path(r'^archive/$', ArchiveView.as_view(), name='archive'),

+     re_path(r'^inspiration/$', InspirationView.as_view(), name='inspiration'),

+     re_path(r'^received-messages/$', ReceivedMessagesView.as_view(), name='received_messages'),

+     re_path(r'^sent-messages/$', SentMessagesView.as_view(), name='sent_messages'),

+     re_path(r'^blacklist-email/(?P<email>[\w\.@\+-]+)/(?P<digest>\w+)/$', BlacklistEmailView.as_view(), name='blacklist_email'),

+     re_path(r'^send/$', MessageSendView.as_view(), name='send'),

+     re_path(r'^send/confirmation-sent/$', MessageSenderConfirmationSentView.as_view(), name='sender_confirmation_sent'),

+     re_path(r'^send/confirmation/(?P<identifier>[\w-]+)/(?P<token>[\w-]+)/$', MessageSenderConfirmationView.as_view(), name='sender_confirm'),

+     re_path(r'^send/confirmed/$', MessageSenderConfirmedView.as_view(), name='sender_confirmed'),

+     re_path(r'^recipient/(?P<identifier>[\w-]+)/(?P<token>[\w-]+)/$', MessageRecipientMessageUpdate.as_view(), name='recipient_message_update'),

+     re_path(r'^search/?$', MessageSearchView.as_view(), name='search'),

  ]

@@ -4,7 +4,7 @@ 

  import logging

  

  from django.contrib import messages

- from django.core.urlresolvers import reverse, reverse_lazy

+ from django.urls import reverse, reverse_lazy

  from django.http import HttpResponseRedirect, Http404

  from django.utils.crypto import salted_hmac, constant_time_compare

  from django.utils.decorators import method_decorator

@@ -13,6 +13,7 @@ 

  from django.views.generic import FormView, TemplateView, UpdateView, ListView

  from django.contrib.auth.mixins import LoginRequiredMixin

  from django.db.models import Q

+ from django.shortcuts import render

  

  from haystack.generic_views import SearchView

  from haystack.forms import SearchForm

@@ -126,10 +127,10 @@ 

          try:

              message = Message.objects.get(identifier=kwargs['identifier'], sender_email_token=kwargs['token'])

          except Message.DoesNotExist:

-             return self.render_to_response({'not_found': True})

+             return render(request, self.template_name, {'not_found': True})

  

          if message.status != Message.STATUS.pending_sender_confirmation:

-             return self.render_to_response({'already_confirmed': True})

+             return render(request, self.template_name, {'already_confirmed': True})

  

          message.send_to_recipient(self.request.is_secure(), self.request.get_host())

  

@@ -145,9 +146,9 @@ 

          try:

              publish(message)

          except PublishReturned:

-             return self.render_to_response({'publish_returned': True})

+             return render(request, self.template_name, {'publish_returned': True})

          except ConnectionException:

-             return self.render_to_response({'connection_exception': True})

+             return render(request, self.template_name, {'connection_exception': True})

          return HttpResponseRedirect(reverse('messaging:sender_confirmed'))

  

  

@@ -60,7 +60,7 @@ 

  )

  

  # noinspection PyUnresolvedReferences

- MIDDLEWARE_CLASSES = [

+ MIDDLEWARE = [

      'django.contrib.sessions.middleware.SessionMiddleware',

      'happinesspackets.utils.middleware.SetRemoteAddrFromForwardedFor',

      'opbeat.contrib.django.middleware.OpbeatAPMMiddleware',

@@ -1,6 +1,7 @@ 

  # -*- coding: utf-8 -*-

  # noinspection PyUnresolvedReferences

  import json

+ import sys

  

  from .base import *  # noqa

  

@@ -39,7 +40,7 @@ 

  

  ADMIN_ENABLED = True

  

- MIDDLEWARE_CLASSES = [

+ MIDDLEWARE = [

      'django.contrib.sessions.middleware.SessionMiddleware',

      'django.contrib.auth.middleware.AuthenticationMiddleware',

      'happinesspackets.utils.middleware.SetRemoteAddrFromForwardedFor',

@@ -47,12 +48,16 @@ 

      'django.middleware.common.CommonMiddleware',

      'django.middleware.csrf.CsrfViewMiddleware',

      'django.contrib.messages.middleware.MessageMiddleware',

-     'debug_toolbar.middleware.DebugToolbarMiddleware',

  ]

  

- INSTALLED_APPS += (

-     'debug_toolbar',

- )

+ TESTING = 'test' in sys.argv

+ 

+ if not TESTING:

+ 

+     MIDDLEWARE += ('debug_toolbar.middleware.DebugToolbarMiddleware',)

+     INSTALLED_APPS += (

+         'debug_toolbar',

+     )

  

  SELENIUM_SCREENSHOT_DIR = PROJECT_DIR.child('selenium-screenshots')

  

file modified
+1 -1

@@ -10,7 +10,7 @@ 

      message.attach_alternative(body_html, 'text/html')

      message.mixed_subtype = 'related'

  

-     logo_file = open(settings.STATIC_ROOT.child('images').child('logo.png'))

+     logo_file = open(settings.STATIC_ROOT.child('images').child('logo.png'), 'rb')

      logo_mime = MIMEImage(logo_file.read())

      logo_file.close()

      logo_mime.add_header('Content-ID', '<logo.png@happinesspackets.io>')

file modified
+10 -5

@@ -2,16 +2,21 @@ 

  

  import django

  from django.conf import settings

- from django.conf.urls import include, url

+ from django.urls import include, re_path, path

+ from django.conf.urls.static import static

  from django.contrib import admin

  

  urlpatterns = [

-     url(r'^oidc/', include('mozilla_django_oidc.urls')),

-     url(r'^', include('happinesspackets.messaging.urls', namespace="messaging")),

+     re_path(r'^oidc/', include('mozilla_django_oidc.urls')),

+     re_path(r'^', include('happinesspackets.messaging.urls')),

  ]

  

  if settings.ADMIN_ENABLED or settings.DEBUG:

-     urlpatterns.append(url(r'^drunken-octo-lama/', include(admin.site.urls)))

+     urlpatterns.append(re_path(r'^drunken-octo-lama/', admin.site.urls))

  

  if settings.DEBUG:

-     urlpatterns.append(url(r'^media/(?P<path>.*)$', django.views.static.serve, {'document_root': settings.MEDIA_ROOT}))

+     import debug_toolbar

+     urlpatterns += [

+         path('__debug__/', include(debug_toolbar.urls))

+         ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

+ 

@@ -1,7 +1,7 @@ 

  from __future__ import unicode_literals

+ from django.utils.deprecation import MiddlewareMixin

  

- 

- class SetRemoteAddrFromForwardedFor(object):

+ class SetRemoteAddrFromForwardedFor(MiddlewareMixin):

      """

      Middleware that sets REMOTE_ADDR based on HTTP_X_FORWARDED_FOR, if the

      latter is set. This is useful if you're sitting behind a reverse proxy that

file modified
+7 -8

@@ -1,19 +1,18 @@ 

- Django==1.11.5

+ #django-haystack doesn't have support for django2.1 yet

+ Django==2.0

  

  # Basic Django extensions

  django-extensions==1.6.1

  django-braces==1.8.1

- django-crispy-forms==1.6.0

+ django-crispy-forms==1.7.2

  django-model-utils==2.4

- dogslow==0.9.7                       # For logging details about very slow requests

+ dogslow==1.2                       # For logging details about very slow requests

  six>=1.11.0                          # Dependency of django-extensions

  

  # Basic Python libraries

  Unipath==1.1          # Better path handling

- wsgiref==0.1.2        # ???

  pytz==2015.7          # Timezone data

- ipython==4.1.1        # Prettier python prompt

- gnureadline==6.3.3    # Dependency of ipython

+ ipython==7.3.0        # Prettier python prompt

  

  # For generating docs - sphinx and dependencies

  Sphinx==1.3.6

@@ -31,8 +30,8 @@ 

  # Misc

  python-dateutil==2.5.0

  factory-boy==2.9.2

- opbeat==3.3

- mozilla-django-oidc==1.0.0

+ opbeat==3.6.1

+ mozilla-django-oidc==1.2.1

  fedora-messaging>=1.4.0

  happinesspacket-schema>=0.1.2

  celery[redis]==4.2.1

file modified
+1 -2

@@ -1,7 +1,6 @@ 

  -r base.txt

  coverage==4.0.3

  django-coverage==1.2.4

- django-debug-toolbar==1.4

+ django-debug-toolbar==1.11

  mock==1.3.0

  selenium==2.52

- sqlparse==0.1.18  # Dependency of debug-toolbar

file modified
+1 -1

@@ -1,4 +1,4 @@ 

- {% load static from staticfiles %}

+ {% load static %}

  <!DOCTYPE html>

  <html lang="en">

  <head>

This commit upgrades FHP from Python 2 to Python 3 and Django 1.11
to Django 2.0.

The following changes have been done with the reasons listed below:

  1. Docker Image for python has been changed to Python3.6.8 [can't be upgraded to 3.7 due to this issue]
  2. Changed Django 1.11 to Django 2.0 [It can't be changed to 2.1 as django-haystack (used for search) doesn't support Django 2.1]
  3. Upgraded dependencies to work with Python 3 and Django 2.
  4. Changed all these deprecated instructions to recent instructions for Django 2.0:
    • django.core.urlresolvers => django.urls
    • url => re_path
    • app_name = 'messaging' is required for url namespacing in Django 2.0
    • render_to_response => render
    • MIDDLEWARE_CLASSES => MIDDLEWARE
    • configuring static files is changed to static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
    • changed old style custom Middleware SetRemoteAddrFromForwardedFor using this
    • {% load static from staticfiles %}=> {% load static %}
  5. Django Debug Toolbar is configured to work only when Debug is set to true. It is disabled while testing as it causes this error
  6. Image is opened in binary mode ie rb to solve UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 0: invalid start byte.

Test suite is passed successfully after upgrading to Python3 and Django 2.1

Metadata Update from @jflory7:
- Pull-request tagged with: new change, type - backend, type - summer coding
- Request assigned

9 months ago

All looks good, none of the actual functionalities is broken I'm +1 for merge.

Pull-Request has been merged by bt0dotninja

9 months ago

@bt0dotninja Thank you so much for the speedy review :)