django-stubs '1.10.0' introduced a regression when used with Django 3.2, that has persisted in all subsequent releases and currently still exists in 'master' #1113
Labels
bug
Something isn't working
Bug report
What's wrong
It is indicated in the readme that all versions of
django-stubs >= 1.9.0
supportDjango 3.2
(note:1.12.0
is the latestdjango-stubs
release at the time of writing). But, ever since #683 was merged and released as part ofdjango-stubs 1.10.0
, support forDjango 3.2
breaks in at least one place. Specifically, I've noticed the stub for the.bulk_update()
method on both the QuerySet and Manager no longer work forDjango 3.2
, because they were changed in1.10.0
to return anint
instead ofNone
(as they did in version1.9.0
). However, this presents problems forDjango 3.2
because, prior toDjango 4.0
,.bulk_update()
did indeed returnNone
. It wasn't untilDjango 4.0
that.bulk_update()
started returning anint
.To quote from the
Django 4.0
docs on.bulk_update()
:Now contrast to the Django 3.2 docs on
.bulk_update()
:Here is very simple code snippet that should demonstrate this behavior on
Django 3.2
withdjango-stubs >= 1.10.0
installed:This will raise the following error in
mypy
(again, usingDjango 3.2
anddjango-stubs >= 1.10.0
):How should it be
mypy
should not be raising an error here when a subclass of QuerySet/Manager is created that has an overriden.bulk_update()
method annotated withNone
as the return type whenDjango 3.2
is being used, because the return type of.bulk_update()
inDjango 3.2
is indeedNone
and not anint
.I have a few ideas for ways this could be fixed, ordered by what I think the best option is (1) to the worst option (3):
Changing the return value of
.bulk_update()
stub to beOptional[int]
, which should support both theDjango 3.2
behavior (returnsNone
) and theDjango >= 4.0
behavior (returnsint
). See below code snippet for a tiny proof of concept to show how usingOptional[int]
as the return type in the base class allows subclasses to return eitherNone
orint
, which results in nomypy
errors. This change can/should be released as part of version1.13.0
(assuming that version is still intended to supportDjango 3.2
, which I would hope so sinceDjango 3.2
is currently the only supported LTS version ofDjango
and will be supported until at least 2024). I would also think this should include back-porting this fix to all versions ofdjango-stubs >= 1.10.0
(ie. versions1.10.2
(1.10.1
already exists),1.11.1
,1.12.1
) so that they supportDjango 3.2
as they purport to do in the readme.If
django-stubs 1.13.0
is nearly ready to be released, and it is intended to still supportDjango 3.2
, perhaps back-porting the change to previous releases could be considered non-essential. Ie. Just make the change and release it as part of1.13.0
and encourage users to upgrade to that version if they run into this issue. However, we may want to back-port in any case to pin theDjango
dependency insetup.py
fordjango-stubs
versions>=1.10.0,<=1.12.0
to be>=4.0
, in which case, we might as well include the fix for this issue in the back-port. (This overlaps with option 2 below.)Django 3.2
annotations are broken fordjango-stubs
versions1.10.x
,1.11.0
,1.12.0
and hope that folks read it, but experience tells me that most folks won't. (This also overlaps with option 2 below.)Updating the readme to indicate that
django-stubs >= 1.10.0
only supportsDjango >= 4.0
(which leaves the only version ofdjango-stubs
supportingDjango 3.2
to be1.9.0
, which isn't ideal, since many bugs that were present in1.9.0
have been fixed since then), or, at least, as mentioned above, add a disclaimer to the readme to indicate that some annotations forDjango 3.2
do not work with these versions. ofdjango-stubs
.1.10.2
(1.10.1
already exists),1.11.1
,1.12.1
) to change the requirement boundaries set insetup.py
to indicate thatDjango >= 4.0
is need for these versions. Without doing that, dependency management tools (pipfile
,poetry
, etc.) will still happily allow versions1.10.0
,1.11.0
, and1.12.0
to be installed onDjango 3.2
projects, causingmypy
to fail when this issue is encountered.Do nothing and hope users of
Django 3.2
figure out that they need to either downgrade todjango-stubs 1.9.0
, or be forced to use# type: ignore
whenever they run into this issue using a newer version. In my experience, the more# type: ignore
s a repository has, the more likely it is to accidentally deploy broken code thatmypy
could have caught. So, IMHO, I think this should be the last resort.Since both options 1 and 2 are of the same, pretty low lift, I would recommend going with option 1 - though I am, of course, open to any argument for one of the other options - or any other options that I haven't thought of.
PR for merging option 1 into
master
is here: #1114Also happy to back-port the changes to versions
1.10.1
,1.11.0
, and1.12.0
if this proposal is accepted.System information
Re-created the issue on 2 systems, but it's pretty clear that this is just a direct incompatibility for the behavior of
.bulk_update()
, asDjango 3.2
returnsNone
, but the annotations found indjango-stubs >= 1.10.0
indicate the method needs to return anint
, which is only the behavior inDjango >= 4.0
.System 1
python
version:3.9.13
django
version:3.2.15
mypy
version:0.910
(with1.9.0
),0.942
(with1.10.0
and1.10.1
), and0.950
(with1.11.0
and1.12.0
)django-stubs
version:1.10.0
,1.10.1
,1.11.0
, and1.12.0
were all attempted (along with1.9.0
, which works fine since this breaking change for users ofDjango 3.2
wasn't introduced until1.10.0
)django-stubs-ext
version:0.5.0
System 2
python
version:3.9.5
django
version:3.2.15
mypy
version:0.910
(with1.9.0
) and0.931
(with1.10.0
,1.10.1
,1.11.0
, and1.12.0
)django-stubs
version:1.10.0
,1.10.1
,1.11.0
, and1.12.0
were all attempted (as above,1.9.0
was tested and works fine)django-stubs-ext
version:0.3.0
(with1.9.0
and1.10.0
) and0.4.0
(with all versions>= 1.9.0, <= 1.12.0
)The text was updated successfully, but these errors were encountered: