|
6 | 6 | import operator |
7 | 7 | import timeit |
8 | 8 | import math |
| 9 | +import sys |
9 | 10 | import traceback |
10 | 11 | import weakref |
11 | 12 | import warnings |
12 | 13 | import threading |
13 | 14 | import contextlib |
14 | 15 |
|
15 | 16 | from types import ModuleType |
| 17 | +from importlib import import_module |
16 | 18 | from collections.abc import Mapping, Sequence |
17 | 19 | import numpy as np |
18 | 20 |
|
@@ -537,3 +539,47 @@ def unified_function_type(numba_types, require_precise=True): |
537 | 539 | function = types.UndefinedFunctionType(mnargs, dispatchers) |
538 | 540 |
|
539 | 541 | return function |
| 542 | + |
| 543 | + |
| 544 | +class _RedirectSubpackage(ModuleType): |
| 545 | + """Redirect a subpackage to a subpackage. |
| 546 | +
|
| 547 | + This allows all references like: |
| 548 | +
|
| 549 | + >>> from numba.old_subpackage import module |
| 550 | + >>> module.item |
| 551 | +
|
| 552 | + >>> import numba.old_subpackage.module |
| 553 | + >>> numba.old_subpackage.module.item |
| 554 | +
|
| 555 | + >>> from numba.old_subpackage.module import item |
| 556 | + """ |
| 557 | + def __init__(self, old_module_locals, new_module): |
| 558 | + old_module = old_module_locals['__name__'] |
| 559 | + super().__init__(old_module) |
| 560 | + |
| 561 | + self.__old_module_states = {} |
| 562 | + self.__new_module = new_module |
| 563 | + |
| 564 | + new_mod_obj = import_module(new_module) |
| 565 | + |
| 566 | + # Map all sub-modules over |
| 567 | + for k, v in new_mod_obj.__dict__.items(): |
| 568 | + # Get attributes so that `subpackage.xyz` and |
| 569 | + # `from subpackage import xyz` work |
| 570 | + setattr(self, k, v) |
| 571 | + if isinstance(v, ModuleType): |
| 572 | + # Map modules into the interpreter so that |
| 573 | + # `import subpackage.xyz` works |
| 574 | + sys.modules[f"{old_module}.{k}"] = sys.modules[v.__name__] |
| 575 | + |
| 576 | + # copy across dunders so that package imports work too |
| 577 | + for attr, value in old_module_locals.items(): |
| 578 | + if attr.startswith('__') and attr.endswith('__'): |
| 579 | + if attr != "__builtins__": |
| 580 | + setattr(self, attr, value) |
| 581 | + self.__old_module_states[attr] = value |
| 582 | + |
| 583 | + def __reduce__(self): |
| 584 | + args = (self.__old_module_states, self.__new_module) |
| 585 | + return _RedirectSubpackage, args |
0 commit comments