Back to Ruff

Augmented assignment

crates/ty_python_semantic/resources/mdtest/assignment/augmented.md

0.15.123.4 KB
Original Source

Augmented assignment

Basic

py
x = 3
x -= 1
reveal_type(x)  # revealed: Literal[2]

x = 1.0
x /= 2
reveal_type(x)  # revealed: int | float

x = (1, 2)
x += (3, 4)
reveal_type(x)  # revealed: tuple[Literal[1, 2, 3, 4], ...]

Walrus target

py
def f(xs: list[int | str]) -> None:
    ys = xs
    ys[0] = "s"
    (ys := [1])[0] += 1

Dunder methods

py
class C:
    def __isub__(self, other: int) -> str:
        return "Hello, world!"

x = C()
x -= 1
reveal_type(x)  # revealed: str

class C:
    def __iadd__(self, other: str) -> int:
        return 1

x = C()
x += "Hello"
reveal_type(x)  # revealed: int

Unsupported types

py
class C:
    def __isub__(self, other: str) -> int:
        return 42

x = C()
# snapshot: unsupported-operator
x -= 1

reveal_type(x)  # revealed: int
snapshot
error[unsupported-operator]: Unsupported `-=` operation
 --> src/mdtest_snippet.py:7:1
  |
7 | x -= 1
  | -^^^^-
  | |    |
  | |    Has type `Literal[1]`
  | Has type `C`
  |

Method union

py
def _(flag: bool):
    class Foo:
        if flag:
            def __iadd__(self, other: int) -> str:
                return "Hello, world!"

        else:
            def __iadd__(self, other: int) -> int:
                return 42

    f = Foo()
    f += 12

    reveal_type(f)  # revealed: str | int

Partially bound __iadd__

py
def _(flag: bool):
    class Foo:
        if flag:
            def __iadd__(self, other: str) -> int:
                return 42

    f = Foo()

    # error: [unsupported-operator] "Operator `+=` is not supported between objects of type `Foo` and `Literal["Hello, world!"]`"
    f += "Hello, world!"

    reveal_type(f)  # revealed: int | Unknown

Partially bound with __add__

py
def _(flag: bool):
    class Foo:
        def __add__(self, other: str) -> str:
            return "Hello, world!"
        if flag:
            def __iadd__(self, other: str) -> int:
                return 42

    f = Foo()
    f += "Hello, world!"

    reveal_type(f)  # revealed: int | str

Partially bound target union

py
def _(flag1: bool, flag2: bool):
    class Foo:
        def __add__(self, other: int) -> str:
            return "Hello, world!"
        if flag1:
            def __iadd__(self, other: int) -> int:
                return 42

    if flag2:
        f = Foo()
    else:
        f = 42.0
    f += 12

    reveal_type(f)  # revealed: int | str | float

Target union

py
def _(flag: bool):
    class Foo:
        def __iadd__(self, other: int) -> str:
            return "Hello, world!"

    if flag:
        f = Foo()
    else:
        f = 42
    f += 12

    reveal_type(f)  # revealed: str | Literal[54]

Partially bound target union with __add__

py
def f(flag: bool, flag2: bool):
    class Foo:
        def __add__(self, other: int) -> str:
            return "Hello, world!"
        if flag:
            def __iadd__(self, other: int) -> int:
                return 42

    class Bar:
        def __add__(self, other: int) -> bytes:
            return b"Hello, world!"

        def __iadd__(self, other: int) -> float:
            return 42.0

    if flag2:
        f = Foo()
    else:
        f = Bar()
    f += 12

    reveal_type(f)  # revealed: int | str | float

Implicit dunder calls on class objects

py
class Meta(type):
    def __iadd__(cls, other: int) -> str:
        return ""

class C(metaclass=Meta): ...

cls = C
cls += 1

reveal_type(cls)  # revealed: str