diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 98db567a4..e284da347 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -23,15 +23,13 @@ jobs: strategy: matrix: os: [ubuntu-latest, macos-latest] - python-version: ["3.12", "3.13"] + python-version: ["3.12", "3.13", "3.14"] rdkit: [true, false] - openeye: [true, false] + openeye: [false] nagl: [true, false] exclude: - rdkit: false openeye: false - - openeye: true - python-version: "3.13" - rdkit: false nagl: true diff --git a/devtools/conda-envs/rdkit-examples.yaml b/devtools/conda-envs/rdkit-examples.yaml index 6ac9bf115..bf943d019 100644 --- a/devtools/conda-envs/rdkit-examples.yaml +++ b/devtools/conda-envs/rdkit-examples.yaml @@ -6,7 +6,7 @@ dependencies: - python - versioningit - packaging - - numpy <2.3 + - numpy - networkx - cachetools # https://github.com/openforcefield/openff-toolkit/issues/2150 @@ -23,7 +23,6 @@ dependencies: - typing_extensions - nglview # Toolkit-specific - - ambertools # https://github.com/rdkit/rdkit/issues/7221 and https://github.com/rdkit/rdkit/issues/7583 - rdkit =2024 # Test-only/optional/dev/typing/examples diff --git a/devtools/conda-envs/rdkit.yaml b/devtools/conda-envs/rdkit.yaml index 6f1d980ce..d7270ce5d 100644 --- a/devtools/conda-envs/rdkit.yaml +++ b/devtools/conda-envs/rdkit.yaml @@ -6,7 +6,7 @@ dependencies: - python - versioningit - packaging - - numpy <2.3 + - numpy - networkx - cachetools # https://github.com/openforcefield/openff-toolkit/issues/2150 @@ -22,7 +22,6 @@ dependencies: - openff-nagl-models >=0.3.0 - typing_extensions # Toolkit-specific - - ambertools >=22 # https://github.com/rdkit/rdkit/issues/7221 and https://github.com/rdkit/rdkit/issues/7583 - rdkit !=2024.03.6,!=2024.03.5 # Test-only/optional/dev/typing diff --git a/devtools/conda-envs/test_env.yaml b/devtools/conda-envs/test_env.yaml index 29c16d47b..5004795ec 100644 --- a/devtools/conda-envs/test_env.yaml +++ b/devtools/conda-envs/test_env.yaml @@ -7,7 +7,7 @@ dependencies: - python - versioningit - packaging - - numpy <2.3 + - numpy - networkx - cachetools # https://github.com/openforcefield/openff-toolkit/issues/2150 @@ -23,7 +23,6 @@ dependencies: - openff-nagl-models >=0.3.0 - typing_extensions # Toolkit-specific - - ambertools >=22 # rdkit 2024.03.6 and 2024.09.1 packages fail when run natively on osx-arm64 macs # https://github.com/rdkit/rdkit/issues/7583 - rdkit !=2024.03.6,!=2024.09.1 diff --git a/devtools/scripts/build_cookiecutter_json.py b/devtools/scripts/build_cookiecutter_json.py index 85bb7f62c..b142959c8 100644 --- a/devtools/scripts/build_cookiecutter_json.py +++ b/devtools/scripts/build_cookiecutter_json.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import json import sys diff --git a/docs/conf.py b/docs/conf.py index ce43d924b..19755a8a6 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -16,6 +16,8 @@ # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. # +from __future__ import annotations + import os import sys from importlib.util import find_spec as find_import_spec diff --git a/docs/conftest.py b/docs/conftest.py index 764e854c8..92c9e0949 100644 --- a/docs/conftest.py +++ b/docs/conftest.py @@ -6,6 +6,8 @@ The nbval-sanitize.cfg file is also for use with nbval. """ +from __future__ import annotations + def pytest_collectstart(collector): """ diff --git a/docs/users/molecule_cookbook.ipynb b/docs/users/molecule_cookbook.ipynb index 2aa9d794b..7355cb076 100644 --- a/docs/users/molecule_cookbook.ipynb +++ b/docs/users/molecule_cookbook.ipynb @@ -56,6 +56,8 @@ ], "source": [ "# Workaround for https://github.com/conda-forge/qcfractal-feedstock/issues/43\n", + "from __future__ import annotations\n", + "\n", "try:\n", " import qcportal # noqa: RUF100\n", "except ImportError:\n", diff --git a/docs/users/pdb_cookbook/index.ipynb b/docs/users/pdb_cookbook/index.ipynb index 73d5531ef..fa6773d39 100644 --- a/docs/users/pdb_cookbook/index.ipynb +++ b/docs/users/pdb_cookbook/index.ipynb @@ -66,6 +66,8 @@ }, "outputs": [], "source": [ + "from __future__ import annotations\n", + "\n", "import sys\n", "import warnings\n", "\n", diff --git a/examples/QCArchive_interface/QCarchive_interface.ipynb b/examples/QCArchive_interface/QCarchive_interface.ipynb index 28b61dee1..2558c7e17 100644 --- a/examples/QCArchive_interface/QCarchive_interface.ipynb +++ b/examples/QCArchive_interface/QCarchive_interface.ipynb @@ -256,6 +256,8 @@ } ], "source": [ + "from __future__ import annotations\n", + "\n", "import qcportal\n", "\n", "from openff.toolkit import Molecule\n", diff --git a/examples/SMIRNOFF_simulation/run_simulation.ipynb b/examples/SMIRNOFF_simulation/run_simulation.ipynb index 020688f3d..0b07a7a5a 100644 --- a/examples/SMIRNOFF_simulation/run_simulation.ipynb +++ b/examples/SMIRNOFF_simulation/run_simulation.ipynb @@ -28,6 +28,8 @@ "metadata": {}, "outputs": [], "source": [ + "from __future__ import annotations\n", + "\n", "from openff.toolkit.utils import get_data_file_path" ] }, diff --git a/examples/conformer_energies/conformer_energies.ipynb b/examples/conformer_energies/conformer_energies.ipynb index 352ad7528..069aad8ad 100644 --- a/examples/conformer_energies/conformer_energies.ipynb +++ b/examples/conformer_energies/conformer_energies.ipynb @@ -23,6 +23,8 @@ }, "outputs": [], "source": [ + "from __future__ import annotations\n", + "\n", "from openff.interchange.drivers.openmm import get_openmm_energies\n", "from rdkit.Chem import rdMolAlign\n", "\n", diff --git a/examples/conformer_energies/conformer_energies.py b/examples/conformer_energies/conformer_energies.py index f1ce7c8ee..ff51f3549 100644 --- a/examples/conformer_energies/conformer_energies.py +++ b/examples/conformer_energies/conformer_energies.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import argparse from openff.interchange.drivers.openmm import get_openmm_energies diff --git a/examples/examples_helper.py b/examples/examples_helper.py index 99bc28687..bc2f63b59 100755 --- a/examples/examples_helper.py +++ b/examples/examples_helper.py @@ -1,6 +1,8 @@ #!/usr/bin/env python3 """Copy the openff-toolkit examples suite to a local directory""" +from __future__ import annotations + import argparse from os import environ from pathlib import Path diff --git a/examples/forcefield_modification/forcefield_modification.ipynb b/examples/forcefield_modification/forcefield_modification.ipynb index 80b65b830..806e20f77 100644 --- a/examples/forcefield_modification/forcefield_modification.ipynb +++ b/examples/forcefield_modification/forcefield_modification.ipynb @@ -15,6 +15,8 @@ "metadata": {}, "outputs": [], "source": [ + "from __future__ import annotations\n", + "\n", "from copy import deepcopy\n", "\n", "from openff.units import unit\n", diff --git a/examples/inspect_assigned_parameters/inspect_assigned_parameters.ipynb b/examples/inspect_assigned_parameters/inspect_assigned_parameters.ipynb index b947e0ea8..4c039b80f 100644 --- a/examples/inspect_assigned_parameters/inspect_assigned_parameters.ipynb +++ b/examples/inspect_assigned_parameters/inspect_assigned_parameters.ipynb @@ -118,6 +118,8 @@ } ], "source": [ + "from __future__ import annotations\n", + "\n", "from openff.toolkit import ForceField, Molecule, Topology\n", "\n", "# Create a simple molecule from SMILES and turn it into a topology.\n", diff --git a/examples/toolkit_showcase/toolkit_showcase.ipynb b/examples/toolkit_showcase/toolkit_showcase.ipynb index 7eef9b1a8..663f2e4af 100644 --- a/examples/toolkit_showcase/toolkit_showcase.ipynb +++ b/examples/toolkit_showcase/toolkit_showcase.ipynb @@ -43,6 +43,8 @@ ], "source": [ "# Imports from the comp chem ecosystem\n", + "from __future__ import annotations\n", + "\n", "import mdtraj\n", "import nglview\n", "import numpy as np\n", diff --git a/examples/using_smirnoff_in_amber_or_gromacs/export_with_interchange.ipynb b/examples/using_smirnoff_in_amber_or_gromacs/export_with_interchange.ipynb index ae5ca5995..269d921a3 100644 --- a/examples/using_smirnoff_in_amber_or_gromacs/export_with_interchange.ipynb +++ b/examples/using_smirnoff_in_amber_or_gromacs/export_with_interchange.ipynb @@ -28,6 +28,8 @@ "metadata": {}, "outputs": [], "source": [ + "from __future__ import annotations\n", + "\n", "from pprint import pprint\n", "from shutil import which\n", "\n", diff --git a/examples/using_smirnoff_with_amber_protein_forcefield/BRD4_inhibitor_benchmark.ipynb b/examples/using_smirnoff_with_amber_protein_forcefield/BRD4_inhibitor_benchmark.ipynb index 4b7df39c6..b077a999b 100644 --- a/examples/using_smirnoff_with_amber_protein_forcefield/BRD4_inhibitor_benchmark.ipynb +++ b/examples/using_smirnoff_with_amber_protein_forcefield/BRD4_inhibitor_benchmark.ipynb @@ -19,6 +19,8 @@ "source": [ "# Retrieve protein and ligand files for BRD4 and a docked inhibitor from the benchmark systems GitHub repository\n", "# https://github.com/MobleyLab/benchmarksets\n", + "from __future__ import annotations\n", + "\n", "import requests\n", "\n", "repo_url = \"https://raw.githubusercontent.com/MobleyLab/benchmarksets/master/input_files/\"\n", diff --git a/examples/virtual_sites/vsite_showcase.ipynb b/examples/virtual_sites/vsite_showcase.ipynb index bb7b63cea..7729d6d39 100644 --- a/examples/virtual_sites/vsite_showcase.ipynb +++ b/examples/virtual_sites/vsite_showcase.ipynb @@ -44,6 +44,8 @@ } ], "source": [ + "from __future__ import annotations\n", + "\n", "import time\n", "\n", "import numpy\n", diff --git a/examples/visualization/visualization.ipynb b/examples/visualization/visualization.ipynb index 660560eb0..8b154e963 100644 --- a/examples/visualization/visualization.ipynb +++ b/examples/visualization/visualization.ipynb @@ -66,6 +66,8 @@ }, "outputs": [], "source": [ + "from __future__ import annotations\n", + "\n", "from openff.toolkit import Molecule, Topology\n", "from openff.toolkit.utils import get_data_file_path" ] diff --git a/openff/toolkit/__init__.py b/openff/toolkit/__init__.py index cf62c730a..830405752 100644 --- a/openff/toolkit/__init__.py +++ b/openff/toolkit/__init__.py @@ -3,6 +3,8 @@ A modern, extensible library for molecular mechanics force field science from the Open Force Field Consortium. """ +from __future__ import annotations + import importlib from importlib.metadata import version from typing import TYPE_CHECKING diff --git a/openff/toolkit/_tests/_stale_tests.py b/openff/toolkit/_tests/_stale_tests.py index 221418430..4ac808d5f 100644 --- a/openff/toolkit/_tests/_stale_tests.py +++ b/openff/toolkit/_tests/_stale_tests.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import pytest from openff.toolkit import ForceField diff --git a/openff/toolkit/_tests/conftest.py b/openff/toolkit/_tests/conftest.py index fe9f735f8..d804f040b 100644 --- a/openff/toolkit/_tests/conftest.py +++ b/openff/toolkit/_tests/conftest.py @@ -2,6 +2,8 @@ Configuration file for pytest. """ +from __future__ import annotations + import logging import pytest diff --git a/openff/toolkit/_tests/create_molecules.py b/openff/toolkit/_tests/create_molecules.py index b9cfafd59..06ec9a8bd 100644 --- a/openff/toolkit/_tests/create_molecules.py +++ b/openff/toolkit/_tests/create_molecules.py @@ -5,6 +5,8 @@ """ +from __future__ import annotations + import numpy as np from openff.toolkit import unit diff --git a/openff/toolkit/_tests/mocking.py b/openff/toolkit/_tests/mocking.py index 9672dc805..cd8e188f6 100644 --- a/openff/toolkit/_tests/mocking.py +++ b/openff/toolkit/_tests/mocking.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import numpy from openff.toolkit import Quantity, unit diff --git a/openff/toolkit/_tests/molecule/test_state_enumeration.py b/openff/toolkit/_tests/molecule/test_state_enumeration.py index 3ba3e6524..62d4feaf7 100644 --- a/openff/toolkit/_tests/molecule/test_state_enumeration.py +++ b/openff/toolkit/_tests/molecule/test_state_enumeration.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import pytest from openff.toolkit import Molecule diff --git a/openff/toolkit/_tests/test_energies.py b/openff/toolkit/_tests/test_energies.py index 849cb79d6..d83d9dabd 100644 --- a/openff/toolkit/_tests/test_energies.py +++ b/openff/toolkit/_tests/test_energies.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import json import numpy as np diff --git a/openff/toolkit/_tests/test_examples.py b/openff/toolkit/_tests/test_examples.py index 71a9124d0..d6919ea8f 100644 --- a/openff/toolkit/_tests/test_examples.py +++ b/openff/toolkit/_tests/test_examples.py @@ -2,6 +2,8 @@ Test that the examples in the repo run without errors. """ +from __future__ import annotations + import pathlib import re import subprocess diff --git a/openff/toolkit/_tests/test_forcefield.py b/openff/toolkit/_tests/test_forcefield.py index d5fed21fb..28f9a764a 100644 --- a/openff/toolkit/_tests/test_forcefield.py +++ b/openff/toolkit/_tests/test_forcefield.py @@ -3,6 +3,8 @@ """ +from __future__ import annotations + import copy import itertools import os diff --git a/openff/toolkit/_tests/test_interchange.py b/openff/toolkit/_tests/test_interchange.py index 318608b23..8c9396ee0 100644 --- a/openff/toolkit/_tests/test_interchange.py +++ b/openff/toolkit/_tests/test_interchange.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import pytest from openff.utilities import requires_package as requires_pkg diff --git a/openff/toolkit/_tests/test_io.py b/openff/toolkit/_tests/test_io.py index e441f78ce..694951729 100644 --- a/openff/toolkit/_tests/test_io.py +++ b/openff/toolkit/_tests/test_io.py @@ -3,6 +3,8 @@ """ +from __future__ import annotations + import pytest from openff.toolkit.typing.engines.smirnoff.io import XMLParameterIOHandler diff --git a/openff/toolkit/_tests/test_links.py b/openff/toolkit/_tests/test_links.py index b3d29e49e..d6a115f72 100644 --- a/openff/toolkit/_tests/test_links.py +++ b/openff/toolkit/_tests/test_links.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import pathlib import re from urllib.request import Request, urlopen diff --git a/openff/toolkit/_tests/test_mm_molecule.py b/openff/toolkit/_tests/test_mm_molecule.py index 179763d4b..113f4b3da 100644 --- a/openff/toolkit/_tests/test_mm_molecule.py +++ b/openff/toolkit/_tests/test_mm_molecule.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import copy import numpy as np diff --git a/openff/toolkit/_tests/test_molecule.py b/openff/toolkit/_tests/test_molecule.py index f4950b754..7a41cfc4a 100644 --- a/openff/toolkit/_tests/test_molecule.py +++ b/openff/toolkit/_tests/test_molecule.py @@ -13,6 +13,8 @@ """ +from __future__ import annotations + import copy import os import pathlib diff --git a/openff/toolkit/_tests/test_nagl.py b/openff/toolkit/_tests/test_nagl.py index 16e32be87..9839eb698 100644 --- a/openff/toolkit/_tests/test_nagl.py +++ b/openff/toolkit/_tests/test_nagl.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import pathlib import re diff --git a/openff/toolkit/_tests/test_parameter_plugins.py b/openff/toolkit/_tests/test_parameter_plugins.py index 58d9929d1..797922419 100644 --- a/openff/toolkit/_tests/test_parameter_plugins.py +++ b/openff/toolkit/_tests/test_parameter_plugins.py @@ -2,6 +2,8 @@ Test classes and function in module openff.toolkit.typing.engines.smirnoff.plugins """ +from __future__ import annotations + import pytest from openff.toolkit import ForceField, Quantity diff --git a/openff/toolkit/_tests/test_parameters.py b/openff/toolkit/_tests/test_parameters.py index 8bb0b196b..1f62befdf 100644 --- a/openff/toolkit/_tests/test_parameters.py +++ b/openff/toolkit/_tests/test_parameters.py @@ -3,6 +3,8 @@ """ +from __future__ import annotations + from collections import defaultdict from inspect import isabstract, isclass diff --git a/openff/toolkit/_tests/test_toolkit_io.py b/openff/toolkit/_tests/test_toolkit_io.py index 9d911d094..b86d6331f 100644 --- a/openff/toolkit/_tests/test_toolkit_io.py +++ b/openff/toolkit/_tests/test_toolkit_io.py @@ -3,6 +3,8 @@ """ +from __future__ import annotations + import pathlib import sys import tempfile diff --git a/openff/toolkit/_tests/test_toolkits.py b/openff/toolkit/_tests/test_toolkits.py index f48f4c68f..1c8f8f12d 100644 --- a/openff/toolkit/_tests/test_toolkits.py +++ b/openff/toolkit/_tests/test_toolkits.py @@ -3,6 +3,8 @@ """ +from __future__ import annotations + import logging import os import pathlib diff --git a/openff/toolkit/_tests/test_topology.py b/openff/toolkit/_tests/test_topology.py index 6b6a17d36..f8d8853bd 100644 --- a/openff/toolkit/_tests/test_topology.py +++ b/openff/toolkit/_tests/test_topology.py @@ -3,6 +3,8 @@ """ +from __future__ import annotations + import itertools import re from copy import deepcopy diff --git a/openff/toolkit/_tests/test_utils.py b/openff/toolkit/_tests/test_utils.py index 7733b7505..04d40ac00 100644 --- a/openff/toolkit/_tests/test_utils.py +++ b/openff/toolkit/_tests/test_utils.py @@ -3,6 +3,8 @@ """ +from __future__ import annotations + import os import pytest diff --git a/openff/toolkit/_tests/test_utils_callback.py b/openff/toolkit/_tests/test_utils_callback.py index 79248d727..b3ecb045f 100644 --- a/openff/toolkit/_tests/test_utils_callback.py +++ b/openff/toolkit/_tests/test_utils_callback.py @@ -3,6 +3,8 @@ """ +from __future__ import annotations + import pytest from openff.toolkit.utils.callback import Callbackable, callback_method diff --git a/openff/toolkit/_tests/test_utils_collections.py b/openff/toolkit/_tests/test_utils_collections.py index c33bfd5ac..c5696be15 100644 --- a/openff/toolkit/_tests/test_utils_collections.py +++ b/openff/toolkit/_tests/test_utils_collections.py @@ -3,6 +3,8 @@ """ +from __future__ import annotations + import copy import pytest diff --git a/openff/toolkit/_tests/test_utils_serialization.py b/openff/toolkit/_tests/test_utils_serialization.py index 71c1d7dd4..cac0bd229 100644 --- a/openff/toolkit/_tests/test_utils_serialization.py +++ b/openff/toolkit/_tests/test_utils_serialization.py @@ -3,6 +3,8 @@ """ +from __future__ import annotations + import numpy as np import pytest from openff.utilities import requires_package as requires_pkg diff --git a/openff/toolkit/_tests/utils.py b/openff/toolkit/_tests/utils.py index a0f2bcc87..61b4ad0d9 100644 --- a/openff/toolkit/_tests/utils.py +++ b/openff/toolkit/_tests/utils.py @@ -3,6 +3,8 @@ """ +from __future__ import annotations + import collections import copy import functools diff --git a/openff/toolkit/topology/__init__.py b/openff/toolkit/topology/__init__.py index 67c96c6c3..b58e2a1cd 100644 --- a/openff/toolkit/topology/__init__.py +++ b/openff/toolkit/topology/__init__.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from openff.toolkit.topology.molecule import ( Atom, Bond, diff --git a/openff/toolkit/topology/_mm_molecule.py b/openff/toolkit/topology/_mm_molecule.py index 114e94ce8..2161f6fb9 100644 --- a/openff/toolkit/topology/_mm_molecule.py +++ b/openff/toolkit/topology/_mm_molecule.py @@ -10,9 +10,11 @@ """ +from __future__ import annotations + import functools from collections.abc import Generator, Iterable -from typing import TYPE_CHECKING, NoReturn, Union +from typing import TYPE_CHECKING, NoReturn from openff.units.elements import MASSES, SYMBOLS @@ -62,7 +64,7 @@ def add_bond(self, atom1, atom2, **kwargs): self.bonds.append(bond) @property - def conformers(self) -> list["Quantity"] | None: + def conformers(self) -> list[Quantity] | None: return self._conformers def add_conformer(self, conformer): @@ -82,13 +84,13 @@ def n_bonds(self) -> int: def n_conformers(self) -> int: return 0 if self._conformers is None else len(self._conformers) - def atom(self, index: int) -> "_SimpleAtom": + def atom(self, index: int) -> _SimpleAtom: return self.atoms[index] def atom_index(self, atom) -> int: return self.atoms.index(atom) - def bond(self, index: int) -> "_SimpleBond": + def bond(self, index: int) -> _SimpleBond: return self.bonds[index] def get_bond_between(self, atom1_index, atom2_index): @@ -104,9 +106,9 @@ def angles( self, ) -> Generator[ tuple[ - "_SimpleAtom", - "_SimpleAtom", - "_SimpleAtom", + _SimpleAtom, + _SimpleAtom, + _SimpleAtom, ], None, None, @@ -127,10 +129,10 @@ def propers( self, ) -> Generator[ tuple[ - "_SimpleAtom", - "_SimpleAtom", - "_SimpleAtom", - "_SimpleAtom", + _SimpleAtom, + _SimpleAtom, + _SimpleAtom, + _SimpleAtom, ], None, None, @@ -155,10 +157,10 @@ def impropers( self, ) -> Generator[ tuple[ - "_SimpleAtom", - "_SimpleAtom", - "_SimpleAtom", - "_SimpleAtom", + _SimpleAtom, + _SimpleAtom, + _SimpleAtom, + _SimpleAtom, ], None, None, @@ -181,10 +183,10 @@ def smirnoff_impropers( self, ) -> Generator[ tuple[ - "_SimpleAtom", - "_SimpleAtom", - "_SimpleAtom", - "_SimpleAtom", + _SimpleAtom, + _SimpleAtom, + _SimpleAtom, + _SimpleAtom, ], None, None, @@ -198,10 +200,10 @@ def amber_impropers( self, ) -> Generator[ tuple[ - "_SimpleAtom", - "_SimpleAtom", - "_SimpleAtom", - "_SimpleAtom", + _SimpleAtom, + _SimpleAtom, + _SimpleAtom, + _SimpleAtom, ], None, None, @@ -232,7 +234,7 @@ def hill_formula(self) -> str: return self.to_hill_formula() @property - def hierarchy_schemes(self) -> dict[str, "HierarchyScheme"]: + def hierarchy_schemes(self) -> dict[str, HierarchyScheme]: return self._hierarchy_schemes def to_hill_formula(self) -> str: @@ -243,7 +245,7 @@ def to_hill_formula(self) -> str: return _atom_nums_to_hill_formula(atom_nums) - def to_networkx(self) -> "nx.Graph": + def to_networkx(self) -> nx.Graph: # TODO: Custom attribtues should probably be attached to the nodes (and possibly also # the edges?). See for more: # https://github.com/openforcefield/openff-toolkit/pull/1179#discussion_r808549385 @@ -264,7 +266,7 @@ def to_networkx(self) -> "nx.Graph": return graph - def to_topology(self) -> "Topology": + def to_topology(self) -> Topology: from openff.toolkit.topology import Topology return Topology.from_molecules([self]) @@ -277,7 +279,7 @@ def nth_degree_neighbors(self, n_degrees): return _nth_degree_neighbors_from_graphlike(graphlike=self, n_degrees=n_degrees) @classmethod - def _from_subgraph(cls, subgraph: "nx.Graph"): + def _from_subgraph(cls, subgraph: nx.Graph): molecule = cls() # The subgraph stores indices that might not start at zero (i.e. topology indices) @@ -434,7 +436,7 @@ def to_molecule(self) -> NoReturn: "an OpenFF Molecule with sufficiently specified chemistry." ) - def is_isomorphic_with(self, other: Union["FrozenMolecule", "_SimpleMolecule", "nx.Graph"], **kwargs) -> bool: + def is_isomorphic_with(self, other: FrozenMolecule | _SimpleMolecule | nx.Graph, **kwargs) -> bool: """ Check for pseudo-isomorphism. @@ -454,8 +456,8 @@ def is_isomorphic_with(self, other: Union["FrozenMolecule", "_SimpleMolecule", " @staticmethod def are_isomorphic( - mol1: Union["FrozenMolecule", "_SimpleMolecule", "nx.Graph"], - mol2: Union["FrozenMolecule", "_SimpleMolecule", "nx.Graph"], + mol1: FrozenMolecule | _SimpleMolecule | nx.Graph, + mol2: FrozenMolecule | _SimpleMolecule | nx.Graph, return_atom_map: bool = False, ) -> tuple[bool, dict[int, int] | None]: import networkx @@ -521,7 +523,7 @@ def has_unique_atom_names(self) -> bool: """``True`` if the molecule has unique atom names, ``False`` otherwise.""" return _has_unique_atom_names(self) - def __getattr__(self, name: str) -> list["HierarchyElement"]: + def __getattr__(self, name: str) -> list[HierarchyElement]: """If a requested attribute is not found, check the hierarchy schemes""" try: return self.__dict__["_hierarchy_schemes"][name].hierarchy_elements @@ -583,7 +585,7 @@ def symbol(self) -> str: return SYMBOLS[self.atomic_number] @property - def mass(self) -> "Quantity": + def mass(self) -> Quantity: return MASSES[self.atomic_number] @property diff --git a/openff/toolkit/topology/molecule.py b/openff/toolkit/topology/molecule.py index fee8216df..401d2a091 100644 --- a/openff/toolkit/topology/molecule.py +++ b/openff/toolkit/topology/molecule.py @@ -25,6 +25,8 @@ """ +from __future__ import annotations + import hashlib import json import operator @@ -41,7 +43,6 @@ Literal, TextIO, TypeVar, - Union, overload, ) @@ -127,10 +128,10 @@ class Particle(Serializable): """ - _molecule: "FrozenMolecule" + _molecule: FrozenMolecule @property - def molecule(self) -> "FrozenMolecule": + def molecule(self) -> FrozenMolecule: r""" The ``Molecule`` this particle is part of. @@ -144,7 +145,7 @@ def molecule(self) -> "FrozenMolecule": return self._molecule @molecule.setter - def molecule(self, molecule: "FrozenMolecule"): + def molecule(self, molecule: FrozenMolecule): """ Set the particle's molecule pointer. Note that this will only work if the particle currently doesn't have a molecule @@ -285,7 +286,7 @@ def __init__( # TODO: We can probably avoid an explicit call and determine this dynamically # from self._molecule (maybe caching the result) to get rid of some bookkeeping. # TODO: Should stereochemistry be reset/cleared/recomputed upon addition of a bond? - def add_bond(self, bond: "Bond"): + def add_bond(self, bond: Bond): """Adds a bond that this atom is involved in .. todo :: Is this how we want to keep records? @@ -343,7 +344,7 @@ def formal_charge(self) -> Quantity: return self._formal_charge @formal_charge.setter - def formal_charge(self, other: "int | Quantity | OMMQuantity"): + def formal_charge(self, other: int | Quantity | OMMQuantity): """ Set the atom's formal charge. Accepts either ints or unit-wrapped ints with units of charge. """ @@ -503,7 +504,7 @@ def bonds(self): return self._bonds @property - def bonded_atoms(self) -> Generator["Atom", None, None]: + def bonded_atoms(self) -> Generator[Atom, None, None]: """ The list of ``Atom`` objects this atom is involved in bonds with @@ -780,7 +781,7 @@ def is_aromatic(self) -> bool: return self._is_aromatic @property - def molecule(self) -> "FrozenMolecule": + def molecule(self) -> FrozenMolecule: return self._molecule @molecule.setter @@ -1451,7 +1452,7 @@ def add_hierarchy_scheme( self, uniqueness_criteria: Iterable[str], iterator_name: str, - ) -> "HierarchyScheme": + ) -> HierarchyScheme: """ Use the molecule's metadata to facilitate iteration over its atoms. @@ -1516,7 +1517,7 @@ def add_hierarchy_scheme( return new_hier_scheme @property - def hierarchy_schemes(self) -> dict[str, "HierarchyScheme"]: + def hierarchy_schemes(self) -> dict[str, HierarchyScheme]: """ The hierarchy schemes available on the molecule. @@ -1589,7 +1590,7 @@ def update_hierarchy_schemes(self, iter_names: list[str] | None = None): hierarchy_scheme = self._hierarchy_schemes[iter_name] hierarchy_scheme.perceive_hierarchy() - def __getattr__(self, name: str) -> list["HierarchyElement"]: + def __getattr__(self, name: str) -> list[HierarchyElement]: """If a requested attribute is not found, check the hierarchy schemes""" try: return self.__dict__["_hierarchy_schemes"][name].hierarchy_elements @@ -1950,8 +1951,8 @@ def _is_exactly_the_same_as(self, other): @staticmethod def are_isomorphic( - mol1: "FrozenMolecule | _SimpleMolecule | nx.Graph[int]", - mol2: "FrozenMolecule | _SimpleMolecule | nx.Graph[int]", + mol1: FrozenMolecule | _SimpleMolecule | nx.Graph[int], + mol2: FrozenMolecule | _SimpleMolecule | nx.Graph[int], return_atom_map: bool = False, aromatic_matching: bool = True, formal_charge_matching: bool = True, @@ -2191,7 +2192,7 @@ def _to_networkx(data: FrozenMolecule | nx.Graph) -> nx.Graph: def is_isomorphic_with( self, - other: "FrozenMolecule | _SimpleMolecule | nx.Graph[int]", + other: FrozenMolecule | _SimpleMolecule | nx.Graph[int], aromatic_matching: bool = True, formal_charge_matching: bool = True, bond_order_matching: bool = True, @@ -2803,7 +2804,7 @@ def _invalidate_cached_properties(self): if "_molecule_atom_index" in atom.__dict__: del atom.__dict__["_molecule_atom_index"] - def to_networkx(self) -> "nx.Graph": + def to_networkx(self) -> nx.Graph: """Generate a NetworkX undirected graph from the molecule. Nodes are Atoms labeled with atom indices and atomic elements (via the ``element`` node atrribute). @@ -3541,7 +3542,7 @@ def to_hill_formula(self) -> str: return self._hill_formula @staticmethod - def _object_to_hill_formula(obj: Union["FrozenMolecule", "nx.Graph[int]"]) -> str: + def _object_to_hill_formula(obj: FrozenMolecule | nx.Graph[int]) -> str: """Take a Molecule or NetworkX graph and generate its Hill formula. This provides a backdoor to the old functionality of Molecule.to_hill_formula, which was a static method that duck-typed inputs of Molecule or graph objects.""" @@ -4337,7 +4338,7 @@ def to_rdkit( self, aromaticity_model=DEFAULT_AROMATICITY_MODEL, toolkit_registry=GLOBAL_TOOLKIT_REGISTRY, - ) -> "RDMol": + ) -> RDMol: """ Create an RDKit molecule @@ -4376,7 +4377,7 @@ def from_openeye( cls: type[FM], oemol, allow_undefined_stereo: bool = False, - ) -> "FrozenMolecule": + ) -> FrozenMolecule: """ Create a ``Molecule`` from an OpenEye molecule. @@ -5286,8 +5287,8 @@ def add_atom( def add_bond( self, - atom1: Union[int, "Atom"], - atom2: Union[int, "Atom"], + atom1: int | Atom, + atom2: int | Atom, bond_order: int, is_aromatic: bool, stereochemistry: Literal["E", "Z", None] = None, @@ -5364,19 +5365,19 @@ def clear_conformers(self): def visualize( self, backend: Literal["rdkit"], - ) -> "IPython.display.SVG": ... + ) -> IPython.display.SVG: ... @overload def visualize( self, backend: Literal["openeye"], - ) -> "IPython.display.Image": ... + ) -> IPython.display.Image: ... @overload def visualize( self, backend: Literal["nglview"], - ) -> "nglview.NGLWidget": ... + ) -> nglview.NGLWidget: ... def visualize( self, @@ -5384,7 +5385,7 @@ def visualize( width: int = 500, height: int = 300, show_all_hydrogens: bool = True, - ) -> Union["IPython.display.SVG", "IPython.display.Image", "nglview.NGLWidget"]: + ) -> IPython.display.SVG | IPython.display.Image | nglview.NGLWidget: """ Render a visualization of the molecule in Jupyter @@ -5634,7 +5635,7 @@ def _ipython_display_(self): # pragma: no cover pass -def _networkx_graph_to_hill_formula(graph: "nx.Graph[int]") -> str: +def _networkx_graph_to_hill_formula(graph: nx.Graph[int]) -> str: """ Convert a NetworkX graph to a Hill formula. @@ -5697,7 +5698,7 @@ def _atom_nums_to_hill_formula(atom_nums: list[int]) -> str: def _nth_degree_neighbors_from_graphlike( graphlike: MoleculeLike, n_degrees: int, -) -> Iterator[tuple[Atom, Atom] | tuple["_SimpleAtom", "_SimpleAtom"]]: +) -> Iterator[tuple[Atom, Atom] | tuple[_SimpleAtom, _SimpleAtom]]: """ Given a graph-like object, return a tuple of the nth degree neighbors of each atom. @@ -5864,7 +5865,7 @@ def add_hierarchy_element( self, identifier: tuple[str | int, ...], atom_indices: Sequence[int], - ) -> "HierarchyElement": + ) -> HierarchyElement: """ Instantiate a new HierarchyElement belonging to this HierarchyScheme. @@ -5990,7 +5991,7 @@ def n_atoms(self) -> int: return len(self.atom_indices) @property - def atoms(self) -> Iterator["Atom"]: + def atoms(self) -> Iterator[Atom]: """ Iterator over the atoms in this hierarchy element. """ @@ -6044,7 +6045,7 @@ def generate_unique_atom_names(self, suffix: str = "x"): def _has_unique_atom_names( - obj: "FrozenMolecule | _SimpleMolecule | HierarchyElement", + obj: FrozenMolecule | _SimpleMolecule | HierarchyElement, ) -> bool: """``True`` if the object has unique atom names, ``False`` otherwise.""" unique_atom_names = set([atom.name for atom in obj.atoms]) diff --git a/openff/toolkit/topology/topology.py b/openff/toolkit/topology/topology.py index 9467d350e..4613f2acb 100644 --- a/openff/toolkit/topology/topology.py +++ b/openff/toolkit/topology/topology.py @@ -12,6 +12,8 @@ """ +from __future__ import annotations + import re from collections import defaultdict from collections.abc import Generator, Iterable, Iterator, MutableMapping @@ -22,7 +24,6 @@ TYPE_CHECKING, Literal, TextIO, - Union, ) import numpy as np @@ -520,7 +521,7 @@ def n_unique_molecules(self) -> int: def from_molecules( cls, molecules: MoleculeLike | Iterable[MoleculeLike], - ) -> "Topology": + ) -> Topology: """ Create a new Topology object containing one copy of each of the specified molecule(s). @@ -546,7 +547,7 @@ def from_molecules( return topology - def assert_bonded(self, atom1: Union[int, "Atom"], atom2: Union[int, "Atom"]): + def assert_bonded(self, atom1: int | Atom, atom2: int | Atom): """ Raise an exception if the specified atoms are not bonded in the topology. @@ -724,7 +725,7 @@ def n_atoms(self) -> int: return n_atoms @property - def atoms(self) -> Generator["Atom", None, None]: + def atoms(self) -> Generator[Atom, None, None]: """Returns an iterator over the atoms in this Topology. These will be in ascending order of topology index. Returns @@ -734,7 +735,7 @@ def atoms(self) -> Generator["Atom", None, None]: for molecule in self._molecules: yield from molecule.atoms - def atom_index(self, atom: "Atom") -> int: + def atom_index(self, atom: Atom) -> int: """ Returns the index of a given atom in this topology @@ -861,7 +862,7 @@ def impropers(self) -> Generator[tuple[AtomLike, AtomLike, AtomLike, AtomLike], @property def smirnoff_impropers( self, - ) -> Generator[tuple[Union["Atom", _SimpleAtom], ...], None, None]: + ) -> Generator[tuple[Atom | _SimpleAtom, ...], None, None]: """ Iterate over improper torsions in the molecule, but only those with trivalent centers, reporting the central atom second in each improper. @@ -901,7 +902,7 @@ def smirnoff_impropers( @property def amber_impropers( self, - ) -> Generator[tuple[Union["Atom", _SimpleAtom], ...], None, None]: + ) -> Generator[tuple[Atom | _SimpleAtom, ...], None, None]: """ Iterate over improper torsions in the molecule, but only those with trivalent centers, reporting the central atom first in each improper. @@ -1327,10 +1328,10 @@ def _openmm_topology_to_networkx(openmm_topology): @requires_package("openmm") def from_openmm( cls, - openmm_topology: "openmm.app.Topology", + openmm_topology: openmm.app.Topology, unique_molecules: Iterable[FrozenMolecule] | None = None, - positions: Union[None, Quantity, "OMMQuantity"] = None, - ) -> "Topology": + positions: None | Quantity | OMMQuantity = None, + ) -> Topology: """ Construct an OpenFF Topology object from an OpenMM Topology object. @@ -1771,7 +1772,7 @@ def from_pdb( def to_openmm( self, ensure_unique_atom_names: str | bool = "residues", - ) -> "openmm.app.Topology": + ) -> openmm.app.Topology: """ Create an OpenMM Topology object. @@ -1935,7 +1936,7 @@ def to_openmm( def to_file( self, file: Path | str | TextIO, - positions: Union["OMMQuantity", Quantity, NDArray] | None = None, + positions: OMMQuantity | Quantity | NDArray | None = None, file_format: Literal["PDB"] = "PDB", keep_ids: bool = False, ensure_unique_atom_names: str | bool = "residues", @@ -2122,9 +2123,9 @@ def set_positions(self, array: Quantity) -> None: @requires_package("mdtraj") def from_mdtraj( cls, - mdtraj_topology: "mdtraj.Topology", + mdtraj_topology: mdtraj.Topology, unique_molecules: Iterable[MoleculeLike] | None = None, - positions: Union[None, "OMMQuantity", Quantity] = None, + positions: None | OMMQuantity | Quantity = None, ): """ Construct an OpenFF ``Topology`` from an MDTraj ``Topology`` @@ -2192,7 +2193,7 @@ def _to_mdtraj(self): return md.Topology.from_openmm(self.to_openmm()) - def get_bond_between(self, i: Union[int, "Atom"], j: Union[int, "Atom"]) -> "Bond": + def get_bond_between(self, i: int | Atom, j: int | Atom) -> Bond: """Returns the bond between two atoms Parameters @@ -2228,7 +2229,7 @@ def get_bond_between(self, i: Union[int, "Atom"], j: Union[int, "Atom"]) -> "Bon raise NotBondedError(f"No bond between atom {i} and {j}") - def is_bonded(self, i: Union[int, "Atom"], j: Union[int, "Atom"]) -> bool: + def is_bonded(self, i: int | Atom, j: int | Atom) -> bool: """Returns True if the two atoms are bonded Parameters @@ -2248,7 +2249,7 @@ def is_bonded(self, i: Union[int, "Atom"], j: Union[int, "Atom"]) -> bool: except NotBondedError: return False - def atom(self, atom_topology_index: int) -> "Atom": + def atom(self, atom_topology_index: int) -> Atom: """ Get the Atom at a given Topology atom index. @@ -2437,7 +2438,7 @@ def is_constrained(self, iatom, jatom): return False @requires_package("nglview") - def visualize(self, ensure_correct_connectivity: bool = False) -> "NGLWidget": + def visualize(self, ensure_correct_connectivity: bool = False) -> NGLWidget: """ Visualize with NGLView. @@ -2537,7 +2538,7 @@ def hierarchy_iterator( if hasattr(molecule, iter_name): yield from getattr(molecule, iter_name) - def __getattr__(self, name: str) -> list["HierarchyElement"]: + def __getattr__(self, name: str) -> list[HierarchyElement]: """If a requested attribute is not found, check the hierarchy schemes""" # Avoid attempting to process dunder methods as hierarchy scheme iterator names if name.startswith("__"): diff --git a/openff/toolkit/typing/engines/smirnoff/__init__.py b/openff/toolkit/typing/engines/smirnoff/__init__.py index d881c950d..833e75984 100644 --- a/openff/toolkit/typing/engines/smirnoff/__init__.py +++ b/openff/toolkit/typing/engines/smirnoff/__init__.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from openff.toolkit.typing.engines.smirnoff.forcefield import ( ForceField, get_available_force_fields, diff --git a/openff/toolkit/typing/engines/smirnoff/forcefield.py b/openff/toolkit/typing/engines/smirnoff/forcefield.py index 19447e32c..326cfd860 100644 --- a/openff/toolkit/typing/engines/smirnoff/forcefield.py +++ b/openff/toolkit/typing/engines/smirnoff/forcefield.py @@ -11,11 +11,13 @@ """ +from __future__ import annotations + import logging import os import pathlib from importlib.metadata import entry_points -from typing import IO, TYPE_CHECKING, Any, Union +from typing import IO, TYPE_CHECKING, Any from packaging.version import Version @@ -1104,8 +1106,8 @@ def to_file( def combine( self, - other: "ForceField", - ) -> "ForceField": + other: ForceField, + ) -> ForceField: """ Combine this `ForceField` with another `ForceField`, returning a new `ForceField`. @@ -1128,13 +1130,13 @@ def combine( @requires_package("openmm") def create_openmm_system( self, - topology: "Topology", + topology: Topology, *, - toolkit_registry: Union["ToolkitRegistry", "ToolkitWrapper"] | None = None, - charge_from_molecules: list["Molecule"] | None = None, - partial_bond_orders_from_molecules: list["Molecule"] | None = None, + toolkit_registry: ToolkitRegistry | ToolkitWrapper | None = None, + charge_from_molecules: list[Molecule] | None = None, + partial_bond_orders_from_molecules: list[Molecule] | None = None, allow_nonintegral_charges: bool = False, - ) -> "openmm.System": + ) -> openmm.System: """Create an OpenMM System from this ForceField and a Topology. Note that most force fields specify their own partial charges, and any @@ -1174,12 +1176,12 @@ def create_openmm_system( @requires_package("openff.interchange") def create_interchange( self, - topology: "Topology", - toolkit_registry: Union["ToolkitRegistry", "ToolkitWrapper"] | None = None, - charge_from_molecules: list["Molecule"] | None = None, - partial_bond_orders_from_molecules: list["Molecule"] | None = None, + topology: Topology, + toolkit_registry: ToolkitRegistry | ToolkitWrapper | None = None, + charge_from_molecules: list[Molecule] | None = None, + partial_bond_orders_from_molecules: list[Molecule] | None = None, allow_nonintegral_charges: bool = False, - ) -> "Interchange": + ) -> Interchange: """ Create an Interchange object from a ForceField, Topology, and (optionally) box vectors. @@ -1228,7 +1230,7 @@ def create_interchange( allow_nonintegral_charges=allow_nonintegral_charges, ) - def label_molecules(self, topology: "Topology") -> list[dict[str, "ValenceDict"]]: + def label_molecules(self, topology: Topology) -> list[dict[str, ValenceDict]]: """ Return labels for a list of molecules corresponding to parameters from this force field. @@ -1313,7 +1315,7 @@ def _get_parameter_handler_class(self, tagname: str) -> type[ParameterHandler]: return ph_class @requires_package("openff.interchange") - def get_partial_charges(self, molecule: "Molecule", **kwargs: Any) -> Quantity: + def get_partial_charges(self, molecule: Molecule, **kwargs: Any) -> Quantity: """Generate the partial charges for the given molecule in this force field. Parameters diff --git a/openff/toolkit/typing/engines/smirnoff/io.py b/openff/toolkit/typing/engines/smirnoff/io.py index ba36ddc1c..cd9e129ed 100644 --- a/openff/toolkit/typing/engines/smirnoff/io.py +++ b/openff/toolkit/typing/engines/smirnoff/io.py @@ -7,6 +7,8 @@ """ +from __future__ import annotations + __all__ = [ "ParameterIOHandler", "XMLParameterIOHandler", diff --git a/openff/toolkit/typing/engines/smirnoff/parameters.py b/openff/toolkit/typing/engines/smirnoff/parameters.py index 3ae8445ae..5c3151fc9 100644 --- a/openff/toolkit/typing/engines/smirnoff/parameters.py +++ b/openff/toolkit/typing/engines/smirnoff/parameters.py @@ -7,6 +7,8 @@ """ +from __future__ import annotations + __all__ = [ "AngleHandler", "AngleType", @@ -60,7 +62,7 @@ import re from collections import defaultdict from collections.abc import Callable -from typing import Any, Literal, Union, cast, get_args +from typing import Any, Literal, cast, get_args import numpy from openff.units.units import Unit @@ -1374,7 +1376,7 @@ class ParameterList(list): def __init__( self, - input_parameter_list: list["ParameterType"] | None = None, + input_parameter_list: list[ParameterType] | None = None, ): """ Initialize a new ParameterList, optionally providing a list of ParameterType objects @@ -1489,7 +1491,7 @@ def __delitem__(self, item): index = self.index(item) super().__delitem__(index) - def __getitem__(self, item: Union[int, slice, str, "ParameterType"]): # type: ignore[override] + def __getitem__(self, item: int | slice | str | ParameterType): # type: ignore[override] """ Retrieve item by index or SMIRKS. If multiple parameters have the same SMIRKS, this returns the last one. @@ -1555,7 +1557,7 @@ def to_list(self, discard_cosmetic_attributes=True): class VirtualSiteParameterList(ParameterList): - def __getitem__(self, val: Union[int, slice, str, "ParameterType"]): # type: ignore[override] + def __getitem__(self, val: int | slice | str | ParameterType): # type: ignore[override] indexable_item: int | slice if isinstance(val, int): @@ -2273,7 +2275,7 @@ def to_dict( def _check_attributes_are_equal( self, - other: "ParameterHandler", + other: ParameterHandler, identical_attrs: tuple[str, ...] = tuple(), tolerance_attrs: tuple[str, ...] = tuple(), tolerance: float = 1e-6, @@ -2431,7 +2433,7 @@ def __init__(self, **kwargs): elif self.version == Version("0.4") and "potential" not in kwargs: self.potential = "(k/2)*(r-length)^2" - def check_handler_compatibility(self, other_handler: "BondHandler"): + def check_handler_compatibility(self, other_handler: BondHandler): """ Checks whether this ParameterHandler encodes compatible physics as another ParameterHandler. This is called if a second handler is attempted to be initialized for the same tag. @@ -2481,7 +2483,7 @@ class AngleType(ParameterType): potential = ParameterAttribute(default="harmonic") - def check_handler_compatibility(self, other_handler: "AngleHandler"): + def check_handler_compatibility(self, other_handler: AngleHandler): """ Checks whether this ParameterHandler encodes compatible physics as another ParameterHandler. This is called if a second handler is attempted to be initialized for the same tag. @@ -2529,7 +2531,7 @@ class ProperTorsionType(ParameterType): fractional_bondorder_method = ParameterAttribute(default="AM1-Wiberg") fractional_bondorder_interpolation = ParameterAttribute(default="linear", converter=_allow_only(["linear"])) - def check_handler_compatibility(self, other_handler: "ProperTorsionHandler"): + def check_handler_compatibility(self, other_handler: ProperTorsionHandler): """ Checks whether this ParameterHandler encodes compatible physics as another ParameterHandler. This is called if a second handler is attempted to be initialized for the same tag. @@ -2585,7 +2587,7 @@ class ImproperTorsionType(ParameterType): ) default_idivf = ParameterAttribute(default="auto") - def check_handler_compatibility(self, other_handler: "ImproperTorsionHandler"): + def check_handler_compatibility(self, other_handler: ImproperTorsionHandler): """ Checks whether this ParameterHandler encodes compatible physics as another ParameterHandler. This is called if a second handler is attempted to be initialized for the same tag. @@ -2772,7 +2774,7 @@ def scale15(self, attrs, new_scale15): # Tolerance when comparing float attributes for handler compatibility. _SCALETOL = 1e-5 - def check_handler_compatibility(self, other_handler: "vdWHandler"): + def check_handler_compatibility(self, other_handler: vdWHandler): """ Checks whether this ParameterHandler encodes compatible physics as another ParameterHandler. This is called if a second handler is attempted to be initialized for the same tag. @@ -2951,7 +2953,7 @@ def __init__(self, **kwargs): ) super().__init__(**kwargs) - def check_handler_compatibility(self, other_handler: "ElectrostaticsHandler"): + def check_handler_compatibility(self, other_handler: ElectrostaticsHandler): """ Checks whether this ParameterHandler encodes compatible physics as another ParameterHandler. This is called if a second handler is attempted to be initialized for the same tag. @@ -3133,7 +3135,7 @@ class NAGLChargesHandler(_NonbondedHandler): def check_handler_compatibility( self, - other_handler: "NAGLChargesHandler", + other_handler: NAGLChargesHandler, assume_missing_is_default: bool = True, ): """ @@ -3193,7 +3195,7 @@ class ToolkitAM1BCCHandler(_NonbondedHandler): def check_handler_compatibility( self, - other_handler: "ToolkitAM1BCCHandler", + other_handler: ToolkitAM1BCCHandler, assume_missing_is_default: bool = True, ): """ @@ -3255,7 +3257,7 @@ def __init__(self, **kwargs): def check_handler_compatibility( self, - other_handler: "ChargeIncrementModelHandler", + other_handler: ChargeIncrementModelHandler, assume_missing_is_default: bool = True, ): """ @@ -3335,7 +3337,7 @@ class GBSAType(ParameterType): # Tolerance when comparing float attributes for handler compatibility. _SCALETOL = 1e-5 - def check_handler_compatibility(self, other_handler: "GBSAHandler"): + def check_handler_compatibility(self, other_handler: GBSAHandler): """ Checks whether this ParameterHandler encodes compatible physics as another ParameterHandler. This is called if a second handler is attempted to be initialized for the same tag. @@ -3617,7 +3619,7 @@ def _validate_found_match( f"environment variable `OPENFF_UNSAFE_VSITES=1`." ) - def check_handler_compatibility(self, other_handler: "VirtualSiteHandler"): + def check_handler_compatibility(self, other_handler: VirtualSiteHandler): self._check_attributes_are_equal( other_handler, identical_attrs=("exclusion_policy",), diff --git a/openff/toolkit/typing/engines/smirnoff/plugins.py b/openff/toolkit/typing/engines/smirnoff/plugins.py index 49145ef86..91f338975 100644 --- a/openff/toolkit/typing/engines/smirnoff/plugins.py +++ b/openff/toolkit/typing/engines/smirnoff/plugins.py @@ -18,6 +18,8 @@ inherits from ``ParameterHandler`` named ``CustomHandler``. """ +from __future__ import annotations + import logging from importlib.metadata import entry_points diff --git a/openff/toolkit/utils/__init__.py b/openff/toolkit/utils/__init__.py index 5c37404b8..175731cbf 100644 --- a/openff/toolkit/utils/__init__.py +++ b/openff/toolkit/utils/__init__.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from openff.toolkit.utils.constants import ( ALLOWED_AROMATICITY_MODELS, ALLOWED_CHARGE_MODELS, diff --git a/openff/toolkit/utils/_viz.py b/openff/toolkit/utils/_viz.py index 3ff292c63..2a79d8464 100644 --- a/openff/toolkit/utils/_viz.py +++ b/openff/toolkit/utils/_viz.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import uuid from io import StringIO from typing import TYPE_CHECKING @@ -40,7 +42,7 @@ class MoleculeNGLViewTrajectory(Structure, Trajectory): def __init__( self, - molecule: "Molecule", + molecule: Molecule, ext: str = "MOL2", ): if not molecule.conformers: @@ -89,7 +91,7 @@ class TopologyNGLViewStructure(Structure): def __init__( self, - topology: "Topology", + topology: Topology, ext: str = "PDB", ): self.topology = topology diff --git a/openff/toolkit/utils/ambertools_wrapper.py b/openff/toolkit/utils/ambertools_wrapper.py index 3792b9cd5..c4b8e8d6e 100644 --- a/openff/toolkit/utils/ambertools_wrapper.py +++ b/openff/toolkit/utils/ambertools_wrapper.py @@ -2,6 +2,8 @@ Wrapper class providing a minimal consistent interface to `AmberTools `_. """ +from __future__ import annotations + __all__ = ("AmberToolsToolkitWrapper",) import functools @@ -100,7 +102,7 @@ def is_available() -> bool: def assign_partial_charges( self, - molecule: "Molecule", + molecule: Molecule, partial_charge_method: str | None = None, use_conformers: list[Quantity] | None = None, strict_n_conformers: bool = False, @@ -380,7 +382,7 @@ def _get_fractional_bond_orders_from_sqm_out(self, file_path, validate_elements= def assign_fractional_bond_orders( self, - molecule: "Molecule", + molecule: Molecule, bond_order_model: str | None = None, use_conformers: list[str] | None = None, _cls=None, diff --git a/openff/toolkit/utils/base_wrapper.py b/openff/toolkit/utils/base_wrapper.py index dc4865a2d..b423d4edb 100644 --- a/openff/toolkit/utils/base_wrapper.py +++ b/openff/toolkit/utils/base_wrapper.py @@ -2,6 +2,8 @@ Base class for toolkit wrappers. Defines the public API and some shared methods """ +from __future__ import annotations + __all__ = ("ToolkitWrapper",) from functools import wraps @@ -27,7 +29,7 @@ class _ChargeSettings(TypedDict, total=False): oe_charge_method: str -def _mol_to_ctab_and_aro_key(self, molecule: "Molecule", aromaticity_model=DEFAULT_AROMATICITY_MODEL) -> str: +def _mol_to_ctab_and_aro_key(self, molecule: Molecule, aromaticity_model=DEFAULT_AROMATICITY_MODEL) -> str: return f"{molecule.ordered_connection_table_hash()}-{aromaticity_model}" @@ -186,7 +188,7 @@ def from_file_obj(self, file_obj, file_format, allow_undefined_stereo=False, _cl def _check_n_conformers( self, - molecule: "Molecule", + molecule: Molecule, partial_charge_method: str | None = None, min_confs: int | None = None, max_confs: int | None = None, diff --git a/openff/toolkit/utils/builtin_wrapper.py b/openff/toolkit/utils/builtin_wrapper.py index 9b1bdfafa..702f2459d 100644 --- a/openff/toolkit/utils/builtin_wrapper.py +++ b/openff/toolkit/utils/builtin_wrapper.py @@ -2,6 +2,8 @@ Built-in ToolkitWrapper for very basic functionality. Intended for testing and not much more. """ +from __future__ import annotations + __all__ = ("BuiltInToolkitWrapper",) from typing import TYPE_CHECKING @@ -38,7 +40,7 @@ def __init__(self): def assign_partial_charges( self, - molecule: "FrozenMolecule", + molecule: FrozenMolecule, partial_charge_method: str | None = None, use_conformers: Quantity | None = None, strict_n_conformers: bool = False, diff --git a/openff/toolkit/utils/callback.py b/openff/toolkit/utils/callback.py index a86170b83..6dcd4fc09 100644 --- a/openff/toolkit/utils/callback.py +++ b/openff/toolkit/utils/callback.py @@ -3,6 +3,8 @@ """ +from __future__ import annotations + __all__ = [ "Callbackable", "callback_method", diff --git a/openff/toolkit/utils/collections.py b/openff/toolkit/utils/collections.py index b9b1dd13c..9338c5792 100644 --- a/openff/toolkit/utils/collections.py +++ b/openff/toolkit/utils/collections.py @@ -3,6 +3,8 @@ """ +from __future__ import annotations + __all__ = [ "ValidatedDict", "ValidatedList", diff --git a/openff/toolkit/utils/constants.py b/openff/toolkit/utils/constants.py index 1b368d2ed..5e6b0de06 100644 --- a/openff/toolkit/utils/constants.py +++ b/openff/toolkit/utils/constants.py @@ -1,3 +1,5 @@ +from __future__ import annotations + __all__ = ( "ALLOWED_AROMATICITY_MODELS", "ALLOWED_CHARGE_MODELS", diff --git a/openff/toolkit/utils/exceptions.py b/openff/toolkit/utils/exceptions.py index f8e69b8bf..2d1a43330 100644 --- a/openff/toolkit/utils/exceptions.py +++ b/openff/toolkit/utils/exceptions.py @@ -1,6 +1,8 @@ +from __future__ import annotations + from collections import defaultdict from collections.abc import Mapping -from typing import TYPE_CHECKING, Optional +from typing import TYPE_CHECKING if TYPE_CHECKING: from openmm.app import Atom as OpenMMAtom @@ -429,7 +431,7 @@ def __init__( self, msg: str | None = None, substructure_library: dict[str, list[tuple]] | None = None, - omm_top: Optional["OpenMMTopology"] = None, + omm_top: OpenMMTopology | None = None, unassigned_bonds: list[tuple[int, int]] | None = None, unassigned_atoms: list[int] | None = None, matches: defaultdict[int, list[str]] | None = None, diff --git a/openff/toolkit/utils/nagl_wrapper.py b/openff/toolkit/utils/nagl_wrapper.py index 7587ce2ff..bf9d350f4 100644 --- a/openff/toolkit/utils/nagl_wrapper.py +++ b/openff/toolkit/utils/nagl_wrapper.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import importlib import pathlib import warnings @@ -60,14 +62,14 @@ def is_available(cls) -> bool: def assign_partial_charges( self, - molecule: "Molecule", + molecule: Molecule, partial_charge_method: str, - use_conformers: list["Quantity"] | None = None, + use_conformers: list[Quantity] | None = None, strict_n_conformers: bool = False, normalize_partial_charges: bool = True, doi: str | None = None, file_hash: str | None = None, - _cls: type["FrozenMolecule"] | None = None, + _cls: type[FrozenMolecule] | None = None, ): """ Compute partial charges with NAGL and store in ``self.partial_charges`` diff --git a/openff/toolkit/utils/openeye_wrapper.py b/openff/toolkit/utils/openeye_wrapper.py index 2a33c4a3e..33ffc2371 100644 --- a/openff/toolkit/utils/openeye_wrapper.py +++ b/openff/toolkit/utils/openeye_wrapper.py @@ -3,6 +3,8 @@ the `OpenEye Toolkit `_ """ +from __future__ import annotations + __all__ = ("OpenEyeToolkitWrapper",) @@ -277,7 +279,7 @@ def from_object( obj, allow_undefined_stereo: bool = False, _cls=None, - ) -> "FrozenMolecule": + ) -> FrozenMolecule: """ Convert an OEMol (or OEMol-derived object) into an openff.toolkit.topology.molecule @@ -325,7 +327,7 @@ def _polymer_openmm_topology_to_offmol(self, mol_class, omm_top, substructure_di def _polymer_openmm_topology_to_oemol( self, - omm_top: "openmm.app.Topology", + omm_top: openmm.app.Topology, substructure_library: dict[str, dict], ): """ @@ -460,7 +462,7 @@ def from_file( file_format: str, allow_undefined_stereo: bool = False, _cls=None, - ) -> list["FrozenMolecule"]: + ) -> list[FrozenMolecule]: """ Return an openff.toolkit.topology.Molecule from a file using this toolkit. @@ -524,7 +526,7 @@ def from_file_obj( file_format: str, allow_undefined_stereo: bool = False, _cls=None, - ) -> list["Molecule"]: + ) -> list[Molecule]: """ Return an openff.toolkit.topology.Molecule from a file-like object (an object with a ".read()" method using this toolkit. @@ -563,7 +565,7 @@ def from_file_obj( return self._read_oemolistream_molecules(ifs, allow_undefined_stereo, _cls=_cls) - def to_file_obj(self, molecule: "Molecule", file_obj, file_format: str): + def to_file_obj(self, molecule: Molecule, file_obj, file_format: str): """ Writes an OpenFF Molecule to a file-like object @@ -593,7 +595,7 @@ def to_file_obj(self, molecule: "Molecule", file_obj, file_format: str): def to_file( self, - molecule: "Molecule", + molecule: Molecule, file_path: str | pathlib.Path, file_format: str, ): @@ -807,9 +809,9 @@ def _assign_aromaticity_and_stereo_from_3d(self, offmol): def enumerate_protomers( self, - molecule: "FrozenMolecule", + molecule: FrozenMolecule, max_states: int = 0, - ) -> list["FrozenMolecule"]: + ) -> list[FrozenMolecule]: """ Enumerate the formal charges of a molecule to generate different protomers. Note that, in cases where the input molecule has an uncommon protonation state @@ -850,11 +852,11 @@ def enumerate_protomers( def enumerate_stereoisomers( self, - molecule: "FrozenMolecule", + molecule: FrozenMolecule, undefined_only: bool = False, max_isomers: int = 20, rationalise: bool = True, - ) -> list["FrozenMolecule"]: + ) -> list[FrozenMolecule]: """ Enumerate the stereocenters and bonds of the current molecule. @@ -910,7 +912,7 @@ def enumerate_stereoisomers( return molecules[:max_isomers] - def enumerate_tautomers(self, molecule: "FrozenMolecule", max_states: int = 20) -> list["FrozenMolecule"]: + def enumerate_tautomers(self, molecule: FrozenMolecule, max_states: int = 20) -> list[FrozenMolecule]: """ Enumerate the possible tautomers of the current molecule @@ -1063,7 +1065,7 @@ def from_openeye( oemol, allow_undefined_stereo: bool = False, _cls=None, - ) -> "FrozenMolecule": + ) -> FrozenMolecule: """ Create a Molecule from an OpenEye molecule. If the OpenEye molecule has implicit hydrogens, this function will make them explicit. @@ -1444,7 +1446,7 @@ def _connection_table_to_openeye(self, molecule, aromaticity_model=DEFAULT_AROMA def to_openeye( self, - molecule: "FrozenMolecule", + molecule: FrozenMolecule, aromaticity_model: str = DEFAULT_AROMATICITY_MODEL, ): r""" @@ -1606,7 +1608,7 @@ def to_openeye( return oemol - def atom_is_in_ring(self, atom: "Atom") -> bool: + def atom_is_in_ring(self, atom: Atom) -> bool: """Return whether or not an atom is in a ring. It is assumed that this atom is in molecule. @@ -1638,7 +1640,7 @@ def atom_is_in_ring(self, atom: "Atom") -> bool: return is_in_ring - def bond_is_in_ring(self, bond: "Bond") -> bool: + def bond_is_in_ring(self, bond: Bond) -> bool: """Return whether or not a bond is in a ring. It is assumed that this atom is in molecule. @@ -1696,7 +1698,7 @@ def _get_smiles_flavor(self, isomeric: bool, explicit_hydrogens: bool) -> int: def to_smiles( self, - molecule: "Molecule", + molecule: Molecule, isomeric: bool = True, explicit_hydrogens: bool = True, mapped: bool = False, @@ -1766,7 +1768,7 @@ def to_smiles( smiles = oechem.OECreateSmiString(oemol, smiles_options) return smiles - def to_inchi(self, molecule: "Molecule", fixed_hydrogens: bool = False) -> str: + def to_inchi(self, molecule: Molecule, fixed_hydrogens: bool = False) -> str: """ Create an InChI string for the molecule using the OpenEye OEChem Toolkit. InChI is a standardised representation that does not capture tautomers @@ -1813,7 +1815,7 @@ def to_inchi(self, molecule: "Molecule", fixed_hydrogens: bool = False) -> str: return inchi - def to_inchikey(self, molecule: "Molecule", fixed_hydrogens: bool = False) -> str: + def to_inchikey(self, molecule: Molecule, fixed_hydrogens: bool = False) -> str: """ Create an InChIKey for the molecule using the OpenEye OEChem Toolkit. InChIKey is a standardised representation that does not capture tautomers @@ -1858,7 +1860,7 @@ def to_inchikey(self, molecule: "Molecule", fixed_hydrogens: bool = False) -> st return inchi_key - def to_iupac(self, molecule: "Molecule") -> str: + def to_iupac(self, molecule: Molecule) -> str: """Generate IUPAC name from Molecule Parameters @@ -1888,7 +1890,7 @@ def to_iupac(self, molecule: "Molecule") -> str: return oeiupac.OECreateIUPACName(oemol) - def canonical_order_atoms(self, molecule: "FrozenMolecule") -> "FrozenMolecule": + def canonical_order_atoms(self, molecule: FrozenMolecule) -> FrozenMolecule: """ Canonical order the atoms in the molecule using the OpenEye toolkit. @@ -1938,7 +1940,7 @@ def from_smiles( allow_undefined_stereo: bool = False, _cls=None, name: str = "", - ) -> "FrozenMolecule": + ) -> FrozenMolecule: """ Create a Molecule from a SMILES string using the OpenEye toolkit. @@ -2002,7 +2004,7 @@ def from_inchi( allow_undefined_stereo: bool = False, _cls=None, name: str = "", - ) -> "FrozenMolecule": + ) -> FrozenMolecule: """ Construct a Molecule from a InChI representation @@ -2052,7 +2054,7 @@ def from_iupac( allow_undefined_stereo: bool = False, _cls=None, **kwargs, - ) -> "FrozenMolecule": + ) -> FrozenMolecule: """ Construct a Molecule from an IUPAC name @@ -2089,7 +2091,7 @@ def from_iupac( def generate_conformers( self, - molecule: "Molecule", + molecule: Molecule, n_conformers: int = 1, rms_cutoff: Quantity | None = None, clear_existing: bool = True, @@ -2161,7 +2163,7 @@ def generate_conformers( def apply_elf_conformer_selection( self, - molecule: "Molecule", + molecule: Molecule, percentage: float = 2.0, limit: int = 10, ): @@ -2256,7 +2258,7 @@ def apply_elf_conformer_selection( def assign_partial_charges( self, - molecule: "Molecule", + molecule: Molecule, partial_charge_method: str | None = None, use_conformers: list[Quantity] | None = None, strict_n_conformers: bool = False, @@ -2426,7 +2428,7 @@ def assign_partial_charges( def assign_fractional_bond_orders( self, - molecule: "Molecule", + molecule: Molecule, bond_order_model: str | None = None, use_conformers: list[Quantity] | None = None, _cls=None, @@ -2681,7 +2683,7 @@ def _find_smarts_matches( def find_smarts_matches( self, - molecule: "Molecule", + molecule: Molecule, smarts: str, aromaticity_model=DEFAULT_AROMATICITY_MODEL, unique=False, diff --git a/openff/toolkit/utils/rdkit_wrapper.py b/openff/toolkit/utils/rdkit_wrapper.py index 90d1da47a..52f189fc2 100644 --- a/openff/toolkit/utils/rdkit_wrapper.py +++ b/openff/toolkit/utils/rdkit_wrapper.py @@ -3,6 +3,8 @@ Wrapper class providing a minimal consistent interface to the `RDKit `. """ +from __future__ import annotations + __all__ = ("RDKitToolkitWrapper",) import copy @@ -1105,7 +1107,7 @@ def from_file_obj( # TODO: TDT file support return mols - def to_file_obj(self, molecule: "Molecule", file_obj, file_format: str): + def to_file_obj(self, molecule: Molecule, file_obj, file_format: str): """ Writes an OpenFF Molecule to a file-like object @@ -1155,7 +1157,7 @@ def to_file_obj(self, molecule: "Molecule", file_obj, file_format: str): finally: writer.close() - def to_file(self, molecule: "Molecule", file_path: str, file_format: str): + def to_file(self, molecule: Molecule, file_path: str, file_format: str): """ Writes an OpenFF Molecule to a file-like object @@ -1179,11 +1181,11 @@ def to_file(self, molecule: "Molecule", file_path: str, file_format: str): def enumerate_stereoisomers( self, - molecule: "Molecule", + molecule: Molecule, undefined_only: bool = False, max_isomers: int = 20, rationalise: bool = True, - ) -> list["Molecule"]: + ) -> list[Molecule]: """ Enumerate the stereocenters and bonds of the current molecule. @@ -1240,7 +1242,7 @@ def enumerate_stereoisomers( return molecules - def enumerate_tautomers(self, molecule: "Molecule", max_states: int = 20) -> list["Molecule"]: + def enumerate_tautomers(self, molecule: Molecule, max_states: int = 20) -> list[Molecule]: """ Enumerate the possible tautomers of the current molecule. @@ -1279,7 +1281,7 @@ def enumerate_tautomers(self, molecule: "Molecule", max_states: int = 20) -> lis return molecules[:max_states] - def canonical_order_atoms(self, molecule: "Molecule") -> "Molecule": + def canonical_order_atoms(self, molecule: Molecule) -> Molecule: """ Canonical order the atoms in the molecule using the RDKit. @@ -1320,7 +1322,7 @@ def canonical_order_atoms(self, molecule: "Molecule") -> "Molecule": def to_smiles( self, - molecule: "Molecule", + molecule: Molecule, isomeric: bool = True, explicit_hydrogens: bool = True, mapped: bool = False, @@ -1560,7 +1562,7 @@ def from_inchi( def generate_conformers( self, - molecule: "Molecule", + molecule: Molecule, n_conformers: int = 1, rms_cutoff: Quantity | None = None, clear_existing: bool = True, @@ -1637,7 +1639,7 @@ def generate_conformers( def assign_partial_charges( self, - molecule: "Molecule", + molecule: Molecule, partial_charge_method: str | None = None, use_conformers: list[Quantity] | None = None, strict_n_conformers: bool = False, @@ -1713,7 +1715,7 @@ def assign_partial_charges( @classmethod def _elf_is_problematic_conformer( cls, - molecule: "Molecule", + molecule: Molecule, conformer: Quantity, ) -> tuple[bool, str | None]: """A function which checks if a particular conformer is known to be problematic @@ -1760,7 +1762,7 @@ def _elf_is_problematic_conformer( return False, None @classmethod - def _elf_prune_problematic_conformers(cls, molecule: "Molecule") -> list[Quantity]: + def _elf_prune_problematic_conformers(cls, molecule: Molecule) -> list[Quantity]: """A function which attempts to remove conformers which are known to be problematic when computing ELF partial charges. @@ -1793,7 +1795,7 @@ def _elf_prune_problematic_conformers(cls, molecule: "Molecule") -> list[Quantit @classmethod def _elf_compute_electrostatic_energy( cls, - molecule: "Molecule", + molecule: Molecule, conformer: Quantity, ) -> float: """Computes the 'electrostatic interaction energy' of a particular conformer @@ -1864,7 +1866,7 @@ def _elf_compute_electrostatic_energy( return 0.5 * interaction_energies.sum() @classmethod - def _elf_compute_rms_matrix(cls, molecule: "Molecule") -> NDArray: + def _elf_compute_rms_matrix(cls, molecule: Molecule) -> NDArray: """Computes the symmetric RMS matrix of all conformers in a molecule taking only heavy atoms into account. @@ -1906,7 +1908,7 @@ def _elf_compute_rms_matrix(cls, molecule: "Molecule") -> NDArray: @classmethod def _elf_select_diverse_conformers( cls, - molecule: "Molecule", + molecule: Molecule, ranked_conformers: list[Quantity], limit: int, rms_tolerance: Quantity, @@ -1979,7 +1981,7 @@ def _elf_select_diverse_conformers( def apply_elf_conformer_selection( self, - molecule: "Molecule", + molecule: Molecule, percentage: float = 2.0, limit: int = 10, rms_tolerance: Quantity = 0.05 * unit.angstrom, @@ -2475,7 +2477,7 @@ def _connection_table_to_rdkit(self, molecule, aromaticity_model=DEFAULT_AROMATI return rdmol - def to_rdkit(self, molecule: "Molecule", aromaticity_model: str = DEFAULT_AROMATICITY_MODEL): + def to_rdkit(self, molecule: Molecule, aromaticity_model: str = DEFAULT_AROMATICITY_MODEL): """ Create an RDKit molecule Requires the RDKit to be installed. @@ -2603,7 +2605,7 @@ def to_rdkit(self, molecule: "Molecule", aromaticity_model: str = DEFAULT_AROMAT # Return non-editable version return Chem.Mol(rdmol) - def to_inchi(self, molecule: "Molecule", fixed_hydrogens: bool = False): + def to_inchi(self, molecule: Molecule, fixed_hydrogens: bool = False): """ Create an InChI string for the molecule using the RDKit Toolkit. InChI is a standardised representation that does not capture tautomers @@ -2649,7 +2651,7 @@ def to_inchi(self, molecule: "Molecule", fixed_hydrogens: bool = False): return inchi - def to_inchikey(self, molecule: "Molecule", fixed_hydrogens: bool = False) -> str: + def to_inchikey(self, molecule: Molecule, fixed_hydrogens: bool = False) -> str: """ Create an InChIKey for the molecule using the RDKit Toolkit. InChIKey is a standardised representation that does not capture tautomers @@ -2847,7 +2849,7 @@ def _match_smarts_with_heavy_atoms_first(rdmol, qmol, match_kwargs): def find_smarts_matches( self, - molecule: "Molecule", + molecule: Molecule, smarts: str, aromaticity_model: str = "OEAroModel_MDL", unique: bool = False, @@ -2877,7 +2879,7 @@ def find_smarts_matches( unique=unique, ) - def atom_is_in_ring(self, atom: "Atom") -> bool: + def atom_is_in_ring(self, atom: Atom) -> bool: """Return whether or not an atom is in a ring. It is assumed that this atom is in molecule. @@ -2909,7 +2911,7 @@ def atom_is_in_ring(self, atom: "Atom") -> bool: return is_in_ring - def bond_is_in_ring(self, bond: "Bond") -> bool: + def bond_is_in_ring(self, bond: Bond) -> bool: """Return whether or not a bond is in a ring. It is assumed that this atom is in molecule. @@ -3135,7 +3137,7 @@ def _constrain_rank( raise NotImplementedError() @classmethod - def _assign_rdmol_bonds_stereo(cls, off_molecule: "Molecule", rd_molecule): + def _assign_rdmol_bonds_stereo(cls, off_molecule: Molecule, rd_molecule): """Copy the info about bonds stereochemistry from the OFF Molecule to RDKit Mol. The method proceeds by formulating mapping global E/Z stereo information onto local 'bond directions' as a constraint satisfaction problem (CSP). diff --git a/openff/toolkit/utils/serialization.py b/openff/toolkit/utils/serialization.py index 33ec87d1c..df62c213c 100644 --- a/openff/toolkit/utils/serialization.py +++ b/openff/toolkit/utils/serialization.py @@ -12,6 +12,8 @@ """ +from __future__ import annotations + import abc from typing import TypeVar diff --git a/openff/toolkit/utils/toolkit_registry.py b/openff/toolkit/utils/toolkit_registry.py index 26bceb782..4ddbba849 100644 --- a/openff/toolkit/utils/toolkit_registry.py +++ b/openff/toolkit/utils/toolkit_registry.py @@ -1,5 +1,7 @@ "Registry for ToolkitWrapper objects" +from __future__ import annotations + __all__ = ("ToolkitRegistry", "toolkit_registry_manager") import inspect diff --git a/openff/toolkit/utils/toolkits.py b/openff/toolkit/utils/toolkits.py index da19d1b77..8fe3d3d22 100644 --- a/openff/toolkit/utils/toolkits.py +++ b/openff/toolkit/utils/toolkits.py @@ -20,6 +20,8 @@ """ +from __future__ import annotations + __all__ = ( "ALLOWED_AROMATICITY_MODELS", "ALLOWED_CHARGE_MODELS", diff --git a/openff/toolkit/utils/utils.py b/openff/toolkit/utils/utils.py index 5cc7a6a13..9ddf6039a 100644 --- a/openff/toolkit/utils/utils.py +++ b/openff/toolkit/utils/utils.py @@ -3,6 +3,8 @@ """ +from __future__ import annotations + __all__ = [ "all_subclasses", "convert_0_1_smirnoff_to_0_2", @@ -298,7 +300,7 @@ def convert_all_quantities_to_string( @overload def convert_all_quantities_to_string( - smirnoff_data: "Quantity", + smirnoff_data: Quantity, ) -> str | list[str] | dict[str, Any]: ... @@ -701,7 +703,7 @@ def recursive_attach_unit_strings(smirnoff_data, units_to_attach): return smirnoff_data -def get_molecule_parameterIDs(molecules: list["Molecule"], forcefield: "ForceField") -> tuple[dict, dict]: +def get_molecule_parameterIDs(molecules: list[Molecule], forcefield: ForceField) -> tuple[dict, dict]: """Process a list of molecules with a specified SMIRNOFF ffxml file and determine which parameters are used by which molecules, returning collated results. diff --git a/pyproject.toml b/pyproject.toml index eac6ca15f..ebdd3458c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -41,6 +41,7 @@ lint.isort.known-first-party = [ "openff.toolkit" ] # can't find a clean way to get Rust's globset to handle this via regex ... # https://docs.astral.sh/ruff/settings/#lint_isort_known-third-party lint.isort.known-third-party = [ "openff.interchange", "openff.utilities", "openff.units" ] +lint.isort.required-imports = [ "from __future__ import annotations" ] [tool.mypy] python_version = 3.12 diff --git a/utilities/make_substructure_dict/_make_chemical_substructures.py b/utilities/make_substructure_dict/_make_chemical_substructures.py index 6185cd9d5..b6dae5a82 100644 --- a/utilities/make_substructure_dict/_make_chemical_substructures.py +++ b/utilities/make_substructure_dict/_make_chemical_substructures.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import os from _cif_to_substructure_dict import CifSubstructures diff --git a/utilities/make_substructure_dict/_make_metadata_assignment_substructures.py b/utilities/make_substructure_dict/_make_metadata_assignment_substructures.py index e7f19be13..a26f7ea1e 100644 --- a/utilities/make_substructure_dict/_make_metadata_assignment_substructures.py +++ b/utilities/make_substructure_dict/_make_metadata_assignment_substructures.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import os from _cif_to_substructure_dict import CifSubstructures diff --git a/utilities/test_plugins/custom_plugins/handler_plugins.py b/utilities/test_plugins/custom_plugins/handler_plugins.py index 8b7790613..075ab9100 100644 --- a/utilities/test_plugins/custom_plugins/handler_plugins.py +++ b/utilities/test_plugins/custom_plugins/handler_plugins.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from openff.toolkit import unit from openff.toolkit.typing.engines.smirnoff import ParameterHandler, ParameterIOHandler from openff.toolkit.typing.engines.smirnoff.parameters import ( diff --git a/utilities/test_plugins/setup.py b/utilities/test_plugins/setup.py index 6f2ae13d9..7e04ee42b 100644 --- a/utilities/test_plugins/setup.py +++ b/utilities/test_plugins/setup.py @@ -3,6 +3,8 @@ A test package used to ensure that parameterhandler plugins are handled correctly """ +from __future__ import annotations + from setuptools import setup setup(