Skip to content
Open
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
15 changes: 3 additions & 12 deletions .github/workflows/CI.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,15 @@ on:
pull_request:
branches:
- "main"
#schedule:
# # Nightly tests run on master by default:
# # Scheduled workflows run on the latest commit on the default or base branch.
# # (from https://help.github.com/en/actions/reference/events-that-trigger-workflows#scheduled-events-schedule)
# - cron: "0 0 * * *"

jobs:
test:
name: Test on ${{ matrix.os }}, Python ${{ matrix.python-version }}
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest] #[ubuntu-latest, macOS-latest]
python-version: ['3.10'] #[3.7, 3.8, 3.9, 3.10, 3.11, 3.12]
os: [ubuntu-latest]
python-version: ['3.10']

steps:
- uses: actions/checkout@v4
Expand All @@ -32,10 +27,8 @@ jobs:
df -h
ulimit -a


- uses: mamba-org/setup-micromamba@v1
with:
#python-version: ${{ matrix.python-version }}
create-args: >-
python=${{ matrix.python-version }}
init-shell: bash
Expand All @@ -47,12 +40,10 @@ jobs:
pip install . --no-deps
conda list


- name: Run tests
shell: bash -l {0}
run: |
pip install . --no-deps
pytest -v --color=yes --cov=serenityff --cov-report=xml --run-slow serenityff/charge/tests/ tests/
pytest -v --color=yes --cov=serenityff --cov-report=xml --run-slow --tier max serenityff/charge/tests/ tests/

analyze:
name: Analyze
Expand Down
43 changes: 43 additions & 0 deletions .github/workflows/scheduled.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
name: scheduled-tests

on:
schedule:
- cron: "0 2 * * 6"

jobs:
test:
name: Run ${{ matrix.env-name }} environment
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
include:
- env-name: "min"
file: "tree_only_env.yml"
mark: "min"
- env-name: "med"
file: "min_environment.yml"
mark: "med"
- env-name: "max"
file: "environment.yml"
mark: "max"

steps:
- uses: actions/checkout@v4

- name: Setup Conda
uses: conda-incubator/setup-miniconda@v3
with:
activate-environment: test-env
environment-file: ${{ matrix.file }}

- name: End-to-End Install
shell: bash -l {0}
run: |
conda install -y pytest pytest-cov
pip install git+https://github.com/rinikerlab/DASH-tree.git@${{ github.sha }}"

- name: Run Tests
shell: bash -l {0}
run: |
pytest -v --color=yes --cov=serenityff --cov-report=xml --run-slow --tier "${{ matrix.mark }}" serenityff/charge/tests/ tests/
15 changes: 15 additions & 0 deletions serenityff/charge/tests/test_gnn_extraction.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,18 +104,21 @@ def graph(cwd) -> CustomData:
)


@pytest.mark.max
def test_getter_setter(explainer) -> None:
with pytest.raises(TypeError):
explainer.gnn_explainer = "asdf"
assert isinstance(explainer.gnn_explainer, GNNExplainer)
return


@pytest.mark.max
def test_load(model, statedict) -> None:
assert all(a == b for a, b in zip(model.state_dict(), statedict))
return


@pytest.mark.max
def test_explain_atom(explainer, graph) -> None:
explainer.gnn_explainer.explain_node(
node_idx=0,
Expand Down Expand Up @@ -150,6 +153,7 @@ def test_explain_atom(explainer, graph) -> None:
return


@pytest.mark.max
def test_extractor_properties(extractor, model, model_path, statedict_path, explainer) -> None:
extractor._set_model(model)
assert isinstance(extractor.model, ChargeCorrectedNodeWiseAttentiveFP)
Expand All @@ -166,6 +170,7 @@ def test_extractor_properties(extractor, model, model_path, statedict_path, expl
assert isinstance(extractor.model, NodeWiseAttentiveFP)


@pytest.mark.max
def test_split_sdf(cwd, sdf_path) -> None:
Extractor._split_sdf(
sdf_file=sdf_path,
Expand All @@ -178,6 +183,7 @@ def test_split_sdf(cwd, sdf_path) -> None:
return


@pytest.mark.max
def test_job_id(cwd) -> None:
with open(f"{cwd}/id.txt", "w") as f:
f.write("sdcep ab ein \n sdf <12345> saoeb <sd>")
Expand All @@ -187,11 +193,13 @@ def test_job_id(cwd) -> None:
return


@pytest.mark.max
def test_mol_from_sdf(sdf_path):
mol = mols_from_sdf(sdf_file=sdf_path)[0]
assert mol.GetNumBonds() == 19


@pytest.mark.max
def test_graph_from_mol(mol, num_atoms, num_bonds, formal_charge, smiles) -> None:
with pytest.raises(ValueError):
get_graph_from_mol(mol=mol, index=0, sdf_property_name=None)
Expand All @@ -209,6 +217,7 @@ def test_graph_from_mol(mol, num_atoms, num_bonds, formal_charge, smiles) -> Non
return


@pytest.mark.max
@pytest.mark.parametrize("sdf_prop", [(None), ("MBIScharge")])
def test_graph_from_mol_no_y(mol, num_atoms, num_bonds, formal_charge, smiles, sdf_prop) -> None:
graph = get_graph_from_mol(mol=mol, index=0, sdf_property_name=sdf_prop, no_y=True)
Expand All @@ -223,13 +232,15 @@ def test_graph_from_mol_no_y(mol, num_atoms, num_bonds, formal_charge, smiles, s
return


@pytest.mark.max
def test_arg_parser(args, sdf_path, statedict_path) -> None:
args = Extractor._parse_filenames(args)
assert args.sdffile == sdf_path
assert args.mlmodel == statedict_path
return


@pytest.mark.max
def test_script_writing(cwd) -> None:
Extractor._write_worker(directory=cwd)
Extractor._write_cleaner(directory=cwd)
Expand All @@ -239,11 +250,13 @@ def test_script_writing(cwd) -> None:
return


@pytest.mark.max
def test_explainer_initialization(extractor, model) -> None:
extractor._initialize_expaliner(model=model, epochs=1)
return


@pytest.mark.max
def test_command_to_shell_file(cwd) -> None:
command_to_shell_file("echo Hello World", f"{cwd}/test.sh")
os.path.isfile(f"{cwd}/test.sh")
Expand All @@ -253,6 +266,7 @@ def test_command_to_shell_file(cwd) -> None:
os.remove(f"{cwd}/test.sh")


@pytest.mark.max
def test_csv_handling(cwd, sdf_path, extractor, model):
extractor._initialize_expaliner(model=model, epochs=1)
outfile = f"{cwd}/sdftest/combined.csv"
Expand All @@ -268,6 +282,7 @@ def test_csv_handling(cwd, sdf_path, extractor, model):
rmtree(f"{cwd}/sdftest")


@pytest.mark.max
def test_run_extraction_local(extractor, statedict_path, cwd, sdf_path) -> None:
extractor.run_extraction_local(
sdf_file=sdf_path,
Expand Down
6 changes: 6 additions & 0 deletions serenityff/charge/tests/test_gnn_training.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ def trainer(model, optimizer):
return trainer


@pytest.mark.max
def test_init_and_forward_model(model, graph) -> None:
model = model
model.train()
Expand All @@ -99,6 +100,7 @@ def test_init_and_forward_model(model, graph) -> None:
return


@pytest.mark.max
def test_initialize_trainer(trainer, model, sdf_path, pt_path, statedict_path, model_path, statedict) -> None:
# test init
assert trainer.device == device("cuda") if is_available() else device("cpu")
Expand Down Expand Up @@ -147,6 +149,7 @@ def test_initialize_trainer(trainer, model, sdf_path, pt_path, statedict_path, m
return


@pytest.mark.max
def test_prepare_train_data(trainer, sdf_path):
with pytest.warns(Warning):
trainer.prepare_training_data()
Expand All @@ -158,6 +161,7 @@ def test_prepare_train_data(trainer, sdf_path):
return


@pytest.mark.max
def test_train_model(trainer, sdf_path) -> None:
trainer.gen_graphs_from_sdf(sdf_path)
trainer.prepare_training_data(train_ratio=0.5)
Expand All @@ -173,6 +177,7 @@ def test_train_model(trainer, sdf_path) -> None:
return


@pytest.mark.max
def test_prediction(trainer, graph, molecule) -> None:

a = trainer.predict(graph)
Expand All @@ -198,6 +203,7 @@ def test_prediction(trainer, graph, molecule) -> None:
return


@pytest.mark.max
def test_on_gpu(trainer) -> None:

assert trainer._on_gpu == is_available()
18 changes: 18 additions & 0 deletions serenityff/charge/tests/test_gnn_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ def node_features() -> np.ndarray:
)


@pytest.mark.max
def test_get_split_numbers() -> None:
assert [1, 0] == get_split_numbers(N=1, train_ratio=0.5)
assert [1, 1] == get_split_numbers(N=2, train_ratio=0.5)
Expand All @@ -136,13 +137,15 @@ def test_get_split_numbers() -> None:
return


@pytest.mark.max
def test_random_split(data) -> None:
train, test = split_data_random(data_list=data, train_ratio=0.5)
assert len(train) == 6
assert len(test) == 5
return


@pytest.mark.max
def test_kfold_split(data) -> None:
train1, test1 = split_data_Kfold(data, n_splits=2, split=0)
train2, test2 = split_data_Kfold(data, n_splits=2, split=1)
Expand All @@ -151,6 +154,7 @@ def test_kfold_split(data) -> None:
return


@pytest.mark.max
def test_initialization() -> None:
featurizer = Featurizer()
featurizer = MolecularFeaturizer()
Expand All @@ -159,13 +163,15 @@ def test_initialization() -> None:
return


@pytest.mark.max
def test_one_hot_encode(atoms, allowable_set) -> None:
assert one_hot_encode(atoms[0].GetSymbol(), allowable_set) == [1.0, 0.0, 0.0]
assert one_hot_encode(atoms[0].GetSymbol(), allowable_set, include_unknown_set=True) == [1.0, 0.0, 0.0, 0.0]
assert one_hot_encode(atoms[9].GetSymbol(), allowable_set, include_unknown_set=False) == [0.0, 0.0, 0.0]
return


@pytest.mark.max
def test_hbond_constructor(mol) -> None:
factory = _ChemicalFeaturesFactory.get_instance()
import os
Expand All @@ -180,12 +186,14 @@ def test_hbond_constructor(mol) -> None:
return


@pytest.mark.max
def test_H_bonding(mol, atoms) -> None:
hbond_infos = construct_hydrogen_bonding_info(mol)
assert get_atom_hydrogen_bonding_one_hot(atoms[11], hbond_infos) == [1.0, 1.0]
return


@pytest.mark.max
def test_degree(atoms) -> None:
assert np.where(get_atom_total_degree_one_hot(atoms[20])) == np.array([[1]])
assert np.where(get_atom_total_degree_one_hot(atoms[11])) == np.array([[2]])
Expand All @@ -194,6 +202,7 @@ def test_degree(atoms) -> None:
return


@pytest.mark.max
def test_atom_feature(mol, atoms, allowable_set) -> None:
hbond_infos = construct_hydrogen_bonding_info(mol)
feat = _construct_atom_feature(
Expand All @@ -206,6 +215,7 @@ def test_atom_feature(mol, atoms, allowable_set) -> None:
return


@pytest.mark.max
def test_bond_feat(bonds) -> None:
np.testing.assert_array_equal(np.where(_construct_bond_feature(bonds[0])), np.array([[3, 4, 5, 6]]))
np.testing.assert_array_equal(np.where(_construct_bond_feature(bonds[6])), np.array([[0, 4, 6]]))
Expand All @@ -214,6 +224,7 @@ def test_bond_feat(bonds) -> None:
return


@pytest.mark.max
def test_feature_vector_generation(smiles, mol, allowable_set, empty_set) -> None:
featurizer = MolGraphConvFeaturizer(use_edges=True)

Expand All @@ -231,6 +242,7 @@ def test_feature_vector_generation(smiles, mol, allowable_set, empty_set) -> Non
return


@pytest.mark.max
def test_graph_data_basics(node_features, edge_index, edge_features, node_pos_features) -> None:
# Trigger all __init__() failures.
with pytest.raises(TypeError):
Expand All @@ -255,6 +267,7 @@ def test_graph_data_basics(node_features, edge_index, edge_features, node_pos_fe
return


@pytest.mark.max
def test_getters(
graph_data,
custom_graph_data,
Expand Down Expand Up @@ -285,6 +298,7 @@ def test_getters(
return


@pytest.mark.max
def test_to_pyg(
custom_graph_data,
node_features,
Expand All @@ -301,6 +315,7 @@ def test_to_pyg(
return


@pytest.mark.max
def test_custom_data_attributes(custom_data) -> None:
data = custom_data
assert data.smiles == "abc"
Expand All @@ -321,6 +336,7 @@ def test_custom_data_attributes(custom_data) -> None:
return


@pytest.mark.max
def test_base_featurizer():
featurizer = Featurizer()
datapoints = [1]
Expand All @@ -332,6 +348,7 @@ def test_base_featurizer():
assert np.array_equal(features, np.asarray([np.array([])]))


@pytest.mark.max
def test_molecular_featurizer(mol, smiles):
featurizer = MolecularFeaturizer()
featurizer.featurize([mol])
Expand All @@ -340,6 +357,7 @@ def test_molecular_featurizer(mol, smiles):
featurizer.featurize(smiles)


@pytest.mark.max
def test_exceptions():
with pytest.raises(NotInitializedError):
raise NotInitializedError("msg")
Expand Down
Loading
Loading