重命名python子包,将旧名称标记为已弃用

时间:2019-07-18 11:41:08

标签: python python-3.x python-3.6 python-3.5

我有一个具有以下目录结构的python包

package/
├── __init__.py
└── subpackage_A/
    ├── __init__.py
    ├── moduleA.py
    └── moduleB.py

现在,我想将subpackage_A的名称更改为subpackage_B,同时保持旧名称可用,否则很多脚本都会中断。所以这应该是可能的:

from package.subpackage_B import moduleA
from package.subpackage_B.moduleB import ClassB

# This should, if possible, display a deprecation warning
from package.subpackage_A import moduleA

我试图将新软件包简单地导入名为subpackage_A的模块中,但这不起作用:

# File: package/subpackage_A.py
# This does not work:
from package.subpackage_B import *  # Import everything from the new module

# This is also not working:
sys.modules[__name__] = __import__('package.subpackage_A')

如果脚本试图从旧位置导入ModuleNotFoundError,则第一个版本将导致moduleA

from package.subpackage_A import moduleA
Traceback (most recent call last):
...
ModuleNotFoundError: No module named 'package.subpackage_A.moduleA'

如何在不破坏向后兼容性的情况下重命名模块?该解决方案应该适用于python 3.5及更高版本。

2 个答案:

答案 0 :(得分:1)

问题在于subpackage_B/__init__.py不导入moduleAmoduleB,因此import *不导入任何内容。

使用显式导入:

from .subpackage_B import moduleA, moduleB

或修改subpackage_B/__init__.py以显式进行导入:

from . import moduleA, moduleB

关于使用subpackage_A时发出警告:您可以简单地触发它。在subpackage_A内部:

import warnings

warnings.warn('The name subpackage_A is deprecated. Please use subpackage_B')

from .subpackage_B import *

答案 1 :(得分:1)

如果您使用的是Python 3.7+,则可以使用PEP562中定义的模块级别__getattr__

您已将subpackageA重命名为subpackageB,然后在package/__init__.py中输入以下内容

from . import subpackageB
from warnings import warn

def __getattr__(name):
    if name == 'subpackageA':
        warn('subpackageA has been renamed to subpackageB')
        return subpackageB
    raise AttributeError('No module named ' + name)

然后在使用包裹时

>>> from package import subpackageB
>>> from package import subpackageA
/path/to/package/__init__.py:5: UserWarning: subpackageA has been renamed subpackageB
  warn('subB has been renamed subA')
>>> subpackageA == subpackageB
true
>>>