mirror of
https://github.com/Tautulli/Tautulli.git
synced 2025-08-19 21:03:21 -07:00
Add future 0.18.2
This commit is contained in:
parent
08c8ee0774
commit
fa97d3f88d
210 changed files with 43159 additions and 0 deletions
257
lib/future/types/__init__.py
Normal file
257
lib/future/types/__init__.py
Normal file
|
@ -0,0 +1,257 @@
|
|||
"""
|
||||
This module contains backports the data types that were significantly changed
|
||||
in the transition from Python 2 to Python 3.
|
||||
|
||||
- an implementation of Python 3's bytes object (pure Python subclass of
|
||||
Python 2's builtin 8-bit str type)
|
||||
- an implementation of Python 3's str object (pure Python subclass of
|
||||
Python 2's builtin unicode type)
|
||||
- a backport of the range iterator from Py3 with slicing support
|
||||
|
||||
It is used as follows::
|
||||
|
||||
from __future__ import division, absolute_import, print_function
|
||||
from builtins import bytes, dict, int, range, str
|
||||
|
||||
to bring in the new semantics for these functions from Python 3. And
|
||||
then, for example::
|
||||
|
||||
b = bytes(b'ABCD')
|
||||
assert list(b) == [65, 66, 67, 68]
|
||||
assert repr(b) == "b'ABCD'"
|
||||
assert [65, 66] in b
|
||||
|
||||
# These raise TypeErrors:
|
||||
# b + u'EFGH'
|
||||
# b.split(u'B')
|
||||
# bytes(b',').join([u'Fred', u'Bill'])
|
||||
|
||||
|
||||
s = str(u'ABCD')
|
||||
|
||||
# These raise TypeErrors:
|
||||
# s.join([b'Fred', b'Bill'])
|
||||
# s.startswith(b'A')
|
||||
# b'B' in s
|
||||
# s.find(b'A')
|
||||
# s.replace(u'A', b'a')
|
||||
|
||||
# This raises an AttributeError:
|
||||
# s.decode('utf-8')
|
||||
|
||||
assert repr(s) == 'ABCD' # consistent repr with Py3 (no u prefix)
|
||||
|
||||
|
||||
for i in range(10**11)[:10]:
|
||||
pass
|
||||
|
||||
and::
|
||||
|
||||
class VerboseList(list):
|
||||
def append(self, item):
|
||||
print('Adding an item')
|
||||
super().append(item) # new simpler super() function
|
||||
|
||||
For more information:
|
||||
---------------------
|
||||
|
||||
- future.types.newbytes
|
||||
- future.types.newdict
|
||||
- future.types.newint
|
||||
- future.types.newobject
|
||||
- future.types.newrange
|
||||
- future.types.newstr
|
||||
|
||||
|
||||
Notes
|
||||
=====
|
||||
|
||||
range()
|
||||
-------
|
||||
``range`` is a custom class that backports the slicing behaviour from
|
||||
Python 3 (based on the ``xrange`` module by Dan Crosta). See the
|
||||
``newrange`` module docstring for more details.
|
||||
|
||||
|
||||
super()
|
||||
-------
|
||||
``super()`` is based on Ryan Kelly's ``magicsuper`` module. See the
|
||||
``newsuper`` module docstring for more details.
|
||||
|
||||
|
||||
round()
|
||||
-------
|
||||
Python 3 modifies the behaviour of ``round()`` to use "Banker's Rounding".
|
||||
See http://stackoverflow.com/a/10825998. See the ``newround`` module
|
||||
docstring for more details.
|
||||
|
||||
"""
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
import functools
|
||||
from numbers import Integral
|
||||
|
||||
from future import utils
|
||||
|
||||
|
||||
# Some utility functions to enforce strict type-separation of unicode str and
|
||||
# bytes:
|
||||
def disallow_types(argnums, disallowed_types):
|
||||
"""
|
||||
A decorator that raises a TypeError if any of the given numbered
|
||||
arguments is of the corresponding given type (e.g. bytes or unicode
|
||||
string).
|
||||
|
||||
For example:
|
||||
|
||||
@disallow_types([0, 1], [unicode, bytes])
|
||||
def f(a, b):
|
||||
pass
|
||||
|
||||
raises a TypeError when f is called if a unicode object is passed as
|
||||
`a` or a bytes object is passed as `b`.
|
||||
|
||||
This also skips over keyword arguments, so
|
||||
|
||||
@disallow_types([0, 1], [unicode, bytes])
|
||||
def g(a, b=None):
|
||||
pass
|
||||
|
||||
doesn't raise an exception if g is called with only one argument a,
|
||||
e.g.:
|
||||
|
||||
g(b'Byte string')
|
||||
|
||||
Example use:
|
||||
|
||||
>>> class newbytes(object):
|
||||
... @disallow_types([1], [unicode])
|
||||
... def __add__(self, other):
|
||||
... pass
|
||||
|
||||
>>> newbytes('1234') + u'1234' #doctest: +IGNORE_EXCEPTION_DETAIL
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
TypeError: can't concat 'bytes' to (unicode) str
|
||||
"""
|
||||
|
||||
def decorator(function):
|
||||
|
||||
@functools.wraps(function)
|
||||
def wrapper(*args, **kwargs):
|
||||
# These imports are just for this decorator, and are defined here
|
||||
# to prevent circular imports:
|
||||
from .newbytes import newbytes
|
||||
from .newint import newint
|
||||
from .newstr import newstr
|
||||
|
||||
errmsg = "argument can't be {0}"
|
||||
for (argnum, mytype) in zip(argnums, disallowed_types):
|
||||
# Handle the case where the type is passed as a string like 'newbytes'.
|
||||
if isinstance(mytype, str) or isinstance(mytype, bytes):
|
||||
mytype = locals()[mytype]
|
||||
|
||||
# Only restrict kw args only if they are passed:
|
||||
if len(args) <= argnum:
|
||||
break
|
||||
|
||||
# Here we use type() rather than isinstance() because
|
||||
# __instancecheck__ is being overridden. E.g.
|
||||
# isinstance(b'abc', newbytes) is True on Py2.
|
||||
if type(args[argnum]) == mytype:
|
||||
raise TypeError(errmsg.format(mytype))
|
||||
|
||||
return function(*args, **kwargs)
|
||||
return wrapper
|
||||
return decorator
|
||||
|
||||
|
||||
def no(mytype, argnums=(1,)):
|
||||
"""
|
||||
A shortcut for the disallow_types decorator that disallows only one type
|
||||
(in any position in argnums).
|
||||
|
||||
Example use:
|
||||
|
||||
>>> class newstr(object):
|
||||
... @no('bytes')
|
||||
... def __add__(self, other):
|
||||
... pass
|
||||
|
||||
>>> newstr(u'1234') + b'1234' #doctest: +IGNORE_EXCEPTION_DETAIL
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
TypeError: argument can't be bytes
|
||||
|
||||
The object can also be passed directly, but passing the string helps
|
||||
to prevent circular import problems.
|
||||
"""
|
||||
if isinstance(argnums, Integral):
|
||||
argnums = (argnums,)
|
||||
disallowed_types = [mytype] * len(argnums)
|
||||
return disallow_types(argnums, disallowed_types)
|
||||
|
||||
|
||||
def issubset(list1, list2):
|
||||
"""
|
||||
Examples:
|
||||
|
||||
>>> issubset([], [65, 66, 67])
|
||||
True
|
||||
>>> issubset([65], [65, 66, 67])
|
||||
True
|
||||
>>> issubset([65, 66], [65, 66, 67])
|
||||
True
|
||||
>>> issubset([65, 67], [65, 66, 67])
|
||||
False
|
||||
"""
|
||||
n = len(list1)
|
||||
for startpos in range(len(list2) - n + 1):
|
||||
if list2[startpos:startpos+n] == list1:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
if utils.PY3:
|
||||
import builtins
|
||||
bytes = builtins.bytes
|
||||
dict = builtins.dict
|
||||
int = builtins.int
|
||||
list = builtins.list
|
||||
object = builtins.object
|
||||
range = builtins.range
|
||||
str = builtins.str
|
||||
|
||||
# The identity mapping
|
||||
newtypes = {bytes: bytes,
|
||||
dict: dict,
|
||||
int: int,
|
||||
list: list,
|
||||
object: object,
|
||||
range: range,
|
||||
str: str}
|
||||
|
||||
__all__ = ['newtypes']
|
||||
|
||||
else:
|
||||
|
||||
from .newbytes import newbytes
|
||||
from .newdict import newdict
|
||||
from .newint import newint
|
||||
from .newlist import newlist
|
||||
from .newrange import newrange
|
||||
from .newobject import newobject
|
||||
from .newstr import newstr
|
||||
|
||||
newtypes = {bytes: newbytes,
|
||||
dict: newdict,
|
||||
int: newint,
|
||||
long: newint,
|
||||
list: newlist,
|
||||
object: newobject,
|
||||
range: newrange,
|
||||
str: newbytes,
|
||||
unicode: newstr}
|
||||
|
||||
__all__ = ['newbytes', 'newdict', 'newint', 'newlist', 'newrange', 'newstr', 'newtypes']
|
460
lib/future/types/newbytes.py
Normal file
460
lib/future/types/newbytes.py
Normal file
|
@ -0,0 +1,460 @@
|
|||
"""
|
||||
Pure-Python implementation of a Python 3-like bytes object for Python 2.
|
||||
|
||||
Why do this? Without it, the Python 2 bytes object is a very, very
|
||||
different beast to the Python 3 bytes object.
|
||||
"""
|
||||
|
||||
from numbers import Integral
|
||||
import string
|
||||
import copy
|
||||
|
||||
from future.utils import istext, isbytes, PY2, PY3, with_metaclass
|
||||
from future.types import no, issubset
|
||||
from future.types.newobject import newobject
|
||||
|
||||
if PY2:
|
||||
from collections import Iterable
|
||||
else:
|
||||
from collections.abc import Iterable
|
||||
|
||||
|
||||
_builtin_bytes = bytes
|
||||
|
||||
if PY3:
|
||||
# We'll probably never use newstr on Py3 anyway...
|
||||
unicode = str
|
||||
|
||||
|
||||
class BaseNewBytes(type):
|
||||
def __instancecheck__(cls, instance):
|
||||
if cls == newbytes:
|
||||
return isinstance(instance, _builtin_bytes)
|
||||
else:
|
||||
return issubclass(instance.__class__, cls)
|
||||
|
||||
|
||||
def _newchr(x):
|
||||
if isinstance(x, str): # this happens on pypy
|
||||
return x.encode('ascii')
|
||||
else:
|
||||
return chr(x)
|
||||
|
||||
|
||||
class newbytes(with_metaclass(BaseNewBytes, _builtin_bytes)):
|
||||
"""
|
||||
A backport of the Python 3 bytes object to Py2
|
||||
"""
|
||||
def __new__(cls, *args, **kwargs):
|
||||
"""
|
||||
From the Py3 bytes docstring:
|
||||
|
||||
bytes(iterable_of_ints) -> bytes
|
||||
bytes(string, encoding[, errors]) -> bytes
|
||||
bytes(bytes_or_buffer) -> immutable copy of bytes_or_buffer
|
||||
bytes(int) -> bytes object of size given by the parameter initialized with null bytes
|
||||
bytes() -> empty bytes object
|
||||
|
||||
Construct an immutable array of bytes from:
|
||||
- an iterable yielding integers in range(256)
|
||||
- a text string encoded using the specified encoding
|
||||
- any object implementing the buffer API.
|
||||
- an integer
|
||||
"""
|
||||
|
||||
encoding = None
|
||||
errors = None
|
||||
|
||||
if len(args) == 0:
|
||||
return super(newbytes, cls).__new__(cls)
|
||||
elif len(args) >= 2:
|
||||
args = list(args)
|
||||
if len(args) == 3:
|
||||
errors = args.pop()
|
||||
encoding=args.pop()
|
||||
# Was: elif isinstance(args[0], newbytes):
|
||||
# We use type() instead of the above because we're redefining
|
||||
# this to be True for all unicode string subclasses. Warning:
|
||||
# This may render newstr un-subclassable.
|
||||
if type(args[0]) == newbytes:
|
||||
# Special-case: for consistency with Py3.3, we return the same object
|
||||
# (with the same id) if a newbytes object is passed into the
|
||||
# newbytes constructor.
|
||||
return args[0]
|
||||
elif isinstance(args[0], _builtin_bytes):
|
||||
value = args[0]
|
||||
elif isinstance(args[0], unicode):
|
||||
try:
|
||||
if 'encoding' in kwargs:
|
||||
assert encoding is None
|
||||
encoding = kwargs['encoding']
|
||||
if 'errors' in kwargs:
|
||||
assert errors is None
|
||||
errors = kwargs['errors']
|
||||
except AssertionError:
|
||||
raise TypeError('Argument given by name and position')
|
||||
if encoding is None:
|
||||
raise TypeError('unicode string argument without an encoding')
|
||||
###
|
||||
# Was: value = args[0].encode(**kwargs)
|
||||
# Python 2.6 string encode() method doesn't take kwargs:
|
||||
# Use this instead:
|
||||
newargs = [encoding]
|
||||
if errors is not None:
|
||||
newargs.append(errors)
|
||||
value = args[0].encode(*newargs)
|
||||
###
|
||||
elif hasattr(args[0], '__bytes__'):
|
||||
value = args[0].__bytes__()
|
||||
elif isinstance(args[0], Iterable):
|
||||
if len(args[0]) == 0:
|
||||
# This could be an empty list or tuple. Return b'' as on Py3.
|
||||
value = b''
|
||||
else:
|
||||
# Was: elif len(args[0])>0 and isinstance(args[0][0], Integral):
|
||||
# # It's a list of integers
|
||||
# But then we can't index into e.g. frozensets. Try to proceed
|
||||
# anyway.
|
||||
try:
|
||||
value = bytearray([_newchr(x) for x in args[0]])
|
||||
except:
|
||||
raise ValueError('bytes must be in range(0, 256)')
|
||||
elif isinstance(args[0], Integral):
|
||||
if args[0] < 0:
|
||||
raise ValueError('negative count')
|
||||
value = b'\x00' * args[0]
|
||||
else:
|
||||
value = args[0]
|
||||
if type(value) == newbytes:
|
||||
# Above we use type(...) rather than isinstance(...) because the
|
||||
# newbytes metaclass overrides __instancecheck__.
|
||||
# oldbytes(value) gives the wrong thing on Py2: the same
|
||||
# result as str(value) on Py3, e.g. "b'abc'". (Issue #193).
|
||||
# So we handle this case separately:
|
||||
return copy.copy(value)
|
||||
else:
|
||||
return super(newbytes, cls).__new__(cls, value)
|
||||
|
||||
def __repr__(self):
|
||||
return 'b' + super(newbytes, self).__repr__()
|
||||
|
||||
def __str__(self):
|
||||
return 'b' + "'{0}'".format(super(newbytes, self).__str__())
|
||||
|
||||
def __getitem__(self, y):
|
||||
value = super(newbytes, self).__getitem__(y)
|
||||
if isinstance(y, Integral):
|
||||
return ord(value)
|
||||
else:
|
||||
return newbytes(value)
|
||||
|
||||
def __getslice__(self, *args):
|
||||
return self.__getitem__(slice(*args))
|
||||
|
||||
def __contains__(self, key):
|
||||
if isinstance(key, int):
|
||||
newbyteskey = newbytes([key])
|
||||
# Don't use isinstance() here because we only want to catch
|
||||
# newbytes, not Python 2 str:
|
||||
elif type(key) == newbytes:
|
||||
newbyteskey = key
|
||||
else:
|
||||
newbyteskey = newbytes(key)
|
||||
return issubset(list(newbyteskey), list(self))
|
||||
|
||||
@no(unicode)
|
||||
def __add__(self, other):
|
||||
return newbytes(super(newbytes, self).__add__(other))
|
||||
|
||||
@no(unicode)
|
||||
def __radd__(self, left):
|
||||
return newbytes(left) + self
|
||||
|
||||
@no(unicode)
|
||||
def __mul__(self, other):
|
||||
return newbytes(super(newbytes, self).__mul__(other))
|
||||
|
||||
@no(unicode)
|
||||
def __rmul__(self, other):
|
||||
return newbytes(super(newbytes, self).__rmul__(other))
|
||||
|
||||
def __mod__(self, vals):
|
||||
if isinstance(vals, newbytes):
|
||||
vals = _builtin_bytes.__str__(vals)
|
||||
|
||||
elif isinstance(vals, tuple):
|
||||
newvals = []
|
||||
for v in vals:
|
||||
if isinstance(v, newbytes):
|
||||
v = _builtin_bytes.__str__(v)
|
||||
newvals.append(v)
|
||||
vals = tuple(newvals)
|
||||
|
||||
elif (hasattr(vals.__class__, '__getitem__') and
|
||||
hasattr(vals.__class__, 'iteritems')):
|
||||
for k, v in vals.iteritems():
|
||||
if isinstance(v, newbytes):
|
||||
vals[k] = _builtin_bytes.__str__(v)
|
||||
|
||||
return _builtin_bytes.__mod__(self, vals)
|
||||
|
||||
def __imod__(self, other):
|
||||
return self.__mod__(other)
|
||||
|
||||
def join(self, iterable_of_bytes):
|
||||
errmsg = 'sequence item {0}: expected bytes, {1} found'
|
||||
if isbytes(iterable_of_bytes) or istext(iterable_of_bytes):
|
||||
raise TypeError(errmsg.format(0, type(iterable_of_bytes)))
|
||||
for i, item in enumerate(iterable_of_bytes):
|
||||
if istext(item):
|
||||
raise TypeError(errmsg.format(i, type(item)))
|
||||
return newbytes(super(newbytes, self).join(iterable_of_bytes))
|
||||
|
||||
@classmethod
|
||||
def fromhex(cls, string):
|
||||
# Only on Py2:
|
||||
return cls(string.replace(' ', '').decode('hex'))
|
||||
|
||||
@no(unicode)
|
||||
def find(self, sub, *args):
|
||||
return super(newbytes, self).find(sub, *args)
|
||||
|
||||
@no(unicode)
|
||||
def rfind(self, sub, *args):
|
||||
return super(newbytes, self).rfind(sub, *args)
|
||||
|
||||
@no(unicode, (1, 2))
|
||||
def replace(self, old, new, *args):
|
||||
return newbytes(super(newbytes, self).replace(old, new, *args))
|
||||
|
||||
def encode(self, *args):
|
||||
raise AttributeError("encode method has been disabled in newbytes")
|
||||
|
||||
def decode(self, encoding='utf-8', errors='strict'):
|
||||
"""
|
||||
Returns a newstr (i.e. unicode subclass)
|
||||
|
||||
Decode B using the codec registered for encoding. Default encoding
|
||||
is 'utf-8'. errors may be given to set a different error
|
||||
handling scheme. Default is 'strict' meaning that encoding errors raise
|
||||
a UnicodeDecodeError. Other possible values are 'ignore' and 'replace'
|
||||
as well as any other name registered with codecs.register_error that is
|
||||
able to handle UnicodeDecodeErrors.
|
||||
"""
|
||||
# Py2 str.encode() takes encoding and errors as optional parameter,
|
||||
# not keyword arguments as in Python 3 str.
|
||||
|
||||
from future.types.newstr import newstr
|
||||
|
||||
if errors == 'surrogateescape':
|
||||
from future.utils.surrogateescape import register_surrogateescape
|
||||
register_surrogateescape()
|
||||
|
||||
return newstr(super(newbytes, self).decode(encoding, errors))
|
||||
|
||||
# This is currently broken:
|
||||
# # We implement surrogateescape error handling here in addition rather
|
||||
# # than relying on the custom error handler from
|
||||
# # future.utils.surrogateescape to be registered globally, even though
|
||||
# # that is fine in the case of decoding. (But not encoding: see the
|
||||
# # comments in newstr.encode()``.)
|
||||
#
|
||||
# if errors == 'surrogateescape':
|
||||
# # Decode char by char
|
||||
# mybytes = []
|
||||
# for code in self:
|
||||
# # Code is an int
|
||||
# if 0x80 <= code <= 0xFF:
|
||||
# b = 0xDC00 + code
|
||||
# elif code <= 0x7F:
|
||||
# b = _unichr(c).decode(encoding=encoding)
|
||||
# else:
|
||||
# # # It may be a bad byte
|
||||
# # FIXME: What to do in this case? See the Py3 docs / tests.
|
||||
# # # Try swallowing it.
|
||||
# # continue
|
||||
# # print("RAISE!")
|
||||
# raise NotASurrogateError
|
||||
# mybytes.append(b)
|
||||
# return newbytes(mybytes)
|
||||
# return newbytes(super(newstr, self).decode(encoding, errors))
|
||||
|
||||
@no(unicode)
|
||||
def startswith(self, prefix, *args):
|
||||
return super(newbytes, self).startswith(prefix, *args)
|
||||
|
||||
@no(unicode)
|
||||
def endswith(self, prefix, *args):
|
||||
return super(newbytes, self).endswith(prefix, *args)
|
||||
|
||||
@no(unicode)
|
||||
def split(self, sep=None, maxsplit=-1):
|
||||
# Py2 str.split() takes maxsplit as an optional parameter, not as a
|
||||
# keyword argument as in Python 3 bytes.
|
||||
parts = super(newbytes, self).split(sep, maxsplit)
|
||||
return [newbytes(part) for part in parts]
|
||||
|
||||
def splitlines(self, keepends=False):
|
||||
"""
|
||||
B.splitlines([keepends]) -> list of lines
|
||||
|
||||
Return a list of the lines in B, breaking at line boundaries.
|
||||
Line breaks are not included in the resulting list unless keepends
|
||||
is given and true.
|
||||
"""
|
||||
# Py2 str.splitlines() takes keepends as an optional parameter,
|
||||
# not as a keyword argument as in Python 3 bytes.
|
||||
parts = super(newbytes, self).splitlines(keepends)
|
||||
return [newbytes(part) for part in parts]
|
||||
|
||||
@no(unicode)
|
||||
def rsplit(self, sep=None, maxsplit=-1):
|
||||
# Py2 str.rsplit() takes maxsplit as an optional parameter, not as a
|
||||
# keyword argument as in Python 3 bytes.
|
||||
parts = super(newbytes, self).rsplit(sep, maxsplit)
|
||||
return [newbytes(part) for part in parts]
|
||||
|
||||
@no(unicode)
|
||||
def partition(self, sep):
|
||||
parts = super(newbytes, self).partition(sep)
|
||||
return tuple(newbytes(part) for part in parts)
|
||||
|
||||
@no(unicode)
|
||||
def rpartition(self, sep):
|
||||
parts = super(newbytes, self).rpartition(sep)
|
||||
return tuple(newbytes(part) for part in parts)
|
||||
|
||||
@no(unicode, (1,))
|
||||
def rindex(self, sub, *args):
|
||||
'''
|
||||
S.rindex(sub [,start [,end]]) -> int
|
||||
|
||||
Like S.rfind() but raise ValueError when the substring is not found.
|
||||
'''
|
||||
pos = self.rfind(sub, *args)
|
||||
if pos == -1:
|
||||
raise ValueError('substring not found')
|
||||
|
||||
@no(unicode)
|
||||
def index(self, sub, *args):
|
||||
'''
|
||||
Returns index of sub in bytes.
|
||||
Raises ValueError if byte is not in bytes and TypeError if can't
|
||||
be converted bytes or its length is not 1.
|
||||
'''
|
||||
if isinstance(sub, int):
|
||||
if len(args) == 0:
|
||||
start, end = 0, len(self)
|
||||
elif len(args) == 1:
|
||||
start = args[0]
|
||||
elif len(args) == 2:
|
||||
start, end = args
|
||||
else:
|
||||
raise TypeError('takes at most 3 arguments')
|
||||
return list(self)[start:end].index(sub)
|
||||
if not isinstance(sub, bytes):
|
||||
try:
|
||||
sub = self.__class__(sub)
|
||||
except (TypeError, ValueError):
|
||||
raise TypeError("can't convert sub to bytes")
|
||||
try:
|
||||
return super(newbytes, self).index(sub, *args)
|
||||
except ValueError:
|
||||
raise ValueError('substring not found')
|
||||
|
||||
def __eq__(self, other):
|
||||
if isinstance(other, (_builtin_bytes, bytearray)):
|
||||
return super(newbytes, self).__eq__(other)
|
||||
else:
|
||||
return False
|
||||
|
||||
def __ne__(self, other):
|
||||
if isinstance(other, _builtin_bytes):
|
||||
return super(newbytes, self).__ne__(other)
|
||||
else:
|
||||
return True
|
||||
|
||||
unorderable_err = 'unorderable types: bytes() and {0}'
|
||||
|
||||
def __lt__(self, other):
|
||||
if isinstance(other, _builtin_bytes):
|
||||
return super(newbytes, self).__lt__(other)
|
||||
raise TypeError(self.unorderable_err.format(type(other)))
|
||||
|
||||
def __le__(self, other):
|
||||
if isinstance(other, _builtin_bytes):
|
||||
return super(newbytes, self).__le__(other)
|
||||
raise TypeError(self.unorderable_err.format(type(other)))
|
||||
|
||||
def __gt__(self, other):
|
||||
if isinstance(other, _builtin_bytes):
|
||||
return super(newbytes, self).__gt__(other)
|
||||
raise TypeError(self.unorderable_err.format(type(other)))
|
||||
|
||||
def __ge__(self, other):
|
||||
if isinstance(other, _builtin_bytes):
|
||||
return super(newbytes, self).__ge__(other)
|
||||
raise TypeError(self.unorderable_err.format(type(other)))
|
||||
|
||||
def __native__(self):
|
||||
# We can't just feed a newbytes object into str(), because
|
||||
# newbytes.__str__() returns e.g. "b'blah'", consistent with Py3 bytes.
|
||||
return super(newbytes, self).__str__()
|
||||
|
||||
def __getattribute__(self, name):
|
||||
"""
|
||||
A trick to cause the ``hasattr`` builtin-fn to return False for
|
||||
the 'encode' method on Py2.
|
||||
"""
|
||||
if name in ['encode', u'encode']:
|
||||
raise AttributeError("encode method has been disabled in newbytes")
|
||||
return super(newbytes, self).__getattribute__(name)
|
||||
|
||||
@no(unicode)
|
||||
def rstrip(self, bytes_to_strip=None):
|
||||
"""
|
||||
Strip trailing bytes contained in the argument.
|
||||
If the argument is omitted, strip trailing ASCII whitespace.
|
||||
"""
|
||||
return newbytes(super(newbytes, self).rstrip(bytes_to_strip))
|
||||
|
||||
@no(unicode)
|
||||
def strip(self, bytes_to_strip=None):
|
||||
"""
|
||||
Strip leading and trailing bytes contained in the argument.
|
||||
If the argument is omitted, strip trailing ASCII whitespace.
|
||||
"""
|
||||
return newbytes(super(newbytes, self).strip(bytes_to_strip))
|
||||
|
||||
def lower(self):
|
||||
"""
|
||||
b.lower() -> copy of b
|
||||
|
||||
Return a copy of b with all ASCII characters converted to lowercase.
|
||||
"""
|
||||
return newbytes(super(newbytes, self).lower())
|
||||
|
||||
@no(unicode)
|
||||
def upper(self):
|
||||
"""
|
||||
b.upper() -> copy of b
|
||||
|
||||
Return a copy of b with all ASCII characters converted to uppercase.
|
||||
"""
|
||||
return newbytes(super(newbytes, self).upper())
|
||||
|
||||
@classmethod
|
||||
@no(unicode)
|
||||
def maketrans(cls, frm, to):
|
||||
"""
|
||||
B.maketrans(frm, to) -> translation table
|
||||
|
||||
Return a translation table (a bytes object of length 256) suitable
|
||||
for use in the bytes or bytearray translate method where each byte
|
||||
in frm is mapped to the byte at the same position in to.
|
||||
The bytes objects frm and to must be of the same length.
|
||||
"""
|
||||
return newbytes(string.maketrans(frm, to))
|
||||
|
||||
|
||||
__all__ = ['newbytes']
|
111
lib/future/types/newdict.py
Normal file
111
lib/future/types/newdict.py
Normal file
|
@ -0,0 +1,111 @@
|
|||
"""
|
||||
A dict subclass for Python 2 that behaves like Python 3's dict
|
||||
|
||||
Example use:
|
||||
|
||||
>>> from builtins import dict
|
||||
>>> d1 = dict() # instead of {} for an empty dict
|
||||
>>> d2 = dict(key1='value1', key2='value2')
|
||||
|
||||
The keys, values and items methods now return iterators on Python 2.x
|
||||
(with set-like behaviour on Python 2.7).
|
||||
|
||||
>>> for d in (d1, d2):
|
||||
... assert not isinstance(d.keys(), list)
|
||||
... assert not isinstance(d.values(), list)
|
||||
... assert not isinstance(d.items(), list)
|
||||
"""
|
||||
|
||||
import sys
|
||||
|
||||
from future.utils import with_metaclass
|
||||
from future.types.newobject import newobject
|
||||
|
||||
|
||||
_builtin_dict = dict
|
||||
ver = sys.version_info[:2]
|
||||
|
||||
|
||||
class BaseNewDict(type):
|
||||
def __instancecheck__(cls, instance):
|
||||
if cls == newdict:
|
||||
return isinstance(instance, _builtin_dict)
|
||||
else:
|
||||
return issubclass(instance.__class__, cls)
|
||||
|
||||
|
||||
class newdict(with_metaclass(BaseNewDict, _builtin_dict)):
|
||||
"""
|
||||
A backport of the Python 3 dict object to Py2
|
||||
"""
|
||||
def items(self):
|
||||
"""
|
||||
On Python 2.7+:
|
||||
D.items() -> a set-like object providing a view on D's items
|
||||
On Python 2.6:
|
||||
D.items() -> an iterator over D's items
|
||||
"""
|
||||
if ver == (2, 7):
|
||||
return self.viewitems()
|
||||
elif ver == (2, 6):
|
||||
return self.iteritems()
|
||||
elif ver >= (3, 0):
|
||||
return self.items()
|
||||
|
||||
def keys(self):
|
||||
"""
|
||||
On Python 2.7+:
|
||||
D.keys() -> a set-like object providing a view on D's keys
|
||||
On Python 2.6:
|
||||
D.keys() -> an iterator over D's keys
|
||||
"""
|
||||
if ver == (2, 7):
|
||||
return self.viewkeys()
|
||||
elif ver == (2, 6):
|
||||
return self.iterkeys()
|
||||
elif ver >= (3, 0):
|
||||
return self.keys()
|
||||
|
||||
def values(self):
|
||||
"""
|
||||
On Python 2.7+:
|
||||
D.values() -> a set-like object providing a view on D's values
|
||||
On Python 2.6:
|
||||
D.values() -> an iterator over D's values
|
||||
"""
|
||||
if ver == (2, 7):
|
||||
return self.viewvalues()
|
||||
elif ver == (2, 6):
|
||||
return self.itervalues()
|
||||
elif ver >= (3, 0):
|
||||
return self.values()
|
||||
|
||||
def __new__(cls, *args, **kwargs):
|
||||
"""
|
||||
dict() -> new empty dictionary
|
||||
dict(mapping) -> new dictionary initialized from a mapping object's
|
||||
(key, value) pairs
|
||||
dict(iterable) -> new dictionary initialized as if via:
|
||||
d = {}
|
||||
for k, v in iterable:
|
||||
d[k] = v
|
||||
dict(**kwargs) -> new dictionary initialized with the name=value pairs
|
||||
in the keyword argument list. For example: dict(one=1, two=2)
|
||||
"""
|
||||
|
||||
if len(args) == 0:
|
||||
return super(newdict, cls).__new__(cls)
|
||||
elif type(args[0]) == newdict:
|
||||
value = args[0]
|
||||
else:
|
||||
value = args[0]
|
||||
return super(newdict, cls).__new__(cls, value)
|
||||
|
||||
def __native__(self):
|
||||
"""
|
||||
Hook for the future.utils.native() function
|
||||
"""
|
||||
return dict(self)
|
||||
|
||||
|
||||
__all__ = ['newdict']
|
381
lib/future/types/newint.py
Normal file
381
lib/future/types/newint.py
Normal file
|
@ -0,0 +1,381 @@
|
|||
"""
|
||||
Backport of Python 3's int, based on Py2's long.
|
||||
|
||||
They are very similar. The most notable difference is:
|
||||
|
||||
- representation: trailing L in Python 2 removed in Python 3
|
||||
"""
|
||||
from __future__ import division
|
||||
|
||||
import struct
|
||||
|
||||
from future.types.newbytes import newbytes
|
||||
from future.types.newobject import newobject
|
||||
from future.utils import PY3, isint, istext, isbytes, with_metaclass, native
|
||||
|
||||
|
||||
if PY3:
|
||||
long = int
|
||||
from collections.abc import Iterable
|
||||
else:
|
||||
from collections import Iterable
|
||||
|
||||
|
||||
class BaseNewInt(type):
|
||||
def __instancecheck__(cls, instance):
|
||||
if cls == newint:
|
||||
# Special case for Py2 short or long int
|
||||
return isinstance(instance, (int, long))
|
||||
else:
|
||||
return issubclass(instance.__class__, cls)
|
||||
|
||||
|
||||
class newint(with_metaclass(BaseNewInt, long)):
|
||||
"""
|
||||
A backport of the Python 3 int object to Py2
|
||||
"""
|
||||
def __new__(cls, x=0, base=10):
|
||||
"""
|
||||
From the Py3 int docstring:
|
||||
|
||||
| int(x=0) -> integer
|
||||
| int(x, base=10) -> integer
|
||||
|
|
||||
| Convert a number or string to an integer, or return 0 if no
|
||||
| arguments are given. If x is a number, return x.__int__(). For
|
||||
| floating point numbers, this truncates towards zero.
|
||||
|
|
||||
| If x is not a number or if base is given, then x must be a string,
|
||||
| bytes, or bytearray instance representing an integer literal in the
|
||||
| given base. The literal can be preceded by '+' or '-' and be
|
||||
| surrounded by whitespace. The base defaults to 10. Valid bases are
|
||||
| 0 and 2-36. Base 0 means to interpret the base from the string as an
|
||||
| integer literal.
|
||||
| >>> int('0b100', base=0)
|
||||
| 4
|
||||
|
||||
"""
|
||||
try:
|
||||
val = x.__int__()
|
||||
except AttributeError:
|
||||
val = x
|
||||
else:
|
||||
if not isint(val):
|
||||
raise TypeError('__int__ returned non-int ({0})'.format(
|
||||
type(val)))
|
||||
|
||||
if base != 10:
|
||||
# Explicit base
|
||||
if not (istext(val) or isbytes(val) or isinstance(val, bytearray)):
|
||||
raise TypeError(
|
||||
"int() can't convert non-string with explicit base")
|
||||
try:
|
||||
return super(newint, cls).__new__(cls, val, base)
|
||||
except TypeError:
|
||||
return super(newint, cls).__new__(cls, newbytes(val), base)
|
||||
# After here, base is 10
|
||||
try:
|
||||
return super(newint, cls).__new__(cls, val)
|
||||
except TypeError:
|
||||
# Py2 long doesn't handle bytearray input with an explicit base, so
|
||||
# handle this here.
|
||||
# Py3: int(bytearray(b'10'), 2) == 2
|
||||
# Py2: int(bytearray(b'10'), 2) == 2 raises TypeError
|
||||
# Py2: long(bytearray(b'10'), 2) == 2 raises TypeError
|
||||
try:
|
||||
return super(newint, cls).__new__(cls, newbytes(val))
|
||||
except:
|
||||
raise TypeError("newint argument must be a string or a number,"
|
||||
"not '{0}'".format(type(val)))
|
||||
|
||||
def __repr__(self):
|
||||
"""
|
||||
Without the L suffix
|
||||
"""
|
||||
value = super(newint, self).__repr__()
|
||||
assert value[-1] == 'L'
|
||||
return value[:-1]
|
||||
|
||||
def __add__(self, other):
|
||||
value = super(newint, self).__add__(other)
|
||||
if value is NotImplemented:
|
||||
return long(self) + other
|
||||
return newint(value)
|
||||
|
||||
def __radd__(self, other):
|
||||
value = super(newint, self).__radd__(other)
|
||||
if value is NotImplemented:
|
||||
return other + long(self)
|
||||
return newint(value)
|
||||
|
||||
def __sub__(self, other):
|
||||
value = super(newint, self).__sub__(other)
|
||||
if value is NotImplemented:
|
||||
return long(self) - other
|
||||
return newint(value)
|
||||
|
||||
def __rsub__(self, other):
|
||||
value = super(newint, self).__rsub__(other)
|
||||
if value is NotImplemented:
|
||||
return other - long(self)
|
||||
return newint(value)
|
||||
|
||||
def __mul__(self, other):
|
||||
value = super(newint, self).__mul__(other)
|
||||
if isint(value):
|
||||
return newint(value)
|
||||
elif value is NotImplemented:
|
||||
return long(self) * other
|
||||
return value
|
||||
|
||||
def __rmul__(self, other):
|
||||
value = super(newint, self).__rmul__(other)
|
||||
if isint(value):
|
||||
return newint(value)
|
||||
elif value is NotImplemented:
|
||||
return other * long(self)
|
||||
return value
|
||||
|
||||
def __div__(self, other):
|
||||
# We override this rather than e.g. relying on object.__div__ or
|
||||
# long.__div__ because we want to wrap the value in a newint()
|
||||
# call if other is another int
|
||||
value = long(self) / other
|
||||
if isinstance(other, (int, long)):
|
||||
return newint(value)
|
||||
else:
|
||||
return value
|
||||
|
||||
def __rdiv__(self, other):
|
||||
value = other / long(self)
|
||||
if isinstance(other, (int, long)):
|
||||
return newint(value)
|
||||
else:
|
||||
return value
|
||||
|
||||
def __idiv__(self, other):
|
||||
# long has no __idiv__ method. Use __itruediv__ and cast back to
|
||||
# newint:
|
||||
value = self.__itruediv__(other)
|
||||
if isinstance(other, (int, long)):
|
||||
return newint(value)
|
||||
else:
|
||||
return value
|
||||
|
||||
def __truediv__(self, other):
|
||||
value = super(newint, self).__truediv__(other)
|
||||
if value is NotImplemented:
|
||||
value = long(self) / other
|
||||
return value
|
||||
|
||||
def __rtruediv__(self, other):
|
||||
return super(newint, self).__rtruediv__(other)
|
||||
|
||||
def __itruediv__(self, other):
|
||||
# long has no __itruediv__ method
|
||||
mylong = long(self)
|
||||
mylong /= other
|
||||
return mylong
|
||||
|
||||
def __floordiv__(self, other):
|
||||
return newint(super(newint, self).__floordiv__(other))
|
||||
|
||||
def __rfloordiv__(self, other):
|
||||
return newint(super(newint, self).__rfloordiv__(other))
|
||||
|
||||
def __ifloordiv__(self, other):
|
||||
# long has no __ifloordiv__ method
|
||||
mylong = long(self)
|
||||
mylong //= other
|
||||
return newint(mylong)
|
||||
|
||||
def __mod__(self, other):
|
||||
value = super(newint, self).__mod__(other)
|
||||
if value is NotImplemented:
|
||||
return long(self) % other
|
||||
return newint(value)
|
||||
|
||||
def __rmod__(self, other):
|
||||
value = super(newint, self).__rmod__(other)
|
||||
if value is NotImplemented:
|
||||
return other % long(self)
|
||||
return newint(value)
|
||||
|
||||
def __divmod__(self, other):
|
||||
value = super(newint, self).__divmod__(other)
|
||||
if value is NotImplemented:
|
||||
mylong = long(self)
|
||||
return (mylong // other, mylong % other)
|
||||
return (newint(value[0]), newint(value[1]))
|
||||
|
||||
def __rdivmod__(self, other):
|
||||
value = super(newint, self).__rdivmod__(other)
|
||||
if value is NotImplemented:
|
||||
mylong = long(self)
|
||||
return (other // mylong, other % mylong)
|
||||
return (newint(value[0]), newint(value[1]))
|
||||
|
||||
def __pow__(self, other):
|
||||
value = super(newint, self).__pow__(other)
|
||||
if value is NotImplemented:
|
||||
return long(self) ** other
|
||||
return newint(value)
|
||||
|
||||
def __rpow__(self, other):
|
||||
value = super(newint, self).__rpow__(other)
|
||||
if value is NotImplemented:
|
||||
return other ** long(self)
|
||||
return newint(value)
|
||||
|
||||
def __lshift__(self, other):
|
||||
if not isint(other):
|
||||
raise TypeError(
|
||||
"unsupported operand type(s) for <<: '%s' and '%s'" %
|
||||
(type(self).__name__, type(other).__name__))
|
||||
return newint(super(newint, self).__lshift__(other))
|
||||
|
||||
def __rshift__(self, other):
|
||||
if not isint(other):
|
||||
raise TypeError(
|
||||
"unsupported operand type(s) for >>: '%s' and '%s'" %
|
||||
(type(self).__name__, type(other).__name__))
|
||||
return newint(super(newint, self).__rshift__(other))
|
||||
|
||||
def __and__(self, other):
|
||||
if not isint(other):
|
||||
raise TypeError(
|
||||
"unsupported operand type(s) for &: '%s' and '%s'" %
|
||||
(type(self).__name__, type(other).__name__))
|
||||
return newint(super(newint, self).__and__(other))
|
||||
|
||||
def __or__(self, other):
|
||||
if not isint(other):
|
||||
raise TypeError(
|
||||
"unsupported operand type(s) for |: '%s' and '%s'" %
|
||||
(type(self).__name__, type(other).__name__))
|
||||
return newint(super(newint, self).__or__(other))
|
||||
|
||||
def __xor__(self, other):
|
||||
if not isint(other):
|
||||
raise TypeError(
|
||||
"unsupported operand type(s) for ^: '%s' and '%s'" %
|
||||
(type(self).__name__, type(other).__name__))
|
||||
return newint(super(newint, self).__xor__(other))
|
||||
|
||||
def __neg__(self):
|
||||
return newint(super(newint, self).__neg__())
|
||||
|
||||
def __pos__(self):
|
||||
return newint(super(newint, self).__pos__())
|
||||
|
||||
def __abs__(self):
|
||||
return newint(super(newint, self).__abs__())
|
||||
|
||||
def __invert__(self):
|
||||
return newint(super(newint, self).__invert__())
|
||||
|
||||
def __int__(self):
|
||||
return self
|
||||
|
||||
def __nonzero__(self):
|
||||
return self.__bool__()
|
||||
|
||||
def __bool__(self):
|
||||
"""
|
||||
So subclasses can override this, Py3-style
|
||||
"""
|
||||
return super(newint, self).__nonzero__()
|
||||
|
||||
def __native__(self):
|
||||
return long(self)
|
||||
|
||||
def to_bytes(self, length, byteorder='big', signed=False):
|
||||
"""
|
||||
Return an array of bytes representing an integer.
|
||||
|
||||
The integer is represented using length bytes. An OverflowError is
|
||||
raised if the integer is not representable with the given number of
|
||||
bytes.
|
||||
|
||||
The byteorder argument determines the byte order used to represent the
|
||||
integer. If byteorder is 'big', the most significant byte is at the
|
||||
beginning of the byte array. If byteorder is 'little', the most
|
||||
significant byte is at the end of the byte array. To request the native
|
||||
byte order of the host system, use `sys.byteorder' as the byte order value.
|
||||
|
||||
The signed keyword-only argument determines whether two's complement is
|
||||
used to represent the integer. If signed is False and a negative integer
|
||||
is given, an OverflowError is raised.
|
||||
"""
|
||||
if length < 0:
|
||||
raise ValueError("length argument must be non-negative")
|
||||
if length == 0 and self == 0:
|
||||
return newbytes()
|
||||
if signed and self < 0:
|
||||
bits = length * 8
|
||||
num = (2**bits) + self
|
||||
if num <= 0:
|
||||
raise OverflowError("int too smal to convert")
|
||||
else:
|
||||
if self < 0:
|
||||
raise OverflowError("can't convert negative int to unsigned")
|
||||
num = self
|
||||
if byteorder not in ('little', 'big'):
|
||||
raise ValueError("byteorder must be either 'little' or 'big'")
|
||||
h = b'%x' % num
|
||||
s = newbytes((b'0'*(len(h) % 2) + h).zfill(length*2).decode('hex'))
|
||||
if signed:
|
||||
high_set = s[0] & 0x80
|
||||
if self > 0 and high_set:
|
||||
raise OverflowError("int too big to convert")
|
||||
if self < 0 and not high_set:
|
||||
raise OverflowError("int too small to convert")
|
||||
if len(s) > length:
|
||||
raise OverflowError("int too big to convert")
|
||||
return s if byteorder == 'big' else s[::-1]
|
||||
|
||||
@classmethod
|
||||
def from_bytes(cls, mybytes, byteorder='big', signed=False):
|
||||
"""
|
||||
Return the integer represented by the given array of bytes.
|
||||
|
||||
The mybytes argument must either support the buffer protocol or be an
|
||||
iterable object producing bytes. Bytes and bytearray are examples of
|
||||
built-in objects that support the buffer protocol.
|
||||
|
||||
The byteorder argument determines the byte order used to represent the
|
||||
integer. If byteorder is 'big', the most significant byte is at the
|
||||
beginning of the byte array. If byteorder is 'little', the most
|
||||
significant byte is at the end of the byte array. To request the native
|
||||
byte order of the host system, use `sys.byteorder' as the byte order value.
|
||||
|
||||
The signed keyword-only argument indicates whether two's complement is
|
||||
used to represent the integer.
|
||||
"""
|
||||
if byteorder not in ('little', 'big'):
|
||||
raise ValueError("byteorder must be either 'little' or 'big'")
|
||||
if isinstance(mybytes, unicode):
|
||||
raise TypeError("cannot convert unicode objects to bytes")
|
||||
# mybytes can also be passed as a sequence of integers on Py3.
|
||||
# Test for this:
|
||||
elif isinstance(mybytes, Iterable):
|
||||
mybytes = newbytes(mybytes)
|
||||
b = mybytes if byteorder == 'big' else mybytes[::-1]
|
||||
if len(b) == 0:
|
||||
b = b'\x00'
|
||||
# The encode() method has been disabled by newbytes, but Py2's
|
||||
# str has it:
|
||||
num = int(native(b).encode('hex'), 16)
|
||||
if signed and (b[0] & 0x80):
|
||||
num = num - (2 ** (len(b)*8))
|
||||
return cls(num)
|
||||
|
||||
|
||||
# def _twos_comp(val, bits):
|
||||
# """compute the 2's compliment of int value val"""
|
||||
# if( (val&(1<<(bits-1))) != 0 ):
|
||||
# val = val - (1<<bits)
|
||||
# return val
|
||||
|
||||
|
||||
__all__ = ['newint']
|
95
lib/future/types/newlist.py
Normal file
95
lib/future/types/newlist.py
Normal file
|
@ -0,0 +1,95 @@
|
|||
"""
|
||||
A list subclass for Python 2 that behaves like Python 3's list.
|
||||
|
||||
The primary difference is that lists have a .copy() method in Py3.
|
||||
|
||||
Example use:
|
||||
|
||||
>>> from builtins import list
|
||||
>>> l1 = list() # instead of {} for an empty list
|
||||
>>> l1.append('hello')
|
||||
>>> l2 = l1.copy()
|
||||
|
||||
"""
|
||||
|
||||
import sys
|
||||
import copy
|
||||
|
||||
from future.utils import with_metaclass
|
||||
from future.types.newobject import newobject
|
||||
|
||||
|
||||
_builtin_list = list
|
||||
ver = sys.version_info[:2]
|
||||
|
||||
|
||||
class BaseNewList(type):
|
||||
def __instancecheck__(cls, instance):
|
||||
if cls == newlist:
|
||||
return isinstance(instance, _builtin_list)
|
||||
else:
|
||||
return issubclass(instance.__class__, cls)
|
||||
|
||||
|
||||
class newlist(with_metaclass(BaseNewList, _builtin_list)):
|
||||
"""
|
||||
A backport of the Python 3 list object to Py2
|
||||
"""
|
||||
def copy(self):
|
||||
"""
|
||||
L.copy() -> list -- a shallow copy of L
|
||||
"""
|
||||
return copy.copy(self)
|
||||
|
||||
def clear(self):
|
||||
"""L.clear() -> None -- remove all items from L"""
|
||||
for i in range(len(self)):
|
||||
self.pop()
|
||||
|
||||
def __new__(cls, *args, **kwargs):
|
||||
"""
|
||||
list() -> new empty list
|
||||
list(iterable) -> new list initialized from iterable's items
|
||||
"""
|
||||
|
||||
if len(args) == 0:
|
||||
return super(newlist, cls).__new__(cls)
|
||||
elif type(args[0]) == newlist:
|
||||
value = args[0]
|
||||
else:
|
||||
value = args[0]
|
||||
return super(newlist, cls).__new__(cls, value)
|
||||
|
||||
def __add__(self, value):
|
||||
return newlist(super(newlist, self).__add__(value))
|
||||
|
||||
def __radd__(self, left):
|
||||
" left + self "
|
||||
try:
|
||||
return newlist(left) + self
|
||||
except:
|
||||
return NotImplemented
|
||||
|
||||
def __getitem__(self, y):
|
||||
"""
|
||||
x.__getitem__(y) <==> x[y]
|
||||
|
||||
Warning: a bug in Python 2.x prevents indexing via a slice from
|
||||
returning a newlist object.
|
||||
"""
|
||||
if isinstance(y, slice):
|
||||
return newlist(super(newlist, self).__getitem__(y))
|
||||
else:
|
||||
return super(newlist, self).__getitem__(y)
|
||||
|
||||
def __native__(self):
|
||||
"""
|
||||
Hook for the future.utils.native() function
|
||||
"""
|
||||
return list(self)
|
||||
|
||||
def __nonzero__(self):
|
||||
return len(self) > 0
|
||||
|
||||
|
||||
__all__ = ['newlist']
|
29
lib/future/types/newmemoryview.py
Normal file
29
lib/future/types/newmemoryview.py
Normal file
|
@ -0,0 +1,29 @@
|
|||
"""
|
||||
A pretty lame implementation of a memoryview object for Python 2.6.
|
||||
"""
|
||||
from numbers import Integral
|
||||
import string
|
||||
|
||||
from future.utils import istext, isbytes, PY2, with_metaclass
|
||||
from future.types import no, issubset
|
||||
|
||||
if PY2:
|
||||
from collections import Iterable
|
||||
else:
|
||||
from collections.abc import Iterable
|
||||
|
||||
# class BaseNewBytes(type):
|
||||
# def __instancecheck__(cls, instance):
|
||||
# return isinstance(instance, _builtin_bytes)
|
||||
|
||||
|
||||
class newmemoryview(object): # with_metaclass(BaseNewBytes, _builtin_bytes)):
|
||||
"""
|
||||
A pretty lame backport of the Python 2.7 and Python 3.x
|
||||
memoryviewview object to Py2.6.
|
||||
"""
|
||||
def __init__(self, obj):
|
||||
return obj
|
||||
|
||||
|
||||
__all__ = ['newmemoryview']
|
117
lib/future/types/newobject.py
Normal file
117
lib/future/types/newobject.py
Normal file
|
@ -0,0 +1,117 @@
|
|||
"""
|
||||
An object subclass for Python 2 that gives new-style classes written in the
|
||||
style of Python 3 (with ``__next__`` and unicode-returning ``__str__`` methods)
|
||||
the appropriate Python 2-style ``next`` and ``__unicode__`` methods for compatible.
|
||||
|
||||
Example use::
|
||||
|
||||
from builtins import object
|
||||
|
||||
my_unicode_str = u'Unicode string: \u5b54\u5b50'
|
||||
|
||||
class A(object):
|
||||
def __str__(self):
|
||||
return my_unicode_str
|
||||
|
||||
a = A()
|
||||
print(str(a))
|
||||
|
||||
# On Python 2, these relations hold:
|
||||
assert unicode(a) == my_unicode_string
|
||||
assert str(a) == my_unicode_string.encode('utf-8')
|
||||
|
||||
|
||||
Another example::
|
||||
|
||||
from builtins import object
|
||||
|
||||
class Upper(object):
|
||||
def __init__(self, iterable):
|
||||
self._iter = iter(iterable)
|
||||
def __next__(self): # note the Py3 interface
|
||||
return next(self._iter).upper()
|
||||
def __iter__(self):
|
||||
return self
|
||||
|
||||
assert list(Upper('hello')) == list('HELLO')
|
||||
|
||||
"""
|
||||
|
||||
|
||||
class newobject(object):
|
||||
"""
|
||||
A magical object class that provides Python 2 compatibility methods::
|
||||
next
|
||||
__unicode__
|
||||
__nonzero__
|
||||
|
||||
Subclasses of this class can merely define the Python 3 methods (__next__,
|
||||
__str__, and __bool__).
|
||||
"""
|
||||
def next(self):
|
||||
if hasattr(self, '__next__'):
|
||||
return type(self).__next__(self)
|
||||
raise TypeError('newobject is not an iterator')
|
||||
|
||||
def __unicode__(self):
|
||||
# All subclasses of the builtin object should have __str__ defined.
|
||||
# Note that old-style classes do not have __str__ defined.
|
||||
if hasattr(self, '__str__'):
|
||||
s = type(self).__str__(self)
|
||||
else:
|
||||
s = str(self)
|
||||
if isinstance(s, unicode):
|
||||
return s
|
||||
else:
|
||||
return s.decode('utf-8')
|
||||
|
||||
def __nonzero__(self):
|
||||
if hasattr(self, '__bool__'):
|
||||
return type(self).__bool__(self)
|
||||
if hasattr(self, '__len__'):
|
||||
return type(self).__len__(self)
|
||||
# object has no __nonzero__ method
|
||||
return True
|
||||
|
||||
# Are these ever needed?
|
||||
# def __div__(self):
|
||||
# return self.__truediv__()
|
||||
|
||||
# def __idiv__(self, other):
|
||||
# return self.__itruediv__(other)
|
||||
|
||||
def __long__(self):
|
||||
if not hasattr(self, '__int__'):
|
||||
return NotImplemented
|
||||
return self.__int__() # not type(self).__int__(self)
|
||||
|
||||
# def __new__(cls, *args, **kwargs):
|
||||
# """
|
||||
# dict() -> new empty dictionary
|
||||
# dict(mapping) -> new dictionary initialized from a mapping object's
|
||||
# (key, value) pairs
|
||||
# dict(iterable) -> new dictionary initialized as if via:
|
||||
# d = {}
|
||||
# for k, v in iterable:
|
||||
# d[k] = v
|
||||
# dict(**kwargs) -> new dictionary initialized with the name=value pairs
|
||||
# in the keyword argument list. For example: dict(one=1, two=2)
|
||||
# """
|
||||
|
||||
# if len(args) == 0:
|
||||
# return super(newdict, cls).__new__(cls)
|
||||
# elif type(args[0]) == newdict:
|
||||
# return args[0]
|
||||
# else:
|
||||
# value = args[0]
|
||||
# return super(newdict, cls).__new__(cls, value)
|
||||
|
||||
def __native__(self):
|
||||
"""
|
||||
Hook for the future.utils.native() function
|
||||
"""
|
||||
return object(self)
|
||||
|
||||
__slots__ = []
|
||||
|
||||
__all__ = ['newobject']
|
32
lib/future/types/newopen.py
Normal file
32
lib/future/types/newopen.py
Normal file
|
@ -0,0 +1,32 @@
|
|||
"""
|
||||
A substitute for the Python 3 open() function.
|
||||
|
||||
Note that io.open() is more complete but maybe slower. Even so, the
|
||||
completeness may be a better default. TODO: compare these
|
||||
"""
|
||||
|
||||
_builtin_open = open
|
||||
|
||||
class newopen(object):
|
||||
"""Wrapper providing key part of Python 3 open() interface.
|
||||
|
||||
From IPython's py3compat.py module. License: BSD.
|
||||
"""
|
||||
def __init__(self, fname, mode="r", encoding="utf-8"):
|
||||
self.f = _builtin_open(fname, mode)
|
||||
self.enc = encoding
|
||||
|
||||
def write(self, s):
|
||||
return self.f.write(s.encode(self.enc))
|
||||
|
||||
def read(self, size=-1):
|
||||
return self.f.read(size).decode(self.enc)
|
||||
|
||||
def close(self):
|
||||
return self.f.close()
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
def __exit__(self, etype, value, traceback):
|
||||
self.f.close()
|
170
lib/future/types/newrange.py
Normal file
170
lib/future/types/newrange.py
Normal file
|
@ -0,0 +1,170 @@
|
|||
"""
|
||||
Nearly identical to xrange.py, by Dan Crosta, from
|
||||
|
||||
https://github.com/dcrosta/xrange.git
|
||||
|
||||
This is included here in the ``future`` package rather than pointed to as
|
||||
a dependency because there is no package for ``xrange`` on PyPI. It is
|
||||
also tweaked to appear like a regular Python 3 ``range`` object rather
|
||||
than a Python 2 xrange.
|
||||
|
||||
From Dan Crosta's README:
|
||||
|
||||
"A pure-Python implementation of Python 2.7's xrange built-in, with
|
||||
some features backported from the Python 3.x range built-in (which
|
||||
replaced xrange) in that version."
|
||||
|
||||
Read more at
|
||||
https://late.am/post/2012/06/18/what-the-heck-is-an-xrange
|
||||
"""
|
||||
from __future__ import absolute_import
|
||||
|
||||
from future.utils import PY2
|
||||
|
||||
if PY2:
|
||||
from collections import Sequence, Iterator
|
||||
else:
|
||||
from collections.abc import Sequence, Iterator
|
||||
from itertools import islice
|
||||
|
||||
from future.backports.misc import count # with step parameter on Py2.6
|
||||
# For backward compatibility with python-future versions < 0.14.4:
|
||||
_count = count
|
||||
|
||||
|
||||
class newrange(Sequence):
|
||||
"""
|
||||
Pure-Python backport of Python 3's range object. See `the CPython
|
||||
documentation for details:
|
||||
<http://docs.python.org/py3k/library/functions.html#range>`_
|
||||
"""
|
||||
|
||||
def __init__(self, *args):
|
||||
if len(args) == 1:
|
||||
start, stop, step = 0, args[0], 1
|
||||
elif len(args) == 2:
|
||||
start, stop, step = args[0], args[1], 1
|
||||
elif len(args) == 3:
|
||||
start, stop, step = args
|
||||
else:
|
||||
raise TypeError('range() requires 1-3 int arguments')
|
||||
|
||||
try:
|
||||
start, stop, step = int(start), int(stop), int(step)
|
||||
except ValueError:
|
||||
raise TypeError('an integer is required')
|
||||
|
||||
if step == 0:
|
||||
raise ValueError('range() arg 3 must not be zero')
|
||||
elif step < 0:
|
||||
stop = min(stop, start)
|
||||
else:
|
||||
stop = max(stop, start)
|
||||
|
||||
self._start = start
|
||||
self._stop = stop
|
||||
self._step = step
|
||||
self._len = (stop - start) // step + bool((stop - start) % step)
|
||||
|
||||
@property
|
||||
def start(self):
|
||||
return self._start
|
||||
|
||||
@property
|
||||
def stop(self):
|
||||
return self._stop
|
||||
|
||||
@property
|
||||
def step(self):
|
||||
return self._step
|
||||
|
||||
def __repr__(self):
|
||||
if self._step == 1:
|
||||
return 'range(%d, %d)' % (self._start, self._stop)
|
||||
return 'range(%d, %d, %d)' % (self._start, self._stop, self._step)
|
||||
|
||||
def __eq__(self, other):
|
||||
return (isinstance(other, newrange) and
|
||||
(self._len == 0 == other._len or
|
||||
(self._start, self._step, self._len) ==
|
||||
(other._start, other._step, self._len)))
|
||||
|
||||
def __len__(self):
|
||||
return self._len
|
||||
|
||||
def index(self, value):
|
||||
"""Return the 0-based position of integer `value` in
|
||||
the sequence this range represents."""
|
||||
try:
|
||||
diff = value - self._start
|
||||
except TypeError:
|
||||
raise ValueError('%r is not in range' % value)
|
||||
quotient, remainder = divmod(diff, self._step)
|
||||
if remainder == 0 and 0 <= quotient < self._len:
|
||||
return abs(quotient)
|
||||
raise ValueError('%r is not in range' % value)
|
||||
|
||||
def count(self, value):
|
||||
"""Return the number of ocurrences of integer `value`
|
||||
in the sequence this range represents."""
|
||||
# a value can occur exactly zero or one times
|
||||
return int(value in self)
|
||||
|
||||
def __contains__(self, value):
|
||||
"""Return ``True`` if the integer `value` occurs in
|
||||
the sequence this range represents."""
|
||||
try:
|
||||
self.index(value)
|
||||
return True
|
||||
except ValueError:
|
||||
return False
|
||||
|
||||
def __reversed__(self):
|
||||
return iter(self[::-1])
|
||||
|
||||
def __getitem__(self, index):
|
||||
"""Return the element at position ``index`` in the sequence
|
||||
this range represents, or raise :class:`IndexError` if the
|
||||
position is out of range."""
|
||||
if isinstance(index, slice):
|
||||
return self.__getitem_slice(index)
|
||||
if index < 0:
|
||||
# negative indexes access from the end
|
||||
index = self._len + index
|
||||
if index < 0 or index >= self._len:
|
||||
raise IndexError('range object index out of range')
|
||||
return self._start + index * self._step
|
||||
|
||||
def __getitem_slice(self, slce):
|
||||
"""Return a range which represents the requested slce
|
||||
of the sequence represented by this range.
|
||||
"""
|
||||
scaled_indices = (self._step * n for n in slce.indices(self._len))
|
||||
start_offset, stop_offset, new_step = scaled_indices
|
||||
return newrange(self._start + start_offset,
|
||||
self._start + stop_offset,
|
||||
new_step)
|
||||
|
||||
def __iter__(self):
|
||||
"""Return an iterator which enumerates the elements of the
|
||||
sequence this range represents."""
|
||||
return range_iterator(self)
|
||||
|
||||
|
||||
class range_iterator(Iterator):
|
||||
"""An iterator for a :class:`range`.
|
||||
"""
|
||||
def __init__(self, range_):
|
||||
self._stepper = islice(count(range_.start, range_.step), len(range_))
|
||||
|
||||
def __iter__(self):
|
||||
return self
|
||||
|
||||
def __next__(self):
|
||||
return next(self._stepper)
|
||||
|
||||
def next(self):
|
||||
return next(self._stepper)
|
||||
|
||||
|
||||
__all__ = ['newrange']
|
426
lib/future/types/newstr.py
Normal file
426
lib/future/types/newstr.py
Normal file
|
@ -0,0 +1,426 @@
|
|||
"""
|
||||
This module redefines ``str`` on Python 2.x to be a subclass of the Py2
|
||||
``unicode`` type that behaves like the Python 3.x ``str``.
|
||||
|
||||
The main differences between ``newstr`` and Python 2.x's ``unicode`` type are
|
||||
the stricter type-checking and absence of a `u''` prefix in the representation.
|
||||
|
||||
It is designed to be used together with the ``unicode_literals`` import
|
||||
as follows:
|
||||
|
||||
>>> from __future__ import unicode_literals
|
||||
>>> from builtins import str, isinstance
|
||||
|
||||
On Python 3.x and normally on Python 2.x, these expressions hold
|
||||
|
||||
>>> str('blah') is 'blah'
|
||||
True
|
||||
>>> isinstance('blah', str)
|
||||
True
|
||||
|
||||
However, on Python 2.x, with this import:
|
||||
|
||||
>>> from __future__ import unicode_literals
|
||||
|
||||
the same expressions are False:
|
||||
|
||||
>>> str('blah') is 'blah'
|
||||
False
|
||||
>>> isinstance('blah', str)
|
||||
False
|
||||
|
||||
This module is designed to be imported together with ``unicode_literals`` on
|
||||
Python 2 to bring the meaning of ``str`` back into alignment with unprefixed
|
||||
string literals (i.e. ``unicode`` subclasses).
|
||||
|
||||
Note that ``str()`` (and ``print()``) would then normally call the
|
||||
``__unicode__`` method on objects in Python 2. To define string
|
||||
representations of your objects portably across Py3 and Py2, use the
|
||||
:func:`python_2_unicode_compatible` decorator in :mod:`future.utils`.
|
||||
|
||||
"""
|
||||
|
||||
from numbers import Number
|
||||
|
||||
from future.utils import PY3, istext, with_metaclass, isnewbytes
|
||||
from future.types import no, issubset
|
||||
from future.types.newobject import newobject
|
||||
|
||||
|
||||
if PY3:
|
||||
# We'll probably never use newstr on Py3 anyway...
|
||||
unicode = str
|
||||
from collections.abc import Iterable
|
||||
else:
|
||||
from collections import Iterable
|
||||
|
||||
|
||||
class BaseNewStr(type):
|
||||
def __instancecheck__(cls, instance):
|
||||
if cls == newstr:
|
||||
return isinstance(instance, unicode)
|
||||
else:
|
||||
return issubclass(instance.__class__, cls)
|
||||
|
||||
|
||||
class newstr(with_metaclass(BaseNewStr, unicode)):
|
||||
"""
|
||||
A backport of the Python 3 str object to Py2
|
||||
"""
|
||||
no_convert_msg = "Can't convert '{0}' object to str implicitly"
|
||||
|
||||
def __new__(cls, *args, **kwargs):
|
||||
"""
|
||||
From the Py3 str docstring:
|
||||
|
||||
str(object='') -> str
|
||||
str(bytes_or_buffer[, encoding[, errors]]) -> str
|
||||
|
||||
Create a new string object from the given object. If encoding or
|
||||
errors is specified, then the object must expose a data buffer
|
||||
that will be decoded using the given encoding and error handler.
|
||||
Otherwise, returns the result of object.__str__() (if defined)
|
||||
or repr(object).
|
||||
encoding defaults to sys.getdefaultencoding().
|
||||
errors defaults to 'strict'.
|
||||
|
||||
"""
|
||||
if len(args) == 0:
|
||||
return super(newstr, cls).__new__(cls)
|
||||
# Special case: If someone requests str(str(u'abc')), return the same
|
||||
# object (same id) for consistency with Py3.3. This is not true for
|
||||
# other objects like list or dict.
|
||||
elif type(args[0]) == newstr and cls == newstr:
|
||||
return args[0]
|
||||
elif isinstance(args[0], unicode):
|
||||
value = args[0]
|
||||
elif isinstance(args[0], bytes): # i.e. Py2 bytes or newbytes
|
||||
if 'encoding' in kwargs or len(args) > 1:
|
||||
value = args[0].decode(*args[1:], **kwargs)
|
||||
else:
|
||||
value = args[0].__str__()
|
||||
else:
|
||||
value = args[0]
|
||||
return super(newstr, cls).__new__(cls, value)
|
||||
|
||||
def __repr__(self):
|
||||
"""
|
||||
Without the u prefix
|
||||
"""
|
||||
|
||||
value = super(newstr, self).__repr__()
|
||||
# assert value[0] == u'u'
|
||||
return value[1:]
|
||||
|
||||
def __getitem__(self, y):
|
||||
"""
|
||||
Warning: Python <= 2.7.6 has a bug that causes this method never to be called
|
||||
when y is a slice object. Therefore the type of newstr()[:2] is wrong
|
||||
(unicode instead of newstr).
|
||||
"""
|
||||
return newstr(super(newstr, self).__getitem__(y))
|
||||
|
||||
def __contains__(self, key):
|
||||
errmsg = "'in <string>' requires string as left operand, not {0}"
|
||||
# Don't use isinstance() here because we only want to catch
|
||||
# newstr, not Python 2 unicode:
|
||||
if type(key) == newstr:
|
||||
newkey = key
|
||||
elif isinstance(key, unicode) or isinstance(key, bytes) and not isnewbytes(key):
|
||||
newkey = newstr(key)
|
||||
else:
|
||||
raise TypeError(errmsg.format(type(key)))
|
||||
return issubset(list(newkey), list(self))
|
||||
|
||||
@no('newbytes')
|
||||
def __add__(self, other):
|
||||
return newstr(super(newstr, self).__add__(other))
|
||||
|
||||
@no('newbytes')
|
||||
def __radd__(self, left):
|
||||
" left + self "
|
||||
try:
|
||||
return newstr(left) + self
|
||||
except:
|
||||
return NotImplemented
|
||||
|
||||
def __mul__(self, other):
|
||||
return newstr(super(newstr, self).__mul__(other))
|
||||
|
||||
def __rmul__(self, other):
|
||||
return newstr(super(newstr, self).__rmul__(other))
|
||||
|
||||
def join(self, iterable):
|
||||
errmsg = 'sequence item {0}: expected unicode string, found bytes'
|
||||
for i, item in enumerate(iterable):
|
||||
# Here we use type() rather than isinstance() because
|
||||
# __instancecheck__ is being overridden. E.g.
|
||||
# isinstance(b'abc', newbytes) is True on Py2.
|
||||
if isnewbytes(item):
|
||||
raise TypeError(errmsg.format(i))
|
||||
# Support use as a staticmethod: str.join('-', ['a', 'b'])
|
||||
if type(self) == newstr:
|
||||
return newstr(super(newstr, self).join(iterable))
|
||||
else:
|
||||
return newstr(super(newstr, newstr(self)).join(iterable))
|
||||
|
||||
@no('newbytes')
|
||||
def find(self, sub, *args):
|
||||
return super(newstr, self).find(sub, *args)
|
||||
|
||||
@no('newbytes')
|
||||
def rfind(self, sub, *args):
|
||||
return super(newstr, self).rfind(sub, *args)
|
||||
|
||||
@no('newbytes', (1, 2))
|
||||
def replace(self, old, new, *args):
|
||||
return newstr(super(newstr, self).replace(old, new, *args))
|
||||
|
||||
def decode(self, *args):
|
||||
raise AttributeError("decode method has been disabled in newstr")
|
||||
|
||||
def encode(self, encoding='utf-8', errors='strict'):
|
||||
"""
|
||||
Returns bytes
|
||||
|
||||
Encode S using the codec registered for encoding. Default encoding
|
||||
is 'utf-8'. errors may be given to set a different error
|
||||
handling scheme. Default is 'strict' meaning that encoding errors raise
|
||||
a UnicodeEncodeError. Other possible values are 'ignore', 'replace' and
|
||||
'xmlcharrefreplace' as well as any other name registered with
|
||||
codecs.register_error that can handle UnicodeEncodeErrors.
|
||||
"""
|
||||
from future.types.newbytes import newbytes
|
||||
# Py2 unicode.encode() takes encoding and errors as optional parameter,
|
||||
# not keyword arguments as in Python 3 str.
|
||||
|
||||
# For the surrogateescape error handling mechanism, the
|
||||
# codecs.register_error() function seems to be inadequate for an
|
||||
# implementation of it when encoding. (Decoding seems fine, however.)
|
||||
# For example, in the case of
|
||||
# u'\udcc3'.encode('ascii', 'surrogateescape_handler')
|
||||
# after registering the ``surrogateescape_handler`` function in
|
||||
# future.utils.surrogateescape, both Python 2.x and 3.x raise an
|
||||
# exception anyway after the function is called because the unicode
|
||||
# string it has to return isn't encodable strictly as ASCII.
|
||||
|
||||
if errors == 'surrogateescape':
|
||||
if encoding == 'utf-16':
|
||||
# Known to fail here. See test_encoding_works_normally()
|
||||
raise NotImplementedError('FIXME: surrogateescape handling is '
|
||||
'not yet implemented properly')
|
||||
# Encode char by char, building up list of byte-strings
|
||||
mybytes = []
|
||||
for c in self:
|
||||
code = ord(c)
|
||||
if 0xD800 <= code <= 0xDCFF:
|
||||
mybytes.append(newbytes([code - 0xDC00]))
|
||||
else:
|
||||
mybytes.append(c.encode(encoding=encoding))
|
||||
return newbytes(b'').join(mybytes)
|
||||
return newbytes(super(newstr, self).encode(encoding, errors))
|
||||
|
||||
@no('newbytes', 1)
|
||||
def startswith(self, prefix, *args):
|
||||
if isinstance(prefix, Iterable):
|
||||
for thing in prefix:
|
||||
if isnewbytes(thing):
|
||||
raise TypeError(self.no_convert_msg.format(type(thing)))
|
||||
return super(newstr, self).startswith(prefix, *args)
|
||||
|
||||
@no('newbytes', 1)
|
||||
def endswith(self, prefix, *args):
|
||||
# Note we need the decorator above as well as the isnewbytes()
|
||||
# check because prefix can be either a bytes object or e.g. a
|
||||
# tuple of possible prefixes. (If it's a bytes object, each item
|
||||
# in it is an int.)
|
||||
if isinstance(prefix, Iterable):
|
||||
for thing in prefix:
|
||||
if isnewbytes(thing):
|
||||
raise TypeError(self.no_convert_msg.format(type(thing)))
|
||||
return super(newstr, self).endswith(prefix, *args)
|
||||
|
||||
@no('newbytes', 1)
|
||||
def split(self, sep=None, maxsplit=-1):
|
||||
# Py2 unicode.split() takes maxsplit as an optional parameter,
|
||||
# not as a keyword argument as in Python 3 str.
|
||||
parts = super(newstr, self).split(sep, maxsplit)
|
||||
return [newstr(part) for part in parts]
|
||||
|
||||
@no('newbytes', 1)
|
||||
def rsplit(self, sep=None, maxsplit=-1):
|
||||
# Py2 unicode.rsplit() takes maxsplit as an optional parameter,
|
||||
# not as a keyword argument as in Python 3 str.
|
||||
parts = super(newstr, self).rsplit(sep, maxsplit)
|
||||
return [newstr(part) for part in parts]
|
||||
|
||||
@no('newbytes', 1)
|
||||
def partition(self, sep):
|
||||
parts = super(newstr, self).partition(sep)
|
||||
return tuple(newstr(part) for part in parts)
|
||||
|
||||
@no('newbytes', 1)
|
||||
def rpartition(self, sep):
|
||||
parts = super(newstr, self).rpartition(sep)
|
||||
return tuple(newstr(part) for part in parts)
|
||||
|
||||
@no('newbytes', 1)
|
||||
def index(self, sub, *args):
|
||||
"""
|
||||
Like newstr.find() but raise ValueError when the substring is not
|
||||
found.
|
||||
"""
|
||||
pos = self.find(sub, *args)
|
||||
if pos == -1:
|
||||
raise ValueError('substring not found')
|
||||
return pos
|
||||
|
||||
def splitlines(self, keepends=False):
|
||||
"""
|
||||
S.splitlines(keepends=False) -> list of strings
|
||||
|
||||
Return a list of the lines in S, breaking at line boundaries.
|
||||
Line breaks are not included in the resulting list unless keepends
|
||||
is given and true.
|
||||
"""
|
||||
# Py2 unicode.splitlines() takes keepends as an optional parameter,
|
||||
# not as a keyword argument as in Python 3 str.
|
||||
parts = super(newstr, self).splitlines(keepends)
|
||||
return [newstr(part) for part in parts]
|
||||
|
||||
def __eq__(self, other):
|
||||
if (isinstance(other, unicode) or
|
||||
isinstance(other, bytes) and not isnewbytes(other)):
|
||||
return super(newstr, self).__eq__(other)
|
||||
else:
|
||||
return NotImplemented
|
||||
|
||||
def __hash__(self):
|
||||
if (isinstance(self, unicode) or
|
||||
isinstance(self, bytes) and not isnewbytes(self)):
|
||||
return super(newstr, self).__hash__()
|
||||
else:
|
||||
raise NotImplementedError()
|
||||
|
||||
def __ne__(self, other):
|
||||
if (isinstance(other, unicode) or
|
||||
isinstance(other, bytes) and not isnewbytes(other)):
|
||||
return super(newstr, self).__ne__(other)
|
||||
else:
|
||||
return True
|
||||
|
||||
unorderable_err = 'unorderable types: str() and {0}'
|
||||
|
||||
def __lt__(self, other):
|
||||
if (isinstance(other, unicode) or
|
||||
isinstance(other, bytes) and not isnewbytes(other)):
|
||||
return super(newstr, self).__lt__(other)
|
||||
raise TypeError(self.unorderable_err.format(type(other)))
|
||||
|
||||
def __le__(self, other):
|
||||
if (isinstance(other, unicode) or
|
||||
isinstance(other, bytes) and not isnewbytes(other)):
|
||||
return super(newstr, self).__le__(other)
|
||||
raise TypeError(self.unorderable_err.format(type(other)))
|
||||
|
||||
def __gt__(self, other):
|
||||
if (isinstance(other, unicode) or
|
||||
isinstance(other, bytes) and not isnewbytes(other)):
|
||||
return super(newstr, self).__gt__(other)
|
||||
raise TypeError(self.unorderable_err.format(type(other)))
|
||||
|
||||
def __ge__(self, other):
|
||||
if (isinstance(other, unicode) or
|
||||
isinstance(other, bytes) and not isnewbytes(other)):
|
||||
return super(newstr, self).__ge__(other)
|
||||
raise TypeError(self.unorderable_err.format(type(other)))
|
||||
|
||||
def __getattribute__(self, name):
|
||||
"""
|
||||
A trick to cause the ``hasattr`` builtin-fn to return False for
|
||||
the 'decode' method on Py2.
|
||||
"""
|
||||
if name in ['decode', u'decode']:
|
||||
raise AttributeError("decode method has been disabled in newstr")
|
||||
return super(newstr, self).__getattribute__(name)
|
||||
|
||||
def __native__(self):
|
||||
"""
|
||||
A hook for the future.utils.native() function.
|
||||
"""
|
||||
return unicode(self)
|
||||
|
||||
@staticmethod
|
||||
def maketrans(x, y=None, z=None):
|
||||
"""
|
||||
Return a translation table usable for str.translate().
|
||||
|
||||
If there is only one argument, it must be a dictionary mapping Unicode
|
||||
ordinals (integers) or characters to Unicode ordinals, strings or None.
|
||||
Character keys will be then converted to ordinals.
|
||||
If there are two arguments, they must be strings of equal length, and
|
||||
in the resulting dictionary, each character in x will be mapped to the
|
||||
character at the same position in y. If there is a third argument, it
|
||||
must be a string, whose characters will be mapped to None in the result.
|
||||
"""
|
||||
|
||||
if y is None:
|
||||
assert z is None
|
||||
if not isinstance(x, dict):
|
||||
raise TypeError('if you give only one argument to maketrans it must be a dict')
|
||||
result = {}
|
||||
for (key, value) in x.items():
|
||||
if len(key) > 1:
|
||||
raise ValueError('keys in translate table must be strings or integers')
|
||||
result[ord(key)] = value
|
||||
else:
|
||||
if not isinstance(x, unicode) and isinstance(y, unicode):
|
||||
raise TypeError('x and y must be unicode strings')
|
||||
if not len(x) == len(y):
|
||||
raise ValueError('the first two maketrans arguments must have equal length')
|
||||
result = {}
|
||||
for (xi, yi) in zip(x, y):
|
||||
if len(xi) > 1:
|
||||
raise ValueError('keys in translate table must be strings or integers')
|
||||
result[ord(xi)] = ord(yi)
|
||||
|
||||
if z is not None:
|
||||
for char in z:
|
||||
result[ord(char)] = None
|
||||
return result
|
||||
|
||||
def translate(self, table):
|
||||
"""
|
||||
S.translate(table) -> str
|
||||
|
||||
Return a copy of the string S, where all characters have been mapped
|
||||
through the given translation table, which must be a mapping of
|
||||
Unicode ordinals to Unicode ordinals, strings, or None.
|
||||
Unmapped characters are left untouched. Characters mapped to None
|
||||
are deleted.
|
||||
"""
|
||||
l = []
|
||||
for c in self:
|
||||
if ord(c) in table:
|
||||
val = table[ord(c)]
|
||||
if val is None:
|
||||
continue
|
||||
elif isinstance(val, unicode):
|
||||
l.append(val)
|
||||
else:
|
||||
l.append(chr(val))
|
||||
else:
|
||||
l.append(c)
|
||||
return ''.join(l)
|
||||
|
||||
def isprintable(self):
|
||||
raise NotImplementedError('fixme')
|
||||
|
||||
def isidentifier(self):
|
||||
raise NotImplementedError('fixme')
|
||||
|
||||
def format_map(self):
|
||||
raise NotImplementedError('fixme')
|
||||
|
||||
|
||||
__all__ = ['newstr']
|
Loading…
Add table
Add a link
Reference in a new issue