diff --git a/gufe/mapping/atom_mapper.py b/gufe/mapping/atom_mapper.py index c2844979..1bda99b6 100644 --- a/gufe/mapping/atom_mapper.py +++ b/gufe/mapping/atom_mapper.py @@ -9,7 +9,7 @@ from .atom_mapping import AtomMapping -class AtomMapper(GufeTokenizable): +class AtomMapper[_Component: gufe.Component](GufeTokenizable): """A class for manufacturing mappings Implementations of this class can require an arbitrary and non-standardised @@ -19,7 +19,7 @@ class AtomMapper(GufeTokenizable): """ @abc.abstractmethod - def suggest_mappings(self, A: gufe.Component, B: gufe.Component) -> Iterator[AtomMapping]: + def suggest_mappings(self, A: _Component, B: _Component) -> Iterator[AtomMapping]: """Suggests possible mappings between two Components Suggests zero or more :class:`.AtomMapping` objects, which are possible diff --git a/gufe/mapping/componentmapping.py b/gufe/mapping/componentmapping.py index 8c665a0a..bea4378d 100644 --- a/gufe/mapping/componentmapping.py +++ b/gufe/mapping/componentmapping.py @@ -1,12 +1,11 @@ # This code is part of gufe and is licensed under the MIT license. # For details, see https://github.com/OpenFreeEnergy/gufe -import abc import gufe from gufe.tokenization import GufeTokenizable -class ComponentMapping(GufeTokenizable, abc.ABC): +class ComponentMapping(GufeTokenizable): """A relationship between two Components stating that they transform in some way For components that are atom-based is specialised to :class:`.AtomMapping` diff --git a/gufe/mapping/ligandatommapper.py b/gufe/mapping/ligandatommapper.py new file mode 100644 index 00000000..fff53d64 --- /dev/null +++ b/gufe/mapping/ligandatommapper.py @@ -0,0 +1,64 @@ +import abc +from typing import Iterator + +from gufe import SmallMoleculeComponent + +from .atom_mapper import AtomMapper +from .ligandatommapping import LigandAtomMapping + + +class LigandAtomMapper(AtomMapper): + """ + Suggest atom mappings between two :class:`SmallMoleculeComponent` instances. + + Subclasses will typically implement the ``_mappings_generator`` method, + which returns an Iterator of :class:`.LigandAtomMapping` suggestions. + """ + + @abc.abstractmethod + def _mappings_generator( + self, + componentA: SmallMoleculeComponent, + componentB: SmallMoleculeComponent, + ) -> Iterator[dict[int, int]]: + """ + Suggest mapping options for the input molecules. + + Parameters + ---------- + componentA, componentB : rdkit.Mol + the two molecules to create a mapping for + + Returns + ------- + Iterator[dict[int, int]] : + an Iterator over proposed mappings from componentA to componentB + """ + ... + + def suggest_mappings( + self, + componentA: SmallMoleculeComponent, + componentB: SmallMoleculeComponent, + ) -> Iterator[LigandAtomMapping]: + """ + Suggest :class:`.LigandAtomMapping` options for the input molecules. + + Parameters + --------- + componentA, componentB : :class:`.SmallMoleculeComponent` + the two molecules to create a mapping for + + Returns + ------- + Iterator[LigandAtomMapping] : + an Iterator over proposed mappings + """ + # For this base class, implementation is redundant with + # _mappings_generator. However, we keep it separate so that abstract + # subclasses of this can customize suggest_mappings while always + # maintaining the consistency that concrete implementations must + # implement _mappings_generator. + + for map_dct in self._mappings_generator(componentA, componentB): + yield LigandAtomMapping(componentA, componentB, map_dct) diff --git a/pyproject.toml b/pyproject.toml index cf1471c5..fc72b5c7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -12,15 +12,13 @@ readme = "README.md" license = "MIT" license-files = [ "LICENSE" ] authors = [ { name = "The OpenFE developers", email = "openfe@omsf.io" } ] -requires-python = ">=3.10" +requires-python = ">=3.12" classifiers = [ "Development Status :: 5 - Production/Stable", "Intended Audience :: Science/Research", "Operating System :: POSIX", "Programming Language :: Python :: 3 :: Only", - "Programming Language :: Python :: 3.10", - "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14",