-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implemented flake8-django plugin rules #2586
Merged
Merged
Changes from all commits
Commits
Show all changes
18 commits
Select commit
Hold shift + click to select a range
5e0d097
Implemented "DJ08 Model does not define __str__ method" rule
konysko 0fb719a
Implemented "DJ13 @receiver decorator must be on top of all the other…
konysko 91d0df1
Implemented rule "DJ01 Avoid using null=True on string-based fields s…
konysko 23a9343
Merge branch 'main' into flake8-django
konysko 9bf68ff
Run clippy and fixes after merge main
konysko 45bc680
Merge branch 'main' into flake8-django
konysko 6f35738
Fixes after merge with main
konysko 4648073
Split code into separate files and applied fixes after review
konysko bb494e2
Copied fixtures from original library and applied suggestions from re…
konysko eb9c63b
Merge branch 'main' into flake8-django
konysko 2c1b7ec
Fixes after running clippy
konysko c9a8078
Added checking path of model field whether its actually imported from…
konysko af06b75
Update README; run Black over fixtures
charliermarsh 057585a
Merge branch 'main' into flake8-django
charliermarsh e00b7ad
Use named fields
charliermarsh e96d61b
Check receiver first
charliermarsh 41d9fd7
Rename to DJ001 etc
charliermarsh 56d3a09
Add docs
charliermarsh File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
39 changes: 39 additions & 0 deletions
39
crates/ruff/resources/test/fixtures/flake8_django/DJ001.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
from django.db.models import Model as DjangoModel | ||
from django.db import models | ||
from django.db.models import CharField as SmthCharField | ||
|
||
|
||
class IncorrectModel(models.Model): | ||
charfield = models.CharField(max_length=255, null=True) | ||
textfield = models.TextField(max_length=255, null=True) | ||
slugfield = models.SlugField(max_length=255, null=True) | ||
emailfield = models.EmailField(max_length=255, null=True) | ||
filepathfield = models.FilePathField(max_length=255, null=True) | ||
urlfield = models.URLField(max_length=255, null=True) | ||
|
||
|
||
class IncorrectModelWithAliasedBase(DjangoModel): | ||
charfield = DjangoModel.CharField(max_length=255, null=True) | ||
textfield = SmthCharField(max_length=255, null=True) | ||
slugfield = models.SlugField(max_length=255, null=True) | ||
emailfield = models.EmailField(max_length=255, null=True) | ||
filepathfield = models.FilePathField(max_length=255, null=True) | ||
urlfield = models.URLField(max_length=255, null=True) | ||
|
||
|
||
class CorrectModel(models.Model): | ||
charfield = models.CharField(max_length=255, null=False, blank=True) | ||
textfield = models.TextField(max_length=255, null=False, blank=True) | ||
slugfield = models.SlugField(max_length=255, null=False, blank=True) | ||
emailfield = models.EmailField(max_length=255, null=False, blank=True) | ||
filepathfield = models.FilePathField(max_length=255, null=False, blank=True) | ||
urlfield = models.URLField(max_length=255, null=False, blank=True) | ||
|
||
charfieldu = models.CharField(max_length=255, null=True, blank=True, unique=True) | ||
textfieldu = models.TextField(max_length=255, null=True, blank=True, unique=True) | ||
slugfieldu = models.SlugField(max_length=255, null=True, blank=True, unique=True) | ||
emailfieldu = models.EmailField(max_length=255, null=True, blank=True, unique=True) | ||
filepathfieldu = models.FilePathField( | ||
max_length=255, null=True, blank=True, unique=True | ||
) | ||
urlfieldu = models.URLField(max_length=255, null=True, blank=True, unique=True) |
167 changes: 167 additions & 0 deletions
167
crates/ruff/resources/test/fixtures/flake8_django/DJ008.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,167 @@ | ||
from django.db import models | ||
from django.db.models import Model | ||
|
||
|
||
# Models without __str__ | ||
class TestModel1(models.Model): | ||
new_field = models.CharField(max_length=10) | ||
|
||
class Meta: | ||
verbose_name = "test model" | ||
verbose_name_plural = "test models" | ||
|
||
@property | ||
def my_brand_new_property(self): | ||
return 1 | ||
|
||
def my_beautiful_method(self): | ||
return 2 | ||
|
||
|
||
class TestModel2(Model): | ||
new_field = models.CharField(max_length=10) | ||
|
||
class Meta: | ||
verbose_name = "test model" | ||
verbose_name_plural = "test models" | ||
|
||
@property | ||
def my_brand_new_property(self): | ||
return 1 | ||
|
||
def my_beautiful_method(self): | ||
return 2 | ||
|
||
|
||
class TestModel3(Model): | ||
new_field = models.CharField(max_length=10) | ||
|
||
class Meta: | ||
abstract = False | ||
|
||
@property | ||
def my_brand_new_property(self): | ||
return 1 | ||
|
||
def my_beautiful_method(self): | ||
return 2 | ||
|
||
|
||
# Models with __str__ | ||
class TestModel4(Model): | ||
new_field = models.CharField(max_length=10) | ||
|
||
class Meta: | ||
verbose_name = "test model" | ||
verbose_name_plural = "test models" | ||
|
||
def __str__(self): | ||
return self.new_field | ||
|
||
@property | ||
def my_brand_new_property(self): | ||
return 1 | ||
|
||
def my_beautiful_method(self): | ||
return 2 | ||
|
||
|
||
class TestModel5(models.Model): | ||
new_field = models.CharField(max_length=10) | ||
|
||
class Meta: | ||
verbose_name = "test model" | ||
verbose_name_plural = "test models" | ||
|
||
def __str__(self): | ||
return self.new_field | ||
|
||
@property | ||
def my_brand_new_property(self): | ||
return 1 | ||
|
||
def my_beautiful_method(self): | ||
return 2 | ||
|
||
|
||
# Abstract models without str | ||
class AbstractTestModel1(models.Model): | ||
new_field = models.CharField(max_length=10) | ||
|
||
class Meta: | ||
abstract = True | ||
|
||
@property | ||
def my_brand_new_property(self): | ||
return 1 | ||
|
||
def my_beautiful_method(self): | ||
return 2 | ||
|
||
|
||
class AbstractTestModel2(Model): | ||
new_field = models.CharField(max_length=10) | ||
|
||
class Meta: | ||
abstract = True | ||
|
||
@property | ||
def my_brand_new_property(self): | ||
return 1 | ||
|
||
def my_beautiful_method(self): | ||
return 2 | ||
|
||
|
||
# Abstract models with __str__ | ||
|
||
|
||
class AbstractTestModel3(Model): | ||
new_field = models.CharField(max_length=10) | ||
|
||
class Meta: | ||
abstract = True | ||
|
||
def __str__(self): | ||
return self.new_field | ||
|
||
@property | ||
def my_brand_new_property(self): | ||
return 1 | ||
|
||
def my_beautiful_method(self): | ||
return 2 | ||
|
||
|
||
class AbstractTestModel4(models.Model): | ||
new_field = models.CharField(max_length=10) | ||
|
||
class Meta: | ||
abstract = True | ||
|
||
def __str__(self): | ||
return self.new_field | ||
|
||
@property | ||
def my_brand_new_property(self): | ||
return 1 | ||
|
||
def my_beautiful_method(self): | ||
return 2 | ||
|
||
|
||
class AbstractTestModel5(models.Model): | ||
new_field = models.CharField(max_length=10) | ||
|
||
class Meta: | ||
abstract = False | ||
|
||
def __str__(self): | ||
return self.new_field | ||
|
||
@property | ||
def my_brand_new_property(self): | ||
return 1 | ||
|
||
def my_beautiful_method(self): | ||
return 2 |
17 changes: 17 additions & 0 deletions
17
crates/ruff/resources/test/fixtures/flake8_django/DJ013.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
from django.db.models.signals import pre_save | ||
from django.dispatch import receiver | ||
from myapp.models import MyModel | ||
|
||
test_decorator = lambda func: lambda *args, **kwargs: func(*args, **kwargs) | ||
|
||
|
||
@receiver(pre_save, sender=MyModel) | ||
@test_decorator | ||
def correct_pre_save_handler(): | ||
pass | ||
|
||
|
||
@test_decorator | ||
@receiver(pre_save, sender=MyModel) | ||
def incorrect_pre_save_handler(): | ||
pass |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
//! Rules from [django-flake8](https://pypi.org/project/flake8-django/) | ||
pub(crate) mod rules; | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use std::path::Path; | ||
|
||
use anyhow::Result; | ||
use test_case::test_case; | ||
|
||
use crate::registry::Rule; | ||
use crate::test::test_path; | ||
use crate::{assert_yaml_snapshot, settings}; | ||
|
||
#[test_case(Rule::ModelStringFieldNullable, Path::new("DJ001.py"); "DJ001")] | ||
#[test_case(Rule::ModelDunderStr, Path::new("DJ008.py"); "DJ008")] | ||
#[test_case(Rule::ReceiverDecoratorChecker, Path::new("DJ013.py"); "DJ013")] | ||
fn rules(rule_code: Rule, path: &Path) -> Result<()> { | ||
let snapshot = format!("{}_{}", rule_code.code(), path.to_string_lossy()); | ||
let diagnostics = test_path( | ||
Path::new("flake8_django").join(path).as_path(), | ||
&settings::Settings::for_rule(rule_code), | ||
)?; | ||
assert_yaml_snapshot!(snapshot, diagnostics); | ||
Ok(()) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
use rustpython_parser::ast::Expr; | ||
|
||
use crate::checkers::ast::Checker; | ||
|
||
/// Return `true` if a Python class appears to be a Django model based on a base class. | ||
pub fn is_model(checker: &Checker, base: &Expr) -> bool { | ||
checker.resolve_call_path(base).map_or(false, |call_path| { | ||
call_path.as_slice() == ["django", "db", "models", "Model"] | ||
}) | ||
} | ||
|
||
pub fn get_model_field_name<'a>(checker: &'a Checker, expr: &'a Expr) -> Option<&'a str> { | ||
checker.resolve_call_path(expr).and_then(|call_path| { | ||
let call_path = call_path.as_slice(); | ||
if !call_path.starts_with(&["django", "db", "models"]) { | ||
return None; | ||
} | ||
call_path.last().copied() | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
mod helpers; | ||
mod model_dunder_str; | ||
mod model_string_field_nullable; | ||
mod receiver_decorator_checker; | ||
|
||
pub use model_dunder_str::{model_dunder_str, ModelDunderStr}; | ||
pub use model_string_field_nullable::{model_string_field_nullable, ModelStringFieldNullable}; | ||
pub use receiver_decorator_checker::{receiver_decorator_checker, ReceiverDecoratorChecker}; |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Controversially, I renamed these to add a leading zero. It deviates from upstream, but it's much more consistent with the other plugins.