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

Workflow tests caching #62

Merged
merged 43 commits into from
Jan 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
5ef149b
pass all parameters to cellfinder_run
sfmig Dec 20, 2023
cb0d506
changed required, optional and internal fields. read_config passes. a…
sfmig Dec 20, 2023
974140b
add signal and background data from local
sfmig Dec 20, 2023
b41d743
add missing data config fixtures
sfmig Dec 20, 2023
574733c
mark GIN download data test as slow
sfmig Dec 20, 2023
075cc50
refactor config class methods and remove setup_workflow
sfmig Dec 22, 2023
40a658d
tests pass with default config
sfmig Dec 22, 2023
45c118d
remove unused fixtures
sfmig Dec 22, 2023
b911ef3
update entry point
sfmig Dec 22, 2023
a00177d
Merge branch 'main' into smg/cellfinder-config
sfmig Jan 9, 2024
e96a883
change cellfinder-core to cellfinder in pyproject
sfmig Jan 9, 2024
a511c36
update cellfinder to cellfinder_core
sfmig Jan 9, 2024
c15b09f
renaming cellfinder script workflow to cellfinder_core. fix entrypoin…
sfmig Jan 9, 2024
f8f2af6
docstrings for class config
sfmig Jan 9, 2024
7022785
fix entry point
sfmig Jan 9, 2024
bedd3ba
skip add input paths test
sfmig Jan 9, 2024
9947440
split tests with and without CLI inputs
sfmig Dec 20, 2023
86bb090
all tests passing with default config
sfmig Dec 20, 2023
91284b9
all tests passing with default option
sfmig Dec 20, 2023
d60f503
make all paths input strings. move methods to class. make some fixtur…
sfmig Dec 20, 2023
9172e3a
refactor setup_workflow
sfmig Dec 21, 2023
242668d
cosmetic changes to fixtures
sfmig Dec 21, 2023
9500446
remove spurious monkeypatched cwd from merge
sfmig Dec 21, 2023
ca51acb
add skips that were removed in merge
sfmig Dec 21, 2023
ce4bc6e
move fixtures to code where they are used
sfmig Dec 21, 2023
d2dfb2f
bring back default_input_config_cellfinder fixture
sfmig Dec 21, 2023
2651d46
finalise adding local config as parameter in test_read_cellfinder_config
sfmig Dec 21, 2023
39043ee
add local config to remaining unit tests
sfmig Dec 21, 2023
8418ef0
add local config and GIN config to test main
sfmig Dec 21, 2023
167d78e
monkeypatched home in integration tests (only works in main)
sfmig Dec 21, 2023
1f141da
skip tests that use subprocess for now
sfmig Dec 21, 2023
35824df
monkeypatch pooch.retrieve when forcing download
sfmig Dec 21, 2023
a4d1e39
make config local fixture copy downloaded GIN data (rather than re-do…
sfmig Dec 21, 2023
0c59ba9
fix output dir definition
sfmig Dec 21, 2023
e3b3900
docstrings and remove merge artifact
sfmig Jan 9, 2024
f6f2978
fill in docstrings
sfmig Jan 10, 2024
6bc68fb
add GIN default location as a fixture
sfmig Jan 10, 2024
5cdbbeb
remove commented out GIN default location
sfmig Jan 10, 2024
a3e5370
remove tests for running script (monkeypatched home function not pass…
sfmig Jan 10, 2024
c4c998d
replace entry point test for smoketest
sfmig Jan 10, 2024
f84be90
fixes from rebase
sfmig Jan 10, 2024
6b9f90c
fix ruff
sfmig Jan 10, 2024
9c8dfaf
Merge branch 'main' into smg/workflow-tests-caching
sfmig Jan 10, 2024
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
4 changes: 2 additions & 2 deletions brainglobe_workflows/cellfinder_core/cellfinder_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@
Example usage:
- to pass a custom configuration, run (from the cellfinder_main.py
parent directory):
python cellfinder_main.py --config path/to/input/config.json
python cellfinder_core.py --config path/to/input/config.json
- to use the default configuration, run
python cellfinder_main.py
python cellfinder_core.py


"""
Expand Down
23 changes: 16 additions & 7 deletions brainglobe_workflows/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,14 +70,23 @@ def config_parser(
# initialise argument parser
parser = argparse.ArgumentParser(
description=(
"To launch the workflow with "
"a specific set of input parameters, run: "
"`python brainglobe_workflows/cellfinder.py "
"--config path/to/config.json`"
"where path/to/input/config.json is the json file "
"containing the workflow parameters."
)
"""
To launch the cellfinder workflow with default parameters, run:
`cellfinder-workflow`.
The default parameters are those specifed in brainglobe_workflows/
cellfinder_core/configs/cellfinder.json.


To launch the cellfinder workflow with a specific set of input
parameters, run:
`cellfinder-workflow --config path/to/config.json`,
where `path/to/input/config.json` is the json file with the
desired parameters.
"""
),
formatter_class=argparse.RawTextHelpFormatter,
)

# add arguments
parser.add_argument(
"-c",
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ classifiers = [
"Topic :: Scientific/Engineering :: Image Recognition",
]

# Below the dependenciess for brainmapper (the cellfinder CLI tool) only
# Below the dependencies for brainmapper (the cellfinder CLI tool) only
# (i.e., only what users will need for brainmapper)
dependencies = [
"brainglobe>=1.0.0",
Expand Down
240 changes: 227 additions & 13 deletions tests/cellfinder_core/conftest.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,47 @@
"""Pytest fixtures shared across unit and integration tests"""


import json
from pathlib import Path

import pooch
import pytest


@pytest.fixture(autouse=True)
def mock_home_directory(monkeypatch: pytest.MonkeyPatch):
"""
Monkeypatch pathlib.Path.home()

Instead of returning the usual home path, the
monkeypatched version returns the path to
Path.home() / ".brainglobe-tests"

Parameters
----------
monkeypatch : pytest.MonkeyPatch
a monkeypatch fixture
"""
# define mock home path
home_path = Path.home() # actual home path
mock_home_path = home_path / ".brainglobe-tests"

# create mock home directory if it doesn't exist
if not mock_home_path.exists():
mock_home_path.mkdir()

# monkeypatch Path.home() to point to the mock home
def mock_home():
return mock_home_path

monkeypatch.setattr(Path, "home", mock_home)


@pytest.fixture()
def default_input_config_cellfinder() -> Path:
"""Return path to default input config for cellfinder workflow
"""
Fixture for the path to the default input
configuration file for the cellfinder workflow

Returns
-------
Expand All @@ -20,18 +54,198 @@
return DEFAULT_JSON_CONFIG_PATH_CELLFINDER


@pytest.fixture(autouse=True)
def mock_home_directory(monkeypatch: pytest.MonkeyPatch):
# define mock home path
home_path = Path.home() # actual home path
mock_home_path = home_path / ".brainglobe-tests" # tmp_path #
@pytest.fixture(scope="session")
def cellfinder_GIN_data() -> dict:
"""
Fixture for the location of the test data in the GIN repository

# create dir if it doesn't exist
if not mock_home_path.exists():
mock_home_path.mkdir()
Returns
-------
dict
URL and hash of the GIN repository with the cellfinder test data
"""
return {
"url": "https://gin.g-node.org/BrainGlobe/test-data/raw/master/cellfinder/cellfinder-test-data.zip",
"hash": "b0ef53b1530e4fa3128fcc0a752d0751909eab129d701f384fc0ea5f138c5914", # noqa
}

# monkeypatch Path.home() to point to the mock home
def mock_home():
return mock_home_path

monkeypatch.setattr(Path, "home", mock_home)
@pytest.fixture()
def GIN_default_location() -> Path:
"""A fixture returning a path to the default location
where GIN data is downloaded.

Returns
-------
Path
path to the default location where to download GIN data
"""

return (
Path.home()
/ ".brainglobe"
/ "workflows"
/ "cellfinder_core"
/ "cellfinder_test_data"
)


@pytest.fixture()
def config_GIN_dict(
cellfinder_GIN_data: dict,
default_input_config_cellfinder: Path,
GIN_default_location: Path,
) -> dict:
"""
Fixture that returns a config as a dictionary, pointing to the location
where the GIN data would be by default, and download the data there.

If the file exists in the given path and the hash matches, pooch.retrieve()
will not download the file and instead its path is returned.

Parameters
----------
cellfinder_GIN_data : dict
dictionary with the location of the test data in the GIN repository
default_input_config_cellfinder : Path
path to the default input configuration file for the cellfinder
workflow
GIN_default_location : Path
path to the default location where to download GIN data

Returns
-------
dict
dictionary with the config for a workflow that uses the downloaded
GIN data
"""

# read default config as a dictionary
with open(default_input_config_cellfinder) as cfg:
config_dict = json.load(cfg)

# modify the default config:
# - add url
# - add data hash
# - remove input_data_dir if present
config_dict["data_url"] = cellfinder_GIN_data["url"]
config_dict["data_hash"] = cellfinder_GIN_data["hash"]
if "input_data_dir" in config_dict.keys():
del config_dict["input_data_dir"]

Check warning on line 134 in tests/cellfinder_core/conftest.py

View check run for this annotation

Codecov / codecov/patch

tests/cellfinder_core/conftest.py#L134

Added line #L134 was not covered by tests

# download GIN data to default location for GIN
# if the file exists in the given path and the hash matches,
# it will not be downloaded and the absolute path to the file is returned.
pooch.retrieve(
url=cellfinder_GIN_data["url"],
known_hash=cellfinder_GIN_data["hash"],
path=GIN_default_location.parent, # path to download zip to
progressbar=True,
processor=pooch.Unzip(extract_dir=GIN_default_location.stem),
)

return config_dict


@pytest.fixture()
def config_local_dict(
config_GIN_dict: dict,
GIN_default_location: Path,
) -> dict:
"""
Fixture that returns a config as a dictionary, pointing to a local dataset.

The data is copied to the local directory from the
default location used in the config_GIN_dict fixture.

Parameters
----------
config_GIN_dict : dict
dictionary with the config for a workflow that uses the downloaded
GIN data
GIN_default_location : Path
path to the default location where to download GIN data\

Returns
-------
dict
dictionary with the config for a workflow that uses local data
"""
import shutil

# copy GIN config as a dictionary
config_dict = config_GIN_dict.copy()

# modify the GIN config:
# - remove url
# - remove data hash
# - set input data directory to a local directory under home
config_dict["data_url"] = None
config_dict["data_hash"] = None
config_dict["input_data_dir"] = str(Path.home() / "local_cellfinder_data")

# copy data from default GIN location to the local location
shutil.copytree(
GIN_default_location,
config_dict["input_data_dir"],
dirs_exist_ok=True,
)

return config_dict


@pytest.fixture()
def config_GIN_json(config_GIN_dict: dict, tmp_path: Path) -> Path:
"""
Fixture that returns a config as a JSON file path, that points to GIN
downloaded data as input

Parameters
----------
config_GIN_dict : dict
dictionary with the config for a workflow that uses the downloaded
GIN data
tmp_path : Path
Pytest fixture providing a temporary path

Returns
-------
Path
path to a cellfinder config JSON file
"""
# define location of input config file
config_file_path = tmp_path / "input_config.json"

# write config dict to that location
with open(config_file_path, "w") as js:
json.dump(config_GIN_dict, js)

return config_file_path


@pytest.fixture()
def config_local_json(config_local_dict: dict, tmp_path: Path) -> Path:
"""
Fixture that returns config as a JSON file path, that points to local data
as input

Parameters
----------
config_local_dict : dict
_description_
tmp_path : Path
Pytest fixture providing a temporary path

Returns
-------
Path
path to a cellfinder config JSON file
"""
# define location of input config file
config_file_path = tmp_path / "input_config.json"

# write config dict to that location
with open(config_file_path, "w") as js:
json.dump(config_local_dict, js)

return config_file_path
Loading