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

jra*_*ast 5 python python-3.x python-3.5 python-3.6

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

\n\n
package/\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 __init__.py\n\xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 subpackage_A/\n    \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 __init__.py\n    \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 moduleA.py\n    \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 moduleB.py\n
Run Code Online (Sandbox Code Playgroud)\n\n

现在我想更改 的名称,subpackage_A同时subpackage_B保持旧名称可用,否则许多脚本会损坏。所以这应该是可能的:

\n\n
package/\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 __init__.py\n\xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 subpackage_A/\n    \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 __init__.py\n    \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 moduleA.py\n    \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 moduleB.py\n
Run Code Online (Sandbox Code Playgroud)\n\n

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

\n\n
from package.subpackage_B import moduleA\nfrom package.subpackage_B.moduleB import ClassB\n\n# This should, if possible, display a deprecation warning\nfrom package.subpackage_A import moduleA\n
Run Code Online (Sandbox Code Playgroud)\n\n

如果脚本尝试从旧位置ModuleNotFoundError导入,第一个版本会导致:moduleA

\n\n
# File: package/subpackage_A.py\n# This does not work:\nfrom package.subpackage_B import *  # Import everything from the new module\n\n# This is also not working:\nsys.modules[__name__] = __import__(\'package.subpackage_A\')\n
Run Code Online (Sandbox Code Playgroud)\n\n
Traceback (most recent call last):\n...\nModuleNotFoundError: No module named \'package.subpackage_A.moduleA\'\n
Run Code Online (Sandbox Code Playgroud)\n\n

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

\n

Hol*_*way 5

如果您使用的是 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)
Run Code Online (Sandbox Code Playgroud)

然后当使用你的包时

>>> 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
>>>
Run Code Online (Sandbox Code Playgroud)


Gia*_*tta 3

问题是subpackage_B/__init__.py不导入moduleAmoduleB因此import *什么也不导入。

使用显式导入:

from .subpackage_B import moduleA, moduleB
Run Code Online (Sandbox Code Playgroud)

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

from . import moduleA, moduleB
Run Code Online (Sandbox Code Playgroud)

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

import warnings

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

from .subpackage_B import *
Run Code Online (Sandbox Code Playgroud)