python / python/mypy

Idea: short-circuit analysis with `if <platform-check>: return`

Open
#5,964 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

feature topic-reachability
Dominant language
Python
Stars
20.6k
Forks
3.3k
PR merge metrics
PR metrics pending

Description

Hey all,

I'm adding OS-specific typechecking to a large Python app, and we have a fair number of files and functions that mix OS versions. Currently, mypy only does limited analysis with platform/version/constants to figure out which lines it shouldn't check. With that limited analysis, it's possible to add OS-specific typechecking to the app, but it'll make the code a bit messier.

I'd like to get your feedback on two ideas that would make adding OS-specific typechecking easier.

  1. For if statements where the expression is a mypy-constant, short-circuit if there's a return statement one-level deep in the body of the if. (Currently, the inner bodies of the if are conditionally checked, and return doesn't short-circuit checking.)

E.g.

# flags: --always-false=IS_WINDOWS
if IS_WINDOWS:
    import win_specific_import

def some_fun_broken() -> int:
    if not IS_WINDOWS:
        return 1 # checked
    # The rest of this function is analyzed even though we returned above. 

    # Blows up since `win_specific_import` isn't defined
    return win_specific_import.something()

def some_fun_fixed() -> int:
    if not IS_WINDOWS:
        return 1  # checked
    else:
        # Not analyzed because this is in the `else` part of the `if` statement
        return win_specific_import.something()  # Works

We use the if not IS_WINDOWS: return pattern a fair amount in our codebase, and it would be nice if mypy supported that.

I'm not sure how we'd implement that in mypy, though. Maybe we can scan for a return one-level deep in if statement bodies which have a mypy-constant expression and mark the rest of the function as unreachable.

  1. Make mypy-constant asserts also ignore function bodies. This would be an extension of #5308. E.g.
# flags: --always-false=IS_WINDOWS

if IS_WINDOWS:
    import win_specific_import

def invalid_win_specific_function() -> bool:
    assert IS_WINDOWS
    return win_specific_import.some_func()  # This blows up

if IS_WINDOWS:
    def valid_win_specific_function() -> bool:
        return win_specific_import.some_func()

It would be convenient if we ignored the rest of the function body if the first statement in it is a mypy-constant assert. I don't think we'd want to look for asserts elsewhere in the function block, though, even though that would make it a magical special-case.

Any thoughts on the above ideas?

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by tracing mypy’s existing platform, version, and constant analysis, including the behavior described for conditional imports and function bodies. Resolve whether either proposed short-circuiting behavior is wanted, then define coverage for the if/return and leading assert examples before implementing tests and changes.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
compilers
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.