Skip to content

try: except: continue inside for: else: causes spurious used-before-def #19690

@ambv

Description

@ambv

Using a for-loop to search for a value where the else: clause raises an exception should be enough to ensure that the value is always set after the loop. But in a pretty specific scenario this doesn't happen and a spurious used-before-def is reported. The conditions required:

  • an outer if/else with both branches defining (without it there's no error)
  • a try: except: specifically:
    • without an if inside the try block (with an if there's no error)
    • with continue (when pass is used instead, there's no error)

To reproduce

import random

if random.random():
    for i in range(10):
        try:
            value = random.random()
            break
        except Exception:
            continue
    else:
        raise ValueError
    
    print(value)  # error: Name "value" is used before definition  [used-before-def]
else:
    value = random.random()

print(value)  # curiously no error reported here!

Examples not triggering the bug

As mentioned above, only a very specific control flow combination triggers the issue. Small variations to it remove the spurious error.

No outer if/else

for i in range(10):
    try:
        value = random.random()
        break
    except Exception:
        continue
else:
    raise ValueError

print(value)  # no error

pass instead of continue

import random

if random.random():
    for i in range(10):
        try:
            value = random.random()
            break
        except Exception:
            pass
    else:
        raise ValueError

    print(value)  # no error
else:
    value = random.random()

print(value)  # no error

if inside the try: block

import random

if random.random():
    for i in range(10):
        try:
            if i > 10:
                value = random.random()
                break
        except Exception:
            continue
    else:
        raise ValueError

    print(value)  # no error
else:
    value = random.random()

print(value)  # no error

Actual Behavior

My Environment

  • Mypy version used: 1.17.1
  • Mypy command-line flags: mypy test_mypy.py
  • Mypy configuration options from mypy.ini (and other config files): no configuration
  • Python version used: 3.13.5

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugmypy got something wrongsemantic-analyzerProblems that happen during semantic analysis

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions