NumPy-源码解析-十一-

81 阅读1小时+

NumPy 源码解析(十一)

.\numpy\numpy\f2py\tests\test_isoc.py

# 从当前目录导入util模块
from . import util
# 导入numpy库,并重命名为np
import numpy as np
# 导入pytest库
import pytest
# 从numpy.testing模块导入assert_allclose函数
from numpy.testing import assert_allclose

# 定义一个测试类TestISOC,继承自util.F2PyTest
class TestISOC(util.F2PyTest):
    # 定义sources属性,包含一个源文件路径的列表
    sources = [
        util.getpath("tests", "src", "isocintrin", "isoCtests.f90"),
    ]

    # 标记为gh-24553的测试方法,用于测试c_double函数
    @pytest.mark.slow
    def test_c_double(self):
        # 调用self.module.coddity.c_add方法,计算1加2的结果
        out = self.module.coddity.c_add(1, 2)
        # 预期输出为3
        exp_out = 3
        # 断言计算结果与预期输出相等
        assert out == exp_out

    # 标记为gh-9693的测试方法,用于测试bindc_function函数
    def test_bindc_function(self):
        # 调用self.module.coddity.wat方法,计算1和20的结果
        out = self.module.coddity.wat(1, 20)
        # 预期输出为8
        exp_out = 8
        # 断言计算结果与预期输出相等
        assert out == exp_out

    # 标记为gh-25207的测试方法,用于测试bindc_kinds函数
    def test_bindc_kinds(self):
        # 调用self.module.coddity.c_add_int64方法,计算1和20的结果
        out = self.module.coddity.c_add_int64(1, 20)
        # 预期输出为21
        exp_out = 21
        # 断言计算结果与预期输出相等
        assert out == exp_out

    # 标记为gh-25207的测试方法,用于测试bindc_add_arr函数
    def test_bindc_add_arr(self):
        # 创建一个包含1, 2, 3的numpy数组a
        a = np.array([1,2,3])
        # 创建一个包含1, 2, 3的numpy数组b
        b = np.array([1,2,3])
        # 调用self.module.coddity.add_arr方法,将数组a和b相加
        out = self.module.coddity.add_arr(a, b)
        # 预期输出为a的每个元素乘以2
        exp_out = a * 2
        # 使用assert_allclose函数断言计算结果与预期输出在允许误差范围内相等
        assert_allclose(out, exp_out)


# 定义测试函数test_process_f2cmap_dict
def test_process_f2cmap_dict():
    # 从numpy.f2py.auxfuncs模块导入process_f2cmap_dict函数
    from numpy.f2py.auxfuncs import process_f2cmap_dict

    # 定义f2cmap_all字典,包含一个键为"integer",值为{"8": "rubbish_type"}的字典
    f2cmap_all = {"integer": {"8": "rubbish_type"}}
    # 定义new_map字典,包含一个键为"INTEGER",值为{"4": "int"}的字典
    new_map = {"INTEGER": {"4": "int"}}
    # 定义c2py_map字典,包含一个键为"int",值为"int",一个键为"rubbish_type",值为"long"的字典
    c2py_map = {"int": "int", "rubbish_type": "long"}

    # 定义期望的exp_map和exp_maptyp结果
    exp_map, exp_maptyp = ({"integer": {"8": "rubbish_type", "4": "int"}}, ["int"])

    # 调用process_f2cmap_dict函数,传入f2cmap_all、new_map和c2py_map作为参数,获取结果
    res_map, res_maptyp = process_f2cmap_dict(f2cmap_all, new_map, c2py_map)

    # 使用assert断言确保计算结果与期望输出相等
    assert res_map == exp_map
    assert res_maptyp == exp_maptyp

.\numpy\numpy\f2py\tests\test_kind.py

# 导入必要的模块和库
import sys  # 导入系统模块
import os  # 导入操作系统模块
import pytest  # 导入 pytest 测试框架
import platform  # 导入平台信息模块

# 导入 util 模块中的特定函数
from numpy.f2py.crackfortran import (
    _selected_int_kind_func as selected_int_kind,  # 导入整数类型处理函数
    _selected_real_kind_func as selected_real_kind,  # 导入实数类型处理函数
)
from . import util  # 导入当前包中的 util 模块

# 定义一个测试类 TestKind,继承自 util.F2PyTest 类
class TestKind(util.F2PyTest):
    sources = [util.getpath("tests", "src", "kind", "foo.f90")]  # 指定测试源文件路径

    # 装饰器标记,如果系统最大整数值小于 2^31+1,则跳过该测试
    @pytest.mark.skipif(sys.maxsize < 2 ** 31 + 1, reason="Fails for 32 bit machines")
    def test_int(self):
        """Test `int` kind_func for integers up to 10**40."""
        selectedintkind = self.module.selectedintkind  # 获取模块中的整数处理函数

        # 遍历整数范围 [0, 39],验证整数处理函数的正确性
        for i in range(40):
            assert selectedintkind(i) == selected_int_kind(
                i
            ), f"selectedintkind({i}): expected {selected_int_kind(i)!r} but got {selectedintkind(i)!r}"

    # 测试实数类型处理函数
    def test_real(self):
        """
        Test (processor-dependent) `real` kind_func for real numbers
        of up to 31 digits precision (extended/quadruple).
        """
        selectedrealkind = self.module.selectedrealkind  # 获取模块中的实数处理函数

        # 遍历实数范围 [0, 31],验证实数处理函数的正确性
        for i in range(32):
            assert selectedrealkind(i) == selected_real_kind(
                i
            ), f"selectedrealkind({i}): expected {selected_real_kind(i)!r} but got {selectedrealkind(i)!r}"

    # 装饰器标记,如果当前机器是 PowerPC,则标记测试为预期失败
    @pytest.mark.xfail(platform.machine().lower().startswith("ppc"), reason="Some PowerPC may not support full IEEE 754 precision")
    def test_quad_precision(self):
        """
        Test kind_func for quadruple precision [`real(16)`] of 32+ digits .
        """
        selectedrealkind = self.module.selectedrealkind  # 获取模块中的实数处理函数

        # 遍历实数范围 [32, 39],验证实数处理函数在四重精度下的正确性
        for i in range(32, 40):
            assert selectedrealkind(i) == selected_real_kind(
                i
            ), f"selectedrealkind({i}): expected {selected_real_kind(i)!r} but got {selectedrealkind(i)!r}"

.\numpy\numpy\f2py\tests\test_mixed.py

import os
import textwrap
import pytest

from numpy.testing import IS_PYPY
from . import util  # 导入本地的util模块

class TestMixed(util.F2PyTest):  # 定义一个测试类TestMixed,继承自util.F2PyTest
    sources = [
        util.getpath("tests", "src", "mixed", "foo.f"),  # 获取特定路径下的文件路径
        util.getpath("tests", "src", "mixed", "foo_fixed.f90"),  # 获取特定路径下的文件路径
        util.getpath("tests", "src", "mixed", "foo_free.f90"),  # 获取特定路径下的文件路径
    ]

    @pytest.mark.slow  # 标记该测试方法为slow,运行时可能较慢
    def test_all(self):
        assert self.module.bar11() == 11  # 断言调用self.module.bar11()返回值为11
        assert self.module.foo_fixed.bar12() == 12  # 断言调用self.module.foo_fixed.bar12()返回值为12
        assert self.module.foo_free.bar13() == 13  # 断言调用self.module.foo_free.bar13()返回值为13

    @pytest.mark.xfail(IS_PYPY, reason="PyPy cannot modify tp_doc after PyType_Ready")
    # 标记该测试方法为xfail,在PyPy环境下预期失败,并附带原因说明
    def test_docstring(self):
        expected = textwrap.dedent("""\
        a = bar11()

        Wrapper for ``bar11``.

        Returns
        -------
        a : int
        """)
        assert self.module.bar11.__doc__ == expected  # 断言self.module.bar11的文档字符串与expected相等

.\numpy\numpy\f2py\tests\test_modules.py

# 导入 pytest 模块,用于编写和运行测试
import pytest
# 导入 textwrap 模块,用于处理文本的缩进和格式化
import textwrap

# 从当前包中导入 util 模块
from . import util
# 导入 numpy.testing 模块中的 IS_PYPY 常量
from numpy.testing import IS_PYPY

# 使用 pytest.mark.slow 标记的测试类,继承自 util.F2PyTest 类
@pytest.mark.slow
class TestModuleDocString(util.F2PyTest):
    # 源文件列表,包含一个 Fortran 源文件路径
    sources = [util.getpath("tests", "src", "modules", "module_data_docstring.f90")]

    # 标记为 xfail,当在 PyPy 环境下运行时,测试预期会失败
    @pytest.mark.xfail(IS_PYPY, reason="PyPy cannot modify tp_doc after PyType_Ready")
    def test_module_docstring(self):
        # 断言模块的文档字符串等于指定的文本(经过 textwrap.dedent 处理)
        assert self.module.mod.__doc__ == textwrap.dedent(
            """\
                     i : 'i'-scalar
                     x : 'i'-array(4)
                     a : 'f'-array(2,3)
                     b : 'f'-array(-1,-1), not allocated\x00
                     foo()\n
                     Wrapper for ``foo``.\n\n"""
        )

# 使用 pytest.mark.slow 标记的测试类,继承自 util.F2PyTest 类
@pytest.mark.slow
class TestModuleAndSubroutine(util.F2PyTest):
    # 模块名称为 "example"
    module_name = "example"
    # 源文件列表,包含两个 Fortran 源文件路径
    sources = [
        util.getpath("tests", "src", "modules", "gh25337", "data.f90"),
        util.getpath("tests", "src", "modules", "gh25337", "use_data.f90"),
    ]

    def test_gh25337(self):
        # 设置数据模块的偏移量为 3
        self.module.data.set_shift(3)
        # 断言模块中包含 "data" 对象
        assert "data" in dir(self.module)

# 使用 pytest.mark.slow 标记的测试类,继承自 util.F2PyTest 类
@pytest.mark.slow
class TestUsedModule(util.F2PyTest):
    # 模块名称为 "fmath"
    module_name = "fmath"
    # 源文件列表,包含一个 Fortran 源文件路径
    sources = [
        util.getpath("tests", "src", "modules", "use_modules.f90"),
    ]

    def test_gh25867(self):
        # 获取已编译模块的列表(排除双下划线开头的特殊成员)
        compiled_mods = [x for x in dir(self.module) if "__" not in x]
        # 断言模块中包含 "useops" 模块
        assert "useops" in compiled_mods
        # 调用并断言模块中的 useops.sum_and_double 方法返回值为 20
        assert self.module.useops.sum_and_double(3, 7) == 20
        # 断言模块中包含 "mathops" 模块
        assert "mathops" in compiled_mods
        # 调用并断言模块中的 mathops.add 方法返回值为 10
        assert self.module.mathops.add(3, 7) == 10

.\numpy\numpy\f2py\tests\test_parameter.py

import os  # 导入操作系统模块
import pytest  # 导入 pytest 测试框架

import numpy as np  # 导入 NumPy 数学计算库

from . import util  # 从当前包中导入 util 模块


class TestParameters(util.F2PyTest):
    # 测试参数类,继承自 util.F2PyTest 类

    # 定义测试所需的源文件路径列表
    sources = [
        util.getpath("tests", "src", "parameter", "constant_real.f90"),
        util.getpath("tests", "src", "parameter", "constant_integer.f90"),
        util.getpath("tests", "src", "parameter", "constant_both.f90"),
        util.getpath("tests", "src", "parameter", "constant_compound.f90"),
        util.getpath("tests", "src", "parameter", "constant_non_compound.f90"),
        util.getpath("tests", "src", "parameter", "constant_array.f90"),
    ]

    @pytest.mark.slow
    def test_constant_real_single(self):
        # 测试单精度实数参数的函数

        # 创建非连续数组 x,并断言调用 self.module.foo_single(x) 会引发 ValueError 异常
        x = np.arange(6, dtype=np.float32)[::2]
        pytest.raises(ValueError, self.module.foo_single, x)

        # 使用连续数组 x 进行数值检查,并断言数组的数值接近期望值
        x = np.arange(3, dtype=np.float32)
        self.module.foo_single(x)
        assert np.allclose(x, [0 + 1 + 2 * 3, 1, 2])

    @pytest.mark.slow
    def test_constant_real_double(self):
        # 测试双精度实数参数的函数

        # 创建非连续数组 x,并断言调用 self.module.foo_double(x) 会引发 ValueError 异常
        x = np.arange(6, dtype=np.float64)[::2]
        pytest.raises(ValueError, self.module.foo_double, x)

        # 使用连续数组 x 进行数值检查,并断言数组的数值接近期望值
        x = np.arange(3, dtype=np.float64)
        self.module.foo_double(x)
        assert np.allclose(x, [0 + 1 + 2 * 3, 1, 2])

    @pytest.mark.slow
    def test_constant_compound_int(self):
        # 测试复合整数参数的函数

        # 创建非连续数组 x,并断言调用 self.module.foo_compound_int(x) 会引发 ValueError 异常
        x = np.arange(6, dtype=np.int32)[::2]
        pytest.raises(ValueError, self.module.foo_compound_int, x)

        # 使用连续数组 x 进行数值检查,并断言数组的数值接近期望值
        x = np.arange(3, dtype=np.int32)
        self.module.foo_compound_int(x)
        assert np.allclose(x, [0 + 1 + 2 * 6, 1, 2])

    @pytest.mark.slow
    def test_constant_non_compound_int(self):
        # 测试非复合整数参数的函数

        # 使用数组 x 进行数值检查,并断言数组的数值接近期望值
        x = np.arange(4, dtype=np.int32)
        self.module.foo_non_compound_int(x)
        assert np.allclose(x, [0 + 1 + 2 + 3 * 4, 1, 2, 3])

    @pytest.mark.slow
    def test_constant_integer_int(self):
        # 测试整数参数的函数

        # 创建非连续数组 x,并断言调用 self.module.foo_int(x) 会引发 ValueError 异常
        x = np.arange(6, dtype=np.int32)[::2]
        pytest.raises(ValueError, self.module.foo_int, x)

        # 使用连续数组 x 进行数值检查,并断言数组的数值接近期望值
        x = np.arange(3, dtype=np.int32)
        self.module.foo_int(x)
        assert np.allclose(x, [0 + 1 + 2 * 3, 1, 2])

    @pytest.mark.slow
    def test_constant_integer_long(self):
        # 测试长整数参数的函数

        # 创建非连续数组 x,并断言调用 self.module.foo_long(x) 会引发 ValueError 异常
        x = np.arange(6, dtype=np.int64)[::2]
        pytest.raises(ValueError, self.module.foo_long, x)

        # 使用连续数组 x 进行数值检查,并断言数组的数值接近期望值
        x = np.arange(3, dtype=np.int64)
        self.module.foo_long(x)
        assert np.allclose(x, [0 + 1 + 2 * 3, 1, 2])
    # 定义测试方法:验证非连续数组是否引发错误
    def test_constant_both(self):
        # 创建一个包含6个元素的浮点数类型的数组,步长为2,非连续数组
        x = np.arange(6, dtype=np.float64)[::2]
        # 断言调用 self.module.foo(x) 会引发 ValueError 异常
        pytest.raises(ValueError, self.module.foo, x)

        # 使用连续数组检查函数的返回值
        x = np.arange(3, dtype=np.float64)
        self.module.foo(x)
        # 断言 x 的所有元素与指定的值接近
        assert np.allclose(x, [0 + 1 * 3 * 3 + 2 * 3 * 3, 1 * 3, 2 * 3])

    # 使用 @pytest.mark.slow 标记的测试方法
    @pytest.mark.slow
    def test_constant_no(self):
        # 创建一个包含6个元素的浮点数类型的数组,步长为2,非连续数组
        x = np.arange(6, dtype=np.float64)[::2]
        # 断言调用 self.module.foo_no(x) 会引发 ValueError 异常
        pytest.raises(ValueError, self.module.foo_no, x)

        # 使用连续数组检查函数的返回值
        x = np.arange(3, dtype=np.float64)
        self.module.foo_no(x)
        # 断言 x 的所有元素与指定的值接近
        assert np.allclose(x, [0 + 1 * 3 * 3 + 2 * 3 * 3, 1 * 3, 2 * 3])

    # 使用 @pytest.mark.slow 标记的测试方法
    @pytest.mark.slow
    def test_constant_sum(self):
        # 创建一个包含6个元素的浮点数类型的数组,步长为2,非连续数组
        x = np.arange(6, dtype=np.float64)[::2]
        # 断言调用 self.module.foo_sum(x) 会引发 ValueError 异常
        pytest.raises(ValueError, self.module.foo_sum, x)

        # 使用连续数组检查函数的返回值
        x = np.arange(3, dtype=np.float64)
        self.module.foo_sum(x)
        # 断言 x 的所有元素与指定的值接近
        assert np.allclose(x, [0 + 1 * 3 * 3 + 2 * 3 * 3, 1 * 3, 2 * 3])

    # 定义测试方法:验证函数 foo_array 的功能
    def test_constant_array(self):
        # 创建一个包含3个元素的浮点数类型的数组 x 和包含5个元素的浮点数类型的数组 y
        x = np.arange(3, dtype=np.float64)
        y = np.arange(5, dtype=np.float64)
        # 调用函数 self.module.foo_array(x, y),并断言结果
        z = self.module.foo_array(x, y)
        assert np.allclose(x, [0.0, 1./10, 2./10])
        assert np.allclose(y, [0.0, 1.*10, 2.*10, 3.*10, 4.*10])
        assert np.allclose(z, 19.0)

    # 定义测试方法:验证函数 foo_array_any_index 的功能
    def test_constant_array_any_index(self):
        # 创建一个包含6个元素的浮点数类型的数组 x
        x = np.arange(6, dtype=np.float64)
        # 调用函数 self.module.foo_array_any_index(x),并断言结果
        y = self.module.foo_array_any_index(x)
        assert np.allclose(y, x.reshape((2, 3), order='F'))

    # 定义测试方法:验证函数 foo_array_delims 的功能
    def test_constant_array_delims(self):
        # 调用函数 self.module.foo_array_delims(),并断言返回值为 9
        x = self.module.foo_array_delims()
        assert x == 9

.\numpy\numpy\f2py\tests\test_pyf_src.py

# 导入必要的模块和函数,这段代码从numpy.distutils移植而来
from numpy.f2py._src_pyf import process_str  # 导入process_str函数,用于处理字符串
from numpy.testing import assert_equal  # 导入assert_equal函数,用于比较两个值是否相等


# 定义输入的Fortran语言接口代码字符串
pyf_src = """
python module foo
    <_rd=real,double precision>
    interface
        subroutine <s,d>foosub(tol)
            <_rd>, intent(in,out) :: tol
        end subroutine <s,d>foosub
    end interface
end python module foo
"""

# 预期的Fortran语言接口代码字符串
expected_pyf = """
python module foo
    interface
        subroutine sfoosub(tol)
            real, intent(in,out) :: tol
        end subroutine sfoosub
        subroutine dfoosub(tol)
            double precision, intent(in,out) :: tol
        end subroutine dfoosub
    end interface
end python module foo
"""


def normalize_whitespace(s):
    """
    去除字符串首尾的空白字符,并将内部连续的空白字符转换为单个空格。
    """
    return ' '.join(s.split())


def test_from_template():
    """
    gh-10712的回归测试函数。
    """
    # 使用process_str函数处理pyf_src字符串
    pyf = process_str(pyf_src)
    # 对处理后的字符串进行空白字符标准化处理
    normalized_pyf = normalize_whitespace(pyf)
    # 对预期字符串进行空白字符标准化处理
    normalized_expected_pyf = normalize_whitespace(expected_pyf)
    # 断言处理后的字符串与预期字符串相等
    assert_equal(normalized_pyf, normalized_expected_pyf)

.\numpy\numpy\f2py\tests\test_quoted_character.py

"""See https://github.com/numpy/numpy/pull/10676.

"""
# 导入系统和 pytest 库
import sys
import pytest

# 从当前目录中的 util 模块导入
from . import util

# 定义一个测试类 TestQuotedCharacter,继承自 util.F2PyTest
class TestQuotedCharacter(util.F2PyTest):
    # 指定测试所需的源文件路径列表
    sources = [util.getpath("tests", "src", "quoted_character", "foo.f")]

    # 使用 pytest.mark.skipif 装饰器,如果运行平台为 win32,则跳过该测试
    @pytest.mark.skipif(sys.platform == "win32",
                        reason="Fails with MinGW64 Gfortran (Issue #9673)")
    # 标记为慢速测试
    @pytest.mark.slow
    # 定义测试方法 test_quoted_character
    def test_quoted_character(self):
        # 断言调用 self.module.foo() 返回元组 (b"'", b'"', b";", b"!", b"(", b")")
        assert self.module.foo() == (b"'", b'"', b";", b"!", b"(", b")")

.\numpy\numpy\f2py\tests\test_regression.py

# 导入所需的库和模块
import os
import pytest
import platform

import numpy as np  # 导入 NumPy 库
import numpy.testing as npt  # 导入 NumPy 测试模块

from . import util  # 从当前包导入 util 模块


class TestIntentInOut(util.F2PyTest):
    # 检查 intent(in out) 是否正确翻译为 intent(inout)
    sources = [util.getpath("tests", "src", "regression", "inout.f90")]

    @pytest.mark.slow
    def test_inout(self):
        # 对非连续数组应该引发 ValueError 错误
        x = np.arange(6, dtype=np.float32)[::2]
        pytest.raises(ValueError, self.module.foo, x)

        # 使用连续数组检查数值
        x = np.arange(3, dtype=np.float32)
        self.module.foo(x)
        assert np.allclose(x, [3, 1, 2])


class TestNegativeBounds(util.F2PyTest):
    # 检查负索引边界是否正常工作
    sources = [util.getpath("tests", "src", "negative_bounds", "issue_20853.f90")]

    @pytest.mark.slow
    def test_negbound(self):
        xvec = np.arange(12)
        xlow = -6
        xhigh = 4

        # 计算上限,
        # 注意保持索引为 1
        def ubound(xl, xh):
            return xh - xl + 1

        rval = self.module.foo(is_=xlow, ie_=xhigh,
                               arr=xvec[:ubound(xlow, xhigh)])
        expval = np.arange(11, dtype=np.float32)
        assert np.allclose(rval, expval)


class TestNumpyVersionAttribute(util.F2PyTest):
    # 检查编译模块中是否存在 __f2py_numpy_version__ 属性,
    # 并且其值为 np.__version__
    sources = [util.getpath("tests", "src", "regression", "inout.f90")]

    @pytest.mark.slow
    def test_numpy_version_attribute(self):
        # 检查 self.module 是否有名为 "__f2py_numpy_version__" 的属性
        assert hasattr(self.module, "__f2py_numpy_version__")

        # 检查 "__f2py_numpy_version__" 属性是否为字符串类型
        assert isinstance(self.module.__f2py_numpy_version__, str)

        # 检查 "__f2py_numpy_version__" 属性的值是否为 numpy.__version__
        assert np.__version__ == self.module.__f2py_numpy_version__


def test_include_path():
    # 测试 np.f2py.get_include() 是否能正确返回包含文件的路径
    incdir = np.f2py.get_include()
    fnames_in_dir = os.listdir(incdir)
    for fname in ("fortranobject.c", "fortranobject.h"):
        assert fname in fnames_in_dir


class TestIncludeFiles(util.F2PyTest):
    # 检查编译模块时指定的包含文件是否正确加载
    sources = [util.getpath("tests", "src", "regression", "incfile.f90")]
    options = [f"-I{util.getpath('tests', 'src', 'regression')}",
               f"--include-paths {util.getpath('tests', 'src', 'regression')}"]

    @pytest.mark.slow
    def test_gh25344(self):
        exp = 7.0
        res = self.module.add(3.0, 4.0)
        assert exp == res


class TestF77Comments(util.F2PyTest):
    # 检查从 F77 连续行中剥离注释是否正确
    sources = [util.getpath("tests", "src", "regression", "f77comments.f")]

    @pytest.mark.slow
    # 定义一个测试方法,用于测试 GH26148 的情况
    def test_gh26148(self):
        # 创建一个包含单个整数值 3 的 numpy 数组,数据类型为 int32
        x1 = np.array(3, dtype=np.int32)
        # 创建一个包含单个整数值 5 的 numpy 数组,数据类型为 int32
        x2 = np.array(5, dtype=np.int32)
        # 调用被测试模块的 testsub 方法,传入 x1 和 x2 作为参数,获取返回值
        res = self.module.testsub(x1, x2)
        # 断言返回值的第一个元素是否为 8
        assert(res[0] == 8)
        # 断言返回值的第二个元素是否为 15
        assert(res[1] == 15)

    # 使用 pytest 的标记 @pytest.mark.slow,定义一个慢速测试方法
    def test_gh26466(self):
        # 创建一个预期结果数组,包含从 1 到 10 的浮点数,步长为 2
        expected = np.arange(1, 11, dtype=np.float32) * 2
        # 调用被测试模块的 testsub2 方法,获取返回值
        res = self.module.testsub2()
        # 使用 numpy.testing 库中的 assert_allclose 方法,比较预期结果和实际结果的近似程度
        npt.assert_allclose(expected, res)
class TestF90Contiuation(util.F2PyTest):
    # 定义一个测试类,继承自util.F2PyTest,用于测试Fortran90的连续行中是否正确处理了注释
    sources = [util.getpath("tests", "src", "regression", "f90continuation.f90")]

    @pytest.mark.slow
    def test_gh26148b(self):
        # 测试函数,标记为较慢执行的测试
        x1 = np.array(3, dtype=np.int32)
        x2 = np.array(5, dtype=np.int32)
        # 调用self.module中的testsub函数,并验证返回值
        res=self.module.testsub(x1, x2)
        assert(res[0] == 8)
        assert(res[1] == 15)

@pytest.mark.slow
def test_gh26623():
    # 测试函数,验证包含有.的库名是否能正确生成meson.build文件
    try:
        aa = util.build_module(
            [util.getpath("tests", "src", "regression", "f90continuation.f90")],
            ["-lfoo.bar"],
            module_name="Blah",
        )
    except RuntimeError as rerr:
        assert "lparen got assign" not in str(rerr)


@pytest.mark.slow
@pytest.mark.skipif(platform.system() not in ['Linux', 'Darwin'], reason='Unsupported on this platform for now')
def test_gh25784():
    # 测试函数,根据传递的标志编译一个可疑的文件
    try:
        aa = util.build_module(
            [util.getpath("tests", "src", "regression", "f77fixedform.f95")],
            options=[
                # Meson将会收集并去重这些标志,传递给fortran_args:
                "--f77flags='-ffixed-form -O2'",
                "--f90flags=\"-ffixed-form -Og\"",
            ],
            module_name="Blah",
        )
    except ImportError as rerr:
        assert "unknown_subroutine_" in str(rerr)

.\numpy\numpy\f2py\tests\test_return_character.py

# 导入 pytest 测试框架
import pytest

# 导入 numpy 数组模块,并导入 array 函数
from numpy import array

# 从当前目录下的 . 包中导入 util 模块
from . import util

# 导入 platform 模块
import platform

# 检查当前机器是否为 s390x 架构,返回布尔值
IS_S390X = platform.machine() == "s390x"

# 用 pytest.mark.slow 标记的测试类,继承自 util.F2PyTest 类
@pytest.mark.slow
class TestReturnCharacter(util.F2PyTest):
    
    # 定义一个检查函数,接受参数 t 和 tname
    def check_function(self, t, tname):
        
        # 如果 tname 在以下列表中
        if tname in ["t0", "t1", "s0", "s1"]:
            # 断言 t("23") 返回 b"2"
            assert t("23") == b"2"
            # 将 t("ab") 的返回结果赋给 r,断言 r 等于 b"a"
            r = t("ab")
            assert r == b"a"
            # 将 t(array("ab")) 的返回结果赋给 r,断言 r 等于 b"a"
            r = t(array("ab"))
            assert r == b"a"
            # 将 t(array(77, "u1")) 的返回结果赋给 r,断言 r 等于 b"M"
            r = t(array(77, "u1"))
            assert r == b"M"
        
        # 如果 tname 在以下列表中
        elif tname in ["ts", "ss"]:
            # 断言 t(23) 返回 b"23"
            assert t(23) == b"23"
            # 断言 t("123456789abcdef") 返回 b"123456789a"
            assert t("123456789abcdef") == b"123456789a"
        
        # 如果 tname 在以下列表中
        elif tname in ["t5", "s5"]:
            # 断言 t(23) 返回 b"23"
            assert t(23) == b"23"
            # 断言 t("ab") 返回 b"ab"
            assert t("ab") == b"ab"
            # 断言 t("123456789abcdef") 返回 b"12345"
            assert t("123456789abcdef") == b"12345"
        
        # 如果不在以上任何一个列表中,抛出 NotImplementedError 异常
        else:
            raise NotImplementedError

# 测试类 TestFReturnCharacter 继承自 TestReturnCharacter 类
class TestFReturnCharacter(TestReturnCharacter):
    
    # sources 列表包含两个路径,指定测试源文件位置
    sources = [
        util.getpath("tests", "src", "return_character", "foo77.f"),
        util.getpath("tests", "src", "return_character", "foo90.f90"),
    ]
    
    # 使用 pytest.mark.xfail 标记测试,如果 IS_S390X 为 True,则原因为 "callback returns ' '" 的测试失败
    @pytest.mark.xfail(IS_S390X, reason="callback returns ' '")
    # 参数化测试,name 参数取自字符串 "t0,t1,t5,s0,s1,s5,ss",分割后成为列表
    @pytest.mark.parametrize("name", "t0,t1,t5,s0,s1,s5,ss".split(","))
    def test_all_f77(self, name):
        # 调用父类的 check_function 方法,传入相应的函数和名称进行测试
        self.check_function(getattr(self.module, name), name)
    
    # 使用 pytest.mark.xfail 标记测试,如果 IS_S390X 为 True,则原因为 "callback returns ' '" 的测试失败
    @pytest.mark.xfail(IS_S390X, reason="callback returns ' '")
    # 参数化测试,name 参数取自字符串 "t0,t1,t5,ts,s0,s1,s5,ss",分割后成为列表
    @pytest.mark.parametrize("name", "t0,t1,t5,ts,s0,s1,s5,ss".split(","))
    def test_all_f90(self, name):
        # 调用父类的 check_function 方法,传入相应的函数和名称进行测试
        self.check_function(getattr(self.module.f90_return_char, name), name)

.\numpy\numpy\f2py\tests\test_return_complex.py

import pytest  # 导入 pytest 测试框架

from numpy import array  # 从 numpy 中导入 array 类
from . import util  # 导入当前目录下的 util 模块

@pytest.mark.slow  # 标记该测试类为慢速测试
class TestReturnComplex(util.F2PyTest):  # 定义测试类 TestReturnComplex,继承自 util.F2PyTest

    def check_function(self, t, tname):  # 定义方法 check_function,用于测试函数 t
        if tname in ["t0", "t8", "s0", "s8"]:  # 如果 tname 在列表中
            err = 1e-5  # 设置误差容限为 1e-5
        else:  # 否则
            err = 0.0  # 设置误差容限为 0.0
        assert abs(t(234j) - 234.0j) <= err  # 断言 t(234j) 的返回值与期望值 234.0j 的差的绝对值小于等于 err
        assert abs(t(234.6) - 234.6) <= err  # 断言 t(234.6) 的返回值与期望值 234.6 的差的绝对值小于等于 err
        assert abs(t(234) - 234.0) <= err  # 断言 t(234) 的返回值与期望值 234.0 的差的绝对值小于等于 err
        assert abs(t(234.6 + 3j) - (234.6 + 3j)) <= err  # 断言 t(234.6 + 3j) 的返回值与期望值 (234.6 + 3j) 的差的绝对值小于等于 err
        # assert abs(t('234')-234.)<=err  # 注释掉的断言
        # assert abs(t('234.6')-234.6)<=err  # 注释掉的断言
        assert abs(t(-234) + 234.0) <= err  # 断言 t(-234) 的返回值与期望值 234.0 的和的绝对值小于等于 err
        assert abs(t([234]) - 234.0) <= err  # 断言 t([234]) 的返回值与期望值 234.0 的差的绝对值小于等于 err
        assert abs(t((234, )) - 234.0) <= err  # 断言 t((234,)) 的返回值与期望值 234.0 的差的绝对值小于等于 err
        assert abs(t(array(234)) - 234.0) <= err  # 断言 t(array(234)) 的返回值与期望值 234.0 的差的绝对值小于等于 err
        assert abs(t(array(23 + 4j, "F")) - (23 + 4j)) <= err  # 断言 t(array(23+4j, 'F')) 的返回值与期望值 (23+4j) 的差的绝对值小于等于 err
        assert abs(t(array([234])) - 234.0) <= err  # 断言 t(array([234])) 的返回值与期望值 234.0 的差的绝对值小于等于 err
        assert abs(t(array([[234]])) - 234.0) <= err  # 断言 t(array([[234]])) 的返回值与期望值 234.0 的差的绝对值小于等于 err
        assert abs(t(array([234]).astype("b")) + 22.0) <= err  # 断言 t(array([234], 'b')) 的返回值与期望值 22.0 的和的绝对值小于等于 err
        assert abs(t(array([234], "h")) - 234.0) <= err  # 断言 t(array([234], 'h')) 的返回值与期望值 234.0 的差的绝对值小于等于 err
        assert abs(t(array([234], "i")) - 234.0) <= err  # 断言 t(array([234], 'i')) 的返回值与期望值 234.0 的差的绝对值小于等于 err
        assert abs(t(array([234], "l")) - 234.0) <= err  # 断言 t(array([234], 'l')) 的返回值与期望值 234.0 的差的绝对值小于等于 err
        assert abs(t(array([234], "q")) - 234.0) <= err  # 断言 t(array([234], 'q')) 的返回值与期望值 234.0 的差的绝对值小于等于 err
        assert abs(t(array([234], "f")) - 234.0) <= err  # 断言 t(array([234], 'f')) 的返回值与期望值 234.0 的差的绝对值小于等于 err
        assert abs(t(array([234], "d")) - 234.0) <= err  # 断言 t(array([234], 'd')) 的返回值与期望值 234.0 的差的绝对值小于等于 err
        assert abs(t(array([234 + 3j], "F")) - (234 + 3j)) <= err  # 断言 t(array([234+3j], 'F')) 的返回值与期望值 (234+3j) 的差的绝对值小于等于 err
        assert abs(t(array([234], "D")) - 234.0) <= err  # 断言 t(array([234], 'D')) 的返回值与期望值 234.0 的差的绝对值小于等于 err

        # pytest.raises(TypeError, t, array([234], 'S1'))  # 注释掉的断言,测试 t(array([234], 'S1')) 是否抛出 TypeError 异常
        pytest.raises(TypeError, t, "abc")  # 断言 t("abc") 抛出 TypeError 异常

        pytest.raises(IndexError, t, [])  # 断言 t([]) 抛出 IndexError 异常
        pytest.raises(IndexError, t, ())  # 断言 t(()) 抛出 IndexError 异常

        pytest.raises(TypeError, t, t)  # 断言 t(t) 抛出 TypeError 异常
        pytest.raises(TypeError, t, {})  # 断言 t({}) 抛出 TypeError 异常

        try:
            r = t(10**400)  # 尝试计算 t(10**400)
            assert repr(r) in ["(inf+0j)", "(Infinity+0j)"]  # 断言 r 的字符串表示在列表中
        except OverflowError:  # 如果出现 OverflowError 异常
            pass  # 忽略异常

class TestFReturnComplex(TestReturnComplex):  # 定义测试类 TestFReturnComplex,继承自 TestReturnComplex
    sources = [  # 定义源文件列表
        util.getpath("tests", "src", "return_complex", "foo77.f"),  # 获取 foo77.f 的路径
        util.getpath("tests", "src", "return_complex", "foo90.f90"),  # 获取 foo90.f90 的路径
    ]

    @pytest.mark.parametrize("name", "t0,t8,t16,td,s0,s8,s16,sd".split(","))  # 参数化测试方法名
    def test_all_f77(self, name):  # 定义测试方法 test_all_f77
        self.check_function(getattr(self.module, name), name)  # 调用 check_function 测试函数名为 name 的函数

    @pytest.mark.parametrize("name", "t0,t8,t16,td,s0,s8,s16,sd".split(","))  # 参数化测试方法名
    def test_all_f90(self, name):  # 定义测试方法 test_all_f90
        self.check_function(getattr(self.module.f90_return_complex, name),  # 调用 check_function 测试 module.f90_return_complex 下的 name 函数
                            name)  # 传入函数名 name

.\numpy\numpy\f2py\tests\test_return_integer.py

# 导入 pytest 模块,用于编写和运行测试
import pytest

# 导入 numpy 中的 array 对象
from numpy import array

# 从当前包中导入 util 模块
from . import util

# 为测试类标记为慢速测试
@pytest.mark.slow
class TestReturnInteger(util.F2PyTest):
    # 定义用于检查函数行为的方法
    def check_function(self, t, tname):
        # 断言函数 t 正确处理整数输入,返回相同整数
        assert t(123) == 123
        assert t(123.6) == 123
        assert t("123") == 123
        assert t(-123) == -123
        assert t([123]) == 123
        assert t((123, )) == 123
        assert t(array(123)) == 123
        assert t(array(123, "b")) == 123
        assert t(array(123, "h")) == 123
        assert t(array(123, "i")) == 123
        assert t(array(123, "l")) == 123
        assert t(array(123, "B")) == 123
        assert t(array(123, "f")) == 123
        assert t(array(123, "d")) == 123

        # 测试抛出 ValueError 异常情况
        pytest.raises(ValueError, t, "abc")

        # 测试抛出 IndexError 异常情况
        pytest.raises(IndexError, t, [])
        pytest.raises(IndexError, t, ())

        # 测试抛出任意异常情况
        pytest.raises(Exception, t, t)
        pytest.raises(Exception, t, {})

        # 对于特定的 tname 值,测试是否能够抛出 OverflowError 异常
        if tname in ["t8", "s8"]:
            pytest.raises(OverflowError, t, 100000000000000000000000)
            pytest.raises(OverflowError, t, 10000000011111111111111.23)


# 继承自 TestReturnInteger 类,测试与 Fortran 相关的整数返回函数
class TestFReturnInteger(TestReturnInteger):
    # 指定测试的源文件路径列表
    sources = [
        util.getpath("tests", "src", "return_integer", "foo77.f"),
        util.getpath("tests", "src", "return_integer", "foo90.f90"),
    ]

    # 参数化测试方法,依次对 t0 到 s8 进行测试
    @pytest.mark.parametrize("name",
                             "t0,t1,t2,t4,t8,s0,s1,s2,s4,s8".split(","))
    def test_all_f77(self, name):
        # 调用 check_function 方法测试每个函数名对应的函数
        self.check_function(getattr(self.module, name), name)

    # 参数化测试方法,依次对 t0 到 s8 进行测试(针对 Fortran 90)
    @pytest.mark.parametrize("name",
                             "t0,t1,t2,t4,t8,s0,s1,s2,s4,s8".split(","))
    def test_all_f90(self, name):
        # 调用 check_function 方法测试每个函数名对应的函数(针对 Fortran 90)
        self.check_function(getattr(self.module.f90_return_integer, name),
                            name)

.\numpy\numpy\f2py\tests\test_return_logical.py

import pytest  # 导入 pytest 库

from numpy import array  # 从 numpy 库导入 array 函数
from . import util  # 导入当前目录下的 util 模块


class TestReturnLogical(util.F2PyTest):
    def check_function(self, t):
        assert t(True) == 1  # 断言 t(True) 的返回值为 1
        assert t(False) == 0  # 断言 t(False) 的返回值为 0
        assert t(0) == 0  # 断言 t(0) 的返回值为 0
        assert t(None) == 0  # 断言 t(None) 的返回值为 0
        assert t(0.0) == 0  # 断言 t(0.0) 的返回值为 0
        assert t(0j) == 0  # 断言 t(0j) 的返回值为 0
        assert t(1j) == 1  # 断言 t(1j) 的返回值为 1
        assert t(234) == 1  # 断言 t(234) 的返回值为 1
        assert t(234.6) == 1  # 断言 t(234.6) 的返回值为 1
        assert t(234.6 + 3j) == 1  # 断言 t(234.6 + 3j) 的返回值为 1
        assert t("234") == 1  # 断言 t("234") 的返回值为 1
        assert t("aaa") == 1  # 断言 t("aaa") 的返回值为 1
        assert t("") == 0  # 断言 t("") 的返回值为 0
        assert t([]) == 0  # 断言 t([]) 的返回值为 0
        assert t(()) == 0  # 断言 t(()) 的返回值为 0
        assert t({}) == 0  # 断言 t({}) 的返回值为 0
        assert t(t) == 1  # 断言 t(t) 的返回值为 1
        assert t(-234) == 1  # 断言 t(-234) 的返回值为 1
        assert t(10**100) == 1  # 断言 t(10**100) 的返回值为 1
        assert t([234]) == 1  # 断言 t([234]) 的返回值为 1
        assert t((234,)) == 1  # 断言 t((234,)) 的返回值为 1
        assert t(array(234)) == 1  # 断言 t(array(234)) 的返回值为 1
        assert t(array([234])) == 1  # 断言 t(array([234])) 的返回值为 1
        assert t(array([[234]])) == 1  # 断言 t(array([[234]])) 的返回值为 1
        assert t(array([127], "b")) == 1  # 断言 t(array([127], "b")) 的返回值为 1
        assert t(array([234], "h")) == 1  # 断言 t(array([234], "h")) 的返回值为 1
        assert t(array([234], "i")) == 1  # 断言 t(array([234], "i")) 的返回值为 1
        assert t(array([234], "l")) == 1  # 断言 t(array([234], "l")) 的返回值为 1
        assert t(array([234], "f")) == 1  # 断言 t(array([234], "f")) 的返回值为 1
        assert t(array([234], "d")) == 1  # 断言 t(array([234], "d")) 的返回值为 1
        assert t(array([234 + 3j], "F")) == 1  # 断言 t(array([234 + 3j], "F")) 的返回值为 1
        assert t(array([234], "D")) == 1  # 断言 t(array([234], "D")) 的返回值为 1
        assert t(array(0)) == 0  # 断言 t(array(0)) 的返回值为 0
        assert t(array([0])) == 0  # 断言 t(array([0])) 的返回值为 0
        assert t(array([[0]])) == 0  # 断言 t(array([[0]])) 的返回值为 0
        assert t(array([0j])) == 0  # 断言 t(array([0j])) 的返回值为 0
        assert t(array([1])) == 1  # 断言 t(array([1])) 的返回值为 1
        pytest.raises(ValueError, t, array([0, 0]))  # 使用 pytest 断言 t(array([0, 0])) 抛出 ValueError


class TestFReturnLogical(TestReturnLogical):
    sources = [
        util.getpath("tests", "src", "return_logical", "foo77.f"),  # 设置 sources 列表,包含 foo77.f 文件路径
        util.getpath("tests", "src", "return_logical", "foo90.f90"),  # 设置 sources 列表,包含 foo90.f90 文件路径
    ]

    @pytest.mark.slow  # 标记为慢速测试
    @pytest.mark.parametrize("name", "t0,t1,t2,t4,s0,s1,s2,s4".split(","))  # 参数化测试用例名列表
    def test_all_f77(self, name):
        self.check_function(getattr(self.module, name))  # 调用 check_function 方法测试指定的函数名

    @pytest.mark.slow  # 标记为慢速测试
    @pytest.mark.parametrize("name",
                             "t0,t1,t2,t4,t8,s0,s1,s2,s4,s8".split(","))  # 参数化测试用例名列表
    def test_all_f90(self, name):
        self.check_function(getattr(self.module.f90_return_logical, name))  # 调用 check_function 方法测试指定的函数名

.\numpy\numpy\f2py\tests\test_return_real.py

# 导入必要的模块
import platform  # 导入平台模块,用于获取操作系统信息
import pytest  # 导入 pytest 测试框架
import numpy as np  # 导入 NumPy 库,并命名为 np

from numpy import array  # 从 NumPy 中导入 array 函数
from . import util  # 从当前包中导入 util 模块

@pytest.mark.slow
class TestReturnReal(util.F2PyTest):
    # 定义 TestReturnReal 类,继承自 util.F2PyTest 类,标记为 pytest 的慢速测试用例

    def check_function(self, t, tname):
        # 定义检查函数 check_function,接受 t 函数和 tname 参数

        if tname in ["t0", "t4", "s0", "s4"]:
            err = 1e-5  # 如果 tname 在指定列表中,设置误差阈值为 1e-5
        else:
            err = 0.0  # 否则,误差阈值为 0.0

        # 一系列断言,验证 t 函数对于不同类型输入的返回值是否在误差范围内
        assert abs(t(234) - 234.0) <= err
        assert abs(t(234.6) - 234.6) <= err
        assert abs(t("234") - 234) <= err
        assert abs(t("234.6") - 234.6) <= err
        assert abs(t(-234) + 234) <= err
        assert abs(t([234]) - 234) <= err
        assert abs(t((234, )) - 234.0) <= err
        assert abs(t(array(234)) - 234.0) <= err
        assert abs(t(array(234).astype("b")) + 22) <= err
        assert abs(t(array(234, "h")) - 234.0) <= err
        assert abs(t(array(234, "i")) - 234.0) <= err
        assert abs(t(array(234, "l")) - 234.0) <= err
        assert abs(t(array(234, "B")) - 234.0) <= err
        assert abs(t(array(234, "f")) - 234.0) <= err
        assert abs(t(array(234, "d")) - 234.0) <= err

        if tname in ["t0", "t4", "s0", "s4"]:
            assert t(1e200) == t(1e300)  # 对于特定 tname,验证 t 函数在处理大数时的行为(应为 inf)

        # 使用 pytest.raises 断言捕获异常,验证 t 函数在特定输入情况下会触发 ValueError 或 IndexError 异常
        pytest.raises(ValueError, t, "abc")
        pytest.raises(IndexError, t, [])
        pytest.raises(IndexError, t, ())

        # 使用 pytest.raises 断言捕获异常,验证 t 函数在其他异常情况下会触发 Exception 异常
        pytest.raises(Exception, t, t)
        pytest.raises(Exception, t, {})

        try:
            r = t(10**400)
            assert repr(r) in ["inf", "Infinity"]  # 验证 t 函数返回值的字符串表示是否为 "inf" 或 "Infinity"
        except OverflowError:
            pass  # 捕获 OverflowError 异常,不进行任何操作

@pytest.mark.skipif(
    platform.system() == "Darwin",
    reason="Prone to error when run with numpy/f2py/tests on mac os, "
    "but not when run in isolation",
)
@pytest.mark.skipif(
    np.dtype(np.intp).itemsize < 8,
    reason="32-bit builds are buggy"
)
class TestCReturnReal(TestReturnReal):
    # 定义 TestCReturnReal 类,继承自 TestReturnReal 类,标记为 pytest 的跳过条件测试用例

    suffix = ".pyf"
    module_name = "c_ext_return_real"
    code = """
python module c_ext_return_real
usercode \'\'\'
float t4(float value) { return value; }
void s4(float *t4, float value) { *t4 = value; }
double t8(double value) { return value; }
void s8(double *t8, double value) { *t8 = value; }
\'\'\'
interface
  function t4(value)
    real*4 intent(c) :: t4,value
  end
  function t8(value)
    real*8 intent(c) :: t8,value
  end
  subroutine s4(t4,value)
    intent(c) s4
    real*4 intent(out) :: t4
    real*4 intent(c) :: value
  end
  subroutine s8(t8,value)
    intent(c) s8
    real*8 intent(out) :: t8
    real*8 intent(c) :: value
  end
end interface
end python module c_ext_return_real
    """

    @pytest.mark.parametrize("name", "t4,t8,s4,s8".split(","))
    def test_all(self, name):
        # 使用 pytest.mark.parametrize 注入参数化测试,依次测试 t4, t8, s4, s8 函数
        self.check_function(getattr(self.module, name), name)  # 调用 check_function 验证各函数行为

class TestFReturnReal(TestReturnReal):
    # 定义 TestFReturnReal 类,继承自 TestReturnReal 类

    sources = [
        util.getpath("tests", "src", "return_real", "foo77.f"),
        util.getpath("tests", "src", "return_real", "foo90.f90"),
    ]

    @pytest.mark.parametrize("name", "t0,t4,t8,td,s0,s4,s8,sd".split(","))
    def test_all(self, name):
        # 使用 pytest.mark.parametrize 注入参数化测试,依次测试 t0, t4, t8, td, s0, s4, s8, sd 函数
    # 定义一个测试方法,用于测试给定名称的 Fortran 77 函数是否符合预期
    def test_all_f77(self, name):
        # 调用 self.module 中的特定名称的函数,并使用 self.check_function 进行检查
        self.check_function(getattr(self.module, name), name)
    
    # 使用 pytest 的参数化装饰器,指定多个参数来执行测试,参数名称为 "t0", "t4", "t8", "td", "s0", "s4", "s8", "sd"
    @pytest.mark.parametrize("name", "t0,t4,t8,td,s0,s4,s8,sd".split(","))
    def test_all_f90(self, name):
        # 调用 self.module.f90_return_real 中特定名称的函数,并使用 self.check_function 进行检查
        self.check_function(getattr(self.module.f90_return_real, name), name)

.\numpy\numpy\f2py\tests\test_semicolon_split.py

# 导入必要的模块和库:platform、pytest、numpy
import platform
import pytest
import numpy as np

# 从当前包中导入 util 模块
from . import util

# 使用 pytest 的装饰器标记,指定条件为在 macOS 系统上运行时跳过测试
# 原因是在运行 numpy/f2py/tests 测试时可能会出错,但单独运行时没有问题
@pytest.mark.skipif(
    platform.system() == "Darwin",
    reason="Prone to error when run with numpy/f2py/tests on mac os, "
    "but not when run in isolation",
)
# 使用 pytest 的装饰器标记,指定条件为在 32 位构建时跳过测试
# 原因是 32 位构建存在错误
@pytest.mark.skipif(
    np.dtype(np.intp).itemsize < 8,
    reason="32-bit builds are buggy"
)
# 定义一个名为 TestMultiline 的测试类,继承自 util.F2PyTest
class TestMultiline(util.F2PyTest):
    # 设置类属性 suffix 为 ".pyf"
    suffix = ".pyf"
    # 设置类属性 module_name 为 "multiline"
    module_name = "multiline"
    # 定义类属性 code,包含一个多行字符串,表示一个 Python 模块的代码
    code = f"""
python module {module_name}
    usercode '''
void foo(int* x) {{
    char dummy = ';';
    *x = 42;
}}
'''
    interface
        subroutine foo(x)
            intent(c) foo
            integer intent(out) :: x
        end subroutine foo
    end interface
end python module {module_name}
    """

    # 定义测试方法 test_multiline
    def test_multiline(self):
        # 断言调用 self.module 的 foo 方法返回值为 42
        assert self.module.foo() == 42


# 使用 pytest 的装饰器标记,指定条件为在 macOS 系统上运行时跳过测试
# 原因是在运行 numpy/f2py/tests 测试时可能会出错,但单独运行时没有问题
@pytest.mark.skipif(
    platform.system() == "Darwin",
    reason="Prone to error when run with numpy/f2py/tests on mac os, "
    "but not when run in isolation",
)
# 使用 pytest 的装饰器标记,指定条件为在 32 位构建时跳过测试
# 原因是 32 位构建存在错误
@pytest.mark.skipif(
    np.dtype(np.intp).itemsize < 8,
    reason="32-bit builds are buggy"
)
# 使用 pytest 的装饰器标记,标记这是一个耗时的测试
@pytest.mark.slow
# 定义一个名为 TestCallstatement 的测试类,继承自 util.F2PyTest
class TestCallstatement(util.F2PyTest):
    # 设置类属性 suffix 为 ".pyf"
    suffix = ".pyf"
    # 设置类属性 module_name 为 "callstatement"
    module_name = "callstatement"
    # 定义类属性 code,包含一个多行字符串,表示一个 Python 模块的代码
    code = f"""
python module {module_name}
    usercode '''
void foo(int* x) {{
}}
'''
    interface
        subroutine foo(x)
            intent(c) foo
            integer intent(out) :: x
            callprotoargument int*
            callstatement {{ &
                ; &
                x = 42; &
            }}
        end subroutine foo
    end interface
end python module {module_name}
    """

    # 定义测试方法 test_callstatement
    def test_callstatement(self):
        # 断言调用 self.module 的 foo 方法返回值为 42
        assert self.module.foo() == 42

.\numpy\numpy\f2py\tests\test_size.py

# 导入必要的模块
import os             # 操作系统功能模块
import pytest         # 测试框架 pytest
import numpy as np    # 数值计算库 NumPy

# 从当前包中导入自定义的 util 模块
from . import util

# 定义一个测试类 TestSizeSumExample,继承自 util.F2PyTest
class TestSizeSumExample(util.F2PyTest):
    
    # 指定源文件路径列表
    sources = [util.getpath("tests", "src", "size", "foo.f90")]

    # 标记为慢速测试
    @pytest.mark.slow
    # 定义测试方法 test_all
    def test_all(self):
        # 调用 self.module.foo 方法进行测试,传入空列表 [[]]
        r = self.module.foo([[]])
        # 断言 r 应该等于 [0]
        assert r == [0]

        # 继续进行其他测试用例的断言
        r = self.module.foo([[1, 2]])
        assert r == [3]

        r = self.module.foo([[1, 2], [3, 4]])
        assert np.allclose(r, [3, 7])

        r = self.module.foo([[1, 2], [3, 4], [5, 6]])
        assert np.allclose(r, [3, 7, 11])

    # 标记为慢速测试
    @pytest.mark.slow
    # 定义测试方法 test_transpose
    def test_transpose(self):
        # 调用 self.module.trans 方法进行测试,传入空列表 [[]]
        r = self.module.trans([[]])
        # 断言 r.T 应该与空数组 np.array([[]]) 的转置相等
        assert np.allclose(r.T, np.array([[]]))

        # 继续进行其他测试用例的断言
        r = self.module.trans([[1, 2]])
        assert np.allclose(r, [[1.], [2.]])

        r = self.module.trans([[1, 2, 3], [4, 5, 6]])
        assert np.allclose(r, [[1, 4], [2, 5], [3, 6]])

    # 标记为慢速测试
    @pytest.mark.slow
    # 定义测试方法 test_flatten
    def test_flatten(self):
        # 调用 self.module.flatten 方法进行测试,传入空列表 [[]]
        r = self.module.flatten([[]])
        # 断言 r 应该等于空数组 []
        assert np.allclose(r, [])

        # 继续进行其他测试用例的断言
        r = self.module.flatten([[1, 2]])
        assert np.allclose(r, [1, 2])

        r = self.module.flatten([[1, 2, 3], [4, 5, 6]])
        assert np.allclose(r, [1, 2, 3, 4, 5, 6])

.\numpy\numpy\f2py\tests\test_string.py

import os
import pytest
import textwrap
import numpy as np
from . import util  # 导入自定义的 util 模块

class TestString(util.F2PyTest):
    sources = [util.getpath("tests", "src", "string", "char.f90")]  # 定义测试源文件路径列表

    @pytest.mark.slow
    def test_char(self):
        strings = np.array(["ab", "cd", "ef"], dtype="c").T  # 创建包含字符数组的 numpy 数组
        inp, out = self.module.char_test.change_strings(  # 调用模块方法,修改输入和输出字符串
            strings, strings.shape[1])
        assert inp == pytest.approx(strings)  # 断言输入是否与预期相符
        expected = strings.copy()  # 复制输入字符串数组作为预期输出的基础
        expected[1, :] = "AAA"  # 修改预期输出的第二行为 "AAA"
        assert out == pytest.approx(expected)  # 断言输出是否与预期相符

class TestDocStringArguments(util.F2PyTest):
    sources = [util.getpath("tests", "src", "string", "string.f")]  # 定义测试源文件路径列表

    def test_example(self):
        a = np.array(b"123\0\0")  # 创建包含字节串的 numpy 数组 a
        b = np.array(b"123\0\0")  # 创建包含字节串的 numpy 数组 b
        c = np.array(b"123")  # 创建包含字节串的 numpy 数组 c
        d = np.array(b"123")  # 创建包含字节串的 numpy 数组 d

        self.module.foo(a, b, c, d)  # 调用模块方法 foo 处理这些数组

        assert a.tobytes() == b"123\0\0"  # 断言数组 a 是否被正确处理
        assert b.tobytes() == b"B23\0\0"  # 断言数组 b 是否被正确处理
        assert c.tobytes() == b"123"  # 断言数组 c 是否被正确处理
        assert d.tobytes() == b"D23"  # 断言数组 d 是否被正确处理

class TestFixedString(util.F2PyTest):
    sources = [util.getpath("tests", "src", "string", "fixed_string.f90")]  # 定义测试源文件路径列表

    @staticmethod
    def _sint(s, start=0, end=None):
        """Return the content of a string buffer as integer value.

        For example:
          _sint('1234') -> 4321
          _sint('123A') -> 17321
        """
        if isinstance(s, np.ndarray):  # 如果 s 是 numpy 数组
            s = s.tobytes()  # 将其转换为字节串
        elif isinstance(s, str):  # 如果 s 是字符串
            s = s.encode()  # 将其编码为字节串
        assert isinstance(s, bytes)  # 断言 s 确实是字节串
        if end is None:
            end = len(s)
        i = 0
        for j in range(start, min(end, len(s))):  # 遍历字节串的一部分
            i += s[j] * 10**j  # 将字节串的每个字符乘以相应的权值并求和,构成整数
        return i  # 返回整数结果

    def _get_input(self, intent="in"):
        if intent in ["in"]:  # 如果意图是输入
            yield ""  # 返回空字符串
            yield "1"  # 返回字符串 "1"
            yield "1234"  # 返回字符串 "1234"
            yield "12345"  # 返回字符串 "12345"
            yield b""  # 返回空字节串
            yield b"\0"  # 返回含有一个空字符的字节串
            yield b"1"  # 返回含有字符 '1' 的字节串
            yield b"\01"  # 返回含有字符 '\x01' 的字节串
            yield b"1\0"  # 返回含有字符 '1' 和一个空字符的字节串
            yield b"1234"  # 返回字节串 "1234"
            yield b"12345"  # 返回字节串 "12345"
        yield np.ndarray((), np.bytes_, buffer=b"")  # 返回一个空的 numpy 字节串数组
        yield np.array(b"")  # 返回一个空的 numpy 字节串数组
        yield np.array(b"\0")  # 返回一个含有一个空字符的 numpy 字节串数组
        yield np.array(b"1")  # 返回一个含有字符 '1' 的 numpy 字节串数组
        yield np.array(b"1\0")  # 返回一个含有字符 '1' 和一个空字符的 numpy 字节串数组
        yield np.array(b"\01")  # 返回一个含有字符 '\x01' 的 numpy 字节串数组
        yield np.array(b"1234")  # 返回一个含有字节串 "1234" 的 numpy 数组
        yield np.array(b"123\0")  # 返回一个含有字节串 "123\0" 的 numpy 数组
        yield np.array(b"12345")  # 返回一个含有字节串 "12345" 的 numpy 数组

    def test_intent_in(self):
        for s in self._get_input():
            r = self.module.test_in_bytes4(s)  # 调用模块方法,处理输入的字节串 s
            # also checks that s is not changed inplace
            expected = self._sint(s, end=4)  # 计算预期的整数值
            assert r == expected, s  # 断言处理结果与预期整数值相符

    def test_intent_inout(self):
        for s in self._get_input(intent="inout"):
            rest = self._sint(s, start=4)  # 获取字节串 s 的后四个字符的整数值
            r = self.module.test_inout_bytes4(s)  # 调用模块方法,处理输入的字节串 s
            expected = self._sint(s, end=4)  # 计算预期的整数值
            assert r == expected  # 断言处理结果与预期整数值相符

            # check that the rest of input string is preserved
            assert rest == self._sint(s, start=4)  # 断言字节串 s 的后四个字符的整数值与之前一致

.\numpy\numpy\f2py\tests\test_symbolic.py

# 导入 pytest 模块,用于单元测试
import pytest

# 从 numpy.f2py.symbolic 模块中导入多个符号化相关的类和函数
from numpy.f2py.symbolic import (
    Expr,           # 符号表达式类
    Op,             # 操作符类
    ArithOp,        # 算术操作符类
    Language,       # 语言类
    as_symbol,      # 转换为符号对象函数
    as_number,      # 转换为数字函数
    as_string,      # 转换为字符串函数
    as_array,       # 转换为数组函数
    as_complex,     # 转换为复数函数
    as_terms,       # 转换为项函数
    as_factors,     # 转换为因子函数
    eliminate_quotes,   # 消除引号函数
    insert_quotes,      # 插入引号函数
    fromstring,         # 从字符串创建对象函数
    as_expr,            # 转换为表达式函数
    as_apply,           # 转换为应用函数
    as_numer_denom,     # 转换为分子分母函数
    as_ternary,         # 转换为三元操作符函数
    as_ref,             # 转换为引用函数
    as_deref,           # 转换为解引用函数
    normalize,          # 标准化函数
    as_eq,              # 转换为等于操作符函数
    as_ne,              # 转换为不等于操作符函数
    as_lt,              # 转换为小于操作符函数
    as_gt,              # 转换为大于操作符函数
    as_le,              # 转换为小于等于操作符函数
    as_ge,              # 转换为大于等于操作符函数
)

# 从当前目录下的 util 模块中导入 F2PyTest 类
from . import util


# 定义 TestSymbolic 类,继承自 util.F2PyTest 类
class TestSymbolic(util.F2PyTest):
    
    # 定义单元测试方法 test_eliminate_quotes
    def test_eliminate_quotes(self):
        
        # 定义内部函数 worker,接收字符串 s 作为参数
        def worker(s):
            # 调用 eliminate_quotes 函数处理字符串 s,返回结果保存在 r 和 d 中
            r, d = eliminate_quotes(s)
            # 调用 insert_quotes 函数,使用 r 和 d,得到重新插入引号后的字符串 s1
            s1 = insert_quotes(r, d)
            # 断言重新插入引号后的字符串 s1 应该等于原始字符串 s
            assert s1 == s
        
        # 遍历测试用例中的两种情况:空字符串和 'mykind_' 字符串前缀
        for kind in ["", "mykind_"]:
            # 调用 worker 函数,传入拼接好的测试字符串
            worker(kind + '"1234" // "ABCD"')
            worker(kind + '"1234" // ' + kind + '"ABCD"')
            worker(kind + "\"1234\" // 'ABCD'")
            worker(kind + '"1234" // ' + kind + "'ABCD'")
            worker(kind + '"1\\"2\'AB\'34"')
            worker("a = " + kind + "'1\\'2\"AB\"34'")
    # 定义一个单元测试方法,用于测试符号、数字、复数、字符串、数组、项、因子、三元组和关系表达式的符号化函数
    def test_sanity(self):
        # 创建符号表达式 x, y, z
        x = as_symbol("x")
        y = as_symbol("y")
        z = as_symbol("z")

        # 断言符号表达式 x 的操作类型为 Op.SYMBOL
        assert x.op == Op.SYMBOL
        # 断言符号表达式 x 的字符串表示为 "Expr(Op.SYMBOL, 'x')"
        assert repr(x) == "Expr(Op.SYMBOL, 'x')"
        # 断言 x 等于自身
        assert x == x
        # 断言 x 不等于 y
        assert x != y
        # 断言 x 的哈希值不为 None
        assert hash(x) is not None

        # 创建整数表达式 n, m
        n = as_number(123)
        m = as_number(456)
        # 断言整数表达式 n 的操作类型为 Op.INTEGER
        assert n.op == Op.INTEGER
        # 断言整数表达式 n 的字符串表示为 "Expr(Op.INTEGER, (123, 4))"
        assert repr(n) == "Expr(Op.INTEGER, (123, 4))"
        # 断言 n 等于自身
        assert n == n
        # 断言 n 不等于 m
        assert n != m
        # 断言 n 的哈希值不为 None
        assert hash(n) is not None

        # 创建实数表达式 fn, fm
        fn = as_number(12.3)
        fm = as_number(45.6)
        # 断言实数表达式 fn 的操作类型为 Op.REAL
        assert fn.op == Op.REAL
        # 断言实数表达式 fn 的字符串表示为 "Expr(Op.REAL, (12.3, 4))"
        assert repr(fn) == "Expr(Op.REAL, (12.3, 4))"
        # 断言 fn 等于自身
        assert fn == fn
        # 断言 fn 不等于 fm
        assert fn != fm
        # 断言 fn 的哈希值不为 None
        assert hash(fn) is not None

        # 创建复数表达式 c, c2
        c = as_complex(1, 2)
        c2 = as_complex(3, 4)
        # 断言复数表达式 c 的操作类型为 Op.COMPLEX
        assert c.op == Op.COMPLEX
        # 断言复数表达式 c 的字符串表示为复杂的表达式
        assert repr(c) == ("Expr(Op.COMPLEX, (Expr(Op.INTEGER, (1, 4)), "
                           "Expr(Op.INTEGER, (2, 4))))")
        # 断言 c 等于自身
        assert c == c
        # 断言 c 不等于 c2
        assert c != c2
        # 断言 c 的哈希值不为 None
        assert hash(c) is not None

        # 创建字符串表达式 s, s2
        s = as_string("'123'")
        s2 = as_string('"ABC"')
        # 断言字符串表达式 s 的操作类型为 Op.STRING
        assert s.op == Op.STRING
        # 断言字符串表达式 s 的字符串表示为 "Expr(Op.STRING, (\"'123'\", 1))"
        assert repr(s) == "Expr(Op.STRING, (\"'123'\", 1))"
        # 断言 s 等于自身
        assert s == s
        # 断言 s 不等于 s2
        assert s != s2

        # 创建数组表达式 a, b
        a = as_array((n, m))
        b = as_array((n, ))
        # 断言数组表达式 a 的操作类型为 Op.ARRAY
        assert a.op == Op.ARRAY
        # 断言数组表达式 a 的字符串表示为复杂的数组表达式
        assert repr(a) == ("Expr(Op.ARRAY, (Expr(Op.INTEGER, (123, 4)), "
                           "Expr(Op.INTEGER, (456, 4))))")
        # 断言 a 等于自身
        assert a == a
        # 断言 a 不等于 b
        assert a != b

        # 创建项表达式 t, u
        t = as_terms(x)
        u = as_terms(y)
        # 断言项表达式 t 的操作类型为 Op.TERMS
        assert t.op == Op.TERMS
        # 断言项表达式 t 的字符串表示为 "Expr(Op.TERMS, {Expr(Op.SYMBOL, 'x'): 1})"
        assert repr(t) == "Expr(Op.TERMS, {Expr(Op.SYMBOL, 'x'): 1})"
        # 断言 t 等于自身
        assert t == t
        # 断言 t 不等于 u
        assert t != u
        # 断言 t 的哈希值不为 None
        assert hash(t) is not None

        # 创建因子表达式 v, w
        v = as_factors(x)
        w = as_factors(y)
        # 断言因子表达式 v 的操作类型为 Op.FACTORS
        assert v.op == Op.FACTORS
        # 断言因子表达式 v 的字符串表示为 "Expr(Op.FACTORS, {Expr(Op.SYMBOL, 'x'): 1})"
        assert repr(v) == "Expr(Op.FACTORS, {Expr(Op.SYMBOL, 'x'): 1})"
        # 断言 v 等于自身
        assert v == v
        # 断言 w 不等于 v
        assert w != v
        # 断言 v 的哈希值不为 None
        assert hash(v) is not None

        # 创建三元表达式 t, u
        t = as_ternary(x, y, z)
        u = as_ternary(x, z, y)
        # 断言三元表达式 t 的操作类型为 Op.TERNARY
        assert t.op == Op.TERNARY
        # 断言 t 等于自身
        assert t == t
        # 断言 t 不等于 u
        assert t != u
        # 断言 t 的哈希值不为 None
        assert hash(t) is not None

        # 创建等式表达式 e, f
        e = as_eq(x, y)
        f = as_lt(x, y)
        # 断言等式表达式 e 的操作类型为 Op.RELATIONAL
        assert e.op == Op.RELATIONAL
        # 断言 e 等于自身
        assert e == e
        # 断言 e 不等于 f
        assert e != f
        # 断言 e 的哈希值不为 None
        assert hash(e) is not None
    # 定义一个测试函数,用于测试生成字符串的函数
    def test_tostring_fortran(self):
        # 创建符号 'x', 'y', 'z',以及数字 123 和 456 的表示对象
        x = as_symbol("x")
        y = as_symbol("y")
        z = as_symbol("z")
        n = as_number(123)
        m = as_number(456)
        # 创建包含数字 n 和 m 的数组对象 a
        a = as_array((n, m))
        # 创建复数对象 c,以数字 n 和 m 作为实部和虚部
        c = as_complex(n, m)

        # 断言表达式对象的字符串表示与预期相符
        assert str(x) == "x"
        assert str(n) == "123"
        assert str(a) == "[123, 456]"
        assert str(c) == "(123, 456)"

        # 测试表达式对象中操作为 TERMS 的情况
        assert str(Expr(Op.TERMS, {x: 1})) == "x"
        assert str(Expr(Op.TERMS, {x: 2})) == "2 * x"
        assert str(Expr(Op.TERMS, {x: -1})) == "-x"
        assert str(Expr(Op.TERMS, {x: -2})) == "-2 * x"
        assert str(Expr(Op.TERMS, {x: 1, y: 1})) == "x + y"
        assert str(Expr(Op.TERMS, {x: -1, y: -1})) == "-x - y"
        assert str(Expr(Op.TERMS, {x: 2, y: 3})) == "2 * x + 3 * y"
        assert str(Expr(Op.TERMS, {x: -2, y: 3})) == "-2 * x + 3 * y"
        assert str(Expr(Op.TERMS, {x: 2, y: -3})) == "2 * x - 3 * y"

        # 测试表达式对象中操作为 FACTORS 的情况
        assert str(Expr(Op.FACTORS, {x: 1})) == "x"
        assert str(Expr(Op.FACTORS, {x: 2})) == "x ** 2"
        assert str(Expr(Op.FACTORS, {x: -1})) == "x ** -1"
        assert str(Expr(Op.FACTORS, {x: -2})) == "x ** -2"
        assert str(Expr(Op.FACTORS, {x: 1, y: 1})) == "x * y"
        assert str(Expr(Op.FACTORS, {x: 2, y: 3})) == "x ** 2 * y ** 3"

        # 测试混合操作:FACTORS 中包含 TERMS 的情况
        v = Expr(Op.FACTORS, {x: 2, Expr(Op.TERMS, {x: 1, y: 1}): 3})
        assert str(v) == "x ** 2 * (x + y) ** 3", str(v)
        v = Expr(Op.FACTORS, {x: 2, Expr(Op.FACTORS, {x: 1, y: 1}): 3})
        assert str(v) == "x ** 2 * (x * y) ** 3", str(v)

        # 测试 APPLY 操作
        assert str(Expr(Op.APPLY, ("f", (), {}))) == "f()"
        assert str(Expr(Op.APPLY, ("f", (x, ), {}))) == "f(x)"
        assert str(Expr(Op.APPLY, ("f", (x, y), {}))) == "f(x, y)"

        # 测试 INDEXING 操作
        assert str(Expr(Op.INDEXING, ("f", x))) == "f[x]"

        # 测试特定的字符串生成函数
        assert str(as_ternary(x, y, z)) == "merge(y, z, x)"
        assert str(as_eq(x, y)) == "x .eq. y"
        assert str(as_ne(x, y)) == "x .ne. y"
        assert str(as_lt(x, y)) == "x .lt. y"
        assert str(as_le(x, y)) == "x .le. y"
        assert str(as_gt(x, y)) == "x .gt. y"
        assert str(as_ge(x, y)) == "x .ge. y"
    # 定义一个测试函数,用于测试将表达式转换为字符串的功能
    def test_tostring_c(self):
        # 设置编程语言为C语言
        language = Language.C
        # 创建符号对象x, y, z,并将字符串与符号关联
        x = as_symbol("x")
        y = as_symbol("y")
        z = as_symbol("z")
        # 创建数字对象n,并将整数123与之关联
        n = as_number(123)

        # 断言:将Op.FACTORS操作应用于{x: 2}表达式,并将结果转换为字符串后与 "x * x" 比较
        assert Expr(Op.FACTORS, {x: 2}).tostring(language=language) == "x * x"
        # 断言:将Op.FACTORS操作应用于{x + y: 2}表达式,并将结果转换为字符串后与 "(x + y) * (x + y)" 比较
        assert (Expr(Op.FACTORS, {
            x + y: 2
        }).tostring(language=language) == "(x + y) * (x + y)")
        # 断言:将Op.FACTORS操作应用于{x: 12}表达式,并将结果转换为字符串后与 "pow(x, 12)" 比较
        assert Expr(Op.FACTORS, {
            x: 12
        }).tostring(language=language) == "pow(x, 12)"

        # 断言:将ArithOp.DIV操作应用于x和y,并将结果转换为字符串后与 "x / y" 比较
        assert as_apply(ArithOp.DIV, x,
                        y).tostring(language=language) == "x / y"
        # 断言:将ArithOp.DIV操作应用于x和(x + y),并将结果转换为字符串后与 "x / (x + y)" 比较
        assert (as_apply(ArithOp.DIV, x,
                         x + y).tostring(language=language) == "x / (x + y)")
        # 断言:将ArithOp.DIV操作应用于(x - y)和(x + y),并将结果转换为字符串后与 "(x - y) / (x + y)" 比较
        assert (as_apply(ArithOp.DIV, x - y, x +
                         y).tostring(language=language) == "(x - y) / (x + y)")
        # 断言:将x + (x - y) / (x + y) + n表达式转换为字符串后与 "123 + x + (x - y) / (x + y)" 比较
        assert (x + (x - y) / (x + y) +
                n).tostring(language=language) == "123 + x + (x - y) / (x + y)"

        # 断言:将x, y, z作为条件表达式的条件部分,转换为字符串后与 "(x?y:z)" 比较
        assert as_ternary(x, y, z).tostring(language=language) == "(x?y:z)"
        # 断言:将x == y关系运算转换为字符串后与 "x == y" 比较
        assert as_eq(x, y).tostring(language=language) == "x == y"
        # 断言:将x != y关系运算转换为字符串后与 "x != y" 比较
        assert as_ne(x, y).tostring(language=language) == "x != y"
        # 断言:将x < y关系运算转换为字符串后与 "x < y" 比较
        assert as_lt(x, y).tostring(language=language) == "x < y"
        # 断言:将x <= y关系运算转换为字符串后与 "x <= y" 比较
        assert as_le(x, y).tostring(language=language) == "x <= y"
        # 断言:将x > y关系运算转换为字符串后与 "x > y" 比较
        assert as_gt(x, y).tostring(language=language) == "x > y"
        # 断言:将x >= y关系运算转换为字符串后与 "x >= y" 比较
        assert as_ge(x, y).tostring(language=language) == "x >= y"
    # 定义一个测试函数,用于测试表达式操作
    def test_operations(self):
        # 创建符号变量 x, y, z
        x = as_symbol("x")
        y = as_symbol("y")
        z = as_symbol("z")

        # 断言:x + x 应该等于一个包含两个 x 的表达式
        assert x + x == Expr(Op.TERMS, {x: 2})
        # 断言:x - x 应该等于一个整数表达式,表示值为 0
        assert x - x == Expr(Op.INTEGER, (0, 4))
        # 断言:x + y 应该等于一个包含 x 和 y 的表达式
        assert x + y == Expr(Op.TERMS, {x: 1, y: 1})
        # 断言:x - y 应该等于一个包含 x 和 -y 的表达式
        assert x - y == Expr(Op.TERMS, {x: 1, y: -1})
        # 断言:x * x 应该等于一个包含两个 x 的因子表达式
        assert x * x == Expr(Op.FACTORS, {x: 2})
        # 断言:x * y 应该等于一个包含 x 和 y 的因子表达式
        assert x * y == Expr(Op.FACTORS, {x: 1, y: 1})

        # 断言:+x 应该等于 x
        assert +x == x
        # 断言:-x 应该等于一个包含 -1 倍 x 的表达式
        assert -x == Expr(Op.TERMS, {x: -1}), repr(-x)
        # 断言:2 * x 应该等于一个包含 2 倍 x 的表达式
        assert 2 * x == Expr(Op.TERMS, {x: 2})
        # 断言:2 + x 应该等于一个包含 1 个 x 和 2 的表达式
        assert 2 + x == Expr(Op.TERMS, {x: 1, as_number(1): 2})
        # 断言:2 * x + 3 * y 应该等于一个包含 2 倍 x 和 3 倍 y 的表达式
        assert 2 * x + 3 * y == Expr(Op.TERMS, {x: 2, y: 3})
        # 断言:(x + y) * 2 应该等于一个包含 2 倍 (x + y) 的表达式
        assert (x + y) * 2 == Expr(Op.TERMS, {x: 2, y: 2})

        # 断言:x 的平方应该等于一个包含两个 x 的因子表达式
        assert x**2 == Expr(Op.FACTORS, {x: 2})
        # 断言:(x + y) 的平方应该等于一个表达式,包含 x^2, y^2 和 2xy 的系数
        assert (x + y)**2 == Expr(
            Op.TERMS,
            {
                Expr(Op.FACTORS, {x: 2}): 1,
                Expr(Op.FACTORS, {y: 2}): 1,
                Expr(Op.FACTORS, {
                    x: 1,
                    y: 1
                }): 2,
            },
        )
        # 断言:(x + y) * x 应该等于 x^2 + xy 的表达式
        assert (x + y) * x == x**2 + x * y
        # 断言:(x + y) 的平方应该等于 x^2 + 2xy + y^2 的表达式
        assert (x + y)**2 == x**2 + 2 * x * y + y**2
        # 断言:(x + y) 的平方加上 (x - y) 的平方应该等于 2x^2 + 2y^2 的表达式
        assert (x + y)**2 + (x - y)**2 == 2 * x**2 + 2 * y**2
        # 断言:(x + y) * z 应该等于 xz + yz 的表达式
        assert (x + y) * z == x * z + y * z
        # 断言:z * (x + y) 应该等于 zx + zy 的表达式
        assert z * (x + y) == x * z + y * z

        # 断言:(x / 2) 应该等于一个包含 x 和 2 的除法表达式
        assert (x / 2) == as_apply(ArithOp.DIV, x, as_number(2))
        # 断言:(2 * x / 2) 应该等于 x
        assert (2 * x / 2) == x
        # 断言:(3 * x / 2) 应该等于一个包含 3x 和 2 的除法表达式
        assert (3 * x / 2) == as_apply(ArithOp.DIV, 3 * x, as_number(2))
        # 断言:(4 * x / 2) 应该等于 2x 的表达式
        assert (4 * x / 2) == 2 * x
        # 断言:(5 * x / 2) 应该等于一个包含 5x 和 2 的除法表达式
        assert (5 * x / 2) == as_apply(ArithOp.DIV, 5 * x, as_number(2))
        # 断言:(6 * x / 2) 应该等于 3x 的表达式
        assert (6 * x / 2) == 3 * x
        # 断言:((3 * 5) * x / 6) 应该等于一个包含 5x 和 2 的除法表达式
        assert ((3 * 5) * x / 6) == as_apply(ArithOp.DIV, 5 * x, as_number(2))
        # 断言:(30 * x^2 * y^4 / (24 * x^3 * y^3)) 应该等于一个包含 5y 和 4x 的除法表达式
        assert (30 * x**2 * y**4 / (24 * x**3 * y**3)) == as_apply(
            ArithOp.DIV, 5 * y, 4 * x)
        # 断言:((15 * x / 6) / 5) 应该等于一个包含 x 和 2 的除法表达式
        assert ((15 * x / 6) / 5) == as_apply(ArithOp.DIV, x,
                                              as_number(2)), (15 * x / 6) / 5
        # 断言:(x / (5 / x)) 应该等于一个包含 x^2 和 5 的除法表达式
        assert (x / (5 / x)) == as_apply(ArithOp.DIV, x**2, as_number(5))

        # 断言:(x / 2.0) 应该等于一个包含 x 和 0.5 的表达式
        assert (x / 2.0) == Expr(Op.TERMS, {x: 0.5})

        # 创建字符串 s 和 t
        s = as_string('"ABC"')
        t = as_string('"123"')

        # 断言:s // t 应该等于一个包含 "ABC123" 的字符串连接表达式
        assert s // t == Expr(Op.STRING, ('"ABC123"', 1))
        # 断言:s // x 应该等于一个包含 s 和 x 的字符串连接表达式
        assert s // x == Expr(Op.CONCAT, (s, x))
        # 断言:x // s 应该等于一个包含 x 和 s 的字符串连接表达式
        assert x // s == Expr(Op.CONCAT, (x, s))

        # 创建复数 c
        c = as_complex(1.0, 2.0)
        # 断言:-c 应该等于一个包含 -1-2j 的复数表达式
        assert -c == as_complex(-1.0, -2.0)
        # 断言:c + c 应该等于一个包含 (1+2j)*2 的表达式
        assert c + c == as_expr((1 + 2j) * 2)
        # 断言:c * c 应该等于一个
    # 定义测试函数 test_substitute,用于测试符号替换的功能
    def test_substitute(self):
        # 创建符号 x, y, z 并分别初始化为相应的符号对象
        x = as_symbol("x")
        y = as_symbol("y")
        z = as_symbol("z")
        # 创建数组 a,并将 x, y 作为元素
        a = as_array((x, y))

        # 断言语句:测试替换 x 为 y 的情况
        assert x.substitute({x: y}) == y
        # 断言语句:测试替换 x 为 z 后加法表达式的情况
        assert (x + y).substitute({x: z}) == y + z
        # 断言语句:测试替换 x 为 z 后乘法表达式的情况
        assert (x * y).substitute({x: z}) == y * z
        # 断言语句:测试替换 x 为 z 后幂运算的情况
        assert (x**4).substitute({x: z}) == z**4
        # 断言语句:测试替换 x 为 z 后除法表达式的情况
        assert (x / y).substitute({x: z}) == z / y
        # 断言语句:测试替换 x 为 y + z 后的情况
        assert x.substitute({x: y + z}) == y + z
        # 断言语句:测试数组 a 替换 x 为 y + z 后的情况
        assert a.substitute({x: y + z}) == as_array((y + z, y))

        # 断言语句:测试替换 x 为 y + z 后三元运算符的情况
        assert as_ternary(x, y, z).substitute({x: y + z}) == as_ternary(y + z, y, z)
        # 断言语句:测试替换 x 为 y + z 后等式表达式的情况
        assert as_eq(x, y).substitute({x: y + z}) == as_eq(y + z, y)

    # 定义测试函数 test_traverse,用于测试符号遍历的功能
    def test_traverse(self):
        # 创建符号 x, y, z, f 并分别初始化为相应的符号对象
        x = as_symbol("x")
        y = as_symbol("y")
        z = as_symbol("z")
        f = as_symbol("f")

        # 定义替换函数 replace_visit,用于符号遍历中的替换操作,默认替换为 z
        def replace_visit(s, r=z):
            if s == x:
                return r

        # 断言语句:测试使用替换函数 replace_visit 替换 x 的情况
        assert x.traverse(replace_visit) == z
        # 断言语句:测试替换其他符号时不变的情况
        assert y.traverse(replace_visit) == y
        assert z.traverse(replace_visit) == z
        assert (f(y)).traverse(replace_visit) == f(y)
        assert (f(x)).traverse(replace_visit) == f(z)
        assert (f[y]).traverse(replace_visit) == f[y]
        assert (f[z]).traverse(replace_visit) == f[z]
        # 断言语句:测试复杂表达式替换 x 后的情况
        assert (x + y + z).traverse(replace_visit) == (2 * z + y)
        assert (x + f(y, x - z)).traverse(replace_visit) == (z + f(y, as_number(0)))

        # 定义符号收集函数 collect_symbols,用于遍历中收集符号和函数
        function_symbols = set()
        symbols = set()

        def collect_symbols(s):
            if s.op is Op.APPLY:
                oper = s.data[0]
                function_symbols.add(oper)
                if oper in symbols:
                    symbols.remove(oper)
            elif s.op is Op.SYMBOL and s not in function_symbols:
                symbols.add(s)

        # 断言语句:测试符号收集函数 collect_symbols 的功能
        (x + f(y, x - z)).traverse(collect_symbols)
        assert function_symbols == {f}
        assert symbols == {x, y, z}

        # 定义第二种符号收集函数 collect_symbols2,用于遍历中收集符号
        def collect_symbols2(expr, symbols):
            if expr.op is Op.SYMBOL:
                symbols.add(expr)

        symbols = set()
        # 断言语句:测试第二种符号收集函数 collect_symbols2 的功能
        (x + f(y, x - z)).traverse(collect_symbols2, symbols)
        assert symbols == {x, y, z, f}

        # 定义第三种部分符号收集函数 collect_symbols3,用于部分符号的遍历收集
        def collect_symbols3(expr, symbols):
            if expr.op is Op.APPLY:
                # 跳过对函数调用的遍历
                return expr
            if expr.op is Op.SYMBOL:
                symbols.add(expr)

        symbols = set()
        # 断言语句:测试第三种部分符号收集函数 collect_symbols3 的功能
        (x + f(y, x - z)).traverse(collect_symbols3, symbols)
        assert symbols == {x}
    # 定义测试线性求解的函数
    def test_linear_solve(self):
        # 创建符号变量 x, y, z
        x = as_symbol("x")
        y = as_symbol("y")
        z = as_symbol("z")

        # 测试 x.linear_solve(x),期望返回 (1, 0)
        assert x.linear_solve(x) == (as_number(1), as_number(0))
        # 测试 (x + 1).linear_solve(x),期望返回 (1, 1)
        assert (x + 1).linear_solve(x) == (as_number(1), as_number(1))
        # 测试 (2 * x).linear_solve(x),期望返回 (2, 0)
        assert (2 * x).linear_solve(x) == (as_number(2), as_number(0))
        # 测试 (2 * x + 3).linear_solve(x),期望返回 (2, 3)
        assert (2 * x + 3).linear_solve(x) == (as_number(2), as_number(3))
        # 测试 as_number(3).linear_solve(x),期望返回 (0, 3)
        assert as_number(3).linear_solve(x) == (as_number(0), as_number(3))
        # 测试 y.linear_solve(x),期望返回 (0, y)
        assert y.linear_solve(x) == (as_number(0), y)
        # 测试 (y * z).linear_solve(x),期望返回 (0, y * z)
        assert (y * z).linear_solve(x) == (as_number(0), y * z)

        # 测试 (x + y).linear_solve(x),期望返回 (1, y)
        assert (x + y).linear_solve(x) == (as_number(1), y)
        # 测试 (z * x + y).linear_solve(x),期望返回 (z, y)
        assert (z * x + y).linear_solve(x) == (z, y)
        # 测试 ((z + y) * x + y).linear_solve(x),期望返回 (z + y, y)
        assert ((z + y) * x + y).linear_solve(x) == (z + y, y)
        # 测试 (z * y * x + y).linear_solve(x),期望返回 (z * y, y)
        assert (z * y * x + y).linear_solve(x) == (z * y, y)

        # 测试抛出 RuntimeError 的情况:(x * x).linear_solve(x)
        pytest.raises(RuntimeError, lambda: (x * x).linear_solve(x))

    # 定义测试将表达式转换为分子分母形式的函数
    def test_as_numer_denom(self):
        # 创建符号变量 x, y,并设定常数 n = 123
        x = as_symbol("x")
        y = as_symbol("y")
        n = as_number(123)

        # 测试 as_numer_denom(x),期望返回 (x, 1)
        assert as_numer_denom(x) == (x, as_number(1))
        # 测试 as_numer_denom(x / n),期望返回 (x, n)
        assert as_numer_denom(x / n) == (x, n)
        # 测试 as_numer_denom(n / x),期望返回 (n, x)
        assert as_numer_denom(n / x) == (n, x)
        # 测试 as_numer_denom(x / y),期望返回 (x, y)
        assert as_numer_denom(x / y) == (x, y)
        # 测试 as_numer_denom(x * y),期望返回 (x * y, 1)
        assert as_numer_denom(x * y) == (x * y, as_number(1))
        # 测试 as_numer_denom(n + x / y),期望返回 (x + n * y, y)
        assert as_numer_denom(n + x / y) == (x + n * y, y)
        # 测试 as_numer_denom(n + x / (y - x / n)),期望返回 (y * n**2, y * n - x)
        assert as_numer_denom(n + x / (y - x / n)) == (y * n**2, y * n - x)

    # 定义测试多项式的原子项的函数
    def test_polynomial_atoms(self):
        # 创建符号变量 x, y,并设定常数 n = 123
        x = as_symbol("x")
        y = as_symbol("y")
        n = as_number(123)

        # 测试 x.polynomial_atoms(),期望返回 {x}
        assert x.polynomial_atoms() == {x}
        # 测试 n.polynomial_atoms(),期望返回空集合
        assert n.polynomial_atoms() == set()
        # 测试 (y[x]).polynomial_atoms(),期望返回 {y[x]}
        assert (y[x]).polynomial_atoms() == {y[x]}
        # 测试 (y(x)).polynomial_atoms(),期望返回 {y(x)}
        assert (y(x)).polynomial_atoms() == {y(x)}
        # 测试 (y(x) + x).polynomial_atoms(),期望返回 {y(x), x}
        assert (y(x) + x).polynomial_atoms() == {y(x), x}
        # 测试 (y(x) * x[y]).polynomial_atoms(),期望返回 {y(x), x[y]}
        assert (y(x) * x[y]).polynomial_atoms() == {y(x), x[y]}
        # 测试 (y(x)**x).polynomial_atoms(),期望返回 {y(x)}
        assert (y(x)**x).polynomial_atoms() == {y(x)}

.\numpy\numpy\f2py\tests\test_value_attrspec.py

# 导入标准库 os 和 pytest 模块
import os
import pytest

# 从当前包中导入 util 模块
from . import util

# 定义测试类 TestValueAttr,继承自 util.F2PyTest
class TestValueAttr(util.F2PyTest):
    # 指定源文件路径列表,该路径为 util 模块中的 getpath 函数返回的路径
    sources = [util.getpath("tests", "src", "value_attrspec", "gh21665.f90")]

    # 标记为慢速测试(slow),用以区分测试的特性或执行时间
    @pytest.mark.slow
    # 定义测试方法 test_gh21665,用于测试 GitHub 问题编号为 21665 的情况
    def test_gh21665(self):
        # 输入值为 2
        inp = 2
        # 调用被测试模块(self.module)中的 fortfuncs 对象的 square 方法,并传入输入值 inp
        out = self.module.fortfuncs.square(inp)
        # 预期输出值为 4
        exp_out = 4
        # 断言实际输出值与预期输出值相等
        assert out == exp_out

.\numpy\numpy\f2py\tests\util.py

"""
Utility functions for

- building and importing modules on test time, using a temporary location
- detecting if compilers are present
- determining paths to tests

"""
# 导入必要的库和模块
import glob
import os
import sys
import subprocess
import tempfile
import shutil
import atexit
import textwrap
import re
import pytest
import contextlib
import numpy
import concurrent.futures

from pathlib import Path
from numpy._utils import asunicode
from numpy.testing import temppath, IS_WASM
from importlib import import_module
from numpy.f2py._backends._meson import MesonBackend

#
# Maintaining a temporary module directory
#

# 初始化临时模块目录和模块编号
_module_dir = None
_module_num = 5403

# 如果运行平台是cygwin,设置numpy的安装根目录
if sys.platform == "cygwin":
    NUMPY_INSTALL_ROOT = Path(__file__).parent.parent.parent
    _module_list = list(NUMPY_INSTALL_ROOT.glob("**/*.dll"))


def _cleanup():
    global _module_dir
    # 清理临时模块目录
    if _module_dir is not None:
        try:
            sys.path.remove(_module_dir)
        except ValueError:
            pass
        try:
            shutil.rmtree(_module_dir)
        except OSError:
            pass
        _module_dir = None


def get_module_dir():
    global _module_dir
    # 获取临时模块目录,如果不存在则创建
    if _module_dir is None:
        _module_dir = tempfile.mkdtemp()
        atexit.register(_cleanup)
        if _module_dir not in sys.path:
            sys.path.insert(0, _module_dir)
    return _module_dir


def get_temp_module_name():
    # 获取一个唯一的临时模块名
    global _module_num
    get_module_dir()
    name = "_test_ext_module_%d" % _module_num
    _module_num += 1
    if name in sys.modules:
        # 检查是否已存在同名模块,理论上不应该出现这种情况
        raise RuntimeError("Temporary module name already in use.")
    return name


def _memoize(func):
    memo = {}

    def wrapper(*a, **kw):
        key = repr((a, kw))
        if key not in memo:
            try:
                memo[key] = func(*a, **kw)
            except Exception as e:
                memo[key] = e
                raise
        ret = memo[key]
        if isinstance(ret, Exception):
            raise ret
        return ret

    wrapper.__name__ = func.__name__
    return wrapper

#
# Building modules
#


@_memoize
def build_module(source_files, options=[], skip=[], only=[], module_name=None):
    """
    Compile and import a f2py module, built from the given files.

    """

    # 准备执行编译操作的代码字符串
    code = f"import sys; sys.path = {sys.path!r}; import numpy.f2py; numpy.f2py.main()"

    # 获取临时模块目录
    d = get_module_dir()

    # 复制文件到临时模块目录并准备编译所需的源文件列表
    dst_sources = []
    f2py_sources = []
    for fn in source_files:
        if not os.path.isfile(fn):
            raise RuntimeError("%s is not a file" % fn)
        dst = os.path.join(d, os.path.basename(fn))
        shutil.copyfile(fn, dst)
        dst_sources.append(dst)

        base, ext = os.path.splitext(dst)
        if ext in (".f90", ".f95", ".f", ".c", ".pyf"):
            f2py_sources.append(dst)

    assert f2py_sources

    # 准备编译选项
    # 如果模块名未指定,则生成临时模块名
    if module_name is None:
        module_name = get_temp_module_name()

    # 构建 f2py 的选项列表,包括编译选项、模块名和源文件列表
    f2py_opts = ["-c", "-m", module_name] + options + f2py_sources
    f2py_opts += ["--backend", "meson"]

    # 如果有跳过的选项,则添加到 f2py 的选项列表中
    if skip:
        f2py_opts += ["skip:"] + skip

    # 如果有仅包含的选项,则添加到 f2py 的选项列表中
    if only:
        f2py_opts += ["only:"] + only

    # 构建
    # 保存当前工作目录
    cwd = os.getcwd()
    try:
        # 切换到指定目录 d
        os.chdir(d)
        # 构建执行的命令列表,包括 Python 解释器、执行代码、f2py 选项
        cmd = [sys.executable, "-c", code] + f2py_opts
        # 启动子进程执行命令,捕获标准输出和标准错误
        p = subprocess.Popen(cmd,
                             stdout=subprocess.PIPE,
                             stderr=subprocess.STDOUT)
        out, err = p.communicate()
        # 如果返回码不为 0,则抛出运行时错误
        if p.returncode != 0:
            raise RuntimeError("Running f2py failed: %s\n%s" %
                               (cmd[4:], asunicode(out)))
    finally:
        # 恢复到之前保存的工作目录
        os.chdir(cwd)

        # 部分清理
        # 删除指定的源文件列表中的文件
        for fn in dst_sources:
            os.unlink(fn)

    # 重新基址(仅适用于 Cygwin)
    if sys.platform == "cygwin":
        # 如果在导入后有人开始删除模块,则需要更改以记录每个模块的大小,
        # 而不是依赖 rebase 能够从文件中找到这些信息。
        # 将模块名匹配的文件列表扩展到 _module_list 中
        _module_list.extend(
            glob.glob(os.path.join(d, "{:s}*".format(module_name)))
        )
        # 调用 rebase 进行重新基址,使用数据库和详细模式
        subprocess.check_call(
            ["/usr/bin/rebase", "--database", "--oblivious", "--verbose"]
            + _module_list
        )

    # 导入模块
    return import_module(module_name)
# 装饰器函数,用于对 build_code 函数进行记忆化(memoization)
@_memoize
# 编译给定的 Fortran 代码并导入为模块
def build_code(source_code,
               options=[],
               skip=[],
               only=[],
               suffix=None,
               module_name=None):
    """
    Compile and import Fortran code using f2py.
    编译并导入 Fortran 代码,使用 f2py 工具。
    """
    # 如果未指定后缀名,则默认为 .f
    if suffix is None:
        suffix = ".f"
    # 利用临时路径创建一个文件,写入源代码
    with temppath(suffix=suffix) as path:
        with open(path, "w") as f:
            f.write(source_code)
        # 调用 build_module 函数,编译指定路径的代码文件为模块并返回
        return build_module([path],
                            options=options,
                            skip=skip,
                            only=only,
                            module_name=module_name)


#
# 检查是否至少有一个编译器可用...
#

# 检查指定语言的编译器是否可用
def check_language(lang, code_snippet=None):
    # 创建一个临时目录
    tmpdir = tempfile.mkdtemp()
    try:
        # 在临时目录下创建一个 Meson 构建文件
        meson_file = os.path.join(tmpdir, "meson.build")
        with open(meson_file, "w") as f:
            f.write("project('check_compilers')\n")
            f.write(f"add_languages('{lang}')\n")
            if code_snippet:
                f.write(f"{lang}_compiler = meson.get_compiler('{lang}')\n")
                f.write(f"{lang}_code = '''{code_snippet}'''\n")
                f.write(
                    f"_have_{lang}_feature ="
                    f"{lang}_compiler.compiles({lang}_code,"
                    f" name: '{lang} feature check')\n"
                )
        # 在临时目录下运行 Meson 进行设置
        runmeson = subprocess.run(
            ["meson", "setup", "btmp"],
            check=False,
            cwd=tmpdir,
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
        )
        # 如果 Meson 设置成功返回 True,否则返回 False
        if runmeson.returncode == 0:
            return True
        else:
            return False
    finally:
        # 最后删除临时目录及其内容
        shutil.rmtree(tmpdir)
    return False

# Fortran 77 示例代码
fortran77_code = '''
C Example Fortran 77 code
      PROGRAM HELLO
      PRINT *, 'Hello, Fortran 77!'
      END
'''

# Fortran 90 示例代码
fortran90_code = '''
! Example Fortran 90 code
program hello90
  type :: greeting
    character(len=20) :: text
  end type greeting

  type(greeting) :: greet
  greet%text = 'hello, fortran 90!'
  print *, greet%text
end program hello90
'''

# 用于缓存相关检查的虚拟类
class CompilerChecker:
    def __init__(self):
        self.compilers_checked = False
        self.has_c = False
        self.has_f77 = False
        self.has_f90 = False

    # 检查各种编译器的可用性
    def check_compilers(self):
        if (not self.compilers_checked) and (not sys.platform == "cygwin"):
            with concurrent.futures.ThreadPoolExecutor() as executor:
                futures = [
                    executor.submit(check_language, "c"),
                    executor.submit(check_language, "fortran", fortran77_code),
                    executor.submit(check_language, "fortran", fortran90_code)
                ]
                # 获取并记录每种语言的编译器可用性
                self.has_c = futures[0].result()
                self.has_f77 = futures[1].result()
                self.has_f90 = futures[2].result()

            self.compilers_checked = True

# 如果不是 WebAssembly 环境,创建一个编译器检查实例并进行检查
if not IS_WASM:
    checker = CompilerChecker()
    checker.check_compilers()

# 检查是否有 C 编译器可用
def has_c_compiler():
    # 返回变量 checker 的属性 has_c 的值
    return checker.has_c
# 检查当前系统是否具有 Fortran 77 编译器
def has_f77_compiler():
    return checker.has_f77

# 检查当前系统是否具有 Fortran 90 编译器
def has_f90_compiler():
    return checker.has_f90

#
# 使用 Meson 构建
#


class SimplifiedMesonBackend(MesonBackend):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

    # 编译方法,生成 Meson 构建文件并执行构建
    def compile(self):
        self.write_meson_build(self.build_dir)  # 写入 Meson 构建文件到指定目录
        self.run_meson(self.build_dir)  # 在指定目录运行 Meson 构建


def build_meson(source_files, module_name=None, **kwargs):
    """
    通过 Meson 构建并导入一个模块。
    """
    build_dir = get_module_dir()  # 获取模块的构建目录
    if module_name is None:
        module_name = get_temp_module_name()  # 获取临时模块名称

    # 初始化 SimplifiedMesonBackend 实例
    backend = SimplifiedMesonBackend(
        modulename=module_name,
        sources=source_files,
        extra_objects=kwargs.get("extra_objects", []),
        build_dir=build_dir,
        include_dirs=kwargs.get("include_dirs", []),
        library_dirs=kwargs.get("library_dirs", []),
        libraries=kwargs.get("libraries", []),
        define_macros=kwargs.get("define_macros", []),
        undef_macros=kwargs.get("undef_macros", []),
        f2py_flags=kwargs.get("f2py_flags", []),
        sysinfo_flags=kwargs.get("sysinfo_flags", []),
        fc_flags=kwargs.get("fc_flags", []),
        flib_flags=kwargs.get("flib_flags", []),
        setup_flags=kwargs.get("setup_flags", []),
        remove_build_dir=kwargs.get("remove_build_dir", False),
        extra_dat=kwargs.get("extra_dat", {}),
    )

    # 编译模块
    # 注意:由于没有 distutils,很难确定 CI 上使用的编译器栈,因此使用了一个捕获所有异常的通用处理
    try:
        backend.compile()
    except:
        pytest.skip("Failed to compile module")  # 若编译失败则跳过测试

    # 导入编译后的模块
    sys.path.insert(0, f"{build_dir}/{backend.meson_build_dir}")
    return import_module(module_name)


#
# 单元测试便利性
#


class F2PyTest:
    code = None
    sources = None
    options = []
    skip = []
    only = []
    suffix = ".f"
    module = None
    _has_c_compiler = None
    _has_f77_compiler = None
    _has_f90_compiler = None

    @property
    def module_name(self):
        cls = type(self)
        return f'_{cls.__module__.rsplit(".",1)[-1]}_{cls.__name__}_ext_module'

    @classmethod
    def setup_class(cls):
        if sys.platform == "win32":
            pytest.skip("Fails with MinGW64 Gfortran (Issue #9673)")
        F2PyTest._has_c_compiler = has_c_compiler()  # 检查当前系统是否具有 C 编译器
        F2PyTest._has_f77_compiler = has_f77_compiler()  # 检查当前系统是否具有 Fortran 77 编译器
        F2PyTest._has_f90_compiler = has_f90_compiler()  # 检查当前系统是否具有 Fortran 90 编译器
    # 设置测试方法的准备工作
    def setup_method(self):
        # 如果模块已经存在,则直接返回,避免重复设置
        if self.module is not None:
            return

        # 初始化代码列表,默认为空列表
        codes = self.sources if self.sources else []

        # 如果有单独的代码文件(self.code),将其添加到代码列表中
        if self.code:
            codes.append(self.suffix)

        # 检查代码列表中是否有需要使用 Fortran 77、Fortran 90 或 Python-Fortran 源文件的需求
        needs_f77 = any(str(fn).endswith(".f") for fn in codes)
        needs_f90 = any(str(fn).endswith(".f90") for fn in codes)
        needs_pyf = any(str(fn).endswith(".pyf") for fn in codes)

        # 如果需要 Fortran 77 编译器但系统没有,则跳过测试
        if needs_f77 and not self._has_f77_compiler:
            pytest.skip("No Fortran 77 compiler available")

        # 如果需要 Fortran 90 编译器但系统没有,则跳过测试
        if needs_f90 and not self._has_f90_compiler:
            pytest.skip("No Fortran 90 compiler available")

        # 如果需要 Python-Fortran 但系统没有支持的编译器,则跳过测试
        if needs_pyf and not (self._has_f90_compiler or self._has_f77_compiler):
            pytest.skip("No Fortran compiler available")

        # 如果指定了代码(self.code),则使用 build_code 函数构建模块
        if self.code is not None:
            self.module = build_code(
                self.code,
                options=self.options,
                skip=self.skip,
                only=self.only,
                suffix=self.suffix,
                module_name=self.module_name,
            )

        # 如果指定了源文件列表(self.sources),则使用 build_module 函数构建模块
        if self.sources is not None:
            self.module = build_module(
                self.sources,
                options=self.options,
                skip=self.skip,
                only=self.only,
                module_name=self.module_name,
            )
#
# Helper functions
#


# 根据给定的路径参数构造并返回路径对象
def getpath(*a):
    # 获取 numpy.f2py 模块的文件路径,并获取其父目录的绝对路径作为根目录
    d = Path(numpy.f2py.__file__).parent.resolve()
    return d.joinpath(*a)


# 上下文管理器,用于临时切换工作目录至指定路径,并在结束时恢复原工作目录
@contextlib.contextmanager
def switchdir(path):
    # 获取当前工作目录
    curpath = Path.cwd()
    # 切换工作目录至指定路径
    os.chdir(path)
    try:
        yield  # 执行被装饰函数体
    finally:
        # 最终恢复原工作目录
        os.chdir(curpath)

.\numpy\numpy\f2py\tests\__init__.py

# 从 numpy.testing 模块中导入 IS_WASM 和 IS_EDITABLE 常量
from numpy.testing import IS_WASM, IS_EDITABLE
# 从 pytest 模块中导入 pytest 函数或类

# 如果 IS_WASM 常量为真,则跳过当前测试,并提供相应的消息
if IS_WASM:
    pytest.skip(
        "WASM/Pyodide does not use or support Fortran",
        allow_module_level=True
    )

# 如果 IS_EDITABLE 常量为真,则跳过当前测试,并提供相应的消息
if IS_EDITABLE:
    pytest.skip(
        "Editable install doesn't support tests with a compile step",
        allow_module_level=True
    )

.\numpy\numpy\f2py\use_rules.py

"""
Build 'use others module data' mechanism for f2py2e.

Copyright 1999 -- 2011 Pearu Peterson all rights reserved.
Copyright 2011 -- present NumPy Developers.
Permission to use, modify, and distribute this software is given under the
terms of the NumPy License.

NO WARRANTY IS EXPRESSED OR IMPLIED.  USE AT YOUR OWN RISK.
"""
__version__ = "$Revision: 1.3 $"[10:-1]

# 设置 f2py2e 的版本号信息
f2py_version = 'See `f2py -v`'

# 导入 auxfuncs 模块中的若干函数
from .auxfuncs import (
    applyrules, dictappend, gentitle, hasnote, outmess
)

# 定义 usemodule_rules 字典,包含针对不同部分的模板和需求
usemodule_rules = {
    'body': """
#begintitle#
static char doc_#apiname#[] = \"\\\nVariable wrapper signature:\\n\\
\t #name# = get_#name#()\\n\\
Arguments:\\n\\
#docstr#\";
extern F_MODFUNC(#usemodulename#,#USEMODULENAME#,#realname#,#REALNAME#);
static PyObject *#apiname#(PyObject *capi_self, PyObject *capi_args) {
/*#decl#*/
\tif (!PyArg_ParseTuple(capi_args, \"\")) goto capi_fail;
printf(\"c: %d\\n\",F_MODFUNC(#usemodulename#,#USEMODULENAME#,#realname#,#REALNAME#));
\treturn Py_BuildValue(\"\");
capi_fail:
\treturn NULL;
}
""",
    'method': '\t{\"get_#name#\",#apiname#,METH_VARARGS|METH_KEYWORDS,doc_#apiname#},',
    'need': ['F_MODFUNC']
}

################

# 定义 buildusevars 函数,用于构建模块的使用变量钩子
def buildusevars(m, r):
    ret = {}  # 初始化返回的字典
    outmess(
        '\t\tBuilding use variable hooks for module "%s" (feature only for F90/F95)...\n' % (m['name']))
    varsmap = {}  # 初始化变量映射字典
    revmap = {}  # 初始化反向映射字典

    # 如果规则字典中包含映射关系,处理重复和变量映射
    if 'map' in r:
        for k in r['map'].keys():
            if r['map'][k] in revmap:
                outmess('\t\t\tVariable "%s<=%s" is already mapped by "%s". Skipping.\n' % (
                    r['map'][k], k, revmap[r['map'][k]]))
            else:
                revmap[r['map'][k]] = k

    # 如果只允许特定映射,并且规则中声明了,只处理符合条件的变量
    if 'only' in r and r['only']:
        for v in r['map'].keys():
            if r['map'][v] in m['vars']:
                if revmap[r['map'][v]] == v:
                    varsmap[v] = r['map'][v]
                else:
                    outmess('\t\t\tIgnoring map "%s=>%s". See above.\n' %
                            (v, r['map'][v]))
            else:
                outmess(
                    '\t\t\tNo definition for variable "%s=>%s". Skipping.\n' % (v, r['map'][v]))
    else:
        for v in m['vars'].keys():
            if v in revmap:
                varsmap[v] = revmap[v]
            else:
                varsmap[v] = v

    # 根据映射关系构建使用变量的字典
    for v in varsmap.keys():
        ret = dictappend(ret, buildusevar(v, varsmap[v], m['vars'], m['name']))

    return ret

# 定义 buildusevar 函数,用于构建单个变量的包装器函数
def buildusevar(name, realname, vars, usemodulename):
    outmess('\t\t\tConstructing wrapper function for variable "%s=>%s"...\n' % (
        name, realname))
    ret = {}  # 初始化返回的字典
    # 创建一个字典 vrd,包含各种与名称相关的键值对
    vrd = {'name': name,
           'realname': realname,
           'REALNAME': realname.upper(),  # 将 realname 转换为大写保存到 REALNAME 键中
           'usemodulename': usemodulename,
           'USEMODULENAME': usemodulename.upper(),  # 将 usemodulename 转换为大写保存到 USEMODULENAME 键中
           'texname': name.replace('_', '\\_'),  # 将名称中的下划线替换为转义后的斜线保存到 texname 键中
           'begintitle': gentitle('%s=>%s' % (name, realname)),  # 使用 gentitle 函数生成名称和真实名称的标题保存到 begintitle 键中
           'endtitle': gentitle('end of %s=>%s' % (name, realname)),  # 使用 gentitle 函数生成名称和真实名称结尾的标题保存到 endtitle 键中
           'apiname': '#modulename#_use_%s_from_%s' % (realname, usemodulename)  # 生成 API 名称保存到 apiname 键中
           }
    
    # 创建一个数字映射的字典 nummap
    nummap = {0: 'Ro', 1: 'Ri', 2: 'Rii', 3: 'Riii', 4: 'Riv',
              5: 'Rv', 6: 'Rvi', 7: 'Rvii', 8: 'Rviii', 9: 'Rix'}
    
    # 将 texnamename 键设置为初始的名称
    vrd['texnamename'] = name
    
    # 替换名称中的数字为对应的罗马数字
    for i in nummap.keys():
        vrd['texnamename'] = vrd['texnamename'].replace(repr(i), nummap[i])
    
    # 如果 realname 在 vars 中有注释,则将注释保存到 vrd 的 note 键中
    if hasnote(vars[realname]):
        vrd['note'] = vars[realname]['note']
    
    # 将 vrd 添加到一个新创建的字典 rd 中
    rd = dictappend({}, vrd)

    # 打印 name、realname 和 vars[realname] 的内容
    print(name, realname, vars[realname])
    
    # 应用 usemodule_rules 到 rd 上,并返回结果
    ret = applyrules(usemodule_rules, rd)
    return ret

.\numpy\numpy\f2py\_backends\_backend.py

# 引入从 Python 3.7 开始的类型注解特性,用于声明类型
from __future__ import annotations

# 引入抽象基类(Abstract Base Class)模块
from abc import ABC, abstractmethod

# 定义名为 Backend 的抽象基类,继承自 ABC 类
class Backend(ABC):
    # 初始化方法,接收多个参数用于配置编译环境
    def __init__(
        self,
        modulename,         # 模块名
        sources,            # 源文件列表
        extra_objects,      # 额外的对象文件列表
        build_dir,          # 构建目录
        include_dirs,       # 包含文件目录列表
        library_dirs,       # 库文件目录列表
        libraries,          # 库名列表
        define_macros,      # 宏定义列表
        undef_macros,       # 未定义宏列表
        f2py_flags,         # f2py 标志列表
        sysinfo_flags,      # 系统信息标志列表
        fc_flags,           # fc 编译器标志列表
        flib_flags,         # flib 标志列表
        setup_flags,        # 设置标志列表
        remove_build_dir,   # 是否移除构建目录的标志
        extra_dat           # 额外的数据
    ):
        # 将传入的参数分别赋值给实例变量
        self.modulename = modulename
        self.sources = sources
        self.extra_objects = extra_objects
        self.build_dir = build_dir
        self.include_dirs = include_dirs
        self.library_dirs = library_dirs
        self.libraries = libraries
        self.define_macros = define_macros
        self.undef_macros = undef_macros
        self.f2py_flags = f2py_flags
        self.sysinfo_flags = sysinfo_flags
        self.fc_flags = fc_flags
        self.flib_flags = flib_flags
        self.setup_flags = setup_flags
        self.remove_build_dir = remove_build_dir
        self.extra_dat = extra_dat

    @abstractmethod
    def compile(self) -> None:
        """Compile the wrapper."""
        pass

.\numpy\numpy\f2py\_backends\_distutils.py

# 从 _backend 模块导入 Backend 类
from ._backend import Backend

# 导入 numpy.distutils.core 模块中的 setup 和 Extension 类
from numpy.distutils.core import setup, Extension
# 导入 numpy.distutils.system_info 模块中的 get_info 函数
from numpy.distutils.system_info import get_info
# 导入 numpy.distutils.misc_util 模块中的 dict_append 函数
from numpy.distutils.misc_util import dict_append
# 导入 numpy.exceptions 中的 VisibleDeprecationWarning 异常
from numpy.exceptions import VisibleDeprecationWarning

# 导入标准库中的 os、sys、shutil、warnings 模块
import os
import sys
import shutil
import warnings

# 定义 DistutilsBackend 类,继承自 Backend 类
class DistutilsBackend(Backend):
    # 初始化方法
    def __init__(sef, *args, **kwargs):
        # 发出 VisibleDeprecationWarning 警告,提示 distutils 已自 NumPy 1.26.x 起废弃
        warnings.warn(
            "\ndistutils has been deprecated since NumPy 1.26.x\n"
            "Use the Meson backend instead, or generate wrappers"
            " without -c and use a custom build script",
            VisibleDeprecationWarning,
            stacklevel=2,
        )
        # 调用父类 Backend 的初始化方法
        super().__init__(*args, **kwargs)

    # 编译方法
    def compile(self):
        # 初始化 num_info 字典为空
        num_info = {}
        # 如果 num_info 不为空,则将其 include_dirs 属性添加到 self.include_dirs 中
        if num_info:
            self.include_dirs.extend(num_info.get("include_dirs", []))
        
        # 构建 Extension 对象的参数字典 ext_args
        ext_args = {
            "name": self.modulename,
            "sources": self.sources,
            "include_dirs": self.include_dirs,
            "library_dirs": self.library_dirs,
            "libraries": self.libraries,
            "define_macros": self.define_macros,
            "undef_macros": self.undef_macros,
            "extra_objects": self.extra_objects,
            "f2py_options": self.f2py_flags,
        }

        # 如果 self.sysinfo_flags 不为空,则遍历 self.sysinfo_flags 列表
        if self.sysinfo_flags:
            for n in self.sysinfo_flags:
                # 调用 get_info 函数获取名称为 n 的系统信息并赋值给 i
                i = get_info(n)
                # 如果 i 为空,则打印相关信息提示找不到资源
                if not i:
                    print(
                        f"No {repr(n)} resources found"
                        "in system (try `f2py --help-link`)"
                    )
                # 将获取的系统信息 i 添加到 ext_args 字典中
                dict_append(ext_args, **i)

        # 创建 Extension 对象 ext
        ext = Extension(**ext_args)

        # 设置 sys.argv 的参数以便进行 setup 操作
        sys.argv = [sys.argv[0]] + self.setup_flags
        sys.argv.extend(
            [
                "build",
                "--build-temp",
                self.build_dir,
                "--build-base",
                self.build_dir,
                "--build-platlib",
                ".",
                "--disable-optimization",
            ]
        )

        # 如果 self.fc_flags 不为空,则将其添加到 sys.argv 中
        if self.fc_flags:
            sys.argv.extend(["config_fc"] + self.fc_flags)
        # 如果 self.flib_flags 不为空,则将其添加到 sys.argv 中
        if self.flib_flags:
            sys.argv.extend(["build_ext"] + self.flib_flags)

        # 调用 setup 函数进行模块的扩展编译,使用之前构建的 Extension 对象 ext
        setup(ext_modules=[ext])

        # 如果设置了 remove_build_dir 为 True,并且 self.build_dir 存在,则删除该目录
        if self.remove_build_dir and os.path.exists(self.build_dir):
            print(f"Removing build directory {self.build_dir}")
            shutil.rmtree(self.build_dir)

.\numpy\numpy\f2py\_backends\_meson.py

    # 从 __future__ 导入 annotations 特性,用于支持注解类型提示
    from __future__ import annotations

    # 导入操作系统相关模块
    import os
    # 导入 errno 模块,用于处理错误码
    import errno
    # 导入 shutil 模块,用于文件操作
    import shutil
    # 导入 subprocess 模块,用于执行外部命令
    import subprocess
    # 导入 sys 模块,提供对 Python 解释器的访问
    import sys
    # 导入 re 模块,用于正则表达式操作
    import re
    # 导入 pathlib 中的 Path 类
    from pathlib import Path

    # 从 _backend 模块导入 Backend 类
    from ._backend import Backend
    # 导入 string 模块中的 Template 类,用于字符串模板替换
    from string import Template
    # 导入 itertools 模块中的 chain 函数,用于迭代工具函数
    from itertools import chain

    # 导入 warnings 模块,用于处理警告信息

    # MesonTemplate 类,用于生成 Meson 构建文件模板
    class MesonTemplate:
        """Template meson build file generation class."""

        # 初始化方法,接收多个参数用于设置模板的各项属性
        def __init__(
            self,
            modulename: str,         # 模块名
            sources: list[Path],     # 源文件路径列表
            deps: list[str],         # 依赖模块列表
            libraries: list[str],    # 库列表
            library_dirs: list[Path],# 库目录列表
            include_dirs: list[Path],# 包含目录列表
            object_files: list[Path],# 目标文件列表
            linker_args: list[str],  # 链接器参数列表
            fortran_args: list[str], # Fortran 编译器参数列表
            build_type: str,         # 构建类型
            python_exe: str,         # Python 解释器路径
        ):
            # 初始化各属性
            self.modulename = modulename
            # 设置构建模板文件路径
            self.build_template_path = (
                Path(__file__).parent.absolute() / "meson.build.template"
            )
            self.sources = sources          # 源文件列表
            self.deps = deps                # 依赖模块列表
            self.libraries = libraries      # 库列表
            self.library_dirs = library_dirs# 库目录列表
            # 如果 include_dirs 不为 None,则使用给定列表,否则为空列表
            if include_dirs is not None:
                self.include_dirs = include_dirs
            else:
                self.include_dirs = []
            self.substitutions = {}         # 模板替换字典
            self.objects = object_files     # 目标文件列表

            # 将 Fortran 编译器参数转换为 Meson 需要的格式
            self.fortran_args = [
                f"'{x}'" if not (x.startswith("'") and x.endswith("'")) else x
                for x in fortran_args
            ]

            # 定义模板处理管道,按顺序调用各个替换方法
            self.pipeline = [
                self.initialize_template,
                self.sources_substitution,
                self.deps_substitution,
                self.include_substitution,
                self.libraries_substitution,
                self.fortran_args_substitution,
            ]

            self.build_type = build_type     # 构建类型
            self.python_exe = python_exe     # Python 解释器路径
            self.indent = " " * 21           # 缩进字符串

        # 生成 Meson 构建模板文件内容的方法,返回字符串
        def meson_build_template(self) -> str:
            # 检查构建模板文件是否存在,如果不存在则抛出 FileNotFoundError 异常
            if not self.build_template_path.is_file():
                raise FileNotFoundError(
                    errno.ENOENT,
                    "Meson build template"
                    f" {self.build_template_path.absolute()}"
                    " does not exist.",
                )
            # 读取并返回构建模板文件的文本内容
            return self.build_template_path.read_text()

        # 初始化模板替换字典的方法
        def initialize_template(self) -> None:
            self.substitutions["modulename"] = self.modulename  # 设置模块名替换项
            self.substitutions["buildtype"] = self.build_type   # 设置构建类型替换项
            self.substitutions["python"] = self.python_exe      # 设置 Python 解释器路径替换项

        # 替换源文件列表的方法
        def sources_substitution(self) -> None:
            self.substitutions["source_list"] = ",\n".join(
                [f"{self.indent}'''{source}'''," for source in self.sources]
            )

        # 替换依赖模块列表的方法
        def deps_substitution(self) -> None:
            self.substitutions["dep_list"] = f",\n{self.indent}".join(
                [f"{self.indent}dependency('{dep}')," for dep in self.deps]
            )
    # 定义一个方法用于处理库目录的替换
    def libraries_substitution(self) -> None:
        # 将每个库目录生成声明依赖的字符串,并连接成一个换行分隔的字符串
        self.substitutions["lib_dir_declarations"] = "\n".join(
            [
                f"lib_dir_{i} = declare_dependency(link_args : ['''-L{lib_dir}'''])"
                for i, lib_dir in enumerate(self.library_dirs)
            ]
        )

        # 将每个库生成声明依赖的字符串,并连接成一个换行分隔的字符串
        self.substitutions["lib_declarations"] = "\n".join(
            [
                f"{lib.replace('.','_')} = declare_dependency(link_args : ['-l{lib}'])"
                for lib in self.libraries
            ]
        )

        # 生成库列表的字符串,每个库名替换点号为下划线,并以缩进开始每行
        self.substitutions["lib_list"] = f"\n{self.indent}".join(
            [f"{self.indent}{lib.replace('.','_')}," for lib in self.libraries]
        )
        
        # 生成库目录列表的字符串,以缩进开始每行
        self.substitutions["lib_dir_list"] = f"\n{self.indent}".join(
            [f"{self.indent}lib_dir_{i}," for i in range(len(self.library_dirs))]
        )

    # 定义一个方法用于处理包含文件路径的替换
    def include_substitution(self) -> None:
        # 生成包含文件路径列表的字符串,每个路径以三引号括起来,并以缩进开始每行
        self.substitutions["inc_list"] = f",\n{self.indent}".join(
            [f"{self.indent}'''{inc}'''," for inc in self.include_dirs]
        )

    # 定义一个方法用于处理 Fortran 编译参数的替换
    def fortran_args_substitution(self) -> None:
        # 如果有 Fortran 编译参数,生成对应的字符串;否则为空字符串
        if self.fortran_args:
            self.substitutions["fortran_args"] = (
                f"{self.indent}fortran_args: [{', '.join([arg for arg in self.fortran_args])}],"
            )
        else:
            self.substitutions["fortran_args"] = ""

    # 定义一个方法用于生成 Meson 构建文件
    def generate_meson_build(self):
        # 执行管道中每个节点的操作
        for node in self.pipeline:
            node()
        
        # 使用 Meson 构建模板创建模板对象
        template = Template(self.meson_build_template())
        # 根据替换字典替换模板中的变量
        meson_build = template.substitute(self.substitutions)
        # 去除生成字符串中可能存在的连续逗号
        meson_build = re.sub(r",,", ",", meson_build)
        # 返回最终生成的 Meson 构建文件内容
        return meson_build
# 定义 MesonBackend 类,继承自 Backend 类
class MesonBackend(Backend):
    # 初始化方法,接收任意位置参数和关键字参数
    def __init__(self, *args, **kwargs):
        # 调用父类 Backend 的初始化方法
        super().__init__(*args, **kwargs)
        # 从 extra_dat 中获取依赖列表,默认为空列表
        self.dependencies = self.extra_dat.get("dependencies", [])
        # 设置 Meson 的构建目录为 "bbdir"
        self.meson_build_dir = "bbdir"
        # 确定构建类型是 "debug" 还是 "release",根据 self.fc_flags 中是否包含 "debug" 标志决定
        self.build_type = (
            "debug" if any("debug" in flag for flag in self.fc_flags) else "release"
        )
        # 处理编译标志,调用 _get_flags 函数对 self.fc_flags 进行处理
        self.fc_flags = _get_flags(self.fc_flags)

    # 将生成的可执行文件移动到根目录下的私有方法
    def _move_exec_to_root(self, build_dir: Path):
        # 设置遍历目录为 build_dir 下的 self.meson_build_dir 目录
        walk_dir = Path(build_dir) / self.meson_build_dir
        # 构建文件路径迭代器,包含所有与 self.modulename 匹配的 .so 和 .pyd 文件
        path_objects = chain(
            walk_dir.glob(f"{self.modulename}*.so"),
            walk_dir.glob(f"{self.modulename}*.pyd"),
        )
        # 遍历所有文件路径对象
        for path_object in path_objects:
            # 设置目标路径为当前工作目录下的 path_object 的文件名
            dest_path = Path.cwd() / path_object.name
            # 如果目标路径存在,则删除
            if dest_path.exists():
                dest_path.unlink()
            # 复制 path_object 到 dest_path
            shutil.copy2(path_object, dest_path)
            # 删除原始文件 path_object
            os.remove(path_object)

    # 写入 Meson 构建文件的方法,接收构建目录参数 build_dir,并返回 None
    def write_meson_build(self, build_dir: Path) -> None:
        """Writes the meson build file at specified location"""
        # 创建 MesonTemplate 对象,生成 Meson 构建文件内容
        meson_template = MesonTemplate(
            self.modulename,
            self.sources,
            self.dependencies,
            self.libraries,
            self.library_dirs,
            self.include_dirs,
            self.extra_objects,
            self.flib_flags,
            self.fc_flags,
            self.build_type,
            sys.executable,
        )
        # 创建构建目录 build_dir(如果不存在),确保父目录存在
        Path(build_dir).mkdir(parents=True, exist_ok=True)
        # 构建 Meson 构建文件路径
        meson_build_file = Path(build_dir) / "meson.build"
        # 将生成的 Meson 构建文件内容写入到 meson_build_file
        meson_build_file.write_text(src)
        # 返回生成的 Meson 构建文件路径 meson_build_file
        return meson_build_file

    # 运行子进程命令的私有方法,接收命令和工作目录参数
    def _run_subprocess_command(self, command, cwd):
        # 在指定工作目录 cwd 下运行命令 subprocess.run,检查返回状态
        subprocess.run(command, cwd=cwd, check=True)

    # 运行 Meson 构建系统的方法,接收构建目录参数 build_dir
    def run_meson(self, build_dir: Path):
        # 设置 Meson 的 setup 命令,初始化 self.meson_build_dir 目录
        setup_command = ["meson", "setup", self.meson_build_dir]
        # 调用 _run_subprocess_command 方法运行 setup_command,设置工作目录为 build_dir
        self._run_subprocess_command(setup_command, build_dir)
        # 设置 Meson 的 compile 命令,编译 self.meson_build_dir 目录下的项目
        compile_command = ["meson", "compile", "-C", self.meson_build_dir]
        # 调用 _run_subprocess_command 方法运行 compile_command,设置工作目录为 build_dir
        self._run_subprocess_command(compile_command, build_dir)

    # 编译方法,返回 None
    def compile(self) -> None:
        # 准备源文件列表,调用 _prepare_sources 函数,更新 self.sources
        self.sources = _prepare_sources(self.modulename, self.sources, self.build_dir)
        # 写入 Meson 构建文件到 self.build_dir
        self.write_meson_build(self.build_dir)
        # 运行 Meson 构建系统,设置工作目录为 self.build_dir
        self.run_meson(self.build_dir)
        # 移动生成的可执行文件到根目录
        self._move_exec_to_root(self.build_dir)


# 准备源文件的函数,接收模块名 mname、源文件列表 sources 和构建目录 bdir
def _prepare_sources(mname, sources, bdir):
    # 复制原始源文件列表到 extended_sources
    extended_sources = sources.copy()
    # 创建构建目录 bdir(如果不存在),确保父目录存在
    Path(bdir).mkdir(parents=True, exist_ok=True)
    # 遍历源文件列表 sources
    for source in sources:
        # 如果源文件路径 source 存在且为文件
        if Path(source).exists() and Path(source).is_file():
            # 将源文件复制到构建目录 bdir
            shutil.copy(source, bdir)
    # 生成的源文件列表
    generated_sources = [
        Path(f"{mname}module.c"),
        Path(f"{mname}-f2pywrappers2.f90"),
        Path(f"{mname}-f2pywrappers.f"),
    ]
    # 设置构建目录为 Path 对象 bdir
    bdir = Path(bdir)
    # 遍历生成的源文件列表
    for generated_source in generated_sources:
        # 检查生成的源文件是否存在
        if generated_source.exists():
            # 将生成的源文件复制到目标目录中,保留原文件名
            shutil.copy(generated_source, bdir / generated_source.name)
            # 将复制后的文件名添加到扩展源文件列表中
            extended_sources.append(generated_source.name)
            # 删除原始的生成源文件
            generated_source.unlink()

    # 从扩展源文件列表中提取文件名,同时过滤掉后缀为“.pyf”的文件
    extended_sources = [
        Path(source).name
        for source in extended_sources
        if not Path(source).suffix == ".pyf"
    ]

    # 返回经过筛选和处理的扩展源文件名列表
    return extended_sources
# 定义一个函数 _get_flags,用于从给定的 fc_flags 列表中提取标志值并返回一个去重后的列表
def _get_flags(fc_flags):
    # 初始化一个空列表,用于存储提取出的标志值
    flag_values = []
    
    # 定义一个正则表达式模式,用于匹配形如 "--f77flags=xxx" 或 "--f90flags=xxx" 的标志
    flag_pattern = re.compile(r"--f(77|90)flags=(.*)")
    
    # 遍历 fc_flags 列表中的每一个标志
    for flag in fc_flags:
        # 尝试在当前标志中匹配 flag_pattern
        match_result = flag_pattern.match(flag)
        
        # 如果匹配成功
        if match_result:
            # 获取匹配结果中第二个分组(即标志值部分),去除首尾空格后按空格分割,然后去除每个元素的引号
            values = match_result.group(2).strip().split()
            values = [val.strip("'\"") for val in values]
            
            # 将处理后的标志值列表合并到 flag_values 中
            flag_values.extend(values)
    
    # 使用字典的方式来去除重复的标志值,从而保持标志值的顺序
    unique_flags = list(dict.fromkeys(flag_values))
    
    # 返回去重后的标志值列表
    return unique_flags

.\numpy\numpy\f2py\_backends\__init__.py

# 定义一个函数,用于根据给定的 name 参数生成不同的构建后端生成器
def f2py_build_generator(name):
    # 如果 name 参数为 "meson"
    if name == "meson":
        # 导入 MesonBackend 类并返回
        from ._meson import MesonBackend
        return MesonBackend
    # 如果 name 参数为 "distutils"
    elif name == "distutils":
        # 导入 DistutilsBackend 类并返回
        from ._distutils import DistutilsBackend
        return DistutilsBackend
    else:
        # 如果 name 参数不是预期的值,则引发 ValueError 异常
        raise ValueError(f"Unknown backend: {name}")

.\numpy\numpy\f2py\_isocbind.py

"""
ISO_C_BINDING maps for f2py2e.
Only required declarations/macros/functions will be used.

Copyright 1999 -- 2011 Pearu Peterson all rights reserved.
Copyright 2011 -- present NumPy Developers.
Permission to use, modify, and distribute this software is given under the
terms of the NumPy License.

NO WARRANTY IS EXPRESSED OR IMPLIED.  USE AT YOUR OWN RISK.
"""

# 定义 ISO_C_BINDING 映射字典,用于将 C 类型映射到对应的 Fortran 类型
iso_c_binding_map = {
    'integer': {
        'c_int': 'int',                   # 将 'c_int' 映射到 'int'
        'c_short': 'short',               # 将 'c_short' 映射到 'short'
        'c_long': 'long',                 # 将 'c_long' 映射到 'long'
        'c_long_long': 'long_long',       # 将 'c_long_long' 映射到 'long_long'
        'c_signed_char': 'signed_char',   # 将 'c_signed_char' 映射到 'signed_char'
        'c_size_t': 'unsigned',           # 将 'c_size_t' 映射到 'unsigned'
        'c_int8_t': 'signed_char',        # 将 'c_int8_t' 映射到 'signed_char'
        'c_int16_t': 'short',             # 将 'c_int16_t' 映射到 'short'
        'c_int32_t': 'int',               # 将 'c_int32_t' 映射到 'int'
        'c_int64_t': 'long_long',         # 将 'c_int64_t' 映射到 'long_long'
        'c_int_least8_t': 'signed_char',  # 将 'c_int_least8_t' 映射到 'signed_char'
        'c_int_least16_t': 'short',       # 将 'c_int_least16_t' 映射到 'short'
        'c_int_least32_t': 'int',         # 将 'c_int_least32_t' 映射到 'int'
        'c_int_least64_t': 'long_long',   # 将 'c_int_least64_t' 映射到 'long_long'
        'c_int_fast8_t': 'signed_char',   # 将 'c_int_fast8_t' 映射到 'signed_char'
        'c_int_fast16_t': 'short',        # 将 'c_int_fast16_t' 映射到 'short'
        'c_int_fast32_t': 'int',          # 将 'c_int_fast32_t' 映射到 'int'
        'c_int_fast64_t': 'long_long',    # 将 'c_int_fast64_t' 映射到 'long_long'
        'c_intmax_t': 'long_long',        # 将 'c_intmax_t' 映射到 'long_long'
        'c_intptr_t': 'long',             # 将 'c_intptr_t' 映射到 'long'
        'c_ptrdiff_t': 'long',            # 将 'c_ptrdiff_t' 映射到 'long'
    },
    'real': {
        'c_float': 'float',               # 将 'c_float' 映射到 'float'
        'c_double': 'double',             # 将 'c_double' 映射到 'double'
        'c_long_double': 'long_double'    # 将 'c_long_double' 映射到 'long_double'
    },
    'complex': {
        'c_float_complex': 'complex_float',         # 将 'c_float_complex' 映射到 'complex_float'
        'c_double_complex': 'complex_double',       # 将 'c_double_complex' 映射到 'complex_double'
        'c_long_double_complex': 'complex_long_double'  # 将 'c_long_double_complex' 映射到 'complex_long_double'
    },
    'logical': {
        'c_bool': 'unsigned_char'         # 将 'c_bool' 映射到 'unsigned_char'
    },
    'character': {
        'c_char': 'char'                  # 将 'c_char' 映射到 'char'
    }
}

# TODO: See gh-25229

# 定义空字典 isoc_c2pycode_map 和 isoc_c2py_map,用于后续的映射操作
isoc_c2pycode_map = {}
iso_c2py_map = {}

# 定义空字典 isoc_kindmap,用于将 C 类型映射到对应的 Fortran 类型
isoc_kindmap = {}

# 遍历 iso_c_binding_map 中的每个 Fortran 类型和其对应的 C 类型字典
for fortran_type, c_type_dict in iso_c_binding_map.items():
    # 遍历每个 C 类型及其对应的 Fortran 类型
    for c_type in c_type_dict.keys():
        # 将当前的 C 类型映射到对应的 Fortran 类型
        isoc_kindmap[c_type] = fortran_type

.\numpy\numpy\f2py\_src_pyf.py

# 导入 re 模块,用于正则表达式操作
import re

# START OF CODE VENDORED FROM `numpy.distutils.from_template`
#############################################################
"""
process_file(filename)

  takes templated file .xxx.src and produces .xxx file where .xxx
  is .pyf .f90 or .f using the following template rules:

  '<..>' denotes a template.

  All function and subroutine blocks in a source file with names that
  contain '<..>' will be replicated according to the rules in '<..>'.

  The number of comma-separated words in '<..>' will determine the number of
  replicates.

  '<..>' may have two different forms, named and short. For example,

  named:
   <p=d,s,z,c> where anywhere inside a block '<p>' will be replaced with
   'd', 's', 'z', and 'c' for each replicate of the block.

   <_c>  is already defined: <_c=s,d,c,z>
   <_t>  is already defined: <_t=real,double precision,complex,double complex>

  short:
   <s,d,c,z>, a short form of the named, useful when no <p> appears inside
   a block.

  In general, '<..>' contains a comma separated list of arbitrary
  expressions. If these expression must contain a comma|leftarrow|rightarrow,
  then prepend the comma|leftarrow|rightarrow with a backslash.

  If an expression matches '\\<index>' then it will be replaced
  by <index>-th expression.

  Note that all '<..>' forms in a block must have the same number of
  comma-separated entries.

 Predefined named template rules:
  <prefix=s,d,c,z>
  <ftype=real,double precision,complex,double complex>
  <ftypereal=real,double precision,\\0,\\1>
  <ctype=float,double,complex_float,complex_double>
  <ctypereal=float,double,\\0,\\1>
"""

# 正则表达式,用于匹配子程序(subroutine)和函数(function)的开始
routine_start_re = re.compile(r'(\n|\A)((     (\$|\*))|)\s*(subroutine|function)\b', re.I)
# 正则表达式,用于匹配子程序(subroutine)和函数(function)的结束
routine_end_re = re.compile(r'\n\s*end\s*(subroutine|function)\b.*(\n|\Z)', re.I)
# 正则表达式,用于匹配函数(function)的开始
function_start_re = re.compile(r'\n     (\$|\*)\s*function\b', re.I)

def parse_structure(astr):
    """ Return a list of tuples for each function or subroutine each
    tuple is the start and end of a subroutine or function to be
    expanded.
    """
    # 初始化存储子程序和函数起始和结束位置的列表
    spanlist = []
    ind = 0
    while True:
        # 搜索子程序或函数的开始位置
        m = routine_start_re.search(astr, ind)
        if m is None:
            break
        start = m.start()
        if function_start_re.match(astr, start, m.end()):
            while True:
                # 找到函数的起始位置
                i = astr.rfind('\n', ind, start)
                if i == -1:
                    break
                start = i
                if astr[i:i+7] != '\n     $':
                    break
        start += 1
        # 搜索子程序或函数的结束位置
        m = routine_end_re.search(astr, m.end())
        ind = end = m and m.end()-1 or len(astr)
        spanlist.append((start, end))
    return spanlist

# 正则表达式,用于匹配模板标记(<..>)
template_re = re.compile(r"<\s*(\w[\w\d]*)\s*>")
# 正则表达式,用于匹配命名模板标记(<name=value>)
named_re = re.compile(r"<\s*(\w[\w\d]*)\s*=\s*(.*?)\s*>")
# 正则表达式,用于匹配简单的模板标记(<...>)
list_re = re.compile(r"<\s*((.*?))\s*>")

def find_repl_patterns(astr):
    # 使用命名模板正则表达式,找到所有命名模板标记并返回
    reps = named_re.findall(astr)
    names = {}
    # 对于每一个替换规则 rep 在 reps 列表中进行迭代
    for rep in reps:
        # 获取替换规则的名称,去除首尾空格,如果为空则使用唯一键生成一个新的名称
        name = rep[0].strip() or unique_key(names)
        # 获取替换规则的内容 repl,并将其中的逗号转换为特殊标记 '@comma@'
        repl = rep[1].replace(r'\,', '@comma@')
        # 使用 conv 函数对替换内容 repl 进行处理,转换为列表形式
        thelist = conv(repl)
        # 将处理后的替换规则名称 name 关联到处理后的列表内容 thelist
        names[name] = thelist
    # 返回处理后的所有替换规则名称及其对应的列表内容组成的字典 names
    return names
def find_and_remove_repl_patterns(astr):
    # 调用 find_repl_patterns 函数,找到并返回替换模式的名称列表
    names = find_repl_patterns(astr)
    # 使用 re.subn 函数将命名的替换模式替换为空字符串,并取替换后的字符串部分
    astr = re.subn(named_re, '', astr)[0]
    return astr, names

item_re = re.compile(r"\A\\(?P<index>\d+)\Z")
def conv(astr):
    # 将字符串按逗号分割成列表 b
    b = astr.split(',')
    # 对列表中的每个元素去除首尾空格,形成列表 l
    l = [x.strip() for x in b]
    # 遍历列表 l 的索引
    for i in range(len(l)):
        # 使用正则表达式 item_re 匹配列表元素 l[i]
        m = item_re.match(l[i])
        if m:
            # 如果匹配成功,提取匹配的索引号并转换为整数 j
            j = int(m.group('index'))
            # 将 l[i] 替换为列表中索引为 j 的元素
            l[i] = l[j]
    # 将列表 l 拼接成以逗号分隔的字符串并返回
    return ','.join(l)

def unique_key(adict):
    """ Obtain a unique key given a dictionary."""
    # 将字典的所有键转换成列表 allkeys
    allkeys = list(adict.keys())
    done = False
    n = 1
    while not done:
        # 构造新的键名
        newkey = '__l%s' % (n)
        if newkey in allkeys:
            n += 1
        else:
            done = True
    # 返回一个确保在字典中唯一的新键名
    return newkey

template_name_re = re.compile(r'\A\s*(\w[\w\d]*)\s*\Z')
def expand_sub(substr, names):
    # 将字符串中的特殊字符替换为标记,便于后续处理
    substr = substr.replace(r'\>', '@rightarrow@')
    substr = substr.replace(r'\<', '@leftarrow@')
    # 调用 find_repl_patterns 函数,找到并返回替换模式的名称列表
    lnames = find_repl_patterns(substr)
    # 使用 named_re 替换 substr 中的定义模板,将其替换为标准的 <name> 形式
    substr = named_re.sub(r"<\1>", substr)

    def listrepl(mobj):
        # 获取列表内容并进行处理,将特殊字符转换回逗号,并匹配已存在的列表名称
        thelist = conv(mobj.group(1).replace(r'\,', '@comma@'))
        if template_name_re.match(thelist):
            return "<%s>" % (thelist)
        name = None
        for key in lnames.keys():    # 查看列表是否已存在于字典中
            if lnames[key] == thelist:
                name = key
        if name is None:      # 若列表尚未存在于字典中
            name = unique_key(lnames)
            lnames[name] = thelist
        return "<%s>" % name

    substr = list_re.sub(listrepl, substr) # 将所有列表转换为命名模板
                                           # 根据需要构建新的名称

    numsubs = None
    base_rule = None
    rules = {}
    for r in template_re.findall(substr):
        if r not in rules:
            # 获取规则对应的替换列表
            thelist = lnames.get(r, names.get(r, None))
            if thelist is None:
                raise ValueError('No replicates found for <%s>' % (r))
            # 若规则不在 names 中,则添加到 names 中
            if r not in names and not thelist.startswith('_'):
                names[r] = thelist
            # 将规则转换为列表,并获取其长度
            rule = [i.replace('@comma@', ',') for i in thelist.split(',')]
            num = len(rule)

            if numsubs is None:
                numsubs = num
                rules[r] = rule
                base_rule = r
            elif num == numsubs:
                rules[r] = rule
            else:
                print("Mismatch in number of replacements (base <{}={}>) "
                      "for <{}={}>. Ignoring.".format(base_rule, ','.join(rules[base_rule]), r, thelist))
    if not rules:
        return substr

    def namerepl(mobj):
        # 获取命名规则并进行替换
        name = mobj.group(1)
        return rules.get(name, (k+1)*[name])[k]

    newstr = ''
    for k in range(numsubs):
        newstr += template_re.sub(namerepl, substr) + '\n\n'

    # 替换特殊标记为原字符
    newstr = newstr.replace('@rightarrow@', '>')
    newstr = newstr.replace('@leftarrow@', '<')
    return newstr

def process_str(allstr):
    # 初始化字符串处理
    newstr = allstr
    writestr = ''
    # 解析给定字符串的结构并返回结构化数据
    struct = parse_structure(newstr)
    
    # 初始化一个变量用于跟踪旧的结束位置
    oldend = 0
    
    # 初始化一个空字典用于存储变量名和对应的值,将特殊名称初始化到字典中
    names = {}
    names.update(_special_names)
    
    # 遍历结构化数据中的每个子结构
    for sub in struct:
        # 在原始字符串中查找和移除替换模式的定义,返回清理后的字符串和新定义的变量字典
        cleanedstr, defs = find_and_remove_repl_patterns(newstr[oldend:sub[0]])
        # 将清理后的字符串追加到输出字符串中
        writestr += cleanedstr
        # 更新变量名字典,添加新的定义
        names.update(defs)
        # 将子结构展开并添加到输出字符串中
        writestr += expand_sub(newstr[sub[0]:sub[1]], names)
        # 更新旧的结束位置为当前子结构的结束位置,以便继续处理下一个子结构
        oldend = sub[1]
    
    # 将剩余的未处理部分字符串添加到输出字符串中
    writestr += newstr[oldend:]
    
    # 返回最终生成的完整字符串
    return writestr
# 匹配包含文件名的行,以便解析 include 语句
include_src_re = re.compile(r"(\n|\A)\s*include\s*['\"](?P<name>[\w\d./\\]+\.src)['\"]", re.I)

# 解析源文件中的 include 语句,并展开所有包含的文件内容
def resolve_includes(source):
    # 获取源文件的目录路径
    d = os.path.dirname(source)
    # 打开源文件
    with open(source) as fid:
        lines = []
        # 逐行处理源文件内容
        for line in fid:
            # 尝试匹配 include_src_re 正则表达式
            m = include_src_re.match(line)
            if m:
                # 提取匹配到的文件名
                fn = m.group('name')
                # 如果文件名不是绝对路径,则与源文件目录路径拼接
                if not os.path.isabs(fn):
                    fn = os.path.join(d, fn)
                # 如果文件存在,则递归处理其内容
                if os.path.isfile(fn):
                    lines.extend(resolve_includes(fn))
                else:
                    lines.append(line)  # 否则直接添加当前行到结果列表
            else:
                lines.append(line)  # 将未匹配到的行直接添加到结果列表
    return lines

# 处理给定源文件的包含语句,并返回处理后的结果
def process_file(source):
    # 解析所有 include 并展开内容后的源文件内容
    lines = resolve_includes(source)
    # 对合并后的字符串进行处理,返回处理后的结果
    return process_str(''.join(lines))

# 在字符串中查找和替换特殊模式,并返回替换模式的结果
_special_names = find_repl_patterns('''
<_c=s,d,c,z>
<_t=real,double precision,complex,double complex>
<prefix=s,d,c,z>
<ftype=real,double precision,complex,double complex>
<ctype=float,double,complex_float,complex_double>
<ftypereal=real,double precision,\\0,\\1>
<ctypereal=float,double,\\0,\\1>
''')

# 代码块结束,这段代码是从 `numpy.distutils.from_template` 中提取的
# END OF CODE VENDORED FROM `numpy.distutils.from_template`
###########################################################

.\numpy\numpy\f2py\__init__.py

#!/usr/bin/env python3
"""Fortran to Python Interface Generator.

Copyright 1999 -- 2011 Pearu Peterson all rights reserved.
Copyright 2011 -- present NumPy Developers.
Permission to use, modify, and distribute this software is given under the terms
of the NumPy License.

NO WARRANTY IS EXPRESSED OR IMPLIED.  USE AT YOUR OWN RISK.
"""

__all__ = ['run_main', 'get_include']

import sys                     # 导入 sys 模块,用于系统相关操作
import subprocess              # 导入 subprocess 模块,用于调用外部程序
import os                      # 导入 os 模块,提供操作系统相关功能
import warnings                # 导入 warnings 模块,用于警告处理

from numpy.exceptions import VisibleDeprecationWarning  # 导入 VisibleDeprecationWarning 异常
from . import f2py2e           # 从当前包中导入 f2py2e 模块
from . import diagnose         # 从当前包中导入 diagnose 模块

run_main = f2py2e.run_main    # 将 f2py2e 模块中的 run_main 函数赋值给 run_main 变量
main = f2py2e.main            # 将 f2py2e 模块中的 main 函数赋值给 main 变量


def get_include():
    """
    Return the directory that contains the ``fortranobject.c`` and ``.h`` files.

    .. note::

        This function is not needed when building an extension with
        `numpy.distutils` directly from ``.f`` and/or ``.pyf`` files
        in one go.

    Python extension modules built with f2py-generated code need to use
    ``fortranobject.c`` as a source file, and include the ``fortranobject.h``
    header. This function can be used to obtain the directory containing
    both of these files.

    Returns
    -------
    include_path : str
        Absolute path to the directory containing ``fortranobject.c`` and
        ``fortranobject.h``.

    Notes
    -----
    .. versionadded:: 1.21.1

    Unless the build system you are using has specific support for f2py,
    building a Python extension using a ``.pyf`` signature file is a two-step
    process. For a module ``mymod``:

    * Step 1: run ``python -m numpy.f2py mymod.pyf --quiet``. This
      generates ``mymodmodule.c`` and (if needed)
      ``mymod-f2pywrappers.f`` files next to ``mymod.pyf``.
    * Step 2: build your Python extension module. This requires the
      following source files:

      * ``mymodmodule.c``
      * ``mymod-f2pywrappers.f`` (if it was generated in Step 1)
      * ``fortranobject.c``

    See Also
    --------
    numpy.get_include : function that returns the numpy include directory

    """
    return os.path.join(os.path.dirname(__file__), 'src')  # 返回包含 fortranobject.c 和 .h 文件的目录路径


def __getattr__(attr):
    """
    Handle dynamic attribute access for the module.

    Parameters
    ----------
    attr : str
        The name of the attribute being accessed dynamically.

    Returns
    -------
    object
        The value of the dynamically accessed attribute.

    Raises
    ------
    AttributeError
        If the requested attribute does not exist.

    Notes
    -----
    This function specifically handles access to the 'test' attribute,
    importing PytestTester if needed.

    """
    if attr == "test":
        from numpy._pytesttester import PytestTester
        test = PytestTester(__name__)   # 使用 PytestTester 创建测试对象
        return test
    else:
        raise AttributeError("module {!r} has no attribute "
                              "{!r}".format(__name__, attr))  # 抛出 AttributeError 异常


def __dir__():
    """
    Return the list of attributes available in the module.

    Returns
    -------
    list
        List of attribute names in the module.

    """
    return list(globals().keys() | {"test"})  # 返回当前模块中的全局变量名列表,加上额外的 "test" 属性

.\numpy\numpy\f2py\__init__.pyi

# 导入标准库模块
import os
# 导入 subprocess 模块,用于执行外部命令
import subprocess
# 导入 Iterable 类型用于类型提示
from collections.abc import Iterable
# 导入 Literal 类型别名用于类型提示
from typing import Literal as L, Any, overload, TypedDict

# 导入 numpy._pytesttester 模块中的 PytestTester 类
from numpy._pytesttester import PytestTester

# 定义 _F2PyDictBase 类型字典,包含 csrc 和 h 两个键
class _F2PyDictBase(TypedDict):
    csrc: list[str]
    h: list[str]

# 定义 _F2PyDict 类型字典,继承自 _F2PyDictBase,可选包含 fsrc 和 ltx 两个键
class _F2PyDict(_F2PyDictBase, total=False):
    fsrc: list[str]
    ltx: list[str]

# __all__ 列表,用于定义模块导出的所有公共符号
__all__: list[str]

# test 变量,类型为 PytestTester 类
test: PytestTester

# run_main 函数定义,接受 comline_list 参数(可迭代对象),返回字典,键为 str 类型,值为 _F2PyDict 类型
def run_main(comline_list: Iterable[str]) -> dict[str, _F2PyDict]: ...

# compile 函数的第一个重载定义,接受多个参数并返回 int 类型结果
@overload
def compile(  # type: ignore[misc]
    source: str | bytes,
    modulename: str = ...,
    extra_args: str | list[str] = ...,
    verbose: bool = ...,
    source_fn: None | str | bytes | os.PathLike[Any] = ...,
    extension: L[".f", ".f90"] = ...,
    full_output: L[False] = ...,
) -> int: ...

# compile 函数的第二个重载定义,接受多个参数并返回 subprocess.CompletedProcess[bytes] 类型结果
@overload
def compile(
    source: str | bytes,
    modulename: str = ...,
    extra_args: str | list[str] = ...,
    verbose: bool = ...,
    source_fn: None | str | bytes | os.PathLike[Any] = ...,
    extension: L[".f", ".f90"] = ...,
    full_output: L[True] = ...,
) -> subprocess.CompletedProcess[bytes]: ...

# get_include 函数定义,返回 str 类型结果,用于获取包含文件的路径
def get_include() -> str: ...

.\numpy\numpy\f2py\__main__.py

# 导入主函数 `main` 来自 `numpy.f2py.f2py2e` 模块
from numpy.f2py.f2py2e import main

# 调用 `main` 函数,这个函数通常用于执行 F2PY 编译器
main()

.\numpy\numpy\f2py\__version__.py

# 从numpy库中导入version模块
from numpy.version import version

.\numpy\numpy\fft\helper.py

# 定义一个特殊的属性获取方法,用于获取 numpy.fft._helper 模块中的特定属性
def __getattr__(attr_name):
    # 导入警告模块,用于发出警告信息
    import warnings
    # 从 numpy.fft._helper 模块中获取指定名称的属性
    ret = getattr(_helper, attr_name, None)
    # 如果未找到指定属性,抛出 AttributeError 异常
    if ret is None:
        raise AttributeError(
            f"module 'numpy.fft.helper' has no attribute {attr_name}")
    # 发出警告,说明 numpy.fft.helper 模块已更名并且变为私有,建议使用 numpy.fft._helper
    warnings.warn(
        "The numpy.fft.helper has been made private and renamed to "
        "numpy.fft._helper. All four functions exported by it (i.e. fftshift, "
        "ifftshift, fftfreq, rfftfreq) are available from numpy.fft. "
        f"Please use numpy.fft.{attr_name} instead.",
        DeprecationWarning,
        stacklevel=3
    )
    # 返回获取到的属性
    return ret

.\numpy\numpy\fft\tests\test_helper.py

# 导入必要的库
import numpy as np
from numpy.testing import assert_array_almost_equal
from numpy import fft, pi

# 定义一个测试类 TestFFTShift
class TestFFTShift:

    # 定义测试函数 test_definition,测试 fftshift 和 ifftshift 的定义
    def test_definition(self):
        # 定义输入数组 x 和预期输出数组 y
        x = [0, 1, 2, 3, 4, -4, -3, -2, -1]
        y = [-4, -3, -2, -1, 0, 1, 2, 3, 4]
        # 断言 fftshift(x) 的输出与 y 几乎相等
        assert_array_almost_equal(fft.fftshift(x), y)
        # 断言 ifftshift(y) 的输出与 x 几乎相等
        assert_array_almost_equal(fft.ifftshift(y), x)

        # 重新定义输入数组 x 和预期输出数组 y
        x = [0, 1, 2, 3, 4, -5, -4, -3, -2, -1]
        y = [-5, -4, -3, -2, -1, 0, 1, 2, 3, 4]
        # 断言 fftshift(x) 的输出与 y 几乎相等
        assert_array_almost_equal(fft.fftshift(x), y)
        # 断言 ifftshift(y) 的输出与 x 几乎相等
        assert_array_almost_equal(fft.ifftshift(y), x)

    # 定义测试函数 test_inverse,测试 fftshift 和 ifftshift 的逆操作
    def test_inverse(self):
        # 对于不同的 n 值,生成随机数组 x 进行测试
        for n in [1, 4, 9, 100, 211]:
            x = np.random.random((n,))
            # 断言 ifftshift(fftshift(x)) 的输出与 x 几乎相等
            assert_array_almost_equal(fft.ifftshift(fft.fftshift(x)), x)

    # 定义测试函数 test_axes_keyword,测试带有 axes 关键字参数的 fftshift 和 ifftshift
    def test_axes_keyword(self):
        # 定义频率数组 freqs 和预期输出数组 shifted
        freqs = [[0, 1, 2], [3, 4, -4], [-3, -2, -1]]
        shifted = [[-1, -3, -2], [2, 0, 1], [-4, 3, 4]]
        # 断言 fftshift(freqs, axes=(0, 1)) 的输出与 shifted 几乎相等
        assert_array_almost_equal(fft.fftshift(freqs, axes=(0, 1)), shifted)
        # 断言 fftshift(freqs, axes=0) 的输出与 fftshift(freqs, axes=(0,)) 几乎相等
        assert_array_almost_equal(fft.fftshift(freqs, axes=0),
                                  fft.fftshift(freqs, axes=(0,)))
        # 断言 ifftshift(shifted, axes=(0, 1)) 的输出与 freqs 几乎相等
        assert_array_almost_equal(fft.ifftshift(shifted, axes=(0, 1)), freqs)
        # 断言 ifftshift(shifted, axes=0) 的输出与 ifftshift(shifted, axes=(0,)) 几乎相等
        assert_array_almost_equal(fft.ifftshift(shifted, axes=0),
                                  fft.ifftshift(shifted, axes=(0,)))

        # 断言 fftshift(freqs) 的输出与 shifted 几乎相等
        assert_array_almost_equal(fft.fftshift(freqs), shifted)
        # 断言 ifftshift(shifted) 的输出与 freqs 几乎相等
        assert_array_almost_equal(fft.ifftshift(shifted), freqs)
    def test_uneven_dims(self):
        """ Test 2D input, which has uneven dimension sizes """
        freqs = [
            [0, 1],
            [2, 3],
            [4, 5]
        ]

        # shift in dimension 0
        # 在维度 0 上进行移位
        shift_dim0 = [
            [4, 5],
            [0, 1],
            [2, 3]
        ]
        assert_array_almost_equal(fft.fftshift(freqs, axes=0), shift_dim0)
        assert_array_almost_equal(fft.ifftshift(shift_dim0, axes=0), freqs)
        assert_array_almost_equal(fft.fftshift(freqs, axes=(0,)), shift_dim0)
        assert_array_almost_equal(fft.ifftshift(shift_dim0, axes=[0]), freqs)

        # shift in dimension 1
        # 在维度 1 上进行移位
        shift_dim1 = [
            [1, 0],
            [3, 2],
            [5, 4]
        ]
        assert_array_almost_equal(fft.fftshift(freqs, axes=1), shift_dim1)
        assert_array_almost_equal(fft.ifftshift(shift_dim1, axes=1), freqs)

        # shift in both dimensions
        # 在两个维度上同时进行移位
        shift_dim_both = [
            [5, 4],
            [1, 0],
            [3, 2]
        ]
        assert_array_almost_equal(fft.fftshift(freqs, axes=(0, 1)), shift_dim_both)
        assert_array_almost_equal(fft.ifftshift(shift_dim_both, axes=(0, 1)), freqs)
        assert_array_almost_equal(fft.fftshift(freqs, axes=[0, 1]), shift_dim_both)
        assert_array_almost_equal(fft.ifftshift(shift_dim_both, axes=[0, 1]), freqs)

        # axes=None (default) shift in all dimensions
        # axes=None(默认)在所有维度上进行移位
        assert_array_almost_equal(fft.fftshift(freqs, axes=None), shift_dim_both)
        assert_array_almost_equal(fft.ifftshift(shift_dim_both, axes=None), freqs)
        assert_array_almost_equal(fft.fftshift(freqs), shift_dim_both)
        assert_array_almost_equal(fft.ifftshift(shift_dim_both), freqs)
    def test_equal_to_original(self):
        """ Test that the new (>=v1.15) implementation (see #10073) is equal to the original (<=v1.14) """
        # 导入必要的函数和模块
        from numpy._core import asarray, concatenate, arange, take

        def original_fftshift(x, axes=None):
            """ How fftshift was implemented in v1.14"""
            # 将输入数组转换为数组
            tmp = asarray(x)
            # 获取数组的维度
            ndim = tmp.ndim
            # 如果 axes 未指定,将其设为所有维度的范围列表
            if axes is None:
                axes = list(range(ndim))
            # 如果 axes 是整数,则转换为元组
            elif isinstance(axes, int):
                axes = (axes,)
            # 初始值设为输入数组
            y = tmp
            # 对每一个轴进行操作
            for k in axes:
                # 获取当前轴的长度
                n = tmp.shape[k]
                # 计算中间点位置
                p2 = (n + 1) // 2
                # 创建平移后的索引列表
                mylist = concatenate((arange(p2, n), arange(p2)))
                # 在当前轴上进行取值
                y = take(y, mylist, k)
            return y

        def original_ifftshift(x, axes=None):
            """ How ifftshift was implemented in v1.14 """
            # 将输入数组转换为数组
            tmp = asarray(x)
            # 获取数组的维度
            ndim = tmp.ndim
            # 如果 axes 未指定,将其设为所有维度的范围列表
            if axes is None:
                axes = list(range(ndim))
            # 如果 axes 是整数,则转换为元组
            elif isinstance(axes, int):
                axes = (axes,)
            # 初始值设为输入数组
            y = tmp
            # 对每一个轴进行操作
            for k in axes:
                # 获取当前轴的长度
                n = tmp.shape[k]
                # 计算中间点位置
                p2 = n - (n + 1) // 2
                # 创建逆平移后的索引列表
                mylist = concatenate((arange(p2, n), arange(p2)))
                # 在当前轴上进行取值
                y = take(y, mylist, k)
            return y

        # create possible 2d array combinations and try all possible keywords
        # compare output to original functions
        # 针对可能的二维数组组合和所有可能的关键字进行测试
        for i in range(16):
            for j in range(16):
                for axes_keyword in [0, 1, None, (0,), (0, 1)]:
                    # 生成随机输入数组
                    inp = np.random.rand(i, j)

                    # 检查 fftshift 的输出与原始函数的输出是否几乎相等
                    assert_array_almost_equal(fft.fftshift(inp, axes_keyword),
                                              original_fftshift(inp, axes_keyword))

                    # 检查 ifftshift 的输出与原始函数的输出是否几乎相等
                    assert_array_almost_equal(fft.ifftshift(inp, axes_keyword),
                                              original_ifftshift(inp, axes_keyword))
# 定义一个名为 TestFFTFreq 的测试类
class TestFFTFreq:

    # 定义测试方法 test_definition
    def test_definition(self):
        # 输入数据 x
        x = [0, 1, 2, 3, 4, -4, -3, -2, -1]
        # 断言使用 fft.fftfreq() 函数计算的结果与预期结果 x 几乎相等
        assert_array_almost_equal(9*fft.fftfreq(9), x)
        # 断言使用 fft.fftfreq() 函数计算的结果与预期结果 x 几乎相等,带有自定义的 pi 参数
        assert_array_almost_equal(9*pi*fft.fftfreq(9, pi), x)

        # 更新输入数据 x
        x = [0, 1, 2, 3, 4, -5, -4, -3, -2, -1]
        # 断言使用 fft.fftfreq() 函数计算的结果与预期结果 x 几乎相等
        assert_array_almost_equal(10*fft.fftfreq(10), x)
        # 断言使用 fft.fftfreq() 函数计算的结果与预期结果 x 几乎相等,带有自定义的 pi 参数
        assert_array_almost_equal(10*pi*fft.fftfreq(10, pi), x)


# 定义一个名为 TestRFFTFreq 的测试类
class TestRFFTFreq:

    # 定义测试方法 test_definition
    def test_definition(self):
        # 输入数据 x
        x = [0, 1, 2, 3, 4]
        # 断言使用 fft.rfftfreq() 函数计算的结果与预期结果 x 几乎相等
        assert_array_almost_equal(9*fft.rfftfreq(9), x)
        # 断言使用 fft.rfftfreq() 函数计算的结果与预期结果 x 几乎相等,带有自定义的 pi 参数
        assert_array_almost_equal(9*pi*fft.rfftfreq(9, pi), x)

        # 更新输入数据 x
        x = [0, 1, 2, 3, 4, 5]
        # 断言使用 fft.rfftfreq() 函数计算的结果与预期结果 x 几乎相等
        assert_array_almost_equal(10*fft.rfftfreq(10), x)
        # 断言使用 fft.rfftfreq() 函数计算的结果与预期结果 x 几乎相等,带有自定义的 pi 参数
        assert_array_almost_equal(10*pi*fft.rfftfreq(10, pi), x)


# 定义一个名为 TestIRFFTN 的测试类
class TestIRFFTN:

    # 定义测试方法 test_not_last_axis_success
    def test_not_last_axis_success(self):
        # 创建一个大小为 (2, 16, 8, 32) 的随机复数数组 ar 和 ai
        ar, ai = np.random.random((2, 16, 8, 32))
        # 将 ar 和 ai 组合成复数数组 a
        a = ar + 1j*ai

        # 指定轴向参数 axes = (-2)
        axes = (-2,)

        # 应该不会引发错误,执行 fft.irfftn() 函数
        fft.irfftn(a, axes=axes)

.\numpy\numpy\fft\tests\test_pocketfft.py

# 导入必要的库
import numpy as np  # 导入NumPy库
import pytest  # 导入pytest库用于单元测试
from numpy.random import random  # 导入NumPy的随机数生成函数random
from numpy.testing import (  # 导入NumPy测试模块中的断言函数
        assert_array_equal, assert_raises, assert_allclose, IS_WASM
        )
import threading  # 导入线程模块
import queue  # 导入队列模块


def fft1(x):
    # 计算输入数组的长度
    L = len(x)
    # 计算相位信息,用于FFT计算
    phase = -2j * np.pi * (np.arange(L) / L)
    # 创建相位矩阵,形状为(L, 1)
    phase = np.arange(L).reshape(-1, 1) * phase
    # 执行FFT计算并返回结果
    return np.sum(x*np.exp(phase), axis=1)


class TestFFTShift:

    def test_fft_n(self):
        # 测试在指定情况下是否会引发值错误
        assert_raises(ValueError, np.fft.fft, [1, 2, 3], 0)


class TestFFT1D:

    def test_identity(self):
        # 测试FFT和逆FFT的身份运算是否精确
        maxlen = 512
        # 生成随机复数数组
        x = random(maxlen) + 1j*random(maxlen)
        xr = random(maxlen)
        for i in range(1, maxlen):
            # 检查FFT和逆FFT的精确度
            assert_allclose(np.fft.ifft(np.fft.fft(x[0:i])), x[0:i],
                            atol=1e-12)
            assert_allclose(np.fft.irfft(np.fft.rfft(xr[0:i]), i),
                            xr[0:i], atol=1e-12)

    @pytest.mark.parametrize("dtype", [np.single, np.double, np.longdouble])
    def test_identity_long_short(self, dtype):
        # 使用不同数据类型进行测试,包括单精度、双精度和长双精度
        maxlen = 16
        # 计算数值精度容忍度
        atol = 4 * np.spacing(np.array(1., dtype=dtype))
        # 生成随机复数数组,指定数据类型
        x = random(maxlen).astype(dtype) + 1j*random(maxlen).astype(dtype)
        xx = np.concatenate([x, np.zeros_like(x)])
        xr = random(maxlen).astype(dtype)
        xxr = np.concatenate([xr, np.zeros_like(xr)])
        for i in range(1, maxlen*2):
            # 执行FFT和逆FFT,并检查结果精确度
            check_c = np.fft.ifft(np.fft.fft(x, n=i), n=i)
            assert check_c.real.dtype == dtype
            assert_allclose(check_c, xx[0:i], atol=atol, rtol=0)
            check_r = np.fft.irfft(np.fft.rfft(xr, n=i), n=i)
            assert check_r.dtype == dtype
            assert_allclose(check_r, xxr[0:i], atol=atol, rtol=0)

    @pytest.mark.parametrize("dtype", [np.single, np.double, np.longdouble])
    # 测试函数,用于验证 FFT 和 IFFT 的逆向操作
    def test_identity_long_short_reversed(self, dtype):
        # 也测试以相反顺序明确给出点数的情况。
        maxlen = 16
        # 定义绝对容差
        atol = 5 * np.spacing(np.array(1., dtype=dtype))
        # 创建复数数组 x,包含随机实部和虚部
        x = random(maxlen).astype(dtype) + 1j*random(maxlen).astype(dtype)
        # 将 x 与其翻转拼接为 xx
        xx = np.concatenate([x, np.zeros_like(x)])
        # 遍历不同点数的范围
        for i in range(1, maxlen*2):
            # 使用 FFT 和 IFFT 进行交叉验证
            check_via_c = np.fft.fft(np.fft.ifft(x, n=i), n=i)
            # 断言验证结果的数据类型与 x 的数据类型相同
            assert check_via_c.dtype == x.dtype
            # 断言验证 FFT 和 IFFT 操作后的结果近似相等
            assert_allclose(check_via_c, xx[0:i], atol=atol, rtol=0)
            # 对于 irfft,如果点数是偶数,则无法恢复第一个元素的虚部
            # 或者最后一个元素的虚部。因此在比较时将其设为 0。
            y = x.copy()
            n = i // 2 + 1
            y.imag[0] = 0
            if i % 2 == 0:
                y.imag[n-1:] = 0
            yy = np.concatenate([y, np.zeros_like(y)])
            # 使用 FFT 和 IFFT 进行反向交叉验证
            check_via_r = np.fft.rfft(np.fft.irfft(x, n=i), n=i)
            # 断言验证结果的数据类型与 x 的数据类型相同
            assert check_via_r.dtype == x.dtype
            # 断言验证 rfft 和 irfft 操作后的结果近似相等
            assert_allclose(check_via_r, yy[0:n], atol=atol, rtol=0)

    # 测试 FFT 函数的不同用法
    def test_fft(self):
        # 创建复数数组 x,包含随机实部和虚部
        x = random(30) + 1j*random(30)
        # 断言验证 fft1(x) 和 np.fft.fft(x) 的结果近似相等
        assert_allclose(fft1(x), np.fft.fft(x), atol=1e-6)
        # 断言验证 fft1(x) 和 np.fft.fft(x, norm="backward") 的结果近似相等
        assert_allclose(fft1(x), np.fft.fft(x, norm="backward"), atol=1e-6)
        # 断言验证 fft1(x) / np.sqrt(30) 和 np.fft.fft(x, norm="ortho") 的结果近似相等
        assert_allclose(fft1(x) / np.sqrt(30),
                        np.fft.fft(x, norm="ortho"), atol=1e-6)
        # 断言验证 fft1(x) / 30. 和 np.fft.fft(x, norm="forward") 的结果近似相等
        assert_allclose(fft1(x) / 30.,
                        np.fft.fft(x, norm="forward"), atol=1e-6)

    # 测试 FFT 函数的 out 参数
    @pytest.mark.parametrize("axis", (0, 1))
    @pytest.mark.parametrize("dtype", (complex, float))
    @pytest.mark.parametrize("transpose", (True, False))
    def test_fft_out_argument(self, dtype, transpose, axis):
        # 定义类似于 np.zeros_like 的函数
        def zeros_like(x):
            if transpose:
                return np.zeros_like(x.T).T
            else:
                return np.zeros_like(x)

        # 仅测试 out 参数
        if dtype is complex:
            y = random((10, 20)) + 1j*random((10, 20))
            fft, ifft = np.fft.fft, np.fft.ifft
        else:
            y = random((10, 20))
            fft, ifft = np.fft.rfft, np.fft.irfft

        # 期望的 FFT 结果
        expected = fft(y, axis=axis)
        # 创建与 expected 相同形状的零数组
        out = zeros_like(expected)
        # 使用 out 参数进行 FFT 操作
        result = fft(y, out=out, axis=axis)
        # 断言验证 result 和 out 是同一对象
        assert result is out
        # 断言验证 result 和 expected 的值近似相等
        assert_array_equal(result, expected)

        # 期望的 IFFT 结果
        expected2 = ifft(expected, axis=axis)
        # 根据数据类型创建与 expected2 相同形状的零数组
        out2 = out if dtype is complex else zeros_like(expected2)
        # 使用 out 参数进行 IFFT 操作
        result2 = ifft(out, out=out2, axis=axis)
        # 断言验证 result2 和 out2 是同一对象
        assert result2 is out2
        # 断言验证 result2 和 expected2 的值近似相等
        assert_array_equal(result2, expected2)
    # 测试原地 FFT(快速傅里叶变换)的各种组合情况
    def test_fft_inplace_out(self, axis):
        # 创建一个大小为 (20, 20) 的复数随机数组 y
        y = random((20, 20)) + 1j * random((20, 20))
        
        # 完全原地计算 FFT
        y1 = y.copy()
        expected1 = np.fft.fft(y1, axis=axis)  # 计算预期的 FFT
        result1 = np.fft.fft(y1, axis=axis, out=y1)  # 原地计算 FFT,并将结果存入 y1
        assert result1 is y1  # 确保原地操作成功
        assert_array_equal(result1, expected1)  # 确保结果与预期一致
        
        # 部分数组原地计算 FFT;其余部分不变
        y2 = y.copy()
        out2 = y2[:10] if axis == 0 else y2[:, :10]
        expected2 = np.fft.fft(y2, n=10, axis=axis)  # 计算预期的 FFT
        result2 = np.fft.fft(y2, n=10, axis=axis, out=out2)  # 原地计算 FFT,并将结果存入 out2
        assert result2 is out2  # 确保原地操作成功
        assert_array_equal(result2, expected2)  # 确保结果与预期一致
        if axis == 0:
            assert_array_equal(y2[10:], y[10:])  # 确保其余部分未被修改
        else:
            assert_array_equal(y2[:, 10:], y[:, 10:])  # 确保其余部分未被修改
        
        # 原地计算另一部分数组的 FFT
        y3 = y.copy()
        y3_sel = y3[5:] if axis == 0 else y3[:, 5:]
        out3 = y3[5:15] if axis == 0 else y3[:, 5:15]
        expected3 = np.fft.fft(y3_sel, n=10, axis=axis)  # 计算预期的 FFT
        result3 = np.fft.fft(y3_sel, n=10, axis=axis, out=out3)  # 原地计算 FFT,并将结果存入 out3
        assert result3 is out3  # 确保原地操作成功
        assert_array_equal(result3, expected3)  # 确保结果与预期一致
        if axis == 0:
            assert_array_equal(y3[:5], y[:5])  # 确保其余部分未被修改
            assert_array_equal(y3[15:], y[15:])  # 确保其余部分未被修改
        else:
            assert_array_equal(y3[:, :5], y[:, :5])  # 确保其余部分未被修改
            assert_array_equal(y3[:, 15:], y[:, 15:])  # 确保其余部分未被修改
        
        # 原地计算 FFT,其中 n > 输入的数组长度;其余部分不变
        y4 = y.copy()
        y4_sel = y4[:10] if axis == 0 else y4[:, :10]
        out4 = y4[:15] if axis == 0 else y4[:, :15]
        expected4 = np.fft.fft(y4_sel, n=15, axis=axis)  # 计算预期的 FFT
        result4 = np.fft.fft(y4_sel, n=15, axis=axis, out=out4)  # 原地计算 FFT,并将结果存入 out4
        assert result4 is out4  # 确保原地操作成功
        assert_array_equal(result4, expected4)  # 确保结果与预期一致
        if axis == 0:
            assert_array_equal(y4[15:], y[15:])  # 确保其余部分未被修改
        else:
            assert_array_equal(y4[:, 15:], y[:, 15:])  # 确保其余部分未被修改
        
        # 在转置操作中进行覆写
        y5 = y.copy()
        out5 = y5.T
        result5 = np.fft.fft(y5, axis=axis, out=out5)  # 原地计算 FFT,并将结果存入 out5
        assert result5 is out5  # 确保原地操作成功
        assert_array_equal(result5, expected1)  # 确保结果与预期一致
        
        # 反向步长操作
        y6 = y.copy()
        out6 = y6[::-1] if axis == 0 else y6[:, ::-1]
        result6 = np.fft.fft(y6, axis=axis, out=out6)  # 原地计算 FFT,并将结果存入 out6
        assert result6 is out6  # 确保原地操作成功
        assert_array_equal(result6, expected1)  # 确保结果与预期一致
    # 定义测试函数,测试逆快速傅里叶变换(IFFT)功能
    def test_ifft(self, norm):
        # 生成一个包含随机复数的长度为30的数组
        x = random(30) + 1j*random(30)
        # 断言:对 x 进行 FFT 后再进行 IFFT 应当近似于 x 自身,使用指定的归一化方式
        assert_allclose(
            x, np.fft.ifft(np.fft.fft(x, norm=norm), norm=norm),
            atol=1e-6)
        # 确保会得到预期的错误消息
        with pytest.raises(ValueError,
                           match='Invalid number of FFT data points'):
            # 对一个空列表进行 IFFT 操作,应当引发 ValueError 异常
            np.fft.ifft([], norm=norm)

    # 定义测试函数,测试二维快速傅里叶变换(FFT2)功能
    def test_fft2(self):
        # 生成一个大小为 (30, 20) 的二维随机复数数组
        x = random((30, 20)) + 1j*random((30, 20))
        # 断言:对 x 进行两次 FFT 操作(分别在不同的轴上),结果应当与直接使用 FFT2 函数结果近似
        assert_allclose(np.fft.fft(np.fft.fft(x, axis=1), axis=0),
                        np.fft.fft2(x), atol=1e-6)
        # 断言:使用 FFT2 函数的默认归一化方式应当与指定 "backward" 归一化方式的 FFT2 函数结果近似
        assert_allclose(np.fft.fft2(x),
                        np.fft.fft2(x, norm="backward"), atol=1e-6)
        # 断言:使用 "ortho" 归一化方式对 FFT2 的结果进行归一化应当近似于原结果除以 sqrt(30 * 20)
        assert_allclose(np.fft.fft2(x) / np.sqrt(30 * 20),
                        np.fft.fft2(x, norm="ortho"), atol=1e-6)
        # 断言:使用 "forward" 归一化方式对 FFT2 的结果进行归一化应当近似于原结果除以 (30. * 20.)
        assert_allclose(np.fft.fft2(x) / (30. * 20.),
                        np.fft.fft2(x, norm="forward"), atol=1e-6)

    # 定义测试函数,测试二维逆快速傅里叶变换(IFFT2)功能
    def test_ifft2(self):
        # 生成一个大小为 (30, 20) 的二维随机复数数组
        x = random((30, 20)) + 1j*random((30, 20))
        # 断言:对 x 进行两次 IFFT 操作(分别在不同的轴上),结果应当与直接使用 IFFT2 函数结果近似
        assert_allclose(np.fft.ifft(np.fft.ifft(x, axis=1), axis=0),
                        np.fft.ifft2(x), atol=1e-6)
        # 断言:使用 IFFT2 函数的默认归一化方式应当与指定 "backward" 归一化方式的 IFFT2 函数结果近似
        assert_allclose(np.fft.ifft2(x),
                        np.fft.ifft2(x, norm="backward"), atol=1e-6)
        # 断言:使用 "ortho" 归一化方式对 IFFT2 的结果进行归一化应当近似于原结果乘以 sqrt(30 * 20)
        assert_allclose(np.fft.ifft2(x) * np.sqrt(30 * 20),
                        np.fft.ifft2(x, norm="ortho"), atol=1e-6)
        # 断言:使用 "forward" 归一化方式对 IFFT2 的结果进行归一化应当近似于原结果乘以 (30. * 20.)
        assert_allclose(np.fft.ifft2(x) * (30. * 20.),
                        np.fft.ifft2(x, norm="forward"), atol=1e-6)

    # 定义测试函数,测试多维快速傅里叶变换(FFTN)功能
    def test_fftn(self):
        # 生成一个大小为 (30, 20, 10) 的三维随机复数数组
        x = random((30, 20, 10)) + 1j*random((30, 20, 10))
        # 断言:对 x 进行三次 FFT 操作(分别在不同的轴上),结果应当与直接使用 FFTN 函数结果近似
        assert_allclose(
            np.fft.fft(np.fft.fft(np.fft.fft(x, axis=2), axis=1), axis=0),
            np.fft.fftn(x), atol=1e-6)
        # 断言:使用 FFTN 函数的默认归一化方式应当与指定 "backward" 归一化方式的 FFTN 函数结果近似
        assert_allclose(np.fft.fftn(x),
                        np.fft.fftn(x, norm="backward"), atol=1e-6)
        # 断言:使用 "ortho" 归一化方式对 FFTN 的结果进行归一化应当近似于原结果除以 sqrt(30 * 20 * 10)
        assert_allclose(np.fft.fftn(x) / np.sqrt(30 * 20 * 10),
                        np.fft.fftn(x, norm="ortho"), atol=1e-6)
        # 断言:使用 "forward" 归一化方式对 FFTN 的结果进行归一化应当近似于原结果除以 (30. * 20. * 10.)
        assert_allclose(np.fft.fftn(x) / (30. * 20. * 10.),
                        np.fft.fftn(x, norm="forward"), atol=1e-6)

    # 定义测试函数,测试多维逆快速傅里叶变换(IFFTN)功能
    def test_ifftn(self):
        # 生成一个大小为 (30, 20, 10) 的三维随机复数数组
        x = random((30, 20, 10)) + 1j*random((30, 20, 10))
        # 断言:对 x 进行三次 IFFT 操作(分别在不同的轴上),结果应当与直接使用 IFFTN 函数结果近似
        assert_allclose(
            np.fft.ifft(np.fft.ifft(np.fft.ifft(x, axis=2), axis=1), axis=0),
            np.fft.ifftn(x), atol=1e-6)
        # 断言:使用 IFFTN 函数的默认归一化方式应当与指定 "backward" 归一化方式的 IFFTN 函数结果近似
        assert_allclose(np.fft.ifftn(x),
                        np.fft.ifftn(x, norm="backward"), atol=1e-6)
        # 断言:使用 "ortho" 归一化方式对 IFFTN 的结果进行归一化应当近似于原结果乘以 sqrt(30 * 20 * 10)
        assert_allclose(np.fft.ifftn(x) * np.sqrt(30 * 20 * 10),
                        np.fft.ifftn(x, norm="ortho"), atol=1e-6)
        # 断言:使用 "forward" 归一化方式对 IFFTN 的结果进行归一化应当近似于原结果乘以 (30. * 20. * 10.)
        assert_allclose(np.fft.ifftn(x) * (30. * 20. * 10.),
                        np.fft.ifftn(x, norm="forward"), atol=1e-6)
    # 定义测试函数 test_rfft,用于测试 np.fft.rfft 函数的不同参数组合
    def test_rfft(self):
        # 创建长度为 30 的随机数组 x
        x = random(30)
        # 遍历 n 的两种可能取值:x.size 和 2*x.size
        for n in [x.size, 2*x.size]:
            # 遍历 norm 的四种可能取值:None, 'backward', 'ortho', 'forward'
            for norm in [None, 'backward', 'ortho', 'forward']:
                # 断言 np.fft.fft(x, n=n, norm=norm) 的前半部分与 np.fft.rfft(x, n=n, norm=norm) 的结果相近
                assert_allclose(
                    np.fft.fft(x, n=n, norm=norm)[:(n//2 + 1)],
                    np.fft.rfft(x, n=n, norm=norm), atol=1e-6)
            # 断言 np.fft.rfft(x, n=n) 与 np.fft.rfft(x, n=n, norm="backward") 的结果相近
            assert_allclose(
                np.fft.rfft(x, n=n),
                np.fft.rfft(x, n=n, norm="backward"), atol=1e-6)
            # 断言 np.fft.rfft(x, n=n) / np.sqrt(n) 与 np.fft.rfft(x, n=n, norm="ortho") 的结果相近
            assert_allclose(
                np.fft.rfft(x, n=n) / np.sqrt(n),
                np.fft.rfft(x, n=n, norm="ortho"), atol=1e-6)
            # 断言 np.fft.rfft(x, n=n) / n 与 np.fft.rfft(x, n=n, norm="forward") 的结果相近
            assert_allclose(
                np.fft.rfft(x, n=n) / n,
                np.fft.rfft(x, n=n, norm="forward"), atol=1e-6)

    # 定义测试函数 test_rfft_even,用于测试 np.fft.rfft 对于偶数长度输入的行为
    def test_rfft_even(self):
        # 创建长度为 8 的 numpy 数组 x
        x = np.arange(8)
        n = 4
        # 计算 np.fft.rfft(x, n) 的结果,并与 np.fft.fft(x[:n])[:n//2 + 1] 的结果进行比较
        y = np.fft.rfft(x, n)
        assert_allclose(y, np.fft.fft(x[:n])[:n//2 + 1], rtol=1e-14)

    # 定义测试函数 test_rfft_odd,用于测试 np.fft.rfft 对于奇数长度输入的行为
    def test_rfft_odd(self):
        # 创建长度为 5 的 numpy 数组 x
        x = np.array([1, 0, 2, 3, -3])
        # 计算 np.fft.rfft(x) 的结果,并与 np.fft.fft(x)[:3] 的结果进行比较
        y = np.fft.rfft(x)
        assert_allclose(y, np.fft.fft(x)[:3], rtol=1e-14)

    # 定义测试函数 test_irfft,用于测试 np.fft.irfft 函数的不同参数组合
    def test_irfft(self):
        # 创建长度为 30 的随机数组 x
        x = random(30)
        # 断言 np.fft.irfft(np.fft.rfft(x)) 与 x 的结果相近
        assert_allclose(x, np.fft.irfft(np.fft.rfft(x)), atol=1e-6)
        # 断言 np.fft.irfft(np.fft.rfft(x, norm="backward"), norm="backward") 与 x 的结果相近
        assert_allclose(x, np.fft.irfft(np.fft.rfft(x, norm="backward"),
                        norm="backward"), atol=1e-6)
        # 断言 np.fft.irfft(np.fft.rfft(x, norm="ortho"), norm="ortho") 与 x 的结果相近
        assert_allclose(x, np.fft.irfft(np.fft.rfft(x, norm="ortho"),
                        norm="ortho"), atol=1e-6)
        # 断言 np.fft.irfft(np.fft.rfft(x, norm="forward"), norm="forward") 与 x 的结果相近
        assert_allclose(x, np.fft.irfft(np.fft.rfft(x, norm="forward"),
                        norm="forward"), atol=1e-6)

    # 定义测试函数 test_rfft2,用于测试 np.fft.rfft2 函数的不同参数组合
    def test_rfft2(self):
        # 创建大小为 (30, 20) 的随机二维数组 x
        x = random((30, 20))
        # 断言 np.fft.fft2(x)[:, :11] 与 np.fft.rfft2(x) 的结果相近
        assert_allclose(np.fft.fft2(x)[:, :11], np.fft.rfft2(x), atol=1e-6)
        # 断言 np.fft.rfft2(x) 与 np.fft.rfft2(x, norm="backward") 的结果相近
        assert_allclose(np.fft.rfft2(x),
                        np.fft.rfft2(x, norm="backward"), atol=1e-6)
        # 断言 np.fft.rfft2(x) / np.sqrt(30 * 20) 与 np.fft.rfft2(x, norm="ortho") 的结果相近
        assert_allclose(np.fft.rfft2(x) / np.sqrt(30 * 20),
                        np.fft.rfft2(x, norm="ortho"), atol=1e-6)
        # 断言 np.fft.rfft2(x) / (30. * 20.) 与 np.fft.rfft2(x, norm="forward") 的结果相近
        assert_allclose(np.fft.rfft2(x) / (30. * 20.),
                        np.fft.rfft2(x, norm="forward"), atol=1e-6)

    # 定义测试函数 test_irfft2,用于测试 np.fft.irfft2 函数的不同参数组合
    def test_irfft2(self):
        # 创建大小为 (30, 20) 的随机二维数组 x
        x = random((30, 20))
        # 断言 np.fft.irfft2(np.fft.rfft2(x)) 与 x 的结果相近
        assert_allclose(x, np.fft.irfft2(np.fft.rfft2(x)), atol=1e-6)
        # 断言 np.fft.irfft2(np.fft.rfft2(x, norm="backward"), norm="backward") 与 x 的结果相近
        assert_allclose(x, np.fft.irfft2(np.fft.rfft2(x, norm="backward"),
                        norm="backward"), atol=1e-6)
        # 断言 np.fft.irfft2(np.fft.rfft2(x, norm="ortho"), norm="ortho") 与 x 的结果相近
        assert_allclose(x, np.fft.irfft2(np.fft.rfft2(x, norm="ortho"),
                        norm="ortho"), atol=1e-6)
        # 断言 np.fft.irfft2(np.fft.rfft2(x, norm="forward"), norm="forward") 与 x 的结果相近
        assert_allclose(x, np.fft.irfft2(np.fft.rfft2(x, norm="forward"),
                        norm="forward"), atol=1e-6)
    # 定义测试函数 test_rfftn,用于测试 np.fft.rfftn 函数的功能
    def test_rfftn(self):
        # 创建一个形状为 (30, 20, 10) 的随机数组 x
        x = random((30, 20, 10))
        # 断言 np.fft.fftn(x) 的前三个维度切片与 np.fft.rfftn(x) 相近,允许的绝对误差为 1e-6
        assert_allclose(np.fft.fftn(x)[:, :, :6], np.fft.rfftn(x), atol=1e-6)
        # 断言 np.fft.rfftn(x) 与 np.fft.rfftn(x, norm="backward") 相近,允许的绝对误差为 1e-6
        assert_allclose(np.fft.rfftn(x),
                        np.fft.rfftn(x, norm="backward"), atol=1e-6)
        # 断言 np.fft.rfftn(x) 除以 np.sqrt(30 * 20 * 10) 与 np.fft.rfftn(x, norm="ortho") 相近,允许的绝对误差为 1e-6
        assert_allclose(np.fft.rfftn(x) / np.sqrt(30 * 20 * 10),
                        np.fft.rfftn(x, norm="ortho"), atol=1e-6)
        # 断言 np.fft.rfftn(x) 除以 (30. * 20. * 10.) 与 np.fft.rfftn(x, norm="forward") 相近,允许的绝对误差为 1e-6
        assert_allclose(np.fft.rfftn(x) / (30. * 20. * 10.),
                        np.fft.rfftn(x, norm="forward"), atol=1e-6)

    # 定义测试函数 test_irfftn,用于测试 np.fft.irfftn 函数的功能
    def test_irfftn(self):
        # 创建一个形状为 (30, 20, 10) 的随机数组 x
        x = random((30, 20, 10))
        # 断言 x 与 np.fft.irfftn(np.fft.rfftn(x)) 相近,允许的绝对误差为 1e-6
        assert_allclose(x, np.fft.irfftn(np.fft.rfftn(x)), atol=1e-6)
        # 断言 x 与 np.fft.irfftn(np.fft.rfftn(x, norm="backward"), norm="backward") 相近,允许的绝对误差为 1e-6
        assert_allclose(x, np.fft.irfftn(np.fft.rfftn(x, norm="backward"),
                        norm="backward"), atol=1e-6)
        # 断言 x 与 np.fft.irfftn(np.fft.rfftn(x, norm="ortho"), norm="ortho") 相近,允许的绝对误差为 1e-6
        assert_allclose(x, np.fft.irfftn(np.fft.rfftn(x, norm="ortho"),
                        norm="ortho"), atol=1e-6)
        # 断言 x 与 np.fft.irfftn(np.fft.rfftn(x, norm="forward"), norm="forward") 相近,允许的绝对误差为 1e-6
        assert_allclose(x, np.fft.irfftn(np.fft.rfftn(x, norm="forward"),
                        norm="forward"), atol=1e-6)

    # 定义测试函数 test_hfft,用于测试 np.fft.hfft 函数的功能
    def test_hfft(self):
        # 创建长度为 14 的随机复数数组 x
        x = random(14) + 1j * random(14)
        # 构造 Hermite 对称序列 x_herm
        x_herm = np.concatenate((random(1), x, random(1)))
        x = np.concatenate((x_herm, x[::-1].conj()))
        # 断言 np.fft.fft(x) 与 np.fft.hfft(x_herm) 相近,允许的绝对误差为 1e-6
        assert_allclose(np.fft.fft(x), np.fft.hfft(x_herm), atol=1e-6)
        # 断言 np.fft.hfft(x_herm) 与 np.fft.hfft(x_herm, norm="backward") 相近,允许的绝对误差为 1e-6
        assert_allclose(np.fft.hfft(x_herm),
                        np.fft.hfft(x_herm, norm="backward"), atol=1e-6)
        # 断言 np.fft.hfft(x_herm) 除以 np.sqrt(30) 与 np.fft.hfft(x_herm, norm="ortho") 相近,允许的绝对误差为 1e-6
        assert_allclose(np.fft.hfft(x_herm) / np.sqrt(30),
                        np.fft.hfft(x_herm, norm="ortho"), atol=1e-6)
        # 断言 np.fft.hfft(x_herm) 除以 30. 与 np.fft.hfft(x_herm, norm="forward") 相近,允许的绝对误差为 1e-6
        assert_allclose(np.fft.hfft(x_herm) / 30.,
                        np.fft.hfft(x_herm, norm="forward"), atol=1e-6)

    # 定义测试函数 test_ihfft,用于测试 np.fft.ihfft 函数的功能
    def test_ihfft(self):
        # 创建长度为 14 的随机复数数组 x
        x = random(14) + 1j * random(14)
        # 构造 Hermite 对称序列 x_herm
        x_herm = np.concatenate((random(1), x, random(1)))
        x = np.concatenate((x_herm, x[::-1].conj()))
        # 断言 x_herm 与 np.fft.ihfft(np.fft.hfft(x_herm)) 相近,允许的绝对误差为 1e-6
        assert_allclose(x_herm, np.fft.ihfft(np.fft.hfft(x_herm)), atol=1e-6)
        # 断言 x_herm 与 np.fft.ihfft(np.fft.hfft(x_herm, norm="backward"), norm="backward") 相近,允许的绝对误差为 1e-6
        assert_allclose(x_herm, np.fft.ihfft(np.fft.hfft(x_herm,
                        norm="backward"), norm="backward"), atol=1e-6)
        # 断言 x_herm 与 np.fft.ihfft(np.fft.hfft(x_herm, norm="ortho"), norm="ortho") 相近,允许的绝对误差为 1e-6
        assert_allclose(x_herm, np.fft.ihfft(np.fft.hfft(x_herm,
                        norm="ortho"), norm="ortho"), atol=1e-6)
        # 断言 x_herm 与 np.fft.ihfft(np.fft.hfft(x_herm, norm="forward"), norm="forward") 相近,允许的绝对误差为 1e-6
        assert_allclose(x_herm, np.fft.ihfft(np.fft.hfft(x_herm,
                        norm="forward"), norm="forward"), atol=1e-6)

    # 使用 pytest 的参数化装饰器,定义测试函数 test_axes,测试多种 FFT 相关函数在不同轴上的转置操作
    @pytest.mark.parametrize("op", [np.fft.fftn, np.fft.ifftn,
                                    np.fft.rfftn, np.fft.irfftn])
    def test_axes(self, op):
        # 创建一个形状为 (30, 20, 10) 的随机数组 x
        x = random((30, 20, 10))
        # 定义多种轴置换方案
        axes = [(0, 1, 2), (0, 2, 1), (1, 0, 2), (1, 2, 0), (2, 0, 1), (2, 1, 0)]
        # 遍历每种轴置换方案
        for a in axes:
            # 对 np.transpose(x, a) 进行 op 操作
            op_tr = op(np.transpose(x, a))
            # 对 x 在轴 a 上进行 op 操作,并再次进行轴置换为 a
            tr_op = np.transpose(op(x, axes=a), a)
            # 断言 op_tr 与 tr_op 相近,允许的绝对误差为 1e-6
            assert_allclose(op_tr, tr_op, atol=1e-
    # 定义测试方法,用于测试带有 s 参数的操作函数 op
    def test_s_negative_1(self, op):
        # 创建一个 10x10 的二维数组,包含 0 到 99 的整数
        x = np.arange(100).reshape(10, 10)
        # 断言调用 op 函数后返回的数组形状为 (10, 5)
        # s=(-1, 5) 表示沿着第一个轴使用整个输入数组
        assert op(x, s=(-1, 5), axes=(0, 1)).shape == (10, 5)

    # 使用 pytest 的参数化装饰器,测试带有 s 参数和警告的操作函数 op
    @pytest.mark.parametrize("op", [np.fft.fftn, np.fft.ifftn,
                                    np.fft.rfftn, np.fft.irfftn])
    def test_s_axes_none(self, op):
        # 创建一个 10x10 的二维数组,包含 0 到 99 的整数
        x = np.arange(100).reshape(10, 10)
        # 期望捕获警告,警告信息应包含 "`axes` should not be `None` if `s`"
        with pytest.warns(match='`axes` should not be `None` if `s`'):
            # 调用 op 函数,传入 s=(-1, 5)
            op(x, s=(-1, 5))

    # 使用 pytest 的参数化装饰器,测试带有 s 参数和警告的 2D 操作函数 op
    @pytest.mark.parametrize("op", [np.fft.fft2, np.fft.ifft2])
    def test_s_axes_none_2D(self, op):
        # 创建一个 10x10 的二维数组,包含 0 到 99 的整数
        x = np.arange(100).reshape(10, 10)
        # 期望捕获警告,警告信息应包含 "`axes` should not be `None` if `s`"
        with pytest.warns(match='`axes` should not be `None` if `s`'):
            # 调用 op 函数,传入 s=(-1, 5),axes=None
            op(x, s=(-1, 5), axes=None)

    # 使用 pytest 的参数化装饰器,测试带有 s 参数和包含 None 的操作函数 op
    @pytest.mark.parametrize("op", [np.fft.fftn, np.fft.ifftn,
                                    np.fft.rfftn, np.fft.irfftn,
                                    np.fft.fft2, np.fft.ifft2])
    def test_s_contains_none(self, op):
        # 创建一个形状为 (30, 20, 10) 的随机数组
        x = random((30, 20, 10))
        # 期望捕获警告,警告信息应包含 "array containing `None` values to `s`"
        with pytest.warns(match='array containing `None` values to `s`'):
            # 调用 op 函数,传入 s=(10, None, 10),axes=(0, 1, 2)
            op(x, s=(10, None, 10), axes=(0, 1, 2))

    # 定义测试方法,验证一维正向和反向变换是否保持范数不变
    def test_all_1d_norm_preserving(self):
        # 创建一个包含 30 个随机元素的一维数组
        x = random(30)
        # 计算原始数组 x 的范数
        x_norm = np.linalg.norm(x)
        # 将数组长度倍增为 n,并测试所有的正向和反向变换
        # func_pairs 列表包含了正向和反向变换函数对
        func_pairs = [(np.fft.fft, np.fft.ifft),
                      (np.fft.rfft, np.fft.irfft),
                      # hfft: 指定第一个函数取 x.size 个样本以便与上述 x_norm 进行比较
                      (np.fft.ihfft, np.fft.hfft),
                      ]
        for forw, back in func_pairs:
            for n in [x.size, 2*x.size]:
                for norm in [None, 'backward', 'ortho', 'forward']:
                    # 执行正向变换
                    tmp = forw(x, n=n, norm=norm)
                    # 执行反向变换
                    tmp = back(tmp, n=n, norm=norm)
                    # 断言经过变换后的范数与原始 x 的范数相近,误差限定为 1e-6
                    assert_allclose(x_norm,
                                    np.linalg.norm(tmp), atol=1e-6)

    # 使用 pytest 的参数化装饰器,测试不同参数 axes 和 dtype 的操作
    @pytest.mark.parametrize("axes", [(0, 1), (0, 2), None])
    @pytest.mark.parametrize("dtype", (complex, float))
    @pytest.mark.parametrize("transpose", (True, False))
    # 定义一个内部函数 `zeros_like`,根据输入数组 `x` 的形状返回一个零填充的数组,如果 `transpose` 为真,则对 `x` 进行转置操作
    def zeros_like(x):
        if transpose:
            return np.zeros_like(x.T).T
        else:
            return np.zeros_like(x)

    # 根据参数 `dtype` 的类型(复数或实数),选择不同的随机数组 `x`,并分别设置 FFT 和 IFFT 函数
    if dtype is complex:
        x = random((10, 5, 6)) + 1j*random((10, 5, 6))
        fft, ifft = np.fft.fftn, np.fft.ifftn
    else:
        x = random((10, 5, 6))
        fft, ifft = np.fft.rfftn, np.fft.irfftn

    # 计算预期的 FFT 结果
    expected = fft(x, axes=axes)
    # 创建一个与 `expected` 形状相同的零填充数组 `out`
    out = zeros_like(expected)
    # 在指定输出数组 `out` 的情况下计算 FFT,结果保存在 `result` 中
    result = fft(x, out=out, axes=axes)
    # 断言 `result` 与 `out` 是同一个对象
    assert result is out
    # 断言 `result` 与 `expected` 相等
    assert_array_equal(result, expected)

    # 计算预期的 IFFT 结果
    expected2 = ifft(expected, axes=axes)
    # 如果 `dtype` 是复数,则 `out2` 使用之前计算的 `out`;否则,创建一个与 `expected2` 形状相同的零填充数组 `out2`
    out2 = out if dtype is complex else zeros_like(expected2)
    # 在指定输出数组 `out2` 的情况下计算 IFFT,结果保存在 `result2` 中
    result2 = ifft(out, out=out2, axes=axes)
    # 断言 `result2` 与 `out2` 是同一个对象
    assert result2 is out2
    # 断言 `result2` 与 `expected2` 相等
    assert_array_equal(result2, expected2)

@pytest.mark.parametrize("fft", [np.fft.fftn, np.fft.ifftn, np.fft.rfftn])
def test_fftn_out_and_s_interaction(self, fft):
    # 对于带有 `s` 参数的情况,由于形状可能变化,通常不能传递 `out` 参数。
    if fft is np.fft.rfftn:
        x = random((10, 5, 6))
    else:
        x = random((10, 5, 6)) + 1j*random((10, 5, 6))
    # 使用 `pytest.raises` 断言,在指定 `out` 参数的情况下会引发 ValueError 异常,并且异常信息包含 "has wrong shape"
    with pytest.raises(ValueError, match="has wrong shape"):
        fft(x, out=np.zeros_like(x), s=(3, 3, 3), axes=(0, 1, 2))
    # 除了第一个轴(即 `axes` 的最后一个轴)之外,对于指定了 `s` 参数的情况,计算预期的 FFT 结果
    s = (10, 5, 5)
    expected = fft(x, s=s, axes=(0, 1, 2))
    # 创建一个与 `expected` 形状相同的零填充数组 `out`
    out = np.zeros_like(expected)
    # 在指定输出数组 `out` 的情况下计算 FFT,结果保存在 `result` 中
    result = fft(x, s=s, axes=(0, 1, 2), out=out)
    # 断言 `result` 与 `out` 是同一个对象
    assert result is out
    # 断言 `result` 与 `expected` 相等
    assert_array_equal(result, expected)

@pytest.mark.parametrize("s", [(9, 5, 5), (3, 3, 3)])
def test_irfftn_out_and_s_interaction(self, s):
    # 对于 `irfftn`,输出是实数,因此不能用于中间步骤,应始终有效。
    x = random((9, 5, 6, 2)) + 1j*random((9, 5, 6, 2))
    # 计算预期的 `irfftn` 结果
    expected = np.fft.irfftn(x, s=s, axes=(0, 1, 2))
    # 创建一个与 `expected` 形状相同的零填充数组 `out`
    out = np.zeros_like(expected)
    # 在指定输出数组 `out` 的情况下计算 `irfftn`,结果保存在 `result` 中
    result = np.fft.irfftn(x, s=s, axes=(0, 1, 2), out=out)
    # 断言 `result` 与 `out` 是同一个对象
    assert result is out
    # 断言 `result` 与 `expected` 相等
    assert_array_equal(result, expected)
@pytest.mark.parametrize(
        "dtype",
        [np.float32, np.float64, np.complex64, np.complex128])
@pytest.mark.parametrize("order", ["F", 'non-contiguous'])
@pytest.mark.parametrize(
        "fft",
        [np.fft.fft, np.fft.fft2, np.fft.fftn,
         np.fft.ifft, np.fft.ifft2, np.fft.ifftn])
def test_fft_with_order(dtype, order, fft):
    # 检查对于C、Fortran和非连续数组,FFT/IFFT是否产生相同结果
    rng = np.random.RandomState(42)
    X = rng.rand(8, 7, 13).astype(dtype, copy=False)
    # 根据 pull/14178 中的讨论设置容差值
    _tol = 8.0 * np.sqrt(np.log2(X.size)) * np.finfo(X.dtype).eps
    if order == 'F':
        Y = np.asfortranarray(X)
    else:
        # 创建一个非连续数组
        Y = X[::-1]
        X = np.ascontiguousarray(X[::-1])

    if fft.__name__.endswith('fft'):
        # 对于 fft 函数,沿着三个轴进行循环
        for axis in range(3):
            X_res = fft(X, axis=axis)
            Y_res = fft(Y, axis=axis)
            assert_allclose(X_res, Y_res, atol=_tol, rtol=_tol)
    elif fft.__name__.endswith(('fft2', 'fftn')):
        # 对于 fft2 和 fftn 函数,使用不同的轴组合
        axes = [(0, 1), (1, 2), (0, 2)]
        if fft.__name__.endswith('fftn'):
            axes.extend([(0,), (1,), (2,), None])
        for ax in axes:
            X_res = fft(X, axes=ax)
            Y_res = fft(Y, axes=ax)
            assert_allclose(X_res, Y_res, atol=_tol, rtol=_tol)
    else:
        # 抛出数值错误异常
        raise ValueError()


@pytest.mark.skipif(IS_WASM, reason="Cannot start thread")
class TestFFTThreadSafe:
    threads = 16
    input_shape = (800, 200)

    def _test_mtsame(self, func, *args):
        def worker(args, q):
            q.put(func(*args))

        q = queue.Queue()
        expected = func(*args)

        # 启动一组线程同时调用同一函数
        t = [threading.Thread(target=worker, args=(args, q))
             for i in range(self.threads)]
        [x.start() for x in t]

        [x.join() for x in t]
        # 确保所有线程返回正确的值
        for i in range(self.threads):
            assert_array_equal(q.get(timeout=5), expected,
                'Function returned wrong value in multithreaded context')

    def test_fft(self):
        a = np.ones(self.input_shape) * 1+0j
        self._test_mtsame(np.fft.fft, a)

    def test_ifft(self):
        a = np.ones(self.input_shape) * 1+0j
        self._test_mtsame(np.fft.ifft, a)

    def test_rfft(self):
        a = np.ones(self.input_shape)
        self._test_mtsame(np.fft.rfft, a)

    def test_irfft(self):
        a = np.ones(self.input_shape) * 1+0j
        self._test_mtsame(np.fft.irfft, a)


def test_irfft_with_n_1_regression():
    # gh-25661 的回归测试
    x = np.arange(10)
    np.fft.irfft(x, n=1)
    np.fft.hfft(x, n=1)
    np.fft.irfft(np.array([0], complex), n=10)


def test_irfft_with_n_large_regression():
    # gh-25679 的回归测试
    x = np.arange(5) * (1 + 1j)
    result = np.fft.hfft(x, n=10)
    # 定义预期的 NumPy 数组,包含期望的浮点数值
    expected = np.array([20., 9.91628173, -11.8819096, 7.1048486,
                         -6.62459848, 4., -3.37540152, -0.16057669,
                         1.8819096, -20.86055364])
    # 使用 assert_allclose 函数检查 result 数组与预期数组 expected 是否在允许误差范围内相等
    assert_allclose(result, expected)
# 使用 pytest 的 parametrize 装饰器为 test_fft_with_integer_or_bool_input 函数参数化,fft 参数为四种不同的 FFT 函数
@pytest.mark.parametrize("fft", [
    np.fft.fft, np.fft.ifft, np.fft.rfft, np.fft.irfft
])
# 使用 pytest 的 parametrize 装饰器为 test_fft_with_integer_or_bool_input 函数参数化,data 参数为三种不同的输入数据类型和值
@pytest.mark.parametrize("data", [
    np.array([False, True, False]),   # 布尔类型数组作为输入数据
    np.arange(10, dtype=np.uint8),    # 无符号 8 位整数数组作为输入数据
    np.arange(5, dtype=np.int16),     # 有符号 16 位整数数组作为输入数据
])
def test_fft_with_integer_or_bool_input(data, fft):
    # Regression test for gh-25819
    # 对于给定的数据 data,使用指定的 FFT 函数 fft 进行变换
    result = fft(data)
    # 将输入数据 data 转换为浮点数类型,用于比较期望结果
    float_data = data.astype(np.result_type(data, 1.))
    # 使用 fft 函数对转换后的浮点数数据进行变换,得到期望结果
    expected = fft(float_data)
    # 检查变换后的结果是否一致
    assert_array_equal(result, expected)

.\numpy\numpy\fft\tests\__init__.py

# 导入 datetime 模块中的 datetime 类
from datetime import datetime

# 定义一个名为 parse_timestamp 的函数,接收一个字符串参数 ts
def parse_timestamp(ts):
    # 使用 datetime 类的 strptime 方法解析时间戳字符串为 datetime 对象
    dt = datetime.strptime(ts, '%Y-%m-%d %H:%M:%S')
    # 返回解析后的 datetime 对象
    return dt

.\numpy\numpy\fft\_helper.py

"""
Discrete Fourier Transforms - _helper.py

"""
from numpy._core import integer, empty, arange, asarray, roll
from numpy._core.overrides import array_function_dispatch, set_module

# Created by Pearu Peterson, September 2002

__all__ = ['fftshift', 'ifftshift', 'fftfreq', 'rfftfreq']

integer_types = (int, integer)


def _fftshift_dispatcher(x, axes=None):
    return (x,)


@array_function_dispatch(_fftshift_dispatcher, module='numpy.fft')
def fftshift(x, axes=None):
    """
    Shift the zero-frequency component to the center of the spectrum.

    This function swaps half-spaces for all axes listed (defaults to all).
    Note that ``y[0]`` is the Nyquist component only if ``len(x)`` is even.

    Parameters
    ----------
    x : array_like
        Input array.
    axes : int or shape tuple, optional
        Axes over which to shift.  Default is None, which shifts all axes.

    Returns
    -------
    y : ndarray
        The shifted array.

    See Also
    --------
    ifftshift : The inverse of `fftshift`.

    Examples
    --------
    >>> freqs = np.fft.fftfreq(10, 0.1)
    >>> freqs
    array([ 0.,  1.,  2., ..., -3., -2., -1.])
    >>> np.fft.fftshift(freqs)
    array([-5., -4., -3., -2., -1.,  0.,  1.,  2.,  3.,  4.])

    Shift the zero-frequency component only along the second axis:

    >>> freqs = np.fft.fftfreq(9, d=1./9).reshape(3, 3)
    >>> freqs
    array([[ 0.,  1.,  2.],
           [ 3.,  4., -4.],
           [-3., -2., -1.]])
    >>> np.fft.fftshift(freqs, axes=(1,))
    array([[ 2.,  0.,  1.],
           [-4.,  3.,  4.],
           [-1., -3., -2.]])

    """
    # 将输入数组转换为 ndarray 类型
    x = asarray(x)
    # 如果未指定轴,则默认对所有轴进行移动
    if axes is None:
        axes = tuple(range(x.ndim))
        # 计算每个轴要移动的步数
        shift = [dim // 2 for dim in x.shape]
    # 如果 axes 是整数类型,则只移动指定轴的一半长度
    elif isinstance(axes, integer_types):
        shift = x.shape[axes] // 2
    # 否则,移动每个指定轴的一半长度
    else:
        shift = [x.shape[ax] // 2 for ax in axes]

    # 对数组进行轴向移动
    return roll(x, shift, axes)


@array_function_dispatch(_fftshift_dispatcher, module='numpy.fft')
def ifftshift(x, axes=None):
    """
    The inverse of `fftshift`. Although identical for even-length `x`, the
    functions differ by one sample for odd-length `x`.

    Parameters
    ----------
    x : array_like
        Input array.
    axes : int or shape tuple, optional
        Axes over which to calculate.  Defaults to None, which shifts all axes.

    Returns
    -------
    y : ndarray
        The shifted array.

    See Also
    --------
    fftshift : Shift zero-frequency component to the center of the spectrum.

    Examples
    --------
    >>> freqs = np.fft.fftfreq(9, d=1./9).reshape(3, 3)
    >>> freqs
    array([[ 0.,  1.,  2.],
           [ 3.,  4., -4.],
           [-3., -2., -1.]])
    >>> np.fft.ifftshift(np.fft.fftshift(freqs))
    array([[ 0.,  1.,  2.],
           [ 3.,  4., -4.],
           [-3., -2., -1.]])

    """
    # 将输入数组转换为 ndarray 类型
    x = asarray(x)
    # 如果未指定轴,则默认对所有轴进行移动
    if axes is None:
        axes = tuple(range(x.ndim))
        # 计算每个轴要移动的步数(负数表示反向移动)
        shift = [-(dim // 2) for dim in x.shape]
    # 如果 axes 是整数类型,则计算要滚动的偏移量
    elif isinstance(axes, integer_types):
        shift = -(x.shape[axes] // 2)
    # 如果 axes 是一个迭代对象(通常是一个列表或元组),则分别计算每个轴的偏移量
    else:
        shift = [-(x.shape[ax] // 2) for ax in axes]

    # 使用 roll 函数对数组 x 进行滚动操作,滚动的偏移量由 shift 决定,作用在指定的轴 axes 上
    return roll(x, shift, axes)
# 设置模块为 'numpy.fft'
@set_module('numpy.fft')
# 定义函数 fftfreq,返回离散傅里叶变换的采样频率
def fftfreq(n, d=1.0, device=None):
    """
    Return the Discrete Fourier Transform sample frequencies.

    The returned float array `f` contains the frequency bin centers in cycles
    per unit of the sample spacing (with zero at the start).  For instance, if
    the sample spacing is in seconds, then the frequency unit is cycles/second.

    Given a window length `n` and a sample spacing `d`::

      f = [0, 1, ...,   n/2-1,     -n/2, ..., -1] / (d*n)   if n is even
      f = [0, 1, ..., (n-1)/2, -(n-1)/2, ..., -1] / (d*n)   if n is odd

    Parameters
    ----------
    n : int
        窗口长度。
    d : scalar, optional
        采样间隔(采样率的倒数)。默认为 1。
    device : str, optional
        创建数组时指定的设备。默认为 ``None``。
        仅供 Array-API 兼容性使用,如果传入,必须是 ``"cpu"``。

        .. versionadded:: 2.0.0

    Returns
    -------
    f : ndarray
        长度为 `n` 的数组,包含采样频率。

    Examples
    --------
    >>> signal = np.array([-2, 8, 6, 4, 1, 0, 3, 5], dtype=float)
    >>> fourier = np.fft.fft(signal)
    >>> n = signal.size
    >>> timestep = 0.1
    >>> freq = np.fft.fftfreq(n, d=timestep)
    >>> freq
    array([ 0.  ,  1.25,  2.5 , ..., -3.75, -2.5 , -1.25])

    """
    # 检查 n 是否为整数类型
    if not isinstance(n, integer_types):
        raise ValueError("n should be an integer")
    # 计算 val,用于后续频率计算
    val = 1.0 / (n * d)
    # 创建一个长度为 n 的空数组 results,数据类型为 int,可指定设备
    results = empty(n, int, device=device)
    # 计算 N,为正频率部分的长度
    N = (n-1)//2 + 1
    # 生成从 0 到 N-1 的整数数组 p1,数据类型为 int,可指定设备
    p1 = arange(0, N, dtype=int, device=device)
    # 将 p1 复制到 results 的前 N 个元素
    results[:N] = p1
    # 生成从 -(n//2) 到 -1 的整数数组 p2,数据类型为 int,可指定设备
    p2 = arange(-(n//2), 0, dtype=int, device=device)
    # 将 p2 复制到 results 的后半部分
    results[N:] = p2
    # 返回结果数组乘以 val
    return results * val


# 设置模块为 'numpy.fft'
@set_module('numpy.fft')
# 定义函数 rfftfreq,返回用于实部快速傅里叶变换的采样频率
def rfftfreq(n, d=1.0, device=None):
    """
    Return the Discrete Fourier Transform sample frequencies
    (for usage with rfft, irfft).

    The returned float array `f` contains the frequency bin centers in cycles
    per unit of the sample spacing (with zero at the start).  For instance, if
    the sample spacing is in seconds, then the frequency unit is cycles/second.

    Given a window length `n` and a sample spacing `d`::

      f = [0, 1, ...,     n/2-1,     n/2] / (d*n)   if n is even
      f = [0, 1, ..., (n-1)/2-1, (n-1)/2] / (d*n)   if n is odd

    Unlike `fftfreq` (but like `scipy.fftpack.rfftfreq`)
    the Nyquist frequency component is considered to be positive.

    Parameters
    ----------
    n : int
        窗口长度。
    d : scalar, optional
        采样间隔(采样率的倒数)。默认为 1。
    device : str, optional
        创建数组时指定的设备。默认为 ``None``。
        仅供 Array-API 兼容性使用,如果传入,必须是 ``"cpu"``。

        .. versionadded:: 2.0.0

    Returns
    -------
    f : ndarray
        长度为 ``n//2 + 1`` 的数组,包含采样频率。

    Examples
    --------
    # 创建一个 numpy 数组,表示输入的信号,其中包含浮点数
    signal = np.array([-2, 8, 6, 4, 1, 0, 3, 5, -3, 4], dtype=float)
    
    # 对信号进行快速傅立叶变换(FFT),返回变换后的复数数组
    fourier = np.fft.rfft(signal)
    
    # 获取信号的长度(即样本数)
    n = signal.size
    
    # 设置采样率为 100
    sample_rate = 100
    
    # 使用 FFT 计算频率数组,以实数形式返回频率值
    freq = np.fft.fftfreq(n, d=1./sample_rate)
    
    # 输出频率数组
    freq
    array([  0.,  10.,  20., ..., -30., -20., -10.])
    
    # 使用 rfft 方法计算频率数组,以实数形式返回频率值,仅包括非负部分
    freq = np.fft.rfftfreq(n, d=1./sample_rate)
    
    # 输出频率数组
    freq
    array([  0.,  10.,  20.,  30.,  40.,  50.])
    
    """
    如果 n 不是整数类型(integer_types),则抛出数值错误
    n 应该是一个整数
    val = 1.0/(n*d)  # 计算频率间隔
    N = n//2 + 1  # 计算频率数组的长度
    results = arange(0, N, dtype=int, device=device)  # 生成一个整数数组,表示频率索引
    return results * val  # 返回频率数组乘以频率间隔后的结果