diff --git a/DjangoLint/AstCheckers/__init__.py b/DjangoLint/AstCheckers/__init__.py index d3c8d26..f0b73c0 100644 --- a/DjangoLint/AstCheckers/__init__.py +++ b/DjangoLint/AstCheckers/__init__.py @@ -20,11 +20,13 @@ def register(linter): from size import SizeChecker + from admin import AdminChecker from settings import SettingsChecker from model_fields import ModelFieldsChecker from model_methods import ModelMethodsChecker linter.register_checker(SizeChecker(linter)) + linter.register_checker(AdminChecker(linter)) linter.register_checker(SettingsChecker(linter)) linter.register_checker(ModelFieldsChecker(linter)) linter.register_checker(ModelMethodsChecker(linter)) diff --git a/DjangoLint/AstCheckers/admin.py b/DjangoLint/AstCheckers/admin.py new file mode 100644 index 0000000..96ae4e1 --- /dev/null +++ b/DjangoLint/AstCheckers/admin.py @@ -0,0 +1,57 @@ +# -*- coding: utf-8 -*- + +# django-lint -- Static analysis tool for Django projects and applications +# Copyright (C) 2008-2009 Chris Lamb +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +from pylint.interfaces import IASTNGChecker +from pylint.checkers import BaseChecker + +from .utils import nodeisinstance + +class AdminChecker(BaseChecker): + __implements__ = IASTNGChecker + + name = 'django_admin' + msgs = { + 'W8020': ( + 'Admin class %r not in admin.py', + 'loldongs',), + } + + ADMIN_BASE_CLASSES = ( + 'django.contrib.admin.options.ModelAdmin', + ) + + def visit_module(self, node): + self.module = node + + def leave_class(self, node): + if not nodeisinstance(node, self.ADMIN_BASE_CLASSES): + return + + if not self.module.file.endswith('admin.py'): + # Admin classes not in an app's admin.py can cause circular import + # problems throughout a project. + # + # This is because registering an admin class implies a call to + # models.get_apps() which attempts to import *every* models.py in + # the project. + # + # Whilst your project should probably not have significant + # inter-app dependencies, importing every possible models.py does + # not help the situation and can cause ImportError when models are + # loaded in different scenarios. + self.add_message('W8020', node=node, args=(node.name,)) diff --git a/django_lint_example/example/models/__init__.py b/django_lint_example/example/models/__init__.py index 7c76175..92357e5 100644 --- a/django_lint_example/example/models/__init__.py +++ b/django_lint_example/example/models/__init__.py @@ -1,4 +1,5 @@ from django.db import models +from django.contrib import admin class NullableModel(models.Model): TRUTH_VALUE = True @@ -165,3 +166,9 @@ class WeirdPrimaryKeyModel(models.Model): class ManyToManyModel(models.Model): nullable = models.ManyToManyField(Model2, null=True) blank = models.ManyToManyField(Model3, blank=True) + +class AdminKlass(admin.ModelAdmin): + search_fields = ('nullable',) + + class Meta: + model = ManyToManyModel