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
Uh oh!
There was an error while loading. Please reload this page.
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: