diff --git a/src/jobflow/core/reference.py b/src/jobflow/core/reference.py index 0bbf2205..ab17b3df 100644 --- a/src/jobflow/core/reference.py +++ b/src/jobflow/core/reference.py @@ -8,9 +8,9 @@ from monty.json import MontyDecoder, MontyEncoder, MSONable, jsanitize from pydantic import BaseModel -from pydantic.v1.utils import lenient_issubclass from jobflow.utils.enum import ValueEnum +from jobflow.utils.types import lenient_issubclass if typing.TYPE_CHECKING: from collections.abc import Sequence diff --git a/src/jobflow/utils/types.py b/src/jobflow/utils/types.py new file mode 100644 index 00000000..86cd92cf --- /dev/null +++ b/src/jobflow/utils/types.py @@ -0,0 +1,30 @@ +"""Utilities for types.""" + +from __future__ import annotations + +from typing import Any + + +def lenient_issubclass(cls: Any, class_or_tuple: Any) -> bool: + """ + Check if a class is a subclass of another class. + + Partially inspired by pydantic.v1.utils.lenient_issubclass. + TypeError is not raised if the standard issublass fails. + + Parameters + ---------- + cls + The class to check. + class_or_tuple + The potential parent class of the class to check. + + Returns + ------- + bool + True if the class is a subclass of the target class. + """ + try: + return isinstance(cls, type) and issubclass(cls, class_or_tuple) + except TypeError: + return False diff --git a/tests/utils/test_types.py b/tests/utils/test_types.py new file mode 100644 index 00000000..37451dc1 --- /dev/null +++ b/tests/utils/test_types.py @@ -0,0 +1,17 @@ +def test_lenient_issubclass(): + from collections.abc import Mapping + + from pydantic import BaseModel + + from jobflow.core.schemas import JobStoreDocument + from jobflow.utils.types import lenient_issubclass + + assert lenient_issubclass(int, int) + assert not lenient_issubclass(str, int) + assert lenient_issubclass(JobStoreDocument, BaseModel) + + # these cases will raise errors using issubclass + assert not lenient_issubclass("test", str) + assert not lenient_issubclass(list[str], Mapping) + assert not lenient_issubclass("test", BaseModel) + assert not lenient_issubclass(str, "not_a_class")