From b786596729940fa5b8d6cdf56fc53a6b3f039afd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dennis=20G=C3=B6ries?= Date: Sat, 27 Dec 2025 22:18:12 +0100 Subject: [PATCH 1/4] refactor: Migrate to Python 3.14 --- .github/workflows/python-app.yml | 4 +- src/downsample/_ltd.c | 98 ++++++++++++-------------------- 2 files changed, 39 insertions(+), 63 deletions(-) diff --git a/.github/workflows/python-app.yml b/.github/workflows/python-app.yml index 656405b..929cbf9 100644 --- a/.github/workflows/python-app.yml +++ b/.github/workflows/python-app.yml @@ -12,7 +12,7 @@ jobs: strategy: matrix: os: [ubuntu-latest] - python-version: ["3.11", "3.12", "3.13", "3.13"] + python-version: ["3.11", "3.12", "3.13", "3.14"] steps: - name: Check out repository @@ -35,4 +35,4 @@ jobs: - name: Test with pytest run: | - pytest \ No newline at end of file + pytest diff --git a/src/downsample/_ltd.c b/src/downsample/_ltd.c index ecbf6c6..bc92b33 100644 --- a/src/downsample/_ltd.c +++ b/src/downsample/_ltd.c @@ -36,20 +36,20 @@ static PyObject *split_bucket_at(PyObject *buckets_list, int index) { return NULL; } - // Get the bucket of interest and index + // Get the bucket of interest PyArrayObject *bucket = (PyArrayObject *)PyList_GetItem(buckets_list, index); npy_intp bucket_size = PyArray_DIM(bucket, 0); npy_intp dim = PyArray_DIM(bucket, 1); - // calculate split sizes and split the bucket into half + // calculate split sizes npy_intp bucket_a_length = (npy_intp)ceil((double)bucket_size / 2.0); npy_intp bucket_b_length = bucket_size - bucket_a_length; npy_intp dims_a[2] = {bucket_a_length, dim}; npy_intp dims_b[2] = {bucket_b_length, dim}; - // get views for bucket_a and bucket_b in the original data + // get views double *bucket_a_data = (double *)PyArray_DATA(bucket); double *bucket_b_data = (double *)PyArray_GETPTR2(bucket, bucket_a_length, 0); @@ -59,23 +59,27 @@ static PyObject *split_bucket_at(PyObject *buckets_list, int index) { PyObject *bucket_b = PyArray_SimpleNewFromData(2, dims_b, NPY_DOUBLE, bucket_b_data); - // resulting bucket size increases by 1 - PyObject *result_buckets = PyList_New(bucket_count + 1); + // Ensure bucket stays alive exactly as long as either bucket_a or + // bucket_b exists. + Py_INCREF(bucket); + PyArray_SetBaseObject((PyArrayObject *)bucket_a, (PyObject *)bucket); + Py_INCREF(bucket); + PyArray_SetBaseObject((PyArrayObject *)bucket_b, (PyObject *)bucket); + PyObject *result_buckets = PyList_New(bucket_count + 1); for (Py_ssize_t i = 0; i < bucket_count; i++) { - // Note: Don't copy bucket at 'index', it is split later. if (i == index) { continue; } PyObject *item = PyList_GetItem(buckets_list, i); Py_INCREF(item); - PyList_SET_ITEM(result_buckets, (i < index) ? i : i + 1, item); + PyList_SetItem(result_buckets, (i < index) ? i : i + 1, item); } - // Insert to the new list the split bucket at index and index +1 - // Note: PyList_SET_ITEM steals the references of bucket_a and bucket_b - PyList_SET_ITEM(result_buckets, index, bucket_a); - PyList_SET_ITEM(result_buckets, index + 1, bucket_b); + // Insert split buckets + // PyList_SetItem steals the reference + PyList_SetItem(result_buckets, index, bucket_a); + PyList_SetItem(result_buckets, index + 1, bucket_b); return result_buckets; } @@ -92,39 +96,33 @@ static PyObject *merge_bucket_at(PyObject *buckets_list, int index) { PyArrayObject *bucket_b = (PyArrayObject *)PyList_GetItem(buckets_list, index + 1); - // set up the new concatenated bucket as a Python list with the two parts to - // be merged PyObject *arrays_to_merge = PyList_New(2); Py_INCREF(bucket_a); Py_INCREF(bucket_b); - PyList_SET_ITEM(arrays_to_merge, 0, (PyObject *)bucket_a); - PyList_SET_ITEM(arrays_to_merge, 1, (PyObject *)bucket_b); - // merge not bucket_a and bucket_b + PyList_SetItem(arrays_to_merge, 0, (PyObject *)bucket_a); + PyList_SetItem(arrays_to_merge, 1, (PyObject *)bucket_b); + PyObject *merged_bucket = PyArray_Concatenate(arrays_to_merge, 0); Py_DECREF(arrays_to_merge); - // create a new list with the merged bucket in place of bucket_a and - // bucket_b, so the bucket count goes -1 PyObject *result_buckets = PyList_New(bucket_count - 1); - // Copy the other items into result_buckets until the specified index + for (Py_ssize_t i = 0; i < index; i++) { PyObject *item = PyList_GetItem(buckets_list, i); Py_INCREF(item); - PyList_SET_ITEM(result_buckets, i, item); + PyList_SetItem(result_buckets, i, item); } - // place the merged bucket at index - PyList_SET_ITEM(result_buckets, index, merged_bucket); - // And finally copy buckets after index + 1 from buckets_list to - // result_buckets, shifting each index by one (due to the removal of one - // bucket). + PyList_SetItem(result_buckets, index, merged_bucket); + for (Py_ssize_t i = index + 2; i < bucket_count; i++) { PyObject *item = PyList_GetItem(buckets_list, i); Py_INCREF(item); - PyList_SET_ITEM(result_buckets, i - 1, item); + PyList_SetItem(result_buckets, i - 1, item); } - Py_DECREF(buckets_list); + + // No DECREF of buckets_list here (borrowed ref) return result_buckets; } @@ -185,7 +183,6 @@ static PyObject *LTTB_for_buckets(PyObject *buckets_list) { PyObject *result = PyTuple_Pack(2, x_array, y_array); Py_DECREF(x_array); Py_DECREF(y_array); - // This function borrows the list, hence it should not destroy it (DECREF). return result; } @@ -195,9 +192,6 @@ static double calculate_sse_for_bucket(PyArrayObject *bucket) { npy_intp num_points = PyArray_DIM(bucket, 0); double *data = (double *)PyArray_DATA(bucket); - // We calculate the sum of squared errors (SSE) where - // first, we need calculate linear regression coefficients for the fit - // function (y = a * x + b) double sum_x = 0.0, sum_y = 0.0; double a_numerator = 0.0; double a_denominator = 0.0; @@ -209,8 +203,6 @@ static double calculate_sse_for_bucket(PyArrayObject *bucket) { double avg_x = sum_x / (double)num_points; double avg_y = sum_y / (double)num_points; - // Calculate how the regression line (fitted) predicts the y values - // with the x values. for (npy_intp i = 0; i < num_points; i++) { double deviation_x = data[i * 2] - avg_x; double deviation_y = data[i * 2 + 1] - avg_y; @@ -250,8 +242,6 @@ static npy_intp find_highest_sse_bucket_index(PyObject *buckets_list, double max_sse = 0.0; npy_intp max_sse_idx = -1; - // Find the maximum SSE index, excluding the first and last elements, - // they are always set to zero for (npy_intp i = 1; i < sse_len - 1; i++) { PyObject *bucket = PyList_GetItem(buckets_list, i); npy_intp bucket_dim = PyArray_DIM((PyArrayObject *)bucket, 0); @@ -278,7 +268,6 @@ static npy_intp find_lowest_sse_adjacent_buckets_index(PyArrayObject *sse_array, double min_sse_sum = INFINITY; npy_intp min_sse_index = -1; - // Find adjacent buckets with the lowest sse, excluding ignoreIndex for (npy_intp i = 1; i < sse_len - 2; i++) { if (i == ignore_index || i + 1 == ignore_index) { continue; @@ -303,7 +292,7 @@ static PyObject *calculate_sse_for_buckets(PyObject *buckets_list) { npy_intp sse_len = num_buckets; PyObject *sse_array = PyArray_Zeros(1, &sse_len, PyArray_DescrFromType(NPY_DOUBLE), 0); - // We have a zeros array, hence start and end are filled already + double *sse_data = (double *)PyArray_DATA((PyArrayObject *)sse_array); for (Py_ssize_t i = 1; i < num_buckets - 1; i++) { @@ -316,31 +305,25 @@ static PyObject *calculate_sse_for_buckets(PyObject *buckets_list) { npy_intp curr_rows = PyArray_DIM(curr_bucket, 0); npy_intp cols = PyArray_DIM(curr_bucket, 1); - // Combined array has 2 rows more + npy_intp combined_dims[2] = {curr_rows + 2, cols}; PyArrayObject *bucket_with_adj = (PyArrayObject *)PyArray_SimpleNew(2, combined_dims, NPY_DOUBLE); - // Copy data from the last row of prev_bucket to the first row of - // bucket_with_adj double *bucket_adj_data = (double *)PyArray_DATA(bucket_with_adj); double *prev_last_row = (double *)PyArray_GETPTR2( prev_bucket, PyArray_DIM(prev_bucket, 0) - 1, 0); memcpy(bucket_adj_data, prev_last_row, cols * __DOUBLE_SIZE__); - // Copy data from curr_bucket into the middle rows of bucket_with_adj double *curr_data = (double *)PyArray_DATA(curr_bucket); memcpy(bucket_adj_data + cols, curr_data, curr_rows * cols * __DOUBLE_SIZE__); - // Copy data from the first row of next_bucket to the last row of - // bucket_with_adj double *next_first_row = (double *)PyArray_GETPTR2(next_bucket, 0, 0); memcpy(bucket_adj_data + (curr_rows + 1) * cols, next_first_row, cols * __DOUBLE_SIZE__); sse_data[i] = calculate_sse_for_bucket(bucket_with_adj); - // Don't forget to DECREF! Py_DECREF(bucket_with_adj); } @@ -348,8 +331,6 @@ static PyObject *calculate_sse_for_buckets(PyObject *buckets_list) { } static PyObject *ltd_for_buckets(PyObject *buckets_list) { - // We modify the local 'buckets_list' variable (swap it), - // so we must own a reference to it initially. Py_INCREF(buckets_list); Py_ssize_t num_buckets = PyList_Size(buckets_list); @@ -387,6 +368,7 @@ static PyObject *ltd_for_buckets(PyObject *buckets_list) { lowest_sse_adjacent_bucket_index += 1; } + // Merge PyObject *merged_buckets = merge_bucket_at(buckets_list, lowest_sse_adjacent_bucket_index); @@ -398,8 +380,6 @@ static PyObject *ltd_for_buckets(PyObject *buckets_list) { PyObject *lttb_result = LTTB_for_buckets(buckets_list); - // Finally, release the final buckets_list (balances the initial INCREF - // or creation in loop Py_DECREF(buckets_list); return lttb_result; @@ -416,24 +396,25 @@ static PyObject *split_into_buckets(PyArrayObject *data, int threshold) { npy_intp first_dims[2] = {1, num_cols}; PyArrayObject *first_point = (PyArrayObject *)PyArray_SimpleNewFromData( 2, first_dims, NPY_DOUBLE, PyArray_DATA(data)); - PyList_SET_ITEM(buckets, 0, (PyObject *)first_point); + + PyList_SetItem(buckets, 0, (PyObject *)first_point); double bucket_size = (double)(num_points - 2) / (threshold - 2); for (int i = 0; i < threshold - 2; i++) { - npy_intp bucket_start_index = - (npy_intp)floor(i * bucket_size) + 1; // Skip the first element + npy_intp bucket_start_index = (npy_intp)floor(i * bucket_size) + 1; npy_intp bucket_end_index = (npy_intp)floor((i + 1) * bucket_size) + 1; npy_intp current_bucket_size = bucket_end_index - bucket_start_index; npy_intp bucket_dims[2] = {current_bucket_size, num_cols}; - // PyArray_DATA provides starting pointer for this bucket, we shift + double *bucket_start_ptr = (double *)PyArray_DATA(data) + bucket_start_index * num_cols; - // Create a new view for the current bucket + PyArrayObject *current_bucket = (PyArrayObject *)PyArray_SimpleNewFromData( 2, bucket_dims, NPY_DOUBLE, (void *)bucket_start_ptr); - PyList_SET_ITEM(buckets, i + 1, (PyObject *)current_bucket); + + PyList_SetItem(buckets, i + 1, (PyObject *)current_bucket); } // And the last point as the last bucket for margins @@ -442,7 +423,8 @@ static PyObject *split_into_buckets(PyArrayObject *data, int threshold) { (double *)PyArray_DATA(data) + (num_points - 1) * num_cols; PyArrayObject *last_point = (PyArrayObject *)PyArray_SimpleNewFromData( 2, last_dims, NPY_DOUBLE, (void *)last_point_ptr); - PyList_SET_ITEM(buckets, threshold - 1, (PyObject *)last_point); + + PyList_SetItem(buckets, threshold - 1, (PyObject *)last_point); return buckets; } @@ -486,21 +468,16 @@ static PyObject *largest_triangle_dynamic(PyObject *self, PyObject *args) { npy_intp len_points = PyArray_DIM(x, 0); if (threshold >= len_points || len_points <= 2) { - // If the threshold is greater than the number of points, return x and y - // as they are. - // Special case if the length of points. PyObject *result = PyTuple_Pack(2, x, y); Py_DECREF(x); Py_DECREF(y); return result; } - // Create 2 dim array for combined points npy_intp points_dims[2] = {len_points, 2}; PyArrayObject *points = (PyArrayObject *)PyArray_SimpleNew(2, points_dims, NPY_DOUBLE); - // Fill points array with x and y values double *points_data = (double *)PyArray_DATA(points); for (npy_intp i = 0; i < len_points; i++) { points_data[i * 2] = *(double *)PyArray_GETPTR1(x, i); @@ -510,7 +487,6 @@ static PyObject *largest_triangle_dynamic(PyObject *self, PyObject *args) { PyObject *buckets = split_into_buckets(points, threshold); PyObject *result = ltd_for_buckets(buckets); - // Clean up references Py_DECREF(x); Py_DECREF(y); Py_DECREF(buckets); From 9619e22e1fdd4e8c1d805e56997bc8341cc292d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dennis=20G=C3=B6ries?= Date: Sat, 27 Dec 2025 22:29:40 +0100 Subject: [PATCH 2/4] Reference count changed in python 3.14 --- src/downsample/tests/test_ltd.py | 144 +++++++++++++++---------------- 1 file changed, 72 insertions(+), 72 deletions(-) diff --git a/src/downsample/tests/test_ltd.py b/src/downsample/tests/test_ltd.py index a3585a0..6977d97 100644 --- a/src/downsample/tests/test_ltd.py +++ b/src/downsample/tests/test_ltd.py @@ -18,25 +18,25 @@ def test_single_array(): """Test that the ltd algorithm rejects arrays with multiple dims""" x = np.linspace(0, 1, 100000) y = np.random.rand(100000) - assert sys.getrefcount(x) == 2 - assert sys.getrefcount(y) == 2 + assert sys.getrefcount(x) <= 2 + assert sys.getrefcount(y) <= 2 nx, ny = downsample.ltd(x, y, 100) assert nx.dtype == np.double assert ny.dtype == np.double - assert sys.getrefcount(x) == 2 - assert sys.getrefcount(y) == 2 + assert sys.getrefcount(x) <= 2 + assert sys.getrefcount(y) <= 2 assert nx.shape == (100,) assert ny.shape == (100,) - assert sys.getrefcount(nx) == 2 - assert sys.getrefcount(ny) == 2 + assert sys.getrefcount(nx) <= 2 + assert sys.getrefcount(ny) <= 2 def test_negative_threshold(): """Test if a negative threshold provides problems""" x = np.arange(100000, dtype=np.int32) y = np.random.randint(1000, size=100000, dtype=np.uint64) - assert sys.getrefcount(x) == 2 - assert sys.getrefcount(y) == 2 + assert sys.getrefcount(x) <= 2 + assert sys.getrefcount(y) <= 2 with pytest.raises(ValueError): downsample.ltd(x, y, -100) @@ -45,35 +45,35 @@ def test_threshold_larger(): """Test if a larger threshold provides problems""" x = np.arange(100000, dtype=np.int32) y = np.random.randint(1000, size=100000, dtype=np.uint64) - assert sys.getrefcount(x) == 2 - assert sys.getrefcount(y) == 2 + assert sys.getrefcount(x) <= 2 + assert sys.getrefcount(y) <= 2 # Will return the arrays! nx, ny = downsample.ltd(x, y, 100000 + 1) assert len(nx) == 100000 assert len(ny) == 100000 assert nx.dtype == np.double assert ny.dtype == np.double - assert sys.getrefcount(x) == 2 - assert sys.getrefcount(y) == 2 - assert sys.getrefcount(nx) == 2 - assert sys.getrefcount(ny) == 2 + assert sys.getrefcount(x) <= 2 + assert sys.getrefcount(y) <= 2 + assert sys.getrefcount(nx) <= 2 + assert sys.getrefcount(ny) <= 2 def test_input_list(): """Test the down sampling with lists types""" x = list(range(100000)) y = [True] * 100000 - assert sys.getrefcount(x) == 2 - assert sys.getrefcount(y) == 2 + assert sys.getrefcount(x) <= 2 + assert sys.getrefcount(y) <= 2 nx, ny = downsample.ltd(x, y, 10) assert len(nx) == 10 assert len(ny) == 10 assert nx.dtype == np.double assert ny.dtype == np.double - assert sys.getrefcount(x) == 2 - assert sys.getrefcount(y) == 2 - assert sys.getrefcount(nx) == 2 - assert sys.getrefcount(ny) == 2 + assert sys.getrefcount(x) <= 2 + assert sys.getrefcount(y) <= 2 + assert sys.getrefcount(nx) <= 2 + assert sys.getrefcount(ny) <= 2 test_array = np.array([0.0, 1.0, 12500.0, 25000.0, 37500.0, 50000.0, 62499.0, 74999.0, 87499.0, 99999.0], dtype=np.double) @@ -87,17 +87,17 @@ def test_input_list_array(): """Test the down sampling with mixed types""" x = list(range(100000)) y = np.array([True] * 100000, dtype=bool) - assert sys.getrefcount(x) == 2 - assert sys.getrefcount(y) == 2 + assert sys.getrefcount(x) <= 2 + assert sys.getrefcount(y) <= 2 nx, ny = downsample.ltd(x, y, 100) assert len(nx) == 100 assert len(ny) == 100 assert nx.dtype == np.double assert ny.dtype == np.double - assert sys.getrefcount(x) == 2 - assert sys.getrefcount(y) == 2 - assert sys.getrefcount(nx) == 2 - assert sys.getrefcount(ny) == 2 + assert sys.getrefcount(x) <= 2 + assert sys.getrefcount(y) <= 2 + assert sys.getrefcount(nx) <= 2 + assert sys.getrefcount(ny) <= 2 test_array = np.array([1.0] * 100, dtype=np.double) test_array_bool = np.array([1.0] * 100, dtype=bool) np.testing.assert_array_almost_equal(ny, test_array) @@ -108,46 +108,46 @@ def test_array_size(): """Test the input failure for different dimensions of arrays""" x = np.arange(100000) y = np.random.randint(1000, size=100000 - 1, dtype=np.uint64) - assert sys.getrefcount(x) == 2 - assert sys.getrefcount(y) == 2 + assert sys.getrefcount(x) <= 2 + assert sys.getrefcount(y) <= 2 with pytest.raises(ValueError): assert downsample.ltd(x, y, 100000) - assert sys.getrefcount(x) == 2 - assert sys.getrefcount(y) == 2 + assert sys.getrefcount(x) <= 2 + assert sys.getrefcount(y) <= 2 def test_ltd_uint64(): """Test the base down sampling of the module""" x = np.arange(100000, dtype=np.int32) y = np.random.randint(1000, size=100000, dtype=np.uint64) - assert sys.getrefcount(x) == 2 - assert sys.getrefcount(y) == 2 + assert sys.getrefcount(x) <= 2 + assert sys.getrefcount(y) <= 2 nx, ny = downsample.ltd(x, y, 100) assert len(nx) == 100 assert len(ny) == 100 assert nx.dtype == np.double assert ny.dtype == np.double - assert sys.getrefcount(x) == 2 - assert sys.getrefcount(y) == 2 - assert sys.getrefcount(nx) == 2 - assert sys.getrefcount(ny) == 2 + assert sys.getrefcount(x) <= 2 + assert sys.getrefcount(y) <= 2 + assert sys.getrefcount(nx) <= 2 + assert sys.getrefcount(ny) <= 2 def test_ltd_bool(): """Test the down sampling with boolean types""" x = np.arange(100000, dtype=np.int32) y = np.array([True] * 100000, dtype=bool) - assert sys.getrefcount(x) == 2 - assert sys.getrefcount(y) == 2 + assert sys.getrefcount(x) <= 2 + assert sys.getrefcount(y) <= 2 nx, ny = downsample.ltd(x, y, 100) assert len(nx) == 100 assert len(ny) == 100 assert nx.dtype == np.double assert ny.dtype == np.double - assert sys.getrefcount(x) == 2 - assert sys.getrefcount(y) == 2 - assert sys.getrefcount(nx) == 2 - assert sys.getrefcount(ny) == 2 + assert sys.getrefcount(x) <= 2 + assert sys.getrefcount(y) <= 2 + assert sys.getrefcount(nx) <= 2 + assert sys.getrefcount(ny) <= 2 test_array = np.array([1.0] * 100, dtype=np.double) test_array_bool = np.array([1.0] * 100, dtype=bool) np.testing.assert_array_almost_equal(ny, test_array) @@ -158,17 +158,17 @@ def test_inf(): """Test the down sampling with inf types""" x = np.arange(100000, dtype=np.int32) y = np.array([np.inf] * 100000, dtype=np.double) - assert sys.getrefcount(x) == 2 - assert sys.getrefcount(y) == 2 + assert sys.getrefcount(x) <= 2 + assert sys.getrefcount(y) <= 2 nx, ny = downsample.ltd(x, y, 100) assert len(nx) == 100 assert len(ny) == 100 assert nx.dtype == np.double assert ny.dtype == np.double - assert sys.getrefcount(x) == 2 - assert sys.getrefcount(y) == 2 - assert sys.getrefcount(nx) == 2 - assert sys.getrefcount(ny) == 2 + assert sys.getrefcount(x) <= 2 + assert sys.getrefcount(y) <= 2 + assert sys.getrefcount(nx) <= 2 + assert sys.getrefcount(ny) <= 2 test_array = np.array([np.inf] * 100, dtype=np.double) np.testing.assert_array_almost_equal(ny, test_array) @@ -180,17 +180,17 @@ def test_single_inf(): [1.0, 1.0, 2.0, np.inf, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18, 19.0, ], dtype=np.double, ) - assert sys.getrefcount(x) == 2 - assert sys.getrefcount(y) == 2 + assert sys.getrefcount(x) <= 2 + assert sys.getrefcount(y) <= 2 nx, ny = downsample.ltd(x, y, 10) assert len(nx) == 10 assert len(ny) == 10 assert nx.dtype == np.double assert ny.dtype == np.double - assert sys.getrefcount(x) == 2 - assert sys.getrefcount(y) == 2 - assert sys.getrefcount(nx) == 2 - assert sys.getrefcount(ny) == 2 + assert sys.getrefcount(x) <= 2 + assert sys.getrefcount(y) <= 2 + assert sys.getrefcount(nx) <= 2 + assert sys.getrefcount(ny) <= 2 test_array = np.array([0., 0., 4., 5., 7., 10., 12., 14., 16., 19.], dtype=np.double) np.testing.assert_array_almost_equal(nx, test_array) @@ -203,17 +203,17 @@ def test_nan(): """Test the down sampling with NaN types""" x = np.arange(100000, dtype=np.int32) y = np.array([np.nan] * 100000, dtype=np.double) - assert sys.getrefcount(x) == 2 - assert sys.getrefcount(y) == 2 + assert sys.getrefcount(x) <= 2 + assert sys.getrefcount(y) <= 2 nx, ny = downsample.ltd(x, y, 100) assert len(nx) == 100 assert len(ny) == 100 assert nx.dtype == np.double assert ny.dtype == np.double - assert sys.getrefcount(x) == 2 - assert sys.getrefcount(y) == 2 - assert sys.getrefcount(nx) == 2 - assert sys.getrefcount(ny) == 2 + assert sys.getrefcount(x) <= 2 + assert sys.getrefcount(y) <= 2 + assert sys.getrefcount(nx) <= 2 + assert sys.getrefcount(ny) <= 2 def test_array_mix_inf_nan(): @@ -223,17 +223,17 @@ def test_array_mix_inf_nan(): [0.0, 1.0, 2.0, np.nan, 4.0, 5.0, 6.0, np.nan, np.inf, np.inf, 10.0, np.nan, 12.0, -np.inf, 14.0, 15.0, 16.0, 17.0, np.nan, 19.0, ], dtype=np.double) - assert sys.getrefcount(x) == 2 - assert sys.getrefcount(y) == 2 + assert sys.getrefcount(x) <= 2 + assert sys.getrefcount(y) <= 2 nx, ny = downsample.ltd(x, y, 10) assert len(nx) == 10 assert len(ny) == 10 assert nx.dtype == np.double assert ny.dtype == np.double - assert sys.getrefcount(x) == 2 - assert sys.getrefcount(y) == 2 - assert sys.getrefcount(nx) == 2 - assert sys.getrefcount(ny) == 2 + assert sys.getrefcount(x) <= 2 + assert sys.getrefcount(y) <= 2 + assert sys.getrefcount(nx) <= 2 + assert sys.getrefcount(ny) <= 2 test_array = np.array( [0., 0., 4., 4., 6., np.inf, np.nan, -np.inf, 15., 19.], dtype=np.double) @@ -246,18 +246,18 @@ def test_single_nan(): y = np.array([0.0, 1.0, 2.0, np.nan, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18, 19.0, ], dtype=np.double) - assert sys.getrefcount(x) == 2 - assert sys.getrefcount(y) == 2 + assert sys.getrefcount(x) <= 2 + assert sys.getrefcount(y) <= 2 z = x.copy() nx, ny = downsample.ltd(x, y, 10) assert len(nx) == 10 assert len(ny) == 10 assert nx.dtype == np.double assert ny.dtype == np.double - assert sys.getrefcount(x) == 2 - assert sys.getrefcount(y) == 2 - assert sys.getrefcount(nx) == 2 - assert sys.getrefcount(ny) == 2 + assert sys.getrefcount(x) <= 2 + assert sys.getrefcount(y) <= 2 + assert sys.getrefcount(nx) <= 2 + assert sys.getrefcount(ny) <= 2 test_array = np.array([0., 0., 4., 5., 7., 10., 12., 14., 16., 19.], dtype=np.double) np.testing.assert_array_almost_equal(x, z) From a74b25fc1b0eacd57642d2572e7cf5016d480316 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dennis=20G=C3=B6ries?= Date: Sat, 27 Dec 2025 22:37:15 +0100 Subject: [PATCH 3/4] Also lttb --- src/downsample/tests/test_lttb.py | 146 +++++++++++++++--------------- 1 file changed, 73 insertions(+), 73 deletions(-) diff --git a/src/downsample/tests/test_lttb.py b/src/downsample/tests/test_lttb.py index 4c2b7a3..1b88a4d 100644 --- a/src/downsample/tests/test_lttb.py +++ b/src/downsample/tests/test_lttb.py @@ -46,7 +46,7 @@ def test_single_dimension_validation(): [0.8, 0.5], [0.8, 0.5], [0.7, 0.5], [0.1, 0.], [0., 0.]], dtype=np.double) assert x.shape == (10, 2) - assert x.ndim == 2 + assert x.ndim <= 2 y = np.array([True] * ARRAY_SIZE, dtype=bool) with pytest.raises(ValueError): @@ -57,8 +57,8 @@ def test_negative_threshold(): """Test if a negative threshold provides problems""" x = np.arange(ARRAY_SIZE, dtype=np.int32) y = np.random.randint(1000, size=ARRAY_SIZE, dtype=np.uint64) - assert sys.getrefcount(x) == 2 - assert sys.getrefcount(y) == 2 + assert sys.getrefcount(x) <= 2 + assert sys.getrefcount(y) <= 2 with pytest.raises(ValueError): downsample.lttb(x, y, -THRESHOLD) @@ -67,18 +67,18 @@ def test_threshold_larger(): """Test if a larger threshold provides problems""" x = np.arange(ARRAY_SIZE, dtype=np.int32) y = np.random.randint(1000, size=ARRAY_SIZE, dtype=np.uint64) - assert sys.getrefcount(x) == 2 - assert sys.getrefcount(y) == 2 + assert sys.getrefcount(x) <= 2 + assert sys.getrefcount(y) <= 2 # Will return the arrays! nx, ny = downsample.lttb(x, y, ARRAY_SIZE + 1) assert len(nx) == ARRAY_SIZE assert len(ny) == ARRAY_SIZE assert nx.dtype == np.double assert ny.dtype == np.double - assert sys.getrefcount(x) == 2 - assert sys.getrefcount(y) == 2 - assert sys.getrefcount(nx) == 2 - assert sys.getrefcount(ny) == 2 + assert sys.getrefcount(x) <= 2 + assert sys.getrefcount(y) <= 2 + assert sys.getrefcount(nx) <= 2 + assert sys.getrefcount(ny) <= 2 # NOTE: Known feature, we return double arrays ... np.testing.assert_array_almost_equal(nx, x) @@ -89,17 +89,17 @@ def test_input_list(): """Test the down sampling with lists types""" x = list(range(ARRAY_SIZE)) y = [True] * ARRAY_SIZE - assert sys.getrefcount(x) == 2 - assert sys.getrefcount(y) == 2 + assert sys.getrefcount(x) <= 2 + assert sys.getrefcount(y) <= 2 nx, ny = downsample.lttb(x, y, THRESHOLD) assert len(nx) == THRESHOLD assert len(ny) == THRESHOLD assert nx.dtype == np.double assert ny.dtype == np.double - assert sys.getrefcount(x) == 2 - assert sys.getrefcount(y) == 2 - assert sys.getrefcount(nx) == 2 - assert sys.getrefcount(ny) == 2 + assert sys.getrefcount(x) <= 2 + assert sys.getrefcount(y) <= 2 + assert sys.getrefcount(nx) <= 2 + assert sys.getrefcount(ny) <= 2 test_array = np.array([1.0] * THRESHOLD, dtype=np.float64) test_array_bool = np.array([1.0] * THRESHOLD, dtype=bool) np.testing.assert_array_almost_equal(ny, test_array) @@ -110,17 +110,17 @@ def test_input_list_array(): """Test the down sampling with mixed types""" x = list(range(ARRAY_SIZE)) y = np.array([True] * ARRAY_SIZE, dtype=bool) - assert sys.getrefcount(x) == 2 - assert sys.getrefcount(y) == 2 + assert sys.getrefcount(x) <= 2 + assert sys.getrefcount(y) <= 2 nx, ny = downsample.lttb(x, y, THRESHOLD) assert len(nx) == THRESHOLD assert len(ny) == THRESHOLD assert nx.dtype == np.double assert ny.dtype == np.double - assert sys.getrefcount(x) == 2 - assert sys.getrefcount(y) == 2 - assert sys.getrefcount(nx) == 2 - assert sys.getrefcount(ny) == 2 + assert sys.getrefcount(x) <= 2 + assert sys.getrefcount(y) <= 2 + assert sys.getrefcount(nx) <= 2 + assert sys.getrefcount(ny) <= 2 test_array = np.array([1.0] * THRESHOLD, dtype=np.float64) test_array_bool = np.array([1.0] * THRESHOLD, dtype=bool) np.testing.assert_array_almost_equal(ny, test_array) @@ -131,46 +131,46 @@ def test_array_size(): """Test the input failure for different dimensions of arrays""" x = np.arange(ARRAY_SIZE) y = np.random.randint(1000, size=ARRAY_SIZE - 1, dtype=np.uint64) - assert sys.getrefcount(x) == 2 - assert sys.getrefcount(y) == 2 + assert sys.getrefcount(x) <= 2 + assert sys.getrefcount(y) <= 2 with pytest.raises(ValueError): assert downsample.lttb(x, y, ARRAY_SIZE) - assert sys.getrefcount(x) == 2 - assert sys.getrefcount(y) == 2 + assert sys.getrefcount(x) <= 2 + assert sys.getrefcount(y) <= 2 def test_downsample_uint64(): """Test the base down sampling of the module""" x = np.arange(ARRAY_SIZE, dtype=np.int32) y = np.random.randint(1000, size=ARRAY_SIZE, dtype=np.uint64) - assert sys.getrefcount(x) == 2 - assert sys.getrefcount(y) == 2 + assert sys.getrefcount(x) <= 2 + assert sys.getrefcount(y) <= 2 nx, ny = downsample.lttb(x, y, THRESHOLD) assert len(nx) == THRESHOLD assert len(ny) == THRESHOLD assert nx.dtype == np.double assert ny.dtype == np.double - assert sys.getrefcount(x) == 2 - assert sys.getrefcount(y) == 2 - assert sys.getrefcount(nx) == 2 - assert sys.getrefcount(ny) == 2 + assert sys.getrefcount(x) <= 2 + assert sys.getrefcount(y) <= 2 + assert sys.getrefcount(nx) <= 2 + assert sys.getrefcount(ny) <= 2 def test_downsample_bool(): """Test the down sampling with boolean types""" x = np.arange(ARRAY_SIZE, dtype=np.int32) y = np.array([True] * ARRAY_SIZE, dtype=bool) - assert sys.getrefcount(x) == 2 - assert sys.getrefcount(y) == 2 + assert sys.getrefcount(x) <= 2 + assert sys.getrefcount(y) <= 2 nx, ny = downsample.lttb(x, y, THRESHOLD) assert len(nx) == THRESHOLD assert len(ny) == THRESHOLD assert nx.dtype == np.double assert ny.dtype == np.double - assert sys.getrefcount(x) == 2 - assert sys.getrefcount(y) == 2 - assert sys.getrefcount(nx) == 2 - assert sys.getrefcount(ny) == 2 + assert sys.getrefcount(x) <= 2 + assert sys.getrefcount(y) <= 2 + assert sys.getrefcount(nx) <= 2 + assert sys.getrefcount(ny) <= 2 test_array = np.array([1.0] * THRESHOLD, dtype=np.float64) test_array_bool = np.array([1.0] * THRESHOLD, dtype=bool) np.testing.assert_array_almost_equal(ny, test_array) @@ -181,17 +181,17 @@ def test_inf(): """Test the down sampling with inf types""" x = np.arange(ARRAY_SIZE, dtype=np.int32) y = np.array([np.inf] * ARRAY_SIZE, dtype=np.float64) - assert sys.getrefcount(x) == 2 - assert sys.getrefcount(y) == 2 + assert sys.getrefcount(x) <= 2 + assert sys.getrefcount(y) <= 2 nx, ny = downsample.lttb(x, y, THRESHOLD) assert len(nx) == THRESHOLD assert len(ny) == THRESHOLD assert nx.dtype == np.double assert ny.dtype == np.double - assert sys.getrefcount(x) == 2 - assert sys.getrefcount(y) == 2 - assert sys.getrefcount(nx) == 2 - assert sys.getrefcount(ny) == 2 + assert sys.getrefcount(x) <= 2 + assert sys.getrefcount(y) <= 2 + assert sys.getrefcount(nx) <= 2 + assert sys.getrefcount(ny) <= 2 test_array = np.array([0.0] * THRESHOLD, dtype=np.float64) np.testing.assert_array_almost_equal(ny, test_array) @@ -200,17 +200,17 @@ def test_nan(): """Test the down sampling with NaN types""" x = np.arange(ARRAY_SIZE, dtype=np.int32) y = np.array([np.nan] * ARRAY_SIZE, dtype=np.float64) - assert sys.getrefcount(x) == 2 - assert sys.getrefcount(y) == 2 + assert sys.getrefcount(x) <= 2 + assert sys.getrefcount(y) <= 2 nx, ny = downsample.lttb(x, y, THRESHOLD) assert len(nx) == THRESHOLD assert len(ny) == THRESHOLD assert nx.dtype == np.double assert ny.dtype == np.double - assert sys.getrefcount(x) == 2 - assert sys.getrefcount(y) == 2 - assert sys.getrefcount(nx) == 2 - assert sys.getrefcount(ny) == 2 + assert sys.getrefcount(x) <= 2 + assert sys.getrefcount(y) <= 2 + assert sys.getrefcount(nx) <= 2 + assert sys.getrefcount(ny) <= 2 test_array = np.array([0.0] * THRESHOLD, dtype=np.float64) np.testing.assert_array_almost_equal(ny, test_array) @@ -219,8 +219,8 @@ def test_benchmark(): """Basic skeletton benchmark test for the down sample algorithm""" x = np.arange(LARGE_ARRAY, dtype=np.int32) y = np.arange(LARGE_ARRAY, dtype=np.float64) - assert sys.getrefcount(x) == 2 - assert sys.getrefcount(y) == 2 + assert sys.getrefcount(x) <= 2 + assert sys.getrefcount(y) <= 2 def sample(): nx, ny = downsample.lttb(x, y, LARGE_THRESHOLD) @@ -234,10 +234,10 @@ def sample(): assert len(ny) == LARGE_THRESHOLD assert nx.dtype == np.double assert ny.dtype == np.double - assert sys.getrefcount(x) == 2 - assert sys.getrefcount(y) == 2 - assert sys.getrefcount(nx) == 2 - assert sys.getrefcount(ny) == 2 + assert sys.getrefcount(x) <= 2 + assert sys.getrefcount(y) <= 2 + assert sys.getrefcount(nx) <= 2 + assert sys.getrefcount(ny) <= 2 assert elapsed < 0.1 @@ -248,17 +248,17 @@ def test_array_mix_inf_nan(): y = np.array([0.0, 1.0, 2.0, np.nan, 4.0, 5.0, 6.0, np.nan, np.inf, np.inf, 10.0, np.nan, 12.0, -np.inf, 14.0, 15.0, 16.0, 17.0, np.nan, 19.0], dtype=np.float64) - assert sys.getrefcount(x) == 2 - assert sys.getrefcount(y) == 2 + assert sys.getrefcount(x) <= 2 + assert sys.getrefcount(y) <= 2 nx, ny = downsample.lttb(x, y, 10) assert len(nx) == 10 assert len(ny) == 10 assert nx.dtype == np.double assert ny.dtype == np.double - assert sys.getrefcount(x) == 2 - assert sys.getrefcount(y) == 2 - assert sys.getrefcount(nx) == 2 - assert sys.getrefcount(ny) == 2 + assert sys.getrefcount(x) <= 2 + assert sys.getrefcount(y) <= 2 + assert sys.getrefcount(nx) <= 2 + assert sys.getrefcount(ny) <= 2 test_array = np.array( [0., 0., 4., 0., 0., 0., 12., 0., 16., 19.], dtype=np.float64) np.testing.assert_array_almost_equal(ny, test_array) @@ -270,17 +270,17 @@ def test_single_nan(): y = np.array([0.0, 1.0, 2.0, np.nan, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0], dtype=np.float64) - assert sys.getrefcount(x) == 2 - assert sys.getrefcount(y) == 2 + assert sys.getrefcount(x) <= 2 + assert sys.getrefcount(y) <= 2 nx, ny = downsample.lttb(x, y, 10) assert len(nx) == 10 assert len(ny) == 10 assert nx.dtype == np.double assert ny.dtype == np.double - assert sys.getrefcount(x) == 2 - assert sys.getrefcount(y) == 2 - assert sys.getrefcount(nx) == 2 - assert sys.getrefcount(ny) == 2 + assert sys.getrefcount(x) <= 2 + assert sys.getrefcount(y) <= 2 + assert sys.getrefcount(nx) <= 2 + assert sys.getrefcount(ny) <= 2 test_array = np.array( [0., 0., 4., 5., 7., 10., 12., 14., 16., 19.], dtype=np.float64) @@ -293,17 +293,17 @@ def test_single_inf(): y = np.array([0.0, 1.0, 2.0, np.inf, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0], dtype=np.float64) - assert sys.getrefcount(x) == 2 - assert sys.getrefcount(y) == 2 + assert sys.getrefcount(x) <= 2 + assert sys.getrefcount(y) <= 2 nx, ny = downsample.lttb(x, y, 10) assert len(nx) == 10 assert len(ny) == 10 assert nx.dtype == np.double assert ny.dtype == np.double - assert sys.getrefcount(x) == 2 - assert sys.getrefcount(y) == 2 - assert sys.getrefcount(nx) == 2 - assert sys.getrefcount(ny) == 2 + assert sys.getrefcount(x) <= 2 + assert sys.getrefcount(y) <= 2 + assert sys.getrefcount(nx) <= 2 + assert sys.getrefcount(ny) <= 2 test_array = np.array( [0., 0., 4., 5., 7., 10., 12., 14., 16., 19.], dtype=np.float64) From a43d1b6a9667cc3b61a7b23efe0270d4bd39b6a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dennis=20G=C3=B6ries?= Date: Sat, 27 Dec 2025 22:37:31 +0100 Subject: [PATCH 4/4] And ltob --- src/downsample/tests/test_ltob.py | 144 +++++++++++++++--------------- 1 file changed, 72 insertions(+), 72 deletions(-) diff --git a/src/downsample/tests/test_ltob.py b/src/downsample/tests/test_ltob.py index b41bef0..dae318a 100644 --- a/src/downsample/tests/test_ltob.py +++ b/src/downsample/tests/test_ltob.py @@ -18,25 +18,25 @@ def test_single_array(): """Test that the ltob algorithm rejects arrays with multiple dims""" x = np.linspace(0, 1, 100000) y = np.random.rand(100000) - assert sys.getrefcount(x) == 2 - assert sys.getrefcount(y) == 2 + assert sys.getrefcount(x) <= 2 + assert sys.getrefcount(y) <= 2 nx, ny = downsample.ltob(x, y, 100) assert nx.dtype == np.double assert ny.dtype == np.double - assert sys.getrefcount(x) == 2 - assert sys.getrefcount(y) == 2 + assert sys.getrefcount(x) <= 2 + assert sys.getrefcount(y) <= 2 assert nx.shape == (100,) assert ny.shape == (100,) - assert sys.getrefcount(nx) == 2 - assert sys.getrefcount(ny) == 2 + assert sys.getrefcount(nx) <= 2 + assert sys.getrefcount(ny) <= 2 def test_negative_threshold(): """Test if a negative threshold provides problems""" x = np.arange(100000, dtype=np.int32) y = np.random.randint(1000, size=100000, dtype=np.uint64) - assert sys.getrefcount(x) == 2 - assert sys.getrefcount(y) == 2 + assert sys.getrefcount(x) <= 2 + assert sys.getrefcount(y) <= 2 with pytest.raises(ValueError): downsample.ltob(x, y, -100) @@ -45,35 +45,35 @@ def test_threshold_larger(): """Test if a larger threshold provides problems""" x = np.arange(100000, dtype=np.int32) y = np.random.randint(1000, size=100000, dtype=np.uint64) - assert sys.getrefcount(x) == 2 - assert sys.getrefcount(y) == 2 + assert sys.getrefcount(x) <= 2 + assert sys.getrefcount(y) <= 2 # Will return the arrays! nx, ny = downsample.ltob(x, y, 100000 + 1) assert len(nx) == 100000 assert len(ny) == 100000 assert nx.dtype == np.double assert ny.dtype == np.double - assert sys.getrefcount(x) == 2 - assert sys.getrefcount(y) == 2 - assert sys.getrefcount(nx) == 2 - assert sys.getrefcount(ny) == 2 + assert sys.getrefcount(x) <= 2 + assert sys.getrefcount(y) <= 2 + assert sys.getrefcount(nx) <= 2 + assert sys.getrefcount(ny) <= 2 def test_input_list(): """Test the down sampling with lists types""" x = list(range(100000)) y = [True] * 100000 - assert sys.getrefcount(x) == 2 - assert sys.getrefcount(y) == 2 + assert sys.getrefcount(x) <= 2 + assert sys.getrefcount(y) <= 2 nx, ny = downsample.ltob(x, y, 10) assert len(nx) == 10 assert len(ny) == 10 assert nx.dtype == np.double assert ny.dtype == np.double - assert sys.getrefcount(x) == 2 - assert sys.getrefcount(y) == 2 - assert sys.getrefcount(nx) == 2 - assert sys.getrefcount(ny) == 2 + assert sys.getrefcount(x) <= 2 + assert sys.getrefcount(y) <= 2 + assert sys.getrefcount(nx) <= 2 + assert sys.getrefcount(ny) <= 2 test_array = np.array( [0., 12499., 24999., 37499., 49999., 62498., 74998., 87498., 99998., 99999.], @@ -88,17 +88,17 @@ def test_input_list_array(): """Test the down sampling with mixed types""" x = list(range(100000)) y = np.array([True] * 100000, dtype=bool) - assert sys.getrefcount(x) == 2 - assert sys.getrefcount(y) == 2 + assert sys.getrefcount(x) <= 2 + assert sys.getrefcount(y) <= 2 nx, ny = downsample.ltob(x, y, 100) assert len(nx) == 100 assert len(ny) == 100 assert nx.dtype == np.double assert ny.dtype == np.double - assert sys.getrefcount(x) == 2 - assert sys.getrefcount(y) == 2 - assert sys.getrefcount(nx) == 2 - assert sys.getrefcount(ny) == 2 + assert sys.getrefcount(x) <= 2 + assert sys.getrefcount(y) <= 2 + assert sys.getrefcount(nx) <= 2 + assert sys.getrefcount(ny) <= 2 test_array = np.array([1.0] * 100, dtype=np.double) test_array_bool = np.array([1.0] * 100, dtype=bool) np.testing.assert_array_almost_equal(ny, test_array) @@ -109,46 +109,46 @@ def test_array_size(): """Test the input failure for different dimensions of arrays""" x = np.arange(100000) y = np.random.randint(1000, size=100000 - 1, dtype=np.uint64) - assert sys.getrefcount(x) == 2 - assert sys.getrefcount(y) == 2 + assert sys.getrefcount(x) <= 2 + assert sys.getrefcount(y) <= 2 with pytest.raises(ValueError): assert downsample.ltob(x, y, 100000) - assert sys.getrefcount(x) == 2 - assert sys.getrefcount(y) == 2 + assert sys.getrefcount(x) <= 2 + assert sys.getrefcount(y) <= 2 def test_ltob_uint64(): """Test the base down sampling of the module""" x = np.arange(100000, dtype=np.int32) y = np.random.randint(1000, size=100000, dtype=np.uint64) - assert sys.getrefcount(x) == 2 - assert sys.getrefcount(y) == 2 + assert sys.getrefcount(x) <= 2 + assert sys.getrefcount(y) <= 2 nx, ny = downsample.ltob(x, y, 100) assert len(nx) == 100 assert len(ny) == 100 assert nx.dtype == np.double assert ny.dtype == np.double - assert sys.getrefcount(x) == 2 - assert sys.getrefcount(y) == 2 - assert sys.getrefcount(nx) == 2 - assert sys.getrefcount(ny) == 2 + assert sys.getrefcount(x) <= 2 + assert sys.getrefcount(y) <= 2 + assert sys.getrefcount(nx) <= 2 + assert sys.getrefcount(ny) <= 2 def test_ltob_bool(): """Test the down sampling with boolean types""" x = np.arange(100000, dtype=np.int32) y = np.array([True] * 100000, dtype=bool) - assert sys.getrefcount(x) == 2 - assert sys.getrefcount(y) == 2 + assert sys.getrefcount(x) <= 2 + assert sys.getrefcount(y) <= 2 nx, ny = downsample.ltob(x, y, 100) assert len(nx) == 100 assert len(ny) == 100 assert nx.dtype == np.double assert ny.dtype == np.double - assert sys.getrefcount(x) == 2 - assert sys.getrefcount(y) == 2 - assert sys.getrefcount(nx) == 2 - assert sys.getrefcount(ny) == 2 + assert sys.getrefcount(x) <= 2 + assert sys.getrefcount(y) <= 2 + assert sys.getrefcount(nx) <= 2 + assert sys.getrefcount(ny) <= 2 test_array = np.array([1.0] * 100, dtype=np.double) test_array_bool = np.array([1.0] * 100, dtype=bool) np.testing.assert_array_almost_equal(ny, test_array) @@ -159,17 +159,17 @@ def test_inf(): """Test the down sampling with inf types""" x = np.arange(100000, dtype=np.int32) y = np.array([np.inf] * 100000, dtype=np.double) - assert sys.getrefcount(x) == 2 - assert sys.getrefcount(y) == 2 + assert sys.getrefcount(x) <= 2 + assert sys.getrefcount(y) <= 2 nx, ny = downsample.ltob(x, y, 100) assert len(nx) == 100 assert len(ny) == 100 assert nx.dtype == np.double assert ny.dtype == np.double - assert sys.getrefcount(x) == 2 - assert sys.getrefcount(y) == 2 - assert sys.getrefcount(nx) == 2 - assert sys.getrefcount(ny) == 2 + assert sys.getrefcount(x) <= 2 + assert sys.getrefcount(y) <= 2 + assert sys.getrefcount(nx) <= 2 + assert sys.getrefcount(ny) <= 2 test_array = np.array([0.0] * 100, dtype=np.float64) np.testing.assert_array_almost_equal(ny, test_array) @@ -181,17 +181,17 @@ def test_single_inf(): [1.0, 1.0, 2.0, np.inf, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18, 19.0, ], dtype=np.double, ) - assert sys.getrefcount(x) == 2 - assert sys.getrefcount(y) == 2 + assert sys.getrefcount(x) <= 2 + assert sys.getrefcount(y) <= 2 nx, ny = downsample.ltob(x, y, 10) assert len(nx) == 10 assert len(ny) == 10 assert nx.dtype == np.double assert ny.dtype == np.double - assert sys.getrefcount(x) == 2 - assert sys.getrefcount(y) == 2 - assert sys.getrefcount(nx) == 2 - assert sys.getrefcount(ny) == 2 + assert sys.getrefcount(x) <= 2 + assert sys.getrefcount(y) <= 2 + assert sys.getrefcount(nx) <= 2 + assert sys.getrefcount(ny) <= 2 test_array = np.array([0., 0., 5., 6., 9., 11., 13., 15., 18., 19.], dtype=np.double) np.testing.assert_array_almost_equal(nx, test_array) @@ -204,17 +204,17 @@ def test_nan(): """Test the down sampling with NaN types""" x = np.arange(100000, dtype=np.int32) y = np.array([np.nan] * 100000, dtype=np.double) - assert sys.getrefcount(x) == 2 - assert sys.getrefcount(y) == 2 + assert sys.getrefcount(x) <= 2 + assert sys.getrefcount(y) <= 2 nx, ny = downsample.ltob(x, y, 100) assert len(nx) == 100 assert len(ny) == 100 assert nx.dtype == np.double assert ny.dtype == np.double - assert sys.getrefcount(x) == 2 - assert sys.getrefcount(y) == 2 - assert sys.getrefcount(nx) == 2 - assert sys.getrefcount(ny) == 2 + assert sys.getrefcount(x) <= 2 + assert sys.getrefcount(y) <= 2 + assert sys.getrefcount(nx) <= 2 + assert sys.getrefcount(ny) <= 2 def test_array_mix_inf_nan(): @@ -224,17 +224,17 @@ def test_array_mix_inf_nan(): [0.0, 1.0, 2.0, np.nan, 4.0, 5.0, 6.0, np.nan, np.inf, np.inf, 10.0, np.nan, 12.0, -np.inf, 14.0, 15.0, 16.0, 17.0, np.nan, 19.0, ], dtype=np.double) - assert sys.getrefcount(x) == 2 - assert sys.getrefcount(y) == 2 + assert sys.getrefcount(x) <= 2 + assert sys.getrefcount(y) <= 2 nx, ny = downsample.ltob(x, y, 10) assert len(nx) == 10 assert len(ny) == 10 assert nx.dtype == np.double assert ny.dtype == np.double - assert sys.getrefcount(x) == 2 - assert sys.getrefcount(y) == 2 - assert sys.getrefcount(nx) == 2 - assert sys.getrefcount(ny) == 2 + assert sys.getrefcount(x) <= 2 + assert sys.getrefcount(y) <= 2 + assert sys.getrefcount(nx) <= 2 + assert sys.getrefcount(ny) <= 2 test_array = np.array([0., 0., 5., 0., 0., 0., 0., 15., 0., 19.], dtype=np.double) np.testing.assert_array_almost_equal(ny, test_array) @@ -246,18 +246,18 @@ def test_single_nan(): y = np.array([0.0, 1.0, 2.0, np.nan, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18, 19.0, ], dtype=np.double) - assert sys.getrefcount(x) == 2 - assert sys.getrefcount(y) == 2 + assert sys.getrefcount(x) <= 2 + assert sys.getrefcount(y) <= 2 z = x.copy() nx, ny = downsample.ltob(x, y, 10) assert len(nx) == 10 assert len(ny) == 10 assert nx.dtype == np.double assert ny.dtype == np.double - assert sys.getrefcount(x) == 2 - assert sys.getrefcount(y) == 2 - assert sys.getrefcount(nx) == 2 - assert sys.getrefcount(ny) == 2 + assert sys.getrefcount(x) <= 2 + assert sys.getrefcount(y) <= 2 + assert sys.getrefcount(nx) <= 2 + assert sys.getrefcount(ny) <= 2 test_array = np.array([0., 0., 5., 6., 9., 11., 13., 15., 18., 19.], dtype=np.double) np.testing.assert_array_almost_equal(x, z)