Skip to content

Conditionally excluding backward incompatible syntax based on python version #19134

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
alisaifee opened this issue May 22, 2025 · 3 comments
Open
Labels

Comments

@alisaifee
Copy link

alisaifee commented May 22, 2025

Feature

There doesn't seem to be a way to progressively provide improvements in libraries that support older versions with syntactically backward incompatible code that is conditionally included at runtime.

For example in pythons < 3.12 it's not possible to exclude certain files containing PEP 695 type syntax even if the module is only imported with a sys.version_info >= (3,12) guard.

import sys

if sys.version_info >= (3, 12):
    from _py312_types import A
else:
    from _types import A

__all__ = ["A"]
# file: _py312_types.py
type A = list[int|A]
# file: _types.py
A = list[int|list["A"]]

Pitch

The only existing path that I could find was to allow python_version overrides on a per module basis (which is currently only acceptable as a global configuration) though that seems hacky and brittle.

@JelleZijlstra
Copy link
Member

I'm not sure how you are invoking mypy, but one complication is that mypy uses Python's own parser to parse the source code. So if you're using Python 3.11 to run mypy, it won't be able to parse the type statement at all, even if you set --python-version.

And if you invoke mypy in a way that makes it look at an entire directory, it's going to type check files like _py312_types.py even if nothing imports them.

@sterliakov
Copy link
Collaborator

If you run mypy using a modern interpreter but with lower --python-version target, this should be possible to support. We have top-level asserts working for all non-syntax errors, so ideally this could work as

import sys

assert sys.version_info >= (3, 12)

class C[_T]: ...

This isn't supported, we fail earlier than detect top-level guards, but that sounds more reasonable IMO. Cf.

import sys

# assert sys.version_info >= (3, 12)

from typing import Unpack

which passes with --python-version 3.10 iff assert is not commented out.

@alisaifee
Copy link
Author

So if you're using Python 3.11 to run mypy, it won't be able to parse the type statement at all, even if you set --python-version.

Yes, for each supported version (in my scenario >= 3.10) the code base is validated using that version + the latest mypy. I'm not sure why this wasn't obvious to me but it makes perfect sense that mypy running in 3.11 can't parse the code as 3.12 - so the python_version override is indeed a non direction in this use case.

if you invoke mypy in a way that makes it look at an entire directory

Yes, mypy is run with the relevant package directories: i.e. mypy src tests

At the moment I've simply excluded the files that are 3.12+ only - the types declared in those files still get validated as a side effect of being used else where and though that does get the job done - I wonder if having the ability to explicitly conditionally exclude certain files/modules would be beneficial (perhaps also implicitly in cases such as mentioned in the previous comment):

We have top-level asserts working for all non-syntax errors, so ideally this could work

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants