From 8fe16eca7dd7222417f64a8f74e43b8616edb42c Mon Sep 17 00:00:00 2001 From: Sean Law Date: Sat, 14 Feb 2026 00:28:16 -0500 Subject: [PATCH 1/3] Initial migration conversion --- conftest.py | 18 +++++ test.sh | 2 +- tests/test_core.py | 164 ++++++++++++++++++++++----------------------- 3 files changed, 100 insertions(+), 84 deletions(-) diff --git a/conftest.py b/conftest.py index fe4951163..e1c84d583 100644 --- a/conftest.py +++ b/conftest.py @@ -4,3 +4,21 @@ # to fix eventual module import errors that can arise, for example when # running tests from inside VS code. # See https://stackoverflow.com/a/34520971 +import json + +import numpy as np +import pytest + +pytest.RNG = np.random.default_rng() +# pytest.RNG.bit_generator.state = { +# Set RNG state here +# } + + +def pytest_configure(config): + """ + Called after command line options have been parsed + and all plugins and initial conftest files been loaded. + """ + state = json.dumps(pytest.RNG.bit_generator.state, indent=4) + print(f"conftest.py: pytest.RNG.bit_generator.state = {state}") diff --git a/test.sh b/test.sh index 194288574..94b5cb244 100755 --- a/test.sh +++ b/test.sh @@ -83,7 +83,7 @@ check_flake() check_print() { if [[ $print_mode == "verbose" ]]; then - if [[ `grep print */*.py | wc -l` -gt "0" ]]; then + if [[ `grep print --exclude="conftext.py" */*.py | wc -l` -gt "0" ]]; then echo "Error: print statement found in code" grep print */*.py exit 1 diff --git a/tests/test_core.py b/tests/test_core.py index 8f7fbc9ce..7d46b596f 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -149,7 +149,7 @@ def naive_bfs_indices(n, fill_value=None): np.array([9, 8100, -60], dtype=np.float64), np.array([584, -11, 23, 79, 1001], dtype=np.float64), ), - (np.random.uniform(-1000, 1000, [8]), np.random.uniform(-1000, 1000, [64])), + (pytest.RNG.uniform(-1000, 1000, size=8), pytest.RNG.uniform(-1000, 1000, size=64)), ] n = list(range(1, 50)) @@ -158,11 +158,11 @@ def naive_bfs_indices(n, fill_value=None): def test_check_bad_dtype(): for dtype in [np.int32, np.int64, np.float32]: with pytest.raises(TypeError): - core.check_dtype(np.random.rand(10).astype(dtype)) + core.check_dtype(pytest.RNG.random(10).astype(dtype)) def test_check_dtype_float64(): - assert core.check_dtype(np.random.rand(10)) + assert core.check_dtype(pytest.RNG.random(10)) def test_get_max_window_size(): @@ -196,7 +196,7 @@ def test_check_max_window_size(): def test_check_window_size_excl_zone(): # To ensure warning is raised if there is at least one subsequence # that has no non-trivial neighbor - T = np.random.rand(10) + T = pytest.RNG.random(10) m = 7 # For `len(T) == 10` and `m == 7`, the `excl_zone` is ceil(m / 4) = 2. @@ -223,7 +223,7 @@ def test_sliding_dot_product(Q, T): def test_welford_nanvar(): - T = np.random.rand(64) + T = pytest.RNG.random(64) m = 10 ref_var = np.nanvar(T) @@ -245,7 +245,7 @@ def test_welford_nanvar_catastrophic_cancellation(): def test_welford_nanvar_nan(): - T = np.random.rand(64) + T = pytest.RNG.random(64) m = 10 T[1] = np.nan @@ -262,7 +262,7 @@ def test_welford_nanvar_nan(): def test_welford_nanstd(): - T = np.random.rand(64) + T = pytest.RNG.random(64) m = 10 ref_var = np.nanstd(T) @@ -275,7 +275,7 @@ def test_welford_nanstd(): def test_rolling_std_1d(): - a = np.random.rand(64) + a = pytest.RNG.random(64) for w in range(3, 6): ref_std = naive.rolling_nanstd(a, w) @@ -291,7 +291,7 @@ def test_rolling_std_1d(): def test_rolling_std_2d(): w = 5 for n_rows in range(1, 4): - a = np.random.rand(n_rows * 64).reshape(n_rows, 64) + a = pytest.RNG.random(size=(n_rows, 64)) ref_std = naive.rolling_nanstd(a, w) # welford = False (default) @@ -304,7 +304,7 @@ def test_rolling_std_2d(): def test_rolling_nanmin_1d(): - T = np.random.rand(64) + T = pytest.RNG.random(64) for m in range(1, 12): ref_min = np.nanmin(T) comp_min = core._rolling_nanmin_1d(T) @@ -316,7 +316,7 @@ def test_rolling_nanmin_1d(): def test_rolling_nanmin(): - T = np.random.rand(64) + T = pytest.RNG.random(64) for m in range(1, 12): ref_min = np.nanmin(core.rolling_window(T, m), axis=1) comp_min = core.rolling_nanmin(T, m) @@ -328,7 +328,7 @@ def test_rolling_nanmin(): def test_rolling_nanmax_1d(): - T = np.random.rand(64) + T = pytest.RNG.random(64) for m in range(1, 12): ref_max = np.nanmax(T) comp_max = core._rolling_nanmax_1d(T) @@ -340,7 +340,7 @@ def test_rolling_nanmax_1d(): def test_rolling_nanmax(): - T = np.random.rand(64) + T = pytest.RNG.random(64) for m in range(1, 12): ref_max = np.nanmax(core.rolling_window(T, m), axis=1) comp_max = core.rolling_nanmax(T, m) @@ -402,8 +402,8 @@ def test_compute_mean_std_chunked_many(Q, T): def test_compute_mean_std_multidimensional(Q, T): m = Q.shape[0] - Q = np.array([Q, np.random.uniform(-1000, 1000, [Q.shape[0]])]) - T = np.array([T, T, np.random.uniform(-1000, 1000, [T.shape[0]])]) + Q = np.array([Q, pytest.RNG.uniform(-1000, 1000, size=Q.shape[0])]) + T = np.array([T, T, pytest.RNG.uniform(-1000, 1000, size=T.shape[0])]) ref_μ_Q, ref_σ_Q = naive_compute_mean_std_multidimensional(Q, m) ref_M_T, ref_Σ_T = naive_compute_mean_std_multidimensional(T, m) @@ -420,8 +420,8 @@ def test_compute_mean_std_multidimensional(Q, T): def test_compute_mean_std_multidimensional_chunked(Q, T): m = Q.shape[0] - Q = np.array([Q, np.random.uniform(-1000, 1000, [Q.shape[0]])]) - T = np.array([T, T, np.random.uniform(-1000, 1000, [T.shape[0]])]) + Q = np.array([Q, pytest.RNG.uniform(-1000, 1000, size=Q.shape[0])]) + T = np.array([T, T, pytest.RNG.uniform(-1000, 1000, size=T.shape[0])]) with patch("stumpy.config.STUMPY_MEAN_STD_NUM_CHUNKS", 2): ref_μ_Q, ref_σ_Q = naive_compute_mean_std_multidimensional(Q, m) @@ -439,8 +439,8 @@ def test_compute_mean_std_multidimensional_chunked(Q, T): def test_compute_mean_std_multidimensional_chunked_many(Q, T): m = Q.shape[0] - Q = np.array([Q, np.random.uniform(-1000, 1000, [Q.shape[0]])]) - T = np.array([T, T, np.random.uniform(-1000, 1000, [T.shape[0]])]) + Q = np.array([Q, pytest.RNG.uniform(-1000, 1000, size=Q.shape[0])]) + T = np.array([T, T, pytest.RNG.uniform(-1000, 1000, size=T.shape[0])]) with patch("stumpy.config.STUMPY_MEAN_STD_NUM_CHUNKS", 128): ref_μ_Q, ref_σ_Q = naive_compute_mean_std_multidimensional(Q, m) @@ -933,7 +933,7 @@ def test_preprocess_diagonal(): def test_replace_distance(): - right = np.random.rand(30).reshape(5, 6) + right = pytest.RNG.random(size=(5, 6)) left = right.copy() np.fill_diagonal(right, config.STUMPY_MAX_DISTANCE - 1e-9) np.fill_diagonal(left, np.inf) @@ -941,7 +941,7 @@ def test_replace_distance(): def test_array_to_temp_file(): - left = np.random.rand() + left = pytest.RNG.random() fname = core.array_to_temp_file(left) right = np.load(fname, allow_pickle=False) os.remove(fname) @@ -953,7 +953,7 @@ def test_count_diagonal_ndist(): for n_A in range(10, 15): for n_B in range(10, 15): for m in range(3, 6): - diags = np.random.permutation( + diags = pytest.RNG.permutation( range(-(n_A - m + 1) + 1, n_B - m + 1) ).astype(np.int64) ones_matrix = np.ones((n_A - m + 1, n_B - m + 1), dtype=np.int64) @@ -1122,12 +1122,12 @@ def test_get_mask_slices(): def test_idx_to_mp(): n = 64 m = 5 - T = np.random.rand(n) + T = pytest.RNG.random(n) # T[1] = np.nan # T[8] = np.inf # T[:] = 1.0 l = n - m + 1 - I = np.random.randint(0, l, l) + I = pytest.RNG.integers(0, l, l) # `normalize == True` and `T_subseq_isconstant` is None (default) ref_mp = naive_idx_to_mp(I, T, m) @@ -1135,7 +1135,7 @@ def test_idx_to_mp(): npt.assert_almost_equal(ref_mp, cmp_mp) # `normalize == True` and `T_subseq_isconstant` is provided - T_subseq_isconstant = np.random.choice([True, False], l, replace=True) + T_subseq_isconstant = pytest.RNG.choice([True, False], l, replace=True) ref_mp = naive_idx_to_mp(I, T, m, T_subseq_isconstant=T_subseq_isconstant) cmp_mp = core._idx_to_mp(I, T, m, T_subseq_isconstant=T_subseq_isconstant) npt.assert_almost_equal(ref_mp, cmp_mp) @@ -1186,7 +1186,7 @@ def test_bfs_indices_fill_value(n): def test_select_P_ABBA_val_inf(): - P_ABBA = np.random.rand(10) + P_ABBA = pytest.RNG.random(10) k = 2 P_ABBA[k:] = np.inf p_abba = P_ABBA.copy() @@ -1202,13 +1202,13 @@ def test_merge_topk_PI_without_overlap(): # is no overlap between row IA[i] and row IB[i]. n = 50 for k in range(1, 6): - PA = np.random.rand(n * k).reshape(n, k) + PA = pytest.RNG.random(size=(n, k)) PA[:, :] = np.sort(PA, axis=1) # sorting each row separately - PB = np.random.rand(n * k).reshape(n, k) - col_idx = np.random.randint(0, k, size=n) + PB = pytest.RNG.random(size=(n, k)) + col_idx = pytest.RNG.integers(0, k, size=n) for i in range(n): # creating ties between values of PA and PB - val = np.random.choice(PA[i], size=1, replace=False) + val = pytest.RNG.choice(PA[i], size=1, replace=False) PB[i, col_idx[i]] = val.item() PB[:, :] = np.sort(PB, axis=1) # sorting each row separately @@ -1235,17 +1235,17 @@ def test_merge_topk_PI_with_overlap(): for k in range(1, 6): # note: we do not have overlap issue when k is 1. The `k=1` is considered # for the sake of consistency with the `without-overlap` test function. - PA = np.random.rand(n * k).reshape(n, k) - PB = np.random.rand(n * k).reshape(n, k) + PA = pytest.RNG.random(size=(n, k)) + PB = pytest.RNG.random(size=(n, k)) IA = np.arange(n * k).reshape(n, k) IB = IA + n * k - num_overlaps = np.random.randint(1, k + 1, size=n) + num_overlaps = pytest.RNG.integers(1, k + 1, size=n) for i in range(n): # create overlaps - col_IDX = np.random.choice(np.arange(k), num_overlaps[i], replace=False) - imprecision = np.random.uniform(low=-1e-06, high=1e-06, size=len(col_IDX)) + col_IDX = pytest.RNG.choice(np.arange(k), num_overlaps[i], replace=False) + imprecision = pytest.RNG.uniform(low=-1e-06, high=1e-06, size=len(col_IDX)) PB[i, col_IDX] = PA[i, col_IDX] + imprecision IB[i, col_IDX] = IA[i, col_IDX] @@ -1274,15 +1274,15 @@ def test_merge_topk_PI_with_overlap(): def test_merge_topk_PI_with_1D_input(): # including some overlaps randomly n = 50 - PA = np.random.rand(n) - PB = np.random.rand(n) + PA = pytest.RNG.random(n) + PB = pytest.RNG.random(n) IA = np.arange(n) IB = IA + n - n_overlaps = np.random.randint(1, n + 1) - IDX_rows_with_overlaps = np.random.choice(np.arange(n), n_overlaps, replace=False) - imprecision = np.random.uniform(low=-1e-06, high=1e-06, size=n_overlaps) + n_overlaps = pytest.RNG.integers(1, n + 1) + IDX_rows_with_overlaps = pytest.RNG.choice(np.arange(n), n_overlaps, replace=False) + imprecision = pytest.RNG.uniform(low=-1e-06, high=1e-06, size=n_overlaps) PB[IDX_rows_with_overlaps] = PA[IDX_rows_with_overlaps] + imprecision IB[IDX_rows_with_overlaps] = IA[IDX_rows_with_overlaps] @@ -1327,13 +1327,13 @@ def test_merge_topk_ρI_without_overlap(): # is no overlap between row IA[i] and row IB[i]. n = 50 for k in range(1, 6): - ρA = np.random.rand(n * k).reshape(n, k) + ρA = pytest.RNG.random(size=(n, k)) ρA[:, :] = np.sort(ρA, axis=1) # sorting each row separately - ρB = np.random.rand(n * k).reshape(n, k) - col_idx = np.random.randint(0, k, size=n) + ρB = pytest.RNG.random(size=(n, k)) + col_idx = pytest.RNG.integers(0, k, size=n) for i in range(n): # creating ties between values of PA and PB - val = np.random.choice(ρA[i], size=1, replace=False) + val = pytest.RNG.choice(ρA[i], size=1, replace=False) ρB[i, col_idx[i]] = val.item() ρB[:, :] = np.sort(ρB, axis=1) # sorting each row separately @@ -1360,17 +1360,17 @@ def test_merge_topk_ρI_with_overlap(): for k in range(1, 6): # note: we do not have overlap issue when k is 1. The `k=1` is considered # for the sake of consistency with the `without-overlap` test function. - ρA = np.random.rand(n * k).reshape(n, k) - ρB = np.random.rand(n * k).reshape(n, k) + ρA = pytest.RNG.random(size=(n, k)) + ρB = pytest.RNG.random(size=(n, k)) IA = np.arange(n * k).reshape(n, k) IB = IA + n * k - num_overlaps = np.random.randint(1, k + 1, size=n) + num_overlaps = pytest.RNG.integers(1, k + 1, size=n) for i in range(n): # create overlaps - col_IDX = np.random.choice(np.arange(k), num_overlaps[i], replace=False) - imprecision = np.random.uniform(low=-1e-06, high=1e-06, size=len(col_IDX)) + col_IDX = pytest.RNG.choice(np.arange(k), num_overlaps[i], replace=False) + imprecision = pytest.RNG.uniform(low=-1e-06, high=1e-06, size=len(col_IDX)) ρB[i, col_IDX] = ρA[i, col_IDX] + imprecision IB[i, col_IDX] = IA[i, col_IDX] @@ -1399,15 +1399,15 @@ def test_merge_topk_ρI_with_overlap(): def test_merge_topk_ρI_with_1D_input(): # including some overlaps randomly n = 50 - ρA = np.random.rand(n) - ρB = np.random.rand(n) + ρA = pytest.RNG.random(n) + ρB = pytest.RNG.random(n) IA = np.arange(n) IB = IA + n - n_overlaps = np.random.randint(1, n + 1) - IDX_rows_with_overlaps = np.random.choice(np.arange(n), n_overlaps, replace=False) - imprecision = np.random.uniform(low=-1e-06, high=1e-06, size=n_overlaps) + n_overlaps = pytest.RNG.integers(1, n + 1) + IDX_rows_with_overlaps = pytest.RNG.choice(np.arange(n), n_overlaps, replace=False) + imprecision = pytest.RNG.uniform(low=-1e-06, high=1e-06, size=n_overlaps) ρB[IDX_rows_with_overlaps] = ρA[IDX_rows_with_overlaps] + imprecision IB[IDX_rows_with_overlaps] = IA[IDX_rows_with_overlaps] @@ -1449,12 +1449,12 @@ def test_merge_topk_ρI_with_1D_input_hardcoded(): def test_shift_insert_at_index(): for k in range(1, 6): - a = np.random.rand(k) + a = pytest.RNG.random(k) ref = np.empty(k, dtype=np.float64) comp = np.empty(k, dtype=np.float64) indices = np.arange(k + 1) - values = np.random.rand(k + 1) + values = pytest.RNG.random(k + 1) # test shift = "right" for idx, v in zip(indices, values): @@ -1483,13 +1483,13 @@ def test_shift_insert_at_index(): def test_check_P(): with pytest.raises(ValueError): - core._check_P(np.random.rand(10).reshape(2, 5)) + core._check_P(pytest.RNG.random(size=(2, 5))) def test_find_matches_all(): # max_matches: None, i.e. find all matches max_distance = np.inf - D = np.random.rand(64) + D = pytest.RNG.random(64) for excl_zone in range(3): ref = naive.find_matches(D, excl_zone, max_distance, max_matches=None) comp = core._find_matches(D, excl_zone, max_distance, max_matches=None) @@ -1499,9 +1499,9 @@ def test_find_matches_all(): def test_find_matches_maxmatch(): max_distance = np.inf - D = np.random.rand(64) + D = pytest.RNG.random(64) for excl_zone in range(3): - max_matches = np.random.randint(0, 100) + max_matches = pytest.RNG.integers(0, 100) ref = naive.find_matches(D, excl_zone, max_distance, max_matches) comp = core._find_matches(D, excl_zone, max_distance, max_matches) @@ -1524,11 +1524,11 @@ def test_gpu_searchsorted(): device_bfs = cuda.to_device(core._bfs_indices(k, fill_value=-1)) nlevel = np.floor(np.log2(k) + 1).astype(np.int64) - A = np.sort(np.random.rand(n, k), axis=1) + A = np.sort(pytest.RNG.random(n, k), axis=1) device_A = cuda.to_device(A) - V[:] = np.random.rand(n) - for i, idx in enumerate(np.random.choice(np.arange(n), size=k, replace=False)): + V[:] = pytest.RNG.random(n) + for i, idx in enumerate(pytest.RNG.choice(np.arange(n), size=k, replace=False)): V[idx] = A[idx, i] # create ties device_V = cuda.to_device(V) @@ -1563,7 +1563,7 @@ def test_client_to_func(): def test_apply_include(): - D = np.random.uniform(-1000, 1000, [10, 20]).astype(np.float64) + D = pytest.RNG.uniform(-1000, 1000, [10, 20]).astype(np.float64) ref_D = np.empty(D.shape) comp_D = np.empty(D.shape) for width in range(D.shape[0]): @@ -1698,7 +1698,7 @@ def test_process_isconstant_1d(): m = 8 # case 1: without nan - T = np.random.rand(n) + T = pytest.RNG.random(n) T_subseq_isconstant_ref = naive.rolling_isconstant(T, m, isconstant_custom_func) T_subseq_isconstant_comp = core.process_isconstant(T, m, isconstant_custom_func) @@ -1706,10 +1706,10 @@ def test_process_isconstant_1d(): npt.assert_array_equal(T_subseq_isconstant_ref, T_subseq_isconstant_comp) # case 2: with nan - T = np.random.rand(n) - idx = np.random.randint(n) + T = pytest.RNG.random(n) + idx = pytest.RNG.integers(n) T[idx] = np.nan - T_subseq_isconstant = np.random.choice([True, False], n - m + 1, replace=True) + T_subseq_isconstant = pytest.RNG.choice([True, False], n - m + 1, replace=True) T_subseq_isfinite = core.rolling_isfinite(T, m) @@ -1729,11 +1729,11 @@ def test_process_isconstant_2d(): d = 3 # case 1: without nan - T = np.random.rand(d, n) + T = pytest.RNG.random(size=(d, n)) T_subseq_isconstant = [ None, isconstant_custom_func, - np.random.choice([True, False], n - m + 1, replace=True), + pytest.RNG.choice([True, False], n - m + 1, replace=True), ] T_subseq_isconstant_ref = np.array( @@ -1745,8 +1745,8 @@ def test_process_isconstant_2d(): npt.assert_array_equal(T_subseq_isconstant_ref, T_subseq_isconstant_comp) # case 2: with nan - T = np.random.rand(d, n) - i, j = np.random.choice(np.arange(n - m + 1), size=2, replace=False) + T = pytest.RNG.random(size=(d, n)) + i, j = pytest.RNG.choice(np.arange(n - m + 1), size=2, replace=False) T[-1, i : i + m] = 0.0 T[-1, j : j + m] = 0.0 T[-1, j] = np.nan @@ -1779,7 +1779,7 @@ def test_process_isconstant_1d_default(): m = 8 # case 1: without nan - T = np.random.rand(n) + T = pytest.RNG.random(n) T[:m] = 0.5 # constant subsequence T_subseq_isconstant_ref = naive.rolling_isconstant(T, m, a_subseq_isconstant=None) @@ -1788,7 +1788,7 @@ def test_process_isconstant_1d_default(): npt.assert_array_equal(T_subseq_isconstant_ref, T_subseq_isconstant_comp) # case 2: with nan - T = np.random.rand(n) + T = pytest.RNG.random(n) T[:m] = 0.5 # constant subsequence T[-m:] = np.nan # non-finite subsequence @@ -1802,8 +1802,8 @@ def test_update_incremental_PI_egressFalse(): # This tests the function `core._update_incremental_PI` # when `egress` is False, meaning new data point is being # appended to the historical data. - T = np.random.rand(64) - t = np.random.rand() # new datapoint + T = pytest.RNG.random(64) + t = pytest.RNG.random() # new datapoint T_new = np.append(T, t) m = 3 @@ -1844,8 +1844,8 @@ def test_update_incremental_PI_egressFalse(): def test_update_incremental_PI_egressTrue(): - T = np.random.rand(64) - t = np.random.rand() # new data point + T = pytest.RNG.random(64) + t = pytest.RNG.random() # new data point m = 3 excl_zone = int(np.ceil(m / config.STUMPY_EXCL_ZONE_DENOM)) @@ -1906,19 +1906,17 @@ def test_update_incremental_PI_egressTrue_MemoryCheck(): # a new data point is appended. However, the updated matrix profile index for the # middle subsequence `s` should still refer to the first subsequence in # the historical data. - seed = 0 - np.random.seed(seed) - T = np.random.rand(64) + T = pytest.RNG.random(64) m = 3 excl_zone = int(np.ceil(m / config.STUMPY_EXCL_ZONE_DENOM)) - s = np.random.rand(m) + s = pytest.RNG.random(m) T[:m] = s T[30 : 30 + m] = s T[-m:] = s - t = np.random.rand() # new data point + t = pytest.RNG.random() # new data point T_with_t = np.append(T, t) # In egress=True mode, a new data point, t, is being appended From da87749a53517b01b23e0129e178c77f800cae5e Mon Sep 17 00:00:00 2001 From: Sean Law Date: Sat, 14 Feb 2026 00:48:06 -0500 Subject: [PATCH 2/3] Fixed typo --- tests/test_core.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_core.py b/tests/test_core.py index 7d46b596f..d6be34193 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -1524,7 +1524,7 @@ def test_gpu_searchsorted(): device_bfs = cuda.to_device(core._bfs_indices(k, fill_value=-1)) nlevel = np.floor(np.log2(k) + 1).astype(np.int64) - A = np.sort(pytest.RNG.random(n, k), axis=1) + A = np.sort(pytest.RNG.random(size=(n, k)), axis=1) device_A = cuda.to_device(A) V[:] = pytest.RNG.random(n) From 9efa0f50be0d84ecbad28983e5791e1abe1f0fc1 Mon Sep 17 00:00:00 2001 From: Sean Law Date: Sat, 14 Feb 2026 18:52:03 -0500 Subject: [PATCH 3/3] Removed --exclude flag --- test.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test.sh b/test.sh index 94b5cb244..194288574 100755 --- a/test.sh +++ b/test.sh @@ -83,7 +83,7 @@ check_flake() check_print() { if [[ $print_mode == "verbose" ]]; then - if [[ `grep print --exclude="conftext.py" */*.py | wc -l` -gt "0" ]]; then + if [[ `grep print */*.py | wc -l` -gt "0" ]]; then echo "Error: print statement found in code" grep print */*.py exit 1