ai-content-maker/.venv/Lib/site-packages/numba/tests/test_entrypoints.py

231 lines
8.0 KiB
Python
Raw Normal View History

2024-05-03 04:18:51 +03:00
import sys
from unittest import mock
import types
import warnings
import unittest
import os
import subprocess
import threading
from numba import config, njit
from numba.tests.support import TestCase
from numba.testing.main import _TIMEOUT as _RUNNER_TIMEOUT
if config.PYVERSION < (3, 9):
import importlib_metadata
else:
from importlib import metadata as importlib_metadata
_TEST_TIMEOUT = _RUNNER_TIMEOUT - 60.
class _DummyClass(object):
def __init__(self, value):
self.value = value
def __repr__(self):
return '_DummyClass(%f, %f)' % self.value
class TestEntrypoints(TestCase):
"""
Test registration of init() functions from Numba extensions
"""
def test_init_entrypoint(self):
# loosely based on Pandas test from:
# https://github.com/pandas-dev/pandas/pull/27488
mod = mock.Mock(__name__='_test_numba_extension')
try:
# will remove this module at the end of the test
sys.modules[mod.__name__] = mod
my_entrypoint = importlib_metadata.EntryPoint(
'init', '_test_numba_extension:init_func', 'numba_extensions',
)
with mock.patch.object(
importlib_metadata,
'entry_points',
return_value={'numba_extensions': (my_entrypoint,)},
):
from numba.core import entrypoints
# Allow reinitialization
entrypoints._already_initialized = False
entrypoints.init_all()
# was our init function called?
mod.init_func.assert_called_once()
# ensure we do not initialize twice
entrypoints.init_all()
mod.init_func.assert_called_once()
finally:
# remove fake module
if mod.__name__ in sys.modules:
del sys.modules[mod.__name__]
def test_entrypoint_tolerance(self):
# loosely based on Pandas test from:
# https://github.com/pandas-dev/pandas/pull/27488
mod = mock.Mock(__name__='_test_numba_bad_extension')
mod.configure_mock(**{'init_func.side_effect': ValueError('broken')})
try:
# will remove this module at the end of the test
sys.modules[mod.__name__] = mod
my_entrypoint = importlib_metadata.EntryPoint(
'init',
'_test_numba_bad_extension:init_func',
'numba_extensions',
)
with mock.patch.object(
importlib_metadata,
'entry_points',
return_value={'numba_extensions': (my_entrypoint,)},
):
from numba.core import entrypoints
# Allow reinitialization
entrypoints._already_initialized = False
with warnings.catch_warnings(record=True) as w:
entrypoints.init_all()
bad_str = "Numba extension module '_test_numba_bad_extension'"
for x in w:
if bad_str in str(x):
break
else:
raise ValueError("Expected warning message not found")
# was our init function called?
mod.init_func.assert_called_once()
finally:
# remove fake module
if mod.__name__ in sys.modules:
del sys.modules[mod.__name__]
_EP_MAGIC_TOKEN = 'RUN_ENTRY'
@unittest.skipIf(os.environ.get('_EP_MAGIC_TOKEN', None) != _EP_MAGIC_TOKEN,
"needs token")
def test_entrypoint_handles_type_extensions(self):
# loosely based on Pandas test from:
# https://github.com/pandas-dev/pandas/pull/27488
import numba
def init_function():
# This init function would normally just call a module init via
# import or similar, for the sake of testing, inline registration
# of how to handle the global "_DummyClass".
class DummyType(numba.types.Type):
def __init__(self):
super(DummyType, self).__init__(name='DummyType')
@numba.extending.typeof_impl.register(_DummyClass)
def typer_DummyClass(val, c):
return DummyType()
@numba.extending.register_model(DummyType)
class DummyModel(numba.extending.models.StructModel):
def __init__(self, dmm, fe_type):
members = [
('value', numba.types.float64), ]
super(DummyModel, self).__init__(dmm, fe_type, members)
@numba.extending.unbox(DummyType)
def unbox_dummy(typ, obj, c):
value_obj = c.pyapi.object_getattr_string(obj, "value")
dummy_struct_proxy = numba.core.cgutils.create_struct_proxy(typ)
dummy_struct = dummy_struct_proxy(c.context, c.builder)
dummy_struct.value = c.pyapi.float_as_double(value_obj)
c.pyapi.decref(value_obj)
err_flag = c.pyapi.err_occurred()
is_error = numba.core.cgutils.is_not_null(c.builder, err_flag)
return numba.extending.NativeValue(dummy_struct._getvalue(),
is_error=is_error)
@numba.extending.box(DummyType)
def box_dummy(typ, val, c):
dummy_struct_proxy = numba.core.cgutils.create_struct_proxy(typ)
dummy_struct = dummy_struct_proxy(c.context, c.builder)
value_obj = c.pyapi.float_from_double(dummy_struct.value)
serialized_clazz = c.pyapi.serialize_object(_DummyClass)
class_obj = c.pyapi.unserialize(serialized_clazz)
res = c.pyapi.call_function_objargs(class_obj, (value_obj,))
c.pyapi.decref(value_obj)
c.pyapi.decref(class_obj)
return res
mod = types.ModuleType("_test_numba_init_sequence")
mod.init_func = init_function
try:
# will remove this module at the end of the test
sys.modules[mod.__name__] = mod
my_entrypoint = importlib_metadata.EntryPoint(
'init',
'_test_numba_init_sequence:init_func',
'numba_extensions',
)
with mock.patch.object(
importlib_metadata,
'entry_points',
return_value={'numba_extensions': (my_entrypoint,)},
):
@njit
def foo(x):
return x
ival = _DummyClass(10)
foo(ival)
finally:
# remove fake module
if mod.__name__ in sys.modules:
del sys.modules[mod.__name__]
def run_cmd(self, cmdline, env):
popen = subprocess.Popen(cmdline,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
env=env)
# finish in _TEST_TIMEOUT seconds or kill it
timeout = threading.Timer(_TEST_TIMEOUT, popen.kill)
try:
timeout.start()
out, err = popen.communicate()
if popen.returncode != 0:
raise AssertionError(
"process failed with code %s: stderr follows\n%s\n" %
(popen.returncode, err.decode()))
return out.decode(), err.decode()
finally:
timeout.cancel()
return None, None
def test_entrypoint_extension_sequence(self):
env_copy = os.environ.copy()
env_copy['_EP_MAGIC_TOKEN'] = str(self._EP_MAGIC_TOKEN)
themod = self.__module__
thecls = type(self).__name__
methname = 'test_entrypoint_handles_type_extensions'
injected_method = '%s.%s.%s' % (themod, thecls, methname)
cmdline = [sys.executable, "-m", "numba.runtests", injected_method]
out, err = self.run_cmd(cmdline, env_copy)
_DEBUG = False
if _DEBUG:
print(out, err)