diff --git a/conda.recipe/recipe.yaml b/conda.recipe/recipe.yaml index 21e4a041a..35b65c1ab 100644 --- a/conda.recipe/recipe.yaml +++ b/conda.recipe/recipe.yaml @@ -45,6 +45,7 @@ requirements: - python - formulaic >=0.6 - joblib + - narwhals >=2.0.0 - numexpr - packaging - pandas diff --git a/pixi.lock b/pixi.lock index ec956722e..89c702114 100644 --- a/pixi.lock +++ b/pixi.lock @@ -653,6 +653,8 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pip-25.2-pyh145f28c_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.5.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/polars-1.35.2-pyh6a1acc5_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/polars-runtime-32-1.35.2-py310hffdcd12_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/prometheus-cpp-1.3.0-ha5d0236_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/prompt-toolkit-3.0.52-pyha770c72_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/psutil-7.1.3-py314h0f05182_0.conda @@ -842,6 +844,8 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pip-25.2-pyh145f28c_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.5.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/polars-1.35.2-pyh6a1acc5_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/polars-runtime-32-1.35.2-py310h34bb384_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/prometheus-cpp-1.3.0-h0967b3e_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/prompt-toolkit-3.0.52-pyha770c72_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/psutil-7.1.3-py314h9d33bd4_0.conda @@ -989,6 +993,8 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pip-25.2-pyh145f28c_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.5.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/polars-1.35.2-pyh6a1acc5_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/polars-runtime-32-1.35.2-py310hca7251b_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/prompt-toolkit-3.0.52-pyha770c72_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/psutil-7.1.3-py314hc5dbbe4_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pure_eval-0.2.3-pyhd8ed1ab_1.conda @@ -2262,6 +2268,8 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pip-25.2-pyh145f28c_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.5.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/polars-1.35.2-pyh6a1acc5_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/polars-runtime-32-1.35.2-py310hffdcd12_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/prometheus-cpp-1.3.0-ha5d0236_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/prompt-toolkit-3.0.52-pyha770c72_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/psutil-7.1.3-py314h0f05182_0.conda @@ -2454,6 +2462,8 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pip-25.2-pyh145f28c_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.5.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/polars-1.35.2-pyh6a1acc5_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/polars-runtime-32-1.35.2-py310h34bb384_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/prometheus-cpp-1.3.0-h0967b3e_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/prompt-toolkit-3.0.52-pyha770c72_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/psutil-7.1.3-py314h9d33bd4_0.conda @@ -2607,6 +2617,8 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pip-25.2-pyh145f28c_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.5.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/polars-1.35.2-pyh6a1acc5_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/polars-runtime-32-1.35.2-py310hca7251b_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/prompt-toolkit-3.0.52-pyha770c72_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/psutil-7.1.3-py314hc5dbbe4_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pure_eval-0.2.3-pyhd8ed1ab_1.conda @@ -2800,6 +2812,7 @@ environments: linux-64: - conda: https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-2_gnu.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/_python_abi3_support-1.0-hd8ed1ab_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/attrs-25.4.0-pyh71513ae_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/aws-c-auth-0.9.1-he9688bd_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/aws-c-cal-0.9.5-h346e085_1.conda @@ -2829,6 +2842,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/click-8.3.0-pyh707e725_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/conda-gcc-specs-14.3.0-hb991d5c_7.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cpython-3.13.9-py313hd8ed1ab_101.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/cxx-compiler-1.11.0-hfcd1e18_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/cython-3.1.6-py313hc80a56d_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.3.0-pyhd8ed1ab_0.conda @@ -2923,6 +2937,8 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/patsy-1.0.2-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pip-25.2-pyh145f28c_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/polars-1.35.2-pyh6a1acc5_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/polars-runtime-32-1.35.2-py310hffdcd12_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/prometheus-cpp-1.3.0-ha5d0236_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/psutil-7.1.3-py313h54dd161_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pyarrow-22.0.0-py313h78bf25f_0.conda @@ -2932,6 +2948,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-xdist-3.8.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.13.9-hc97d973_101_cp313.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python-gil-3.13.9-h4df99d1_101.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python-tzdata-2025.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.13-8_cp313.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pytz-2025.2-pyhd8ed1ab_0.conda @@ -2961,6 +2978,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/zlib-1.3.1-hb9d3cd8_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.7-hb8e6e7a_2.conda osx-arm64: + - conda: https://conda.anaconda.org/conda-forge/noarch/_python_abi3_support-1.0-hd8ed1ab_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/attrs-25.4.0-pyh71513ae_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/aws-c-auth-0.9.1-hd6d1d5d_4.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/aws-c-cal-0.9.5-hca30140_1.conda @@ -2997,6 +3015,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/compiler-rt-19.1.7-h855ad52_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/compiler-rt_osx-arm64-19.1.7-he32a8d3_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cpython-3.13.9-py313hd8ed1ab_101.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/cxx-compiler-1.11.0-h88570a1_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/cython-3.1.6-py313h66a7184_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.3.0-pyhd8ed1ab_0.conda @@ -3082,6 +3101,8 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/patsy-1.0.2-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pip-25.2-pyh145f28c_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/polars-1.35.2-pyh6a1acc5_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/polars-runtime-32-1.35.2-py310h34bb384_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/prometheus-cpp-1.3.0-h0967b3e_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/psutil-7.1.3-py313h9734d34_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyarrow-22.0.0-py313h39782a4_0.conda @@ -3091,6 +3112,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-xdist-3.8.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/python-3.13.9-hfc2f54d_101_cp313.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python-gil-3.13.9-h4df99d1_101.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python-tzdata-2025.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.13-8_cp313.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pytz-2025.2-pyhd8ed1ab_0.conda @@ -3121,6 +3143,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/zstd-1.5.7-h6491c7d_2.conda win-64: - conda: https://conda.anaconda.org/conda-forge/win-64/_openmp_mutex-4.5-2_gnu.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/_python_abi3_support-1.0-hd8ed1ab_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/attrs-25.4.0-pyh71513ae_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/aws-c-auth-0.9.1-h5a8d611_4.conda - conda: https://conda.anaconda.org/conda-forge/win-64/aws-c-cal-0.9.5-ha82e055_1.conda @@ -3141,6 +3164,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2025.10.5-h4c7d964_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/click-8.3.0-pyh7428d3b_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cpython-3.13.9-py313hd8ed1ab_101.conda - conda: https://conda.anaconda.org/conda-forge/win-64/cxx-compiler-1.11.0-h1c1089f_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/cython-3.1.6-py313h560b0a0_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.3.0-pyhd8ed1ab_0.conda @@ -3204,6 +3228,8 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/patsy-1.0.2-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pip-25.2-pyh145f28c_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/polars-1.35.2-pyh6a1acc5_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/polars-runtime-32-1.35.2-py310hca7251b_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/psutil-7.1.3-py313h5fd188c_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/pyarrow-22.0.0-py313hfa70ccb_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/pyarrow-core-22.0.0-py313h5921983_0_cpu.conda @@ -3212,6 +3238,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-xdist-3.8.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/python-3.13.9-h09917c8_101_cp313.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python-gil-3.13.9-h4df99d1_101.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python-tzdata-2025.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.13-8_cp313.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pytz-2025.2-pyhd8ed1ab_0.conda @@ -3250,6 +3277,7 @@ environments: linux-64: - conda: https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-2_gnu.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/_python_abi3_support-1.0-hd8ed1ab_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/astor-0.8.1-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/attrs-25.3.0-pyh71513ae_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/aws-c-auth-0.9.1-he9688bd_4.conda @@ -3281,6 +3309,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/click-8.1.8-pyh707e725_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/conda-gcc-specs-14.3.0-hb991d5c_7.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cpython-3.9.23-py39hd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/cxx-compiler-1.11.0-hfcd1e18_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/cython-3.1.3-py39h6bc127c_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.3.0-pyhd8ed1ab_0.conda @@ -3360,6 +3389,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/lz4-c-1.10.0-h5888daf_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/mypy-1.17.1-py39hd399759_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/mypy_extensions-1.1.0-pyha770c72_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/narwhals-2.0.1-pyhe01879c_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.5-h2d0b736_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/nlohmann_json-3.12.0-h54a6638_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/nomkl-1.0-h5ca1d4c_0.tar.bz2 @@ -3373,6 +3403,8 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/patsy-1.0.1-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pip-25.2-pyh8b19718_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/polars-1.33.1-default_h755bcc6_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/polars-default-1.33.1-py39hf521cc8_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/prometheus-cpp-1.3.0-ha5d0236_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/psutil-7.0.0-py39h8cd3c5a_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pyarrow-21.0.0-py39hf3d152e_0.conda @@ -3382,6 +3414,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-xdist-3.8.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.9.23-hc30ae73_0_cpython.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python-gil-3.9.23-hd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.9-8_cp39.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pytz-2025.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/re2-2025.08.12-h5301d42_1.conda @@ -3409,6 +3442,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/zlib-1.3.1-hb9d3cd8_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.7-hb8e6e7a_2.conda osx-arm64: + - conda: https://conda.anaconda.org/conda-forge/noarch/_python_abi3_support-1.0-hd8ed1ab_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/astor-0.8.1-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/attrs-25.3.0-pyh71513ae_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/aws-c-auth-0.9.1-hd6d1d5d_4.conda @@ -3447,6 +3481,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/compiler-rt-19.1.7-h855ad52_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/compiler-rt_osx-arm64-19.1.7-he32a8d3_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cpython-3.9.23-py39hd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/cxx-compiler-1.11.0-h88570a1_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/cython-3.1.3-py39hba8e057_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.3.0-pyhd8ed1ab_0.conda @@ -3515,6 +3550,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/lz4-c-1.10.0-h286801f_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/mypy-1.17.1-py39he7485ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/mypy_extensions-1.1.0-pyha770c72_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/narwhals-2.0.1-pyhe01879c_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ncurses-6.5-h5e97a16_3.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/nlohmann_json-3.12.0-h248ca61_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/numexpr-2.10.0-py39h998126f_0.conda @@ -3527,6 +3563,8 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/patsy-1.0.1-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pip-25.2-pyh8b19718_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/polars-1.33.1-default_h107b989_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/polars-default-1.33.1-py39h31c57e4_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/prometheus-cpp-1.3.0-h0967b3e_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/psutil-7.0.0-py39hf3bc14e_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyarrow-21.0.0-py39hdf13c20_0.conda @@ -3536,6 +3574,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-xdist-3.8.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/python-3.9.23-h7139b31_0_cpython.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python-gil-3.9.23-hd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.9-8_cp39.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pytz-2025.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/re2-2025.08.12-h64b956e_1.conda @@ -3563,6 +3602,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/zlib-1.3.1-h8359307_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/zstd-1.5.7-h6491c7d_2.conda win-64: + - conda: https://conda.anaconda.org/conda-forge/noarch/_python_abi3_support-1.0-hd8ed1ab_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/astor-0.8.1-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/attrs-25.3.0-pyh71513ae_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/aws-c-auth-0.9.1-h5a8d611_4.conda @@ -3586,6 +3626,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/cached_property-1.5.2-pyha770c72_1.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/noarch/click-8.1.8-pyh7428d3b_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cpython-3.9.23-py39hd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/cxx-compiler-1.11.0-h1c1089f_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/cython-3.1.3-py39hc6ecc89_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.3.0-pyhd8ed1ab_0.conda @@ -3636,6 +3677,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/win-64/msys2-conda-epoch-20160418-1.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/win-64/mypy-1.17.1-py39h0802e32_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/mypy_extensions-1.1.0-pyha770c72_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/narwhals-2.0.1-pyhe01879c_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/nomkl-1.0-h5ca1d4c_0.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/win-64/numexpr-2.10.0-py39h4919eaa_100.conda - conda: https://conda.anaconda.org/conda-forge/win-64/numpy-1.22.4-py39h0948cea_0.tar.bz2 @@ -3647,6 +3689,8 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/patsy-1.0.1-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pip-25.2-pyh8b19718_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/polars-1.33.1-default_hd0420bf_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/polars-default-1.33.1-py39he906d20_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/psutil-7.0.0-py39ha55e580_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/pyarrow-21.0.0-py39hcbf5309_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/pyarrow-core-21.0.0-py39hca79ef2_0_cpu.conda @@ -3655,6 +3699,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-xdist-3.8.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/python-3.9.23-h8c5b53a_0_cpython.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python-gil-3.9.23-hd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.9-8_cp39.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pytz-2025.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/re2-2025.08.12-ha104f34_1.conda @@ -3691,6 +3736,7 @@ environments: linux-64: - conda: https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-2_gnu.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/_python_abi3_support-1.0-hd8ed1ab_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/attrs-25.4.0-pyh71513ae_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/aws-c-auth-0.9.1-he9688bd_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/aws-c-cal-0.9.5-h346e085_1.conda @@ -3720,6 +3766,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/click-8.3.0-pyh707e725_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/conda-gcc-specs-14.3.0-hb991d5c_7.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cpython-3.10.19-py310hd8ed1ab_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/cxx-compiler-1.11.0-hfcd1e18_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/cython-3.1.6-py310ha58568a_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.3.0-pyhd8ed1ab_0.conda @@ -3811,6 +3858,8 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/patsy-1.0.2-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pip-25.2-pyh8b19718_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/polars-1.35.2-pyh6a1acc5_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/polars-runtime-32-1.35.2-py310hffdcd12_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/prometheus-cpp-1.3.0-ha5d0236_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/psutil-7.1.3-py310h139afa4_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pyarrow-22.0.0-py310hff52083_0.conda @@ -3820,6 +3869,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-xdist-3.8.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.10.19-h3c07f61_2_cpython.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python-gil-3.10.19-hd8ed1ab_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python-tzdata-2025.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.10-8_cp310.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pytz-2025.2-pyhd8ed1ab_0.conda @@ -3848,6 +3898,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/zlib-1.3.1-hb9d3cd8_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.7-hb8e6e7a_2.conda osx-arm64: + - conda: https://conda.anaconda.org/conda-forge/noarch/_python_abi3_support-1.0-hd8ed1ab_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/attrs-25.4.0-pyh71513ae_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/aws-c-auth-0.9.1-hd6d1d5d_4.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/aws-c-cal-0.9.5-hca30140_1.conda @@ -3884,6 +3935,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/compiler-rt-19.1.7-h855ad52_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/compiler-rt_osx-arm64-19.1.7-he32a8d3_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cpython-3.10.19-py310hd8ed1ab_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/cxx-compiler-1.11.0-h88570a1_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/cython-3.1.6-py310hf41fa49_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.3.0-pyhd8ed1ab_0.conda @@ -3964,6 +4016,8 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/patsy-1.0.2-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pip-25.2-pyh8b19718_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/polars-1.35.2-pyh6a1acc5_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/polars-runtime-32-1.35.2-py310h34bb384_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/prometheus-cpp-1.3.0-h0967b3e_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/psutil-7.1.3-py310hf151d32_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyarrow-22.0.0-py310hb6292c7_0.conda @@ -3973,6 +4027,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-xdist-3.8.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/python-3.10.19-hcd7f573_2_cpython.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python-gil-3.10.19-hd8ed1ab_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python-tzdata-2025.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.10-8_cp310.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pytz-2025.2-pyhd8ed1ab_0.conda @@ -4001,6 +4056,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/zlib-1.3.1-h8359307_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/zstd-1.5.7-h6491c7d_2.conda win-64: + - conda: https://conda.anaconda.org/conda-forge/noarch/_python_abi3_support-1.0-hd8ed1ab_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/attrs-25.4.0-pyh71513ae_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/aws-c-auth-0.9.1-h5a8d611_4.conda - conda: https://conda.anaconda.org/conda-forge/win-64/aws-c-cal-0.9.5-ha82e055_1.conda @@ -4021,6 +4077,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2025.10.5-h4c7d964_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/click-8.3.0-pyh7428d3b_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cpython-3.10.19-py310hd8ed1ab_2.conda - conda: https://conda.anaconda.org/conda-forge/win-64/cxx-compiler-1.11.0-h1c1089f_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/cython-3.1.6-py310h23e71ea_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.3.0-pyhd8ed1ab_0.conda @@ -4077,6 +4134,8 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/patsy-1.0.2-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pip-25.2-pyh8b19718_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/polars-1.35.2-pyh6a1acc5_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/polars-runtime-32-1.35.2-py310hca7251b_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/psutil-7.1.3-py310h1637853_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/pyarrow-22.0.0-py310h5588dad_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/pyarrow-core-22.0.0-py310hb6ca4c2_0_cpu.conda @@ -4085,6 +4144,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-xdist-3.8.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/python-3.10.19-hc20f281_2_cpython.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python-gil-3.10.19-hd8ed1ab_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python-tzdata-2025.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.10-8_cp310.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pytz-2025.2-pyhd8ed1ab_0.conda @@ -4122,6 +4182,7 @@ environments: linux-64: - conda: https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-2_gnu.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/_python_abi3_support-1.0-hd8ed1ab_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/attrs-25.4.0-pyh71513ae_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/aws-c-auth-0.9.1-he9688bd_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/aws-c-cal-0.9.5-h346e085_1.conda @@ -4151,6 +4212,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/click-8.3.0-pyh707e725_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/conda-gcc-specs-14.3.0-hb991d5c_7.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cpython-3.11.14-py311hd8ed1ab_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/cxx-compiler-1.11.0-hfcd1e18_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/cython-3.1.6-py311h0daaf2c_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.3.0-pyhd8ed1ab_0.conda @@ -4242,6 +4304,8 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/patsy-1.0.2-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pip-25.2-pyh8b19718_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/polars-1.35.2-pyh6a1acc5_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/polars-runtime-32-1.35.2-py310hffdcd12_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/prometheus-cpp-1.3.0-ha5d0236_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/psutil-7.1.3-py311haee01d2_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pyarrow-22.0.0-py311h38be061_0.conda @@ -4251,6 +4315,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-xdist-3.8.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.11.14-hd63d673_2_cpython.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python-gil-3.11.14-hd8ed1ab_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python-tzdata-2025.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.11-8_cp311.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pytz-2025.2-pyhd8ed1ab_0.conda @@ -4279,6 +4344,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/zlib-1.3.1-hb9d3cd8_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.7-hb8e6e7a_2.conda osx-arm64: + - conda: https://conda.anaconda.org/conda-forge/noarch/_python_abi3_support-1.0-hd8ed1ab_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/attrs-25.4.0-pyh71513ae_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/aws-c-auth-0.9.1-hd6d1d5d_4.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/aws-c-cal-0.9.5-hca30140_1.conda @@ -4315,6 +4381,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/compiler-rt-19.1.7-h855ad52_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/compiler-rt_osx-arm64-19.1.7-he32a8d3_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cpython-3.11.14-py311hd8ed1ab_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/cxx-compiler-1.11.0-h88570a1_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/cython-3.1.6-py311hac7d6c3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.3.0-pyhd8ed1ab_0.conda @@ -4395,6 +4462,8 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/patsy-1.0.2-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pip-25.2-pyh8b19718_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/polars-1.35.2-pyh6a1acc5_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/polars-runtime-32-1.35.2-py310h34bb384_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/prometheus-cpp-1.3.0-h0967b3e_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/psutil-7.1.3-py311h5bb9006_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyarrow-22.0.0-py311ha1ab1f8_0.conda @@ -4404,6 +4473,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-xdist-3.8.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/python-3.11.14-h18782d2_2_cpython.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python-gil-3.11.14-hd8ed1ab_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python-tzdata-2025.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.11-8_cp311.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pytz-2025.2-pyhd8ed1ab_0.conda @@ -4432,6 +4502,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/zlib-1.3.1-h8359307_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/zstd-1.5.7-h6491c7d_2.conda win-64: + - conda: https://conda.anaconda.org/conda-forge/noarch/_python_abi3_support-1.0-hd8ed1ab_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/attrs-25.4.0-pyh71513ae_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/aws-c-auth-0.9.1-h5a8d611_4.conda - conda: https://conda.anaconda.org/conda-forge/win-64/aws-c-cal-0.9.5-ha82e055_1.conda @@ -4452,6 +4523,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2025.10.5-h4c7d964_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/click-8.3.0-pyh7428d3b_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cpython-3.11.14-py311hd8ed1ab_2.conda - conda: https://conda.anaconda.org/conda-forge/win-64/cxx-compiler-1.11.0-h1c1089f_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/cython-3.1.6-py311h9990397_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.3.0-pyhd8ed1ab_0.conda @@ -4508,6 +4580,8 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/patsy-1.0.2-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pip-25.2-pyh8b19718_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/polars-1.35.2-pyh6a1acc5_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/polars-runtime-32-1.35.2-py310hca7251b_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/psutil-7.1.3-py311hf893f09_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/pyarrow-22.0.0-py311h1ea47a8_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/pyarrow-core-22.0.0-py311ha836b3b_0_cpu.conda @@ -4516,6 +4590,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-xdist-3.8.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/python-3.11.14-h0159041_2_cpython.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python-gil-3.11.14-hd8ed1ab_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python-tzdata-2025.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.11-8_cp311.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pytz-2025.2-pyhd8ed1ab_0.conda @@ -4553,6 +4628,7 @@ environments: linux-64: - conda: https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-2_gnu.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/_python_abi3_support-1.0-hd8ed1ab_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/attrs-25.4.0-pyh71513ae_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/aws-c-auth-0.9.1-he9688bd_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/aws-c-cal-0.9.5-h346e085_1.conda @@ -4582,6 +4658,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/click-8.3.0-pyh707e725_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/conda-gcc-specs-14.3.0-hb991d5c_7.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cpython-3.12.12-py312hd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/cxx-compiler-1.11.0-hfcd1e18_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/cython-3.1.6-py312h68e6be4_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.3.0-pyhd8ed1ab_0.conda @@ -4673,6 +4750,8 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/patsy-1.0.2-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pip-25.2-pyh8b19718_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/polars-1.35.2-pyh6a1acc5_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/polars-runtime-32-1.35.2-py310hffdcd12_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/prometheus-cpp-1.3.0-ha5d0236_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/psutil-7.1.3-py312h5253ce2_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pyarrow-22.0.0-py312h7900ff3_0.conda @@ -4682,6 +4761,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-xdist-3.8.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.12.12-hd63d673_1_cpython.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python-gil-3.12.12-hd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python-tzdata-2025.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.12-8_cp312.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pytz-2025.2-pyhd8ed1ab_0.conda @@ -4710,6 +4790,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/zlib-1.3.1-hb9d3cd8_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.7-hb8e6e7a_2.conda osx-arm64: + - conda: https://conda.anaconda.org/conda-forge/noarch/_python_abi3_support-1.0-hd8ed1ab_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/attrs-25.4.0-pyh71513ae_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/aws-c-auth-0.9.1-hd6d1d5d_4.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/aws-c-cal-0.9.5-hca30140_1.conda @@ -4746,6 +4827,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/compiler-rt-19.1.7-h855ad52_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/compiler-rt_osx-arm64-19.1.7-he32a8d3_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cpython-3.12.12-py312hd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/cxx-compiler-1.11.0-h88570a1_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/cython-3.1.6-py312h6868a3c_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.3.0-pyhd8ed1ab_0.conda @@ -4826,6 +4908,8 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/patsy-1.0.2-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pip-25.2-pyh8b19718_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/polars-1.35.2-pyh6a1acc5_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/polars-runtime-32-1.35.2-py310h34bb384_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/prometheus-cpp-1.3.0-h0967b3e_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/psutil-7.1.3-py312h37e1c23_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyarrow-22.0.0-py312h1f38498_0.conda @@ -4835,6 +4919,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-xdist-3.8.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/python-3.12.12-h18782d2_1_cpython.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python-gil-3.12.12-hd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python-tzdata-2025.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.12-8_cp312.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pytz-2025.2-pyhd8ed1ab_0.conda @@ -4863,6 +4948,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/zlib-1.3.1-h8359307_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/zstd-1.5.7-h6491c7d_2.conda win-64: + - conda: https://conda.anaconda.org/conda-forge/noarch/_python_abi3_support-1.0-hd8ed1ab_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/attrs-25.4.0-pyh71513ae_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/aws-c-auth-0.9.1-h5a8d611_4.conda - conda: https://conda.anaconda.org/conda-forge/win-64/aws-c-cal-0.9.5-ha82e055_1.conda @@ -4883,6 +4969,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2025.10.5-h4c7d964_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/click-8.3.0-pyh7428d3b_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cpython-3.12.12-py312hd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/win-64/cxx-compiler-1.11.0-h1c1089f_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/cython-3.1.6-py312hd245ac3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.3.0-pyhd8ed1ab_0.conda @@ -4939,6 +5026,8 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/patsy-1.0.2-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pip-25.2-pyh8b19718_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/polars-1.35.2-pyh6a1acc5_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/polars-runtime-32-1.35.2-py310hca7251b_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/psutil-7.1.3-py312he5662c2_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/pyarrow-22.0.0-py312h2e8e312_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/pyarrow-core-22.0.0-py312h85419b5_0_cpu.conda @@ -4947,6 +5036,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-xdist-3.8.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/python-3.12.12-h0159041_1_cpython.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python-gil-3.12.12-hd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python-tzdata-2025.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.12-8_cp312.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pytz-2025.2-pyhd8ed1ab_0.conda @@ -4984,6 +5074,7 @@ environments: linux-64: - conda: https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-2_gnu.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/_python_abi3_support-1.0-hd8ed1ab_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/attrs-25.4.0-pyh71513ae_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/aws-c-auth-0.9.1-he9688bd_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/aws-c-cal-0.9.5-h346e085_1.conda @@ -5013,6 +5104,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/click-8.3.0-pyh707e725_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/conda-gcc-specs-14.3.0-hb991d5c_7.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cpython-3.13.9-py313hd8ed1ab_101.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/cxx-compiler-1.11.0-hfcd1e18_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/cython-3.1.6-py313hc80a56d_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.3.0-pyhd8ed1ab_0.conda @@ -5103,6 +5195,8 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/patsy-1.0.2-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pip-25.2-pyh145f28c_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/polars-1.35.2-pyh6a1acc5_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/polars-runtime-32-1.35.2-py310hffdcd12_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/prometheus-cpp-1.3.0-ha5d0236_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/psutil-7.1.3-py313h54dd161_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pyarrow-22.0.0-py313h78bf25f_0.conda @@ -5112,6 +5206,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-xdist-3.8.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.13.9-hc97d973_101_cp313.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python-gil-3.13.9-h4df99d1_101.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python-tzdata-2025.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.13-8_cp313.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pytz-2025.2-pyhd8ed1ab_0.conda @@ -5140,6 +5235,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/zlib-1.3.1-hb9d3cd8_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.7-hb8e6e7a_2.conda osx-arm64: + - conda: https://conda.anaconda.org/conda-forge/noarch/_python_abi3_support-1.0-hd8ed1ab_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/attrs-25.4.0-pyh71513ae_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/aws-c-auth-0.9.1-hd6d1d5d_4.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/aws-c-cal-0.9.5-hca30140_1.conda @@ -5176,6 +5272,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/compiler-rt-19.1.7-h855ad52_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/compiler-rt_osx-arm64-19.1.7-he32a8d3_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cpython-3.13.9-py313hd8ed1ab_101.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/cxx-compiler-1.11.0-h88570a1_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/cython-3.1.6-py313h66a7184_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.3.0-pyhd8ed1ab_0.conda @@ -5257,6 +5354,8 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/patsy-1.0.2-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pip-25.2-pyh145f28c_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/polars-1.35.2-pyh6a1acc5_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/polars-runtime-32-1.35.2-py310h34bb384_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/prometheus-cpp-1.3.0-h0967b3e_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/psutil-7.1.3-py313h9734d34_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyarrow-22.0.0-py313h39782a4_0.conda @@ -5266,6 +5365,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-xdist-3.8.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/python-3.13.9-hfc2f54d_101_cp313.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python-gil-3.13.9-h4df99d1_101.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python-tzdata-2025.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.13-8_cp313.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pytz-2025.2-pyhd8ed1ab_0.conda @@ -5294,6 +5394,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/zlib-1.3.1-h8359307_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/zstd-1.5.7-h6491c7d_2.conda win-64: + - conda: https://conda.anaconda.org/conda-forge/noarch/_python_abi3_support-1.0-hd8ed1ab_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/attrs-25.4.0-pyh71513ae_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/aws-c-auth-0.9.1-h5a8d611_4.conda - conda: https://conda.anaconda.org/conda-forge/win-64/aws-c-cal-0.9.5-ha82e055_1.conda @@ -5314,6 +5415,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2025.10.5-h4c7d964_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/click-8.3.0-pyh7428d3b_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cpython-3.13.9-py313hd8ed1ab_101.conda - conda: https://conda.anaconda.org/conda-forge/win-64/cxx-compiler-1.11.0-h1c1089f_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/cython-3.1.6-py313h560b0a0_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.3.0-pyhd8ed1ab_0.conda @@ -5371,6 +5473,8 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/patsy-1.0.2-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pip-25.2-pyh145f28c_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/polars-1.35.2-pyh6a1acc5_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/polars-runtime-32-1.35.2-py310hca7251b_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/psutil-7.1.3-py313h5fd188c_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/pyarrow-22.0.0-py313hfa70ccb_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/pyarrow-core-22.0.0-py313h5921983_0_cpu.conda @@ -5379,6 +5483,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-xdist-3.8.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/python-3.13.9-h09917c8_101_cp313.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python-gil-3.13.9-h4df99d1_101.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python-tzdata-2025.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.13-8_cp313.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pytz-2025.2-pyhd8ed1ab_0.conda @@ -5416,6 +5521,7 @@ environments: linux-64: - conda: https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-2_gnu.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/_python_abi3_support-1.0-hd8ed1ab_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/attrs-25.3.0-pyh71513ae_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/aws-c-auth-0.9.1-he9688bd_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/aws-c-cal-0.9.5-h346e085_1.conda @@ -5445,6 +5551,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/click-8.1.8-pyh707e725_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/conda-gcc-specs-14.3.0-hb991d5c_7.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cpython-3.9.23-py39hd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/cxx-compiler-1.11.0-hfcd1e18_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/cython-3.1.3-py39h6bc127c_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.3.0-pyhd8ed1ab_0.conda @@ -5537,6 +5644,8 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/patsy-1.0.1-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pip-25.2-pyh8b19718_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/polars-1.33.1-default_h755bcc6_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/polars-default-1.33.1-py39hf521cc8_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/prometheus-cpp-1.3.0-ha5d0236_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/psutil-7.0.0-py39h8cd3c5a_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pyarrow-21.0.0-py39hf3d152e_0.conda @@ -5546,6 +5655,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-xdist-3.8.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.9.23-hc30ae73_0_cpython.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python-gil-3.9.23-hd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python-tzdata-2025.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.9-8_cp39.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pytz-2025.2-pyhd8ed1ab_0.conda @@ -5574,6 +5684,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/zlib-1.3.1-hb9d3cd8_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.7-hb8e6e7a_2.conda osx-arm64: + - conda: https://conda.anaconda.org/conda-forge/noarch/_python_abi3_support-1.0-hd8ed1ab_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/astor-0.8.1-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/attrs-25.3.0-pyh71513ae_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/aws-c-auth-0.9.1-hd6d1d5d_4.conda @@ -5612,6 +5723,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/compiler-rt-19.1.7-h855ad52_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/compiler-rt_osx-arm64-19.1.7-he32a8d3_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cpython-3.9.23-py39hd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/cxx-compiler-1.11.0-h88570a1_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/cython-3.1.3-py39hba8e057_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.3.0-pyhd8ed1ab_0.conda @@ -5693,6 +5805,8 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/patsy-1.0.1-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pip-25.2-pyh8b19718_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/polars-1.33.1-default_h107b989_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/polars-default-1.33.1-py39h31c57e4_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/prometheus-cpp-1.3.0-h0967b3e_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/psutil-7.0.0-py39hf3bc14e_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyarrow-21.0.0-py39hdf13c20_0.conda @@ -5702,6 +5816,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-xdist-3.8.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/python-3.9.23-h7139b31_0_cpython.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python-gil-3.9.23-hd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python-tzdata-2025.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.9-8_cp39.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pytz-2025.2-pyhd8ed1ab_0.conda @@ -5730,6 +5845,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/zlib-1.3.1-h8359307_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/zstd-1.5.7-h6491c7d_2.conda win-64: + - conda: https://conda.anaconda.org/conda-forge/noarch/_python_abi3_support-1.0-hd8ed1ab_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/attrs-25.3.0-pyh71513ae_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/aws-c-auth-0.9.1-h5a8d611_4.conda - conda: https://conda.anaconda.org/conda-forge/win-64/aws-c-cal-0.9.5-ha82e055_1.conda @@ -5750,6 +5866,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2025.10.5-h4c7d964_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/click-8.1.8-pyh7428d3b_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cpython-3.9.23-py39hd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/cxx-compiler-1.11.0-h1c1089f_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/cython-3.1.3-py39hc6ecc89_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.3.0-pyhd8ed1ab_0.conda @@ -5806,6 +5923,8 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/patsy-1.0.1-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pip-25.2-pyh8b19718_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/polars-1.33.1-default_hd0420bf_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/polars-default-1.33.1-py39he906d20_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/psutil-7.0.0-py39ha55e580_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/pyarrow-21.0.0-py39hcbf5309_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/pyarrow-core-21.0.0-py39hca79ef2_0_cpu.conda @@ -5814,6 +5933,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-xdist-3.8.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/python-3.9.23-h8c5b53a_0_cpython.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python-gil-3.9.23-hd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python-tzdata-2025.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.9-8_cp39.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pytz-2025.2-pyhd8ed1ab_0.conda @@ -7689,6 +7809,36 @@ packages: license_family: BSD size: 225780 timestamp: 1756544971020 +- conda: https://conda.anaconda.org/conda-forge/noarch/cpython-3.10.19-py310hd8ed1ab_2.conda + noarch: generic + sha256: a6e5a75a2a79d7bb2519930b8e897ee062983d58af97d82050698e3df4b3b100 + md5: 5aad50a3b1adaffbc9713a2a8dd87bfc + depends: + - python >=3.10,<3.11.0a0 + - python_abi * *_cp310 + license: Python-2.0 + size: 50196 + timestamp: 1761172103204 +- conda: https://conda.anaconda.org/conda-forge/noarch/cpython-3.11.14-py311hd8ed1ab_2.conda + noarch: generic + sha256: c871fe68dcc6b79b322e4fcf9f2b131162094c32a68d48c87aa8582995948a01 + md5: 43ed151bed1a0eb7181d305fed7cf051 + depends: + - python >=3.11,<3.12.0a0 + - python_abi * *_cp311 + license: Python-2.0 + size: 47257 + timestamp: 1761172995774 +- conda: https://conda.anaconda.org/conda-forge/noarch/cpython-3.12.12-py312hd8ed1ab_1.conda + noarch: generic + sha256: b88c76a6d6b45378552ccfd9e88b2a073161fe83fd1294c8fa103ffd32f7934a + md5: 99d689ccc1a360639eec979fd7805be9 + depends: + - python >=3.12,<3.13.0a0 + - python_abi * *_cp312 + license: Python-2.0 + size: 45767 + timestamp: 1761175217281 - conda: https://conda.anaconda.org/conda-forge/noarch/cpython-3.13.9-py313hd8ed1ab_101.conda noarch: generic sha256: 31da683e8a15e2062adfb29c9fb23d4253550a0b3c9be1cd45530f88796b4644 @@ -7709,6 +7859,16 @@ packages: license: Python-2.0 size: 49003 timestamp: 1761175499490 +- conda: https://conda.anaconda.org/conda-forge/noarch/cpython-3.9.23-py39hd8ed1ab_0.conda + noarch: generic + sha256: c7e0c7cf0467e80dc00107950e7295a794262d4fe3109cf6e07a90b627ea5b59 + md5: 59965790c6aef69b417ccb9938512ec9 + depends: + - python >=3.9,<3.10.0a0 + - python_abi * *_cp39 + license: Python-2.0 + size: 49247 + timestamp: 1749059639291 - conda: https://conda.anaconda.org/conda-forge/linux-64/cxx-compiler-1.11.0-hfcd1e18_0.conda sha256: 3fcc97ae3e89c150401a50a4de58794ffc67b1ed0e1851468fcc376980201e25 md5: 5da8c935dca9186673987f79cef0b2a5 @@ -14224,6 +14384,16 @@ packages: license_family: MIT size: 11766 timestamp: 1745776666688 +- conda: https://conda.anaconda.org/conda-forge/noarch/narwhals-2.0.1-pyhe01879c_0.conda + sha256: 167ed2f6100909830863531faa2dce250eedee78f2d64c4e5506dc3f3ae3c354 + md5: 5f0dea40791cecf0f82882b9eea7f7c1 + depends: + - python >=3.9 + - python + license: MIT + license_family: MIT + size: 240527 + timestamp: 1753814733349 - conda: https://conda.anaconda.org/conda-forge/noarch/narwhals-2.1.2-pyhe01879c_0.conda sha256: 54c58f45029b79a1fec25dc6f6179879afa4dddb73e5c38c85e574f66bb1d930 md5: 90d3b6c75c144e8c461b846410d7c0bf @@ -16740,6 +16910,198 @@ packages: license_family: MIT size: 24246 timestamp: 1747339794916 +- conda: https://conda.anaconda.org/conda-forge/linux-64/polars-1.33.1-default_h755bcc6_0.conda + sha256: 1e087571dd53b179e42b7d47acd6031921c9b9de4c341a408fc8bb23096d28c3 + md5: 1884a1a6acc457c8e4b59b0f6450e140 + depends: + - polars-default ==1.33.1 py39hf521cc8_0 + license: MIT + license_family: MIT + size: 5729 + timestamp: 1757413932841 +- conda: https://conda.anaconda.org/conda-forge/noarch/polars-1.35.2-pyh6a1acc5_0.conda + sha256: 21619fb41876fb3ad602de2f1a493891fd02bd82f0659d0ccb4d8ddd3271eca7 + md5: 24e8f78d79881b3c035f89f4b83c565c + depends: + - polars-runtime-32 ==1.35.2 + - python >=3.10 + - python + constrains: + - numpy >=1.16.0 + - pyarrow >=7.0.0 + - fastexcel >=0.9 + - openpyxl >=3.0.0 + - xlsx2csv >=0.8.0 + - connectorx >=0.3.2 + - deltalake >=1.0.0 + - pyiceberg >=0.7.1 + - altair >=5.4.0 + - great_tables >=0.8.0 + - polars-runtime-32 ==1.35.2 + - polars-runtime-64 ==1.35.2 + - polars-runtime-compat ==1.35.2 + license: MIT + license_family: MIT + size: 513921 + timestamp: 1763738199817 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/polars-1.33.1-default_h107b989_0.conda + sha256: 396fe6dd7d25ecd05ca1e290465c6aab30388adbb27f6b80c776f44548b9a627 + md5: 7bb9d21a632ff0e2240c475438591db7 + depends: + - polars-default ==1.33.1 py39h31c57e4_0 + license: MIT + license_family: MIT + size: 5754 + timestamp: 1757413441375 +- conda: https://conda.anaconda.org/conda-forge/win-64/polars-1.33.1-default_hd0420bf_0.conda + sha256: 8b2229f96725090d4ef1c23b0082562b048cb2a9c2abfa0c3b8e5cbcf2cf95e5 + md5: 3cb9d0e5f40305440675a5f094c3b721 + depends: + - polars-default ==1.33.1 py39he906d20_0 + license: MIT + license_family: MIT + size: 5753 + timestamp: 1757413424803 +- conda: https://conda.anaconda.org/conda-forge/linux-64/polars-default-1.33.1-py39hf521cc8_0.conda + noarch: python + sha256: 789e3a969a1b437c1df80265088ddc656dbb6f69443c0a9724a4b587faf0da42 + md5: 900f486d119d5c83d14c812068a3ecad + depends: + - python + - libgcc >=14 + - __glibc >=2.17,<3.0.a0 + - libstdcxx >=14 + - libgcc >=14 + - _python_abi3_support 1.* + - cpython >=3.9 + constrains: + - numpy >=1.16.0 + - pyarrow >=7.0.0 + - fastexcel >=0.9 + - openpyxl >=3.0.0 + - xlsx2csv >=0.8.0 + - connectorx >=0.3.2 + - deltalake >=1.0.0 + - pyiceberg >=0.7.1 + - altair >=5.4.0 + - great_tables >=0.8.0 + - polars-lts-cpu <0.0.0a0 + - polars-u64-idx <0.0.0a0 + - __glibc >=2.17 + license: MIT + license_family: MIT + size: 32170742 + timestamp: 1757413932841 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/polars-default-1.33.1-py39h31c57e4_0.conda + noarch: python + sha256: 65a0122d2ed894a9f94dcd96bd9de740ceffbf1b34341e8d6e1b1be0aa207a3a + md5: 0bac077a11de4673eeb6aa609ab7bd69 + depends: + - python + - __osx >=11.0 + - libcxx >=19 + - _python_abi3_support 1.* + - cpython >=3.9 + constrains: + - numpy >=1.16.0 + - pyarrow >=7.0.0 + - fastexcel >=0.9 + - openpyxl >=3.0.0 + - xlsx2csv >=0.8.0 + - connectorx >=0.3.2 + - deltalake >=1.0.0 + - pyiceberg >=0.7.1 + - altair >=5.4.0 + - great_tables >=0.8.0 + - polars-lts-cpu <0.0.0a0 + - polars-u64-idx <0.0.0a0 + - __osx >=11.0 + license: MIT + license_family: MIT + size: 29418459 + timestamp: 1757413441375 +- conda: https://conda.anaconda.org/conda-forge/win-64/polars-default-1.33.1-py39he906d20_0.conda + noarch: python + sha256: f30d7e72d445014d63ec907900331b20ddab87c729996dd2c39be1ae2a53854d + md5: 5ae3ef1e9e0afb6c5a86100d05890970 + depends: + - python + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + - ucrt >=10.0.20348.0 + - _python_abi3_support 1.* + - cpython >=3.9 + constrains: + - numpy >=1.16.0 + - pyarrow >=7.0.0 + - fastexcel >=0.9 + - openpyxl >=3.0.0 + - xlsx2csv >=0.8.0 + - connectorx >=0.3.2 + - deltalake >=1.0.0 + - pyiceberg >=0.7.1 + - altair >=5.4.0 + - great_tables >=0.8.0 + - polars-lts-cpu <0.0.0a0 + - polars-u64-idx <0.0.0a0 + license: MIT + license_family: MIT + size: 35019348 + timestamp: 1757413424802 +- conda: https://conda.anaconda.org/conda-forge/linux-64/polars-runtime-32-1.35.2-py310hffdcd12_0.conda + noarch: python + sha256: a2294d8079173544b519e1564ce4897dc176b92dbba9508c75c42e8cba6fe680 + md5: 2b90c3aaf73a5b6028b068cf3c76e0b7 + depends: + - python + - __glibc >=2.17,<3.0.a0 + - libstdcxx >=14 + - libgcc >=14 + - _python_abi3_support 1.* + - cpython >=3.10 + constrains: + - __glibc >=2.17 + license: MIT + license_family: MIT + size: 33271651 + timestamp: 1763738199812 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/polars-runtime-32-1.35.2-py310h34bb384_0.conda + noarch: python + sha256: 3f1b00a0ee4e56edfe272d60d51b3c243abeb1e0f872288182ef82d60f7c0d7b + md5: a5f4a3ca01f292a6b21aa42bb1c5a9aa + depends: + - python + - __osx >=11.0 + - libcxx >=19 + - _python_abi3_support 1.* + - cpython >=3.10 + constrains: + - __osx >=11.0 + license: MIT + license_family: MIT + size: 30029154 + timestamp: 1763738030442 +- conda: https://conda.anaconda.org/conda-forge/win-64/polars-runtime-32-1.35.2-py310hca7251b_0.conda + noarch: python + sha256: 03fcd84f828086be2cf658fb6250dfa665da241900f61326cae4c5d8c49642b7 + md5: 56f24763ee87604f694db3e0c74ae38c + depends: + - python + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + - ucrt >=10.0.20348.0 + - _python_abi3_support 1.* + - cpython >=3.10 + license: MIT + license_family: MIT + size: 36375197 + timestamp: 1763738028556 - conda: https://conda.anaconda.org/conda-forge/noarch/pre-commit-4.3.0-pyha770c72_0.conda sha256: 66b6d429ab2201abaa7282af06b17f7631dcaafbc5aff112922b48544514b80a md5: bc6c44af2a9e6067dd7e949ef10cdfba @@ -18459,6 +18821,33 @@ packages: license_family: BSD size: 244628 timestamp: 1755304154927 +- conda: https://conda.anaconda.org/conda-forge/noarch/python-gil-3.10.19-hd8ed1ab_2.conda + sha256: 460ea488d7b545eb434cb58a6022df14bd0ba0a9cbe2d1b5816ba9fc268615c3 + md5: 6f3b7a672f47e87de27a9941b5876f60 + depends: + - cpython 3.10.19.* + - python_abi * *_cp310 + license: Python-2.0 + size: 50183 + timestamp: 1761172142297 +- conda: https://conda.anaconda.org/conda-forge/noarch/python-gil-3.11.14-hd8ed1ab_2.conda + sha256: 9261923f0dc8a3c8c517c29d8f3b7eea80f2577b094198239895bd7a88b534c5 + md5: a4effc7e6eb335d0e1080a5554590425 + depends: + - cpython 3.11.14.* + - python_abi * *_cp311 + license: Python-2.0 + size: 47569 + timestamp: 1761172935811 +- conda: https://conda.anaconda.org/conda-forge/noarch/python-gil-3.12.12-hd8ed1ab_1.conda + sha256: 59f17182813f8b23709b7d4cfda82c33b72dd007cb729efa0033c609fbd92122 + md5: c20172b4c59fbe288fa50cdc1b693d73 + depends: + - cpython 3.12.12.* + - python_abi * *_cp312 + license: Python-2.0 + size: 45888 + timestamp: 1761175248278 - conda: https://conda.anaconda.org/conda-forge/noarch/python-gil-3.13.9-h4df99d1_101.conda sha256: 7535b9cb2414e34c73ed4a97a90bcadcc76b9d47d0bb8ef5002c592d85fe022d md5: f41e3c1125e292e6bfcea8392a3de3d8 @@ -18477,6 +18866,15 @@ packages: license: Python-2.0 size: 48968 timestamp: 1761175555295 +- conda: https://conda.anaconda.org/conda-forge/noarch/python-gil-3.9.23-hd8ed1ab_0.conda + sha256: 60faea237d55d9ff27f7a77dc720af552f2a79690d7a8718089c730255334d40 + md5: 7f35c7c4b3484c74844bb8ede73a02bc + depends: + - cpython 3.9.23.* + - python_abi * *_cp39 + license: Python-2.0 + size: 49213 + timestamp: 1749059665408 - conda: https://conda.anaconda.org/conda-forge/noarch/python-json-logger-2.0.7-pyhd8ed1ab_0.conda sha256: 4790787fe1f4e8da616edca4acf6a4f8ed4e7c6967aa31b920208fc8f95efcca md5: a61bf9ec79426938ff785eb69dbb1960 diff --git a/pixi.toml b/pixi.toml index 07736334c..f0cc70bce 100644 --- a/pixi.toml +++ b/pixi.toml @@ -54,6 +54,7 @@ wheel = "*" [dependencies] formulaic = "*" +narwhals = ">=2.0.0" numexpr = "*" packaging = "*" pandas = ">=1.4" @@ -77,6 +78,7 @@ attrs = "*" click = "*" git_root = "*" mypy = "*" +polars = "*" psutil = "*" pytest = "*" pytest-xdist = "*" @@ -134,7 +136,7 @@ cxx-compiler = "*" cython = "!=3.0.4" make = "*" mako = "*" -narwhals = ">=1.4.1" +narwhals = ">=2.0.0" pip = "*" setuptools-scm = "*" xsimd = "<11|>12.1" @@ -154,6 +156,7 @@ python = "3.13.*" [feature.oldies.dependencies] formulaic = "0.6.*" +narwhals = "2.0.*" pandas = "1.4.*" python = "3.9.*" scikit-learn = "0.24.*" diff --git a/src/glum/_glm.py b/src/glum/_glm.py index f5ab58b62..c15c2d029 100644 --- a/src/glum/_glm.py +++ b/src/glum/_glm.py @@ -4,16 +4,19 @@ import typing import warnings from collections.abc import Iterable, Mapping, Sequence -from typing import Any, Optional, Union +from typing import Any, Optional, Union, cast import formulaic +import narwhals.stable.v2 as nw import numpy as np import packaging.version import pandas as pd import scipy.sparse as sps import sklearn as skl import tabmat as tm +from narwhals.typing import IntoDataFrame from scipy import linalg, sparse, stats +from typing_extensions import deprecated from ._distribution import ( BinomialDistribution, @@ -38,12 +41,17 @@ _least_squares_solver, _trust_constr_solver, ) -from ._typing import ArrayLike, ShapedArrayLike, VectorLike, WaldTestResult +from ._typing import ( + ArrayLike, + ShapedArrayLike, + ShapedArrayLikeConverted, + VectorLike, + WaldTestResult, +) from ._utils import ( add_missing_categories, align_df_categories, expand_categorical_penalties, - is_contiguous, safe_toarray, standardize, standardize_warm_start, @@ -174,6 +182,29 @@ def link_instance(self) -> Link: else: return get_link(self.link, self.family_instance) + @property + def categorical_levels_(self) -> dict[str, list[str]]: + if hasattr(self, "_categorical_levels_"): + return self._categorical_levels_ + if hasattr(self, "feature_dtypes_"): + # Compatibility with pickled models + return { + col: dtype.categories.tolist() + for col, dtype in self.feature_dtypes_.items() + if isinstance(dtype, pd.CategoricalDtype) + } + raise AttributeError("No categorical levels stored.") + + @property + @deprecated("Use `categorical_levels_` instead.") + def feature_dtypes_(self) -> dict[str, Any]: + return self._feature_dtypes_ + + @feature_dtypes_.setter + @deprecated("Use `categorical_levels_` instead.") + def feature_dtypes_(self, value: dict[str, Any]) -> None: + self._feature_dtypes_ = value + def _get_start_coef( self, X: Union[tm.MatrixBase, tm.StandardizedMatrix], @@ -245,9 +276,9 @@ def _get_start_coef( return coef - def _convert_from_pandas( + def _convert_from_df( self, - df: pd.DataFrame, + df: IntoDataFrame, context: Optional[Mapping[str, Any]] = None, ) -> tm.MatrixBase: """Convert a pandas data frame to a tabmat matrix.""" @@ -256,17 +287,19 @@ def _convert_from_pandas( cat_missing_method_after_alignment = getattr(self, "cat_missing_method", "fail") - if hasattr(self, "feature_dtypes_"): + df = nw.from_native(df) + + if hasattr(self, "categorical_levels_"): df = align_df_categories( df, - self.feature_dtypes_, + self.categorical_levels_, getattr(self, "has_missing_category_", {}), cat_missing_method_after_alignment, ) if cat_missing_method_after_alignment == "convert": df = add_missing_categories( df=df, - dtypes=self.feature_dtypes_, + categorical_levels=self.categorical_levels_, feature_names=self.feature_names_, cat_missing_name=self.cat_missing_name, categorical_format=self.categorical_format, @@ -274,7 +307,7 @@ def _convert_from_pandas( # there should be no missing categories after this cat_missing_method_after_alignment = "fail" - X = tm.from_pandas( + X = tm.from_df( df, drop_first=self.drop_first, categorical_format=getattr( # convention prior to v3 @@ -718,8 +751,8 @@ def linear_predictor( elif alpha is not None: alpha_index = [self._find_alpha_index(a) for a in alpha] # type: ignore - if isinstance(X, pd.DataFrame): - X = self._convert_from_pandas(X, context=capture_context(context)) + if nw.dependencies.is_into_dataframe(X): + X = self._convert_from_df(X, context=capture_context(context)) X = check_array_tabmat_compliant( X, @@ -807,8 +840,9 @@ def predict( array, shape (n_samples, n_alphas) Predicted values times ``sample_weight``. """ - if isinstance(X, pd.DataFrame): - X = self._convert_from_pandas(X, context=capture_context(context)) + if nw.dependencies.is_into_dataframe(X): + X = self._convert_from_df(X, context=capture_context(context)) + X = cast(ShapedArrayLikeConverted, X) eta = self.linear_predictor( X, offset=offset, alpha_index=alpha_index, alpha=alpha, context=context @@ -1452,8 +1486,8 @@ def covariance_matrix( y = self.y_model_spec_.get_model_matrix(X).toarray().ravel() # This has to go first because X is modified in the next line - if isinstance(X, pd.DataFrame): - X = self._convert_from_pandas(X, context=capture_context(context)) + if nw.dependencies.is_into_dataframe(X): + X = self._convert_from_df(X, context=capture_context(context)) X, y = check_X_y_tabmat_compliant( X, @@ -1566,8 +1600,8 @@ def covariance_matrix( def score( self, X: ShapedArrayLike, - y: ShapedArrayLike, - sample_weight: Optional[ArrayLike] = None, + y: VectorLike, + sample_weight: Optional[VectorLike] = None, offset: Optional[ArrayLike] = None, *, context: Optional[Union[int, Mapping[str, Any]]] = None, @@ -1724,7 +1758,7 @@ def _should_copy_X(self): def _set_up_and_check_fit_args( self, X: ArrayLike, - y: Optional[ArrayLike], + y: Optional[VectorLike], sample_weight: Optional[VectorLike], offset: Optional[VectorLike], force_all_finite, @@ -1747,8 +1781,8 @@ def _set_up_and_check_fit_args( copy_X = self._should_copy_X() drop_first = getattr(self, "drop_first", False) - if isinstance(X, pd.DataFrame): - if hasattr(self, "formula") and self.formula is not None: + if nw.dependencies.is_into_dataframe(X): + if getattr(self, "formula", None) is not None: lhs, rhs = parse_formula( self.formula, include_intercept=self.fit_intercept ) @@ -1802,16 +1836,28 @@ def _set_up_and_check_fit_args( else: # Maybe TODO: expand categorical penalties with formulas - self.feature_dtypes_ = X.dtypes.to_dict() + # Backwards compatibility + if isinstance(X, pd.DataFrame): + self.feature_dtypes_ = X.dtypes.to_dict() + + X = cast(nw.DataFrame, nw.from_native(X)) # avoid inferring `Never` + + self._categorical_levels_ = { + col: X[col].cat.get_categories().to_list() + for col, dtype in X.schema.items() + if isinstance(dtype, (nw.Categorical, nw.Enum)) + } self.has_missing_category_ = { col: (getattr(self, "cat_missing_method", "fail") == "convert") - and X[col].isna().any() - for col, dtype in self.feature_dtypes_.items() - if isinstance(dtype, pd.CategoricalDtype) + and X[col].is_null().any() + for col in self.categorical_levels_ } - if any(X.dtypes == "category"): + if any( + isinstance(dtype, (nw.Categorical, nw.Enum)) + for dtype in X.schema.values() + ): P1 = expand_categorical_penalties( self.P1, X, drop_first, self.has_missing_category_ ) @@ -1819,7 +1865,7 @@ def _set_up_and_check_fit_args( self.P2, X, drop_first, self.has_missing_category_ ) - X = tm.from_pandas( + X = tm.from_df( X, drop_first=drop_first, categorical_format=getattr( # convention prior to v3 @@ -1835,14 +1881,6 @@ def _set_up_and_check_fit_args( "requires y to be passed, but the target y is None." ) - if not is_contiguous(X): - if self.copy_X is not None and not self.copy_X: - raise ValueError( - "The X matrix is noncontiguous and copy_X = False." - "To fix this, either set copy_X = None or pass a contiguous matrix." - ) - X = X.copy() - if ( not isinstance(X, tm.CategoricalMatrix) and hasattr(X, "dtype") @@ -2672,8 +2710,8 @@ def fit( def _compute_information_criteria( self, - X: ShapedArrayLike, - y: ShapedArrayLike, + X: ShapedArrayLikeConverted, + y: VectorLike, sample_weight: Optional[ArrayLike] = None, context: Optional[Mapping[str, Any]] = None, ): @@ -2732,7 +2770,7 @@ def _compute_information_criteria( def aic( self, X: ArrayLike, - y: ArrayLike, + y: VectorLike, sample_weight: Optional[ArrayLike] = None, *, context: Optional[Union[int, Mapping[str, Any]]] = None, @@ -2769,7 +2807,7 @@ def aic( def aicc( self, X: ArrayLike, - y: ArrayLike, + y: VectorLike, sample_weight: Optional[ArrayLike] = None, *, context: Optional[Union[int, Mapping[str, Any]]] = None, @@ -2814,7 +2852,7 @@ def aicc( def bic( self, X: ArrayLike, - y: ArrayLike, + y: VectorLike, sample_weight: Optional[ArrayLike] = None, *, context: Optional[Union[int, Mapping[str, Any]]] = None, @@ -2853,7 +2891,7 @@ def _get_info_criteria( self, crit: str, X: ArrayLike, - y: ArrayLike, + y: VectorLike, sample_weight: Optional[ArrayLike] = None, context: Optional[Union[int, Mapping[str, Any]]] = None, ): diff --git a/src/glum/_typing.py b/src/glum/_typing.py index 2d21461bc..fcf494419 100644 --- a/src/glum/_typing.py +++ b/src/glum/_typing.py @@ -4,6 +4,7 @@ import pandas as pd import scipy.sparse import tabmat as tm +from narwhals.typing import IntoDataFrame VectorLike = Union[np.ndarray, pd.api.extensions.ExtensionArray, pd.Index, pd.Series] @@ -11,7 +12,7 @@ list, tm.MatrixBase, tm.StandardizedMatrix, - pd.DataFrame, + IntoDataFrame, scipy.sparse.spmatrix, VectorLike, ] @@ -19,7 +20,14 @@ ShapedArrayLike = Union[ tm.MatrixBase, tm.StandardizedMatrix, - pd.DataFrame, + IntoDataFrame, + scipy.sparse.spmatrix, + VectorLike, +] + +ShapedArrayLikeConverted = Union[ + tm.MatrixBase, + tm.StandardizedMatrix, scipy.sparse.spmatrix, VectorLike, ] diff --git a/src/glum/_utils.py b/src/glum/_utils.py index 9bb54aa5f..ffc56fbaa 100644 --- a/src/glum/_utils.py +++ b/src/glum/_utils.py @@ -2,8 +2,8 @@ from collections.abc import Sequence from typing import Any, Optional, Union +import narwhals.stable.v2 as nw import numpy as np -import pandas as pd import tabmat as tm from scipy import sparse @@ -11,50 +11,42 @@ def align_df_categories( - df, dtypes, has_missing_category, cat_missing_method -) -> pd.DataFrame: + df: nw.DataFrame, + categorical_levels: dict[str, list[str]], + has_missing_category: dict[str, bool], + cat_missing_method: str, +) -> nw.DataFrame: """Align data types for prediction. This function checks that categorical columns have same categories in the - same order as specified in ``dtypes``. If an entry has a category not - specified in ``dtypes``, it will be set to ``numpy.nan``. - - Parameters - ---------- - df : pandas.DataFrame - dtypes : Dict[str, str | type | pandas.core.dtypes.base.ExtensionDtype] - has_missing_category : Dict[str, bool] - missing_method : str + same order as specified in ``categorical_levels``. If an entry has a category not + specified in ``categorical_levels``, it will be set to ``numpy.nan``. """ - if not isinstance(df, pd.DataFrame): - raise TypeError(f"Expected `pandas.DataFrame'; got {type(df)}.") - - changed_dtypes = {} - - categorical_dtypes = [ - column - for column, dtype in dtypes.items() - if isinstance(dtype, pd.CategoricalDtype) and (column in df) - ] - - for column in categorical_dtypes: - if not isinstance(df[column].dtype, pd.CategoricalDtype): - _logger.info(f"Casting {column} to categorical.") - changed_dtypes[column] = df[column].astype(dtypes[column]) - elif list(df[column].cat.categories) != list(dtypes[column].categories): + if not isinstance(df, nw.DataFrame): + raise TypeError(f"Expected `narwhals.DataFrame'; got {type(df)}.") + + changed_dtypes: dict[str, nw.Series] = {} + + for column, levels in categorical_levels.items(): + if column not in df.schema: + continue + elif not isinstance(df[column].dtype, (nw.Enum)): + _logger.info(f"Casting {column} to Enum (categorical).") + elif df[column].cat.get_categories().to_list() != levels: _logger.info(f"Aligning categories of {column}.") - changed_dtypes[column] = df[column].cat.set_categories( - dtypes[column].categories - ) else: continue + changed_dtypes[column] = df[column].cast(nw.Enum(levels)) + if cat_missing_method == "convert" and not has_missing_category[column]: - unseen_categories = set(df[column].unique()) - unseen_categories = unseen_categories - set(dtypes[column].categories) + unseen_categories = set(df[column].unique()) - set( + categorical_levels[column] + ) else: - unseen_categories = set(df[column].dropna().unique()) - unseen_categories = unseen_categories - set(dtypes[column].categories) + unseen_categories = set(df[column].drop_nulls().unique()) - set( + categorical_levels[column] + ) if unseen_categories: raise ValueError( @@ -62,51 +54,49 @@ def align_df_categories( ) if changed_dtypes: - df = df.assign(**changed_dtypes) + df = df.with_columns(**changed_dtypes) return df def add_missing_categories( - df, - dtypes, + df: nw.DataFrame, + categorical_levels: dict[str, list[str]], feature_names: Sequence[str], categorical_format: str, cat_missing_name: str, -) -> pd.DataFrame: - if not isinstance(df, pd.DataFrame): - raise TypeError(f"Expected `pandas.DataFrame'; got {type(df)}.") - - changed_dtypes = {} +) -> nw.DataFrame: + if not isinstance(df, nw.DataFrame): + raise TypeError(f"Expected `narwhals.DataFrame'; got {type(df)}.") - categorical_dtypes = [ - column - for column, dtype in dtypes.items() - if isinstance(dtype, pd.CategoricalDtype) and (column in df) - ] + changed_dtypes: dict[str, nw.Series] = {} - for column in categorical_dtypes: + for column in categorical_levels: if ( categorical_format.format(name=column, category=cat_missing_name) in feature_names ): - if cat_missing_name in df[column].cat.categories: + if cat_missing_name in df[column].cat.get_categories(): raise ValueError( f"Missing category {cat_missing_name} already exists in {column}." ) _logger.info(f"Adding missing category {cat_missing_name} to {column}.") - changed_dtypes[column] = df[column].cat.add_categories(cat_missing_name) - if df[column].isnull().any(): - changed_dtypes[column] = changed_dtypes[column].fillna(cat_missing_name) + changed_dtypes[column] = df[column].cast( + nw.Enum(df[column].cat.get_categories().to_list() + [cat_missing_name]) + ) + if df[column].is_null().any(): + changed_dtypes[column] = changed_dtypes[column].fill_null( + cat_missing_name + ) if changed_dtypes: - df = df.assign(**changed_dtypes) + df = df.with_columns(**changed_dtypes) return df def expand_categorical_penalties( - penalty, X, drop_first, has_missing_category + penalty, X: nw.DataFrame, drop_first: bool, has_missing_category: dict[str, bool] ) -> Union[np.ndarray, str]: """Determine penalty matrices ``P1`` or ``P2`` after expanding categorical columns. @@ -129,9 +119,13 @@ def expand_categorical_penalties( expanded_penalty = [] # type: ignore - for element, (column, dt) in zip(penalty, X.dtypes.items()): - if isinstance(dt, pd.CategoricalDtype): - length = len(dt.categories) + has_missing_category[column] - drop_first + for element, (column, dt) in zip(penalty, X.schema.items()): + if isinstance(dt, (nw.Enum, nw.Categorical)): + length = ( + len(X[column].cat.get_categories()) + + has_missing_category[column] + - drop_first + ) expanded_penalty.extend(element for _ in range(length)) else: expanded_penalty.append(element) @@ -142,16 +136,6 @@ def expand_categorical_penalties( return penalty -def is_contiguous(X) -> bool: - if isinstance(X, np.ndarray): - return X.flags["C_CONTIGUOUS"] or X.flags["F_CONTIGUOUS"] - elif isinstance(X, pd.DataFrame): - return is_contiguous(X.values) - else: - # If not a numpy array or pandas data frame, we assume it is contiguous. - return True - - def safe_toarray(X) -> np.ndarray: """Return a numpy array.""" if sparse.issparse(X): diff --git a/src/glum/_validation.py b/src/glum/_validation.py index 079ab5516..b9146e838 100644 --- a/src/glum/_validation.py +++ b/src/glum/_validation.py @@ -1,9 +1,9 @@ import copy import typing +import narwhals.stable.v2 as nw import numpy as np import packaging.version -import pandas as pd import sklearn as skl import tabmat as tm from scipy import sparse @@ -20,7 +20,7 @@ def check_array_tabmat_compliant(mat: ArrayLike, drop_first: bool = False, **kwargs): to_copy = kwargs.get("copy", False) - if isinstance(mat, pd.DataFrame): + if nw.dependencies.is_into_dataframe(mat): raise RuntimeError("DataFrames should have been converted by this point.") if isinstance(mat, tm.SplitMatrix): diff --git a/tests/glm/test_utils.py b/tests/glm/test_utils.py index 7bc58ee2e..552c2536a 100644 --- a/tests/glm/test_utils.py +++ b/tests/glm/test_utils.py @@ -1,3 +1,4 @@ +import narwhals.stable.v2 as nw import numpy as np import pandas as pd import pytest @@ -7,7 +8,7 @@ @pytest.fixture() def df(): - return pd.DataFrame( + _df = pd.DataFrame( { "x1": np.array([0, 1], dtype="int64"), "x2": np.array([0, 1], dtype="bool"), @@ -19,11 +20,11 @@ def df(): "x8": pd.Categorical(["a", pd.NA], categories=["b", "a"]), } ) + return nw.from_native(_df) def test_align_df_categories_numeric(df): - dtypes = {column: np.float64 for column in df} - has_missing_category = {column: False for column in df} + has_missing_category = {column: False for column in df.columns} missing_method = "fail" expected = pd.DataFrame( @@ -40,14 +41,15 @@ def test_align_df_categories_numeric(df): ) pd.testing.assert_frame_equal( - align_df_categories(df, dtypes, has_missing_category, missing_method), expected + align_df_categories(df, {}, has_missing_category, missing_method).to_native(), + expected, ) def test_align_df_categories_categorical(df): df = df[["x5", "x6", "x7", "x8"]] - dtypes = {column: pd.CategoricalDtype(["a", "b"]) for column in df} - has_missing_category = {column: False for column in df} + categorical_levels = {column: ["a", "b"] for column in df.columns} + has_missing_category = {column: False for column in df.columns} missing_method = "fail" expected = pd.DataFrame( @@ -57,18 +59,19 @@ def test_align_df_categories_categorical(df): "x7": pd.Categorical(["a", "b"]), "x8": pd.Categorical(["a", pd.NA], categories=["b", "a"]), }, - dtype=pd.CategoricalDtype(["a", "b"]), + dtype=pd.CategoricalDtype(["a", "b"], ordered=True), ) pd.testing.assert_frame_equal( - align_df_categories(df, dtypes, has_missing_category, missing_method), + align_df_categories( + df, categorical_levels, has_missing_category, missing_method + ).to_native(), expected, ) def test_align_df_categories_excess_columns(df): - dtypes = {"x1": np.float64} - has_missing_category = {column: False for column in df} + has_missing_category = {column: False for column in df.columns} missing_method = "fail" expected = pd.DataFrame( @@ -85,13 +88,13 @@ def test_align_df_categories_excess_columns(df): ) pd.testing.assert_frame_equal( - align_df_categories(df, dtypes, has_missing_category, missing_method), expected + align_df_categories(df, {}, has_missing_category, missing_method).to_native(), + expected, ) def test_align_df_categories_missing_columns(df): - dtypes = {"x0": np.float64} - has_missing_category = {column: False for column in df} + has_missing_category = {column: False for column in df.columns} missing_method = "fail" expected = pd.DataFrame( @@ -108,15 +111,16 @@ def test_align_df_categories_missing_columns(df): ) pd.testing.assert_frame_equal( - align_df_categories(df, dtypes, has_missing_category, missing_method), expected + align_df_categories(df, {}, has_missing_category, missing_method).to_native(), + expected, ) @pytest.mark.parametrize("has_missings", [False, True]) def test_align_df_categories_convert(df, has_missings): df = df[["x5", "x6", "x7", "x8"]] - dtypes = {column: pd.CategoricalDtype(["a", "b"]) for column in df} - has_missing_category = {column: has_missings for column in df} + categorical_levels = {column: ["a", "b"] for column in df.columns} + has_missing_category = {column: has_missings for column in df.columns} missing_method = "convert" expected = pd.DataFrame( @@ -126,38 +130,38 @@ def test_align_df_categories_convert(df, has_missings): "x7": pd.Categorical(["a", "b"]), "x8": pd.Categorical(["a", pd.NA], categories=["b", "a"]), }, - dtype=pd.CategoricalDtype(["a", "b"]), + dtype=pd.CategoricalDtype(["a", "b"], ordered=True), ) if has_missings: pd.testing.assert_frame_equal( align_df_categories( df[["x5", "x6", "x7", "x8"]], - dtypes, + categorical_levels, has_missing_category, missing_method, - ), + ).to_native(), expected, ) else: with pytest.raises(ValueError, match="contains unseen categories"): align_df_categories( df[["x5", "x6", "x7", "x8"]], - dtypes, + categorical_levels, has_missing_category, missing_method, ) def test_align_df_categories_raise_on_unseen(df): - dtypes = {column: pd.CategoricalDtype(["a", "b"]) for column in df} - has_missing_category = {column: False for column in df} + categorical_levels = {column: ["a", "b"] for column in df.columns} + has_missing_category = {column: False for column in df.columns} missing_method = "fail" with pytest.raises(ValueError, match="contains unseen categories"): align_df_categories( df, - dtypes, + categorical_levels, has_missing_category, missing_method, ) @@ -170,7 +174,7 @@ def test_align_df_categories_not_df(): @pytest.fixture() def df_na(): - return pd.DataFrame( + df = pd.DataFrame( { "num": np.array([0, 1], dtype="float64"), "cat": pd.Categorical(["a", "b"]), @@ -178,12 +182,17 @@ def df_na(): "cat2": pd.Categorical(["a", "b"]), } ) + return nw.from_native(df) def test_add_missing_categories(df_na): categorical_format = "{name}[{category}]" cat_missing_name = "(M)" - dtypes = df_na.dtypes + categorical_levels = { + "cat": ["a", "b", "(M)"], + "cat_na": ["a", "(M)"], + "cat2": ["a", "b"], + } feature_names = [ "num", "num[(M)]", @@ -199,20 +208,26 @@ def test_add_missing_categories(df_na): expected = pd.DataFrame( { "num": np.array([0, 1], dtype="float64"), - "cat": pd.Categorical(["a", "b"], categories=["a", "b", "(M)"]), - "cat_na": pd.Categorical(["a", "(M)"], categories=["a", "(M)"]), - "cat2": pd.Categorical(["a", "b"], categories=["a", "b"]), + "cat": pd.Categorical( + ["a", "b"], categories=["a", "b", "(M)"], ordered=True + ), + "cat_na": pd.Categorical( + ["a", "(M)"], categories=["a", "(M)"], ordered=True + ), + "cat2": pd.Categorical( + ["a", "b"], categories=["a", "b"] + ), # Note: not ordered as no change was made } ) pd.testing.assert_frame_equal( add_missing_categories( df=df_na, - dtypes=dtypes, + categorical_levels=categorical_levels, feature_names=feature_names, categorical_format=categorical_format, cat_missing_name=cat_missing_name, - ), + ).to_native(), expected, ) @@ -220,7 +235,11 @@ def test_add_missing_categories(df_na): def test_raise_on_existing_missing(df_na): categorical_format = "{name}[{category}]" cat_missing_name = "(M)" - dtypes = df_na.dtypes + categorical_levels = { + "cat": ["a", "b", "(M)"], + "cat_na": ["a", "(M)"], + "cat2": ["a", "b"], + } feature_names = [ "num", "num[(M)]", @@ -233,14 +252,15 @@ def test_raise_on_existing_missing(df_na): "cat2[b]", ] - df = df_na + df = df_na.to_native() df["cat_na"] = df["cat_na"].cat.add_categories("(M)") df.loc[df.cat_na.isna(), "cat_na"] = "(M)" + df = nw.from_native(df) with pytest.raises(ValueError): add_missing_categories( df=df, - dtypes=dtypes, + categorical_levels=categorical_levels, feature_names=feature_names, categorical_format=categorical_format, cat_missing_name=cat_missing_name,