sourcery icon indicating copy to clipboard operation
sourcery copied to clipboard

Simplify `Union` type annotations

Open ruancomelli opened this issue 2 years ago • 3 comments

Issue description or question

Hi again! It would be awesome if Sourcery were able to simplify Unions in type annotations, just like described in the docs. There would be a number of possible refactorings here:

  • Flattening unions: Union[int, Union[str, float]]Union[int, str, float]
  • Simplifying single-type unions: Union[int]int
  • Skipping redundant types: Union[int, int, str, int]Union[int, str]
  • Suggesting Optional:
    • Union[None, int]Optional[int]
    • Union[None, int, float]Optional[Union[int, float]]

Note: when suggesting Optional, it is important to add from typing import Optional, and also to make sure that this newly imported name does not clash with user-defined classes named Optional... Perhaps it is better to avoid this case for now.

Another example of refactoring (although a lot more complex to get right) is simplifying "subtypes":

  • Union[int, bool]int (since every bool is an int)
  • Union[List[bool], Sequence[int]]Sequence[int] (since every List is a Sequence, they are covariant types and every bool is an int)

Note: Perhaps it is better to avoid those refactorings as well, for now :grimacing:

Given all of those refactoring options, the following piece code:

from typing import Union

def f(x: Union[int, Union[None, bool]]) -> Union[int, Union[int]]:
    ...

would be refactored as:

from typing import Optional, Union

def f(x: Optional[int]) -> int:
    ...

Sourcery Version

0.9.4

Code editor or IDE name and version

VS Code 1.60.0 (x64)

OS name and version

Ubuntu 20.04.3 LTS

ruancomelli avatar Sep 12 '21 20:09 ruancomelli

Nice suggestions!

Hellebore avatar Sep 13 '21 09:09 Hellebore

A consequence from the subtype simplification is that Unions with Anys always result in Any:

  • Union[Any, <whatever>]Any

ruancomelli avatar Oct 08 '21 13:10 ruancomelli

Hard mode: piped types using py3.10's unions where str | int == Union[str, int]

Ideally this would be a setting per-project, somehow. I wouldn't want my 3.8+ lib to use 3.10 features such as this, but I'd like my 3.10 projects to take advantage of this.

diceroll123 avatar Dec 11 '21 21:12 diceroll123