test_deprecations.py 14.3 KB
Newer Older
dugupeiwen's avatar
dugupeiwen committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
import warnings
import unittest
from contextlib import contextmanager

from numba import jit, generated_jit, vectorize, guvectorize
from numba.core.errors import (NumbaDeprecationWarning,
                               NumbaPendingDeprecationWarning, NumbaWarning)
from numba.tests.support import TestCase, needs_setuptools


@contextmanager
def _catch_numba_deprecation_warnings():
    with warnings.catch_warnings(record=True) as w:
        warnings.simplefilter("ignore", category=NumbaWarning)
        warnings.simplefilter("always", category=NumbaDeprecationWarning)
        yield w


class TestDeprecation(TestCase):

    def check_warning(self, warnings, expected_str, category):
        self.assertEqual(len(warnings), 1)
        self.assertEqual(warnings[0].category, category)
        self.assertIn(expected_str, str(warnings[0].message))
        self.assertIn("https://numba.readthedocs.io", str(warnings[0].message))

    @TestCase.run_test_in_subprocess
    def test_jitfallback(self):
        # tests that @jit falling back to object mode raises a
        # NumbaDeprecationWarning
        with _catch_numba_deprecation_warnings() as w:
            # ignore the warning about the nopython kwarg not being supplied
            warnings.filterwarnings("ignore",
                                    message=(r".*The 'nopython' keyword "
                                             r"argument was not supplied.*"),
                                    category=NumbaDeprecationWarning,)

            def foo():
                return []  # empty list cannot be typed
            jit(foo)()

            msg = ("Fall-back from the nopython compilation path to the object "
                   "mode compilation path")

            self.check_warning(w, msg, NumbaDeprecationWarning)

    @TestCase.run_test_in_subprocess
    def test_default_missing_nopython_kwarg(self):
        # test that not supplying `nopython` kwarg to @jit raises a warning
        # about the default changing.
        with _catch_numba_deprecation_warnings() as w:

            @jit
            def foo():
                pass

            foo()

            msg = "The 'nopython' keyword argument was not supplied"
            self.check_warning(w, msg, NumbaDeprecationWarning)

    @TestCase.run_test_in_subprocess
    def test_explicit_false_nopython_kwarg(self):
        # tests that explicitly setting `nopython=False` in @jit raises a
        # warning about the default changing and it being an error in the
        # future.
        with _catch_numba_deprecation_warnings() as w:

            @jit(nopython=False)
            def foo():
                pass

            foo()

            msg = "The keyword argument 'nopython=False' was supplied"
            self.check_warning(w, msg, NumbaDeprecationWarning)

    @TestCase.run_test_in_subprocess
    def test_default_missing_nopython_kwarg_silent_if_forceobj(self):
        # Checks that if forceobj is set and the nopython kwarg is also not
        # present then no warning is raised. The user intentially wants objmode.

        with _catch_numba_deprecation_warnings() as w:

            @jit(forceobj=True)
            def foo():
                object()

            foo()

        # no warnings should be raised.
        self.assertFalse(w)

    @TestCase.run_test_in_subprocess
    def test_vectorize_missing_nopython_kwarg_not_reported(self):
        # Checks that use of @vectorize without a nopython kwarg doesn't raise
        # a warning about lack of said kwarg.

        with _catch_numba_deprecation_warnings() as w:
            # This compiles via nopython mode directly
            @vectorize('float64(float64)')
            def foo(a):
                return a + 1

        self.assertFalse(w)

    @TestCase.run_test_in_subprocess
    def test_vectorize_nopython_false_is_reported(self):
        # Checks that use of @vectorize with nopython=False raises a warning
        # about supplying it.

        with _catch_numba_deprecation_warnings() as w:
            # This compiles via nopython mode directly
            @vectorize('float64(float64)', nopython=False)
            def foo(a):
                return a + 1

        msg = "The keyword argument 'nopython=False' was supplied"
        self.check_warning(w, msg, NumbaDeprecationWarning)

    @TestCase.run_test_in_subprocess
    def test_vectorize_objmode_missing_nopython_kwarg_not_reported(self):
        # Checks that use of @vectorize without a nopython kwarg doesn't raise
        # a warning about lack of the nopython kwarg, but does raise a warning
        # about falling back to obj mode to compile.

        with _catch_numba_deprecation_warnings() as w:
            # This compiles via objmode fallback
            @vectorize('float64(float64)')
            def foo(a):
                object()
                return a + 1

        msg = ("Fall-back from the nopython compilation path to the object "
               "mode compilation path")
        self.check_warning(w, msg, NumbaDeprecationWarning)

    @TestCase.run_test_in_subprocess
    def test_vectorize_objmode_nopython_false_is_reported(self):
        # Checks that use of @vectorize with a nopython kwarg set to False
        # doesn't raise a warning about lack of the nopython kwarg, but does
        # raise a warning about it being False and then a warning about falling
        # back to obj mode to compile.

        with _catch_numba_deprecation_warnings() as w:
            # This compiles via objmode fallback with a warning about
            # nopython=False supplied.
            @vectorize('float64(float64)', nopython=False)
            def foo(a):
                object()
                return a + 1

        # 2 warnings: 1. use of nopython=False, then, 2. objmode fallback
        self.assertEqual(len(w), 2)

        msg = "The keyword argument 'nopython=False' was supplied"
        self.check_warning([w[0]], msg, NumbaDeprecationWarning)

        msg = ("Fall-back from the nopython compilation path to the object "
               "mode compilation path")
        self.check_warning([w[1]], msg, NumbaDeprecationWarning)

    @TestCase.run_test_in_subprocess
    def test_vectorize_objmode_direct_compilation_no_warnings(self):
        # Checks that use of @vectorize with forceobj=True raises no warnings.

        with _catch_numba_deprecation_warnings() as w:
            # Compiles via objmode directly with no warnings raised
            @vectorize('float64(float64)', forceobj=True)
            def foo(a):
                object()
                return a + 1

        self.assertFalse(w)

    @TestCase.run_test_in_subprocess
    def test_vectorize_objmode_compilation_nopython_false_no_warnings(self):
        # Checks that use of @vectorize with forceobj set and nopython set as
        # False raises no warnings.

        with _catch_numba_deprecation_warnings() as w:
            # Compiles via objmode directly with no warnings raised
            @vectorize('float64(float64)', forceobj=True, nopython=False)
            def foo(a):
                object()
                return a + 1

        self.assertFalse(w)

    @TestCase.run_test_in_subprocess
    def test_vectorize_parallel_true_no_warnings(self):
        # Checks that use of @vectorize with the parallel target doesn't
        # raise warnings about nopython kwarg, the parallel target doesn't
        # support objmode so nopython=True is implicit.
        with _catch_numba_deprecation_warnings() as w:
            @vectorize('float64(float64)', target='parallel')
            def foo(x):
                return x + 1

        self.assertFalse(w)

    @TestCase.run_test_in_subprocess
    def test_vectorize_parallel_true_nopython_true_no_warnings(self):
        # Checks that use of @vectorize with the parallel target and
        # nopython=True doesn't raise warnings about nopython kwarg.
        with _catch_numba_deprecation_warnings() as w:
            @vectorize('float64(float64)', target='parallel', nopython=True)
            def foo(x):
                return x + 1

        self.assertFalse(w)

    @TestCase.run_test_in_subprocess
    def test_vectorize_parallel_true_nopython_false_warns(self):
        # Checks that use of @vectorize with the parallel target and
        # nopython=False raises a warning about the nopython kwarg being False.
        with _catch_numba_deprecation_warnings() as w:
            @vectorize('float64(float64)', target='parallel', nopython=False)
            def foo(x):
                return x + 1

        msg = "The keyword argument 'nopython=False' was supplied"
        self.check_warning(w, msg, NumbaDeprecationWarning)

    @TestCase.run_test_in_subprocess
    def test_vectorize_calling_jit_with_nopython_false_warns_from_jit(self):
        # Checks the scope of the suppression of deprecation warnings that are
        # present in e.g. vectorize. The function `bar` should raise a
        # deprecation warning, the `@vectorize`d `foo` function should not,
        # even though both don't have a nopython kwarg.

        # First check that the @vectorize call doesn't raise anything
        with _catch_numba_deprecation_warnings() as w:
            @vectorize('float64(float64)', forceobj=True)
            def foo(x):
                return bar(x + 1)

            def bar(*args):
                pass

        self.assertFalse(w)

        # Now check the same compilation but this time compiling through to a
        # @jit call.
        with _catch_numba_deprecation_warnings() as w:
            @vectorize('float64(float64)', forceobj=True)
            def foo(x): # noqa : F811
                return bar(x + 1)

            @jit
            def bar(x): # noqa : F811
                return x

        msg = "The 'nopython' keyword argument was not supplied"
        self.check_warning(w, msg, NumbaDeprecationWarning)

    @TestCase.run_test_in_subprocess
    def test_guvectorize_implicit_nopython_no_warnings(self):
        # Checks that use of @guvectorize with implicit nopython compilation
        # does not warn on compilation.
        with _catch_numba_deprecation_warnings() as w:

            @guvectorize('void(float64[::1], float64[::1])', '(n)->(n)')
            def bar(a, b):
                a += 1

        self.assertFalse(w)

    @TestCase.run_test_in_subprocess
    def test_guvectorize_forceobj_no_warnings(self):
        # Checks that use of @guvectorize with direct objmode compilation does
        # not warn.
        with _catch_numba_deprecation_warnings() as w:

            @guvectorize('void(float64[::1], float64[::1])', '(n)->(n)',
                         forceobj=True)
            def bar(a, b):
                object()
                a += 1

        self.assertFalse(w)

    @TestCase.run_test_in_subprocess
    def test_guvectorize_parallel_implicit_nopython_no_warnings(self):
        # Checks that use of @guvectorize with parallel target and implicit
        # nopython mode compilation does not warn.
        with _catch_numba_deprecation_warnings() as w:

            @guvectorize('void(float64[::1], float64[::1])', '(n)->(n)',
                         target='parallel')
            def bar(a, b):
                a += 1

        self.assertFalse(w)

    @TestCase.run_test_in_subprocess
    def test_guvectorize_parallel_forceobj_no_warnings(self):
        # Checks that use of @guvectorize with parallel target and direct
        # objmode compilation does not warn.
        with _catch_numba_deprecation_warnings() as w:

            # This compiles somewhat surprisingly for the parallel target using
            # object mode?!
            @guvectorize('void(float64[::1], float64[::1])', '(n)->(n)',
                         target='parallel', forceobj=True)
            def bar(a, b):
                object()
                a += 1

        self.assertFalse(w)

    @TestCase.run_test_in_subprocess
    def test_reflection_of_mutable_container(self):
        # tests that reflection in list/set warns
        def foo_list(a):
            return a.append(1)

        def foo_set(a):
            return a.add(1)

        for f in [foo_list, foo_set]:
            container = f.__name__.strip('foo_')
            inp = eval(container)([10, ])
            with warnings.catch_warnings(record=True) as w:
                warnings.simplefilter("ignore", category=NumbaWarning)
                warnings.simplefilter("always",
                                      category=NumbaPendingDeprecationWarning)
                jit(nopython=True)(f)(inp)
                self.assertEqual(len(w), 1)
                self.assertEqual(w[0].category, NumbaPendingDeprecationWarning)
                warn_msg = str(w[0].message)
                msg = ("Encountered the use of a type that is scheduled for "
                       "deprecation")
                self.assertIn(msg, warn_msg)
                msg = ("\'reflected %s\' found for argument" % container)
                self.assertIn(msg, warn_msg)
                self.assertIn("https://numba.readthedocs.io", warn_msg)

    @TestCase.run_test_in_subprocess
    def test_generated_jit(self):

        with _catch_numba_deprecation_warnings() as w:

            @generated_jit
            def bar():
                return lambda : None

            @jit(nopython=True)
            def foo():
                bar()

            foo()

            self.check_warning(w, "numba.generated_jit is deprecated",
                               NumbaDeprecationWarning)

    @needs_setuptools
    @TestCase.run_test_in_subprocess
    def test_pycc_module(self):
        # checks import of module warns

        with warnings.catch_warnings(record=True) as w:
            warnings.simplefilter("always",
                                  category=NumbaPendingDeprecationWarning)
            import numba.pycc # noqa: F401

            expected_str = ("The 'pycc' module is pending deprecation.")
            self.check_warning(w, expected_str, NumbaPendingDeprecationWarning)

    @needs_setuptools
    @TestCase.run_test_in_subprocess
    def test_pycc_CC(self):
        # check the most commonly used functionality (CC) warns

        with warnings.catch_warnings(record=True) as w:
            warnings.simplefilter("always",
                                  category=NumbaPendingDeprecationWarning)
            from numba.pycc import CC # noqa: F401

            expected_str = ("The 'pycc' module is pending deprecation.")
            self.check_warning(w, expected_str, NumbaPendingDeprecationWarning)


if __name__ == '__main__':
    unittest.main()