.\numpy\benchmarks\benchmarks\__init__.py
# 导入名为 common 的当前目录下的模块
from . import common
# 导入 sys 和 os 模块
import sys
import os
# 定义函数 show_cpu_features
def show_cpu_features():
# 从 numpy 库中导入 _opt_info 函数
from numpy.lib._utils_impl import _opt_info
# 调用 _opt_info 函数获取信息
info = _opt_info()
# 构造 info 字符串,描述 NumPy 的 CPU 特性信息
info = "NumPy CPU features: " + (info if info else 'nothing enabled')
# 检查是否在环境变量中找到 'SHELL',并且不在 Windows 平台上
if 'SHELL' in os.environ and sys.platform != 'win32':
# 在终端中输出带有黄色前景色的 info 字符串
print(f"\033[33m{info}\033[0m")
else:
# 在终端中输出 info 字符串
print(info)
# 定义函数 dirty_lock
def dirty_lock(lock_name, lock_on_count=1):
# 检查当前操作系统是否具有 getppid 函数
if not hasattr(os, "getppid"):
return False
# 获取当前进程的父进程 ID
ppid = os.getppid()
# 如果没有父进程或者父进程 ID 等于当前进程 ID,则返回 False
if not ppid or ppid == os.getpid():
return False
# 构造锁文件的路径
lock_path = os.path.abspath(os.path.join(
os.path.dirname(__file__), "..", "env", lock_name)
)
# 尝试在锁文件中进行加锁操作
try:
with open(lock_path, 'a+') as f:
f.seek(0)
# 读取锁文件中的计数和父进程 ID
count, _ppid = (f.read().split() + [0, 0])[:2]
count, _ppid = int(count), int(_ppid)
# 如果父进程 ID 相同,则进行锁计数逻辑
if _ppid == ppid:
if count >= lock_on_count:
return True
count += 1
else:
count = 0
# 清空并更新锁文件内容为新的计数和父进程 ID
f.seek(0)
f.truncate()
f.write(f"{str(count)} {str(ppid)}")
except OSError:
pass
return False
# 如果未能获取到名为 "print_cpu_features.lock" 的脏锁,则调用 show_cpu_features 函数
if not dirty_lock("print_cpu_features.lock"):
show_cpu_features()
NumPy Logo Guidelines
These guidelines are meant to help keep the NumPy logo consistent and recognizable across all its uses. They also provide a common language for referring to the logos and their components.
The primary logo is the horizontal option (logomark and text next to each other) and the secondary logo is the stacked version (logomark over text). I’ve also provided the logomark on its own (meaning it doesn’t have text). When in doubt, it’s preferable to use primary or secondary options over the logomark alone.
Color
The full color options are a combo of two shades of blue, rgb(77, 171, 207) and rgb(77, 119, 207), while light options are rgb(255, 255, 255) and dark options are rgb(1, 50, 67).
Whenever possible, use the full color logos. One color logos (light or dark) are to be used when full color will not have enough contrast, usually when logos must be on colored backgrounds.
Minimum Size
Please do not make the primary logo smaller than 50px wide, secondary logo smaller than 35px wide, or logomark smaller than 20px wide.
Logo Integrity
A few other notes to keep in mind when using the logo:
- Make sure to scale the logo proportionally.
- Maintain a good amount of space around the logo. Don’t let it overlap with text, images, or other elements.
- Do not try and recreate or modify the logo. For example, do not use the logomark and then try to write NumPy in another font.
Building with Meson
Note: this is for early adopters. It has been tested on Linux and macOS, and
with Python 3.10-3.12. There is one CI job to keep the build stable. This may
have rough edges, please open an issue if you run into a problem.
Developer build
Install build tools: Use one of:
-
mamba env create -f environment.yml && mamba activate numpy-dev
-
python -m pip install -r requirements/build_requirements.txt
Note: also make sure you havepkg-config
and the usual system dependencies
for NumPy
Then install spin:
python -m pip install spin
Compile and install: spin build
This builds in the build/
directory, and installs into the build-install
directory.
Then run the test suite or a shell via spin
:
spin test
spin ipython
Alternatively, to use the package, add it to your PYTHONPATH
:
export PYTHONPATH=${PWD}/build/lib64/python3.10/site-packages # may vary
pytest --pyargs numpy
pip install
Note that pip
will use the default build system, which is now Meson.
Commands such as pip install .
or pip install --no-build-isolation .
will work as expected, as does building an sdist or wheel with python -m build
,
or pip install -e . --no-build-isolation
for an editable install.
For a more complete developer experience than editable installs, consider using
spin
instead though (see above).
Workaround for a hiccup on Fedora
- Fedora does not distribute
openblas.pc
. Install the following file in~/lib/pkgconfig/openblas.pc
:
prefix=/usr
includedir=${prefix}/include
libdir=${prefix}/lib64
Name: openblas
Description: OpenBLAS is an optimized BLAS library based on GotoBLAS2 1.13 BSD version
Version: 0.3.19
Cflags: -I${includedir}/openblas
Libs: -L${libdir} -lopenblas
Then build with:
spin build -- -Dpkg_config_path=${HOME}/lib/pkgconfig
.\numpy\doc\conftest.py
"""
Pytest configuration and fixtures for the Numpy test suite.
"""
# 导入 pytest 库,用于测试框架
import pytest
# 导入 numpy 库,用于科学计算
import numpy
# 导入 matplotlib 库,用于绘图
import matplotlib
# 导入 doctest 库,用于文档测试
import doctest
# 设置 matplotlib 使用后端 'agg',强制使用该后端
matplotlib.use('agg', force=True)
# 忽略 matplotlib 输出,如 `<matplotlib.image.AxesImage at
# 0x7f956908c280>`。使用 doctest 的 monkeypatching 实现,
# 受 https://github.com/wooyek/pytest-doctest-ellipsis-markers (MIT license) 启发
# 定义一个自定义的输出检查器类,继承自 doctest.OutputChecker
OutputChecker = doctest.OutputChecker
# 定义要忽略的空行标记列表,如 '<matplotlib.', '<mpl_toolkits.mplot3d.'
empty_line_markers = ['<matplotlib.', '<mpl_toolkits.mplot3d.']
class SkipMatplotlibOutputChecker(doctest.OutputChecker):
def check_output(self, want, got, optionflags):
# 遍历空行标记列表,如果输出中包含其中之一的标记,则将 got 设为空字符串
for marker in empty_line_markers:
if marker in got:
got = ''
break
# 调用父类的 check_output 方法检查输出
return OutputChecker.check_output(self, want, got, optionflags)
# 将 doctest.OutputChecker 替换为自定义的 SkipMatplotlibOutputChecker
doctest.OutputChecker = SkipMatplotlibOutputChecker
# 定义一个自动使用的 fixture,向 doctest 的命名空间中添加 'np',值为 numpy
@pytest.fixture(autouse=True)
def add_np(doctest_namespace):
# 设置 numpy 的随机种子为 1
numpy.random.seed(1)
# 向 doctest 的命名空间中添加 'np',值为 numpy
doctest_namespace['np'] = numpy
.\numpy\doc\neps\conf.py
#
# NumPy Enhancement Proposals documentation build configuration file, created by
# sphinx-quickstart on Mon Dec 11 12:45:09 2017.
#
# This file is execfile()d with the current directory set to its
# containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.
# 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('.'))
# -- General configuration ------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
#
# needs_sphinx = '1.0'
# 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.imgmath', # 导入数学公式图片生成扩展模块
'sphinx.ext.intersphinx', # 导入交叉引用扩展模块
]
# Add any paths that contain templates here, relative to this directory.
templates_path = ['../source/_templates/']
# The suffix(es) of source filenames.
# You can specify multiple suffix as a list of string:
#
# source_suffix = ['.rst', '.md']
source_suffix = '.rst'
# The master toctree document.
master_doc = 'content'
# General information about the project.
project = 'NumPy Enhancement Proposals' # 项目名称为“NumPy Enhancement Proposals”
copyright = '2017-2018, NumPy Developers'
author = 'NumPy Developers'
title = 'NumPy Enhancement Proposals Documentation' # 文档标题为“NumPy Enhancement Proposals Documentation”
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = ''
# The full version, including alpha/beta/rc tags.
release = ''
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#
# This is also used if you do content translation via gettext catalogs.
# Usually you set "language" from the command line for these cases.
language = "en" # 使用英语作为生成文档的语言
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This patterns also effect to html_static_path and html_extra_path
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# If true, `todo` and `todoList` produce output, else they produce nothing.
todo_include_todos = False
## -- Options for HTML output ----------------------------------------------
#
html_theme = 'pydata_sphinx_theme' # 使用PyData Sphinx主题
html_logo = '../source/_static/numpylogo.svg' # 设置HTML页面的Logo图标
html_favicon = '../source/_static/favicon/favicon.ico' # 设置HTML页面的favicon图标
# 定义 HTML 主题的选项字典
html_theme_options = {
# GitHub 项目的 URL
"github_url": "https://github.com/numpy/numpy",
# 外部链接列表,包含一个字典,指定链接名称和 URL
"external_links": [
{"name": "Wishlist",
"url": "https://github.com/numpy/numpy/issues?q=is%3Aopen+is%3Aissue+label%3A%2223+-+Wish+List%22",
},
],
# 是否显示上一篇和下一篇链接,默认为 False
"show_prev_next": False,
}
# 设置 HTML 页面的标题,使用项目名称进行格式化
html_title = "%s" % (project)
# 设置静态文件路径,指向源文件中的 _static 文件夹
html_static_path = ['../source/_static']
# 设置 HTML 页面中最后更新时间的格式
html_last_updated_fmt = '%b %d, %Y'
# 设置是否使用模块索引,默认为 True
html_use_modindex = True
# 设置是否复制源文件到输出目录,默认为 False
html_copy_source = False
# 设置是否显示域索引,默认为 False
html_domain_indices = False
# 设置 HTML 页面文件的后缀名,默认为 '.html'
html_file_suffix = '.html'
# 如果 sphinx.ext.pngmath 在 extensions 列表中
if 'sphinx.ext.pngmath' in extensions:
# 设置 PNG 数学公式是否显示预览,默认为 True
pngmath_use_preview = True
# 设置 dvipng 参数,包括 gamma 值、分辨率、背景透明度等
pngmath_dvipng_args = ['-gamma', '1.5', '-D', '96', '-bg', 'Transparent']
# 设置是否显示绘图的 HTML 格式选项,默认为 False
plot_html_show_formats = False
# 设置是否显示绘图的源文件链接,默认为 False
plot_html_show_source_link = False
# -- Options for HTMLHelp output ------------------------------------------
# 设置 HTMLHelp 输出文件的基本名称
htmlhelp_basename = 'NumPyEnhancementProposalsdoc'
# -- Options for LaTeX output ---------------------------------------------
# LaTeX 文档的相关配置项
latex_elements = {
# 纸张大小,可选 'letterpaper' 或 'a4paper'
# 'papersize': 'letterpaper',
# 字体大小,可选 '10pt', '11pt' 或 '12pt'
# 'pointsize': '10pt',
# LaTeX 导言区的附加内容
# 'preamble': '',
# 图片浮动位置设定
# 'figure_align': 'htbp',
}
# LaTeX 文档列表,包括源文件、目标文件名、标题、作者、文档类别等信息
latex_documents = [
(master_doc, 'NumPyEnhancementProposals.tex', title,
'NumPy Developers', 'manual'),
]
# -- Options for manual page output ---------------------------------------
# 每个手册页的配置项,包括源文件、名称、描述、作者、手册页章节等信息
man_pages = [
(master_doc, 'numpyenhancementproposals', title,
[author], 1)
]
# -- Options for Texinfo output -------------------------------------------
# Texinfo 输出文件的配置项,包括源文件、目标名称、标题、作者、目录项、描述、分类等信息
texinfo_documents = [
(master_doc, 'NumPyEnhancementProposals', title,
author, 'NumPyEnhancementProposals', 'One line description of project.',
'Miscellaneous'),
]
# -----------------------------------------------------------------------------
# Intersphinx 配置
# -----------------------------------------------------------------------------
# 将文档树分组到 Intersphinx 文件中,指定每个库的名称和对应 URL
intersphinx_mapping = {
'python': ('https://docs.python.org/dev', None),
'numpy': ('https://numpy.org/devdocs', None),
'scipy': ('https://docs.scipy.org/doc/scipy/reference', None),
'matplotlib': ('https://matplotlib.org', None)
}
.\numpy\doc\neps\nep-0016-benchmark.py
# 导入性能测试模块 perf
import perf
# 导入抽象基类模块 abc
import abc
# 导入 NumPy 库并使用 np 别名
import numpy as np
# 定义一个名为 NotArray 的空类
class NotArray:
pass
# 定义一个名为 AttrArray 的类,并设置类属性 __array_implementer__ 为 True
class AttrArray:
__array_implementer__ = True
# 定义一个名为 ArrayBase 的抽象基类
class ArrayBase(abc.ABC):
pass
# 定义一个名为 ABCArray1 的类,继承自 ArrayBase 抽象基类
class ABCArray1(ArrayBase):
pass
# 定义一个名为 ABCArray2 的类,没有明确指定继承关系
class ABCArray2:
pass
# 将 ABCArray2 注册为 ArrayBase 的虚拟子类
ArrayBase.register(ABCArray2)
# 创建 NotArray 类的实例
not_array = NotArray()
# 创建 AttrArray 类的实例
attr_array = AttrArray()
# 创建 ABCArray1 类的实例
abc_array_1 = ABCArray1()
# 创建 ABCArray2 类的实例
abc_array_2 = ABCArray2()
# 确保抽象基类 ABC 的缓存被预先加载
# 测试 isinstance 函数,检查 not_array 是否为 ArrayBase 的实例
isinstance(not_array, ArrayBase)
# 测试 isinstance 函数,检查 abc_array_1 是否为 ArrayBase 的实例
isinstance(abc_array_1, ArrayBase)
# 测试 isinstance 函数,检查 abc_array_2 是否为 ArrayBase 的实例
# 创建性能测试的 Runner 对象
runner = perf.Runner()
# 定义函数 t,用于执行性能测试并记录时间
def t(name, statement):
runner.timeit(name, statement, globals=globals())
# 测试 np.asarray([]) 的性能
t("np.asarray([])", "np.asarray([])")
# 创建一个空 NumPy 数组 arrobj
arrobj = np.array([])
# 测试 np.asarray(arrobj) 的性能
t("np.asarray(arrobj)", "np.asarray(arrobj)")
# 测试 getattr 函数,获取 not_array 的 '__array_implementer__' 属性,如果不存在返回 False
t("attr, False", "getattr(not_array, '__array_implementer__', False)")
# 测试 getattr 函数,获取 attr_array 的 '__array_implementer__' 属性,如果不存在返回 False
t("attr, True", "getattr(attr_array, '__array_implementer__', False)")
# 测试 isinstance 函数,检查 not_array 是否为 ArrayBase 的实例,预期结果为 False
t("ABC, False", "isinstance(not_array, ArrayBase)")
# 测试 isinstance 函数,检查 abc_array_1 是否为 ArrayBase 的实例,预期结果为 True(通过继承实现)
t("ABC, True, via inheritance", "isinstance(abc_array_1, ArrayBase)")
# 测试 isinstance 函数,检查 abc_array_2 是否为 ArrayBase 的实例,预期结果为 True(通过注册实现)
t("ABC, True, via register", "isinstance(abc_array_2, ArrayBase)")
.\numpy\doc\neps\tools\build_index.py
"""
Scan the directory of nep files and extract their metadata. The
metadata is passed to Jinja for filling out the toctrees for various NEP
categories.
"""
# 导入必要的模块
import os # 提供与操作系统相关的功能
import jinja2 # 模板引擎
import glob # 文件名匹配
import re # 正则表达式操作
# 渲染函数,用于渲染 Jinja 模板
def render(tpl_path, context):
# 拆分模板路径和文件名
path, filename = os.path.split(tpl_path)
# 返回渲染后的模板内容
return jinja2.Environment(
loader=jinja2.FileSystemLoader(path or './')
).get_template(filename).render(context)
# 提取 NEP 元数据的函数
def nep_metadata():
# 忽略的文件名
ignore = ('nep-template.rst')
# 匹配所有符合 nep-*.rst 模式的文件,并按文件名排序
sources = sorted(glob.glob(r'nep-*.rst'))
# 过滤掉忽略的文件名
sources = [s for s in sources if not s in ignore]
# 元数据的正则表达式模式
meta_re = r':([a-zA-Z\-]*): (.*)'
# 是否存在 Provisional 类型的 NEP
has_provisional = False
# 存储 NEP 元数据的字典
neps = {}
# 打印加载的元数据信息
print('Loading metadata for:')
# 遍历每个 NEP 文件
for source in sources:
# 打印加载的文件名
print(f' - {source}')
# 提取 NEP 编号
nr = int(re.match(r'nep-([0-9]{4}).*\.rst', source).group(1))
# 打开 NEP 文件并读取每一行内容
with open(source) as f:
lines = f.readlines()
# 提取每行中的标签信息
tags = [re.match(meta_re, line) for line in lines]
tags = [match.groups() for match in tags if match is not None]
# 将标签信息转化为字典形式
tags = {tag[0]: tag[1] for tag in tags}
# 查找 NEP 标题所在行
for i, line in enumerate(lines[:-1]):
chars = set(line.rstrip())
# 判断标题行的特征
if len(chars) == 1 and ("=" in chars or "*" in chars):
break
else:
# 如果找不到 NEP 标题行,则引发运行时错误
raise RuntimeError("Unable to find NEP title.")
# 将 NEP 标题和文件名添加到标签信息中
tags['Title'] = lines[i+1].strip()
tags['Filename'] = source
# 检查 NEP 标题是否以正确格式开始
if not tags['Title'].startswith(f'NEP {nr} — '):
raise RuntimeError(
f'Title for NEP {nr} does not start with "NEP {nr} — " '
'(note that — here is a special, elongated dash). Got: '
f' {tags["Title"]!r}')
# 检查已接受、已拒绝或已撤回的 NEP 是否有解决方案标签
if tags['Status'] in ('Accepted', 'Rejected', 'Withdrawn'):
if not 'Resolution' in tags:
raise RuntimeError(
f'NEP {nr} is Accepted/Rejected/Withdrawn but '
'has no Resolution tag'
)
# 如果 NEP 的状态是 Provisional,则设置标志位为 True
if tags['Status'] == 'Provisional':
has_provisional = True
# 将 NEP 数据存入 neps 字典中
neps[nr] = tags
# 现在已经获取了所有 NEP 元数据,可以执行一些全局一致性检查
# 遍历字典 neps,其中 nr 是 NEP 编号,tags 是 NEP 的标签字典
for nr, tags in neps.items():
# 检查 NEP 的状态是否为 'Superseded'(已废弃)
if tags['Status'] == 'Superseded':
# 如果 NEP 被标记为 'Superseded',则检查是否存在 'Replaced-By' 标签
if not 'Replaced-By' in tags:
# 如果缺少 'Replaced-By' 标签,则抛出运行时错误,指明 NEP 已废弃但未指定替代的 NEP 编号
raise RuntimeError(
f'NEP {nr} has been Superseded, but has no Replaced-By tag'
)
# 获取被替代的 NEP 编号,并转换为整数
replaced_by = int(re.findall(r'\d+', tags['Replaced-By'])[0])
# 获取替代 NEP 对象的标签信息
replacement_nep = neps[replaced_by]
# 检查替代 NEP 是否有 'Replaces' 标签
if not 'Replaces' in replacement_nep:
# 如果替代 NEP 缺少 'Replaces' 标签,则抛出运行时错误,指明当前 NEP 被替代但替代的 NEP 没有指定被替代的 NEP 编号
raise RuntimeError(
f'NEP {nr} is superseded by {replaced_by}, but that NEP has no Replaces tag.'
)
# 检查当前 NEP 是否在替代 NEP 的 'Replaces' 标签中
if nr not in parse_replaces_metadata(replacement_nep):
# 如果当前 NEP 不在替代 NEP 的 'Replaces' 标签中,则抛出运行时错误,指明当前 NEP 被替代但被替代 NEP 的 'Replaces' 标签指定了不正确的 NEP 编号
raise RuntimeError(
f'NEP {nr} is superseded by {replaced_by}, but that NEP has a Replaces tag of `{replacement_nep['Replaces']}`.'
)
# 如果当前 NEP 存在 'Replaces' 标签
if 'Replaces' in tags:
# 解析当前 NEP 的 'Replaces' 标签,并遍历每个被替代的 NEP 编号
replaced_neps = parse_replaces_metadata(tags)
for nr_replaced in replaced_neps:
# 获取被替代 NEP 对象的标签信息
replaced_nep_tags = neps[nr_replaced]
# 检查被替代 NEP 的状态是否为 'Superseded'
if not replaced_nep_tags['Status'] == 'Superseded':
# 如果被替代 NEP 的状态不是 'Superseded',则抛出运行时错误,指明当前 NEP 替代了一个未被设置为 'Superseded' 的 NEP
raise RuntimeError(
f'NEP {nr} replaces NEP {nr_replaced}, but that NEP has not been set to Superseded'
)
# 返回包含更新后的 NEP 数据字典和是否存在临时 NEP 的标志的字典
return {'neps': neps, 'has_provisional': has_provisional}
# 定义函数,处理替换的元数据中的 :Replaces: 字段,返回替换后的 NEP 编号列表
def parse_replaces_metadata(replacement_nep):
"""Handle :Replaces: as integer or list of integers"""
# 使用正则表达式查找替换的 NEP 编号,返回匹配到的所有数字字符串列表
replaces = re.findall(r'\d+', replacement_nep['Replaces'])
# 将匹配到的数字字符串列表转换为整数列表
replaced_neps = [int(s) for s in replaces]
# 返回替换后的 NEP 编号列表
return replaced_neps
# 调用 nep_metadata() 函数获取 NEP 元数据
meta = nep_metadata()
# 遍历给定的 NEP 类别列表
for nepcat in (
"provisional", "accepted", "deferred", "finished", "meta",
"open", "rejected",
):
# 构建输入文件名和输出文件名
infile = f"{nepcat}.rst.tmpl"
outfile = f"{nepcat}.rst"
# 打印编译信息,指示正在处理哪个模板文件到哪个输出文件
print(f'Compiling {infile} -> {outfile}')
# 调用 render 函数,生成指定模板文件的内容
genf = render(infile, meta)
# 打开输出文件,写入生成的内容
with open(outfile, 'w') as f:
f.write(genf)
.\numpy\doc\postprocess.py
#!/usr/bin/env python3
"""
Post-processes HTML and Latex files output by Sphinx.
"""
# 主程序入口
def main():
import argparse
# 创建命令行参数解析器
parser = argparse.ArgumentParser(description=__doc__)
# 添加参数:模式(html 或 tex)
parser.add_argument('mode', help='file mode', choices=('html', 'tex'))
# 添加参数:输入文件列表
parser.add_argument('file', nargs='+', help='input file(s)')
# 解析命令行参数
args = parser.parse_args()
# 获取模式参数
mode = args.mode
# 遍历每个输入文件
for fn in args.file:
# 打开文件并读取内容
with open(fn, encoding="utf-8") as f:
# 根据模式选择处理函数处理文件内容
if mode == 'html':
lines = process_html(fn, f.readlines())
elif mode == 'tex':
lines = process_tex(f.readlines())
# 将处理后的内容写回文件
with open(fn, 'w', encoding="utf-8") as f:
f.write("".join(lines))
# 处理 HTML 文件内容的函数
def process_html(fn, lines):
return lines
# 处理 LaTeX 文件内容的函数
def process_tex(lines):
"""
Remove unnecessary section titles from the LaTeX file.
移除 LaTeX 文件中不必要的章节标题。
"""
new_lines = []
# 遍历每一行内容
for line in lines:
# 如果是以特定的 numpy 相关标题开头,则跳过这一行
if (line.startswith(r'\section{numpy.')
or line.startswith(r'\subsection{numpy.')
or line.startswith(r'\subsubsection{numpy.')
or line.startswith(r'\paragraph{numpy.')
or line.startswith(r'\subparagraph{numpy.')
):
pass # 跳过这些行!
else:
# 否则将这一行添加到新的内容列表中
new_lines.append(line)
return new_lines
# 如果作为主程序运行,则调用 main 函数
if __name__ == "__main__":
main()
.\numpy\doc\preprocess.py
#!/usr/bin/env python3
# 指定解释器
import subprocess
# 引入subprocess模块,用于生成子进程执行外部命令
import os
# 引入os模块,用于提供与操作系统交互的函数
import sys
# 引入sys模块,用于提供Python解释器与Python环境的相关功能
from string import Template
# 从string模块中引入Template类,用于字符串模板化
def main():
# 调用doxy_gen函数,参数为程序的绝对路径
doxy_gen(os.path.abspath(os.path.join('..')))
def doxy_gen(root_path):
"""
Generate Doxygen configuration file.
"""
# 调用doxy_config函数,参数为根路径
confs = doxy_config(root_path)
# 构建文档生成路径
build_path = os.path.join(root_path, "doc", "build", "doxygen")
# 生成文件路径
gen_path = os.path.join(build_path, "Doxyfile")
# 如果生成文件路径不存在,则创建
if not os.path.exists(build_path):
os.makedirs(build_path)
# 以写入模式打开生成文件路径
with open(gen_path, 'w') as fd:
# 写入注释
fd.write("#Please Don't Edit! This config file was autogenerated by ")
# 写入注释
fd.write(f"doxy_gen({root_path}) in doc/preprocess.py.\n")
# 迭代写入配置信息
for c in confs:
fd.write(c)
class DoxyTpl(Template):
delimiter = '@'
def doxy_config(root_path):
"""
Fetch all Doxygen sub-config files and gather it with the main config file.
"""
# 子配置列表
confs = []
# Doxygen源文件路径
dsrc_path = os.path.join(root_path, "doc", "source")
# 子配置信息
sub = dict(ROOT_DIR=root_path)
# 以读取模式打开Doxyfile文件
with open(os.path.join(dsrc_path, "doxyfile")) as fd:
# 实例化模板对象
conf = DoxyTpl(fd.read())
# 格式化子配置
confs.append(conf.substitute(CUR_DIR=dsrc_path, **sub))
# 遍历根路径下的所有文件和目录
for dpath, _, files in os.walk(root_path):
# 如果.doxyfile文件不在文件列表中,则继续循环
if ".doxyfile" not in files:
continue
# 获取子配置文件路径
conf_path = os.path.join(dpath, ".doxyfile")
# 以读取模式打开子配置文件
with open(conf_path) as fd:
# 实例化模板对象
conf = DoxyTpl(fd.read())
# 格式化子配置
confs.append(conf.substitute(CUR_DIR=dpath, **sub))
# 返回所有配置信息
return confs
if __name__ == "__main__":
# 调用main函数
main()
.\numpy\doc\source\conf.py
# 导入必要的标准库和第三方库
import os # 操作系统接口
import re # 正则表达式
import sys # 系统特定的参数和函数
import importlib # 实现动态加载模块和包
from docutils import nodes # 文档处理工具
from docutils.parsers.rst import Directive # reStructuredText 的指令
# Minimum version, enforced by sphinx
# 最低版本要求,由 Sphinx 强制执行
needs_sphinx = '4.3'
# This is a nasty hack to use platform-agnostic names for types in the
# documentation.
# 这是一个不好的 hack,用于在文档中使用与平台无关的类型名称。
# must be kept alive to hold the patched names
# 必须保持存活状态以保存打补丁的名称
_name_cache = {}
def replace_scalar_type_names():
""" Rename numpy types to use the canonical names to make sphinx behave """
""" 重命名 numpy 类型以使用规范名称,使 sphinx 正常工作 """
import ctypes
Py_ssize_t = ctypes.c_int64 if ctypes.sizeof(ctypes.c_void_p) == 8 else ctypes.c_int32
class PyObject(ctypes.Structure):
pass
class PyTypeObject(ctypes.Structure):
pass
PyObject._fields_ = [
('ob_refcnt', Py_ssize_t),
('ob_type', ctypes.POINTER(PyTypeObject)),
]
PyTypeObject._fields_ = [
# varhead
('ob_base', PyObject),
('ob_size', Py_ssize_t),
# declaration
('tp_name', ctypes.c_char_p),
]
# prevent numpy attaching docstrings to the scalar types
# 防止 numpy 将文档字符串附加到标量类型上
assert 'numpy._core._add_newdocs_scalars' not in sys.modules
sys.modules['numpy._core._add_newdocs_scalars'] = object()
import numpy
# change the __name__ of the scalar types
# 更改标量类型的 __name__
for name in [
'byte', 'short', 'intc', 'int_', 'longlong',
'ubyte', 'ushort', 'uintc', 'uint', 'ulonglong',
'half', 'single', 'double', 'longdouble',
'half', 'csingle', 'cdouble', 'clongdouble',
]:
typ = getattr(numpy, name)
c_typ = PyTypeObject.from_address(id(typ))
c_typ.tp_name = _name_cache[typ] = b"numpy." + name.encode('utf8')
# now generate the docstrings as usual
# 现在像往常一样生成文档字符串
del sys.modules['numpy._core._add_newdocs_scalars']
import numpy._core._add_newdocs_scalars
replace_scalar_type_names()
# As of NumPy 1.25, a deprecation of `str`/`bytes` attributes happens.
# For some reasons, the doc build accesses these, so ignore them.
# 从 NumPy 1.25 开始,将会弃用 `str`/`bytes` 属性。
# 由于某些原因,文档生成访问了这些属性,因此忽略它们。
import warnings
warnings.filterwarnings("ignore", "In the future.*NumPy scalar", FutureWarning)
# -----------------------------------------------------------------------------
# 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.
# 在这里添加任何 Sphinx 扩展模块名称,作为字符串。它们可以是随 Sphinx 一起提供的扩展(如 'sphinx.ext.*')或您自己的扩展。
sys.path.insert(0, os.path.abspath('../sphinxext'))
extensions = [
'sphinx.ext.autodoc', # 自动生成 API 文档
'numpydoc', # 支持 NumPy 风格的文档
'sphinx.ext.intersphinx', # 支持链接外部文档
'sphinx.ext.coverage', # 测试覆盖率相关
'sphinx.ext.doctest', # 运行文档中的示例,并验证结果的正确性
'sphinx.ext.autosummary', # 自动生成摘要
'sphinx.ext.graphviz', # 生成图形
'sphinx.ext.ifconfig', # 条件设置配置
'matplotlib.sphinxext.plot_directive', # 绘图指令
'IPython.sphinxext.ipython_console_highlighting', # IPython 控制台高亮
'IPython.sphinxext.ipython_directive', # IPython 指令
'sphinx.ext.mathjax', # 数学公式支持
'sphinx_design', # Sphinx 主题设计扩展
]
skippable_extensions = [
('breathe', 'skip generating C/C++ API from comment blocks.'),
]
for ext, warn in skippable_extensions:
# 检查指定的 Sphinx 扩展是否存在于当前环境中
ext_exist = importlib.util.find_spec(ext) is not None
# 如果找到了指定的 Sphinx 扩展,则将其添加到列表中
if ext_exist:
extensions.append(ext)
# 如果未找到指定的 Sphinx 扩展,则打印警告信息
else:
print(f"Unable to find Sphinx extension '{ext}', {warn}.")
# Add any paths that contain templates here, relative to this directory.
# 添加包含模板的路径列表,相对于当前目录。
templates_path = ['_templates']
# The suffix of source filenames.
# 源文件名的后缀。
source_suffix = '.rst'
# General substitutions.
# 一般的替换项。
project = 'NumPy'
copyright = '2008-2024, NumPy Developers'
# The default replacements for |version| and |release|, also used in various
# other places throughout the built documents.
# 默认的 |version| 和 |release| 替换值,在构建文档中的多处使用。
import numpy
# The short X.Y version (including .devXXXX, rcX, b1 suffixes if present)
# 短版本 X.Y(包括 .devXXXX、rcX、b1 后缀,如果存在的话)
version = re.sub(r'(\d+\.\d+)\.\d+(.*)', r'\1\2', numpy.__version__)
version = re.sub(r'(\.dev\d+).*?$', r'\1', version)
# The full version, including alpha/beta/rc tags.
# 完整版本,包括 alpha/beta/rc 标签。
release = numpy.__version__
print("%s %s" % (version, release))
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
#today = ''
# Else, today_fmt is used as the format for a strftime call.
# 有两种方式替换 |today|:一种是将 today 设置为某个非假值,然后它会被使用;
# 另一种是使用 today_fmt 作为 strftime 调用的格式。
today_fmt = '%B %d, %Y'
# List of documents that shouldn't be included in the build.
# 不应包含在构建中的文档列表。
#unused_docs = []
# The reST default role (used for this markup: `text`) to use for all documents.
# 所有文档使用的 reST 默认角色(用于此标记:`text`)。
default_role = "autolink"
# List of directories, relative to source directories, that shouldn't be searched
# for source files.
# 不应搜索源文件的目录列表,相对于源目录。
exclude_dirs = []
exclude_patterns = []
if sys.version_info[:2] >= (3, 12):
exclude_patterns += ["reference/distutils.rst"]
# If true, '()' will be appended to :func: etc. cross-reference text.
# 如果为 True,则在 :func: 等交叉引用文本后附加 '()'。
add_function_parentheses = False
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
# 如果为 True,则当前模块名将前置于所有描述单元标题之前(例如 .. function::)。
#add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
# 如果为 True,则输出中将显示 sectionauthor 和 moduleauthor 指令。它们默认情况下被忽略。
#show_authors = False
class LegacyDirective(Directive):
"""
Adapted from docutils/parsers/rst/directives/admonitions.py
Uses a default text if the directive does not have contents. If it does,
the default text is concatenated to the contents.
See also the same implementation in SciPy's conf.py.
"""
# 来自 docutils/parsers/rst/directives/admonitions.py 的适应版本
# 如果指令没有内容,则使用默认文本。如果有内容,则将默认文本连接到内容中。
has_content = True
node_class = nodes.admonition
optional_arguments = 1
def run(self):
try:
# 尝试获取第一个参数作为对象名称
obj = self.arguments[0]
except IndexError:
# 没有参数传入时,默认使用文本 "submodule"
obj = "submodule"
# 创建包含说明文本的字符串
text = (f"This {obj} is considered legacy and will no longer receive "
"updates. This could also mean it will be removed in future "
"NumPy versions.")
try:
# 尝试将文本添加到现有内容列表的第一个位置
self.content[0] = text + " " + self.content[0]
except IndexError:
# 如果内容列表为空,则创建新的内容条目
source, lineno = self.state_machine.get_source_and_line(
self.lineno
)
self.content.append(
text,
source=source,
offset=lineno
)
# 将内容列表转换为单个文本字符串
text = '\n'.join(self.content)
# 创建警告提示节点,稍后由 `nested_parse` 填充内容
admonition_node = self.node_class(rawsource=text)
# 设置自定义标题
title_text = "Legacy"
textnodes, _ = self.state.inline_text(title_text, self.lineno)
# 创建标题节点
title = nodes.title(title_text, '', *textnodes)
admonition_node += title
# 设置警告提示节点的 CSS 类
admonition_node['classes'] = ['admonition-legacy']
# 解析指令内容并填充到警告提示节点中
self.state.nested_parse(self.content, self.content_offset,
admonition_node)
# 返回最终的警告提示节点列表
return [admonition_node]
# 为 Sphinx 应用程序设置函数,用于配置各种选项和插件
def setup(app):
# 添加一个配置值,用于 `ifconfig` 指令
app.add_config_value('python_version_major', str(sys.version_info.major), 'env')
# 添加一个词法分析器,将 'NumPyC' 识别为 NumPyLexer 类型
app.add_lexer('NumPyC', NumPyLexer)
# 添加一个自定义指令 'legacy',使用 LegacyDirective 处理
app.add_directive("legacy", LegacyDirective)
# 将 'numpy.char' 的模块别名设定为 numpy.char
# 虽然对象类型是 `module`,但名称是模块的别名,用于使 Sphinx 可以识别这些别名作为真实模块
sys.modules['numpy.char'] = numpy.char
# -----------------------------------------------------------------------------
# HTML 输出配置
# -----------------------------------------------------------------------------
# 设置 HTML 主题
html_theme = 'pydata_sphinx_theme'
# 设置网站图标路径
html_favicon = '_static/favicon/favicon.ico'
# 设置版本切换器,versions.json 存储在文档仓库中
if os.environ.get('CIRCLE_JOB', False) and \
os.environ.get('CIRCLE_BRANCH', '') != 'main':
# 对于 PR,将版本名称设置为其引用
switcher_version = os.environ['CIRCLE_BRANCH']
elif ".dev" in version:
switcher_version = "devdocs"
else:
switcher_version = f"{version}"
# 设置 HTML 主题选项
html_theme_options = {
"logo": {
"image_light": "_static/numpylogo.svg",
"image_dark": "_static/numpylogo_dark.svg",
},
"github_url": "https://github.com/numpy/numpy",
"collapse_navigation": True,
"external_links": [
{"name": "Learn", "url": "https://numpy.org/numpy-tutorials/"},
{"name": "NEPs", "url": "https://numpy.org/neps"},
],
"header_links_before_dropdown": 6,
# 添加亮色/暗色模式和文档版本切换器
"navbar_end": [
"search-button",
"theme-switcher",
"version-switcher",
"navbar-icon-links"
],
"navbar_persistent": [],
"switcher": {
"version_match": switcher_version,
"json_url": "https://numpy.org/doc/_static/versions.json",
},
"show_version_warning_banner": True,
}
# 设置 HTML 页面标题
html_title = "%s v%s Manual" % (project, version)
# 设置静态文件路径
html_static_path = ['_static']
# 设置最后更新时间格式
html_last_updated_fmt = '%b %d, %Y'
# 设置 HTML 使用的 CSS 文件
html_css_files = ["numpy.css"]
# 设置 HTML 上下文
html_context = {"default_mode": "light"}
# 禁用模块索引
html_use_modindex = True
# 不复制源文件
html_copy_source = False
# 禁用文档索引
html_domain_indices = False
# 设置 HTML 文件后缀
html_file_suffix = '.html'
# 设置 HTML 帮助文档的基本名称
htmlhelp_basename = 'numpy'
# 如果扩展列表中包含 'sphinx.ext.pngmath'
if 'sphinx.ext.pngmath' in extensions:
# 启用 PNG 数学公式预览
pngmath_use_preview = True
# 设置 dvipng 参数
pngmath_dvipng_args = ['-gamma', '1.5', '-D', '96', '-bg', 'Transparent']
# -----------------------------------------------------------------------------
# LaTeX 输出配置
# -----------------------------------------------------------------------------
# 设置纸张大小('letter' 或 'a4')
#latex_paper_size = 'letter'
# 设置字体大小('10pt', '11pt' 或 '12pt')
#latex_font_size = '10pt'
# 设置 LaTeX 引擎为 XeLaTeX,以支持更好的 Unicode 字符处理能力
latex_engine = 'xelatex'
# 将文档树分组为 LaTeX 文件的列表。每个元组包含:
# (源文件的起始点,目标文件名,标题,作者,文档类别[如何指南/手册])
_stdauthor = 'Written by the NumPy community'
latex_documents = [
('reference/index', 'numpy-ref.tex', 'NumPy Reference',
_stdauthor, 'manual'),
('user/index', 'numpy-user.tex', 'NumPy User Guide',
_stdauthor, 'manual'),
]
# 标题页顶部放置的图像文件名(相对于当前目录)
#latex_logo = None
# 对于“手册”文档,如果为 True,则顶级标题为部分而不是章节
#latex_use_parts = False
latex_elements = {
}
# LaTeX 导言区的附加内容
latex_elements['preamble'] = r'''
\newfontfamily\FontForChinese{FandolSong-Regular}[Extension=.otf]
\catcode`琴\active\protected\def琴{{\FontForChinese\string琴}}
\catcode`春\active\protected\def春{{\FontForChinese\string春}}
\catcode`鈴\active\protected\def鈴{{\FontForChinese\string鈴}}
\catcode`猫\active\protected\def猫{{\FontForChinese\string猫}}
\catcode`傅\active\protected\def傅{{\FontForChinese\string傅}}
\catcode`立\active\protected\def立{{\FontForChinese\string立}}
\catcode`业\active\protected\def业{{\FontForChinese\string业}}
\catcode`(\active\protected\def({{\FontForChinese\string(}}
\catcode`)\active\protected\def){{\FontForChinese\string)}}
% 在参数部分的标题后面放置一个换行。这在 Sphinx 5.0.0+ 中是默认行为,因此不再需要旧的 hack。
% 不幸的是,sphinx.sty 5.0.0 没有更新其版本日期,因此我们检查 sphinxpackagefootnote.sty(自 Sphinx 4.0.0 起存在)。
\makeatletter
\@ifpackagelater{sphinxpackagefootnote}{2022/02/12}
{}% Sphinx >= 5.0.0,无需操作
{%
\usepackage{expdlist}
\let\latexdescription=\description
\def\description{\latexdescription{}{} \breaklabel}
% 修复 expdlist 旧 LaTeX 包的问题:
% 1) 移除额外的空格
\usepackage{etoolbox}
\patchcmd\@item{{\@breaklabel} }{{\@breaklabel}}{}{}
% 2) 修复 expdlist 在长标签后换行的 bug
\def\breaklabel{%
\def\@breaklabel{%
\leavevmode\par
% 现在是一个 hack,因为 Sphinx 在术语节点之后插入 \leavevmode
\def\leavevmode{\def\leavevmode{\unhbox\voidb@x}}%
}%
}
}% Sphinx < 5.0.0(假设 >= 4.0.0)
\makeatother
% 使示例等部分的标题更小更紧凑
\makeatletter
\titleformat{\paragraph}{\normalsize\py@HeaderFamily}%
{\py@TitleColor}{0em}{\py@TitleColor}{\py@NormalColor}
\titlespacing*{\paragraph}{0pt}{1ex}{0pt}
\makeatother
% 修复页眉页脚
\renewcommand{\chaptermark}[1]{\markboth{\MakeUppercase{\thechapter.\ #1}}{}}
\renewcommand{\sectionmark}[1]{\markright{\MakeUppercase{\thesection.\ #1}}}
'''
# 将文档附加为所有手册的附录
#latex_appendices = []
# 如果为 False,则不生成模块索引
latex_use_modindex = False
# -----------------------------------------------------------------------------
# Texinfo output
# -----------------------------------------------------------------------------
# 定义生成 Texinfo 格式文档的配置参数
texinfo_documents = [
("index", 'numpy', 'NumPy Documentation', _stdauthor, 'NumPy',
"NumPy: array processing for numbers, strings, records, and objects.",
'Programming',
1),
]
# -----------------------------------------------------------------------------
# Intersphinx configuration
# -----------------------------------------------------------------------------
# 定义用于 intersphinx 的映射配置,指定外部文档的链接
intersphinx_mapping = {
'neps': ('https://numpy.org/neps', None),
'python': ('https://docs.python.org/3', None),
'scipy': ('https://docs.scipy.org/doc/scipy', None),
'matplotlib': ('https://matplotlib.org/stable', None),
'imageio': ('https://imageio.readthedocs.io/en/stable', None),
'skimage': ('https://scikit-image.org/docs/stable', None),
'pandas': ('https://pandas.pydata.org/pandas-docs/stable', None),
'scipy-lecture-notes': ('https://scipy-lectures.org', None),
'pytest': ('https://docs.pytest.org/en/stable', None),
'numpy-tutorials': ('https://numpy.org/numpy-tutorials', None),
'numpydoc': ('https://numpydoc.readthedocs.io/en/latest', None),
'dlpack': ('https://dmlc.github.io/dlpack/latest', None)
}
# -----------------------------------------------------------------------------
# NumPy extensions
# -----------------------------------------------------------------------------
# 定义 NumPy 扩展功能的配置选项
# 指定进行虚拟导入的 XML 文件
phantom_import_file = 'dump.xml'
# 设置 numpydoc 是否生成示例部分的图表
numpydoc_use_plots = True
# -----------------------------------------------------------------------------
# Autosummary
# -----------------------------------------------------------------------------
# 自动生成摘要页面的配置开关
autosummary_generate = True
# -----------------------------------------------------------------------------
# Coverage checker
# -----------------------------------------------------------------------------
# 覆盖率检查工具的配置选项
# 忽略的模块列表
coverage_ignore_modules = r"""
""".split()
# 忽略的函数列表的正则表达式
coverage_ignore_functions = r"""
test($|_) (some|all)true bitwise_not cumproduct pkgload
generic\.
""".split()
# 忽略的类列表
coverage_ignore_classes = r"""
""".split()
# C 语言覆盖检查路径
coverage_c_path = []
# C 语言覆盖检查正则表达式
coverage_c_regexes = {}
# 忽略的 C 语言项
coverage_ignore_c_items = {}
# -----------------------------------------------------------------------------
# Plots
# -----------------------------------------------------------------------------
# 绘图配置选项
# 绘图前的预处理代码
plot_pre_code = """
import numpy as np
np.random.seed(0)
"""
# 是否包含绘图源代码
plot_include_source = True
# 绘图格式及其分辨率设置
plot_formats = [('png', 100), 'pdf']
# 绘图参数配置
import math
phi = (math.sqrt(5) + 1)/2
plot_rcparams = {
'font.size': 8,
'axes.titlesize': 8,
'axes.labelsize': 8,
'xtick.labelsize': 8,
'ytick.labelsize': 8,
'legend.fontsize': 8,
'figure.figsize': (3*phi, 3),
'figure.subplot.bottom': 0.2,
'figure.subplot.left': 0.2,
'figure.subplot.right': 0.9,
}
# 设置图形的顶部子图位置为0.85
'figure.subplot.top': 0.85,
# 设置子图之间的水平间距为0.4
'figure.subplot.wspace': 0.4,
# 禁用使用LaTeX渲染文本
'text.usetex': False,
}
# -----------------------------------------------------------------------------
# Source code links
# -----------------------------------------------------------------------------
import inspect # 导入 inspect 模块,用于检查和分析 Python 对象
from os.path import relpath, dirname # 从 os.path 模块中导入 relpath 和 dirname 函数
# 循环遍历包含字符串列表,尝试导入指定的模块,如果成功则将模块名添加到 extensions 列表中
for name in ['sphinx.ext.linkcode', 'numpydoc.linkcode']:
try:
__import__(name)
extensions.append(name) # 将成功导入的模块名添加到 extensions 列表
break # 如果成功导入模块,则结束循环
except ImportError:
pass
else:
print("NOTE: linkcode extension not found -- no links to source generated") # 如果未找到任何 linkcode 扩展模块,则打印提示信息
# 定义一个函数,根据输入的对象返回相应的 C 源文件路径
def _get_c_source_file(obj):
if issubclass(obj, numpy.generic):
return r"_core/src/multiarray/scalartypes.c.src" # 如果输入对象是 numpy.generic 的子类,返回对应的 C 源文件路径
elif obj is numpy.ndarray:
return r"_core/src/multiarray/arrayobject.c" # 如果输入对象是 numpy.ndarray 类型,则返回对应的 C 源文件路径
else:
# 如果输入对象不符合以上条件,返回 None,并提醒需要找到更好的生成方式
return None
def linkcode_resolve(domain, info):
"""
Determine the URL corresponding to Python object
"""
if domain != 'py':
return None # 如果域不是 'py',返回 None
modname = info['module'] # 获取模块名
fullname = info['fullname'] # 获取完整的对象名(包括模块名和对象名)
submod = sys.modules.get(modname) # 获取模块对象
if submod is None:
return None # 如果未找到模块对象,返回 None
obj = submod
for part in fullname.split('.'):
try:
obj = getattr(obj, part) # 逐级获取对象的属性
except Exception:
return None # 如果获取属性时发生异常,返回 None
# 尝试去掉装饰器,这可能是 inspect.getsourcefile 的一个问题
try:
unwrap = inspect.unwrap
except AttributeError:
pass
else:
obj = unwrap(obj)
fn = None # 初始化文件名变量为 None
lineno = None # 初始化行号变量为 None
# 尝试链接 C 扩展类型
if isinstance(obj, type) and obj.__module__ == 'numpy':
fn = _get_c_source_file(obj) # 获取对应的 C 源文件路径
if fn is None:
try:
fn = inspect.getsourcefile(obj) # 尝试获取对象的源文件路径
except Exception:
fn = None
if not fn:
return None # 如果未获取到源文件路径,返回 None
# 忽略重新导出的对象,因为它们的源文件不在 numpy 仓库内
module = inspect.getmodule(obj)
if module is not None and not module.__name__.startswith("numpy"):
return None # 如果模块不是以 'numpy' 开头,返回 None
try:
source, lineno = inspect.getsourcelines(obj) # 获取对象的源码和起始行号
except Exception:
lineno = None
fn = relpath(fn, start=dirname(numpy.__file__)) # 获取相对于 numpy 包的路径
if lineno:
linespec = "#L%d-L%d" % (lineno, lineno + len(source) - 1) # 构造行号范围字符串
else:
linespec = ""
if 'dev' in numpy.__version__:
return "https://github.com/numpy/numpy/blob/main/numpy/%s%s" % (
fn, linespec) # 返回 GitHub 上对应源码的 URL
else:
return "https://github.com/numpy/numpy/blob/v%s/numpy/%s%s" % (
numpy.__version__, fn, linespec) # 返回 GitHub 上对应版本源码的 URL
from pygments.lexers import CLexer # 从 pygments 库导入 CLexer 类
from pygments.lexer import inherit, bygroups # 从 pygments 库导入 inherit 和 bygroups 函数
from pygments.token import Comment # 从 pygments 库导入 Comment 类
class NumPyLexer(CLexer):
name = 'NUMPYLEXER' # 定义自定义的词法分析器名称为 'NUMPYLEXER'
tokens = {
'statements': [
(r'@[a-zA-Z_]*@', Comment.Preproc, 'macro'), # 定义预处理指令的词法规则
inherit, # 继承默认的词法规则
],
}
# -----------------------------------------------------------------------------
# Breathe & Doxygen
# -----------------------------------------------------------------------------
# 定义一个字典,用于指定 Breathe 文档生成工具的项目配置,
# 将 "numpy" 项目的 XML 文档路径设置为相对路径 "../build/doxygen/xml"
breathe_projects = dict(numpy=os.path.join("..", "build", "doxygen", "xml"))
# 设置默认的 Breathe 项目为 "numpy"
breathe_default_project = "numpy"
# 设置默认的成员过滤器,包括 "members", "undoc-members", "protected-members"
breathe_default_members = ("members", "undoc-members", "protected-members")
# See https://github.com/breathe-doc/breathe/issues/696
# 忽略特定的 Doxygen 错误或警告,这里列出了需要忽略的标识符列表
nitpick_ignore = [
('c:identifier', 'FILE'),
('c:identifier', 'size_t'),
('c:identifier', 'PyHeapTypeObject'),
]
.\numpy\doc\source\dev\examples\doxy_class.hpp
/**
* Template to represent limbo numbers.
*
* Specializations for integer types that are part of nowhere.
* It doesn't support with any real types.
*
* @param Tp Type of the integer. Required to be an integer type.
* @param N Number of elements.
*/
template<typename Tp, std::size_t N>
class DoxyLimbo {
public:
/// Default constructor. Initialize nothing.
DoxyLimbo();
/// Set Default behavior for copy the limbo.
DoxyLimbo(const DoxyLimbo<Tp, N> &l);
/// Returns the raw data for the limbo.
const Tp *data();
protected:
Tp p_data[N]; ///< Example for inline comment.
};
.\numpy\doc\source\dev\examples\doxy_func.h
/**
* This a simple brief.
*
* And the details goes here.
* Multi lines are welcome.
*
* @param num leave a comment for parameter num.
* Specify the purpose or expected value range if applicable.
* @param str leave a comment for the second parameter.
* Describe its significance or expected format if applicable.
* @return leave a comment for the returned value.
* Clarify what the function returns, its type, and possible values.
*/
int doxy_javadoc_example(int num, const char *str);
.\numpy\doc\source\dev\examples\doxy_rst.h
/**
* A comment block contains reST markup.
* @rst
* .. note::
*
* Thanks to Breathe_, we were able to bring it to Doxygen_
*
* Some code example::
*
* int example(int x) {
* return x * 2;
* }
* @endrst
*/
void doxy_reST_example(void);
.\numpy\doc\source\f2py\code\setup_example.py
# 从 numpy.distutils.core 模块导入 Extension 类
from numpy.distutils.core import Extension
# 创建名为 ext1 的 Extension 对象,指定名称为 'scalar',源文件为 'scalar.f'
ext1 = Extension(name = 'scalar',
sources = ['scalar.f'])
# 创建名为 ext2 的 Extension 对象,指定名称为 'fib2',源文件为 'fib2.pyf' 和 'fib1.f'
ext2 = Extension(name = 'fib2',
sources = ['fib2.pyf', 'fib1.f'])
# 如果当前脚本被直接执行
if __name__ == "__main__":
# 从 numpy.distutils.core 模块导入 setup 函数
from numpy.distutils.core import setup
# 调用 setup 函数,设置项目名称为 'f2py_example',描述为 "F2PY Users Guide examples"
# 作者为 "Pearu Peterson",作者邮箱为 "pearu@cens.ioc.ee",扩展模块为 [ext1, ext2]
setup(name = 'f2py_example',
description = "F2PY Users Guide examples",
author = "Pearu Peterson",
author_email = "pearu@cens.ioc.ee",
ext_modules = [ext1, ext2]
)
# End of setup_example.py
.\numpy\doc\source\f2py\code\setup_skbuild.py
# 导入 skbuild 库中的 setup 函数,用于配置和安装 Python 包
from skbuild import setup
# 调用 setup 函数,配置和安装一个 Python 包
setup(
# 包的名称为 "fibby"
name="fibby",
# 包的版本号为 "0.0.1"
version="0.0.1",
# 包的描述信息为 "a minimal example package (fortran version)"
description="a minimal example package (fortran version)",
# 包的许可证为 MIT 许可证
license="MIT",
# 指定要包含的包列表,这里包含名为 'fibby' 的包
packages=['fibby'],
# 指定 Python 的最低版本要求为 3.7 及以上
python_requires=">=3.7",
)
.\numpy\doc\source\reference\random\examples\cython\extending.pyx
# extending.pyx 文件的路径
-------------
# 包含外部的文件 extending.pyx,路径相对当前文件的位置
.. include:: ../../../../../../numpy/random/examples/extending.pyx
.\numpy\doc\source\reference\random\performance.py
from timeit import repeat # 导入计时器函数
import pandas as pd # 导入 pandas 库
import numpy as np # 导入 numpy 库
from numpy.random import MT19937, PCG64, PCG64DXSM, Philox, SFC64 # 从 numpy.random 导入多个随机数生成器类
PRNGS = [MT19937, PCG64, PCG64DXSM, Philox, SFC64] # 定义随机数生成器类列表
funcs = {} # 初始化空字典 funcs 用于存储函数调用字符串
integers = 'integers(0, 2**{bits},size=1000000, dtype="uint{bits}")' # 定义整数生成函数模板
funcs['32-bit Unsigned Ints'] = integers.format(bits=32) # 添加生成 32 位无符号整数的函数调用字符串
funcs['64-bit Unsigned Ints'] = integers.format(bits=64) # 添加生成 64 位无符号整数的函数调用字符串
funcs['Uniforms'] = 'random(size=1000000)' # 添加生成均匀分布随机数的函数调用字符串
funcs['Normals'] = 'standard_normal(size=1000000)' # 添加生成标准正态分布随机数的函数调用字符串
funcs['Exponentials'] = 'standard_exponential(size=1000000)' # 添加生成指数分布随机数的函数调用字符串
funcs['Gammas'] = 'standard_gamma(3.0,size=1000000)' # 添加生成 Gamma 分布随机数的函数调用字符串
funcs['Binomials'] = 'binomial(9, .1, size=1000000)' # 添加生成二项分布随机数的函数调用字符串
funcs['Laplaces'] = 'laplace(size=1000000)' # 添加生成拉普拉斯分布随机数的函数调用字符串
funcs['Poissons'] = 'poisson(3.0, size=1000000)' # 添加生成泊松分布随机数的函数调用字符串
setup = """
from numpy.random import {prng}, Generator
rg = Generator({prng}())
""" # 定义设置字符串模板,用于设置随机数生成器
test = "rg.{func}" # 定义测试字符串模板,用于测试随机数生成器性能
table = {} # 初始化空字典 table 用于存储测试结果表格
for prng in PRNGS: # 遍历每个随机数生成器类
print(prng) # 打印当前随机数生成器类的名称
col = {} # 初始化空字典 col 用于存储每种函数调用的最小执行时间
for key in funcs: # 遍历每种函数调用字符串
t = repeat(test.format(func=funcs[key]), # 测试当前函数调用的执行时间
setup.format(prng=prng().__class__.__name__), # 设置随机数生成器
number=1, repeat=3) # 设置测试参数
col[key] = 1000 * min(t) # 将最小执行时间(毫秒)添加到 col 字典中
col = pd.Series(col) # 将 col 字典转换为 pandas Series 对象
table[prng().__class__.__name__] = col # 将当前随机数生成器类的测试结果添加到 table 字典中
npfuncs = {} # 初始化空字典 npfuncs 用于存储 numpy 函数调用字符串
npfuncs.update(funcs) # 将 funcs 字典中的内容复制到 npfuncs 字典中
npfuncs['32-bit Unsigned Ints'] = 'randint(2**32,dtype="uint32",size=1000000)' # 替换生成 32 位无符号整数的函数调用字符串
npfuncs['64-bit Unsigned Ints'] = 'randint(2**64,dtype="uint64",size=1000000)' # 替换生成 64 位无符号整数的函数调用字符串
setup = """
from numpy.random import RandomState
rg = RandomState()
""" # 更新设置字符串模板,用于设置随机数生成器
col = {} # 初始化空字典 col 用于存储每种函数调用的最小执行时间
for key in npfuncs: # 遍历每种函数调用字符串
t = repeat(test.format(func=npfuncs[key]), # 测试当前函数调用的执行时间
setup.format(prng=prng().__class__.__name__), # 设置随机数生成器
number=1, repeat=3) # 设置测试参数
col[key] = 1000 * min(t) # 将最小执行时间(毫秒)添加到 col 字典中
table['RandomState'] = pd.Series(col) # 将 RandomState 类的测试结果添加到 table 字典中
columns = ['MT19937', 'PCG64', 'PCG64DXSM', 'Philox', 'SFC64', 'RandomState'] # 定义表格的列名列表
table = pd.DataFrame(table) # 将 table 字典转换为 pandas DataFrame 对象
order = np.log(table).mean().sort_values().index # 对表格进行排序,按照均值对数值排序
table = table.T # 转置表格
table = table.reindex(columns) # 根据指定列名重新索引表格
table = table.T # 再次转置表格
table = table.reindex([k for k in funcs], axis=0) # 根据函数调用字符串的键重新索引表格
print(table.to_csv(float_format='%0.1f')) # 将表格输出为 CSV 格式,保留一位小数
rel = table.loc[:, ['RandomState']].values @ np.ones( # 计算相对性能比率
(1, table.shape[1])) / table # 计算比率
rel.pop('RandomState') # 删除 RandomState 列
rel = rel.T # 转置比率表格
rel['Overall'] = np.exp(np.log(rel).mean(1)) # 计算平均对数值,再取指数,作为 Overall 列
rel *= 100 # 将比率转换为百分比
rel = np.round(rel) # 四舍五入到整数
rel = rel.T # 再次转置比率表格
print(rel.to_csv(float_format='%0d')) # 将比率表格输出为 CSV 格式,保留整数
# Cross-platform table
rows = ['32-bit Unsigned Ints','64-bit Unsigned Ints','Uniforms','Normals','Exponentials'] # 定义跨平台表格的行名列表
xplat = rel.reindex(rows, axis=0) # 根据指定行名重新索引比率表格
xplat = 100 * (xplat / xplat.MT19937.values[:,None]) # 计算相对于 MT19937 的百分比
overall = np.exp(np.log(xplat).mean(0)) # 计算平均对数值,再取指数,作为 Overall 行
xplat = xplat.T.copy() # 转置并复制比率表格
xplat['Overall']=overall # 添加 Overall 行
print(xplat.T.round(1)) # 将跨平台表格输出为 CSV 格式,保留一位小数
.\numpy\doc\source\reference\simd\gen_features.py
"""
Generate CPU features tables from CCompilerOpt
"""
# 导入必要的模块和类
from os import sys, path
from numpy.distutils.ccompiler_opt import CCompilerOpt
class FakeCCompilerOpt(CCompilerOpt):
# 禁用缓存,因为不需要
conf_nocache = True
def __init__(self, arch, cc, *args, **kwargs):
# 初始化虚拟编译器信息
self.fake_info = (arch, cc, '')
# 调用父类的初始化方法
CCompilerOpt.__init__(self, None, **kwargs)
def dist_compile(self, sources, flags, **kwargs):
# 编译源文件,简化返回所有源文件
return sources
def dist_info(self):
# 返回虚拟编译器信息
return self.fake_info
@staticmethod
def dist_log(*args, stderr=False):
# 静态方法,用于记录日志,这里是避免打印
pass
def feature_test(self, name, force_flags=None, macros=[]):
# 进行特性测试,假设总是返回 True,用于加速
return True
class Features:
def __init__(self, arch, cc):
# 初始化特性对象,使用自定义的虚拟编译器选项
self.copt = FakeCCompilerOpt(arch, cc, cpu_baseline="max")
def names(self):
# 返回CPU基线名称列表
return self.copt.cpu_baseline_names()
def serialize(self, features_names):
# 序列化特性信息
result = []
for f in self.copt.feature_sorted(features_names):
gather = self.copt.feature_supported.get(f, {}).get("group", [])
implies = self.copt.feature_sorted(self.copt.feature_implies(f))
result.append((f, implies, gather))
return result
def table(self, **kwargs):
# 生成特性表格
return self.gen_table(self.serialize(self.names()), **kwargs)
def table_diff(self, vs, **kwargs):
# 比较两个特性对象之间的差异
fnames = set(self.names())
fnames_vs = set(vs.names())
common = fnames.intersection(fnames_vs)
extra = fnames.difference(fnames_vs)
notavl = fnames_vs.difference(fnames)
iextra = {}
inotavl = {}
idiff = set()
for f in common:
implies = self.copt.feature_implies(f)
implies_vs = vs.copt.feature_implies(f)
e = implies.difference(implies_vs)
i = implies_vs.difference(implies)
if not i and not e:
continue
if e:
iextra[f] = e
if i:
inotavl[f] = e
idiff.add(f)
def fbold(f):
# 根据特性是否在extra或notavl集合中返回不同的格式
if f in extra:
return f':enabled:`{f}`'
if f in notavl:
return f':disabled:`{f}`'
return f
def fbold_implies(f, i):
# 根据特性是否在iextra或inotavl集合中返回不同的格式
if i in iextra.get(f, {}):
return f':enabled:`{i}`'
if f in notavl or i in inotavl.get(f, {}):
return f':disabled:`{i}`'
return i
# 将所有差异特性序列化并生成特性表格
diff_all = self.serialize(idiff.union(extra))
diff_all += vs.serialize(notavl)
content = self.gen_table(
diff_all, fstyle=fbold, fstyle_implies=fbold_implies, **kwargs
)
return content
# 生成一个表格的函数,接受多个参数,其中 serialized_features 是序列化特征的列表,
# fstyle 是一个函数,默认为 lambda 表达式,用于格式化特征名字
# fstyle_implies 也是一个函数,默认为 lambda 表达式,用于格式化特征暗示
# **kwargs 是额外的关键字参数
def gen_table(self, serialized_features, fstyle=None, fstyle_implies=None,
**kwargs):
# 如果 fstyle 没有提供,使用默认的 lambda 函数格式化特征名字
if fstyle is None:
fstyle = lambda ft: f'``{ft}``'
# 如果 fstyle_implies 没有提供,使用默认的 lambda 函数格式化特征暗示
if fstyle_implies is None:
fstyle_implies = lambda origin, ft: fstyle(ft)
# 初始化空列表 rows 用于存储表格的每一行
rows = []
# 初始化标志 have_gather,用于标记是否存在 gather 类型的特征
have_gather = False
# 遍历 serialized_features 中的每个元素 (f, implies, gather)
for f, implies, gather in serialized_features:
# 如果 gather 为真值(非空),则设置 have_gather 为 True
if gather:
have_gather = True
# 使用 fstyle 函数格式化特征名字 f
name = fstyle(f)
# 使用 fstyle_implies 函数格式化 implies 列表中的每个元素
implies = ' '.join([fstyle_implies(f, i) for i in implies])
# 使用 fstyle_implies 函数格式化 gather 列表中的每个元素
gather = ' '.join([fstyle_implies(f, i) for i in gather])
# 将格式化后的 (name, implies, gather) 添加到 rows 中
rows.append((name, implies, gather))
# 如果 rows 列表为空,则返回空字符串
if not rows:
return ''
# 初始化字段列表 fields
fields = ["Name", "Implies", "Gathers"]
# 如果没有 gather 类型的特征,删除 fields 中的最后一个元素
if not have_gather:
del fields[2]
# 更新 rows,只保留 name 和 implies 两列
rows = [(name, implies) for name, implies, _ in rows]
# 调用 gen_rst_table 方法生成并返回一个 reStructuredText 格式的表格
return self.gen_rst_table(fields, rows, **kwargs)
# 生成 reStructuredText 格式的表格,接受字段名和行数据
def gen_rst_table(self, field_names, rows, tab_size=4):
# 断言条件:如果 rows 为空或者 field_names 的长度等于 rows 的第一行的长度
assert(not rows or len(field_names) == len(rows[0]))
# 在 rows 中添加 field_names 作为表格的首行
rows.append(field_names)
# 计算字段的长度列表
fld_len = len(field_names)
cls_len = [max(len(c[i]) for c in rows) for i in range(fld_len)]
# 根据字段长度列表生成表格的边框
cformat = ' '.join('{:<%d}' % i for i in cls_len)
border = cformat.format(*['='*i for i in cls_len])
# 对每一行数据进行格式化
rows = [cformat.format(*row) for row in rows]
# 添加表格的头部和底部边框
rows = [border, cformat.format(*field_names), border] + rows
# 添加表格的底部边框
rows += [border]
# 在每一行数据前添加指定大小的左边距
rows = [(' ' * tab_size) + r for r in rows]
# 返回格式化后的表格内容,使用换行符连接每一行
return '\n'.join(rows)
# 定义一个函数,生成包含标题和内容的文本段落,内容用表格格式化
def wrapper_section(title, content, tab_size=4):
tab = ' '*tab_size
# 如果内容不为空,则生成带标题的文本段落
if content:
return (
f"{title}\n{'~'*len(title)}" # 标题及其下方的波浪线
f"\n.. table::\n{tab}:align: left\n\n" # 开始定义表格
f"{content}\n\n" # 添加表格内容
)
return '' # 内容为空时返回空字符串
# 定义一个函数,生成包含标题和表格的标签页
def wrapper_tab(title, table, tab_size=4):
tab = ' '*tab_size
# 如果表格不为空,则生成包含标题和表格的标签页
if table:
('\n' + tab).join((
'.. tab:: ' + title, # 标签页标题
tab + '.. table::', # 定义表格
tab + 'align: left', # 设置表格对齐方式
table + '\n\n' # 添加表格内容
))
return '' # 表格为空时返回空字符串
# 主程序入口
if __name__ == '__main__':
# 美化后的架构名称映射表
pretty_names = {
"PPC64": "IBM/POWER big-endian",
"PPC64LE": "IBM/POWER little-endian",
"S390X": "IBM/ZSYSTEM(S390X)",
"ARMHF": "ARMv7/A32",
"AARCH64": "ARMv8/A64",
"ICC": "Intel Compiler",
# "ICCW": "Intel Compiler msvc-like",
"MSVC": "Microsoft Visual C/C++"
}
# 生成路径:当前脚本所在目录下的generated_tables文件夹
gen_path = path.join(
path.dirname(path.realpath(__file__)), "generated_tables"
)
# 打开并写入cpu_features.inc文件
with open(path.join(gen_path, 'cpu_features.inc'), 'w') as fd:
fd.write(f'.. generated via {__file__}\n\n') # 写入生成信息
# 遍历架构列表生成表格段落
for arch in (
("x86", "PPC64", "PPC64LE", "ARMHF", "AARCH64", "S390X")
):
title = "On " + pretty_names.get(arch, arch) # 获取美化后的架构名称
table = Features(arch, 'gcc').table() # 调用Features类生成表格内容
fd.write(wrapper_section(title, table)) # 调用wrapper_section生成段落并写入文件
# 打开并写入compilers-diff.inc文件
with open(path.join(gen_path, 'compilers-diff.inc'), 'w') as fd:
fd.write(f'.. generated via {__file__}\n\n') # 写入生成信息
# 遍历架构和编译器对生成表格段落
for arch, cc_names in (
("x86", ("clang", "ICC", "MSVC")),
("PPC64", ("clang",)),
("PPC64LE", ("clang",)),
("ARMHF", ("clang",)),
("AARCH64", ("clang",)),
("S390X", ("clang",))
):
arch_pname = pretty_names.get(arch, arch) # 获取美化后的架构名称
# 遍历编译器列表生成表格段落
for cc in cc_names:
title = f"On {arch_pname}::{pretty_names.get(cc, cc)}" # 构造标题
# 调用Features类生成表格差异内容
table = Features(arch, cc).table_diff(Features(arch, "gcc"))
fd.write(wrapper_section(title, table)) # 调用wrapper_section生成段落并写入文件
.\numpy\doc\source\user\conftest.py
# 从 numpy 的 conftest 模块导入 dt_config 对象,用于 doctesting 配置
from numpy.conftest import dt_config # noqa: F401
# 导入的 dt_config 对象未直接使用,但通过 noqa: F401 标记避免未使用的警告
# 如果需要设置断点调试,可以取消注释下一行代码
# breakpoint()
.\numpy\doc\source\user\plots\matplotlib1.py
# 导入 matplotlib.pyplot 模块,并简写为 plt
import matplotlib.pyplot as plt
# 导入 numpy 模块,并简写为 np
import numpy as np
# 创建一个包含指定数据的 NumPy 数组
a = np.array([2, 1, 5, 7, 4, 6, 8, 14, 10, 9, 18, 20, 22])
# 使用 matplotlib.pyplot 的 plot 函数绘制 a 数组的折线图
plt.plot(a)
# 显示绘制的图形
plt.show()
.\numpy\doc\source\user\plots\matplotlib2.py
import matplotlib.pyplot as plt # 导入matplotlib的绘图模块,命名为plt
import numpy as np # 导入numpy数值计算库,命名为np
x = np.linspace(0, 5, 20) # 在0到5之间生成20个等间距的数值,作为x轴数据
y = np.linspace(0, 10, 20) # 在0到10之间生成20个等间距的数值,作为y轴数据
plt.plot(x, y, 'purple') # 绘制以(x, y)为坐标的紫色线条,用于展示连接的数据点
plt.plot(x, y, 'o') # 绘制以(x, y)为坐标的散点,用圆圈表示每个数据点
plt.show() # 显示图形,展示绘制的图像