-
Notifications
You must be signed in to change notification settings - Fork 42
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Strengthen CI and add support for rdkit>=2022.09.1 (#58)
As discussed in #57, `rdkit` introduced a breaking change in `2022.09.1` that changes the return type of `GetSSSR` from an integer (number of rings) to the rings themselves, which broke the featurization in `chem/topology_features.py`. This PR makes several changes around this: - Patching `GetSSSR` to behave differently depending on `rdkit` version, so that the downstream code works across all versions (fixes #57). - Adding `test_cli.py` which downloads the pretrained MoLeR checkpoint and uses it in CLI to verify that the behaviour (i.e. encodings of particular molecules or samples produced through random sampling) did not change (fixes #12). - Extending CI to test under a range of dependency versions, starting with the original versions used when developing MoLeR (`python==3.7.7`, `tensorflow==2.1.0` and `rdkit==2020.09.1.0`) and finishing with modern ones (`python=3.10` and latest versions of `tensorflow` and `rdkit`). With extended CI and the new CLI test, we can now be reasonably sure MoLeR works reliably across different dependency versions, and that the checkpoint trained under old versions continues to work in exactly the same way under modern ones.
- Loading branch information
Showing
13 changed files
with
163 additions
and
45 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
name: moler-env | ||
channels: | ||
- rdkit | ||
- conda-forge | ||
dependencies: | ||
- pip==23.1.2 | ||
- python==3.8.16 | ||
- rdkit==2021.09.1 | ||
- tensorflow==2.6.2 | ||
- pip: | ||
- numpy==1.22.4 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
name: moler-env | ||
channels: | ||
- rdkit | ||
- conda-forge | ||
dependencies: | ||
- pip==23.1.2 | ||
- python==3.9.16 | ||
- rdkit==2022.09.1 | ||
- tensorflow==2.9.1 | ||
- pip: | ||
- numpy==1.24.3 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
from pathlib import Path | ||
from typing import List | ||
|
||
import pytest | ||
|
||
|
||
@pytest.fixture | ||
def test_smiles_path() -> str: | ||
return Path(__file__).resolve().parent / "test_datasets" / "10_test_smiles.smiles" | ||
|
||
|
||
@pytest.fixture | ||
def test_smiles(test_smiles_path: str) -> List[str]: | ||
with open(test_smiles_path) as f: | ||
data = f.readlines() | ||
return data |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
import hashlib | ||
import urllib.request | ||
import pickle | ||
import subprocess | ||
import tempfile | ||
from pathlib import Path | ||
from typing import List | ||
|
||
import numpy as np | ||
import pytest | ||
|
||
|
||
@pytest.fixture(scope="module") | ||
def pretrained_checkpoint_dir() -> Path: | ||
"""Download a pretrained MoLeR checkpoint for testing and remove it afterwards.""" | ||
with tempfile.TemporaryDirectory() as temp_dir: | ||
temp_dir_path = Path(temp_dir) | ||
urllib.request.urlretrieve( | ||
"https://figshare.com/ndownloader/files/34642724", temp_dir_path / "model.pkl" | ||
) | ||
yield temp_dir_path | ||
|
||
|
||
def run_cli(args: List[str]) -> str: | ||
return subprocess.run( | ||
["molecule_generation"] + args, stdout=subprocess.PIPE, check=True, text=True | ||
).stdout | ||
|
||
|
||
def test_encode(pretrained_checkpoint_dir: Path, test_smiles_path: Path) -> None: | ||
output_path = pretrained_checkpoint_dir / "embeddings.pkl" | ||
run_cli(["encode", pretrained_checkpoint_dir, str(test_smiles_path), output_path]) | ||
|
||
with open(output_path, "rb") as f: | ||
embeddings = np.stack(pickle.load(f)) | ||
output_path.unlink() | ||
|
||
# There should be one encoding per SMILES in `test_smiles_path`. | ||
assert embeddings.shape == (10, 512) | ||
|
||
# Compress encodings into their norms and compare with precomputed values. | ||
expected_norms = np.asarray( | ||
[4.09043, 3.56717, 5.40588, 5.60358, 5.41453, 5.55465, 3.48990, 4.50119, 4.33559, 5.36916] | ||
) | ||
assert np.allclose(np.linalg.norm(embeddings, axis=-1), expected_norms) | ||
|
||
|
||
def test_sample(pretrained_checkpoint_dir: Path) -> None: | ||
num_samples = 100 | ||
output = run_cli(["sample", pretrained_checkpoint_dir, str(num_samples)]) | ||
|
||
samples = [smiles for smiles in output.split("\n")[1:-1]] | ||
assert len(samples) == num_samples | ||
|
||
# Check the first three outputs verbatim for easier debugging. | ||
expected_first_samples = [ | ||
"O=C1C2=CC=C(C3=CC=CC=C3)C=C=C2OC2=CC=CC=C12", | ||
"CC(=O)NC1=NC2=CC(OCC3=CC=CN(CC4=CC=C(Cl)C=C4)C3=O)=CC=C2N1", | ||
"CCN1C(=O)C2=CC=CC=C2N=C1NC(C)C(=O)NCC(=O)N=[N+]=[N-]", | ||
] | ||
assert samples[: len(expected_first_samples)] == expected_first_samples | ||
|
||
# Check all samples by comparing to a precomputed hash. | ||
samples_hash = hashlib.shake_256("\n".join(samples).encode()).hexdigest(16) | ||
assert samples_hash == "366d78fd2c71c6754a4fd9d403ad8276" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters