Search code examples
pythonmypynonetype

Appease mypy where None is type hinted and other operands are used


I have 2 pieces of code where default values could be None, but the None values are caught before the operation (>) or iteration of a list. Mypy is still producing an error message despite the fact that I can't see how None could get through in either case.

def plot_columns(df: pd.DataFrame, columns: list[str] | None = None):
    if not columns:
        columns = df.columns

    for col in columns:
        plt.plot(df[col])
def function_2(tup: tuple[float | int | None, float | int | None]) -> bool:
    assert len(tup) == 2

    if all(tup):  # Also tried: if tup.count(None) == 0
        return tup[0] > tup[1]

    return False

In both cases mypy throws errors

first: Item "None" of "Optional[List[str]]" has no attribute "__iter__" (not iterable) [union-attr]

second (multiple similar errors): Unsupported operand types for > ("float" and "None") [operator]

Is there a better way to write these or a more pythonic way to do it? Or should I just ignore mypy on this one?

Edit: Appeased the first one by making it an empty list.


Solution

  • For the first one, pandas itself doesn't seem to have typed df.columns so that you can tell statically that the value is not None. Try

    def plot_columns(df: pd.DataFrame, columns: list[str] | None = None):
        if not columns:
            columns = cast(list[str], df.columns)
        ...
    

    For the second one, all(tup) doesn't seem to be on mypy's list of recognized forms for type narrowing. (Or, type narrowing lets you narrow the type of tup itself, not the elements of tup.) Be more explicit:

    def function_2(tup: tuple[float | int | None, float | int | None]) -> bool:
        
        assert len(tup) == 2
    
        a, b = tup
    
        if a is None or b is None:
            return False
    
        returnn a > b