Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add --force mode for metadata.yml file #86

Merged
merged 16 commits into from
Jul 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,14 @@ jobs:
- name: Install package
run: pip install .[test]

- uses: actions/cache@v4
id: cache
with:
path: /home/runner/work/eye2bids/eye2bids/tests/data/osf
key: data

- name: Install data
if: ${{ steps.cache.outputs.cache-hit != 'true' }}
run: make test_data

- name: unit tests
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
[![test](https://github.com/bids-standard/eye2bids/actions/workflows/tests.yml/badge.svg)](https://github.com/bids-standard/eye2bids/actions/workflows/tests.yml)

# eye2bids

## Installation
Expand Down
1 change: 1 addition & 0 deletions eye2bids/_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,5 @@ def cli(argv: Sequence[str] = sys.argv) -> None:
metadata_file=metadata_file,
output_dir=output_dir,
interactive=args.interactive,
force=args.force,
)
9 changes: 9 additions & 0 deletions eye2bids/_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,4 +70,13 @@ def global_parser() -> ArgumentParser:
type=int,
nargs=2,
)
parser.add_argument(
"-f",
"--force",
help="""
To run the converter without passing a metadata.yml file.\n
Creates an invalid BIDS dataset.
""",
action="store_true",
)
return parser
32 changes: 26 additions & 6 deletions eye2bids/edf2bids.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ def _check_inputs(
metadata_file: str | Path | None = None,
output_dir: str | Path | None = None,
interactive: bool = False,
force: bool = False,
) -> tuple[Path, Path | None, Path]:
"""Check if inputs are valid."""
if input_file is None:
Expand All @@ -45,16 +46,34 @@ def _check_inputs(
raise FileNotFoundError(f"No such input file: {cheked_input_file}")

if metadata_file in [None, ""] and interactive:
e2b_log.info(
e2b_log.warning(
"""Load the metadata.yml file with the additional metadata.\n
This file must contain at least the additional REQUIRED metadata
You can find a template in the eye2bids GitHub.\n
This file must contain at least the additional REQUIRED metadata\n
in the format specified in the BIDS specification.\n"""
Comment on lines 50 to 53
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

update message to let users know how to avoid this warning

)
metadata_file = Prompt.ask("Enter the file path to the metadata.yml file")
Remi-Gau marked this conversation as resolved.
Show resolved Hide resolved

if metadata_file in ["", None]:
checked_metadata_file = None
elif isinstance(metadata_file, str):
if metadata_file in [None, ""]:
if not force:
e2b_log.error(
"""You didn't pass a metadata.yml file.
As this file contains metadata
which is REQUIRED for a valid BIDS dataset,
the conversion process now stops.
Please start again with a metadata.yml file
or run eye2bids in --force mode.\n
This will produce an invalid BIDS dataset.\n"""
)
raise SystemExit(1)
else:
e2b_log.warning(
"""You didn't pass a metadata.yml file.
Note that this will produce an invalid BIDS dataset.\n"""
)

checked_metadata_file = None
if isinstance(metadata_file, str):
checked_metadata_file = Path(metadata_file)
elif isinstance(metadata_file, Path):
checked_metadata_file = metadata_file
Expand Down Expand Up @@ -484,13 +503,14 @@ def edf2bids(
metadata_file: str | Path | None = None,
output_dir: str | Path | None = None,
interactive: bool = False,
force: bool = False,
) -> None:
"""Convert edf to tsv + json."""
if not _check_edf2asc_present():
return

input_file, metadata_file, output_dir = _check_inputs(
input_file, metadata_file, output_dir, interactive
input_file, metadata_file, output_dir, interactive, force
)

# CONVERSION events
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,6 @@ module = [
]

[tool.pytest.ini_options]
addopts = "-ra -q -vv --cov eye2bids"
addopts = "-ra -q -vv --cov eye2bids --durations=0"
norecursedirs = "data"
testpaths = ["tests/"]
21 changes: 12 additions & 9 deletions tests/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,23 +16,25 @@ def root_dir() -> Path:


@pytest.mark.skipif(not _check_edf2asc_present(), reason="edf2asc missing")
@pytest.mark.parametrize("metadata_file", [data_dir() / "metadata.yml", None])
@pytest.mark.parametrize("output_dir", [data_dir() / "output", None])
@pytest.mark.parametrize("use_relative_path", [False, True])
def test_edf_cli(use_relative_path, metadata_file, output_dir, eyelink_test_data_dir):
def test_edf_cli(use_relative_path, output_dir, eyelink_test_data_dir):

metadata_file = data_dir() / "metadata.yml"

input_dir = eyelink_test_data_dir / "satf"
input_file = edf_test_files(input_dir=input_dir)[0]

if use_relative_path:
input_file = input_file.relative_to(root_dir())
metadata_file = metadata_file.relative_to(root_dir())

command = ["eye2bids", "--input_file", str(input_file)]
if metadata_file is not None:
if use_relative_path:
metadata_file = metadata_file.relative_to(root_dir())
metadata_file = str(metadata_file)
command.extend(["--metadata_file", metadata_file])

command = [
"eye2bids",
"--input_file",
str(input_file),
*["--metadata_file", str(metadata_file)],
]
if output_dir is not None:
if use_relative_path:
output_dir = output_dir.relative_to(root_dir())
Expand All @@ -53,5 +55,6 @@ def test_all_edf_files(input_file):
str(input_file),
"--output_dir",
str(data_dir() / "output"),
"--force",
]
cli(command)
39 changes: 30 additions & 9 deletions tests/test_edf2bids.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,9 @@ def _check_output_exists(output_dir, input_file, eye=1):


@pytest.mark.skipif(not _check_edf2asc_present(), reason="edf2asc missing")
@pytest.mark.parametrize("metadata_file", [data_dir() / "metadata.yml", None])
def test_edf_end_to_end(metadata_file, eyelink_test_data_dir):
def test_edf_end_to_end(eyelink_test_data_dir):
metadata_file = data_dir() / "metadata.yml"

input_dir = eyelink_test_data_dir / "satf"
input_file = edf_test_files(input_dir=input_dir)[0]

Expand All @@ -75,8 +76,28 @@ def test_edf_end_to_end(metadata_file, eyelink_test_data_dir):


@pytest.mark.skipif(not _check_edf2asc_present(), reason="edf2asc missing")
@pytest.mark.parametrize("metadata_file", [data_dir() / "metadata.yml", None])
def test_edf_end_to_end_2eyes(metadata_file, eyelink_test_data_dir):
def test_edf_end_to_end_error_no_metadata(eyelink_test_data_dir):
input_dir = eyelink_test_data_dir / "2eyes"
input_file = edf_test_files(input_dir=input_dir)[0]

output_dir = data_dir() / "output"
output_dir.mkdir(exist_ok=True)

# when force is true no system exit even with no metadata file
edf2bids(input_file=input_file, metadata_file=None, output_dir=output_dir, force=True)
# but when force is false, no metadata file triggers a failure
with pytest.raises(SystemExit) as pytest_wrapped_e:
edf2bids(
input_file=input_file, metadata_file=None, output_dir=output_dir, force=False
)
assert pytest_wrapped_e.type == SystemExit
assert pytest_wrapped_e.value.code == 1


@pytest.mark.skipif(not _check_edf2asc_present(), reason="edf2asc missing")
def test_edf_end_to_end_2eyes(eyelink_test_data_dir):
metadata_file = data_dir() / "metadata.yml"

input_dir = eyelink_test_data_dir / "2eyes"
input_file = edf_test_files(input_dir=input_dir)[0]

Expand Down Expand Up @@ -123,7 +144,7 @@ def test_edf_nan_in_tsv(eyelink_test_data_dir):
output_dir = data_dir() / "output"
output_dir.mkdir(exist_ok=True)

edf2bids(input_file=input_file, output_dir=output_dir)
edf2bids(input_file=input_file, output_dir=output_dir, force=True)

expected_eyetrack_tsv = output_dir / f"{input_file.stem}_recording-eye1_physio.tsv.gz"
df = pd.read_csv(expected_eyetrack_tsv, sep="\t", header=None)
Expand All @@ -144,7 +165,7 @@ def test_number_columns_2eyes_tsv(eyelink_test_data_dir):
output_dir = data_dir() / "output"
output_dir.mkdir(exist_ok=True)

edf2bids(input_file=input_file, output_dir=output_dir)
edf2bids(input_file=input_file, output_dir=output_dir, force=True)

expected_eyetrack_tsv = output_dir / f"{input_file.stem}_recording-eye1_physio.tsv.gz"
df = pd.read_csv(expected_eyetrack_tsv, sep="\t")
Expand All @@ -165,7 +186,7 @@ def test_number_columns_1eye_tsv(eyelink_test_data_dir):
output_dir = data_dir() / "output"
output_dir.mkdir(exist_ok=True)

edf2bids(input_file=input_file, output_dir=output_dir)
edf2bids(input_file=input_file, output_dir=output_dir, force=True)

expected_eyetrack_tsv = output_dir / f"{input_file.stem}_recording-eye1_physio.tsv.gz"
df = pd.read_csv(expected_eyetrack_tsv, sep="\t")
Expand Down Expand Up @@ -469,7 +490,7 @@ def test_number_columns_physioevents_tsv(eyelink_test_data_dir):
output_dir = data_dir() / "output"
output_dir.mkdir(exist_ok=True)

edf2bids(input_file=input_file, output_dir=output_dir)
edf2bids(input_file=input_file, output_dir=output_dir, force=True)

expected_physioevents_tsv = (
output_dir / f"{input_file.stem}_recording-eye2_physioevents.tsv.gz"
Expand Down Expand Up @@ -528,7 +549,7 @@ def test_physioevents_value(folder, expected, eyelink_test_data_dir):
output_dir = data_dir() / "output"
output_dir.mkdir(exist_ok=True)

edf2bids(input_file=input_file, output_dir=output_dir)
edf2bids(input_file=input_file, output_dir=output_dir, force=True)

expected_eyetrackphysio_tsv = (
output_dir / f"{input_file.stem}_recording-eye1_physioevents.tsv.gz"
Expand Down
2 changes: 2 additions & 0 deletions tools/download_test_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@

output_dir = root_dir / "tests" / "data" / "osf"

print(f"Saving files to {output_dir}")

if output_dir.exists():
shutil.rmtree(output_dir)
output_dir.mkdir(parents=True)
Expand Down