|
@@ -1,272 +1,272 @@
|
|
|
-"""
|
|
|
-This module is designed to be used as follows::
|
|
|
-
|
|
|
- from past.builtins.noniterators import filter, map, range, reduce, zip
|
|
|
-
|
|
|
-And then, for example::
|
|
|
-
|
|
|
- assert isinstance(range(5), list)
|
|
|
+"""
|
|
|
+This module is designed to be used as follows::
|
|
|
+
|
|
|
+ from past.builtins.noniterators import filter, map, range, reduce, zip
|
|
|
+
|
|
|
+And then, for example::
|
|
|
+
|
|
|
+ assert isinstance(range(5), list)
|
|
|
+
|
|
|
+The list-producing functions this brings in are::
|
|
|
+
|
|
|
+- ``filter``
|
|
|
+- ``map``
|
|
|
+- ``range``
|
|
|
+- ``reduce``
|
|
|
+- ``zip``
|
|
|
+
|
|
|
+"""
|
|
|
+
|
|
|
+from __future__ import division, absolute_import, print_function
|
|
|
|
|
|
-The list-producing functions this brings in are::
|
|
|
-
|
|
|
-- ``filter``
|
|
|
-- ``map``
|
|
|
-- ``range``
|
|
|
-- ``reduce``
|
|
|
-- ``zip``
|
|
|
-
|
|
|
-"""
|
|
|
-
|
|
|
-from __future__ import division, absolute_import, print_function
|
|
|
-
|
|
|
from itertools import chain, starmap
|
|
|
-import itertools # since zip_longest doesn't exist on Py2
|
|
|
-from past.types import basestring
|
|
|
-from past.utils import PY3
|
|
|
-
|
|
|
-
|
|
|
-def flatmap(f, items):
|
|
|
- return chain.from_iterable(map(f, items))
|
|
|
-
|
|
|
-
|
|
|
-if PY3:
|
|
|
- import builtins
|
|
|
-
|
|
|
- # list-producing versions of the major Python iterating functions
|
|
|
- def oldfilter(*args):
|
|
|
- """
|
|
|
- filter(function or None, sequence) -> list, tuple, or string
|
|
|
+import itertools # since zip_longest doesn't exist on Py2
|
|
|
+from past.types import basestring
|
|
|
+from past.utils import PY3
|
|
|
+
|
|
|
+
|
|
|
+def flatmap(f, items):
|
|
|
+ return chain.from_iterable(map(f, items))
|
|
|
+
|
|
|
+
|
|
|
+if PY3:
|
|
|
+ import builtins
|
|
|
|
|
|
- Return those items of sequence for which function(item) is true.
|
|
|
- If function is None, return the items that are true. If sequence
|
|
|
- is a tuple or string, return the same type, else return a list.
|
|
|
- """
|
|
|
- mytype = type(args[1])
|
|
|
- if isinstance(args[1], basestring):
|
|
|
- return mytype().join(builtins.filter(*args))
|
|
|
- elif isinstance(args[1], (tuple, list)):
|
|
|
- return mytype(builtins.filter(*args))
|
|
|
- else:
|
|
|
- # Fall back to list. Is this the right thing to do?
|
|
|
- return list(builtins.filter(*args))
|
|
|
-
|
|
|
- # This is surprisingly difficult to get right. For example, the
|
|
|
- # solutions here fail with the test cases in the docstring below:
|
|
|
- # http://stackoverflow.com/questions/8072755/
|
|
|
- def oldmap(func, *iterables):
|
|
|
- """
|
|
|
- map(function, sequence[, sequence, ...]) -> list
|
|
|
+ # list-producing versions of the major Python iterating functions
|
|
|
+ def oldfilter(*args):
|
|
|
+ """
|
|
|
+ filter(function or None, sequence) -> list, tuple, or string
|
|
|
|
|
|
- Return a list of the results of applying the function to the
|
|
|
- items of the argument sequence(s). If more than one sequence is
|
|
|
- given, the function is called with an argument list consisting of
|
|
|
- the corresponding item of each sequence, substituting None for
|
|
|
- missing values when not all sequences have the same length. If
|
|
|
- the function is None, return a list of the items of the sequence
|
|
|
- (or a list of tuples if more than one sequence).
|
|
|
+ Return those items of sequence for which function(item) is true.
|
|
|
+ If function is None, return the items that are true. If sequence
|
|
|
+ is a tuple or string, return the same type, else return a list.
|
|
|
+ """
|
|
|
+ mytype = type(args[1])
|
|
|
+ if isinstance(args[1], basestring):
|
|
|
+ return mytype().join(builtins.filter(*args))
|
|
|
+ elif isinstance(args[1], (tuple, list)):
|
|
|
+ return mytype(builtins.filter(*args))
|
|
|
+ else:
|
|
|
+ # Fall back to list. Is this the right thing to do?
|
|
|
+ return list(builtins.filter(*args))
|
|
|
+
|
|
|
+ # This is surprisingly difficult to get right. For example, the
|
|
|
+ # solutions here fail with the test cases in the docstring below:
|
|
|
+ # http://stackoverflow.com/questions/8072755/
|
|
|
+ def oldmap(func, *iterables):
|
|
|
+ """
|
|
|
+ map(function, sequence[, sequence, ...]) -> list
|
|
|
+
|
|
|
+ Return a list of the results of applying the function to the
|
|
|
+ items of the argument sequence(s). If more than one sequence is
|
|
|
+ given, the function is called with an argument list consisting of
|
|
|
+ the corresponding item of each sequence, substituting None for
|
|
|
+ missing values when not all sequences have the same length. If
|
|
|
+ the function is None, return a list of the items of the sequence
|
|
|
+ (or a list of tuples if more than one sequence).
|
|
|
+
|
|
|
+ Test cases:
|
|
|
+ >>> oldmap(None, 'hello world')
|
|
|
+ ['h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd']
|
|
|
+
|
|
|
+ >>> oldmap(None, range(4))
|
|
|
+ [0, 1, 2, 3]
|
|
|
|
|
|
- Test cases:
|
|
|
- >>> oldmap(None, 'hello world')
|
|
|
- ['h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd']
|
|
|
-
|
|
|
- >>> oldmap(None, range(4))
|
|
|
- [0, 1, 2, 3]
|
|
|
-
|
|
|
More test cases are in test_past.test_builtins.
|
|
|
- """
|
|
|
- zipped = itertools.zip_longest(*iterables)
|
|
|
- l = list(zipped)
|
|
|
- if len(l) == 0:
|
|
|
- return []
|
|
|
- if func is None:
|
|
|
- result = l
|
|
|
- else:
|
|
|
- result = list(starmap(func, l))
|
|
|
-
|
|
|
- # Inspect to see whether it's a simple sequence of tuples
|
|
|
- try:
|
|
|
- if max([len(item) for item in result]) == 1:
|
|
|
- return list(chain.from_iterable(result))
|
|
|
- # return list(flatmap(func, result))
|
|
|
- except TypeError as e:
|
|
|
- # Simple objects like ints have no len()
|
|
|
- pass
|
|
|
- return result
|
|
|
-
|
|
|
- ############################
|
|
|
- ### For reference, the source code for Py2.7 map function:
|
|
|
- # static PyObject *
|
|
|
- # builtin_map(PyObject *self, PyObject *args)
|
|
|
- # {
|
|
|
- # typedef struct {
|
|
|
- # PyObject *it; /* the iterator object */
|
|
|
- # int saw_StopIteration; /* bool: did the iterator end? */
|
|
|
- # } sequence;
|
|
|
+ """
|
|
|
+ zipped = itertools.zip_longest(*iterables)
|
|
|
+ l = list(zipped)
|
|
|
+ if len(l) == 0:
|
|
|
+ return []
|
|
|
+ if func is None:
|
|
|
+ result = l
|
|
|
+ else:
|
|
|
+ result = list(starmap(func, l))
|
|
|
+
|
|
|
+ # Inspect to see whether it's a simple sequence of tuples
|
|
|
+ try:
|
|
|
+ if max([len(item) for item in result]) == 1:
|
|
|
+ return list(chain.from_iterable(result))
|
|
|
+ # return list(flatmap(func, result))
|
|
|
+ except TypeError as e:
|
|
|
+ # Simple objects like ints have no len()
|
|
|
+ pass
|
|
|
+ return result
|
|
|
+
|
|
|
+ ############################
|
|
|
+ ### For reference, the source code for Py2.7 map function:
|
|
|
+ # static PyObject *
|
|
|
+ # builtin_map(PyObject *self, PyObject *args)
|
|
|
+ # {
|
|
|
+ # typedef struct {
|
|
|
+ # PyObject *it; /* the iterator object */
|
|
|
+ # int saw_StopIteration; /* bool: did the iterator end? */
|
|
|
+ # } sequence;
|
|
|
#
|
|
|
- # PyObject *func, *result;
|
|
|
- # sequence *seqs = NULL, *sqp;
|
|
|
- # Py_ssize_t n, len;
|
|
|
- # register int i, j;
|
|
|
+ # PyObject *func, *result;
|
|
|
+ # sequence *seqs = NULL, *sqp;
|
|
|
+ # Py_ssize_t n, len;
|
|
|
+ # register int i, j;
|
|
|
#
|
|
|
- # n = PyTuple_Size(args);
|
|
|
- # if (n < 2) {
|
|
|
- # PyErr_SetString(PyExc_TypeError,
|
|
|
- # "map() requires at least two args");
|
|
|
- # return NULL;
|
|
|
- # }
|
|
|
+ # n = PyTuple_Size(args);
|
|
|
+ # if (n < 2) {
|
|
|
+ # PyErr_SetString(PyExc_TypeError,
|
|
|
+ # "map() requires at least two args");
|
|
|
+ # return NULL;
|
|
|
+ # }
|
|
|
#
|
|
|
- # func = PyTuple_GetItem(args, 0);
|
|
|
- # n--;
|
|
|
+ # func = PyTuple_GetItem(args, 0);
|
|
|
+ # n--;
|
|
|
#
|
|
|
- # if (func == Py_None) {
|
|
|
- # if (PyErr_WarnPy3k("map(None, ...) not supported in 3.x; "
|
|
|
- # "use list(...)", 1) < 0)
|
|
|
- # return NULL;
|
|
|
- # if (n == 1) {
|
|
|
- # /* map(None, S) is the same as list(S). */
|
|
|
- # return PySequence_List(PyTuple_GetItem(args, 1));
|
|
|
- # }
|
|
|
- # }
|
|
|
+ # if (func == Py_None) {
|
|
|
+ # if (PyErr_WarnPy3k("map(None, ...) not supported in 3.x; "
|
|
|
+ # "use list(...)", 1) < 0)
|
|
|
+ # return NULL;
|
|
|
+ # if (n == 1) {
|
|
|
+ # /* map(None, S) is the same as list(S). */
|
|
|
+ # return PySequence_List(PyTuple_GetItem(args, 1));
|
|
|
+ # }
|
|
|
+ # }
|
|
|
#
|
|
|
- # /* Get space for sequence descriptors. Must NULL out the iterator
|
|
|
- # * pointers so that jumping to Fail_2 later doesn't see trash.
|
|
|
- # */
|
|
|
- # if ((seqs = PyMem_NEW(sequence, n)) == NULL) {
|
|
|
- # PyErr_NoMemory();
|
|
|
- # return NULL;
|
|
|
- # }
|
|
|
- # for (i = 0; i < n; ++i) {
|
|
|
- # seqs[i].it = (PyObject*)NULL;
|
|
|
- # seqs[i].saw_StopIteration = 0;
|
|
|
- # }
|
|
|
+ # /* Get space for sequence descriptors. Must NULL out the iterator
|
|
|
+ # * pointers so that jumping to Fail_2 later doesn't see trash.
|
|
|
+ # */
|
|
|
+ # if ((seqs = PyMem_NEW(sequence, n)) == NULL) {
|
|
|
+ # PyErr_NoMemory();
|
|
|
+ # return NULL;
|
|
|
+ # }
|
|
|
+ # for (i = 0; i < n; ++i) {
|
|
|
+ # seqs[i].it = (PyObject*)NULL;
|
|
|
+ # seqs[i].saw_StopIteration = 0;
|
|
|
+ # }
|
|
|
#
|
|
|
- # /* Do a first pass to obtain iterators for the arguments, and set len
|
|
|
- # * to the largest of their lengths.
|
|
|
- # */
|
|
|
- # len = 0;
|
|
|
- # for (i = 0, sqp = seqs; i < n; ++i, ++sqp) {
|
|
|
- # PyObject *curseq;
|
|
|
- # Py_ssize_t curlen;
|
|
|
+ # /* Do a first pass to obtain iterators for the arguments, and set len
|
|
|
+ # * to the largest of their lengths.
|
|
|
+ # */
|
|
|
+ # len = 0;
|
|
|
+ # for (i = 0, sqp = seqs; i < n; ++i, ++sqp) {
|
|
|
+ # PyObject *curseq;
|
|
|
+ # Py_ssize_t curlen;
|
|
|
#
|
|
|
- # /* Get iterator. */
|
|
|
- # curseq = PyTuple_GetItem(args, i+1);
|
|
|
- # sqp->it = PyObject_GetIter(curseq);
|
|
|
- # if (sqp->it == NULL) {
|
|
|
- # static char errmsg[] =
|
|
|
- # "argument %d to map() must support iteration";
|
|
|
- # char errbuf[sizeof(errmsg) + 25];
|
|
|
- # PyOS_snprintf(errbuf, sizeof(errbuf), errmsg, i+2);
|
|
|
- # PyErr_SetString(PyExc_TypeError, errbuf);
|
|
|
- # goto Fail_2;
|
|
|
- # }
|
|
|
+ # /* Get iterator. */
|
|
|
+ # curseq = PyTuple_GetItem(args, i+1);
|
|
|
+ # sqp->it = PyObject_GetIter(curseq);
|
|
|
+ # if (sqp->it == NULL) {
|
|
|
+ # static char errmsg[] =
|
|
|
+ # "argument %d to map() must support iteration";
|
|
|
+ # char errbuf[sizeof(errmsg) + 25];
|
|
|
+ # PyOS_snprintf(errbuf, sizeof(errbuf), errmsg, i+2);
|
|
|
+ # PyErr_SetString(PyExc_TypeError, errbuf);
|
|
|
+ # goto Fail_2;
|
|
|
+ # }
|
|
|
#
|
|
|
- # /* Update len. */
|
|
|
- # curlen = _PyObject_LengthHint(curseq, 8);
|
|
|
- # if (curlen > len)
|
|
|
- # len = curlen;
|
|
|
- # }
|
|
|
+ # /* Update len. */
|
|
|
+ # curlen = _PyObject_LengthHint(curseq, 8);
|
|
|
+ # if (curlen > len)
|
|
|
+ # len = curlen;
|
|
|
+ # }
|
|
|
#
|
|
|
- # /* Get space for the result list. */
|
|
|
- # if ((result = (PyObject *) PyList_New(len)) == NULL)
|
|
|
- # goto Fail_2;
|
|
|
+ # /* Get space for the result list. */
|
|
|
+ # if ((result = (PyObject *) PyList_New(len)) == NULL)
|
|
|
+ # goto Fail_2;
|
|
|
#
|
|
|
- # /* Iterate over the sequences until all have stopped. */
|
|
|
- # for (i = 0; ; ++i) {
|
|
|
- # PyObject *alist, *item=NULL, *value;
|
|
|
- # int numactive = 0;
|
|
|
+ # /* Iterate over the sequences until all have stopped. */
|
|
|
+ # for (i = 0; ; ++i) {
|
|
|
+ # PyObject *alist, *item=NULL, *value;
|
|
|
+ # int numactive = 0;
|
|
|
#
|
|
|
- # if (func == Py_None && n == 1)
|
|
|
- # alist = NULL;
|
|
|
- # else if ((alist = PyTuple_New(n)) == NULL)
|
|
|
- # goto Fail_1;
|
|
|
+ # if (func == Py_None && n == 1)
|
|
|
+ # alist = NULL;
|
|
|
+ # else if ((alist = PyTuple_New(n)) == NULL)
|
|
|
+ # goto Fail_1;
|
|
|
#
|
|
|
- # for (j = 0, sqp = seqs; j < n; ++j, ++sqp) {
|
|
|
- # if (sqp->saw_StopIteration) {
|
|
|
- # Py_INCREF(Py_None);
|
|
|
- # item = Py_None;
|
|
|
- # }
|
|
|
- # else {
|
|
|
- # item = PyIter_Next(sqp->it);
|
|
|
- # if (item)
|
|
|
- # ++numactive;
|
|
|
- # else {
|
|
|
- # if (PyErr_Occurred()) {
|
|
|
- # Py_XDECREF(alist);
|
|
|
- # goto Fail_1;
|
|
|
- # }
|
|
|
- # Py_INCREF(Py_None);
|
|
|
- # item = Py_None;
|
|
|
- # sqp->saw_StopIteration = 1;
|
|
|
- # }
|
|
|
- # }
|
|
|
- # if (alist)
|
|
|
- # PyTuple_SET_ITEM(alist, j, item);
|
|
|
- # else
|
|
|
- # break;
|
|
|
- # }
|
|
|
+ # for (j = 0, sqp = seqs; j < n; ++j, ++sqp) {
|
|
|
+ # if (sqp->saw_StopIteration) {
|
|
|
+ # Py_INCREF(Py_None);
|
|
|
+ # item = Py_None;
|
|
|
+ # }
|
|
|
+ # else {
|
|
|
+ # item = PyIter_Next(sqp->it);
|
|
|
+ # if (item)
|
|
|
+ # ++numactive;
|
|
|
+ # else {
|
|
|
+ # if (PyErr_Occurred()) {
|
|
|
+ # Py_XDECREF(alist);
|
|
|
+ # goto Fail_1;
|
|
|
+ # }
|
|
|
+ # Py_INCREF(Py_None);
|
|
|
+ # item = Py_None;
|
|
|
+ # sqp->saw_StopIteration = 1;
|
|
|
+ # }
|
|
|
+ # }
|
|
|
+ # if (alist)
|
|
|
+ # PyTuple_SET_ITEM(alist, j, item);
|
|
|
+ # else
|
|
|
+ # break;
|
|
|
+ # }
|
|
|
#
|
|
|
- # if (!alist)
|
|
|
- # alist = item;
|
|
|
+ # if (!alist)
|
|
|
+ # alist = item;
|
|
|
#
|
|
|
- # if (numactive == 0) {
|
|
|
- # Py_DECREF(alist);
|
|
|
- # break;
|
|
|
- # }
|
|
|
+ # if (numactive == 0) {
|
|
|
+ # Py_DECREF(alist);
|
|
|
+ # break;
|
|
|
+ # }
|
|
|
#
|
|
|
- # if (func == Py_None)
|
|
|
- # value = alist;
|
|
|
- # else {
|
|
|
- # value = PyEval_CallObject(func, alist);
|
|
|
- # Py_DECREF(alist);
|
|
|
- # if (value == NULL)
|
|
|
- # goto Fail_1;
|
|
|
- # }
|
|
|
- # if (i >= len) {
|
|
|
- # int status = PyList_Append(result, value);
|
|
|
- # Py_DECREF(value);
|
|
|
- # if (status < 0)
|
|
|
- # goto Fail_1;
|
|
|
- # }
|
|
|
- # else if (PyList_SetItem(result, i, value) < 0)
|
|
|
- # goto Fail_1;
|
|
|
- # }
|
|
|
+ # if (func == Py_None)
|
|
|
+ # value = alist;
|
|
|
+ # else {
|
|
|
+ # value = PyEval_CallObject(func, alist);
|
|
|
+ # Py_DECREF(alist);
|
|
|
+ # if (value == NULL)
|
|
|
+ # goto Fail_1;
|
|
|
+ # }
|
|
|
+ # if (i >= len) {
|
|
|
+ # int status = PyList_Append(result, value);
|
|
|
+ # Py_DECREF(value);
|
|
|
+ # if (status < 0)
|
|
|
+ # goto Fail_1;
|
|
|
+ # }
|
|
|
+ # else if (PyList_SetItem(result, i, value) < 0)
|
|
|
+ # goto Fail_1;
|
|
|
+ # }
|
|
|
#
|
|
|
- # if (i < len && PyList_SetSlice(result, i, len, NULL) < 0)
|
|
|
- # goto Fail_1;
|
|
|
+ # if (i < len && PyList_SetSlice(result, i, len, NULL) < 0)
|
|
|
+ # goto Fail_1;
|
|
|
#
|
|
|
- # goto Succeed;
|
|
|
+ # goto Succeed;
|
|
|
#
|
|
|
- # Fail_1:
|
|
|
- # Py_DECREF(result);
|
|
|
- # Fail_2:
|
|
|
- # result = NULL;
|
|
|
- # Succeed:
|
|
|
- # assert(seqs);
|
|
|
- # for (i = 0; i < n; ++i)
|
|
|
- # Py_XDECREF(seqs[i].it);
|
|
|
- # PyMem_DEL(seqs);
|
|
|
- # return result;
|
|
|
- # }
|
|
|
-
|
|
|
- def oldrange(*args, **kwargs):
|
|
|
- return list(builtins.range(*args, **kwargs))
|
|
|
-
|
|
|
- def oldzip(*args, **kwargs):
|
|
|
- return list(builtins.zip(*args, **kwargs))
|
|
|
-
|
|
|
- filter = oldfilter
|
|
|
- map = oldmap
|
|
|
- range = oldrange
|
|
|
- from functools import reduce
|
|
|
- zip = oldzip
|
|
|
- __all__ = ['filter', 'map', 'range', 'reduce', 'zip']
|
|
|
-
|
|
|
-else:
|
|
|
- import __builtin__
|
|
|
- # Python 2-builtin ranges produce lists
|
|
|
- filter = __builtin__.filter
|
|
|
- map = __builtin__.map
|
|
|
- range = __builtin__.range
|
|
|
- reduce = __builtin__.reduce
|
|
|
- zip = __builtin__.zip
|
|
|
- __all__ = []
|
|
|
+ # Fail_1:
|
|
|
+ # Py_DECREF(result);
|
|
|
+ # Fail_2:
|
|
|
+ # result = NULL;
|
|
|
+ # Succeed:
|
|
|
+ # assert(seqs);
|
|
|
+ # for (i = 0; i < n; ++i)
|
|
|
+ # Py_XDECREF(seqs[i].it);
|
|
|
+ # PyMem_DEL(seqs);
|
|
|
+ # return result;
|
|
|
+ # }
|
|
|
+
|
|
|
+ def oldrange(*args, **kwargs):
|
|
|
+ return list(builtins.range(*args, **kwargs))
|
|
|
+
|
|
|
+ def oldzip(*args, **kwargs):
|
|
|
+ return list(builtins.zip(*args, **kwargs))
|
|
|
+
|
|
|
+ filter = oldfilter
|
|
|
+ map = oldmap
|
|
|
+ range = oldrange
|
|
|
+ from functools import reduce
|
|
|
+ zip = oldzip
|
|
|
+ __all__ = ['filter', 'map', 'range', 'reduce', 'zip']
|
|
|
+
|
|
|
+else:
|
|
|
+ import __builtin__
|
|
|
+ # Python 2-builtin ranges produce lists
|
|
|
+ filter = __builtin__.filter
|
|
|
+ map = __builtin__.map
|
|
|
+ range = __builtin__.range
|
|
|
+ reduce = __builtin__.reduce
|
|
|
+ zip = __builtin__.zip
|
|
|
+ __all__ = []
|