From fc10418fba4fb906e4265650b62c510d526d63f7 Mon Sep 17 00:00:00 2001 From: Aymeric Augustin Date: Sat, 3 Nov 2012 21:43:11 +0100 Subject: [PATCH] Fixed #18963 -- Used a subclass-friendly pattern for Python 2 object model compatibility methods. --- 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 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