django-stubs icon indicating copy to clipboard operation
django-stubs copied to clipboard

Find a way to split types by Django version

Open adamchainz opened this issue 3 years ago • 6 comments

Mypy supports splitting types by Python versions by interpreting if sys.version_info ... checks. But we have no mechanism to conditionally split types by Django version. This has lead to lots of small issues where Django’s API has changed and we cannot have correct types for all versions we attempt to support.

To counter this problem, @sobolevn suggested doing releases per Django version, where we only officially support the latest version: https://github.com/typeddjango/django-stubs/issues/1095#issuecomment-1307066177 . This is going to be the easiest for the time being, but if we can find a mechanism to split types by Django version, we could backtrack on this decision.

Related Mypy issue: https://github.com/python/typing/issues/693

@ngnpope investigated a possibility with literal numerical types: https://github.com/typeddjango/django-stubs/pull/1160#issuecomment-1297030732 . If we could supply the literal numerical type for the Django version from the MYpy plugin, then perhaps Mypy could use the type of that for conditions in stub files.

adamchainz avatar Nov 09 '22 10:11 adamchainz

There was some earlier discussion about supporting multiple Django versions in #262 and draft PR in #288.

intgr avatar Nov 11 '22 00:11 intgr

Parsing the stubs into multiple versioned, committed files is an interesting approach. We may not even need something as complex as libcst to do it, a few choice regexes could work, or the Cog tool for processing text with inline Python.

adamchainz avatar Nov 11 '22 09:11 adamchainz

Having conditional checks against the Django version is interesting but might be verbose e.g. for newly added arguments. Consider the new db_default parameter, it would require the following:

if DJANGO_5:
    def __init__(
            self,
            # All the other arguments
            db_default: type[NOT_PROVIDED] | Expression | _ST = ...,
    ): ...
else:
    # The same `__init__` method without `db_default`

And this for all Django fields.

As the django-stubs versioning seems to now be inline with the Django versions, maybe we could consider the 4.2.x releases to only support Django 4.2, and the next stubs release (presumably 5.x) to be inline with Django 5. For each addition on the main branch, we could backport changes to a 4.2.x branch if the addition isn't Django 5 only.

Viicos avatar Dec 15 '23 12:12 Viicos

For each addition on the main branch, we could backport changes to a 4.2.x branch if the addition isn't Django 5 only.

It's possible, but personally I have no interest in the maintenance work involved: backporting, maintaining old branches and doing twice the releases. If someone else were to handle it, maybe, but I suspect it would still affect the rest of maintainers in one way or another.

My projects using django-stubs are have been one Django release behind for a while and I don't think I ever had any typing issues due to differing APIs between Django versions. And I can only remember one issue reported to us about this. My impression is that Django public APIs change rarely enough that this tends not to be an issue.

With the example db_default=, Django 4.2 users can just as well use 5.0 stubs and simply avoid using db_default=. Maybe someone can bring up better examples, but this example doesn't seem worth the trouble of maintaining multiple versions.

intgr avatar Dec 17 '23 13:12 intgr

My impression is that Django public APIs change rarely enough that this tends not to be an issue.

You're right, considering this it might not be worth maintaining two branches. Maybe in the future this would be a builtin feature when writing stubs.

Viicos avatar Dec 18 '23 07:12 Viicos