重构模块并保持向后兼容性,包括intersphinx

时间:2017-05-23 15:54:00

标签: python python-sphinx api-design

给定一个提供pack类的python包pack.foo.Bar

pack/
    __init__.py  # empty
    foo.py
        # content of foo.py
        """
        This module does stuff using the :class:`pack.foo.Bar` class.
        """

        class Bar(object):
            pass

        # much more code here

我想将pack.foo模块重构为一个包,以便将Bar类移动到pack/foo/bar.py文件。为了保持向后兼容性,我可以使用pack/foo/__init__.py文件:

"""
This module does stuff using the :class:`pack.foo.Bar` class.
"""

from pack.foo.bar import Bar
__all__ = ['Bar']

API的用户仍然可以使用from pack.foo import Bar

还有一个问题:使用sphinx时的参考。当sphinx解析pack/foo/__init__.py中的docstring时,它无法找到目标:

WARNING: py:class reference target not found pack.foo.bar.Bar

在使用intersphinx扩展名时,会破坏用户提供的文档。

重构包结构的正确方法是什么,仍保持完全向后兼容性,包括sphinx对象库存?

1 个答案:

答案 0 :(得分:0)

以下是我自己的答案和一些调查结果。

在这种情况下没有银弹。

首先,sphinx-apidoc生成的代码文档将从文件布局中获取模块布局。这意味着Bar中定义的pack/foo.py类将被记录为pack.foo.Bar,无论pack/__init__.py中发生何种导入错误。

其次,人们仍然可以使用autodoc extension。 Autodoc只是尝试在重组文本中定义的文本符号进行正常导入。这样,您就可以使用

Bar类生成HTML文档
.. autoclass:: pack.Bar
    :members:

虽然有一个问题。任何记录的符号(以及它们的每个依赖项,可以传递)必须与要记录的完全相同的命名空间一起使用。考虑我们示例的变体,提供额外的类Baz

pack/
    __init__.py
        # content of __init__.py
        from pack.foo.bar import Bar, Baz
        __all__ = ['Bar', 'Baz']

    foo.py
        # content of foo.py
        """
        This module does stuff using the :class:`pack.foo.Bar` class.
        """

        class Bar(object):
            pass

        class Baz(Bar):  # Here, sphinx thinks that Baz inherits from
            pass         # pack.foo.Bar because Bar.__module__ is
                         # pack.foo in this context.

Sphinx无法导入pack.foo.Bar,因为pack.Bar的内容只能导入pack/__init__.py

为了完成这项工作,我们必须找到一种方法,只使用API​​代码本身中软件包API提供的确切导入布局。在我们的示例中,这可以通过在单独的文件中定义BarBaz类来实现。祝你好运,并警惕循环进口!