Skip to content

Commit

Permalink
Revert "Remove openff.toolkit.typing.chemistry (#1509)" (#1663)
Browse files Browse the repository at this point in the history
This reverts commit a498ae0.
  • Loading branch information
j-wags authored Jun 30, 2023
1 parent f73c695 commit 1456fe0
Show file tree
Hide file tree
Showing 8 changed files with 519 additions and 8 deletions.
6 changes: 0 additions & 6 deletions docs/releasehistory.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,6 @@ Releases follow the `major.minor.micro` scheme recommended by [PEP440](https://w
* `minor` increments add features but do not break API compatibility
* `micro` increments represent bugfix releases or improvements in documentation

# 0.14.0 (or other breaking change some months after 0.12.0)

### Behavior changes
- [PR #15XX](https://github.com/openforcefield/openff-toolkit/pull/15XX):
Removes `ChemicalEnvironment` and the entire `openff.toolkit.typing.chemistry` submodule, which was deprecated in 0.12.0.

## Current development

### API-breaking changes
Expand Down
13 changes: 13 additions & 0 deletions docs/typing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,19 @@
Force field typing tools
========================

Chemical environments
---------------------

Tools for representing and operating on chemical environments

.. currentmodule:: openff.toolkit.typing.chemistry
.. autosummary::
:nosignatures:
:toctree: api/generated/

ChemicalEnvironment


Force field typing engines
--------------------------

Expand Down
212 changes: 212 additions & 0 deletions openff/toolkit/_tests/test_chemicalenvironment.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
from typing import List

import pytest

from openff.toolkit.typing.chemistry import (
AngleChemicalEnvironment,
AtomChemicalEnvironment,
BondChemicalEnvironment,
ChemicalEnvironment,
ImproperChemicalEnvironment,
TorsionChemicalEnvironment,
)
from openff.toolkit.utils.exceptions import SMIRKSMismatchError, SMIRKSParsingError
from openff.toolkit.utils.toolkits import OPENEYE_AVAILABLE

# TODO: Evaluate which tests in this file should be moved to test_toolkits
toolkits: List = []
if OPENEYE_AVAILABLE:
from openff.toolkit.utils.toolkits import OpenEyeToolkitWrapper, RDKitToolkitWrapper

toolkits.append("openeye")
toolkits.append(OpenEyeToolkitWrapper())
else:
from openff.toolkit.utils.toolkits import RDKitToolkitWrapper

toolkits.append("rdkit")
toolkits.append(RDKitToolkitWrapper())


class TestChemicalEnvironments:
def test_deprecation_warning(self):
from openff.toolkit.typing.chemistry.environment import (
ChemicalEnvironmentDeprecationWarning,
)

with pytest.warns(ChemicalEnvironmentDeprecationWarning):
ChemicalEnvironment("[*:1]")

def test_createEnvironments(self):
"""
Test all types of ChemicalEnvironment objects with defined atoms and bonds
Each will be tetrahedral carbons connected by ring single bonds
"""
AtomChemicalEnvironment("[#6X4:1]", "CT")
BondChemicalEnvironment("[#6X4:1]-[#6X4:2]", "CT-CT")
AngleChemicalEnvironment("[#6X4:1]-[#6X4:2]-[#6X4:3]", "CT-CT-CT")
TorsionChemicalEnvironment("[#6X4:1]-[#6X4:2]-[#6X4:3]-[#6X4:4]", "CT-CT-CT-CT")
ImproperChemicalEnvironment(
"[#6X4:1]-[#6X4:2](-[#6X4:3])-[#6X4:4]", "CT-CT(-CT)-CT"
)

@pytest.mark.parametrize(
["smirks", "expected_valence", "expected_chemenv_class"],
[
["[#6](-[#1])-[#8]", None, ChemicalEnvironment],
["[#6&X4&H0:1](-[#1])-[#6&X4]", "Atom", AtomChemicalEnvironment],
["[#6&X4&H0:1](-[#1])-[#6&X4:2]", "Bond", BondChemicalEnvironment],
["[*:1]-[*:2](-[#6&X4])-[*:3]", "Angle", AngleChemicalEnvironment],
[
"[#6&X4&H0:1](-[#1])-[#6&X4:2]-[#6&X4&H0:3](-[#1])-[#6&X4:4]",
"ProperTorsion",
TorsionChemicalEnvironment,
],
[
"[#1:1]-[#6&X4:2](-[#8:3])-[#1:4]",
"ImproperTorsion",
ImproperChemicalEnvironment,
],
# Test that an improper smirks is also valid as a general ChemicalEnvironment
[
"[#1:1]-[#6&X4:2](-[#8:3])-[*:4](-[#6&H1])-[#8:5]",
None,
ChemicalEnvironment,
],
["[#6$(*~[#6]=[#8])$(*-,=[#7!-1,#8,#16,#7])]", None, ChemicalEnvironment],
["CCC", None, ChemicalEnvironment],
["[#6:1]1(-;!@[#1,#6])=;@[#6]-;@[#6]1", "Atom", ChemicalEnvironment],
["C(O-[#7,#8])CC=[*]", None, ChemicalEnvironment],
[
"[#6$([#6X4](~[#7!-1,#8!-1,#16!-1,#9,#17,#35,#53])(~[#8]~[#1])):1]-"
"[#6X2H2;+0:2]-,=,:;!@;!#[#7!-1,#8,#16:3]-[#4:4]",
"ProperTorsion",
TorsionChemicalEnvironment,
],
[
"[#6$([#6X4](~[#7!-1,#8!-1,#16!-1,#9,#17,#35,#53])(~[#8]~[#1])):1]1=CCCC1",
"Atom",
AtomChemicalEnvironment,
],
[
"[*:1]-[#7X3:2](-[#6a$(*1ccc(-[#8-1X1])cc1):3])-[*:4]",
"ImproperTorsion",
ImproperChemicalEnvironment,
],
["[#6X4:1]1~[*:2]~[*$(*~[#1]):3]1", "Angle", AngleChemicalEnvironment],
["[$([#7]1~[#6]-CC1)]", None, ChemicalEnvironment],
["[$(c1ccccc1)]", None, ChemicalEnvironment],
# The next two tests are for ring-closing bonds
[
"[H][C@:4]1(C(C([C:3]([N:2]1[C:1](=O)C([H])([H])[H])([H])[H])([H])[H])([H])[H])C=O",
"ImproperTorsion",
ChemicalEnvironment,
],
["[P:1]=1=[P]=[P]=[P]=[P:2]=1", "Bond", BondChemicalEnvironment],
],
)
@pytest.mark.parametrize("toolkit", toolkits)
def test_parseSMIRKS(
self, toolkit, smirks, expected_valence, expected_chemenv_class
):
"""
Test creating environments with SMIRKS
"""
env = expected_chemenv_class(smirks=smirks, toolkit_registry=toolkit)
actual_type = env.get_type()
assert (
actual_type == expected_valence
), f"SMIRKS ({smirks}) classified as {actual_type} instead of {expected_valence} using {toolkit} toolkit"

@pytest.mark.parametrize(
("smirks", "wrong_envs"),
[
(
"[*]",
[
AtomChemicalEnvironment,
BondChemicalEnvironment,
AngleChemicalEnvironment,
TorsionChemicalEnvironment,
ImproperChemicalEnvironment,
],
),
(
"[*:1]",
[
BondChemicalEnvironment,
AngleChemicalEnvironment,
TorsionChemicalEnvironment,
ImproperChemicalEnvironment,
],
),
(
"[*:1]~[*:2]",
[
AtomChemicalEnvironment,
AngleChemicalEnvironment,
TorsionChemicalEnvironment,
ImproperChemicalEnvironment,
],
),
(
"[*:3]~[*:2]~[*:1]",
[
AtomChemicalEnvironment,
BondChemicalEnvironment,
TorsionChemicalEnvironment,
ImproperChemicalEnvironment,
],
),
(
"[*:1]~[*:2]~[*:3]~[*:4]",
[
AtomChemicalEnvironment,
BondChemicalEnvironment,
AngleChemicalEnvironment,
ImproperChemicalEnvironment,
],
),
(
"[*:1]~[*:2](~[*:3])~[*:4]",
[
AtomChemicalEnvironment,
BondChemicalEnvironment,
AngleChemicalEnvironment,
TorsionChemicalEnvironment,
],
),
(
"[*:1]~[*:2]~[*:3]~[*:4]~[*:5]",
[
AtomChemicalEnvironment,
BondChemicalEnvironment,
AngleChemicalEnvironment,
TorsionChemicalEnvironment,
ImproperChemicalEnvironment,
],
),
],
)
def test_creating_wrong_environments(self, smirks, wrong_envs):
"""
Test exceptions for making environments with the wrong smirks
"""
for wrong_env in wrong_envs:
with pytest.raises(SMIRKSMismatchError):
wrong_env(smirks)

@pytest.mark.parametrize("toolkit", toolkits)
def test_wrong_smirks_error(self, toolkit):
"""
Check that an imparseable SMIRKS raises errors
"""
smirks = "[*;:1]"
with pytest.raises(SMIRKSParsingError):
ChemicalEnvironment(smirks, toolkit_registry=toolkit)

def test_embedded_atoms_smirks(self):
"""
Check embedded atom parsing works
"""
smirks = "[#1$(*-[#6](-[#7,#8,#9,#16,#17,#35])-[#7,#8,#9,#16,#17,#35]):1]~[$([#1]~[#6])]"
ChemicalEnvironment(smirks)
7 changes: 7 additions & 0 deletions openff/toolkit/_tests/test_molecule.py
Original file line number Diff line number Diff line change
Expand Up @@ -3206,6 +3206,13 @@ def test_add_atoms_and_bonds(self, molecule):

assert molecule == molecule_copy

def test_chemical_environment_old_arg(self):
from openff.toolkit.typing.chemistry import ChemicalEnvironment

molecule = create_ethanol()
with pytest.raises(ValueError, match="'query' must be a SMARTS"):
molecule.chemical_environment_matches(ChemicalEnvironment("[*:1]"))

@requires_openeye
def test_chemical_environment_matches_OE(self):
"""Test chemical environment matches"""
Expand Down
19 changes: 19 additions & 0 deletions openff/toolkit/_tests/test_parameters.py
Original file line number Diff line number Diff line change
Expand Up @@ -820,6 +820,25 @@ def test_create(self):
p2 = ParameterType(smirks="[#1:1]")
ParameterList([p1, p2])

@pytest.mark.wip(
reason="Until ChemicalEnvironment won't be refactored to use the ToolkitRegistry "
"API, the smirks assignment will fail with RDKit."
)
def test_getitem(self):
"""Test ParameterList __getitem__ overloading."""
p1 = ParameterType(smirks="[*:1]")
p2 = ParameterType(smirks="[#1:1]")
parameters = ParameterList([p1, p2])
assert parameters[0] == p1
assert parameters[1] == p2
assert parameters[p1.smirks] == p1
assert parameters[p2.smirks] == p2

# Note that this call access __getitem__, not __setitem__.
parameters["[*:1]"].smirks = "[*X4:1]"
assert parameters[0].smirks == "[*X4:1]"
assert p1.smirks == "[*X4:1]"

def test_index(self):
"""
Tests the ParameterList.index() function by attempting lookups by SMIRKS and by ParameterType equivalence.
Expand Down
9 changes: 7 additions & 2 deletions openff/toolkit/topology/molecule.py
Original file line number Diff line number Diff line change
Expand Up @@ -3524,21 +3524,26 @@ def chemical_environment_matches(
``chemical_environment_matches``
"""
if isinstance(query, str):
smirks = query
else:
raise ValueError("'query' must be a SMARTS/SMIRKS string")

# Use specified cheminformatics toolkit to determine matches with specified aromaticity model
# TODO: Simplify this by requiring a toolkit registry for the molecule?
# TODO: Do we have to pass along an aromaticity model?
if isinstance(toolkit_registry, ToolkitRegistry):
matches = toolkit_registry.call(
"find_smarts_matches",
self,
query,
smirks,
unique=unique,
raise_exception_types=[],
)
elif isinstance(toolkit_registry, ToolkitWrapper):
matches = toolkit_registry.find_smarts_matches( # type: ignore[attr-defined]
self,
query,
smirks,
unique=unique,
)
else:
Expand Down
10 changes: 10 additions & 0 deletions openff/toolkit/typing/chemistry/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
from openff.toolkit.typing.chemistry.environment import (
AngleChemicalEnvironment,
AtomChemicalEnvironment,
BondChemicalEnvironment,
ChemicalEnvironment,
ImproperChemicalEnvironment,
SMIRKSMismatchError,
SMIRKSParsingError,
TorsionChemicalEnvironment,
)
Loading

0 comments on commit 1456fe0

Please sign in to comment.