Pylance v2024.10.1 doesn't work with Django models
The Pylance version v2024.8.1 works well on django models. After I updated the Pylance to latest version v2024.10.1. Pylance was failed to get the id, foreign key properties. Can you help to check it?
Environment data
- Pylance version: v2024.10.1
- OS and version: Centos 7
- Python version (& distribution if applicable, e.g. Anaconda): 3.10.6 (main, Jun 19 2024, 14:45:38) [GCC 7.3.0] on linux
- Django version: 4.2
- django-stubs: 4.2.7
Code Snippet
def get_referred_by_projects(self):
"""Return the jsom format for the refering obj"""
return {
"id": self.id,
"type": self.get_reversed_type(),
'design': self.design.name,
'design_id': self.design.id,
'design_type': self.design.get_design_type(),
"use_version": "",
"latest_version": "",
"since_version": "",
"latest_design": "",
"date": user_tz(self.created_date),
"added_by": self.added_by.get_full_idname(),
'obj_name' : ''
}
Pyright config
{
"exclude": [
"db_conversion/**",
"ipds/templates/**",
"ipds/static/**"
],
"include": [
"ipds/**",
"ipds/**/**"
]
}
Issue
Logs
2024-10-16 16:36:24.665 [info] (Client) Pylance async client (2024.10.1) started with python extension (2024.14.1)
2024-10-16 16:36:26.783 [info] [Info - 4:36:26 PM] (24516) Server root directory: file:///home/users/luant/.vscode-server/extensions/ms-python.vscode-pylance-2024.10.1/dist
2024-10-16 16:36:26.945 [info] [Info - 4:36:26 PM] (24516) Pylance language server 2024.10.1 (pyright version 1.1.382, commit e46efc6b) starting
2024-10-16 16:36:26.971 [info] [Info - 4:36:26 PM] (24516) Starting service instance "django-ipds"
2024-10-16 16:36:27.040 [info] [Info - 4:36:27 PM] (24516) Starting service instance "ipkits"
2024-10-16 16:36:27.052 [info] [Info - 4:36:27 PM] (24516) Starting service instance "commons"
2024-10-16 16:36:28.006 [info] [Info - 4:36:28 PM] (24516) Loading configuration file at /home/users/luant/proj/django-ipds/pyrightconfig.json
2024-10-16 16:36:28.014 [info] [Info - 4:36:28 PM] (24516) Setting pythonPath for service "django-ipds": "/home/users/luant/SVR17_ADM_NEW/bin/python"
2024-10-16 16:36:28.169 [info] [Info - 4:36:28 PM] (24516) Assuming Python version 3.10.6.final.0
2024-10-16 16:36:34.552 [info] [Info - 4:36:34 PM] (24516) Found 254 source files
2024-10-16 16:36:34.587 [info] [Info - 4:36:34 PM] (24516) Background analysis(1) root directory: file:///home/users/luant/.vscode-server/extensions/ms-python.vscode-pylance-2024.10.1/dist
2024-10-16 16:36:34.587 [info] [Info - 4:36:34 PM] (24516) Background analysis(1) started
2024-10-16 16:36:34.589 [info] [Info - 4:36:34 PM] (24516) Setting environmentName for service "ipkits": "3.10.6 (SVR17_ADM_NEW venv)"
2024-10-16 16:36:34.589 [info] [Info - 4:36:34 PM] (24516) Setting pythonPath for service "ipkits": "/home/users/luant/SVR17_ADM_NEW/bin/python"
2024-10-16 16:36:34.589 [info] [Info - 4:36:34 PM] (24516) No include entries specified; assuming /home/users/luant/proj/ipkits
2024-10-16 16:36:34.753 [info] [Info - 4:36:34 PM] (24516) Assuming Python version 3.10.6.final.0
2024-10-16 16:36:38.410 [info] [Info - 4:36:38 PM] (24516) Found 189 source files
2024-10-16 16:36:38.417 [info] [Info - 4:36:38 PM] (24516) Background analysis(2) root directory: file:///home/users/luant/.vscode-server/extensions/ms-python.vscode-pylance-2024.10.1/dist
2024-10-16 16:36:38.417 [info] [Info - 4:36:38 PM] (24516) Background analysis(2) started
2024-10-16 16:36:38.418 [info] [Info - 4:36:38 PM] (24516) Setting environmentName for service "commons": "3.10.6 (SVR17_ADM_NEW venv)"
2024-10-16 16:36:38.418 [info] [Info - 4:36:38 PM] (24516) Setting pythonPath for service "commons": "/home/users/luant/SVR17_ADM_NEW/bin/python"
2024-10-16 16:36:38.418 [info] [Info - 4:36:38 PM] (24516) No include entries specified; assuming /home/users/luant/proj/commons
2024-10-16 16:36:38.542 [info] [Info - 4:36:38 PM] (24516) Assuming Python version 3.10.6.final.0
2024-10-16 16:36:41.288 [info] [Info - 4:36:41 PM] (24516) Found 109 source files
2024-10-16 16:36:42.764 [info] [Info - 4:36:42 PM] (24516) Background analysis(3) root directory: file:///home/users/luant/.vscode-server/extensions/ms-python.vscode-pylance-2024.10.1/dist
2024-10-16 16:36:42.764 [info] [Info - 4:36:42 PM] (24516) Background analysis(3) started
2024-10-16 16:36:42.764 [info] [Info - 4:36:42 PM] (24516) Indexer background runner(4) root directory: file:///home/users/luant/.vscode-server/extensions/ms-python.vscode-pylance-2024.10.1/dist (index)
2024-10-16 16:36:42.764 [info] [Info - 4:36:42 PM] (24516) Indexing(4) started
2024-10-16 16:36:45.771 [info] [Info - 4:36:45 PM] (24516) [BG(1)] Long operation: SemanticTokens range 2052:0 - 2139:74 at file:///home/users/luant/proj/django-ipds/ipds/models/design/base.py (3058ms)
2024-10-16 16:36:52.725 [info] [Info - 4:36:52 PM] (24516) [BG(1)] Long operation: SemanticTokens full at file:///home/users/luant/proj/django-ipds/ipds/models/design/base.py (6952ms)
2024-10-16 16:36:57.364 [info] [Info - 4:36:57 PM] (24516) [IDX(4)] Long operation: scan packages file:///home/users/luant/proj/django-ipds (14709ms)
2024-10-16 16:36:57.372 [info] [Info - 4:36:57 PM] (24516) scanned(4) 173 files over 1 exec env
2024-10-16 16:37:03.423 [info] [Info - 4:37:03 PM] (24516) [FG] Long operation: parsing: file:///home/users/luant/proj/django-ipds/ipds/util/main.py (2151ms)
2024-10-16 16:37:04.483 [info] [Info - 4:37:04 PM] (24516) [IDX(4)] Long operation: parsing: file:///home/users/luant/.vscode-server/extensions/ms-python.vscode-pylance-2024.10.1/dist/bundled/stubs/networkx/classes/ordered.pyi (2203ms)
2024-10-16 16:37:04.483 [info] [Info - 4:37:04 PM] (24516) [IDX(4)] Long operation: binding: file:///home/users/luant/.vscode-server/extensions/ms-python.vscode-pylance-2024.10.1/dist/bundled/stubs/networkx/classes/__init__.pyi (2207ms)
2024-10-16 16:37:04.483 [info] [Info - 4:37:04 PM] (24516) [IDX(4)] Long operation: binding: file:///home/users/luant/.vscode-server/extensions/ms-python.vscode-pylance-2024.10.1/dist/typeshed-fallback/stubs/networkx/networkx/__init__.pyi (2380ms)
2024-10-16 16:37:04.520 [info] [Info - 4:37:04 PM] (24516) [IDX(4)] Long operation: indexing: file:///home/users/luant/.vscode-server/extensions/ms-python.vscode-pylance-2024.10.1/dist/typeshed-fallback/stubs/networkx/networkx/__init__.pyi (4365ms)
2024-10-16 16:37:12.824 [info] [Info - 4:37:12 PM] (24516) [IDX(4)] Long operation: parsing: file:///home/users/luant/SVR17_ADM_NEW/lib/python3.10/site-packages/jwt/jwks_client.py (2485ms)
2024-10-16 16:37:12.824 [info] [Info - 4:37:12 PM] (24516) [IDX(4)] Long operation: indexing: file:///home/users/luant/SVR17_ADM_NEW/lib/python3.10/site-packages/jwt/__init__.py (2546ms)
2024-10-16 16:37:15.176 [info] [Info - 4:37:15 PM] (24516) [IDX(4)] Long operation: index execution environment file:///home/users/luant/proj/django-ipds (17157ms)
2024-10-16 16:37:18.448 [info] [Info - 4:37:18 PM] (24516) [IDX(4)] Long operation: index packages file:///home/users/luant/proj/django-ipds (20436ms)
2024-10-16 16:37:18.456 [info] [Info - 4:37:18 PM] (24516) indexed(4) 173 files over 1 exec env
2024-10-16 16:37:18.721 [info] [Info - 4:37:18 PM] (24516) Indexing finished(4).
Thanks for reaching out. To help us investigate, could you provide the complete code sample that reproduces the issue? If your project is in a public repo, sharing the link would also be helpful.
Could you also provide more logs as outlined in our troubleshooting guide here? The logs you shared don't seem to have python.analysis.logLevel set to Trace.
Without the full project, it's hard to diagnose the exact problem. However, if you're seeing new diagnostics, it might be related to the typeCheckingMode setting. Could you check if you have typeCheckingMode enabled in your settings.json or config file? This might explain the change.
This is a known issue. These fields are added dynamically by django and there's currently no way in the Python type system to tell a static type checker that they will exist.
General improvements for django are tracked by https://github.com/microsoft/pylance-release/issues/3701
@StellaHuang95 Please see my attached sample script and the log. server_log.txt
Pylance was failed to check field id from django model and some fields from django rest framework such data, query_params. Pylance version v2024.8.1 can check these fields.
from django.db import models
from rest_framework.response import Response
from rest_framework import viewsets, serializers, permissions, decorators
class Author(models.Model):
"""Author model"""
name = models.CharField(max_length=100, help_text="Author name")
description = models.TextField(max_length=200, help_text="Author description")
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
def __str__(self):
"""To string"""
return self.name
def get_books(self):
"""Get books"""
return Book.objects.filter(author_id=self.id)
def update_signature(self, signature=None):
"""Update signature"""
if signature is None:
raise ValueError("Signature is required")
for obj in self.get_books():
obj.signature = signature
obj.save()
class Signature(models.Model):
"""Signature model"""
name = models.CharField(max_length=100, help_text="Signature name")
data = models.TextField(max_length=200, help_text="Signature description")
author = models.ForeignKey(Author, on_delete=models.CASCADE)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
def __str__(self):
"""To string"""
return self.name
class Book(models.Model):
"""Test model"""
title = models.CharField(max_length=100)
author = models.ForeignKey(Author, on_delete=models.CASCADE)
description = models.TextField(max_length=100)
signature = models.TextField(max_length=100)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
def __str__(self):
"""To string"""
return self.title
def get_author_name(self):
"""Get author name"""
return self.author.name
def set_author(self, author_obj:'Author'):
"""Set author"""
if author_obj is None:
raise ValueError("Author is required")
if author_obj.get_books().count() > 5:
raise ValueError("Author has too many books")
self.author = author_obj
self.save()
def set_signutare(self):
"""Set signature"""
signature_obj = Signature.objects.filter(author_id=self.author.id).first()
if signature_obj is None:
raise ValueError("Signature not found")
self.signature = signature_obj
self.save()
class AuthorSerializer(serializers.ModelSerializer):
"""Author serializer"""
class Meta:
model = Author
fields = '__all__'
class AuthorViewSet(viewsets.ModelViewSet):
"""Author view set"""
queryset = Author.objects.all()
serializer_class = AuthorSerializer
permission_classes = [permissions.IsAuthenticatedOrReadOnly]
@decorators.action(
detail=False, methods=['get'],
url_path='find-author', url_name='find-author')
def find_author(self, *args, **kwargs):
"""Get author name"""
name = self.request.query_params.get('name', '')
return Response({ "data": name })
@decorators.action(
detail=True, methods=['post'],
url_path='create-signature', url_name='create-signature')
def create_signature(self, *args, **kwargs):
"""Get author name"""
print(self.request.data)
return Response({ "data": "created" })
This is the error from Pylance
This is a known issue. These fields are added dynamically by django and there's currently no way in the Python type system to tell a static type checker that they will exist.
General improvements for django are tracked by #3701
@debonte In version v2024.8.1. I didn't face this issue. Please see my screenshot for version 2024.8.1
The same issue rears its head elsewhere when using dynamic model fetching, in this example with djangorestframework's get_object().
As a result, any type inferences for children and children's children of that object (in this instance, company) get mangled into NoReturn too, and no intellisense.
In pylance==2024.9.2, everything works as expected:
As far as I can tell, this particular invocation of the issue arises in djangorestframework's GenericAPIView.get_object().
In pylance==2024.9.2, this function is evaluated to return Any.
In pylance==2024.10.1, the function is evaluated to return NoReturn - despite the fact that obj is Any during the return statement (for clarity, Django's get_object_or_404() is evaluated to return Any):
NoReturn generally means Pylance/Pyright thinks the function is throwing an exception. Looking at that code, maybe that's a bug in Pyright? It must think the assert always fires?
@luanft, from the logs, I see Loading configuration file at /home/users/luant/proj/django-ipds/pyrightconfig.json, which indicates that you have a configuration file in your workspace. In this case, there's a recent change we make such that the config file takes precedence, and certain settings, including typeCheckingMode, will be applied regardless of what's set in settings.json.
What's causing confusion is probably that the default value for typeCheckingMode in a pyrightconfig.json file is standard if not explicitly specified, whereas the default in settings.json is off. So, when the pyrightconfig file is present, the standard mode is applied to your workspace, enabling multiple diagnostic rules.
I think we could improve clarity by adding more detail to the warning message when typeCheckingMode is overridden by the configuration file
@luanft, from the logs, I see
Loading configuration file at /home/users/luant/proj/django-ipds/pyrightconfig.json, which indicates that you have a configuration file in your workspace. In this case, there's a recent change we make such that the config file takes precedence, and certain settings, includingtypeCheckingMode, will be applied regardless of what's set insettings.json.What's causing confusion is probably that the default value for
typeCheckingModein apyrightconfig.jsonfile isstandardif not explicitly specified, whereas the default insettings.jsonisoff. So, when thepyrightconfigfile is present, thestandardmode is applied to your workspace, enabling multiple diagnostic rules.I think we could improve clarity by adding more detail to the warning message when
typeCheckingModeis overridden by the configuration file
@StellaHuang95 This is my pyright configuration file. I didn't define the typeCheckingMode in the pyright configuration file
{
"exclude": [
"db_conversion/**",
"ipds/templates/**",
"ipds/static/**"
],
"include": [
"ipds/**",
"ipds/**/**"
]
}
@luanft Right, so two things are happening here:
-
When a
pyrightconfig.jsonfile is present, any settings that can be specified in the config file will override those insettings.json. -
If
typeCheckingModeis not explicitly set inpyrightconfig.json, the default valuestandardtakes precedence over theoffvalue insettings.json.
I hope this clears up the confusion. To get the same behavior, you can add "typeCheckingMode": "off" to your pyrightconfig.json
@StellaHuang95 Thank you, define typeCheckingMode = off in pyright config worked for me.