Fixed #18963 -- Used a subclass-friendly pattern

for Python 2 object model compatibility methods.
This commit is contained in:
Aymeric Augustin 2012-11-03 21:43:11 +01:00
parent 973f539ab8
commit fc10418fba
14 changed files with 61 additions and 50 deletions

View File

@ -18,7 +18,9 @@ class PermLookupDict(object):
def __bool__(self): def __bool__(self):
return self.user.has_module_perms(self.module_name) 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): class PermWrapper(object):

View File

@ -151,7 +151,9 @@ class MeasureBase(object):
**{self.STANDARD_UNIT: (self.standard / other)}) **{self.STANDARD_UNIT: (self.standard / other)})
else: else:
raise TypeError('%(class)s must be divided with number or %(class)s' % {"class":pretty_name(self)}) 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): def __itruediv__(self, other):
if isinstance(other, NUMERIC_TYPES): if isinstance(other, NUMERIC_TYPES):
@ -159,11 +161,15 @@ class MeasureBase(object):
return self return self
else: else:
raise TypeError('%(class)s must be divided with number' % {"class":pretty_name(self)}) 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): def __bool__(self):
return bool(self.standard) 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): def default_units(self, kwargs):
""" """
@ -314,7 +320,9 @@ class Area(MeasureBase):
**{self.STANDARD_UNIT: (self.standard / other)}) **{self.STANDARD_UNIT: (self.standard / other)})
else: else:
raise TypeError('%(class)s must be divided by a number' % {"class":pretty_name(self)}) 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 # Shortcuts

View File

@ -28,7 +28,9 @@ class File(FileProxyMixin):
def __bool__(self): def __bool__(self):
return bool(self.name) return bool(self.name)
__nonzero__ = __bool__ # Python 2
def __nonzero__(self): # Python 2 compatibility
return type(self).__bool__(self)
def __len__(self): def __len__(self):
return self.size return self.size
@ -142,7 +144,9 @@ class ContentFile(File):
def __bool__(self): def __bool__(self):
return True return True
__nonzero__ = __bool__ # Python 2
def __nonzero__(self): # Python 2 compatibility
return type(self).__bool__(self)
def open(self, mode=None): def open(self, mode=None):
self.seek(0) self.seek(0)

View File

@ -112,7 +112,7 @@ class Serializer(object):
if callable(getattr(self.stream, 'getvalue', None)): if callable(getattr(self.stream, 'getvalue', None)):
return self.stream.getvalue() return self.stream.getvalue()
class Deserializer(object): class Deserializer(six.Iterator):
""" """
Abstract base deserializer class. Abstract base deserializer class.
""" """
@ -138,8 +138,6 @@ class Deserializer(object):
"""Iteration iterface -- return the next item in the stream""" """Iteration iterface -- return the next item in the stream"""
raise NotImplementedError raise NotImplementedError
next = __next__ # Python 2 compatibility
class DeserializedObject(object): class DeserializedObject(object):
""" """
A deserialized model. A deserialized model.

View File

@ -161,8 +161,6 @@ class Deserializer(base.Deserializer):
return self._handle_object(node) return self._handle_object(node)
raise StopIteration raise StopIteration
next = __next__ # Python 2 compatibility
def _handle_object(self, node): def _handle_object(self, node):
""" """
Convert an <object> node to a DeserializedObject. Convert an <object> node to a DeserializedObject.

View File

@ -774,7 +774,7 @@ class FormatStylePlaceholderCursor(object):
return CursorIterator(self.cursor) return CursorIterator(self.cursor)
class CursorIterator(object): class CursorIterator(six.Iterator):
"""Cursor iterator wrapper that invokes our custom row factory.""" """Cursor iterator wrapper that invokes our custom row factory."""
@ -788,8 +788,6 @@ class CursorIterator(object):
def __next__(self): def __next__(self):
return _rowfactory(next(self.iter), self.cursor) return _rowfactory(next(self.iter), self.cursor)
next = __next__ # Python 2 compatibility
def _rowfactory(row, cursor): def _rowfactory(row, cursor):
# Cast numeric values as the appropriate Python type based upon the # Cast numeric values as the appropriate Python type based upon the

View File

@ -62,7 +62,9 @@ class ExpressionNode(tree.Node):
def __truediv__(self, other): def __truediv__(self, other):
return self._combine(other, self.DIV, False) 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): def __mod__(self, other):
return self._combine(other, self.MOD, False) return self._combine(other, self.MOD, False)
@ -94,7 +96,9 @@ class ExpressionNode(tree.Node):
def __rtruediv__(self, other): def __rtruediv__(self, other):
return self._combine(other, self.DIV, True) 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): def __rmod__(self, other):
return self._combine(other, self.MOD, True) 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 (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.) 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. 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. operations raise a TypeError.
""" """
def __init__(self, children, connector, negated=False): def __init__(self, children, connector, negated=False):

View File

@ -136,7 +136,9 @@ class QuerySet(object):
except StopIteration: except StopIteration:
return False return False
return True return True
__nonzero__ = __bool__ # Python 2
def __nonzero__(self): # Python 2 compatibility
return type(self).__bool__(self)
def __contains__(self, val): def __contains__(self, val):
# The 'in' operator works without this method, due to __iter__. This # The 'in' operator works without this method, due to __iter__. This

View File

@ -67,9 +67,9 @@ class BoundMethodWeakref(object):
same BoundMethodWeakref instance. same BoundMethodWeakref instance.
""" """
_allInstances = weakref.WeakValueDictionary() _allInstances = weakref.WeakValueDictionary()
def __new__( cls, target, onDelete=None, *arguments,**named ): def __new__( cls, target, onDelete=None, *arguments,**named ):
"""Create new instance or return current instance """Create new instance or return current instance
@ -92,7 +92,7 @@ class BoundMethodWeakref(object):
cls._allInstances[key] = base cls._allInstances[key] = base
base.__init__( target, onDelete, *arguments,**named) base.__init__( target, onDelete, *arguments,**named)
return base return base
def __init__(self, target, onDelete=None): def __init__(self, target, onDelete=None):
"""Return a weak-reference-like instance for a bound method """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.weakFunc = weakref.ref(target.__func__, remove)
self.selfName = str(target.__self__) self.selfName = str(target.__self__)
self.funcName = str(target.__func__.__name__) self.funcName = str(target.__func__.__name__)
def calculateKey( cls, target ): def calculateKey( cls, target ):
"""Calculate the reference key for this reference """Calculate the reference key for this reference
@ -141,7 +141,7 @@ class BoundMethodWeakref(object):
""" """
return (id(target.__self__),id(target.__func__)) return (id(target.__self__),id(target.__func__))
calculateKey = classmethod( calculateKey ) calculateKey = classmethod( calculateKey )
def __str__(self): def __str__(self):
"""Give a friendly representation of the object""" """Give a friendly representation of the object"""
return """%s( %s.%s )"""%( return """%s( %s.%s )"""%(
@ -157,14 +157,16 @@ class BoundMethodWeakref(object):
def __bool__( self ): def __bool__( self ):
"""Whether we are still a valid reference""" """Whether we are still a valid reference"""
return self() is not None return self() is not None
__nonzero__ = __bool__ # Python 2
def __nonzero__(self): # Python 2 compatibility
return type(self).__bool__(self)
def __eq__(self, other): def __eq__(self, other):
"""Compare with another reference""" """Compare with another reference"""
if not isinstance(other, self.__class__): if not isinstance(other, self.__class__):
return self.__class__ == type(other) return self.__class__ == type(other)
return self.key == other.key return self.key == other.key
def __call__(self): def __call__(self):
"""Return a strong reference to the bound method """Return a strong reference to the bound method

View File

@ -69,7 +69,9 @@ class BaseFormSet(object):
def __bool__(self): def __bool__(self):
"""All formsets have a management form which is not included in the length""" """All formsets have a management form which is not included in the length"""
return True return True
__nonzero__ = __bool__ # Python 2
def __nonzero__(self): # Python 2 compatibility
return type(self).__bool__(self)
@property @property
def management_form(self): def management_form(self):

View File

@ -256,7 +256,7 @@ class MultiPartParser(object):
"""Cleanup filename from Internet Explorer full paths.""" """Cleanup filename from Internet Explorer full paths."""
return filename and filename[filename.rfind("\\")+1:].strip() 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. The LazyStream wrapper allows one to get and "unget" bytes from a stream.
@ -323,8 +323,6 @@ class LazyStream(object):
self.position += len(output) self.position += len(output)
return output return output
next = __next__ # Python 2 compatibility
def close(self): def close(self):
""" """
Used to invalidate/disable this lazy stream. Used to invalidate/disable this lazy stream.
@ -369,7 +367,7 @@ class LazyStream(object):
" if there is none, report this to the Django developers." " 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 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 constructor, this object will yield chunks of read operations from that
@ -389,12 +387,10 @@ class ChunkIter(object):
else: else:
raise StopIteration() raise StopIteration()
next = __next__ # Python 2 compatibility
def __iter__(self): def __iter__(self):
return self return self
class InterBoundaryIter(object): class InterBoundaryIter(six.Iterator):
""" """
A Producer that will iterate over boundaries. A Producer that will iterate over boundaries.
""" """
@ -411,9 +407,7 @@ class InterBoundaryIter(object):
except InputStreamExhausted: except InputStreamExhausted:
raise StopIteration() raise StopIteration()
next = __next__ # Python 2 compatibility class BoundaryIter(six.Iterator):
class BoundaryIter(object):
""" """
A Producer that is sensitive to boundaries. A Producer that is sensitive to boundaries.
@ -489,8 +483,6 @@ class BoundaryIter(object):
stream.unget(chunk[-rollback:]) stream.unget(chunk[-rollback:])
return chunk[:-rollback] return chunk[:-rollback]
next = __next__ # Python 2 compatibility
def _find_boundary(self, data, eof = False): def _find_boundary(self, data, eof = False):
""" """
Finds a multipart boundary in data. Finds a multipart boundary in data.

View File

@ -23,7 +23,7 @@ class BadHeaderError(ValueError):
pass pass
class HttpResponseBase(object): class HttpResponseBase(six.Iterator):
""" """
An HTTP response base class with dictionary-accessed headers. An HTTP response base class with dictionary-accessed headers.
@ -218,8 +218,6 @@ class HttpResponseBase(object):
# Subclasses must define self._iterator for this function. # Subclasses must define self._iterator for this function.
return self.make_bytes(next(self._iterator)) return self.make_bytes(next(self._iterator))
next = __next__ # Python 2 compatibility
# These methods partially implement the file-like object interface. # These methods partially implement the file-like object interface.
# See http://docs.python.org/lib/bltin-file-objects.html # See http://docs.python.org/lib/bltin-file-objects.html

View File

@ -73,7 +73,9 @@ class Node(object):
For truth value testing. For truth value testing.
""" """
return bool(self.children) return bool(self.children)
__nonzero__ = __bool__ # Python 2
def __nonzero__(self): # Python 2 compatibility
return type(self).__bool__(self)
def __contains__(self, other): def __contains__(self, other):
""" """

View File

@ -278,15 +278,13 @@ Iterators
:: ::
class MyIterator(object): class MyIterator(six.Iterator):
def __iter__(self): def __iter__(self):
return self # implement some logic here return self # implement some logic here
def __next__(self): def __next__(self):
raise StopIteration # implement some logic here raise StopIteration # implement some logic here
next = __next__ # Python 2 compatibility
Boolean evaluation Boolean evaluation
~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~
@ -297,7 +295,8 @@ Boolean evaluation
def __bool__(self): def __bool__(self):
return True # implement some logic here return True # implement some logic here
__nonzero__ = __bool__ # Python 2 compatibility def __nonzero__(self): # Python 2 compatibility
return type(self).__bool__(self)
Division Division
~~~~~~~~ ~~~~~~~~
@ -309,12 +308,14 @@ Division
def __truediv__(self, other): def __truediv__(self, other):
return self / other # implement some logic here 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): def __itruediv__(self, other):
return self // other # implement some logic here 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 .. module: django.utils.six