Skip to content

Conditionally excluding backward incompatible syntax based on python version #19134

Open
@alisaifee

Description

@alisaifee

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.

Activity

JelleZijlstra

JelleZijlstra commented on May 23, 2025

@JelleZijlstra
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

sterliakov commented on May 23, 2025

@sterliakov
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

alisaifee commented on May 24, 2025

@alisaifee
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

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @alisaifee@JelleZijlstra@sterliakov

        Issue actions

          Conditionally excluding backward incompatible syntax based on python version · Issue #19134 · python/mypy