| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647 |
- # -*- coding: utf-8 -*-
- r"""旧导入前缀 → 新导入前缀的**别名**(仅用于模块实现包搬迁的过渡期;下个版本删除)。
- 背景(用户令 2026-09-28 新结构):实现包由 `<模块>/common/<pkg>/` 上提到 `<模块>/<pkg>/`。
- 旧写法 `from app_X.common.app_X_guanlan.api import …` 要在一个版本内继续可用,且**不能产生两份模块对象**
- (两份 = 两份全局状态,isinstance/缓存/单例会静默失效)。
- 做法:往 `sys.meta_path` 装一个只认旧前缀的 finder;命中时把 `create_module` 直接指向新前缀的模块对象,
- 于是 `sys.modules[旧名] is sys.modules[新名]`(同名同体),子模块也逐个这样映射,不预先 import 任何实现。
- """
- from __future__ import annotations
- import importlib
- import importlib.abc
- import importlib.util
- import sys
- class _PrefixAlias(importlib.abc.MetaPathFinder, importlib.abc.Loader):
- def __init__(self, old: str, new: str) -> None:
- self.old = old
- self.new = new
- def find_spec(self, fullname, path=None, target=None): # noqa: D102
- if fullname == self.old or fullname.startswith(self.old + '.'):
- return importlib.util.spec_from_loader(fullname, self)
- return None
- def create_module(self, spec): # noqa: D102
- new_name = self.new + spec.name[len(self.old):]
- mod = importlib.import_module(new_name)
- sys.modules[spec.name] = mod # 同名同体
- return mod
- def exec_module(self, module) -> None: # noqa: D102
- pass # 实现已执行过,无需再跑
- def alias_prefix(old: str, new: str) -> None:
- """把 `old` 前缀(含其子模块)别名到 `new` 前缀;重复调用幂等。"""
- for f in sys.meta_path:
- if isinstance(f, _PrefixAlias) and f.old == old and f.new == new:
- return
- sys.meta_path.insert(0, _PrefixAlias(old, new))
- __all__ = ['alias_prefix']
|