diff --git a/pixi.lock b/pixi.lock index 23fcb3ee..5d3612f7 100644 --- a/pixi.lock +++ b/pixi.lock @@ -170,7 +170,7 @@ environments: - conda: https://prefix.dev/conda-forge/linux-64/snappy-1.2.1-h8bd8927_1.conda - conda: https://prefix.dev/conda-forge/noarch/sortedcontainers-2.4.0-pyhd8ed1ab_0.tar.bz2 - conda: https://prefix.dev/conda-forge/noarch/sparse-0.15.4-pyh267e887_1.conda - - conda: https://prefix.dev/conda-forge/noarch/sympy-1.13.3-pyh2585a3b_104.conda + - conda: https://prefix.dev/conda-forge/noarch/sympy-1.13.3-pyh2585a3b_105.conda - conda: https://prefix.dev/conda-forge/linux-64/tbb-2021.13.0-hceb3a55_1.conda - conda: https://prefix.dev/conda-forge/noarch/tblib-3.0.0-pyhd8ed1ab_1.conda - conda: https://prefix.dev/conda-forge/linux-64/tk-8.6.13-noxft_h4845f30_101.conda @@ -343,7 +343,7 @@ environments: - conda: https://prefix.dev/conda-forge/osx-arm64/snappy-1.2.1-h98b9ce2_1.conda - conda: https://prefix.dev/conda-forge/noarch/sortedcontainers-2.4.0-pyhd8ed1ab_0.tar.bz2 - conda: https://prefix.dev/conda-forge/noarch/sparse-0.15.4-pyh267e887_1.conda - - conda: https://prefix.dev/conda-forge/noarch/sympy-1.13.3-pyh2585a3b_104.conda + - conda: https://prefix.dev/conda-forge/noarch/sympy-1.13.3-pyh2585a3b_105.conda - conda: https://prefix.dev/conda-forge/noarch/tblib-3.0.0-pyhd8ed1ab_1.conda - conda: https://prefix.dev/conda-forge/osx-arm64/tk-8.6.13-h5083fa2_1.conda - conda: https://prefix.dev/conda-forge/noarch/toml-0.10.2-pyhd8ed1ab_1.conda @@ -675,7 +675,7 @@ environments: - conda: https://prefix.dev/conda-forge/noarch/pluggy-1.5.0-pyhd8ed1ab_1.conda - conda: https://prefix.dev/conda-forge/noarch/pytest-8.3.4-pyhd8ed1ab_1.conda - conda: https://prefix.dev/conda-forge/noarch/pytest-cov-6.0.0-pyhd8ed1ab_1.conda - - conda: https://prefix.dev/conda-forge/linux-64/python-3.13.1-ha99a958_102_cp313.conda + - conda: https://prefix.dev/conda-forge/linux-64/python-3.13.1-ha99a958_103_cp313.conda - conda: https://prefix.dev/conda-forge/linux-64/python_abi-3.13-5_cp313.conda - conda: https://prefix.dev/conda-forge/linux-64/readline-8.2-h8228510_1.conda - conda: https://prefix.dev/conda-forge/linux-64/tk-8.6.13-noxft_h4845f30_101.conda @@ -713,7 +713,7 @@ environments: - conda: https://prefix.dev/conda-forge/noarch/pluggy-1.5.0-pyhd8ed1ab_1.conda - conda: https://prefix.dev/conda-forge/noarch/pytest-8.3.4-pyhd8ed1ab_1.conda - conda: https://prefix.dev/conda-forge/noarch/pytest-cov-6.0.0-pyhd8ed1ab_1.conda - - conda: https://prefix.dev/conda-forge/osx-arm64/python-3.13.1-h4f43103_102_cp313.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/python-3.13.1-h4f43103_103_cp313.conda - conda: https://prefix.dev/conda-forge/osx-arm64/python_abi-3.13-5_cp313.conda - conda: https://prefix.dev/conda-forge/osx-arm64/readline-8.2-h92ec313_1.conda - conda: https://prefix.dev/conda-forge/osx-arm64/tk-8.6.13-h5083fa2_1.conda @@ -751,7 +751,7 @@ environments: - conda: https://prefix.dev/conda-forge/noarch/pluggy-1.5.0-pyhd8ed1ab_1.conda - conda: https://prefix.dev/conda-forge/noarch/pytest-8.3.4-pyhd8ed1ab_1.conda - conda: https://prefix.dev/conda-forge/noarch/pytest-cov-6.0.0-pyhd8ed1ab_1.conda - - conda: https://prefix.dev/conda-forge/win-64/python-3.13.1-h071d269_102_cp313.conda + - conda: https://prefix.dev/conda-forge/win-64/python-3.13.1-h071d269_103_cp313.conda - conda: https://prefix.dev/conda-forge/win-64/python_abi-3.13-5_cp313.conda - conda: https://prefix.dev/conda-forge/win-64/tbb-2021.13.0-h62715c5_1.conda - conda: https://prefix.dev/conda-forge/win-64/tk-8.6.13-h5226925_1.conda @@ -788,7 +788,7 @@ environments: - conda: https://prefix.dev/conda-forge/linux-64/libzlib-1.3.1-hb9d3cd8_2.conda - conda: https://prefix.dev/conda-forge/linux-64/ncurses-6.5-he02047a_1.conda - conda: https://prefix.dev/conda-forge/linux-64/openssl-3.4.0-h7b32b05_1.conda - - conda: https://prefix.dev/conda-forge/linux-64/python-3.13.1-ha99a958_102_cp313.conda + - conda: https://prefix.dev/conda-forge/linux-64/python-3.13.1-ha99a958_103_cp313.conda - conda: https://prefix.dev/conda-forge/linux-64/python_abi-3.13-5_cp313.conda - conda: https://prefix.dev/conda-forge/linux-64/readline-8.2-h8228510_1.conda - conda: https://prefix.dev/conda-forge/linux-64/tk-8.6.13-noxft_h4845f30_101.conda @@ -806,7 +806,7 @@ environments: - conda: https://prefix.dev/conda-forge/osx-arm64/libzlib-1.3.1-h8359307_2.conda - conda: https://prefix.dev/conda-forge/osx-arm64/ncurses-6.5-h7bae524_1.conda - conda: https://prefix.dev/conda-forge/osx-arm64/openssl-3.4.0-h81ee809_1.conda - - conda: https://prefix.dev/conda-forge/osx-arm64/python-3.13.1-h4f43103_102_cp313.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/python-3.13.1-h4f43103_103_cp313.conda - conda: https://prefix.dev/conda-forge/osx-arm64/python_abi-3.13-5_cp313.conda - conda: https://prefix.dev/conda-forge/osx-arm64/readline-8.2-h92ec313_1.conda - conda: https://prefix.dev/conda-forge/osx-arm64/tk-8.6.13-h5083fa2_1.conda @@ -823,7 +823,7 @@ environments: - conda: https://prefix.dev/conda-forge/win-64/libsqlite-3.47.2-h67fdade_0.conda - conda: https://prefix.dev/conda-forge/win-64/libzlib-1.3.1-h2466b09_2.conda - conda: https://prefix.dev/conda-forge/win-64/openssl-3.4.0-ha4e3fda_1.conda - - conda: https://prefix.dev/conda-forge/win-64/python-3.13.1-h071d269_102_cp313.conda + - conda: https://prefix.dev/conda-forge/win-64/python-3.13.1-h071d269_103_cp313.conda - conda: https://prefix.dev/conda-forge/win-64/python_abi-3.13-5_cp313.conda - conda: https://prefix.dev/conda-forge/win-64/tk-8.6.13-h5226925_1.conda - conda: https://prefix.dev/conda-forge/noarch/tzdata-2024b-hc8b5060_0.conda @@ -931,7 +931,7 @@ environments: - conda: https://prefix.dev/conda-forge/noarch/pysocks-1.7.1-pyha55dd90_7.conda - conda: https://prefix.dev/conda-forge/noarch/pytest-8.3.4-pyhd8ed1ab_1.conda - conda: https://prefix.dev/conda-forge/noarch/pytest-cov-6.0.0-pyhd8ed1ab_1.conda - - conda: https://prefix.dev/conda-forge/linux-64/python-3.13.1-ha99a958_102_cp313.conda + - conda: https://prefix.dev/conda-forge/linux-64/python-3.13.1-ha99a958_103_cp313.conda - conda: https://prefix.dev/conda-forge/linux-64/python_abi-3.13-5_cp313.conda - conda: https://prefix.dev/conda-forge/noarch/pytz-2024.2-pyhd8ed1ab_1.conda - conda: https://prefix.dev/conda-forge/linux-64/pyyaml-6.0.2-py313h536fd9c_1.conda @@ -1055,7 +1055,7 @@ environments: - conda: https://prefix.dev/conda-forge/noarch/pysocks-1.7.1-pyha55dd90_7.conda - conda: https://prefix.dev/conda-forge/noarch/pytest-8.3.4-pyhd8ed1ab_1.conda - conda: https://prefix.dev/conda-forge/noarch/pytest-cov-6.0.0-pyhd8ed1ab_1.conda - - conda: https://prefix.dev/conda-forge/osx-arm64/python-3.13.1-h4f43103_102_cp313.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/python-3.13.1-h4f43103_103_cp313.conda - conda: https://prefix.dev/conda-forge/osx-arm64/python_abi-3.13-5_cp313.conda - conda: https://prefix.dev/conda-forge/noarch/pytz-2024.2-pyhd8ed1ab_1.conda - conda: https://prefix.dev/conda-forge/osx-arm64/pyyaml-6.0.2-py313h20a7fcf_1.conda @@ -1175,7 +1175,7 @@ environments: - conda: https://prefix.dev/conda-forge/noarch/pysocks-1.7.1-pyh09c184e_7.conda - conda: https://prefix.dev/conda-forge/noarch/pytest-8.3.4-pyhd8ed1ab_1.conda - conda: https://prefix.dev/conda-forge/noarch/pytest-cov-6.0.0-pyhd8ed1ab_1.conda - - conda: https://prefix.dev/conda-forge/win-64/python-3.13.1-h071d269_102_cp313.conda + - conda: https://prefix.dev/conda-forge/win-64/python-3.13.1-h071d269_103_cp313.conda - conda: https://prefix.dev/conda-forge/win-64/python_abi-3.13-5_cp313.conda - conda: https://prefix.dev/conda-forge/noarch/pytz-2024.2-pyhd8ed1ab_1.conda - conda: https://prefix.dev/conda-forge/win-64/pyyaml-6.0.2-py313ha7868ed_1.conda @@ -1269,7 +1269,7 @@ environments: - conda: https://prefix.dev/conda-forge/noarch/pycparser-2.22-pyh29332c3_1.conda - conda: https://prefix.dev/conda-forge/noarch/pygments-2.19.1-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/noarch/pysocks-1.7.1-pyha55dd90_7.conda - - conda: https://prefix.dev/conda-forge/linux-64/python-3.13.1-ha99a958_102_cp313.conda + - conda: https://prefix.dev/conda-forge/linux-64/python-3.13.1-ha99a958_103_cp313.conda - conda: https://prefix.dev/conda-forge/linux-64/python_abi-3.13-5_cp313.conda - conda: https://prefix.dev/conda-forge/noarch/pytz-2024.2-pyhd8ed1ab_1.conda - conda: https://prefix.dev/conda-forge/linux-64/pyyaml-6.0.2-py313h536fd9c_1.conda @@ -1333,7 +1333,7 @@ environments: - conda: https://prefix.dev/conda-forge/noarch/pycparser-2.22-pyh29332c3_1.conda - conda: https://prefix.dev/conda-forge/noarch/pygments-2.19.1-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/noarch/pysocks-1.7.1-pyha55dd90_7.conda - - conda: https://prefix.dev/conda-forge/osx-arm64/python-3.13.1-h4f43103_102_cp313.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/python-3.13.1-h4f43103_103_cp313.conda - conda: https://prefix.dev/conda-forge/osx-arm64/python_abi-3.13-5_cp313.conda - conda: https://prefix.dev/conda-forge/noarch/pytz-2024.2-pyhd8ed1ab_1.conda - conda: https://prefix.dev/conda-forge/osx-arm64/pyyaml-6.0.2-py313h20a7fcf_1.conda @@ -1395,7 +1395,7 @@ environments: - conda: https://prefix.dev/conda-forge/noarch/pycparser-2.22-pyh29332c3_1.conda - conda: https://prefix.dev/conda-forge/noarch/pygments-2.19.1-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/noarch/pysocks-1.7.1-pyh09c184e_7.conda - - conda: https://prefix.dev/conda-forge/win-64/python-3.13.1-h071d269_102_cp313.conda + - conda: https://prefix.dev/conda-forge/win-64/python-3.13.1-h071d269_103_cp313.conda - conda: https://prefix.dev/conda-forge/win-64/python_abi-3.13-5_cp313.conda - conda: https://prefix.dev/conda-forge/noarch/pytz-2024.2-pyhd8ed1ab_1.conda - conda: https://prefix.dev/conda-forge/win-64/pyyaml-6.0.2-py313ha7868ed_1.conda @@ -1504,7 +1504,7 @@ environments: - conda: https://prefix.dev/conda-forge/noarch/pylint-3.3.3-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/noarch/pysocks-1.7.1-pyha55dd90_7.conda - conda: https://prefix.dev/conda-forge/noarch/pytest-8.3.4-pyhd8ed1ab_1.conda - - conda: https://prefix.dev/conda-forge/linux-64/python-3.13.1-ha99a958_102_cp313.conda + - conda: https://prefix.dev/conda-forge/linux-64/python-3.13.1-ha99a958_103_cp313.conda - conda: https://prefix.dev/conda-forge/linux-64/python_abi-3.13-5_cp313.conda - conda: https://prefix.dev/conda-forge/noarch/pytz-2024.2-pyhd8ed1ab_1.conda - conda: https://prefix.dev/conda-forge/linux-64/pyyaml-6.0.2-py313h536fd9c_1.conda @@ -1600,7 +1600,7 @@ environments: - conda: https://prefix.dev/conda-forge/noarch/pylint-3.3.3-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/noarch/pysocks-1.7.1-pyha55dd90_7.conda - conda: https://prefix.dev/conda-forge/noarch/pytest-8.3.4-pyhd8ed1ab_1.conda - - conda: https://prefix.dev/conda-forge/osx-arm64/python-3.13.1-h4f43103_102_cp313.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/python-3.13.1-h4f43103_103_cp313.conda - conda: https://prefix.dev/conda-forge/osx-arm64/python_abi-3.13-5_cp313.conda - conda: https://prefix.dev/conda-forge/noarch/pytz-2024.2-pyhd8ed1ab_1.conda - conda: https://prefix.dev/conda-forge/osx-arm64/pyyaml-6.0.2-py313h20a7fcf_1.conda @@ -1694,7 +1694,7 @@ environments: - conda: https://prefix.dev/conda-forge/noarch/pylint-3.3.3-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/noarch/pysocks-1.7.1-pyh09c184e_7.conda - conda: https://prefix.dev/conda-forge/noarch/pytest-8.3.4-pyhd8ed1ab_1.conda - - conda: https://prefix.dev/conda-forge/win-64/python-3.13.1-h071d269_102_cp313.conda + - conda: https://prefix.dev/conda-forge/win-64/python-3.13.1-h071d269_103_cp313.conda - conda: https://prefix.dev/conda-forge/win-64/python_abi-3.13-5_cp313.conda - conda: https://prefix.dev/conda-forge/noarch/pytz-2024.2-pyhd8ed1ab_1.conda - conda: https://prefix.dev/conda-forge/win-64/pyyaml-6.0.2-py313ha7868ed_1.conda @@ -1770,7 +1770,7 @@ environments: - conda: https://prefix.dev/conda-forge/noarch/pluggy-1.5.0-pyhd8ed1ab_1.conda - conda: https://prefix.dev/conda-forge/noarch/pytest-8.3.4-pyhd8ed1ab_1.conda - conda: https://prefix.dev/conda-forge/noarch/pytest-cov-6.0.0-pyhd8ed1ab_1.conda - - conda: https://prefix.dev/conda-forge/linux-64/python-3.13.1-ha99a958_102_cp313.conda + - conda: https://prefix.dev/conda-forge/linux-64/python-3.13.1-ha99a958_103_cp313.conda - conda: https://prefix.dev/conda-forge/linux-64/python_abi-3.13-5_cp313.conda - conda: https://prefix.dev/conda-forge/linux-64/readline-8.2-h8228510_1.conda - conda: https://prefix.dev/conda-forge/linux-64/tk-8.6.13-noxft_h4845f30_101.conda @@ -1808,7 +1808,7 @@ environments: - conda: https://prefix.dev/conda-forge/noarch/pluggy-1.5.0-pyhd8ed1ab_1.conda - conda: https://prefix.dev/conda-forge/noarch/pytest-8.3.4-pyhd8ed1ab_1.conda - conda: https://prefix.dev/conda-forge/noarch/pytest-cov-6.0.0-pyhd8ed1ab_1.conda - - conda: https://prefix.dev/conda-forge/osx-arm64/python-3.13.1-h4f43103_102_cp313.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/python-3.13.1-h4f43103_103_cp313.conda - conda: https://prefix.dev/conda-forge/osx-arm64/python_abi-3.13-5_cp313.conda - conda: https://prefix.dev/conda-forge/osx-arm64/readline-8.2-h92ec313_1.conda - conda: https://prefix.dev/conda-forge/osx-arm64/tk-8.6.13-h5083fa2_1.conda @@ -1846,7 +1846,7 @@ environments: - conda: https://prefix.dev/conda-forge/noarch/pluggy-1.5.0-pyhd8ed1ab_1.conda - conda: https://prefix.dev/conda-forge/noarch/pytest-8.3.4-pyhd8ed1ab_1.conda - conda: https://prefix.dev/conda-forge/noarch/pytest-cov-6.0.0-pyhd8ed1ab_1.conda - - conda: https://prefix.dev/conda-forge/win-64/python-3.13.1-h071d269_102_cp313.conda + - conda: https://prefix.dev/conda-forge/win-64/python-3.13.1-h071d269_103_cp313.conda - conda: https://prefix.dev/conda-forge/win-64/python_abi-3.13-5_cp313.conda - conda: https://prefix.dev/conda-forge/win-64/tbb-2021.13.0-h62715c5_1.conda - conda: https://prefix.dev/conda-forge/win-64/tk-8.6.13-h5226925_1.conda @@ -2043,7 +2043,7 @@ environments: - conda: https://prefix.dev/conda-forge/linux-64/snappy-1.2.1-h8bd8927_1.conda - conda: https://prefix.dev/conda-forge/noarch/sortedcontainers-2.4.0-pyhd8ed1ab_0.tar.bz2 - conda: https://prefix.dev/conda-forge/noarch/sparse-0.15.4-pyh267e887_1.conda - - conda: https://prefix.dev/conda-forge/noarch/sympy-1.13.3-pyh2585a3b_104.conda + - conda: https://prefix.dev/conda-forge/noarch/sympy-1.13.3-pyh2585a3b_105.conda - conda: https://prefix.dev/conda-forge/linux-64/tbb-2021.13.0-hceb3a55_1.conda - conda: https://prefix.dev/conda-forge/noarch/tblib-3.0.0-pyhd8ed1ab_1.conda - conda: https://prefix.dev/conda-forge/linux-64/tk-8.6.13-noxft_h4845f30_101.conda @@ -2216,7 +2216,7 @@ environments: - conda: https://prefix.dev/conda-forge/osx-arm64/snappy-1.2.1-h98b9ce2_1.conda - conda: https://prefix.dev/conda-forge/noarch/sortedcontainers-2.4.0-pyhd8ed1ab_0.tar.bz2 - conda: https://prefix.dev/conda-forge/noarch/sparse-0.15.4-pyh267e887_1.conda - - conda: https://prefix.dev/conda-forge/noarch/sympy-1.13.3-pyh2585a3b_104.conda + - conda: https://prefix.dev/conda-forge/noarch/sympy-1.13.3-pyh2585a3b_105.conda - conda: https://prefix.dev/conda-forge/noarch/tblib-3.0.0-pyhd8ed1ab_1.conda - conda: https://prefix.dev/conda-forge/osx-arm64/tk-8.6.13-h5083fa2_1.conda - conda: https://prefix.dev/conda-forge/noarch/toml-0.10.2-pyhd8ed1ab_1.conda @@ -2469,7 +2469,7 @@ packages: - pypi: . name: array-api-extra version: 0.5.1.dev0 - sha256: 844f582d7ea2045c164b04200b3bc32dd7f4c868cad9da16621a743f0d0bf381 + sha256: d8083ec4ee363a390f2afd622df56756078ce3ba5f1f67e88867111a2d306b57 requires_dist: - array-api-compat>=1.10.0,<2 - furo>=2023.8.17 ; extra == 'docs' @@ -8627,10 +8627,10 @@ packages: purls: [] size: 25199631 timestamp: 1733409331823 -- conda: https://prefix.dev/conda-forge/linux-64/python-3.13.1-ha99a958_102_cp313.conda - build_number: 102 - sha256: b10f25c5edc203d15b3f54861bec4868b8200ebc16c8cbc82202e4c8da2b183e - md5: 6e7535f1d1faf524e9210d2689b3149b +- conda: https://prefix.dev/conda-forge/linux-64/python-3.13.1-ha99a958_103_cp313.conda + build_number: 103 + sha256: 365f9294ba2d36513f85085b95b705d4d02110a6d11ec4b683f5a10d37dde020 + md5: 899de8f76e198a36bc5a36132a6db887 depends: - __glibc >=2.17,<3.0.a0 - bzip2 >=1.0.8,<2.0a0 @@ -8640,7 +8640,7 @@ packages: - libgcc >=13 - liblzma >=5.6.3,<6.0a0 - libmpdec >=4.0.0,<5.0a0 - - libsqlite >=3.47.0,<4.0a0 + - libsqlite >=3.47.2,<4.0a0 - libuuid >=2.38.1,<3.0a0 - libzlib >=1.3.1,<2.0a0 - ncurses >=6.5,<7.0a0 @@ -8651,8 +8651,8 @@ packages: - tzdata license: Python-2.0 purls: [] - size: 33263183 - timestamp: 1733436074842 + size: 33262248 + timestamp: 1736273267565 - conda: https://prefix.dev/conda-forge/osx-arm64/python-3.10.16-h870587a_1_cpython.conda build_number: 1 sha256: cd617b15712c4f9316b22c75459311ed106ccb0659c0bf36e281a9162b4e2d95 @@ -8675,10 +8675,10 @@ packages: purls: [] size: 12372048 timestamp: 1733408850559 -- conda: https://prefix.dev/conda-forge/osx-arm64/python-3.13.1-h4f43103_102_cp313.conda - build_number: 102 - sha256: 0379adf6bb35ca47036860983701e8f6fae89c028d422f2b9439f3110893bc24 - md5: 8c65c1dfc98312ef8666dbb7c7fc47ca +- conda: https://prefix.dev/conda-forge/osx-arm64/python-3.13.1-h4f43103_103_cp313.conda + build_number: 103 + sha256: 0ebda5e85d5d37f0af1dae8ad500ef298a547ec790cdbfdb271ffbe4d2c56770 + md5: b43efdca6d96347894527844a4cdd5c8 depends: - __osx >=11.0 - bzip2 >=1.0.8,<2.0a0 @@ -8686,7 +8686,7 @@ packages: - libffi >=3.4,<4.0a0 - liblzma >=5.6.3,<6.0a0 - libmpdec >=4.0.0,<5.0a0 - - libsqlite >=3.47.0,<4.0a0 + - libsqlite >=3.47.2,<4.0a0 - libzlib >=1.3.1,<2.0a0 - ncurses >=6.5,<7.0a0 - openssl >=3.4.0,<4.0a0 @@ -8696,8 +8696,8 @@ packages: - tzdata license: Python-2.0 purls: [] - size: 12905237 - timestamp: 1733433280639 + size: 11727435 + timestamp: 1736271845822 - conda: https://prefix.dev/conda-forge/win-64/python-3.10.16-h37870fc_1_cpython.conda build_number: 1 sha256: 3392db6a7a90864d3fd1ce281859a49e27ee68121b63eece2ae6f1dbb2a8aaf1 @@ -8720,17 +8720,17 @@ packages: purls: [] size: 16061214 timestamp: 1733408154785 -- conda: https://prefix.dev/conda-forge/win-64/python-3.13.1-h071d269_102_cp313.conda - build_number: 102 - sha256: ee41eda85ebc3a257a3b21a76d255d986b08a285d891e418cbfb70113ee14684 - md5: 70568ba8bbd5f0c7b830e690775eb8b7 +- conda: https://prefix.dev/conda-forge/win-64/python-3.13.1-h071d269_103_cp313.conda + build_number: 103 + sha256: 1517cbdf453557c7445c05b77c23da95a8b45586b270c6534f822c5b64bfeeaf + md5: 884ad80bf8454b8feff00b1f77a3dda9 depends: - bzip2 >=1.0.8,<2.0a0 - libexpat >=2.6.4,<3.0a0 - libffi >=3.4,<4.0a0 - liblzma >=5.6.3,<6.0a0 - libmpdec >=4.0.0,<5.0a0 - - libsqlite >=3.47.0,<4.0a0 + - libsqlite >=3.47.2,<4.0a0 - libzlib >=1.3.1,<2.0a0 - openssl >=3.4.0,<4.0a0 - python_abi 3.13.* *_cp313 @@ -8741,8 +8741,8 @@ packages: - vc14_runtime >=14.29.30139 license: Python-2.0 purls: [] - size: 16753813 - timestamp: 1733433028707 + size: 16841405 + timestamp: 1736270799704 - conda: https://prefix.dev/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhff2d567_1.conda sha256: a50052536f1ef8516ed11a844f9413661829aa083304dc624c5925298d078d79 md5: 5ba79d7c71f03c678c8ead841f347d6e @@ -9440,21 +9440,21 @@ packages: - pkg:pypi/stack-data?source=hash-mapping size: 26988 timestamp: 1733569565672 -- conda: https://prefix.dev/conda-forge/noarch/sympy-1.13.3-pyh2585a3b_104.conda - sha256: 35b2620d109c8a01a301222b4f546690316b7ed61d5c0325ec4a317fa27ea8d7 - md5: 68085d736d2b2f54498832b65059875d +- conda: https://prefix.dev/conda-forge/noarch/sympy-1.13.3-pyh2585a3b_105.conda + sha256: 929d939c5a8bcdc10a17501890918da68cf14a5883b36fddf77b8f0fbf040be2 + md5: 254cd5083ffa04d96e3173397a3d30f4 depends: - __unix - cpython - gmpy2 >=2.0.8 - mpmath >=0.19 - - python >=3.8 + - python >=3.9 license: BSD-3-Clause license_family: BSD purls: - pkg:pypi/sympy?source=hash-mapping - size: 4561387 - timestamp: 1728484644967 + size: 4523617 + timestamp: 1736248315124 - conda: https://prefix.dev/conda-forge/noarch/tabulate-0.9.0-pyhd8ed1ab_2.conda sha256: 090023bddd40d83468ef86573976af8c514f64119b2bd814ee63a838a542720a md5: 959484a66b4b76befcddc4fa97c95567 diff --git a/pyproject.toml b/pyproject.toml index d139278e..dadc311f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -232,6 +232,11 @@ reportUnknownVariableType = false # false positives for input validation reportUnreachable = false +executionEnvironments = [ + { root = "tests", reportPrivateUsage = false }, + { root = "src" }, +] + # Ruff diff --git a/src/array_api_extra/_funcs.py b/src/array_api_extra/_funcs.py index 2f4bc0f4..0d8bb162 100644 --- a/src/array_api_extra/_funcs.py +++ b/src/array_api_extra/_funcs.py @@ -6,8 +6,9 @@ import operator import warnings from collections.abc import Callable +from enum import Enum from types import ModuleType -from typing import ClassVar, Literal, cast +from typing import ClassVar, cast from ._lib import _compat, _utils from ._lib._compat import ( @@ -635,6 +636,31 @@ def pad( return padded +class _AtOp(Enum): + """Operations for use in `xpx.at`.""" + + SET = "set" + ADD = "add" + SUBTRACT = "subtract" + MULTIPLY = "multiply" + DIVIDE = "divide" + POWER = "power" + MIN = "min" + MAX = "max" + + # @override from Python 3.12 + def __str__(self) -> str: # type: ignore[explicit-override] # pyright: ignore[reportImplicitOverride] + """ + Return string representation (useful for pytest logs). + + Returns + ------- + str + The operation's name. + """ + return self.value + + _undef = object() @@ -784,7 +810,7 @@ def __getitem__(self, idx: Index, /) -> at: # numpydoc ignore=PR01,RT01 def _update_common( self, - at_op: str, + at_op: _AtOp, y: Array, /, copy: bool | None, @@ -827,7 +853,7 @@ def _update_common( if copy: if is_jax_array(x): # Use JAX's at[] - func = cast(Callable[[Array], Array], getattr(x.at[idx], at_op)) + func = cast(Callable[[Array], Array], getattr(x.at[idx], at_op.value)) return func(y), None # Emulate at[] behaviour for non-JAX arrays # with a copy followed by an update @@ -856,7 +882,7 @@ def set( xp: ModuleType | None = None, ) -> Array: # numpydoc ignore=PR01,RT01 """Apply ``x[idx] = y`` and return the update array.""" - res, x = self._update_common("set", y, copy=copy, xp=xp) + res, x = self._update_common(_AtOp.SET, y, copy=copy, xp=xp) if res is not None: return res assert x is not None @@ -865,9 +891,7 @@ def set( def _iop( self, - at_op: Literal[ - "set", "add", "subtract", "multiply", "divide", "power", "min", "max" - ], + at_op: _AtOp, elwise_op: Callable[[Array, Array], Array], y: Array, /, @@ -903,7 +927,7 @@ def add( # Note for this and all other methods based on _iop: # operator.iadd and operator.add subtly differ in behaviour, as # only iadd will trigger exceptions when y has an incompatible dtype. - return self._iop("add", operator.iadd, y, copy=copy, xp=xp) + return self._iop(_AtOp.ADD, operator.iadd, y, copy=copy, xp=xp) def subtract( self, @@ -913,7 +937,7 @@ def subtract( xp: ModuleType | None = None, ) -> Array: # numpydoc ignore=PR01,RT01 """Apply ``x[idx] -= y`` and return the updated array.""" - return self._iop("subtract", operator.isub, y, copy=copy, xp=xp) + return self._iop(_AtOp.SUBTRACT, operator.isub, y, copy=copy, xp=xp) def multiply( self, @@ -923,7 +947,7 @@ def multiply( xp: ModuleType | None = None, ) -> Array: # numpydoc ignore=PR01,RT01 """Apply ``x[idx] *= y`` and return the updated array.""" - return self._iop("multiply", operator.imul, y, copy=copy, xp=xp) + return self._iop(_AtOp.MULTIPLY, operator.imul, y, copy=copy, xp=xp) def divide( self, @@ -933,7 +957,7 @@ def divide( xp: ModuleType | None = None, ) -> Array: # numpydoc ignore=PR01,RT01 """Apply ``x[idx] /= y`` and return the updated array.""" - return self._iop("divide", operator.itruediv, y, copy=copy, xp=xp) + return self._iop(_AtOp.DIVIDE, operator.itruediv, y, copy=copy, xp=xp) def power( self, @@ -943,7 +967,7 @@ def power( xp: ModuleType | None = None, ) -> Array: # numpydoc ignore=PR01,RT01 """Apply ``x[idx] **= y`` and return the updated array.""" - return self._iop("power", operator.ipow, y, copy=copy, xp=xp) + return self._iop(_AtOp.POWER, operator.ipow, y, copy=copy, xp=xp) def min( self, @@ -956,7 +980,7 @@ def min( if xp is None: xp = array_namespace(self._x) y = xp.asarray(y) - return self._iop("min", xp.minimum, y, copy=copy, xp=xp) + return self._iop(_AtOp.MIN, xp.minimum, y, copy=copy, xp=xp) def max( self, @@ -969,4 +993,4 @@ def max( if xp is None: xp = array_namespace(self._x) y = xp.asarray(y) - return self._iop("max", xp.maximum, y, copy=copy, xp=xp) + return self._iop(_AtOp.MAX, xp.maximum, y, copy=copy, xp=xp) diff --git a/tests/test_at.py b/tests/test_at.py index f50b9248..bd4e444a 100644 --- a/tests/test_at.py +++ b/tests/test_at.py @@ -1,5 +1,6 @@ from collections.abc import Callable, Generator from contextlib import contextmanager +from enum import Enum from importlib import import_module from typing import cast @@ -13,31 +14,37 @@ ) from array_api_extra import at +from array_api_extra._funcs import _AtOp from array_api_extra._lib._typing import Array -all_libraries = ( - "array_api_strict", - "numpy", - "numpy_readonly", - "cupy", - "torch", - "dask.array", - "sparse", - "jax.numpy", -) + +class Library(Enum): + ARRAY_API_STRICT = "array_api_strict" + NUMPY = "numpy" + NUMPY_READONLY = "numpy_readonly" + CUPY = "cupy" + TORCH = "torch" + DASK_ARRAY = "dask.array" + SPARSE = "sparse" + JAX_NUMPY = "jax.numpy" + + # @override from Python 3.12 + def __str__(self) -> str: # type: ignore[explicit-override] # pyright: ignore[reportImplicitOverride] + return self.value -@pytest.fixture(params=all_libraries) +@pytest.fixture(params=tuple(Library)) def array(request: pytest.FixtureRequest) -> Array: library = request.param - if library == "numpy_readonly": + if library is Library.NUMPY_READONLY: x = np.asarray([10.0, 20.0, 30.0]) x.flags.writeable = False else: + library_name = library.value try: - lib = import_module(library) + lib = import_module(library_name) except ImportError: - pytest.skip(f"{library} is not installed") + pytest.skip(f"{library_name} is not installed") x = lib.asarray([10.0, 20.0, 30.0]) return x @@ -79,21 +86,21 @@ def assert_copy(array: Array, copy: bool | None) -> Generator[None, None, None]: @pytest.mark.parametrize( ("op", "arg", "expect"), [ - ("set", 40.0, [10.0, 40.0, 40.0]), - ("add", 40.0, [10.0, 60.0, 70.0]), - ("subtract", 100.0, [10.0, -80.0, -70.0]), - ("multiply", 2.0, [10.0, 40.0, 60.0]), - ("divide", 2.0, [10.0, 10.0, 15.0]), - ("power", 2.0, [10.0, 400.0, 900.0]), - ("min", 25.0, [10.0, 20.0, 25.0]), - ("max", 25.0, [10.0, 25.0, 30.0]), + (_AtOp.SET, 40.0, [10.0, 40.0, 40.0]), + (_AtOp.ADD, 40.0, [10.0, 60.0, 70.0]), + (_AtOp.SUBTRACT, 100.0, [10.0, -80.0, -70.0]), + (_AtOp.MULTIPLY, 2.0, [10.0, 40.0, 60.0]), + (_AtOp.DIVIDE, 2.0, [10.0, 10.0, 15.0]), + (_AtOp.POWER, 2.0, [10.0, 400.0, 900.0]), + (_AtOp.MIN, 25.0, [10.0, 20.0, 25.0]), + (_AtOp.MAX, 25.0, [10.0, 25.0, 30.0]), ], ) def test_update_ops( array: Array, kwargs: dict[str, bool | None], expect_copy: bool | None, - op: str, + op: _AtOp, arg: float, expect: list[float], ): @@ -101,7 +108,7 @@ def test_update_ops( pytest.skip("at() does not support updates on sparse arrays") with assert_copy(array, expect_copy): - func = cast(Callable[..., Array], getattr(at(array)[1:], op)) # type: ignore[no-any-explicit] + func = cast(Callable[..., Array], getattr(at(array)[1:], op.value)) # type: ignore[no-any-explicit] y = func(arg, **kwargs) assert isinstance(y, type(array)) assert_array_equal(y, expect) @@ -141,8 +148,10 @@ def test_alternate_index_syntax(): @pytest.mark.parametrize("copy", [True, False]) -@pytest.mark.parametrize("op", ["add", "subtract", "multiply", "divide", "power"]) -def test_iops_incompatible_dtype(op: str, copy: bool): +@pytest.mark.parametrize( + "op", [_AtOp.ADD, _AtOp.SUBTRACT, _AtOp.MULTIPLY, _AtOp.DIVIDE, _AtOp.POWER] +) +def test_iops_incompatible_dtype(op: _AtOp, copy: bool): """Test that at() replicates the backend's behaviour for in-place operations with incompatible dtypes. @@ -155,6 +164,6 @@ def test_iops_incompatible_dtype(op: str, copy: bool): to dtype('int64') with casting rule 'same_kind' """ a = np.asarray([2, 4]) - func = cast(Callable[..., Array], getattr(at(a)[:], op)) # type: ignore[no-any-explicit] + func = cast(Callable[..., Array], getattr(at(a)[:], op.value)) # type: ignore[no-any-explicit] with pytest.raises(TypeError, match="Cannot cast ufunc"): func(1.1, copy=copy)