From 2d078b0004fb6456fb99e46682af7d29748c8dc2 Mon Sep 17 00:00:00 2001
From: Ben Sturmfels <ben@sturm.com.au>
Date: Tue, 30 Nov 2021 07:55:45 +1100
Subject: [PATCH] Apply `futurize --stage-2` Python 2/3 compatibility
 transformations.

These changes specifically require the use of the "future" library.
---
 www/conservancy/__init__.py                        |  1 +
 www/conservancy/apps/blog/models.py                |  9 ++++++---
 www/conservancy/apps/events/view_helpers.py        |  2 +-
 www/conservancy/apps/fundgoal/models.py            |  4 +++-
 www/conservancy/apps/news/models.py                |  8 +++++---
 www/conservancy/apps/news/templatetags/fill_url.py | 11 +++++++----
 www/conservancy/bsoup.py                           |  3 ++-
 www/conservancy/local_context_processors.py        |  4 ++--
 www/conservancy/static/views.py                    |  1 +
 www/modpythoncustom.py                             |  5 +++--
 10 files changed, 31 insertions(+), 17 deletions(-)

diff --git a/www/conservancy/__init__.py b/www/conservancy/__init__.py
index 9c112546..dba7ab71 100644
--- a/www/conservancy/__init__.py
+++ b/www/conservancy/__init__.py
@@ -1,3 +1,4 @@
+from past.builtins import basestring
 from builtins import object
 import hashlib
 
diff --git a/www/conservancy/apps/blog/models.py b/www/conservancy/apps/blog/models.py
index 88b5cbf3..4429a161 100644
--- a/www/conservancy/apps/blog/models.py
+++ b/www/conservancy/apps/blog/models.py
@@ -1,3 +1,6 @@
+from future import standard_library
+standard_library.install_aliases()
+from builtins import object
 from django.db import models
 from django.conf import settings
 from conservancy import bsoup
@@ -65,14 +68,14 @@ class Entry(models.Model, bsoup.SoupModelMixin):
         post_url = ('http://www.sfconservancy.org'
                     + self.get_absolute_url())
 
-        import xmlrpclib
+        import xmlrpc.client
 
         # Ping Technorati
-        j = xmlrpclib.Server('http://rpc.technorati.com/rpc/ping')
+        j = xmlrpc.client.Server('http://rpc.technorati.com/rpc/ping')
         reply = j.weblogUpdates.ping(blog_name, blog_url)
 
         # Ping Google Blog Search
-        j = xmlrpclib.Server('http://blogsearch.google.com/ping/RPC2')
+        j = xmlrpc.client.Server('http://blogsearch.google.com/ping/RPC2')
         reply = j.weblogUpdates.ping(blog_name, blog_url, post_url)
 
         # Call any superclass's method
diff --git a/www/conservancy/apps/events/view_helpers.py b/www/conservancy/apps/events/view_helpers.py
index 40233649..b9f586fb 100644
--- a/www/conservancy/apps/events/view_helpers.py
+++ b/www/conservancy/apps/events/view_helpers.py
@@ -15,6 +15,6 @@ def organize_media_by_event(eventmedia_queryset):
     mbe = [{'event': x[0].event,
             'date': max(y.date_created for y in x),
             'media_list': ', '.join(set(y.get_format_display() for y in x))}
-           for x in media_by_event.values()]
+           for x in list(media_by_event.values())]
     mbe.sort(key=(lambda x: x['date']), reverse=True) # sort by date
     return mbe
diff --git a/www/conservancy/apps/fundgoal/models.py b/www/conservancy/apps/fundgoal/models.py
index ac1d8252..6e1fa24e 100644
--- a/www/conservancy/apps/fundgoal/models.py
+++ b/www/conservancy/apps/fundgoal/models.py
@@ -1,3 +1,5 @@
+from __future__ import division
+from past.utils import old_div
 from builtins import object
 import random
 
@@ -17,7 +19,7 @@ class FundraisingGoal(models.Model):
         return self.fundraiser_code_name
 
     def percentage_there(self):
-        return (self.fundraiser_so_far_amount / self.fundraiser_goal_amount ) * 100
+        return (old_div(self.fundraiser_so_far_amount, self.fundraiser_goal_amount) ) * 100
     
     class Meta(object):
         ordering = ('fundraiser_code_name',)
diff --git a/www/conservancy/apps/news/models.py b/www/conservancy/apps/news/models.py
index 081029a7..9b556958 100644
--- a/www/conservancy/apps/news/models.py
+++ b/www/conservancy/apps/news/models.py
@@ -1,3 +1,5 @@
+from future import standard_library
+standard_library.install_aliases()
 from builtins import object
 from django.db import models
 from django.conf import settings
@@ -54,14 +56,14 @@ class PressRelease(models.Model, bsoup.SoupModelMixin):
         post_url = ('https://www.sfconservancy.org'
                     + self.get_absolute_url())
 
-        import xmlrpclib
+        import xmlrpc.client
 
         # Ping Technorati
-        j = xmlrpclib.Server('http://rpc.technorati.com/rpc/ping')
+        j = xmlrpc.client.Server('http://rpc.technorati.com/rpc/ping')
         reply = j.weblogUpdates.ping(blog_name, blog_url)
 
         # Ping Google Blog Search
-        j = xmlrpclib.Server('http://blogsearch.google.com/ping/RPC2')
+        j = xmlrpc.client.Server('http://blogsearch.google.com/ping/RPC2')
         reply = j.weblogUpdates.ping(blog_name, blog_url, post_url)
 
         # Call any superclass's method
diff --git a/www/conservancy/apps/news/templatetags/fill_url.py b/www/conservancy/apps/news/templatetags/fill_url.py
index 5d9d9a02..e36fbee5 100644
--- a/www/conservancy/apps/news/templatetags/fill_url.py
+++ b/www/conservancy/apps/news/templatetags/fill_url.py
@@ -1,4 +1,7 @@
-import urlparse
+from future import standard_library
+standard_library.install_aliases()
+from builtins import zip
+import urllib.parse
 
 from django import template
 
@@ -13,8 +16,8 @@ def fill_url(given_url, base_url):
     Typical usage is "/URL/path"|fill_url:"https://hostname/"
     to generate "https://hostname/URL/path".
     """
-    given_parts = urlparse.urlsplit(given_url)
-    base_parts = urlparse.urlsplit(base_url)
-    return urlparse.urlunsplit(
+    given_parts = urllib.parse.urlsplit(given_url)
+    base_parts = urllib.parse.urlsplit(base_url)
+    return urllib.parse.urlunsplit(
         given_part or base_part for given_part, base_part in zip(given_parts, base_parts)
     )
diff --git a/www/conservancy/bsoup.py b/www/conservancy/bsoup.py
index de0107c0..1aecc9ce 100644
--- a/www/conservancy/bsoup.py
+++ b/www/conservancy/bsoup.py
@@ -1,5 +1,6 @@
 # -*- encoding: utf-8 -*-
 
+from builtins import filter
 from builtins import object
 import io
 import itertools
@@ -144,7 +145,7 @@ class SoupModelMixin(object):
         return elem_pred
 
     def _sort_and_slice_elems(self, elem_seq, elem_key, pred, *slice_args):
-        seq = itertools.ifilter(pred, sorted(elem_seq, key=elem_key))
+        seq = filter(pred, sorted(elem_seq, key=elem_key))
         if slice_args:
             return itertools.islice(seq, *slice_args)
         else:
diff --git a/www/conservancy/local_context_processors.py b/www/conservancy/local_context_processors.py
index 9dfe9632..4759b1e5 100644
--- a/www/conservancy/local_context_processors.py
+++ b/www/conservancy/local_context_processors.py
@@ -22,7 +22,7 @@ def sitefundraiser(request):
 if conservancy.settings.FORCE_CANONICAL_HOSTNAME:
     _HOST_URL_VAR = {'host_url': 'https://' + conservancy.settings.FORCE_CANONICAL_HOSTNAME}
     def host_url(request):
-        return _HOST_URL_VAR
+        return _HOST_URL_VAR.decode('utf-8')
 else:
     def host_url(request):
-        return {'host_url': request.build_absolute_uri('/').rstrip('/')}
+        return {'host_url': request.build_absolute_uri('/').rstrip('/').decode('utf-8')}
diff --git a/www/conservancy/static/views.py b/www/conservancy/static/views.py
index 2da8ff8a..8029241d 100644
--- a/www/conservancy/static/views.py
+++ b/www/conservancy/static/views.py
@@ -1,3 +1,4 @@
+from builtins import str
 import mimetypes
 import os.path
 from django.http import HttpResponse
diff --git a/www/modpythoncustom.py b/www/modpythoncustom.py
index f5e0a14e..1d6380ec 100644
--- a/www/modpythoncustom.py
+++ b/www/modpythoncustom.py
@@ -1,3 +1,4 @@
+from builtins import str
 from mod_python import apache
 
 # 404 should do NOTHING so apache can handle it.  This view is referenced
@@ -83,10 +84,10 @@ class ModPythonHandler(BaseHandler):
 
         # Convert our custom HttpResponse object back into the mod_python req.
         req.content_type = response['Content-Type']
-        for key, value in response.items():
+        for key, value in list(response.items()):
             if key != 'content-type':
                 req.headers_out[str(key)] = str(value)
-        for c in response.cookies.values():
+        for c in list(response.cookies.values()):
             req.headers_out.add('Set-Cookie', c.output(header=''))
         req.status = response.status_code
         try: