From 43ccaaab8255b40f0f8a62b79d647ecd23908a2b Mon Sep 17 00:00:00 2001 From: Chang Huan Lo Date: Wed, 11 Sep 2024 18:50:23 -0400 Subject: [PATCH] Support NumPy > 2.0 and Python 3.12 (#115) * Replace deprecated `np.string_` with `np.bytes_` * Replace `datetime.datetime.utcnow()` with `datetime.datetime.now(datetime.timezone.utc)` * Use `np.array_equal` in grayscale detection * Replace `np.in1d` with `np.isin` * Format labelstudio.py * Remove numpy version restriction + fix build name --- environment.yml | 4 ++-- sleap_io/io/labelstudio.py | 19 ++++++++++--------- sleap_io/io/slp.py | 8 ++++---- sleap_io/io/video.py | 2 +- tests/io/test_nwb.py | 2 +- 5 files changed, 18 insertions(+), 17 deletions(-) diff --git a/environment.yml b/environment.yml index d883e016..33344f92 100644 --- a/environment.yml +++ b/environment.yml @@ -14,7 +14,7 @@ dependencies: - simplejson - h5py >=3.8.0 - hdmf - - numpy <2.0.0 + - numpy - opencv - pynwb - ndx-pose @@ -24,7 +24,7 @@ dependencies: - pydocstyle - toml - twine - - build + - python-build - pip - pip: - "--editable=.[dev]" diff --git a/sleap_io/io/labelstudio.py b/sleap_io/io/labelstudio.py index c9ae3b14..95208b75 100644 --- a/sleap_io/io/labelstudio.py +++ b/sleap_io/io/labelstudio.py @@ -9,13 +9,14 @@ """ import datetime -import simplejson as json import math import uuid -from typing import Dict, Iterable, List, Tuple, Optional, Union import warnings +from typing import Dict, Iterable, List, Optional, Tuple, Union + +import simplejson as json -from sleap_io import Instance, LabeledFrame, Labels, Node, Point, Video, Skeleton +from sleap_io import Instance, LabeledFrame, Labels, Node, Point, Skeleton, Video def read_labels( @@ -193,12 +194,12 @@ def convert_labels(labels: Labels) -> List[dict]: "result": frame_annots, "was_cancelled": False, "ground_truth": False, - "created_at": datetime.datetime.utcnow().strftime( - "%Y-%m-%dT%H:%M:%S.%fZ" - ), - "updated_at": datetime.datetime.utcnow().strftime( - "%Y-%m-%dT%H:%M:%S.%fZ" - ), + "created_at": datetime.datetime.now( + datetime.timezone.utc + ).strftime("%Y-%m-%dT%H:%M:%S.%fZ"), + "updated_at": datetime.datetime.now( + datetime.timezone.utc + ).strftime("%Y-%m-%dT%H:%M:%S.%fZ"), "lead_time": 0, "result_count": 1, # "completed_by": user['id'] diff --git a/sleap_io/io/slp.py b/sleap_io/io/slp.py index abb6614d..605545aa 100644 --- a/sleap_io/io/slp.py +++ b/sleap_io/io/slp.py @@ -434,7 +434,7 @@ def write_videos(labels_path: str, videos: list[Video], restore_source: bool = F video_json = video_to_dict(video) - video_jsons.append(np.string_(json.dumps(video_json, separators=(",", ":")))) + video_jsons.append(np.bytes_(json.dumps(video_json, separators=(",", ":")))) with h5py.File(labels_path, "a") as f: f.create_dataset("videos_json", data=video_jsons, maxshape=(None,)) @@ -466,7 +466,7 @@ def write_tracks(labels_path: str, tracks: list[Track]): # TODO: Add support for track metadata like spawned on frame. SPAWNED_ON = 0 tracks_json = [ - np.string_(json.dumps([SPAWNED_ON, track.name], separators=(",", ":"))) + np.bytes_(json.dumps([SPAWNED_ON, track.name], separators=(",", ":"))) for track in tracks ] with h5py.File(labels_path, "a") as f: @@ -517,7 +517,7 @@ def write_suggestions( "frame_idx": suggestion.frame_idx, "group": GROUP, } - suggestion_json = np.string_(json.dumps(suggestion_dict, separators=(",", ":"))) + suggestion_json = np.bytes_(json.dumps(suggestion_dict, separators=(",", ":"))) suggestions_json.append(suggestion_json) with h5py.File(labels_path, "a") as f: @@ -743,7 +743,7 @@ def write_metadata(labels_path: str, labels: Labels): with h5py.File(labels_path, "a") as f: grp = f.require_group("metadata") grp.attrs["format_id"] = 1.2 - grp.attrs["json"] = np.string_(json.dumps(md, separators=(",", ":"))) + grp.attrs["json"] = np.bytes_(json.dumps(md, separators=(",", ":"))) def read_points(labels_path: str) -> list[Point]: diff --git a/sleap_io/io/video.py b/sleap_io/io/video.py index 25ccc0d0..d3b950df 100644 --- a/sleap_io/io/video.py +++ b/sleap_io/io/video.py @@ -148,7 +148,7 @@ def detect_grayscale(self, test_img: np.ndarray | None = None) -> bool: """ if test_img is None: test_img = self.read_test_frame() - is_grayscale = bool(np.all(test_img[..., 0] == test_img[..., -1])) + is_grayscale = np.array_equal(test_img[..., 0], test_img[..., -1]) self.grayscale = is_grayscale return is_grayscale diff --git a/tests/io/test_nwb.py b/tests/io/test_nwb.py index 5963dd92..02d14ef7 100644 --- a/tests/io/test_nwb.py +++ b/tests/io/test_nwb.py @@ -211,7 +211,7 @@ def test_complex_case_append_with_timestamps_metadata(nwbfile, centered_pair): # Other store timestamps and the timestmaps should be a subset of the videotimestamps else: extracted_timestamps = pose_estimation_series.timestamps - assert np.in1d( + assert np.isin( extracted_timestamps, video_timestamps, assume_unique=True ).all()