Merge branch 'main' into fix/charge_molecules_cli_formatting

This commit is contained in:
Alyssa Travitz
2025-04-07 07:14:02 -07:00
committed by GitHub
4 changed files with 72 additions and 21 deletions

View File

@@ -378,18 +378,25 @@ Now the CLI tool should work as well ::
--log PATH logging configuration file
-h, --help Show this message and exit.
Setup Commands:
atommapping Check the atom mapping of a given pair of ligands
plan-rhfe-network Plan a relative hydration free energy network, saved in a
dir with multiple JSON files
plan-rbfe-network Plan a relative binding free energy network, saved in a
dir with multiple JSON files.
Network Planning Commands:
plan-rhfe-network Plan a relative hydration free energy network, saved as
JSON files for the quickrun command.
plan-rbfe-network Plan a relative binding free energy network, saved as
JSON files for the quickrun command.
view-ligand-network Visualize a ligand network
Simulation Commands:
gather Gather DAG result jsons for network of RFE results into single TSV
file
Quickrun Executor Commands:
gather Gather result jsons for network of RFE results into a TSV file
quickrun Run a given transformation, saved as a JSON file
Miscellaneous Commands:
fetch Fetch tutorial or other resource.
charge-molecules Generate partial charges for a set of molecules.
test Run the OpenFE test suite
To make sure everything is working, run the tests ::
$ pytest --pyargs openfe openfecli

View File

@@ -0,0 +1,23 @@
**Added:**
* ``openfe gather`` now accepts any number of filepaths and/or directories containing results JSON files, instead of only accepting one results directory.
**Changed:**
* <news item>
**Deprecated:**
* <news item>
**Removed:**
* <news item>
**Fixed:**
* <news item>
**Security:**
* <news item>

View File

@@ -4,7 +4,7 @@
import click
import os
import pathlib
from typing import Callable, Literal
from typing import Callable, Literal, List
import warnings
from openfecli import OFECommandPlugin
@@ -370,8 +370,9 @@ def _write_dg_mle(legs:dict, writer:Callable, allow_partial:bool):
'gather',
short_help="Gather result jsons for network of RFE results into a TSV file"
)
@click.argument('rootdir',
type=click.Path(dir_okay=True, file_okay=False,
@click.argument('results',
nargs=-1, # accept any number of results
type=click.Path(dir_okay=True, file_okay=True,
path_type=pathlib.Path),
required=True)
@click.option(
@@ -395,14 +396,15 @@ def _write_dg_mle(legs:dict, writer:Callable, allow_partial:bool):
"(Skip those edges and issue warning instead.)"
)
)
def gather(rootdir:os.PathLike|str,
def gather(results:List[os.PathLike|str],
output:os.PathLike|str,
report:Literal['dg','ddg','raw'],
allow_partial:bool
):
"""Gather simulation result jsons of relative calculations to a tsv file
"""Gather simulation result JSON files of relative calculations to a tsv file.
This walks ROOTDIR recursively and finds all result JSON files from the
This walks RESULTS recursively and finds all result JSON files from the
quickrun command (these files must end in .json). Each of these contains
the results of a separate leg from a relative free energy thermodynamic
cycle.
@@ -427,8 +429,19 @@ def gather(rootdir:os.PathLike|str,
import glob
import csv
results = sorted(results) # not necessary, but ensures reproducibility
def collect_jsons(results:List[os.PathLike]):
all_jsons = []
for p in results:
if str(p).endswith('json'):
all_jsons.append(p)
elif p.is_dir():
all_jsons.extend(glob.glob(f"{p}/**/*json", recursive=True))
return all_jsons
# 1) find all possible jsons
json_fns = glob.glob(str(rootdir) + '/**/*json', recursive=True)
json_fns = collect_jsons(results)
# 2) filter only result jsons
result_fns = filter(is_results_json, json_fns)

View File

@@ -1,3 +1,4 @@
import glob
from click.testing import CliRunner
import os
import pathlib
@@ -230,7 +231,8 @@ def rbfe_result_dir()->pathlib.Path:
@pytest.mark.skipif(not os.path.exists(POOCH_CACHE) and not HAS_INTERNET,reason="Internet seems to be unavailable and test data is not cached locally.")
@pytest.mark.parametrize('dataset', ['rbfe_results_serial_repeats', 'rbfe_results_parallel_repeats'])
@pytest.mark.parametrize('report', ["", "dg", "ddg", "raw"])
def test_gather(rbfe_result_dir, dataset, report):
@pytest.mark.parametrize('input_mode', ['directory','filepaths'])
def test_gather(rbfe_result_dir, dataset, report, input_mode):
expected = {
"": _EXPECTED_DG,
@@ -245,12 +247,18 @@ def test_gather(rbfe_result_dir, dataset, report):
else:
args = []
results_dir = rbfe_result_dir(dataset)
result = runner.invoke(gather, [str(results_dir)] + args + ['-o', '-'])
results = rbfe_result_dir(dataset)
if input_mode == 'directory':
results = [str(results)]
elif input_mode == 'filepaths':
results = glob.glob(f"{results}/*", recursive=True)
assert len(results) > 1 # sanity check to make sure we're passing in multiple paths
assert_click_success(result)
cli_result = runner.invoke(gather, results + args + ['-o', '-'])
actual_lines = set(result.stdout_bytes.split(b'\n'))
assert_click_success(cli_result)
actual_lines = set(cli_result.stdout_bytes.split(b'\n'))
assert set(expected.split(b'\n')) == actual_lines
@pytest.mark.skipif(not os.path.exists(POOCH_CACHE) and not HAS_INTERNET,reason="Internet seems to be unavailable and test data is not cached locally.")