-1

Does anyone have any idea why MyPy is complaining about this? It is extremely frustrating because it works if it's a ternary but not if in a standard if/else:

from typing import List, Optional, Union

def get_relevant_params() -> List[str]:
    return sorted(list(set(['1', '2', '3'])))

# also doesn't work with: ... -> Union[List[str], None]
def get_config(config_path: Optional[str] = None) -> Optional[List[str]]:
    
    # this doesn't work
    if config_path:
        read_cols = get_relevant_params()
    else:
        read_cols = None
        
    # # this works
    # read_cols = get_relevant_params() if config_path else None

    return read_cols

Here is an interactive MyPy playground with the example: https://mypy-play.net/?mypy=latest&python=3.8&gist=2c846e569ecbd5f8884367393a754adc

Zach
  • 1,243
  • 5
  • 19
  • 28

2 Answers2

1

You didn't annotate read_cols, so mypy has to infer a type for it based on the first assignment to read_cols. The first assignment assigns a value of type List[str], so mypy decides that's read_cols's type, and None is not a valid value of that type.

If you want a different type, annotate your variables:

read_cols: Optional[List[str]]
user2357112
  • 260,549
  • 28
  • 431
  • 505
  • I'm not sure what you mean, if you look at the function `get_relevant_params()` then it clearly states the return type as `List[str]` -- but I've also been pulling my hair out on this for some time now so maybe I'm missing something -- could you post a working solution? – Zach Nov 02 '21 at 16:57
  • @Zach: I *posted* a working solution. So did ddg. – user2357112 Nov 02 '21 at 17:07
  • You annotated `get_relevant_params`. You did not annotate `read_cols`. – user2357112 Nov 02 '21 at 17:19
1

Change line 11 to read:

 read_cols: Optional[List[str]] = get_relevant_params()

Your problem is that mypy identified the type of the variable read_cols automatically as a List[str] because that's the return type of get_relevant_params. Then when you try to assign None to it, it says "incompatible type". If you specify on variable creation that you want it to be optional, everything works.


Maybe a cleaner solution is to avoid using a return variable.

    if config_path:
        return get_relevant_params()
    else:
        return None

This way, there's never any confusion about the type of config_path.

ddg
  • 1,090
  • 1
  • 6
  • 17
  • This is a simplified example of the problem, I would actually just use the ternary because it works, but there are several other assignments in the if/else statement in the actual code. – Zach Nov 02 '21 at 16:59
  • I get what you're saying but it seems like a bug on MyPy's part, if/else statements is pretty standard logic that should understand that a variable can be assigned different values... – Zach Nov 02 '21 at 17:00
  • It does work if I change `line 11` to what you wrote, but that makes the code much less readable imo, thanks anyway! – Zach Nov 02 '21 at 17:03
  • @Zach: [ddg's code works fine.](https://mypy-play.net/?mypy=latest&python=3.10&gist=e3226b5fc0500d483ce612f45d479874) ([My code works fine too.](https://mypy-play.net/?mypy=latest&python=3.10&gist=2b73b8c05f0d80a38ddf65f4ee4f2f6e)) – user2357112 Nov 02 '21 at 17:05