1import atexit
2import builtins
3import functools
4import inspect
5import os
6import operator
7import threading
8import timeit
9import math
10import sys
11import traceback
12import weakref
13import warnings
14from types import ModuleType
15from importlib import import_module
16from collections.abc import Mapping, Sequence
17import numpy as np
18
19from inspect import signature as pysignature # noqa: F401
20from inspect import Signature as pySignature # noqa: F401
21from inspect import Parameter as pyParameter # noqa: F401
22
23from numba.core.config import (PYVERSION, MACHINE_BITS, # noqa: F401
24                               DEVELOPER_MODE) # noqa: F401
25from numba.core import types
26
27INT_TYPES = (int,)
28longint = int
29get_ident = threading.get_ident
30intern = sys.intern
31file_replace = os.replace
32asbyteint = int
33
34# ------------------------------------------------------------------------------
35# Start: Originally from `numba.six` under the following license
36
37"""Utilities for writing code that runs on Python 2 and 3"""
38
39# Copyright (c) 2010-2015 Benjamin Peterson
40#
41# Permission is hereby granted, free of charge, to any person obtaining a copy
42# of this software and associated documentation files (the "Software"), to deal
43# in the Software without restriction, including without limitation the rights
44# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
45# copies of the Software, and to permit persons to whom the Software is
46# furnished to do so, subject to the following conditions:
47#
48# The above copyright notice and this permission notice shall be included in all
49# copies or substantial portions of the Software.
50#
51# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
52# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
53# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
54# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
55# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
56# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
57# SOFTWARE.
58
59
60def add_metaclass(metaclass):
61    """Class decorator for creating a class with a metaclass."""
62    def wrapper(cls):
63        orig_vars = cls.__dict__.copy()
64        slots = orig_vars.get('__slots__')
65        if slots is not None:
66            if isinstance(slots, str):
67                slots = [slots]
68            for slots_var in slots:
69                orig_vars.pop(slots_var)
70        orig_vars.pop('__dict__', None)
71        orig_vars.pop('__weakref__', None)
72        return metaclass(cls.__name__, cls.__bases__, orig_vars)
73    return wrapper
74
75
76def reraise(tp, value, tb=None):
77    if value is None:
78        value = tp()
79    if value.__traceback__ is not tb:
80        raise value.with_traceback(tb)
81    raise value
82
83
84def iteritems(d, **kw):
85    return iter(d.items(**kw))
86
87
88def itervalues(d, **kw):
89    return iter(d.values(**kw))
90
91
92get_function_globals = operator.attrgetter("__globals__")
93
94# End: Originally from `numba.six` under the following license
95# ------------------------------------------------------------------------------
96
97
98def erase_traceback(exc_value):
99    """
100    Erase the traceback and hanging locals from the given exception instance.
101    """
102    if exc_value.__traceback__ is not None:
103        traceback.clear_frames(exc_value.__traceback__)
104    return exc_value.with_traceback(None)
105
106
107def safe_relpath(path, start=os.curdir):
108    """
109    Produces a "safe" relative path, on windows relpath doesn't work across
110    drives as technically they don't share the same root.
111    See: https://bugs.python.org/issue7195 for details.
112    """
113    # find the drive letters for path and start and if they are not the same
114    # then don't use relpath!
115    drive_letter = lambda x: os.path.splitdrive(os.path.abspath(x))[0]
116    drive_path = drive_letter(path)
117    drive_start = drive_letter(start)
118    if drive_path != drive_start:
119        return os.path.abspath(path)
120    else:
121        return os.path.relpath(path, start=start)
122
123
124# Mapping between operator module functions and the corresponding built-in
125# operators.
126
127BINOPS_TO_OPERATORS = {
128    '+': operator.add,
129    '-': operator.sub,
130    '*': operator.mul,
131    '//': operator.floordiv,
132    '/': operator.truediv,
133    '%': operator.mod,
134    '**': operator.pow,
135    '&': operator.and_,
136    '|': operator.or_,
137    '^': operator.xor,
138    '<<': operator.lshift,
139    '>>': operator.rshift,
140    '==': operator.eq,
141    '!=': operator.ne,
142    '<': operator.lt,
143    '<=': operator.le,
144    '>': operator.gt,
145    '>=': operator.ge,
146    'is': operator.is_,
147    'is not': operator.is_not,
148    # This one has its args reversed!
149    'in': operator.contains
150}
151
152INPLACE_BINOPS_TO_OPERATORS = {
153    '+=': operator.iadd,
154    '-=': operator.isub,
155    '*=': operator.imul,
156    '//=': operator.ifloordiv,
157    '/=': operator.itruediv,
158    '%=': operator.imod,
159    '**=': operator.ipow,
160    '&=': operator.iand,
161    '|=': operator.ior,
162    '^=': operator.ixor,
163    '<<=': operator.ilshift,
164    '>>=': operator.irshift,
165}
166
167UNARY_BUITINS_TO_OPERATORS = {
168    '+': operator.pos,
169    '-': operator.neg,
170    '~': operator.invert,
171    'not': operator.not_,
172    'is_true': operator.truth
173}
174
175OPERATORS_TO_BUILTINS = {
176    operator.add: '+',
177    operator.iadd: '+=',
178    operator.sub: '-',
179    operator.isub: '-=',
180    operator.mul: '*',
181    operator.imul: '*=',
182    operator.floordiv: '//',
183    operator.ifloordiv: '//=',
184    operator.truediv: '/',
185    operator.itruediv: '/=',
186    operator.mod: '%',
187    operator.imod: '%=',
188    operator.pow: '**',
189    operator.ipow: '**=',
190    operator.and_: '&',
191    operator.iand: '&=',
192    operator.or_: '|',
193    operator.ior: '|=',
194    operator.xor: '^',
195    operator.ixor: '^=',
196    operator.lshift: '<<',
197    operator.ilshift: '<<=',
198    operator.rshift: '>>',
199    operator.irshift: '>>=',
200    operator.eq: '==',
201    operator.ne: '!=',
202    operator.lt: '<',
203    operator.le: '<=',
204    operator.gt: '>',
205    operator.ge: '>=',
206    operator.is_: 'is',
207    operator.is_not: 'is not',
208    # This one has its args reversed!
209    operator.contains: 'in',
210    # Unary
211    operator.pos: '+',
212    operator.neg: '-',
213    operator.invert: '~',
214    operator.not_: 'not',
215    operator.truth: 'is_true',
216}
217
218BINOPS_TO_OPERATORS['@'] = operator.matmul
219INPLACE_BINOPS_TO_OPERATORS['@='] = operator.imatmul
220
221
222_shutting_down = False
223
224
225def _at_shutdown():
226    global _shutting_down
227    _shutting_down = True
228
229
230def shutting_down(globals=globals):
231    """
232    Whether the interpreter is currently shutting down.
233    For use in finalizers, __del__ methods, and similar; it is advised
234    to early bind this function rather than look it up when calling it,
235    since at shutdown module globals may be cleared.
236    """
237    # At shutdown, the attribute may have been cleared or set to None.
238    v = globals().get('_shutting_down')
239    return v is True or v is None
240
241
242# weakref.finalize registers an exit function that runs all finalizers for
243# which atexit is True. Some of these finalizers may call shutting_down() to
244# check whether the interpreter is shutting down. For this to behave correctly,
245# we need to make sure that _at_shutdown is called before the finalizer exit
246# function. Since atexit operates as a LIFO stack, we first contruct a dummy
247# finalizer then register atexit to ensure this ordering.
248weakref.finalize(lambda: None, lambda: None)
249atexit.register(_at_shutdown)
250
251
252class ConfigOptions(object):
253    OPTIONS = {}
254
255    def __init__(self):
256        self._values = self.OPTIONS.copy()
257
258    def set(self, name, value=True):
259        if name not in self.OPTIONS:
260            raise NameError("Invalid flag: %s" % name)
261        self._values[name] = value
262
263    def unset(self, name):
264        self.set(name, False)
265
266    def _check_attr(self, name):
267        if name not in self.OPTIONS:
268            raise AttributeError("Invalid flag: %s" % name)
269
270    def __getattr__(self, name):
271        self._check_attr(name)
272        return self._values[name]
273
274    def __setattr__(self, name, value):
275        if name.startswith('_'):
276            super(ConfigOptions, self).__setattr__(name, value)
277        else:
278            self._check_attr(name)
279            self._values[name] = value
280
281    def __repr__(self):
282        return "Flags(%s)" % ', '.join('%s=%s' % (k, v)
283                                       for k, v in self._values.items()
284                                       if v is not False)
285
286    def copy(self):
287        copy = type(self)()
288        copy._values = self._values.copy()
289        return copy
290
291    def __eq__(self, other):
292        return (isinstance(other, ConfigOptions) and
293                other._values == self._values)
294
295    def __ne__(self, other):
296        return not self == other
297
298    def __hash__(self):
299        return hash(tuple(sorted(self._values.items())))
300
301
302class SortedMap(Mapping):
303    """Immutable
304    """
305
306    def __init__(self, seq):
307        self._values = []
308        self._index = {}
309        for i, (k, v) in enumerate(sorted(seq)):
310            self._index[k] = i
311            self._values.append((k, v))
312
313    def __getitem__(self, k):
314        i = self._index[k]
315        return self._values[i][1]
316
317    def __len__(self):
318        return len(self._values)
319
320    def __iter__(self):
321        return iter(k for k, v in self._values)
322
323
324class UniqueDict(dict):
325    def __setitem__(self, key, value):
326        if key in self:
327            raise AssertionError("key already in dictionary: %r" % (key,))
328        super(UniqueDict, self).__setitem__(key, value)
329
330
331# Django's cached_property
332# see https://docs.djangoproject.com/en/dev/ref/utils/#django.utils.functional.cached_property    # noqa: E501
333
334class cached_property(object):
335    """
336    Decorator that converts a method with a single self argument into a
337    property cached on the instance.
338
339    Optional ``name`` argument allows you to make cached properties of other
340    methods. (e.g.  url = cached_property(get_absolute_url, name='url') )
341    """
342    def __init__(self, func, name=None):
343        self.func = func
344        self.name = name or func.__name__
345
346    def __get__(self, instance, type=None):
347        if instance is None:
348            return self
349        res = instance.__dict__[self.name] = self.func(instance)
350        return res
351
352
353def runonce(fn):
354    @functools.wraps(fn)
355    def inner():
356        if not inner._ran:
357            res = fn()
358            inner._result = res
359            inner._ran = True
360        return inner._result
361
362    inner._ran = False
363    return inner
364
365
366def bit_length(intval):
367    """
368    Return the number of bits necessary to represent integer `intval`.
369    """
370    assert isinstance(intval, INT_TYPES)
371    if intval >= 0:
372        return len(bin(intval)) - 2
373    else:
374        return len(bin(-intval - 1)) - 2
375
376
377def stream_list(lst):
378    """
379    Given a list, return an infinite iterator of iterators.
380    Each iterator iterates over the list from the last seen point up to
381    the current end-of-list.
382
383    In effect, each iterator will give the newly appended elements from the
384    previous iterator instantiation time.
385    """
386    def sublist_iterator(start, stop):
387        return iter(lst[start:stop])
388
389    start = 0
390    while True:
391        stop = len(lst)
392        yield sublist_iterator(start, stop)
393        start = stop
394
395
396class BenchmarkResult(object):
397    def __init__(self, func, records, loop):
398        self.func = func
399        self.loop = loop
400        self.records = np.array(records) / loop
401        self.best = np.min(self.records)
402
403    def __repr__(self):
404        name = getattr(self.func, "__name__", self.func)
405        args = (name, self.loop, self.records.size, format_time(self.best))
406        return "%20s: %10d loops, best of %d: %s per loop" % args
407
408
409def format_time(tm):
410    units = "s ms us ns ps".split()
411    base = 1
412    for unit in units[:-1]:
413        if tm >= base:
414            break
415        base /= 1000
416    else:
417        unit = units[-1]
418    return "%.1f%s" % (tm / base, unit)
419
420
421def benchmark(func, maxsec=1):
422    timer = timeit.Timer(func)
423    number = 1
424    result = timer.repeat(1, number)
425    # Too fast to be measured
426    while min(result) / number == 0:
427        number *= 10
428        result = timer.repeat(3, number)
429    best = min(result) / number
430    if best >= maxsec:
431        return BenchmarkResult(func, result, number)
432        # Scale it up to make it close the maximum time
433    max_per_run_time = maxsec / 3 / number
434    number = max(max_per_run_time / best / 3, 1)
435    # Round to the next power of 10
436    number = int(10 ** math.ceil(math.log10(number)))
437    records = timer.repeat(3, number)
438    return BenchmarkResult(func, records, number)
439
440
441RANGE_ITER_OBJECTS = (builtins.range,)
442
443
444# A dummy module for dynamically-generated functions
445_dynamic_modname = '<dynamic>'
446_dynamic_module = ModuleType(_dynamic_modname)
447_dynamic_module.__builtins__ = builtins
448
449
450def chain_exception(new_exc, old_exc):
451    """Set the __cause__ attribute on *new_exc* for explicit exception
452    chaining.  Returns the inplace modified *new_exc*.
453    """
454    if DEVELOPER_MODE:
455        new_exc.__cause__ = old_exc
456    return new_exc
457
458
459def get_nargs_range(pyfunc):
460    """Return the minimal and maximal number of Python function
461    positional arguments.
462    """
463    sig = pysignature(pyfunc)
464    min_nargs = 0
465    max_nargs = 0
466    for p in sig.parameters.values():
467        max_nargs += 1
468        if p.default == inspect._empty:
469            min_nargs += 1
470    return min_nargs, max_nargs
471
472
473def unify_function_types(numba_types):
474    """Return a normalized tuple of Numba function types so that
475
476        Tuple(numba_types)
477
478    becomes
479
480        UniTuple(dtype=<unified function type>, count=len(numba_types))
481
482    If the above transformation would be incorrect, return the
483    original input as given. For instance, if the input tuple contains
484    types that are not function or dispatcher type, the transformation
485    is considered incorrect.
486    """
487    dtype = unified_function_type(numba_types)
488    if dtype is None:
489        return numba_types
490    return (dtype,) * len(numba_types)
491
492
493def unified_function_type(numba_types, require_precise=True):
494    """Returns a unified Numba function type if possible.
495
496    Parameters
497    ----------
498    numba_types : Sequence of numba Type instances.
499    require_precise : bool
500      If True, the returned Numba function type must be precise.
501
502    Returns
503    -------
504    typ : {numba.core.types.Type, None}
505      A unified Numba function type. Or ``None`` when the Numba types
506      cannot be unified, e.g. when the ``numba_types`` contains at
507      least two different Numba function type instances.
508
509    If ``numba_types`` contains a Numba dispatcher type, the unified
510    Numba function type will be an imprecise ``UndefinedFunctionType``
511    instance, or None when ``require_precise=True`` is specified.
512
513    Specifying ``require_precise=False`` enables unifying imprecise
514    Numba dispatcher instances when used in tuples or if-then branches
515    when the precise Numba function cannot be determined on the first
516    occurrence that is not a call expression.
517    """
518    from numba.core.errors import NumbaExperimentalFeatureWarning
519
520    if not (isinstance(numba_types, Sequence) and
521            len(numba_types) > 0 and
522            isinstance(numba_types[0],
523                       (types.Dispatcher, types.FunctionType))):
524        return
525
526    warnings.warn("First-class function type feature is experimental",
527                  category=NumbaExperimentalFeatureWarning)
528
529    mnargs, mxargs = None, None
530    dispatchers = set()
531    function = None
532    undefined_function = None
533
534    for t in numba_types:
535        if isinstance(t, types.Dispatcher):
536            mnargs1, mxargs1 = get_nargs_range(t.dispatcher.py_func)
537            if mnargs is None:
538                mnargs, mxargs = mnargs1, mxargs1
539            elif not (mnargs, mxargs) == (mnargs1, mxargs1):
540                return
541            dispatchers.add(t.dispatcher)
542            t = t.dispatcher.get_function_type()
543            if t is None:
544                continue
545        if isinstance(t, types.FunctionType):
546            if mnargs is None:
547                mnargs = mxargs = t.nargs
548            elif not (mnargs == mxargs == t.nargs):
549                return
550            if isinstance(t, types.UndefinedFunctionType):
551                if undefined_function is None:
552                    undefined_function = t
553                else:
554                    # Refuse to unify using function type
555                    return
556                dispatchers.update(t.dispatchers)
557            else:
558                if function is None:
559                    function = t
560                else:
561                    assert function == t
562        else:
563            return
564    if require_precise and (function is None or undefined_function is not None):
565        return
566    if function is not None:
567        if undefined_function is not None:
568            assert function.nargs == undefined_function.nargs
569            function = undefined_function
570    elif undefined_function is not None:
571        undefined_function.dispatchers.update(dispatchers)
572        function = undefined_function
573    else:
574        function = types.UndefinedFunctionType(mnargs, dispatchers)
575
576    return function
577
578
579class _RedirectSubpackage(ModuleType):
580    """Redirect a subpackage to a subpackage.
581
582    This allows all references like:
583
584    >>> from numba.old_subpackage import module
585    >>> module.item
586
587    >>> import numba.old_subpackage.module
588    >>> numba.old_subpackage.module.item
589
590    >>> from numba.old_subpackage.module import item
591    """
592    def __init__(self, old_module_locals, new_module):
593        old_module = old_module_locals['__name__']
594        super().__init__(old_module)
595
596        new_mod_obj = import_module(new_module)
597
598        # Map all sub-modules over
599        for k, v in new_mod_obj.__dict__.items():
600            # Get attributes so that `subpackage.xyz` and
601            # `from subpackage import xyz` work
602            setattr(self, k, v)
603            if isinstance(v, ModuleType):
604                # Map modules into the interpreter so that
605                # `import subpackage.xyz` works
606                sys.modules[f"{old_module}.{k}"] = sys.modules[v.__name__]
607
608        # copy across dunders so that package imports work too
609        for attr, value in old_module_locals.items():
610            if attr.startswith('__') and attr.endswith('__'):
611                setattr(self, attr, value)
612