Skip to content

Commit b692e4f

Browse files
galenlynchclaude
andcommitted
GH #2744 Fix installation and tests for Python 3.10-3.13
Three pinned dependencies blocked installation on Python 3.12+: - numpy<1.24: no cp312 wheels, distutils removal kills source build - pandas==1.5.3: no cp312 wheels, same distutils issue - scipy<1.11: requires_python="<3.12", resolver rejects outright Dependency changes: - numpy: uncap (numpy 2.x supported after source fixes below) - pandas: relax to >=1.5.3,<3 (2.x supported; 3.0 needs further work) - scipy: uncap (1.14+ supported after interp2d removal) - pynwb: cap <3 to avoid breaking API changes - xarray: unpin <2023.2.0 (pure Python, no breakage found) - pytz: add as explicit dep (was transitive via pandas 1.x) - setuptools: cap <81 (pkg_resources removed in 81+) Source fixes for removed/changed APIs: - scipy.interpolate.interp2d → RectBivariateSpline (removed in 1.14) - ConfigParser.readfp → read_string (removed in Python 3.12) - DataFrame.iteritems() → items() (removed in pandas 2.0) - DataFrame.append() → pd.concat() (removed in pandas 2.0) - pd.to_datetime: add format="ISO8601" for mixed-precision timestamps (pandas 2.x rejects mixed microsecond precision without explicit format) - pd.to_datetime: fix utc="True" (string) → utc=True (bool) bug in behavior_project_cloud_api.py - np.int() → int() (removed in numpy 1.24) - np.NaN/np.NAN → np.nan (removed in numpy 2.0) - np.Inf → np.inf, np.string_ → np.bytes_ (removed in numpy 2.0) - np.product → np.prod, np.in1d → np.isin (removed in numpy 2.0) - np.ediff1d to_begin dtype must match array dtype in numpy 2.0 - np.VisibleDeprecationWarning → try/except import (removed in 2.0) - nwbfile.modules → .processing (pynwb 2.x deprecation) - IndexSeries unit='None' → 'N/A' (pynwb 2.5+ validation) - np.linalg.norm([array, scalar]) → np.vstack (numpy 1.24+ rejects) - aiohttp.ClientSession → lazy property (aiohttp 3.9+ event loop) - groupby().apply() → select column first (pandas 2.2+ behavior) - demixer: add np.isfinite guard after linalg.solve (some LAPACK implementations return inf instead of raising LinAlgError for singular matrices) Notebook fixes: - IPython.core.display → IPython.display (removed in IPython 8.x) in visual_behavior_compare_across_trial_types and visual_behavior_mouse_history notebooks Test fixes: - pytest.warns(None) → warnings.catch_warnings (pytest 8) - mock.called_once_with → assert_called_once() (proper assertion) - Add res.x to MagicMock for scipy.optimize result - rng.choice(inhomogeneous) → rng.integers + index (numpy 1.24+) - Widen curve-fit tolerances for platform variance - Cast dtypes for pynwb 2.x roundtrip and pandas 2.x index changes - subprocess 'python' → sys.executable for venv correctness - Replace flaky test_demix_raises_warning_for_singular_matrix with a result-based assertion in test_demix_point - from mock import → from unittest.mock import (69 test files) - Uncap/modernize test dependency bounds, remove dead weight - Add pandas 2.x datetime regression tests (test_pandas_compat.py) CI: - Update to actions/checkout@v4, actions/setup-python@v5 - Slim matrix to min/max Python (3.10, 3.13) on ubuntu, 3.13 on macOS/windows - Add pip caching, coverage on single matrix element only - Modernize notebook_runner.yml to Python 3.13 - Update nightly.yml to checkout@v4 - Switch notebook runner to ubuntu-latest-8x (32GB RAM) for ecephys notebooks that peak at ~21GB RSS - Change notebook workflow trigger to push on master (expensive job should not run on every pull request) Fixes #2747, #2744, #2746, #2754 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent a9b5c68 commit b692e4f

139 files changed

Lines changed: 386 additions & 361 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/github-actions-ci.yml

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ jobs:
2626
name: Lint
2727
runs-on: "ubuntu-latest"
2828
steps:
29-
- uses: actions/checkout@v2
29+
- uses: actions/checkout@v4
3030
- name: flake8 linting
3131
run: |
3232
pip install flake8
@@ -43,28 +43,30 @@ jobs:
4343
runs-on: ${{ matrix.os }}
4444
strategy:
4545
matrix:
46-
os: ["macos-latest", "windows-latest", "ubuntu-latest"]
47-
python-version: ["3.8", "3.9", "3.10", "3.11"]
46+
os: ["ubuntu-latest"]
47+
python-version: ["3.10", "3.13"]
48+
include:
49+
- os: "macos-latest"
50+
python-version: "3.13"
51+
- os: "windows-latest"
52+
python-version: "3.13"
4853
fail-fast: false
49-
defaults:
50-
run:
51-
shell: bash -l {0}
5254
steps:
53-
- uses: actions/checkout@v2
54-
- uses: conda-incubator/setup-miniconda@v2
55+
- uses: actions/checkout@v4
56+
- uses: actions/setup-python@v5
5557
with:
56-
auto-update-conda: true
5758
python-version: ${{ matrix.python-version }}
58-
activate-environment: test-env
59+
cache: pip
60+
cache-dependency-path: |
61+
requirements.txt
62+
test_requirements.txt
5963
- name: Install
6064
run: |
61-
conda activate test-env
62-
pip install codecov
6365
pip install -r test_requirements.txt
6466
pip install .
6567
- name: Test
6668
run: |
67-
py.test --cov=allensdk -n 4
69+
python -m pytest -n 4 ${{ (matrix.os == 'ubuntu-latest' && matrix.python-version == '3.13') && '--cov=allensdk' || '' }}
6870
6971
onprem:
7072
name: python ${{ matrix.image }} on-prem test
@@ -73,7 +75,7 @@ jobs:
7375
matrix:
7476
image: ["allensdk_local_py38:latest"]
7577
steps:
76-
- uses: actions/checkout@v2
78+
- uses: actions/checkout@v4
7779
- name: run test in docker
7880
run: |
7981
docker run \

.github/workflows/nightly.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ jobs:
1313
image: ["allensdk_local_py38:latest"]
1414
branch: ["master", "rc/**"]
1515
steps:
16-
- uses: actions/checkout@v2
16+
- uses: actions/checkout@v4
1717
with:
1818
ref: ${{ matrix.branch }}
1919
- name: run test in docker

.github/workflows/notebook_runner.yml

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,27 @@
11
name: Notebooks
22
on:
3-
pull_request:
3+
push:
44
branches:
55
- master
66
jobs:
77
run_notebooks:
88
name: Notebook runner
99
strategy:
1010
matrix:
11-
os: ["ubuntu-latest"]
12-
python-version: ["3.8"]
11+
python-version: ["3.13"]
1312
fail-fast: false
14-
runs-on: ${{ matrix.os }}
13+
runs-on: ubuntu-latest-8x
1514
steps:
16-
- uses: actions/checkout@v3
15+
- uses: actions/checkout@v4
1716
- name: Set up Python
18-
uses: actions/setup-python@v4
17+
uses: actions/setup-python@v5
1918
with:
2019
python-version: ${{ matrix.python-version }}
20+
cache: pip
21+
cache-dependency-path: |
22+
requirements.txt
23+
dev_requirements.txt
24+
notebook_requirements.txt
2125
- name: Install
2226
run: |
2327
pip install -r requirements.txt

allensdk/brain_observatory/behavior/behavior_project_cache/project_apis/data_io/behavior_project_cloud_api.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ def _get_ophys_session_table(self):
187187
df = sanitize_data_columns(session_table_path, {"mouse_id": str})
188188
# Add UTC to match DateOfAcquisition object.
189189
df["date_of_acquisition"] = pd.to_datetime(
190-
df["date_of_acquisition"], utc="True"
190+
df["date_of_acquisition"], format="ISO8601", utc=True
191191
)
192192
df = enforce_df_int_typing(
193193
input_df=df, int_columns=VBO_INTEGER_COLUMNS, use_pandas_type=True
@@ -217,7 +217,7 @@ def _get_behavior_session_table(self):
217217
df = sanitize_data_columns(session_table_path, {"mouse_id": str})
218218
# Add UTC to match DateOfAcquisition object.
219219
df["date_of_acquisition"] = pd.to_datetime(
220-
df["date_of_acquisition"], utc="True"
220+
df["date_of_acquisition"], format="ISO8601", utc=True
221221
)
222222
df = enforce_df_int_typing(
223223
input_df=df, int_columns=VBO_INTEGER_COLUMNS, use_pandas_type=True
@@ -252,7 +252,7 @@ def _get_ophys_experiment_table(self):
252252
df = sanitize_data_columns(experiment_table_path, {"mouse_id": str})
253253
# Add UTC to match DateOfAcquisition object.
254254
df["date_of_acquisition"] = pd.to_datetime(
255-
df["date_of_acquisition"], utc="True"
255+
df["date_of_acquisition"], format="ISO8601", utc=True
256256
)
257257
df = enforce_df_int_typing(
258258
input_df=df, int_columns=VBO_INTEGER_COLUMNS, use_pandas_type=True

allensdk/brain_observatory/behavior/behavior_project_cache/project_apis/data_io/behavior_project_lims_api.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -511,7 +511,7 @@ def get_ophys_session_table(self) -> pd.DataFrame:
511511
)
512512
# Make date time explicitly UTC.
513513
table["date_of_acquisition"] = pd.to_datetime(
514-
table["date_of_acquisition"], utc=True
514+
table["date_of_acquisition"], format="ISO8601", utc=True
515515
)
516516

517517
# Fill NaN values of imaging_plane_group_count with zero to match
@@ -554,7 +554,7 @@ def get_ophys_experiment_table(self) -> pd.DataFrame:
554554
"""
555555
df = self._get_ophys_experiment_table()
556556
df["date_of_acquisition"] = pd.to_datetime(
557-
df["date_of_acquisition"], utc=True
557+
df["date_of_acquisition"], format="ISO8601", utc=True
558558
)
559559
# Set type to pandas.Int64 to enforce integer typing and not revert to
560560
# float.
@@ -581,7 +581,7 @@ def get_behavior_session_table(self) -> pd.DataFrame:
581581
summary_tbl = self._get_behavior_summary_table()
582582
# Add UTC time zone to match timezone from DateOfAcquisition object.
583583
summary_tbl["date_of_acquisition"] = pd.to_datetime(
584-
summary_tbl["date_of_acquisition"], utc=True
584+
summary_tbl["date_of_acquisition"], format="ISO8601", utc=True
585585
)
586586
# Query returns float typing of age_in_days. Convert to int to match
587587
# typing of the Age data_object.

allensdk/brain_observatory/behavior/behavior_project_cache/tables/metadata_table_schemas.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ class BehaviorSessionMetadataSchema(RaisingSchema):
7878
def convert_date_time(self, data, **kwargs):
7979
"""Change date_of_acquisition to a date time type from string."""
8080
data["date_of_acquisition"] = pd.to_datetime(
81-
data["date_of_acquisition"], utc=True
81+
data["date_of_acquisition"], format="ISO8601", utc=True
8282
)
8383
return data
8484

allensdk/brain_observatory/behavior/data_objects/cell_specimens/cell_specimens.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -857,13 +857,13 @@ def _validate_traces(
857857
if traces is None:
858858
continue
859859
# validate traces contain expected roi ids
860-
if not np.in1d(traces.value.index, cell_roi_ids).all():
860+
if not np.isin(traces.value.index, cell_roi_ids).all():
861861
raise RuntimeError(
862862
f"{traces.name} contains ROI IDs that "
863863
f"are not in "
864864
f"cell_specimen_table.cell_roi_id"
865865
)
866-
if not np.in1d(cell_roi_ids, traces.value.index).all():
866+
if not np.isin(cell_roi_ids, traces.value.index).all():
867867
raise RuntimeError(
868868
f"cell_specimen_table contains ROI IDs "
869869
f"that are not in {traces.name}"

allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ def get_task_parameters(data: Dict) -> Dict:
149149
# displayed stimuli (no flashes).
150150

151151
if stim_duration is None:
152-
stim_duration = np.NaN
152+
stim_duration = np.nan
153153
else:
154154
stim_duration = stim_duration[0]
155155

allensdk/brain_observatory/behavior/data_objects/running_speed/running_acquisition.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ def from_nwb(
129129
cls,
130130
nwbfile: NWBFile
131131
) -> "RunningAcquisition":
132-
running_module = nwbfile.modules['running']
132+
running_module = nwbfile.processing['running']
133133
dx_interface = running_module.get_data_interface('dx')
134134

135135
dx = dx_interface.data

allensdk/brain_observatory/behavior/data_objects/running_speed/running_speed.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ def from_nwb(
188188
nwbfile: NWBFile,
189189
filtered=True
190190
) -> "RunningSpeed":
191-
running_module = nwbfile.modules['running']
191+
running_module = nwbfile.processing['running']
192192
interface_name = 'speed' if filtered else 'speed_unfiltered'
193193
running_interface = running_module.get_data_interface(interface_name)
194194

0 commit comments

Comments
 (0)