1

I would like to assert that an expression equals some boolean value:

assert result['foo'][0] == False
assert result['foo'][1] == True

However, pylint suggests to use is or 'not' instead of ==:

Comparison 'result['foo'][0] == True' should be 'result['foo'][0] is True' if checking for the singleton value False, or 'not result['a'][0]' if testing for falsiness (singleton-comparison)

If I use 'is' the test fails.

If I use 'not' I find the expression harder to read/interpret because it seems to be less explicit:

assert not result['foo'][0]
assert result['foo'][1]

a) Is the last way really the best practice to assert boolean expressions and I should get used to it?

b) Or should I disable the warning?

c) Or should I use something like

assertIsFalse(result['foo'][0])
assertIsTrue(result['foo'][1])

or

assert falsy(result['foo'][0])
assert truthy(result['foo'][1])

Further notes:

  1. The pytest documentation does not seem to have a recommendation on how to assert boolean values:

https://docs.pytest.org/en/7.1.x/how-to/assert.html

  1. Pytest does not seem to provide extra assertion methods like assertIsTrue or truthy:

https://docs.pytest.org/en/4.6.x/reference.html#functions

  1. Unittest provides methods assertTrue, assertFalse. However, that would require to derive from the unittest class.

https://www.pythontutorial.net/python-unit-testing/python-asserttrue/

  1. Numpy does not seem to include assertion methods for boolean values:

https://numpy.org/devdocs/reference/routines.testing.html#asserts

Stefan
  • 10,010
  • 7
  • 61
  • 117
  • Are you sure that `result['foo'][0]` is boolean `False`? It seems to me that it might be `0` which is why `==` comparison would succeed but `is` comparison would fail. – tmt Jan 27 '23 at 09:15
  • Yes result['a'][0] Out[4]: False type(result['a'][0]) Out[5]: numpy.bool_ – Stefan Jan 27 '23 at 09:21
  • 1
    Hmm, `numpy.bool`... see https://github.com/numpy/numpy/issues/5942 and https://stackoverflow.com/questions/55905690/how-exactly-does-the-behavior-of-python-bool-and-numpy-bool-differ – tmt Jan 27 '23 at 09:27
  • Maybe then the pylint warning should be adapted to not be shown for assertion or more specific if used for numpy.bool_ (if that is possible): https://github.com/PyCQA/pylint/issues/8117 – Stefan Jan 27 '23 at 10:29
  • No, I don't think it's up to pylint to understand that you in fact do not want to be comparing to Python's built-in `False`. Unfortunately, I'm not familiar with numpy so I don't think I can give you a good recommendation what to do. However, I do know it's not option *c)*. Also, *Pytest does not seem to provide extra assertion methods like assertIsTrue or truthy:* - no because that's what `assert result['foo'][1]` does. – tmt Jan 27 '23 at 10:42

2 Answers2

1

I wrote some custom helper functions to improve readability, based on the built in bool() function:

def truthy(value):
    return bool(value)


def falsy(value):
    return not bool(value)

usage:

assert falsy(result['foo'][0])
assert truthy(result['foo'][1])

https://www.geeksforgeeks.org/truthy-vs-falsy-values-in-python/

Stefan
  • 10,010
  • 7
  • 61
  • 117
  • 1
    IMHO, this is equivalent to `assert bool(result['foo'][0]) is False` and `assert not result['foo'][0]`, and as such is rather pointless. – tmt Jan 27 '23 at 10:47
  • So you vote for option a) :) – Stefan Jan 27 '23 at 10:48
  • Not necessarily because I don't know how exact you want to be. `assert result['foo'][0]` checks for truthiness which means other types would pass too, e.g. `assert [1]`. If you want to check for a numpy's boolean, then you should probably do `assert result['foo'][0] == XXX` where `XXX` is numpy's `True`/`False`, whatever way that is created/imported in numpy's world. This way pylint probably wouldn't make that suggestion to change it to `is` comparison. – tmt Jan 27 '23 at 11:57
0

pytest is using assertion directly so you don't have to learn about function names and existence and directly use what the language offer and display error nicely. So, if you want to test for falsyness/trutheyness with pytest you do this::

assert not result['foo'][0]
assert result['foo'][1]

If you want to check that something is literally False or True then you do this::

assert result['foo'][0] is False
assert result['foo'][1] is True

Creating a function that does something that already exists in python because you're not familiar with it, is not a good practice. Use the tools of the language everyone familiar with python is already using. Otherwise reading your codebase will have a cost of entry for things that you invented and that no one is familiar with.

Pierre.Sassoulas
  • 3,733
  • 3
  • 33
  • 48