sourcery
sourcery copied to clipboard
Simplify `Union` type annotations
Issue description or question
Hi again! It would be awesome if Sourcery were able to simplify Union
s 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 everybool
is anint
) -
Union[List[bool], Sequence[int]]
→Sequence[int]
(since everyList
is aSequence
, they are covariant types and everybool
is anint
)
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
Nice suggestions!
A consequence from the subtype simplification is that Union
s with Any
s always result in Any
:
-
Union[Any, <whatever>]
→Any
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.