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
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.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.

numpy/core/src/scalarmathmodule.c.src

Lines changed: 9 additions & 3 deletions
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

Lines changed: 80 additions & 0 deletions
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

Lines changed: 7 additions & 4 deletions
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

Lines changed: 34 additions & 27 deletions
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

Lines changed: 37 additions & 0 deletions
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

Lines changed: 0 additions & 1 deletion
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)