【问题标题】:How to correctly setup for PyQt5 imports on readthedocs?如何在 readthedocs 上正确设置 PyQt5 导入?
【发布时间】:2018-05-06 19:00:03
【问题描述】:

构建导入 PyQt5 的 project 的 sphinx 文档失败 (build log) 与

QStandardPaths: XDG_RUNTIME_DIR not set, defaulting to '/tmp/runtime-docs'
qt.qpa.screen: QXcbConnection: Could not connect to display 
Could not connect to any X display.

tox.ini 中需要以下内容:

[testenv:docs]
# avoid QStandardPaths: XDG_RUNTIME_DIR not set
passenv = XDG_RUNTIME_DIR
# xvfb-run prevents Could not connect to any X display
commands = /usr/bin/xvfb-run sphinx-build --color -W -b html -d {envtmpdir}/doctrees . {envtmpdir}/html

如何在 readthedocs 上做到这一点?

这与PyQt 4 import in read-the-docs密切相关, 不幸的是,其中不包含错误消息。 PyQt5 可以从 pip 安装的。

注意事项:

  • 在高级设置中,Install your project inside a virtualenv using setup.py install 被选中(但取消选中没有帮助)。
  • 以下暂定的参考geoptics快照是f33d233bf67bd7922ec864635e7589e7f4feb40f

暂定

1。带模拟模块

也许mocking PyQT5 可以工作。但这似乎有点cumbersome

改编自this answer,添加

import mock 
MOCK_MODULES = ['sip', 'PyQt5', 'PyQt5.QtGui', 'PyQt5.QtCore', 'PyQt5.QtWidgets']
sys.modules.update((mod_name, mock.MagicMock()) for mod_name in MOCK_MODULES)

conf.py 产生

    class _GRay(GCounterPart, QGraphicsPathItem):
TypeError: metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases

2。内置狮身人面像autodoc_mock_imports

与更简单的错误相同(仅在conf.py 中添加了一行)

autodoc_mock_imports = ['sip', 'PyQt5', 'PyQt5.QtGui', 'PyQt5.QtCore', 'PyQt5.QtWidgets']

3。使用自定义 Mock

使用julen's custom Mock class

class Mock(object):
    def __init__(self, *args, **kwargs):
        pass

    def __call__(self, *args, **kwargs):
        return Mock()

    @classmethod
    def __getattr__(cls, name):
        if name in ('__file__', '__path__'):
            return '/dev/null'
        elif name[0] == name[0].upper():
            mockType = type(name, (), {})
            mockType.__module__ = __name__
            return mockType
        else:
            return Mock()

MOCK_MODULES = ['sip', 'PyQt5', 'PyQt5.QtGui', 'PyQt5.QtCore', 'PyQt5.QtWidgets']
for mod_name in MOCK_MODULES:
    sys.modules[mod_name] = Mock()

产量

  File ".../geoptics/guis/qt/main.py", line 59, in <module>
    app = QCoreApplication.instance()
AttributeError: type object 'QCoreApplication' has no attribute 'instance'

应该可以将app 定义/检索内容从模块级别移动到函数体,而不是在模块导入时执行。

4。 autodoc_mock_imports 没有多重继承

autodoc_mock_imports = ['sip', 'PyQt5', 'PyQt5.QtGui', 'PyQt5.QtCore', 'PyQt5.QtWidgets']

conf.py 中,与第 2 次试探一样,但多重继承被装饰器取代。此pull request 中描述了这些更改。

现在错误是

geoptics.guis.qt.handles.LineHandle.reset_move:1:term not in glossary: move restrictions

因为定义该术语的 geooptics 类 _GScene(QGraphicsScene) 已被 sphinx 模拟掉,并且其文档丢失了。


在相关问题上留下的评论:

【问题讨论】:

  • 避免多重继承肯定会消除模拟 PyQt 的问题。不确定这是否是唯一的解决方案
  • 经过一番努力,因为 isclass 对于模拟类是错误的,所以装饰器而不是多重继承确实允许使用 autodoc_mock_imports。不幸的是 sphinx 模拟了所有从 PyQt5 继承的类,并且它们的文档丢失了。这又回到了最初的问题:是否可以让 readthedocs 通过 XDG_RUNTIME_DIR 并使用 xvfb-run
  • 我找不到任何证据表明xvfb 甚至可以在构建环境中使用,即使您确实设法传递了该环境变量。几乎没有办法绕过嘲笑 PyQt。你到底想从 PyQt 文档中生成什么?据我所知,狮身人面像实际上并没有那么多可用的东西。也许让intersphinx 工作就足够了?如果是这样,请参阅this。我设法使用该帖子中的自定义 .inv 文件将您的文档中的基类列表链接到 Qt C++ 文档。
  • 另外,使用conda 有帮助吗?见here
  • @three_pineapples 感谢您的链接(已经提出了这个问题,但还没有看到答案)。这将在以后有用。当前的问题是 GeOptics 类及其文档。添加暂定的 4 有望使这一点更清楚。新的issue 已打开,如果您愿意,可能更适合讨论。

标签: python pyqt read-the-docs


【解决方案1】:

autodoc_mock_imports 一直是fixed in sphinx-1.7.5

docs/conf.py 中添加以下行:

autodoc_mock_imports = ['sip', 'PyQt5', 'PyQt5.QtGui', 'PyQt5.QtCore', 'PyQt5.QtWidgets']

然后,用一行创建一个 docs/requirements.txt

sphinx>=1.7.5

并在 readthedocs 项目中声明 docs/requirements.txt admin&gt;advanced settings&gt;Requirements file.

幸运的是,这并没有绕过 setup.py,它只是添加了 sphinx-1.7.5 版本要求。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-07
    相关资源
    最近更新 更多