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
2 changes: 0 additions & 2 deletions .github/workflows/CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,6 @@ jobs:
exclude:
- rdkit: false
openeye: false
- openeye: true
python-version: "3.11"
Comment on lines -31 to -32
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the primary culprit; we need to double-check the CI matrix after removing old Python versions (or run more combinations on multiple version)

- openeye: true
python-version: "3.12"
- openeye: true
Expand Down
2 changes: 1 addition & 1 deletion devtools/conda-envs/openeye.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ dependencies:
- mdtraj
- nglview
- parmed =4
- mypy =1.15
- mypy =1.18
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the most recent version; if there's a reason to downpin I am happy to update

- typing_extensions
- pip:
- types-setuptools
Expand Down
6 changes: 3 additions & 3 deletions docs/api/toolkits.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ The default value of this argument is the [`GLOBAL_TOOLKIT_REGISTRY`], which by
```pycon
>>> from openff.toolkit import GLOBAL_TOOLKIT_REGISTRY
>>> len(GLOBAL_TOOLKIT_REGISTRY.registered_toolkits)
4
5

```

Expand All @@ -64,7 +64,7 @@ The [`toolkit_registry_manager`] context manager allows `GLOBAL_TOOLKIT_REGISTRY
```pycon
>>> from openff.toolkit.utils import toolkit_registry_manager
>>> print(len(GLOBAL_TOOLKIT_REGISTRY.registered_toolkits))
4
5
>>> with toolkit_registry_manager(
... ToolkitRegistry([RDKitToolkitWrapper(), AmberToolsToolkitWrapper()])
... ):
Expand Down Expand Up @@ -98,4 +98,4 @@ For more information about modifying `GLOBAL_TOOLKIT_REGISTRY`, see the [`GLOBAL
BuiltInToolkitWrapper
GLOBAL_TOOLKIT_REGISTRY
toolkit_registry_manager
```
```
517 changes: 259 additions & 258 deletions docs/users/molecule_cookbook.ipynb

Large diffs are not rendered by default.

10 changes: 7 additions & 3 deletions openff/toolkit/topology/molecule.py
Original file line number Diff line number Diff line change
Expand Up @@ -1250,8 +1250,9 @@ def ordered_connection_table_hash(self) -> int:
for bond in self.bonds:
id += f"{bond.bond_order}_{bond.stereochemistry}_{bond.atom1_index}_{bond.atom2_index}__"

self._ordered_connection_table_hash = hashlib.sha3_224(id.encode("utf-8")).hexdigest()
return self._ordered_connection_table_hash
# at this point, it's no longer a union type
self._ordered_connection_table_hash = hashlib.sha3_224(id.encode("utf-8")).hexdigest() # type: ignore[assignment]
return self._ordered_connection_table_hash # type: ignore[return-value]

@classmethod
def from_dict(cls: type[FM], molecule_dict: dict) -> FM:
Expand Down Expand Up @@ -2785,6 +2786,8 @@ def _invalidate_cached_properties(self):
self._hill_formula = None
self._cached_smiles = dict()
# TODO: Clear fractional bond orders

# TODO: deleting this attribute instead of setting it to None would be cleaner
self._ordered_connection_table_hash = None

for atom in self.atoms:
Expand Down Expand Up @@ -5652,7 +5655,8 @@ def _networkx_graph_to_hill_formula(graph: "nx.Graph[int]") -> str:
if not isinstance(graph, nx.Graph):
raise ValueError("The graph must be a NetworkX graph.")

atom_nums = list(dict(graph.nodes(data="atomic_number", default=1)).values())
atom_nums: list[int] = [atomic_number for (_, atomic_number) in graph.nodes(data="atomic_number", default=1)]

return _atom_nums_to_hill_formula(atom_nums) # type:ignore[arg-type]


Expand Down
30 changes: 18 additions & 12 deletions openff/toolkit/topology/topology.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@
from openff.toolkit.utils import ToolkitRegistry, ToolkitWrapper

TKR: TypeAlias = Union["ToolkitRegistry", "ToolkitWrapper"]

AtomLike: TypeAlias = Union["Atom", "_SimpleAtom"]
BondLike: TypeAlias = Union["Bond", "_SimpleBond"]
MoleculeLike: TypeAlias = Union["Molecule", "FrozenMolecule", "_SimpleMolecule"]

_DISTANCE_UNITS = set(
Expand Down Expand Up @@ -459,7 +462,7 @@ def _initialize(self):
"""
self._constrained_atom_pairs = dict()
self._box_vectors = None
self._molecules = list()
self._molecules: list[MoleculeLike] = list()
self._cached_chemically_identical_molecules = None

def __iadd__(self, other):
Expand Down Expand Up @@ -501,7 +504,7 @@ def __add__(self, other):
return combined

@property
def unique_molecules(self) -> Iterator[Molecule | _SimpleMolecule]:
def unique_molecules(self) -> Iterator[MoleculeLike]:
"""
Get a list of chemically unique molecules in this Topology.

Expand Down Expand Up @@ -700,7 +703,7 @@ def molecules(self) -> Iterator[MoleculeLike]:
# invalidate themselves during appropriate events.
yield from self._molecules

def molecule(self, index: int) -> Molecule | _SimpleMolecule:
def molecule(self, index: int) -> MoleculeLike:
"""
Returns the molecule with a given index in this Topology.

Expand Down Expand Up @@ -816,7 +819,7 @@ def n_bonds(self) -> int:
return n_bonds

@property
def bonds(self) -> Generator["Bond", None, None]:
def bonds(self) -> Generator[BondLike, None, None]:
"""Returns an iterator over the bonds in this Topology

Returns
Expand All @@ -832,7 +835,7 @@ def n_angles(self) -> int:
return sum(mol.n_angles for mol in self._molecules)

@property
def angles(self) -> Generator[tuple["Atom", ...], None, None]:
def angles(self) -> Generator[tuple[AtomLike, AtomLike, AtomLike], None, None]:
Comment on lines -835 to +838
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This changes are intentional

  • Having it cover Atom | _SimpleAtom is intentional
  • Being length-3 (length-4 below) is important; tuple[x, ...] can be a tuple of any length but containing only X (docs)

"""Iterator over the angles in this Topology. Returns a Generator of tuple[Atom]."""
for molecule in self._molecules:
yield from molecule.angles
Expand All @@ -843,7 +846,7 @@ def n_propers(self) -> int:
return sum(mol.n_propers for mol in self._molecules)

@property
def propers(self) -> Generator[tuple[Union["Atom", _SimpleAtom], ...], None, None]:
def propers(self) -> Generator[tuple[AtomLike, AtomLike, AtomLike, AtomLike], None, None]:
"""Iterable of tuple[Atom]: iterator over the proper torsions in this Topology."""
for molecule in self.molecules:
yield from molecule.propers
Expand All @@ -854,7 +857,7 @@ def n_impropers(self) -> int:
return sum(mol.n_impropers for mol in self._molecules)

@property
def impropers(self) -> Generator[tuple["Atom", ...], None, None]:
def impropers(self) -> Generator[tuple[AtomLike, AtomLike, AtomLike, AtomLike], None, None]:
"""Generator of tuple[Atom]: iterator over the possible improper torsions in this Topology."""
for molecule in self._molecules:
yield from molecule.impropers
Expand Down Expand Up @@ -1764,7 +1767,7 @@ def from_pdb(
off_atom.name = atom.name

for offmol in topology.molecules:
offmol.add_default_hierarchy_schemes()
offmol.add_default_hierarchy_schemes() # type: ignore[operator]
Comment on lines -1767 to +1770
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method if properly defined, but something in the writing was getting crossed and add_default_hierarchy_schemes was inferred to be a list[HierarchyElement]. That's not a function, so ()-ing it is an error


return topology

Expand Down Expand Up @@ -2105,8 +2108,10 @@ def set_positions(self, array: Quantity) -> None:

# Copy the array in nanometers and make it an OpenFF Quantity
array = Quantity(np.asarray(array.to(unit.nanometer).magnitude), unit.nanometer)
if array.shape != (self.n_atoms, 3):
raise WrongShapeError(f"Array has shape {array.shape} but should have shape {self.n_atoms, 3}")
if array.shape != (self.n_atoms, 3): # type: ignore[attr-defined]
raise WrongShapeError(
f"Array has shape {array.shape} but should have shape {self.n_atoms, 3}" # type: ignore[attr-defined]
)

start = 0
for molecule in self.molecules:
Expand Down Expand Up @@ -2298,7 +2303,7 @@ def atom(self, atom_topology_index: int) -> "Atom":
# atom_molecule_index = atom_topology_index - search_index
# return topology_molecule.atom(atom_molecule_index)

def bond(self, bond_topology_index: int) -> "Bond": # type: ignore[return]
def bond(self, bond_topology_index: int) -> BondLike: # type: ignore[return]
"""
Get the Bond at a given Topology bond index.

Expand All @@ -2311,6 +2316,7 @@ def bond(self, bond_topology_index: int) -> "Bond": # type: ignore[return]
-------
An openff.toolkit.topology.Bond
"""
# TODO: Does this work with _SimpleMolecule/_SimpleBond?
if not isinstance(bond_topology_index, int):
raise ValueError(
"Argument passed to `Topology.bond` must be an int. "
Expand Down Expand Up @@ -2341,7 +2347,7 @@ def add_molecule(

To add multiple molecules, particularly many times, use `add_molecules` for better performance.
"""
if isinstance(molecule, Molecule | _SimpleMolecule):
if isinstance(molecule, FrozenMolecule | _SimpleMolecule):
# Route everything through add_molecules for simplicity; the overhead of
# making a list and grabbing the first element should be negligible
return self.add_molecules([molecule])[0]
Expand Down
2 changes: 1 addition & 1 deletion openff/toolkit/typing/engines/smirnoff/parameters.py
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ class ParameterAttribute:
>>> my_par.attr_required
Traceback (most recent call last):
...
AttributeError: 'MyParameter' object has no attribute '_attr_required'. Did you mean: 'attr_required'?
AttributeError: 'MyParameter' object has no attribute '_attr_required'

The attribute allow automatic conversion and validation of units.

Expand Down
2 changes: 1 addition & 1 deletion openff/toolkit/utils/toolkit_registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ class ToolkitRegistry:

>>> from openff.toolkit.utils.toolkits import GLOBAL_TOOLKIT_REGISTRY
>>> GLOBAL_TOOLKIT_REGISTRY
<ToolkitRegistry containing OpenEye Toolkit, The RDKit, AmberTools, Built-in Toolkit>
<ToolkitRegistry containing OpenFF NAGL, OpenEye Toolkit, The RDKit, AmberTools, Built-in Toolkit>

Note that this will contain different ToolkitWrapper objects based on what
toolkits are currently installed.
Expand Down