Skip to content

Commit 443ec37

Browse files
committed
RF: Remove old as_int() hack
1 parent dabfc46 commit 443ec37

File tree

6 files changed

+30
-106
lines changed

6 files changed

+30
-106
lines changed

nibabel/arraywriters.py

Lines changed: 10 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,7 @@ def __init__(self, array, out_dtype=None)
3030
"""
3131
import numpy as np
3232

33-
from .casting import (
34-
as_int,
35-
best_float,
36-
floor_exact,
37-
int_abs,
38-
int_to_float,
39-
shared_range,
40-
type_info,
41-
)
33+
from .casting import best_float, floor_exact, int_abs, int_to_float, shared_range, type_info
4234
from .volumeutils import array_to_file, finite_range
4335

4436

@@ -152,9 +144,8 @@ def scaling_needed(self):
152144
# No scaling needed if data already fits in output type
153145
# But note - we need to convert to ints, to avoid conversion to float
154146
# during comparisons, and therefore int -> float conversions which are
155-
# not exact. Only a problem for uint64 though. We need as_int here to
156-
# work around a numpy 1.4.1 bug in uint conversion
157-
if as_int(mn) >= as_int(info.min) and as_int(mx) <= as_int(info.max):
147+
# not exact. Only a problem for uint64 though.
148+
if int(mn) >= int(info.min) and int(mx) <= int(info.max):
158149
return False
159150
return True
160151

@@ -392,7 +383,7 @@ def _do_scaling(self):
392383
out_max, out_min = info.max, info.min
393384
# If left as int64, uint64, comparisons will default to floats, and
394385
# these are inexact for > 2**53 - so convert to int
395-
if as_int(mx) <= as_int(out_max) and as_int(mn) >= as_int(out_min):
386+
if int(mx) <= int(out_max) and int(mn) >= int(out_min):
396387
# already in range
397388
return
398389
# (u)int to (u)int scaling
@@ -410,7 +401,7 @@ def _iu2iu(self):
410401
# that deals with max neg ints. abs problem only arises when all
411402
# the data is set to max neg integer value
412403
o_min, o_max = shared_range(self.scaler_dtype, out_dt)
413-
if mx <= 0 and int_abs(mn) <= as_int(o_max): # sign flip enough?
404+
if mx <= 0 and int_abs(mn) <= int(o_max): # sign flip enough?
414405
# -1.0 * arr will be in scaler_dtype precision
415406
self.slope = -1.0
416407
return
@@ -546,14 +537,13 @@ def to_fileobj(self, fileobj, order='F'):
546537

547538
def _iu2iu(self):
548539
# (u)int to (u)int
549-
mn, mx = (as_int(v) for v in self.finite_range())
540+
mn, mx = (int(v) for v in self.finite_range())
550541
# range may be greater than the largest integer for this type.
551-
# as_int needed to work round numpy 1.4.1 int casting bug
552542
out_dtype = self._out_dtype
553543
# Options in this method are scaling using intercept only. These will
554544
# have to pass through ``self.scaler_dtype`` (because the intercept is
555545
# in this type).
556-
o_min, o_max = (as_int(v) for v in shared_range(self.scaler_dtype, out_dtype))
546+
o_min, o_max = (int(v) for v in shared_range(self.scaler_dtype, out_dtype))
557547
type_range = o_max - o_min
558548
mn2mx = mx - mn
559549
if mn2mx <= type_range: # might offset be enough?
@@ -565,12 +555,12 @@ def _iu2iu(self):
565555
else: # int output - take midpoint to 0
566556
# ceil below increases inter, pushing scale up to 0.5 towards
567557
# -inf, because ints have abs min == abs max + 1
568-
midpoint = mn + as_int(np.ceil(mn2mx / 2.0))
558+
midpoint = mn + int(np.ceil(mn2mx / 2.0))
569559
# Floor exact decreases inter, so pulling scaled values more
570560
# positive. This may make mx - inter > t_max
571561
inter = floor_exact(midpoint, self.scaler_dtype)
572562
# Need to check still in range after floor_exact-ing
573-
int_inter = as_int(inter)
563+
int_inter = int(inter)
574564
assert mn - int_inter >= o_min
575565
if mx - int_inter <= o_max:
576566
self.inter = inter
@@ -598,7 +588,7 @@ def _range_scale(self, in_min, in_max):
598588
# same as double so in_range will be 2**64 - thus overestimating
599589
# slope slightly. Casting to int needed to allow in_max-in_min to
600590
# be larger than the largest (u)int value
601-
in_min, in_max = as_int(in_min), as_int(in_max)
591+
in_min, in_max = int(in_min), int(in_max)
602592
in_range = int_to_float(in_max - in_min, big_float)
603593
# Cast to float for later processing.
604594
in_min, in_max = (int_to_float(v, big_float) for v in (in_min, in_max))

nibabel/casting.py

Lines changed: 6 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010

1111
import numpy as np
1212

13+
from .deprecated import deprecate_with_version
14+
1315

1416
class CastingError(Exception):
1517
pass
@@ -402,6 +404,7 @@ def _check_maxexp(np_type, maxexp):
402404
return np.isfinite(two ** (maxexp - 1)) and not np.isfinite(two**maxexp)
403405

404406

407+
@deprecate_with_version('as_int() is deprecated. Use int() instead.', '5.2.0', '7.0.0')
405408
def as_int(x, check=True):
406409
"""Return python integer representation of number
407410
@@ -411,9 +414,6 @@ def as_int(x, check=True):
411414
It is also useful to work around a numpy 1.4.1 bug in conversion of uints
412415
to python ints.
413416
414-
This routine will still raise an OverflowError for values that are outside
415-
the range of float64.
416-
417417
Parameters
418418
----------
419419
x : object
@@ -439,28 +439,10 @@ def as_int(x, check=True):
439439
>>> as_int(2.1, check=False)
440440
2
441441
"""
442-
x = np.array(x)
443-
if x.dtype.kind in 'iu':
444-
# This works around a nasty numpy 1.4.1 bug such that:
445-
# >>> int(np.uint32(2**32-1)
446-
# -1
447-
return int(str(x))
448442
ix = int(x)
449-
if ix == x:
450-
return ix
451-
fx = np.floor(x)
452-
if check and fx != x:
443+
if check and ix != x:
453444
raise FloatingError(f'Not an integer: {x}')
454-
if not fx.dtype.type == np.longdouble:
455-
return int(x)
456-
# Subtract float64 chunks until we have all of the number. If the int is
457-
# too large, it will overflow
458-
ret = 0
459-
while fx != 0:
460-
f64 = np.float64(fx)
461-
fx -= f64
462-
ret += int(f64)
463-
return ret
445+
return ix
464446

465447

466448
def int_to_float(val, flt_type):
@@ -549,7 +531,7 @@ def floor_exact(val, flt_type):
549531
if not np.isfinite(fval):
550532
return fval
551533
info = type_info(flt_type)
552-
diff = val - as_int(fval)
534+
diff = val - int(fval)
553535
if diff >= 0: # floating point value <= val
554536
return fval
555537
# Float casting made the value go up

nibabel/tests/test_analyze.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
from .. import imageglobals
2727
from ..analyze import AnalyzeHeader, AnalyzeImage
2828
from ..arraywriters import WriterError
29-
from ..casting import as_int, sctypes_aliases
29+
from ..casting import sctypes_aliases
3030
from ..nifti1 import Nifti1Header
3131
from ..optpkg import optional_package
3232
from ..spatialimages import HeaderDataError, HeaderTypeError, supported_np_types
@@ -308,8 +308,7 @@ def test_shapes(self):
308308
assert hdr.get_data_shape() == shape
309309
# Check max works, but max+1 raises error
310310
dim_dtype = hdr.structarr['dim'].dtype
311-
# as_int for safety to deal with numpy 1.4.1 int conversion errors
312-
mx = as_int(np.iinfo(dim_dtype).max)
311+
mx = int(np.iinfo(dim_dtype).max)
313312
shape = (mx,)
314313
hdr.set_data_shape(shape)
315314
assert hdr.get_data_shape() == shape

nibabel/tests/test_casting.py

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
from ..casting import (
1111
CastingError,
1212
able_int_type,
13-
as_int,
1413
best_float,
1514
float_to_int,
1615
floor_log2,
@@ -101,11 +100,6 @@ def test_casting():
101100
mn, mx = shared_range(ft, it)
102101
with np.errstate(invalid='ignore'):
103102
iarr = float_to_int(farr, it)
104-
# Dammit - for long doubles we need to jump through some hoops not
105-
# to round to numbers outside the range
106-
if ft is np.longdouble:
107-
mn = as_int(mn)
108-
mx = as_int(mx)
109103
exp_arr = np.array([mn, mx, mn, mx, 0, 0, 11], dtype=it)
110104
assert_array_equal(iarr, exp_arr)
111105
# Now test infmax version
@@ -149,7 +143,7 @@ def test_int_abs():
149143
assert udtype.kind == 'u'
150144
assert idtype.itemsize == udtype.itemsize
151145
mn, mx = in_arr
152-
e_mn = as_int(mx) + 1 # as_int needed for numpy 1.4.1 casting
146+
e_mn = int(mx) + 1
153147
assert int_abs(mx) == mx
154148
assert int_abs(mn) == e_mn
155149
assert_array_equal(int_abs(in_arr), [e_mn, mx])

nibabel/tests/test_floating.py

Lines changed: 10 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
FloatingError,
1212
_check_maxexp,
1313
_check_nmant,
14-
as_int,
1514
ceil_exact,
1615
floor_exact,
1716
floor_log2,
@@ -128,48 +127,6 @@ def test_check_nmant_nexp():
128127
assert _check_maxexp(t, ti['maxexp'])
129128

130129

131-
def test_as_int():
132-
# Integer representation of number
133-
assert as_int(2.0) == 2
134-
assert as_int(-2.0) == -2
135-
with pytest.raises(FloatingError):
136-
as_int(2.1)
137-
with pytest.raises(FloatingError):
138-
as_int(-2.1)
139-
assert as_int(2.1, False) == 2
140-
assert as_int(-2.1, False) == -2
141-
v = np.longdouble(2**64)
142-
assert as_int(v) == 2**64
143-
# Have all long doubles got 63+1 binary bits of precision? Windows 32-bit
144-
# longdouble appears to have 52 bit precision, but we avoid that by checking
145-
# for known precisions that are less than that required
146-
try:
147-
nmant = type_info(np.longdouble)['nmant']
148-
except FloatingError:
149-
nmant = 63 # Unknown precision, let's hope it's at least 63
150-
v = np.longdouble(2) ** (nmant + 1) - 1
151-
assert as_int(v) == 2 ** (nmant + 1) - 1
152-
# Check for predictable overflow
153-
nexp64 = floor_log2(type_info(np.float64)['max'])
154-
with np.errstate(over='ignore'):
155-
val = np.longdouble(2**nexp64) * 2 # outside float64 range
156-
assert val > np.finfo('float64').max
157-
# TODO: Should this actually still overflow? Does it matter?
158-
if FP_OVERFLOW_WARN:
159-
ctx = pytest.raises(OverflowError)
160-
else:
161-
ctx = nullcontext()
162-
out_val = None
163-
with ctx:
164-
out_val = as_int(val)
165-
if out_val is not None:
166-
assert out_val == val
167-
with ctx:
168-
out_val = as_int(-val)
169-
if out_val is not None:
170-
assert out_val == -val
171-
172-
173130
def test_int_to_float():
174131
# Convert python integer to floating point
175132
# Standard float types just return cast value
@@ -215,23 +172,24 @@ def test_int_to_float():
215172
return
216173
# test we recover precision just above nmant
217174
i = 2 ** (nmant + 1) - 1
218-
assert as_int(int_to_float(i, LD)) == i
219-
assert as_int(int_to_float(-i, LD)) == -i
175+
assert int(int_to_float(i, LD)) == i
176+
assert int(int_to_float(-i, LD)) == -i
220177
# If longdouble can cope with 2**64, test
221178
if nmant >= 63:
222179
# Check conversion to int; the line below causes an error subtracting
223180
# ints / uint64 values, at least for Python 3.3 and numpy dev 1.8
224181
big_int = np.uint64(2**64 - 1)
225-
assert as_int(int_to_float(big_int, LD)) == big_int
182+
assert int(int_to_float(big_int, LD)) == big_int
226183

227184

228-
def test_as_int_np_fix():
229-
# Test as_int works for integers. We need as_int for integers because of a
185+
def test_int_np_regression():
186+
# Test int works as expected for integers.
187+
# We previously used a custom as_int() for integers because of a
230188
# numpy 1.4.1 bug such that int(np.uint32(2**32-1) == -1
231189
for t in sctypes['int'] + sctypes['uint']:
232190
info = np.iinfo(t)
233191
mn, mx = np.array([info.min, info.max], dtype=t)
234-
assert (mn, mx) == (as_int(mn), as_int(mx))
192+
assert (mn, mx) == (int(mn), int(mx))
235193

236194

237195
def test_floor_exact_16():
@@ -264,8 +222,8 @@ def test_floor_exact():
264222
to_test.append(np.longdouble)
265223
# When numbers go above int64 - I believe, numpy comparisons break down,
266224
# so we have to cast to int before comparison
267-
int_flex = lambda x, t: as_int(floor_exact(x, t))
268-
int_ceex = lambda x, t: as_int(ceil_exact(x, t))
225+
int_flex = lambda x, t: int(floor_exact(x, t))
226+
int_ceex = lambda x, t: int(ceil_exact(x, t))
269227
for t in to_test:
270228
# A number bigger than the range returns the max
271229
info = type_info(t)
@@ -302,7 +260,7 @@ def test_floor_exact():
302260
for i in range(5):
303261
iv = 2 ** (nmant + 1 + i)
304262
gap = 2 ** (i + 1)
305-
assert as_int(t(iv) + t(gap)) == iv + gap
263+
assert int(t(iv) + t(gap)) == iv + gap
306264
for j in range(1, gap):
307265
assert int_flex(iv + j, t) == iv
308266
assert int_flex(iv + gap + j, t) == iv + gap

nibabel/tests/test_removalschedule.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
(
1818
'8.0.0',
1919
[
20+
('nibabel.casting', 'as_int'),
2021
('nibabel.tmpdirs', 'TemporaryDirectory'),
2122
],
2223
),

0 commit comments

Comments
 (0)