diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index cd75ebf54..98db567a4 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -23,15 +23,13 @@ jobs: strategy: matrix: os: [ubuntu-latest, macos-latest] - python-version: ["3.11", "3.12", "3.13"] + python-version: ["3.12", "3.13"] rdkit: [true, false] openeye: [true, false] nagl: [true, false] exclude: - rdkit: false openeye: false - - openeye: true - python-version: "3.12" - openeye: true python-version: "3.13" - rdkit: false @@ -153,7 +151,7 @@ jobs: - name: Run notebooks in docs if: ${{ matrix.rdkit == true && matrix.openeye == true }} - run: python -m pytest -v --no-cov --nbval-lax docs/ + run: python -m pytest -v --durations=10 --no-cov --nbval-lax docs/ - name: Run examples in docstrings if: ${{ matrix.rdkit == true && matrix.openeye == true && matrix.nagl == true }} diff --git a/.github/workflows/beta_rc.yaml b/.github/workflows/beta_rc.yaml index 70c474d95..dbb7d5461 100644 --- a/.github/workflows/beta_rc.yaml +++ b/.github/workflows/beta_rc.yaml @@ -20,7 +20,7 @@ jobs: - ubuntu-latest - macos-latest python-version: - - "3.11" + - "3.12" env: OE_LICENSE: ${{ github.workspace }}/oe_license.txt diff --git a/.github/workflows/conda.yml b/.github/workflows/conda.yml index e4d9340ca..f085681cf 100644 --- a/.github/workflows/conda.yml +++ b/.github/workflows/conda.yml @@ -21,7 +21,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest, macos-latest] - python-version: ["3.11"] + python-version: ["3.12"] openeye: ["true", "false"] env: diff --git a/.github/workflows/examples.yml b/.github/workflows/examples.yml index 5a8eae0f0..0943458e7 100644 --- a/.github/workflows/examples.yml +++ b/.github/workflows/examples.yml @@ -24,7 +24,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest, macos-latest] - python-version: ["3.11", "3.12"] + python-version: [ "3.12"] rdkit: [true, false] openeye: [true, false] nagl: [true, false] diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 77b6dcb5e..acafea7e3 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -3,7 +3,7 @@ ci: files: ^pyproject.toml|openff|(^examples/((?!deprecated).)*$)|^docs|(^utilities/((?!deprecated).)*$) repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.15.9 + rev: v0.15.12 hooks: - id: ruff-format - id: ruff-check @@ -14,6 +14,6 @@ repos: - id: blacken-docs files: ^docs/.*\.(rst|md)$ - repo: https://github.com/tox-dev/pyproject-fmt - rev: v2.21.0 + rev: v2.21.1 hooks: - id: pyproject-fmt diff --git a/README.md b/README.md index 06557eca0..5c6fcf95c 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ | :------ |:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **Latest Release** | [![Last release tag](https://img.shields.io/github/release-pre/openforcefield/openff-toolkit.svg)](https://github.com/openforcefield/openff-toolkit/releases) [![Commits since release](https://img.shields.io/github/commits-since/openforcefield/openff-toolkit/0.18.0.svg)](https://github.com/openforcefield/openff-toolkit/releases/tag/0.18.0)[![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.17525527.svg)](https://doi.org/10.5281/zenodo.17525527) | **Communication** | [![docs stable](https://img.shields.io/badge/docs-stable-5077AB.svg?logo=read%20the%20docs)](https://open-forcefield-toolkit.readthedocs.io/) [![user & dev discussions](https://img.shields.io/badge/user%20%26%20dev%20discussions-GitHub-red?logo=github)](https://github.com/openforcefield/discussions/discussions) | -| **Foundation** | [![license](https://img.shields.io/github/license/openforcefield/openff-toolkit.svg)](https://opensource.org/licenses/MIT) [![platforms](https://img.shields.io/badge/Platforms-Linux%2C%20MacOS-orange.svg)](https://open-forcefield-toolkit.readthedocs.io/en/stable/installation.html) [![python](https://img.shields.io/badge/python-3.11%2C%203.12%2C%203.13-blue.svg)](https://open-forcefield-toolkit.readthedocs.io/en/stable/installation.html) [![Funding](https://img.shields.io/badge/Funding-Open%20Force%20Field%20Consortium-brightgreen.svg)](http://openforcefield.org) | +| **Foundation** | [![license](https://img.shields.io/github/license/openforcefield/openff-toolkit.svg)](https://opensource.org/licenses/MIT) [![platforms](https://img.shields.io/badge/Platforms-Linux%2C%20MacOS-orange.svg)](https://open-forcefield-toolkit.readthedocs.io/en/stable/installation.html) [![python](https://img.shields.io/badge/python-3.12%2C%203.13-blue.svg)](https://open-forcefield-toolkit.readthedocs.io/en/stable/installation.html) [![Funding](https://img.shields.io/badge/Funding-Open%20Force%20Field%20Consortium-brightgreen.svg)](http://openforcefield.org) | | **Installation** | [![Releases](https://img.shields.io/badge/obtain-latest-green.svg)](https://github.com/openforcefield/openff-toolkit/releases) [![Conda](https://img.shields.io/conda/v/conda-forge/openff-toolkit.svg)](https://anaconda.org/conda-forge/openff-toolkit) [![Last updated](https://anaconda.org/conda-forge/openff-toolkit/badges/latest_release_relative_date.svg)](https://anaconda.org/conda-forge/openff-toolkit) [![Anaconda Cloud downloads](https://anaconda.org/conda-forge/openff-toolkit/badges/downloads.svg)](https://anaconda.org/conda-forge/openff-toolkit) | # The Open Force Field toolkit diff --git a/docs/environment.yml b/docs/environment.yml index 4dedf33cb..a447a1b06 100644 --- a/docs/environment.yml +++ b/docs/environment.yml @@ -13,7 +13,7 @@ dependencies: - sphinx-notfound-page - sphinx=6 # conda build dependencies - - python <3.13 + - python =3.12 - setuptools - numpy - openmm diff --git a/docs/releasehistory.md b/docs/releasehistory.md index 9dda23083..931eed133 100644 --- a/docs/releasehistory.md +++ b/docs/releasehistory.md @@ -16,6 +16,8 @@ Releases follow the `major.minor.micro` scheme recommended by [PEP440](https://w ### Behavior changes +- [PR #2174](https://github.com/openforcefield/openff-toolkit/pull/2174): Drop support for Python 3.11 + ### Bugfixes ### New features diff --git a/docs/users/developing.md b/docs/users/developing.md index eb5c5ca89..354694028 100644 --- a/docs/users/developing.md +++ b/docs/users/developing.md @@ -427,7 +427,6 @@ Widget state can also be saved programmatically by executing the notebook with [ ## Supported Python versions The OpenFF Toolkit roughly follows [NEP 29](https://numpy.org/neps/nep-0029-deprecation_policy.html). -As of April 2023 this means Python 3.9-3.10 are officially supported (3.11 is missing some upstream dependencies). We develop, test, and distribute on macOS and Linux-based operating systems. We do not currently support Windows. Some CI builds run using only RDKit as a backend, some run using only OpenEye Toolkits, and some run using both installed at once. @@ -440,14 +439,12 @@ The CI matrix is currently as follows: +-----------------------+------------+-----------+-------------+------------+-----------+-------------+ | | RDKit | OpenEye | RDKit + OE | RDKit | OpenEye | RDKit + OE | +=======================+============+===========+=============+============+===========+=============+ -| Python 3.8 and older | No support after April 2023 | +| Python 3.11 and older | No support after April 2026 | +-----------------------+------------+-----------+-------------+------------+-----------+-------------+ -| Python 3.9 | **Test** | **Test** | **Test** | **Test** | **Test** | **Test** | +| Python 3.12 | **Test** | **Test** | **Test** | **Test** | **Test** | **Test** | +-----------------------+------------+-----------+-------------+------------+-----------+-------------+ -| Python 3.10 | **Test** | Skip | Skip | **Test** | Skip | Skip | +| Python 3.13 | **Test** | Skip | Skip | **Test** | Skip | Skip | +-----------------------+------------+-----------+-------------+------------+-----------+-------------+ -| Python 3.11 | **Test** | Skip | Skip | **Test** | Skip | Skip | -+-----------------------+------------+-----------+-------------+------------+-----------+-------------+ -| Python 3.12 and newer | Pending official releases and upstream support | +| Python 3.14 and newer | Pending official releases and upstream support | +-----------------------+------------+-----------+-------------+------------+-----------+-------------+ ``` diff --git a/openff/toolkit/topology/molecule.py b/openff/toolkit/topology/molecule.py index 076e00404..24097677c 100644 --- a/openff/toolkit/topology/molecule.py +++ b/openff/toolkit/topology/molecule.py @@ -40,7 +40,6 @@ Any, Literal, TextIO, - TypeAlias, TypeVar, Union, overload, @@ -105,8 +104,8 @@ # TODO: These aliases are duplicated in a few places, might make sense to consolidate them # into a single location, but that'd weirdly nudge them towards first-class existence -TKR: TypeAlias = ToolkitRegistry | ToolkitWrapper -MoleculeLike: TypeAlias = Union["Molecule", "FrozenMolecule", "_SimpleMolecule"] +type TKR = ToolkitRegistry | ToolkitWrapper +type MoleculeLike = "Molecule" | "FrozenMolecule" | "_SimpleMolecule" FM = TypeVar("FM", bound="FrozenMolecule") P = TypeVar("P", bound="Particle") A = TypeVar("A", bound="Atom") diff --git a/openff/toolkit/topology/topology.py b/openff/toolkit/topology/topology.py index 18c177e51..9467d350e 100644 --- a/openff/toolkit/topology/topology.py +++ b/openff/toolkit/topology/topology.py @@ -22,7 +22,6 @@ TYPE_CHECKING, Literal, TextIO, - TypeAlias, Union, ) @@ -73,11 +72,10 @@ from openff.toolkit.topology.molecule import Atom, Bond from openff.toolkit.utils import ToolkitRegistry, ToolkitWrapper -TKR: TypeAlias = Union["ToolkitRegistry", "ToolkitWrapper"] - -AtomLike: TypeAlias = Union["Atom", "_SimpleAtom"] -BondLike: TypeAlias = Union["Bond", "_SimpleBond"] -MoleculeLike: TypeAlias = Union["Molecule", "FrozenMolecule", "_SimpleMolecule"] +type TKR = ToolkitRegistry | ToolkitWrapper +type AtomLike = "Atom" | "_SimpleAtom" +type BondLike = "Bond" | "_SimpleBond" +type MoleculeLike = "Molecule" | "FrozenMolecule" | "_SimpleMolecule" _DISTANCE_UNITS = set( [ diff --git a/openff/toolkit/typing/engines/smirnoff/parameters.py b/openff/toolkit/typing/engines/smirnoff/parameters.py index e6115edc4..3ae8445ae 100644 --- a/openff/toolkit/typing/engines/smirnoff/parameters.py +++ b/openff/toolkit/typing/engines/smirnoff/parameters.py @@ -273,7 +273,7 @@ class ParameterAttribute: >>> my_par.attr_required Traceback (most recent call last): ... - AttributeError: 'MyParameter' object has no attribute '_attr_required' + AttributeError: 'MyParameter' object has no attribute '_attr_required'. Did you mean: 'attr_required'? The attribute allow automatic conversion and validation of units. diff --git a/openff/toolkit/utils/openeye_wrapper.py b/openff/toolkit/utils/openeye_wrapper.py index f33237e84..2a33c4a3e 100644 --- a/openff/toolkit/utils/openeye_wrapper.py +++ b/openff/toolkit/utils/openeye_wrapper.py @@ -19,7 +19,7 @@ import warnings from collections import defaultdict from functools import wraps -from typing import TYPE_CHECKING, Any, TypeAlias +from typing import TYPE_CHECKING, Any import numpy as np from cachetools import LRUCache, cached @@ -67,7 +67,7 @@ logger = logging.getLogger(__name__) -TTA: TypeAlias = tuple[tuple[Any, ...], ...] +type TTA = tuple[tuple[Any, ...], ...] def get_oeformat(file_format: str) -> str: diff --git a/openff/toolkit/utils/utils.py b/openff/toolkit/utils/utils.py index c6a271dd7..5cc7a6a13 100644 --- a/openff/toolkit/utils/utils.py +++ b/openff/toolkit/utils/utils.py @@ -61,7 +61,7 @@ def inherit_docstrings(cls): T = TypeVar("T") -def all_subclasses(cls: type[T]) -> list[type[T]]: +def all_subclasses[T](cls: type[T]) -> list[type[T]]: """Recursively retrieve all subclasses of the specified class""" return cls.__subclasses__() + [g for s in cls.__subclasses__() for g in all_subclasses(s)] diff --git a/pyproject.toml b/pyproject.toml index e00f4868a..5ba267c84 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -10,27 +10,25 @@ keywords = [ "force field", "molecular mechanics", "parameterization" ] license = "MIT" license-files = [ "LICENSE" ] authors = [ { name = "Open Force Field Consortium", email = "info@openforcefield.org" } ] -requires-python = ">=3.11" +requires-python = ">=3.12" classifiers = [ "Development Status :: 3 - Alpha", "Programming Language :: Python :: 3 :: Only", - "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", "Topic :: Utilities", ] - dynamic = [ "version" ] urls = { Homepage = "https://github.com/openforcefield/openff-toolkit" } -[tool.setuptools.packages.find] -include = [ 'openff.toolkit*' ] +[tool.setuptools] +packages.find.include = [ "openff.toolkit*" ] [tool.ruff] +target-version = "py312" line-length = 119 exclude = [ "examples/deprecated/", "utilities/deprecated" ] - lint.select = [ "E", "F", "I", "NPY", "RUF", "UP", "W" ] lint.ignore = [ "D105", "D107", "D200", "D203", "D212", "E721", "RUF012" ] lint.per-file-ignores."docs/users/molecule_cookbook.ipynb" = [ "E402", "F821" ] @@ -44,19 +42,6 @@ lint.isort.known-first-party = [ "openff.toolkit" ] # https://docs.astral.sh/ruff/settings/#lint_isort_known-third-party lint.isort.known-third-party = [ "openff.interchange", "openff.utilities", "openff.units" ] -[tool.coverage.run] -omit = [ - "*/*/_tests/*", -] - -[tool.coverage.report] -exclude_lines = [ - "pragma: no cover", - "if TYPE_CHECKING:", - "raise NotImplementedError", - "@overload", -] - [tool.mypy] python_version = 3.12 plugins = "numpy.typing.mypy_plugin" @@ -92,4 +77,15 @@ module = [ ] ignore_missing_imports = true +[tool.coverage] +run.omit = [ + "*/*/_tests/*", +] +report.exclude_lines = [ + "@overload", + "if TYPE_CHECKING:", + "pragma: no cover", + "raise NotImplementedError", +] + [tool.versioningit]