Skip to content

Commit

Permalink
add IsTrueLike type (#25)
Browse files Browse the repository at this point in the history
* add IsTrueLike type

* tweak tests to fix for 3.7

* tweak IsFalseLike repr, fix empty strings
  • Loading branch information
samuelcolvin authored Mar 29, 2022
1 parent fff045a commit 1955762
Show file tree
Hide file tree
Showing 5 changed files with 86 additions and 21 deletions.
3 changes: 2 additions & 1 deletion dirty_equals/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from ._base import AnyThing, DirtyEquals, IsInstance, IsOneOf
from ._boolean import IsFalseLike
from ._boolean import IsFalseLike, IsTrueLike
from ._datetime import IsDate, IsDatetime, IsNow, IsToday
from ._dict import IsDict, IsIgnoreDict, IsPartialDict, IsStrictDict
from ._numeric import (
Expand Down Expand Up @@ -28,6 +28,7 @@
'IsInstance',
'IsOneOf',
# boolean
'IsTrueLike',
'IsFalseLike',
# datetime
'IsDatetime',
Expand Down
58 changes: 44 additions & 14 deletions dirty_equals/_boolean.py
Original file line number Diff line number Diff line change
@@ -1,43 +1,67 @@
from typing import Any, Optional, TypeVar
from typing import Any

from ._base import DirtyEquals
from ._utils import Omit

B = TypeVar('B')

class IsTrueLike(DirtyEquals[bool]):
"""
Check if the value is True like. `IsTrueLike` allows comparison to anything and effectively uses just
`return bool(other)`.
Example of basic usage:
class IsFalseLike(DirtyEquals[B]):
```py title="IsTrueLike"
from dirty_equals import IsTrueLike
assert True == IsTrueLike
assert 1 == IsTrueLike
assert 'true' == IsTrueLike
assert 'foobar' == IsTrueLike # any non-empty string is "True"
assert '' != IsTrueLike
assert [1] == IsTrueLike
assert {} != IsTrueLike
assert None != IsTrueLike
```
"""

def equals(self, other: Any) -> bool:
return bool(other)


class IsFalseLike(DirtyEquals[bool]):
"""
Check if the value is False like. `IsFalseLike` allows comparison to anything and effectively uses
`return not bool(other)` (with string checks if `allow_strings=True` is set).
"""

def __init__(
self,
*,
allow_strings: Optional[bool] = None,
):
def __init__(self, *, allow_strings: bool = False):
"""
Args:
allow_strings: if `True`, allow comparisons to False like strings
allow_strings: if `True`, allow comparisons to `False` like strings, case-insensitive, allows
`''`, `'false'` and any string where `float(other) == 0` (e.g. `'0'`).
Example of basic usage:
```py title="IsFalseLike"
from dirty_equals import IsFalseLike
assert 'false' == IsFalseLike(allow_strings=True)
assert 'foobar' != IsFalseLike(allow_strings=True)
assert False == IsFalseLike
assert 0 == IsFalseLike
assert 'false' == IsFalseLike(allow_strings=True)
assert '0' == IsFalseLike(allow_strings=True)
assert 'foobar' != IsFalseLike(allow_strings=True)
assert 'false' != IsFalseLike
assert 'True' != IsFalseLike(allow_strings=True)
assert [1] != IsFalseLike
assert {} == IsFalseLike
assert None == IsFalseLike
assert '' == IsFalseLike(allow_strings=True)
assert '' == IsFalseLike
```
"""
self.allow_strings: Optional[bool] = allow_strings
super().__init__(allow_strings=allow_strings)
self.allow_strings = allow_strings
super().__init__(allow_strings=allow_strings or Omit)

def equals(self, other: Any) -> bool:
if isinstance(other, str) and self.allow_strings:
Expand All @@ -46,4 +70,10 @@ def equals(self, other: Any) -> bool:

@staticmethod
def make_string_check(other: str) -> bool:
return other.lower() in {'0', '0.0', 'false'}
if other.lower() in {'false', ''}:
return True

try:
return float(other) == 0
except ValueError:
return False
2 changes: 2 additions & 0 deletions docs/types/boolean.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# Boolean Types

::: dirty_equals.IsTrueLike

::: dirty_equals.IsFalseLike
2 changes: 1 addition & 1 deletion mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,9 @@ nav:
- types/dict.md
- types/sequence.md
- types/string.md
- types/boolean.md
- types/other.md
- types/custom.md
- types/boolean.md

markdown_extensions:
- toc:
Expand Down
42 changes: 37 additions & 5 deletions tests/test_boolean.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import pytest

from dirty_equals import IsFalseLike
from dirty_equals import IsFalseLike, IsTrueLike


@pytest.mark.parametrize(
Expand All @@ -11,28 +11,36 @@
([], IsFalseLike),
([1], ~IsFalseLike),
((), IsFalseLike),
('', IsFalseLike),
('', IsFalseLike(allow_strings=True)),
((1, 2), ~IsFalseLike),
({}, IsFalseLike),
({1: 'a'}, ~IsFalseLike),
(set(), IsFalseLike),
({'a', 'b', 'c'}, ~IsFalseLike),
(None, IsFalseLike),
(object, ~IsFalseLike),
(0, IsFalseLike),
(1, ~IsFalseLike),
(0.0, IsFalseLike),
(1.0, ~IsFalseLike),
('0', IsFalseLike(allow_strings=True)),
('1', ~IsFalseLike(allow_strings=True)),
('0.0', IsFalseLike(allow_strings=True)),
('0.000', IsFalseLike(allow_strings=True)),
('1.0', ~IsFalseLike(allow_strings=True)),
('False', IsFalseLike(allow_strings=True)),
('True', ~IsFalseLike(allow_strings=True)),
(0, IsFalseLike(allow_strings=True)),
],
)
class TestIsFalseLike:
def test_dirty_equals(self, other, expected):
assert other == expected
def test_is_false_like(other, expected):
assert other == expected


def test_is_false_like_repr():
assert repr(IsFalseLike) == 'IsFalseLike'
assert repr(IsFalseLike()) == 'IsFalseLike()'
assert repr(IsFalseLike(allow_strings=True)) == 'IsFalseLike(allow_strings=True)'


def test_dirty_not_equals():
Expand All @@ -43,3 +51,27 @@ def test_dirty_not_equals():
def test_invalid_initialization():
with pytest.raises(TypeError, match='takes 1 positional argument but 2 were given'):
IsFalseLike(True)


@pytest.mark.parametrize(
'other, expected',
[
(False, ~IsTrueLike),
(True, IsTrueLike),
([], ~IsTrueLike),
([1], IsTrueLike),
((), ~IsTrueLike),
((1, 2), IsTrueLike),
({}, ~IsTrueLike),
({1: 'a'}, IsTrueLike),
(set(), ~IsTrueLike),
({'a', 'b', 'c'}, IsTrueLike),
(None, ~IsTrueLike),
(0, ~IsTrueLike),
(1, IsTrueLike),
(0.0, ~IsTrueLike),
(1.0, IsTrueLike),
],
)
def test_is_true_like(other, expected):
assert other == expected

0 comments on commit 1955762

Please sign in to comment.