@override decorator: Mypy cannot find base "save" method on django.db.models.Model inherited models
Bug report
On overriding the save method with a @override decorator and running it through mypy, we get an error that mypy cannot find this method in the base model. Thank you for looking into this, we're kinda lost here.
from collections.abc import Iterable
from typing import override
from django.db import models
class Tenant(models.Model):
@override
def save(
self,
force_insert: bool = False,
force_update: bool = False,
using: str | None = None,
update_fields: Iterable[str] | None = None,
) -> None:
pass
If only I could produce an actual trace, it would be helpful if I could see whether this false positive originates in mypy or django-stubs.
The reason we want this is because of the type signature and Ruff https://docs.astral.sh/ruff/rules/boolean-type-hint-positional-argument/ . We want to make clear that we're not inventing a method with boolean args, we're following the method pre-defined by Django.
What's wrong
mypy .
src/tenants/models.py:45: error: Method "save" is marked as an override, but no base method was found with this name [misc]
Found 1 error in 1 file (checked 21 source files)
How is that should be
No error
System information
- OS: Ubuntu 22.04
-
pythonversion: 3.12 -
djangoversion: 5.0.3 -
mypyversion: 1.9.0 -
django-stubsversion: 4.2.7 -
django-stubs-extversion: 4.2.7
I can't reprodce this.
How are you running mypy? Are you sure that django-stubs is installed in that environment?
In your original report you mentioned pre-commit. I believe you need to explicitly configure additional packages to be installed into pre-commit's environment.
The actual source is running in a poetry-installed, pre-commit checked repo using a "src"-layout. The mypy rules are in pyproject.toml:
[tool.mypy]
python_version = "3.12"
explicit_package_bases = true
ignore_missing_imports = true
no_site_packages = true
disallow_untyped_defs = true
disallow_incomplete_defs = true
check_untyped_defs = true
disallow_any_explicit = true
plugins = ["mypy_django_plugin.main"]
mypy_path="./src:./tests"
[[tool.mypy.overrides]]
module = "*.migrations.*"
ignore_errors = true
I hoped not having to toss all config files into this issue but it's clear that I need to do some more documentation to re-create this in a reproducible environment. I can rule out any pre-commit interference by installing mypy and django-stubs using
poetry add --group=dev mypy django-stubs[mypy-compatible]
This installs the versions listed above and produces the error reported
I'll see if I can isolate a minimum example
I've concocted a fully reproducible minimalistic example here: https://github.com/reinvantveer/django-save-override
It was initialized from a django-admin initialized basic setup, with an added basic but custom Django model.
I've concocted a fully reproducible minimalistic example here: https://github.com/reinvantveer/django-save-override It was initialized from a
django-admininitialized basic setup, with an added basic but custom Django model.
Does adding myapp to INSTALLED_APPS in the settings of the above project change anything?
Does adding
myapptoINSTALLED_APPSin the settings of the above project change anything?
Unfortunately it does not, I just pushed and checked so you'll be able to reproduce if you want
I checked this up and realised that this is simply a misconfiguration of mypy. You should use files = instead of mypy_path = in your config, since it's files that configures what paths should be checked by mypy
Docs for files:
files TYPE: comma-separated list of strings
A comma-separated list of paths which should be checked by mypy if none are given on the command line. Supports >recursive file globbing using glob, where * (e.g. .py) matches >files in the current directory and **/ (e.g. **/.py) matches files in any directories below the current one. User home directory and environment variables will be expanded.
This option may only be set in the global section ([mypy]).
Docs for mypy_path
mypy_path TYPE: string
Specifies the paths to use, after trying the paths from MYPYPATH environment variable. Useful if you’d like to keep stubs in >your repo, along with the config file. Multiple paths are always separated with a : or , regardless of the platform. User home >directory and environment variables will be expanded.
Relative paths are treated relative to the working directory of the mypy command, not the config file. Use the >MYPY_CONFIG_FILE_DIR environment variable to refer to paths relative to the config file (e.g. mypy_path = >$MYPY_CONFIG_FILE_DIR/src).
This option may only be set in the global section ([mypy]).
Note: On Windows, use UNC paths to avoid using : (e.g. \127.0.0.1\X$\MyDir where X is the drive letter).