diff --git a/README.md b/README.md index f0092f6..9300da8 100644 --- a/README.md +++ b/README.md @@ -59,8 +59,7 @@ from phantom import Phantom from phantom.predicates.collection import contained -class Name(str, Phantom, predicate=contained({"Jane", "Joe"})): - ... +class Name(str, Phantom, predicate=contained({"Jane", "Joe"})): ... def greet(name: Name): diff --git a/docs/conf.py b/docs/conf.py index 1070876..cf5edbf 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -10,7 +10,7 @@ # root, use os.path.abspath to make it absolute, like shown here. sys.path.insert(0, os.path.abspath("../src")) -import phantom # noqa: E402 +import phantom current_dir = pathlib.Path(__file__).resolve().parent diff --git a/src/phantom/__init__.py b/src/phantom/__init__.py index d39bd82..a33d6f2 100644 --- a/src/phantom/__init__.py +++ b/src/phantom/__init__.py @@ -10,12 +10,12 @@ def is_big(value: int) -> bool: return value > 5 - class Big(int, Phantom, predicate=is_big): - ... + class Big(int, Phantom, predicate=is_big): ... assert isinstance(10, Big) # this passes """ + from ._base import Phantom from ._base import PhantomBase from ._base import PhantomMeta diff --git a/src/phantom/_base.py b/src/phantom/_base.py index 361de96..20c5c56 100644 --- a/src/phantom/_base.py +++ b/src/phantom/_base.py @@ -27,8 +27,7 @@ @runtime_checkable class InstanceCheckable(Protocol): - def __instancecheck__(self, instance: object) -> bool: - ... + def __instancecheck__(self, instance: object) -> bool: ... class PhantomMeta(abc.ABCMeta): @@ -73,8 +72,7 @@ def parse(cls: type[Derived], instance: object) -> Derived: @classmethod @abc.abstractmethod - def __instancecheck__(cls, instance: object) -> bool: - ... + def __instancecheck__(cls, instance: object) -> bool: ... @classmethod def __get_validators__(cls: type[Derived]) -> Iterator[Callable[[object], Derived]]: @@ -82,12 +80,10 @@ def __get_validators__(cls: type[Derived]) -> Iterator[Callable[[object], Derive yield cls.parse -class AbstractInstanceCheck(TypeError): - ... +class AbstractInstanceCheck(TypeError): ... -class MutableType(TypeError): - ... +class MutableType(TypeError): ... class Phantom(PhantomBase, Generic[T]): diff --git a/src/phantom/_utils/misc.py b/src/phantom/_utils/misc.py index 0c3eb6f..5d12e41 100644 --- a/src/phantom/_utils/misc.py +++ b/src/phantom/_utils/misc.py @@ -18,8 +18,7 @@ from typing_extensions import get_origin -class UnresolvedClassAttribute(NotImplementedError): - ... +class UnresolvedClassAttribute(NotImplementedError): ... def resolve_class_attr( @@ -125,8 +124,7 @@ def is_not_known_mutable_type(type_: BoundType) -> TypeGuard[NotKnownMutableType return not ( any(is_subtype(type_, mutable_type) for mutable_type in mutable) or ( - is_dataclass(type_) - and not type_.__dataclass_params__.frozen # type: ignore[union-attr] + is_dataclass(type_) and not type_.__dataclass_params__.frozen # type: ignore[union-attr] ) ) diff --git a/src/phantom/_utils/types.py b/src/phantom/_utils/types.py index 7cee446..a79df9d 100644 --- a/src/phantom/_utils/types.py +++ b/src/phantom/_utils/types.py @@ -10,68 +10,58 @@ @runtime_checkable class _SupportsLt(Protocol[T_contra]): - def __lt__(self, other: T_contra) -> bool: - ... + def __lt__(self, other: T_contra) -> bool: ... class SupportsLt( _SupportsLt[T_contra], Protocol[T_contra], metaclass=CachingProtocolMeta, -): - ... +): ... @runtime_checkable class _SupportsLe(Protocol[T_contra]): - def __le__(self, other: T_contra) -> bool: - ... + def __le__(self, other: T_contra) -> bool: ... class SupportsLe( _SupportsLe[T_contra], Protocol[T_contra], metaclass=CachingProtocolMeta, -): - ... +): ... @runtime_checkable class _SupportsGt(Protocol[T_contra]): - def __gt__(self, other: T_contra) -> bool: - ... + def __gt__(self, other: T_contra) -> bool: ... class SupportsGt( _SupportsGt[T_contra], Protocol[T_contra], metaclass=CachingProtocolMeta, -): - ... +): ... @runtime_checkable class _SupportsGe(Protocol[T_contra]): - def __ge__(self, other: T_contra) -> bool: - ... + def __ge__(self, other: T_contra) -> bool: ... class SupportsGe( _SupportsGe[T_contra], Protocol[T_contra], metaclass=CachingProtocolMeta, -): - ... +): ... @runtime_checkable class _SupportsEq(Protocol): - def __eq__(self, other: object) -> bool: - ... + def __eq__(self, other: object) -> bool: ... -class SupportsEq(Protocol, metaclass=CachingProtocolMeta): - ... +class SupportsEq(Protocol, metaclass=CachingProtocolMeta): ... @runtime_checkable @@ -82,78 +72,66 @@ class _Comparable( SupportsGe[T_contra], SupportsEq, Protocol[T_contra], -): - ... +): ... class Comparable( _Comparable[T_contra], Protocol[T_contra], metaclass=CachingProtocolMeta, -): - ... +): ... @runtime_checkable -class _SupportsLeGe(SupportsLe[T_contra], SupportsGe[T_contra], Protocol[T_contra]): - ... +class _SupportsLeGe(SupportsLe[T_contra], SupportsGe[T_contra], Protocol[T_contra]): ... class SupportsLeGe( _SupportsLeGe[T_contra], Protocol[T_contra], metaclass=CachingProtocolMeta, -): - ... +): ... @runtime_checkable -class _SupportsLeGt(SupportsLe[T_contra], SupportsGt[T_contra], Protocol[T_contra]): - ... +class _SupportsLeGt(SupportsLe[T_contra], SupportsGt[T_contra], Protocol[T_contra]): ... class SupportsLeGt( _SupportsLeGt[T_contra], Protocol[T_contra], metaclass=CachingProtocolMeta, -): - ... +): ... @runtime_checkable -class _SupportsLtGe(SupportsLt[T_contra], SupportsGe[T_contra], Protocol[T_contra]): - ... +class _SupportsLtGe(SupportsLt[T_contra], SupportsGe[T_contra], Protocol[T_contra]): ... class SupportsLtGe( _SupportsLtGe[T_contra], Protocol[T_contra], metaclass=CachingProtocolMeta, -): - ... +): ... -class _SupportsLtGt(SupportsLt[T_contra], SupportsGt[T_contra], Protocol[T_contra]): - ... +class _SupportsLtGt(SupportsLt[T_contra], SupportsGt[T_contra], Protocol[T_contra]): ... class SupportsLtGt( _SupportsLtGt[T_contra], Protocol[T_contra], metaclass=CachingProtocolMeta, -): - ... +): ... @runtime_checkable class _SupportsMod(Protocol[T_contra, U_co]): - def __mod__(self, other: T_contra) -> U_co: - ... + def __mod__(self, other: T_contra) -> U_co: ... class SupportsMod( _SupportsMod[T_contra, U_co], Protocol[T_contra, U_co], metaclass=CachingProtocolMeta, -): - ... +): ... diff --git a/src/phantom/boolean.py b/src/phantom/boolean.py index 5a122af..c4ba22b 100644 --- a/src/phantom/boolean.py +++ b/src/phantom/boolean.py @@ -2,6 +2,7 @@ Types describing objects that coerce to either ``True`` or ``False`` respectively when calling ``bool()`` on them. """ + from __future__ import annotations from typing import TYPE_CHECKING diff --git a/src/phantom/datetime.py b/src/phantom/datetime.py index 1852815..a8d39ff 100644 --- a/src/phantom/datetime.py +++ b/src/phantom/datetime.py @@ -7,6 +7,7 @@ You can install python-dateutil by using the ``[dateutil]`` or ``[all]`` extras. """ + from __future__ import annotations import datetime diff --git a/src/phantom/errors.py b/src/phantom/errors.py index 0e64e5a..71513fa 100644 --- a/src/phantom/errors.py +++ b/src/phantom/errors.py @@ -1,6 +1,4 @@ -class BoundError(TypeError): - ... +class BoundError(TypeError): ... -class MissingDependency(Exception): - ... +class MissingDependency(Exception): ... diff --git a/src/phantom/ext/phonenumbers.py b/src/phantom/ext/phonenumbers.py index 23444aa..edb7be4 100644 --- a/src/phantom/ext/phonenumbers.py +++ b/src/phantom/ext/phonenumbers.py @@ -7,6 +7,7 @@ $ python3 -m pip install phantom-types[phonenumbers] """ + from __future__ import annotations from typing import Final diff --git a/src/phantom/interval.py b/src/phantom/interval.py index e591c72..3ac58e2 100644 --- a/src/phantom/interval.py +++ b/src/phantom/interval.py @@ -6,8 +6,7 @@ .. code-block:: python - class VolumeLevel(int, Inclusive, low=0, high=100): - ... + class VolumeLevel(int, Inclusive, low=0, high=100): ... There is also a set of concrete ready-to-use interval types provided, that use predicate functions from :py:mod:`phantom.predicates.interval`. @@ -43,16 +42,14 @@ def take_portion(portion: Portion, whole: Natural) -> float: class IntervalCheck(Protocol): - def __call__(self, a: N, b: N) -> Predicate[N]: - ... + def __call__(self, a: N, b: N) -> Predicate[N]: ... inf: Final = float("inf") neg_inf: Final = float("-inf") -class _NonScalarBounds(Exception): - ... +class _NonScalarBounds(Exception): ... def _get_scalar_int_bounds( diff --git a/src/phantom/iso3166.py b/src/phantom/iso3166.py index 10e2e4e..aa344ee 100644 --- a/src/phantom/iso3166.py +++ b/src/phantom/iso3166.py @@ -8,6 +8,7 @@ countries: tuple[CountryCode] = ("SE", "DK", ParsedAlpha2.parse("FR")) """ + from __future__ import annotations from typing import Final @@ -292,8 +293,7 @@ is_alpha2_country_code = contained(ALPHA2) -class InvalidCountryCode(TypeError): - ... +class InvalidCountryCode(TypeError): ... def normalize_alpha2_country_code(country_code: str) -> ParsedAlpha2: diff --git a/src/phantom/negated.py b/src/phantom/negated.py index b6b8674..c729cb1 100644 --- a/src/phantom/negated.py +++ b/src/phantom/negated.py @@ -5,6 +5,7 @@ eliminate the easy mistake of forgetting to wrap a string value in a containing sequence. """ + from __future__ import annotations from collections.abc import Sequence diff --git a/src/phantom/re.py b/src/phantom/re.py index 3ba05f5..c1a2e68 100644 --- a/src/phantom/re.py +++ b/src/phantom/re.py @@ -3,12 +3,12 @@ .. code-block:: python - class Greeting(Match, pattern=r"^(Hi|Hello)"): - ... + class Greeting(Match, pattern=r"^(Hi|Hello)"): ... assert isinstance("Hello Jane!", Greeting) """ + from __future__ import annotations import re diff --git a/src/phantom/sized.py b/src/phantom/sized.py index 0719138..c1d4bd3 100644 --- a/src/phantom/sized.py +++ b/src/phantom/sized.py @@ -12,18 +12,17 @@ .. code-block:: python - class SpecificSize(PhantomBound[int], min=5, max=10): - ... + class SpecificSize(PhantomBound[int], min=5, max=10): ... This example creates a type that accepts strings with 255 or less characters: .. code-block:: python - class SizedStr(str, PhantomBound[str], max=255): - ... + class SizedStr(str, PhantomBound[str], max=255): ... """ + from __future__ import annotations from collections.abc import Iterable @@ -69,8 +68,7 @@ class SizedIterable(Sized, Iterable[T], Protocol[T]): """Intersection of :py:class:`typing.Sized` and :py:class:`typing.Iterable`.""" -class SizedIterablePhantomMeta(PhantomMeta, _ProtocolMeta): - ... +class SizedIterablePhantomMeta(PhantomMeta, _ProtocolMeta): ... class PhantomSized( @@ -109,12 +107,10 @@ def __schema__(cls) -> Schema: } -class UnresolvedBounds(Exception): - ... +class UnresolvedBounds(Exception): ... -class LSPViolation(Exception): - ... +class LSPViolation(Exception): ... class PhantomBound( diff --git a/tests/ext/test_hypothesis.py b/tests/ext/test_hypothesis.py index 49ecac2..00a03f7 100644 --- a/tests/ext/test_hypothesis.py +++ b/tests/ext/test_hypothesis.py @@ -40,26 +40,22 @@ from tests.types import IntIncExc -class TensFloat(float, InclusiveExclusive, low=10, high=20): - ... +class TensFloat(float, InclusiveExclusive, low=10, high=20): ... -class TensInt(int, InclusiveExclusive, low=10, high=20): - ... +class TensInt(int, InclusiveExclusive, low=10, high=20): ... class Url( FullMatch, pattern=r"https?://www\.[A-z]+\.(com|se|org)", -): - ... +): ... T = TypeVar("T", bound=object, covariant=True) -class Few(PhantomBound[T], Generic[T], min=5, max=15): - ... +class Few(PhantomBound[T], Generic[T], min=5, max=15): ... @total_ordering @@ -72,20 +68,16 @@ def __lt__(self, other): # Test can create types that don't map to a Hypothesis strategy. -class InmappableInc(int, Inclusive, low=Inf(), high=100): - ... +class InmappableInc(int, Inclusive, low=Inf(), high=100): ... -class InmappableExc(float, Exclusive, low=Inf(), high=100): - ... +class InmappableExc(float, Exclusive, low=Inf(), high=100): ... -class InmappableIncExc(int, InclusiveExclusive, low=Inf(), high=100): - ... +class InmappableIncExc(int, InclusiveExclusive, low=Inf(), high=100): ... -class InmappableExcInc(float, ExclusiveInclusive, low=Inf(), high=100): - ... +class InmappableExcInc(float, ExclusiveInclusive, low=Inf(), high=100): ... @dataclass diff --git a/tests/pydantic/test_schemas.py b/tests/pydantic/test_schemas.py index cebc39c..f4e146f 100644 --- a/tests/pydantic/test_schemas.py +++ b/tests/pydantic/test_schemas.py @@ -25,32 +25,25 @@ pytestmark = [pytest.mark.external] -class ExclusiveType(int, Exclusive, low=0, high=100): - ... +class ExclusiveType(int, Exclusive, low=0, high=100): ... -class InclusiveType(float, Inclusive, low=-1, high=1): - ... +class InclusiveType(float, Inclusive, low=-1, high=1): ... -class ExclusiveInclusiveType(float, ExclusiveInclusive, low=0, high=100): - ... +class ExclusiveInclusiveType(float, ExclusiveInclusive, low=0, high=100): ... -class InclusiveExclusiveType(float, InclusiveExclusive, low=-100, high=0): - ... +class InclusiveExclusiveType(float, InclusiveExclusive, low=-100, high=0): ... -class MatchType(Match, pattern=r"^[A-Z]{2}[0-9]{2}$"): - ... +class MatchType(Match, pattern=r"^[A-Z]{2}[0-9]{2}$"): ... -class FullMatchType(FullMatch, pattern=r"^[A-Z]{2}[0-9]{2}$"): - ... +class FullMatchType(FullMatch, pattern=r"^[A-Z]{2}[0-9]{2}$"): ... -class OddSize(PhantomSized[int], len=odd): - ... +class OddSize(PhantomSized[int], len=odd): ... class DataModel(pydantic.BaseModel): diff --git a/tests/test_base.py b/tests/test_base.py index 4a04102..d4bfcba 100644 --- a/tests/test_base.py +++ b/tests/test_base.py @@ -58,28 +58,22 @@ def test_raises_for_invalid_pep_604_union(self): parser("3") def test_can_parse_intersection(self): - class A: - ... + class A: ... - class B: - ... + class B: ... - class C(A, B): - ... + class C(A, B): ... parser: Parser[C] = get_bound_parser((A, B)) value = C() assert parser(value) is value def test_can_parse_union(self): - class A: - ... + class A: ... - class B: - ... + class B: ... - class C(A, B): - ... + class C(A, B): ... parser: Callable[[object], Union[A, B]] = get_bound_parser(Union[A, B]) a = A() @@ -96,69 +90,56 @@ def test_subclass_without_predicate_raises(self): UnresolvedClassAttribute, match="must define class attribute __predicate__" ): - class A(Phantom, bound=int): - ... + class A(Phantom, bound=int): ... def test_subclass_without_bound_raises(self): with pytest.raises( UnresolvedClassAttribute, match="must define class attribute __bound__" ): - class A(Phantom, predicate=positive): - ... + class A(Phantom, predicate=positive): ... def test_rejects_partial_bound(self): - class A(Phantom, predicate=positive, bound=(int, float)): - ... + class A(Phantom, predicate=positive, bound=(int, float)): ... assert not isinstance(1.0, A) def test_concrecte_subclass_of_abstract_raises_for_missing_class_attribute(self): - class A(Phantom, bound=int, abstract=True): - ... + class A(Phantom, bound=int, abstract=True): ... with pytest.raises( UnresolvedClassAttribute, match="must define class attribute __predicate__" ): - class B(A): - ... + class B(A): ... def test_can_subclass_without_predicate_if_abstract(self): - class A(Phantom, bound=int, abstract=True): - ... + class A(Phantom, bound=int, abstract=True): ... def test_can_subclass_without_bound_if_abstract(self): - class A(Phantom, predicate=positive, abstract=True): - ... + class A(Phantom, predicate=positive, abstract=True): ... def test_subclass_with_incompatible_bounds_raises(self): - class A(Phantom, bound=Union[int, float], abstract=True): - ... + class A(Phantom, bound=Union[int, float], abstract=True): ... with pytest.raises(BoundError): - class B(A, bound=str, abstract=True): - ... + class B(A, bound=str, abstract=True): ... def test_can_define_bound_implicitly(self): - class A(float, Phantom, abstract=True): - ... + class A(float, Phantom, abstract=True): ... assert A.__bound__ is float def test_can_define_bound_explicitly(self): - class A(Phantom, bound=float, abstract=True): - ... + class A(Phantom, bound=float, abstract=True): ... assert A.__bound__ is float def test_can_inherit_bound(self): - class A(Phantom, bound=float, abstract=True): - ... + class A(Phantom, bound=float, abstract=True): ... - class B(A, abstract=True): - ... + class B(A, abstract=True): ... assert B.__bound__ is float @@ -178,27 +159,22 @@ class A( bound_type, # type: ignore[misc] Phantom, abstract=True, - ): - ... + ): ... def test_can_use_frozen_dataclass_as_bound(self): @dataclass(frozen=True) - class A: - ... + class A: ... - class B(A, Phantom, predicate=boolean.true): - ... + class B(A, Phantom, predicate=boolean.true): ... def test_abstract_instance_check_raises(self): - class A(Phantom, bound=float, abstract=True): - ... + class A(Phantom, bound=float, abstract=True): ... with pytest.raises(AbstractInstanceCheck): isinstance(1, A) def test_phantom_meta_is_usable_without_phantom_base(self): - class Alt(metaclass=PhantomMeta): - ... + class Alt(metaclass=PhantomMeta): ... assert isinstance("a", Alt) is False diff --git a/tests/test_fn.py b/tests/test_fn.py index 506cfc7..2100cd4 100644 --- a/tests/test_fn.py +++ b/tests/test_fn.py @@ -23,8 +23,7 @@ class Test_name: class Nested: - def method(self): - ... + def method(self): ... @pytest.mark.parametrize( "function, expected", @@ -84,20 +83,16 @@ def test_can_compose_complex_predicate(self) -> None: assert is_valid_name("") is False -class BaseError(Exception): - ... +class BaseError(Exception): ... -class Error(BaseError): - ... +class Error(BaseError): ... -class ErrorA(Error): - ... +class ErrorA(Error): ... -class ErrorB(Error): - ... +class ErrorB(Error): ... def dummy_function(val: type[Exception]) -> None: diff --git a/tests/test_interval.py b/tests/test_interval.py index bcb07af..7a921eb 100644 --- a/tests/test_interval.py +++ b/tests/test_interval.py @@ -25,12 +25,10 @@ class TestInterval: def test_subclassing_without_check_raises(self): with pytest.raises(TypeError, match="A must define an interval check$"): - class A(Interval, abstract=False): - ... + class A(Interval, abstract=False): ... def test_parse_coerces_str(self): - class Great(int, Inclusive, low=10): - ... + class Great(int, Inclusive, low=10): ... assert Great.parse("10") == 10 @@ -41,19 +39,16 @@ class A( check=interval.exclusive, low=Decimal("1.15"), high=Decimal("2.36"), - ): - ... + ): ... assert not isinstance(2, A) assert not isinstance(1.98, A) assert isinstance(Decimal("1.98"), A) def test_subclass_inherits_bounds(self): - class A(int, Inclusive, low=-10, high=10): - ... + class A(int, Inclusive, low=-10, high=10): ... - class B(A): - ... + class B(A): ... assert B.__check__ is A.__check__ assert isinstance(-10, B) @@ -61,8 +56,7 @@ class B(A): assert not isinstance(-11, B) assert not isinstance(11, B) - class C(A, low=0): - ... + class C(A, low=0): ... assert C.__check__ is A.__check__ assert isinstance(0, C) @@ -70,8 +64,7 @@ class C(A, low=0): assert not isinstance(-1, C) assert not isinstance(11, C) - class D(A, high=0): - ... + class D(A, high=0): ... assert D.__check__ is A.__check__ assert isinstance(-10, D) @@ -189,8 +182,7 @@ def __eq__(self, other): def __lt__(self, other): return False - class Int(int, Inclusive, low=Inf(), high=100): - ... + class Int(int, Inclusive, low=Inf(), high=100): ... with pytest.raises(_NonScalarBounds): _get_scalar_int_bounds(Int) @@ -204,8 +196,7 @@ def __eq__(self, other): def __lt__(self, other): return False - class Int(int, Inclusive, low=0, high=Inf()): - ... + class Int(int, Inclusive, low=0, high=Inf()): ... with pytest.raises(_NonScalarBounds): _get_scalar_int_bounds(Int) @@ -240,8 +231,7 @@ def __eq__(self, other): def __lt__(self, other): return False - class Int(float, Inclusive, low=Inf(), high=100): - ... + class Int(float, Inclusive, low=Inf(), high=100): ... with pytest.raises(_NonScalarBounds): _get_scalar_float_bounds(Int) @@ -255,8 +245,7 @@ def __eq__(self, other): def __lt__(self, other): return False - class Int(float, Inclusive, low=0, high=Inf()): - ... + class Int(float, Inclusive, low=0, high=Inf()): ... with pytest.raises(_NonScalarBounds): _get_scalar_float_bounds(Int) diff --git a/tests/test_re.py b/tests/test_re.py index eed5c3d..6333d38 100644 --- a/tests/test_re.py +++ b/tests/test_re.py @@ -8,12 +8,10 @@ from phantom.re import Match -class MatchPatternInstance(Match, pattern=re.compile(r"abc")): - ... +class MatchPatternInstance(Match, pattern=re.compile(r"abc")): ... -class MatchPatternStr(Match, pattern=r"abc"): - ... +class MatchPatternStr(Match, pattern=r"abc"): ... parametrize_match = pytest.mark.parametrize( @@ -43,12 +41,10 @@ def test_instantiation_returns_instance(self, match_type: type[Match]): assert s is match_type.parse(s) -class FullMatchPatternInstance(FullMatch, pattern=re.compile(r"abc")): - ... +class FullMatchPatternInstance(FullMatch, pattern=re.compile(r"abc")): ... -class FullMatchStr(FullMatch, pattern=r"abc"): - ... +class FullMatchStr(FullMatch, pattern=r"abc"): ... parametrize_full_match = pytest.mark.parametrize( diff --git a/tests/test_sized.py b/tests/test_sized.py index 2864a0d..a5ef421 100644 --- a/tests/test_sized.py +++ b/tests/test_sized.py @@ -39,8 +39,7 @@ class MutableDataclass: T = TypeVar("T") -class OddSize(PhantomSized[T], Generic[T], len=odd): - ... +class OddSize(PhantomSized[T], Generic[T], len=odd): ... class TestPhantomSized: @@ -94,8 +93,7 @@ def test_subscription_returns_type_alias(self): assert arg is tuple -class Tens(PhantomBound[T], Generic[T], min=10, max=19): - ... +class Tens(PhantomBound[T], Generic[T], min=10, max=19): ... class TestPhantomBound: @@ -139,18 +137,15 @@ def test_subscription_returns_type_alias(self): def test_raises_lsp_violation_when_attempting_to_decrease_min(self): with pytest.raises(LSPViolation): - class Lower(Tens, min=9): - ... + class Lower(Tens, min=9): ... def test_raises_lsp_violation_when_attempting_to_increase_max(self): with pytest.raises(LSPViolation): - class Higher(Tens, max=20): - ... + class Higher(Tens, max=20): ... def test_can_narrow_range_in_subclass(self): - class Fewer(Tens, min=11, max=18): - ... + class Fewer(Tens, min=11, max=18): ... assert isinstance(11 * (0,), Fewer) assert isinstance(18 * (0,), Fewer) @@ -158,11 +153,9 @@ class Fewer(Tens, min=11, max=18): assert not isinstance(19 * (0,), Fewer) def test_abstract_subclass_can_omit_bounds(self): - class A(PhantomBound, abstract=True): - ... + class A(PhantomBound, abstract=True): ... - class B(A, min=10, max=20): - ... + class B(A, min=10, max=20): ... assert B.__min__ == 10 assert B.__max__ == 20 @@ -170,8 +163,7 @@ class B(A, min=10, max=20): def test_raises_unresolved_bounds_when_concrete_subclass_omits_bounds(self): with pytest.raises(UnresolvedBounds): - class A(PhantomBound): - ... + class A(PhantomBound): ... class TestNonEmpty: diff --git a/tests/test_utils.py b/tests/test_utils.py index 878e785..0343751 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -6,24 +6,19 @@ from phantom._utils.misc import is_subtype -class A: - ... +class A: ... -class B: - ... +class B: ... -class C: - ... +class C: ... -class AAndB(A, B): - ... +class AAndB(A, B): ... -class SubOfA(A): - ... +class SubOfA(A): ... class TestIsSubtype: diff --git a/tests/types.py b/tests/types.py index ccc7819..d0562ad 100644 --- a/tests/types.py +++ b/tests/types.py @@ -4,33 +4,25 @@ from phantom.interval import InclusiveExclusive -class FloatInc(float, Inclusive, low=0, high=100): - ... +class FloatInc(float, Inclusive, low=0, high=100): ... -class IntInc(int, Inclusive, low=0, high=100): - ... +class IntInc(int, Inclusive, low=0, high=100): ... -class FloatExc(float, Exclusive, low=0, high=100): - ... +class FloatExc(float, Exclusive, low=0, high=100): ... -class IntExc(int, Exclusive, low=0, high=100): - ... +class IntExc(int, Exclusive, low=0, high=100): ... -class FloatIncExc(float, InclusiveExclusive, low=0, high=100): - ... +class FloatIncExc(float, InclusiveExclusive, low=0, high=100): ... -class IntIncExc(int, InclusiveExclusive, low=0, high=100): - ... +class IntIncExc(int, InclusiveExclusive, low=0, high=100): ... -class FloatExcInc(float, ExclusiveInclusive, low=0, high=100): - ... +class FloatExcInc(float, ExclusiveInclusive, low=0, high=100): ... -class IntExcInc(int, ExclusiveInclusive, low=0, high=100): - ... +class IntExcInc(int, ExclusiveInclusive, low=0, high=100): ...