给定一个提供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对象库存?
答案 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提供的确切导入布局。在我们的示例中,这可以通过在单独的文件中定义Bar
和Baz
类来实现。祝你好运,并警惕循环进口!