Search code examples
pythonpython-typing

How To Annotate an Argument That Can Be Cast As Boolean?


I'm starting to get into type hints (aka annotations) in python 3.6, and I can't figure some of the dynamic aspects of this feature.

I wrote the following piece of code, and I want to add annotation and not sure how, even after looking through the docs on type hinting.

This is the function:

def validate_expression(expression: ?):
    try:
        assert expression
    except AssertionError as e:
        ...

expression needs to be anything that an assert works on (assuming any expression for which bool(expression) is valid).

What should I write instead of the question mark?

UPDATE:

I know that most python expressions can be cast as a Boolean, but the context in which I write this code is one where it is reasonable to expect an expression to not be a assertable.

The relevant example in my case is pandas.DataFrame. Running bool(pandas.DataFrame()) raises an error, and I have good reason to expect that someone might try to pass a dataframe to the validation function.

UPDATE 2: Following Chepner's comments and answer, I understand now that:

  1. In the vast majority of cases, any python expression will have a valid casting to Boolean, and this is either covered by typing.Any or by not adding annotation at all.
  2. In the edge case I was interested in, which is bool(pandas.DataFrame()) # --> ValueError, annotations won't help since this is a runtime error.
  3. If there is another edge case that is relevant for static type hinting, I am not aware of it.
  4. Given the rarity/non-existence of a relevant example, there's no out of the box type that generically describes just the quality of the ability to be casted to boolean (similar to typing.Iterable), and as far as I'm concerned it is not worth bending over backwards to address such an edge case (although it would be interesting to hear of relevant example and a bend-y solution!)

Solution

  • Any value whatsoever can be used in a boolean context. An instance of object is considered to be a truthy value unless a descendent class provides an alternate definition; anything that is considered false (like an empty list, an empty str, an empty dict, False itself, etc) does so because it has been specially defined to be so.

    As such, the only type hint you could use is typing.Any:

    from typing import Any
    
    
    def validate_expression(expression: Any):
        try:
            assert expression
        except AssertionError as e:
            ...
    

    which, really, is barely worth stating explicitly.