From 2e163a031f6ca013f0fdbfe51532e20797224f2d Mon Sep 17 00:00:00 2001
From: Mike Henry <11765982+mikemhenry@users.noreply.github.com>
Date: Fri, 5 Jun 2026 13:43:37 -0700
Subject: [PATCH 1/7] Test Python 3.14
---
.github/workflows/CI.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml
index 98db567a4..a274f05bf 100644
--- a/.github/workflows/CI.yml
+++ b/.github/workflows/CI.yml
@@ -23,7 +23,7 @@ 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]
nagl: [true, false]
From a490f276ed709d3555428a55ad9d9cb6a86064e7 Mon Sep 17 00:00:00 2001
From: Mike Henry <11765982+mikemhenry@users.noreply.github.com>
Date: Thu, 11 Jun 2026 07:04:43 -0700
Subject: [PATCH 2/7] no python 3.14 builds for ambertools (yet)
---
devtools/conda-envs/rdkit-examples.yaml | 1 -
devtools/conda-envs/rdkit.yaml | 1 -
devtools/conda-envs/test_env.yaml | 1 -
3 files changed, 3 deletions(-)
diff --git a/devtools/conda-envs/rdkit-examples.yaml b/devtools/conda-envs/rdkit-examples.yaml
index 6ac9bf115..19e6bbe64 100644
--- a/devtools/conda-envs/rdkit-examples.yaml
+++ b/devtools/conda-envs/rdkit-examples.yaml
@@ -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..b2cc3d923 100644
--- a/devtools/conda-envs/rdkit.yaml
+++ b/devtools/conda-envs/rdkit.yaml
@@ -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..47aace469 100644
--- a/devtools/conda-envs/test_env.yaml
+++ b/devtools/conda-envs/test_env.yaml
@@ -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
From 6e0f39cc2afdb07c38f9ef2021bd2f089fd4f4e3 Mon Sep 17 00:00:00 2001
From: Mike Henry <11765982+mikemhenry@users.noreply.github.com>
Date: Thu, 11 Jun 2026 07:13:37 -0700
Subject: [PATCH 3/7] skip python 3.14 builds with openeye
---
.github/workflows/CI.yml | 2 ++
1 file changed, 2 insertions(+)
diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml
index a274f05bf..d52217db9 100644
--- a/.github/workflows/CI.yml
+++ b/.github/workflows/CI.yml
@@ -32,6 +32,8 @@ jobs:
openeye: false
- openeye: true
python-version: "3.13"
+ - openeye: true
+ python-version: "3.14"
- rdkit: false
nagl: true
From abd067b3376e832634130e723fcd94e64b36ac51 Mon Sep 17 00:00:00 2001
From: Mike Henry <11765982+mikemhenry@users.noreply.github.com>
Date: Thu, 11 Jun 2026 07:17:57 -0700
Subject: [PATCH 4/7] unpin numpy
---
devtools/conda-envs/rdkit-examples.yaml | 2 +-
devtools/conda-envs/rdkit.yaml | 2 +-
devtools/conda-envs/test_env.yaml | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/devtools/conda-envs/rdkit-examples.yaml b/devtools/conda-envs/rdkit-examples.yaml
index 19e6bbe64..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
diff --git a/devtools/conda-envs/rdkit.yaml b/devtools/conda-envs/rdkit.yaml
index b2cc3d923..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
diff --git a/devtools/conda-envs/test_env.yaml b/devtools/conda-envs/test_env.yaml
index 47aace469..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
From bd89bb26580b1fc97e1dc84fbdb99f45a6bf42f0 Mon Sep 17 00:00:00 2001
From: Mike Henry <11765982+mikemhenry@users.noreply.github.com>
Date: Thu, 11 Jun 2026 11:14:54 -0700
Subject: [PATCH 5/7] see if this fixes it
---
devtools/scripts/build_cookiecutter_json.py | 2 +
docs/conf.py | 2 +
docs/conftest.py | 1 +
docs/users/molecule_cookbook.ipynb | 2 +
docs/users/pdb_cookbook/index.ipynb | 2 +
.../QCarchive_interface.ipynb | 2 +
.../SMIRNOFF_simulation/run_simulation.ipynb | 2 +
.../conformer_energies.ipynb | 2 +
.../conformer_energies/conformer_energies.py | 2 +
examples/examples_helper.py | 1 +
.../forcefield_modification.ipynb | 2 +
.../inspect_assigned_parameters.ipynb | 2 +
.../toolkit_showcase/toolkit_showcase.ipynb | 2 +
.../export_with_interchange.ipynb | 2 +
.../BRD4_inhibitor_benchmark.ipynb | 2 +
examples/virtual_sites/vsite_showcase.ipynb | 2 +
examples/visualization/visualization.ipynb | 2 +
openff/toolkit/__init__.py | 1 +
openff/toolkit/_tests/_stale_tests.py | 2 +
openff/toolkit/_tests/conftest.py | 1 +
openff/toolkit/_tests/create_molecules.py | 1 +
openff/toolkit/_tests/mocking.py | 2 +
.../_tests/molecule/test_state_enumeration.py | 2 +
openff/toolkit/_tests/test_energies.py | 2 +
openff/toolkit/_tests/test_examples.py | 1 +
openff/toolkit/_tests/test_forcefield.py | 1 +
openff/toolkit/_tests/test_interchange.py | 2 +
openff/toolkit/_tests/test_io.py | 1 +
openff/toolkit/_tests/test_links.py | 2 +
openff/toolkit/_tests/test_mm_molecule.py | 2 +
openff/toolkit/_tests/test_molecule.py | 1 +
openff/toolkit/_tests/test_nagl.py | 2 +
.../toolkit/_tests/test_parameter_plugins.py | 1 +
openff/toolkit/_tests/test_parameters.py | 1 +
openff/toolkit/_tests/test_toolkit_io.py | 1 +
openff/toolkit/_tests/test_toolkits.py | 1 +
openff/toolkit/_tests/test_topology.py | 1 +
openff/toolkit/_tests/test_utils.py | 1 +
openff/toolkit/_tests/test_utils_callback.py | 1 +
.../toolkit/_tests/test_utils_collections.py | 1 +
.../_tests/test_utils_serialization.py | 1 +
openff/toolkit/_tests/utils.py | 1 +
openff/toolkit/topology/__init__.py | 2 +
openff/toolkit/topology/_mm_molecule.py | 65 ++++++++++---------
openff/toolkit/topology/molecule.py | 58 ++++++++---------
openff/toolkit/topology/topology.py | 38 +++++------
.../typing/engines/smirnoff/__init__.py | 2 +
.../typing/engines/smirnoff/forcefield.py | 31 ++++-----
openff/toolkit/typing/engines/smirnoff/io.py | 1 +
.../typing/engines/smirnoff/parameters.py | 33 +++++-----
.../typing/engines/smirnoff/plugins.py | 1 +
openff/toolkit/utils/__init__.py | 2 +
openff/toolkit/utils/_viz.py | 6 +-
openff/toolkit/utils/ambertools_wrapper.py | 5 +-
openff/toolkit/utils/base_wrapper.py | 5 +-
openff/toolkit/utils/builtin_wrapper.py | 3 +-
openff/toolkit/utils/callback.py | 1 +
openff/toolkit/utils/collections.py | 1 +
openff/toolkit/utils/constants.py | 2 +
openff/toolkit/utils/exceptions.py | 6 +-
openff/toolkit/utils/nagl_wrapper.py | 8 ++-
openff/toolkit/utils/openeye_wrapper.py | 57 ++++++++--------
openff/toolkit/utils/rdkit_wrapper.py | 45 ++++++-------
openff/toolkit/utils/serialization.py | 1 +
openff/toolkit/utils/toolkit_registry.py | 1 +
openff/toolkit/utils/toolkits.py | 1 +
openff/toolkit/utils/utils.py | 5 +-
pyproject.toml | 2 +-
.../_make_chemical_substructures.py | 2 +
..._make_metadata_assignment_substructures.py | 2 +
.../custom_plugins/handler_plugins.py | 2 +
utilities/test_plugins/setup.py | 1 +
72 files changed, 278 insertions(+), 176 deletions(-)
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..8cde5f186 100644
--- a/docs/conftest.py
+++ b/docs/conftest.py
@@ -5,6 +5,7 @@
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..32bf80d6d 100755
--- a/examples/examples_helper.py
+++ b/examples/examples_helper.py
@@ -1,5 +1,6 @@
#!/usr/bin/env python3
"""Copy the openff-toolkit examples suite to a local directory"""
+from __future__ import annotations
import argparse
from os import environ
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..b1d08db58 100644
--- a/openff/toolkit/__init__.py
+++ b/openff/toolkit/__init__.py
@@ -2,6 +2,7 @@
openff-toolkit
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
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..f61ef1a1c 100644
--- a/openff/toolkit/_tests/conftest.py
+++ b/openff/toolkit/_tests/conftest.py
@@ -1,6 +1,7 @@
"""
Configuration file for pytest.
"""
+from __future__ import annotations
import logging
diff --git a/openff/toolkit/_tests/create_molecules.py b/openff/toolkit/_tests/create_molecules.py
index b9cfafd59..e88e98589 100644
--- a/openff/toolkit/_tests/create_molecules.py
+++ b/openff/toolkit/_tests/create_molecules.py
@@ -4,6 +4,7 @@
These are common to several test modules.
"""
+from __future__ import annotations
import numpy as np
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..3d28ea2ee 100644
--- a/openff/toolkit/_tests/test_examples.py
+++ b/openff/toolkit/_tests/test_examples.py
@@ -1,6 +1,7 @@
"""
Test that the examples in the repo run without errors.
"""
+from __future__ import annotations
import pathlib
import re
diff --git a/openff/toolkit/_tests/test_forcefield.py b/openff/toolkit/_tests/test_forcefield.py
index d5fed21fb..827b07350 100644
--- a/openff/toolkit/_tests/test_forcefield.py
+++ b/openff/toolkit/_tests/test_forcefield.py
@@ -2,6 +2,7 @@
Tests for forcefield class
"""
+from __future__ import annotations
import copy
import itertools
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..f6967b2bf 100644
--- a/openff/toolkit/_tests/test_io.py
+++ b/openff/toolkit/_tests/test_io.py
@@ -2,6 +2,7 @@
Test classes and function in module openff.toolkit.typing.engines.smirnoff.io.
"""
+from __future__ import annotations
import pytest
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..5b0851684 100644
--- a/openff/toolkit/_tests/test_molecule.py
+++ b/openff/toolkit/_tests/test_molecule.py
@@ -12,6 +12,7 @@
serialized OFFMols.
"""
+from __future__ import annotations
import copy
import os
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..397a8c3e8 100644
--- a/openff/toolkit/_tests/test_parameter_plugins.py
+++ b/openff/toolkit/_tests/test_parameter_plugins.py
@@ -1,6 +1,7 @@
"""
Test classes and function in module openff.toolkit.typing.engines.smirnoff.plugins
"""
+from __future__ import annotations
import pytest
diff --git a/openff/toolkit/_tests/test_parameters.py b/openff/toolkit/_tests/test_parameters.py
index 8bb0b196b..7c488f8d6 100644
--- a/openff/toolkit/_tests/test_parameters.py
+++ b/openff/toolkit/_tests/test_parameters.py
@@ -2,6 +2,7 @@
Test classes and function in module openff.toolkit.typing.engines.smirnoff.parameters.
"""
+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..5338ce114 100644
--- a/openff/toolkit/_tests/test_toolkit_io.py
+++ b/openff/toolkit/_tests/test_toolkit_io.py
@@ -2,6 +2,7 @@
Tests for I/O functionality of the toolkit wrappers
"""
+from __future__ import annotations
import pathlib
import sys
diff --git a/openff/toolkit/_tests/test_toolkits.py b/openff/toolkit/_tests/test_toolkits.py
index f48f4c68f..0be2d2969 100644
--- a/openff/toolkit/_tests/test_toolkits.py
+++ b/openff/toolkit/_tests/test_toolkits.py
@@ -2,6 +2,7 @@
Tests for cheminformatics toolkit wrappers
"""
+from __future__ import annotations
import logging
import os
diff --git a/openff/toolkit/_tests/test_topology.py b/openff/toolkit/_tests/test_topology.py
index 6b6a17d36..d652d920c 100644
--- a/openff/toolkit/_tests/test_topology.py
+++ b/openff/toolkit/_tests/test_topology.py
@@ -2,6 +2,7 @@
Tests for Topology
"""
+from __future__ import annotations
import itertools
import re
diff --git a/openff/toolkit/_tests/test_utils.py b/openff/toolkit/_tests/test_utils.py
index 7733b7505..e6f0b2b1e 100644
--- a/openff/toolkit/_tests/test_utils.py
+++ b/openff/toolkit/_tests/test_utils.py
@@ -2,6 +2,7 @@
Tests for utility methods
"""
+from __future__ import annotations
import os
diff --git a/openff/toolkit/_tests/test_utils_callback.py b/openff/toolkit/_tests/test_utils_callback.py
index 79248d727..90b6741b3 100644
--- a/openff/toolkit/_tests/test_utils_callback.py
+++ b/openff/toolkit/_tests/test_utils_callback.py
@@ -2,6 +2,7 @@
Tests for callback utility classes and functions.
"""
+from __future__ import annotations
import pytest
diff --git a/openff/toolkit/_tests/test_utils_collections.py b/openff/toolkit/_tests/test_utils_collections.py
index c33bfd5ac..694018073 100644
--- a/openff/toolkit/_tests/test_utils_collections.py
+++ b/openff/toolkit/_tests/test_utils_collections.py
@@ -2,6 +2,7 @@
Tests for custom collections classes.
"""
+from __future__ import annotations
import copy
diff --git a/openff/toolkit/_tests/test_utils_serialization.py b/openff/toolkit/_tests/test_utils_serialization.py
index 71c1d7dd4..54cb24a21 100644
--- a/openff/toolkit/_tests/test_utils_serialization.py
+++ b/openff/toolkit/_tests/test_utils_serialization.py
@@ -2,6 +2,7 @@
Tests for utility methods for serialization
"""
+from __future__ import annotations
import numpy as np
import pytest
diff --git a/openff/toolkit/_tests/utils.py b/openff/toolkit/_tests/utils.py
index a0f2bcc87..9051fded4 100644
--- a/openff/toolkit/_tests/utils.py
+++ b/openff/toolkit/_tests/utils.py
@@ -2,6 +2,7 @@
Utilities for testing.
"""
+from __future__ import annotations
import collections
import copy
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..3d4d3a2a3 100644
--- a/openff/toolkit/topology/_mm_molecule.py
+++ b/openff/toolkit/topology/_mm_molecule.py
@@ -9,10 +9,11 @@
deserialize a Molecule or a TypedMolecule.
"""
+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 +63,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 +83,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 +105,9 @@ def angles(
self,
) -> Generator[
tuple[
- "_SimpleAtom",
- "_SimpleAtom",
- "_SimpleAtom",
+ _SimpleAtom,
+ _SimpleAtom,
+ _SimpleAtom,
],
None,
None,
@@ -127,10 +128,10 @@ def propers(
self,
) -> Generator[
tuple[
- "_SimpleAtom",
- "_SimpleAtom",
- "_SimpleAtom",
- "_SimpleAtom",
+ _SimpleAtom,
+ _SimpleAtom,
+ _SimpleAtom,
+ _SimpleAtom,
],
None,
None,
@@ -155,10 +156,10 @@ def impropers(
self,
) -> Generator[
tuple[
- "_SimpleAtom",
- "_SimpleAtom",
- "_SimpleAtom",
- "_SimpleAtom",
+ _SimpleAtom,
+ _SimpleAtom,
+ _SimpleAtom,
+ _SimpleAtom,
],
None,
None,
@@ -181,10 +182,10 @@ def smirnoff_impropers(
self,
) -> Generator[
tuple[
- "_SimpleAtom",
- "_SimpleAtom",
- "_SimpleAtom",
- "_SimpleAtom",
+ _SimpleAtom,
+ _SimpleAtom,
+ _SimpleAtom,
+ _SimpleAtom,
],
None,
None,
@@ -198,10 +199,10 @@ def amber_impropers(
self,
) -> Generator[
tuple[
- "_SimpleAtom",
- "_SimpleAtom",
- "_SimpleAtom",
- "_SimpleAtom",
+ _SimpleAtom,
+ _SimpleAtom,
+ _SimpleAtom,
+ _SimpleAtom,
],
None,
None,
@@ -232,7 +233,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 +244,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 +265,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 +278,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 +435,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 +455,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 +522,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 +584,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..1c85a826b 100644
--- a/openff/toolkit/topology/molecule.py
+++ b/openff/toolkit/topology/molecule.py
@@ -24,6 +24,7 @@
* Speed up overall import time by putting non-global imports only where they are needed
"""
+from __future__ import annotations
import hashlib
import json
@@ -41,7 +42,6 @@
Literal,
TextIO,
TypeVar,
- Union,
overload,
)
@@ -127,10 +127,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 +144,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 +285,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 +343,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 +503,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 +780,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 +1451,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 +1516,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 +1589,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 +1950,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 +2191,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 +2803,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 +3541,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 +4337,7 @@ def to_rdkit(
self,
aromaticity_model=DEFAULT_AROMATICITY_MODEL,
toolkit_registry=GLOBAL_TOOLKIT_REGISTRY,
- ) -> "RDMol":
+ ) -> RDMol:
"""
Create an RDKit molecule
@@ -4376,7 +4376,7 @@ def from_openeye(
cls: type[FM],
oemol,
allow_undefined_stereo: bool = False,
- ) -> "FrozenMolecule":
+ ) -> FrozenMolecule:
"""
Create a ``Molecule`` from an OpenEye molecule.
@@ -5286,8 +5286,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 +5364,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 +5384,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 +5634,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 +5697,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 +5864,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 +5990,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 +6044,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..3124348b2 100644
--- a/openff/toolkit/topology/topology.py
+++ b/openff/toolkit/topology/topology.py
@@ -11,6 +11,7 @@
* Use `attrs `_ for object setter boilerplate?
"""
+from __future__ import annotations
import re
from collections import defaultdict
@@ -22,7 +23,6 @@
TYPE_CHECKING,
Literal,
TextIO,
- Union,
)
import numpy as np
@@ -520,7 +520,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 +546,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 +724,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 +734,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 +861,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 +901,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 +1327,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 +1771,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 +1935,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 +2122,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 +2192,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 +2228,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 +2248,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 +2437,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 +2537,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..e3c26ca64 100644
--- a/openff/toolkit/typing/engines/smirnoff/forcefield.py
+++ b/openff/toolkit/typing/engines/smirnoff/forcefield.py
@@ -10,12 +10,13 @@
* Speed up overall import time by putting non-global imports only where they are needed
"""
+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 +1105,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 +1129,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 +1175,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 +1229,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 +1314,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..ff6e13a56 100644
--- a/openff/toolkit/typing/engines/smirnoff/io.py
+++ b/openff/toolkit/typing/engines/smirnoff/io.py
@@ -6,6 +6,7 @@
.. codeauthor:: Peter K. Eastman
"""
+from __future__ import annotations
__all__ = [
"ParameterIOHandler",
diff --git a/openff/toolkit/typing/engines/smirnoff/parameters.py b/openff/toolkit/typing/engines/smirnoff/parameters.py
index 3ae8445ae..ead8b2470 100644
--- a/openff/toolkit/typing/engines/smirnoff/parameters.py
+++ b/openff/toolkit/typing/engines/smirnoff/parameters.py
@@ -6,6 +6,7 @@
New pluggable handlers can be created by creating subclasses of :class:`ParameterHandler`.
"""
+from __future__ import annotations
__all__ = [
"AngleHandler",
@@ -60,7 +61,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 +1375,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 +1490,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 +1556,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 +2274,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 +2432,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 +2482,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 +2530,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 +2586,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 +2773,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 +2952,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 +3134,7 @@ class NAGLChargesHandler(_NonbondedHandler):
def check_handler_compatibility(
self,
- other_handler: "NAGLChargesHandler",
+ other_handler: NAGLChargesHandler,
assume_missing_is_default: bool = True,
):
"""
@@ -3193,7 +3194,7 @@ class ToolkitAM1BCCHandler(_NonbondedHandler):
def check_handler_compatibility(
self,
- other_handler: "ToolkitAM1BCCHandler",
+ other_handler: ToolkitAM1BCCHandler,
assume_missing_is_default: bool = True,
):
"""
@@ -3255,7 +3256,7 @@ def __init__(self, **kwargs):
def check_handler_compatibility(
self,
- other_handler: "ChargeIncrementModelHandler",
+ other_handler: ChargeIncrementModelHandler,
assume_missing_is_default: bool = True,
):
"""
@@ -3335,7 +3336,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 +3618,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..583d5acf4 100644
--- a/openff/toolkit/typing/engines/smirnoff/plugins.py
+++ b/openff/toolkit/typing/engines/smirnoff/plugins.py
@@ -17,6 +17,7 @@
where in this example your package is named ``myapp`` and contains a class which
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..22663a2a1 100644
--- a/openff/toolkit/utils/ambertools_wrapper.py
+++ b/openff/toolkit/utils/ambertools_wrapper.py
@@ -1,6 +1,7 @@
"""
Wrapper class providing a minimal consistent interface to `AmberTools `_.
"""
+from __future__ import annotations
__all__ = ("AmberToolsToolkitWrapper",)
@@ -100,7 +101,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 +381,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..74a836619 100644
--- a/openff/toolkit/utils/base_wrapper.py
+++ b/openff/toolkit/utils/base_wrapper.py
@@ -1,6 +1,7 @@
"""
Base class for toolkit wrappers. Defines the public API and some shared methods
"""
+from __future__ import annotations
__all__ = ("ToolkitWrapper",)
@@ -27,7 +28,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 +187,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..efe612db4 100644
--- a/openff/toolkit/utils/builtin_wrapper.py
+++ b/openff/toolkit/utils/builtin_wrapper.py
@@ -1,6 +1,7 @@
"""
Built-in ToolkitWrapper for very basic functionality. Intended for testing and not much more.
"""
+from __future__ import annotations
__all__ = ("BuiltInToolkitWrapper",)
@@ -38,7 +39,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..c6d29f74a 100644
--- a/openff/toolkit/utils/callback.py
+++ b/openff/toolkit/utils/callback.py
@@ -2,6 +2,7 @@
Utility classes and functions to create objects supporting callback registration.
"""
+from __future__ import annotations
__all__ = [
"Callbackable",
diff --git a/openff/toolkit/utils/collections.py b/openff/toolkit/utils/collections.py
index b9b1dd13c..2badc4f59 100644
--- a/openff/toolkit/utils/collections.py
+++ b/openff/toolkit/utils/collections.py
@@ -2,6 +2,7 @@
Custom collections classes.
"""
+from __future__ import annotations
__all__ = [
"ValidatedDict",
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..ee21f8de1 100644
--- a/openff/toolkit/utils/openeye_wrapper.py
+++ b/openff/toolkit/utils/openeye_wrapper.py
@@ -2,6 +2,7 @@
Wrapper class providing a minimal consistent interface to
the `OpenEye Toolkit `_
"""
+from __future__ import annotations
__all__ = ("OpenEyeToolkitWrapper",)
@@ -277,7 +278,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 +326,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 +461,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 +525,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 +564,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 +594,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 +808,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 +851,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 +911,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 +1064,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 +1445,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 +1607,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 +1639,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 +1697,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 +1767,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 +1814,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 +1859,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 +1889,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 +1939,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 +2003,7 @@ def from_inchi(
allow_undefined_stereo: bool = False,
_cls=None,
name: str = "",
- ) -> "FrozenMolecule":
+ ) -> FrozenMolecule:
"""
Construct a Molecule from a InChI representation
@@ -2052,7 +2053,7 @@ def from_iupac(
allow_undefined_stereo: bool = False,
_cls=None,
**kwargs,
- ) -> "FrozenMolecule":
+ ) -> FrozenMolecule:
"""
Construct a Molecule from an IUPAC name
@@ -2089,7 +2090,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 +2162,7 @@ def generate_conformers(
def apply_elf_conformer_selection(
self,
- molecule: "Molecule",
+ molecule: Molecule,
percentage: float = 2.0,
limit: int = 10,
):
@@ -2256,7 +2257,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 +2427,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 +2682,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..03fc451af 100644
--- a/openff/toolkit/utils/rdkit_wrapper.py
+++ b/openff/toolkit/utils/rdkit_wrapper.py
@@ -2,6 +2,7 @@
"""
Wrapper class providing a minimal consistent interface to the `RDKit `.
"""
+from __future__ import annotations
__all__ = ("RDKitToolkitWrapper",)
@@ -1105,7 +1106,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 +1156,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 +1180,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 +1241,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 +1280,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 +1321,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 +1561,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 +1638,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 +1714,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 +1761,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 +1794,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 +1865,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 +1907,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 +1980,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 +2476,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 +2604,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 +2650,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 +2848,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 +2878,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 +2910,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 +3136,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..f3e643f84 100644
--- a/openff/toolkit/utils/serialization.py
+++ b/openff/toolkit/utils/serialization.py
@@ -11,6 +11,7 @@
installed?
"""
+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..47b47112a 100644
--- a/openff/toolkit/utils/toolkit_registry.py
+++ b/openff/toolkit/utils/toolkit_registry.py
@@ -1,4 +1,5 @@
"Registry for ToolkitWrapper objects"
+from __future__ import annotations
__all__ = ("ToolkitRegistry", "toolkit_registry_manager")
diff --git a/openff/toolkit/utils/toolkits.py b/openff/toolkit/utils/toolkits.py
index da19d1b77..3dcfc8f17 100644
--- a/openff/toolkit/utils/toolkits.py
+++ b/openff/toolkit/utils/toolkits.py
@@ -19,6 +19,7 @@
* Change global variables from _INSTALLED to _AVAILABLE
"""
+from __future__ import annotations
__all__ = (
"ALLOWED_AROMATICITY_MODELS",
diff --git a/openff/toolkit/utils/utils.py b/openff/toolkit/utils/utils.py
index 5cc7a6a13..5ca01c418 100644
--- a/openff/toolkit/utils/utils.py
+++ b/openff/toolkit/utils/utils.py
@@ -2,6 +2,7 @@
Utility subroutines
"""
+from __future__ import annotations
__all__ = [
"all_subclasses",
@@ -298,7 +299,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 +702,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..a67ea2151 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -41,7 +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
warn_unused_configs = true
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..3bdfd8926 100644
--- a/utilities/test_plugins/setup.py
+++ b/utilities/test_plugins/setup.py
@@ -2,6 +2,7 @@
openff-test-parameter-plugins
A test package used to ensure that parameterhandler plugins are handled correctly
"""
+from __future__ import annotations
from setuptools import setup
From af7b23bc416350cba1dbbf5207a7faea80ed3360 Mon Sep 17 00:00:00 2001
From: "pre-commit-ci[bot]"
<66853113+pre-commit-ci[bot]@users.noreply.github.com>
Date: Thu, 11 Jun 2026 18:16:03 +0000
Subject: [PATCH 6/7] [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
---
docs/conftest.py | 1 +
examples/examples_helper.py | 1 +
openff/toolkit/__init__.py | 1 +
openff/toolkit/_tests/conftest.py | 1 +
openff/toolkit/_tests/create_molecules.py | 1 +
openff/toolkit/_tests/test_examples.py | 1 +
openff/toolkit/_tests/test_forcefield.py | 1 +
openff/toolkit/_tests/test_io.py | 1 +
openff/toolkit/_tests/test_molecule.py | 1 +
openff/toolkit/_tests/test_parameter_plugins.py | 1 +
openff/toolkit/_tests/test_parameters.py | 1 +
openff/toolkit/_tests/test_toolkit_io.py | 1 +
openff/toolkit/_tests/test_toolkits.py | 1 +
openff/toolkit/_tests/test_topology.py | 1 +
openff/toolkit/_tests/test_utils.py | 1 +
openff/toolkit/_tests/test_utils_callback.py | 1 +
openff/toolkit/_tests/test_utils_collections.py | 1 +
openff/toolkit/_tests/test_utils_serialization.py | 1 +
openff/toolkit/_tests/utils.py | 1 +
openff/toolkit/topology/_mm_molecule.py | 1 +
openff/toolkit/topology/molecule.py | 1 +
openff/toolkit/topology/topology.py | 1 +
openff/toolkit/typing/engines/smirnoff/forcefield.py | 1 +
openff/toolkit/typing/engines/smirnoff/io.py | 1 +
openff/toolkit/typing/engines/smirnoff/parameters.py | 1 +
openff/toolkit/typing/engines/smirnoff/plugins.py | 1 +
openff/toolkit/utils/ambertools_wrapper.py | 1 +
openff/toolkit/utils/base_wrapper.py | 1 +
openff/toolkit/utils/builtin_wrapper.py | 1 +
openff/toolkit/utils/callback.py | 1 +
openff/toolkit/utils/collections.py | 1 +
openff/toolkit/utils/openeye_wrapper.py | 1 +
openff/toolkit/utils/rdkit_wrapper.py | 1 +
openff/toolkit/utils/serialization.py | 1 +
openff/toolkit/utils/toolkit_registry.py | 1 +
openff/toolkit/utils/toolkits.py | 1 +
openff/toolkit/utils/utils.py | 1 +
pyproject.toml | 3 ++-
utilities/test_plugins/setup.py | 1 +
39 files changed, 40 insertions(+), 1 deletion(-)
diff --git a/docs/conftest.py b/docs/conftest.py
index 8cde5f186..92c9e0949 100644
--- a/docs/conftest.py
+++ b/docs/conftest.py
@@ -5,6 +5,7 @@
The nbval-sanitize.cfg file is also for use with nbval.
"""
+
from __future__ import annotations
diff --git a/examples/examples_helper.py b/examples/examples_helper.py
index 32bf80d6d..bc2f63b59 100755
--- a/examples/examples_helper.py
+++ b/examples/examples_helper.py
@@ -1,5 +1,6 @@
#!/usr/bin/env python3
"""Copy the openff-toolkit examples suite to a local directory"""
+
from __future__ import annotations
import argparse
diff --git a/openff/toolkit/__init__.py b/openff/toolkit/__init__.py
index b1d08db58..830405752 100644
--- a/openff/toolkit/__init__.py
+++ b/openff/toolkit/__init__.py
@@ -2,6 +2,7 @@
openff-toolkit
A modern, extensible library for molecular mechanics force field science from the Open Force Field Consortium.
"""
+
from __future__ import annotations
import importlib
diff --git a/openff/toolkit/_tests/conftest.py b/openff/toolkit/_tests/conftest.py
index f61ef1a1c..d804f040b 100644
--- a/openff/toolkit/_tests/conftest.py
+++ b/openff/toolkit/_tests/conftest.py
@@ -1,6 +1,7 @@
"""
Configuration file for pytest.
"""
+
from __future__ import annotations
import logging
diff --git a/openff/toolkit/_tests/create_molecules.py b/openff/toolkit/_tests/create_molecules.py
index e88e98589..06ec9a8bd 100644
--- a/openff/toolkit/_tests/create_molecules.py
+++ b/openff/toolkit/_tests/create_molecules.py
@@ -4,6 +4,7 @@
These are common to several test modules.
"""
+
from __future__ import annotations
import numpy as np
diff --git a/openff/toolkit/_tests/test_examples.py b/openff/toolkit/_tests/test_examples.py
index 3d28ea2ee..d6919ea8f 100644
--- a/openff/toolkit/_tests/test_examples.py
+++ b/openff/toolkit/_tests/test_examples.py
@@ -1,6 +1,7 @@
"""
Test that the examples in the repo run without errors.
"""
+
from __future__ import annotations
import pathlib
diff --git a/openff/toolkit/_tests/test_forcefield.py b/openff/toolkit/_tests/test_forcefield.py
index 827b07350..28f9a764a 100644
--- a/openff/toolkit/_tests/test_forcefield.py
+++ b/openff/toolkit/_tests/test_forcefield.py
@@ -2,6 +2,7 @@
Tests for forcefield class
"""
+
from __future__ import annotations
import copy
diff --git a/openff/toolkit/_tests/test_io.py b/openff/toolkit/_tests/test_io.py
index f6967b2bf..694951729 100644
--- a/openff/toolkit/_tests/test_io.py
+++ b/openff/toolkit/_tests/test_io.py
@@ -2,6 +2,7 @@
Test classes and function in module openff.toolkit.typing.engines.smirnoff.io.
"""
+
from __future__ import annotations
import pytest
diff --git a/openff/toolkit/_tests/test_molecule.py b/openff/toolkit/_tests/test_molecule.py
index 5b0851684..7a41cfc4a 100644
--- a/openff/toolkit/_tests/test_molecule.py
+++ b/openff/toolkit/_tests/test_molecule.py
@@ -12,6 +12,7 @@
serialized OFFMols.
"""
+
from __future__ import annotations
import copy
diff --git a/openff/toolkit/_tests/test_parameter_plugins.py b/openff/toolkit/_tests/test_parameter_plugins.py
index 397a8c3e8..797922419 100644
--- a/openff/toolkit/_tests/test_parameter_plugins.py
+++ b/openff/toolkit/_tests/test_parameter_plugins.py
@@ -1,6 +1,7 @@
"""
Test classes and function in module openff.toolkit.typing.engines.smirnoff.plugins
"""
+
from __future__ import annotations
import pytest
diff --git a/openff/toolkit/_tests/test_parameters.py b/openff/toolkit/_tests/test_parameters.py
index 7c488f8d6..1f62befdf 100644
--- a/openff/toolkit/_tests/test_parameters.py
+++ b/openff/toolkit/_tests/test_parameters.py
@@ -2,6 +2,7 @@
Test classes and function in module openff.toolkit.typing.engines.smirnoff.parameters.
"""
+
from __future__ import annotations
from collections import defaultdict
diff --git a/openff/toolkit/_tests/test_toolkit_io.py b/openff/toolkit/_tests/test_toolkit_io.py
index 5338ce114..b86d6331f 100644
--- a/openff/toolkit/_tests/test_toolkit_io.py
+++ b/openff/toolkit/_tests/test_toolkit_io.py
@@ -2,6 +2,7 @@
Tests for I/O functionality of the toolkit wrappers
"""
+
from __future__ import annotations
import pathlib
diff --git a/openff/toolkit/_tests/test_toolkits.py b/openff/toolkit/_tests/test_toolkits.py
index 0be2d2969..1c8f8f12d 100644
--- a/openff/toolkit/_tests/test_toolkits.py
+++ b/openff/toolkit/_tests/test_toolkits.py
@@ -2,6 +2,7 @@
Tests for cheminformatics toolkit wrappers
"""
+
from __future__ import annotations
import logging
diff --git a/openff/toolkit/_tests/test_topology.py b/openff/toolkit/_tests/test_topology.py
index d652d920c..f8d8853bd 100644
--- a/openff/toolkit/_tests/test_topology.py
+++ b/openff/toolkit/_tests/test_topology.py
@@ -2,6 +2,7 @@
Tests for Topology
"""
+
from __future__ import annotations
import itertools
diff --git a/openff/toolkit/_tests/test_utils.py b/openff/toolkit/_tests/test_utils.py
index e6f0b2b1e..04d40ac00 100644
--- a/openff/toolkit/_tests/test_utils.py
+++ b/openff/toolkit/_tests/test_utils.py
@@ -2,6 +2,7 @@
Tests for utility methods
"""
+
from __future__ import annotations
import os
diff --git a/openff/toolkit/_tests/test_utils_callback.py b/openff/toolkit/_tests/test_utils_callback.py
index 90b6741b3..b3ecb045f 100644
--- a/openff/toolkit/_tests/test_utils_callback.py
+++ b/openff/toolkit/_tests/test_utils_callback.py
@@ -2,6 +2,7 @@
Tests for callback utility classes and functions.
"""
+
from __future__ import annotations
import pytest
diff --git a/openff/toolkit/_tests/test_utils_collections.py b/openff/toolkit/_tests/test_utils_collections.py
index 694018073..c5696be15 100644
--- a/openff/toolkit/_tests/test_utils_collections.py
+++ b/openff/toolkit/_tests/test_utils_collections.py
@@ -2,6 +2,7 @@
Tests for custom collections classes.
"""
+
from __future__ import annotations
import copy
diff --git a/openff/toolkit/_tests/test_utils_serialization.py b/openff/toolkit/_tests/test_utils_serialization.py
index 54cb24a21..cac0bd229 100644
--- a/openff/toolkit/_tests/test_utils_serialization.py
+++ b/openff/toolkit/_tests/test_utils_serialization.py
@@ -2,6 +2,7 @@
Tests for utility methods for serialization
"""
+
from __future__ import annotations
import numpy as np
diff --git a/openff/toolkit/_tests/utils.py b/openff/toolkit/_tests/utils.py
index 9051fded4..61b4ad0d9 100644
--- a/openff/toolkit/_tests/utils.py
+++ b/openff/toolkit/_tests/utils.py
@@ -2,6 +2,7 @@
Utilities for testing.
"""
+
from __future__ import annotations
import collections
diff --git a/openff/toolkit/topology/_mm_molecule.py b/openff/toolkit/topology/_mm_molecule.py
index 3d4d3a2a3..2161f6fb9 100644
--- a/openff/toolkit/topology/_mm_molecule.py
+++ b/openff/toolkit/topology/_mm_molecule.py
@@ -9,6 +9,7 @@
deserialize a Molecule or a TypedMolecule.
"""
+
from __future__ import annotations
import functools
diff --git a/openff/toolkit/topology/molecule.py b/openff/toolkit/topology/molecule.py
index 1c85a826b..401d2a091 100644
--- a/openff/toolkit/topology/molecule.py
+++ b/openff/toolkit/topology/molecule.py
@@ -24,6 +24,7 @@
* Speed up overall import time by putting non-global imports only where they are needed
"""
+
from __future__ import annotations
import hashlib
diff --git a/openff/toolkit/topology/topology.py b/openff/toolkit/topology/topology.py
index 3124348b2..4613f2acb 100644
--- a/openff/toolkit/topology/topology.py
+++ b/openff/toolkit/topology/topology.py
@@ -11,6 +11,7 @@
* Use `attrs `_ for object setter boilerplate?
"""
+
from __future__ import annotations
import re
diff --git a/openff/toolkit/typing/engines/smirnoff/forcefield.py b/openff/toolkit/typing/engines/smirnoff/forcefield.py
index e3c26ca64..326cfd860 100644
--- a/openff/toolkit/typing/engines/smirnoff/forcefield.py
+++ b/openff/toolkit/typing/engines/smirnoff/forcefield.py
@@ -10,6 +10,7 @@
* Speed up overall import time by putting non-global imports only where they are needed
"""
+
from __future__ import annotations
import logging
diff --git a/openff/toolkit/typing/engines/smirnoff/io.py b/openff/toolkit/typing/engines/smirnoff/io.py
index ff6e13a56..cd9e129ed 100644
--- a/openff/toolkit/typing/engines/smirnoff/io.py
+++ b/openff/toolkit/typing/engines/smirnoff/io.py
@@ -6,6 +6,7 @@
.. codeauthor:: Peter K. Eastman
"""
+
from __future__ import annotations
__all__ = [
diff --git a/openff/toolkit/typing/engines/smirnoff/parameters.py b/openff/toolkit/typing/engines/smirnoff/parameters.py
index ead8b2470..5c3151fc9 100644
--- a/openff/toolkit/typing/engines/smirnoff/parameters.py
+++ b/openff/toolkit/typing/engines/smirnoff/parameters.py
@@ -6,6 +6,7 @@
New pluggable handlers can be created by creating subclasses of :class:`ParameterHandler`.
"""
+
from __future__ import annotations
__all__ = [
diff --git a/openff/toolkit/typing/engines/smirnoff/plugins.py b/openff/toolkit/typing/engines/smirnoff/plugins.py
index 583d5acf4..91f338975 100644
--- a/openff/toolkit/typing/engines/smirnoff/plugins.py
+++ b/openff/toolkit/typing/engines/smirnoff/plugins.py
@@ -17,6 +17,7 @@
where in this example your package is named ``myapp`` and contains a class which
inherits from ``ParameterHandler`` named ``CustomHandler``.
"""
+
from __future__ import annotations
import logging
diff --git a/openff/toolkit/utils/ambertools_wrapper.py b/openff/toolkit/utils/ambertools_wrapper.py
index 22663a2a1..c4b8e8d6e 100644
--- a/openff/toolkit/utils/ambertools_wrapper.py
+++ b/openff/toolkit/utils/ambertools_wrapper.py
@@ -1,6 +1,7 @@
"""
Wrapper class providing a minimal consistent interface to `AmberTools `_.
"""
+
from __future__ import annotations
__all__ = ("AmberToolsToolkitWrapper",)
diff --git a/openff/toolkit/utils/base_wrapper.py b/openff/toolkit/utils/base_wrapper.py
index 74a836619..b423d4edb 100644
--- a/openff/toolkit/utils/base_wrapper.py
+++ b/openff/toolkit/utils/base_wrapper.py
@@ -1,6 +1,7 @@
"""
Base class for toolkit wrappers. Defines the public API and some shared methods
"""
+
from __future__ import annotations
__all__ = ("ToolkitWrapper",)
diff --git a/openff/toolkit/utils/builtin_wrapper.py b/openff/toolkit/utils/builtin_wrapper.py
index efe612db4..702f2459d 100644
--- a/openff/toolkit/utils/builtin_wrapper.py
+++ b/openff/toolkit/utils/builtin_wrapper.py
@@ -1,6 +1,7 @@
"""
Built-in ToolkitWrapper for very basic functionality. Intended for testing and not much more.
"""
+
from __future__ import annotations
__all__ = ("BuiltInToolkitWrapper",)
diff --git a/openff/toolkit/utils/callback.py b/openff/toolkit/utils/callback.py
index c6d29f74a..6dcd4fc09 100644
--- a/openff/toolkit/utils/callback.py
+++ b/openff/toolkit/utils/callback.py
@@ -2,6 +2,7 @@
Utility classes and functions to create objects supporting callback registration.
"""
+
from __future__ import annotations
__all__ = [
diff --git a/openff/toolkit/utils/collections.py b/openff/toolkit/utils/collections.py
index 2badc4f59..9338c5792 100644
--- a/openff/toolkit/utils/collections.py
+++ b/openff/toolkit/utils/collections.py
@@ -2,6 +2,7 @@
Custom collections classes.
"""
+
from __future__ import annotations
__all__ = [
diff --git a/openff/toolkit/utils/openeye_wrapper.py b/openff/toolkit/utils/openeye_wrapper.py
index ee21f8de1..33ffc2371 100644
--- a/openff/toolkit/utils/openeye_wrapper.py
+++ b/openff/toolkit/utils/openeye_wrapper.py
@@ -2,6 +2,7 @@
Wrapper class providing a minimal consistent interface to
the `OpenEye Toolkit `_
"""
+
from __future__ import annotations
__all__ = ("OpenEyeToolkitWrapper",)
diff --git a/openff/toolkit/utils/rdkit_wrapper.py b/openff/toolkit/utils/rdkit_wrapper.py
index 03fc451af..52f189fc2 100644
--- a/openff/toolkit/utils/rdkit_wrapper.py
+++ b/openff/toolkit/utils/rdkit_wrapper.py
@@ -2,6 +2,7 @@
"""
Wrapper class providing a minimal consistent interface to the `RDKit `.
"""
+
from __future__ import annotations
__all__ = ("RDKitToolkitWrapper",)
diff --git a/openff/toolkit/utils/serialization.py b/openff/toolkit/utils/serialization.py
index f3e643f84..df62c213c 100644
--- a/openff/toolkit/utils/serialization.py
+++ b/openff/toolkit/utils/serialization.py
@@ -11,6 +11,7 @@
installed?
"""
+
from __future__ import annotations
import abc
diff --git a/openff/toolkit/utils/toolkit_registry.py b/openff/toolkit/utils/toolkit_registry.py
index 47b47112a..4ddbba849 100644
--- a/openff/toolkit/utils/toolkit_registry.py
+++ b/openff/toolkit/utils/toolkit_registry.py
@@ -1,4 +1,5 @@
"Registry for ToolkitWrapper objects"
+
from __future__ import annotations
__all__ = ("ToolkitRegistry", "toolkit_registry_manager")
diff --git a/openff/toolkit/utils/toolkits.py b/openff/toolkit/utils/toolkits.py
index 3dcfc8f17..8fe3d3d22 100644
--- a/openff/toolkit/utils/toolkits.py
+++ b/openff/toolkit/utils/toolkits.py
@@ -19,6 +19,7 @@
* Change global variables from _INSTALLED to _AVAILABLE
"""
+
from __future__ import annotations
__all__ = (
diff --git a/openff/toolkit/utils/utils.py b/openff/toolkit/utils/utils.py
index 5ca01c418..9ddf6039a 100644
--- a/openff/toolkit/utils/utils.py
+++ b/openff/toolkit/utils/utils.py
@@ -2,6 +2,7 @@
Utility subroutines
"""
+
from __future__ import annotations
__all__ = [
diff --git a/pyproject.toml b/pyproject.toml
index a67ea2151..ebdd3458c 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -41,7 +41,8 @@ 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"]
+lint.isort.required-imports = [ "from __future__ import annotations" ]
+
[tool.mypy]
python_version = 3.12
warn_unused_configs = true
diff --git a/utilities/test_plugins/setup.py b/utilities/test_plugins/setup.py
index 3bdfd8926..7e04ee42b 100644
--- a/utilities/test_plugins/setup.py
+++ b/utilities/test_plugins/setup.py
@@ -2,6 +2,7 @@
openff-test-parameter-plugins
A test package used to ensure that parameterhandler plugins are handled correctly
"""
+
from __future__ import annotations
from setuptools import setup
From 1ffcb78aa65db467aecd2f2b7161156ae6736e46 Mon Sep 17 00:00:00 2001
From: Mike Henry <11765982+mikemhenry@users.noreply.github.com>
Date: Thu, 11 Jun 2026 12:02:37 -0700
Subject: [PATCH 7/7] skip openeye b/c of license issues
---
.github/workflows/CI.yml | 6 +-----
1 file changed, 1 insertion(+), 5 deletions(-)
diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml
index d52217db9..e284da347 100644
--- a/.github/workflows/CI.yml
+++ b/.github/workflows/CI.yml
@@ -25,15 +25,11 @@ jobs:
os: [ubuntu-latest, macos-latest]
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"
- - openeye: true
- python-version: "3.14"
- rdkit: false
nagl: true