summaryrefslogtreecommitdiff
path: root/numpy/lib
diff options
context:
space:
mode:
Diffstat (limited to 'numpy/lib')
-rw-r--r--numpy/lib/arraysetops.py10
-rw-r--r--numpy/lib/format.py45
-rw-r--r--numpy/lib/function_base.py120
-rw-r--r--numpy/lib/npyio.py8
-rw-r--r--numpy/lib/tests/data/python3.npybin0 -> 96 bytes
-rw-r--r--numpy/lib/tests/data/win64python2.npybin0 -> 96 bytes
-rw-r--r--numpy/lib/tests/test_format.py10
-rw-r--r--numpy/lib/tests/test_function_base.py38
-rw-r--r--numpy/lib/tests/test_io.py11
-rw-r--r--numpy/lib/tests/test_nanfunctions.py16
-rw-r--r--numpy/lib/utils.py158
11 files changed, 270 insertions, 146 deletions
diff --git a/numpy/lib/arraysetops.py b/numpy/lib/arraysetops.py
index 5c3b504de..d3b6119f4 100644
--- a/numpy/lib/arraysetops.py
+++ b/numpy/lib/arraysetops.py
@@ -241,6 +241,11 @@ def intersect1d(ar1, ar2, assume_unique=False):
>>> np.intersect1d([1, 3, 4, 3], [3, 1, 2, 1])
array([1, 3])
+ To intersect more than two arrays, use functools.reduce:
+
+ >>> from functools import reduce
+ >>> reduce(np.intersect1d, ([1, 3, 4, 3], [3, 1, 2, 1], [6, 3, 4, 2]))
+ array([3])
"""
if not assume_unique:
# Might be faster than unique( intersect1d( ar1, ar2 ) )?
@@ -421,6 +426,11 @@ def union1d(ar1, ar2):
>>> np.union1d([-1, 0, 1], [-2, 0, 2])
array([-2, -1, 0, 1, 2])
+ To find the union of more than two arrays, use functools.reduce:
+
+ >>> from functools import reduce
+ >>> reduce(np.union1d, ([1, 3, 4, 3], [3, 1, 2, 1], [6, 3, 4, 2]))
+ array([1, 2, 3, 4, 6])
"""
return unique(np.concatenate((ar1, ar2)))
diff --git a/numpy/lib/format.py b/numpy/lib/format.py
index 98743b6ad..b93f86ca3 100644
--- a/numpy/lib/format.py
+++ b/numpy/lib/format.py
@@ -141,7 +141,7 @@ import sys
import io
import warnings
from numpy.lib.utils import safe_eval
-from numpy.compat import asbytes, isfileobj, long, basestring
+from numpy.compat import asbytes, asstr, isfileobj, long, basestring
if sys.version_info[0] >= 3:
import pickle
@@ -298,7 +298,8 @@ def _write_array_header(fp, d, version=None):
# can take advantage of our premature optimization.
current_header_len = MAGIC_LEN + 2 + len(header) + 1 # 1 for the newline
topad = 16 - (current_header_len % 16)
- header = asbytes(header + ' '*topad + '\n')
+ header = header + ' '*topad + '\n'
+ header = asbytes(_filter_header(header))
if len(header) >= (256*256) and version == (1, 0):
raise ValueError("header does not fit inside %s bytes required by the"
@@ -410,6 +411,45 @@ def read_array_header_2_0(fp):
"""
_read_array_header(fp, version=(2, 0))
+
+def _filter_header(s):
+ """Clean up 'L' in npz header ints.
+
+ Cleans up the 'L' in strings representing integers. Needed to allow npz
+ headers produced in Python2 to be read in Python3.
+
+ Parameters
+ ----------
+ s : byte string
+ Npy file header.
+
+ Returns
+ -------
+ header : str
+ Cleaned up header.
+
+ """
+ import tokenize
+ if sys.version_info[0] >= 3:
+ from io import StringIO
+ else:
+ from StringIO import StringIO
+
+ tokens = []
+ last_token_was_number = False
+ for token in tokenize.generate_tokens(StringIO(asstr(s)).read):
+ token_type = token[0]
+ token_string = token[1]
+ if (last_token_was_number and
+ token_type == tokenize.NAME and
+ token_string == "L"):
+ continue
+ else:
+ tokens.append(token)
+ last_token_was_number = (token_type == tokenize.NUMBER)
+ return tokenize.untokenize(tokens)
+
+
def _read_array_header(fp, version):
"""
see read_array_header_1_0
@@ -434,6 +474,7 @@ def _read_array_header(fp, version):
# "shape" : tuple of int
# "fortran_order" : bool
# "descr" : dtype.descr
+ header = _filter_header(header)
try:
d = safe_eval(header)
except SyntaxError as e:
diff --git a/numpy/lib/function_base.py b/numpy/lib/function_base.py
index 8b384bfaa..36ce94bad 100644
--- a/numpy/lib/function_base.py
+++ b/numpy/lib/function_base.py
@@ -515,8 +515,7 @@ def average(a, axis=None, weights=None, returned=False):
scl = avg.dtype.type(a.size/avg.size)
else:
a = a + 0.0
- wgt = np.array(weights, dtype=a.dtype, copy=0)
-
+ wgt = np.asarray(weights)
# Sanity checks
if a.shape != wgt.shape:
if axis is None:
@@ -533,7 +532,7 @@ def average(a, axis=None, weights=None, returned=False):
# setup wgt to broadcast along axis
wgt = np.array(wgt, copy=0, ndmin=a.ndim).swapaxes(-1, axis)
- scl = wgt.sum(axis=axis)
+ scl = wgt.sum(axis=axis, dtype=np.result_type(a.dtype, wgt.dtype))
if (scl == 0.0).any():
raise ZeroDivisionError(
"Weights sum to zero, can't be normalized")
@@ -883,28 +882,33 @@ def copy(a, order='K'):
# Basic operations
-def gradient(f, *varargs):
+def gradient(f, *varargs, **kwargs):
"""
Return the gradient of an N-dimensional array.
-
+
The gradient is computed using second order accurate central differences
- in the interior and second order accurate one-sides (forward or backwards)
- differences at the boundaries. The returned gradient hence has the same
- shape as the input array.
+ in the interior and either first differences or second order accurate
+ one-sides (forward or backwards) differences at the boundaries. The
+ returned gradient hence has the same shape as the input array.
Parameters
----------
f : array_like
- An N-dimensional array containing samples of a scalar function.
- `*varargs` : scalars
- 0, 1, or N scalars specifying the sample distances in each direction,
- that is: `dx`, `dy`, `dz`, ... The default distance is 1.
+ An N-dimensional array containing samples of a scalar function.
+ varargs : list of scalar, optional
+ N scalars specifying the sample distances for each dimension,
+ i.e. `dx`, `dy`, `dz`, ... Default distance: 1.
+ edge_order : {1, 2}, optional
+ Gradient is calculated using N\ :sup:`th` order accurate differences
+ at the boundaries. Default: 1.
+
+ .. versionadded:: 1.9.1
Returns
-------
gradient : ndarray
- N arrays of the same shape as `f` giving the derivative of `f` with
- respect to each dimension.
+ N arrays of the same shape as `f` giving the derivative of `f` with
+ respect to each dimension.
Examples
--------
@@ -916,15 +920,14 @@ def gradient(f, *varargs):
>>> np.gradient(np.array([[1, 2, 6], [3, 4, 5]], dtype=np.float))
[array([[ 2., 2., -1.],
- [ 2., 2., -1.]]),
- array([[ 1. , 2.5, 4. ],
- [ 1. , 1. , 1. ]])]
+ [ 2., 2., -1.]]), array([[ 1. , 2.5, 4. ],
+ [ 1. , 1. , 1. ]])]
- >>> x = np.array([0,1,2,3,4])
- >>> dx = gradient(x)
+ >>> x = np.array([0, 1, 2, 3, 4])
+ >>> dx = np.gradient(x)
>>> y = x**2
- >>> gradient(y,dx)
- array([0., 2., 4., 6., 8.])
+ >>> np.gradient(y, dx, edge_order=2)
+ array([-0., 2., 4., 6., 8.])
"""
f = np.asanyarray(f)
N = len(f.shape) # number of dimensions
@@ -939,6 +942,13 @@ def gradient(f, *varargs):
raise SyntaxError(
"invalid number of arguments")
+ edge_order = kwargs.pop('edge_order', 1)
+ if kwargs:
+ raise TypeError('"{}" are not valid keyword arguments.'.format(
+ '", "'.join(kwargs.keys())))
+ if edge_order > 2:
+ raise ValueError("'edge_order' greater than 2 not supported")
+
# use central differences on interior and one-sided differences on the
# endpoints. This preserves second order-accuracy over the full domain.
@@ -978,7 +988,7 @@ def gradient(f, *varargs):
"at least two elements are required.")
# Numerical differentiation: 1st order edges, 2nd order interior
- if y.shape[axis] == 2:
+ if y.shape[axis] == 2 or edge_order == 1:
# Use first order differences for time data
out = np.empty_like(y, dtype=otype)
@@ -1026,7 +1036,8 @@ def gradient(f, *varargs):
out[slice1] = (3.0*y[slice2] - 4.0*y[slice3] + y[slice4])/2.0
# divide by step size
- outvals.append(out / dx[axis])
+ out /= dx[axis]
+ outvals.append(out)
# reset the slice object in this dimension to ":"
slice1[axis] = slice(None)
@@ -1102,7 +1113,7 @@ def diff(a, n=1, axis=-1):
return a[slice1]-a[slice2]
-def interp(x, xp, fp, left=None, right=None):
+def interp(x, xp, fp, left=None, right=None, period=None):
"""
One-dimensional linear interpolation.
@@ -1115,7 +1126,9 @@ def interp(x, xp, fp, left=None, right=None):
The x-coordinates of the interpolated values.
xp : 1-D sequence of floats
- The x-coordinates of the data points, must be increasing.
+ The x-coordinates of the data points, must be increasing if argument
+ `period` is not specified. Otherwise, `xp` is internally sorted after
+ normalizing the periodic boundaries with ``xp = xp % period``.
fp : 1-D sequence of floats
The y-coordinates of the data points, same length as `xp`.
@@ -1126,6 +1139,12 @@ def interp(x, xp, fp, left=None, right=None):
right : float, optional
Value to return for `x > xp[-1]`, default is `fp[-1]`.
+ period : None or float, optional
+ .. versionadded:: 1.10.0
+ A period for the x-coordinates. This parameter allows the proper
+ interpolation of angular x-coordinates. Parameters `left` and `right`
+ are ignored if `period` is specified.
+
Returns
-------
y : {float, ndarray}
@@ -1135,6 +1154,8 @@ def interp(x, xp, fp, left=None, right=None):
------
ValueError
If `xp` and `fp` have different length
+ If `xp` or `fp` are not 1-D sequences
+ If `period == 0`
Notes
-----
@@ -1144,7 +1165,6 @@ def interp(x, xp, fp, left=None, right=None):
np.all(np.diff(xp) > 0)
-
Examples
--------
>>> xp = [1, 2, 3]
@@ -1170,13 +1190,51 @@ def interp(x, xp, fp, left=None, right=None):
[<matplotlib.lines.Line2D object at 0x...>]
>>> plt.show()
+ Interpolation with periodic x-coordinates:
+
+ >>> x = [-180, -170, -185, 185, -10, -5, 0, 365]
+ >>> xp = [190, -190, 350, -350]
+ >>> fp = [5, 10, 3, 4]
+ >>> np.interp(x, xp, fp, period=360)
+ array([7.5, 5., 8.75, 6.25, 3., 3.25, 3.5, 3.75])
+
"""
- if isinstance(x, (float, int, number)):
- return compiled_interp([x], xp, fp, left, right).item()
- elif isinstance(x, np.ndarray) and x.ndim == 0:
- return compiled_interp([x], xp, fp, left, right).item()
+ if period is None:
+ if isinstance(x, (float, int, number)):
+ return compiled_interp([x], xp, fp, left, right).item()
+ elif isinstance(x, np.ndarray) and x.ndim == 0:
+ return compiled_interp([x], xp, fp, left, right).item()
+ else:
+ return compiled_interp(x, xp, fp, left, right)
else:
- return compiled_interp(x, xp, fp, left, right)
+ if period == 0:
+ raise ValueError("period must be a non-zero value")
+ period = abs(period)
+ left = None
+ right = None
+ return_array = True
+ if isinstance(x, (float, int, number)):
+ return_array = False
+ x = [x]
+ x = np.asarray(x, dtype=np.float64)
+ xp = np.asarray(xp, dtype=np.float64)
+ fp = np.asarray(fp, dtype=np.float64)
+ if xp.ndim != 1 or fp.ndim != 1:
+ raise ValueError("Data points must be 1-D sequences")
+ if xp.shape[0] != fp.shape[0]:
+ raise ValueError("fp and xp are not of the same length")
+ # normalizing periodic boundaries
+ x = x % period
+ xp = xp % period
+ asort_xp = np.argsort(xp)
+ xp = xp[asort_xp]
+ fp = fp[asort_xp]
+ xp = np.concatenate((xp[-1:]-period, xp, xp[0:1]+period))
+ fp = np.concatenate((fp[-1:], fp, fp[0:1]))
+ if return_array:
+ return compiled_interp(x, xp, fp, left, right)
+ else:
+ return compiled_interp(x, xp, fp, left, right).item()
def angle(z, deg=0):
diff --git a/numpy/lib/npyio.py b/numpy/lib/npyio.py
index 641203f34..cbef1a6e2 100644
--- a/numpy/lib/npyio.py
+++ b/numpy/lib/npyio.py
@@ -122,6 +122,14 @@ class BagObj(object):
return object.__getattribute__(self, '_obj')[key]
except KeyError:
raise AttributeError(key)
+
+ def __dir__(self):
+ """
+ Enables dir(bagobj) to list the files in an NpzFile.
+
+ This also enables tab-completion in an interpreter or IPython.
+ """
+ return object.__getattribute__(self, '_obj').keys()
def zipfile_factory(*args, **kwargs):
diff --git a/numpy/lib/tests/data/python3.npy b/numpy/lib/tests/data/python3.npy
new file mode 100644
index 000000000..7c6997dd6
--- /dev/null
+++ b/numpy/lib/tests/data/python3.npy
Binary files differ
diff --git a/numpy/lib/tests/data/win64python2.npy b/numpy/lib/tests/data/win64python2.npy
new file mode 100644
index 000000000..d9bc36af7
--- /dev/null
+++ b/numpy/lib/tests/data/win64python2.npy
Binary files differ
diff --git a/numpy/lib/tests/test_format.py b/numpy/lib/tests/test_format.py
index c09386789..ee77386bc 100644
--- a/numpy/lib/tests/test_format.py
+++ b/numpy/lib/tests/test_format.py
@@ -524,6 +524,16 @@ def test_compressed_roundtrip():
assert_array_equal(arr, arr1)
+def test_python2_python3_interoperability():
+ if sys.version_info[0] >= 3:
+ fname = 'win64python2.npy'
+ else:
+ fname = 'python3.npy'
+ path = os.path.join(os.path.dirname(__file__), 'data', fname)
+ data = np.load(path)
+ assert_array_equal(data, np.ones(2))
+
+
def test_version_2_0():
f = BytesIO()
# requires more than 2 byte for header
diff --git a/numpy/lib/tests/test_function_base.py b/numpy/lib/tests/test_function_base.py
index c800f8347..80faf85a6 100644
--- a/numpy/lib/tests/test_function_base.py
+++ b/numpy/lib/tests/test_function_base.py
@@ -124,6 +124,11 @@ class TestAverage(TestCase):
assert_array_equal(average(y1, weights=w2, axis=1), desired)
assert_equal(average(y1, weights=w2), 5.)
+ y3 = rand(5).astype(np.float32)
+ w3 = rand(5).astype(np.float64)
+
+ assert_(np.average(y3, weights=w3).dtype == np.result_type(y3, w3))
+
def test_returned(self):
y = np.array([[1, 2, 3], [4, 5, 6]])
@@ -526,8 +531,18 @@ class TestGradient(TestCase):
def test_masked(self):
# Make sure that gradient supports subclasses like masked arrays
- x = np.ma.array([[1, 1], [3, 4]])
- assert_equal(type(gradient(x)[0]), type(x))
+ x = np.ma.array([[1, 1], [3, 4]],
+ mask=[[False, False], [False, False]])
+ out = gradient(x)[0]
+ assert_equal(type(out), type(x))
+ # And make sure that the output and input don't have aliased mask
+ # arrays
+ assert_(x.mask is not out.mask)
+ # Also check that edge_order=2 doesn't alter the original mask
+ x2 = np.ma.arange(5)
+ x2[2] = np.ma.masked
+ np.gradient(x2, edge_order=2)
+ assert_array_equal(x2.mask, [False, False, True, False, False])
def test_datetime64(self):
# Make sure gradient() can handle special types like datetime64
@@ -536,7 +551,7 @@ class TestGradient(TestCase):
'1910-10-12', '1910-12-12', '1912-12-12'],
dtype='datetime64[D]')
dx = np.array(
- [-7, -3, 0, 31, 61, 396, 1066],
+ [-5, -3, 0, 31, 61, 396, 731],
dtype='timedelta64[D]')
assert_array_equal(gradient(x), dx)
assert_(dx.dtype == np.dtype('timedelta64[D]'))
@@ -547,7 +562,7 @@ class TestGradient(TestCase):
[-5, -3, 10, 12, 61, 321, 300],
dtype='timedelta64[D]')
dx = np.array(
- [-3, 7, 7, 25, 154, 119, -161],
+ [2, 7, 7, 25, 154, 119, -21],
dtype='timedelta64[D]')
assert_array_equal(gradient(x), dx)
assert_(dx.dtype == np.dtype('timedelta64[D]'))
@@ -561,7 +576,7 @@ class TestGradient(TestCase):
dx = x[1] - x[0]
y = 2 * x ** 3 + 4 * x ** 2 + 2 * x
analytical = 6 * x ** 2 + 8 * x + 2
- num_error = np.abs((np.gradient(y, dx) / analytical) - 1)
+ num_error = np.abs((np.gradient(y, dx, edge_order=2) / analytical) - 1)
assert_(np.all(num_error < 0.03) == True)
@@ -1604,6 +1619,9 @@ class TestInterp(TestCase):
def test_exceptions(self):
assert_raises(ValueError, interp, 0, [], [])
assert_raises(ValueError, interp, 0, [0], [1, 2])
+ assert_raises(ValueError, interp, 0, [0, 1], [1, 2], period=0)
+ assert_raises(ValueError, interp, 0, [], [], period=360)
+ assert_raises(ValueError, interp, 0, [0], [1, 2], period=360)
def test_basic(self):
x = np.linspace(0, 1, 5)
@@ -1644,6 +1662,16 @@ class TestInterp(TestCase):
fp = np.sin(xp)
assert_almost_equal(np.interp(np.pi, xp, fp), 0.0)
+ def test_period(self):
+ x = [-180, -170, -185, 185, -10, -5, 0, 365]
+ xp = [190, -190, 350, -350]
+ fp = [5, 10, 3, 4]
+ y = [7.5, 5., 8.75, 6.25, 3., 3.25, 3.5, 3.75]
+ assert_almost_equal(np.interp(x, xp, fp, period=360), y)
+ x = np.array(x, order='F').reshape(2, -1)
+ y = np.array(y, order='C').reshape(2, -1)
+ assert_almost_equal(np.interp(x, xp, fp, period=360), y)
+
def compare_results(res, desired):
for i in range(len(desired)):
diff --git a/numpy/lib/tests/test_io.py b/numpy/lib/tests/test_io.py
index 4038d6a7f..68b2018cd 100644
--- a/numpy/lib/tests/test_io.py
+++ b/numpy/lib/tests/test_io.py
@@ -216,6 +216,17 @@ class TestSavezLoad(RoundtripTest, TestCase):
l = np.load(c)
assert_equal(a, l['file_a'])
assert_equal(b, l['file_b'])
+
+ def test_BagObj(self):
+ a = np.array([[1, 2], [3, 4]], float)
+ b = np.array([[1 + 2j, 2 + 7j], [3 - 6j, 4 + 12j]], complex)
+ c = BytesIO()
+ np.savez(c, file_a=a, file_b=b)
+ c.seek(0)
+ l = np.load(c)
+ assert_equal(sorted(dir(l.f)), ['file_a','file_b'])
+ assert_equal(a, l.f.file_a)
+ assert_equal(b, l.f.file_b)
def test_savez_filename_clashes(self):
# Test that issue #852 is fixed
diff --git a/numpy/lib/tests/test_nanfunctions.py b/numpy/lib/tests/test_nanfunctions.py
index 3da6b5149..35ae86c20 100644
--- a/numpy/lib/tests/test_nanfunctions.py
+++ b/numpy/lib/tests/test_nanfunctions.py
@@ -645,6 +645,22 @@ class TestNanFunctions_Median(TestCase):
assert_raises(IndexError, np.nanmedian, d, axis=(0, 4))
assert_raises(ValueError, np.nanmedian, d, axis=(1, 1))
+ def test_float_special(self):
+ with warnings.catch_warnings(record=True):
+ warnings.simplefilter('ignore', RuntimeWarning)
+ a = np.array([[np.inf, np.nan], [np.nan, np.nan]])
+ assert_equal(np.nanmedian(a, axis=0), [np.inf, np.nan])
+ assert_equal(np.nanmedian(a, axis=1), [np.inf, np.nan])
+ assert_equal(np.nanmedian(a), np.inf)
+
+ # minimum fill value check
+ a = np.array([[np.nan, np.nan, np.inf], [np.nan, np.nan, np.inf]])
+ assert_equal(np.nanmedian(a, axis=1), np.inf)
+
+ # no mask path
+ a = np.array([[np.inf, np.inf], [np.inf, np.inf]])
+ assert_equal(np.nanmedian(a, axis=1), np.inf)
+
class TestNanFunctions_Percentile(TestCase):
diff --git a/numpy/lib/utils.py b/numpy/lib/utils.py
index df0052493..519d0e9b9 100644
--- a/numpy/lib/utils.py
+++ b/numpy/lib/utils.py
@@ -4,6 +4,7 @@ import os
import sys
import types
import re
+import warnings
from numpy.core.numerictypes import issubclass_, issubsctype, issubdtype
from numpy.core import ndarray, ufunc, asarray
@@ -1002,111 +1003,70 @@ class SafeEval(object):
This includes strings with lists, dicts and tuples using the abstract
syntax tree created by ``compiler.parse``.
- For an example of usage, see `safe_eval`.
+ .. deprecated:: 1.10.0
See Also
--------
safe_eval
"""
+ def __init__(self):
+ warnings.warn("SafeEval is deprecated in 1.10 and will be removed.",
+ DeprecationWarning)
- if sys.version_info[0] < 3:
- def visit(self, node, **kw):
- cls = node.__class__
- meth = getattr(self, 'visit'+cls.__name__, self.default)
- return meth(node, **kw)
+ def visit(self, node):
+ cls = node.__class__
+ meth = getattr(self, 'visit' + cls.__name__, self.default)
+ return meth(node)
- def default(self, node, **kw):
- raise SyntaxError("Unsupported source construct: %s"
- % node.__class__)
+ def default(self, node):
+ raise SyntaxError("Unsupported source construct: %s"
+ % node.__class__)
- def visitExpression(self, node, **kw):
- for child in node.getChildNodes():
- return self.visit(child, **kw)
+ def visitExpression(self, node):
+ return self.visit(node.body)
- def visitConst(self, node, **kw):
- return node.value
+ def visitNum(self, node):
+ return node.n
- def visitDict(self, node,**kw):
- return dict(
- [(self.visit(k), self.visit(v)) for k, v in node.items]
- )
-
- def visitTuple(self, node, **kw):
- return tuple([self.visit(i) for i in node.nodes])
-
- def visitList(self, node, **kw):
- return [self.visit(i) for i in node.nodes]
-
- def visitUnaryAdd(self, node, **kw):
- return +self.visit(node.getChildNodes()[0])
-
- def visitUnarySub(self, node, **kw):
- return -self.visit(node.getChildNodes()[0])
-
- def visitName(self, node, **kw):
- if node.name == 'False':
- return False
- elif node.name == 'True':
- return True
- elif node.name == 'None':
- return None
- else:
- raise SyntaxError("Unknown name: %s" % node.name)
- else:
-
- def visit(self, node):
- cls = node.__class__
- meth = getattr(self, 'visit' + cls.__name__, self.default)
- return meth(node)
-
- def default(self, node):
- raise SyntaxError("Unsupported source construct: %s"
- % node.__class__)
-
- def visitExpression(self, node):
- return self.visit(node.body)
-
- def visitNum(self, node):
- return node.n
+ def visitStr(self, node):
+ return node.s
- def visitStr(self, node):
- return node.s
+ def visitBytes(self, node):
+ return node.s
- def visitBytes(self, node):
- return node.s
+ def visitDict(self, node,**kw):
+ return dict([(self.visit(k), self.visit(v))
+ for k, v in zip(node.keys, node.values)])
- def visitDict(self, node,**kw):
- return dict([(self.visit(k), self.visit(v))
- for k, v in zip(node.keys, node.values)])
+ def visitTuple(self, node):
+ return tuple([self.visit(i) for i in node.elts])
- def visitTuple(self, node):
- return tuple([self.visit(i) for i in node.elts])
+ def visitList(self, node):
+ return [self.visit(i) for i in node.elts]
- def visitList(self, node):
- return [self.visit(i) for i in node.elts]
+ def visitUnaryOp(self, node):
+ import ast
+ if isinstance(node.op, ast.UAdd):
+ return +self.visit(node.operand)
+ elif isinstance(node.op, ast.USub):
+ return -self.visit(node.operand)
+ else:
+ raise SyntaxError("Unknown unary op: %r" % node.op)
+
+ def visitName(self, node):
+ if node.id == 'False':
+ return False
+ elif node.id == 'True':
+ return True
+ elif node.id == 'None':
+ return None
+ else:
+ raise SyntaxError("Unknown name: %s" % node.id)
- def visitUnaryOp(self, node):
- import ast
- if isinstance(node.op, ast.UAdd):
- return +self.visit(node.operand)
- elif isinstance(node.op, ast.USub):
- return -self.visit(node.operand)
- else:
- raise SyntaxError("Unknown unary op: %r" % node.op)
-
- def visitName(self, node):
- if node.id == 'False':
- return False
- elif node.id == 'True':
- return True
- elif node.id == 'None':
- return None
- else:
- raise SyntaxError("Unknown name: %s" % node.id)
+ def visitNameConstant(self, node):
+ return node.value
- def visitNameConstant(self, node):
- return node.value
def safe_eval(source):
"""
@@ -1151,26 +1111,8 @@ def safe_eval(source):
SyntaxError: Unsupported source construct: compiler.ast.CallFunc
"""
- # Local imports to speed up numpy's import time.
- import warnings
-
- with warnings.catch_warnings():
- # compiler package is deprecated for 3.x, which is already solved
- # here
- warnings.simplefilter('ignore', DeprecationWarning)
- try:
- import compiler
- except ImportError:
- import ast as compiler
-
- walker = SafeEval()
- try:
- ast = compiler.parse(source, mode="eval")
- except SyntaxError:
- raise
- try:
- return walker.visit(ast)
- except SyntaxError:
- raise
+ # Local import to speed up numpy's import time.
+ import ast
+ return ast.literal_eval(source)
#-----------------------------------------------------------------------------