Skip to content

Commit d3fae53

Browse files
author
Ilan Schnell
committed
Merge commit '8cbed8ce5253a0aa4341e6edbf8be123a06bb123' (Nov 18) into refactor
Conflicts: setup.py
2 parents 04b0ab4 + 8cbed8c commit d3fae53

17 files changed

+167
-35
lines changed

doc/CAPI.txt doc/CAPI.rst.txt

File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.

doc/Py3K.txt doc/Py3K.rst.txt

File renamed without changes.

doc/TESTS.txt doc/TESTS.rst.txt

File renamed without changes.
File renamed without changes.

doc/ufuncs.txt doc/ufuncs.rst.txt

File renamed without changes.

numpy/core/src/scalarmathmodule.c.src

+9-3
Original file line numberDiff line numberDiff line change
@@ -652,7 +652,13 @@ static PyObject *
652652
{
653653
PyObject *ret;
654654
@name@ arg1, arg2;
655-
@otyp@ out;
655+
/*
656+
* NOTE: In gcc >= 4.1, the compiler will reorder floating point operations and
657+
* floating point error state checks. In particular, the arithmetic operations
658+
* were being reordered so that the errors weren't caught. Declaring this output
659+
* variable volatile was the minimal fix for the issue. (Ticket #1671)
660+
*/
661+
volatile @otyp@ out;
656662
#if @twoout@
657663
@otyp@ out2;
658664
PyObject *obj;
@@ -693,9 +699,9 @@ static PyObject *
693699
* as a function call.
694700
*/
695701
#if @twoout@
696-
@name@_ctype_@oper@(arg1, arg2, &out, &out2);
702+
@name@_ctype_@oper@(arg1, arg2, (@otyp@ *)&out, &out2);
697703
#else
698-
@name@_ctype_@oper@(arg1, arg2, &out);
704+
@name@_ctype_@oper@(arg1, arg2, (@otyp@ *)&out);
699705
#endif
700706

701707
#if @fperr@

numpy/core/tests/test_numeric.py

+80
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,86 @@ def test_divide_err(self):
251251
seterr(**err)
252252

253253

254+
class TestFloatExceptions(TestCase):
255+
def assert_raises_fpe(self, fpeerr, flop, x, y):
256+
ftype = type(x)
257+
try:
258+
flop(x, y)
259+
assert_(False,
260+
"Type %s did not raise fpe error '%s'." % (ftype, fpeerr))
261+
except FloatingPointError, exc:
262+
assert_(str(exc).find(fpeerr) >= 0,
263+
"Type %s raised wrong fpe error '%s'." % (ftype, exc))
264+
265+
def assert_op_raises_fpe(self, fpeerr, flop, sc1, sc2):
266+
"""Check that fpe exception is raised.
267+
268+
Given a floating operation `flop` and two scalar values, check that
269+
the operation raises the floating point exception specified by
270+
`fpeerr`. Tests all variants with 0-d array scalars as well.
271+
272+
"""
273+
self.assert_raises_fpe(fpeerr, flop, sc1, sc2);
274+
self.assert_raises_fpe(fpeerr, flop, sc1[()], sc2);
275+
self.assert_raises_fpe(fpeerr, flop, sc1, sc2[()]);
276+
self.assert_raises_fpe(fpeerr, flop, sc1[()], sc2[()]);
277+
278+
def test_floating_exceptions(self):
279+
"""Test basic arithmetic function errors"""
280+
oldsettings = np.seterr(all='raise')
281+
try:
282+
# Test for all real and complex float types
283+
for typecode in np.typecodes['AllFloat']:
284+
ftype = np.obj2sctype(typecode)
285+
if np.dtype(ftype).kind == 'f':
286+
# Get some extreme values for the type
287+
fi = np.finfo(ftype)
288+
ft_tiny = fi.tiny
289+
ft_max = fi.max
290+
ft_eps = fi.eps
291+
underflow = 'underflow'
292+
divbyzero = 'divide by zero'
293+
else:
294+
# 'c', complex, corresponding real dtype
295+
rtype = type(ftype(0).real)
296+
fi = np.finfo(rtype)
297+
ft_tiny = ftype(fi.tiny)
298+
ft_max = ftype(fi.max)
299+
ft_eps = ftype(fi.eps)
300+
# The complex types raise different exceptions
301+
underflow = ''
302+
divbyzero = ''
303+
overflow = 'overflow'
304+
invalid = 'invalid'
305+
306+
self.assert_raises_fpe(underflow,
307+
lambda a,b:a/b, ft_tiny, ft_max)
308+
self.assert_raises_fpe(underflow,
309+
lambda a,b:a*b, ft_tiny, ft_tiny)
310+
self.assert_raises_fpe(overflow,
311+
lambda a,b:a*b, ft_max, ftype(2))
312+
self.assert_raises_fpe(overflow,
313+
lambda a,b:a/b, ft_max, ftype(0.5))
314+
self.assert_raises_fpe(overflow,
315+
lambda a,b:a+b, ft_max, ft_max*ft_eps)
316+
self.assert_raises_fpe(overflow,
317+
lambda a,b:a-b, -ft_max, ft_max*ft_eps)
318+
self.assert_raises_fpe(divbyzero,
319+
lambda a,b:a/b, ftype(1), ftype(0))
320+
self.assert_raises_fpe(invalid,
321+
lambda a,b:a/b, ftype(0), ftype(0))
322+
self.assert_raises_fpe(invalid,
323+
lambda a,b:a-b, ftype(np.inf), ftype(np.inf))
324+
self.assert_raises_fpe(invalid,
325+
lambda a,b:a+b, ftype(np.inf), ftype(-np.inf))
326+
self.assert_raises_fpe(invalid,
327+
lambda a,b:a*b, ftype(0), ftype(np.inf))
328+
self.assert_raises_fpe(overflow,
329+
np.power, ftype(2), ftype(2**fi.nexp))
330+
finally:
331+
np.seterr(**oldsettings)
332+
333+
254334
class TestFromiter(TestCase):
255335
def makegen(self):
256336
for x in xrange(24):

numpy/lib/_iotools.py

+7-4
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ def _delimited_splitter(self, line):
209209
return line.split(self.delimiter)
210210
#
211211
def _fixedwidth_splitter(self, line):
212-
line = line.split(self.comments)[0]
212+
line = line.split(self.comments)[0].strip(asbytes("\r\n"))
213213
if not line:
214214
return []
215215
fixed = self.delimiter
@@ -707,8 +707,8 @@ def iterupgrade(self, value):
707707
self._status = _status
708708
self.iterupgrade(value)
709709

710-
def update(self, func, default=None, missing_values=asbytes(''),
711-
locked=False):
710+
def update(self, func, default=None, testing_value=None,
711+
missing_values=asbytes(''), locked=False):
712712
"""
713713
Set StringConverter attributes directly.
714714
@@ -720,6 +720,9 @@ def update(self, func, default=None, missing_values=asbytes(''),
720720
Value to return by default, that is, when the string to be converted
721721
is flagged as missing. If not given, `StringConverter` tries to supply
722722
a reasonable default value.
723+
testing_value : str, optional
724+
A string representing a standard input value of the converter.
725+
This string is used to help defining a reasonable default value.
723726
missing_values : sequence of str, optional
724727
Sequence of strings indicating a missing value.
725728
locked : bool, optional
@@ -741,7 +744,7 @@ def update(self, func, default=None, missing_values=asbytes(''),
741744
self.type = self._getsubdtype(default)
742745
else:
743746
try:
744-
tester = func(asbytes('1'))
747+
tester = func(testing_value or asbytes('1'))
745748
except (TypeError, ValueError):
746749
tester = None
747750
self.type = self._getsubdtype(tester)

numpy/lib/npyio.py

+34-27
Original file line numberDiff line numberDiff line change
@@ -42,36 +42,37 @@ def seek_gzip_factory(f):
4242
"""
4343
import gzip
4444

45-
def seek(self, offset, whence=0):
46-
# figure out new position (we can only seek forwards)
47-
if whence == 1:
48-
offset = self.offset + offset
45+
class GzipFile(gzip.GzipFile):
4946

50-
if whence not in [0, 1]:
51-
raise IOError, "Illegal argument"
47+
def seek(self, offset, whence=0):
48+
# figure out new position (we can only seek forwards)
49+
if whence == 1:
50+
offset = self.offset + offset
5251

53-
if offset < self.offset:
54-
# for negative seek, rewind and do positive seek
55-
self.rewind()
56-
count = offset - self.offset
57-
for i in range(count // 1024):
58-
self.read(1024)
59-
self.read(count % 1024)
52+
if whence not in [0, 1]:
53+
raise IOError, "Illegal argument"
54+
55+
if offset < self.offset:
56+
# for negative seek, rewind and do positive seek
57+
self.rewind()
58+
count = offset - self.offset
59+
for i in range(count // 1024):
60+
self.read(1024)
61+
self.read(count % 1024)
62+
63+
def tell(self):
64+
return self.offset
6065

61-
def tell(self):
62-
return self.offset
6366

6467
if isinstance(f, str):
65-
f = gzip.GzipFile(f)
68+
f = GzipFile(f)
69+
elif isinstance(f, gzip.GzipFile):
70+
# cast to our GzipFile if its already a gzip.GzipFile
71+
g = GzipFile(fileobj=f.fileobj)
72+
g.name = f.name
73+
g.mode = f.mode
6674

67-
if sys.version_info[0] >= 3:
68-
import types
69-
f.seek = types.MethodType(seek, f)
70-
f.tell = types.MethodType(tell, f)
71-
else:
72-
import new
73-
f.seek = new.instancemethod(seek, f)
74-
f.tell = new.instancemethod(tell, f)
75+
f = g
7576

7677
return f
7778

@@ -670,7 +671,6 @@ def loadtxt(fname, dtype=float, comments='#', delimiter=None,
670671
if _is_string_like(fname):
671672
own_fh = True
672673
if fname.endswith('.gz'):
673-
import gzip
674674
fh = seek_gzip_factory(fname)
675675
elif fname.endswith('.bz2'):
676676
import bz2
@@ -1226,7 +1226,7 @@ def genfromtxt(fname, dtype=float, comments='#', delimiter=None,
12261226
if fval in comments:
12271227
del first_values[0]
12281228

1229-
# Check the columns to use
1229+
# Check the columns to use: make sure `usecols` is a list
12301230
if usecols is not None:
12311231
try:
12321232
usecols = [_.strip() for _ in usecols.split(",")]
@@ -1249,7 +1249,6 @@ def genfromtxt(fname, dtype=float, comments='#', delimiter=None,
12491249
# Get the dtype
12501250
if dtype is not None:
12511251
dtype = easy_dtype(dtype, defaultfmt=defaultfmt, names=names)
1252-
names = dtype.names
12531252
# Make sure the names is a list (for 2.5)
12541253
if names is not None:
12551254
names = list(names)
@@ -1270,6 +1269,8 @@ def genfromtxt(fname, dtype=float, comments='#', delimiter=None,
12701269
# If `names` is not None, update the names
12711270
elif (names is not None) and (len(names) > nbcols):
12721271
names = [names[_] for _ in usecols]
1272+
elif (names is not None) and (dtype is not None):
1273+
names = dtype.names
12731274

12741275

12751276
# Process the missing values ...............................
@@ -1404,7 +1405,13 @@ def genfromtxt(fname, dtype=float, comments='#', delimiter=None,
14041405
except ValueError:
14051406
# Unused converter specified
14061407
continue
1408+
# Find the value to test:
1409+
if len(first_line):
1410+
testing_value = first_values[i]
1411+
else:
1412+
testing_value = None
14071413
converters[i].update(conv, locked=True,
1414+
testing_value=testing_value,
14081415
default=filling_values[i],
14091416
missing_values=missing_values[i],)
14101417
uc_update.append((i, conv))

numpy/lib/tests/test_io.py

+37
Original file line numberDiff line numberDiff line change
@@ -714,6 +714,15 @@ def test_invalid_converter(self):
714714
dtype=None)
715715
assert_raises(ConverterError, np.genfromtxt, s, **kwargs)
716716

717+
def test_tricky_converter_bug1666(self):
718+
"Test some corner case"
719+
s = StringIO('q1,2\nq3,4')
720+
cnv = lambda s:float(s[1:])
721+
test = np.genfromtxt(s, delimiter=',', converters={0:cnv})
722+
control = np.array([[1., 2.], [3., 4.]])
723+
assert_equal(test, control)
724+
725+
717726

718727
def test_dtype_with_converters(self):
719728
dstr = "2009; 23; 46"
@@ -774,6 +783,13 @@ def test_spacedelimiter(self):
774783
[ 6., 7., 8., 9., 10.]])
775784
assert_equal(test, control)
776785

786+
def test_integer_delimiter(self):
787+
"Test using an integer for delimiter"
788+
data = " 1 2 3\n 4 5 67\n890123 4"
789+
test = np.genfromtxt(StringIO(data), delimiter=3)
790+
control = np.array([[1, 2, 3], [4, 5, 67], [890, 123, 4]])
791+
assert_equal(test, control)
792+
777793

778794
def test_missing(self):
779795
data = StringIO('1,2,3,,5\n')
@@ -1138,6 +1154,27 @@ def test_names_auto_completion(self):
11381154
dtype=[('a', int), ('f0', float), ('f1', int)])
11391155
assert_equal(test, ctrl)
11401156

1157+
def test_names_with_usecols_bug1636(self):
1158+
"Make sure we pick up the right names w/ usecols"
1159+
data = "A,B,C,D,E\n0,1,2,3,4\n0,1,2,3,4\n0,1,2,3,4"
1160+
ctrl_names = ("A", "C", "E")
1161+
test = np.genfromtxt(StringIO(data),
1162+
dtype=(int, int, int), delimiter=",",
1163+
usecols=(0, 2, 4), names=True)
1164+
assert_equal(test.dtype.names, ctrl_names)
1165+
#
1166+
test = np.genfromtxt(StringIO(data),
1167+
dtype=(int, int, int), delimiter=",",
1168+
usecols=("A", "C", "E"), names=True)
1169+
assert_equal(test.dtype.names, ctrl_names)
1170+
#
1171+
test = np.genfromtxt(StringIO(data),
1172+
dtype=int, delimiter=",",
1173+
usecols=("A", "C", "E"), names=True)
1174+
assert_equal(test.dtype.names, ctrl_names)
1175+
1176+
1177+
11411178
def test_fixed_width_names(self):
11421179
"Test fix-width w/ names"
11431180
data = " A B C\n 0 1 2.3\n 45 67 9."

setupscons.py

-1
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,6 @@
7373
sys.path.insert(0, os.path.dirname(__file__))
7474
try:
7575
setup_py = __import__("setup")
76-
FULLVERSION = setup_py.FULLVERSION
7776
write_version_py = setup_py.write_version_py
7877
finally:
7978
sys.path.pop(0)

0 commit comments

Comments
 (0)