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