NumPy-源码解析-八十-

86 阅读53分钟

NumPy 源码解析(八十)

.\numpy\numpy\_core\tests\test_array_api_info.py

# 导入 numpy 库并导入 pytest 库
import numpy as np
import pytest

# 调用 numpy 的 __array_namespace_info__() 方法获取信息并赋值给变量 info
info = np.__array_namespace_info__()


# 定义测试函数 test_capabilities,用于测试 capabilities 方法
def test_capabilities():
    # 调用 capabilities 方法获取 capabilities 字典
    caps = info.capabilities()
    # 断言 boolean indexing 功能为 True
    assert caps["boolean indexing"] == True
    # 断言 data-dependent shapes 功能为 True
    assert caps["data-dependent shapes"] == True

    # 下面这段代码将在 2024.12 版本的数组 API 标准中添加
    # assert caps["max rank"] == 64
    # np.zeros((1,)*64)
    # 使用 pytest 检测 ValueError 异常是否被触发
    # with pytest.raises(ValueError):
    #     np.zeros((1,)*65)


# 定义测试函数 test_default_device,用于测试 default_device 方法
def test_default_device():
    # 断言 default_device 方法返回值为 "cpu",并且与 np.asarray(0).device 相等
    assert info.default_device() == "cpu" == np.asarray(0).device


# 定义测试函数 test_default_dtypes,用于测试 default_dtypes 方法
def test_default_dtypes():
    # 调用 default_dtypes 方法获取 default_dtypes 字典
    dtypes = info.default_dtypes()
    # 断言 real floating 数据类型为 np.float64,并且 np.asarray(0.0).dtype 与之相等
    assert dtypes["real floating"] == np.float64 == np.asarray(0.0).dtype
    # 断言 complex floating 数据类型为 np.complex128,并且 np.asarray(0.0j).dtype 与之相等
    assert dtypes["complex floating"] == np.complex128 == np.asarray(0.0j).dtype
    # 断言 integral 数据类型为 np.intp,并且 np.asarray(0).dtype 与之相等
    assert dtypes["integral"] == np.intp == np.asarray(0).dtype
    # 断言 indexing 数据类型为 np.intp,并且 np.argmax(np.zeros(10)).dtype 与之相等
    assert dtypes["indexing"] == np.intp == np.argmax(np.zeros(10)).dtype

    # 使用 pytest 检测 ValueError 异常是否被触发,并且匹配 "Device not understood" 字符串
    with pytest.raises(ValueError, match="Device not understood"):
        info.default_dtypes(device="gpu")


# 定义测试函数 test_dtypes_all,用于测试 dtypes 方法
def test_dtypes_all():
    # 调用 dtypes 方法获取 dtypes 字典
    dtypes = info.dtypes()
    # 断言 dtypes 字典是否符合预期的数据类型映射关系
    assert dtypes == {
        "bool": np.bool_,
        "int8": np.int8,
        "int16": np.int16,
        "int32": np.int32,
        "int64": np.int64,
        "uint8": np.uint8,
        "uint16": np.uint16,
        "uint32": np.uint32,
        "uint64": np.uint64,
        "float32": np.float32,
        "float64": np.float64,
        "complex64": np.complex64,
        "complex128": np.complex128,
    }


# 定义 dtype_categories 字典,用于指定不同数据类型类别及其对应的映射关系
dtype_categories = {
    "bool": {"bool": np.bool_},
    "signed integer": {
        "int8": np.int8,
        "int16": np.int16,
        "int32": np.int32,
        "int64": np.int64,
    },
    "unsigned integer": {
        "uint8": np.uint8,
        "uint16": np.uint16,
        "uint32": np.uint32,
        "uint64": np.uint64,
    },
    "integral": ("signed integer", "unsigned integer"),
    "real floating": {"float32": np.float32, "float64": np.float64},
    "complex floating": {"complex64": np.complex64, "complex128":
                         np.complex128},
    "numeric": ("integral", "real floating", "complex floating"),
}


# 使用 pytest 的 parametrize 装饰器进行参数化测试
@pytest.mark.parametrize("kind", dtype_categories)
def test_dtypes_kind(kind):
    # 获取预期结果
    expected = dtype_categories[kind]
    # 如果 expected 是 tuple 类型,比较两种方式获取的结果是否相同
    if isinstance(expected, tuple):
        assert info.dtypes(kind=kind) == info.dtypes(kind=expected)
    else:
        assert info.dtypes(kind=kind) == expected


# 定义测试函数 test_dtypes_tuple,用于测试 dtypes 方法,指定 kind 参数为 ("bool", "integral")
def test_dtypes_tuple():
    dtypes = info.dtypes(kind=("bool", "integral"))
    # 断言 dtypes 字典是否符合预期的数据类型映射关系
    assert dtypes == {
        "bool": np.bool_,
        "int8": np.int8,
        "int16": np.int16,
        "int32": np.int32,
        "int64": np.int64,
        "uint8": np.uint8,
        "uint16": np.uint16,
        "uint32": np.uint32,
        "uint64": np.uint64,
    }


# 定义测试函数 test_dtypes_invalid_kind,用于测试 dtypes 方法,传入不支持的 kind 参数
def test_dtypes_invalid_kind():
    # 使用 pytest 检测 ValueError 异常是否被触发,并且匹配 "unsupported kind" 字符串
    with pytest.raises(ValueError, match="unsupported kind"):
        info.dtypes(kind="invalid")


# 定义测试函数 test_dtypes_invalid_device,用于测试 dtypes 方法,传入不支持的 device 参数
def test_dtypes_invalid_device():
    # 这部分代码在后续补充
    pass
    # 使用 pytest 来验证是否会抛出 ValueError 异常,并检查异常消息是否包含 "Device not understood"
    with pytest.raises(ValueError, match="Device not understood"):
        # 调用 info 对象的 dtypes 方法,并传入参数 device="gpu"
        info.dtypes(device="gpu")
# 定义一个名为 test_devices 的函数,用于测试某个功能或特性
def test_devices():
    # 断言检查调用 info.devices() 的返回值是否等于列表 ["cpu"]
    assert info.devices() == ["cpu"]

.\numpy\numpy\_core\tests\test_array_coercion.py

"""
Tests for array coercion, mainly through testing `np.array` results directly.
Note that other such tests exist, e.g., in `test_api.py` and many corner-cases
are tested (sometimes indirectly) elsewhere.
"""

# 导入必要的库
from itertools import permutations, product

import pytest
from pytest import param

# 导入 NumPy 库及其子模块
import numpy as np
import numpy._core._multiarray_umath as ncu
from numpy._core._rational_tests import rational

# 导入 NumPy 测试工具
from numpy.testing import (
    assert_array_equal, assert_warns, IS_PYPY)


def arraylikes():
    """
    Generator for functions converting an array into various array-likes.
    If full is True (default) it includes array-likes not capable of handling
    all dtypes.
    """
    # 定义基本的数组生成函数
    def ndarray(a):
        return a

    # 生成并返回 ndarray 函数作为 pytest 的参数化测试
    yield param(ndarray, id="ndarray")

    # 定义一个继承自 np.ndarray 的子类
    class MyArr(np.ndarray):
        pass

    # 将数组转换为 MyArr 类型的实例
    def subclass(a):
        return a.view(MyArr)

    # 生成并返回 subclass 函数作为 pytest 的参数化测试
    yield subclass

    # 定义一个类似序列的对象,模拟旧版 NumPy 中的行为
    class _SequenceLike():
        # 在旧版 NumPy 中,有时会关注协议数组是否也是 _SequenceLike
        def __len__(self):
            raise TypeError

        def __getitem__(self):
            raise TypeError

    # 模拟数组接口
    class ArrayDunder(_SequenceLike):
        def __init__(self, a):
            self.a = a

        # 定义 __array__ 方法以实现数组接口
        def __array__(self, dtype=None, copy=None):
            if dtype is None:
                return self.a
            return self.a.astype(dtype)

    # 生成并返回 ArrayDunder 类作为 pytest 的参数化测试
    yield param(ArrayDunder, id="__array__")

    # 生成并返回 memoryview 函数作为 pytest 的参数化测试
    yield param(memoryview, id="memoryview")

    # 模拟数组接口
    class ArrayInterface:
        def __init__(self, a):
            self.a = a  # 需要保持引用以保持接口有效
            self.__array_interface__ = a.__array_interface__

    # 生成并返回 ArrayInterface 类作为 pytest 的参数化测试
    yield param(ArrayInterface, id="__array_interface__")

    # 模拟数组结构
    class ArrayStruct:
        def __init__(self, a):
            self.a = a  # 需要保持引用以保持结构有效
            self.__array_struct__ = a.__array_struct__

    # 生成并返回 ArrayStruct 类作为 pytest 的参数化测试
    yield param(ArrayStruct, id="__array_struct__")


def scalar_instances(times=True, extended_precision=True, user_dtype=True):
    # 预定义的标量实例列表
    # 浮点数:
    yield param(np.sqrt(np.float16(5)), id="float16")
    yield param(np.sqrt(np.float32(5)), id="float32")
    yield param(np.sqrt(np.float64(5)), id="float64")
    if extended_precision:
        yield param(np.sqrt(np.longdouble(5)), id="longdouble")

    # 复数:
    yield param(np.sqrt(np.complex64(2+3j)), id="complex64")
    yield param(np.sqrt(np.complex128(2+3j)), id="complex128")
    if extended_precision:
        yield param(np.sqrt(np.clongdouble(2+3j)), id="clongdouble")

    # 布尔:
    # XFAIL: Bool 应该添加,但在处理字符串时存在一些问题,参见 gh-9875
    # yield param(np.bool(0), id="bool")

    # 整数:
    yield param(np.int8(2), id="int8")


这里的注释对代码中每个函数和类的定义进行了解释,确保符合题目要求的格式和注意事项。
    # Yield an np.int16 parameter with value 2 and identifier "int16"
    yield param(np.int16(2), id="int16")
    
    # Yield an np.int32 parameter with value 2 and identifier "int32"
    yield param(np.int32(2), id="int32")
    
    # Yield an np.int64 parameter with value 2 and identifier "int64"
    yield param(np.int64(2), id="int64")

    # Yield an np.uint8 parameter with value 2 and identifier "uint8"
    yield param(np.uint8(2), id="uint8")
    
    # Yield an np.uint16 parameter with value 2 and identifier "uint16"
    yield param(np.uint16(2), id="uint16")
    
    # Yield an np.uint32 parameter with value 2 and identifier "uint32"
    yield param(np.uint32(2), id="uint32")
    
    # Yield an np.uint64 parameter with value 2 and identifier "uint64"
    yield param(np.uint64(2), id="uint64")

    # Rational:
    # If user_dtype is True, yield a rational parameter with value 1/2 and identifier "rational"
    if user_dtype:
        yield param(rational(1, 2), id="rational")

    # Cannot create a structured void scalar directly:
    # Create a structured np.array with one element of type ("i,i"), and extract the first element
    structured = np.array([(1, 3)], "i,i")[0]
    
    # Assert that structured is indeed of type np.void
    assert isinstance(structured, np.void)
    
    # Assert that structured's dtype is np.dtype("i,i")
    assert structured.dtype == np.dtype("i,i")
    
    # Yield a param with structured as value and identifier "structured"
    yield param(structured, id="structured")

    # If times is True:
    if times:
        # Datetimes and timedelta
        # Yield a np.timedelta64 parameter with value 2 and identifier "timedelta64[generic]"
        yield param(np.timedelta64(2), id="timedelta64[generic]")
        
        # Yield a np.timedelta64 parameter with value 23 seconds and identifier "timedelta64[s]"
        yield param(np.timedelta64(23, "s"), id="timedelta64[s]")
        
        # Yield a np.timedelta64 parameter with NaT (Not a Time) value in seconds and identifier "timedelta64[s](NaT)"
        yield param(np.timedelta64("NaT", "s"), id="timedelta64[s](NaT)")

        # Yield a np.datetime64 parameter with NaT (Not a Time) value and identifier "datetime64[generic](NaT)"
        yield param(np.datetime64("NaT"), id="datetime64[generic](NaT)")
        
        # Yield a np.datetime64 parameter with specific datetime value and identifier "datetime64[ms]"
        yield param(np.datetime64("2020-06-07 12:43", "ms"), id="datetime64[ms]")

    # Strings and unstructured void:
    # Yield a np.bytes_ parameter with value b"1234" and identifier "bytes"
    yield param(np.bytes_(b"1234"), id="bytes")
    
    # Yield a np.str_ parameter with value "2345" and identifier "unicode"
    yield param(np.str_("2345"), id="unicode")
    
    # Yield a np.void parameter with value b"4321" and identifier "unstructured_void"
    yield param(np.void(b"4321"), id="unstructured_void")
def is_parametric_dtype(dtype):
    """Returns True if the dtype is a parametric legacy dtype (itemsize
    is 0, or a datetime without units)
    """
    # 检查 dtype 的 itemsize 是否为 0
    if dtype.itemsize == 0:
        return True
    # 检查 dtype 是否为 np.datetime64 或 np.timedelta64 的子类,并且以 "64" 结尾
    if issubclass(dtype.type, (np.datetime64, np.timedelta64)):
        if dtype.name.endswith("64"):
            # 返回 True,表示是通用的时间单位
            return True
    # 否则返回 False
    return False


class TestStringDiscovery:
    @pytest.mark.parametrize("obj",
            [object(), 1.2, 10**43, None, "string"],
            ids=["object", "1.2", "10**43", "None", "string"])
    def test_basic_stringlength(self, obj):
        # 获取对象 obj 的字符串长度
        length = len(str(obj))
        # 创建一个预期的 dtype,以字符串长度为长度的字节类型
        expected = np.dtype(f"S{length}")

        # 断言将 obj 转换为字节字符串后的 dtype 是否等于预期的 dtype
        assert np.array(obj, dtype="S").dtype == expected
        # 断言将包含 obj 的数组转换为字节字符串后的 dtype 是否等于预期的 dtype
        assert np.array([obj], dtype="S").dtype == expected

        # 检查嵌套数组也能正确地被发现
        arr = np.array(obj, dtype="O")
        assert np.array(arr, dtype="S").dtype == expected
        # 如果使用 dtype 类来指定,也应该能正确地被发现
        assert np.array(arr, dtype=type(expected)).dtype == expected
        # 检查 .astype() 方法的行为是否一致
        assert arr.astype("S").dtype == expected
        # `.astype()` 方法也能接受 DType 类型
        assert arr.astype(type(np.dtype("S"))).dtype == expected

    @pytest.mark.parametrize("obj",
            [object(), 1.2, 10**43, None, "string"],
            ids=["object", "1.2", "10**43", "None", "string"])
    def test_nested_arrays_stringlength(self, obj):
        # 获取对象 obj 的字符串长度
        length = len(str(obj))
        # 创建一个预期的 dtype,以字符串长度为长度的字节类型
        expected = np.dtype(f"S{length}")
        arr = np.array(obj, dtype="O")
        # 断言将包含 arr 和 arr 的数组转换为字节字符串后的 dtype 是否等于预期的 dtype
        assert np.array([arr, arr], dtype="S").dtype == expected

    @pytest.mark.parametrize("arraylike", arraylikes())
    def test_unpack_first_level(self, arraylike):
        # 我们解包一级数组
        obj = np.array([None])
        obj[0] = np.array(1.2)
        # 获取 obj[0] 的字符串表示的长度
        length = len(str(obj[0]))
        # 创建一个预期的 dtype,以字符串长度为长度的字节类型
        expected = np.dtype(f"S{length}")

        obj = arraylike(obj)
        # 将 obj 转换为字节字符串后,检查其形状是否为 (1, 1)
        arr = np.array([obj], dtype="S")
        assert arr.shape == (1, 1)
        # 检查转换后的 dtype 是否等于预期的 dtype
        assert arr.dtype == expected


class TestScalarDiscovery:
    def test_void_special_case(self):
        # 空类型 dtype 可以将元组识别为元素
        arr = np.array((1, 2, 3), dtype="i,i,i")
        # 检查数组形状是否为空
        assert arr.shape == ()
        arr = np.array([(1, 2, 3)], dtype="i,i,i")
        # 检查数组形状是否为 (1,)
        assert arr.shape == (1,)

    def test_char_special_case(self):
        # 字符类型的特殊情况
        arr = np.array("string", dtype="c")
        # 检查数组形状是否为 (6,)
        assert arr.shape == (6,)
        # 检查数组的字符类型是否为 'c'
        assert arr.dtype.char == "c"
        arr = np.array(["string"], dtype="c")
        # 检查数组形状是否为 (1, 6)
        assert arr.shape == (1, 6)
        # 检查数组的字符类型是否为 'c'
        assert arr.dtype.char == "c"
    # 定义一个测试方法,用于检查特殊字符情况是否能正确处理错误,如果数组维度太深会报错:
    def test_char_special_case_deep(self):
        # 嵌套列表,初始为包含一个字符串的列表(由于字符串是一个序列,所以是二维)
        nested = ["string"]  
        # 循环创建更深层次的嵌套,直到达到设定的最大维度减去2
        for i in range(ncu.MAXDIMS - 2):
            nested = [nested]

        # 创建一个 NumPy 数组,数据类型为 'c'(字符型)
        arr = np.array(nested, dtype='c')
        # 断言数组的形状为 (1,) * (ncu.MAXDIMS - 1) + (6,)
        assert arr.shape == (1,) * (ncu.MAXDIMS - 1) + (6,)
        # 使用 pytest 断言应该会抛出 ValueError 异常
        with pytest.raises(ValueError):
            # 创建一个 NumPy 数组,包含一个嵌套列表,数据类型为 'c'(字符型)
            np.array([nested], dtype="c")

    # 定义一个测试方法,用于检查创建未知对象的 NumPy 数组的情况:
    def test_unknown_object(self):
        # 创建一个包含未知对象的 NumPy 数组
        arr = np.array(object())
        # 断言数组的形状为空
        assert arr.shape == ()
        # 断言数组的数据类型为对象类型(np.dtype("O"))
        assert arr.dtype == np.dtype("O")

    # 使用 pytest.mark.parametrize 参数化测试方法,参数为 scalar_instances() 函数返回的值
    @pytest.mark.parametrize("scalar", scalar_instances())
    # 定义一个测试方法,用于检查标量情况的 NumPy 数组创建:
    def test_scalar(self, scalar):
        # 创建一个包含标量的 NumPy 数组
        arr = np.array(scalar)
        # 断言数组的形状为空
        assert arr.shape == ()
        # 断言数组的数据类型与标量的数据类型相同
        assert arr.dtype == scalar.dtype

        # 创建一个包含嵌套列表的 NumPy 数组,每个元素为相同的标量
        arr = np.array([[scalar, scalar]])
        # 断言数组的形状为 (1, 2)
        assert arr.shape == (1, 2)
        # 断言数组的数据类型与标量的数据类型相同
        assert arr.dtype == scalar.dtype

    # 使用 pytest.mark.filterwarnings 标记测试方法,忽略 "Promotion of numbers:FutureWarning" 警告
    # 定义一个测试方法,用于检查标量升级的情况:
    def test_scalar_promotion(self):
        # 对 scalar_instances() 返回的标量实例进行笛卡尔积的遍历
        for sc1, sc2 in product(scalar_instances(), scalar_instances()):
            # 从每个标量实例中取出第一个值
            sc1, sc2 = sc1.values[0], sc2.values[0]
            # 尝试创建一个包含 sc1 和 sc2 的 NumPy 数组
            try:
                arr = np.array([sc1, sc2])
            except (TypeError, ValueError):
                # 可能由于时间类型之间的升级问题而失败
                # XFAIL (ValueError): Some object casts are currently undefined
                continue
            # 断言数组的形状为 (2,)
            assert arr.shape == (2,)
            # 尝试确定 sc1 和 sc2 升级后的数据类型
            try:
                dt1, dt2 = sc1.dtype, sc2.dtype
                expected_dtype = np.promote_types(dt1, dt2)
                # 断言数组的数据类型与预期的升级数据类型相同
                assert arr.dtype == expected_dtype
            except TypeError as e:
                # 当前会导致数组的数据类型总是变为对象类型
                assert arr.dtype == np.dtype("O")
    # 定义一个测试方法,用于测试标量强制转换的不同路径,主要针对数值类型。
    # 包括一些与 `np.array` 直接相关的路径。
    def test_scalar_coercion(self, scalar):
        # 如果标量是浮点数类型,确保使用完整精度的数字
        if isinstance(scalar, np.inexact):
            scalar = type(scalar)((scalar * 2)**0.5)

        # 如果标量类型是 rational,通常由于缺少强制转换而失败。
        # 未来应基于 `setitem` 自动定义对象转换。
        if type(scalar) is rational:
            pytest.xfail("Rational to object cast is undefined currently.")

        # 使用对象类型的强制转换创建一个 numpy 数组
        arr = np.array(scalar, dtype=object).astype(scalar.dtype)

        # 测试创建包含此标量的数组的各种方法:
        arr1 = np.array(scalar).reshape(1)
        arr2 = np.array([scalar])
        arr3 = np.empty(1, dtype=scalar.dtype)
        arr3[0] = scalar
        arr4 = np.empty(1, dtype=scalar.dtype)
        arr4[:] = [scalar]
        # 所有这些方法应该产生相同的结果
        assert_array_equal(arr, arr1)
        assert_array_equal(arr, arr2)
        assert_array_equal(arr, arr3)
        assert_array_equal(arr, arr4)

    # 标记测试用例为预期失败(XFAIL),如果运行在 PyPy 环境下则跳过,
    # 原因是 `int(np.complex128(3))` 在 PyPy 上会失败。
    @pytest.mark.xfail(IS_PYPY, reason="`int(np.complex128(3))` fails on PyPy")
    # 忽略 numpy 的 ComplexWarning 警告
    @pytest.mark.filterwarnings("ignore::numpy.exceptions.ComplexWarning")
    # 使用 scalar_instances() 的参数化标记
    @pytest.mark.parametrize("cast_to", scalar_instances())
    # 测试标量强制转换是否与类型转换和赋值行为相同
    def test_scalar_coercion_same_as_cast_and_assignment(self, cast_to):
        """
        Test that in most cases:
           * `np.array(scalar, dtype=dtype)`
           * `np.empty((), dtype=dtype)[()] = scalar`
           * `np.array(scalar).astype(dtype)`
        should behave the same.  The only exceptions are parametric dtypes
        (mainly datetime/timedelta without unit) and void without fields.
        """
        dtype = cast_to.dtype  # 用于参数化目标数据类型

        # 对于标量实例的循环测试
        for scalar in scalar_instances(times=False):
            scalar = scalar.values[0]

            # 如果数据类型是 void
            if dtype.type == np.void:
               if scalar.dtype.fields is not None and dtype.fields is None:
                    # 在这种情况下,强制转换为 "V6" 是有效的,但类型转换会失败。
                    # 因为类型相同,SETITEM 会处理这个问题,但其规则与类型转换不同。
                    with pytest.raises(TypeError):
                        np.array(scalar).astype(dtype)
                    np.array(scalar, dtype=dtype)
                    np.array([scalar], dtype=dtype)
                    continue

            # 主要的测试路径,首先尝试使用类型转换,如果成功则继续下面的测试
            try:
                cast = np.array(scalar).astype(dtype)
            except (TypeError, ValueError, RuntimeError):
                # 强制转换也应该引发异常(错误类型可能会改变)
                with pytest.raises(Exception):
                    np.array(scalar, dtype=dtype)

                if (isinstance(scalar, rational) and
                        np.issubdtype(dtype, np.signedinteger)):
                    return

                with pytest.raises(Exception):
                    np.array([scalar], dtype=dtype)
                # 赋值也应该引发异常
                res = np.zeros((), dtype=dtype)
                with pytest.raises(Exception):
                    res[()] = scalar

                return

            # 非错误路径:
            arr = np.array(scalar, dtype=dtype)
            assert_array_equal(arr, cast)
            # 赋值行为相同
            ass = np.zeros((), dtype=dtype)
            ass[()] = scalar
            assert_array_equal(ass, cast)

    @pytest.mark.parametrize("pyscalar", [10, 10.32, 10.14j, 10**100])
    def test_pyscalar_subclasses(self, pyscalar):
        """NumPy arrays are read/write which means that anything but invariant
        behaviour is on thin ice.  However, we currently are happy to discover
        subclasses of Python float, int, complex the same as the base classes.
        This should potentially be deprecated.
        """
        class MyScalar(type(pyscalar)):
            pass

        res = np.array(MyScalar(pyscalar))
        expected = np.array(pyscalar)
        assert_array_equal(res, expected)
    # 使用 pytest 的参数化功能,对参数 dtype_char 逐一测试
    @pytest.mark.parametrize("dtype_char", np.typecodes["All"])
    def test_default_dtype_instance(self, dtype_char):
        # 如果 dtype_char 是 "SU" 中的字符之一
        if dtype_char in "SU":
            # 创建一个特定类型的 NumPy dtype 对象,例如 "S1" 或 "U1"
            dtype = np.dtype(dtype_char + "1")
        elif dtype_char == "V":
            # 在旧版行为中使用 V8,由于 float64 是默认的 dtype,并且占用 8 字节
            dtype = np.dtype("V8")
        else:
            # 创建一个普通的 NumPy dtype 对象,根据给定的字符 dtype_char
            dtype = np.dtype(dtype_char)

        # 调用 ncu._discover_array_parameters 函数,返回一个元组,其中包含发现的 dtype 和一个未使用的占位符
        discovered_dtype, _ = ncu._discover_array_parameters([], type(dtype))

        # 断言发现的 dtype 和预期的 dtype 相同
        assert discovered_dtype == dtype
        # 断言发现的 dtype 的字节大小与预期的 dtype 的字节大小相同
        assert discovered_dtype.itemsize == dtype.itemsize

    # 使用 pytest 的参数化功能,对参数 dtype 和一组特定的测试参数进行组合测试
    @pytest.mark.parametrize("dtype", np.typecodes["Integer"])
    @pytest.mark.parametrize(["scalar", "error"],
            [(np.float64(np.nan), ValueError),
             (np.array(-1).astype(np.ulonglong)[()], OverflowError)])
    def test_scalar_to_int_coerce_does_not_cast(self, dtype, scalar, error):
        """
        Signed integers are currently different in that they do not cast other
        NumPy scalar, but instead use scalar.__int__(). The hardcoded
        exception to this rule is `np.array(scalar, dtype=integer)`.
        """
        # 创建一个特定类型的 NumPy dtype 对象,根据参数 dtype
        dtype = np.dtype(dtype)

        # 在特定的错误状态下执行以下逻辑,忽略 "invalid" 错误
        with np.errstate(invalid="ignore"):
            # 使用 casting 逻辑创建 coerced 数组
            coerced = np.array(scalar, dtype=dtype)
            # 使用 astype 方法创建 cast 数组
            cast = np.array(scalar).astype(dtype)
        # 断言 coerced 和 cast 数组相等
        assert_array_equal(coerced, cast)

        # 然而以下情况会引发异常:
        with pytest.raises(error):
            # 使用特定的 dtype 创建包含 scalar 的数组,预期会抛出 error 异常
            np.array([scalar], dtype=dtype)
        with pytest.raises(error):
            # 使用特定的 dtype 对 cast 数组的元素进行赋值操作,预期会抛出 error 异常
            cast[()] = scalar
# 定义一个名为 TestTimeScalars 的测试类
class TestTimeScalars:
    
    # 使用 pytest.mark.parametrize 装饰器,为参数 dtype 指定多个取值
    # 取值为 np.int64 和 np.float32
    @pytest.mark.parametrize("dtype", [np.int64, np.float32])
    # 使用 pytest.mark.parametrize 装饰器,为参数 scalar 指定多个取值
    # 这些取值是 param() 对象,每个对象代表一个测试参数组合
    @pytest.mark.parametrize("scalar",
            [param(np.timedelta64("NaT", "s"), id="timedelta64[s](NaT)"),
             param(np.timedelta64(123, "s"), id="timedelta64[s]"),
             param(np.datetime64("NaT", "generic"), id="datetime64[generic](NaT)"),
             param(np.datetime64(1, "D"), id="datetime64[D]")],)
    # 定义测试方法 test_coercion_basic,接受参数 dtype 和 scalar
    def test_coercion_basic(self, dtype, scalar):
        # 注释:在这里加上 `[scalar]` 是因为 np.array(scalar) 使用更严格的
        # `scalar.__int__()` 规则,以保持向后兼容性。
        
        # 创建一个数组 arr,使用 scalar 和指定的 dtype
        arr = np.array(scalar, dtype=dtype)
        # 创建一个数组 cast,使用 scalar 并转换为指定的 dtype
        cast = np.array(scalar).astype(dtype)
        # 断言数组 arr 和 cast 相等
        assert_array_equal(arr, cast)

        # 创建一个全为 1 的数组 ass,dtype 为指定的 dtype
        ass = np.ones((), dtype=dtype)
        # 如果 dtype 是 np.integer 的子类
        if issubclass(dtype, np.integer):
            # 使用 pytest.raises 检查是否会抛出 TypeError 异常
            with pytest.raises(TypeError):
                # 注释:抛出异常,就像 np.array([scalar], dtype=dtype) 一样,
                # 这是时间的转换,但整数的行为。
                ass[()] = scalar
        else:
            # 将 ass 数组的第一个元素赋值为 scalar
            ass[()] = scalar
            # 断言数组 ass 和 cast 相等
            assert_array_equal(ass, cast)

    # 使用 pytest.mark.parametrize 装饰器,为参数 dtype 指定多个取值
    # 取值为 np.int64 和 np.float32
    @pytest.mark.parametrize("dtype", [np.int64, np.float32])
    # 使用 pytest.mark.parametrize 装饰器,为参数 scalar 指定多个取值
    # 这些取值是 param() 对象,每个对象代表一个测试参数组合
    @pytest.mark.parametrize("scalar",
            [param(np.timedelta64(123, "ns"), id="timedelta64[ns]"),
             param(np.timedelta64(12, "generic"), id="timedelta64[generic]")])
    # 定义测试方法 test_coercion_timedelta_convert_to_number,接受参数 dtype 和 scalar
    def test_coercion_timedelta_convert_to_number(self, dtype, scalar):
        # 注释:只有 "ns" 和 "generic" 类型的 timedelta 可以转换为数字,
        # 所以这些稍微特殊一些。
        
        # 创建一个数组 arr,使用 scalar 和指定的 dtype
        arr = np.array(scalar, dtype=dtype)
        # 创建一个数组 cast,使用 scalar 并转换为指定的 dtype
        cast = np.array(scalar).astype(dtype)
        # 创建一个全为 1 的数组 ass,dtype 为指定的 dtype
        ass = np.ones((), dtype=dtype)
        # 将 ass 数组的第一个元素赋值为 scalar,会抛出异常,就像 np.array([scalar], dtype=dtype) 一样
        ass[()] = scalar  

        # 断言数组 arr 和 cast 相等
        assert_array_equal(arr, cast)
        # 断言数组 cast 和 cast 相等
        assert_array_equal(cast, cast)

    # 使用 pytest.mark.parametrize 装饰器,为参数 dtype 指定多个取值
    # 取值为 "S6" 和 "U6"
    @pytest.mark.parametrize("dtype", ["S6", "U6"])
    # 使用 pytest.mark.parametrize 装饰器,为参数 val 和 unit 指定多个取值
    # 这些取值是 param() 对象,每个对象代表一个测试参数组合
    @pytest.mark.parametrize(["val", "unit"],
            [param(123, "s", id="[s]"), param(123, "D", id="[D]")])
    # 定义一个测试方法,用于验证 datetime64 类型数据的赋值和强制类型转换
    def test_coercion_assignment_datetime(self, val, unit, dtype):
        # 对于从 datetime64 赋值的字符串,目前特别处理,不会进行强制类型转换。
        # 这是因为在这种情况下强制转换会导致错误,而传统上大多数情况下保持这种行为。
        # (`np.array(scalar, dtype="U6")` 在此之前会失败)
        # TODO: 应该解决这种差异,可以通过放宽强制转换或者弃用第一部分来解决。
        scalar = np.datetime64(val, unit)
        dtype = np.dtype(dtype)
        # 从 dtype 中提取 datetime64 的字符串表示,并截取前6个字符
        cut_string = dtype.type(str(scalar)[:6])

        # 使用 scalar 创建一个 dtype 类型的数组 arr
        arr = np.array(scalar, dtype=dtype)
        # 验证数组 arr 中索引为 () 的值与截取的字符串相等
        assert arr[()] == cut_string

        # 创建一个元素为 () 的 dtype 类型数组 ass,并将 scalar 赋值给该数组
        ass = np.ones((), dtype=dtype)
        ass[()] = scalar
        # 验证数组 ass 中索引为 () 的值与截取的字符串相等
        assert ass[()] == cut_string

        # 使用 pytest 检查以下代码会抛出 RuntimeError 异常
        with pytest.raises(RuntimeError):
            # 然而,与使用 `str(scalar)[:6]` 进行赋值不同,因为它由字符串类型处理而不是强制类型转换,
            # 显式强制类型转换失败:
            np.array(scalar).astype(dtype)


    @pytest.mark.parametrize(["val", "unit"],
            # 参数化测试用例,用于验证 timedelta64 类型数据的赋值和强制类型转换
            [param(123, "s", id="[s]"), param(123, "D", id="[D]")])
    def test_coercion_assignment_timedelta(self, val, unit):
        # 使用给定的 val 和 unit 创建一个 timedelta64 类型的 scalar
        scalar = np.timedelta64(val, unit)

        # 与 datetime64 不同,timedelta 允许不安全的强制转换:
        np.array(scalar, dtype="S6")
        # 使用 np.array 创建一个 scalar 的 S 类型的数组 cast
        cast = np.array(scalar).astype("S6")
        # 创建一个元素为 () 的 S 类型数组 ass,并将 scalar 赋值给该数组
        ass = np.ones((), dtype="S6")
        ass[()] = scalar
        # 预期的结果是将 scalar 强制转换为 S 类型后取前6个字符
        expected = scalar.astype("S")[:6]
        # 验证 cast 数组中索引为 () 的值与 expected 相等
        assert cast[()] == expected
        # 验证 ass 数组中索引为 () 的值与 expected 相等
        assert ass[()] == expected
    @pytest.mark.parametrize("arraylike", arraylikes())
    # 使用参数化测试,依次传入各种类似数组的对象进行测试
    def test_nested_arraylikes(self, arraylike):
        # 创建一个形状为 (1, 1) 的数组对象,并将其赋给 initial
        initial = arraylike(np.ones((1, 1)))

        # 使用 initial 初始化 nested 变量
        nested = initial
        # 循环创建 ncu.MAXDIMS - 1 层嵌套结构
        for i in range(ncu.MAXDIMS - 1):
            nested = [nested]

        # 断言尝试创建 np.array(nested, dtype="float64") 时抛出 ValueError 异常
        with pytest.raises(ValueError, match=".*would exceed the maximum"):
            np.array(nested, dtype="float64")

        # 创建一个 np.array,将 nested 对象放入,指定 dtype 为 object
        arr = np.array(nested, dtype=object)
        # 断言 arr 的数据类型为 np.dtype("O")
        assert arr.dtype == np.dtype("O")
        # 断言 arr 的形状为 (1,) * ncu.MAXDIMS
        assert arr.shape == (1,) * ncu.MAXDIMS
        # 断言 arr 的单元素与 initial 相同
        assert arr.item() == np.array(initial).item()
    def test_empty_sequence(self):
        # 创建一个包含空数组的对象数组,第一个数组为空,影响后续维度的发现
        arr = np.array([[], [1], [[1]]], dtype=object)
        # 断言数组的形状为 (3,)
        assert arr.shape == (3,)

        # 空序列会阻止进一步的维度发现,因此结果的形状将是 (0,),
        # 在以下操作中将导致错误:
        with pytest.raises(ValueError):
            # 创建包含空数组和空对象的数组,会引发异常
            np.array([[], np.empty((0, 1))], dtype=object)

    def test_array_of_different_depths(self):
        # 当序列中包含深度不同的多个数组(或类数组对象)时,当前方法会发现它们共享的维度。
        # 参见也 gh-17224
        # 创建一个形状为 (3, 2) 的全零数组
        arr = np.zeros((3, 2))
        # 创建一个与 arr 第一维度不匹配的全零数组
        mismatch_first_dim = np.zeros((1, 2))
        # 创建一个与 arr 第二维度不匹配的全零数组
        mismatch_second_dim = np.zeros((3, 3))

        # 使用 ncu._discover_array_parameters 函数发现数组的参数,指定数据类型为对象类型
        dtype, shape = ncu._discover_array_parameters(
            [arr, mismatch_second_dim], dtype=np.dtype("O"))
        # 断言发现的形状为 (2, 3)
        assert shape == (2, 3)

        # 再次使用 ncu._discover_array_parameters 函数发现数组的参数,指定数据类型为对象类型
        dtype, shape = ncu._discover_array_parameters(
            [arr, mismatch_first_dim], dtype=np.dtype("O"))
        # 断言发现的形状为 (2,)
        assert shape == (2,)
        
        # 第二种情况目前受支持,因为这些数组可以存储为对象:
        # 使用 np.asarray 将数组 arr 和 mismatch_first_dim 转换为对象数组
        res = np.asarray([arr, mismatch_first_dim], dtype=np.dtype("O"))
        # 断言 res 的第一个元素是 arr
        assert res[0] is arr
        # 断言 res 的第二个元素是 mismatch_first_dim
        assert res[1] is mismatch_first_dim
class TestBadSequences:
    # 这些是对传递给 `np.array` 的不良对象进行测试的用例,通常会导致未定义的行为。
    # 在旧代码中,它们部分工作,但在现在它们将会失败。
    # 我们可以(也许应该)复制所有序列来防范不良行为者。

    def test_growing_list(self):
        # 要强制转换的列表,`mylist` 在强制转换期间会向其追加内容
        obj = []
        class mylist(list):
            def __len__(self):
                obj.append([1, 2])
                return super().__len__()

        obj.append(mylist([1, 2]))

        # 断言会抛出 RuntimeError 异常
        with pytest.raises(RuntimeError):
            np.array(obj)

    # 注意:我们没有测试缩减列表。这些会做非常恶意的事情,
    #       要修复它们的唯一方法是复制所有序列。
    #       (这在未来可能是一个真实的选项。)

    def test_mutated_list(self):
        # 要强制转换的列表,`mylist` 会改变第一个元素
        obj = []
        class mylist(list):
            def __len__(self):
                obj[0] = [2, 3]  # 用另一个列表替换第一个元素
                return super().__len__()

        obj.append([2, 3])
        obj.append(mylist([1, 2]))
        # 不会导致崩溃:
        np.array(obj)

    def test_replace_0d_array(self):
        # 要强制转换的列表,`baditem` 会改变第一个元素
        obj = []
        class baditem:
            def __len__(self):
                obj[0][0] = 2  # 用另一个列表替换第一个元素
                raise ValueError("not actually a sequence!")

            def __getitem__(self):
                pass

        # 在新代码中遇到一个边缘情况,`array(2)` 被缓存,
        # 因此替换它会使缓存无效。
        obj.append([np.array(2), baditem()])
        # 断言会抛出 RuntimeError 异常
        with pytest.raises(RuntimeError):
            np.array(obj)


class TestArrayLikes:
    @pytest.mark.parametrize("arraylike", arraylikes())
    def test_0d_object_special_case(self, arraylike):
        arr = np.array(0.)
        obj = arraylike(arr)
        # 单个类数组总是被转换:
        res = np.array(obj, dtype=object)
        assert_array_equal(arr, res)

        # 但单个 0-D 嵌套类数组永远不会:
        res = np.array([obj], dtype=object)
        assert res[0] is obj

    @pytest.mark.parametrize("arraylike", arraylikes())
    @pytest.mark.parametrize("arr", [np.array(0.), np.arange(4)])
    def test_object_assignment_special_case(self, arraylike, arr):
        obj = arraylike(arr)
        empty = np.arange(1, dtype=object)
        empty[:] = [obj]
        assert empty[0] is obj
    def test_0d_generic_special_case(self):
        # 定义一个继承自 np.ndarray 的数组子类,重写 __float__ 方法抛出 TypeError
        class ArraySubclass(np.ndarray):
            def __float__(self):
                raise TypeError("e.g. quantities raise on this")

        # 创建一个包含单个浮点数 0.0 的 numpy 数组
        arr = np.array(0.)
        # 通过视图将 arr 转换为 ArraySubclass 类型的对象
        obj = arr.view(ArraySubclass)
        # 再次将 obj 转换为 numpy 数组
        res = np.array(obj)
        # 断言两个数组内容相等
        assert_array_equal(arr, res)

        # 如果包含了 0 维数组,当前保证会使用 __float__ 方法抛出 TypeError 异常
        # 这里可能会考虑改变这种行为,因为 quantities 和 masked arrays 部分依赖于这一特性
        with pytest.raises(TypeError):
            np.array([obj])

        # 对于 memoryview 类型的对象也是一样的
        obj = memoryview(arr)
        # 再次尝试将其转换为 numpy 数组
        res = np.array(obj)
        # 断言两个数组内容相等
        assert_array_equal(arr, res)
        with pytest.raises(ValueError):
            # 这里错误类型并不重要
            np.array([obj])

    def test_arraylike_classes(self):
        # 各种数组类通常应该能够被存储在 numpy 的对象数组中
        # 这里测试了所有特殊属性(因为在强制转换期间会检查所有属性)
        
        # 创建一个包含 np.int64 类型的 numpy 数组
        arr = np.array(np.int64)
        # 断言索引 () 处的元素是 np.int64 类型
        assert arr[()] is np.int64
        
        # 创建一个包含 [np.int64] 的 numpy 数组
        arr = np.array([np.int64])
        # 断言第一个元素是 np.int64 类型
        assert arr[0] is np.int64

        # 对于属性/未绑定方法同样适用
        class ArrayLike:
            @property
            def __array_interface__(self):
                pass

            @property
            def __array_struct__(self):
                pass

            def __array__(self, dtype=None, copy=None):
                pass

        # 创建一个包含 ArrayLike 类型的 numpy 数组
        arr = np.array(ArrayLike)
        # 断言索引 () 处的元素是 ArrayLike 类型
        assert arr[()] is ArrayLike

        # 创建一个包含 [ArrayLike] 的 numpy 数组
        arr = np.array([ArrayLike])
        # 断言第一个元素是 ArrayLike 类型
        assert arr[0] is ArrayLike

    @pytest.mark.skipif(
            np.dtype(np.intp).itemsize < 8, reason="Needs 64bit platform")
    def test_too_large_array_error_paths(self):
        """Test the error paths, including for memory leaks"""
        # 创建一个 uint8 类型的元素为 0 的 numpy 数组
        arr = np.array(0, dtype="uint8")
        # 确保一个连续的拷贝不会起作用
        arr = np.broadcast_to(arr, 2**62)

        # 循环测试,确保缓存无法产生影响
        for i in range(5):
            # 期望内存错误异常被抛出,因为无法分配如此大的内存
            with pytest.raises(MemoryError):
                np.array(arr)
            with pytest.raises(MemoryError):
                np.array([arr])

    @pytest.mark.parametrize("attribute",
        ["__array_interface__", "__array__", "__array_struct__"])
    @pytest.mark.parametrize("error", [RecursionError, MemoryError])
    # 测试处理具有类似数组的不良属性的情况,使用指定的属性和错误类型

    # 定义一个名为 BadInterface 的类,用于模拟具有不良属性的接口
    class BadInterface:
        # 当调用不存在的属性时,如果属性名与传入的 attribute 相同,则抛出指定的错误
        def __getattr__(self, attr):
            if attr == attribute:
                raise error
            # 否则调用父类的同名方法,但是这里实际上应该使用 super().__getattribute__(attr)
            super().__getattr__(attr)

    # 使用 pytest 的上下文管理器检查是否会抛出指定的错误
    with pytest.raises(error):
        # 将 BadInterface 实例化为 NumPy 数组,期望抛出错误
        np.array(BadInterface())

@pytest.mark.parametrize("error", [RecursionError, MemoryError])
def test_bad_array_like_bad_length(self, error):
    # 测试处理具有类似数组但长度错误的情况,使用指定的错误类型

    # 定义一个名为 BadSequence 的类,用于模拟具有错误长度的序列
    class BadSequence:
        # 当调用 __len__ 方法时,抛出指定的错误
        def __len__(self):
            raise error
        # 必须实现 __getitem__ 方法以符合序列的要求,这里只是简单返回一个值
        def __getitem__(self):
            return 1

    # 使用 pytest 的上下文管理器检查是否会抛出指定的错误
    with pytest.raises(error):
        # 将 BadSequence 实例化为 NumPy 数组,期望抛出错误
        np.array(BadSequence())
# 定义一个名为 TestAsArray 的类,用于测试函数 asarray 的预期行为
class TestAsArray:
    """Test expected behaviors of ``asarray``."""
    def test_dtype_identity(self):
        """
        确认 *dtype* 关键字参数的预期行为。

        当使用 ``asarray()`` 时,通过关键字参数提供的 dtype 应该被应用到结果数组上。
        这会强制对于唯一的 np.dtype 对象产生唯一的数组处理方式,但对于等价的 dtypes,底层数据(即基础对象)与原始数组对象是共享的。

        参考 https://github.com/numpy/numpy/issues/1468
        """
        # 创建一个整数数组 int_array
        int_array = np.array([1, 2, 3], dtype='i')
        # 断言 np.asarray(int_array) 返回的是 int_array 本身
        assert np.asarray(int_array) is int_array

        # 字符代码解析为由 numpy 包提供的单例 dtype 对象。
        assert np.asarray(int_array, dtype='i') is int_array

        # 从 n.dtype('i') 派生一个 dtype,但添加一个元数据对象以强制使 dtype 不同。
        unequal_type = np.dtype('i', metadata={'spam': True})
        annotated_int_array = np.asarray(int_array, dtype=unequal_type)
        # 断言 annotated_int_array 不是 int_array
        assert annotated_int_array is not int_array
        # 断言 annotated_int_array 的基础对象是 int_array
        assert annotated_int_array.base is int_array
        # 创建一个具有新的不同 dtype 实例的等价描述符。
        equivalent_requirement = np.dtype('i', metadata={'spam': True})
        annotated_int_array_alt = np.asarray(annotated_int_array,
                                             dtype=equivalent_requirement)
        # 断言 unequal_type 与 equivalent_requirement 相等
        assert unequal_type == equivalent_requirement
        # 断言 unequal_type 不是 equivalent_requirement
        assert unequal_type is not equivalent_requirement
        # 断言 annotated_int_array_alt 不是 annotated_int_array
        assert annotated_int_array_alt is not annotated_int_array
        # 断言 annotated_int_array_alt 的 dtype 是 equivalent_requirement
        assert annotated_int_array_alt.dtype is equivalent_requirement

        # 检查一对 C 类型的相同逻辑,它们在计算环境之间的等效性可能有所不同。
        # 找到一个等价对。
        integer_type_codes = ('i', 'l', 'q')
        integer_dtypes = [np.dtype(code) for code in integer_type_codes]
        typeA = None
        typeB = None
        for typeA, typeB in permutations(integer_dtypes, r=2):
            if typeA == typeB:
                assert typeA is not typeB
                break
        assert isinstance(typeA, np.dtype) and isinstance(typeB, np.dtype)

        # 这些 ``asarray()`` 调用可能产生一个新视图或副本,但绝不是相同的对象。
        long_int_array = np.asarray(int_array, dtype='l')
        long_long_int_array = np.asarray(int_array, dtype='q')
        assert long_int_array is not int_array
        assert long_long_int_array is not int_array
        assert np.asarray(long_int_array, dtype='q') is not long_int_array
        array_a = np.asarray(int_array, dtype=typeA)
        assert typeA == typeB
        assert typeA is not typeB
        assert array_a.dtype is typeA
        assert array_a is not np.asarray(array_a, dtype=typeB)
        assert np.asarray(array_a, dtype=typeB).dtype is typeB
        assert array_a is np.asarray(array_a, dtype=typeB).base
class TestSpecialAttributeLookupFailure:
    # 定义一个测试类用于特殊属性查找失败的情况

    class WeirdArrayLike:
        @property
        def __array__(self, dtype=None, copy=None):
            # 定义一个属性方法__array__,抛出运行时异常"oops!"
            raise RuntimeError("oops!")

    class WeirdArrayInterface:
        @property
        def __array_interface__(self):
            # 定义一个属性方法__array_interface__,抛出运行时异常"oops!"
            raise RuntimeError("oops!")

    def test_deprecated(self):
        # 定义测试方法test_deprecated
        with pytest.raises(RuntimeError):
            # 使用pytest断言捕获RuntimeError异常
            np.array(self.WeirdArrayLike())
        with pytest.raises(RuntimeError):
            # 使用pytest断言捕获RuntimeError异常
            np.array(self.WeirdArrayInterface())


def test_subarray_from_array_construction():
    # 定义测试函数test_subarray_from_array_construction
    # 创建一个数组arr,包含元素[1, 2]
    arr = np.array([1, 2])

    # 将arr转换为指定dtype的数组res,预期结果是[[1, 1], [2, 2]]
    res = arr.astype("2i")
    assert_array_equal(res, [[1, 1], [2, 2]])

    # 使用arr构造一个新数组res,指定dtype为"(2,)i",预期结果是[[1, 1], [2, 2]]
    res = np.array(arr, dtype="(2,)i")
    assert_array_equal(res, [[1, 1], [2, 2]])

    # 使用arr和其他元素构造一个多维数组res,指定dtype为"2i",预期结果是[[[1, 1], [2, 2]], [[1, 1], [2, 2]]]
    res = np.array([[(1,), (2,)], arr], dtype="2i")
    assert_array_equal(res, [[[1, 1], [2, 2]], [[1, 1], [2, 2]]])

    # 再次尝试多维示例:
    # 创建一个5行2列的数组arr
    arr = np.arange(5 * 2).reshape(5, 2)
    # 根据arr的形状广播到新形状(5, 2, 2, 2),并赋值给expected
    expected = np.broadcast_to(arr[:, :, np.newaxis, np.newaxis], (5, 2, 2, 2))

    # 将arr转换为指定dtype的数组res,预期结果是广播到expected的形状
    res = arr.astype("(2,2)f")
    assert_array_equal(res, expected)

    # 使用arr构造一个新数组res,指定dtype为"(2,2)f",预期结果是广播到expected的形状
    res = np.array(arr, dtype="(2,2)f")
    assert_array_equal(res, expected)


def test_empty_string():
    # 定义测试函数test_empty_string
    # 创建一个长度为10的空字符串数组,dtype为"S",预期结果是包含"\0"的S1数组
    res = np.array([""] * 10, dtype="S")
    assert_array_equal(res, np.array("\0", "S1"))
    assert res.dtype == "S1"

    # 创建一个长度为10的空字符串数组arr,dtype为object
    arr = np.array([""] * 10, dtype=object)

    # 将arr转换为指定dtype的数组res,预期结果是包含b""的S1数组
    res = arr.astype("S")
    assert_array_equal(res, b"")
    assert res.dtype == "S1"

    # 使用arr构造一个新数组res,dtype为"S",预期结果是包含b""的S1数组
    res = np.array(arr, dtype="S")
    assert_array_equal(res, b"")
    # TODO: This is arguably weird/wrong, but seems old:
    # 断言结果的dtype可能会与旧版本的S1不同,但现在是S1
    assert res.dtype == f"S{np.dtype('O').itemsize}"

    # 使用arr和另一个空字符串数组构造新数组res,dtype为"S",预期结果是包含b""的S1数组,形状为(2, 10)
    res = np.array([[""] * 10, arr], dtype="S")
    assert_array_equal(res, b"")
    assert res.shape == (2, 10)
    assert res.dtype == "S1"

.\numpy\numpy\_core\tests\test_array_interface.py

# 导入系统相关模块
import sys
# 导入 pytest 测试框架模块
import pytest
# 导入 numpy 模块并重命名为 np
import numpy as np
# 从 numpy.testing 模块导入 extbuild, IS_WASM, IS_EDITABLE
from numpy.testing import extbuild, IS_WASM, IS_EDITABLE

# 定义 pytest 的 fixture,用于生成数据和管理临时缓冲区,以便通过数组接口协议与 numpy 共享
@pytest.fixture
def get_module(tmp_path):
    """ Some codes to generate data and manage temporary buffers use when
    sharing with numpy via the array interface protocol.
    """

    # 如果不是在 Linux 平台上,跳过测试(在 cygwin 上链接失败)
    if not sys.platform.startswith('linux'):
        pytest.skip('link fails on cygwin')
    
    # 如果是在 WASM 环境中,跳过测试(无法在 WASM 中构建模块)
    if IS_WASM:
        pytest.skip("Can't build module inside Wasm")
    
    # 如果是可编辑安装,跳过测试(无法为可编辑安装构建模块)
    if IS_EDITABLE:
        pytest.skip("Can't build module for editable install")

    # 定义 prologue 变量,存储 C 语言代码片段,用于构建模块的初始化
    prologue = '''
        #include <Python.h>
        #define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
        #include <numpy/arrayobject.h>
        #include <stdio.h>
        #include <math.h>

        NPY_NO_EXPORT
        void delete_array_struct(PyObject *cap) {

            /* get the array interface structure */
            // 获取数组接口结构体指针
            PyArrayInterface *inter = (PyArrayInterface*)
                PyCapsule_GetPointer(cap, NULL);

            /* get the buffer by which data was shared */
            // 获取共享数据的缓冲区指针
            double *ptr = (double*)PyCapsule_GetContext(cap);

            /* for the purposes of the regression test set the elements
               to nan */
            // 为回归测试目的,将元素设置为 nan
            for (npy_intp i = 0; i < inter->shape[0]; ++i)
                ptr[i] = nan("");

            /* free the shared buffer */
            // 释放共享缓冲区
            free(ptr);

            /* free the array interface structure */
            // 释放数组接口结构体
            free(inter->shape);
            free(inter);

            // 输出调试信息
            fprintf(stderr, "delete_array_struct\\ncap = %ld inter = %ld"
                " ptr = %ld\\n", (long)cap, (long)inter, (long)ptr);
        }
        '''
    functions = [
        ("new_array_struct", "METH_VARARGS", """
            # 定义一个新的 Python C 扩展函数 new_array_struct,接受变长参数
            long long n_elem = 0;  # 声明并初始化数组元素数量为0
            double value = 0.0;  # 声明并初始化数组元素的默认值为0.0

            # 解析传入的 Python 参数 args,期望参数为一个长整型和一个双精度浮点数
            if (!PyArg_ParseTuple(args, "Ld", &n_elem, &value)) {
                Py_RETURN_NONE;  # 如果解析失败,返回 None
            }

            /* 分配并初始化用于与 NumPy 共享的数据内存 */
            long long n_bytes = n_elem*sizeof(double);  // 计算需要分配的字节数
            double *data = (double*)malloc(n_bytes);  // 分配内存空间

            if (!data) {
                PyErr_Format(PyExc_MemoryError,
                    "Failed to malloc %lld bytes", n_bytes);  // 如果分配内存失败,抛出内存错误异常

                Py_RETURN_NONE;  // 返回 None
            }

            // 将数组初始化为指定值
            for (long long i = 0; i < n_elem; ++i) {
                data[i] = value;
            }

            /* 计算数组的形状和步幅 */
            int nd = 1;  // 数组维度为1

            npy_intp *ss = (npy_intp*)malloc(2*nd*sizeof(npy_intp));  // 分配存储形状和步幅的内存
            npy_intp *shape = ss;  // 指向形状数据的指针
            npy_intp *stride = ss + nd;  // 指向步幅数据的指针

            shape[0] = n_elem;  // 设置数组形状的第一个维度为元素数量
            stride[0] = sizeof(double);  // 设置数组步幅的第一个维度为双精度浮点数的大小

            /* 构建数组接口 */
            PyArrayInterface *inter = (PyArrayInterface*)
                malloc(sizeof(PyArrayInterface));  // 分配数组接口的内存空间

            memset(inter, 0, sizeof(PyArrayInterface));  // 将分配的内存清零

            inter->two = 2;  // 设置数组接口版本号
            inter->nd = nd;  // 设置数组接口的维度数
            inter->typekind = 'f';  // 设置数组接口的数据类型为浮点数
            inter->itemsize = sizeof(double);  // 设置数组接口的每个元素大小
            inter->shape = shape;  // 设置数组接口的形状数据指针
            inter->strides = stride;  // 设置数组接口的步幅数据指针
            inter->data = data;  // 设置数组接口的数据指针
            inter->flags = NPY_ARRAY_WRITEABLE | NPY_ARRAY_NOTSWAPPED |
                           NPY_ARRAY_ALIGNED | NPY_ARRAY_C_CONTIGUOUS;  // 设置数组接口的标志位

            /* 封装为一个 Capsule 对象 */
            PyObject *cap = PyCapsule_New(inter, NULL, delete_array_struct);  // 创建一个 Capsule 对象
            PyCapsule_SetContext(cap, data);  // 在 Capsule 对象中保存数据指针

            // 打印调试信息到标准错误输出
            fprintf(stderr, "new_array_struct\\ncap = %ld inter = %ld"
                " ptr = %ld\\n", (long)cap, (long)inter, (long)data);

            // 返回创建的 Capsule 对象
            return cap;
        """)
        ]

    more_init = "import_array();"

    try:
        import array_interface_testing
        return array_interface_testing  # 尝试导入已存在的 array_interface_testing 模块并返回
    except ImportError:
        pass

    // 如果模块不存在,使用 extbuild 构建并导入扩展模块
    return extbuild.build_and_import_extension('array_interface_testing',
                                               functions,
                                               prologue=prologue,
                                               include_dirs=[np.get_include()],
                                               build_dir=tmp_path,
                                               more_init=more_init)
@pytest.mark.slow
def test_cstruct(get_module):
    """
    Test case for validating the behavior of the PyCapsule destructor
    when numpy releases its reference to shared data through the array
    interface protocol.
    """

    class data_source:
        """
        This class is for testing the timing of the PyCapsule destructor
        invoked when numpy release its reference to the shared data as part of
        the numpy array interface protocol. If the PyCapsule destructor is
        called early the shared data is freed and invalid memory accesses will
        occur.
        """

        def __init__(self, size, value):
            self.size = size
            self.value = value

        @property
        def __array_struct__(self):
            """
            Method returning a new array struct using size and value from
            the instance.
            """
            return get_module.new_array_struct(self.size, self.value)

    # write to the same stream as the C code
    stderr = sys.__stderr__

    # used to validate the shared data.
    expected_value = -3.1415
    multiplier = -10000.0

    # create some data to share with numpy via the array interface
    # assign the data an expected value.
    stderr.write(' ---- create an object to share data ---- \n')
    buf = data_source(256, expected_value)
    stderr.write(' ---- OK!\n\n')

    # share the data
    stderr.write(' ---- share data via the array interface protocol ---- \n')
    arr = np.array(buf, copy=False)
    stderr.write('arr.__array_interface___ = %s\n' % (
                 str(arr.__array_interface__)))
    stderr.write('arr.base = %s\n' % (str(arr.base)))
    stderr.write(' ---- OK!\n\n')

    # release the source of the shared data. this will not release the data
    # that was shared with numpy, that is done in the PyCapsule destructor.
    stderr.write(' ---- destroy the object that shared data ---- \n')
    buf = None
    stderr.write(' ---- OK!\n\n')

    # check that we got the expected data. If the PyCapsule destructor we
    # defined was prematurely called then this test will fail because our
    # destructor sets the elements of the array to NaN before free'ing the
    # buffer. Reading the values here may also cause a SEGV
    assert np.allclose(arr, expected_value)

    # read the data. If the PyCapsule destructor we defined was prematurely
    # called then reading the values here may cause a SEGV and will be reported
    # as invalid reads by valgrind
    stderr.write(' ---- read shared data ---- \n')
    stderr.write('arr = %s\n' % (str(arr)))
    stderr.write(' ---- OK!\n\n')

    # write to the shared buffer. If the shared data was prematurely deleted
    # this will may cause a SEGV and valgrind will report invalid writes
    stderr.write(' ---- modify shared data ---- \n')
    arr *= multiplier
    expected_value *= multiplier
    stderr.write('arr.__array_interface___ = %s\n' % (
                 str(arr.__array_interface__)))
    stderr.write('arr.base = %s\n' % (str(arr.base)))
    stderr.write(' ---- OK!\n\n')

    # read the data. If the shared data was prematurely deleted this
    # will may cause a SEGV and valgrind will report invalid reads
    stderr.write(' ---- read modified shared data ---- \n')
    # 输出调试信息,显示 arr 的值
    stderr.write('arr = %s\n' % (str(arr)))
    # 输出调试信息,表示测试通过
    stderr.write(' ---- OK!\n\n')

    # 检查是否获得了预期的数据。如果我们定义的 PyCapsule 析构函数被提前调用,
    # 这个测试将失败,因为我们的析构函数在释放缓冲区之前将数组元素设置为 NaN。
    # 在这里读取值可能会导致段错误(SEGV)。
    assert np.allclose(arr, expected_value)

    # 释放共享数据,这里应该运行 PyCapsule 的析构函数
    stderr.write(' ---- free shared data ---- \n')
    # 将 arr 设置为 None,释放共享数据
    arr = None
    # 输出调试信息,表示释放共享数据成功
    stderr.write(' ---- OK!\n\n')

.\numpy\numpy\_core\tests\test_casting_floatingpoint_errors.py

# 导入 pytest 库,用于编写和运行测试用例
import pytest
# 从 pytest 库中导入 param 对象,用于参数化测试用例
from pytest import param
# 导入 numpy.testing 模块中的 IS_WASM
from numpy.testing import IS_WASM
# 导入 numpy 库,并使用 np 别名
import numpy as np


def values_and_dtypes():
    """
    生成会导致浮点错误的数值和数据类型对,包括整数到浮点数的无效转换(会产生"invalid"警告)
    和浮点数转换的溢出(会产生"overflow"警告)。

    (Python 中 int/float 的路径不需要在所有相同情况下进行测试,但也不会有害。)
    """
    # 转换为 float16:
    yield param(70000, "float16", id="int-to-f2")
    yield param("70000", "float16", id="str-to-f2")
    yield param(70000.0, "float16", id="float-to-f2")
    yield param(np.longdouble(70000.), "float16", id="longdouble-to-f2")
    yield param(np.float64(70000.), "float16", id="double-to-f2")
    yield param(np.float32(70000.), "float16", id="float-to-f2")
    # 转换为 float32:
    yield param(10**100, "float32", id="int-to-f4")
    yield param(1e100, "float32", id="float-to-f2")
    yield param(np.longdouble(1e300), "float32", id="longdouble-to-f2")
    yield param(np.float64(1e300), "float32", id="double-to-f2")
    # 转换为 float64:
    # 如果 longdouble 是 double-double,其最大值可能被舍入到 double 的最大值。
    # 所以我们校正了 double 间距(有点奇怪,不过):
    max_ld = np.finfo(np.longdouble).max
    spacing = np.spacing(np.nextafter(np.finfo("f8").max, 0))
    if max_ld - spacing > np.finfo("f8").max:
        yield param(np.finfo(np.longdouble).max, "float64",
                    id="longdouble-to-f8")

    # 转换为 complex32:
    yield param(2e300, "complex64", id="float-to-c8")
    yield param(2e300+0j, "complex64", id="complex-to-c8")
    yield param(2e300j, "complex64", id="complex-to-c8")
    yield param(np.longdouble(2e300), "complex64", id="longdouble-to-c8")

    # 无效的浮点到整数转换:
    with np.errstate(over="ignore"):
        for to_dt in np.typecodes["AllInteger"]:
            for value in [np.inf, np.nan]:
                for from_dt in np.typecodes["AllFloat"]:
                    from_dt = np.dtype(from_dt)
                    from_val = from_dt.type(value)

                    yield param(from_val, to_dt, id=f"{from_val}-to-{to_dt}")


def check_operations(dtype, value):
    """
    NumPy 中有许多专用路径进行类型转换,应检查在这些转换过程中发生的浮点错误。
    """
    if dtype.kind != 'i':
        # 这些赋值使用更严格的 setitem 逻辑:
        def assignment():
            arr = np.empty(3, dtype=dtype)
            arr[0] = value

        yield assignment

        def fill():
            arr = np.empty(3, dtype=dtype)
            arr.fill(value)

        yield fill

    def copyto_scalar():
        arr = np.empty(3, dtype=dtype)
        np.copyto(arr, value, casting="unsafe")

    yield copyto_scalar

    def copyto():
        arr = np.empty(3, dtype=dtype)
        np.copyto(arr, np.array([value, value, value]), casting="unsafe")

    yield copyto
    yield copyto

    # 定义一个函数 copyto_scalar_masked,用于将 value 复制到长度为 3 的 arr 中的指定位置
    def copyto_scalar_masked():
        arr = np.empty(3, dtype=dtype)
        np.copyto(arr, value, casting="unsafe",
                  where=[True, False, True])

    yield copyto_scalar_masked

    # 定义一个函数 copyto_masked,将 value 复制到长度为 3 的 arr 中的指定位置,支持广播
    def copyto_masked():
        arr = np.empty(3, dtype=dtype)
        np.copyto(arr, np.array([value, value, value]), casting="unsafe",
                  where=[True, False, True])

    yield copyto_masked

    # 定义一个函数 direct_cast,创建一个包含三个相同值的数组,并进行类型转换
    def direct_cast():
        np.array([value, value, value]).astype(dtype)

    yield direct_cast

    # 定义一个函数 direct_cast_nd_strided,创建一个形状为 (5, 5, 5) 的数组,并进行类型转换
    def direct_cast_nd_strided():
        arr = np.full((5, 5, 5), fill_value=value)[:, ::2, :]
        arr.astype(dtype)

    yield direct_cast_nd_strided

    # 定义一个函数 boolean_array_assignment,将 value 复制到长度为 3 的 arr 中的布尔索引位置
    def boolean_array_assignment():
        arr = np.empty(3, dtype=dtype)
        arr[[True, False, True]] = np.array([value, value])

    yield boolean_array_assignment

    # 定义一个函数 integer_array_assignment,将 value 复制到长度为 3 的 arr 中的整数索引位置
    def integer_array_assignment():
        arr = np.empty(3, dtype=dtype)
        values = np.array([value, value])

        arr[[0, 1]] = values

    yield integer_array_assignment

    # 定义一个函数 integer_array_assignment_with_subspace,将 value 复制到形状为 (5, 3) 的 arr 中的整数索引位置
    def integer_array_assignment_with_subspace():
        arr = np.empty((5, 3), dtype=dtype)
        values = np.array([value, value, value])

        arr[[0, 2]] = values

    yield integer_array_assignment_with_subspace

    # 定义一个函数 flat_assignment,将 value 平铺到长度为 3 的 arr 中
    def flat_assignment():
        arr = np.empty((3,), dtype=dtype)
        values = np.array([value, value, value])
        arr.flat[:] = values

    yield flat_assignment
# 如果运行环境是 WebAssembly(WASM),则跳过此测试用例,因为不支持浮点异常
@pytest.mark.skipif(IS_WASM, reason="no wasm fp exception support")

# 使用参数化测试,参数来自 values_and_dtypes 函数返回的值对(value, dtype)
@pytest.mark.parametrize(["value", "dtype"], values_and_dtypes())

# 忽略 numpy 的 ComplexWarning 警告
@pytest.mark.filterwarnings("ignore::numpy.exceptions.ComplexWarning")
def test_floatingpoint_errors_casting(dtype, value):
    # 将 dtype 转换为 numpy 的 dtype 对象
    dtype = np.dtype(dtype)

    # 对于给定的 dtype 和 value,获取其支持的操作列表,并逐个执行
    for operation in check_operations(dtype, value):
        # 重新确认 dtype 类型,虽然此处似乎无实际改变
        dtype = np.dtype(dtype)

        # 确定匹配条件,根据 dtype 的种类决定匹配的异常类型
        match = "invalid" if dtype.kind in 'iu' else "overflow"

        # 使用 pytest.warns 检查是否会引发 RuntimeWarning,匹配特定的异常类型
        with pytest.warns(RuntimeWarning, match=match):
            operation()

        # 使用 np.errstate 设置浮点运算状态,使得所有异常都会被抛出
        with np.errstate(all="raise"):
            # 使用 pytest.raises 检查是否会引发 FloatingPointError,匹配特定的异常类型
            with pytest.raises(FloatingPointError, match=match):
                operation()

.\numpy\numpy\_core\tests\test_casting_unittests.py

"""
The tests exercise the casting machinery in a more low-level manner.
The reason is mostly to test a new implementation of the casting machinery.

Unlike most tests in NumPy, these are closer to unit-tests rather
than integration tests.
"""

# 引入pytest库,用于运行测试
import pytest
# 引入textwrap库,用于文本包装
import textwrap
# 引入enum枚举类,用于定义常量
import enum
# 引入random库,用于生成随机数
import random
# 引入ctypes库,用于与C语言兼容的数据类型转换

# 引入NumPy库,并从中导入相关模块和函数
import numpy as np
# 从NumPy的stride_tricks模块中导入as_strided函数
from numpy.lib.stride_tricks import as_strided
# 从NumPy的testing子模块中导入assert_array_equal函数,用于数组比较
from numpy.testing import assert_array_equal
# 从NumPy的_core._multiarray_umath模块中导入_get_castingimpl函数
from numpy._core._multiarray_umath import _get_castingimpl as get_castingimpl


# 定义简单数据类型列表,排除object、parametric和long double(在struct中不支持)
simple_dtypes = "?bhilqBHILQefdFD"
# 如果long和long long的字节大小不同,则移除它们
if np.dtype("l").itemsize != np.dtype("q").itemsize:
    simple_dtypes = simple_dtypes.replace("l", "").replace("L", "")
# 将字符类型转换为对应的NumPy数据类型对象列表
simple_dtypes = [type(np.dtype(c)) for c in simple_dtypes]


# 定义生成简单数据类型实例的生成器函数
def simple_dtype_instances():
    # 遍历简单数据类型列表中的每个数据类型类
    for dtype_class in simple_dtypes:
        # 创建该数据类型的实例
        dt = dtype_class()
        # 使用pytest.param封装数据类型实例,作为测试参数,并使用其字符串表示作为id
        yield pytest.param(dt, id=str(dt))
        # 如果数据类型的字节顺序不是本地字节顺序,则创建一个新的与本地字节顺序相同的实例
        if dt.byteorder != "|":
            dt = dt.newbyteorder()
            # 再次封装新的数据类型实例作为测试参数,并使用其字符串表示作为id
            yield pytest.param(dt, id=str(dt))


# 定义根据数据类型返回预期字符串长度的函数
def get_expected_stringlength(dtype):
    """Returns the string length when casting the basic dtypes to strings.
    """
    # 如果数据类型是布尔型,返回固定的长度5
    if dtype == np.bool:
        return 5
    # 如果数据类型是无符号整型或有符号整型
    if dtype.kind in "iu":
        # 根据不同的字节大小返回不同的预期长度
        if dtype.itemsize == 1:
            length = 3
        elif dtype.itemsize == 2:
            length = 5
        elif dtype.itemsize == 4:
            length = 10
        elif dtype.itemsize == 8:
            length = 20
        else:
            raise AssertionError(f"did not find expected length for {dtype}")

        # 对于有符号整型,长度需要加上一个字符用于符号位
        if dtype.kind == "i":
            length += 1

        return length

    # 对于长双精度浮点数,根据其字符类型返回固定的长度
    if dtype.char == "g":
        return 48
    elif dtype.char == "G":
        return 48 * 2
    elif dtype.kind == "f":
        return 32  # 半精度浮点数也是32
    elif dtype.kind == "c":
        return 32 * 2  # 复数类型是32的两倍长度

    raise AssertionError(f"did not find expected length for {dtype}")


# 定义枚举类Casting,用于表示类型转换的不同方式
class Casting(enum.IntEnum):
    no = 0
    equiv = 1
    safe = 2
    same_kind = 3
    unsafe = 4


# 定义获取类型转换表的函数
def _get_cancast_table():
    # 创建一个多行字符串,其中包含表格,用于定义数据类型间的类型转换关系
    table = textwrap.dedent("""
        X ? b h i l q B H I L Q e f d g F D G S U V O M m
        ? # = = = = = = = = = = = = = = = = = = = = = . =
        b . # = = = = . . . . . = = = = = = = = = = = . =
        h . ~ # = = = . . . . . ~ = = = = = = = = = = . =
        i . ~ ~ # = = . . . . . ~ ~ = = ~ = = = = = = . =
        l . ~ ~ ~ # # . . . . . ~ ~ = = ~ = = = = = = . =
        q . ~ ~ ~ # # . . . . . ~ ~ = = ~ = = = = = = . =
        B . ~ = = = = # = = = =```
    # 创建一个多行字符串,其中包含表格,用于定义数据类型间的类型转换关系
    table = textwrap.dedent("""
        X ? b h i l q B H I L Q e f d g F D G S U V O M m
        ? # = = = = = = = = = = = = = = = = = = = = = . =
        b . # = = = = . . . . . = = = = = = = = = = = . =
        h . ~ # = = = . . . . . ~ = = = = = = = = = = . =
        i . ~ ~ # = = . . . . . ~ ~ = = ~ = = = = = = . =
        l . ~ ~ ~ # # . . . . . ~ ~ = = ~ = = = = = = . =
        q . ~ ~ ~ # # . . . . . ~ ~ = = ~ = = = = = = . =
        B . ~ = = = = # = = = =```py
        # 创建一个多行字符串,其中包含表格,用于定义数据类型间的类型转换关系
        table = textwrap.dedent("""
            X ? b h i l q B H I L Q e f d g F D G S U V O M m
            ? # = = = = = = = = = = = = = = = = = = = = = . =
            b . # = = = = . . . . . = = = = = = = = = = = . =
            h . ~ # = = = . . . . . ~ = = = = = = = = = = . =
            i . ~ ~ # = = . . . . . ~ ~ = = ~ = = = = = = . =
            l . ~ ~ ~ # # . . . . . ~ ~ = = ~ = = = = = = . =
            q . ~ ~ ~ # # . . . . . ~ ~ = = ~ = = = = = = . =
            B . ~ = = = = # = = = =
    
    
    
        # 根据字符定义转换策略的字典,将字符映射到对应的转换类型
        convert_cast = {".": Casting.unsafe, "~": Casting.same_kind,
                        "=": Casting.safe, "#": Casting.equiv,
                        " ": -1}
    
    
    
        # 创建一个空字典用于存储数据类型间的转换策略
        cancast = {}
        # 遍历数据类型列表和表格的行,将转换策略填充到字典中
        for from_dt, row in zip(dtypes, table[1:]):
            cancast[from_dt] = {}
            for to_dt, c in zip(dtypes, row[2::2]):
                cancast[from_dt][to_dt] = convert_cast[c]
    
    
    
        # 返回填充好的数据类型间转换策略字典
        return cancast
# 调用函数 _get_cancast_table() 并将结果赋给 CAST_TABLE
CAST_TABLE = _get_cancast_table()

# 定义测试类 TestChanges,用于测试行为变化
class TestChanges:
    """
    These test cases exercise some behaviour changes
    """

    # 测试函数 test_float_to_string,参数化测试浮点数转换为字符串
    @pytest.mark.parametrize("string", ["S", "U"])
    @pytest.mark.parametrize("floating", ["e", "f", "d", "g"])
    def test_float_to_string(self, floating, string):
        # 断言能够从浮点数 floating 转换为字符串 string
        assert np.can_cast(floating, string)
        # 断言能够从浮点数 floating 转换为带有后缀 "100" 的字符串 string
        # 100 is long enough to hold any formatted floating
        assert np.can_cast(floating, f"{string}100")

    # 测试函数 test_to_void,验证转换为 void 类型的安全性
    def test_to_void(self):
        # 断言能够从双精度浮点数 "d" 转换为 void 类型 "V"
        assert np.can_cast("d", "V")
        # 断言能够从长度为 20 的字符串 "S20" 转换为 void 类型 "V"

        assert np.can_cast("S20", "V")

        # 当 void 类型的长度过小时,断言转换不安全
        assert not np.can_cast("d", "V1")
        assert not np.can_cast("S20", "V1")
        assert not np.can_cast("U1", "V1")

        # 当源类型和目标类型都是结构化类型时,使用 "same_kind" 转换类型
        assert np.can_cast("d,i", "V", casting="same_kind")

        # 当源类型和目标类型都是无结构化 void 类型时,使用 "no" 表示无需转换
        assert np.can_cast("V3", "V", casting="no")
        assert np.can_cast("V0", "V", casting="no")


# 定义测试类 TestCasting,用于测试类型转换
class TestCasting:
    # 定义类变量 size,用于设置数组大小,最好大于 NPY_LOWLEVEL_BUFFER_BLOCKSIZE * itemsize

    size = 1500  # Best larger than NPY_LOWLEVEL_BUFFER_BLOCKSIZE * itemsize

    # 定义函数 get_data,根据给定的 dtype1 和 dtype2 获取数据
    def get_data(self, dtype1, dtype2):
        # 根据 dtype1 和 dtype2 的大小确定数组的长度
        if dtype2 is None or dtype1.itemsize >= dtype2.itemsize:
            length = self.size // dtype1.itemsize
        else:
            length = self.size // dtype2.itemsize

        # 使用 dtype1 创建空数组 arr1,并进行一些断言以确保数组属性
        arr1 = np.empty(length, dtype=dtype1)
        assert arr1.flags.c_contiguous
        assert arr1.flags.aligned

        # 生成随机值列表 values
        values = [random.randrange(-128, 128) for _ in range(length)]

        # 遍历 values,通过 item 赋值方式向 arr1 中填充值
        for i, value in enumerate(values):
            # 如果 value 小于 0 且 dtype1 是无符号整数类型,则手动转换成对应的正数值
            if value < 0 and dtype1.kind == "u":
                value = value + np.iinfo(dtype1).max + 1
            arr1[i] = value

        # 如果 dtype2 是 None,则返回 arr1 和 values
        if dtype2 is None:
            if dtype1.char == "?":
                values = [bool(v) for v in values]
            return arr1, values

        # 如果 dtype2 是布尔类型,则将 values 转换成布尔值列表
        if dtype2.char == "?":
            values = [bool(v) for v in values]

        # 使用 dtype2 创建空数组 arr2,并进行一些断言以确保数组属性
        arr2 = np.empty(length, dtype=dtype2)
        assert arr2.flags.c_contiguous
        assert arr2.flags.aligned

        # 再次遍历 values,通过 item 赋值方式向 arr2 中填充值
        for i, value in enumerate(values):
            # 如果 value 小于 0 且 dtype2 是无符号整数类型,则手动转换成对应的正数值
            if value < 0 and dtype2.kind == "u":
                value = value + np.iinfo(dtype2).max + 1
            arr2[i] = value

        # 返回 arr1, arr2 和 values
        return arr1, arr2, values
    # 定义一个方法,用于生成经过变异处理的数据数组
    def get_data_variation(self, arr1, arr2, aligned=True, contig=True):
        """
        Returns a copy of arr1 that may be non-contiguous or unaligned, and a
        matching array for arr2 (although not a copy).
        """
        # 如果需要保证连续性,计算 arr1 和 arr2 的字节步长
        if contig:
            stride1 = arr1.dtype.itemsize
            stride2 = arr2.dtype.itemsize
        # 如果需要保证对齐性,计算 arr1 和 arr2 的字节步长
        elif aligned:
            stride1 = 2 * arr1.dtype.itemsize
            stride2 = 2 * arr2.dtype.itemsize
        # 否则,计算 arr1 和 arr2 的字节步长
        else:
            stride1 = arr1.dtype.itemsize + 1
            stride2 = arr2.dtype.itemsize + 1

        # 计算允许的最大字节数,用来分配新数组
        max_size1 = len(arr1) * 3 * arr1.dtype.itemsize + 1
        max_size2 = len(arr2) * 3 * arr2.dtype.itemsize + 1
        # 创建用于存储数据的新数组,类型为无符号 8 位整数
        from_bytes = np.zeros(max_size1, dtype=np.uint8)
        to_bytes = np.zeros(max_size2, dtype=np.uint8)

        # 对上述分配是否足够进行断言检查
        assert stride1 * len(arr1) <= from_bytes.nbytes
        assert stride2 * len(arr2) <= to_bytes.nbytes

        # 如果需要对齐,使用 as_strided 函数生成新的 arr1 和 arr2
        if aligned:
            new1 = as_strided(from_bytes[:-1].view(arr1.dtype),
                              arr1.shape, (stride1,))
            new2 = as_strided(to_bytes[:-1].view(arr2.dtype),
                              arr2.shape, (stride2,))
        # 否则,稍微偏移后使用 as_strided 函数生成新的 arr1 和 arr2
        else:
            new1 = as_strided(from_bytes[1:].view(arr1.dtype),
                              arr1.shape, (stride1,))
            new2 = as_strided(to_bytes[1:].view(arr2.dtype),
                              arr2.shape, (stride2,))

        # 将 arr1 的数据复制到新生成的 new1 数组中
        new1[...] = arr1

        # 如果不需要保证连续性,进行进一步的检查确保没有写入不应该写入的字节
        if not contig:
            offset = arr1.dtype.itemsize if aligned else 0
            buf = from_bytes[offset::stride1].tobytes()
            assert buf.count(b"\0") == len(buf)

        # 根据条件检查 new1 和 new2 的连续性
        if contig:
            assert new1.flags.c_contiguous
            assert new2.flags.c_contiguous
        else:
            assert not new1.flags.c_contiguous
            assert not new2.flags.c_contiguous

        # 根据条件检查 new1 和 new2 的对齐性
        if aligned:
            assert new1.flags.aligned
            assert new2.flags.aligned
        else:
            assert not new1.flags.aligned or new1.dtype.alignment == 1
            assert not new2.flags.aligned or new2.dtype.alignment == 1

        # 返回生成的变异后的数组 new1 和 new2
        return new1, new2

    # 使用 pytest 的参数化功能,针对 simple_dtypes 参数化测试用例
    @pytest.mark.parametrize("from_Dt", simple_dtypes)
    # 定义测试函数,用于测试从指定类型到简单数据类型的类型转换
    def test_simple_cancast(self, from_Dt):
        # 遍历简单数据类型列表,将from_Dt转换为to_Dt并进行测试
        for to_Dt in simple_dtypes:
            # 获取类型转换的实现函数
            cast = get_castingimpl(from_Dt, to_Dt)

            # 遍历from_Dt及其字节序新顺序的实例
            for from_dt in [from_Dt(), from_Dt().newbyteorder()]:
                # 解析描述符,获取默认值和转换结果
                default = cast._resolve_descriptors((from_dt, None))[1][1]
                assert default == to_Dt()
                del default

                # 遍历to_Dt及其字节序新顺序的实例
                for to_dt in [to_Dt(), to_Dt().newbyteorder()]:
                    # 解析描述符,获取类型转换、转换结果、视图偏移
                    casting, (from_res, to_res), view_off = (
                            cast._resolve_descriptors((from_dt, to_dt)))
                    assert(type(from_res) == from_Dt)
                    assert(type(to_res) == to_Dt)

                    # 如果视图偏移不为空,表示视图可接受,需无需进行强制转换
                    # 并且字节顺序必须匹配
                    if view_off is not None:
                        assert casting == Casting.no
                        assert Casting.equiv == CAST_TABLE[from_Dt][to_Dt]
                        assert from_res.isnative == to_res.isnative
                    else:
                        # 如果from_Dt与to_Dt相同,则需要确认to_res不同于from_dt
                        if from_Dt == to_Dt:
                            assert from_res.isnative != to_res.isnative
                        # 否则,根据CAST_TABLE检查强制转换类型
                        assert casting == CAST_TABLE[from_Dt][to_Dt]

                    # 如果from_Dt与to_Dt相同,则from_dt应等于from_res,to_dt应等于to_res
                    if from_Dt is to_Dt:
                        assert(from_dt is from_res)
                        assert(to_dt is to_res)

    # 使用pytest标记过滤掉特定的警告信息
    @pytest.mark.filterwarnings("ignore::numpy.exceptions.ComplexWarning")
    # 使用pytest.mark.parametrize装饰器,参数化测试函数的输入参数from_dt
    @pytest.mark.parametrize("from_dt", simple_dtype_instances())
    # 定义名为 test_simple_direct_casts 的测试方法,用于测试直接类型转换
    def test_simple_direct_casts(self, from_dt):
        """
        This test checks numeric direct casts for dtypes supported also by the
        struct module (plus complex).  It tries to be test a wide range of
        inputs, but skips over possibly undefined behaviour (e.g. int rollover).
        Longdouble and CLongdouble are tested, but only using double precision.

        If this test creates issues, it should possibly just be simplified
        or even removed (checking whether unaligned/non-contiguous casts give
        the same results is useful, though).
        """
        
        # 遍历 simple_dtype_instances() 返回的数据类型实例
        for to_dt in simple_dtype_instances():
            # 取类型实例的第一个值
            to_dt = to_dt.values[0]
            
            # 获取从 from_dt 到 to_dt 的类型转换方法
            cast = get_castingimpl(type(from_dt), type(to_dt))
            
            # 解析类型转换器的描述符,获取转换方法、原始类型结果、目标类型结果及视图偏移量
            casting, (from_res, to_res), view_off = cast._resolve_descriptors((from_dt, to_dt))
            
            # 如果 from_res 或 to_res 不等于 from_dt 或 to_dt,则不进行测试,因为已在多个步骤中测试过
            if from_res is not from_dt or to_res is not to_dt:
                # Do not test this case, it is handled in multiple steps,
                # each of which should is tested individually.
                return
            
            # 判断是否安全转换
            safe = casting <= Casting.safe
            
            # 删除变量以释放内存
            del from_res, to_res, casting
            
            # 获取从 from_dt 到 to_dt 的数据
            arr1, arr2, values = self.get_data(from_dt, to_dt)
            
            # 使用 cast 对象进行简单分块调用
            cast._simple_strided_call((arr1, arr2))
            
            # 使用 Python 列表检查结果是否与预期值 values 相同
            assert arr2.tolist() == values
            
            # 使用分块循环检查是否达到相同的结果
            arr1_o, arr2_o = self.get_data_variation(arr1, arr2, True, False)
            cast._simple_strided_call((arr1_o, arr2_o))
            
            # 使用 assert_array_equal 检查 arr2_o 是否等于 arr2
            assert_array_equal(arr2_o, arr2)
            # 检查 arr2_o 的字节表示是否等于 arr2 的字节表示
            assert arr2_o.tobytes() == arr2.tobytes()
            
            # 如果支持不对齐访问并且对齐会影响结果,则进一步检查
            if ((from_dt.alignment == 1 and to_dt.alignment == 1) or
                    not cast._supports_unaligned):
                return
            
            # 检查不同的数据变化情况下是否依然保持一致性
            arr1_o, arr2_o = self.get_data_variation(arr1, arr2, False, True)
            cast._simple_strided_call((arr1_o, arr2_o))
            
            assert_array_equal(arr2_o, arr2)
            assert arr2_o.tobytes() == arr2.tobytes()
            
            arr1_o, arr2_o = self.get_data_variation(arr1, arr2, False, False)
            cast._simple_strided_call((arr1_o, arr2_o))
            
            assert_array_equal(arr2_o, arr2)
            assert arr2_o.tobytes() == arr2.tobytes()
            
            # 释放内存,删除变量
            del arr1_o, arr2_o, cast
    
    # 使用 pytest 的参数化标记,指定测试数据来源为 simple_dtypes
    @pytest.mark.parametrize("from_Dt", simple_dtypes)
    # 定义一个测试方法,用于测试从日期时间类型到不同时间类型的转换
    def test_numeric_to_times(self, from_Dt):
        # 当前只实现连续循环,因此只需要测试这些情况。
        # 实例化一个从 from_Dt 获取的日期时间对象
        from_dt = from_Dt()

        # 定义不同时间数据类型的列表
        time_dtypes = [np.dtype("M8"), np.dtype("M8[ms]"), np.dtype("M8[4D]"),
                       np.dtype("m8"), np.dtype("m8[ms]"), np.dtype("m8[4D]")]
        
        # 遍历不同的时间数据类型
        for time_dt in time_dtypes:
            # 获取从 from_dt 到 time_dt 的类型转换实现
            cast = get_castingimpl(type(from_dt), type(time_dt))

            # 解析类型转换的描述符,确定转换、起始和目标结果、视图偏移
            casting, (from_res, to_res), view_off = cast._resolve_descriptors(
                (from_dt, time_dt))

            # 断言起始结果为 from_dt
            assert from_res is from_dt
            # 断言目标结果为 time_dt
            assert to_res is time_dt
            # 清理中间变量
            del from_res, to_res

            # 断言转换在转换表中有效
            assert casting & CAST_TABLE[from_Dt][type(time_dt)]
            # 视图偏移应为 None
            assert view_off is None

            # 定义一个 int64 数据类型
            int64_dt = np.dtype(np.int64)
            # 获取数据数组 arr1, arr2 以及其值
            arr1, arr2, values = self.get_data(from_dt, int64_dt)
            # 将 arr2 视图转换为 time_dt 类型
            arr2 = arr2.view(time_dt)
            # 将 arr2 中的所有值设置为 NaT
            arr2[...] = np.datetime64("NaT")

            # 如果时间数据类型为 np.dtype("M8")
            if time_dt == np.dtype("M8"):
                # 确保至少有一个值不是 NaT
                arr1[-1] = 0  # ensure at least one value is not NaT

                # 进行简单的类型转换调用,预期会引发 ValueError 异常
                cast._simple_strided_call((arr1, arr2))
                with pytest.raises(ValueError):
                    str(arr2[-1])  # e.g. conversion to string fails
                # 结束当前测试
                return

            # 进行简单的类型转换调用
            cast._simple_strided_call((arr1, arr2))

            # 断言 arr2 的值列表应与预期的 values 相等
            assert [int(v) for v in arr2.tolist()] == values

            # 检查在步进循环中得到相同的结果
            arr1_o, arr2_o = self.get_data_variation(arr1, arr2, True, False)
            cast._simple_strided_call((arr1_o, arr2_o))

            # 断言 arr2_o 应与 arr2 相等
            assert_array_equal(arr2_o, arr2)
            # 断言 arr2_o 的字节表示应与 arr2 的字节表示相同
            assert arr2_o.tobytes() == arr2.tobytes()
    # 使用pytest的参数化装饰器,为测试用例传入不同的参数组合
    @pytest.mark.parametrize(
            ["from_dt", "to_dt", "expected_casting", "expected_view_off",
             "nom", "denom"],
            # 设置参数组合列表
            [("M8[ns]", None, Casting.no, 0, 1, 1),  # 设置参数组合
             (str(np.dtype("M8[ns]").newbyteorder()), None,
                  Casting.equiv, None, 1, 1),  # 设置参数组合
             ("M8", "M8[ms]", Casting.safe, 0, 1, 1),  # 设置参数组合
             # should be invalid cast:
             ("M8[ms]", "M8", Casting.unsafe, None, 1, 1),  # 设置参数组合
             ("M8[5ms]", "M8[5ms]", Casting.no, 0, 1, 1),  # 设置参数组合
             ("M8[ns]", "M8[ms]", Casting.same_kind, None, 1, 10**6),  # 设置参数组合
             ("M8[ms]", "M8[ns]", Casting.safe, None, 10**6, 1),  # 设置参数组合
             ("M8[ms]", "M8[7ms]", Casting.same_kind, None, 1, 7),  # 设置参数组合
             ("M8[4D]", "M8[1M]", Casting.same_kind, None, None,
                  # give full values based on NumPy 1.19.x
                  [-2**63, 0, -1, 1314, -1315, 564442610]),  # 设置参数组合
             ("m8[ns]", None, Casting.no, 0, 1, 1),  # 设置参数组合
             (str(np.dtype("m8[ns]").newbyteorder()), None,
                  Casting.equiv, None, 1, 1),  # 设置参数组合
             ("m8", "m8[ms]", Casting.safe, 0, 1, 1),  # 设置参数组合
             # should be invalid cast:
             ("m8[ms]", "m8", Casting.unsafe, None, 1, 1),  # 设置参数组合
             ("m8[5ms]", "m8[5ms]", Casting.no, 0, 1, 1),  # 设置参数组合
             ("m8[ns]", "m8[ms]", Casting.same_kind, None, 1, 10**6),  # 设置参数组合
             ("m8[ms]", "m8[ns]", Casting.safe, None, 10**6, 1),  # 设置参数组合
             ("m8[ms]", "m8[7ms]", Casting.same_kind, None, 1, 7),  # 设置参数组合
             ("m8[4D]", "m8[1M]", Casting.unsafe, None, None,
                  # give full values based on NumPy 1.19.x
                  [-2**63, 0, 0, 1314, -1315, 564442610])])  # 设置参数组合
    # 定义测试函数,用于测试时间类型转换功能
    def test_time_to_time(self, from_dt, to_dt,
                          expected_casting, expected_view_off,
                          nom, denom):
        # 将输入参数 from_dt 转换为 numpy 的数据类型对象
        from_dt = np.dtype(from_dt)
        # 如果 to_dt 不为 None,则将其转换为 numpy 的数据类型对象
        if to_dt is not None:
            to_dt = np.dtype(to_dt)

        # 测试几个数值以进行类型转换(使用 NumPy 1.19 生成结果)
        values = np.array([-2**63, 1, 2**63-1, 10000, -10000, 2**32])
        # 将数值数组转换为指定字节序的 int64 类型
        values = values.astype(np.dtype("int64").newbyteorder(from_dt.byteorder))
        # 断言数值数组的字节序与 from_dt 的字节序相同
        assert values.dtype.byteorder == from_dt.byteorder
        # 断言第一个值为 NaT(Not a Time)
        assert np.isnat(values.view(from_dt)[0])

        # 获取 from_dt 类型的类对象
        DType = type(from_dt)
        # 获取类型转换函数的实现
        cast = get_castingimpl(DType, DType)
        # 解析类型转换的描述符
        casting, (from_res, to_res), view_off = cast._resolve_descriptors(
                (from_dt, to_dt))
        # 断言解析后的 from_res 与 from_dt 相同
        assert from_res is from_dt
        # 断言解析后的 to_res 与 to_dt 相同或为 None
        assert to_res is to_dt or to_dt is None
        # 断言解析后的类型转换方式与预期相同
        assert casting == expected_casting
        # 断言解析后的视图偏移量与预期相同
        assert view_off == expected_view_off

        # 如果 nom 不为 None
        if nom is not None:
            # 计算预期输出,将结果视图转换为 to_res 类型
            expected_out = (values * nom // denom).view(to_res)
            # 将第一个元素设为 "NaT"
            expected_out[0] = "NaT"
        else:
            # 创建一个与 values 相同形状的空数组,并赋值为 denom
            expected_out = np.empty_like(values)
            expected_out[...] = denom
            # 将数组视图转换为 to_dt 类型
            expected_out = expected_out.view(to_dt)

        # 将 values 数组视图转换为 from_dt 类型
        orig_arr = values.view(from_dt)
        # 创建一个与 expected_out 相同形状的空数组
        orig_out = np.empty_like(expected_out)

        # 如果 casting 为 Casting.unsafe 并且 to_dt 为 "m8" 或 "M8"
        if casting == Casting.unsafe and (to_dt == "m8" or to_dt == "M8"):
            # 如果从非通用单位到通用单位的类型转换应报告为无效转换
            with pytest.raises(ValueError):
                cast._simple_strided_call((orig_arr, orig_out))
            return

        # 遍历 aligned 和 contig 的组合进行测试
        for aligned in [True, True]:
            for contig in [True, True]:
                # 调用 get_data_variation 获取变化后的数据数组和输出数组
                arr, out = self.get_data_variation(
                        orig_arr, orig_out, aligned, contig)
                # 将输出数组清零
                out[...] = 0
                # 调用类型转换函数进行简单的分步调用
                cast._simple_strided_call((arr, out))
                # 断言输出数组视图与预期输出视图相等
                assert_array_equal(out.view("int64"), expected_out.view("int64"))

    # 根据输入的 dtype 和修改长度,返回一个新的 dtype 对象
    def string_with_modified_length(self, dtype, change_length):
        # 如果 dtype 的字符为 "S",则 fact 为 1,否则为 4
        fact = 1 if dtype.char == "S" else 4
        # 计算新的长度
        length = dtype.itemsize // fact + change_length
        # 构造并返回一个新的 dtype 对象
        return np.dtype(f"{dtype.byteorder}{dtype.char}{length}")

    # 使用参数化测试标记,对 simple_dtypes 和 string_char 进行参数化测试
    @pytest.mark.parametrize("other_DT", simple_dtypes)
    @pytest.mark.parametrize("string_char", ["S", "U"])
    # 测试字符串是否可转换的方法,使用给定的参数进行测试
    def test_string_cancast(self, other_DT, string_char):
        # 如果字符串类型是"S",则设定因子为1,否则设定为4
        fact = 1 if string_char == "S" else 4

        # 获取字符串字符对应的 NumPy 数据类型
        string_DT = type(np.dtype(string_char))
        
        # 调用函数获取类型转换的实现
        cast = get_castingimpl(other_DT, string_DT)

        # 创建其他数据类型的实例
        other_dt = other_DT()
        
        # 获取预期的字符串长度
        expected_length = get_expected_stringlength(other_dt)
        
        # 构造 NumPy 数据类型,以给定字符和预期长度
        string_dt = np.dtype(f"{string_char}{expected_length}")

        # 解析描述符,获取安全性、返回的数据类型以及视图偏移量
        safety, (res_other_dt, res_dt), view_off = cast._resolve_descriptors(
                (other_dt, None))
        assert res_dt.itemsize == expected_length * fact
        assert safety == Casting.safe  # 我们认为字符串转换是“安全的”
        assert view_off is None
        assert isinstance(res_dt, string_DT)

        # 对于不同长度的字符串,检查类型转换的安全性
        for change_length in [-1, 0, 1]:
            if change_length >= 0:
                expected_safety = Casting.safe
            else:
                expected_safety = Casting.same_kind

            # 获取修改后的字符串数据类型
            to_dt = self.string_with_modified_length(string_dt, change_length)
            
            # 解析描述符,获取安全性、返回的数据类型以及视图偏移量
            safety, (_, res_dt), view_off = cast._resolve_descriptors(
                    (other_dt, to_dt))
            assert res_dt is to_dt
            assert safety == expected_safety
            assert view_off is None

        # 反向转换总是被认为是不安全的:
        cast = get_castingimpl(string_DT, other_DT)

        # 解析描述符,获取安全性以及视图偏移量
        safety, _, view_off = cast._resolve_descriptors((string_dt, other_dt))
        assert safety == Casting.unsafe
        assert view_off is None

        # 再次解析描述符,获取安全性、返回的数据类型以及视图偏移量
        cast = get_castingimpl(string_DT, other_DT)
        safety, (_, res_dt), view_off = cast._resolve_descriptors(
            (string_dt, None))
        assert safety == Casting.unsafe
        assert view_off is None
        assert other_dt is res_dt  # 返回简单数据类型的单例对象
    # 定义一个测试方法,用于验证字符串和其他数据类型之间的转换是否满足往返属性
    def test_simple_string_casts_roundtrip(self, other_dt, string_char):
        """
        Tests casts from and to string by checking the roundtripping property.

        The test also covers some string to string casts (but not all).

        If this test creates issues, it should possibly just be simplified
        or even removed (checking whether unaligned/non-contiguous casts give
        the same results is useful, though).
        """
        # 获取 other_dt 对应的 dtype 类型
        string_DT = type(np.dtype(string_char))

        # 获取类型转换的实现函数
        cast = get_castingimpl(type(other_dt), string_DT)
        cast_back = get_castingimpl(string_DT, type(other_dt))

        # 解析描述符,获取返回的 other_dt 和 string_dt 类型
        _, (res_other_dt, string_dt), _ = cast._resolve_descriptors(
                (other_dt, None))

        # 如果 res_other_dt 不等于 other_dt,表示不支持非本机字节顺序,跳过测试
        if res_other_dt is not other_dt:
            assert other_dt.byteorder != res_other_dt.byteorder
            return

        # 获取原始数组和值
        orig_arr, values = self.get_data(other_dt, None)

        # 创建一个与 orig_arr 等长的零填充数组,用于字符串类型 str_arr
        str_arr = np.zeros(len(orig_arr), dtype=string_dt)

        # 创建修改长度后的字符串类型数组,长度为 -1
        string_dt_short = self.string_with_modified_length(string_dt, -1)
        str_arr_short = np.zeros(len(orig_arr), dtype=string_dt_short)

        # 创建修改长度后的字符串类型数组,长度为 1
        string_dt_long = self.string_with_modified_length(string_dt, 1)
        str_arr_long = np.zeros(len(orig_arr), dtype=string_dt_long)

        # 断言不支持非对齐的简单赋值操作
        assert not cast._supports_unaligned
        assert not cast_back._supports_unaligned

        # 循环检查连续和非连续数组的数据变化
        for contig in [True, False]:
            other_arr, str_arr = self.get_data_variation(
                orig_arr, str_arr, True, contig)
            _, str_arr_short = self.get_data_variation(
                orig_arr, str_arr_short.copy(), True, contig)
            _, str_arr_long = self.get_data_variation(
                orig_arr, str_arr_long, True, contig)

            # 对简单的步进调用进行类型转换
            cast._simple_strided_call((other_arr, str_arr))

            # 对短数组进行步进调用,并断言转换后的结果
            cast._simple_strided_call((other_arr, str_arr_short))
            assert_array_equal(str_arr.astype(string_dt_short), str_arr_short)

            # 对长数组进行步进调用,并断言转换后的结果
            cast._simple_strided_call((other_arr, str_arr_long))
            assert_array_equal(str_arr, str_arr_long)

            # 如果 other_dt 的类型是布尔类型,则跳过循环
            if other_dt.kind == "b":
                continue

            # 将 other_arr 数组的所有元素设为 0
            other_arr[...] = 0

            # 对字符串数组 str_arr 和 other_arr 进行反向转换
            cast_back._simple_strided_call((str_arr, other_arr))

            # 断言 orig_arr 和 other_arr 相等
            assert_array_equal(orig_arr, other_arr)

            # 将 other_arr 数组的所有元素设为 0
            other_arr[...] = 0

            # 对长字符串数组 str_arr_long 和 other_arr 进行反向转换
            cast_back._simple_strided_call((str_arr_long, other_arr))

            # 断言 orig_arr 和 other_arr 相等
            assert_array_equal(orig_arr, other_arr)
    # 测试字符串到字符串类型的强制转换是否可行
    def test_string_to_string_cancast(self, other_dt, string_char):
        # 将 other_dt 转换为 NumPy 的数据类型对象
        other_dt = np.dtype(other_dt)

        # 根据 string_char 确定 factor 值,用于计算预期长度
        fact = 1 if string_char == "S" else 4
        # 根据 other_dt 的字符类型确定 div 值,用于计算预期长度
        div = 1 if other_dt.char == "S" else 4

        # 确定 string_DT 为与 string_char 相对应的 NumPy 数据类型对象
        string_DT = type(np.dtype(string_char))
        # 获取从 other_dt 到 string_DT 的转换实现对象
        cast = get_castingimpl(type(other_dt), string_DT)

        # 计算预期的字符串长度
        expected_length = other_dt.itemsize // div
        # 创建一个新的字符串数据类型对象,长度为预期长度
        string_dt = np.dtype(f"{string_char}{expected_length}")

        # 调用转换实现对象的 _resolve_descriptors 方法,解析描述符以获取安全性、结果数据类型和视图偏移量
        safety, (res_other_dt, res_dt), view_off = cast._resolve_descriptors(
                (other_dt, None))
        # 断言结果数据类型的字节大小符合预期长度乘以 factor
        assert res_dt.itemsize == expected_length * fact
        # 断言结果数据类型是预期的字符串数据类型对象
        assert isinstance(res_dt, string_DT)

        # 根据 other_dt 和 string_char 的值确定预期的安全性和视图偏移量
        expected_view_off = None
        if other_dt.char == string_char:
            if other_dt.isnative:
                expected_safety = Casting.no
                expected_view_off = 0
            else:
                expected_safety = Casting.equiv
        elif string_char == "U":
            expected_safety = Casting.safe
        else:
            expected_safety = Casting.unsafe

        # 断言实际的视图偏移量与预期的视图偏移量一致
        assert view_off == expected_view_off
        # 断言实际的安全性与预期的安全性一致
        assert expected_safety == safety

        # 遍历修改长度为[-1, 0, 1]的情况
        for change_length in [-1, 0, 1]:
            # 调用 self.string_with_modified_length 方法,修改 string_dt 的长度为 to_dt
            to_dt = self.string_with_modified_length(string_dt, change_length)
            # 再次调用转换实现对象的 _resolve_descriptors 方法,解析描述符以获取安全性、结果数据类型和视图偏移量
            safety, (_, res_dt), view_off = cast._resolve_descriptors(
                    (other_dt, to_dt))

            # 断言结果数据类型为预期的 to_dt
            assert res_dt is to_dt
            # 根据不同的 change_length 断言视图偏移量是否符合预期
            if change_length <= 0:
                assert view_off == expected_view_off
            else:
                assert view_off is None
            # 根据预期的安全性断言实际的安全性
            if expected_safety == Casting.unsafe:
                assert safety == expected_safety
            elif change_length < 0:
                assert safety == Casting.same_kind
            elif change_length == 0:
                assert safety == expected_safety
            elif change_length > 0:
                assert safety == Casting.safe

    @pytest.mark.parametrize("order1", [">", "<"])
    @pytest.mark.parametrize("order2", [">", "<"])
    def test_unicode_byteswapped_cast(self, order1, order2):
        # 非常具体的测试,用于测试 Unicode 的字节交换,包括非对齐数组数据。
        # 创建两种不同字节顺序的数据类型对象 dtype1 和 dtype2
        dtype1 = np.dtype(f"{order1}U30")
        dtype2 = np.dtype(f"{order2}U30")
        # 创建两个未对齐的数组 data1 和 data2,将其视图设置为 dtype1 和 dtype2
        data1 = np.empty(30 * 4 + 1, dtype=np.uint8)[1:].view(dtype1)
        data2 = np.empty(30 * 4 + 1, dtype=np.uint8)[1:].view(dtype2)
        # 如果 dtype1 的对齐方式不为 1,则进行断言检查
        if dtype1.alignment != 1:
            assert not data1.flags.aligned
            assert not data2.flags.aligned

        # 创建一个 Unicode 元素
        element = "this is a ünicode string‽"
        data1[()] = element
        # 测试 data1 和 data1.copy()(应该是对齐的)两种情况
        for data in [data1, data1.copy()]:
            # 将 data1 的值复制给 data2,并断言它们的值相等
            data2[...] = data1
            assert data2[()] == element
            assert data2.copy()[()] == element
    # 测试空类型到字符串的特殊情况转换
    def test_void_to_string_special_case(self):
        # 测试空类型到字符串的特殊情况转换,这种情况可能可以转换为错误(与下面的 `test_object_to_parametric_internal_error` 进行比较)。
        assert np.array([], dtype="V5").astype("S").dtype.itemsize == 5
        assert np.array([], dtype="V5").astype("U").dtype.itemsize == 4 * 5

    # 测试从对象到参数化类型的内部错误处理
    def test_object_to_parametric_internal_error(self):
        # 拒绝从对象到参数化类型的转换,需要先确定正确的实例。
        object_dtype = type(np.dtype(object))
        other_dtype = type(np.dtype(str))
        cast = get_castingimpl(object_dtype, other_dtype)
        with pytest.raises(TypeError,
                    match="casting from object to the parametric DType"):
            cast._resolve_descriptors((np.dtype("O"), None))

    # 使用简单的数据类型实例参数化测试对象和简单解析
    @pytest.mark.parametrize("dtype", simple_dtype_instances())
    def test_object_and_simple_resolution(self, dtype):
        # 简单的测试,用于测试当没有指定实例时的转换
        object_dtype = type(np.dtype(object))
        cast = get_castingimpl(object_dtype, type(dtype))

        safety, (_, res_dt), view_off = cast._resolve_descriptors(
                (np.dtype("O"), dtype))
        assert safety == Casting.unsafe
        assert view_off is None
        assert res_dt is dtype

        safety, (_, res_dt), view_off = cast._resolve_descriptors(
                (np.dtype("O"), None))
        assert safety == Casting.unsafe
        assert view_off is None
        assert res_dt == dtype.newbyteorder("=")

    # 使用简单的数据类型实例参数化测试简单到对象的解析
    @pytest.mark.parametrize("dtype", simple_dtype_instances())
    def test_simple_to_object_resolution(self, dtype):
        # 简单的测试,用于测试当没有指定实例时从简单类型到对象的转换
        object_dtype = type(np.dtype(object))
        cast = get_castingimpl(type(dtype), object_dtype)

        safety, (_, res_dt), view_off = cast._resolve_descriptors(
                (dtype, None))
        assert safety == Casting.safe
        assert view_off is None
        assert res_dt is np.dtype("O")

    # 使用"no"或"unsafe"参数化测试空类型和带有子数组的结构化数组
    @pytest.mark.parametrize("casting", ["no", "unsafe"])
    def test_void_and_structured_with_subarray(self, casting):
        # 对应于gh-19325的测试案例
        dtype = np.dtype([("foo", "<f4", (3, 2))])
        expected = casting == "unsafe"
        assert np.can_cast("V4", dtype, casting=casting) == expected
        assert np.can_cast(dtype, "V4", casting=casting) == expected
    @pytest.mark.parametrize(["to_dt", "expected_off"],
            [  # Same as `from_dt` but with both fields shifted:
             (np.dtype({"names": ["a", "b"], "formats": ["i4", "f4"],
                        "offsets": [0, 4]}), 2),
             # Additional change of the names
             (np.dtype({"names": ["b", "a"], "formats": ["i4", "f4"],
                        "offsets": [0, 4]}), 2),
             # Incompatible field offset change
             (np.dtype({"names": ["b", "a"], "formats": ["i4", "f4"],
                        "offsets": [0, 6]}), None)])
    def test_structured_field_offsets(self, to_dt, expected_off):
        # This checks the cast-safety and view offset for swapped and "shifted"
        # fields which are viewable
        
        # Define the original structured data type with field names "a" and "b",
        # integer and float formats, and specified offsets.
        from_dt = np.dtype({"names": ["a", "b"],
                            "formats": ["i4", "f4"],
                            "offsets": [2, 6]})
        
        # Obtain the casting implementation for converting from `from_dt` to `to_dt`.
        cast = get_castingimpl(type(from_dt), type(to_dt))
        
        # Resolve the casting descriptors and retrieve safety, ignored flags, and view offset.
        safety, _, view_off = cast._resolve_descriptors((from_dt, to_dt))
        
        # Assert the safety of the cast operation based on the equality of field names.
        if from_dt.names == to_dt.names:
            assert safety == Casting.equiv
        else:
            assert safety == Casting.safe
        
        # Assert the expected view offset after shifting the original data pointer by -2 bytes.
        # This ensures alignment by effectively adding 2 bytes of spacing before `from_dt`.
        assert view_off == expected_off
    @pytest.mark.parametrize(("from_dt", "to_dt", "expected_off"), [
        # 使用 pytest 的参数化标记,定义测试参数和预期结果
        # Subarray cases:
        ("i", "(1,1)i", 0),  # 子数组情况,预期偏移量为0
        ("(1,1)i", "i", 0),  # 子数组情况,预期偏移量为0
        ("(2,1)i", "(2,1)i", 0),  # 子数组情况,预期偏移量为0
        # field cases (field to field is tested explicitly also):
        # 考虑字段到字段的情况(字段间也会被显式测试):
        # 由于负偏移可能导致结构化 dtype 间接访问无效内存,因此不视为可查看
        ("i", dict(names=["a"], formats=["i"], offsets=[2]), None),
        (dict(names=["a"], formats=["i"], offsets=[2]), "i", 2),  # 字段到字段情况,预期偏移量为2
        # 当前不视为可查看,因为存在多个字段,即使它们重叠(也许我们不应该允许这种情况?)
        ("i", dict(names=["a", "b"], formats=["i", "i"], offsets=[2, 2]), None),
        # 不同数量的字段无法工作,应该直接失败,因此从不报告为“可查看”:
        ("i,i", "i,i,i", None),
        # Unstructured void cases:
        ("i4", "V3", 0),  # void较小或相等,预期偏移量为0
        ("i4", "V4", 0),  # void较小或相等,预期偏移量为0
        ("i4", "V10", None),  # void较大(无法查看)
        ("O", "V4", None),  # 当前拒绝对象用于视图
        ("O", "V8", None),  # 当前拒绝对象用于视图
        ("V4", "V3", 0),  # void较小或相等,预期偏移量为0
        ("V4", "V4", 0),  # void较小或相等,预期偏移量为0
        ("V3", "V4", None),  # void较大(无法查看)
        # 注意,当前的void到其他类型的转换通过字节字符串进行,并不是基于“视图”的转换方式,与反向方向不同:
        ("V4", "i4", None),  # 完全无效/不可能的转换
        ("i,i", "i,i,i", None),  # 完全无效/不可能的转换
    ])
    def test_structured_view_offsets_paramteric(
            self, from_dt, to_dt, expected_off):
        # TODO: 虽然这个测试相当彻底,但现在它并没有真正测试一些可能具有非零偏移量的路径(它们实际上不存在)。
        # 使用 pytest 的参数化测试方法,测试结构化视图的偏移量参数化情况
        from_dt = np.dtype(from_dt)
        to_dt = np.dtype(to_dt)
        # 获取类型转换的实现
        cast = get_castingimpl(type(from_dt), type(to_dt))
        # 解析描述符以获取类型转换的偏移量
        _, _, view_off = cast._resolve_descriptors((from_dt, to_dt))
        # 断言视图偏移量是否符合预期
        assert view_off == expected_off

    @pytest.mark.parametrize("dtype", np.typecodes["All"])
    # 测试对象类型转换中 NULL 和 None 的等效性
    def test_object_casts_NULL_None_equivalence(self, dtype):
        # None 转换为其他类型可能成功或失败,但 NULL 化的数组必须与填充了 None 的数组行为相同。
        arr_normal = np.array([None] * 5)  # 创建一个包含 None 的数组
        arr_NULLs = np.empty_like(arr_normal)  # 创建一个形状与 arr_normal 相同的空数组
        ctypes.memset(arr_NULLs.ctypes.data, 0, arr_NULLs.nbytes)  # 使用 ctypes 将 arr_NULLs 的内存数据置为 0
        # 检查是否满足条件,如果失败(也许应该),测试就失去了其目的:
        assert arr_NULLs.tobytes() == b"\x00" * arr_NULLs.nbytes

        try:
            expected = arr_normal.astype(dtype)  # 尝试将 arr_normal 转换为指定的 dtype
        except TypeError:
            with pytest.raises(TypeError):
                arr_NULLs.astype(dtype),  # 如果出现 TypeError,预期会抛出异常
        else:
            assert_array_equal(expected, arr_NULLs.astype(dtype))  # 断言转换后的 arr_NULLs 与预期的数组相等

    @pytest.mark.parametrize("dtype",
            np.typecodes["AllInteger"] + np.typecodes["AllFloat"])
    # 测试非标准布尔类型到其他类型的转换
    def test_nonstandard_bool_to_other(self, dtype):
        # 简单测试将 bool_ 类型转换为数值类型,不应暴露 NumPy 布尔值有时可以取除 0 和 1 之外的值的细节。参见也 gh-19514。
        nonstandard_bools = np.array([0, 3, -7], dtype=np.int8).view(bool)  # 创建一个非标准布尔数组
        res = nonstandard_bools.astype(dtype)  # 将非标准布尔数组转换为指定的 dtype
        expected = [0, 1, 1]
        assert_array_equal(res, expected)  # 断言转换后的结果与预期结果相等

.\numpy\numpy\_core\tests\test_conversion_utils.py

"""
Tests for numpy/_core/src/multiarray/conversion_utils.c
"""
# 导入正则表达式模块
import re
# 导入系统模块
import sys

# 导入 pytest 测试框架
import pytest

# 导入 numpy 库,并重命名为 np
import numpy as np
# 导入 numpy._core._multiarray_tests 模块,并重命名为 mt
import numpy._core._multiarray_tests as mt
# 从 numpy._core.multiarray 中导入 CLIP、WRAP、RAISE 常量
from numpy._core.multiarray import CLIP, WRAP, RAISE
# 从 numpy.testing 中导入 assert_warns 和 IS_PYPY 函数
from numpy.testing import assert_warns, IS_PYPY


class StringConverterTestCase:
    allow_bytes = True
    case_insensitive = True
    exact_match = False
    warn = True

    def _check_value_error(self, val):
        # 构建匹配模式,用于在异常信息中匹配给定的值
        pattern = r'\(got {}\)'.format(re.escape(repr(val)))
        # 使用 pytest 检查是否抛出 ValueError 异常,并匹配指定模式
        with pytest.raises(ValueError, match=pattern) as exc:
            self.conv(val)

    def _check_conv_assert_warn(self, val, expected):
        # 如果设置了 warn 标志,使用 assert_warns 检查是否会有 DeprecationWarning 警告
        if self.warn:
            with assert_warns(DeprecationWarning) as exc:
                assert self.conv(val) == expected
        else:
            # 否则直接比较转换后的结果和期望值
            assert self.conv(val) == expected

    def _check(self, val, expected):
        """Takes valid non-deprecated inputs for converters,
        runs converters on inputs, checks correctness of outputs,
        warnings and errors"""
        # 检查转换器是否能够正确转换给定的值
        assert self.conv(val) == expected

        # 如果允许处理字节类型,则尝试使用 ASCII 编码进行转换
        if self.allow_bytes:
            assert self.conv(val.encode('ascii')) == expected
        else:
            # 如果不允许字节类型,则期望抛出 TypeError 异常
            with pytest.raises(TypeError):
                self.conv(val.encode('ascii'))

        # 如果字符串长度大于 1,则进一步检查边界情况和警告
        if len(val) != 1:
            if self.exact_match:
                # 如果需要精确匹配,检查部分字符和空字符的处理
                self._check_value_error(val[:1])
                self._check_value_error(val + '\0')
            else:
                # 否则,检查部分字符转换时是否会警告
                self._check_conv_assert_warn(val[:1], expected)

        # 如果忽略大小写,则检查转换器对大小写的处理
        if self.case_insensitive:
            if val != val.lower():
                self._check_conv_assert_warn(val.lower(), expected)
            if val != val.upper():
                self._check_conv_assert_warn(val.upper(), expected)
        else:
            # 如果不忽略大小写,则期望转换器无法处理大小写变化
            if val != val.lower():
                self._check_value_error(val.lower())
            if val != val.upper():
                self._check_value_error(val.upper())

    def test_wrong_type(self):
        # 测试不支持的输入类型是否会抛出 TypeError 异常
        with pytest.raises(TypeError):
            self.conv({})
        with pytest.raises(TypeError):
            self.conv([])

    def test_wrong_value(self):
        # 测试不合理的字符串是否会抛出 ValueError 异常
        self._check_value_error('')
        self._check_value_error('\N{greek small letter pi}')

        # 如果允许处理字节类型,进一步测试字节类型的不合理转换是否会抛出异常
        if self.allow_bytes:
            self._check_value_error(b'')
            self._check_value_error(b"\xFF")
        if self.exact_match:
            # 如果需要精确匹配,测试不支持的字符串是否会抛出异常
            self._check_value_error("there's no way this is supported")


class TestByteorderConverter(StringConverterTestCase):
    """ Tests of PyArray_ByteorderConverter """
    # 将转换函数指定为 mt.run_byteorder_converter
    conv = mt.run_byteorder_converter
    # 禁用警告标志
    warn = False
    # 定义测试方法 test_valid,用于验证不同字符串对应的调用 _check 方法的正确性
    def test_valid(self):
        # 对于字符串列表 ['big', '>'],分别调用 _check 方法,期望结果为 'NPY_BIG'
        for s in ['big', '>']:
            self._check(s, 'NPY_BIG')
        
        # 对于字符串列表 ['little', '<'],分别调用 _check 方法,期望结果为 'NPY_LITTLE'
        for s in ['little', '<']:
            self._check(s, 'NPY_LITTLE')
        
        # 对于字符串列表 ['native', '='],分别调用 _check 方法,期望结果为 'NPY_NATIVE'
        for s in ['native', '=']:
            self._check(s, 'NPY_NATIVE')
        
        # 对于字符串列表 ['ignore', '|'],分别调用 _check 方法,期望结果为 'NPY_IGNORE'
        for s in ['ignore', '|']:
            self._check(s, 'NPY_IGNORE')
        
        # 对于字符串列表 ['swap'],只调用一次 _check 方法,期望结果为 'NPY_SWAP'
        for s in ['swap']:
            self._check(s, 'NPY_SWAP')
# 测试 PyArray_SortkindConverter 的测试用例类
class TestSortkindConverter(StringConverterTestCase):
    """ Tests of PyArray_SortkindConverter """
    
    # 设置转换函数为 mt.run_sortkind_converter
    conv = mt.run_sortkind_converter
    # 禁止警告信息
    warn = False

    # 定义有效性测试方法
    def test_valid(self):
        # 调用 _check 方法,验证 'quicksort' 转换为 'NPY_QUICKSORT'
        self._check('quicksort', 'NPY_QUICKSORT')
        # 调用 _check 方法,验证 'heapsort' 转换为 'NPY_HEAPSORT'
        self._check('heapsort', 'NPY_HEAPSORT')
        # 调用 _check 方法,验证 'mergesort' 转换为 'NPY_STABLESORT'(别名)
        self._check('mergesort', 'NPY_STABLESORT')
        # 调用 _check 方法,验证 'stable' 转换为 'NPY_STABLESORT'
        self._check('stable', 'NPY_STABLESORT')


# 测试 PyArray_SelectkindConverter 的测试用例类
class TestSelectkindConverter(StringConverterTestCase):
    """ Tests of PyArray_SelectkindConverter """
    
    # 设置转换函数为 mt.run_selectkind_converter
    conv = mt.run_selectkind_converter
    # 不区分大小写
    case_insensitive = False
    # 精确匹配
    exact_match = True

    # 定义有效性测试方法
    def test_valid(self):
        # 调用 _check 方法,验证 'introselect' 转换为 'NPY_INTROSELECT'
        self._check('introselect', 'NPY_INTROSELECT')


# 测试 PyArray_SearchsideConverter 的测试用例类
class TestSearchsideConverter(StringConverterTestCase):
    """ Tests of PyArray_SearchsideConverter """
    
    # 设置转换函数为 mt.run_searchside_converter
    conv = mt.run_searchside_converter

    # 定义有效性测试方法
    def test_valid(self):
        # 调用 _check 方法,验证 'left' 转换为 'NPY_SEARCHLEFT'
        self._check('left', 'NPY_SEARCHLEFT')
        # 调用 _check 方法,验证 'right' 转换为 'NPY_SEARCHRIGHT'
        self._check('right', 'NPY_SEARCHRIGHT')


# 测试 PyArray_OrderConverter 的测试用例类
class TestOrderConverter(StringConverterTestCase):
    """ Tests of PyArray_OrderConverter """
    
    # 设置转换函数为 mt.run_order_converter
    conv = mt.run_order_converter
    # 禁止警告信息
    warn = False

    # 定义有效性测试方法
    def test_valid(self):
        # 调用 _check 方法,验证 'c' 转换为 'NPY_CORDER'
        self._check('c', 'NPY_CORDER')
        # 调用 _check 方法,验证 'f' 转换为 'NPY_FORTRANORDER'
        self._check('f', 'NPY_FORTRANORDER')
        # 调用 _check 方法,验证 'a' 转换为 'NPY_ANYORDER'
        self._check('a', 'NPY_ANYORDER')
        # 调用 _check 方法,验证 'k' 转换为 'NPY_KEEPORDER'
        self._check('k', 'NPY_KEEPORDER')

    # 定义无效顺序测试方法
    def test_flatten_invalid_order(self):
        # 在 gh-14596 之后为无效,引发 ValueError 异常
        with pytest.raises(ValueError):
            self.conv('Z')
        # 针对 [False, True, 0, 8] 中的每个顺序,引发 TypeError 异常
        for order in [False, True, 0, 8]:
            with pytest.raises(TypeError):
                self.conv(order)


# 测试 PyArray_ClipmodeConverter 的测试用例类
class TestClipmodeConverter(StringConverterTestCase):
    """ Tests of PyArray_ClipmodeConverter """
    
    # 设置转换函数为 mt.run_clipmode_converter
    conv = mt.run_clipmode_converter

    # 定义有效性测试方法
    def test_valid(self):
        # 调用 _check 方法,验证 'clip' 转换为 'NPY_CLIP'
        self._check('clip', 'NPY_CLIP')
        # 调用 _check 方法,验证 'wrap' 转换为 'NPY_WRAP'
        self._check('wrap', 'NPY_WRAP')
        # 调用 _check 方法,验证 'raise' 转换为 'NPY_RAISE'
        self._check('raise', 'NPY_RAISE')

        # 整数值在此处允许
        assert self.conv(CLIP) == 'NPY_CLIP'
        assert self.conv(WRAP) == 'NPY_WRAP'
        assert self.conv(RAISE) == 'NPY_RAISE'


# 测试 PyArray_CastingConverter 的测试用例类
class TestCastingConverter(StringConverterTestCase):
    """ Tests of PyArray_CastingConverter """
    
    # 设置转换函数为 mt.run_casting_converter
    conv = mt.run_casting_converter
    # 不区分大小写
    case_insensitive = False
    # 精确匹配
    exact_match = True

    # 定义有效性测试方法
    def test_valid(self):
        # 调用 _check 方法,验证 "no" 转换为 "NPY_NO_CASTING"
        self._check("no", "NPY_NO_CASTING")
        # 调用 _check 方法,验证 "equiv" 转换为 "NPY_EQUIV_CASTING"
        self._check("equiv", "NPY_EQUIV_CASTING")
        # 调用 _check 方法,验证 "safe" 转换为 "NPY_SAFE_CASTING"
        self._check("safe", "NPY_SAFE_CASTING")
        # 调用 _check 方法,验证 "same_kind" 转换为 "NPY_SAME_KIND_CASTING"
        self._check("same_kind", "NPY_SAME_KIND_CASTING")
        # 调用 _check 方法,验证 "unsafe" 转换为 "NPY_UNSAFE_CASTING"
        self._check("unsafe", "NPY_UNSAFE_CASTING")


# 测试 PyArray_IntpConverter 的测试用例类
class TestIntpConverter:
    """ Tests of PyArray_IntpConverter """
    
    # 设置转换函数为 mt.run_intp_converter
    conv = mt.run_intp_converter

    # 定义基础测试方法
    def test_basic(self):
        # 断言 self.conv(1) 返回 (1,)
        assert self.conv(1) == (1,)
        # 断言 self.conv((1, 2)) 返回 (1, 2)
        assert self.conv((1, 2)) == (1, 2)
        # 断言 self.conv([1, 2]) 返回 (1, 2)
        assert self.conv([1, 2]) == (1, 2)
        # 断言 self.conv(()) 返回 ()
        assert self.conv(()) == ()

    # 定义空值测试方法
    def test_none(self):
        # 在警告过期后,此处将引发 DeprecationWarning
        with pytest.warns(DeprecationWarning):
            # 断言 self.conv(None) 返回 ()
            assert self.conv(None) == ()
    # 使用 pytest.mark.skipif 装饰器标记测试用例,当满足指定条件时跳过执行
    @pytest.mark.skipif(IS_PYPY and sys.implementation.version <= (7, 3, 8),
                        reason="PyPy bug in error formatting")
    # 测试浮点数输入时的情况
    def test_float(self):
        # 断言输入浮点数时会引发 TypeError 异常
        with pytest.raises(TypeError):
            self.conv(1.0)
        # 断言输入包含浮点数的列表时会引发 TypeError 异常
        with pytest.raises(TypeError):
            self.conv([1, 1.0])

    # 测试输入值过大时的情况
    def test_too_large(self):
        # 断言输入超出限制值时会引发 ValueError 异常
        with pytest.raises(ValueError):
            self.conv(2**64)

    # 测试输入维度过多时的情况
    def test_too_many_dims(self):
        # 断言输入维度在限制范围内时,返回符合预期的结果
        assert self.conv([1]*64) == (1,)*64
        # 断言输入维度超出限制时会引发 ValueError 异常
        with pytest.raises(ValueError):
            self.conv([1]*65)

.\numpy\numpy\_core\tests\test_cpu_dispatcher.py

from numpy._core._multiarray_umath import (
    __cpu_features__, __cpu_baseline__, __cpu_dispatch__
)
from numpy._core import _umath_tests
from numpy.testing import assert_equal

def test_dispatcher():
    """
    Testing the utilities of the CPU dispatcher
    """
    # 定义处理器支持的目标特性列表
    targets = (
        "SSE2", "SSE41", "AVX2",
        "VSX", "VSX2", "VSX3",
        "NEON", "ASIMD", "ASIMDHP",
        "VX", "VXE"
    )
    highest_sfx = "" # 用于存储最高特性的后缀,默认为空表示基线没有后缀
    all_sfx = []  # 存储所有特性的后缀列表

    # 逆序遍历目标特性列表
    for feature in reversed(targets):
        # 如果特性在基线特性中,则跳过
        if feature in __cpu_baseline__:
            continue
        # 检查编译器和运行机器是否支持该特性
        if feature not in __cpu_dispatch__ or not __cpu_features__[feature]:
            continue

        # 如果当前没有最高特性后缀,则使用当前特性作为最高特性后缀
        if not highest_sfx:
            highest_sfx = "_" + feature
        # 将当前特性添加到所有特性后缀列表中
        all_sfx.append("func" + "_" + feature)

    # 调用_umath_tests模块中的test_dispatch函数进行测试
    test = _umath_tests.test_dispatch()

    # 断言检查测试结果中的函数名称是否匹配最高特性后缀
    assert_equal(test["func"], "func" + highest_sfx)
    # 断言检查测试结果中的变量名称是否匹配最高特性后缀
    assert_equal(test["var"], "var"  + highest_sfx)

    # 如果存在最高特性后缀,则进一步检查带基线的函数和变量名称是否匹配最高特性后缀
    if highest_sfx:
        assert_equal(test["func_xb"], "func" + highest_sfx)
        assert_equal(test["var_xb"], "var"  + highest_sfx)
    else:
        # 如果不存在最高特性后缀,则函数和变量名称应该为"nobase"
        assert_equal(test["func_xb"], "nobase")
        assert_equal(test["var_xb"], "nobase")

    # 添加基线特性的函数名称到所有特性后缀列表中
    all_sfx.append("func")
    # 断言检查测试结果中的"all"键对应的值是否等于所有特性后缀列表
    assert_equal(test["all"], all_sfx)

.\numpy\numpy\_core\tests\test_cpu_features.py

# 导入必要的模块:sys, platform, re, pytest
# 从 numpy._core._multiarray_umath 中导入特定的 CPU 相关功能
import sys, platform, re, pytest
from numpy._core._multiarray_umath import (
    __cpu_features__,
    __cpu_baseline__,
    __cpu_dispatch__,
)
# 导入 numpy 库并重命名为 np
import numpy as np
# 导入 subprocess 模块用于执行外部命令
import subprocess
# 导入 pathlib 模块用于处理文件路径
import pathlib
# 导入 os 模块,提供了一种与操作系统进行交互的方法
import os
# 再次导入 re 模块,可能是为了与之前的 re 模块有所区分

# 定义一个函数 assert_features_equal,用于比较实际特性和期望特性是否相等
def assert_features_equal(actual, desired, fname):
    __tracebackhide__ = True  # 在 pytest 中隐藏回溯信息
    # 将 actual 和 desired 转换为字符串形式
    actual, desired = str(actual), str(desired)
    # 如果 actual 等于 desired,直接返回,说明相等
    if actual == desired:
        return
    # 将 __cpu_features__ 转换为字符串,并去除单引号
    detected = str(__cpu_features__).replace("'", "")
    # 尝试打开 /proc/cpuinfo 文件,并读取其内容,最多读取 2048 字节
    try:
        with open("/proc/cpuinfo") as fd:
            cpuinfo = fd.read(2048)
    except Exception as err:
        cpuinfo = str(err)

    # 尝试使用 subprocess 模块执行 '/bin/true' 命令,获取其输出
    try:
        import subprocess
        auxv = subprocess.check_output(['/bin/true'], env=dict(LD_SHOW_AUXV="1"))
        auxv = auxv.decode()
    except Exception as err:
        auxv = str(err)

    # 导入 textwrap 模块,用于格式化输出
    import textwrap
    # 构建错误报告,包含检测到的特性、cpuinfo 内容和 auxv 输出
    error_report = textwrap.indent(
"""
###########################################
### Extra debugging information
###########################################
-------------------------------------------
--- NumPy Detections
-------------------------------------------
%s
-------------------------------------------
--- SYS / CPUINFO
-------------------------------------------
%s....
-------------------------------------------
--- SYS / AUXV
-------------------------------------------
%s
""" % (detected, cpuinfo, auxv), prefix='\r')

    # 抛出 AssertionError 异常,显示详细的错误信息和报告
    raise AssertionError((
        "Failure Detection\n"
        " NAME: '%s'\n"
        " ACTUAL: %s\n"
        " DESIRED: %s\n"
        "%s"
    ) % (fname, actual, desired, error_report))

# 定义一个函数 _text_to_list,用于将文本转换为列表形式
def _text_to_list(txt):
    # 去除文本中的 '['、']'、'\n' 和单引号,并按 ', ' 分割为列表
    out = txt.strip("][\n").replace("'", "").split(', ')
    # 如果列表的第一个元素为空字符串,则返回 None,否则返回列表
    return None if out[0] == "" else out

# 定义一个抽象类 AbstractTest
class AbstractTest:
    # 类变量初始化
    features = []
    features_groups = {}
    features_map = {}
    features_flags = set()

    # 定义一个方法 load_flags,作为钩子函数,不做任何操作
    def load_flags(self):
        # a hook
        pass
    
    # 定义一个测试方法 test_features,用于测试 CPU 特性
    def test_features(self):
        # 调用 load_flags 方法加载特性标志
        self.load_flags()
        # 遍历特性分组字典 features_groups
        for gname, features in self.features_groups.items():
            # 对于每个特性分组,获取特性是否存在的列表
            test_features = [self.cpu_have(f) for f in features]
            # 检查 __cpu_features__ 中对应分组的特性是否与测试结果相等
            assert_features_equal(__cpu_features__.get(gname), all(test_features), gname)

        # 遍历单独的特性列表 features
        for feature_name in self.features:
            # 检查 CPU 是否支持该特性
            cpu_have = self.cpu_have(feature_name)
            # 获取 NumPy 是否检测到该特性
            npy_have = __cpu_features__.get(feature_name)
            # 检查 NumPy 检测结果与实际 CPU 支持结果是否相等
            assert_features_equal(npy_have, cpu_have, feature_name)

    # 定义一个方法 cpu_have,用于检查 CPU 是否支持特定特性
    def cpu_have(self, feature_name):
        # 获取特性名称在 features_map 中的映射名称
        map_names = self.features_map.get(feature_name, feature_name)
        # 如果映射名称是字符串,则直接检查是否在 features_flags 集合中
        if isinstance(map_names, str):
            return map_names in self.features_flags
        # 如果映射名称是列表,则遍历列表,检查是否有特性在 features_flags 集合中
        for f in map_names:
            if f in self.features_flags:
                return True
        return False

    # 定义一个方法 load_flags_cpuinfo,用于加载 CPU 相关信息的标志
    def load_flags_cpuinfo(self, magic_key):
        # 调用 get_cpuinfo_item 方法获取 CPU 相关信息的标志,并设置 features_flags
        self.features_flags = self.get_cpuinfo_item(magic_key)
    # 获取指定的 CPU 信息项目
    def get_cpuinfo_item(self, magic_key):
        # 初始化一个空集合来存储数值
        values = set()
        # 打开 CPU 信息文件 '/proc/cpuinfo'
        with open('/proc/cpuinfo') as fd:
            # 逐行读取文件内容
            for line in fd:
                # 如果当前行不以 magic_key 开头,则继续下一行
                if not line.startswith(magic_key):
                    continue
                # 将当前行按 ':' 分割成键和值,并去除两边的空格
                flags_value = [s.strip() for s in line.split(':', 1)]
                # 如果成功分割为键值对,将值转换为大写后分割成集合,并与已有集合合并
                if len(flags_value) == 2:
                    values = values.union(flags_value[1].upper().split())
        # 返回最终得到的数值集合
        return values

    # 加载辅助的标志寄存器信息
    def load_flags_auxv(self):
        # 使用 subprocess 模块执行命令 '/bin/true' 并设置环境变量 LD_SHOW_AUXV="1",获取输出
        auxv = subprocess.check_output(['/bin/true'], env=dict(LD_SHOW_AUXV="1"))
        # 逐行遍历输出内容
        for at in auxv.split(b'\n'):
            # 如果当前行不以 "AT_HWCAP" 开头,则继续下一行
            if not at.startswith(b"AT_HWCAP"):
                continue
            # 将当前行按 ':' 分割成键和值,并去除两边的空格
            hwcap_value = [s.strip() for s in at.split(b':', 1)]
            # 如果成功分割为键值对,将值转换为大写后分割成列表,并与类属性 features_flags 合并
            if len(hwcap_value) == 2:
                self.features_flags = self.features_flags.union(
                    hwcap_value[1].upper().decode().split()
                )
# 如果运行平台是 emscripten,跳过这个测试类
@pytest.mark.skipif(
    sys.platform == 'emscripten',
    reason=(
        "The subprocess module is not available on WASM platforms and"
        " therefore this test class cannot be properly executed."
    ),
)
class TestEnvPrivation:
    # 获取当前文件的父目录的绝对路径
    cwd = pathlib.Path(__file__).parent.resolve()
    # 复制当前环境变量
    env = os.environ.copy()
    # 弹出环境变量中的 'NPY_ENABLE_CPU_FEATURES',并保存到 _enable
    _enable = os.environ.pop('NPY_ENABLE_CPU_FEATURES', None)
    # 弹出环境变量中的 'NPY_DISABLE_CPU_FEATURES',并保存到 _disable
    _disable = os.environ.pop('NPY_DISABLE_CPU_FEATURES', None)
    # 定义子进程参数的字典
    SUBPROCESS_ARGS = dict(cwd=cwd, capture_output=True, text=True, check=True)
    # 在 __cpu_dispatch__ 中遍历,找出不可用的 CPU 特性
    unavailable_feats = [
        feat for feat in __cpu_dispatch__ if not __cpu_features__[feat]
    ]
    # 第一个不可用的 CPU 特性,若没有则为 None
    UNAVAILABLE_FEAT = (
        None if len(unavailable_feats) == 0
        else unavailable_feats[0]
    )
    # 第一个基准 CPU 特性,若没有则为 None
    BASELINE_FEAT = None if len(__cpu_baseline__) == 0 else __cpu_baseline__[0]
    # 测试脚本的内容
    SCRIPT = """
def main():
    from numpy._core._multiarray_umath import (
        __cpu_features__, 
        __cpu_dispatch__
    )

    detected = [feat for feat in __cpu_dispatch__ if __cpu_features__[feat]]
    print(detected)

if __name__ == "__main__":
    main()
    """

    @pytest.fixture(autouse=True)
    def setup_class(self, tmp_path_factory):
        # 创建临时目录来存放运行时测试脚本
        file = tmp_path_factory.mktemp("runtime_test_script")
        file /= "_runtime_detect.py"
        # 将测试脚本内容写入文件
        file.write_text(self.SCRIPT)
        self.file = file
        return

    def _run(self):
        # 运行子进程,执行测试脚本
        return subprocess.run(
            [sys.executable, self.file],
            env=self.env,
            **self.SUBPROCESS_ARGS,
            )

    # 辅助函数,模拟 pytest.raises 对子进程调用的期望错误
    def _expect_error(
        self,
        msg,
        err_type,
        no_error_msg="Failed to generate error"
    ):
        try:
            self._run()
        except subprocess.CalledProcessError as e:
            assertion_message = f"Expected: {msg}\nGot: {e.stderr}"
            assert re.search(msg, e.stderr), assertion_message

            assertion_message = (
                f"Expected error of type: {err_type}; see full "
                f"error:\n{e.stderr}"
            )
            assert re.search(err_type, e.stderr), assertion_message
        else:
            assert False, no_error_msg

    def setup_method(self):
        """确保环境变量被重置"""
        self.env = os.environ.copy()
        return
    def test_runtime_feature_selection(self):
        """
        Ensure that when selecting `NPY_ENABLE_CPU_FEATURES`, only the
        features exactly specified are dispatched.
        """

        # 调用 _run 方法,捕获运行时启用的特性信息
        out = self._run()
        # 解析 stdout 中的非基准特性列表
        non_baseline_features = _text_to_list(out.stdout)

        if non_baseline_features is None:
            # 如果没有检测到除基准外的可调度特性,则跳过测试
            pytest.skip(
                "No dispatchable features outside of baseline detected."
            )
        # 从非基准特性列表中选择一个特性进行测试
        feature = non_baseline_features[0]

        # 设置环境变量 `NPY_ENABLE_CPU_FEATURES` 为选定的特性
        self.env['NPY_ENABLE_CPU_FEATURES'] = feature
        # 再次运行测试,捕获此时启用的特性信息
        out = self._run()
        # 解析 stdout 中的已启用特性列表
        enabled_features = _text_to_list(out.stdout)

        # 确保只有一个特性被启用,并且正是由 `NPY_ENABLE_CPU_FEATURES` 指定的特性
        assert set(enabled_features) == {feature}

        if len(non_baseline_features) < 2:
            # 如果只检测到一个非基准特性,则跳过测试
            pytest.skip("Only one non-baseline feature detected.")
        # 设置环境变量 `NPY_ENABLE_CPU_FEATURES` 为所有非基准特性列表的字符串形式
        self.env['NPY_ENABLE_CPU_FEATURES'] = ",".join(non_baseline_features)
        # 再次运行测试,捕获此时启用的特性信息
        out = self._run()
        # 解析 stdout 中的已启用特性列表
        enabled_features = _text_to_list(out.stdout)

        # 确保所有指定的特性都被正确启用
        assert set(enabled_features) == set(non_baseline_features)
        return

    @pytest.mark.parametrize("enabled, disabled",
    [
        ("feature", "feature"),
        ("feature", "same"),
    ])
    def test_both_enable_disable_set(self, enabled, disabled):
        """
        Ensure that when both environment variables are set then an
        ImportError is thrown
        """
        # 设置环境变量 `NPY_ENABLE_CPU_FEATURES` 和 `NPY_DISABLE_CPU_FEATURES`
        self.env['NPY_ENABLE_CPU_FEATURES'] = enabled
        self.env['NPY_DISABLE_CPU_FEATURES'] = disabled
        # 准备错误消息和错误类型
        msg = "Both NPY_DISABLE_CPU_FEATURES and NPY_ENABLE_CPU_FEATURES"
        err_type = "ImportError"
        # 断言预期的错误发生
        self._expect_error(msg, err_type)

    @pytest.mark.skipif(
        not __cpu_dispatch__,
        reason=(
            "NPY_*_CPU_FEATURES only parsed if "
            "`__cpu_dispatch__` is non-empty"
        )
    )
    @pytest.mark.parametrize("action", ["ENABLE", "DISABLE"])
    def test_variable_too_long(self, action):
        """
        Test that an error is thrown if the environment variables are too long
        to be processed. Current limit is 1024, but this may change later.
        """
        MAX_VAR_LENGTH = 1024
        # 设置环境变量 `NPY_{action}_CPU_FEATURES` 超出处理限制的长度
        self.env[f'NPY_{action}_CPU_FEATURES'] = "t" * MAX_VAR_LENGTH
        # 准备错误消息和错误类型
        msg = (
            f"Length of environment variable 'NPY_{action}_CPU_FEATURES' is "
            f"{MAX_VAR_LENGTH + 1}, only {MAX_VAR_LENGTH} accepted"
        )
        err_type = "RuntimeError"
        # 断言预期的错误发生
        self._expect_error(msg, err_type)
    @pytest.mark.skipif(
        not __cpu_dispatch__,
        reason=(
            "NPY_*_CPU_FEATURES only parsed if "
            "`__cpu_dispatch__` is non-empty"
        )
    )
    # 标记测试用例为跳过状态,条件是如果 `__cpu_dispatch__` 为空,则跳过执行
    def test_impossible_feature_disable(self):
        """
        Test that a RuntimeError is thrown if an impossible feature-disabling
        request is made. This includes disabling a baseline feature.
        """

        if self.BASELINE_FEAT is None:
            # 如果没有基准特性可用,则跳过测试
            pytest.skip("There are no unavailable features to test with")
        
        bad_feature = self.BASELINE_FEAT
        # 将环境变量设置为要禁用的基准特性
        self.env['NPY_DISABLE_CPU_FEATURES'] = bad_feature
        
        msg = (
            f"You cannot disable CPU feature '{bad_feature}', since it is "
            "part of the baseline optimizations"
        )
        err_type = "RuntimeError"
        # 预期出现特定错误消息和错误类型
        self._expect_error(msg, err_type)

    def test_impossible_feature_enable(self):
        """
        Test that a RuntimeError is thrown if an impossible feature-enabling
        request is made. This includes enabling a feature not supported by the
        machine, or disabling a baseline optimization.
        """

        if self.UNAVAILABLE_FEAT is None:
            # 如果没有不可用特性可用,则跳过测试
            pytest.skip("There are no unavailable features to test with")
        
        bad_feature = self.UNAVAILABLE_FEAT
        # 将环境变量设置为要启用的不支持的 CPU 特性
        self.env['NPY_ENABLE_CPU_FEATURES'] = bad_feature
        
        msg = (
            f"You cannot enable CPU features \\({bad_feature}\\), since "
            "they are not supported by your machine."
        )
        err_type = "RuntimeError"
        # 预期出现特定错误消息和错误类型
        self._expect_error(msg, err_type)

        # 确保即使提供了额外的垃圾数据,测试依然会失败
        feats = f"{bad_feature}, Foobar"
        self.env['NPY_ENABLE_CPU_FEATURES'] = feats
        msg = (
            f"You cannot enable CPU features \\({bad_feature}\\), since they "
            "are not supported by your machine."
        )
        self._expect_error(msg, err_type)

        if self.BASELINE_FEAT is not None:
            # 确保只有错误的特性会被报告
            feats = f"{bad_feature}, {self.BASELINE_FEAT}"
            self.env['NPY_ENABLE_CPU_FEATURES'] = feats
            msg = (
                f"You cannot enable CPU features \\({bad_feature}\\), since "
                "they are not supported by your machine."
            )
            self._expect_error(msg, err_type)
# 检查当前操作系统是否为Linux
is_linux = sys.platform.startswith('linux')
# 检查当前操作系统是否为Cygwin
is_cygwin = sys.platform.startswith('cygwin')
# 获取当前机器的架构信息
machine = platform.machine()
# 使用正则表达式匹配机器架构,判断是否为x86架构
is_x86 = re.match("^(amd64|x86|i386|i686)", machine, re.IGNORECASE)

# 根据条件标记测试类为跳过状态,仅当操作系统为Linux且机器架构为x86时执行
@pytest.mark.skipif(
    not (is_linux or is_cygwin) or not is_x86, reason="Only for Linux and x86"
)
class Test_X86_Features(AbstractTest):
    # 定义x86架构支持的特性列表
    features = [
        "MMX", "SSE", "SSE2", "SSE3", "SSSE3", "SSE41", "POPCNT", "SSE42",
        "AVX", "F16C", "XOP", "FMA4", "FMA3", "AVX2", "AVX512F", "AVX512CD",
        "AVX512ER", "AVX512PF", "AVX5124FMAPS", "AVX5124VNNIW", "AVX512VPOPCNTDQ",
        "AVX512VL", "AVX512BW", "AVX512DQ", "AVX512VNNI", "AVX512IFMA",
        "AVX512VBMI", "AVX512VBMI2", "AVX512BITALG", "AVX512FP16",
    ]
    # 定义x86架构特性的分组
    features_groups = dict(
        AVX512_KNL=["AVX512F", "AVX512CD", "AVX512ER", "AVX512PF"],
        AVX512_KNM=["AVX512F", "AVX512CD", "AVX512ER", "AVX512PF", "AVX5124FMAPS",
                    "AVX5124VNNIW", "AVX512VPOPCNTDQ"],
        AVX512_SKX=["AVX512F", "AVX512CD", "AVX512BW", "AVX512DQ", "AVX512VL"],
        AVX512_CLX=["AVX512F", "AVX512CD", "AVX512BW", "AVX512DQ", "AVX512VL", "AVX512VNNI"],
        AVX512_CNL=["AVX512F", "AVX512CD", "AVX512BW", "AVX512DQ", "AVX512VL", "AVX512IFMA",
                    "AVX512VBMI"],
        AVX512_ICL=["AVX512F", "AVX512CD", "AVX512BW", "AVX512DQ", "AVX512VL", "AVX512IFMA",
                    "AVX512VBMI", "AVX512VNNI", "AVX512VBMI2", "AVX512BITALG", "AVX512VPOPCNTDQ"],
        AVX512_SPR=["AVX512F", "AVX512CD", "AVX512BW", "AVX512DQ",
                    "AVX512VL", "AVX512IFMA", "AVX512VBMI", "AVX512VNNI",
                    "AVX512VBMI2", "AVX512BITALG", "AVX512VPOPCNTDQ",
                    "AVX512FP16"],
    )
    # 定义x86架构特性的映射表
    features_map = dict(
        SSE3="PNI", SSE41="SSE4_1", SSE42="SSE4_2", FMA3="FMA",
        AVX512VNNI="AVX512_VNNI", AVX512BITALG="AVX512_BITALG", AVX512VBMI2="AVX512_VBMI2",
        AVX5124FMAPS="AVX512_4FMAPS", AVX5124VNNIW="AVX512_4VNNIW", AVX512VPOPCNTDQ="AVX512_VPOPCNTDQ",
        AVX512FP16="AVX512_FP16",
    )

    # 加载x86架构特性标志的方法
    def load_flags(self):
        self.load_flags_cpuinfo("flags")

# 使用正则表达式匹配机器架构,判断是否为PowerPC架构
is_power = re.match("^(powerpc|ppc)64", machine, re.IGNORECASE)

# 根据条件标记测试类为跳过状态,仅当操作系统为Linux且机器架构为PowerPC时执行
@pytest.mark.skipif(not is_linux or not is_power, reason="Only for Linux and Power")
class Test_POWER_Features(AbstractTest):
    # 定义PowerPC架构支持的特性列表
    features = ["VSX", "VSX2", "VSX3", "VSX4"]
    # 定义PowerPC架构特性的映射表
    features_map = dict(VSX2="ARCH_2_07", VSX3="ARCH_3_00", VSX4="ARCH_3_1")

    # 加载PowerPC架构特性标志的方法
    def load_flags(self):
        self.load_flags_auxv()

# 使用正则表达式匹配机器架构,判断是否为IBM Z架构
is_zarch = re.match("^(s390x)", machine, re.IGNORECASE)

# 根据条件标记测试类为跳过状态,仅当操作系统为Linux且机器架构为IBM Z时执行
@pytest.mark.skipif(not is_linux or not is_zarch,
                    reason="Only for Linux and IBM Z")
class Test_ZARCH_Features(AbstractTest):
    # 定义IBM Z架构支持的特性列表
    features = ["VX", "VXE", "VXE2"]

    # 加载IBM Z架构特性标志的方法
    def load_flags(self):
        self.load_flags_auxv()

# 使用正则表达式匹配机器架构,判断是否为ARM架构
is_arm = re.match("^(arm|aarch64)", machine, re.IGNORECASE)

# 根据条件标记测试类为跳过状态,仅当操作系统为Linux且机器架构为ARM时执行
@pytest.mark.skipif(not is_linux or not is_arm, reason="Only for Linux and ARM")
class Test_ARM_Features(AbstractTest):
    # 空白,待补充的测试类,未提供具体特性和特性映射
    # 定义一个包含处理器功能名称的列表
    features = [
        "SVE", "NEON", "ASIMD", "FPHP", "ASIMDHP", "ASIMDDP", "ASIMDFHM"
    ]
    # 定义一个包含功能组名称和其成员列表的字典
    features_groups = dict(
        NEON_FP16  = ["NEON", "HALF"],
        NEON_VFPV4 = ["NEON", "VFPV4"],
    )
    
    # 定义一个方法用于加载处理器功能标志
    def load_flags(self):
        # 调用一个方法加载 CPU 信息中的特性信息
        self.load_flags_cpuinfo("Features")
        # 获取 CPU 架构信息
        arch = self.get_cpuinfo_item("CPU architecture")
        # 如果是在挂载的虚拟文件系统中运行的 aarch64 内核
        # 判断是否为 aarch64 架构并设置 is_rootfs_v8 标志
        is_rootfs_v8 = int('0'+next(iter(arch))) > 7 if arch else 0
        # 如果系统匹配 aarch64 或 is_rootfs_v8 则进行以下判断
        if  re.match("^(aarch64|AARCH64)", machine) or is_rootfs_v8:
            # 设置特性映射字典,匹配 NEON 到 ASIMD,HALF 到 ASIMD,VFPV4 到 ASIMD
            self.features_map = dict(
                NEON="ASIMD", HALF="ASIMD", VFPV4="ASIMD"
            )
        else:
            # 否则设置特性映射字典,假设 ASIMD 被支持,因为 Linux 内核 (armv8 aarch32) 
            # 在 ELF 辅助向量和 /proc/cpuinfo 上未提供有关 ASIMD 的信息
            self.features_map = dict(
                ASIMD=("AES", "SHA1", "SHA2", "PMULL", "CRC32")
            )

.\numpy\numpy\_core\tests\test_custom_dtypes.py

import sys  # 导入sys模块,用于系统相关操作

from tempfile import NamedTemporaryFile  # 导入NamedTemporaryFile类,用于创建临时文件

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

import numpy as np  # 导入NumPy库,用于科学计算
from numpy.testing import assert_array_equal  # 导入assert_array_equal函数,用于比较NumPy数组是否相等
from numpy._core._multiarray_umath import (  # 导入NumPy内部函数
    _discover_array_parameters as discover_array_params, _get_sfloat_dtype)

SF = _get_sfloat_dtype()  # 获取特定类型的浮点数作为SF的常量

class TestSFloat:
    def _get_array(self, scaling, aligned=True):
        if not aligned:
            a = np.empty(3*8 + 1, dtype=np.uint8)[1:]  # 创建一个未对齐的NumPy数组
            a = a.view(np.float64)  # 将数组视图转换为np.float64类型
            a[:] = [1., 2., 3.]  # 数组赋值为[1., 2., 3.]
        else:
            a = np.array([1., 2., 3.])  # 创建一个包含[1., 2., 3.]的NumPy数组

        a *= 1./scaling  # 数组中每个元素乘以scaling的倒数
        return a.view(SF(scaling))  # 返回数组的SF类型视图

    def test_sfloat_rescaled(self):
        sf = SF(1.)  # 创建SF对象,缩放因子为1.0
        sf2 = sf.scaled_by(2.)  # 使用sf对象的scaled_by方法创建sf2对象,缩放因子为2.0
        assert sf2.get_scaling() == 2.  # 断言sf2对象的缩放因子为2.0
        sf6 = sf2.scaled_by(3.)  # 使用sf2对象的scaled_by方法创建sf6对象,缩放因子为6.0
        assert sf6.get_scaling() == 6.  # 断言sf6对象的缩放因子为6.0

    def test_class_discovery(self):
        # 这个测试并不多,因为我们总是发现缩放因子为1.0。
        # 但是当写入时,大多数NumPy不理解DType类。
        dt, _ = discover_array_params([1., 2., 3.], dtype=SF)  # 调用discover_array_params函数获取数组参数
        assert dt == SF(1.)  # 断言dt对象为SF(1.),即缩放因子为1.0的SF对象

    @pytest.mark.parametrize("scaling", [1., -1., 2.])
    def test_scaled_float_from_floats(self, scaling):
        a = np.array([1., 2., 3.], dtype=SF(scaling))  # 创建指定缩放因子的SF类型的NumPy数组

        assert a.dtype.get_scaling() == scaling  # 断言数组的dtype的缩放因子为scaling
        assert_array_equal(scaling * a.view(np.float64), [1., 2., 3.])  # 断言scaling乘以数组视图的结果与[1., 2., 3.]相等

    def test_repr(self):
        # 检查repr,主要是为了覆盖代码路径:
        assert repr(SF(scaling=1.)) == "_ScaledFloatTestDType(scaling=1.0)"  # 断言SF对象的repr为"_ScaledFloatTestDType(scaling=1.0)"

    def test_dtype_name(self):
        assert SF(1.).name == "_ScaledFloatTestDType64"  # 断言SF(1.)的名称为"_ScaledFloatTestDType64"

    def test_sfloat_structured_dtype_printing(self):
        dt = np.dtype([("id", int), ("value", SF(0.5))])  # 创建包含SF(0.5)的结构化dtype对象
        # 结构化dtype的repr需要特殊处理,因为实现绕过了对象repr
        assert "('value', '_ScaledFloatTestDType64')" in repr(dt)  # 断言结构化dtype的repr包含"('value', '_ScaledFloatTestDType64')"

    @pytest.mark.parametrize("scaling", [1., -1., 2.])
    def test_sfloat_from_float(self, scaling):
        a = np.array([1., 2., 3.]).astype(dtype=SF(scaling))  # 创建指定缩放因子的SF类型的NumPy数组

        assert a.dtype.get_scaling() == scaling  # 断言数组的dtype的缩放因子为scaling
        assert_array_equal(scaling * a.view(np.float64), [1., 2., 3.])  # 断言scaling乘以数组视图的结果与[1., 2., 3.]相等

    @pytest.mark.parametrize("aligned", [True, False])
    @pytest.mark.parametrize("scaling", [1., -1., 2.])
    def test_sfloat_getitem(self, aligned, scaling):
        a = self._get_array(1., aligned)  # 调用_get_array方法创建数组a
        assert a.tolist() == [1., 2., 3.]  # 断言数组a转换为列表后为[1., 2., 3.]

    @pytest.mark.parametrize("aligned", [True, False])
    # 测试单精度浮点数转换函数的功能,使用指定的对齐方式
    def test_sfloat_casts(self, aligned):
        # 获取一个包含单个浮点数的数组,使用给定的对齐方式
        a = self._get_array(1., aligned)

        # 检查是否可以将数组 a 转换为单精度浮点数 SF(-1.),等效转换
        assert np.can_cast(a, SF(-1.), casting="equiv")
        # 检查是否不可以将数组 a 转换为单精度浮点数 SF(-1.),禁止转换
        assert not np.can_cast(a, SF(-1.), casting="no")
        # 将数组 a 转换为单精度浮点数 SF(-1.) 的结果,且其负数值等效于 a 的浮点数视图
        na = a.astype(SF(-1.))
        assert_array_equal(-1 * na.view(np.float64), a.view(np.float64))

        # 检查是否可以将数组 a 转换为单精度浮点数 SF(2.),同类型转换
        assert np.can_cast(a, SF(2.), casting="same_kind")
        # 检查是否不可以将数组 a 转换为单精度浮点数 SF(2.),安全转换
        assert not np.can_cast(a, SF(2.), casting="safe")
        # 将数组 a 转换为单精度浮点数 SF(2.) 的结果,且其正数值等效于 a 的浮点数视图
        a2 = a.astype(SF(2.))
        assert_array_equal(2 * a2.view(np.float64), a.view(np.float64))

    # 使用参数化测试,测试单精度浮点数转换中的内部错误处理
    @pytest.mark.parametrize("aligned", [True, False])
    def test_sfloat_cast_internal_errors(self, aligned):
        # 获取一个包含非常大的浮点数的数组,使用给定的对齐方式
        a = self._get_array(2e300, aligned)

        # 测试在转换为单精度浮点数 SF(2e-300) 时是否引发 TypeError 异常,并匹配指定错误信息
        with pytest.raises(TypeError,
                match="error raised inside the core-loop: non-finite factor!"):
            a.astype(SF(2e-300))

    # 测试单精度浮点数的类型提升功能
    def test_sfloat_promotion(self):
        # 检查单精度浮点数 SF(2.) 和 SF(3.) 的类型提升结果是否为 SF(3.)
        assert np.result_type(SF(2.), SF(3.)) == SF(3.)
        # 检查单精度浮点数 SF(3.) 和 SF(2.) 的类型提升结果是否为 SF(3.)
        assert np.result_type(SF(3.), SF(2.)) == SF(3.)
        # 检查将浮点数类型 Float64 转换为单精度浮点数 SF(1.),然后正常提升,两者结果相同
        assert np.result_type(SF(3.), np.float64) == SF(3.)
        assert np.result_type(np.float64, SF(0.5)) == SF(1.)

        # 测试未定义的类型提升
        with pytest.raises(TypeError):
            np.result_type(SF(1.), np.int64)

    # 测试基本的乘法操作
    def test_basic_multiply(self):
        # 获取两个包含浮点数的数组
        a = self._get_array(2.)
        b = self._get_array(4.)

        # 计算数组 a 和 b 的乘积
        res = a * b
        # 检查乘积的 dtype 缩放因子是否为 8.
        assert res.dtype.get_scaling() == 8.
        # 计算预期的浮点数视图乘积
        expected_view = a.view(np.float64) * b.view(np.float64)
        assert_array_equal(res.view(np.float64), expected_view)

    # 测试可能和不可能的约简操作
    def test_possible_and_impossible_reduce(self):
        # 对于约简操作,第一个和最后一个操作数必须具有相同的 dtype。
        a = self._get_array(2.)
        # 执行加法约简操作,需要指定初始值为 0.
        res = np.add.reduce(a, initial=0.)
        assert res == a.astype(np.float64).sum()

        # 由于每次乘法都会改变因子,因此不可能进行乘法约简操作
        with pytest.raises(TypeError,
                match="the resolved dtypes are not compatible"):
            np.multiply.reduce(a)

    # 测试基本的 ufunc 的 at 方法
    def test_basic_ufunc_at(self):
        # 创建一个浮点数数组 float_a 和 self._get_array 返回的数组 b
        float_a = np.array([1., 2., 3.])
        b = self._get_array(2.)

        # 创建 float_b 的副本,复制其浮点数视图
        float_b = b.view(np.float64).copy()
        # 使用 ufunc 的 at 方法,将 float_a 应用于 float_b 的指定索引位置
        np.multiply.at(float_b, [1, 1, 1], float_a)
        # 使用 ufunc 的 at 方法,将 float_a 应用于数组 b 的指定索引位置
        np.multiply.at(b, [1, 1, 1], float_a)

        # 检查修改后的 b 的浮点数视图是否与修改后的 float_b 的浮点数视图相等
        assert_array_equal(b.view(np.float64), float_b)
    def test_basic_multiply_promotion(self):
        float_a = np.array([1., 2., 3.])  # 创建一个包含浮点数的 NumPy 数组 float_a
        b = self._get_array(2.)  # 调用 self._get_array 方法获取一个数组 b,元素为浮点数

        res1 = float_a * b  # 数组 float_a 和数组 b 相乘的结果
        res2 = b * float_a  # 数组 b 和数组 float_a 相乘的结果

        # 检查结果数组的数据类型是否与数组 b 的数据类型相同
        assert res1.dtype == res2.dtype == b.dtype
        expected_view = float_a * b.view(np.float64)
        assert_array_equal(res1.view(np.float64), expected_view)  # 检查结果数组视图与预期视图是否相等
        assert_array_equal(res2.view(np.float64), expected_view)  # 检查结果数组视图与预期视图是否相等

        # 检查使用 'out' 参数时类型提升是否有效
        np.multiply(b, float_a, out=res2)
        with pytest.raises(TypeError):
            # 该推广器接受此操作(也许不应该),但 SFloat 结果不能转换为整数:
            np.multiply(b, float_a, out=np.arange(3))

    def test_basic_addition(self):
        a = self._get_array(2.)  # 调用 self._get_array 方法获取一个数组 a,元素为浮点数
        b = self._get_array(4.)  # 调用 self._get_array 方法获取一个数组 b,元素为浮点数

        res = a + b  # 数组 a 和数组 b 相加的结果
        # 加法使用结果的类型提升规则:
        assert res.dtype == np.result_type(a.dtype, b.dtype)
        expected_view = (a.astype(res.dtype).view(np.float64) +
                         b.astype(res.dtype).view(np.float64))
        assert_array_equal(res.view(np.float64), expected_view)  # 检查结果数组视图与预期视图是否相等

    def test_addition_cast_safety(self):
        """The addition method is special for the scaled float, because it
        includes the "cast" between different factors, thus cast-safety
        is influenced by the implementation.
        """
        a = self._get_array(2.)  # 调用 self._get_array 方法获取一个数组 a,元素为浮点数
        b = self._get_array(-2.)  # 调用 self._get_array 方法获取一个数组 b,元素为浮点数
        c = self._get_array(3.)  # 调用 self._get_array 方法获取一个数组 c,元素为浮点数

        # 符号变化是 "equiv":
        np.add(a, b, casting="equiv")
        with pytest.raises(TypeError):
            np.add(a, b, casting="no")  # 使用不允许的类型转换引发异常

        # 不同的因子是 "same_kind"(默认),因此检查 "safe" 失败
        with pytest.raises(TypeError):
            np.add(a, c, casting="safe")

        # 检查输出类型转换也失败(由 ufunc 完成)
        with pytest.raises(TypeError):
            np.add(a, a, out=c, casting="safe")

    @pytest.mark.parametrize("ufunc",
            [np.logical_and, np.logical_or, np.logical_xor])
    def test_logical_ufuncs_casts_to_bool(self, ufunc):
        a = self._get_array(2.)  # 调用 self._get_array 方法获取一个数组 a,元素为浮点数
        a[0] = 0.  # 确保第一个元素被认为是 False

        float_equiv = a.astype(float)
        expected = ufunc(float_equiv, float_equiv)
        res = ufunc(a, a)
        assert_array_equal(res, expected)  # 检查逻辑操作的结果是否与预期相等

        # 检查对约简操作也是同样适用:
        expected = ufunc.reduce(float_equiv)
        res = ufunc.reduce(a)
        assert_array_equal(res, expected)  # 检查约简操作的结果是否与预期相等

        # 输出类型转换与 bool, bool -> bool 循环不匹配:
        with pytest.raises(TypeError):
            ufunc(a, a, out=np.empty(a.shape, dtype=int), casting="equiv")
    def test_wrapped_and_wrapped_reductions(self):
        # 创建一个数组 a,其中元素为浮点数,并将其视作等价的浮点数数组
        a = self._get_array(2.)
        float_equiv = a.astype(float)

        # 计算浮点数数组的各元素的直角三角形斜边长度,作为期望结果
        expected = np.hypot(float_equiv, float_equiv)
        # 计算数组 a 中各元素的直角三角形斜边长度
        res = np.hypot(a, a)
        # 断言结果数组的数据类型与数组 a 的数据类型相同
        assert res.dtype == a.dtype
        # 将结果数组视作 np.float64 类型,并乘以 2
        res_float = res.view(np.float64) * 2
        # 断言乘以 2 后的结果数组与期望结果数组相等
        assert_array_equal(res_float, expected)

        # 进行归约计算,保持维度(由于错误的获取项目)
        res = np.hypot.reduce(a, keepdims=True)
        # 断言归约结果数组的数据类型与数组 a 的数据类型相同
        assert res.dtype == a.dtype
        # 计算浮点数数组的归约结果,并保持维度
        expected = np.hypot.reduce(float_equiv, keepdims=True)
        # 断言乘以 2 后的归约结果数组与期望结果数组相等
        assert res.view(np.float64) * 2 == expected

    def test_astype_class(self):
        # 非常简单的测试,验证在类上也接受 `.astype()`
        # ScaledFloat 总是返回默认描述符,但它会检查相关的代码路径
        arr = np.array([1., 2., 3.], dtype=object)

        # 对数组进行类型转换,传入 SF 类
        res = arr.astype(SF)  # 传入类 class
        # 预期结果是经过 SF(1.) 类型转换后的数组
        expected = arr.astype(SF(1.))  # 上述代码将发现 1. 的缩放
        # 断言转换后的数组视作 np.float64 类型后与期望结果数组相等
        assert_array_equal(res.view(np.float64), expected.view(np.float64))

    def test_creation_class(self):
        # 传入 dtype 类应该返回默认的描述符
        arr1 = np.array([1., 2., 3.], dtype=SF)
        # 断言数组的 dtype 与 SF(1.) 相同
        assert arr1.dtype == SF(1.)
        arr2 = np.array([1., 2., 3.], dtype=SF(1.))
        # 断言转换后的数组视作 np.float64 类型后与 arr1 视作 np.float64 类型后相等
        assert_array_equal(arr1.view(np.float64), arr2.view(np.float64))
        # 断言 arr1 和 arr2 的 dtype 相同
        assert arr1.dtype == arr2.dtype

        # 测试创建空数组、空形同数组、全零数组、全零形同数组时的 dtype
        assert np.empty(3, dtype=SF).dtype == SF(1.)
        assert np.empty_like(arr1, dtype=SF).dtype == SF(1.)
        assert np.zeros(3, dtype=SF).dtype == SF(1.)
        assert np.zeros_like(arr1, dtype=SF).dtype == SF(1.)

    def test_np_save_load(self):
        # 必须进行这种猴子补丁,因为 pickle 使用类型的 repr 来重建它
        np._ScaledFloatTestDType = SF

        arr = np.array([1.0, 2.0, 3.0], dtype=SF(1.0))

        # 从 np.save 测试中适配而来的代码,进行数组保存和加载的测试
        with NamedTemporaryFile("wb", delete=False, suffix=".npz") as f:
            with pytest.warns(UserWarning) as record:
                np.savez(f.name, arr)

        # 断言警告的数量为 1
        assert len(record) == 1

        # 使用 np.load 加载保存的数据
        with np.load(f.name, allow_pickle=True) as data:
            larr = data["arr_0"]
        # 断言加载后的数组视作 np.float64 类型后与原数组视作 np.float64 类型后相等
        assert_array_equal(arr.view(np.float64), larr.view(np.float64))
        # 断言加载后的数组的 dtype 与原数组的 dtype 与 SF(1.0) 相同
        assert larr.dtype == arr.dtype == SF(1.0)

        del np._ScaledFloatTestDType

    def test_flatiter(self):
        arr = np.array([1.0, 2.0, 3.0], dtype=SF(1.0))

        # 使用 flatiter 遍历数组的每个元素
        for i, val in enumerate(arr.flat):
            # 断言数组索引 i 处的元素与 flatiter 返回的值相等
            assert arr[i] == val

    @pytest.mark.parametrize(
        "index", [
            [1, 2], ..., slice(None, 2, None),
            np.array([True, True, False]), np.array([0, 1])
        ], ids=["int_list", "ellipsis", "slice", "bool_array", "int_array"])
    # 定义一个测试方法,用于测试 flatiter 的索引功能
    def test_flatiter_index(self, index):
        # 创建一个包含浮点数的 NumPy 数组,使用特定的类型SF(1.0)
        arr = np.array([1.0, 2.0, 3.0], dtype=SF(1.0))
        # 断言:验证通过 flat 属性的索引得到的视图是否与直接索引得到的视图相等
        np.testing.assert_array_equal(
            arr[index].view(np.float64), arr.flat[index].view(np.float64))
    
        # 复制数组 arr 到 arr2
        arr2 = arr.copy()
        # 通过索引将 arr 中的元素设置为 5.0
        arr[index] = 5.0
        # 通过 flat 属性的索引将 arr2 中的元素设置为 5.0
        arr2.flat[index] = 5.0
        # 断言:验证修改后的 arr 和 arr2 是否相等
        np.testing.assert_array_equal(
            arr.view(np.float64), arr2.view(np.float64))
# 测试使用 pickle 模块处理 SF 对象的序列化和反序列化
def test_type_pickle():
    # 导入 pickle 模块
    import pickle

    # 将 SF 对象作为被序列化对象
    np._ScaledFloatTestDType = SF

    # 使用 pickle.dumps 将 SF 对象序列化为字节流 s
    s = pickle.dumps(SF)
    
    # 使用 pickle.loads 将字节流 s 反序列化为对象 res
    res = pickle.loads(s)
    
    # 断言反序列化后的对象 res 与原始 SF 对象相同
    assert res is SF

    # 删除测试时添加的 SF 对象属性
    del np._ScaledFloatTestDType


# 测试 SF 对象的 _is_numeric 属性是否为真
def test_is_numeric():
    # 断言 SF 对象的 _is_numeric 属性为真
    assert SF._is_numeric

.\numpy\numpy\_core\tests\test_cython.py

# 导入 datetime 模块中的 datetime 类,用于处理日期和时间
from datetime import datetime
# 导入 os 模块,提供了访问操作系统功能的接口
import os
# 导入 shutil 模块,提供了高级文件操作功能
import shutil
# 导入 subprocess 模块,用于执行系统命令
import subprocess
# 导入 sys 模块,提供了访问 Python 解释器及其环境的变量和函数
import sys
# 导入 time 模块,提供了处理时间的功能
import time
# 导入 pytest 模块,用于编写和运行测试
import pytest

# 导入 numpy 库,用于数值计算
import numpy as np
# 从 numpy.testing 模块中导入 assert_array_equal 函数,用于比较两个数组是否相等
from numpy.testing import assert_array_equal, IS_WASM, IS_EDITABLE

# 这里是从 random.tests.test_extending 中复制的导入语句
# 尝试导入 cython 模块,用于编写 C 扩展
try:
    import cython
    # 从 Cython.Compiler.Version 中导入 version 属性,获取 Cython 的版本信息
    from Cython.Compiler.Version import version as cython_version
except ImportError:
    cython = None
else:
    # 导入 numpy._utils 模块中的 _pep440 模块
    from numpy._utils import _pep440

    # 定义需要的 Cython 最低版本
    required_version = "3.0.6"
    # 检查当前 Cython 的版本是否满足最低要求
    if _pep440.parse(cython_version) < _pep440.Version(required_version):
        # 如果版本过低或者 Cython 未安装,则将 cython 设置为 None,跳过测试
        cython = None

# 使用 pytest.mark.skipif 标记,如果 cython 为 None,则跳过测试,给出原因
pytestmark = pytest.mark.skipif(cython is None, reason="requires cython")

# 如果 IS_EDITABLE 为真,则跳过测试,给出原因
if IS_EDITABLE:
    pytest.skip(
        "Editable install doesn't support tests with a compile step",
        allow_module_level=True
    )

# 使用 pytest.fixture 装饰器定义一个作用域为 'module' 的测试夹具
@pytest.fixture(scope='module')
def install_temp(tmpdir_factory):
    # 基于 random.tests.test_extending 中的 test_cython 函数实现部分功能
    # 如果 IS_WASM 为真,则跳过测试,给出原因
    if IS_WASM:
        pytest.skip("No subprocess")

    # 定义源代码目录,应该是 examples/cython 的路径
    srcdir = os.path.join(os.path.dirname(__file__), 'examples', 'cython')
    # 创建一个临时构建目录,用于编译过程中的文件生成
    build_dir = tmpdir_factory.mktemp("cython_test") / "build"
    # 确保构建目录存在,如果不存在则创建
    os.makedirs(build_dir, exist_ok=True)
    # 创建一个文件用于指定正确的 Python 解释器路径,即使在不同环境中也能正确使用 'meson'
    native_file = str(build_dir / 'interpreter-native-file.ini')
    with open(native_file, 'w') as f:
        f.write("[binaries]\n")
        f.write(f"python = '{sys.executable}'")

    try:
        # 检查是否能够调用 'meson' 命令
        subprocess.check_call(["meson", "--version"])
    except FileNotFoundError:
        # 如果找不到 'meson' 命令,则跳过测试,给出原因
        pytest.skip("No usable 'meson' found")

    # 根据操作系统类型选择不同的 'meson setup' 命令进行调用
    if sys.platform == "win32":
        subprocess.check_call(["meson", "setup",
                               "--buildtype=release",
                               "--vsenv", "--native-file", native_file,
                               str(srcdir)],
                              cwd=build_dir,
                              )
    else:
        subprocess.check_call(["meson", "setup",
                               "--native-file", native_file, str(srcdir)],
                              cwd=build_dir
                              )

    try:
        # 调用 'meson compile' 命令进行编译
        subprocess.check_call(["meson", "compile", "-vv"], cwd=build_dir)
    except subprocess.CalledProcessError:
        # 如果编译过程中出现错误,则打印错误信息并抛出异常
        print("----------------")
        print("meson build failed when doing")
        print(f"'meson setup --native-file {native_file} {srcdir}'")
        print(f"'meson compile -vv'")
        print(f"in {build_dir}")
        print("----------------")
        raise

    # 将构建目录添加到系统路径中,使得测试代码可以访问编译后的模块
    sys.path.append(str(build_dir))

# 定义一个测试函数,测试是否为 timedelta64 对象
def test_is_timedelta64_object(install_temp):
    # 导入自定义的 checks 模块
    import checks

    # 使用 assert 语句检查是否是 timedelta64 对象
    assert checks.is_td64(np.timedelta64(1234))
    assert checks.is_td64(np.timedelta64(1234, "ns"))
    assert checks.is_td64(np.timedelta64("NaT", "ns"))

    # 使用 assert 语句检查是否不是 timedelta64 对象
    assert not checks.is_td64(1)
    assert not checks.is_td64(None)
    # 断言检查字符串 "foo" 不是 timedelta64 类型
    assert not checks.is_td64("foo")
    # 断言检查当前时间戳的 numpy datetime64 对象不是 timedelta64 类型
    assert not checks.is_td64(np.datetime64("now", "s"))
def test_is_datetime64_object(install_temp):
    import checks  # 导入名为checks的模块

    assert checks.is_dt64(np.datetime64(1234, "ns"))  # 断言检查np.datetime64对象是否为datetime64类型
    assert checks.is_dt64(np.datetime64("NaT", "ns"))  # 断言检查np.datetime64对象是否为datetime64类型

    assert not checks.is_dt64(1)  # 断言检查整数1不是datetime64类型
    assert not checks.is_dt64(None)  # 断言检查None不是datetime64类型
    assert not checks.is_dt64("foo")  # 断言检查字符串"foo"不是datetime64类型
    assert not checks.is_dt64(np.timedelta64(1234))  # 断言检查np.timedelta64对象不是datetime64类型


def test_get_datetime64_value(install_temp):
    import checks  # 导入名为checks的模块

    dt64 = np.datetime64("2016-01-01", "ns")  # 创建一个datetime64对象

    result = checks.get_dt64_value(dt64)  # 调用函数获取datetime64对象的值
    expected = dt64.view("i8")  # 获取datetime64对象的i8视图

    assert result == expected  # 断言检查结果是否等于期望值


def test_get_timedelta64_value(install_temp):
    import checks  # 导入名为checks的模块

    td64 = np.timedelta64(12345, "h")  # 创建一个timedelta64对象

    result = checks.get_td64_value(td64)  # 调用函数获取timedelta64对象的值
    expected = td64.view("i8")  # 获取timedelta64对象的i8视图

    assert result == expected  # 断言检查结果是否等于期望值


def test_get_datetime64_unit(install_temp):
    import checks  # 导入名为checks的模块

    dt64 = np.datetime64("2016-01-01", "ns")  # 创建一个datetime64对象
    result = checks.get_dt64_unit(dt64)  # 调用函数获取datetime64对象的单位
    expected = 10  # 期望的单位数值
    assert result == expected  # 断言检查结果是否等于期望值

    td64 = np.timedelta64(12345, "h")  # 创建一个timedelta64对象
    result = checks.get_dt64_unit(td64)  # 调用函数获取timedelta64对象的单位
    expected = 5  # 期望的单位数值
    assert result == expected  # 断言检查结果是否等于期望值


def test_abstract_scalars(install_temp):
    import checks  # 导入名为checks的模块

    assert checks.is_integer(1)  # 断言检查整数1是否为整数类型
    assert checks.is_integer(np.int8(1))  # 断言检查np.int8(1)是否为整数类型
    assert checks.is_integer(np.uint64(1))  # 断言检查np.uint64(1)是否为整数类型


def test_default_int(install_temp):
    import checks  # 导入名为checks的模块

    assert checks.get_default_integer() is np.dtype(int)  # 断言检查默认整数类型是否为np.dtype(int)


def test_convert_datetime64_to_datetimestruct(install_temp):
    # GH#21199
    import checks  # 导入名为checks的模块

    res = checks.convert_datetime64_to_datetimestruct()  # 调用函数将datetime64转换为日期时间结构

    exp = {  # 期望的日期时间结构字典
        "year": 2022,
        "month": 3,
        "day": 15,
        "hour": 20,
        "min": 1,
        "sec": 55,
        "us": 260292,
        "ps": 0,
        "as": 0,
    }

    assert res == exp  # 断言检查结果是否等于期望值


class TestDatetimeStrings:
    def test_make_iso_8601_datetime(self, install_temp):
        # GH#21199
        import checks  # 导入名为checks的模块
        dt = datetime(2016, 6, 2, 10, 45, 19)  # 创建一个datetime对象
        result = checks.make_iso_8601_datetime(dt)  # 调用函数生成ISO 8601格式的日期时间字符串
        assert result == b"2016-06-02T10:45:19"  # 断言检查结果是否等于期望值

    def test_get_datetime_iso_8601_strlen(self, install_temp):
        # GH#21199
        import checks  # 导入名为checks的模块
        res = checks.get_datetime_iso_8601_strlen()  # 调用函数获取ISO 8601日期时间字符串的长度
        assert res == 48  # 断言检查结果是否等于期望值


@pytest.mark.parametrize(  # 使用pytest.mark.parametrize装饰器进行参数化测试
    "arrays",  # 参数名
    [  # 参数列表
        [np.random.rand(2)],  # 第一组参数,包含一个形状为(2,)的随机数组
        [np.random.rand(2), np.random.rand(3, 1)],  # 第二组参数,包含两个随机数组
        [np.random.rand(2), np.random.rand(2, 3, 2), np.random.rand(1, 3, 2)],  # 第三组参数,包含三个随机数组
        [np.random.rand(2, 1)] * 4 + [np.random.rand(1, 1, 1)],  # 第四组参数,包含四个形状为(2,1)的随机数组和一个形状为(1,1,1)的随机数组
    ]
)
def test_multiiter_fields(install_temp, arrays):
    import checks  # 导入名为checks的模块
    bcast = np.broadcast(*arrays)  # 使用np.broadcast创建广播对象

    assert bcast.ndim == checks.get_multiiter_number_of_dims(bcast)  # 断言检查广播对象的维数是否与函数返回值相等
    assert bcast.size == checks.get_multiiter_size(bcast)  # 断言检查广播对象的大小是否与函数返回值相等
    assert bcast.numiter == checks.get_multiiter_num_of_iterators(bcast)  # 断言检查广播对象的迭代器数量是否与函数返回值相等
    assert bcast.shape == checks.get_multiiter_shape(bcast)  # 断言检查广播对象的形状是否与函数返回值相等
    assert bcast.index == checks.get_multiiter_current_index(bcast)  # 断言检查广播对象的当前索引是否与函数返回值相等
    # 断言语句,验证条件是否为真
    assert all(
        [
            x.base is y.base
            # 使用 zip 函数同时迭代 bcast.iters 和 checks.get_multiiter_iters(bcast) 的元素 x, y
            for x, y in zip(bcast.iters, checks.get_multiiter_iters(bcast))
        ]
    )
def test_dtype_flags(install_temp):
    # 导入名为 checks 的模块,用于后续的函数调用
    import checks
    # 创建一个包含一些有趣标志的数据类型对象
    dtype = np.dtype("i,O")  # dtype with somewhat interesting flags
    # 断言这个数据类型对象的标志与通过函数获取的标志相同
    assert dtype.flags == checks.get_dtype_flags(dtype)


def test_conv_intp(install_temp):
    # 导入名为 checks 的模块,用于后续的函数调用
    import checks

    class myint:
        def __int__(self):
            return 3

    # 这些转换通过 `__int__` 方法进行,而不是 `__index__` 方法:
    # 断言对浮点数进行转换后得到的结果为整数 3
    assert checks.conv_intp(3.) == 3
    # 断言对自定义类 myint 的实例进行转换后得到的结果为整数 3
    assert checks.conv_intp(myint()) == 3


def test_npyiter_api(install_temp):
    # 导入名为 checks 的模块,用于后续的函数调用
    import checks
    # 创建一个形状为 (3, 2) 的随机数组
    arr = np.random.rand(3, 2)

    # 创建一个数组迭代器对象 it
    it = np.nditer(arr)
    # 断言通过函数获取的迭代器大小与 it 对象的 itersize 相同,并且等于 arr 数组元素个数
    assert checks.get_npyiter_size(it) == it.itersize == np.prod(arr.shape)
    # 断言通过函数获取的迭代器维度与 it 对象的 ndim 相同,并且等于 1
    assert checks.get_npyiter_ndim(it) == it.ndim == 1
    # 断言通过函数获取的迭代器是否具有索引与 it 对象的 has_index 属性相同,均为 False
    assert checks.npyiter_has_index(it) == it.has_index == False

    # 创建一个带有 "c_index" 标志的数组迭代器对象 it
    it = np.nditer(arr, flags=["c_index"])
    # 断言通过函数获取的迭代器是否具有索引与 it 对象的 has_index 属性相同,均为 True
    assert checks.npyiter_has_index(it) == it.has_index == True
    # 断言通过函数获取的迭代器是否具有延迟缓冲分配与 it 对象的 has_delayed_bufalloc 属性相同,均为 False
    assert (
        checks.npyiter_has_delayed_bufalloc(it)
        == it.has_delayed_bufalloc
        == False
    )

    # 创建一个带有 "buffered", "delay_bufalloc" 标志的数组迭代器对象 it
    it = np.nditer(arr, flags=["buffered", "delay_bufalloc"])
    # 断言通过函数获取的迭代器是否具有延迟缓冲分配与 it 对象的 has_delayed_bufalloc 属性相同,均为 True
    assert (
        checks.npyiter_has_delayed_bufalloc(it)
        == it.has_delayed_bufalloc
        == True
    )

    # 创建一个带有 "multi_index" 标志的数组迭代器对象 it
    it = np.nditer(arr, flags=["multi_index"])
    # 断言通过函数获取的迭代器大小与 it 对象的 itersize 相同,并且等于 arr 数组元素个数
    assert checks.get_npyiter_size(it) == it.itersize == np.prod(arr.shape)
    # 断言通过函数获取的迭代器是否具有多重索引与 it 对象的 has_multi_index 属性相同,均为 True
    assert checks.npyiter_has_multi_index(it) == it.has_multi_index == True
    # 断言通过函数获取的迭代器维度与 it 对象的 ndim 相同,并且等于 2
    assert checks.get_npyiter_ndim(it) == it.ndim == 2

    # 创建一个形状为 (2, 1, 2) 的随机数组 arr2
    arr2 = np.random.rand(2, 1, 2)
    # 创建一个同时迭代 arr 和 arr2 的数组迭代器对象 it
    it = np.nditer([arr, arr2])
    # 断言通过函数获取的迭代器操作数数目与 it 对象的 nop 相同,均为 2
    assert checks.get_npyiter_nop(it) == it.nop == 2
    # 断言通过函数获取的迭代器大小与 it 对象的 itersize 相同,并且等于 12
    assert checks.get_npyiter_size(it) == it.itersize == 12
    # 断言通过函数获取的迭代器维度与 it 对象的 ndim 相同,并且等于 3
    assert checks.get_npyiter_ndim(it) == it.ndim == 3
    # 断言通过函数获取的迭代器操作数列表中的每个元素与 it 对象的 operands 属性中的每个元素相同
    assert all(
        x is y for x, y in zip(checks.get_npyiter_operands(it), it.operands)
    )
    # 断言通过函数获取的迭代器视图列表中的每个元素与 it 对象的 itviews 属性中的每个元素在数值上相近
    assert all(
        [
            np.allclose(x, y)
            for x, y in zip(checks.get_npyiter_itviews(it), it.itviews)
        ]
    )


def test_fillwithbytes(install_temp):
    # 导入名为 checks 的模块,用于后续的函数调用
    import checks
    # 调用函数生成填充有字节的数组 arr
    arr = checks.compile_fillwithbyte()
    # 断言 arr 数组等于形状为 (1, 2) 且元素全为 1 的数组
    assert_array_equal(arr, np.ones((1, 2)))


def test_complex(install_temp):
    # 从 checks 模块中导入 inc2_cfloat_struct 函数
    from checks import inc2_cfloat_struct
    
    # 创建一个复数数组 arr,包含整数和复数
    arr = np.array([0, 10+10j], dtype="F")
    # 调用函数处理这个数组 arr
    inc2_cfloat_struct(arr)
    # 断言处理后 arr 的第二个元素等于 (12 + 12j)
    assert arr[1] == (12 + 12j)

.\numpy\numpy\_core\tests\test_datetime.py

# 导入标准库中的 datetime 和 pickle 模块
import datetime
import pickle

# 导入 pytest 测试框架及相关库
import pytest

# 导入 numpy 库,并给 numpy 别名 np
import numpy
import numpy as np

# 从 numpy.testing 模块导入多个函数和常量
from numpy.testing import (
    IS_WASM,                    # 是否是 WASM 环境的标志
    assert_,                    # 断言函数
    assert_equal,               # 断言相等
    assert_raises,              # 断言引发异常
    assert_warns,               # 断言引发警告
    suppress_warnings,          # 忽略警告
    assert_raises_regex,        # 断言引发指定正则表达式匹配的异常
    assert_array_equal,         # 断言数组相等
)

# 尝试导入 pytz 库中的 timezone 类
try:
    from pytz import timezone as tz
    _has_pytz = True            # 标记是否成功导入 pytz 库
except ImportError:
    _has_pytz = False           # 若导入失败则置为 False

# 尝试定义 RecursionError,兼容 Python < 3.5 的情况
try:
    RecursionError
except NameError:
    RecursionError = RuntimeError  # 将 NameError 映射为 RuntimeError

# 定义测试类 TestDateTime
class TestDateTime:

    # 定义测试方法 test_string
    def test_string(self):
        # 准备警告消息
        msg = "no explicit representation of timezones available for np.datetime64"
        # 使用 pytest 捕获 UserWarning 类型的警告,并匹配特定的消息字符串
        with pytest.warns(UserWarning, match=msg):
            # 创建一个 np.datetime64 对象,带时区信息 '+01',触发警告
            np.datetime64('2000-01-01T00+01')

    # 定义测试方法 test_datetime
    def test_datetime(self):
        # 准备警告消息
        msg = "no explicit representation of timezones available for np.datetime64"
        # 使用 pytest 捕获 UserWarning 类型的警告,并匹配特定的消息字符串
        with pytest.warns(UserWarning, match=msg):
            # 创建一个 np.datetime64 对象,带 'Z' 时区信息,触发警告
            t0 = np.datetime64('2023-06-09T12:18:40Z', 'ns')

        # 创建一个 np.datetime64 对象,无显式时区信息
        t0 = np.datetime64('2023-06-09T12:18:40', 'ns')
    # 定义测试函数,用于测试 datetime 数据类型的创建
    def test_datetime_dtype_creation(self):
        # 遍历不同的时间单位
        for unit in ['Y', 'M', 'W', 'D',
                     'h', 'm', 's', 'ms', 'us',
                     'μs',  # alias for us
                     'ns', 'ps', 'fs', 'as']:
            # 创建一个 datetime64 数据类型的对象 dt1
            dt1 = np.dtype('M8[750%s]' % unit)
            # 断言 dt1 的类型与指定的 datetime64 数据类型相同
            assert_(dt1 == np.dtype('datetime64[750%s]' % unit))
            # 创建一个 timedelta64 数据类型的对象 dt2
            dt2 = np.dtype('m8[%s]' % unit)
            # 断言 dt2 的类型与指定的 timedelta64 数据类型相同
            assert_(dt2 == np.dtype('timedelta64[%s]' % unit))

        # 对于通用单位,不应在末尾添加 []
        assert_equal(str(np.dtype("M8")), "datetime64")

        # 应当可以指定字节顺序
        assert_equal(np.dtype("=M8"), np.dtype("M8"))
        assert_equal(np.dtype("=M8[s]"), np.dtype("M8[s]"))
        # 断言大端序或小端序的 datetime64 数据类型与普通的 datetime64 相同
        assert_(np.dtype(">M8") == np.dtype("M8") or
                np.dtype("<M8") == np.dtype("M8"))
        assert_(np.dtype(">M8[D]") == np.dtype("M8[D]") or
                np.dtype("<M8[D]") == np.dtype("M8[D]"))
        # 断言大端序与小端序的 datetime64 数据类型不相同
        assert_(np.dtype(">M8") != np.dtype("<M8"))

        assert_equal(np.dtype("=m8"), np.dtype("m8"))
        assert_equal(np.dtype("=m8[s]"), np.dtype("m8[s]"))
        # 断言大端序或小端序的 timedelta64 数据类型与普通的 timedelta64 相同
        assert_(np.dtype(">m8") == np.dtype("m8") or
                np.dtype("<m8") == np.dtype("m8"))
        assert_(np.dtype(">m8[D]") == np.dtype("m8[D]") or
                np.dtype("<m8[D]") == np.dtype("m8[D]"))
        # 断言大端序与小端序的 timedelta64 数据类型不相同
        assert_(np.dtype(">m8") != np.dtype("<m8"))

        # 检查解析器是否拒绝错误的 datetime 类型
        assert_raises(TypeError, np.dtype, 'M8[badunit]')
        assert_raises(TypeError, np.dtype, 'm8[badunit]')
        assert_raises(TypeError, np.dtype, 'M8[YY]')
        assert_raises(TypeError, np.dtype, 'm8[YY]')
        assert_raises(TypeError, np.dtype, 'm4')
        assert_raises(TypeError, np.dtype, 'M7')
        assert_raises(TypeError, np.dtype, 'm7')
        assert_raises(TypeError, np.dtype, 'M16')
        assert_raises(TypeError, np.dtype, 'm16')
        assert_raises(TypeError, np.dtype, 'M8[3000000000ps]')
    def test_datetime_prefix_conversions(self):
        # regression tests related to gh-19631;
        # test metric prefixes from seconds down to
        # attoseconds for bidirectional conversions

        # 定义较小时间单位的列表,用于测试从秒到atto秒的双向转换
        smaller_units = ['M8[7000ms]',
                         'M8[2000us]',
                         'M8[1000ns]',
                         'M8[5000ns]',
                         'M8[2000ps]',
                         'M8[9000fs]',
                         'M8[1000as]',
                         'M8[2000000ps]',
                         'M8[1000000as]',
                         'M8[2000000000ps]',
                         'M8[1000000000as]']

        # 定义较大时间单位的列表,用于测试从秒到atto秒的双向转换
        larger_units = ['M8[7s]',
                        'M8[2ms]',
                        'M8[us]',
                        'M8[5us]',
                        'M8[2ns]',
                        'M8[9ps]',
                        'M8[1fs]',
                        'M8[2us]',
                        'M8[1ps]',
                        'M8[2ms]',
                        'M8[1ns]']

        # 遍历较大和较小时间单位列表,进行类型转换的安全性断言
        for larger_unit, smaller_unit in zip(larger_units, smaller_units):
            assert np.can_cast(larger_unit, smaller_unit, casting='safe')
            assert np.can_cast(smaller_unit, larger_unit, casting='safe')

    @pytest.mark.parametrize("unit", [
        "s", "ms", "us", "ns", "ps", "fs", "as"])
    def test_prohibit_negative_datetime(self, unit):
        # 使用断言检测是否能够禁止负的时间单位
        with assert_raises(TypeError):
            np.array([1], dtype=f"M8[-1{unit}]")

    def test_compare_generic_nat(self):
        # regression tests for gh-6452
        # 检测泛型 NaT 的比较行为,测试 gh-6452 的回归情况
        assert_(np.datetime64('NaT') !=
                np.datetime64('2000') + np.timedelta64('NaT'))
        assert_(np.datetime64('NaT') != np.datetime64('NaT', 'us'))
        assert_(np.datetime64('NaT', 'us') != np.datetime64('NaT'))

    @pytest.mark.parametrize("size", [
        3, 21, 217, 1000])
    def test_datetime_nat_argsort_stability(self, size):
        # NaT < NaT should be False internally for
        # sort stability
        # 测试日期时间 NaT 的 argsort 稳定性,确保 NaT < NaT 返回 False
        expected = np.arange(size)
        arr = np.tile(np.datetime64('NaT'), size)
        assert_equal(np.argsort(arr, kind='mergesort'), expected)

    @pytest.mark.parametrize("size", [
        3, 21, 217, 1000])
    def test_timedelta_nat_argsort_stability(self, size):
        # NaT < NaT should be False internally for
        # sort stability
        # 测试时间间隔 NaT 的 argsort 稳定性,确保 NaT < NaT 返回 False
        expected = np.arange(size)
        arr = np.tile(np.timedelta64('NaT'), size)
        assert_equal(np.argsort(arr, kind='mergesort'), expected)
    @pytest.mark.parametrize("arr, expected", [
        # 使用 pytest 的 parametrize 装饰器定义多组输入和期望输出的参数
        # 示例 gh-12629
        (['NaT', 1, 2, 3],
         [1, 2, 3, 'NaT']),
        # 包含多个 NaT 的情况
        (['NaT', 9, 'NaT', -707],
         [-707, 9, 'NaT', 'NaT']),
        # 探索另一种 NaT 排序的代码路径
        ([1, -2, 3, 'NaT'],
         [-2, 1, 3, 'NaT']),
        # 二维数组
        ([[51, -220, 'NaT'],
          [-17, 'NaT', -90]],
         [[-220, 51, 'NaT'],
          [-90, -17, 'NaT']]),
    ])
    @pytest.mark.parametrize("dtype", [
        'M8[ns]', 'M8[us]',
        'm8[ns]', 'm8[us]'])
    def test_datetime_timedelta_sort_nat(self, arr, expected, dtype):
        # 修复 gh-12629 和 gh-15063; 将 NaT 排序到数组末尾
        arr = np.array(arr, dtype=dtype)
        expected = np.array(expected, dtype=dtype)
        arr.sort()
        assert_equal(arr, expected)

    def test_datetime_scalar_construction_timezone(self):
        # 提供关于 np.datetime64 显式时区的警告验证
        msg = "no explicit representation of timezones available for " \
              "np.datetime64"
        with pytest.warns(UserWarning, match=msg):
            assert_equal(np.datetime64('2000-01-01T00Z'),
                         np.datetime64('2000-01-01T00'))
        with pytest.warns(UserWarning, match=msg):
            assert_equal(np.datetime64('2000-01-01T00-08'),
                         np.datetime64('2000-01-01T08'))

    def test_datetime_array_find_type(self):
        dt = np.datetime64('1970-01-01', 'M')
        arr = np.array([dt])
        assert_equal(arr.dtype, np.dtype('M8[M]'))

        # 目前,我们不自动将这些转换为 datetime64

        dt = datetime.date(1970, 1, 1)
        arr = np.array([dt])
        assert_equal(arr.dtype, np.dtype('O'))

        dt = datetime.datetime(1970, 1, 1, 12, 30, 40)
        arr = np.array([dt])
        assert_equal(arr.dtype, np.dtype('O'))

        # 查找非日期和日期的“超类型”

        b = np.bool(True)
        dm = np.datetime64('1970-01-01', 'M')
        d = datetime.date(1970, 1, 1)
        dt = datetime.datetime(1970, 1, 1, 12, 30, 40)

        arr = np.array([b, dm])
        assert_equal(arr.dtype, np.dtype('O'))

        arr = np.array([b, d])
        assert_equal(arr.dtype, np.dtype('O'))

        arr = np.array([b, dt])
        assert_equal(arr.dtype, np.dtype('O'))

        arr = np.array([d, d]).astype('datetime64')
        assert_equal(arr.dtype, np.dtype('M8[D]'))

        arr = np.array([dt, dt]).astype('datetime64')
        assert_equal(arr.dtype, np.dtype('M8[us]'))

    @pytest.mark.parametrize("unit", [
    # 测试所有日期/时间单位并使用
    # "generic" 选择通用单位
    ("Y"), ("M"), ("W"), ("D"), ("h"), ("m"),
    ("s"), ("ms"), ("us"), ("ns"), ("ps"),
    ("fs"), ("as"), ("generic") ])
    # 定义一个测试方法,用于检验 np.timedelta64 和 np.int64 的构造方式是否正常
    def test_timedelta_np_int_construction(self, unit):
        # 用于回归测试 gh-7617
        # 如果单位不是 "generic",则断言 np.timedelta64(np.int64(123), unit) 等于 np.timedelta64(123, unit)
        if unit != "generic":
            assert_equal(np.timedelta64(np.int64(123), unit),
                         np.timedelta64(123, unit))
        else:
            # 如果单位是 "generic",则断言 np.timedelta64(np.int64(123)) 等于 np.timedelta64(123)
            assert_equal(np.timedelta64(np.int64(123)),
                         np.timedelta64(123))

    # 定义一个测试方法,检验 datetime.timedelta 对象数组向 np.timedelta64[D] 类型的数组转换是否正常
    def test_timedelta_object_array_conversion(self):
        # 回归测试 gh-11096
        # 创建包含 datetime.timedelta 对象的列表作为输入
        inputs = [datetime.timedelta(28),
                  datetime.timedelta(30),
                  datetime.timedelta(31)]
        # 创建预期的 np.timedelta64[D] 类型的数组
        expected = np.array([28, 30, 31], dtype='timedelta64[D]')
        # 将输入的 datetime.timedelta 对象数组转换为 np.timedelta64[D] 类型的数组
        actual = np.array(inputs, dtype='timedelta64[D]')
        # 断言转换后的数组与预期数组相等
        assert_equal(expected, actual)

    # 定义一个测试方法,检验将 datetime.timedelta 对象转换为 np.timedelta64 类型的数组是否正常
    def test_timedelta_0_dim_object_array_conversion(self):
        # 回归测试 gh-11151
        # 创建包含 datetime.timedelta(seconds=20) 的 np.ndarray 对象
        test = np.array(datetime.timedelta(seconds=20))
        # 将 test 数组的元素转换为 np.timedelta64 类型的元素
        actual = test.astype(np.timedelta64)
        # 使用数组构造器的 workaround 描述的方式创建预期值
        expected = np.array(datetime.timedelta(seconds=20),
                            np.timedelta64)
        # 断言转换后的数组与预期数组相等
        assert_equal(actual, expected)

    # 定义一个测试方法,检验 np.timedelta64('nat') 的格式化输出是否为 'NaT'
    def test_timedelta_nat_format(self):
        # gh-17552
        # 断言 np.timedelta64('nat') 的格式化输出是否为 'NaT'
        assert_equal('NaT', '{0}'.format(np.timedelta64('nat')))
    def test_datetime_nat_casting(self):
        # 创建一个包含 'NaT' 的 NumPy 数组,数据类型为 'M8[D]'
        a = np.array('NaT', dtype='M8[D]')
        # 创建一个 'NaT' 的 NumPy datetime64 标量,精度为 '[D]'

        b = np.datetime64('NaT', '[D]')

        # 数组操作
        assert_equal(a.astype('M8[s]'), np.array('NaT', dtype='M8[s]'))
        # 将数组 a 转换为秒精度的 datetime64 数组,并与预期结果进行比较
        assert_equal(a.astype('M8[ms]'), np.array('NaT', dtype='M8[ms]'))
        # 将数组 a 转换为毫秒精度的 datetime64 数组,并与预期结果进行比较
        assert_equal(a.astype('M8[M]'), np.array('NaT', dtype='M8[M]'))
        # 将数组 a 转换为月精度的 datetime64 数组,并与预期结果进行比较
        assert_equal(a.astype('M8[Y]'), np.array('NaT', dtype='M8[Y]'))
        # 将数组 a 转换为年精度的 datetime64 数组,并与预期结果进行比较
        assert_equal(a.astype('M8[W]'), np.array('NaT', dtype='M8[W]'))
        # 将数组 a 转换为周精度的 datetime64 数组,并与预期结果进行比较

        # 标量到标量的操作
        assert_equal(np.datetime64(b, '[s]'), np.datetime64('NaT', '[s]'))
        # 将标量 b 转换为秒精度的 datetime64 标量,并与预期结果进行比较
        assert_equal(np.datetime64(b, '[ms]'), np.datetime64('NaT', '[ms]'))
        # 将标量 b 转换为毫秒精度的 datetime64 标量,并与预期结果进行比较
        assert_equal(np.datetime64(b, '[M]'), np.datetime64('NaT', '[M]'))
        # 将标量 b 转换为月精度的 datetime64 标量,并与预期结果进行比较
        assert_equal(np.datetime64(b, '[Y]'), np.datetime64('NaT', '[Y]'))
        # 将标量 b 转换为年精度的 datetime64 标量,并与预期结果进行比较
        assert_equal(np.datetime64(b, '[W]'), np.datetime64('NaT', '[W]'))
        # 将标量 b 转换为周精度的 datetime64 标量,并与预期结果进行比较

        # 数组到标量的操作
        assert_equal(np.datetime64(a, '[s]'), np.datetime64('NaT', '[s]'))
        # 将数组 a 转换为秒精度的 datetime64 标量,并与预期结果进行比较
        assert_equal(np.datetime64(a, '[ms]'), np.datetime64('NaT', '[ms]'))
        # 将数组 a 转换为毫秒精度的 datetime64 标量,并与预期结果进行比较
        assert_equal(np.datetime64(a, '[M]'), np.datetime64('NaT', '[M]'))
        # 将数组 a 转换为月精度的 datetime64 标量,并与预期结果进行比较
        assert_equal(np.datetime64(a, '[Y]'), np.datetime64('NaT', '[Y]'))
        # 将数组 a 转换为年精度的 datetime64 标量,并与预期结果进行比较
        assert_equal(np.datetime64(a, '[W]'), np.datetime64('NaT', '[W]'))
        # 将数组 a 转换为周精度的 datetime64 标量,并与预期结果进行比较

        # NaN 转换为 NaT
        nan = np.array([np.nan] * 8 + [0])
        # 创建一个包含 NaN 的 NumPy 数组
        fnan = nan.astype('f')
        # 将数组 nan 转换为单精度浮点数数组
        lnan = nan.astype('g')
        # 将数组 nan 转换为长整型数组
        cnan = nan.astype('D')
        # 将数组 nan 转换为复数型数组
        cfnan = nan.astype('F')
        # 将数组 nan 转换为复数型数组
        clnan = nan.astype('G')
        # 将数组 nan 转换为长复数型数组
        hnan = nan.astype(np.half)
        # 将数组 nan 转换为半精度浮点数数组

        nat = np.array([np.datetime64('NaT')] * 8 + [np.datetime64(0, 'D')])
        # 创建一个包含 'NaT' 和 '1970-01-01' 的 NumPy datetime64 数组
        assert_equal(nan.astype('M8[ns]'), nat)
        # 将数组 nan 转换为纳秒精度的 datetime64 数组,并与预期结果进行比较
        assert_equal(fnan.astype('M8[ns]'), nat)
        # 将数组 fnan 转换为纳秒精度的 datetime64 数组,并与预期结果进行比较
        assert_equal(lnan.astype('M8[ns]'), nat)
        # 将数组 lnan 转换为纳秒精度的 datetime64 数组,并与预期结果进行比较
        assert_equal(cnan.astype('M8[ns]'), nat)
        # 将数组 cnan 转换为纳秒精度的 datetime64 数组,并与预期结果进行比较
        assert_equal(cfnan.astype('M8[ns]'), nat)
        # 将数组 cfnan 转换为纳秒精度的 datetime64 数组,并与预期结果进行比较
        assert_equal(clnan.astype('M8[ns]'), nat)
        # 将数组 clnan 转换为纳秒精度的 datetime64 数组,并与预期结果进行比较
        assert_equal(hnan.astype('M8[ns]'), nat)
        # 将数组 hnan 转换为纳秒精度的 datetime64 数组,并与预期结果进行比较

        nat = np.array([np.timedelta64('NaT')] * 8 + [np.timedelta64(0)])
        # 创建一个包含 'NaT' 和 '0' 的 NumPy timedelta64 数组
        assert_equal(nan.astype('timedelta64[ns]'), nat)
        # 将数组 nan 转换为纳秒精度的 timedelta64 数组,并与预期结果进行比较
        assert_equal(fnan.astype('timedelta64[ns]'), nat)
        # 将数组 fnan 转换为纳秒精度的 timedelta64 数组,并与预期结果进行比较
        assert_equal(lnan.astype('timedelta64[ns]'), nat)
        # 将数组 lnan 转换为纳秒精度的 timedelta64 数组,并与预期结果进行比较
        assert_equal(cnan.astype('timedelta64[ns]'), nat)
        # 将数组 cnan 转换为纳秒精度的 timedelta64 数组,并与预期结果进行比较
        assert_equal(cfnan.astype('timedelta64[ns]'), nat)
        # 将数组 cfnan 转换为纳秒精度的 timedelta64 数组,并与预期结果进行比较
        assert_equal(clnan.astype('timedelta64[ns]'), nat)
        # 将数组 clnan 转换为纳秒精度的 timedelta64 数组,并与预期结果进行比较
        assert_equal(hnan.astype('timedelta64[ns]'), nat)
        # 将数组 hnan 转换为纳秒精度的 timedelta64 数组,并与预期结果进行比较
    # 定义一个测试方法,用于验证日期创建的功能

        # 断言:对于日期 '1599-01-01',计算从1970年到该日期经过的天数
        assert_equal(np.array('1599', dtype='M8[D]').astype('i8'),
                (1600-1970)*365 - (1972-1600)/4 + 3 - 365)
        
        # 断言:对于日期 '1600-01-01',计算从1970年到该日期经过的天数
        assert_equal(np.array('1600', dtype='M8[D]').astype('i8'),
                (1600-1970)*365 - (1972-1600)/4 + 3)
        
        # 断言:对于日期 '1601-01-01',计算从1970年到该日期经过的天数
        assert_equal(np.array('1601', dtype='M8[D]').astype('i8'),
                (1600-1970)*365 - (1972-1600)/4 + 3 + 366)
        
        # 断言:对于日期 '1900-01-01',计算从1970年到该日期经过的天数
        assert_equal(np.array('1900', dtype='M8[D]').astype('i8'),
                (1900-1970)*365 - (1970-1900)//4)
        
        # 断言:对于日期 '1901-01-01',计算从1970年到该日期经过的天数
        assert_equal(np.array('1901', dtype='M8[D]').astype('i8'),
                (1900-1970)*365 - (1970-1900)//4 + 365)
        
        # 断言:对于日期 '1967-01-01',计算从1970年到该日期经过的天数
        assert_equal(np.array('1967', dtype='M8[D]').astype('i8'), -3*365 - 1)
        
        # 断言:对于日期 '1968-01-01',计算从1970年到该日期经过的天数
        assert_equal(np.array('1968', dtype='M8[D]').astype('i8'), -2*365 - 1)
        
        # 断言:对于日期 '1969-01-01',计算从1970年到该日期经过的天数
        assert_equal(np.array('1969', dtype='M8[D]').astype('i8'), -1*365)
        
        # 断言:对于日期 '1970-01-01',计算从1970年到该日期经过的天数
        assert_equal(np.array('1970', dtype='M8[D]').astype('i8'), 0*365)
        
        # 断言:对于日期 '1971-01-01',计算从1970年到该日期经过的天数
        assert_equal(np.array('1971', dtype='M8[D]').astype('i8'), 1*365)
        
        # 断言:对于日期 '1972-01-01',计算从1970年到该日期经过的天数
        assert_equal(np.array('1972', dtype='M8[D]').astype('i8'), 2*365)
        
        # 断言:对于日期 '1973-01-01',计算从1970年到该日期经过的天数
        assert_equal(np.array('1973', dtype='M8[D]').astype('i8'), 3*365 + 1)
        
        # 断言:对于日期 '1974-01-01',计算从1970年到该日期经过的天数
        assert_equal(np.array('1974', dtype='M8[D]').astype('i8'), 4*365 + 1)
        
        # 断言:对于日期 '2000-01-01',计算从1970年到该日期经过的天数
        assert_equal(np.array('2000', dtype='M8[D]').astype('i8'),
                 (2000 - 1970)*365 + (2000 - 1972)//4)
        
        # 断言:对于日期 '2001-01-01',计算从1970年到该日期经过的天数
        assert_equal(np.array('2001', dtype='M8[D]').astype('i8'),
                 (2000 - 1970)*365 + (2000 - 1972)//4 + 366)
        
        # 断言:对于日期 '2400-01-01',计算从1970年到该日期经过的天数
        assert_equal(np.array('2400', dtype='M8[D]').astype('i8'),
                 (2400 - 1970)*365 + (2400 - 1972)//4 - 3)
        
        # 断言:对于日期 '2401-01-01',计算从1970年到该日期经过的天数
        assert_equal(np.array('2401', dtype='M8[D]').astype('i8'),
                 (2400 - 1970)*365 + (2400 - 1972)//4 - 3 + 366)

        # 断言:对于日期 '1600-02-29',计算从1970年到该日期经过的天数
        assert_equal(np.array('1600-02-29', dtype='M8[D]').astype('i8'),
                (1600-1970)*365 - (1972-1600)//4 + 3 + 31 + 28)
        
        # 断言:对于日期 '1600-03-01',计算从1970年到该日期经过的天数
        assert_equal(np.array('1600-03-01', dtype='M8[D]').astype('i8'),
                (1600-1970)*365 - (1972-1600)//4 + 3 + 31 + 29)
        
        # 断言:对于日期 '2000-02-29',计算从1970年到该日期经过的天数
        assert_equal(np.array('2000-02-29', dtype='M8[D]').astype('i8'),
                 (2000 - 1970)*365 + (2000 - 1972)//4 + 31 + 28)
        
        # 断言:对于日期 '2000-03-01',计算从1970年到该日期经过的天数
        assert_equal(np.array('2000-03-01', dtype='M8[D]').astype('i8'),
                 (2000 - 1970)*365 + (2000 - 1972)//4 + 31 + 29)
        
        # 断言:对于日期 '2001-03-22',计算从1970年到该日期经过的天数
        assert_equal(np.array('2001-03-22', dtype='M8[D]').astype('i8'),
                 (2000 - 1970)*365 + (2000 - 1972)//4 + 366 + 31 + 28 + 21)
    # 测试函数:将字符串表示的日期转换为 datetime.date 对象,并与指定的日期进行比较
    def test_days_to_pydate(self):
        # 断言:将字符串 '1599' 转换为 numpy datetime 数组,再转换为 Python datetime.date 对象,并比较是否等于指定日期
        assert_equal(np.array('1599', dtype='M8[D]').astype('O'),
                     datetime.date(1599, 1, 1))
        assert_equal(np.array('1600', dtype='M8[D]').astype('O'),
                     datetime.date(1600, 1, 1))
        assert_equal(np.array('1601', dtype='M8[D]').astype('O'),
                     datetime.date(1601, 1, 1))
        assert_equal(np.array('1900', dtype='M8[D]').astype('O'),
                     datetime.date(1900, 1, 1))
        assert_equal(np.array('1901', dtype='M8[D]').astype('O'),
                     datetime.date(1901, 1, 1))
        assert_equal(np.array('2000', dtype='M8[D]').astype('O'),
                     datetime.date(2000, 1, 1))
        assert_equal(np.array('2001', dtype='M8[D]').astype('O'),
                     datetime.date(2001, 1, 1))
        assert_equal(np.array('1600-02-29', dtype='M8[D]').astype('O'),
                     datetime.date(1600, 2, 29))
        assert_equal(np.array('1600-03-01', dtype='M8[D]').astype('O'),
                     datetime.date(1600, 3, 1))
        assert_equal(np.array('2001-03-22', dtype='M8[D]').astype('O'),
                     datetime.date(2001, 3, 22))

    # 测试函数:比较不同的 numpy datetime 类型是否相等
    def test_dtype_comparison(self):
        assert_(not (np.dtype('M8[us]') == np.dtype('M8[ms]')))
        assert_(np.dtype('M8[us]') != np.dtype('M8[ms]'))
        assert_(np.dtype('M8[2D]') != np.dtype('M8[D]'))
        assert_(np.dtype('M8[D]') != np.dtype('M8[2D]'))

    # 测试函数:创建 numpy datetime 数组并与 Python datetime.date 对象进行比较
    def test_pydatetime_creation(self):
        a = np.array(['1960-03-12', datetime.date(1960, 3, 12)], dtype='M8[D]')
        assert_equal(a[0], a[1])
        a = np.array(['1999-12-31', datetime.date(1999, 12, 31)], dtype='M8[D]')
        assert_equal(a[0], a[1])
        a = np.array(['2000-01-01', datetime.date(2000, 1, 1)], dtype='M8[D]')
        assert_equal(a[0], a[1])
        # 如果日期在刚好转换时发生变化,则断言将会失败
        a = np.array(['today', datetime.date.today()], dtype='M8[D]')
        assert_equal(a[0], a[1])
        # datetime.datetime.now() 返回本地时间,不是 UTC 时间
        #a = np.array(['now', datetime.datetime.now()], dtype='M8[s]')
        #assert_equal(a[0], a[1])

        # 可以将 datetime.date 对象转换为 M8[s] 时间单位的 numpy datetime 数组
        assert_equal(np.array(datetime.date(1960, 3, 12), dtype='M8[s]'),
                     np.array(np.datetime64('1960-03-12T00:00:00')))
    # 定义一个测试方法,用于测试日期时间字符串转换的功能
    def test_datetime_string_conversion(self):
        # 创建包含日期字符串的列表
        a = ['2011-03-16', '1920-01-01', '2013-05-19']
        # 创建一个包含这些日期字符串的 NumPy 数组,数据类型为字节串 'S'
        str_a = np.array(a, dtype='S')
        # 创建一个包含这些日期字符串的 NumPy 数组,数据类型为 Unicode 字符串 'U'
        uni_a = np.array(a, dtype='U')
        # 创建一个包含这些日期字符串的 NumPy 数组,数据类型为日期时间 'M'
        dt_a = np.array(a, dtype='M')

        # 测试:字符串转换为日期时间
        assert_equal(dt_a, str_a.astype('M'))
        assert_equal(dt_a.dtype, str_a.astype('M').dtype)
        # 创建一个与 dt_a 相同形状的空数组 dt_b,并将 str_a 中的数据复制到 dt_b
        dt_b = np.empty_like(dt_a)
        dt_b[...] = str_a
        assert_equal(dt_a, dt_b)

        # 测试:日期时间转换为字符串
        assert_equal(str_a, dt_a.astype('S0'))
        # 创建一个与 str_a 相同形状的空数组 str_b,并将 dt_a 中的数据复制到 str_b
        str_b = np.empty_like(str_a)
        str_b[...] = dt_a
        assert_equal(str_a, str_b)

        # 测试:Unicode 转换为日期时间
        assert_equal(dt_a, uni_a.astype('M'))
        assert_equal(dt_a.dtype, uni_a.astype('M').dtype)
        # 创建一个与 dt_a 相同形状的空数组 dt_b,并将 uni_a 中的数据复制到 dt_b
        dt_b = np.empty_like(dt_a)
        dt_b[...] = uni_a
        assert_equal(dt_a, dt_b)

        # 测试:日期时间转换为 Unicode
        assert_equal(uni_a, dt_a.astype('U'))
        # 创建一个与 uni_a 相同形状的空数组 uni_b,并将 dt_a 中的数据复制到 uni_b
        uni_b = np.empty_like(uni_a)
        uni_b[...] = dt_a
        assert_equal(uni_a, uni_b)

        # 测试:日期时间转换为长字符串(gh-9712)
        assert_equal(str_a, dt_a.astype((np.bytes_, 128)))
        # 创建一个数据类型为 (np.bytes_, 128) 的空数组 str_b,与 str_a 的形状相同,并将 dt_a 中的数据复制到 str_b
        str_b = np.empty(str_a.shape, dtype=(np.bytes_, 128))
        str_b[...] = dt_a
        assert_equal(str_a, str_b)
    def test_datetime_conversions_byteorders(self, str_dtype, time_dtype):
        # 创建一个包含时间字符串和NaT(Not a Time)的NumPy数组,使用指定的数据类型
        times = np.array(["2017", "NaT"], dtype=time_dtype)
        # 不幸的是,时间间隔无法往返转换:
        # 创建一个包含字符串日期和NaT的NumPy数组,使用指定的数据类型
        from_strings = np.array(["2017", "NaT"], dtype=str_dtype)
        # 假设这是正确的,将时间数组转换为指定数据类型的字符串数组
        to_strings = times.astype(str_dtype)

        # 检查如果源数组已经交换字节顺序,从时间到字符串的转换是否工作:
        times_swapped = times.astype(times.dtype.newbyteorder())
        res = times_swapped.astype(str_dtype)
        # 断言结果数组与目标字符串数组相等
        assert_array_equal(res, to_strings)

        # 检查如果源数组和目标字符串数组都交换了字节顺序,从时间到字符串的转换是否工作:
        res = times_swapped.astype(to_strings.dtype.newbyteorder())
        assert_array_equal(res, to_strings)

        # 检查只有目标字符串数组交换了字节顺序,从时间到字符串的转换是否工作:
        res = times.astype(to_strings.dtype.newbyteorder())
        assert_array_equal(res, to_strings)

        # 检查如果源字符串数组已经交换字节顺序,从字符串到时间的转换是否工作:
        from_strings_swapped = from_strings.astype(from_strings.dtype.newbyteorder())
        res = from_strings_swapped.astype(time_dtype)
        assert_array_equal(res, times)

        # 检查如果源字符串数组和时间数组都交换了字节顺序,从字符串到时间的转换是否工作:
        res = from_strings_swapped.astype(times.dtype.newbyteorder())
        assert_array_equal(res, times)

        # 检查只有时间数组交换了字节顺序,从字符串到时间的转换是否工作:
        res = from_strings.astype(times.dtype.newbyteorder())
        assert_array_equal(res, times)

    def test_datetime_array_str(self):
        # 创建一个包含日期字符串的NumPy数组,使用'M'(datetime64)数据类型
        a = np.array(['2011-03-16', '1920-01-01', '2013-05-19'], dtype='M')
        # 断言将数组转换为字符串后结果是否符合预期格式
        assert_equal(str(a), "['2011-03-16' '1920-01-01' '2013-05-19']")

        # 创建一个包含带时间的日期字符串的NumPy数组,使用'M'(datetime64)数据类型
        a = np.array(['2011-03-16T13:55', '1920-01-01T03:12'], dtype='M')
        # 断言将数组转换为字符串后结果是否符合预期格式,使用自定义格式化器
        assert_equal(np.array2string(a, separator=', ',
                    formatter={'datetime': lambda x:
                            "'%s'" % np.datetime_as_string(x, timezone='UTC')}),
                     "['2011-03-16T13:55Z', '1920-01-01T03:12Z']")

        # 检查当数组中存在NaT时,确保后续条目不受其影响
        a = np.array(['2010', 'NaT', '2030']).astype('M')
        # 断言将数组转换为字符串后结果是否符合预期格式
        assert_equal(str(a), "['2010'  'NaT' '2030']")

    def test_timedelta_array_str(self):
        # 创建一个包含负数、零和正数的NumPy数组,使用'm'(timedelta64)数据类型
        a = np.array([-1, 0, 100], dtype='m')
        # 断言将数组转换为字符串后结果是否符合预期格式
        assert_equal(str(a), "[ -1   0 100]")
        
        # 创建一个包含NaT的NumPy数组,使用'm'(timedelta64)数据类型
        a = np.array(['NaT', 'NaT'], dtype='m')
        # 断言将数组转换为字符串后结果是否符合预期格式
        assert_equal(str(a), "['NaT' 'NaT']")

        # 检查当NaT右对齐时的情况
        a = np.array([-1, 'NaT', 0], dtype='m')
        # 断言将数组转换为字符串后结果是否符合预期格式
        assert_equal(str(a), "[   -1 'NaT'     0]")
        
        # 创建一个包含负数、NaT和正数的NumPy数组,使用'm'(timedelta64)数据类型
        a = np.array([-1, 'NaT', 1234567], dtype='m')
        # 断言将数组转换为字符串后结果是否符合预期格式
        assert_equal(str(a), "[     -1   'NaT' 1234567]")

        # 测试使用其他字节顺序的情况
        a = np.array([-1, 'NaT', 1234567], dtype='>m')
        # 断言将数组转换为字符串后结果是否符合预期格式
        assert_equal(str(a), "[     -1   'NaT' 1234567]")
        
        # 测试使用其他字节顺序的情况
        a = np.array([-1, 'NaT', 1234567], dtype='<m')
        # 断言将数组转换为字符串后结果是否符合预期格式
        assert_equal(str(a), "[     -1   'NaT' 1234567]")
    # 测试 pickle 序列化和反序列化是否正常工作
    def test_pickle(self):
        # 检查不同协议版本下的 pickle 序列化和反序列化
        for proto in range(2, pickle.HIGHEST_PROTOCOL + 1):
            # 创建日期时间类型的 NumPy 数组
            dt = np.dtype('M8[7D]')
            # 断言 pickle 序列化后再反序列化仍然保持不变
            assert_equal(pickle.loads(pickle.dumps(dt, protocol=proto)), dt)
            
            # 创建周时间类型的 NumPy 数组
            dt = np.dtype('M8[W]')
            # 断言 pickle 序列化后再反序列化仍然保持不变
            assert_equal(pickle.loads(pickle.dumps(dt, protocol=proto)), dt)
            
            # 创建标量日期时间对象
            scalar = np.datetime64('2016-01-01T00:00:00.000000000')
            # 断言 pickle 序列化后再反序列化仍然保持不变
            assert_equal(pickle.loads(pickle.dumps(scalar, protocol=proto)), scalar)
            
            # 计算日期时间对象与另一日期时间对象之间的时间差
            delta = scalar - np.datetime64('2015-01-01T00:00:00.000000000')
            # 断言 pickle 序列化后再反序列化仍然保持不变
            assert_equal(pickle.loads(pickle.dumps(delta, protocol=proto)), delta)

        # 检查从旧版本(1.6)pickle 加载是否正常工作
        pkl = b"cnumpy\ndtype\np0\n(S'M8'\np1\nI0\nI1\ntp2\nRp3\n" + \
              b"(I4\nS'<'\np4\nNNNI-1\nI-1\nI0\n((dp5\n(S'D'\np6\n" + \
              b"I7\nI1\nI1\ntp7\ntp8\ntp9\nb."
        assert_equal(pickle.loads(pkl), np.dtype('<M8[7D]'))
        
        pkl = b"cnumpy\ndtype\np0\n(S'M8'\np1\nI0\nI1\ntp2\nRp3\n" + \
              b"(I4\nS'<'\np4\nNNNI-1\nI-1\nI0\n((dp5\n(S'W'\np6\n" + \
              b"I1\nI1\nI1\ntp7\ntp8\ntp9\nb."
        assert_equal(pickle.loads(pkl), np.dtype('<M8[W]'))
        
        pkl = b"cnumpy\ndtype\np0\n(S'M8'\np1\nI0\nI1\ntp2\nRp3\n" + \
              b"(I4\nS'>'\np4\nNNNI-1\nI-1\nI0\n((dp5\n(S'us'\np6\n" + \
              b"I1\nI1\nI1\ntp7\ntp8\ntp9\nb."
        assert_equal(pickle.loads(pkl), np.dtype('>M8[us]'))

    # 验证 datetime 数据类型的 __setstate__ 方法是否能处理错误参数
    def test_setstate(self):
        dt = np.dtype('>M8[us]')
        # 断言传入错误参数时能够抛出 ValueError 异常
        assert_raises(ValueError, dt.__setstate__, (4, '>', None, None, None, -1, -1, 0, 1))
        # 断言 __reduce__ 方法返回的信息与预期一致
        assert_(dt.__reduce__()[2] == np.dtype('>M8[us]').__reduce__()[2])
        # 断言传入错误参数时能够抛出 TypeError 异常
        assert_raises(TypeError, dt.__setstate__, (4, '>', None, None, None, -1, -1, 0, ({}, 'xxx')))
        # 断言 __reduce__ 方法返回的信息与预期一致
        assert_(dt.__reduce__()[2] == np.dtype('>M8[us]').__reduce__()[2])
    # 测试数据类型的提升规则
    def test_dtype_promotion(self):
        # datetime <op> datetime 计算元数据的最大公约数
        # timedelta <op> timedelta 计算元数据的最大公约数
        for mM in ['m', 'M']:
            # 检查同一类型的 datetime 数据类型提升规则
            assert_equal(
                np.promote_types(np.dtype(mM+'8[2Y]'), np.dtype(mM+'8[2Y]')),
                np.dtype(mM+'8[2Y]'))
            # 检查不同年份单位的 datetime 数据类型提升规则
            assert_equal(
                np.promote_types(np.dtype(mM+'8[12Y]'), np.dtype(mM+'8[15Y]')),
                np.dtype(mM+'8[3Y]'))
            # 检查不同月份单位的 datetime 数据类型提升规则
            assert_equal(
                np.promote_types(np.dtype(mM+'8[62M]'), np.dtype(mM+'8[24M]')),
                np.dtype(mM+'8[2M]'))
            # 检查周和日之间的 timedelta 数据类型提升规则
            assert_equal(
                np.promote_types(np.dtype(mM+'8[1W]'), np.dtype(mM+'8[2D]')),
                np.dtype(mM+'8[1D]'))
            # 检查周和秒之间的 timedelta 数据类型提升规则
            assert_equal(
                np.promote_types(np.dtype(mM+'8[W]'), np.dtype(mM+'8[13s]')),
                np.dtype(mM+'8[s]'))
            # 检查周和秒之间的 timedelta 数据类型提升规则
            assert_equal(
                np.promote_types(np.dtype(mM+'8[13W]'), np.dtype(mM+'8[49s]')),
                np.dtype(mM+'8[7s]'))
        # 检查没有合理的最大公约数时 timedelta <op> timedelta 的异常情况
        assert_raises(TypeError, np.promote_types,
                            np.dtype('m8[Y]'), np.dtype('m8[D]'))
        assert_raises(TypeError, np.promote_types,
                            np.dtype('m8[M]'), np.dtype('m8[W]'))
        # 检查 timedelta 和 float 之间无法安全转换的情况
        assert_raises(TypeError, np.promote_types, "float32", "m8")
        assert_raises(TypeError, np.promote_types, "m8", "float32")
        assert_raises(TypeError, np.promote_types, "uint64", "m8")
        assert_raises(TypeError, np.promote_types, "m8", "uint64")

        # 检查大单位范围下 timedelta <op> timedelta 可能溢出的情况
        assert_raises(OverflowError, np.promote_types,
                            np.dtype('m8[W]'), np.dtype('m8[fs]'))
        assert_raises(OverflowError, np.promote_types,
                            np.dtype('m8[s]'), np.dtype('m8[as]'))

    # 测试类型转换时的溢出情况
    def test_cast_overflow(self):
        # gh-4486: 检查 datetime64 到较小时间单位的转换是否会溢出
        def cast():
            numpy.datetime64("1971-01-01 00:00:00.000000000000000").astype("<M8[D]")
        assert_raises(OverflowError, cast)

        # 检查将年份转换为更小单位的情况是否会溢出
        def cast2():
            numpy.datetime64("2014").astype("<M8[fs]")
        assert_raises(OverflowError, cast2)
    def test_pyobject_roundtrip(self):
        # 测试函数:test_pyobject_roundtrip,用于测试各种日期时间类型通过对象类型的往返转换

        # 创建一个包含多种日期时间值的 NumPy 数组,以 np.int64 类型存储
        a = np.array([0, 0, 0, 0, 0, 0, 0, 0, 0,
                      -1020040340, -2942398, -1, 0, 1, 234523453, 1199164176],
                     dtype=np.int64)

        # 使用不同的日期单位进行循环测试
        for unit in ['M8[D]', 'M8[W]', 'M8[M]', 'M8[Y]']:
            # 复制数组 a 并按指定日期单位进行视图转换
            b = a.copy().view(dtype=unit)

            # 设置不同的日期值
            b[0] = '-0001-01-01'
            b[1] = '-0001-12-31'
            b[2] = '0000-01-01'
            b[3] = '0001-01-01'
            b[4] = '1969-12-31'
            b[5] = '1970-01-01'
            b[6] = '9999-12-31'
            b[7] = '10000-01-01'
            b[8] = 'NaT'

            # 断言往返转换后的结果与原始值相等
            assert_equal(b.astype(object).astype(unit), b,
                         "Error roundtripping unit %s" % unit)

        # 使用不同的时间单位进行循环测试
        for unit in ['M8[as]', 'M8[16fs]', 'M8[ps]', 'M8[us]',
                     'M8[300as]', 'M8[20us]']:
            # 复制数组 a 并按指定时间单位进行视图转换
            b = a.copy().view(dtype=unit)

            # 设置不同的时间值
            b[0] = '-0001-01-01T00'
            b[1] = '-0001-12-31T00'
            b[2] = '0000-01-01T00'
            b[3] = '0001-01-01T00'
            b[4] = '1969-12-31T23:59:59.999999'
            b[5] = '1970-01-01T00'
            b[6] = '9999-12-31T23:59:59.999999'
            b[7] = '10000-01-01T00'
            b[8] = 'NaT'

            # 断言往返转换后的结果与原始值相等
            assert_equal(b.astype(object).astype(unit), b,
                         "Error roundtripping unit %s" % unit)


    def test_month_truncation(self):
        # 测试函数:test_month_truncation,用于验证月份截断是否正确

        # 断言两个相同月份的日期数组相等
        assert_equal(np.array('1945-03-01', dtype='M8[M]'),
                     np.array('1945-03-31', dtype='M8[M]'))

        # 断言截断到月份的日期与对应的月末日期相等
        assert_equal(np.array('1969-11-01', dtype='M8[M]'),
                     np.array('1969-11-30T23:59:59.99999', dtype='M').astype('M8[M]'))

        # 断言截断到月份的日期与对应的月末日期相等
        assert_equal(np.array('1969-12-01', dtype='M8[M]'),
                     np.array('1969-12-31T23:59:59.99999', dtype='M').astype('M8[M]'))

        # 断言截断到月份的日期与对应的月末日期相等
        assert_equal(np.array('1970-01-01', dtype='M8[M]'),
                     np.array('1970-01-31T23:59:59.99999', dtype='M').astype('M8[M]'))

        # 断言截断到月份的日期与对应的月末日期相等
        assert_equal(np.array('1980-02-01', dtype='M8[M]'),
                     np.array('1980-02-29T23:59:59.99999', dtype='M').astype('M8[M]'))


    def test_datetime_like(self):
        # 测试函数:test_datetime_like,用于验证 np.ones_like、np.zeros_like 和 np.empty_like 的行为

        # 创建一个包含单个日期时间值的 NumPy 数组,以 'm8[4D]' 类型存储
        a = np.array([3], dtype='m8[4D]')

        # 创建一个包含单个日期值的 NumPy 数组,以 'M8[D]' 类型存储
        b = np.array(['2012-12-21'], dtype='M8[D]')

        # 断言 np.ones_like(a) 的数据类型与 a 相同
        assert_equal(np.ones_like(a).dtype, a.dtype)

        # 断言 np.zeros_like(a) 的数据类型与 a 相同
        assert_equal(np.zeros_like(a).dtype, a.dtype)

        # 断言 np.empty_like(a) 的数据类型与 a 相同
        assert_equal(np.empty_like(a).dtype, a.dtype)

        # 断言 np.ones_like(b) 的数据类型与 b 相同
        assert_equal(np.ones_like(b).dtype, b.dtype)

        # 断言 np.zeros_like(b) 的数据类型与 b 相同
        assert_equal(np.zeros_like(b).dtype, b.dtype)

        # 断言 np.empty_like(b) 的数据类型与 b 相同
        assert_equal(np.empty_like(b).dtype, b.dtype)
    def test_datetime_unary(self):
        for tda, tdb, tdzero, tdone, tdmone in \
                [
                 # One-dimensional arrays
                 (np.array([3], dtype='m8[D]'),
                  np.array([-3], dtype='m8[D]'),
                  np.array([0], dtype='m8[D]'),
                  np.array([1], dtype='m8[D]'),
                  np.array([-1], dtype='m8[D]')),
                 # NumPy scalars
                 (np.timedelta64(3, '[D]'),
                  np.timedelta64(-3, '[D]'),
                  np.timedelta64(0, '[D]'),
                  np.timedelta64(1, '[D]'),
                  np.timedelta64(-1, '[D]'))]:
            # 对于每组测试数据进行以下操作

            # 负数的一元操作
            assert_equal(-tdb, tda)
            assert_equal((-tdb).dtype, tda.dtype)
            assert_equal(np.negative(tdb), tda)
            assert_equal(np.negative(tdb).dtype, tda.dtype)

            # 正数的一元操作
            assert_equal(np.positive(tda), tda)
            assert_equal(np.positive(tda).dtype, tda.dtype)
            assert_equal(np.positive(tdb), tdb)
            assert_equal(np.positive(tdb).dtype, tdb.dtype)

            # 绝对值的一元操作
            assert_equal(np.absolute(tdb), tda)
            assert_equal(np.absolute(tdb).dtype, tda.dtype)

            # 符号的一元操作
            assert_equal(np.sign(tda), tdone)
            assert_equal(np.sign(tdb), tdmone)
            assert_equal(np.sign(tdzero), tdzero)
            assert_equal(np.sign(tda).dtype, tda.dtype)

            # 运算函数总是产生本机字节顺序的结果
            assert_
    def test_datetime_multiply(self):
        # 迭代器,依次处理不同的测试用例
        for dta, tda, tdb, tdc in \
                    [
                     # One-dimensional arrays
                     (np.array(['2012-12-21'], dtype='M8[D]'),
                      np.array([6], dtype='m8[h]'),
                      np.array([9], dtype='m8[h]'),
                      np.array([12], dtype='m8[h]')),
                     # NumPy scalars
                     (np.datetime64('2012-12-21', '[D]'),
                      np.timedelta64(6, '[h]'),
                      np.timedelta64(9, '[h]'),
                      np.timedelta64(12, '[h]'))]:
            # m8 * int
            assert_equal(tda * 2, tdc)
            assert_equal((tda * 2).dtype, np.dtype('m8[h]'))
            # int * m8
            assert_equal(2 * tda, tdc)
            assert_equal((2 * tda).dtype, np.dtype('m8[h]'))
            # m8 * float
            assert_equal(tda * 1.5, tdb)
            assert_equal((tda * 1.5).dtype, np.dtype('m8[h]'))
            # float * m8
            assert_equal(1.5 * tda, tdb)
            assert_equal((1.5 * tda).dtype, np.dtype('m8[h]'))

            # m8 * m8
            assert_raises(TypeError, np.multiply, tda, tdb)
            # m8 * M8
            assert_raises(TypeError, np.multiply, dta, tda)
            # M8 * m8
            assert_raises(TypeError, np.multiply, tda, dta)
            # M8 * int
            assert_raises(TypeError, np.multiply, dta, 2)
            # int * M8
            assert_raises(TypeError, np.multiply, 2, dta)
            # M8 * float
            assert_raises(TypeError, np.multiply, dta, 1.5)
            # float * M8
            assert_raises(TypeError, np.multiply, 1.5, dta)

        # NaTs
        with suppress_warnings() as sup:
            sup.filter(RuntimeWarning, "invalid value encountered in multiply")
            # 创建 NaT(Not a Time)对象
            nat = np.timedelta64('NaT')
            # 定义检查函数,验证 NaT 与其他类型数据的乘法运算结果
            def check(a, b, res):
                assert_equal(a * b, res)
                assert_equal(b * a, res)
            # 对整数和浮点数类型进行检查
            for tp in (int, float):
                check(nat, tp(2), nat)
                check(nat, tp(0), nat)
            # 对于特殊浮点数值(无穷大和NaN)进行检查
            for f in (float('inf'), float('nan')):
                check(np.timedelta64(1), f, nat)
                check(np.timedelta64(0), f, nat)
                check(nat, f, nat)
    @pytest.mark.parametrize("op1, op2, exp", [
        # 定义参数化测试用例,测试 timedelta64 类型的整数除法
        # 当两个正时间差相同单位时,向下取整
        (np.timedelta64(7, 's'),
         np.timedelta64(4, 's'),
         1),
        # 当一个时间差为正,另一个为负且单位相同时,向下取整
        (np.timedelta64(7, 's'),
         np.timedelta64(-4, 's'),
         -2),
        # 当一个时间差为正,另一个为负且单位相同时,向下取整
        (np.timedelta64(8, 's'),
         np.timedelta64(-4, 's'),
         -2),
        # 当两个时间差单位不同时
        (np.timedelta64(1, 'm'),
         np.timedelta64(31, 's'),
         1),
        # 当两个时间差为通用单位时
        (np.timedelta64(1890),
         np.timedelta64(31),
         60),
        # 年 // 月运算
        (np.timedelta64(2, 'Y'),
         np.timedelta64('13', 'M'),
         1),
        # 处理一维数组
        (np.array([1, 2, 3], dtype='m8'),
         np.array([2], dtype='m8'),
         np.array([0, 1, 1], dtype=np.int64)),
        ])
    def test_timedelta_floor_divide(self, op1, op2, exp):
        # 断言整数除法的结果与预期相等
        assert_equal(op1 // op2, exp)

    @pytest.mark.skipif(IS_WASM, reason="fp errors don't work in wasm")
    @pytest.mark.parametrize("op1, op2", [
        # 被零除
        (np.timedelta64(10, 'us'),
         np.timedelta64(0, 'us')),
        # 包含 NaT 的除法
        (np.timedelta64('NaT'),
         np.timedelta64(50, 'us')),
        # int64 最小值的特殊情况
        # 在整数除法中
        (np.timedelta64(np.iinfo(np.int64).min),
         np.timedelta64(-1)),
        ])
    def test_timedelta_floor_div_warnings(self, op1, op2):
        # 断言在运行时发出 RuntimeWarning
        with assert_warns(RuntimeWarning):
            actual = op1 // op2
            assert_equal(actual, 0)
            assert_equal(actual.dtype, np.int64)

    @pytest.mark.parametrize("val1, val2", [
        # 无法在整数除法操作中明确划分年份和月份
        (9007199254740993, 1),
        # 压力测试替代整数除法代码路径
        # 操作数符号不匹配且余数不为 0
        (9007199254740999, -2),
        ])
    def test_timedelta_floor_div_precision(self, val1, val2):
        op1 = np.timedelta64(val1)
        op2 = np.timedelta64(val2)
        actual = op1 // op2
        # Python 参考整数向下取整
        expected = val1 // val2
        # 断言结果与预期相等
        assert_equal(actual, expected)

    @pytest.mark.parametrize("val1, val2", [
        # 年份和月份有时无法明确地划分
        # 用于整数向下取整操作
        (np.timedelta64(7, 'Y'),
         np.timedelta64(3, 's')),
        (np.timedelta64(7, 'M'),
         np.timedelta64(1, 'D')),
        ])
    def test_timedelta_floor_div_error(self, val1, val2):
        # 断言抛出 TypeError 异常,包含特定错误信息
        with assert_raises_regex(TypeError, "common metadata divisor"):
            val1 // val2
    @pytest.mark.parametrize("op1, op2", [
        # 使用 pytest.mark.parametrize 装饰器标记测试用例的参数化,op1 和 op2 是测试函数的输入参数
        # 从 floordiv 中重用测试用例
        (np.timedelta64(7, 's'),  # op1 设置为 7 秒的 np.timedelta64 类型
         np.timedelta64(4, 's')),  # op2 设置为 4 秒的 np.timedelta64 类型
        # m8 相同单位向下取整,包含负数
        (np.timedelta64(7, 's'),  # op1 设置为 7 秒的 np.timedelta64 类型
         np.timedelta64(-4, 's')),  # op2 设置为 -4 秒的 np.timedelta64 类型
        # m8 相同单位负数且无向下取整
        (np.timedelta64(8, 's'),  # op1 设置为 8 秒的 np.timedelta64 类型
         np.timedelta64(-4, 's')),  # op2 设置为 -4 秒的 np.timedelta64 类型
        # m8 不同单位
        (np.timedelta64(1, 'm'),  # op1 设置为 1 分钟的 np.timedelta64 类型
         np.timedelta64(31, 's')),  # op2 设置为 31 秒的 np.timedelta64 类型
        # m8 通用单位
        (np.timedelta64(1890),  # op1 设置为 1890 个时间单位的 np.timedelta64 类型
         np.timedelta64(31)),  # op2 设置为 31 个时间单位的 np.timedelta64 类型
        # Y // M 工作
        (np.timedelta64(2, 'Y'),  # op1 设置为 2 年的 np.timedelta64 类型
         np.timedelta64('13', 'M')),  # op2 设置为 '13' 个月的 np.timedelta64 类型
        # 处理 1D 数组
        (np.array([1, 2, 3], dtype='m8'),  # op1 设置为包含 [1, 2, 3] 的 1D 数组,数据类型为 'm8'
         np.array([2], dtype='m8')),  # op2 设置为包含 [2] 的 1D 数组,数据类型为 'm8'
        ])
    # 定义测试函数 test_timedelta_divmod,测试 np.timedelta64 类型的除法和取模操作
    def test_timedelta_divmod(self, op1, op2):
        # 预期结果是 op1 除以 op2 的商和余数
        expected = (op1 // op2, op1 % op2)
        # 使用 assert_equal 断言函数检查实际计算结果是否与预期结果相同
        assert_equal(divmod(op1, op2), expected)

    @pytest.mark.skipif(IS_WASM, reason="does not work in wasm")
    @pytest.mark.parametrize("op1, op2", [
        # 从 floordiv 中重用用例
        # 被零除
        (np.timedelta64(10, 'us'),  # op1 设置为 10 微秒的 np.timedelta64 类型
         np.timedelta64(0, 'us')),  # op2 设置为 0 微秒的 np.timedelta64 类型
        # 用 NaT 除法
        (np.timedelta64('NaT'),  # op1 设置为 NaT (Not a Time) 的 np.timedelta64 类型
         np.timedelta64(50, 'us')),  # op2 设置为 50 微秒的 np.timedelta64 类型
        # 整数 floor division 的 int64 min 的特殊情况
        (np.timedelta64(np.iinfo(np.int64).min),  # op1 设置为 np.int64 类型的最小值的 np.timedelta64 类型
         np.timedelta64(-1)),  # op2 设置为 -1 的 np.timedelta64 类型
        ])
    # 定义测试函数 test_timedelta_divmod_warnings,测试 np.timedelta64 类型的除法和取模操作,包含警告
    def test_timedelta_divmod_warnings(self, op1, op2):
        # 使用 assert_warns 上下文管理器确保警告被触发
        with assert_warns(RuntimeWarning):
            # 预期结果是 op1 除以 op2 的商和余数
            expected = (op1 // op2, op1 % op2)
        with assert_warns(RuntimeWarning):
            # 计算实际的除法和取模操作结果
            actual = divmod(op1, op2)
        # 使用 assert_equal 断言函数检查实际计算结果是否与预期结果相同
        assert_equal(actual, expected)
    # 定义测试方法 test_datetime_divide,使用 self 参数表示当前测试对象
    def test_datetime_divide(self):
        # 使用 for 循环遍历元组列表,每个元组包含多个变量
        for dta, tda, tdb, tdc, tdd in \
                    [
                     # One-dimensional arrays
                     (np.array(['2012-12-21'], dtype='M8[D]'),
                      np.array([6], dtype='m8[h]'),
                      np.array([9], dtype='m8[h]'),
                      np.array([12], dtype='m8[h]'),
                      np.array([6], dtype='m8[m]')),
                     # NumPy scalars
                     (np.datetime64('2012-12-21', '[D]'),
                      np.timedelta64(6, '[h]'),
                      np.timedelta64(9, '[h]'),
                      np.timedelta64(12, '[h]'),
                      np.timedelta64(6, '[m]'))]:
            # 对于每个元组,执行以下操作:

            # m8 / int
            assert_equal(tdc / 2, tda)  # 断言计算结果 tdc / 2 等于 tda
            assert_equal((tdc / 2).dtype, np.dtype('m8[h]'))  # 断言结果的数据类型为 'm8[h]'

            # m8 / float
            assert_equal(tda / 0.5, tdc)  # 断言计算结果 tda / 0.5 等于 tdc
            assert_equal((tda / 0.5).dtype, np.dtype('m8[h]'))  # 断言结果的数据类型为 'm8[h]'

            # m8 / m8
            assert_equal(tda / tdb, 6 / 9)  # 断言计算结果 tda / tdb 等于 6 / 9
            assert_equal(np.divide(tda, tdb), 6 / 9)  # 使用 np.divide 函数做相同断言
            assert_equal(np.true_divide(tda, tdb), 6 / 9)  # 使用 np.true_divide 函数做相同断言
            assert_equal(tdb / tda, 9 / 6)  # 断言计算结果 tdb / tda 等于 9 / 6
            assert_equal((tda / tdb).dtype, np.dtype('f8'))  # 断言结果的数据类型为 'f8'
            assert_equal(tda / tdd, 60)  # 断言计算结果 tda / tdd 等于 60
            assert_equal(tdd / tda, 1 / 60)  # 断言计算结果 tdd / tda 等于 1 / 60

            # int / m8
            assert_raises(TypeError, np.divide, 2, tdb)  # 断言调用 np.divide(2, tdb) 会抛出 TypeError 异常

            # float / m8
            assert_raises(TypeError, np.divide, 0.5, tdb)  # 断言调用 np.divide(0.5, tdb) 会抛出 TypeError 异常

            # m8 / M8
            assert_raises(TypeError, np.divide, dta, tda)  # 断言调用 np.divide(dta, tda) 会抛出 TypeError 异常

            # M8 / m8
            assert_raises(TypeError, np.divide, tda, dta)  # 断言调用 np.divide(tda, dta) 会抛出 TypeError 异常

            # M8 / int
            assert_raises(TypeError, np.divide, dta, 2)  # 断言调用 np.divide(dta, 2) 会抛出 TypeError 异常

            # int / M8
            assert_raises(TypeError, np.divide, 2, dta)  # 断言调用 np.divide(2, dta) 会抛出 TypeError 异常

            # M8 / float
            assert_raises(TypeError, np.divide, dta, 1.5)  # 断言调用 np.divide(dta, 1.5) 会抛出 TypeError 异常

            # float / M8
            assert_raises(TypeError, np.divide, 1.5, dta)  # 断言调用 np.divide(1.5, dta) 会抛出 TypeError 异常

        # NaTs
        with suppress_warnings() as sup:  # 使用 suppress_warnings 上下文管理器
            sup.filter(RuntimeWarning,  r".*encountered in divide")  # 过滤 RuntimeWarning,正则匹配".*encountered in divide"
            nat = np.timedelta64('NaT')  # 创建 NaT(Not-a-Time)时间间隔对象
            for tp in (int, float):  # 遍历 int 和 float 类型
                assert_equal(np.timedelta64(1) / tp(0), nat)  # 断言计算结果 np.timedelta64(1) / tp(0) 等于 nat
                assert_equal(np.timedelta64(0) / tp(0), nat)  # 断言计算结果 np.timedelta64(0) / tp(0) 等于 nat
                assert_equal(nat / tp(0), nat)  # 断言计算结果 nat / tp(0) 等于 nat
                assert_equal(nat / tp(2), nat)  # 断言计算结果 nat / tp(2) 等于 nat

            # Division by inf
            assert_equal(np.timedelta64(1) / float('inf'), np.timedelta64(0))  # 断言计算结果 np.timedelta64(1) / float('inf') 等于 np.timedelta64(0)
            assert_equal(np.timedelta64(0) / float('inf'), np.timedelta64(0))  # 断言计算结果 np.timedelta64(0) / float('inf') 等于 np.timedelta64(0)
            assert_equal(nat / float('inf'), nat)  # 断言计算结果 nat / float('inf') 等于 nat

            # Division by nan
            assert_equal(np.timedelta64(1) / float('nan'), nat)  # 断言计算结果 np.timedelta64(1) / float('nan') 等于 nat
            assert_equal(np.timedelta64(0) / float('nan'), nat)  # 断言计算结果 np.timedelta64(0) / float('nan') 等于 nat
            assert_equal(nat / float('nan'), nat)  # 断言计算结果 nat / float('nan') 等于 nat
    def test_datetime_compare(self):
        # 测试所有比较操作符
        a = np.datetime64('2000-03-12T18:00:00.000000')
        b = np.array(['2000-03-12T18:00:00.000000',
                      '2000-03-12T17:59:59.999999',
                      '2000-03-12T18:00:00.000001',
                      '1970-01-11T12:00:00.909090',
                      '2016-01-11T12:00:00.909090'],
                      dtype='datetime64[us]')
        # 断言a与b中的元素逐个进行相等比较,结果为[1, 0, 0, 0, 0]
        assert_equal(np.equal(a, b), [1, 0, 0, 0, 0])
        # 断言a与b中的元素逐个进行不等比较,结果为[0, 1, 1, 1, 1]
        assert_equal(np.not_equal(a, b), [0, 1, 1, 1, 1])
        # 断言a与b中的元素逐个进行小于比较,结果为[0, 0, 1, 0, 1]
        assert_equal(np.less(a, b), [0, 0, 1, 0, 1])
        # 断言a与b中的元素逐个进行小于等于比较,结果为[1, 0, 1, 0, 1]
        assert_equal(np.less_equal(a, b), [1, 0, 1, 0, 1])
        # 断言a与b中的元素逐个进行大于比较,结果为[0, 1, 0, 1, 0]
        assert_equal(np.greater(a, b), [0, 1, 0, 1, 0])
        # 断言a与b中的元素逐个进行大于等于比较,结果为[1, 1, 0, 1, 0]
        assert_equal(np.greater_equal(a, b), [1, 1, 0, 1, 0])

    def test_datetime_compare_nat(self):
        dt_nat = np.datetime64('NaT', 'D')
        dt_other = np.datetime64('2000-01-01')
        td_nat = np.timedelta64('NaT', 'h')
        td_other = np.timedelta64(1, 'h')

        for op in [np.equal, np.less, np.less_equal,
                   np.greater, np.greater_equal]:
            # 断言NaT与自身以及其他日期时间的比较结果都为假
            assert_(not op(dt_nat, dt_nat))
            assert_(not op(dt_nat, dt_other))
            assert_(not op(dt_other, dt_nat))

            # 断言NaT与自身以及其他时间间隔的比较结果都为假
            assert_(not op(td_nat, td_nat))
            assert_(not op(td_nat, td_other))
            assert_(not op(td_other, td_nat))

        # 断言NaT与自身以及其他日期时间的不等比较结果都为真
        assert_(np.not_equal(dt_nat, dt_nat))
        assert_(np.not_equal(dt_nat, dt_other))
        assert_(np.not_equal(dt_other, dt_nat))

        # 断言NaT与自身以及其他时间间隔的不等比较结果都为真
        assert_(np.not_equal(td_nat, td_nat))
        assert_(np.not_equal(td_nat, td_other))
        assert_(np.not_equal(td_other, td_nat))
    def test_datetime_minmax(self):
        # 测试日期时间的最小值和最大值计算功能

        # 创建具有特定日期时间类型的数组a和b
        a = np.array('1999-03-12T13', dtype='M8[2m]')
        b = np.array('1999-03-12T12', dtype='M8[s]')
        
        # 测试 np.minimum 函数:返回最小值
        assert_equal(np.minimum(a, b), b)
        # 检查返回结果的数据类型是否符合预期
        assert_equal(np.minimum(a, b).dtype, np.dtype('M8[s]'))
        
        # 测试 np.fmin 函数:返回最小值
        assert_equal(np.fmin(a, b), b)
        # 检查返回结果的数据类型是否符合预期
        assert_equal(np.fmin(a, b).dtype, np.dtype('M8[s]'))
        
        # 测试 np.maximum 函数:返回最大值
        assert_equal(np.maximum(a, b), a)
        # 检查返回结果的数据类型是否符合预期
        assert_equal(np.maximum(a, b).dtype, np.dtype('M8[s]'))
        
        # 测试 np.fmax 函数:返回最大值
        assert_equal(np.fmax(a, b), a)
        # 检查返回结果的数据类型是否符合预期
        assert_equal(np.fmax(a, b).dtype, np.dtype('M8[s]'))
        
        # 将数组a和b视为整数进行比较,由于单位不同,结果与上述相反
        assert_equal(np.minimum(a.view('i8'), b.view('i8')), a.view('i8'))

        # 测试与 NaT (Not-a-Time) 的交互
        a = np.array('1999-03-12T13', dtype='M8[2m]')
        dtnat = np.array('NaT', dtype='M8[h]')
        
        # 测试 np.minimum 函数处理 NaT 的情况
        assert_equal(np.minimum(a, dtnat), dtnat)
        assert_equal(np.minimum(dtnat, a), dtnat)
        
        # 测试 np.maximum 函数处理 NaT 的情况
        assert_equal(np.maximum(a, dtnat), dtnat)
        assert_equal(np.maximum(dtnat, a), dtnat)
        
        # 测试 np.fmin 函数处理 NaT 的情况
        assert_equal(np.fmin(dtnat, a), a)
        assert_equal(np.fmin(a, dtnat), a)
        
        # 测试 np.fmax 函数处理 NaT 的情况
        assert_equal(np.fmax(dtnat, a), a)
        assert_equal(np.fmax(a, dtnat), a)

        # 测试 timedelta 的情况
        a = np.array(3, dtype='m8[h]')
        b = np.array(3*3600 - 3, dtype='m8[s]')
        
        # 测试 np.minimum 函数:返回最小值
        assert_equal(np.minimum(a, b), b)
        # 检查返回结果的数据类型是否符合预期
        assert_equal(np.minimum(a, b).dtype, np.dtype('m8[s]'))
        
        # 测试 np.fmin 函数:返回最小值
        assert_equal(np.fmin(a, b), b)
        # 检查返回结果的数据类型是否符合预期
        assert_equal(np.fmin(a, b).dtype, np.dtype('m8[s]'))
        
        # 测试 np.maximum 函数:返回最大值
        assert_equal(np.maximum(a, b), a)
        # 检查返回结果的数据类型是否符合预期
        assert_equal(np.maximum(a, b).dtype, np.dtype('m8[s]'))
        
        # 测试 np.fmax 函数:返回最大值
        assert_equal(np.fmax(a, b), a)
        # 检查返回结果的数据类型是否符合预期
        assert_equal(np.fmax(a, b).dtype, np.dtype('m8[s]'))
        
        # 将数组a和b视为整数进行比较,由于单位不同,结果与上述相反
        assert_equal(np.minimum(a.view('i8'), b.view('i8')), a.view('i8'))

        # 测试 datetime 和 timedelta 之间的比较是否引发 TypeError
        a = np.array(3, dtype='m8[h]')
        b = np.array('1999-03-12T12', dtype='M8[s]')
        assert_raises(TypeError, np.minimum, a, b, casting='same_kind')
        assert_raises(TypeError, np.maximum, a, b, casting='same_kind')
        assert_raises(TypeError, np.fmin, a, b, casting='same_kind')
        assert_raises(TypeError, np.fmax, a, b, casting='same_kind')

    def test_hours(self):
        # 测试操作时间数组的小时属性

        # 创建一个长度为3的全1数组,数据类型为'M8[s]'
        t = np.ones(3, dtype='M8[s]')
        
        # 修改数组第一个元素的时间值为一天零10小时
        t[0] = 60*60*24 + 60*60*10
        
        # 断言:检查数组第一个元素的小时属性是否为10
        assert_(t[0].item().hour == 10)
    # 定义测试函数,用于验证时间类型的单位转换是否正确

    def test_divisor_conversion_year(self):
        # 断言:年份除以4,等同于3个月
        assert_(np.dtype('M8[Y/4]') == np.dtype('M8[3M]'))
        # 断言:年份除以13,等同于4周
        assert_(np.dtype('M8[Y/13]') == np.dtype('M8[4W]'))
        # 断言:3年除以73,等同于15天
        assert_(np.dtype('M8[3Y/73]') == np.dtype('M8[15D]'))

    def test_divisor_conversion_month(self):
        # 断言:月份除以2,等同于2周
        assert_(np.dtype('M8[M/2]') == np.dtype('M8[2W]'))
        # 断言:月份除以15,等同于2天
        assert_(np.dtype('M8[M/15]') == np.dtype('M8[2D]'))
        # 断言:3个月除以40,等同于54小时
        assert_(np.dtype('M8[3M/40]') == np.dtype('M8[54h]'))

    def test_divisor_conversion_week(self):
        # 断言:周数除以7,等同于1天
        assert_(np.dtype('m8[W/7]') == np.dtype('m8[D]'))
        # 断言:3周除以14,等同于36小时
        assert_(np.dtype('m8[3W/14]') == np.dtype('m8[36h]'))
        # 断言:5周除以140,等同于360分钟
        assert_(np.dtype('m8[5W/140]') == np.dtype('m8[360m]'))

    def test_divisor_conversion_day(self):
        # 断言:天数除以12,等同于2小时
        assert_(np.dtype('M8[D/12]') == np.dtype('M8[2h]'))
        # 断言:天数除以120,等同于12分钟
        assert_(np.dtype('M8[D/120]') == np.dtype('M8[12m]'))
        # 断言:3天除以960,等同于270秒
        assert_(np.dtype('M8[3D/960]') == np.dtype('M8[270s]'))

    def test_divisor_conversion_hour(self):
        # 断言:小时除以30,等同于2分钟
        assert_(np.dtype('m8[h/30]') == np.dtype('m8[2m]'))
        # 断言:3小时除以300,等同于36秒
        assert_(np.dtype('m8[3h/300]') == np.dtype('m8[36s]'))

    def test_divisor_conversion_minute(self):
        # 断言:分钟除以30,等同于2秒
        assert_(np.dtype('m8[m/30]') == np.dtype('m8[2s]'))
        # 断言:3分钟除以300,等同于600毫秒
        assert_(np.dtype('m8[3m/300]') == np.dtype('m8[600ms]'))

    def test_divisor_conversion_second(self):
        # 断言:秒数除以100,等同于10毫秒
        assert_(np.dtype('m8[s/100]') == np.dtype('m8[10ms]'))
        # 断言:3秒除以10000,等同于300微秒
        assert_(np.dtype('m8[3s/10000]') == np.dtype('m8[300us]'))

    def test_divisor_conversion_fs(self):
        # 断言:飞秒除以100,等同于10阿托秒
        assert_(np.dtype('M8[fs/100]') == np.dtype('M8[10as]'))
        # 断言:3飞秒除以10000,引发值错误异常,不支持超过10阿托秒的转换
        assert_raises(ValueError, lambda: np.dtype('M8[3fs/10000]'))

    def test_divisor_conversion_as(self):
        # 断言:阿托秒除以10,引发值错误异常,不支持阿托秒的单位转换
        assert_raises(ValueError, lambda: np.dtype('M8[as/10]'))
    def test_string_parser_variants(self):
        msg = "no explicit representation of timezones available for " \
              "np.datetime64"
        # 空格允许在日期和时间之间代替'T'
        assert_equal(np.array(['1980-02-29T01:02:03'], np.dtype('M8[s]')),
                     np.array(['1980-02-29 01:02:03'], np.dtype('M8[s]')))
        # 允许正年份
        assert_equal(np.array(['+1980-02-29T01:02:03'], np.dtype('M8[s]')),
                     np.array(['+1980-02-29 01:02:03'], np.dtype('M8[s]')))
        # 允许负年份
        assert_equal(np.array(['-1980-02-29T01:02:03'], np.dtype('M8[s]')),
                     np.array(['-1980-02-29 01:02:03'], np.dtype('M8[s]')))
        # UTC 指定符
        with pytest.warns(UserWarning, match=msg):
            assert_equal(
                np.array(['+1980-02-29T01:02:03'], np.dtype('M8[s]')),
                np.array(['+1980-02-29 01:02:03Z'], np.dtype('M8[s]')))
        with pytest.warns(UserWarning, match=msg):
            assert_equal(
                np.array(['-1980-02-29T01:02:03'], np.dtype('M8[s]')),
                np.array(['-1980-02-29 01:02:03Z'], np.dtype('M8[s]')))
        # 时间偏移
        with pytest.warns(UserWarning, match=msg):
            assert_equal(
                np.array(['1980-02-29T02:02:03'], np.dtype('M8[s]')),
                np.array(['1980-02-29 00:32:03-0130'], np.dtype('M8[s]')))
        with pytest.warns(UserWarning, match=msg):
            assert_equal(
                np.array(['1980-02-28T22:32:03'], np.dtype('M8[s]')),
                np.array(['1980-02-29 00:02:03+01:30'], np.dtype('M8[s]')))
        with pytest.warns(UserWarning, match=msg):
            assert_equal(
                np.array(['1980-02-29T02:32:03.506'], np.dtype('M8[s]')),
                np.array(['1980-02-29 00:32:03.506-02'], np.dtype('M8[s]')))
        with pytest.warns(UserWarning, match=msg):
            assert_equal(np.datetime64('1977-03-02T12:30-0230'),
                         np.datetime64('1977-03-02T15:00'))

    def test_creation_overflow(self):
        date = '1980-03-23 20:00:00'
        # 将日期转换为秒级别的时间戳
        timesteps = np.array([date], dtype='datetime64[s]')[0].astype(np.int64)
        for unit in ['ms', 'us', 'ns']:
            timesteps *= 1000
            # 使用不同精度单位创建日期时间对象
            x = np.array([date], dtype='datetime64[%s]' % unit)

            assert_equal(timesteps, x[0].astype(np.int64),
                         err_msg='Datetime conversion error for unit %s' % unit)

        assert_equal(x[0].astype(np.int64), 322689600000000000)

        # gh-13062
        # 检查溢出错误
        with pytest.raises(OverflowError):
            np.datetime64(2**64, 'D')
        with pytest.raises(OverflowError):
            np.timedelta64(2**64, 'D')

    @pytest.mark.skipif(not _has_pytz, reason="The pytz module is not available.")
    def test_datetime_as_string_timezone(self):
        # 测试函数:test_datetime_as_string_timezone,用于测试 np.datetime_as_string 方法的时区功能

        # 创建 numpy datetime 对象 a 和 b
        a = np.datetime64('2010-03-15T06:30', 'm')
        
        # 断言:将 np.datetime_as_string 应用于 a,不带时区信息,结果应为 '2010-03-15T06:30'
        assert_equal(np.datetime_as_string(a),
                    '2010-03-15T06:30')
        
        # 断言:将 np.datetime_as_string 应用于 a,使用 'naive' 时区参数,结果应为 '2010-03-15T06:30'
        assert_equal(np.datetime_as_string(a, timezone='naive'),
                    '2010-03-15T06:30')
        
        # 断言:将 np.datetime_as_string 应用于 a,使用 'UTC' 时区参数,结果应为 '2010-03-15T06:30Z'
        assert_equal(np.datetime_as_string(a, timezone='UTC'),
                    '2010-03-15T06:30Z')
        
        # 断言:将 np.datetime_as_string 应用于 a,使用 'local' 时区参数,结果应不等于 '2010-03-15T06:30'
        assert_(np.datetime_as_string(a, timezone='local') !=
                '2010-03-15T06:30')

        # 创建 numpy datetime 对象 b
        b = np.datetime64('2010-02-15T06:30', 'm')
        
        # 断言:将 np.datetime_as_string 应用于 a,使用 'US/Central' 时区,结果应为 '2010-03-15T01:30-0500'
        assert_equal(np.datetime_as_string(a, timezone=tz('US/Central')),
                     '2010-03-15T01:30-0500')
        
        # 断言:将 np.datetime_as_string 应用于 a,使用 'US/Eastern' 时区,结果应为 '2010-03-15T02:30-0400'
        assert_equal(np.datetime_as_string(a, timezone=tz('US/Eastern')),
                     '2010-03-15T02:30-0400')
        
        # 断言:将 np.datetime_as_string 应用于 a,使用 'US/Pacific' 时区,结果应为 '2010-03-14T23:30-0700'
        assert_equal(np.datetime_as_string(a, timezone=tz('US/Pacific')),
                     '2010-03-14T23:30-0700')

        # 断言:将 np.datetime_as_string 应用于 b,使用 'US/Central' 时区,结果应为 '2010-02-15T00:30-0600'
        assert_equal(np.datetime_as_string(b, timezone=tz('US/Central')),
                     '2010-02-15T00:30-0600')
        
        # 断言:将 np.datetime_as_string 应用于 b,使用 'US/Eastern' 时区,结果应为 '2010-02-15T01:30-0500'
        assert_equal(np.datetime_as_string(b, timezone=tz('US/Eastern')),
                     '2010-02-15T01:30-0500')
        
        # 断言:将 np.datetime_as_string 应用于 b,使用 'US/Pacific' 时区,结果应为 '2010-02-14T22:30-0800'
        assert_equal(np.datetime_as_string(b, timezone=tz('US/Pacific')),
                     '2010-02-14T22:30-0800')

        # 断言:当尝试将日期转换为带时区的字符串时,默认情况下会引发 TypeError 异常
        assert_raises(TypeError, np.datetime_as_string, a, unit='D',
                      timezone=tz('US/Pacific'))
        
        # 断言:使用 'unit' 参数为 'D',将日期以 'US/Pacific' 时区的格式打印,使用 'casting' 参数为 'unsafe'
        assert_equal(np.datetime_as_string(a, unit='D',
                      timezone=tz('US/Pacific'), casting='unsafe'),
                     '2010-03-14')
        
        # 断言:使用 'unit' 参数为 'D',将日期以 'US/Central' 时区的格式打印,使用 'casting' 参数为 'unsafe'
        assert_equal(np.datetime_as_string(b, unit='D',
                      timezone=tz('US/Central'), casting='unsafe'),
                     '2010-02-15')
    def test_datetime_arange(self):
        # 使用字符串指定的两个日期范围创建日期数组
        a = np.arange('2010-01-05', '2010-01-10', dtype='M8[D]')
        assert_equal(a.dtype, np.dtype('M8[D]'))
        assert_equal(a,
            np.array(['2010-01-05', '2010-01-06', '2010-01-07',
                      '2010-01-08', '2010-01-09'], dtype='M8[D]'))

        # 使用倒序创建日期数组,指定步长为-1
        a = np.arange('1950-02-10', '1950-02-06', -1, dtype='M8[D]')
        assert_equal(a.dtype, np.dtype('M8[D]'))
        assert_equal(a,
            np.array(['1950-02-10', '1950-02-09', '1950-02-08',
                      '1950-02-07'], dtype='M8[D]'))

        # 在月份单位下创建日期数组,步长为2
        a = np.arange('1969-05', '1970-05', 2, dtype='M8')
        assert_equal(a.dtype, np.dtype('M8[M]'))
        assert_equal(a,
            np.datetime64('1969-05') + np.arange(12, step=2))

        # 使用年份单位创建日期数组,步长为3
        a = np.arange('1969', 18, 3, dtype='M8')
        assert_equal(a.dtype, np.dtype('M8[Y]'))
        assert_equal(a,
            np.datetime64('1969') + np.arange(18, step=3))

        # 使用时间增量创建日期数组,步长为2天
        a = np.arange('1969-12-19', 22, np.timedelta64(2), dtype='M8')
        assert_equal(a.dtype, np.dtype('M8[D]'))
        assert_equal(a,
            np.datetime64('1969-12-19') + np.arange(22, step=2))

        # 步长为0是不允许的,应引发 ValueError 异常
        assert_raises(ValueError, np.arange, np.datetime64('today'),
                                np.datetime64('today') + 3, 0)
        # 跨越非线性单位边界的提升是不允许的,应引发 TypeError 异常
        assert_raises(TypeError, np.arange, np.datetime64('2011-03-01', 'D'),
                                np.timedelta64(5, 'M'))
        assert_raises(TypeError, np.arange,
                                np.datetime64('2012-02-03T14', 's'),
                                np.timedelta64(5, 'Y'))

    def test_datetime_arange_no_dtype(self):
        # 使用单个日期创建日期数组,并检查抛出 ValueError 异常
        d = np.array('2010-01-04', dtype="M8[D]")
        assert_equal(np.arange(d, d + 1), d)
        assert_raises(ValueError, np.arange, d)

    def test_timedelta_arange(self):
        # 创建时间增量数组,从3到10
        a = np.arange(3, 10, dtype='m8')
        assert_equal(a.dtype, np.dtype('m8'))
        assert_equal(a, np.timedelta64(0) + np.arange(3, 10))

        # 使用时间增量作为起始值,步长为2秒
        a = np.arange(np.timedelta64(3, 's'), 10, 2, dtype='m8')
        assert_equal(a.dtype, np.dtype('m8[s]'))
        assert_equal(a, np.timedelta64(0, 's') + np.arange(3, 10, 2))

        # 步长为0是不允许的,应引发 ValueError 异常
        assert_raises(ValueError, np.arange, np.timedelta64(0),
                                np.timedelta64(5), 0)
        # 跨越非线性单位边界的提升是不允许的,应引发 TypeError 异常
        assert_raises(TypeError, np.arange, np.timedelta64(0, 'D'),
                                np.timedelta64(5, 'M'))
        assert_raises(TypeError, np.arange, np.timedelta64(0, 'Y'),
                                np.timedelta64(5, 'D'))
    @pytest.mark.parametrize("val1, val2, expected", [
        # case from gh-12092
        # 定义测试参数:val1, val2 和期望的结果 expected,用于测试时间差的取模运算

        (np.timedelta64(7, 's'),     # 第一个测试用例:7 秒
         np.timedelta64(3, 's'),     # 第二个测试用例:3 秒
         np.timedelta64(1, 's')),    # 期望的结果:1 秒

        # negative value cases
        # 负值情况的测试

        (np.timedelta64(3, 's'),     # 3 秒
         np.timedelta64(-2, 's'),    # -2 秒
         np.timedelta64(-1, 's')),   # 期望的结果:-1 秒

        (np.timedelta64(-3, 's'),    # -3 秒
         np.timedelta64(2, 's'),     # 2 秒
         np.timedelta64(1, 's')),    # 期望的结果:1 秒

        # larger value cases
        # 较大值的测试

        (np.timedelta64(17, 's'),    # 17 秒
         np.timedelta64(22, 's'),    # 22 秒
         np.timedelta64(17, 's')),   # 期望的结果:17 秒

        (np.timedelta64(22, 's'),    # 22 秒
         np.timedelta64(17, 's'),    # 17 秒
         np.timedelta64(5, 's')),    # 期望的结果:5 秒

        # different units
        # 不同单位的测试

        (np.timedelta64(1, 'm'),     # 1 分钟
         np.timedelta64(57, 's'),    # 57 秒
         np.timedelta64(3, 's')),    # 期望的结果:3 秒

        (np.timedelta64(1, 'us'),    # 1 微秒
         np.timedelta64(727, 'ns'),  # 727 纳秒
         np.timedelta64(273, 'ns')), # 期望的结果:273 纳秒

        # NaT is propagated
        # NaT 值传播测试

        (np.timedelta64('NaT'),      # NaT (Not a Time)
         np.timedelta64(50, 'ns'),   # 50 纳秒
         np.timedelta64('NaT')),     # 期望的结果:NaT

        # Y % M works
        # 年份 % 月份 的测试

        (np.timedelta64(2, 'Y'),     # 2 年
         np.timedelta64(22, 'M'),    # 22 个月
         np.timedelta64(2, 'M')),    # 期望的结果:2 个月
    ])
    def test_timedelta_modulus(self, val1, val2, expected):
        # 断言:val1 % val2 的结果应为 expected
        assert_equal(val1 % val2, expected)

    @pytest.mark.parametrize("val1, val2", [
        # years and months sometimes can't be unambiguously
        # divided for modulus operation
        # 年份和月份有时无法明确地进行取模操作

        (np.timedelta64(7, 'Y'),     # 7 年
         np.timedelta64(3, 's')),    # 3 秒

        (np.timedelta64(7, 'M'),     # 7 个月
         np.timedelta64(1, 'D')),    # 1 天
    ])
    def test_timedelta_modulus_error(self, val1, val2):
        # 使用断言验证 TypeError 异常,错误消息包含 "common metadata divisor"
        with assert_raises_regex(TypeError, "common metadata divisor"):
            val1 % val2

    @pytest.mark.skipif(IS_WASM, reason="fp errors don't work in wasm")
    def test_timedelta_modulus_div_by_zero(self):
        # 如果在 WASM 环境下,则跳过测试:浮点错误在 WASM 中不起作用
        with assert_warns(RuntimeWarning):
            # 执行取模运算,验证结果为 NaT (Not a Time)
            actual = np.timedelta64(10, 's') % np.timedelta64(0, 's')
            assert_equal(actual, np.timedelta64('NaT'))

    @pytest.mark.parametrize("val1, val2", [
        # cases where one operand is not
        # timedelta64
        # 其中一个操作数不是 timedelta64 的情况

        (np.timedelta64(7, 'Y'),     # 7 年
         15,),                       # 整数 15

        (7.5,                         # 浮点数 7.5
         np.timedelta64(1, 'D')),    # 1 天
    ])
    def test_timedelta_modulus_type_resolution(self, val1, val2):
        # 注意:将来可能会支持一些操作
        # 使用断言验证 TypeError 异常,错误消息包含 "'remainder' cannot use operands with types"
        with assert_raises_regex(TypeError,
                                 "'remainder' cannot use operands with types"):
            val1 % val2

    def test_timedelta_arange_no_dtype(self):
        # 创建一个包含单个元素 5 的 numpy 数组,数据类型为 "m8[D]"
        d = np.array(5, dtype="m8[D]")
        # 断言:np.arange(d, d + 1) 应该等于 d
        assert_equal(np.arange(d, d + 1), d)
        # 断言:np.arange(d) 应该等于 np.arange(0, d)
        assert_equal(np.arange(d), np.arange(0, d))
    # 定义一个测试函数,用于验证 np.maximum.reduce 的功能
    def test_datetime_maximum_reduce(self):
        # 创建一个包含日期的 NumPy 数组,以 'M8[D]' 类型存储
        a = np.array(['2010-01-02', '1999-03-14', '1833-03'], dtype='M8[D]')
        # 断言 np.maximum.reduce 的结果数据类型应为 'M8[D]'
        assert_equal(np.maximum.reduce(a).dtype, np.dtype('M8[D]'))
        # 断言 np.maximum.reduce 的结果应为 '2010-01-02' 对应的 np.datetime64 对象
        assert_equal(np.maximum.reduce(a),
                     np.datetime64('2010-01-02'))

        # 创建一个包含时间间隔的 NumPy 数组,以 'm8[s]' 类型存储
        a = np.array([1, 4, 0, 7, 2], dtype='m8[s]')
        # 断言 np.maximum.reduce 的结果数据类型应为 'm8[s]'
        assert_equal(np.maximum.reduce(a).dtype, np.dtype('m8[s]'))
        # 断言 np.maximum.reduce 的结果应为 7 秒对应的 np.timedelta64 对象
        assert_equal(np.maximum.reduce(a),
                     np.timedelta64(7, 's'))

    # 定义一个测试函数,用于验证 np.mean 方法在 timedelta 类型上的正确性
    def test_timedelta_correct_mean(self):
        # 创建一个包含 timedelta 类型数据的 NumPy 数组
        a = np.arange(1000, dtype="m8[s]")
        # 断言数组的平均值等于总和除以数组长度,验证 np.mean 在 timedelta 类型上的表现
        assert_array_equal(a.mean(), a.sum() / len(a))

    # 定义一个测试函数,用于验证不能对 datetime64 类型数据使用 reduce 相关方法的行为
    def test_datetime_no_subtract_reducelike(self):
        # 创建一个包含 datetime64 类型数据的 NumPy 数组
        arr = np.array(["2021-12-02", "2019-05-12"], dtype="M8[ms]")
        # 设置匹配的错误消息
        msg = r"the resolved dtypes are not compatible"

        # 使用 pytest 来断言 np.subtract.reduce 在 datetime64 类型数组上会引发 TypeError 异常
        with pytest.raises(TypeError, match=msg):
            np.subtract.reduce(arr)

        # 使用 pytest 来断言 np.subtract.accumulate 在 datetime64 类型数组上会引发 TypeError 异常
        with pytest.raises(TypeError, match=msg):
            np.subtract.accumulate(arr)

        # 使用 pytest 来断言 np.subtract.reduceat 在 datetime64 类型数组上会引发 TypeError 异常
        with pytest.raises(TypeError, match=msg):
            np.subtract.reduceat(arr, [0])
    def test_datetime_busdaycalendar(self):
        # 检查去除 NaT(Not a Time)、重复日期和周末,并确保结果排序正确。
        bdd = np.busdaycalendar(
            holidays=['NaT', '2011-01-17', '2011-03-06', 'NaT',
                       '2011-12-26', '2011-05-30', '2011-01-17'])
        # 断言节假日数组与预期结果相符
        assert_equal(bdd.holidays,
            np.array(['2011-01-17', '2011-05-30', '2011-12-26'], dtype='M8'))
        # 默认的工作日掩码为星期一到星期五
        assert_equal(bdd.weekmask, np.array([1, 1, 1, 1, 1, 0, 0], dtype='?'))

        # 检查包含不同空白符的字符串工作日掩码
        bdd = np.busdaycalendar(weekmask="Sun TueWed  Thu\tFri")
        # 断言工作日掩码与预期结果相符
        assert_equal(bdd.weekmask, np.array([0, 1, 1, 1, 1, 0, 1], dtype='?'))

        # 检查长度为7的0/1字符串工作日掩码
        bdd = np.busdaycalendar(weekmask="0011001")
        # 断言工作日掩码与预期结果相符
        assert_equal(bdd.weekmask, np.array([0, 0, 1, 1, 0, 0, 1], dtype='?'))

        # 检查长度为7的字符串工作日掩码
        bdd = np.busdaycalendar(weekmask="Mon Tue")
        # 断言工作日掩码与预期结果相符
        assert_equal(bdd.weekmask, np.array([1, 1, 0, 0, 0, 0, 0], dtype='?'))

        # 全零工作日掩码应该引发 ValueError
        assert_raises(ValueError, np.busdaycalendar, weekmask=[0, 0, 0, 0, 0, 0, 0])
        # 工作日名称必须正确大小写
        assert_raises(ValueError, np.busdaycalendar, weekmask="satsun")
        # 全空字符串工作日掩码应该引发 ValueError
        assert_raises(ValueError, np.busdaycalendar, weekmask="")
        # 无效的工作日名称代码应该引发 ValueError
        assert_raises(ValueError, np.busdaycalendar, weekmask="Mon Tue We")
        assert_raises(ValueError, np.busdaycalendar, weekmask="Max")
        assert_raises(ValueError, np.busdaycalendar, weekmask="Monday Tue")
    # 定义测试函数,用于测试 np.busday_count 的不同用例
    def test_datetime_busday_holidays_count(self):
        # 定义节假日列表
        holidays = ['2011-01-01', '2011-10-10', '2011-11-11', '2011-11-24',
                    '2011-12-25', '2011-05-30', '2011-02-21', '2011-01-17',
                    '2011-12-26', '2012-01-02', '2011-02-21', '2011-05-30',
                    '2011-07-01', '2011-07-04', '2011-09-05', '2011-10-10']
        
        # 创建一个工作日日历对象,使用指定的工作日掩码和节假日列表
        bdd = np.busdaycalendar(weekmask='1111100', holidays=holidays)

        # 使用 np.busday_offset 生成日期序列,检验 np.busday_count 的正确性
        dates = np.busday_offset('2011-01-01', np.arange(366),
                        roll='forward', busdaycal=bdd)
        # 断言 np.busday_count 返回的结果与预期的一致
        assert_equal(np.busday_count('2011-01-01', dates, busdaycal=bdd),
                     np.arange(366))
        
        # 当日期反向时,np.busday_count 返回负值
        assert_equal(np.busday_count(dates, '2011-01-01', busdaycal=bdd),
                     -np.arange(366) - 1)

        # 2011-12-31 是星期六,使用 np.busday_offset 生成日期序列
        dates = np.busday_offset('2011-12-31', -np.arange(366),
                        roll='forward', busdaycal=bdd)
        
        # 检验 np.busday_count 的结果是否正确
        expected = np.arange(366)
        expected[0] = -1
        assert_equal(np.busday_count(dates, '2011-12-31', busdaycal=bdd),
                     expected)
        
        # 当日期反向时,np.busday_count 返回负值
        expected = -np.arange(366) + 1
        expected[0] = 0
        assert_equal(np.busday_count('2011-12-31', dates, busdaycal=bdd),
                     expected)

        # 当同时提供了 weekmask/holidays 和 busdaycal 时,应当引发 ValueError 异常
        assert_raises(ValueError, np.busday_offset, '2012-01-03', '2012-02-03',
                        weekmask='1111100', busdaycal=bdd)
        assert_raises(ValueError, np.busday_offset, '2012-01-03', '2012-02-03',
                        holidays=holidays, busdaycal=bdd)

        # 检验 2011 年 3 月的星期一数量
        assert_equal(np.busday_count('2011-03', '2011-04', weekmask='Mon'), 4)
        
        # 当日期反向时,np.busday_count 返回负值
        assert_equal(np.busday_count('2011-04', '2011-03', weekmask='Mon'), -4)

        # 使用 np.datetime64 定义日期对象
        sunday = np.datetime64('2023-03-05')
        monday = sunday + 1
        friday = sunday + 5
        saturday = sunday + 6
        
        # 检验 np.busday_count 对不同日期的计算结果
        assert_equal(np.busday_count(sunday, monday), 0)
        assert_equal(np.busday_count(monday, sunday), -1)

        assert_equal(np.busday_count(friday, saturday), 1)
        assert_equal(np.busday_count(saturday, friday), 0)
    # 测试 datetime 模块中的 is_busday 函数
    def test_datetime_is_busday(self):
        # 定义一组节假日列表
        holidays = ['2011-01-01', '2011-10-10', '2011-11-11', '2011-11-24',
                    '2011-12-25', '2011-05-30', '2011-02-21', '2011-01-17',
                    '2011-12-26', '2012-01-02', '2011-02-21', '2011-05-30',
                    '2011-07-01', '2011-07-04', '2011-09-05', '2011-10-10',
                    'NaT']
        
        # 使用 numpy 的 busdaycalendar 函数创建一个自定义工作日历对象
        bdd = np.busdaycalendar(weekmask='1111100', holidays=holidays)

        # 测试周末和工作日的情况
        assert_equal(np.is_busday('2011-01-01'), False)  # 断言:2011-01-01 不是工作日
        assert_equal(np.is_busday('2011-01-02'), False)  # 断言:2011-01-02 不是工作日
        assert_equal(np.is_busday('2011-01-03'), True)   # 断言:2011-01-03 是工作日

        # 断言:所有节假日都不是工作日
        assert_equal(np.is_busday(holidays, busdaycal=bdd),
                     np.zeros(len(holidays), dtype='?'))

    # 测试 datetime 模块中的 datetime64 类对 Y2038 问题的处理
    def test_datetime_y2038(self):
        msg = "no explicit representation of timezones available for " \
              "np.datetime64"
        
        # 测试 Y2038 问题边界的解析
        a = np.datetime64('2038-01-19T03:14:07')
        assert_equal(a.view(np.int64), 2**31 - 1)  # 断言:a 的 int64 视图等于 2^31 - 1
        
        a = np.datetime64('2038-01-19T03:14:08')
        assert_equal(a.view(np.int64), 2**31)       # 断言:a 的 int64 视图等于 2^31
        
        # 测试 Y2038 问题边界的解析,带有手动指定的时区偏移
        with pytest.warns(UserWarning, match=msg):
            a = np.datetime64('2038-01-19T04:14:07+0100')
            assert_equal(a.view(np.int64), 2**31 - 1)  # 断言:a 的 int64 视图等于 2^31 - 1
        
        with pytest.warns(UserWarning, match=msg):
            a = np.datetime64('2038-01-19T04:14:08+0100')
            assert_equal(a.view(np.int64), 2**31)       # 断言:a 的 int64 视图等于 2^31
        
        # 测试解析 Y2038 后的日期
        a = np.datetime64('2038-01-20T13:21:14')
        assert_equal(str(a), '2038-01-20T13:21:14')   # 断言:a 转换为字符串后与指定的字符串相等

    # 测试 datetime 模块中的 isnat 函数
    def test_isnat(self):
        assert_(np.isnat(np.datetime64('NaT', 'ms')))  # 断言:NaT 表示的日期时间是 NaT(非有效日期时间)
        assert_(np.isnat(np.datetime64('NaT', 'ns')))  # 断言:NaT 表示的日期时间是 NaT(非有效日期时间)
        assert_(not np.isnat(np.datetime64('2038-01-19T03:14:07')))  # 断言:指定的日期时间不是 NaT

        assert_(np.isnat(np.timedelta64('NaT', "ms")))  # 断言:NaT 表示的时间间隔是 NaT(非有效时间间隔)
        assert_(not np.isnat(np.timedelta64(34, "ms")))  # 断言:指定的时间间隔不是 NaT

        res = np.array([False, False, True])
        for unit in ['Y', 'M', 'W', 'D',
                     'h', 'm', 's', 'ms', 'us',
                     'ns', 'ps', 'fs', 'as']:
            arr = np.array([123, -321, "NaT"], dtype='<datetime64[%s]' % unit)
            assert_equal(np.isnat(arr), res)  # 断言:arr 中的日期时间是否为 NaT
            arr = np.array([123, -321, "NaT"], dtype='>datetime64[%s]' % unit)
            assert_equal(np.isnat(arr), res)  # 断言:arr 中的日期时间是否为 NaT
            arr = np.array([123, -321, "NaT"], dtype='<timedelta64[%s]' % unit)
            assert_equal(np.isnat(arr), res)  # 断言:arr 中的时间间隔是否为 NaT
            arr = np.array([123, -321, "NaT"], dtype='>timedelta64[%s]' % unit)
            assert_equal(np.isnat(arr), res)  # 断言:arr 中的时间间隔是否为 NaT
    def test_isnat_error(self):
        # 检查只有 datetime 数据类型的数组被接受
        for t in np.typecodes["All"]:
            if t in np.typecodes["Datetime"]:
                continue
            # 断言应该引发 TypeError 异常,因为只有 datetime 类型的数组能被接受
            assert_raises(TypeError, np.isnat, np.zeros(10, t))

    def test_isfinite_scalar(self):
        # 检查 np.isfinite 对标量的操作
        assert_(not np.isfinite(np.datetime64('NaT', 'ms')))
        assert_(not np.isfinite(np.datetime64('NaT', 'ns')))
        assert_(np.isfinite(np.datetime64('2038-01-19T03:14:07')))

        assert_(not np.isfinite(np.timedelta64('NaT', "ms")))
        assert_(np.isfinite(np.timedelta64(34, "ms")))

    @pytest.mark.parametrize('unit', ['Y', 'M', 'W', 'D', 'h', 'm', 's', 'ms',
                                      'us', 'ns', 'ps', 'fs', 'as'])
    @pytest.mark.parametrize('dstr', ['<datetime64[%s]', '>datetime64[%s]',
                                      '<timedelta64[%s]', '>timedelta64[%s]'])
    def test_isfinite_isinf_isnan_units(self, unit, dstr):
        '''
        检查 <M, >M, <m, >m 数据类型的所有单位的 isfinite, isinf, isnan
        '''
        arr_val = [123, -321, "NaT"]
        arr = np.array(arr_val,  dtype= dstr % unit)
        pos = np.array([True, True,  False])
        neg = np.array([False, False,  True])
        false = np.array([False, False,  False])
        assert_equal(np.isfinite(arr), pos)
        assert_equal(np.isinf(arr), false)
        assert_equal(np.isnan(arr), neg)

    def test_assert_equal(self):
        # 断言应该引发 AssertionError,因为 np.datetime64('nat') 和 np.timedelta64('nat') 不相等
        assert_raises(AssertionError, assert_equal,
                np.datetime64('nat'), np.timedelta64('nat'))

    def test_corecursive_input(self):
        # 构造一个共递归列表
        a, b = [], []
        a.append(b)
        b.append(a)
        obj_arr = np.array([None])
        obj_arr[0] = a

        # 在某些情况下会导致堆栈溢出 (gh-11154)。现在会引发 ValueError,因为嵌套列表无法转换为 datetime。
        assert_raises(ValueError, obj_arr.astype, 'M8')
        assert_raises(ValueError, obj_arr.astype, 'm8')

    @pytest.mark.parametrize("shape", [(), (1,)])
    def test_discovery_from_object_array(self, shape):
        arr = np.array("2020-10-10", dtype=object).reshape(shape)
        res = np.array("2020-10-10", dtype="M8").reshape(shape)
        assert res.dtype == np.dtype("M8[D]")
        assert_equal(arr.astype("M8"), res)
        arr[...] = np.bytes_("2020-10-10")  # 尝试使用 numpy 字符串类型
        assert_equal(arr.astype("M8"), res)
        arr = arr.astype("S")
        assert_equal(arr.astype("S").astype("M8"), res)

    @pytest.mark.parametrize("time_unit", [
        "Y", "M", "W", "D", "h", "m", "s", "ms", "us", "ns", "ps", "fs", "as",
        # 复合单位
        "10D", "2M",
    ])
    def test_limit_symmetry(self, time_unit):
        """
        Dates should have symmetric limits around the unix epoch at +/-np.int64
        """
        # 创建一个表示 Unix 纪元的 numpy datetime 对象
        epoch = np.datetime64(0, time_unit)
        # 创建一个表示 np.int64 的最大值的 numpy datetime 对象
        latest = np.datetime64(np.iinfo(np.int64).max, time_unit)
        # 创建一个表示 np.int64 的最小值的 numpy datetime 对象
        earliest = np.datetime64(-np.iinfo(np.int64).max, time_unit)

        # 断言确保最早日期小于纪元日期小于最晚日期
        assert earliest < epoch < latest

    @pytest.mark.parametrize("time_unit", [
        "Y", "M",
        # 对于 "W" 时间单位,标记为预期失败,因为类似于 gh-13197
        pytest.param("W", marks=pytest.mark.xfail(reason="gh-13197")),
        "D", "h", "m",
        "s", "ms", "us", "ns", "ps", "fs", "as",
        # 对于 "10D" 时间单位,标记为预期失败,类似于 gh-13197
        pytest.param("10D", marks=pytest.mark.xfail(reason="similar to gh-13197")),
    ])
    @pytest.mark.parametrize("sign", [-1, 1])
    def test_limit_str_roundtrip(self, time_unit, sign):
        """
        Limits should roundtrip when converted to strings.

        This tests the conversion to and from npy_datetimestruct.
        """
        # TODO: add absolute (gold standard) time span limit strings
        # 根据时间单位和符号创建一个限制日期的 numpy datetime 对象
        limit = np.datetime64(np.iinfo(np.int64).max * sign, time_unit)

        # 将日期转换为字符串然后再转换回来。由于天数和周数的表示方式不可区分,需要显式指定时间单位。
        limit_via_str = np.datetime64(str(limit), time_unit)
        # 断言转换后的日期与原始日期相等
        assert limit_via_str == limit
class TestDateTimeData:

    def test_basic(self):
        # 创建一个包含单个日期字符串的 numpy 数组,指定日期时间类型为 np.datetime64
        a = np.array(['1980-03-23'], dtype=np.datetime64)
        # 断言 np.datetime_data 函数返回的日期时间数据元组
        assert_equal(np.datetime_data(a.dtype), ('D', 1))

    def test_bytes(self):
        # 以字节单位创建 numpy datetime64 对象,并转换为 Unicode
        dt = np.datetime64('2000', (b'ms', 5))
        # 断言 np.datetime_data 函数返回的日期时间数据元组
        assert np.datetime_data(dt.dtype) == ('ms', 5)

        # 再次以字节单位创建 numpy datetime64 对象,字节单位被解释为时间单位
        dt = np.datetime64('2000', b'5ms')
        # 断言 np.datetime_data 函数返回的日期时间数据元组
        assert np.datetime_data(dt.dtype) == ('ms', 5)

    def test_non_ascii(self):
        # 使用带有非 ASCII 字符的单位字符串创建 numpy datetime64 对象,规范化为 Unicode
        dt = np.datetime64('2000', ('μs', 5))
        # 断言 np.datetime_data 函数返回的日期时间数据元组
        assert np.datetime_data(dt.dtype) == ('us', 5)

        # 再次使用带有非 ASCII 字符的单位字符串创建 numpy datetime64 对象,规范化为 Unicode
        dt = np.datetime64('2000', '5μs')
        # 断言 np.datetime_data 函数返回的日期时间数据元组
        assert np.datetime_data(dt.dtype) == ('us', 5)


def test_comparisons_return_not_implemented():
    # GH#17017

    class custom:
        __array_priority__ = 10000

    obj = custom()

    # 创建一个纳秒精度的 numpy datetime64 对象
    dt = np.datetime64('2000', 'ns')
    # 计算该对象与自身的时间差
    td = dt - dt

    # 对 dt 和 td 进行循环处理
    for item in [dt, td]:
        # 断言比较操作返回 NotImplemented
        assert item.__eq__(obj) is NotImplemented
        assert item.__ne__(obj) is NotImplemented
        assert item.__le__(obj) is NotImplemented
        assert item.__lt__(obj) is NotImplemented
        assert item.__ge__(obj) is NotImplemented
        assert item.__gt__(obj) is NotImplemented