简体   繁体   English

Sphinx autodoc 使用 mock 卡在 random.choice()

[英]Sphinx autodoc gets stuck on random.choice() using mock

This is a continuation of a question I originally asked in this post: random.choice error due to np.linspace and np.logspace这是我最初在这篇文章中提出的一个问题的延续: random.choice error due to np.linspace and np.logspace

In this question, I have stripped down the problem to the bare minimum and was able to reproduce the problem where Sphinx is hanging up on the random.choice() function.在这个问题中,我已将问题简化到最低限度,并且能够重现 Sphinx 挂在 random.choice() function 上的问题。

Here is the Python code in the file randor_test.py;这是文件randor_test.py中的Python代码; it runs in PyCharm:它在 PyCharm 中运行:

import random
import numpy as np

def rand_test(svr_C, svr_gamma):
    """This is test docstring

    #. item one
    #. item two
    """
    ml_params = {'C': random.choice(svr_C), 'gamma': random.choice(svr_gamma)}
    return ml_params

svr_C = list(np.linspace(50, 300, 10))
svr_gamma = list(np.logspace(-4, -2, 3))

rand_result = rand_test(svr_C, svr_gamma)

for i in rand_result:
    print(i, rand_result[i])

I set up the Sphinx directory and followed all instructions in this post: Getting Started with Sphinx...我设置了 Sphinx 目录并按照这篇文章中的所有说明进行操作: Sphinx 入门...

After running make html I receive the following error:运行make html后,我收到以下错误:

WARNING: autodoc: failed to import module 'randor_test'; the following exception was raised:
Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/sphinx/ext/autodoc/importer.py", line 32, in import_module
    return importlib.import_module(modname)
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/importlib/__init__.py", line 127, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 1006, in _gcd_import
  File "<frozen importlib._bootstrap>", line 983, in _find_and_load
  File "<frozen importlib._bootstrap>", line 967, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 677, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 728, in exec_module
  File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
  File "/Users/kellihed/PAC_projects/basic_0629/src/randor_test.py", line 19, in <module>
    rand_result = rand_test(svr_C, svr_gamma)
  File "/Users/kellihed/PAC_projects/basic_0629/src/randor_test.py", line 10, in rand_test
    ml_params = {'C': random.choice(svr_C), 'gamma': random.choice(svr_gamma)}
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/random.py", line 261, in choice
    raise IndexError('Cannot choose from an empty sequence') from None
IndexError: Cannot choose from an empty sequence

My file structure follows the suggested layout:我的文件结构遵循建议的布局:

|--docs
|  |
|  |--Makefile
|  |--build
|  |  |
|  |  |--doctrees
|  |  |--html
|  |  |--_static
|  |  |--genindex.html
|  |  |--index.html 
|  |  |--modules.html
|  |--make.bat
|  |--source
|     |
|     |--_static
|     |--_templates
|     |--conf.py
|     |--index.rst
|     |--modules.rst
|     |--randor_test.rst
|
|--src
|  |__pychache__
|  |  |
|  |  |--randor_test.cpython-37.pyc
|  |
|  |--randor_test.py

I have the following ignore imports statement in conf.py:我在 conf.py 中有以下忽略导入语句:

autodoc_mock_imports = ["random", "numpy"]

Below is my conf.py file:下面是我的 conf.py 文件:

# -- Path setup --------------------------------------------------------------

# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#
import os
import sys
sys.path.insert(0, os.path.abspath(os.path.join('..', '..', 'src')))


# -- Project information -----------------------------------------------------

project = 'random_test'
copyright = '2020, DK'
author = 'DK'

# The full version, including alpha/beta/rc tags
release = '0.1'


# -- General configuration ---------------------------------------------------

# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = ['sphinx.ext.autodoc']
autodoc_mock_imports = ["random", "numpy"]

# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']

# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This pattern also affects html_static_path and html_extra_path.
exclude_patterns = []


# -- Options for HTML output -------------------------------------------------

# The theme to use for HTML and HTML Help pages.  See the documentation for
# a list of builtin themes.
#
html_theme = 'alabaster'

# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']

You have module-level code that will always be executed when Sphinx imports randor_test .当 Sphinx 导入randor_test时,您将始终执行模块级代码。 svr_C = list(np.linspace(50, 300, 10)) will not cause an error directly, but the result is that svr_C is an an empty list. svr_C = list(np.linspace(50, 300, 10))不会直接报错,但结果是svr_C是一个空列表。

The error occurs when random.choice(svr_C) is executed.执行random.choice(svr_C)时发生错误。 I don't think having random in autodoc_mock_imports makes any difference (it is a built-in standard module that is always available).我不认为在autodoc_mock_imports中有random有任何区别(它是一个始终可用的内置标准模块)。 I think the best solution is to put the module-level code in a if __name__ == '__main__' block.我认为最好的解决方案是将模块级代码放在if __name__ == '__main__'块中。

See also Does sphinx run my code on executing 'make html'?另请参阅sphinx 在执行“make html”时是否运行我的代码? . .

If you didn't use autodoc_mock_imports = ["numpy"] it would have worked without giving an error:如果您不使用autodoc_mock_imports = ["numpy"]它会工作而不会给出错误:

在此处输入图像描述

So why did autodoc_mock_imports = ["numpy"] cause the error?那么为什么autodoc_mock_imports = ["numpy"]会导致错误呢? Because using mock will cause import numpy as np to provide signatures that although callable are mockups, so their returns will be empty.因为使用 mock 会导致import numpy as np提供签名,虽然 callable 是 mockups,所以它们的返回将为空。 For example:例如:

import numpy as np
type(np)  # using mock in conf.py
<class 'sphinx.ext.autodoc.mock._MockModule'>
import numpy as np
type(np)  # not using mock in conf.py
<class 'module'>

Quoting the documentation:引用文档:

autodoc_mock_imports This value contains a list of modules to be mocked up. autodoc_mock_imports此值包含要模拟的模块列表。 This is useful when some external dependencies are not met at build time and break the building process.当构建时不满足某些外部依赖项并破坏构建过程时,这很有用。 You may only specify the root package of the dependencies themselves and omit the sub-modules:您只能指定依赖项本身的根 package 并省略子模块:

You don't necessarily have to use mock if your external dependencies (in other words, the imports from outside your own library) work fine at build time when you call Sphinx.如果您在调用 Sphinx 时外部依赖项(换句话说,从您自己的库外部导入)在构建时工作正常,则不一定必须使用 mock。 Your short example would have worked if you hadn't used mock.如果您没有使用模拟,那么您的简短示例将会起作用。 Besides using __main__ , another common option is not having variables initialize at module level by encapsulating them in a method or function.除了使用__main__之外,另一个常见的选项是不通过将变量封装在方法或 function 中来在模块级别初始化变量。

6.1. 6.1. More on Modules A module can contain executable statements as well as function definitions. 更多关于模块模块可以包含可执行语句以及 function 定义。 These statements are intended to initialize the module.这些语句旨在初始化模块。 They are executed only the first time the module name is encountered in an import statement.它们仅在 import 语句中第一次遇到模块名称时执行。 (They are also run if the file is executed as a script.) (如果文件作为脚本执行,它们也会运行。)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM