From aed4c44d8eb30b2519ebe9941ae28ba2ef6e5c69 Mon Sep 17 00:00:00 2001 From: Matt Thompson Date: Fri, 11 Aug 2023 12:59:40 -0500 Subject: [PATCH] Support Pydantic v1 and v2 (#752) Co-authored-by: Co Quach <43968221+daico007@users.noreply.github.com> --- .github/workflows/CI.yaml | 5 ++++- environment-dev.yml | 2 +- environment.yml | 2 +- gmso/abc/abstract_connection.py | 7 +++++-- gmso/abc/abstract_potential.py | 7 +++++-- gmso/abc/abstract_site.py | 6 +++++- gmso/abc/auto_doc.py | 5 ++++- gmso/abc/gmso_base.py | 10 +++++++--- gmso/core/angle.py | 7 +++++-- gmso/core/angle_type.py | 6 +++++- gmso/core/atom.py | 6 +++++- gmso/core/atom_type.py | 6 +++++- gmso/core/bond.py | 7 +++++-- gmso/core/bond_type.py | 6 +++++- gmso/core/dihedral.py | 7 +++++-- gmso/core/dihedral_type.py | 6 +++++- gmso/core/element.py | 6 +++++- gmso/core/improper.py | 7 +++++-- gmso/core/improper_type.py | 6 +++++- gmso/core/pairpotential_type.py | 6 +++++- gmso/lib/potential_templates.py | 6 +++++- gmso/parameterization/topology_parameterizer.py | 6 +++++- gmso/tests/test_angle.py | 6 +++++- gmso/tests/test_atom.py | 6 +++++- gmso/tests/test_bond.py | 6 +++++- gmso/tests/test_dihedral.py | 6 +++++- gmso/tests/test_improper.py | 6 +++++- 27 files changed, 127 insertions(+), 35 deletions(-) diff --git a/.github/workflows/CI.yaml b/.github/workflows/CI.yaml index 1be91dcbd..7c7dfdb76 100644 --- a/.github/workflows/CI.yaml +++ b/.github/workflows/CI.yaml @@ -20,6 +20,7 @@ jobs: matrix: os: [macOS-latest, ubuntu-latest] python-version: ["3.8", "3.9", "3.10", "3.11"] + pydantic-version: ["1", "2"] defaults: run: @@ -33,7 +34,9 @@ jobs: uses: mamba-org/setup-micromamba@v1 with: environment-file: environment-dev.yml - python-version: python=${{ matrix.python-version }} + create-args: >- + python=${{ matrix.python-version }} + pydantic=${{ matrix.pydantic-version }} - name: Install Package run: python -m pip install -e . diff --git a/environment-dev.yml b/environment-dev.yml index 0286bbb67..e5a88244f 100644 --- a/environment-dev.yml +++ b/environment-dev.yml @@ -9,7 +9,7 @@ dependencies: - unyt<=2.9.2 - boltons - lxml - - pydantic=1.10.11 + - pydantic - networkx - pytest - mbuild>=0.11.0 diff --git a/environment.yml b/environment.yml index c7ef337f2..9f9f70b54 100644 --- a/environment.yml +++ b/environment.yml @@ -9,7 +9,7 @@ dependencies: - unyt<=2.9.2 - boltons - lxml - - pydantic=1.10.11 + - pydantic - networkx - ele>=0.2.0 - foyer>=0.11.3 diff --git a/gmso/abc/abstract_connection.py b/gmso/abc/abstract_connection.py index ef8bd4e06..69f96f983 100644 --- a/gmso/abc/abstract_connection.py +++ b/gmso/abc/abstract_connection.py @@ -1,11 +1,14 @@ from typing import Optional, Sequence -from pydantic import Field, root_validator - from gmso.abc.abstract_site import Site from gmso.abc.gmso_base import GMSOBase from gmso.exceptions import GMSOError +try: + from pydantic.v1 import Field, root_validator +except ImportError: + from pydantic import Field, root_validator + class Connection(GMSOBase): __base_doc__ = """An abstract class that stores data about connections between sites. diff --git a/gmso/abc/abstract_potential.py b/gmso/abc/abstract_potential.py index 4ab1febee..673519e0d 100644 --- a/gmso/abc/abstract_potential.py +++ b/gmso/abc/abstract_potential.py @@ -2,11 +2,14 @@ from abc import abstractmethod from typing import Any, Dict, Iterator, List -from pydantic import Field, validator - from gmso.abc.gmso_base import GMSOBase from gmso.utils.expression import PotentialExpression +try: + from pydantic.v1 import Field, validator +except ImportError: + from pydantic import Field, validator + class AbstractPotential(GMSOBase): __base_doc__ = """An abstract potential class. diff --git a/gmso/abc/abstract_site.py b/gmso/abc/abstract_site.py index 3ea20c829..0234446ae 100644 --- a/gmso/abc/abstract_site.py +++ b/gmso/abc/abstract_site.py @@ -4,12 +4,16 @@ import numpy as np import unyt as u -from pydantic import Field, StrictInt, StrictStr, validator from unyt.exceptions import InvalidUnitOperation from gmso.abc.gmso_base import GMSOBase from gmso.exceptions import GMSOError +try: + from pydantic.v1 import Field, StrictInt, StrictStr, validator +except ImportError: + from pydantic import Field, StrictInt, StrictStr, validator + PositionType = Union[Sequence[float], np.ndarray, u.unyt_array] MoleculeType = NamedTuple("Molecule", name=StrictStr, number=StrictInt) ResidueType = NamedTuple("Residue", name=StrictStr, number=StrictInt) diff --git a/gmso/abc/auto_doc.py b/gmso/abc/auto_doc.py index 325f08cf5..3a9634ed6 100644 --- a/gmso/abc/auto_doc.py +++ b/gmso/abc/auto_doc.py @@ -4,7 +4,10 @@ from copy import deepcopy from typing import Any, Dict, List, Optional, Tuple, Type, Union -from pydantic import BaseModel +try: + from pydantic.v1 import BaseModel +except ImportError: + from pydantic import BaseModel BASE_DOC_ATTR = "__base_doc__" FIELDS_IN_DOCSTRING = "__alias_to_fields__" diff --git a/gmso/abc/gmso_base.py b/gmso/abc/gmso_base.py index 63543f67f..3cdc30952 100644 --- a/gmso/abc/gmso_base.py +++ b/gmso/abc/gmso_base.py @@ -4,13 +4,17 @@ from abc import ABC from typing import Any, ClassVar, Type -from pydantic import BaseModel -from pydantic.validators import dict_validator - from gmso.abc import GMSOJSONHandler from gmso.abc.auto_doc import apply_docs from gmso.abc.serialization_utils import dict_to_unyt +try: + from pydantic.v1 import BaseModel + from pydantic.v1.validators import dict_validator +except ImportError: + from pydantic import BaseModel + from pydantic.validators import dict_validator + class GMSOBase(BaseModel, ABC): """A BaseClass to all abstract classes in GMSO.""" diff --git a/gmso/core/angle.py b/gmso/core/angle.py index 17e62ba09..69a9f32f1 100644 --- a/gmso/core/angle.py +++ b/gmso/core/angle.py @@ -1,12 +1,15 @@ """Support for 3-partner connections between gmso.core.Atoms.""" from typing import Callable, ClassVar, Optional, Tuple -from pydantic import Field - from gmso.abc.abstract_connection import Connection from gmso.core.angle_type import AngleType from gmso.core.atom import Atom +try: + from pydantic.v1 import Field +except ImportError: + from pydantic import Field + class Angle(Connection): __base_doc__ = """A 3-partner connection between Atoms. diff --git a/gmso/core/angle_type.py b/gmso/core/angle_type.py index 0fa53df58..9c75dfbff 100644 --- a/gmso/core/angle_type.py +++ b/gmso/core/angle_type.py @@ -1,11 +1,15 @@ from typing import Optional, Tuple import unyt as u -from pydantic import Field from gmso.core.parametric_potential import ParametricPotential from gmso.utils.expression import PotentialExpression +try: + from pydantic.v1 import Field +except ImportError: + from pydantic import Field + class AngleType(ParametricPotential): __base_doc__ = """A descripton of the interaction between 3 bonded partners. diff --git a/gmso/core/atom.py b/gmso/core/atom.py index c2bc71397..3e09c931e 100644 --- a/gmso/core/atom.py +++ b/gmso/core/atom.py @@ -3,7 +3,6 @@ from typing import Optional, Union import unyt as u -from pydantic import Field, validator from gmso.abc.abstract_site import Site from gmso.core.atom_type import AtomType @@ -11,6 +10,11 @@ from gmso.utils._constants import UNIT_WARNING_STRING from gmso.utils.misc import ensure_valid_dimensions +try: + from pydantic.v1 import Field, validator +except ImportError: + from pydantic import Field, validator + class Atom(Site): __base_doc__ = """An atom represents a single element association in a topology. diff --git a/gmso/core/atom_type.py b/gmso/core/atom_type.py index cdee3bd80..7f9f326bb 100644 --- a/gmso/core/atom_type.py +++ b/gmso/core/atom_type.py @@ -3,7 +3,6 @@ from typing import Optional, Set import unyt as u -from pydantic import Field, validator from gmso.core.parametric_potential import ParametricPotential from gmso.utils._constants import UNIT_WARNING_STRING @@ -14,6 +13,11 @@ unyt_to_hashable, ) +try: + from pydantic.v1 import Field, validator +except ImportError: + from pydantic import Field, validator + class AtomType(ParametricPotential): __base_doc__ = """A description of non-bonded interactions between sites. diff --git a/gmso/core/bond.py b/gmso/core/bond.py index 23dd7fe4e..7b4ddca83 100644 --- a/gmso/core/bond.py +++ b/gmso/core/bond.py @@ -1,12 +1,15 @@ """Module for 2-partner connections between sites.""" from typing import Callable, ClassVar, Optional, Tuple -from pydantic import Field - from gmso.abc.abstract_connection import Connection from gmso.core.atom import Atom from gmso.core.bond_type import BondType +try: + from pydantic.v1 import Field +except ImportError: + from pydantic import Field + class Bond(Connection): __base_doc__ = """A 2-partner connection between sites. diff --git a/gmso/core/bond_type.py b/gmso/core/bond_type.py index ed6a367a4..98c08c099 100644 --- a/gmso/core/bond_type.py +++ b/gmso/core/bond_type.py @@ -2,11 +2,15 @@ from typing import Optional, Tuple import unyt as u -from pydantic import Field from gmso.core.parametric_potential import ParametricPotential from gmso.utils.expression import PotentialExpression +try: + from pydantic.v1 import Field +except ImportError: + from pydantic import Field + class BondType(ParametricPotential): __base_doc__ = """A descripton of the interaction between 2 bonded partners. diff --git a/gmso/core/dihedral.py b/gmso/core/dihedral.py index 97859bc52..22c56fa05 100644 --- a/gmso/core/dihedral.py +++ b/gmso/core/dihedral.py @@ -1,11 +1,14 @@ from typing import Callable, ClassVar, Optional, Tuple -from pydantic import Field - from gmso.abc.abstract_connection import Connection from gmso.core.atom import Atom from gmso.core.dihedral_type import DihedralType +try: + from pydantic.v1 import Field +except ImportError: + from pydantic import Field + class Dihedral(Connection): __base_doc__ = """A 4-partner connection between sites. diff --git a/gmso/core/dihedral_type.py b/gmso/core/dihedral_type.py index 4740136cc..6096c4d46 100644 --- a/gmso/core/dihedral_type.py +++ b/gmso/core/dihedral_type.py @@ -1,11 +1,15 @@ from typing import Optional, Tuple import unyt as u -from pydantic import Field from gmso.core.parametric_potential import ParametricPotential from gmso.utils.expression import PotentialExpression +try: + from pydantic.v1 import Field +except ImportError: + from pydantic import Field + class DihedralType(ParametricPotential): __base_doc__ = """A descripton of the interaction between 4 bonded partners. diff --git a/gmso/core/element.py b/gmso/core/element.py index 5f13c3033..ccb3fed11 100644 --- a/gmso/core/element.py +++ b/gmso/core/element.py @@ -6,12 +6,16 @@ import numpy as np import unyt as u from pkg_resources import resource_filename -from pydantic import Field from gmso.abc.gmso_base import GMSOBase from gmso.exceptions import GMSOError from gmso.utils.misc import unyt_to_hashable +try: + from pydantic.v1 import Field +except ImportError: + from pydantic import Field + exported = [ "element_by_mass", "element_by_symbol", diff --git a/gmso/core/improper.py b/gmso/core/improper.py index 129c3da37..15c88ee98 100644 --- a/gmso/core/improper.py +++ b/gmso/core/improper.py @@ -1,12 +1,15 @@ """Support for improper style connections (4-member connection).""" from typing import Callable, ClassVar, Optional, Tuple -from pydantic import Field - from gmso.abc.abstract_connection import Connection from gmso.core.atom import Atom from gmso.core.improper_type import ImproperType +try: + from pydantic.v1 import Field +except ImportError: + from pydantic import Field + class Improper(Connection): __base_doc__ = """sA 4-partner connection between sites. diff --git a/gmso/core/improper_type.py b/gmso/core/improper_type.py index b579bbd96..3cb3ebb59 100644 --- a/gmso/core/improper_type.py +++ b/gmso/core/improper_type.py @@ -2,11 +2,15 @@ from typing import Optional, Tuple import unyt as u -from pydantic import Field from gmso.core.parametric_potential import ParametricPotential from gmso.utils.expression import PotentialExpression +try: + from pydantic.v1 import Field +except ImportError: + from pydantic import Field + class ImproperType(ParametricPotential): __base_doc__ = """A description of the interaction between 4 bonded partners. diff --git a/gmso/core/pairpotential_type.py b/gmso/core/pairpotential_type.py index 307e9c429..38b992396 100644 --- a/gmso/core/pairpotential_type.py +++ b/gmso/core/pairpotential_type.py @@ -1,11 +1,15 @@ from typing import Optional, Tuple import unyt as u -from pydantic import Field from gmso.core.parametric_potential import ParametricPotential from gmso.utils.expression import PotentialExpression +try: + from pydantic.v1 import Field +except ImportError: + from pydantic import Field + class PairPotentialType(ParametricPotential): __base_doc__ = """A description of custom pairwise potential between 2 AtomTypes that does not follow combination rule. diff --git a/gmso/lib/potential_templates.py b/gmso/lib/potential_templates.py index 1e29c63ad..a3ad09e4b 100644 --- a/gmso/lib/potential_templates.py +++ b/gmso/lib/potential_templates.py @@ -5,7 +5,6 @@ import sympy import unyt as u -from pydantic import Field, validator from gmso.abc.abstract_potential import AbstractPotential from gmso.exceptions import ( @@ -16,6 +15,11 @@ from gmso.utils.expression import PotentialExpression from gmso.utils.singleton import Singleton +try: + from pydantic.v1 import Field, validator +except ImportError: + from pydantic import Field, validator + POTENTIAL_JSONS = list(Path(__file__).parent.glob("jsons/*.json")) JSON_DIR = Path.joinpath(Path(__file__).parent, "jsons") diff --git a/gmso/parameterization/topology_parameterizer.py b/gmso/parameterization/topology_parameterizer.py index 381165015..b33df3d61 100644 --- a/gmso/parameterization/topology_parameterizer.py +++ b/gmso/parameterization/topology_parameterizer.py @@ -5,7 +5,6 @@ import networkx as nx from boltons.setutils import IndexedSet -from pydantic import Field from gmso.abc.gmso_base import GMSOBase from gmso.core.forcefield import ForceField @@ -29,6 +28,11 @@ ) from gmso.parameterization.utils import POTENTIAL_GROUPS +try: + from pydantic.v1 import Field +except ImportError: + from pydantic import Field + class ParameterizationError(GMSOError): """Raise when parameterization fails.""" diff --git a/gmso/tests/test_angle.py b/gmso/tests/test_angle.py index d60098a44..25693cebe 100644 --- a/gmso/tests/test_angle.py +++ b/gmso/tests/test_angle.py @@ -1,5 +1,4 @@ import pytest -from pydantic import ValidationError from gmso.core.angle import Angle from gmso.core.angle_type import AngleType @@ -8,6 +7,11 @@ from gmso.core.topology import Topology from gmso.tests.base_test import BaseTest +try: + from pydantic.v1 import ValidationError +except ImportError: + from pydantic import ValidationError + class TestAngle(BaseTest): def test_angle_nonparametrized(self): diff --git a/gmso/tests/test_atom.py b/gmso/tests/test_atom.py index a0f39c392..c32faa928 100644 --- a/gmso/tests/test_atom.py +++ b/gmso/tests/test_atom.py @@ -1,7 +1,6 @@ import numpy as np import pytest import unyt as u -from pydantic import ValidationError from gmso.core.atom import Atom from gmso.core.atom_type import AtomType @@ -9,6 +8,11 @@ from gmso.exceptions import GMSOError from gmso.tests.base_test import BaseTest +try: + from pydantic.v1 import ValidationError +except ImportError: + from pydantic import ValidationError + class TestSite(BaseTest): def test_new_site(self): diff --git a/gmso/tests/test_bond.py b/gmso/tests/test_bond.py index 20ab40b96..373d544dd 100644 --- a/gmso/tests/test_bond.py +++ b/gmso/tests/test_bond.py @@ -1,5 +1,4 @@ import pytest -from pydantic import ValidationError from gmso.core.atom import Atom from gmso.core.atom_type import AtomType @@ -8,6 +7,11 @@ from gmso.core.topology import Topology from gmso.tests.base_test import BaseTest +try: + from pydantic.v1 import ValidationError +except ImportError: + from pydantic import ValidationError + class TestBond(BaseTest): def test_bond_nonparametrized(self): diff --git a/gmso/tests/test_dihedral.py b/gmso/tests/test_dihedral.py index b2aefb721..13e2ad45d 100644 --- a/gmso/tests/test_dihedral.py +++ b/gmso/tests/test_dihedral.py @@ -1,5 +1,4 @@ import pytest -from pydantic import ValidationError from gmso.core.atom import Atom from gmso.core.atom_type import AtomType @@ -8,6 +7,11 @@ from gmso.core.topology import Topology from gmso.tests.base_test import BaseTest +try: + from pydantic.v1 import ValidationError +except ImportError: + from pydantic import ValidationError + class TestDihedral(BaseTest): def test_dihedral_nonparametrized(self): diff --git a/gmso/tests/test_improper.py b/gmso/tests/test_improper.py index a853391d5..4188b444a 100644 --- a/gmso/tests/test_improper.py +++ b/gmso/tests/test_improper.py @@ -1,5 +1,4 @@ import pytest -from pydantic import ValidationError from gmso.core.atom import Atom from gmso.core.atom_type import AtomType @@ -8,6 +7,11 @@ from gmso.core.topology import Topology from gmso.tests.base_test import BaseTest +try: + from pydantic.v1 import ValidationError +except ImportError: + from pydantic import ValidationError + class TestImproper(BaseTest): def test_improper_nonparametrized(self):