Question

Pylance reports "Code is unreachable", when my test shows otherwise

Pylance claims that code under if not dfs: is unreachable and greys it out in VS Code.

import pandas as pd

def concat_dfs(dfs: tuple[pd.DataFrame | None], logger) -> pd.DataFrame | None:
    # filter out dfs that are None, if any
    dfs = [df for df in dfs if df is not None]
    
    # concatinate dfs, if any are not None:
    if not dfs:
        logger.warning("All elements of dfs are None, so no inputs remain to be analyzed") 
        return None # greyed out as unreachable
    else:
        return pd.concat(dfs).sort_index()

I tried returning dfs alone, and not pd.concat(dfs).sort_index(), as there are/were some pd.concat related bugs in Pylance.

I also tried making a little test. If Pylance is right, I would have expected not dfs = False, and it is True instead:

dfs = (None, None)
dfs = [df for df in dfs if df is not None] # dfs is an empty list
not dfs # returns True --> code should be reachable when every dataframe in dfs is None to begin with...
 3  70  3
1 Jan 1970

Solution

 2

The reachability checker does not care about the erroneous attempt to assign a list to a name statically typed as a tuple, nor does it attempt to figure out if any particular value of dfs could produce an empty list. The stated static type of dfs is tuple[pd.Dataframe | None], which only consists of singleton tuples, and all such values are truthy.

2024-07-23
chepner

Solution

 2

The reason the code is considered unreachable is that the type hint for the argument dfs is tuple[pd.DataFrame | None]. Type hints take precedence over code interpretation, and this type hint means that the tuple has one element, so not dfs can never be true. Perhaps the type you really want to express is tuple[pd.DataFrame | None, ...] (but you should avoid assigning an object of a different type than the annotation to a variable. In other words, you should not assign [df for df in dfs if df is not None], which is a list, to dfs.).

2024-07-23
marukaz