ruff/crates/ty_python_semantic/resources/mdtest/del.md

2.3 KiB

del statement

Basic

a = 1
del a
# error: [unresolved-reference]
reveal_type(a)  # revealed: Unknown

# error: [invalid-syntax] "Invalid delete target"
del 1

# error: [unresolved-reference]
del a

x, y = 1, 2
del x, y
# error: [unresolved-reference]
reveal_type(x)  # revealed: Unknown
# error: [unresolved-reference]
reveal_type(y)  # revealed: Unknown

def cond() -> bool:
    return True

b = 1
if cond():
    del b

# error: [possibly-unresolved-reference]
reveal_type(b)  # revealed: Literal[1]

c = 1
if cond():
    c = 2
else:
    del c

# error: [possibly-unresolved-reference]
reveal_type(c)  # revealed: Literal[2]

d = 1

def delete():
    # TODO: this results in `UnboundLocalError`; we should emit `unresolved-reference`
    del d

delete()
reveal_type(d)  # revealed: Literal[1]

def delete_global():
    global d
    del d

delete_global()
# The variable should have been removed, but we won't check it for now.
reveal_type(d)  # revealed: Literal[1]

Delete attributes

If an attribute is referenced after being deleted, it will be an error at runtime. But we don't treat this as an error (because there may have been a redefinition by a method between the del statement and the reference). However, deleting an attribute invalidates type narrowing by assignment, and the attribute type will be the originally declared type.

Invalidate narrowing

class C:
    x: int = 1

c = C()
del c.x
reveal_type(c.x)  # revealed: int

# error: [unresolved-attribute]
del c.non_existent

c.x = 1
reveal_type(c.x)  # revealed: Literal[1]
del c.x
reveal_type(c.x)  # revealed: int

Delete an instance attribute definition

class C:
    x: int = 1

c = C()
reveal_type(c.x)  # revealed: int

del C.x
c = C()
# This attribute is unresolved, but we won't check it for now.
reveal_type(c.x)  # revealed: int

Delete items

Deleting an item also invalidates the narrowing by the assignment, but accessing the item itself is still valid.

def f(l: list[int]):
    del l[0]
    # If the length of `l` was 1, this will be a runtime error,
    # but if it was greater than that, it will not be an error.
    reveal_type(l[0])  # revealed: int

    # error: [call-non-callable]
    del l["string"]

    l[0] = 1
    reveal_type(l[0])  # revealed: Literal[1]
    del l[0]
    reveal_type(l[0])  # revealed: int