[Python-modules-commits] [toolz] 02/04: Import toolz_0.8.1.orig.tar.gz
Diane Trout
diane at moszumanska.debian.org
Thu Dec 8 23:16:07 UTC 2016
This is an automated email from the git hooks/post-receive script.
diane pushed a commit to branch master
in repository toolz.
commit 8cb366cd24053493af87325dd2191bf5b507de02
Author: Diane Trout <diane at ghic.org>
Date: Thu Dec 8 14:41:33 2016 -0800
Import toolz_0.8.1.orig.tar.gz
---
.travis.yml | 2 +-
AUTHORS.md | 2 +
MANIFEST.in | 2 +
README.rst | 10 +-
conda.recipe/meta.yaml | 4 +-
doc/source/control.rst | 5 +-
doc/source/streaming-analytics.rst | 16 ++--
setup.py | 17 +++-
tlz/__init__.py | 9 ++
tlz/_build_tlz.py | 100 +++++++++++++++++++
toolz/__init__.py | 2 +-
toolz/_signatures.py | 7 +-
toolz/compatibility.py | 9 +-
toolz/curried/__init__.py | 95 +++++++++++++-----
toolz/curried/exceptions.py | 1 +
toolz/dicttoolz.py | 2 +-
toolz/functoolz.py | 44 ++++++---
toolz/itertoolz.py | 180 +++++++++++++++++++++--------------
toolz/tests/test_curried.py | 49 ++++++++++
toolz/tests/test_curried_doctests.py | 11 +++
toolz/tests/test_itertoolz.py | 12 ++-
toolz/tests/test_serialization.py | 15 +++
toolz/tests/test_tlz.py | 55 +++++++++++
23 files changed, 505 insertions(+), 144 deletions(-)
diff --git a/.travis.yml b/.travis.yml
index 2a24ac3..883d5fe 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -21,7 +21,7 @@ install:
script:
- export MAJOR_PYTHON_VERSION=`echo $TRAVIS_PYTHON_VERSION | cut -c 1`
- coverage run --source=toolz $(which nosetests)
- --with-doctest
+ --with-doctest toolz/
- if [[ $TRAVIS_PYTHON_VERSION != pypy* ]]; then coverage report --show-missing --fail-under=100 ; fi
- if [[ $TRAVIS_PYTHON_VERSION != pypy* ]]; then pep8 --ignore=$PEP8_IGNORE --exclude=conf.py,tests,examples,bench -r --show-source . ; fi
diff --git a/AUTHORS.md b/AUTHORS.md
index 469670d..bd4a563 100644
--- a/AUTHORS.md
+++ b/AUTHORS.md
@@ -29,3 +29,5 @@ Joe Jevnik [@llllllllll](https://github.com
Rory Kirchner [@roryk](https://github.com/roryk)
[Steven Cutting](http://steven-cutting.github.io) [@steven_cutting](https://github.com/steven-cutting)
+
+Aric Coady [@coady](https://github.com/coady)
diff --git a/MANIFEST.in b/MANIFEST.in
index 19e672b..1d3c829 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -1 +1,3 @@
+include LICENSE.txt
+
include toolz/tests/*.py
diff --git a/README.rst b/README.rst
index 1f06c04..ee1628c 100644
--- a/README.rst
+++ b/README.rst
@@ -5,7 +5,7 @@ Toolz
A set of utility functions for iterators, functions, and dictionaries.
-See the PyToolz documentation at http://toolz.readthedocs.org
+See the PyToolz documentation at https://toolz.readthedocs.io
LICENSE
-------
@@ -21,12 +21,6 @@ Install
pip install toolz
-or
-
-::
-
- easy_install toolz
-
Structure and Heritage
----------------------
@@ -54,7 +48,7 @@ These functions come from the legacy of functional languages for list
processing. They interoperate well to accomplish common complex tasks.
Read our `API
-Documentation <http://toolz.readthedocs.org/en/latest/api.html>`__ for
+Documentation <https://toolz.readthedocs.io/en/latest/api.html>`__ for
more details.
Example
diff --git a/conda.recipe/meta.yaml b/conda.recipe/meta.yaml
index 51bbf1f..96e4208 100644
--- a/conda.recipe/meta.yaml
+++ b/conda.recipe/meta.yaml
@@ -1,6 +1,6 @@
package:
name: toolz
- version: "0.8.0"
+ version: "0.8.1"
build:
number: {{environ.get('BINSTAR_BUILD', 1)}}
@@ -22,5 +22,5 @@ test:
- py.test -x --doctest-modules --pyargs toolz
about:
- home: http://toolz.readthedocs.org/
+ home: https://toolz.readthedocs.io/
license: BSD
diff --git a/doc/source/control.rst b/doc/source/control.rst
index 1f5e23e..fe58556 100644
--- a/doc/source/control.rst
+++ b/doc/source/control.rst
@@ -8,9 +8,8 @@ need for simultaneous thought is restricted to only a few elements at a time.
All modern languages provide mechanisms to build data into data structures and
to build functions out of other functions. The third element of programming,
-besides data and functions is control flow. Control flow is the third
-element of programming, after data and functions. Building complex control
-flow out of simple control flow presents deeper challenges.
+besides data and functions, is control flow. Building complex control flow
+out of simple control flow presents deeper challenges.
What?
diff --git a/doc/source/streaming-analytics.rst b/doc/source/streaming-analytics.rst
index c6c9c43..9a8cdd0 100644
--- a/doc/source/streaming-analytics.rst
+++ b/doc/source/streaming-analytics.rst
@@ -34,7 +34,7 @@ These functions correspond to the SQL commands ``SELECT`` and ``WHERE``.
.. code::
>>> from toolz.curried import pipe, map, filter, get
- >>> pipe(accounts, filter(lambda (id, name, balance, gender): balance > 150),
+ >>> pipe(accounts, filter(lambda acc: acc[2] > 150),
... map(get([1, 2])),
... list)
@@ -150,9 +150,9 @@ that adds up the balances for each group:
.. code::
- >>> binop = lambda total, (id, name, bal, gend): total + bal
+ >>> binop = lambda total, account: total + account[2]
- >>> reduceby(get(3), binop, accounts)
+ >>> reduceby(get(3), binop, accounts, 0)
{'F': 400, 'M': 400}
@@ -307,9 +307,9 @@ composition, ...) users interested in data analytics might be better served by
using projects specific to data analytics like Pandas_ or SQLAlchemy.
-.. _groupby: http://toolz.readthedocs.org/en/latest/api.html#toolz.itertoolz.groupby
-.. _join: http://toolz.readthedocs.org/en/latest/api.html#toolz.itertoolz.join
-.. _reduceby: http://toolz.readthedocs.org/en/latest/api.html#toolz.itertoolz.reduceby
-.. _valmap: http://toolz.readthedocs.org/en/latest/api.html#toolz.itertoolz.valmap
+.. _groupby: https://toolz.readthedocs.io/en/latest/api.html#toolz.itertoolz.groupby
+.. _join: https://toolz.readthedocs.io/en/latest/api.html#toolz.itertoolz.join
+.. _reduceby: https://toolz.readthedocs.io/en/latest/api.html#toolz.itertoolz.reduceby
+.. _valmap: https://toolz.readthedocs.io/en/latest/api.html#toolz.dicttoolz.valmap
.. _Pandas: http://pandas.pydata.org/pandas-docs/stable/groupby.html
-.. _curried: http://toolz.readthedocs.org/en/latest/curry.html
+.. _curried: https://toolz.readthedocs.io/en/latest/curry.html
diff --git a/setup.py b/setup.py
index a45d84c..0560e67 100755
--- a/setup.py
+++ b/setup.py
@@ -15,8 +15,21 @@ setup(name='toolz',
keywords='functional utility itertools functools',
packages=['toolz',
'toolz.sandbox',
- 'toolz.curried'],
+ 'toolz.curried',
+ 'tlz'],
package_data={'toolz': ['tests/*.py']},
long_description=(open('README.rst').read() if exists('README.rst')
else ''),
- zip_safe=False)
+ zip_safe=False,
+ classifiers=[
+ "Development Status :: 5 - Production/Stable",
+ "License :: OSI Approved :: BSD License",
+ "Programming Language :: Python",
+ "Programming Language :: Python :: 2.6",
+ "Programming Language :: Python :: 2.7",
+ "Programming Language :: Python :: 3",
+ "Programming Language :: Python :: 3.3",
+ "Programming Language :: Python :: 3.4",
+ "Programming Language :: Python :: 3.5",
+ "Programming Language :: Python :: Implementation :: CPython",
+ "Programming Language :: Python :: Implementation :: PyPy"])
diff --git a/tlz/__init__.py b/tlz/__init__.py
new file mode 100644
index 0000000..9c9c84a
--- /dev/null
+++ b/tlz/__init__.py
@@ -0,0 +1,9 @@
+"""``tlz`` mirrors the ``toolz`` API and uses ``cytoolz`` if possible.
+
+The ``tlz`` package is installed when ``toolz`` is installed. It provides
+a convenient way to use functions from ``cytoolz``--a faster Cython
+implementation of ``toolz``--if it is installed, otherwise it uses
+functions from ``toolz``.
+"""
+
+from . import _build_tlz
diff --git a/tlz/_build_tlz.py b/tlz/_build_tlz.py
new file mode 100644
index 0000000..34eac60
--- /dev/null
+++ b/tlz/_build_tlz.py
@@ -0,0 +1,100 @@
+import sys
+import types
+import toolz
+from toolz.compatibility import import_module
+
+
+class TlzLoader(object):
+ """ Finds and loads ``tlz`` modules when added to sys.meta_path"""
+ def __init__(self):
+ self.always_from_toolz = set([
+ toolz.pipe,
+ ])
+
+ def _load_toolz(self, fullname):
+ rv = {}
+ package, dot, submodules = fullname.partition('.')
+ try:
+ module_name = ''.join(['cytoolz', dot, submodules])
+ rv['cytoolz'] = import_module(module_name)
+ except ImportError:
+ pass
+ try:
+ module_name = ''.join(['toolz', dot, submodules])
+ rv['toolz'] = import_module(module_name)
+ except ImportError:
+ pass
+ if not rv:
+ raise ImportError(fullname)
+ return rv
+
+ def find_module(self, fullname, path=None): # pragma: py3 no cover
+ package, dot, submodules = fullname.partition('.')
+ if package == 'tlz':
+ return self
+
+ def load_module(self, fullname): # pragma: py3 no cover
+ if fullname in sys.modules: # pragma: no cover
+ return sys.modules[fullname]
+ spec = TlzSpec(fullname, self)
+ module = self.create_module(spec)
+ sys.modules[fullname] = module
+ self.exec_module(module)
+ return module
+
+ def find_spec(self, fullname, path, target=None): # pragma: no cover
+ package, dot, submodules = fullname.partition('.')
+ if package == 'tlz':
+ return TlzSpec(fullname, self)
+
+ def create_module(self, spec):
+ return types.ModuleType(spec.name)
+
+ def exec_module(self, module):
+ toolz_mods = self._load_toolz(module.__name__)
+ fast_mod = toolz_mods.get('cytoolz') or toolz_mods['toolz']
+ slow_mod = toolz_mods.get('toolz') or toolz_mods['cytoolz']
+ module.__dict__.update(toolz.merge(fast_mod.__dict__, module.__dict__))
+ package = fast_mod.__package__
+ if package is not None:
+ package, dot, submodules = package.partition('.')
+ module.__package__ = ''.join(['tlz', dot, submodules])
+ if not module.__doc__:
+ module.__doc__ = fast_mod.__doc__
+
+ # show file from toolz during introspection
+ module.__file__ = slow_mod.__file__
+
+ for k, v in fast_mod.__dict__.items():
+ tv = slow_mod.__dict__.get(k)
+ try:
+ hash(tv)
+ except TypeError:
+ tv = None
+ if tv in self.always_from_toolz:
+ module.__dict__[k] = tv
+ elif (
+ isinstance(v, types.ModuleType)
+ and v.__package__ == fast_mod.__name__
+ ):
+ package, dot, submodules = v.__name__.partition('.')
+ module_name = ''.join(['tlz', dot, submodules])
+ submodule = import_module(module_name)
+ module.__dict__[k] = submodule
+
+
+class TlzSpec(object):
+ def __init__(self, name, loader):
+ self.name = name
+ self.loader = loader
+ self.origin = None
+ self.submodule_search_locations = []
+ self.loader_state = None
+ self.cached = None
+ self.parent = None
+ self.has_location = False
+
+
+tlz_loader = TlzLoader()
+sys.meta_path.append(tlz_loader)
+tlz_loader.exec_module(sys.modules['tlz'])
diff --git a/toolz/__init__.py b/toolz/__init__.py
index 43226df..1f4342c 100644
--- a/toolz/__init__.py
+++ b/toolz/__init__.py
@@ -19,4 +19,4 @@ comp = compose
functoolz._sigs.create_signature_registry()
-__version__ = '0.8.0'
+__version__ = '0.8.1'
diff --git a/toolz/_signatures.py b/toolz/_signatures.py
index b84a2e1..28aa95c 100644
--- a/toolz/_signatures.py
+++ b/toolz/_signatures.py
@@ -17,7 +17,7 @@ import inspect
import itertools
import operator
-from .compatibility import PY3
+from .compatibility import PY3, import_module
from .functoolz import (is_partial_args, is_arity, has_varargs,
has_keywords, num_required_args)
@@ -706,10 +706,7 @@ signatures = {}
def create_signature_registry(module_info=module_info, signatures=signatures):
for module, info in module_info.items():
if isinstance(module, str):
- modnames = module.split('.')
- module = __import__(module)
- for attr in modnames[1:]:
- module = getattr(module, attr)
+ module = import_module(module)
for name, sigs in info.items():
if hasattr(module, name):
new_sigs = tuple(expand_sig(sig) for sig in sigs)
diff --git a/toolz/compatibility.py b/toolz/compatibility.py
index 0fe4018..6763502 100644
--- a/toolz/compatibility.py
+++ b/toolz/compatibility.py
@@ -7,7 +7,7 @@ PYPY = hasattr(sys, 'pypy_version_info')
__all__ = ('map', 'filter', 'range', 'zip', 'reduce', 'zip_longest',
'iteritems', 'iterkeys', 'itervalues', 'filterfalse',
- 'PY3', 'PY34', 'PYPY')
+ 'PY3', 'PY34', 'PYPY', 'import_module')
if PY3:
map = map
@@ -31,3 +31,10 @@ else:
iteritems = operator.methodcaller('iteritems')
iterkeys = operator.methodcaller('iterkeys')
itervalues = operator.methodcaller('itervalues')
+
+try:
+ from importlib import import_module
+except ImportError:
+ def import_module(name):
+ __import__(name)
+ return sys.modules[name]
diff --git a/toolz/curried/__init__.py b/toolz/curried/__init__.py
index 6ab6fef..43aeffd 100644
--- a/toolz/curried/__init__.py
+++ b/toolz/curried/__init__.py
@@ -23,33 +23,78 @@ Example:
See Also:
toolz.functoolz.curry
"""
-from . import exceptions
-from . import operator
import toolz
+from . import operator
+from toolz import (
+ comp,
+ complement,
+ compose,
+ concat,
+ concatv,
+ count,
+ curry,
+ diff,
+ dissoc,
+ first,
+ flip,
+ frequencies,
+ identity,
+ interleave,
+ isdistinct,
+ isiterable,
+ juxt,
+ last,
+ memoize,
+ merge_sorted,
+ peek,
+ pipe,
+ second,
+ thread_first,
+ thread_last,
+)
+from .exceptions import merge, merge_with
+accumulate = toolz.curry(toolz.accumulate)
+assoc = toolz.curry(toolz.assoc)
+assoc_in = toolz.curry(toolz.assoc_in)
+cons = toolz.curry(toolz.cons)
+countby = toolz.curry(toolz.countby)
+do = toolz.curry(toolz.do)
+drop = toolz.curry(toolz.drop)
+excepts = toolz.curry(toolz.excepts)
+filter = toolz.curry(toolz.filter)
+get = toolz.curry(toolz.get)
+get_in = toolz.curry(toolz.get_in)
+groupby = toolz.curry(toolz.groupby)
+interpose = toolz.curry(toolz.interpose)
+itemfilter = toolz.curry(toolz.itemfilter)
+itemmap = toolz.curry(toolz.itemmap)
+iterate = toolz.curry(toolz.iterate)
+join = toolz.curry(toolz.join)
+keyfilter = toolz.curry(toolz.keyfilter)
+keymap = toolz.curry(toolz.keymap)
+map = toolz.curry(toolz.map)
+mapcat = toolz.curry(toolz.mapcat)
+nth = toolz.curry(toolz.nth)
+partial = toolz.curry(toolz.partial)
+partition = toolz.curry(toolz.partition)
+partition_all = toolz.curry(toolz.partition_all)
+partitionby = toolz.curry(toolz.partitionby)
+pluck = toolz.curry(toolz.pluck)
+random_sample = toolz.curry(toolz.random_sample)
+reduce = toolz.curry(toolz.reduce)
+reduceby = toolz.curry(toolz.reduceby)
+remove = toolz.curry(toolz.remove)
+sliding_window = toolz.curry(toolz.sliding_window)
+sorted = toolz.curry(toolz.sorted)
+tail = toolz.curry(toolz.tail)
+take = toolz.curry(toolz.take)
+take_nth = toolz.curry(toolz.take_nth)
+topk = toolz.curry(toolz.topk)
+unique = toolz.curry(toolz.unique)
+update_in = toolz.curry(toolz.update_in)
+valfilter = toolz.curry(toolz.valfilter)
+valmap = toolz.curry(toolz.valmap)
-def _should_curry(func):
- if not callable(func) or isinstance(func, toolz.curry):
- return False
- nargs = toolz.functoolz.num_required_args(func)
- if nargs is None or nargs > 1:
- return True
- return nargs == 1 and toolz.functoolz.has_keywords(func)
-
-
-def _curry_namespace(ns):
- return dict(
- (name, toolz.curry(f) if _should_curry(f) else f)
- for name, f in ns.items() if '__' not in name
- )
-
-
-locals().update(toolz.merge(
- _curry_namespace(vars(toolz)),
- _curry_namespace(vars(exceptions)),
-))
-
-# Clean up the namespace.
-del _should_curry
del exceptions
del toolz
diff --git a/toolz/curried/exceptions.py b/toolz/curried/exceptions.py
index 15c5bc8..75a52bb 100644
--- a/toolz/curried/exceptions.py
+++ b/toolz/curried/exceptions.py
@@ -13,5 +13,6 @@ def merge_with(func, d, *dicts, **kwargs):
def merge(d, *dicts, **kwargs):
return toolz.merge(d, *dicts, **kwargs)
+
merge_with.__doc__ = toolz.merge_with.__doc__
merge.__doc__ = toolz.merge.__doc__
diff --git a/toolz/dicttoolz.py b/toolz/dicttoolz.py
index f6cfc38..f840e7f 100644
--- a/toolz/dicttoolz.py
+++ b/toolz/dicttoolz.py
@@ -226,7 +226,7 @@ def assoc_in(d, keys, value, factory=dict):
>>> assoc_in(purchase, ['order', 'costs'], [0.25, 1.00]) # doctest: +SKIP
{'credit card': '5555-1234-1234-1234',
'name': 'Alice',
- 'purchase': {'costs': [0.25, 1.00], 'items': ['Apple', 'Orange']}}
+ 'order': {'costs': [0.25, 1.00], 'items': ['Apple', 'Orange']}}
"""
return update_in(d, keys, lambda x: value, value, factory)
diff --git a/toolz/functoolz.py b/toolz/functoolz.py
index 9081294..ed37c0a 100644
--- a/toolz/functoolz.py
+++ b/toolz/functoolz.py
@@ -4,7 +4,7 @@ import operator
from operator import attrgetter
from textwrap import dedent
-from .compatibility import PY3, PY33, PY34, PYPY
+from .compatibility import PY3, PY33, PY34, PYPY, import_module
from .utils import no_default
@@ -169,7 +169,7 @@ class curry(object):
See Also:
toolz.curried - namespace of curried functions
- http://toolz.readthedocs.org/en/latest/curry.html
+ https://toolz.readthedocs.io/en/latest/curry.html
"""
def __init__(self, *args, **kwargs):
if not args:
@@ -321,17 +321,33 @@ class curry(object):
return self
return curry(self, instance)
- # pickle protocol because functools.partial objects can't be pickled
- def __getstate__(self):
- # dictoolz.keyfilter, I miss you!
+ def __reduce__(self):
+ func = self.func
+ modname = getattr(func, '__module__', None)
+ funcname = getattr(func, '__name__', None)
+ if modname and funcname:
+ module = import_module(modname)
+ obj = getattr(module, funcname, None)
+ if obj is self:
+ return funcname
+ elif isinstance(obj, curry) and obj.func is func:
+ func = '%s.%s' % (modname, funcname)
+
+ # functools.partial objects can't be pickled
userdict = tuple((k, v) for k, v in self.__dict__.items()
if k != '_partial')
- return self.func, self.args, self.keywords, userdict
+ state = (type(self), func, self.args, self.keywords, userdict)
+ return (_restore_curry, state)
- def __setstate__(self, state):
- func, args, kwargs, userdict = state
- self.__init__(func, *args, **(kwargs or {}))
- self.__dict__.update(userdict)
+
+def _restore_curry(cls, func, args, kwargs, userdict):
+ if isinstance(func, str):
+ modname, funcname = func.rsplit('.', 1)
+ module = import_module(modname)
+ func = getattr(module, funcname).func
+ obj = cls(func, *args, **(kwargs or {}))
+ obj.__dict__.update(userdict)
+ return obj
@curry
@@ -601,13 +617,13 @@ def flip(func, a, b):
This function is curried.
>>> def div(a, b):
- ... return a / b
+ ... return a // b
...
- >>> flip(div, 2, 1)
- 0.5
+ >>> flip(div, 2, 6)
+ 3
>>> div_by_two = flip(div, 2)
>>> div_by_two(4)
- 2.0
+ 2
This is particularly useful for built in functions and functions defined
in C extensions that accept positional only arguments. For example:
diff --git a/toolz/itertoolz.py b/toolz/itertoolz.py
index 92f3a3f..2462c5f 100644
--- a/toolz/itertoolz.py
+++ b/toolz/itertoolz.py
@@ -113,59 +113,108 @@ def merge_sorted(*seqs, **kwargs):
>>> list(merge_sorted([2, 3], [1, 3], key=lambda x: x // 3))
[2, 1, 3, 3]
"""
+ if len(seqs) == 0:
+ return iter([])
+ elif len(seqs) == 1:
+ return iter(seqs[0])
+
key = kwargs.get('key', None)
if key is None:
- # heapq.merge does what we do below except by val instead of key(val)
- return heapq.merge(*seqs)
+ return _merge_sorted_binary(seqs)
else:
- return _merge_sorted_key(seqs, key)
-
+ return _merge_sorted_binary_key(seqs, key)
-def _merge_sorted_key(seqs, key):
- # The commented code below shows an alternative (slower) implementation
- # to apply a key function for sorting.
- #
- # mapper = lambda i, item: (key(item), i, item)
- # keyiters = [map(partial(mapper, i), itr) for i, itr in
- # enumerate(seqs)]
- # return (item for (item_key, i, item) in heapq.merge(*keyiters))
- # binary heap as a priority queue
- pq = []
+def _merge_sorted_binary(seqs):
+ mid = len(seqs) // 2
+ L1 = seqs[:mid]
+ if len(L1) == 1:
+ seq1 = iter(L1[0])
+ else:
+ seq1 = _merge_sorted_binary(L1)
+ L2 = seqs[mid:]
+ if len(L2) == 1:
+ seq2 = iter(L2[0])
+ else:
+ seq2 = _merge_sorted_binary(L2)
- # Initial population
- for itnum, it in enumerate(map(iter, seqs)):
- try:
- item = next(it)
- pq.append([key(item), itnum, item, it])
- except StopIteration:
- pass
- heapq.heapify(pq)
+ try:
+ val2 = next(seq2)
+ except StopIteration:
+ for val1 in seq1:
+ yield val1
+ return
+
+ for val1 in seq1:
+ if val2 < val1:
+ yield val2
+ for val2 in seq2:
+ if val2 < val1:
+ yield val2
+ else:
+ yield val1
+ break
+ else:
+ break
+ else:
+ yield val1
+ else:
+ yield val2
+ for val2 in seq2:
+ yield val2
+ return
+ yield val1
+ for val1 in seq1:
+ yield val1
+
+
+def _merge_sorted_binary_key(seqs, key):
+ mid = len(seqs) // 2
+ L1 = seqs[:mid]
+ if len(L1) == 1:
+ seq1 = iter(L1[0])
+ else:
+ seq1 = _merge_sorted_binary_key(L1, key)
+ L2 = seqs[mid:]
+ if len(L2) == 1:
+ seq2 = iter(L2[0])
+ else:
+ seq2 = _merge_sorted_binary_key(L2, key)
- # Repeatedly yield and then repopulate from the same iterator
- heapreplace = heapq.heapreplace
- heappop = heapq.heappop
- while len(pq) > 1:
- try:
- while True:
- # raises IndexError when pq is empty
- _, itnum, item, it = s = pq[0]
- yield item
- item = next(it) # raises StopIteration when exhausted
- s[0] = key(item)
- s[2] = item
- heapreplace(pq, s) # restore heap condition
- except StopIteration:
- heappop(pq) # remove empty iterator
- if pq:
- # Much faster when only a single iterable remains
- _, itnum, item, it = pq[0]
- yield item
- for item in it:
- yield item
+ try:
+ val2 = next(seq2)
+ except StopIteration:
+ for val1 in seq1:
+ yield val1
+ return
+ key2 = key(val2)
+
+ for val1 in seq1:
+ key1 = key(val1)
+ if key2 < key1:
+ yield val2
+ for val2 in seq2:
+ key2 = key(val2)
+ if key2 < key1:
+ yield val2
+ else:
+ yield val1
+ break
+ else:
+ break
+ else:
+ yield val1
+ else:
+ yield val2
+ for val2 in seq2:
+ yield val2
+ return
+ yield val1
+ for val1 in seq1:
+ yield val1
-def interleave(seqs, pass_exceptions=()):
+def interleave(seqs):
""" Interleave a sequence of sequences
>>> list(interleave([[1, 2], [3, 4]]))
@@ -178,16 +227,15 @@ def interleave(seqs, pass_exceptions=()):
Returns a lazy iterator
"""
- iters = map(iter, seqs)
- while iters:
- newiters = []
- for itr in iters:
- try:
+ iters = itertools.cycle(map(iter, seqs))
+ while True:
+ try:
+ for itr in iters:
yield next(itr)
- newiters.append(itr)
- except (StopIteration,) + tuple(pass_exceptions):
- pass
- iters = newiters
+ return
+ except StopIteration:
+ predicate = partial(operator.is_not, itr)
+ iters = itertools.cycle(itertools.takewhile(predicate, iters))
def unique(seq, key=None):
@@ -423,7 +471,7 @@ def concat(seqs):
An infinite sequence will prevent the rest of the arguments from
being included.
- We use chain.from_iterable rather than chain(*seqs) so that seqs
+ We use chain.from_iterable rather than ``chain(*seqs)`` so that seqs
can be a generator.
>>> list(concat([[], [1], [2, 3]]))
@@ -463,9 +511,7 @@ def cons(el, seq):
>>> list(cons(1, [2, 3]))
[1, 2, 3]
"""
- yield el
- for s in seq:
- yield s
+ return itertools.chain([el], seq)
def interpose(el, seq):
@@ -617,16 +663,8 @@ def sliding_window(n, seq):
>>> list(map(mean, sliding_window(2, [1, 2, 3, 4])))
[1.5, 2.5, 3.5]
"""
- it = iter(seq)
- # An efficient FIFO data structure with maximum length
- d = collections.deque(itertools.islice(it, n), n)
- if len(d) != n:
- raise StopIteration()
- d_append = d.append
- for item in it:
- yield tuple(d)
- d_append(item)
- yield tuple(d)
+ return zip(*(collections.deque(itertools.islice(it, i), 0) or it
+ for i, it in enumerate(itertools.tee(seq, n))))
no_pad = '__no__pad__'
@@ -673,7 +711,10 @@ def partition_all(n, seq):
"""
args = [iter(seq)] * n
it = zip_longest(*args, fillvalue=no_pad)
- prev = next(it)
+ try:
+ prev = next(it)
+ except StopIteration:
+ return
for item in it:
yield prev
prev = item
@@ -706,8 +747,7 @@ def pluck(ind, seqs, default=no_default):
This is equivalent to running `map(curried.get(ind), seqs)`
- ``ind`` can be either a single string/index or a sequence of
- strings/indices.
+ ``ind`` can be either a single string/index or a list of strings/indices.
``seqs`` should be sequence containing sequences or dicts.
e.g.
diff --git a/toolz/tests/test_curried.py b/toolz/tests/test_curried.py
index 5c89149..2efb000 100644
--- a/toolz/tests/test_curried.py
+++ b/toolz/tests/test_curried.py
@@ -2,6 +2,7 @@ import toolz
import toolz.curried
from toolz.curried import (take, first, second, sorted, merge_with, reduce,
merge, operator as cop)
+from toolz.compatibility import import_module
from collections import defaultdict
from operator import add
@@ -62,3 +63,51 @@ def test_curried_operator():
# Make sure this isn't totally empty.
assert len(set(vars(cop)) & set(['add', 'sub', 'mul'])) == 3
+
+
+def test_curried_namespace():
+ exceptions = import_module('toolz.curried.exceptions')
+ namespace = {}
+
+ def should_curry(func):
+ if not callable(func) or isinstance(func, toolz.curry):
+ return False
+ nargs = toolz.functoolz.num_required_args(func)
+ if nargs is None or nargs > 1:
+ return True
+ return nargs == 1 and toolz.functoolz.has_keywords(func)
+
+
+ def curry_namespace(ns):
+ return dict(
+ (name, toolz.curry(f) if should_curry(f) else f)
+ for name, f in ns.items() if '__' not in name
+ )
+
+ from_toolz = curry_namespace(vars(toolz))
+ from_exceptions = curry_namespace(vars(exceptions))
+ namespace.update(toolz.merge(from_toolz, from_exceptions))
+
+ namespace = toolz.valfilter(callable, namespace)
+ curried_namespace = toolz.valfilter(callable, toolz.curried.__dict__)
+
+ if namespace != curried_namespace:
+ missing = set(namespace) - set(curried_namespace)
+ if missing:
+ raise AssertionError('There are missing functions in toolz.curried:\n %s'
+ % ' \n'.join(sorted(missing)))
+ extra = set(curried_namespace) - set(namespace)
+ if extra:
+ raise AssertionError('There are extra functions in toolz.curried:\n %s'
+ % ' \n'.join(sorted(extra)))
+ unequal = toolz.merge_with(list, namespace, curried_namespace)
+ unequal = toolz.valfilter(lambda x: x[0] != x[1], unequal)
+ messages = []
+ for name, (orig_func, auto_func) in sorted(unequal.items()):
+ if name in from_exceptions:
+ messages.append('%s should come from toolz.curried.exceptions' % name)
+ elif should_curry(getattr(toolz, name)):
+ messages.append('%s should be curried from toolz' % name)
+ else:
+ messages.append('%s should come from toolz and NOT be curried' % name)
+ raise AssertionError('\n'.join(messages))
diff --git a/toolz/tests/test_curried_doctests.py b/toolz/tests/test_curried_doctests.py
new file mode 100644
index 0000000..5fa0935
--- /dev/null
+++ b/toolz/tests/test_curried_doctests.py
@@ -0,0 +1,11 @@
+import doctest
+import toolz
+
+
+def test_doctests():
+ toolz.__test__ = {}
+ for name, func in vars(toolz).items():
+ if isinstance(func, toolz.curry):
+ toolz.__test__[name] = func.func
+ assert doctest.testmod(toolz).failed == 0
+ del toolz.__test__
diff --git a/toolz/tests/test_itertoolz.py b/toolz/tests/test_itertoolz.py
index bb8838d..93aa856 100644
--- a/toolz/tests/test_itertoolz.py
+++ b/toolz/tests/test_itertoolz.py
@@ -86,6 +86,13 @@ def test_merge_sorted():
[(9, 1), (9, 8), (9, 9)]]
assert list(merge_sorted(*data, key=lambda x: x[1])) == [
(9, 1), (1, 2), (5, 3), (0, 4), (6, 5), (3, 6), (8, 8), (9, 8), (9, 9)]
+ assert list(merge_sorted()) == []
+ assert list(merge_sorted([1, 2, 3])) == [1, 2, 3]
+ assert list(merge_sorted([1, 4, 5], [2, 3])) == [1, 2, 3, 4, 5]
+ assert list(merge_sorted([1, 4, 5], [2, 3], key=identity)) == [
+ 1, 2, 3, 4, 5]
+ assert list(merge_sorted([1, 5], [2], [4, 7], [3, 6], key=identity)) == [
+ 1, 2, 3, 4, 5, 6, 7]
def test_interleave():
@@ -328,11 +335,10 @@ def test_pluck():
data = [{'id': 1, 'name': 'cheese'}, {'id': 2, 'name': 'pies', 'price': 1}]
assert list(pluck('id', data)) == [1, 2]
- assert list(pluck('price', data, None)) == [None, 1]
+ assert list(pluck('price', data, 0)) == [0, 1]
assert list(pluck(['id', 'name'], data)) == [(1, 'cheese'), (2, 'pies')]
assert list(pluck(['name'], data)) == [('cheese',), ('pies',)]
- assert list(pluck(['price', 'other'], data, None)) == [(None, None),
- (1, None)]
+ assert list(pluck(['price', 'other'], data, 0)) == [(0, 0), (1, 0)]
assert raises(IndexError, lambda: list(pluck(1, [[0]])))
assert raises(KeyError, lambda: list(pluck('name', [{'id': 1}])))
diff --git a/toolz/tests/test_serialization.py b/toolz/tests/test_serialization.py
index 17e332b..a49f7a8 100644
--- a/toolz/tests/test_serialization.py
+++ b/toolz/tests/test_serialization.py
@@ -40,3 +40,18 @@ def test_instanceproperty():
assert p2.__get__(None) is None
assert p2.__get__(0) is False
assert p2.__get__(1) is True
+
+
+def f(x, y):
+ return x, y
+
+
+def test_flip():
+ flip = pickle.loads(pickle.dumps(toolz.functoolz.flip))
+ assert flip is toolz.functoolz.flip
+ g1 = flip(f)
+ g2 = pickle.loads(pickle.dumps(g1))
+ assert g1(1, 2) == g2(1, 2) == f(2, 1)
+ g1 = flip(f)(1)
+ g2 = pickle.loads(pickle.dumps(g1))
+ assert g1(2) == g2(2) == f(2, 1)
diff --git a/toolz/tests/test_tlz.py b/toolz/tests/test_tlz.py
new file mode 100644
index 0000000..ed2646a
--- /dev/null
+++ b/toolz/tests/test_tlz.py
@@ -0,0 +1,55 @@
+import toolz
+
+
+def test_tlz():
+ import tlz
+ tlz.curry
+ tlz.functoolz.curry
+ assert tlz.__package__ == 'tlz'
+ assert tlz.__name__ == 'tlz'
+ import tlz.curried
+ assert tlz.curried.__package__ == 'tlz.curried'
+ assert tlz.curried.__name__ == 'tlz.curried'
+ tlz.curried.curry
+ import tlz.curried.operator
+ assert tlz.curried.operator.__package__ in (None, 'tlz.curried')
+ assert tlz.curried.operator.__name__ == 'tlz.curried.operator'
+ assert tlz.functoolz.__name__ == 'tlz.functoolz'
+ m1 = tlz.functoolz
+ import tlz.functoolz as m2
+ assert m1 is m2
+ import tlz.sandbox
... 34 lines suppressed ...
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/toolz.git
More information about the Python-modules-commits
mailing list