From d7688a010a34033a5cc8eecf7b1460169c0e056e Mon Sep 17 00:00:00 2001
From: Aymeric Augustin <aymeric.augustin@m4x.org>
Date: Sat, 3 Nov 2012 21:43:11 +0100
Subject: [PATCH] [1.5.x] Fixed #18963 -- Used a subclass-friendly pattern

for Python 2 object model compatibility methods.

Backport of fc10418 from master.
---
 django/contrib/auth/context_processors.py |  4 +++-
 django/contrib/gis/measure.py             | 16 ++++++++++++----
 django/core/files/base.py                 |  8 ++++++--
 django/core/serializers/base.py           |  4 +---
 django/core/serializers/xml_serializer.py |  2 --
 django/db/backends/oracle/base.py         |  4 +---
 django/db/models/expressions.py           | 12 ++++++++----
 django/db/models/query.py                 |  4 +++-
 django/dispatch/saferef.py                | 16 +++++++++-------
 django/forms/formsets.py                  |  4 +++-
 django/http/multipartparser.py            | 16 ++++------------
 django/http/response.py                   |  4 +---
 django/utils/tree.py                      |  4 +++-
 docs/topics/python3.txt                   | 13 +++++++------
 14 files changed, 61 insertions(+), 50 deletions(-)

diff --git a/django/contrib/auth/context_processors.py b/django/contrib/auth/context_processors.py
index 5929505359..3d17fe2754 100644
--- a/django/contrib/auth/context_processors.py
+++ b/django/contrib/auth/context_processors.py
@@ -18,7 +18,9 @@ class PermLookupDict(object):
 
     def __bool__(self):
         return self.user.has_module_perms(self.module_name)
-    __nonzero__ = __bool__ # Python 2
+
+    def __nonzero__(self):      # Python 2 compatibility
+        return type(self).__bool__(self)
 
 
 class PermWrapper(object):
diff --git a/django/contrib/gis/measure.py b/django/contrib/gis/measure.py
index 6e074be355..e2e6b6bca8 100644
--- a/django/contrib/gis/measure.py
+++ b/django/contrib/gis/measure.py
@@ -151,7 +151,9 @@ class MeasureBase(object):
                 **{self.STANDARD_UNIT: (self.standard / other)})
         else:
             raise TypeError('%(class)s must be divided with number or %(class)s' % {"class":pretty_name(self)})
-    __div__ = __truediv__ # Python 2 compatibility
+
+    def __div__(self, other):   # Python 2 compatibility
+        return type(self).__truediv__(self, other)
 
     def __itruediv__(self, other):
         if isinstance(other, NUMERIC_TYPES):
@@ -159,11 +161,15 @@ class MeasureBase(object):
             return self
         else:
             raise TypeError('%(class)s must be divided with number' % {"class":pretty_name(self)})
-    __idiv__ = __itruediv__ # Python 2 compatibility
+
+    def __idiv__(self, other):  # Python 2 compatibility
+        return type(self).__itruediv__(self, other)
 
     def __bool__(self):
         return bool(self.standard)
-    __nonzero__ = __bool__ # Python 2 compatibility
+
+    def __nonzero__(self):      # Python 2 compatibility
+        return type(self).__bool__(self)
 
     def default_units(self, kwargs):
         """
@@ -314,7 +320,9 @@ class Area(MeasureBase):
                 **{self.STANDARD_UNIT: (self.standard / other)})
         else:
             raise TypeError('%(class)s must be divided by a number' % {"class":pretty_name(self)})
-    __div__ = __truediv__ # Python 2 compatibility
+
+    def __div__(self, other):  # Python 2 compatibility
+        return type(self).__truediv__(self, other)
 
 
 # Shortcuts
diff --git a/django/core/files/base.py b/django/core/files/base.py
index b81e180292..71de5ab741 100644
--- a/django/core/files/base.py
+++ b/django/core/files/base.py
@@ -28,7 +28,9 @@ class File(FileProxyMixin):
 
     def __bool__(self):
         return bool(self.name)
-    __nonzero__ = __bool__ # Python 2
+
+    def __nonzero__(self):      # Python 2 compatibility
+        return type(self).__bool__(self)
 
     def __len__(self):
         return self.size
@@ -142,7 +144,9 @@ class ContentFile(File):
 
     def __bool__(self):
         return True
-    __nonzero__ = __bool__ # Python 2
+
+    def __nonzero__(self):      # Python 2 compatibility
+        return type(self).__bool__(self)
 
     def open(self, mode=None):
         self.seek(0)
diff --git a/django/core/serializers/base.py b/django/core/serializers/base.py
index 276f9a4738..294934a04a 100644
--- a/django/core/serializers/base.py
+++ b/django/core/serializers/base.py
@@ -112,7 +112,7 @@ class Serializer(object):
         if callable(getattr(self.stream, 'getvalue', None)):
             return self.stream.getvalue()
 
-class Deserializer(object):
+class Deserializer(six.Iterator):
     """
     Abstract base deserializer class.
     """
@@ -138,8 +138,6 @@ class Deserializer(object):
         """Iteration iterface -- return the next item in the stream"""
         raise NotImplementedError
 
-    next = __next__             # Python 2 compatibility
-
 class DeserializedObject(object):
     """
     A deserialized model.
diff --git a/django/core/serializers/xml_serializer.py b/django/core/serializers/xml_serializer.py
index 666587dc77..ea333a22bd 100644
--- a/django/core/serializers/xml_serializer.py
+++ b/django/core/serializers/xml_serializer.py
@@ -161,8 +161,6 @@ class Deserializer(base.Deserializer):
                 return self._handle_object(node)
         raise StopIteration
 
-    next = __next__             # Python 2 compatibility
-
     def _handle_object(self, node):
         """
         Convert an <object> node to a DeserializedObject.
diff --git a/django/db/backends/oracle/base.py b/django/db/backends/oracle/base.py
index aad52992dd..dfdfd4fd49 100644
--- a/django/db/backends/oracle/base.py
+++ b/django/db/backends/oracle/base.py
@@ -774,7 +774,7 @@ class FormatStylePlaceholderCursor(object):
         return CursorIterator(self.cursor)
 
 
-class CursorIterator(object):
+class CursorIterator(six.Iterator):
 
     """Cursor iterator wrapper that invokes our custom row factory."""
 
@@ -788,8 +788,6 @@ class CursorIterator(object):
     def __next__(self):
         return _rowfactory(next(self.iter), self.cursor)
 
-    next = __next__             # Python 2 compatibility
-
 
 def _rowfactory(row, cursor):
     # Cast numeric values as the appropriate Python type based upon the
diff --git a/django/db/models/expressions.py b/django/db/models/expressions.py
index 30c44bacde..3566d777c6 100644
--- a/django/db/models/expressions.py
+++ b/django/db/models/expressions.py
@@ -62,7 +62,9 @@ class ExpressionNode(tree.Node):
 
     def __truediv__(self, other):
         return self._combine(other, self.DIV, False)
-    __div__ = __truediv__ # Python 2 compatibility
+
+    def __div__(self, other):  # Python 2 compatibility
+        return type(self).__truediv__(self, other)
 
     def __mod__(self, other):
         return self._combine(other, self.MOD, False)
@@ -94,7 +96,9 @@ class ExpressionNode(tree.Node):
 
     def __rtruediv__(self, other):
         return self._combine(other, self.DIV, True)
-    __rdiv__ = __rtruediv__ # Python 2 compatibility
+
+    def __rdiv__(self, other):  # Python 2 compatibility
+        return type(self).__rtruediv__(self, other)
 
     def __rmod__(self, other):
         return self._combine(other, self.MOD, True)
@@ -151,10 +155,10 @@ class DateModifierNode(ExpressionNode):
         (A custom function is used in order to preserve six digits of fractional
         second information on sqlite, and to format both date and datetime values.)
 
-    Note that microsecond comparisons are not well supported with MySQL, since 
+    Note that microsecond comparisons are not well supported with MySQL, since
     MySQL does not store microsecond information.
 
-    Only adding and subtracting timedeltas is supported, attempts to use other 
+    Only adding and subtracting timedeltas is supported, attempts to use other
     operations raise a TypeError.
     """
     def __init__(self, children, connector, negated=False):
diff --git a/django/db/models/query.py b/django/db/models/query.py
index c00080abef..a3b28e9228 100644
--- a/django/db/models/query.py
+++ b/django/db/models/query.py
@@ -136,7 +136,9 @@ class QuerySet(object):
         except StopIteration:
             return False
         return True
-    __nonzero__ = __bool__ # Python 2
+
+    def __nonzero__(self):      # Python 2 compatibility
+        return type(self).__bool__(self)
 
     def __contains__(self, val):
         # The 'in' operator works without this method, due to __iter__. This
diff --git a/django/dispatch/saferef.py b/django/dispatch/saferef.py
index 84d1b2183c..7423669c96 100644
--- a/django/dispatch/saferef.py
+++ b/django/dispatch/saferef.py
@@ -67,9 +67,9 @@ class BoundMethodWeakref(object):
             same BoundMethodWeakref instance.
 
     """
-    
+
     _allInstances = weakref.WeakValueDictionary()
-    
+
     def __new__( cls, target, onDelete=None, *arguments,**named ):
         """Create new instance or return current instance
 
@@ -92,7 +92,7 @@ class BoundMethodWeakref(object):
             cls._allInstances[key] = base
             base.__init__( target, onDelete, *arguments,**named)
             return base
-    
+
     def __init__(self, target, onDelete=None):
         """Return a weak-reference-like instance for a bound method
 
@@ -132,7 +132,7 @@ class BoundMethodWeakref(object):
         self.weakFunc = weakref.ref(target.__func__, remove)
         self.selfName = str(target.__self__)
         self.funcName = str(target.__func__.__name__)
-    
+
     def calculateKey( cls, target ):
         """Calculate the reference key for this reference
 
@@ -141,7 +141,7 @@ class BoundMethodWeakref(object):
         """
         return (id(target.__self__),id(target.__func__))
     calculateKey = classmethod( calculateKey )
-    
+
     def __str__(self):
         """Give a friendly representation of the object"""
         return """%s( %s.%s )"""%(
@@ -157,14 +157,16 @@ class BoundMethodWeakref(object):
     def __bool__( self ):
         """Whether we are still a valid reference"""
         return self() is not None
-    __nonzero__ = __bool__ # Python 2
+
+    def __nonzero__(self):      # Python 2 compatibility
+        return type(self).__bool__(self)
 
     def __eq__(self, other):
         """Compare with another reference"""
         if not isinstance(other, self.__class__):
             return self.__class__ == type(other)
         return self.key == other.key
-    
+
     def __call__(self):
         """Return a strong reference to the bound method
 
diff --git a/django/forms/formsets.py b/django/forms/formsets.py
index c646eed506..a0a38f336f 100644
--- a/django/forms/formsets.py
+++ b/django/forms/formsets.py
@@ -69,7 +69,9 @@ class BaseFormSet(object):
     def __bool__(self):
         """All formsets have a management form which is not included in the length"""
         return True
-    __nonzero__ = __bool__ # Python 2
+
+    def __nonzero__(self):      # Python 2 compatibility
+        return type(self).__bool__(self)
 
     @property
     def management_form(self):
diff --git a/django/http/multipartparser.py b/django/http/multipartparser.py
index 5bcc874982..9413a1eabb 100644
--- a/django/http/multipartparser.py
+++ b/django/http/multipartparser.py
@@ -256,7 +256,7 @@ class MultiPartParser(object):
         """Cleanup filename from Internet Explorer full paths."""
         return filename and filename[filename.rfind("\\")+1:].strip()
 
-class LazyStream(object):
+class LazyStream(six.Iterator):
     """
     The LazyStream wrapper allows one to get and "unget" bytes from a stream.
 
@@ -323,8 +323,6 @@ class LazyStream(object):
         self.position += len(output)
         return output
 
-    next = __next__             # Python 2 compatibility
-
     def close(self):
         """
         Used to invalidate/disable this lazy stream.
@@ -369,7 +367,7 @@ class LazyStream(object):
                 " if there is none, report this to the Django developers."
             )
 
-class ChunkIter(object):
+class ChunkIter(six.Iterator):
     """
     An iterable that will yield chunks of data. Given a file-like object as the
     constructor, this object will yield chunks of read operations from that
@@ -389,12 +387,10 @@ class ChunkIter(object):
         else:
             raise StopIteration()
 
-    next = __next__             # Python 2 compatibility
-
     def __iter__(self):
         return self
 
-class InterBoundaryIter(object):
+class InterBoundaryIter(six.Iterator):
     """
     A Producer that will iterate over boundaries.
     """
@@ -411,9 +407,7 @@ class InterBoundaryIter(object):
         except InputStreamExhausted:
             raise StopIteration()
 
-    next = __next__             # Python 2 compatibility
-
-class BoundaryIter(object):
+class BoundaryIter(six.Iterator):
     """
     A Producer that is sensitive to boundaries.
 
@@ -489,8 +483,6 @@ class BoundaryIter(object):
                 stream.unget(chunk[-rollback:])
                 return chunk[:-rollback]
 
-    next = __next__             # Python 2 compatibility
-
     def _find_boundary(self, data, eof = False):
         """
         Finds a multipart boundary in data.
diff --git a/django/http/response.py b/django/http/response.py
index 56e3d00096..df0a955b18 100644
--- a/django/http/response.py
+++ b/django/http/response.py
@@ -23,7 +23,7 @@ class BadHeaderError(ValueError):
     pass
 
 
-class HttpResponseBase(object):
+class HttpResponseBase(six.Iterator):
     """
     An HTTP response base class with dictionary-accessed headers.
 
@@ -218,8 +218,6 @@ class HttpResponseBase(object):
         # Subclasses must define self._iterator for this function.
         return self.make_bytes(next(self._iterator))
 
-    next = __next__             # Python 2 compatibility
-
     # These methods partially implement the file-like object interface.
     # See http://docs.python.org/lib/bltin-file-objects.html
 
diff --git a/django/utils/tree.py b/django/utils/tree.py
index 717181d2b9..ce490224e0 100644
--- a/django/utils/tree.py
+++ b/django/utils/tree.py
@@ -73,7 +73,9 @@ class Node(object):
         For truth value testing.
         """
         return bool(self.children)
-    __nonzero__ = __bool__ # Python 2
+
+    def __nonzero__(self):      # Python 2 compatibility
+        return type(self).__bool__(self)
 
     def __contains__(self, other):
         """
diff --git a/docs/topics/python3.txt b/docs/topics/python3.txt
index f5749faaf2..e6dc165399 100644
--- a/docs/topics/python3.txt
+++ b/docs/topics/python3.txt
@@ -278,15 +278,13 @@ Iterators
 
 ::
 
-    class MyIterator(object):
+    class MyIterator(six.Iterator):
         def __iter__(self):
             return self             # implement some logic here
 
         def __next__(self):
             raise StopIteration     # implement some logic here
 
-        next = __next__             # Python 2 compatibility
-
 Boolean evaluation
 ~~~~~~~~~~~~~~~~~~
 
@@ -297,7 +295,8 @@ Boolean evaluation
         def __bool__(self):
             return True             # implement some logic here
 
-        __nonzero__ = __bool__      # Python 2 compatibility
+        def __nonzero__(self):      # Python 2 compatibility
+            return type(self).__bool__(self)
 
 Division
 ~~~~~~~~
@@ -309,12 +308,14 @@ Division
         def __truediv__(self, other):
             return self / other     # implement some logic here
 
-        __div__ = __truediv__           # Python 2 compatibility
+        def __div__(self, other):   # Python 2 compatibility
+            return type(self).__truediv__(self, other)
 
         def __itruediv__(self, other):
             return self // other    # implement some logic here
 
-        __idiv__ = __itruediv__         # Python 2 compatibility
+        def __idiv__(self, other):  # Python 2 compatibility
+            return type(self).__itruediv__(self, other)
 
 .. module: django.utils.six