Skip to content

mypy tries to follow imports in files with top-level sys.platform asserts on non-matching platforms #19346

Open
@petamasS3D

Description

@petamasS3D

Bug Report

I have a platform-specific script that uses libraries only available on one platform. For the sake of the bug report, I'll use this script:

import mslex
import winreg
from ctypes import WinError

windir = winreg.ExpandEnvironmentStrings("%windir%")
print(mslex.quote(windir))
raise WinError()

With the following requirements.txt:

mslex==1.3.0 ; sys_platform=="win32"
mypy==1.16.1

The script needs three different kinds of Windows-specific functionality:

  • A Windows-specific function from a cross-platform builtin module (ctypes.WinError)
  • A Windows-specific builtin module (winreg)
  • A thirdparty module from PyPI, that I'm only installing on Windows (mslex)

I'm currently working on macOS. If I run mypy on the script, the result is, as expected, an error:

mypy_repro % uv run --with-requirements requirements.txt mypy win.py 
win.py:1: error: Cannot find implementation or library stub for module named "mslex"  [import-not-found]
win.py:1: note: See https://mypy.readthedocs.io/en/stable/running_mypy.html#missing-imports
win.py:3: error: Module "ctypes" has no attribute "WinError"  [attr-defined]
win.py:5: error: Module has no attribute "ExpandEnvironmentStrings"  [attr-defined]
Found 3 errors in 1 file (checked 1 source file)

Interestingly, there's no error about the missing winreg module.

If I wrap the script in a platform check, there are no errors:

import sys

if sys.platform=="win32":
    import mslex
    import winreg
    from ctypes import WinError

    windir = winreg.ExpandEnvironmentStrings("%windir%")
    print(mslex.quote(windir))
    raise WinError()
mypy_repro % uv run --with-requirements requirements.txt mypy win_if.py      
Success: no issues found in 1 source file

However, indenting the whole script is not really elegant. Luckily, mypy's docs offer a solution:

As a special case, you can also use one of these checks in a top-level (unindented) assert; this makes mypy skip the rest of the file.

However, when I try it, it still produces an error, although only for the thirdparty mslex module:

import sys
assert sys.platform=="win32"

import mslex
import winreg
from ctypes import WinError

windir = winreg.ExpandEnvironmentStrings("%windir%")
print(mslex.quote(windir))
raise WinError()
mypy_repro % uv run --with-requirements requirements.txt mypy win_assert.py
win_assert.py:4: error: Cannot find implementation or library stub for module named "mslex"  [import-not-found]
win_assert.py:4: note: See https://mypy.readthedocs.io/en/stable/running_mypy.html#missing-imports
Found 1 error in 1 file (checked 1 source file)

It seems like even though the rest of the file after the assert is skipped during type checking, the imports are still processed and error out if unavailable. This is not what I expected; I expected it to pass.

What's even more curious is that if I wrap the imports in an if after the assert, the error persists. It's as if the assert makes mypy skip the rest of the file, including the conditionals around the import statements, but not including the import statements themselves:

import sys
assert sys.platform=="win32"

if sys.platform=="win32":
    import mslex
    import winreg
    from ctypes import WinError

windir = winreg.ExpandEnvironmentStrings("%windir%")
print(mslex.quote(windir))
raise WinError()
mypy_repro % uv run --with-requirements requirements.txt mypy win_assert_then_if.py 
win_assert_then_if.py:5: error: Cannot find implementation or library stub for module named "mslex"  [import-not-found]
win_assert_then_if.py:5: note: See https://mypy.readthedocs.io/en/stable/running_mypy.html#missing-imports
Found 1 error in 1 file (checked 1 source file)

The only workaround I found is to add a platform check around the Windows-specific imports, and put an assert AFTER the imports:

import sys

if sys.platform=="win32":
    import mslex
    import winreg
    from ctypes import WinError

assert sys.platform=="win32"

windir = winreg.ExpandEnvironmentStrings("%windir%")
print(mslex.quote(windir))
raise WinError()
mypy_repro % uv run --with-requirements requirements.txt mypy win_if_then_assert.py
Success: no issues found in 1 source file

To summarize the results:

Testcase Expected behaviour Actual behaviour OK/NOK
No platform check Error for all 3 imports Error for ctypes and mslex imports, but not the winreg import. Also, an error for calling a function from winreg. OK (kinda)
Platform if around entire script No errors No errors OK
Top-level platform assert No errors Error on mslex import NOK
Top-level platform assert, then platform if around imports No errors (if should be redundant) Error on mslex import NOK
Platform if around imports, then top-level platform assert No errors No errors OK

Am I missing something? Or is there a bug in mypy's handling of the top-level platform asserts?

** Environment**

  • Mypy version used: 1.16.1
  • Mypy command-line flags: none
  • Mypy configuration options from mypy.ini (and other config files): none
  • Python version used: 3.12.4
  • OS version: macOS 15.5 Sequoia

The issue is not specific to type-checking Windows-specific script on macOS, the same results can be reproduced on Windows for a macOS-specific script. I haven't checked whether conditions using the python interpreter version misbehave the same way as platform checks.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugmypy got something wrongtopic-reachabilityDetecting unreachable code

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions