Skip to content

Commit 8b4eeac

Browse files
authored
Python 3.13 in CI (#425)
* Python 3.13 in CI * 3.12 for benchmarks
1 parent 48706b7 commit 8b4eeac

File tree

7 files changed

+22
-19
lines changed

7 files changed

+22
-19
lines changed

.github/workflows/ci-additional.yaml

+2-2
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ jobs:
4141

4242
env:
4343
CONDA_ENV_FILE: ci/environment.yml
44-
PYTHON_VERSION: "3.12"
44+
PYTHON_VERSION: "3.13"
4545

4646
steps:
4747
- uses: actions/checkout@v4
@@ -95,7 +95,7 @@ jobs:
9595
shell: bash -l {0}
9696
env:
9797
CONDA_ENV_FILE: ci/environment.yml
98-
PYTHON_VERSION: "3.12"
98+
PYTHON_VERSION: "3.13"
9999

100100
steps:
101101
- uses: actions/checkout@v4

.github/workflows/ci.yaml

+3-3
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,14 @@ jobs:
2626
matrix:
2727
os: ["ubuntu-latest"]
2828
env: ["environment"]
29-
python-version: ["3.10", "3.12"]
29+
python-version: ["3.10", "3.13"]
3030
include:
3131
- os: "windows-latest"
3232
env: "environment"
33-
python-version: "3.12"
33+
python-version: "3.13"
3434
- os: "ubuntu-latest"
3535
env: "no-dask" # "no-xarray", "no-numba"
36-
python-version: "3.12"
36+
python-version: "3.13"
3737
- os: "ubuntu-latest"
3838
env: "minimal-requirements"
3939
python-version: "3.10"

.github/workflows/testpypi-release.yaml

-4
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,6 @@ jobs:
2323

2424
- uses: actions/setup-python@v5
2525
name: Install Python
26-
with:
27-
python-version: "3.12"
2826

2927
- name: Install dependencies
3028
run: |
@@ -64,8 +62,6 @@ jobs:
6462
steps:
6563
- uses: actions/setup-python@v5
6664
name: Install Python
67-
with:
68-
python-version: "3.12"
6965
- uses: actions/download-artifact@v4
7066
with:
7167
name: releases

.github/workflows/upstream-dev-ci.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ jobs:
3434
strategy:
3535
fail-fast: false
3636
matrix:
37-
python-version: ["3.12"]
37+
python-version: ["3.13"]
3838
steps:
3939
- uses: actions/checkout@v4
4040
with:

flox/aggregations.py

+5-2
Original file line numberDiff line numberDiff line change
@@ -590,6 +590,7 @@ class Scan:
590590
identity: Any
591591
# dtype of result
592592
dtype: Any = None
593+
preserves_dtype: bool = False
593594
# "Mode" of applying binary op.
594595
# for np.add we apply the op directly to the `state` array and the `current` array.
595596
# for ffill, bfill we concat `state` to `current` and then run the scan again.
@@ -719,16 +720,18 @@ def scan_binary_op(left_state: ScanState, right_state: ScanState, *, agg: Scan)
719720
reduction="nanlast",
720721
scan="ffill",
721722
# Important: this must be NaN otherwise, ffill does not work.
722-
identity=np.nan,
723+
identity=dtypes.NA,
723724
mode="concat_then_scan",
725+
preserves_dtype=True,
724726
)
725727
bfill = Scan(
726728
"bfill",
727729
binary_op=None,
728730
reduction="nanlast",
729731
scan="ffill",
730732
# Important: this must be NaN otherwise, bfill does not work.
731-
identity=np.nan,
733+
identity=dtypes.NA,
734+
preserves_dtype=True,
732735
mode="concat_then_scan",
733736
preprocess=reverse,
734737
finalize=reverse,

flox/core.py

+10-7
Original file line numberDiff line numberDiff line change
@@ -2823,9 +2823,6 @@ def groupby_scan(
28232823
# nothing to do, no NaNs!
28242824
return array
28252825

2826-
is_bool_array = np.issubdtype(array.dtype, bool)
2827-
array = array.astype(np.int_) if is_bool_array else array
2828-
28292826
if expected_groups is not None:
28302827
raise NotImplementedError("Setting `expected_groups` and binning is not supported yet.")
28312828
expected_groups = _validate_expected_groups(nby, expected_groups)
@@ -2855,6 +2852,11 @@ def groupby_scan(
28552852
if array.dtype.kind in "Mm":
28562853
cast_to = array.dtype
28572854
array = array.view(np.int64)
2855+
elif array.dtype.kind == "b":
2856+
array = array.view(np.int8)
2857+
cast_to = None
2858+
if agg.preserves_dtype:
2859+
cast_to = bool
28582860
else:
28592861
cast_to = None
28602862

@@ -2869,6 +2871,7 @@ def groupby_scan(
28692871
agg.dtype = np.result_type(array.dtype, np.uint)
28702872
else:
28712873
agg.dtype = array.dtype if dtype is None else dtype
2874+
agg.identity = xrdtypes._get_fill_value(agg.dtype, agg.identity)
28722875

28732876
(single_axis,) = axis_ # type: ignore[misc]
28742877
# avoid some roundoff error when we can.
@@ -2887,7 +2890,7 @@ def groupby_scan(
28872890

28882891
if not has_dask:
28892892
final_state = chunk_scan(inp, axis=single_axis, agg=agg, dtype=agg.dtype)
2890-
result = _finalize_scan(final_state)
2893+
result = _finalize_scan(final_state, dtype=agg.dtype)
28912894
else:
28922895
result = dask_groupby_scan(inp.array, inp.group_idx, axes=axis_, agg=agg)
28932896

@@ -2940,9 +2943,9 @@ def _zip(group_idx: np.ndarray, array: np.ndarray) -> AlignedArrays:
29402943
return AlignedArrays(group_idx=group_idx, array=array)
29412944

29422945

2943-
def _finalize_scan(block: ScanState) -> np.ndarray:
2946+
def _finalize_scan(block: ScanState, dtype) -> np.ndarray:
29442947
assert block.result is not None
2945-
return block.result.array
2948+
return block.result.array.astype(dtype, copy=False)
29462949

29472950

29482951
def dask_groupby_scan(array, by, axes: T_Axes, agg: Scan) -> DaskArray:
@@ -2985,7 +2988,7 @@ def dask_groupby_scan(array, by, axes: T_Axes, agg: Scan) -> DaskArray:
29852988
)
29862989

29872990
# 3. Unzip and extract the final result array, discard groups
2988-
result = map_blocks(_finalize_scan, accumulated, dtype=agg.dtype)
2991+
result = map_blocks(partial(_finalize_scan, dtype=agg.dtype), accumulated, dtype=agg.dtype)
29892992

29902993
assert result.chunks == array.chunks
29912994

pyproject.toml

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ classifiers = [
1414
"Programming Language :: Python :: 3.10",
1515
"Programming Language :: Python :: 3.11",
1616
"Programming Language :: Python :: 3.12",
17+
"Programming Language :: Python :: 3.13",
1718
]
1819
dependencies = [
1920
"pandas>=1.5",

0 commit comments

Comments
 (0)