Skip to content

Commit

Permalink
Merge pull request #255 from llllllllll/curried-operator
Browse files Browse the repository at this point in the history
ENH: Adds curried.operator
  • Loading branch information
eriknw committed Aug 1, 2015
2 parents 46af29c + a4127a5 commit b1a051d
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 15 deletions.
35 changes: 21 additions & 14 deletions toolz/curried.py → toolz/curried/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,32 +23,39 @@
See Also:
toolz.functoolz.curry
"""
import inspect

from . import exceptions
from . import operator
import toolz
import toolz.curried_exceptions
from .functoolz import curry
import inspect


def _nargs(f):
try:
return len(inspect.getargspec(f).args)
except TypeError:
return None
return 0


def _should_curry(f):
do_curry = set((toolz.map, toolz.filter, toolz.sorted, toolz.reduce))
return (callable(f) and _nargs(f) and _nargs(f) > 1
or f in do_curry)
do_curry = frozenset((toolz.map, toolz.filter, toolz.sorted, toolz.reduce))
return (callable(f) and _nargs(f) > 1 or f in do_curry)


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
)

_d = dict((name, curry(f) if _should_curry(f) else f)
for name, f in toolz.__dict__.items()
if '__' not in name)

_exceptions = dict((name, curry(f) if callable(f) else f)
for name, f in toolz.curried_exceptions.__dict__.items()
if '__' not in name)
locals().update(toolz.merge(
_curry_namespace(vars(toolz)),
_curry_namespace(vars(exceptions)),
))

locals().update(toolz.merge(_d, _exceptions))
# Clean up the namespace.
del _nargs
del _should_curry
del exceptions
del toolz
5 changes: 5 additions & 0 deletions toolz/curried_exceptions.py → toolz/curried/exceptions.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
import toolz


__all__ = ['merge_with', 'merge']


@toolz.curry
def merge_with(fn, *dicts, **kwargs):
if len(dicts) == 0:
raise TypeError()
else:
return toolz.merge_with(fn, *dicts, **kwargs)


@toolz.curry
def merge(*dicts, **kwargs):
if len(dicts) == 0:
raise TypeError()
Expand Down
30 changes: 30 additions & 0 deletions toolz/curried/operator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
from __future__ import absolute_import

import operator

from toolz import curry


# We use a blacklist instead of whitelist because:
# 1. We have more things to include than exclude.
# 2. This gives us access to things like matmul iff we are in Python >=3.5.
no_curry = frozenset((
'abs',
'index',
'inv',
'invert',
'neg',
'not_',
'pos',
'truth',
))

locals().update(
dict((name, curry(f) if name not in no_curry else f)
for name, f in vars(operator).items() if callable(f)),
)

# Clean up the namespace.
del curry
del no_curry
del operator
21 changes: 20 additions & 1 deletion toolz/tests/test_curried.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import toolz
import toolz.curried
from toolz.curried import (take, first, second, sorted, merge_with, reduce,
merge)
merge, operator as cop)
from collections import defaultdict
from operator import add

Expand Down Expand Up @@ -38,3 +38,22 @@ def test_reduce():

def test_module_name():
assert toolz.curried.__name__ == 'toolz.curried'


def test_curried_operator():
for k, v in vars(cop).items():
if not callable(v):
continue

if not isinstance(v, toolz.curry):
try:
# Make sure it is unary
# We cannot use isunary because it might be defined in C.
v(1)
except TypeError:
raise AssertionError(
'toolz.curried.operator.%s is not curried!' % k,
)

# Make sure this isn't totally empty.
assert len(set(vars(cop)) & set(['add', 'sub', 'mul'])) == 3

0 comments on commit b1a051d

Please sign in to comment.