spinalcordtoolbox / spinalcordtoolbox

Comprehensive and open-source library of analysis tools for MRI of the spinal cord.
https://spinalcordtoolbox.com
GNU Lesser General Public License v3.0
200 stars 101 forks source link

Tests don't cleanup after themselves #2911

Closed Drulex closed 6 months ago

Drulex commented 4 years ago

After a successful run of pytest I noticed that 172 files were created in my working directory. Not a big deal, but it would be nice to cleanup after running the tests.

joshuacwnewton commented 4 years ago

sct_testing should run in a temporary directory, so I don't think this affects the old tests.

https://github.com/neuropoly/spinalcordtoolbox/blob/c7810852dc0908e5a1bdede2e544eb8592817b7c/spinalcordtoolbox/scripts/sct_testing.py#L241-L242

At the very least, moving forward I agree with @Drulex's recommendations that new tests should clean up after themselves.

joshuacwnewton commented 3 years ago

I wanted to find out which tests were to blame, so I modified the check_testing_data_integrity function that @Drulex wrote so that it would run once per test:

Source code for modified fixture I had some fun with sets! :D ```python @pytest.fixture(autouse=True) def test_data_integrity(): checksums_before = checksum_walk() # Run before test executes yield checksums_after = checksum_walk() # Run after test executes # Use only filenames to see which files were added/removed files_before, files_after = set(checksums_before.keys()), set(checksums_after.keys()) files_added = files_after - files_before files_removed = files_before - files_after # Use filenames AND checksums to see which files have changed files_changed = set(checksums_before) - set(checksums_after) # No files were removed/changed, so I only checked files added for now assert not files_added, f"{len(files_added)} ADDED: {files_added}" def checksum(fname: os.PathLike) -> str: with open(fname, 'rb') as f: data = f.read() return md5(data).hexdigest() def checksum_walk(input_path="."): files_checksums = dict() for root, _, files in os.walk(input_path): for f in files: fname = os.path.join(root, f) chksum = checksum(fname) files_checksums[fname] = chksum return files_checksums ```

Here are the tests that don't clean up after themselves:

Raw output ``` ERROR ../unit_testing/test_aggregate_slicewise.py::test_save_as_csv - AssertionError: 1 ADDED: {'./tmp_file_out.csv'} ERROR ../unit_testing/test_image.py::test_change_orientation - AssertionError: 6 ADDED: {'./112-src.nii', './113-src.nii', './113-dst.nii', './111-dst.nii', './111-src.nii', './112-dst.nii'} ERROR ../unit_testing/test_image.py::test_more_change_orientation - AssertionError: 7 ADDED: {'./src.nii', './vis_als.nii', './vis.nii', './vis_rpi.nii', './vis_pli.nii', './vis_ras.nii', './pouet.nii'} ERROR ../unit_testing/test_register.py::test_register_step_ants_slice_regularized_registration - AssertionError: 6 ADDED: {'./step1InverseWarp.nii.gz', './sct_testing_data/mt/mt0_seg_crop_regStep1.nii.gz', './sct_testing_data... ERROR ../unit_testing/test_straightening.py::test_straighten - AssertionError: 4 ADDED: {'./straight_ref.nii.gz', './t2_straight.nii.gz', './warp_straight2curve.nii.gz', './warp_curve2straight.nii.gz'} ERROR ../unit_testing/test_transfo.py::test_transfo_null - AssertionError: 3 ADDED: {'./warp-src.nii', './warp-field.nii', './warp-dst.nii'} ERROR ../unit_testing/test_transfo.py::test_transfo_figure_out_ants_frame_exhaustive - AssertionError: 144 ADDED: {'./warp-PIR-field.nii', './warp-IPR-field.nii', './warp-SRP-src.nii', './warp-ALS-field.nii', './warp-LIA-src.... ERROR ../unit_testing/test_transfo.py::test_transfo_skip_pix2phys - AssertionError: 2 ADDED: {'./warp-field111.nii', './warp-dst111.nii'} ERROR ../unit_testing/cli/test_cli_sct_analyze_lesion.py::test_sct_analyze_lesion_backwards_compat[subprocess] - AssertionError: 3 ADDED: {'./sct_testing_data/t2_seg-manual_analyzis.pkl', './sct_testing_data/t2_seg-manual_ana... ERROR ../unit_testing/cli/test_cli_sct_analyze_texture.py::test_sct_analyze_texture_backwards_compat[subprocess] - AssertionError: 5 ADDED: {'./sct_testing_data/t2_contrast_1_45.nii.gz', './sct_testing_data/t2_contrast_1_mean... ERROR ../unit_testing/cli/test_cli_sct_apply_transfo.py::test_sct_apply_transfo_backwards_compat[subprocess] - AssertionError: 6 ADDED: {'./sct_testing_data/PAM50_small_t2_reg-crop2.nii', './sct_testing_data/PAM50_small_t2_re... ERROR ../unit_testing/cli/test_cli_sct_compute_ernst_angle.py::test_sct_compute_ernst_angle_backwards_compat[subprocess] - AssertionError: 1 ADDED: {'./sct_testing_data/ernst_angle.txt'} ERROR ../unit_testing/cli/test_cli_sct_compute_hausdorff_distance.py::test_sct_compute_hausdorff_distance_backwards_compat[subprocess] - AssertionError: 2 ADDED: {'./sct_testing_data/t2s_gmseg_manual_thinned.nii.gz', './sct_t... ERROR ../unit_testing/cli/test_cli_sct_compute_mtr.py::test_sct_compute_mtr_backwards_compat[subprocess] - AssertionError: 1 ADDED: {'./sct_testing_data/mtr.nii.gz'} ERROR ../unit_testing/cli/test_cli_sct_concat_transfo.py::test_sct_convert_backwards_compat[subprocess] - AssertionError: 1 ADDED: {'./sct_testing_data/warp_final.nii.gz'} ERROR ../unit_testing/cli/test_cli_sct_convert.py::test_sct_convert_backwards_compat[subprocess] - AssertionError: 1 ADDED: {'./sct_testing_data/t2.nii'} ERROR ../unit_testing/cli/test_cli_sct_create_mask.py::test_sct_create_mask_backwards_compat[subprocess] - AssertionError: 2 ADDED: {'./sct_testing_data/mask_mt1.nii.gz', './sct_testing_data/mask_dmri.nii.gz'} ERROR ../unit_testing/cli/test_cli_sct_crop_image.py::test_sct_crop_image_backwards_compat[subprocess] - AssertionError: 3 ADDED: {'./sct_testing_data/t2_crop_xyz.nii', './sct_testing_data/t2_crop_ref.nii', './sct_testing_dat... ERROR ../unit_testing/cli/test_cli_sct_deepseg_gm.py::test_sct_deepseg_gm_backwards_compat[subprocess] - AssertionError: 25 ADDED: {'./sct_testing_data/testing-qc/_assets/fonts/glyphicons-halflings-regular.woff', './sct_testi... ERROR ../unit_testing/cli/test_cli_sct_deepseg_lesion.py::test_sct_deepseg_lesion_backwards_compat[subprocess] - AssertionError: 3 ADDED: {'./sct_testing_data/t2/t2_RPI_seg.nii.gz', './sct_testing_data/t2/t2_res_RPI_seg.nii.g... ERROR ../unit_testing/cli/test_cli_sct_deepseg_sc.py::test_sct_deepseg_sc_backwards_compat[subprocess] - AssertionError: 4 ADDED: {'./sct_testing_data/testing-qc/test_output_dir/sct_testing_data/t2/sct_deepseg_sc/2021_02_15_1... ERROR ../unit_testing/cli/test_cli_sct_detect_pmj.py::test_sct_detect_pmj_backwards_compat[subprocess] - AssertionError: 4 ADDED: {'./sct_testing_data/testing-qc/sct_testing_data/template/template/sct_detect_pmj/2021_02_15_18... ERROR ../unit_testing/cli/test_cli_sct_dmri_compute_dti.py::test_sct_dmri_compute_dti_backwards_compat[subprocess] - AssertionError: 4 ADDED: {'./sct_testing_data/dti_FA.nii.gz', './sct_testing_data/dti_MD.nii.gz', './sct_tes... ERROR ../unit_testing/cli/test_cli_sct_dmri_concat_b0_and_dwi.py::test_sct_dmri_concat_b0_and_dwi_backwards_compat[subprocess] - AssertionError: 3 ADDED: {'./sct_testing_data/bvecs_concat.txt', './sct_testing_data/b0_dwi_conc... ERROR ../unit_testing/cli/test_cli_sct_dmri_moco.py::test_sct_dmri_moco_backwards_compat[subprocess] - AssertionError: 18 ADDED: {'./sct_testing_data/dmri_test1/moco_params_y.nii.gz', './sct_testing_data/dmri_test1/moco_param... ERROR ../unit_testing/cli/test_cli_sct_dmri_separate_b0_and_dwi.py::test_sct_dmri_separate_b0_and_dwi_backwards_compat[subprocess] - AssertionError: 4 ADDED: {'./sct_testing_data/dmri_dwi_mean.nii.gz', './sct_testing_data/dmr... ERROR ../unit_testing/cli/test_cli_sct_dmri_transpose_bvecs.py::test_sct_dmri_transpose_bvecs_backwards_compat[subprocess] - AssertionError: 1 ADDED: {'./sct_testing_data/bvecs.txt'} ERROR ../unit_testing/cli/test_cli_sct_extract_metric.py::test_sct_extract_metric_backwards_compat[subprocess] - AssertionError: 1 ADDED: {'./sct_testing_data/quantif_mtr.csv'} ERROR ../unit_testing/cli/test_cli_sct_flatten_sagittal.py::test_sct_flatten_sagittal_backwards_compat[subprocess] - AssertionError: 1 ADDED: {'./sct_testing_data/t2/t2_flatten.nii.gz'} ERROR ../unit_testing/cli/test_cli_sct_fmri_compute_tsnr.py::test_sct_fmri_compute_tsnr_backwards_compat[subprocess] - AssertionError: 1 ADDED: {'./sct_testing_data/out_fmri_tsnr.nii.gz'} ERROR ../unit_testing/cli/test_cli_sct_fmri_moco.py::test_sct_fmri_moco_backwards_compat[subprocess] - AssertionError: 5 ADDED: {'./sct_testing_data/fmri_r_moco.nii.gz', './sct_testing_data/moco_params_x.nii.gz', './sct_testi... ERROR ../unit_testing/cli/test_cli_sct_get_centerline.py::test_sct_get_centerline_backwards_compat[subprocess] - AssertionError: 2 ADDED: {'./sct_testing_data/t2s/t2s_centerline.nii.gz', './sct_testing_data/t2s/t2s_centerline... ERROR ../unit_testing/cli/test_cli_sct_image.py::test_sct_image_backwards_compat[subprocess] - AssertionError: 9 ADDED: {'./sct_testing_data/sct_image_out.nii.gz', './sct_testing_data/dmri_T0001.nii.gz', './sct_testing_data/d... ERROR ../unit_testing/cli/test_cli_sct_label_utils.py::test_sct_label_utils_backwards_compat[subprocess] - AssertionError: 2 ADDED: {'./sct_testing_data/labels.nii.gz', './sct_testing_data/test_centerofmass.nii.gz'} ERROR ../unit_testing/cli/test_cli_sct_label_vertebrae.py::test_sct_label_vertebrae_backwards_compat[subprocess] - AssertionError: 9 ADDED: {'./sct_testing_data/straight_ref.nii.gz', './sct_testing_data/testing-qc/test_output... ERROR ../unit_testing/cli/test_cli_sct_label_vertebrae.py::test_sct_label_vertebrae_high_value_warning - AssertionError: 1 ADDED: {'./straightening.cache'} ERROR ../unit_testing/cli/test_cli_sct_maths.py::test_sct_maths_backwards_compat[subprocess] - AssertionError: 1 ADDED: {'./sct_testing_data/test.nii.gz'} ERROR ../unit_testing/cli/test_cli_sct_process_segmentation.py::test_sct_process_segmentation_backwards_compat[subprocess] - AssertionError: 1 ADDED: {'./sct_testing_data/csa.csv'} ERROR ../unit_testing/cli/test_cli_sct_propseg.py::test_sct_propseg_backwards_compat[subprocess] - AssertionError: 16 ADDED: {'./sct_testing_data/t2_rescaled_centerline.txt', './sct_testing_data/t2_rescaled_CSF_mesh.vtk', './... ERROR ../unit_testing/cli/test_cli_sct_qc.py::test_sct_qc_backwards_compat[subprocess] - AssertionError: 24 ADDED: {'./sct_testing_data/qc/_assets/js/jquery-3.1.0.min.js', './sct_testing_data/qc/_assets/imgs/axial.png', './sc... ERROR ../unit_testing/cli/test_cli_sct_register_multimodal.py::test_sct_register_multimodal_backwards_compat[subprocess] - AssertionError: 4 ADDED: {'./sct_testing_data/mt0_reg.nii.gz', './sct_testing_data/warp_mt12mt0.nii.gz... ERROR ../unit_testing/cli/test_cli_sct_register_to_template.py::test_sct_register_to_template_backwards_compat[subprocess] - AssertionError: 30 ADDED: {'./sct_testing_data/qc-testing/_assets/css/bootstrap-theme.min.css', './s... ERROR ../unit_testing/cli/test_cli_sct_resample.py::test_sct_resample_backwards_compat[subprocess] - AssertionError: 1 ADDED: {'./sct_testing_data/resampled.nii.gz'} ERROR ../unit_testing/cli/test_cli_sct_smooth_spinalcord.py::test_sct_smooth_spinalcord_backwards_compat[subprocess] - AssertionError: 1 ADDED: {'./sct_testing_data/t2_smooth.nii'} ERROR ../unit_testing/cli/test_cli_sct_straighten_spinalcord.py::test_sct_straighten_spinalcord_backwards_compat[subprocess] - AssertionError: 1 ADDED: {'./sct_testing_data/t2_straight.nii.gz'} ERROR ../unit_testing/cli/test_cli_sct_warp_template.py::test_sct_warp_template_backwards_compat[subprocess] - AssertionError: 5 ADDED: {'./sct_testing_data/label/template/PAM50_small_label_discPosterior.nii.gz', './sct_testi... ============================================================================== 278 passed, 14 skipped, 5493 warnings, 46 errors in 445.86s (0:07:25) =============================================================================== ```
Formatted output |File |Test|# Added| |--------------------------------------------------------------------------------------------------------------------------------|----|------| |test_aggregate_slicewise.py |test_save_as_csv|1 | |test_image.py |test_change_orientation|6 | |test_image.py |test_more_change_orientation|7 | |test_register.py |test_register_step_ants_slice_regularized_registration|6 | |test_straightening.py |test_straighten|4 | |test_transfo.py |test_transfo_null|3 | |test_transfo.py |test_transfo_figure_out_ants_frame_exhaustive|144 | |test_transfo.py |test_transfo_skip_pix2phys|2 | |cli/test_cli_sct_analyze_lesion.py |test_sct_analyze_lesion_backwards_compat|3 | |cli/test_cli_sct_analyze_texture.py |test_sct_analyze_texture_backwards_compat|5 | |cli/test_cli_sct_apply_transfo.py |test_sct_apply_transfo_backwards_compat|6 | |cli/test_cli_sct_compute_ernst_angle.py |test_sct_compute_ernst_angle_backwards_compat|1 | |cli/test_cli_sct_compute_hausdorff_distance.py |test_sct_compute_hausdorff_distance_backwards_compat|2 | |cli/test_cli_sct_compute_mtr.py |test_sct_compute_mtr_backwards_compat|1 | |cli/test_cli_sct_concat_transfo.py |test_sct_convert_backwards_compat|1 | |cli/test_cli_sct_convert.py |test_sct_convert_backwards_compat|1 | |cli/test_cli_sct_create_mask.py |test_sct_create_mask_backwards_compat|2 | |cli/test_cli_sct_crop_image.py |test_sct_crop_image_backwards_compat|3 | |cli/test_cli_sct_deepseg_gm.py |test_sct_deepseg_gm_backwards_compat|25 | |cli/test_cli_sct_deepseg_lesion.py |test_sct_deepseg_lesion_backwards_compat|3 | |cli/test_cli_sct_deepseg_sc.py |test_sct_deepseg_sc_backwards_compat|4 | |cli/test_cli_sct_detect_pmj.py |test_sct_detect_pmj_backwards_compat|4 | |cli/test_cli_sct_dmri_compute_dti.py |test_sct_dmri_compute_dti_backwards_compat|4 | |cli/test_cli_sct_dmri_concat_b0_and_dwi.py |test_sct_dmri_concat_b0_and_dwi_backwards_compat|3 | |cli/test_cli_sct_dmri_moco.py |test_sct_dmri_moco_backwards_compat|18 | |cli/test_cli_sct_dmri_separate_b0_and_dwi.py |test_sct_dmri_separate_b0_and_dwi_backwards_compat|4 | |cli/test_cli_sct_dmri_transpose_bvecs.py |test_sct_dmri_transpose_bvecs_backwards_compat|1 | |cli/test_cli_sct_extract_metric.py |test_sct_extract_metric_backwards_compat|1 | |cli/test_cli_sct_flatten_sagittal.py |test_sct_flatten_sagittal_backwards_compat|1 | |cli/test_cli_sct_fmri_compute_tsnr.py |test_sct_fmri_compute_tsnr_backwards_compat|1 | |cli/test_cli_sct_fmri_moco.py |test_sct_fmri_moco_backwards_compat|5 | |cli/test_cli_sct_get_centerline.py |test_sct_get_centerline_backwards_compat|2 | |cli/test_cli_sct_image.py |test_sct_image_backwards_compat|9 | |cli/test_cli_sct_label_utils.py |test_sct_label_utils_backwards_compat|2 | |cli/test_cli_sct_label_vertebrae.py |test_sct_label_vertebrae_backwards_compat|9 | |cli/test_cli_sct_label_vertebrae.py |test_sct_label_vertebrae_high_value_warning|1 | |cli/test_cli_sct_maths.py |test_sct_maths_backwards_compat|1 | |cli/test_cli_sct_process_segmentation.py |test_sct_process_segmentation_backwards_compat|1 | |cli/test_cli_sct_propseg.py |test_sct_propseg_backwards_compat|16 | |cli/test_cli_sct_qc.py |test_sct_qc_backwards_compat|24 | |cli/test_cli_sct_register_multimodal.py |test_sct_register_multimodal_backwards_compat|4 | |cli/test_cli_sct_register_to_template.py |test_sct_register_to_template_backwards_compat|30 | |cli/test_cli_sct_resample.py |test_sct_resample_backwards_compat|1 | |cli/test_cli_sct_smooth_spinalcord.py |test_sct_smooth_spinalcord_backwards_compat|1 | |cli/test_cli_sct_straighten_spinalcord.py |test_sct_straighten_spinalcord_backwards_compat|1 | |cli/test_cli_sct_warp_template.py |test_sct_warp_template_backwards_compat|5 |

@Drulex The "172 files" amount you noticed roughly matches up with the first 8 pytest tests (1+6+7+6+4+3+144+2=173 in total).

The remaining files are generated inside sct_testing_data/, which was previously covered by #2925. (It was decided to leave it due to the amount of work required to prevent this from happening.)

joshuacwnewton commented 2 years ago

I'm reopening this issue because our tests are once again saving files to the working directory without cleaning up after themselves.

For context: I recently ported our custom-framework sct_testing tests to pytest in https://github.com/spinalcordtoolbox/spinalcordtoolbox/pull/3373. While doing this, I noticed that many new files were being created in the working directory. To avoid a sudden influx of clutter, I added a quick hack:

https://github.com/spinalcordtoolbox/spinalcordtoolbox/blob/bb0fec031177805e9ffb789500539b064e595f58/testing/conftest.py#L41-L48

This doesn't fix the problem -- it just changes the working directory to be sct_testing_data to make the clutter invisible to users/devs.

However, now sct_testing_data is cluttered with output files. So, I would like to try to ensure that our tests really do start and end on a fresh copy of sct_testing_data.

joshuacwnewton commented 1 year ago

I had a bit of a crackpot idea about this. Within the current "data integrity" finalizer function, we already have a list of all "added" files. So, what if we did the cleanup for all of the files at once, within the finalizer, rather than on a per-test basis?

We could even preserve the "files added" by moving them to /tmp, that way they can still be accessed for post-test analysis.

for file in [Path(f) for f in files_added]:
    move_and_cleanup(file, tmp_path)

def move_and_cleanup(file, dest):
    # Identifiy "<subdirs>" in path: "$SCT_DIR/data/sct_testing_data/<subdirs>/added_file.txt"
    # NB: "+1" excludes `sct_testing_data` and "-1" excludes the filename
    subdirs = Path(*file.parts[file.parts.index("sct_testing_data")+1:-1])  
    # Recreate the subdirs inside the destination folder, then move the file inside of them
    (dest / subdirs).mkdir(parents=True, exist_ok=True)
    shutil.move(file, dest / subdirs)
    # Clean up any empty directories left behind in `sct_testing_data`
    for i in range(len(file.parent)):
        if not os.listdir(file.parent[i]):
            shutil.remove(file.parent[i]

The upside here is that it saves us a lot of manual work in specifying file deletions for each test.

However, the downside is that we're less aware of the output files for each test (which is probably something we should be aware of when writing tests!). Also that this behavior is a bit opaque to people who are new to pytest -- the file-moving code would be done silently within conftest.py, away from the tests themselves, unless we can somehow write logging messages to the end of pytest's output to clearly indicate that this is happening.

Still, this might be a nice short-term solution for keeping sct_testing_data clean, before we're able to properly rewrite each of our tests.

mguaypaq commented 1 year ago

I added a comment about this issue on the dev wiki in the section on local testing, since it means that the test suite fails on the second run after a fresh install, which is mysterious if you don't know about it (and annoying if you do know about it).

This is because, although the integrity check ignores new files (with a commented out assertion), those new files become changed files after the first run.

I think the proper fix is to run each test in a temporary directory, rather than in data/sct_testing_data.

Before finding this existing issue, I tried making data/sct_testing_data and its contents read-only, and got 62 failures and 1 error in the test suite:


========================================================================== short test summary info ==========================================================================
FAILED testing/api/test_register.py::test_register_step_ants_slice_regularized_registration - PermissionError: [Errno 13] Permission denied: '$SCT_DIR/data/sct_testing_data/mt/mt0_seg_crop.nii.gz'
FAILED testing/cli/test_cli_sct_analyze_lesion.py::test_sct_analyze_lesion_matches_expected_dummy_lesion_measurements[dummy_lesion0-0.001] - PermissionError: [Errno 13] Permission denied: '/tmp/sct_2023-04-04_15-18-59_analyze-lesion_5w9eprmb/t2_seg-manual.nii.gz'
FAILED testing/cli/test_cli_sct_analyze_lesion.py::test_sct_analyze_lesion_matches_expected_dummy_lesion_measurements[dummy_lesion1-0.001] - PermissionError: [Errno 13] Permission denied: '/tmp/sct_2023-04-04_15-18-59_analyze-lesion_dqykol66/t2_seg-manual.nii.gz'
FAILED testing/cli/test_cli_sct_analyze_lesion.py::test_sct_analyze_lesion_matches_expected_dummy_lesion_measurements[dummy_lesion2-0.01] - PermissionError: [Errno 13] Permission denied: '/tmp/sct_2023-04-04_15-18-59_analyze-lesion_rj_71f_b/t2_seg-manual.nii.gz'
FAILED testing/cli/test_cli_sct_analyze_texture.py::test_sct_analyze_texture_image_data_within_threshold - PermissionError: [Errno 13] Permission denied: './t2_contrast_1_0.nii.gz'
FAILED testing/cli/test_cli_sct_apply_transfo.py::test_sct_apply_transfo_output_image_attributes[template/template/PAM50_small_t2.nii.gz-t2/t2.nii.gz-t2/warp_template2anat.nii.gz-PAM50_small_t2_reg.nii-remaining_args0] - FileNotFoundError: No such file or no access: '$SCT_DIR/data/sct_testing_data/PAM50_small_t2_reg.nii'
FAILED testing/cli/test_cli_sct_apply_transfo.py::test_sct_apply_transfo_output_image_attributes[template/template/PAM50_small_t2.nii.gz-t2/t2.nii.gz-t2/warp_template2anat.nii.gz-PAM50_small_t2_reg-crop1.nii-remaining_args1] - FileNotFoundError: No such file or no access: '$SCT_DIR/data/sct_testing_data/PAM50_small_t2_reg-crop1.nii'
FAILED testing/cli/test_cli_sct_apply_transfo.py::test_sct_apply_transfo_output_image_attributes[template/template/PAM50_small_t2.nii.gz-t2/t2.nii.gz-t2/warp_template2anat.nii.gz-PAM50_small_t2_reg-crop2.nii-remaining_args2] - FileNotFoundError: No such file or no access: '$SCT_DIR/data/sct_testing_data/PAM50_small_t2_reg-crop2.nii'
FAILED testing/cli/test_cli_sct_apply_transfo.py::test_sct_apply_transfo_output_image_attributes[template/template/PAM50_small_t2.nii.gz-t2/t2.nii.gz-t2/warp_template2anat.nii.gz-PAM50_small_t2_reg-concatWarp.nii-remaining_args3] - FileNotFoundError: No such file or no access: '$SCT_DIR/data/sct_testing_data/PAM50_small_t2_reg-concatWarp.nii'
FAILED testing/cli/test_cli_sct_apply_transfo.py::test_sct_apply_transfo_output_image_attributes[template/template/PAM50_small_t2.nii.gz-dmri/dmri.nii.gz-t2/warp_template2anat.nii.gz-PAM50_small_t2_reg-4Dref.nii-remaining_args4] - FileNotFoundError: No such file or no access: '$SCT_DIR/data/sct_testing_data/PAM50_small_t2_reg-4Dref.nii'
FAILED testing/cli/test_cli_sct_apply_transfo.py::test_sct_apply_transfo_output_image_attributes[dmri/dmri.nii.gz-t2/t2.nii.gz-mt/warp_t22mt1.nii.gz-PAM50_small_t2_reg-4Din.nii-remaining_args5] - PermissionError: [Errno 13] Permission denied: 'PAM50_small_t2_reg-4Din.nii'
FAILED testing/cli/test_cli_sct_compute_ernst_angle.py::test_sct_compute_ernst_angle_value_against_groundtruth - PermissionError: [Errno 13] Permission denied: 'ernst_angle.txt'
FAILED testing/cli/test_cli_sct_compute_hausdorff_distance.py::test_sct_compute_hausdorff_distance_null_values - PermissionError: [Errno 13] Permission denied: '$SCT_DIR/data/sct_testing_data/t2s_gmseg_manual_thinned.nii.gz'
FAILED testing/cli/test_cli_sct_concat_transfo.py::test_sct_concat_transfo_no_checks - ValueError: Warping field was not generated! output_image_filename: warp_final.nii.gz
FAILED testing/cli/test_cli_sct_convert.py::test_sct_convert_output_file_exists - PermissionError: [Errno 13] Permission denied: '$SCT_DIR/data/sct_testing_data/t2.nii'
FAILED testing/cli/test_cli_sct_create_mask.py::test_sct_create_mask_no_checks[mt/mt1.nii.gz-coord,15x17-10] - PermissionError: [Errno 13] Permission denied: '$SCT_DIR/data/sct_testing_data/mask_mt1.nii.gz'
FAILED testing/cli/test_cli_sct_create_mask.py::test_sct_create_mask_no_checks[mt/mt1.nii.gz-point,mt/mt1_point.nii.gz-10] - PermissionError: [Errno 13] Permission denied: '$SCT_DIR/data/sct_testing_data/mask_mt1.nii.gz'
FAILED testing/cli/test_cli_sct_create_mask.py::test_sct_create_mask_no_checks[mt/mt1.nii.gz-center-10] - PermissionError: [Errno 13] Permission denied: '$SCT_DIR/data/sct_testing_data/mask_mt1.nii.gz'
FAILED testing/cli/test_cli_sct_create_mask.py::test_sct_create_mask_no_checks[mt/mt1.nii.gz-centerline,mt/mt1_seg.nii.gz-5] - PermissionError: [Errno 13] Permission denied: '$SCT_DIR/data/sct_testing_data/mask_mt1.nii.gz'
FAILED testing/cli/test_cli_sct_create_mask.py::test_sct_create_mask_no_checks[dmri/dmri.nii.gz-center-10] - PermissionError: [Errno 13] Permission denied: '$SCT_DIR/data/sct_testing_data/mask_dmri.nii.gz'
FAILED testing/cli/test_cli_sct_crop_image.py::test_sct_crop_image_output_has_expected_dimensions[t2/t2.nii.gz-t2_crop_xyz.nii-remaining_args0-expected_dim0] - PermissionError: [Errno 13] Permission denied: '$SCT_DIR/data/sct_testing_data/t2_crop_xyz.nii'
FAILED testing/cli/test_cli_sct_crop_image.py::test_sct_crop_image_output_has_expected_dimensions[t2/t2.nii.gz-t2_crop_mask.nii-remaining_args1-expected_dim1] - PermissionError: [Errno 13] Permission denied: '$SCT_DIR/data/sct_testing_data/t2_crop_mask.nii'
FAILED testing/cli/test_cli_sct_crop_image.py::test_sct_crop_image_output_has_expected_dimensions[t2/t2.nii.gz-t2_crop_ref.nii-remaining_args2-expected_dim2] - PermissionError: [Errno 13] Permission denied: '$SCT_DIR/data/sct_testing_data/t2_crop_ref.nii'
FAILED testing/cli/test_cli_sct_crop_image.py::test_sct_crop_image_output_has_expected_dimensions[t2/t2.nii.gz-t2_crop_dilate_xyz.nii-remaining_args3-expected_dim3] - PermissionError: [Errno 13] Permission denied: '$SCT_DIR/data/sct_testing_data/t2_crop_dilate_xyz.nii'
FAILED testing/cli/test_cli_sct_crop_image.py::test_sct_crop_image_output_has_expected_dimensions[t2/t2.nii.gz-t2_crop_dilate_mask.nii-remaining_args4-expected_dim4] - PermissionError: [Errno 13] Permission denied: '$SCT_DIR/data/sct_testing_data/t2_crop_dilate_mask.nii'
FAILED testing/cli/test_cli_sct_crop_image.py::test_sct_crop_image_output_has_expected_dimensions[t2/t2.nii.gz-t2_crop_dilate_ref.nii-remaining_args5-expected_dim5] - PermissionError: [Errno 13] Permission denied: '$SCT_DIR/data/sct_testing_data/t2_crop_dilate_ref.nii'
FAILED testing/cli/test_cli_sct_deepseg_gm.py::test_sct_deepseg_gm_check_dice_coefficient_against_groundtruth - PermissionError: [Errno 13] Permission denied: 'output.nii.gz'
FAILED testing/cli/test_cli_sct_deepseg_lesion.py::test_sct_deepseg_lesion_no_checks - PermissionError: [Errno 13] Permission denied: '$SCT_DIR/data/sct_testing_data/t2/t2_res_RPI_seg.nii.gz'
FAILED testing/cli/test_cli_sct_deepseg_sc.py::test_sct_deepseg_sc_qc_report_exists - PermissionError: [Errno 13] Permission denied: '$SCT_DIR/data/sct_testing_data/t2_seg.nii.gz'
FAILED testing/cli/test_cli_sct_denoising_onlm.py::test_sct_denoising_onlm_no_checks - PermissionError: [Errno 13] Permission denied: 't2_denoised.nii.gz'
FAILED testing/cli/test_cli_sct_detect_pmj.py::test_sct_detect_pmj_check_euclidean_distance_against_groundtruth - PermissionError: [Errno 13] Permission denied: '/tmp/sct_2023-04-04_15-19-18_detect-pmj_ivtfjt59/PAM50_small_t2.nii.gz'
FAILED testing/cli/test_cli_sct_dice_coefficient.py::test_sct_dice_coefficient_check_output_against_groundtruth - PermissionError: [Errno 13] Permission denied: '/tmp/sct_2023-04-04_15-19-18_dice-coefficient__063is41/tmp2_t2_seg-manual.nii.gz'
FAILED testing/cli/test_cli_sct_dmri_compute_dti.py::test_sct_dmri_compute_dti_no_checks - PermissionError: [Errno 13] Permission denied: '$SCT_DIR/data/sct_testing_data/dti_FA.nii.gz'
FAILED testing/cli/test_cli_sct_dmri_concat_b0_and_dwi.py::test_sct_dmri_concat_b0_and_dwi_no_checks - PermissionError: [Errno 13] Permission denied: '$SCT_DIR/data/sct_testing_data/b0_dwi_concat.nii'
FAILED testing/cli/test_cli_sct_dmri_concat_bvals.py::test_sct_dmri_concat_bvals_no_checks - PermissionError: [Errno 13] Permission denied: 'bvals_concat.txt'
FAILED testing/cli/test_cli_sct_dmri_concat_bvecs.py::test_sct_dmri_concat_bvecs_no_checks - PermissionError: [Errno 13] Permission denied: 'bvecs_concat.txt'
FAILED testing/cli/test_cli_sct_dmri_separate_b0_and_dwi.py::test_sct_dmri_separate_b0_and_dwi_image_data_within_threshold - PermissionError: [Errno 13] Permission denied: '$SCT_DIR/data/sct_testing_data/dmri_b0.nii.gz'
FAILED testing/cli/test_cli_sct_dmri_transpose_bvecs.py::test_sct_dmri_transpose_bvecs_no_checks - PermissionError: [Errno 13] Permission denied: 'bvecs.txt'
FAILED testing/cli/test_cli_sct_extract_metric.py::test_sct_extract_metric_against_groundtruth - PermissionError: [Errno 13] Permission denied: 'quantif_mtr.csv'
FAILED testing/cli/test_cli_sct_flatten_sagittal.py::test_sct_flatten_sagittal_no_checks - PermissionError: [Errno 13] Permission denied: '$SCT_DIR/data/sct_testing_data/t2/t2_flatten.nii.gz'
FAILED testing/cli/test_cli_sct_fmri_compute_tsnr.py::test_sct_sct_fmri_compute_tsnr_no_checks - PermissionError: [Errno 13] Permission denied: '$SCT_DIR/data/sct_testing_data/out_fmri_tsnr.nii.gz'
FAILED testing/cli/test_cli_sct_fmri_moco.py::test_sct_fmri_moco_no_checks - PermissionError: [Errno 13] Permission denied: '$SCT_DIR/data/sct_testing_data/fmri_r_moco.nii.gz'
FAILED testing/cli/test_cli_sct_get_centerline.py::test_sct_get_centerline_output_file_exists - PermissionError: [Errno 13] Permission denied: '$SCT_DIR/data/sct_testing_data/t2s/t2s_centerline.nii.gz'
FAILED testing/cli/test_cli_sct_get_centerline.py::test_sct_get_centerline_output_file_exists_with_o_arg[] - AssertionError: assert False
FAILED testing/cli/test_cli_sct_get_centerline.py::test_sct_get_centerline_output_file_exists_with_o_arg[.nii.gz] - AssertionError: assert False
FAILED testing/cli/test_cli_sct_image.py::test_sct_image_pad - PermissionError: [Errno 13] Permission denied: '$SCT_DIR/data/sct_testing_data/sct_image_out.nii.gz'
FAILED testing/cli/test_cli_sct_image.py::test_sct_image_display_warp_check_output_exists - FileNotFoundError: No such file or no access: '$SCT_DIR/data/sct_testing_data/t2/grid_3_resample_warp_template2anat.nii.gz'
FAILED testing/cli/test_cli_sct_label_utils.py::test_sct_label_utils_cubic_to_point - PermissionError: [Errno 13] Permission denied: '$SCT_DIR/data/sct_testing_data/test_centerofmass.nii.gz'
FAILED testing/cli/test_cli_sct_label_utils.py::test_sct_label_utils_create - PermissionError: [Errno 13] Permission denied: '$SCT_DIR/data/sct_testing_data/labels.nii.gz'
FAILED testing/cli/test_cli_sct_label_vertebrae.py::test_sct_label_vertebrae_initfile_qc_no_checks - PermissionError: [Errno 13] Permission denied: 'testing-qc'
FAILED testing/cli/test_cli_sct_maths.py::test_sct_maths_percent_no_checks - PermissionError: [Errno 13] Permission denied: '$SCT_DIR/data/sct_testing_data/test.nii.gz'
FAILED testing/cli/test_cli_sct_maths.py::test_sct_maths_add_integer_no_checks - PermissionError: [Errno 13] Permission denied: '$SCT_DIR/data/sct_testing_data/test.nii.gz'
FAILED testing/cli/test_cli_sct_merge_images.py::test_sct_merge_images_no_checks - PermissionError: [Errno 13] Permission denied: '$SCT_DIR/data/sct_testing_data/merged_images.nii.gz'
FAILED testing/cli/test_cli_sct_process_segmentation.py::test_sct_process_segmentation_no_checks - PermissionError: [Errno 13] Permission denied: '$SCT_DIR/data/sct_testing_data/csa.csv'
FAILED testing/cli/test_cli_sct_propseg.py::test_sct_propseg_check_dice_coefficient_against_groundtruth - PermissionError: [Errno 13] Permission denied: 'testing-qc'
FAILED testing/cli/test_cli_sct_qc.py::test_sct_qc_no_checks - PermissionError: [Errno 13] Permission denied: './qc'
FAILED testing/cli/test_cli_sct_register_to_template.py::test_sct_register_to_template_dice_coefficient_against_groundtruth[template/template/PAM50_small_cord.nii.gz-remaining_args0] - PermissionError: [Errno 13] Permission denied: 'qc-testing'
FAILED testing/cli/test_cli_sct_register_to_template.py::test_sct_register_to_template_dice_coefficient_against_groundtruth[$SCT_DIR/data/PAM50/template/PAM50_cord.nii.gz-remaining_args1] - PermissionError: [Errno 13] Permission denied: 'warp_template2anat.nii.gz'
FAILED testing/cli/test_cli_sct_smooth_spinalcord.py::test_sct_smooth_spinalcord_check_output_files - PermissionError: [Errno 13] Permission denied: '$SCT_DIR/data/sct_testing_data/straightening.cache'
FAILED testing/cli/test_cli_sct_straighten_spinalcord.py::test_sct_straighten_spinalcord_no_checks - PermissionError: [Errno 13] Permission denied: './warp_curve2straight.nii.gz'
FAILED testing/cli/test_cli_sct_warp_template.py::test_sct_warp_template_no_checks - PermissionError: [Errno 13] Permission denied: 'testing-qc'
FAILED testing/cli/test_sct_deepseg.py::test_install_model - PermissionError: [Errno 13] Permission denied: 't2star_sc.pt'
ERROR testing/cli/test_cli_sct_dmri_moco.py::test_sct_dmri_moco_sagittal_no_checks - PermissionError: [Errno 13] Permission denied: '$SCT_DIR/data/sct_testing_data/dmri/dmri_AIL.nii'
============================================== 62 failed, 355 passed, 11 skipped, 66876 warnings, 1 error in 176.62s (0:02:56) ==============================================
joshuacwnewton commented 6 months ago

I think the proper fix is to run each test in a temporary directory, rather than in data/sct_testing_data.

By using an autouse fixture that calls Pytest's tmp_path, each test gets its own output directory, which results in lovely organization for free:

![image](https://github.com/spinalcordtoolbox/spinalcordtoolbox/assets/16181459/139c4693-eb5c-4756-afd4-a41d5fbdc433)

Plus, all of our existing usages of tmp_path can remain unchanged, because both the cd fixture and the test itself refer to the same tmp_path location per-test.

(The only tedious thing will be updating all of the relative input data paths (t2/t2.nii.gz) with explicit paths to the testing directory (sct_test_path('t2', 't2.nii.gz'). But, that was kind of an inevitability with a task like this...)