Skip to content

Commit b71439a

Browse files
committed
Merge pull request #157 from mrocklin/py3.4
add 3.4 to .travis.yml
2 parents cc0c9b6 + 90ba43a commit b71439a

File tree

4 files changed

+83
-8
lines changed

4 files changed

+83
-8
lines changed

.travis.yml

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ python:
44
- "2.7"
55
- "3.2"
66
- "3.3"
7+
- "3.4"
78
- "pypy"
89

910
env:

release-notes

+25
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,28 @@ New in 0.6.0
2828
* Flattened directory structure
2929
* Add `pluck` function from underscore.js
3030
* Remove `sandbox.jackknife`
31+
32+
33+
New in 0.6.1
34+
35+
36+
* Avoid generators, favor map. Assists in debugging.
37+
* Cleaner `curry` implementation
38+
* `EqualityHashKey` added to sandbox
39+
* New `join` operation
40+
* `join`, `groupby`, ... accept non-callable key functions.
41+
* Fix bug in `get` where `get([1], coll)` used to return element rather than
42+
length-one tuple
43+
* `juxt` returns a tuple, not a generator
44+
* `reduceby` no longer requires `default` keyword argument
45+
* Toolz builds on binstar build
46+
* Fix serialization issues for `juxt`, `complement`
47+
* Many speed improvements:
48+
* Cache method lookup
49+
* Faster `merge_sorted` without key
50+
* An additional round of tuning on `groupby`
51+
52+
53+
New Authors:
54+
55+
Leonid Shvechikov, José Ricardo, Lars Buitinck, Tom Prince

toolz/functoolz.py

+56-7
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from functools import reduce, partial
22
import inspect
33
import operator
4+
import sys
45

56

67
__all__ = ('identity', 'thread_first', 'thread_last', 'memoize', 'compose',
@@ -84,6 +85,13 @@ def evalform_back(val, form):
8485
return reduce(evalform_back, forms, val)
8586

8687

88+
# This is a kludge for Python 3.4.0 support
89+
# currently len(inspect.getargspec(map).args) == 0, a wrong result.
90+
# As this is fixed in future versions then hopefully this kludge can be
91+
# removed.
92+
known_numargs = {map: 2, filter: 2, reduce: 2}
93+
94+
8795
def _num_required_args(func):
8896
""" Number of args for func
8997
@@ -99,6 +107,8 @@ def _num_required_args(func):
99107
>>> print(_num_required_args(bar))
100108
None
101109
"""
110+
if func in known_numargs:
111+
return known_numargs[func]
102112
try:
103113
spec = inspect.getargspec(func)
104114
if spec.varargs:
@@ -142,8 +152,10 @@ def __init__(self, func, *args, **kwargs):
142152
raise TypeError("Input must be callable")
143153

144154
# curry- or functools.partial-like object? Unpack and merge arguments
145-
if (hasattr(func, 'func') and hasattr(func, 'args')
146-
and hasattr(func, 'keywords')):
155+
if (hasattr(func, 'func')
156+
and hasattr(func, 'args')
157+
and hasattr(func, 'keywords')
158+
and isinstance(func.args, tuple)):
147159
_kwargs = {}
148160
if func.keywords:
149161
_kwargs.update(func.keywords)
@@ -219,6 +231,45 @@ def __setstate__(self, state):
219231
self.__dict__.update(userdict)
220232

221233

234+
def has_kwargs(f):
235+
""" Does a function have keyword arguments?
236+
237+
>>> def f(x, y=0):
238+
... return x + y
239+
240+
>>> has_kwargs(f)
241+
True
242+
"""
243+
if sys.version_info[0] == 2: # pragma: no cover
244+
spec = inspect.getargspec(f)
245+
return bool(spec and (spec.keywords or spec.defaults))
246+
if sys.version_info[0] == 3: # pragma: no cover
247+
spec = inspect.getfullargspec(f)
248+
return bool(spec.defaults)
249+
250+
251+
def isunary(f):
252+
""" Does a function have only a single argument?
253+
254+
>>> def f(x):
255+
... return x
256+
257+
>>> isunary(f)
258+
True
259+
>>> isunary(lambda x, y: x + y)
260+
False
261+
"""
262+
try:
263+
if sys.version_info[0] == 2: # pragma: no cover
264+
spec = inspect.getargspec(f)
265+
if sys.version_info[0] == 3: # pragma: no cover
266+
spec = inspect.getfullargspec(f)
267+
return bool(spec and spec.varargs is None and not has_kwargs(f)
268+
and len(spec.args) == 1)
269+
except TypeError: # pragma: no cover
270+
return None # in Python < 3.4 builtins fail, return None
271+
272+
222273
@curry
223274
def memoize(func, cache=None, key=None):
224275
""" Cache a function's result for speedy future evaluation
@@ -260,12 +311,10 @@ def memoize(func, cache=None, key=None):
260311
cache = {}
261312

262313
try:
263-
spec = inspect.getargspec(func)
264-
may_have_kwargs = bool(not spec or spec.keywords or spec.defaults)
314+
may_have_kwargs = has_kwargs(func)
265315
# Is unary function (single arg, no variadic argument or keywords)?
266-
is_unary = (spec and spec.varargs is None and not may_have_kwargs
267-
and len(spec.args) == 1)
268-
except TypeError:
316+
is_unary = isunary(func)
317+
except TypeError: # pragma: no cover
269318
may_have_kwargs = True
270319
is_unary = False
271320

toolz/tests/test_functoolz.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,7 @@ def f(x, y=0):
314314

315315

316316
def test__num_required_args():
317-
assert _num_required_args(map) is None
317+
assert _num_required_args(map) != 0
318318
assert _num_required_args(lambda x: x) == 1
319319
assert _num_required_args(lambda x, y: x) == 2
320320

0 commit comments

Comments
 (0)