pylint-django-2.0.13/0000755000175000017500000000000013566222372013726 5ustar josephjosephpylint-django-2.0.13/CONTRIBUTORS.md0000644000175000017500000000120413560025137016174 0ustar josephjoseph* [carlio](https://github.com/carlio) * [mbarrien](https://github.com/mbarrien) * [frost-nzcr4](https://github.com/frost-nzcr4) * [ustun](https://github.com/ustun) * [jproffitt](https://github.com/jproffitt) * [lhupfeldt](https://github.com/lhupfeldt) * [smirolo](https://github.com/smirolo) * [mbertolacci](https://github.com/mbertolacci) * [atodorov](https://github.com/atodorov) * [bittner](https://github.com/bittner) * [federicobond](https://github.com/federicobond) * [matusvalo](https://github.com/matusvalo) * [fadedDexofan](https://github.com/fadeddexofan) * [imomaliev](https://github.com/imomaliev) * [psrb](https://github.com/psrb) pylint-django-2.0.13/pylint_django/0000755000175000017500000000000013566222372016567 5ustar josephjosephpylint-django-2.0.13/pylint_django/checkers/0000755000175000017500000000000013566222372020356 5ustar josephjosephpylint-django-2.0.13/pylint_django/checkers/__init__.py0000644000175000017500000000104213510363306022454 0ustar josephjoseph"""Checkers.""" from pylint_django.checkers.django_installed import DjangoInstalledChecker from pylint_django.checkers.models import ModelChecker from pylint_django.checkers.json_response import JsonResponseChecker from pylint_django.checkers.forms import FormChecker def register_checkers(linter): """Register checkers.""" linter.register_checker(ModelChecker(linter)) linter.register_checker(DjangoInstalledChecker(linter)) linter.register_checker(JsonResponseChecker(linter)) linter.register_checker(FormChecker(linter)) pylint-django-2.0.13/pylint_django/checkers/forms.py0000644000175000017500000000273513510363306022055 0ustar josephjoseph"""Models.""" from astroid.nodes import Assign, ClassDef from pylint.interfaces import IAstroidChecker from pylint.checkers.utils import check_messages from pylint.checkers import BaseChecker from pylint_django.__pkginfo__ import BASE_ID from pylint_django.utils import node_is_subclass def _get_child_meta(node): for child in node.get_children(): if isinstance(child, ClassDef) and child.name == 'Meta': return child return None class FormChecker(BaseChecker): """Django model checker.""" __implements__ = IAstroidChecker name = 'django-form-checker' msgs = { 'W%d04' % BASE_ID: ("Use explicit fields instead of exclude in ModelForm", 'modelform-uses-exclude', "Prevents accidentally allowing users to set fields, " "especially when adding new fields to a Model") } @check_messages('modelform-uses-exclude') def visit_classdef(self, node): """Class visitor.""" if not node_is_subclass(node, 'django.forms.models.ModelForm', '.ModelForm'): # we only care about forms return meta = _get_child_meta(node) if not meta: return for child in meta.get_children(): if not isinstance(child, Assign): continue if child.targets[0].name == 'exclude': self.add_message('W%s04' % BASE_ID, node=child) break pylint-django-2.0.13/pylint_django/checkers/django_installed.py0000644000175000017500000000210213265451424024222 0ustar josephjosephfrom __future__ import absolute_import from pylint.checkers import BaseChecker from pylint.checkers.utils import check_messages from pylint_django.__pkginfo__ import BASE_ID class DjangoInstalledChecker(BaseChecker): name = 'django-installed-checker' msgs = { 'F%s01' % BASE_ID: ("Django is not available on the PYTHONPATH", 'django-not-available', "Django could not be imported by the pylint-django plugin, so most Django related " "improvements to pylint will fail."), 'W%s99' % BASE_ID: ('Placeholder message to prevent disabling of checker', 'django-not-available-placeholder', 'PyLint does not recognise checkers as being enabled unless they have at least' ' one message which is not fatal...') } @check_messages('django-not-available') def close(self): try: __import__('django') except ImportError: self.add_message('F%s01' % BASE_ID) pylint-django-2.0.13/pylint_django/checkers/json_response.py0000644000175000017500000000537413510363306023620 0ustar josephjoseph# Copyright (c) 2018 Alexander Todorov # Licensed under the GPL 2.0: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html # For details: https://github.com/PyCQA/pylint-django/blob/master/LICENSE """ Various suggestions about JSON http responses """ import astroid from pylint import interfaces, checkers from pylint.checkers import utils from pylint_django.__pkginfo__ import BASE_ID class JsonResponseChecker(checkers.BaseChecker): """ Looks for some common patterns when returning http responses containing JSON data! """ __implements__ = (interfaces.IAstroidChecker,) # configuration section name name = 'json-response-checker' msgs = {'R%s01' % BASE_ID: ("Instead of HttpResponse(json.dumps(data)) use JsonResponse(data)", 'http-response-with-json-dumps', 'Used when json.dumps() is used as an argument to HttpResponse().'), 'R%s02' % BASE_ID: ("Instead of HttpResponse(content_type='application/json') use JsonResponse()", 'http-response-with-content-type-json', 'Used when HttpResponse() is returning application/json.'), 'R%s03' % BASE_ID: ("Redundant content_type parameter for JsonResponse()", 'redundant-content-type-for-json-response', 'Used when JsonResponse() contains content_type parameter. ' 'This is either redundant or the content_type is not JSON ' 'which is probably an error.')} @utils.check_messages('http-response-with-json-dumps', 'http-response-with-content-type-json', 'redundant-content-type-for-json-response') def visit_call(self, node): if (node.func.as_string().endswith('HttpResponse') and node.args and isinstance(node.args[0], astroid.Call) and node.args[0].func.as_string() == 'json.dumps'): self.add_message('http-response-with-json-dumps', node=node) if node.func.as_string().endswith('HttpResponse') and node.keywords: for keyword in node.keywords: if (keyword.arg == 'content_type' and keyword.value.as_string().lower().find('application/json') > -1): self.add_message('http-response-with-content-type-json', node=node) break if node.func.as_string().endswith('JsonResponse') and node.keywords: for keyword in node.keywords: if keyword.arg == 'content_type': self.add_message('redundant-content-type-for-json-response', node=node) break pylint-django-2.0.13/pylint_django/checkers/db_performance.py0000644000175000017500000001102413510363317023666 0ustar josephjoseph# Copyright (c) 2018 Alexander Todorov # Licensed under the GPL 2.0: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html # For details: https://github.com/PyCQA/pylint-django/blob/master/LICENSE """ Various DB performance suggestions. Disabled by default! Enable with pylint --load-plugins=pylint_django.checkers.db_performance """ import astroid from pylint import interfaces from pylint import checkers from pylint.checkers import utils from pylint_django.__pkginfo__ import BASE_ID from pylint_django import compat def _is_addfield_with_default(call): if not isinstance(call.func, astroid.Attribute): return False if not call.func.attrname == 'AddField': return False for keyword in call.keywords: # looking for AddField(..., field=XXX(..., default=Y, ...), ...) if keyword.arg == 'field' and isinstance(keyword.value, astroid.Call): # loop over XXX's keywords # NOTE: not checking if XXX is an actual field type because there could # be many types we're not aware of. Also the migration will probably break # if XXX doesn't instantiate a field object! for field_keyword in keyword.value.keywords: if field_keyword.arg == 'default': return True return False def _is_migrations_module(node): if not isinstance(node, astroid.Module): return False return 'migrations' in node.path[0] and not node.path[0].endswith('__init__.py') class NewDbFieldWithDefaultChecker(checkers.BaseChecker): """ Looks for migrations which add new model fields and these fields have a default value. According to Django docs this may have performance penalties especially on large tables: https://docs.djangoproject.com/en/2.0/topics/migrations/#postgresql The prefered way is to add a new DB column with null=True because it will be created instantly and then possibly populate the table with the desired default values. """ __implements__ = (interfaces.IAstroidChecker,) # configuration section name name = 'new-db-field-with-default' msgs = {'W%s98' % BASE_ID: ("%s AddField with default value", 'new-db-field-with-default', 'Used when Pylint detects migrations adding new ' 'fields with a default value.')} _migration_modules = [] _possible_offences = {} def visit_module(self, node): if _is_migrations_module(node): self._migration_modules.append(node) def visit_call(self, node): try: module = node.frame().parent except: # noqa: E722, pylint: disable=bare-except return if not _is_migrations_module(module): return if _is_addfield_with_default(node): if module not in self._possible_offences: self._possible_offences[module] = [] if node not in self._possible_offences[module]: self._possible_offences[module].append(node) @utils.check_messages('new-db-field-with-default') def close(self): def _path(node): return node.path # sort all migrations by name in reverse order b/c # we need only the latest ones self._migration_modules.sort(key=_path, reverse=True) # filter out the last migration modules under each distinct # migrations directory, iow leave only the latest migrations # for each application last_name_space = '' latest_migrations = [] for module in self._migration_modules: name_space = module.path[0].split('migrations')[0] if name_space != last_name_space: last_name_space = name_space latest_migrations.append(module) for module, nodes in self._possible_offences.items(): if module in latest_migrations: for node in nodes: self.add_message('new-db-field-with-default', args=module.name, node=node) def load_configuration(linter): # don't blacklist migrations for this checker new_black_list = list(linter.config.black_list) if 'migrations' in new_black_list: new_black_list.remove('migrations') linter.config.black_list = new_black_list def register(linter): """Required method to auto register this checker.""" linter.register_checker(NewDbFieldWithDefaultChecker(linter)) if not compat.LOAD_CONFIGURATION_SUPPORTED: load_configuration(linter) pylint-django-2.0.13/pylint_django/checkers/models.py0000644000175000017500000001123113510363306022201 0ustar josephjoseph"""Models.""" from astroid import Const from astroid.nodes import Assign from astroid.nodes import ClassDef, FunctionDef, AssignName from pylint.interfaces import IAstroidChecker from pylint.checkers.utils import check_messages from pylint.checkers import BaseChecker from pylint_django.__pkginfo__ import BASE_ID from pylint_django.utils import node_is_subclass, PY3 MESSAGES = { 'E%d01' % BASE_ID: ("__unicode__ on a model must be callable (%s)", 'model-unicode-not-callable', "Django models require a callable __unicode__ method"), 'W%d01' % BASE_ID: ("No __unicode__ method on model (%s)", 'model-missing-unicode', "Django models should implement a __unicode__ method for string representation"), 'W%d02' % BASE_ID: ("Found __unicode__ method on model (%s). Python3 uses __str__.", 'model-has-unicode', "Django models should not implement a __unicode__ " "method for string representation when using Python3"), 'W%d03' % BASE_ID: ("Model does not explicitly define __unicode__ (%s)", 'model-no-explicit-unicode', "Django models should implement a __unicode__ method for string representation. " "A parent class of this model does, but ideally all models should be explicit.") } def _is_meta_with_abstract(node): if isinstance(node, ClassDef) and node.name == 'Meta': for meta_child in node.get_children(): if not isinstance(meta_child, Assign): continue if not meta_child.targets[0].name == 'abstract': continue if not isinstance(meta_child.value, Const): continue # TODO: handle tuple assignment? # eg: # abstract, something_else = True, 1 if meta_child.value.value: # this class is abstract return True return False def _has_python_2_unicode_compatible_decorator(node): if node.decorators is None: return False for decorator in node.decorators.nodes: if getattr(decorator, 'name', None) == 'python_2_unicode_compatible': return True return False def _is_unicode_or_str_in_python_2_compatibility(method): if method.name == '__unicode__': return True if method.name == '__str__' and _has_python_2_unicode_compatible_decorator(method.parent): return True return False class ModelChecker(BaseChecker): """Django model checker.""" __implements__ = IAstroidChecker name = 'django-model-checker' msgs = MESSAGES @check_messages('model-missing-unicode') def visit_classdef(self, node): """Class visitor.""" if not node_is_subclass(node, 'django.db.models.base.Model', '.Model'): # we only care about models return for child in node.get_children(): if _is_meta_with_abstract(child): return if isinstance(child, Assign): grandchildren = list(child.get_children()) if not isinstance(grandchildren[0], AssignName): continue name = grandchildren[0].name if name != '__unicode__': continue grandchild = grandchildren[1] assigned = grandchild.inferred()[0] if assigned.callable(): return self.add_message('E%s01' % BASE_ID, args=node.name, node=node) return if isinstance(child, FunctionDef) and child.name == '__unicode__': if PY3: self.add_message('W%s02' % BASE_ID, args=node.name, node=node) return # if we get here, then we have no __unicode__ method directly on the class itself # a different warning is emitted if a parent declares __unicode__ for method in node.methods(): if method.parent != node and _is_unicode_or_str_in_python_2_compatibility(method): # this happens if a parent declares the unicode method but # this node does not self.add_message('W%s03' % BASE_ID, args=node.name, node=node) return # if the Django compatibility decorator is used then we don't emit a warning # see https://github.com/PyCQA/pylint-django/issues/10 if _has_python_2_unicode_compatible_decorator(node): return if PY3: return self.add_message('W%s01' % BASE_ID, args=node.name, node=node) pylint-django-2.0.13/pylint_django/__init__.py0000644000175000017500000000064713510363317020701 0ustar josephjoseph"""pylint_django module.""" from __future__ import absolute_import import sys from pylint_django import plugin if sys.version_info < (3, ): raise DeprecationWarning("Version 0.11.1 was the last to support Python 2. " "Please migrate to Python 3!") register = plugin.register # pylint: disable=invalid-name load_configuration = plugin.load_configuration # pylint: disable=invalid-name pylint-django-2.0.13/pylint_django/tests/0000755000175000017500000000000013566222372017731 5ustar josephjosephpylint-django-2.0.13/pylint_django/tests/input/0000755000175000017500000000000013566222372021070 5ustar josephjosephpylint-django-2.0.13/pylint_django/tests/input/func_noerror_uuid_field.py0000644000175000017500000000110013510363306026314 0ustar josephjoseph""" Checks that Pylint does not complain about UUID fields. """ # pylint: disable=C0111,W5101 from __future__ import print_function from django.db import models class LotsOfFieldsModel(models.Model): uuidfield = models.UUIDField() def uuidfield_tests(self): print(self.uuidfield.bytes) print(self.uuidfield.bytes_le) print(self.uuidfield.fields[2]) print(self.uuidfield.hex) # print(self.uuidfield.int) # Don't know how to properly check this one print(self.uuidfield.variant) print(self.uuidfield.version) pylint-django-2.0.13/pylint_django/tests/input/func_noerror_model_objects.py0000644000175000017500000000073013510363306027024 0ustar josephjoseph# Test that defining `objects` as a regular model manager # doesn't raise issues, see # https://github.com/PyCQA/pylint-django/issues/144 # # pylint: disable=missing-docstring from django.db import models class ModelWithRegularManager(models.Model): objects = models.Manager() name = models.CharField() def function(): record = ModelWithRegularManager.objects.all()[0] for record in ModelWithRegularManager.objects.all(): print(record.name) pylint-django-2.0.13/pylint_django/tests/input/func_noerror_foreign_key_sets.py0000644000175000017500000000141113510363306027547 0ustar josephjoseph""" Checks that Pylint does not complain about foreign key sets on models """ # pylint: disable=missing-docstring from django.db import models class SomeModel(models.Model): name = models.CharField(max_length=20) def get_others(self): return self.othermodel_set.all() def get_first(self): return self.othermodel_set.first() class OtherModel(models.Model): count = models.IntegerField() something = models.ForeignKey(SomeModel, on_delete=models.CASCADE) class ThirdModel(models.Model): whatever = models.ForeignKey(SomeModel, related_name='whatevs', on_delete=models.CASCADE) def count_whatevers(): if SomeModel().whatevs.exists(): return SomeModel().whatevs.count() return -1 pylint-django-2.0.13/pylint_django/tests/input/func_noerror_test_wsgi_request.py0000644000175000017500000000106613510363306027776 0ustar josephjoseph""" Checks that Pylint does not complain about a standard test. See: https://github.com/PyCQA/pylint-django/issues/78 """ from django.test import TestCase from django.db import models class SomeModel(models.Model): """Just a model.""" class SomeTestCase(TestCase): """A test cast.""" def test_thing(self): """Test a thing.""" expected_object = SomeModel() response = self.client.get('/get/some/thing/') self.assertEqual(response.status_code, 200) self.assertEqual(response.context['object'], expected_object) pylint-django-2.0.13/pylint_django/tests/input/func_noerror_formview_ancestors.py0000644000175000017500000000032213510363306030127 0ustar josephjoseph""" Checks that Pylint does not complain about django FormViews having too many ancestors """ # pylint: disable=missing-docstring from django.views.generic import FormView class SomeView(FormView): pass pylint-django-2.0.13/pylint_django/tests/input/func_noerror_ignore_meta_subclass.py0000644000175000017500000000044713510363306030410 0ustar josephjoseph""" This test ensures that a 'Meta' class defined on a Django model does not raise warnings such as 'old-style-class' and 'too-few-public-methods' """ # pylint: disable=missing-docstring from django.db import models class SomeModel(models.Model): class Meta: ordering = ('-id',) pylint-django-2.0.13/pylint_django/tests/input/func_noerror_foreign_key_attributes.py0000644000175000017500000000114613510363306030764 0ustar josephjoseph""" Checks that Pylint does not complain about foreign key sets on models """ # pylint: disable=missing-docstring from django.db import models class SomeModel(models.Model): name = models.CharField(max_length=20) timestamp = models.DateTimeField() class OtherModel(models.Model): something = models.ForeignKey(SomeModel, on_delete=models.CASCADE) elsething = models.OneToOneField(SomeModel, on_delete=models.CASCADE) def something_doer(self): part_a = '%s - %s' % (self.something.name, self.something.timestamp) part_b = self.elsething.name return part_a, part_b pylint-django-2.0.13/pylint_django/tests/input/external_model_utils_noerror_override_manager.py0000644000175000017500000000162413510363306033016 0ustar josephjoseph# Check that when overriding the 'objects' attribite of a model class # with a manager from the django-model-utils package pylint-django # does not report not-an-iterator error, see # https://github.com/PyCQA/pylint-django/issues/117 # pylint: disable=missing-docstring, invalid-name from model_utils.managers import InheritanceManager from django.db import models class BaseModel(models.Model): name = models.CharField() class BuggyModel(models.Model): objects = InheritanceManager() name = models.CharField() def function(): for record in BaseModel.objects.all(): print(record.name) for record in BuggyModel.objects.all(): print(record.name) class Unit(models.Model): sim = models.CharField(max_length=64, null=True, blank=True) objects = InheritanceManager() installed_units = Unit.objects.filter(sim__isnull=False) ids = [u.sim for u in installed_units] pylint-django-2.0.13/pylint_django/tests/input/func_modelform_exclude.py0000644000175000017500000000035713510363306026147 0ustar josephjoseph""" Checks that Pylint complains about ModelForm using exclude """ # pylint: disable=missing-docstring from django import forms class PersonForm(forms.ModelForm): class Meta: exclude = ('email',) # [modelform-uses-exclude] pylint-django-2.0.13/pylint_django/tests/input/func_noerror_foreign_key_ids.py0000644000175000017500000000067313510363306027361 0ustar josephjoseph""" Checks that Pylint does not complain about foreign key id access """ # pylint: disable=missing-docstring,wrong-import-position from django.db import models class SomeModel(models.Model): count = models.IntegerField() class SomeOtherModel(models.Model): some_model = models.ForeignKey(SomeModel, on_delete=models.CASCADE) number = models.IntegerField() def do_something(self): self.number = self.some_model_id pylint-django-2.0.13/pylint_django/tests/input/__init__.py0000644000175000017500000000000013510363306023157 0ustar josephjosephpylint-django-2.0.13/pylint_django/tests/input/func_model_no_explicit_unicode_str_compat.py0000644000175000017500000000076613510363306032114 0ustar josephjoseph""" Ensures that django models with a __str__ method defined in an ancestor and python_2_unicode_compatible decorator applied are flagged correctly as not having explicitly defined __unicode__ """ # pylint: disable=missing-docstring from django.db import models from django.utils.encoding import python_2_unicode_compatible @python_2_unicode_compatible class BaseModel(models.Model): def __str__(self): return 'Foo' class SomeModel(BaseModel): # [model-no-explicit-unicode] pass pylint-django-2.0.13/pylint_django/tests/input/func_noerror_forms_py33.py0000644000175000017500000000107313510363306026220 0ustar josephjoseph""" Checks that Pylint does not complain about django Forms """ # pylint: disable=missing-docstring,wrong-import-position from django import forms class TestForm(forms.Form): class Meta: pass some_field = forms.CharField() def clean(self): print(self.cleaned_data) print(self.fields) print(self.error_class) class TestModelForm(forms.ModelForm): class Meta: pass class TestFormSubclass(forms.Form): class Meta: pass class TestModelFormSubclass(forms.ModelForm): class Meta: pass pylint-django-2.0.13/pylint_django/tests/input/func_json_response.txt0000644000175000017500000000072113510363306025523 0ustar josephjosephhttp-response-with-json-dumps:9:say_yes:Instead of HttpResponse(json.dumps(data)) use JsonResponse(data) http-response-with-json-dumps:14:say_yes2:Instead of HttpResponse(json.dumps(data)) use JsonResponse(data) redundant-content-type-for-json-response:23:redundant_content_type:Redundant content_type parameter for JsonResponse() http-response-with-content-type-json:28:content_type_json:Instead of HttpResponse(content_type='application/json') use JsonResponse() pylint-django-2.0.13/pylint_django/tests/input/func_model_does_not_use_unicode_py33.py0000644000175000017500000000062513510363306030702 0ustar josephjoseph""" Ensures that under PY3 django models with a __unicode__ method are flagged """ # pylint: disable=missing-docstring from django.db import models class SomeModel(models.Model): # [model-has-unicode] something = models.CharField(max_length=255) # no __str__ method something.something_else = 1 def lala(self): pass def __unicode__(self): return self.something pylint-django-2.0.13/pylint_django/tests/input/func_noerror_model_unicode_callable.py0000644000175000017500000000053613510363306030644 0ustar josephjoseph""" Ensures that django models without a __unicode__ method are flagged """ # pylint: disable=missing-docstring,wrong-import-position from django.db import models def external_unicode_func(model): return model.something class SomeModel(models.Model): something = models.CharField(max_length=255) __unicode__ = external_unicode_func pylint-django-2.0.13/pylint_django/tests/input/func_noerror_model_unicode_lambda.py0000644000175000017500000000046213510363306030323 0ustar josephjoseph""" Ensures that django models without a __unicode__ method are flagged """ # pylint: disable=missing-docstring,wrong-import-position from django.db import models class SomeModel(models.Model): something = models.CharField(max_length=255) __unicode__ = lambda s: str(s.something) # noqa: E731 pylint-django-2.0.13/pylint_django/tests/input/external_psycopg2_noerror_postgres_fields.py0000644000175000017500000000313213510363306032123 0ustar josephjoseph""" Checks that Pylint does not complain Postgres model fields. """ # pylint: disable=C0111,W5101 from __future__ import print_function from django.contrib.postgres import fields from django.db import models class PostgresFieldsModel(models.Model): arrayfield = fields.ArrayField(models.CharField()) hstorefield = fields.HStoreField() jsonfield = fields.JSONField() rangefield = fields.RangeField() integerrangefield = fields.IntegerRangeField() bigintegerrangefield = fields.BigIntegerRangeField() floatrangefield = fields.FloatRangeField() datetimerangefield = fields.DateTimeRangeField() daterangefield = fields.DateRangeField() def arrayfield_tests(self): sorted_array = self.arrayfield.sort() print(sorted_array) def dictfield_tests(self): print(self.hstorefield.keys()) print(self.hstorefield.values()) print(self.hstorefield.update({'foo': 'bar'})) print(self.jsonfield.keys()) print(self.jsonfield.values()) print(self.jsonfield.update({'foo': 'bar'})) def rangefield_tests(self): print(self.rangefield.lower) print(self.rangefield.upper) print(self.integerrangefield.lower) print(self.integerrangefield.upper) print(self.bigintegerrangefield.lower) print(self.bigintegerrangefield.upper) print(self.floatrangefield.lower) print(self.floatrangefield.upper) print(self.datetimerangefield.lower) print(self.datetimerangefield.upper) print(self.daterangefield.lower) print(self.daterangefield.upper) pylint-django-2.0.13/pylint_django/tests/input/migrations/0000755000175000017500000000000013566222372023244 5ustar josephjosephpylint-django-2.0.13/pylint_django/tests/input/migrations/__init__.py0000644000175000017500000000000013510363306025333 0ustar josephjosephpylint-django-2.0.13/pylint_django/tests/input/migrations/0002_new_column.txt0000644000175000017500000000017013556526157026621 0ustar josephjosephnew-db-field-with-default:28:Migration:pylint_django.tests.input.migrations.0002_new_column AddField with default value pylint-django-2.0.13/pylint_django/tests/input/migrations/0001_noerror_initial.py0000644000175000017500000000114013510363306027441 0ustar josephjoseph""" Initial migration which should not raise any pylint warnings. """ # pylint: disable=missing-docstring, invalid-name from django.db import migrations, models class Migration(migrations.Migration): operations = [ migrations.CreateModel( name='TestRun', fields=[ ('id', models.AutoField(serialize=False, primary_key=True)), ('summary', models.TextField()), ('environment_id', models.IntegerField(default=0)), ('auto_update_run_status', models.BooleanField(default=False)), ], ), ] pylint-django-2.0.13/pylint_django/tests/input/migrations/0002_new_column.py0000644000175000017500000000205313510363306026415 0ustar josephjoseph""" Migration file which adds a new column with a default value. This should trigger a warning because adding new columns with default value on a large table leads to DB performance issues. See: https://github.com/PyCQA/pylint-django/issues/118 and https://docs.djangoproject.com/en/2.0/topics/migrations/#postgresql > ... adding columns with default values will cause a full rewrite of > the table, for a time proportional to its size. > For this reason, it’s recommended you always create new columns with > null=True, as this way they will be added immediately. """ # pylint: disable=missing-docstring, invalid-name from datetime import timedelta from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ ('input', '0001_noerror_initial'), ] operations = [ # add a timedelta field migrations.AddField( # [new-db-field-with-default] model_name='testrun', name='estimated_time', field=models.DurationField(default=timedelta(0)), ), ] pylint-django-2.0.13/pylint_django/tests/input/func_noerror_urls.py0000644000175000017500000000055613510363306025206 0ustar josephjoseph""" Checks that Pylint does not complain about attributes and methods when creating a typical urls.py """ # pylint: disable=missing-docstring from django.views.generic import TemplateView from django.conf.urls import url class BoringView(TemplateView): pass urlpatterns = [ url(r'^something', BoringView.as_view(), name='something'), ] pylint-django-2.0.13/pylint_django/tests/input/func_noerror_protected_meta_access.py0000644000175000017500000000126213510363306030534 0ustar josephjoseph""" Tests to make sure that access to _meta on a model does not raise a protected-access warning, as it is part of the public API since Django 1.8 (see https://github.com/PyCQA/pylint-django/issues/66, and https://docs.djangoproject.com/en/1.9/ref/models/meta/) """ # pylint: disable=missing-docstring from __future__ import print_function from django.db import models class ModelWhichLikesMeta(models.Model): ursuary = models.BooleanField(default=False) def do_a_thing(self): return self._meta.get_field('ursuary') if __name__ == '__main__': MODEL = ModelWhichLikesMeta() MODEL.save() print(MODEL._meta.get_field('ursuary')) print(MODEL.do_a_thing()) pylint-django-2.0.13/pylint_django/tests/input/func_noerror_generic_foreign_key.py0000644000175000017500000000114513510363317030213 0ustar josephjoseph""" Checks that Pylint does not complain about GenericForeignKey fields: https://github.com/PyCQA/pylint-django/issues/230 """ # pylint: disable=missing-docstring from django.db import models from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.fields import GenericForeignKey class Ownership(models.Model): # for #230 the important bit is this FK field which doesn't # have any keyword arguments! owner_type = models.ForeignKey(ContentType, models.CASCADE) owner_id = models.PositiveIntegerField() owner = GenericForeignKey("owner_type", "owner_id") pylint-django-2.0.13/pylint_django/tests/input/func_noerror_wsgi.py0000644000175000017500000000057413510363306025172 0ustar josephjoseph""" Standard WSGI config created by django-admin startproject. Used to verify pylint_django doesn't produce invalid-name for the application variable. See: https://github.com/PyCQA/pylint-django/issues/77 """ import os from django.core.wsgi import get_wsgi_application os.environ.setdefault("DJANGO_SETTINGS_MODULE", "testproj.settings") application = get_wsgi_application() pylint-django-2.0.13/pylint_django/tests/input/func_noerror_issue_46.py0000644000175000017500000000032313510363306025652 0ustar josephjoseph""" Checks that Pylint does not complain about raising DoesNotExist """ # pylint: disable=missing-docstring from django.db import models class SomeModel(models.Model): pass raise SomeModel.DoesNotExist pylint-django-2.0.13/pylint_django/tests/input/external_drf_noerror_serializer.py0000644000175000017500000000034413510363306030107 0ustar josephjoseph""" Checks that Pylint does not complain about DRF serializers """ # pylint: disable=C0111,W5101 from rest_framework import serializers class TestSerializerSubclass(serializers.ModelSerializer): class Meta: pass pylint-django-2.0.13/pylint_django/tests/input/func_noerror_model_methods.py0000644000175000017500000000114213510363306027034 0ustar josephjoseph""" Checks that Pylint does not complain about using Model and Manager methods """ # pylint: disable=missing-docstring from django.db import models class SomeModel(models.Model): name = models.CharField(max_length=64) if __name__ == '__main__': MODEL = SomeModel() MODEL.save() MODEL.delete() COUNT = SomeModel.objects.count() # added in django 1.6 FIRST = SomeModel.objects.first() LAST = SomeModel.objects.last() DB_RECORD, CREATED = SomeModel.objects.get_or_create(name='Tester') EXCLUDED_IDS = [obj.pk for obj in SomeModel.objects.exclude(name__isnull=True)] pylint-django-2.0.13/pylint_django/tests/input/external_factory_boy_noerror.py0000644000175000017500000000301313510363317027421 0ustar josephjoseph""" Test to validate that pylint_django doesn't produce Instance of 'SubFactory' has no 'pk' member (no-member) warnings """ # pylint: disable=attribute-defined-outside-init, missing-docstring, too-few-public-methods import factory from django import test from django.db import models class Author(models.Model): name = models.CharField() class Book(models.Model): title = models.CharField() author = models.ForeignKey(Author, related_name='books', on_delete=models.CASCADE) class AuthorFactory(factory.django.DjangoModelFactory): class Meta: model = 'Author' name = factory.Sequence(lambda n: 'Author %d' % n) class BookFactory(factory.django.DjangoModelFactory): class Meta: model = 'Book' title = factory.Sequence(lambda n: 'Book %d' % n) author = factory.SubFactory(AuthorFactory) reviewer = factory.LazyFunction(Author.objects.first()) class BookTestCase(test.LiveServerTestCase): serialized_rollback = True def _fixture_setup(self): super(BookTestCase, self)._fixture_setup() self.book = BookFactory() _author = AuthorFactory() _first_book = _author.books.first() self.assertIsNotNone(_first_book) def test_author_is_not_none(self): self.assertGreater(self.book.pk, 0) self.assertGreater(self.book.author.pk, 0) self.assertIsNotNone(self.book.title) self.assertIsNotNone(self.book.author.name) def test_reviewer_is_not_none(self): self.assertGreater(self.book.reviewer.pk, 0) pylint-django-2.0.13/pylint_django/tests/input/external_psycopg2_noerror_postgres_fields.rc0000644000175000017500000000004213510363306032074 0ustar josephjoseph[testoptions] requires = psycopg2 pylint-django-2.0.13/pylint_django/tests/input/func_modelform_exclude.txt0000644000175000017500000000013613510363306026331 0ustar josephjosephmodelform-uses-exclude:10:PersonForm.Meta:Use explicit fields instead of exclude in ModelForm pylint-django-2.0.13/pylint_django/tests/input/func_model_no_explicit_unicode_str_compat.txt0000644000175000017500000000014013510363306032265 0ustar josephjosephmodel-no-explicit-unicode:18:SomeModel:Model does not explicitly define __unicode__ (SomeModel) pylint-django-2.0.13/pylint_django/tests/input/external_django_tables2_noerror_meta_class.py0000644000175000017500000000065213510363306032156 0ustar josephjoseph# Check that Meta class definitions for django_tables2 classes # don't produce old-style-class warnings, see # https://github.com/PyCQA/pylint-django/issues/56 # pylint: disable=missing-docstring,too-few-public-methods from django.db import models import django_tables2 as tables class SimpleModel(models.Model): name = models.CharField() class SimpleTable(tables.Table): class Meta: model = SimpleModel pylint-django-2.0.13/pylint_django/tests/input/func_noerror_style_members.py0000644000175000017500000000047213510363306027070 0ustar josephjoseph# Test that using `color_style` or `no_style` # doesn't raise no-member error # # pylint: disable=missing-docstring from django.core.management.color import color_style, no_style def function(): style = color_style() print(style.SUCCESS("test")) style = no_style() print(style.SUCCESS("test")) pylint-django-2.0.13/pylint_django/tests/input/func_noerror_import_q.py0000644000175000017500000000024013510363306026041 0ustar josephjoseph""" Checks that Pylint does not complain about import of Q. """ # pylint: disable=missing-docstring,unused-import from django.db.models import Q # noqa: F401 pylint-django-2.0.13/pylint_django/tests/input/func_noerror_model_fields.py0000644000175000017500000000622213510363306026643 0ustar josephjoseph""" Checks that Pylint does not complain about various methods on Django model fields. """ # pylint: disable=missing-docstring from __future__ import print_function from datetime import datetime, date from decimal import Decimal from django.db import models class LotsOfFieldsModel(models.Model): bigintegerfield = models.BigIntegerField() booleanfield = models.BooleanField(default=True) charfield = models.CharField(max_length=40, null=True) commaseparatedintegerfield = models.CommaSeparatedIntegerField() datetimefield = models.DateTimeField(auto_now_add=True) datefield = models.DateField(auto_now_add=True) decimalfield = models.DecimalField(max_digits=5, decimal_places=2) durationfield = models.DurationField() emailfield = models.EmailField() filefield = models.FileField(name='test_file', upload_to='test') filepathfield = models.FilePathField() floatfield = models.FloatField() genericipaddressfield = models.GenericIPAddressField() imagefield = models.ImageField(name='test_image', upload_to='test') ipaddressfield = models.IPAddressField() intfield = models.IntegerField(null=True) nullbooleanfield = models.NullBooleanField() positiveintegerfield = models.PositiveIntegerField() positivesmallintegerfield = models.PositiveSmallIntegerField() slugfield = models.SlugField() smallintegerfield = models.SmallIntegerField() textfield = models.TextField() timefield = models.TimeField() urlfield = models.URLField() def __str__(self): return self.id def boolean_field_tests(self): print(self.booleanfield | True) print(self.nullbooleanfield | True) def string_field_tests(self): print(self.charfield.strip()) print(self.charfield.upper()) print(self.charfield.replace('x', 'y')) print(self.filepathfield.strip()) print(self.filepathfield.upper()) print(self.filepathfield.replace('x', 'y')) print(self.emailfield.strip()) print(self.emailfield.upper()) print(self.emailfield.replace('x', 'y')) print(self.textfield.strip()) print(self.textfield.upper()) print(self.textfield.replace('x', 'y')) def datetimefield_tests(self): now = datetime.now() print(now - self.datetimefield) print(self.datetimefield.ctime()) def datefield_tests(self): now = date.today() print(now - self.datefield) print(self.datefield.isoformat()) def decimalfield_tests(self): print(self.decimalfield.compare(Decimal('1.4'))) def durationfield_tests(self): now = datetime.now() print(now - self.durationfield) print(self.durationfield.total_seconds()) def filefield_tests(self): self.filefield.save('/dev/null', 'TEST') print(self.filefield.file) self.imagefield.save('/dev/null', 'TEST') print(self.imagefield.file) def numberfield_tests(self): print(self.intfield + 5) print(self.bigintegerfield + 4) print(self.smallintegerfield + 3) print(self.positiveintegerfield + 2) print(self.positivesmallintegerfield + 1) pylint-django-2.0.13/pylint_django/tests/input/func_noerror_duplicate_except_doesnotexist.py0000644000175000017500000000101413510363306032341 0ustar josephjoseph""" Checks that Pylint does not complain about duplicate except blocks catching DoesNotExist exceptions: https://github.com/PyCQA/pylint-django/issues/81 """ # pylint: disable=missing-docstring from django.db import models class Book(models.Model): name = models.CharField(max_length=100) class Author(models.Model): name = models.CharField(max_length=100) def dummy_func(): try: print("foo") except Book.DoesNotExist: print("bar") except Author.DoesNotExist: print("baz") pylint-django-2.0.13/pylint_django/tests/input/func_unused_arguments.txt0000644000175000017500000000020213560025137026220 0ustar josephjosephunused-argument:18:user_detail:Unused argument 'user_id':HIGH unused-argument:24:UserView.get:Unused argument 'user_id':INFERENCE pylint-django-2.0.13/pylint_django/tests/input/func_noerror_managers_return_querysets.py0000644000175000017500000000214313510363306031533 0ustar josephjoseph""" Checks that Pylint does not complain about Manager methods returning lists when they in fact return QuerySets """ from django.db import models class SomeModelQuerySet(models.QuerySet): """ A missing docstring """ @staticmethod def public_method(): """ A missing docstring """ return 1 class SomeModelManager(models.Manager): """A missing docstring""" @staticmethod def public_method(): """ A missing docstring """ return 1 @staticmethod def another_public_method(): """ A missing docstring """ return 1 class SomeModel(models.Model): """ A missing docstring """ name = models.CharField(max_length=20) datetimestamp = models.DateTimeField() objects = SomeModelManager() class OtherModel(models.Model): """ A missing docstring """ name = models.CharField(max_length=20) somemodel = models.ForeignKey(SomeModel, on_delete=models.CASCADE, null=False) def call_some_querysets(): """ A missing docstring """ not_a_list = SomeModel.objects.filter() not_a_list.values_list('id', flat=True) pylint-django-2.0.13/pylint_django/tests/input/func_model_does_not_use_unicode_py33.txt0000644000175000017500000000014313510363306031064 0ustar josephjosephmodel-has-unicode:9:SomeModel:Found __unicode__ method on model (SomeModel). Python3 uses __str__. pylint-django-2.0.13/pylint_django/tests/input/func_noerror_foreignkeys.py0000644000175000017500000000426713510363317026553 0ustar josephjoseph""" Checks that Pylint does not complain about various methods on Django model fields. """ # pylint: disable=missing-docstring,wrong-import-position from django.db import models from django.db.models import ForeignKey, OneToOneField class Genre(models.Model): name = models.CharField(max_length=100) class Author(models.Model): author_name = models.CharField(max_length=100) class ISBN(models.Model): value = models.CharField(max_length=100) class Book(models.Model): book_name = models.CharField(max_length=100) # Check this works with and without `to` keyword author = models.ForeignKey(to='Author', on_delete=models.CASCADE) isbn = models.OneToOneField(to=ISBN, on_delete=models.CASCADE) genre = models.ForeignKey(Genre, on_delete=models.CASCADE) def get_isbn(self): return self.isbn.value def get_author_name(self): return self.author.author_name class Fruit(models.Model): fruit_name = models.CharField(max_length=20) class Seed(models.Model): fruit = ForeignKey(to=Fruit, on_delete=models.CASCADE) def get_fruit_name(self): return self.fruit.fruit_name class User(models.Model): username = models.CharField(max_length=32) class UserProfile(models.Model): user = OneToOneField(User, on_delete=models.CASCADE) def get_username(self): return self.user.username class Human(models.Model): child = ForeignKey('self', on_delete=models.SET_NULL, null=True) parent = ForeignKey(to='self', on_delete=models.SET_NULL, null=True) def get_grandchild(self): return self.child.child def get_grandparent(self): return self.parent.parent class UserPreferences(models.Model): """ Used for testing FK which refers to another model by string, not model class, see https://github.com/PyCQA/pylint-django/issues/35 """ user = ForeignKey('User', on_delete=models.CASCADE) class UserAddress(models.Model): user = OneToOneField(to='User', on_delete=models.CASCADE) line_1 = models.CharField(max_length=100) line_2 = models.CharField(max_length=100) city = models.CharField(max_length=100) postal_code = models.CharField(max_length=100) pylint-django-2.0.13/pylint_django/tests/input/func_noerror_views.py0000644000175000017500000000022713510363306025351 0ustar josephjoseph""" Checks that Pylint does not complain when using function based views. """ # pylint: disable=missing-docstring def empty_view(request): pass pylint-django-2.0.13/pylint_django/tests/input/func_noerror_factory_post_generation.py0000644000175000017500000000065113510363306031144 0ustar josephjoseph""" Checks that Pylint does not complain about no self argument in factory.post_generation method. """ # pylint: disable=missing-docstring,too-few-public-methods,unused-argument,no-member import factory class SomeModelFactory(factory.Factory): class Meta: pass @factory.post_generation def action(obj, create, extracted, **kwargs): if extracted: obj.do_action() obj.save() pylint-django-2.0.13/pylint_django/tests/input/func_noerror_foreign_key_package.py0000644000175000017500000000052313510363317030171 0ustar josephjoseph""" Checks that Pylint does not complain about ForeignKey pointing to model in module of models package """ # pylint: disable=missing-docstring from django.db import models class Book(models.Model): author = models.ForeignKey(to='input.Author', on_delete=models.CASCADE) def get_author_name(self): return self.author.id pylint-django-2.0.13/pylint_django/tests/input/func_noerror_ugettext_lazy_format.py0000644000175000017500000000031013510363306030465 0ustar josephjoseph""" Checks that Pylint does not complain about django lazy proxy when using ugettext_lazy """ from django.utils.translation import ugettext_lazy ugettext_lazy('{something}').format(something='lala') pylint-django-2.0.13/pylint_django/tests/input/func_noerror_classviews.py0000644000175000017500000000245713566222266026420 0ustar josephjoseph""" Checks that Pylint does not complain about attributes and methods when using Class-based Views """ # pylint: disable=missing-docstring from django.db import models from django.http import JsonResponse from django.views.generic import DetailView from django.views.generic import TemplateView from django.views.generic import View from django.views.generic.edit import CreateView class BoringView(TemplateView): # ensure that args, kwargs and request are not thrown up as errors def get_context_data(self, **kwargs): return { 'request': self.request, 'args': self.args, 'kwargs': self.kwargs } class JsonView(View): def post(self, request): # do something with objects but don't use # self or request return JsonResponse({'rc': 0, 'response': 'ok'}) class Book(models.Model): name = models.CharField(max_length=100) good = models.BooleanField(default=False) class GetBook(DetailView): model = Book template_name = 'books/get.html' http_method_names = ['get'] class CreateBook(CreateView): model = Book template_name = 'books/new.html' def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context['page_title'] = 'New book' return context pylint-django-2.0.13/pylint_django/tests/input/func_noerror_manytomanyfield.py0000644000175000017500000000342713510363317027423 0ustar josephjoseph""" Checks that Pylint does not complain about various methods on many-to-many relationships """ # pylint: disable=missing-docstring from django.db import models from django.contrib.auth.models import AbstractUser, Permission class Book(models.Model): name = models.CharField(max_length=100) good = models.BooleanField(default=False) class Author(models.Model): name = models.CharField(max_length=100) wrote = models.ManyToManyField(Book, verbose_name="Book", related_name='books') def get_good_books(self): return self.wrote.filter(good=True) def is_author_of(self, book): return book in list(self.wrote.all()) def wrote_how_many(self): return self.wrote.count() # Custom permissions for CustomUser USER_PERMS = ['change_customuser', 'add_customuser'] class CustomUser(AbstractUser): # pylint: disable=model-no-explicit-unicode class Meta: verbose_name = 'CustomUser' verbose_name_plural = 'CustomUsers' app_label = "users" def grant_permissions(self): ''' Example adding permissions to User ''' self.user_permissions.clear() for perm in USER_PERMS: perm = Permission.objects.get(codename=perm) self.user_permissions.add(perm) return self.user_permissions def add_permission(self, permission): self.user_permissions.add(permission) def remove_permission(self, permission): self.user_permissions.remove(permission) def set_permissions(self, permissions): self.user_permissions.set(permissions) def save(self, *args, **kwargs): ''' Saving while granting new permissions ''' self.is_staff = True super(CustomUser, self).save() self.grant_permissions() pylint-django-2.0.13/pylint_django/tests/input/func_noerror_form_fields.py0000644000175000017500000000457113510363306026513 0ustar josephjoseph""" Checks that Pylint does not complain about various methods on Django form forms. """ # pylint: disable=missing-docstring,R0904 from __future__ import print_function from datetime import datetime, date from django import forms from django.contrib.auth.forms import UserCreationForm class ManyFieldsForm(forms.Form): booleanfield = forms.BooleanField() charfield = forms.CharField(max_length=40, null=True) datetimefield = forms.DateTimeField(auto_now_add=True) datefield = forms.DateField(auto_now_add=True) decimalfield = forms.DecimalField(max_digits=5, decimal_places=2) durationfield = forms.DurationField() emailfield = forms.EmailField() filefield = forms.FileField(name='test_file', upload_to='test') filepathfield = forms.FilePathField(path='/some/path') floatfield = forms.FloatField() genericipaddressfield = forms.GenericIPAddressField() imagefield = forms.ImageField(name='test_image', upload_to='test') intfield = forms.IntegerField(null=True) nullbooleanfield = forms.NullBooleanField() slugfield = forms.SlugField() timefield = forms.TimeField() urlfield = forms.URLField() def boolean_field_tests(self): print(self.booleanfield | True) print(self.nullbooleanfield | True) def string_field_tests(self): print(self.charfield.strip()) print(self.charfield.upper()) print(self.charfield.replace('x', 'y')) print(self.filepathfield.strip()) print(self.filepathfield.upper()) print(self.filepathfield.replace('x', 'y')) print(self.emailfield.strip()) print(self.emailfield.upper()) print(self.emailfield.replace('x', 'y')) def datetimefield_tests(self): now = datetime.now() print(now - self.datetimefield) print(self.datetimefield.ctime()) def datefield_tests(self): now = date.today() print(now - self.datefield) print(self.datefield.isoformat()) def decimalfield_tests(self): print(self.decimalfield.adjusted()) def durationfield_tests(self): now = datetime.now() print(now - self.durationfield) print(self.durationfield.total_seconds()) def filefield_tests(self): print(self.filefield) print(self.imagefield) def numberfield_tests(self): print(self.intfield + 5) _ = UserCreationForm.declared_fields pylint-django-2.0.13/pylint_django/tests/input/func_noerror_unicode_py2_compatible.py0000644000175000017500000000071313510363306030633 0ustar josephjoseph""" Ensures that no '__unicode__ missing' warning is emitted if the Django python3/2 compatability dectorator is used See https://github.com/PyCQA/pylint-django/issues/10 """ # pylint: disable=missing-docstring from django.utils.encoding import python_2_unicode_compatible from django.db import models @python_2_unicode_compatible class ModelName(models.Model): name = models.CharField(max_length=200) def __str__(self): return self.name pylint-django-2.0.13/pylint_django/tests/input/external_drf_noerror_serializer.rc0000644000175000017500000000005013510363306030055 0ustar josephjoseph[testoptions] requires = rest_framework pylint-django-2.0.13/pylint_django/tests/input/func_json_response.py0000644000175000017500000000143113510363306025333 0ustar josephjoseph# pylint: disable=missing-docstring, line-too-long import json from django import http from django.http import HttpResponse def say_yes(): return HttpResponse(json.dumps({'rc': 0, 'response': 'ok'})) # [http-response-with-json-dumps] def say_yes2(): data = {'rc': 0, 'response': 'ok'} return http.HttpResponse(json.dumps(data)) # [http-response-with-json-dumps] def say_no(): return HttpResponse("no") def redundant_content_type(): data = {'rc': 0, 'response': 'ok'} return http.JsonResponse(data, content_type='application/json') # [redundant-content-type-for-json-response] def content_type_json(): json_data = "this comes from somewhere" return HttpResponse(json_data, content_type='application/json') # [http-response-with-content-type-json] pylint-django-2.0.13/pylint_django/tests/input/func_noerror_models_py33.py0000644000175000017500000000125013510363306026352 0ustar josephjoseph""" Checks that Pylint does not complain about a fairly standard Django Model """ # pylint: disable=missing-docstring from django.db import models class SomeModel(models.Model): class Meta: pass some_field = models.CharField(max_length=20) other_fields = models.ManyToManyField('AnotherModel') def stuff(self): try: print(self._meta) print(self.other_fields.all()[0]) except self.DoesNotExist: print('does not exist') except self.MultipleObjectsReturned: print('lala') print(self.get_some_field_display()) class SubclassModel(SomeModel): class Meta: pass pylint-django-2.0.13/pylint_django/tests/input/external_model_utils_noerror_override_manager.rc0000644000175000017500000000004513510363306032766 0ustar josephjoseph[testoptions] requires = model_utils pylint-django-2.0.13/pylint_django/tests/input/func_noerror_foreign_key_key_cls_unbound.py0000644000175000017500000000067713510363317031773 0ustar josephjoseph""" Checks that Pylint does not complain about ForeignKey pointing to model in module of models package """ # pylint: disable=missing-docstring from django.db import models class FairyTail(models.Model): # fails with "UnboundLocalError: local variable 'key_cls' referenced before assignment" author = models.ForeignKey(to='input.Author', null=True, on_delete=models.CASCADE) def get_author_name(self): return self.author.id pylint-django-2.0.13/pylint_django/tests/input/models/0000755000175000017500000000000013566222372022353 5ustar josephjosephpylint-django-2.0.13/pylint_django/tests/input/models/__init__.py0000644000175000017500000000006313510363317024455 0ustar josephjosephfrom .author import Author __all__ = ('Author',) pylint-django-2.0.13/pylint_django/tests/input/models/author.py0000644000175000017500000000017613510363317024225 0ustar josephjoseph# pylint: disable=missing-docstring,wrong-import-position from django.db import models class Author(models.Model): pass ././@LongLink0000644000000000000000000000016200000000000011602 Lustar rootrootpylint-django-2.0.13/pylint_django/tests/input/models/func_noerror_foreign_key_key_cls_unbound_in_same_package.pypylint-django-2.0.13/pylint_django/tests/input/models/func_noerror_foreign_key_key_cls_unbound_in_sa0000644000175000017500000000176413510363317033776 0ustar josephjoseph""" Checks that Pylint does not crash with ForeignKey string reference pointing to model in module of models package. See https://github.com/PyCQA/pylint-django/issues/232 Note: the no-member disable is here b/c pylint-django doesn't know how to load models.author.Author. When pylint-django tries to load models referenced by a single string it assumes they are found in the same module it is inspecting. Hence it can't find the Author class here so it tells us it doesn't have an 'id' attribute. Also see: https://github.com/PyCQA/pylint-django/issues/232#issuecomment-495242695 """ # pylint: disable=missing-docstring, no-member from django.db import models class FairyTail(models.Model): # fails with "UnboundLocalError: local variable 'key_cls' referenced before assignment" # when 'Author' model comes from same models package author = models.ForeignKey(to='Author', null=True, on_delete=models.CASCADE) def get_author_name(self): return self.author.id # disable via no-member pylint-django-2.0.13/pylint_django/tests/input/func_unused_arguments.py0000644000175000017500000000235513560025137026044 0ustar josephjoseph""" Checks that Pylint still complains about unused-arguments for other arguments if a function/method contains an argument named `request`. """ # pylint: disable=missing-docstring from django.http import JsonResponse from django.views import View # Pylint generates the warning `redefined-outer-name` if an argument name shadows # a variable name from an outer scope. But if that argument name is ignored this # warning will not be generated. # Therefore define request here to cover this behaviour in this test case. request = None # pylint: disable=invalid-name def user_detail(request, user_id): # [unused-argument] # nothing is done with user_id return JsonResponse({'username': 'steve'}) class UserView(View): def get(self, request, user_id): # [unused-argument] # nothing is done with user_id return JsonResponse({'username': 'steve'}) # The following views are already covered in other test cases. # They are included here for completeness sake. def welcome_view(request): # just don't use `request' b/c we could have Django views # which never use it! return JsonResponse({'message': 'welcome'}) class CBV(View): def get(self, request): return JsonResponse({'message': 'hello world'}) pylint-django-2.0.13/pylint_django/tests/input/external_factory_boy_noerror.rc0000644000175000017500000000004113510363306027371 0ustar josephjoseph[testoptions] requires = factory pylint-django-2.0.13/pylint_django/tests/test_func.py0000644000175000017500000000572413560025137022277 0ustar josephjoseph import os import sys import pytest import pylint if pylint.__version__ >= '2.4': # after version 2.4 pylint stopped shipping the test directory # as part of the package so we check it out locally for testing sys.path.append(os.path.join(os.getenv('HOME', '/home/travis'), 'pylint', 'tests')) else: # because there's no __init__ file in pylint/test/ sys.path.append(os.path.join(os.path.dirname(pylint.__file__), 'test')) import test_functional # noqa: E402 # alter sys.path again because the tests now live as a subdirectory # of pylint_django sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..')) # so we can find migrations sys.path.append(os.path.join(os.path.dirname(__file__), 'input')) class PylintDjangoLintModuleTest(test_functional.LintModuleTest): """ Only used so that we can load this plugin into the linter! """ def __init__(self, test_file): super(PylintDjangoLintModuleTest, self).__init__(test_file) self._linter.load_plugin_modules(['pylint_django']) self._linter.load_plugin_configuration() class PylintDjangoDbPerformanceTest(PylintDjangoLintModuleTest): """ Only used so that we can load pylint_django.checkers.db_performance into the linter! """ def __init__(self, test_file): super(PylintDjangoDbPerformanceTest, self).__init__(test_file) self._linter.load_plugin_modules(['pylint_django.checkers.db_performance']) self._linter.load_plugin_configuration() def get_tests(input_dir='input', sort=False): def _file_name(test): return test.base HERE = os.path.dirname(os.path.abspath(__file__)) input_dir = os.path.join(HERE, input_dir) suite = [] for fname in os.listdir(input_dir): if fname != '__init__.py' and fname.endswith('.py'): suite.append(test_functional.FunctionalTestFile(input_dir, fname)) # when testing the db_performance plugin we need to sort by input file name # because the plugin reports the errors in close() which appends them to the # report for the last file in the list if sort: suite.sort(key=_file_name) return suite TESTS = get_tests() TESTS.extend(get_tests('input/models')) TESTS_NAMES = [t.base for t in TESTS] @pytest.mark.parametrize("test_file", TESTS, ids=TESTS_NAMES) def test_everything(test_file): # copied from pylint.tests.test_functional.test_functional LintTest = PylintDjangoLintModuleTest(test_file) LintTest.setUp() LintTest._runTest() # NOTE: define tests for the db_performance checker! DB_PERFORMANCE_TESTS = get_tests('input/migrations', True) DB_PERFORMANCE_TESTS_NAMES = [t.base for t in DB_PERFORMANCE_TESTS] @pytest.mark.parametrize("test_file", DB_PERFORMANCE_TESTS, ids=DB_PERFORMANCE_TESTS_NAMES) def test_db_performance_plugin(test_file): LintTest = PylintDjangoDbPerformanceTest(test_file) LintTest.setUp() LintTest._runTest() if __name__ == '__main__': sys.exit(pytest.main(sys.argv)) pylint-django-2.0.13/pylint_django/tests/__init__.py0000644000175000017500000000000013510363306022020 0ustar josephjosephpylint-django-2.0.13/pylint_django/__pkginfo__.py0000644000175000017500000000003413265451424021365 0ustar josephjoseph"""pkginfo.""" BASE_ID = 51 pylint-django-2.0.13/pylint_django/plugin.py0000644000175000017500000000271113566217760020445 0ustar josephjoseph"""Common Django module.""" from pylint.checkers.base import NameChecker from pylint_plugin_utils import get_checker from pylint_django.checkers import register_checkers # we want to import the transforms to make sure they get added to the astroid manager, # however we don't actually access them directly, so we'll disable the warning from pylint_django import transforms # noqa, pylint: disable=unused-import from pylint_django import compat def load_configuration(linter): """ Amend existing checker config. """ name_checker = get_checker(linter, NameChecker) name_checker.config.good_names += ('qs', 'urlpatterns', 'register', 'app_name', 'handler400', 'handler403', 'handler404', 'handler500') # we don't care about South migrations linter.config.black_list += ('migrations', 'south_migrations') def register(linter): """ Registering additional checkers. """ # add all of the checkers register_checkers(linter) # register any checking fiddlers try: # pylint: disable=import-outside-toplevel from pylint_django.augmentations import apply_augmentations apply_augmentations(linter) except ImportError: # probably trying to execute pylint_django when Django isn't installed # in this case the django-not-installed checker will kick-in pass if not compat.LOAD_CONFIGURATION_SUPPORTED: load_configuration(linter) pylint-django-2.0.13/pylint_django/compat.py0000644000175000017500000000155213510363317020421 0ustar josephjoseph# flake8: noqa # pylint: skip-file # no sane linter can figure out the hackiness in this compatability layer... try: from astroid.nodes import ClassDef, FunctionDef, ImportFrom, AssignName, Attribute except ImportError: from astroid.nodes import ( Class as ClassDef, Function as FunctionDef, From as ImportFrom, AssName as AssignName, Getattr as Attribute, ) # pylint 2.04->2.2 : YES was renamed to Uninferable, then YES became deprecated, then was removed try: from astroid.bases import YES as Uninferable except ImportError: try: from astroid.util import YES as Uninferable except ImportError: from astroid.util import Uninferable import pylint # pylint before version 2.3 does not support load_configuration() hook. LOAD_CONFIGURATION_SUPPORTED = pylint.__pkginfo__.numversion >= (2, 3) pylint-django-2.0.13/pylint_django/augmentations/0000755000175000017500000000000013566222372021445 5ustar josephjosephpylint-django-2.0.13/pylint_django/augmentations/__init__.py0000644000175000017500000006777113566222266023602 0ustar josephjoseph"""Augmentations.""" # pylint: disable=invalid-name import functools import itertools from astroid import InferenceError from astroid.objects import Super from astroid.nodes import ClassDef, ImportFrom, Attribute from astroid.scoped_nodes import ClassDef as ScopedClass, Module from pylint.checkers.base import DocStringChecker, NameChecker from pylint.checkers.design_analysis import MisdesignChecker from pylint.checkers.classes import ClassChecker from pylint.checkers.newstyle import NewStyleConflictChecker from pylint.checkers.variables import VariablesChecker from pylint.checkers.typecheck import TypeChecker from pylint.checkers.variables import ScopeConsumer from pylint_plugin_utils import augment_visit, suppress_message from django import VERSION as django_version from django.views.generic.base import View, RedirectView, ContextMixin from django.views.generic.dates import DateMixin, DayMixin, MonthMixin, WeekMixin, YearMixin from django.views.generic.detail import SingleObjectMixin, SingleObjectTemplateResponseMixin, TemplateResponseMixin from django.views.generic.edit import DeletionMixin, FormMixin, ModelFormMixin from django.views.generic.list import MultipleObjectMixin, MultipleObjectTemplateResponseMixin from django.utils import termcolors from pylint_django.utils import node_is_subclass, PY3 # Note: it would have been nice to import the Manager object from Django and # get its attributes that way - and this used to be the method - but unfortunately # there's no guarantee that Django is properly configured at that stage, and importing # anything from the django.db package causes an ImproperlyConfigured exception. # Therefore we'll fall back on a hard-coded list of attributes which won't be as accurate, # but this is not 100% accurate anyway. MANAGER_ATTRS = { 'none', 'all', 'count', 'dates', 'distinct', 'extra', 'get', 'get_or_create', 'get_queryset', 'create', 'bulk_create', 'filter', 'aggregate', 'annotate', 'complex_filter', 'exclude', 'in_bulk', 'iterator', 'latest', 'order_by', 'select_for_update', 'select_related', 'prefetch_related', 'values', 'values_list', 'update', 'reverse', 'defer', 'only', 'using', 'exists', } QS_ATTRS = { 'filter', 'exclude', 'annotate', 'order_by', 'reverse', 'distinct', 'values', 'values_list', 'dates', 'datetimes', 'none', 'all', 'select_related', 'prefetch_related', 'extra', 'defer', 'only', 'using', 'select_for_update', 'raw', 'get', 'create', 'get_or_create', 'update_or_create', 'bulk_create', 'count', 'in_bulk', 'iterator', 'latest', 'earliest', 'first', 'last', 'aggregate', 'exists', 'update', 'delete', 'as_manager', 'expression', 'output_field', } MODELADMIN_ATTRS = { # options 'actions', 'actions_on_top', 'actions_on_bottom', 'actions_selection_counter', 'date_hierarchy', 'empty_value_display', 'exclude', 'fields', 'fieldsets', 'filter_horizontal', 'filter_vertical', 'form', 'formfield_overrides', 'inlines', 'list_display', 'list_display_links', 'list_editable', 'list_filter', 'list_max_show_all', 'list_per_page', 'list_select_related', 'ordering', 'paginator', 'prepopulated_fields', 'preserve_filters', 'radio_fields', 'raw_id_fields', 'readonly_fields', 'save_as', 'save_on_top', 'search_fields', 'show_full_result_count', 'view_on_site', # template options 'add_form_template', 'change_form_template', 'change_list_template', 'delete_confirmation_template', 'delete_selected_confirmation_template', 'object_history_template', } MODEL_ATTRS = { 'id', 'DoesNotExist', 'MultipleObjectsReturned', '_base_manager', '_default_manager', '_meta', 'delete', 'get_next_by_date', 'get_previous_by_date', 'objects', 'save', } FIELD_ATTRS = { 'null', 'blank', 'choices', 'db_column', 'db_index', 'db_tablespace', 'default', 'editable', 'error_messages', 'help_text', 'primary_key', 'unique', 'unique_for_date', 'unique_for_month', 'unique_for_year', 'verbose_name', 'validators', } CHAR_FIELD_ATTRS = { 'max_length', } DATE_FIELD_ATTRS = { 'auto_now', 'auto_now_add', } DECIMAL_FIELD_ATTRS = { 'max_digits', 'decimal_places', } FILE_FIELD_ATTRS = { 'upload_to', 'storage', } IMAGE_FIELD_ATTRS = { 'height_field', 'width_field', } IP_FIELD_ATTRS = { 'protocol', 'unpack_ipv4', } SLUG_FIELD_ATTRS = { 'allow_unicode', } FOREIGNKEY_FIELD_ATTRS = { 'limit_choices_to', 'related_name', 'related_query_name', 'to_field', 'db_constraint', 'swappable', } MANYTOMANY_FIELD_ATTRS = { 'add', 'clear', 'related_name', 'related_query_name', 'remove', 'set', 'limit_choices_to', 'symmetrical', 'through', 'through_fields', 'db_table', 'db_constraint', 'swappable', } ONETOONE_FIELD_ATTRS = { 'parent_link', } STYLE_ATTRS = set(itertools.chain.from_iterable(termcolors.PALETTES.values())) VIEW_ATTRS = { ( ( '{}.{}'.format(cls.__module__, cls.__name__), '.{}'.format(cls.__name__) ), tuple(cls.__dict__.keys()) ) for cls in ( View, RedirectView, ContextMixin, DateMixin, DayMixin, MonthMixin, WeekMixin, YearMixin, SingleObjectMixin, SingleObjectTemplateResponseMixin, TemplateResponseMixin, DeletionMixin, FormMixin, ModelFormMixin, MultipleObjectMixin, MultipleObjectTemplateResponseMixin, ) } FORM_ATTRS = { 'declared_fields', } def ignore_import_warnings_for_related_fields(orig_method, self, node): """ Replaces the leave_module method on the VariablesChecker class to prevent unused-import warnings which are caused by the ForeignKey and OneToOneField transformations. By replacing the nodes in the AST with their type rather than the django field, imports of the form 'from django.db.models import OneToOneField' raise an unused-import warning """ consumer = self._to_consume[0] # pylint: disable=W0212 # we can disable this warning ('Access to a protected member _to_consume of a client class') # as it's not actually a client class, but rather, this method is being monkey patched # onto the class and so the access is valid new_things = {} iterat = consumer.to_consume.items if PY3 else consumer.to_consume.iteritems for name, stmts in iterat(): if isinstance(stmts[0], ImportFrom): if any([n[0] in ('ForeignKey', 'OneToOneField') for n in stmts[0].names]): continue new_things[name] = stmts consumer._atomic = ScopeConsumer(new_things, consumer.consumed, consumer.scope_type) # pylint: disable=W0212 self._to_consume = [consumer] # pylint: disable=W0212 return orig_method(self, node) def foreign_key_sets(chain, node): """ When a Django model has a ForeignKey to another model, the target of the foreign key gets a '_set' attribute for accessing a queryset of the model owning the foreign key - eg: class ModelA(models.Model): pass class ModelB(models.Model): a = models.ForeignKey(ModelA) Now, ModelA instances will have a modelb_set attribute. It's also possible to explicitly name the relationship using the related_name argument to the ForeignKey constructor. As it's impossible to know this without inspecting all models before processing, we'll instead do a "best guess" approach and see if the attribute being accessed goes on to be used as a queryset. This is via 'duck typing': if the method called on the attribute being accessed is something we might find in a queryset, we'll warn. """ quack = False if node.attrname in MANAGER_ATTRS or node.attrname.endswith('_set'): # if this is a X_set method, that's a pretty strong signal that this is the default # Django name, rather than one set by related_name quack = True else: # we will if isinstance(node.parent, Attribute): func_name = getattr(node.parent, 'attrname', None) if func_name in MANAGER_ATTRS: quack = True if quack: children = list(node.get_children()) for child in children: try: inferred_cls = child.inferred() except InferenceError: pass else: for cls in inferred_cls: if (node_is_subclass(cls, 'django.db.models.manager.Manager', 'django.db.models.base.Model', '.Model', 'django.db.models.fields.related.ForeignObject')): # This means that we are looking at a subclass of models.Model # and something is trying to access a _set attribute. # Since this could exist, we will return so as not to raise an # error. return chain() def foreign_key_ids(chain, node): if node.attrname.endswith('_id'): return chain() def is_model_admin_subclass(node): """Checks that node is derivative of ModelAdmin class.""" if node.name[-5:] != 'Admin' or isinstance(node.parent, ClassDef): return False return node_is_subclass(node, 'django.contrib.admin.options.ModelAdmin') def is_model_media_subclass(node): """Checks that node is derivative of Media class.""" if node.name != 'Media' or not isinstance(node.parent, ClassDef): return False parents = ('django.contrib.admin.options.ModelAdmin', 'django.forms.widgets.Media', 'django.db.models.base.Model', '.Model', # for the transformed version used in this plugin 'django.forms.forms.Form', '.Form', 'django.forms.widgets.Widget', '.Widget', 'django.forms.models.ModelForm', '.ModelForm') return node_is_subclass(node.parent, *parents) def is_model_meta_subclass(node): """Checks that node is derivative of Meta class.""" if node.name != 'Meta' or not isinstance(node.parent, ClassDef): return False parents = ('.Model', # for the transformed version used here 'django.db.models.base.Model', '.Form', 'django.forms.forms.Form', '.ModelForm', 'django.forms.models.ModelForm', 'rest_framework.serializers.BaseSerializer', 'rest_framework.generics.GenericAPIView', 'rest_framework.viewsets.ReadOnlyModelViewSet', 'rest_framework.viewsets.ModelViewSet', 'django_filters.filterset.FilterSet', 'factory.django.DjangoModelFactory',) return node_is_subclass(node.parent, *parents) def is_model_factory(node): """Checks that node is derivative of DjangoModelFactory or SubFactory class.""" try: parent_classes = node.expr.inferred() except: # noqa: E722, pylint: disable=bare-except return False parents = ('factory.declarations.LazyFunction', 'factory.declarations.SubFactory', 'factory.django.DjangoModelFactory') for parent_class in parent_classes: try: if parent_class.qname() in parents: return True if node_is_subclass(parent_class, *parents): return True except AttributeError: continue return False def is_factory_post_generation_method(node): if not node.decorators: return False for decorator in node.decorators.get_children(): try: inferred = decorator.inferred() except InferenceError: continue for target in inferred: if target.qname() == 'factory.helpers.post_generation': return True return False def is_model_mpttmeta_subclass(node): """Checks that node is derivative of MPTTMeta class.""" if node.name != 'MPTTMeta' or not isinstance(node.parent, ClassDef): return False parents = ('django.db.models.base.Model', '.Model', # for the transformed version used in this plugin 'django.forms.forms.Form', '.Form', 'django.forms.models.ModelForm', '.ModelForm') return node_is_subclass(node.parent, *parents) def _attribute_is_magic(node, attrs, parents): """Checks that node is an attribute used inside one of allowed parents""" if node.attrname not in attrs: return False if not node.last_child(): return False try: for cls in node.last_child().inferred(): if isinstance(cls, Super): cls = cls._self_class # pylint: disable=protected-access if node_is_subclass(cls, *parents) or cls.qname() in parents: return True except InferenceError: pass return False def is_style_attribute(node): parents = ('django.core.management.color.Style', ) return _attribute_is_magic(node, STYLE_ATTRS, parents) def is_manager_attribute(node): """Checks that node is attribute of Manager or QuerySet class.""" parents = ('django.db.models.manager.Manager', '.Manager', 'factory.base.BaseFactory.build', 'django.db.models.query.QuerySet', '.QuerySet') return _attribute_is_magic(node, MANAGER_ATTRS.union(QS_ATTRS), parents) def is_admin_attribute(node): """Checks that node is attribute of BaseModelAdmin.""" parents = ('django.contrib.admin.options.BaseModelAdmin', '.BaseModelAdmin') return _attribute_is_magic(node, MODELADMIN_ATTRS, parents) def is_model_attribute(node): """Checks that node is attribute of Model.""" parents = ('django.db.models.base.Model', '.Model') return _attribute_is_magic(node, MODEL_ATTRS, parents) def is_field_attribute(node): """Checks that node is attribute of Field.""" parents = ('django.db.models.fields.Field', '.Field') return _attribute_is_magic(node, FIELD_ATTRS, parents) def is_charfield_attribute(node): """Checks that node is attribute of CharField.""" parents = ('django.db.models.fields.CharField', '.CharField') return _attribute_is_magic(node, CHAR_FIELD_ATTRS, parents) def is_datefield_attribute(node): """Checks that node is attribute of DateField.""" parents = ('django.db.models.fields.DateField', '.DateField') return _attribute_is_magic(node, DATE_FIELD_ATTRS, parents) def is_decimalfield_attribute(node): """Checks that node is attribute of DecimalField.""" parents = ('django.db.models.fields.DecimalField', '.DecimalField') return _attribute_is_magic(node, DECIMAL_FIELD_ATTRS, parents) def is_filefield_attribute(node): """Checks that node is attribute of FileField.""" parents = ('django.db.models.fields.files.FileField', '.FileField') return _attribute_is_magic(node, FILE_FIELD_ATTRS, parents) def is_imagefield_attribute(node): """Checks that node is attribute of ImageField.""" parents = ('django.db.models.fields.files.ImageField', '.ImageField') return _attribute_is_magic(node, IMAGE_FIELD_ATTRS, parents) def is_ipfield_attribute(node): """Checks that node is attribute of GenericIPAddressField.""" parents = ('django.db.models.fields.GenericIPAddressField', '.GenericIPAddressField') return _attribute_is_magic(node, IP_FIELD_ATTRS, parents) def is_slugfield_attribute(node): """Checks that node is attribute of SlugField.""" parents = ('django.db.models.fields.SlugField', '.SlugField') return _attribute_is_magic(node, SLUG_FIELD_ATTRS, parents) def is_foreignkeyfield_attribute(node): """Checks that node is attribute of ForeignKey.""" parents = ('django.db.models.fields.related.ForeignKey', '.ForeignKey') return _attribute_is_magic(node, FOREIGNKEY_FIELD_ATTRS, parents) def is_manytomanyfield_attribute(node): """Checks that node is attribute of ManyToManyField.""" parents = ('django.db.models.fields.related.ManyToManyField', '.ManyToManyField') return _attribute_is_magic(node, MANYTOMANY_FIELD_ATTRS, parents) def is_onetoonefield_attribute(node): """Checks that node is attribute of OneToOneField.""" parents = ('django.db.models.fields.related.OneToOneField', '.OneToOneField') return _attribute_is_magic(node, ONETOONE_FIELD_ATTRS, parents) def is_form_attribute(node): """Checks that node is attribute of Form.""" parents = ('django.forms.forms.Form', 'django.forms.models.ModelForm') return _attribute_is_magic(node, FORM_ATTRS, parents) def is_model_test_case_subclass(node): """Checks that node is derivative of TestCase class.""" if not node.name.endswith('Test') and not isinstance(node.parent, ClassDef): return False return node_is_subclass(node, 'django.test.testcases.TestCase') def generic_is_view_attribute(parents, attrs): """Generates is_X_attribute function for given parents and attrs.""" def is_attribute(node): return _attribute_is_magic(node, attrs, parents) return is_attribute def is_model_view_subclass_method_shouldnt_be_function(node): """Checks that node is get or post method of the View class.""" if node.name not in ('get', 'post'): return False parent = node.parent while parent and not isinstance(parent, ScopedClass): parent = parent.parent subclass = ('django.views.View', 'django.views.generic.View', 'django.views.generic.base.View',) return parent is not None and node_is_subclass(parent, *subclass) def ignore_unused_argument_warnings_for_request(orig_method, self, stmt, name): """ Ignore unused-argument warnings for function arguments named "request". The signature of Django view functions require the request argument but it is okay if the request is not used. This function should be used as a wrapper for the `VariablesChecker._is_name_ignored` method. """ if name == 'request': return True return orig_method(self, stmt, name) def is_model_field_display_method(node): """Accept model's fields with get_*_display names.""" if not node.attrname.endswith('_display'): return False if not node.attrname.startswith('get_'): return False if node.last_child(): # TODO: could validate the names of the fields on the model rather than # blindly accepting get_*_display try: for cls in node.last_child().inferred(): if node_is_subclass(cls, 'django.db.models.base.Model', '.Model'): return True except InferenceError: return False return False def is_model_media_valid_attributes(node): """Suppress warnings for valid attributes of Media class.""" if node.name not in ('js', ): return False parent = node.parent while parent and not isinstance(parent, ScopedClass): parent = parent.parent if parent is None or parent.name != "Media": return False return True def is_templatetags_module_valid_constant(node): """Suppress warnings for valid constants in templatetags module.""" if node.name not in ('register', ): return False parent = node.parent while not isinstance(parent, Module): parent = parent.parent if "templatetags." not in parent.name: return False return True def is_urls_module_valid_constant(node): """Suppress warnings for valid constants in urls module.""" if node.name not in ('urlpatterns', 'app_name'): return False parent = node.parent while not isinstance(parent, Module): parent = parent.parent if not parent.name.endswith('urls'): return False return True def allow_meta_protected_access(node): if django_version >= (1, 8): return node.attrname == '_meta' return False def is_class(class_name): """Shortcut for node_is_subclass.""" return lambda node: node_is_subclass(node, class_name) def wrap(orig_method, with_method): @functools.wraps(orig_method) def wrap_func(*args, **kwargs): return with_method(orig_method, *args, **kwargs) return wrap_func def is_wsgi_application(node): frame = node.frame() return node.name == 'application' and isinstance(frame, Module) and \ (frame.name == 'wsgi' or frame.path[0].endswith('wsgi.py') or frame.file.endswith('wsgi.py')) # Compat helpers def pylint_newstyle_classdef_compat(linter, warning_name, augment): if not hasattr(NewStyleConflictChecker, 'visit_classdef'): return suppress_message(linter, getattr(NewStyleConflictChecker, 'visit_classdef'), warning_name, augment) def apply_wrapped_augmentations(): """ Apply augmentation and supression rules through monkey patching of pylint. """ # NOTE: The monkey patching is done with wrap and needs to be done in a thread safe manner to support the # parallel option of pylint (-j). # This is achieved by comparing __name__ of the monkey patched object to the original value and only patch it if # these are equal. # Unused argument 'request' (get, post) current_is_name_ignored = VariablesChecker._is_name_ignored # pylint: disable=protected-access if current_is_name_ignored.__name__ == '_is_name_ignored': # pylint: disable=protected-access VariablesChecker._is_name_ignored = wrap(current_is_name_ignored, ignore_unused_argument_warnings_for_request) # ForeignKey and OneToOneField current_leave_module = VariablesChecker.leave_module if current_leave_module.__name__ == 'leave_module': # current_leave_module is not wrapped # Two threads may hit the next assignment concurrently, but the result is the same VariablesChecker.leave_module = wrap(current_leave_module, ignore_import_warnings_for_related_fields) # VariablesChecker.leave_module is now wrapped # else VariablesChecker.leave_module is already wrapped # augment things def apply_augmentations(linter): """Apply augmentation and suppression rules.""" augment_visit(linter, TypeChecker.visit_attribute, foreign_key_sets) augment_visit(linter, TypeChecker.visit_attribute, foreign_key_ids) suppress_message(linter, TypeChecker.visit_attribute, 'no-member', is_model_field_display_method) suppress_message(linter, TypeChecker.visit_attribute, 'no-member', is_style_attribute) suppress_message(linter, NameChecker.visit_assignname, 'invalid-name', is_urls_module_valid_constant) # supress errors when accessing magical class attributes suppress_message(linter, TypeChecker.visit_attribute, 'no-member', is_manager_attribute) suppress_message(linter, TypeChecker.visit_attribute, 'no-member', is_admin_attribute) suppress_message(linter, TypeChecker.visit_attribute, 'no-member', is_model_attribute) suppress_message(linter, TypeChecker.visit_attribute, 'no-member', is_field_attribute) suppress_message(linter, TypeChecker.visit_attribute, 'no-member', is_charfield_attribute) suppress_message(linter, TypeChecker.visit_attribute, 'no-member', is_datefield_attribute) suppress_message(linter, TypeChecker.visit_attribute, 'no-member', is_decimalfield_attribute) suppress_message(linter, TypeChecker.visit_attribute, 'no-member', is_filefield_attribute) suppress_message(linter, TypeChecker.visit_attribute, 'no-member', is_imagefield_attribute) suppress_message(linter, TypeChecker.visit_attribute, 'no-member', is_ipfield_attribute) suppress_message(linter, TypeChecker.visit_attribute, 'no-member', is_slugfield_attribute) suppress_message(linter, TypeChecker.visit_attribute, 'no-member', is_foreignkeyfield_attribute) suppress_message(linter, TypeChecker.visit_attribute, 'no-member', is_manytomanyfield_attribute) suppress_message(linter, TypeChecker.visit_attribute, 'no-member', is_onetoonefield_attribute) suppress_message(linter, TypeChecker.visit_attribute, 'no-member', is_form_attribute) for parents, attrs in VIEW_ATTRS: suppress_message(linter, TypeChecker.visit_attribute, 'no-member', generic_is_view_attribute(parents, attrs)) # formviews have too many ancestors, there's nothing the user of the library can do about that suppress_message(linter, MisdesignChecker.visit_classdef, 'too-many-ancestors', is_class('django.views.generic.edit.FormView')) # class-based generic views just have a longer inheritance chain suppress_message(linter, MisdesignChecker.visit_classdef, 'too-many-ancestors', is_class('django.views.generic.detail.BaseDetailView')) suppress_message(linter, MisdesignChecker.visit_classdef, 'too-many-ancestors', is_class('django.views.generic.edit.ProcessFormView')) # model forms have no __init__ method anywhere in their bases suppress_message(linter, ClassChecker.visit_classdef, 'W0232', is_class('django.forms.models.ModelForm')) # Meta suppress_message(linter, DocStringChecker.visit_classdef, 'missing-docstring', is_model_meta_subclass) pylint_newstyle_classdef_compat(linter, 'old-style-class', is_model_meta_subclass) suppress_message(linter, ClassChecker.visit_classdef, 'no-init', is_model_meta_subclass) suppress_message(linter, MisdesignChecker.leave_classdef, 'too-few-public-methods', is_model_meta_subclass) suppress_message(linter, ClassChecker.visit_attribute, 'protected-access', allow_meta_protected_access) # Media suppress_message(linter, NameChecker.visit_assignname, 'C0103', is_model_media_valid_attributes) suppress_message(linter, DocStringChecker.visit_classdef, 'missing-docstring', is_model_media_subclass) pylint_newstyle_classdef_compat(linter, 'old-style-class', is_model_media_subclass) suppress_message(linter, ClassChecker.visit_classdef, 'no-init', is_model_media_subclass) suppress_message(linter, MisdesignChecker.leave_classdef, 'too-few-public-methods', is_model_media_subclass) # Admin # Too many public methods (40+/20) # TODO: Count public methods of django.contrib.admin.options.ModelAdmin and increase # MisdesignChecker.config.max_public_methods to this value to count only user' methods. # nb_public_methods = 0 # for method in node.methods(): # if not method.name.startswith('_'): # nb_public_methods += 1 suppress_message(linter, MisdesignChecker.leave_classdef, 'R0904', is_model_admin_subclass) # Tests suppress_message(linter, MisdesignChecker.leave_classdef, 'R0904', is_model_test_case_subclass) # View # Method could be a function (get, post) suppress_message(linter, ClassChecker.leave_functiondef, 'no-self-use', is_model_view_subclass_method_shouldnt_be_function) # django-mptt suppress_message(linter, DocStringChecker.visit_classdef, 'missing-docstring', is_model_mpttmeta_subclass) pylint_newstyle_classdef_compat(linter, 'old-style-class', is_model_mpttmeta_subclass) suppress_message(linter, ClassChecker.visit_classdef, 'W0232', is_model_mpttmeta_subclass) suppress_message(linter, MisdesignChecker.leave_classdef, 'too-few-public-methods', is_model_mpttmeta_subclass) # factory_boy's DjangoModelFactory suppress_message(linter, TypeChecker.visit_attribute, 'no-member', is_model_factory) suppress_message(linter, ClassChecker.visit_functiondef, 'no-self-argument', is_factory_post_generation_method) # wsgi.py suppress_message(linter, NameChecker.visit_assignname, 'invalid-name', is_wsgi_application) apply_wrapped_augmentations() pylint-django-2.0.13/pylint_django/utils.py0000644000175000017500000000163413566215174020307 0ustar josephjoseph"""Utils.""" import sys from astroid.bases import Instance from astroid.exceptions import InferenceError from astroid.nodes import ClassDef from pylint_django.compat import Uninferable PY3 = sys.version_info >= (3, 0) def node_is_subclass(cls, *subclass_names): """Checks if cls node has parent with subclass_name.""" if not isinstance(cls, (ClassDef, Instance)): return False if cls.bases == Uninferable: return False for base_cls in cls.bases: try: for inf in base_cls.inferred(): if inf.qname() in subclass_names: return True if inf != cls and node_is_subclass(inf, *subclass_names): # check up the hierarchy in case we are a subclass of # a subclass of a subclass ... return True except InferenceError: continue return False pylint-django-2.0.13/pylint_django/transforms/0000755000175000017500000000000013566222372020765 5ustar josephjosephpylint-django-2.0.13/pylint_django/transforms/__init__.py0000644000175000017500000000227213510363306023071 0ustar josephjoseph"""Transforms.""" import os import re import astroid from pylint_django.transforms import foreignkey, fields foreignkey.add_transform(astroid.MANAGER) fields.add_transforms(astroid.MANAGER) def _add_transform(package_name): def fake_module_builder(): """ Build a fake module to use within transformations. @package_name is a parameter from the outher scope b/c according to the docs this can't receive any parameters. http://pylint.pycqa.org/projects/astroid/en/latest/extending.html?highlight=MANAGER#module-extender-transforms """ transforms_dir = os.path.join(os.path.dirname(__file__), 'transforms') fake_module_path = os.path.join(transforms_dir, '%s.py' % re.sub(r'\.', '_', package_name)) with open(fake_module_path) as modulefile: fake_module = modulefile.read() return astroid.builder.AstroidBuilder(astroid.MANAGER).string_build(fake_module) astroid.register_module_extender(astroid.MANAGER, package_name, fake_module_builder) _add_transform('django.utils.translation') # register transform for FileField/ImageField, see #60 _add_transform('django.db.models.fields.files') pylint-django-2.0.13/pylint_django/transforms/foreignkey.py0000644000175000017500000001126013556267631023507 0ustar josephjosephfrom itertools import chain from astroid import ( MANAGER, nodes, InferenceError, inference_tip, UseInferenceDefault ) from astroid.nodes import ClassDef, Attribute from pylint_django.utils import node_is_subclass def is_foreignkey_in_class(node): # is this of the form field = models.ForeignKey if not isinstance(node.parent, nodes.Assign): return False if not isinstance(node.parent.parent, ClassDef): return False if isinstance(node.func, Attribute): attr = node.func.attrname elif isinstance(node.func, nodes.Name): attr = node.func.name else: return False return attr in ('OneToOneField', 'ForeignKey') def _get_model_class_defs_from_module(module, model_name, module_name): class_defs = [] for module_node in module.lookup(model_name)[1]: if (isinstance(module_node, nodes.ClassDef) and node_is_subclass(module_node, 'django.db.models.base.Model')): class_defs.append(module_node) elif isinstance(module_node, nodes.ImportFrom): imported_module = module_node.do_import_module() class_defs.extend( _get_model_class_defs_from_module( imported_module, model_name, module_name ) ) return class_defs def infer_key_classes(node, context=None): keyword_args = [] if node.keywords: keyword_args = [kw.value for kw in node.keywords if kw.arg == 'to'] all_args = chain(node.args, keyword_args) for arg in all_args: # typically the class of the foreign key will # be the first argument, so we'll go from left to right if isinstance(arg, (nodes.Name, nodes.Attribute)): try: key_cls = None for inferred in arg.infer(context=context): key_cls = inferred break except InferenceError: continue else: if key_cls is not None: break elif isinstance(arg, nodes.Const): try: # can be 'self' , 'Model' or 'app.Model' if arg.value == 'self': module_name = '' # for relations with `to` first parent be Keyword(arg='to') # and we need to go deeper in parent tree to get model name if isinstance(arg.parent, nodes.Keyword) and arg.parent.arg == 'to': model_name = arg.parent.parent.parent.parent.name else: model_name = arg.parent.parent.parent.name else: module_name, _, model_name = arg.value.rpartition('.') except AttributeError: break # when ForeignKey is specified only by class name we assume that # this class must be found in the current module if not module_name: current_module = node.frame() while not isinstance(current_module, nodes.Module): current_module = current_module.parent.frame() module_name = current_module.name elif not module_name.endswith('models'): # otherwise Django allows specifying an app name first, e.g. # ForeignKey('auth.User') so we try to convert that to # 'auth.models', 'User' which works nicely with the `endswith()` # comparison below module_name += '.models' # ensure that module is loaded in astroid_cache, for cases when models is a package if module_name not in MANAGER.astroid_cache: MANAGER.ast_from_module_name(module_name) # create list from dict_values, because it may be modified in a loop for module in list(MANAGER.astroid_cache.values()): # only load model classes from modules which match the module in # which *we think* they are defined. This will prevent infering # other models of the same name which are found elsewhere! if model_name in module.locals and module.name.endswith(module_name): class_defs = _get_model_class_defs_from_module( module, model_name, module_name ) if class_defs: return iter([class_defs[0].instantiate_class()]) else: raise UseInferenceDefault return iter([key_cls.instantiate_class()]) def add_transform(manager): manager.register_transform(nodes.Call, inference_tip(infer_key_classes), is_foreignkey_in_class) pylint-django-2.0.13/pylint_django/transforms/fields.py0000644000175000017500000000664413510363317022611 0ustar josephjosephfrom astroid import ( MANAGER, scoped_nodes, nodes, inference_tip, AstroidImportError ) from pylint_django import utils _STR_FIELDS = ('CharField', 'SlugField', 'URLField', 'TextField', 'EmailField', 'CommaSeparatedIntegerField', 'FilePathField', 'GenericIPAddressField', 'IPAddressField', 'RegexField', 'SlugField') _INT_FIELDS = ('IntegerField', 'SmallIntegerField', 'BigIntegerField', 'PositiveIntegerField', 'PositiveSmallIntegerField') _BOOL_FIELDS = ('BooleanField', 'NullBooleanField') _RANGE_FIELDS = ('RangeField', 'IntegerRangeField', 'BigIntegerRangeField', 'FloatRangeField', 'DateTimeRangeField', 'DateRangeField') def is_model_field(cls): return cls.qname().startswith('django.db.models.fields') or \ cls.qname().startswith('django.contrib.postgres.fields') def is_form_field(cls): return cls.qname().startswith('django.forms.fields') def is_model_or_form_field(cls): return is_model_field(cls) or is_form_field(cls) def apply_type_shim(cls, _context=None): # noqa if cls.name in _STR_FIELDS: base_nodes = scoped_nodes.builtin_lookup('str') elif cls.name in _INT_FIELDS: base_nodes = scoped_nodes.builtin_lookup('int') elif cls.name in _BOOL_FIELDS: base_nodes = scoped_nodes.builtin_lookup('bool') elif cls.name == 'FloatField': base_nodes = scoped_nodes.builtin_lookup('float') elif cls.name == 'DecimalField': try: base_nodes = MANAGER.ast_from_module_name('_decimal').lookup('Decimal') except AstroidImportError: base_nodes = MANAGER.ast_from_module_name('_pydecimal').lookup('Decimal') elif cls.name in ('SplitDateTimeField', 'DateTimeField'): base_nodes = MANAGER.ast_from_module_name('datetime').lookup('datetime') elif cls.name == 'TimeField': base_nodes = MANAGER.ast_from_module_name('datetime').lookup('time') elif cls.name == 'DateField': base_nodes = MANAGER.ast_from_module_name('datetime').lookup('date') elif cls.name == 'DurationField': base_nodes = MANAGER.ast_from_module_name('datetime').lookup('timedelta') elif cls.name == 'UUIDField': base_nodes = MANAGER.ast_from_module_name('uuid').lookup('UUID') elif cls.name == 'ManyToManyField': base_nodes = MANAGER.ast_from_module_name('django.db.models.query').lookup('QuerySet') elif cls.name in ('ImageField', 'FileField'): base_nodes = MANAGER.ast_from_module_name('django.core.files.base').lookup('File') elif cls.name == 'ArrayField': base_nodes = scoped_nodes.builtin_lookup('list') elif cls.name in ('HStoreField', 'JSONField'): base_nodes = scoped_nodes.builtin_lookup('dict') elif cls.name in _RANGE_FIELDS: base_nodes = MANAGER.ast_from_module_name('psycopg2._range').lookup('Range') else: return iter([cls]) # XXX: for some reason, with python3, this particular line triggers a # check in the StdlibChecker for deprecated methods; one of these nodes # is an ImportFrom which has no qname() method, causing the checker # to die... if utils.PY3: base_nodes = [n for n in base_nodes[1] if not isinstance(n, nodes.ImportFrom)] else: base_nodes = list(base_nodes[1]) return iter([cls] + base_nodes) def add_transforms(manager): manager.register_transform(nodes.ClassDef, inference_tip(apply_type_shim), is_model_or_form_field) pylint-django-2.0.13/pylint_django/transforms/transforms/0000755000175000017500000000000013566222372023163 5ustar josephjosephpylint-django-2.0.13/pylint_django/transforms/transforms/__init__.py0000644000175000017500000000000013510363306025252 0ustar josephjosephpylint-django-2.0.13/pylint_django/transforms/transforms/django_utils_translation.py0000644000175000017500000000004413510363306030623 0ustar josephjosephdef ugettext_lazy(_): return '' pylint-django-2.0.13/pylint_django/transforms/transforms/django_db_models_fields_files.py0000644000175000017500000000116313510363306031510 0ustar josephjoseph# pylint: disable=super-init-not-called from django.db.models.fields import files as django_fields class FileField(django_fields.FieldFile, django_fields.FileField): def __init__(self, verbose_name=None, name=None, upload_to='', storage=None, **kwargs): django_fields.FileField.__init__(verbose_name, name, upload_to, storage, **kwargs) class ImageField(django_fields.ImageFieldFile, django_fields.ImageField): def __init__(self, verbose_name=None, name=None, width_field=None, height_field=None, **kwargs): django_fields.ImageField.__init__(verbose_name, name, width_field, height_field, **kwargs) pylint-django-2.0.13/MANIFEST.in0000644000175000017500000000022313510363306015451 0ustar josephjosephinclude *.md include *.rst include LICENSE include pylint_django/transforms/transforms/*.py recursive-include pylint_django/tests/ *.py *.rc *.txt pylint-django-2.0.13/PKG-INFO0000644000175000017500000006627613566222372015044 0ustar josephjosephMetadata-Version: 2.1 Name: pylint-django Version: 2.0.13 Summary: A Pylint plugin to help Pylint understand the Django web framework Home-page: https://github.com/PyCQA/pylint-django Author: landscape.io Author-email: code@landscape.io License: GPLv2 Description: pylint-django ============= .. image:: https://travis-ci.org/PyCQA/pylint-django.svg?branch=master :target: https://travis-ci.org/PyCQA/pylint-django .. image:: https://landscape.io/github/landscapeio/pylint-django/master/landscape.png :target: https://landscape.io/github/landscapeio/pylint-django .. image:: https://coveralls.io/repos/PyCQA/pylint-django/badge.svg :target: https://coveralls.io/r/PyCQA/pylint-django .. image:: https://img.shields.io/pypi/v/pylint-django.svg :target: https://pypi.python.org/pypi/pylint-django About ----- ``pylint-django`` is a `Pylint `__ plugin for improving code analysis when analysing code using Django. It is also used by the `Prospector `__ tool. Installation ------------ To install:: pip install pylint-django **WARNING:** ``pylint-django`` will not install ``Django`` by default because this causes more trouble than good, `see discussion `__. If you wish to automatically install the latest version of ``Django`` then:: pip install pylint-django[with_django] otherwise sort out your testing environment and please **DO NOT** report issues about missing Django! Usage ----- Ensure ``pylint-django`` is installed and on your path and then execute:: pylint --load-plugins pylint_django [..other options..] Prospector ---------- If you have ``prospector`` installed, then ``pylint-django`` will already be installed as a dependency, and will be activated automatically if Django is detected:: prospector [..other options..] Features -------- * Prevents warnings about Django-generated attributes such as ``Model.objects`` or ``Views.request``. * Prevents warnings when using ``ForeignKey`` attributes ("Instance of ForeignKey has no member"). * Fixes pylint's knowledge of the types of Model and Form field attributes * Validates ``Model.__unicode__`` methods. * ``Meta`` informational classes on forms and models do not generate errors. * Flags dangerous use of the exclude attribute in ModelForm.Meta. Additional plugins ------------------ ``pylint_django.checkers.db_performance`` looks for migrations which add new model fields and these fields have a default value. According to `Django docs `__ this may have performance penalties especially on large tables. The prefered way is to add a new DB column with ``null=True`` because it will be created instantly and then possibly populate the table with the desired default values. Only the last migration from a sub-directory will be examined! This plugin is disabled by default! To enable it:: pylint --load-plugins pylint_django --load-plugins pylint_django.checkers.db_performance Known issues ------------ If you reference foreign-key models by their name (as string) ``pylint-django`` may not be able to find the model and will report issues because it has no idea what the underlying type of this field is. Supported options are:: - ``self`` and ``Model`` - look for this class in the current module which is being examined - ``app.Model`` - try loading ``app.models`` into the AST parser and look for ``Model`` there If your ``models.py`` itself is not importing the foreign-key class there's probably some import problem (likely circular dependencies) preventing referencing the foreign-key class directly. In this case ``pylint-django`` can't do much about it. We always recommend referencing foreign-key models by their classes. Contributing ------------ Please feel free to add your name to the ``CONTRIBUTORS.rst`` file if you want to be credited when pull requests get merged. You can also add to the ``CHANGELOG.rst`` file if you wish, although we'll also do that when merging. Tests ----- The structure of the test package follows that from pylint itself. It is fairly simple: create a module starting with ``func_`` followed by a test name, and insert into it some code. The tests will run pylint against these modules. If the idea is that no messages now occur, then that is fine, just check to see if it works by running ``scripts/test.sh``. Any command line argument passed to ``scripts/test.sh`` will be passed to the internal invocation of ``pytest``. For example if you want to debug the tests you can execute ``scripts/test.sh --capture=no``. A specific test case can be run by filtering based on the file name of the test case ``./scripts/test.sh -k 'func_noerror_views'``. Ideally, add some pylint error suppression messages to the file to prevent spurious warnings, since these are all tiny little modules not designed to do anything so there's no need to be perfect. It is possible to make tests with expected error output, for example, if adding a new message or simply accepting that pylint is supposed to warn. A ``test_file_name.txt`` file contains a list of expected error messages in the format ``error-type:line number:class name or empty:1st line of detailed error text:confidence or empty``. License ------- ``pylint-django`` is available under the GPLv2 license. Changelog ========= Version 2.0.13 (23 Nov 2019), HackBulgaria edition -------------------------------------------------- - Suppress ``too-many-ancestors`` for class-based generic views - Add ``handler400``, ``handler403``, ``handler404`` to good_names. Fix `#248 `_ Version 2.0.12 (04 Nov 2019) ---------------------------- - Fix too broad suppression of ``unused-argument`` warnings for functions and methods where the first argument is named ``request``. Now issues warnings for the rest of the arguments if they are unused. Fix `#249 `_ (Pascal Urban) - Pass arguments of ``scripts/test.sh`` to ``test_func/pytest`` to ease development (Pascal Urban) - Document behavior when ForeignKey fields are referenced as strings. Fix `#241 `_ Version 2.0.11 (10 July 2019) ----------------------------- - Use ``functools.wrap`` to preserve ``leave_module`` info (Mohit Solanki) Version 2.0.10 (07 July 2019), Novi Sad edition ----------------------------------------------- - Suppress ``no-member`` for ``ManyToManyField``. Fix `#192 `_ and `#237 `_ (Pierre Chiquet) - Fix ``UnboundLocalError`` with ``ForeignKey(to=)``. Fix `#232 `_ (Sardorbek Imomaliev) Version 2.0.9 (26 April 2019) ----------------------------- - Fix ``UnboundLocalError: local variable 'key_cls' referenced before assignment`` for cases when models is a python package, the ``to`` argument is a string that is used in this pattern ``app.Model`` and also there is some other ``bool`` const like ``null=True`` right after ``to``. (Sardorbek Imomaliev) - Don't crash if ForeignKey field doesn't have keyword arguments Fix `#230 `_ Version 2.0.8 (18 April 2019) ----------------------------- - Support recursive (self) ForeignKey relations. Fix `#208 `_ (Daniil Kharkov) Version 2.0.7 (16 April 2019) ----------------------------- - Fixed ``AstroidImportError`` for ``DecimalField``. Fix `#221 `_ (Daniil Kharkov) - Add ``load_configuration()`` in ``pylint_django/__init__.py``. Fix #222 `#222 `_ - Support ForeignKey relations with ``to`` keyword. Fix `#223 `_ (Daniil Kharkov) Version 2.0.6 (27 Feb 2019) --------------------------- - Updating dependency version of pylint-plugin-utils as pylint 2.3 release was not compatible `#220 `_ - Improvements to tox.ini: `#217 `_ and `#216 `_ (@aerostitch) - Add support for new load_configuration hook of pylint `#214 `_ (@matusvalo) - 'urlpatterns' no longer reported as an invalid constant name Version 2.0.5 (17 Dec 2018) --------------------------- Bumping the version number because there's been a mix-up between GitHub tags and the versions pushed to PyPI for 2.0.3 and 2.0.4. Please use 2.0.5 which includes the changes mentioned below! Version 2.0.4 (do not use) -------------------------- - Avoid traceback with concurrent execution. Fix `#197 `_ - Suppress ``no-member`` errors for ``LazyFunction`` in factories - Suppress ``no-member`` errors for ``RelatedManager`` fields - Clean up compatibility code: `PR #207 `_ Version 2.0.3 (do not use) -------------------------- - Fixing compatability between ranges of astroid (2.0.4 -> 2.1) and pylint (2.1.1 -> 2.2). `#201 `_ and `#202 `_ Version 2.0.2 (26 Aug 2018) --------------------------- - Suppress false-positive no-self-argument in factory.post_generation. Fix `#190 `_ (Federico Bond) Version 2.0.1 (20 Aug 2018) --------------------------- - Enable testing with Django 2.1 - Add test for Model.objects.get_or_create(). Close `#156 `__ - Add test for objects.exclude(). Close `#177 `__ - Fix Instance of 'Model' has no 'id' member (no-member), fix Class 'UserCreationForm' has no 'declared_fields' member. Close `#184 `__ - Fix for Instance of 'ManyToManyField' has no 'add' member. Close `#163 `__ - Add test & fix for unused arguments on class based views Version 2.0 (25 July 2018) -------------------------- - Requires pylint >= 2.0 which doesn't support Python 2 anymore! - Add modelform-uses-unicode check to flag dangerous use of the exclude attribute in ModelForm.Meta (Federico Bond). Version 0.11.1 (25 May 2018), the DjangoCon Heidelberg edition -------------------------------------------------------------- - Enable test case for ``urlpatterns`` variable which was previously disabled - Disable ``unused-argument`` message for the ``request`` argument passed to view functions. Fix `#155 `__ - Add transformations for ``model_utils`` managers instead of special-casing them. Fix `#160 `__ Version 0.11 (18 April 2018), the TestCon Moscow edition -------------------------------------------------------- - New ``JsonResponseChecker`` that looks for common anti-patterns with http responses returning JSON. This includes:: HttpResponse(json.dumps(data)) HttpResponse(data, content_type='application/json') JsonResponse(data, content_type=...) Version 0.10.0 (10 April 2018) ------------------------------ - Remove the compatibility layer for older astroid versions - Make flake8 happy. Fix `#102 `__ - Fix: compatibility with Python < 3.6 caused by ``ModuleNotFoundError`` not available on older versions of Python (Juan Rial) - Show README and CHANGELOG on PyPI. Fix `#122 `__ - Fix explicit unicode check with ``python_2_unicode_compatible`` base models (Federico Bond) - Suppress ``not-an-iterable`` message for 'objects'. Fix `#117 `__ - Teach pylint_django that ``objects.all()`` is subscriptable. Fix `#144 `__ - Suppress ``invalid-name`` for ``wsgi.application``. Fix `#77 `__ - Add test for ``WSGIRequest.context``. Closes `#78 `__ - Register transforms for ``FileField``. Fix `#60 `__ - New checker ``pylint_django.checkers.db_performance``. Enables checking of migrations and reports when there's an ``AddField`` operation with a default value which may slow down applying migrations on large tables. This may also lead to production tables being locked while migrations are being applied. Fix `#118 `__ - Suppress ``no-member`` for ``factory.SubFactory`` objects. Useful when model factories use ``factory.SubFactory()`` for foreign key relations. Version 0.9.4 (12 March 2018) ----------------------------- - Add an optional dependency on Django - Fix the ``DjangoInstalledChecker`` so it can actually warn when Django isn't available - Fix `#136 `__ by adding automated build and sanity test scripts Version 0.9.3 (removed from PyPI) --------------------------------- - Fix `#133 `__ and `#134 `__ by including package data when building wheel and tar.gz packages for PyPI (Joseph Herlant) Version 0.9.2 (broken) ---------------------- - Fix `#129 `__ - Move tests under ``site-packages/pylint_django`` (Mr. Senko) - Fix `#96 `__ - List Django as a dependency (Mr. Senko) Version 0.9.1 (26 Feb 2018) --------------------------- - Fix `#123 `__ - Update links after the move to PyCQA (Mr. Senko) - Add test for Meta class from django\_tables2 (Mr. Senko) - Fix flake8 complaints (Peter Bittner) - Add missing .txt and .rc test files to MANIFEST.in (Joseph Herlant) Version 0.9 (25 Jan 2018) ------------------------- - Fix `#120 `__ - TypeError: 'NamesConsumer' object does not support indexing (Simone Basso) - Fix `#110 `__ and `#35 `__ - resolve ForeignKey models specified as strings instead of class names (Mr. Senko) Version 0.8.0 (20 Jan 2018) --------------------------- - This is the last version to support Python 2. Issues a deprecation warning! - `#109 `__, adding 'urlpatterns', 'register', 'app\_name' to good names. Obsoletes `#111 `__, fixes `#108 `__ (Vinay Pai) - Add 'handler500' to good names (Mr. Senko) - `#103 `__: Support factory\_boy's DjangoModelFactory Meta class (Konstantinos Koukopoulos) - `#100 `__: Fix E1101:Instance of '**proxy**\ ' has no 'format' member' when using .format() on a ugettext\_lazy translation. Fixes `#80 `__ (canarduck) - `#99 `__: Add tests and transforms for DurationField, fixes `#95 `__ (James M. Allen) - `#92 `__: Add json field to WSGIRequest proxy (sjk4sc) - `#84 `__: Add support for django.contrib.postgres.fields and UUIDField (Villiers Strauss) - Stop testing with older Django versions. Currently testing with Django 1.11.x and 2.0 - Stop testing on Python 2, no functional changes in the source code though - Update tests and require latest version of pylint (>=1.8), fixes `#53 `__, `#97 `__ - `#81 `__ Fix 'duplicate-except' false negative for except blocks which catch the ``DoesNotExist`` exception. Version 0.7.4 ------------- - `#88 `__ Fixed builds with Django 1.10 (thanks to `federicobond `__) - `#91 `__ Fixed race condition when running with pylint parallel execution mode (thanks to `jeremycarroll `__) - `#64 `__ "Meta is old style class" now suppressed on BaseSerializer too (thanks to `unklphil `__) - `#70 `__ Updating to handle newer pylint/astroid versions (thanks to `iXce `__) Version 0.7.2 ------------- - `#76 `__ Better handling of mongoengine querysetmanager - `#73 `__ `#72 `__ Make package zip safe to help fix some path problems - `#68 `__ Suppressed invalid constant warning for "app\_name" in urls.py - `#67 `__ Fix view.args and view.kwargs - `#66 `__ accessing \_meta no longer causes a protected-access warning as this is a public API as of Django 1.8 - `#65 `__ Add support of mongoengine module. - `#59 `__ Silence old-style-class for widget Meta Version 0.7.1 ------------- - `#52 `__ - Fixed stupid mistake when using versioninfo Version 0.7 ----------- - `#51 `__ - Fixed compatibility with pylint 1.5 / astroid 1.4.1 Version 0.6.1 ------------- - `#43 `__ - Foreign key ID access (``somefk_id``) does not raise an 'attribute not found' warning - `#31 `__ - Support for custom model managers (thanks `smirolo `__) - `#48 `__ - Added support for django-restframework (thanks `mbertolacci `__) Version 0.6 ----------- - Pylint 1.4 dropped support for Python 2.6, therefore a constraint is added that pylint-django will only work with Python2.6 if pylint<=1.3 is installed - `#40 `__ - pylint 1.4 warned about View and Model classes not having enough public methods; this is suppressed - `#37 `__ - fixed an infinite loop when using astroid 1.3.3+ - `#36 `__ - no longer warning about lack of ``__unicode__`` method on abstract model classes - `PR #34 `__ - prevent warning about use of ``super()`` on ModelManager classes Version 0.5.5 ------------- - `PR #27 `__ - better ``ForeignKey`` transforms, which now work when of the form ``othermodule.ModelClass``. This also fixes a problem where an inferred type would be ``_Yes`` and pylint would fail - `PR #28 `__ - better knowledge of ``ManyToManyField`` classes Version 0.5.4 ------------- - Improved resiliance to inference failure when Django types cannot be inferred (which can happen if Django is not on the system path Version 0.5.3 ------------- - `Issue #25 `__ Fixing cases where a module defines ``get`` as a method Version 0.5.2 ------------- - Fixed a problem where type inference could get into an infinite loop Version 0.5.1 ------------- - Removed usage of a Django object, as importing it caused Django to try to configure itself and thus throw an ImproperlyConfigured exception. Version 0.5 ----------- - `Issue #7 `__ Improved handling of Django model fields - `Issue #10 `__ No warning about missing **unicode** if the Django python3/2 compatability tools are used - `Issue #11 `__ Improved handling of Django form fields - `Issue #12 `__ Improved handling of Django ImageField and FileField objects - `Issue #14 `__ Models which do not define **unicode** but whose parents do now have a new error (W5103) instead of incorrectly warning about no **unicode** being present. - `Issue #21 `__ ``ForeignKey`` and ``OneToOneField`` fields on models are replaced with instance of the type they refer to in the AST, which allows pylint to generate correct warnings about attributes they may or may not have. Version 0.3 ----------- - Python3 is now supported - ``__unicode__`` warning on models does not appear in Python3 Version 0.2 ----------- - Pylint now recognises ``BaseForm`` as an ancestor of ``Form`` and subclasses - Improved ``Form`` support - `Issue #2 `__ - a subclass of a ``Model`` or ``Form`` also has warnings about a ``Meta`` class suppressed. - `Issue #3 `__ - ``Form`` and ``ModelForm`` subclasses no longer warn about ``Meta`` classes. Keywords: pylint,django,plugin Platform: UNKNOWN Classifier: Environment :: Console Classifier: Intended Audience :: Developers Classifier: Operating System :: Unix Classifier: Topic :: Software Development :: Quality Assurance Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.5 Classifier: Programming Language :: Python :: 3.6 Classifier: Programming Language :: Python :: 3.7 Provides-Extra: with_django Provides-Extra: for_tests pylint-django-2.0.13/setup.cfg0000644000175000017500000000004613566222372015547 0ustar josephjoseph[egg_info] tag_build = tag_date = 0 pylint-django-2.0.13/SECURITY.md0000644000175000017500000000113213562033660015510 0ustar josephjoseph# Security Policy ## Supported Versions | Version | Supported | | ------- | ------------------ | | [latest](https://pypi.org/project/pylint-django/) | :heavy_check_mark: | ## Reporting a Vulnerability In case you have found a security problem with pylint-django *DO NOT* report it into GitHub Issues. Instead go to [https://tidelift.com/security](https://tidelift.com/security) and follow the instructions there. At least one of the package maintainers ([@atodorov](http://github.com/atodorov)) is a lifter at Tidelift and will be notified when you report the security problem with them! pylint-django-2.0.13/setup.py0000644000175000017500000000237013566222273015442 0ustar josephjoseph# -*- coding: UTF-8 -*- """ Setup module for Pylint plugin for Django. """ from setuptools import setup, find_packages LONG_DESCRIPTION = open('README.rst').read() + "\n" + open('CHANGELOG.rst').read() setup( name='pylint-django', url='https://github.com/PyCQA/pylint-django', author='landscape.io', author_email='code@landscape.io', description='A Pylint plugin to help Pylint understand the Django web framework', long_description=LONG_DESCRIPTION, version='2.0.13', packages=find_packages(), include_package_data=True, install_requires=[ 'pylint-plugin-utils>=0.5', 'pylint>=2.0', ], extras_require={ 'with_django': ['Django'], 'for_tests': ['django_tables2', 'factory-boy', 'coverage', 'pytest'], }, license='GPLv2', classifiers=[ 'Environment :: Console', 'Intended Audience :: Developers', 'Operating System :: Unix', 'Topic :: Software Development :: Quality Assurance', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', ], keywords=['pylint', 'django', 'plugin'], zip_safe=False, ) pylint-django-2.0.13/pylint_django.egg-info/0000755000175000017500000000000013566222372020261 5ustar josephjosephpylint-django-2.0.13/pylint_django.egg-info/not-zip-safe0000644000175000017500000000000113566222346022510 0ustar josephjoseph pylint-django-2.0.13/pylint_django.egg-info/requires.txt0000644000175000017500000000016313566222372022661 0ustar josephjosephpylint-plugin-utils>=0.5 pylint>=2.0 [for_tests] django_tables2 factory-boy coverage pytest [with_django] Django pylint-django-2.0.13/pylint_django.egg-info/PKG-INFO0000644000175000017500000006627613566222372021377 0ustar josephjosephMetadata-Version: 2.1 Name: pylint-django Version: 2.0.13 Summary: A Pylint plugin to help Pylint understand the Django web framework Home-page: https://github.com/PyCQA/pylint-django Author: landscape.io Author-email: code@landscape.io License: GPLv2 Description: pylint-django ============= .. image:: https://travis-ci.org/PyCQA/pylint-django.svg?branch=master :target: https://travis-ci.org/PyCQA/pylint-django .. image:: https://landscape.io/github/landscapeio/pylint-django/master/landscape.png :target: https://landscape.io/github/landscapeio/pylint-django .. image:: https://coveralls.io/repos/PyCQA/pylint-django/badge.svg :target: https://coveralls.io/r/PyCQA/pylint-django .. image:: https://img.shields.io/pypi/v/pylint-django.svg :target: https://pypi.python.org/pypi/pylint-django About ----- ``pylint-django`` is a `Pylint `__ plugin for improving code analysis when analysing code using Django. It is also used by the `Prospector `__ tool. Installation ------------ To install:: pip install pylint-django **WARNING:** ``pylint-django`` will not install ``Django`` by default because this causes more trouble than good, `see discussion `__. If you wish to automatically install the latest version of ``Django`` then:: pip install pylint-django[with_django] otherwise sort out your testing environment and please **DO NOT** report issues about missing Django! Usage ----- Ensure ``pylint-django`` is installed and on your path and then execute:: pylint --load-plugins pylint_django [..other options..] Prospector ---------- If you have ``prospector`` installed, then ``pylint-django`` will already be installed as a dependency, and will be activated automatically if Django is detected:: prospector [..other options..] Features -------- * Prevents warnings about Django-generated attributes such as ``Model.objects`` or ``Views.request``. * Prevents warnings when using ``ForeignKey`` attributes ("Instance of ForeignKey has no member"). * Fixes pylint's knowledge of the types of Model and Form field attributes * Validates ``Model.__unicode__`` methods. * ``Meta`` informational classes on forms and models do not generate errors. * Flags dangerous use of the exclude attribute in ModelForm.Meta. Additional plugins ------------------ ``pylint_django.checkers.db_performance`` looks for migrations which add new model fields and these fields have a default value. According to `Django docs `__ this may have performance penalties especially on large tables. The prefered way is to add a new DB column with ``null=True`` because it will be created instantly and then possibly populate the table with the desired default values. Only the last migration from a sub-directory will be examined! This plugin is disabled by default! To enable it:: pylint --load-plugins pylint_django --load-plugins pylint_django.checkers.db_performance Known issues ------------ If you reference foreign-key models by their name (as string) ``pylint-django`` may not be able to find the model and will report issues because it has no idea what the underlying type of this field is. Supported options are:: - ``self`` and ``Model`` - look for this class in the current module which is being examined - ``app.Model`` - try loading ``app.models`` into the AST parser and look for ``Model`` there If your ``models.py`` itself is not importing the foreign-key class there's probably some import problem (likely circular dependencies) preventing referencing the foreign-key class directly. In this case ``pylint-django`` can't do much about it. We always recommend referencing foreign-key models by their classes. Contributing ------------ Please feel free to add your name to the ``CONTRIBUTORS.rst`` file if you want to be credited when pull requests get merged. You can also add to the ``CHANGELOG.rst`` file if you wish, although we'll also do that when merging. Tests ----- The structure of the test package follows that from pylint itself. It is fairly simple: create a module starting with ``func_`` followed by a test name, and insert into it some code. The tests will run pylint against these modules. If the idea is that no messages now occur, then that is fine, just check to see if it works by running ``scripts/test.sh``. Any command line argument passed to ``scripts/test.sh`` will be passed to the internal invocation of ``pytest``. For example if you want to debug the tests you can execute ``scripts/test.sh --capture=no``. A specific test case can be run by filtering based on the file name of the test case ``./scripts/test.sh -k 'func_noerror_views'``. Ideally, add some pylint error suppression messages to the file to prevent spurious warnings, since these are all tiny little modules not designed to do anything so there's no need to be perfect. It is possible to make tests with expected error output, for example, if adding a new message or simply accepting that pylint is supposed to warn. A ``test_file_name.txt`` file contains a list of expected error messages in the format ``error-type:line number:class name or empty:1st line of detailed error text:confidence or empty``. License ------- ``pylint-django`` is available under the GPLv2 license. Changelog ========= Version 2.0.13 (23 Nov 2019), HackBulgaria edition -------------------------------------------------- - Suppress ``too-many-ancestors`` for class-based generic views - Add ``handler400``, ``handler403``, ``handler404`` to good_names. Fix `#248 `_ Version 2.0.12 (04 Nov 2019) ---------------------------- - Fix too broad suppression of ``unused-argument`` warnings for functions and methods where the first argument is named ``request``. Now issues warnings for the rest of the arguments if they are unused. Fix `#249 `_ (Pascal Urban) - Pass arguments of ``scripts/test.sh`` to ``test_func/pytest`` to ease development (Pascal Urban) - Document behavior when ForeignKey fields are referenced as strings. Fix `#241 `_ Version 2.0.11 (10 July 2019) ----------------------------- - Use ``functools.wrap`` to preserve ``leave_module`` info (Mohit Solanki) Version 2.0.10 (07 July 2019), Novi Sad edition ----------------------------------------------- - Suppress ``no-member`` for ``ManyToManyField``. Fix `#192 `_ and `#237 `_ (Pierre Chiquet) - Fix ``UnboundLocalError`` with ``ForeignKey(to=)``. Fix `#232 `_ (Sardorbek Imomaliev) Version 2.0.9 (26 April 2019) ----------------------------- - Fix ``UnboundLocalError: local variable 'key_cls' referenced before assignment`` for cases when models is a python package, the ``to`` argument is a string that is used in this pattern ``app.Model`` and also there is some other ``bool`` const like ``null=True`` right after ``to``. (Sardorbek Imomaliev) - Don't crash if ForeignKey field doesn't have keyword arguments Fix `#230 `_ Version 2.0.8 (18 April 2019) ----------------------------- - Support recursive (self) ForeignKey relations. Fix `#208 `_ (Daniil Kharkov) Version 2.0.7 (16 April 2019) ----------------------------- - Fixed ``AstroidImportError`` for ``DecimalField``. Fix `#221 `_ (Daniil Kharkov) - Add ``load_configuration()`` in ``pylint_django/__init__.py``. Fix #222 `#222 `_ - Support ForeignKey relations with ``to`` keyword. Fix `#223 `_ (Daniil Kharkov) Version 2.0.6 (27 Feb 2019) --------------------------- - Updating dependency version of pylint-plugin-utils as pylint 2.3 release was not compatible `#220 `_ - Improvements to tox.ini: `#217 `_ and `#216 `_ (@aerostitch) - Add support for new load_configuration hook of pylint `#214 `_ (@matusvalo) - 'urlpatterns' no longer reported as an invalid constant name Version 2.0.5 (17 Dec 2018) --------------------------- Bumping the version number because there's been a mix-up between GitHub tags and the versions pushed to PyPI for 2.0.3 and 2.0.4. Please use 2.0.5 which includes the changes mentioned below! Version 2.0.4 (do not use) -------------------------- - Avoid traceback with concurrent execution. Fix `#197 `_ - Suppress ``no-member`` errors for ``LazyFunction`` in factories - Suppress ``no-member`` errors for ``RelatedManager`` fields - Clean up compatibility code: `PR #207 `_ Version 2.0.3 (do not use) -------------------------- - Fixing compatability between ranges of astroid (2.0.4 -> 2.1) and pylint (2.1.1 -> 2.2). `#201 `_ and `#202 `_ Version 2.0.2 (26 Aug 2018) --------------------------- - Suppress false-positive no-self-argument in factory.post_generation. Fix `#190 `_ (Federico Bond) Version 2.0.1 (20 Aug 2018) --------------------------- - Enable testing with Django 2.1 - Add test for Model.objects.get_or_create(). Close `#156 `__ - Add test for objects.exclude(). Close `#177 `__ - Fix Instance of 'Model' has no 'id' member (no-member), fix Class 'UserCreationForm' has no 'declared_fields' member. Close `#184 `__ - Fix for Instance of 'ManyToManyField' has no 'add' member. Close `#163 `__ - Add test & fix for unused arguments on class based views Version 2.0 (25 July 2018) -------------------------- - Requires pylint >= 2.0 which doesn't support Python 2 anymore! - Add modelform-uses-unicode check to flag dangerous use of the exclude attribute in ModelForm.Meta (Federico Bond). Version 0.11.1 (25 May 2018), the DjangoCon Heidelberg edition -------------------------------------------------------------- - Enable test case for ``urlpatterns`` variable which was previously disabled - Disable ``unused-argument`` message for the ``request`` argument passed to view functions. Fix `#155 `__ - Add transformations for ``model_utils`` managers instead of special-casing them. Fix `#160 `__ Version 0.11 (18 April 2018), the TestCon Moscow edition -------------------------------------------------------- - New ``JsonResponseChecker`` that looks for common anti-patterns with http responses returning JSON. This includes:: HttpResponse(json.dumps(data)) HttpResponse(data, content_type='application/json') JsonResponse(data, content_type=...) Version 0.10.0 (10 April 2018) ------------------------------ - Remove the compatibility layer for older astroid versions - Make flake8 happy. Fix `#102 `__ - Fix: compatibility with Python < 3.6 caused by ``ModuleNotFoundError`` not available on older versions of Python (Juan Rial) - Show README and CHANGELOG on PyPI. Fix `#122 `__ - Fix explicit unicode check with ``python_2_unicode_compatible`` base models (Federico Bond) - Suppress ``not-an-iterable`` message for 'objects'. Fix `#117 `__ - Teach pylint_django that ``objects.all()`` is subscriptable. Fix `#144 `__ - Suppress ``invalid-name`` for ``wsgi.application``. Fix `#77 `__ - Add test for ``WSGIRequest.context``. Closes `#78 `__ - Register transforms for ``FileField``. Fix `#60 `__ - New checker ``pylint_django.checkers.db_performance``. Enables checking of migrations and reports when there's an ``AddField`` operation with a default value which may slow down applying migrations on large tables. This may also lead to production tables being locked while migrations are being applied. Fix `#118 `__ - Suppress ``no-member`` for ``factory.SubFactory`` objects. Useful when model factories use ``factory.SubFactory()`` for foreign key relations. Version 0.9.4 (12 March 2018) ----------------------------- - Add an optional dependency on Django - Fix the ``DjangoInstalledChecker`` so it can actually warn when Django isn't available - Fix `#136 `__ by adding automated build and sanity test scripts Version 0.9.3 (removed from PyPI) --------------------------------- - Fix `#133 `__ and `#134 `__ by including package data when building wheel and tar.gz packages for PyPI (Joseph Herlant) Version 0.9.2 (broken) ---------------------- - Fix `#129 `__ - Move tests under ``site-packages/pylint_django`` (Mr. Senko) - Fix `#96 `__ - List Django as a dependency (Mr. Senko) Version 0.9.1 (26 Feb 2018) --------------------------- - Fix `#123 `__ - Update links after the move to PyCQA (Mr. Senko) - Add test for Meta class from django\_tables2 (Mr. Senko) - Fix flake8 complaints (Peter Bittner) - Add missing .txt and .rc test files to MANIFEST.in (Joseph Herlant) Version 0.9 (25 Jan 2018) ------------------------- - Fix `#120 `__ - TypeError: 'NamesConsumer' object does not support indexing (Simone Basso) - Fix `#110 `__ and `#35 `__ - resolve ForeignKey models specified as strings instead of class names (Mr. Senko) Version 0.8.0 (20 Jan 2018) --------------------------- - This is the last version to support Python 2. Issues a deprecation warning! - `#109 `__, adding 'urlpatterns', 'register', 'app\_name' to good names. Obsoletes `#111 `__, fixes `#108 `__ (Vinay Pai) - Add 'handler500' to good names (Mr. Senko) - `#103 `__: Support factory\_boy's DjangoModelFactory Meta class (Konstantinos Koukopoulos) - `#100 `__: Fix E1101:Instance of '**proxy**\ ' has no 'format' member' when using .format() on a ugettext\_lazy translation. Fixes `#80 `__ (canarduck) - `#99 `__: Add tests and transforms for DurationField, fixes `#95 `__ (James M. Allen) - `#92 `__: Add json field to WSGIRequest proxy (sjk4sc) - `#84 `__: Add support for django.contrib.postgres.fields and UUIDField (Villiers Strauss) - Stop testing with older Django versions. Currently testing with Django 1.11.x and 2.0 - Stop testing on Python 2, no functional changes in the source code though - Update tests and require latest version of pylint (>=1.8), fixes `#53 `__, `#97 `__ - `#81 `__ Fix 'duplicate-except' false negative for except blocks which catch the ``DoesNotExist`` exception. Version 0.7.4 ------------- - `#88 `__ Fixed builds with Django 1.10 (thanks to `federicobond `__) - `#91 `__ Fixed race condition when running with pylint parallel execution mode (thanks to `jeremycarroll `__) - `#64 `__ "Meta is old style class" now suppressed on BaseSerializer too (thanks to `unklphil `__) - `#70 `__ Updating to handle newer pylint/astroid versions (thanks to `iXce `__) Version 0.7.2 ------------- - `#76 `__ Better handling of mongoengine querysetmanager - `#73 `__ `#72 `__ Make package zip safe to help fix some path problems - `#68 `__ Suppressed invalid constant warning for "app\_name" in urls.py - `#67 `__ Fix view.args and view.kwargs - `#66 `__ accessing \_meta no longer causes a protected-access warning as this is a public API as of Django 1.8 - `#65 `__ Add support of mongoengine module. - `#59 `__ Silence old-style-class for widget Meta Version 0.7.1 ------------- - `#52 `__ - Fixed stupid mistake when using versioninfo Version 0.7 ----------- - `#51 `__ - Fixed compatibility with pylint 1.5 / astroid 1.4.1 Version 0.6.1 ------------- - `#43 `__ - Foreign key ID access (``somefk_id``) does not raise an 'attribute not found' warning - `#31 `__ - Support for custom model managers (thanks `smirolo `__) - `#48 `__ - Added support for django-restframework (thanks `mbertolacci `__) Version 0.6 ----------- - Pylint 1.4 dropped support for Python 2.6, therefore a constraint is added that pylint-django will only work with Python2.6 if pylint<=1.3 is installed - `#40 `__ - pylint 1.4 warned about View and Model classes not having enough public methods; this is suppressed - `#37 `__ - fixed an infinite loop when using astroid 1.3.3+ - `#36 `__ - no longer warning about lack of ``__unicode__`` method on abstract model classes - `PR #34 `__ - prevent warning about use of ``super()`` on ModelManager classes Version 0.5.5 ------------- - `PR #27 `__ - better ``ForeignKey`` transforms, which now work when of the form ``othermodule.ModelClass``. This also fixes a problem where an inferred type would be ``_Yes`` and pylint would fail - `PR #28 `__ - better knowledge of ``ManyToManyField`` classes Version 0.5.4 ------------- - Improved resiliance to inference failure when Django types cannot be inferred (which can happen if Django is not on the system path Version 0.5.3 ------------- - `Issue #25 `__ Fixing cases where a module defines ``get`` as a method Version 0.5.2 ------------- - Fixed a problem where type inference could get into an infinite loop Version 0.5.1 ------------- - Removed usage of a Django object, as importing it caused Django to try to configure itself and thus throw an ImproperlyConfigured exception. Version 0.5 ----------- - `Issue #7 `__ Improved handling of Django model fields - `Issue #10 `__ No warning about missing **unicode** if the Django python3/2 compatability tools are used - `Issue #11 `__ Improved handling of Django form fields - `Issue #12 `__ Improved handling of Django ImageField and FileField objects - `Issue #14 `__ Models which do not define **unicode** but whose parents do now have a new error (W5103) instead of incorrectly warning about no **unicode** being present. - `Issue #21 `__ ``ForeignKey`` and ``OneToOneField`` fields on models are replaced with instance of the type they refer to in the AST, which allows pylint to generate correct warnings about attributes they may or may not have. Version 0.3 ----------- - Python3 is now supported - ``__unicode__`` warning on models does not appear in Python3 Version 0.2 ----------- - Pylint now recognises ``BaseForm`` as an ancestor of ``Form`` and subclasses - Improved ``Form`` support - `Issue #2 `__ - a subclass of a ``Model`` or ``Form`` also has warnings about a ``Meta`` class suppressed. - `Issue #3 `__ - ``Form`` and ``ModelForm`` subclasses no longer warn about ``Meta`` classes. Keywords: pylint,django,plugin Platform: UNKNOWN Classifier: Environment :: Console Classifier: Intended Audience :: Developers Classifier: Operating System :: Unix Classifier: Topic :: Software Development :: Quality Assurance Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.5 Classifier: Programming Language :: Python :: 3.6 Classifier: Programming Language :: Python :: 3.7 Provides-Extra: with_django Provides-Extra: for_tests pylint-django-2.0.13/pylint_django.egg-info/dependency_links.txt0000644000175000017500000000000113566222372024327 0ustar josephjoseph pylint-django-2.0.13/pylint_django.egg-info/top_level.txt0000644000175000017500000000001613566222372023010 0ustar josephjosephpylint_django pylint-django-2.0.13/pylint_django.egg-info/SOURCES.txt0000644000175000017500000001077513566222372022157 0ustar josephjosephCHANGELOG.rst CONTRIBUTORS.md LICENSE MANIFEST.in README.rst SECURITY.md setup.py pylint_django/__init__.py pylint_django/__pkginfo__.py pylint_django/compat.py pylint_django/plugin.py pylint_django/utils.py pylint_django.egg-info/PKG-INFO pylint_django.egg-info/SOURCES.txt pylint_django.egg-info/dependency_links.txt pylint_django.egg-info/not-zip-safe pylint_django.egg-info/requires.txt pylint_django.egg-info/top_level.txt pylint_django/augmentations/__init__.py pylint_django/checkers/__init__.py pylint_django/checkers/db_performance.py pylint_django/checkers/django_installed.py pylint_django/checkers/forms.py pylint_django/checkers/json_response.py pylint_django/checkers/models.py pylint_django/tests/__init__.py pylint_django/tests/test_func.py pylint_django/tests/input/__init__.py pylint_django/tests/input/external_django_tables2_noerror_meta_class.py pylint_django/tests/input/external_drf_noerror_serializer.py pylint_django/tests/input/external_drf_noerror_serializer.rc pylint_django/tests/input/external_factory_boy_noerror.py pylint_django/tests/input/external_factory_boy_noerror.rc pylint_django/tests/input/external_model_utils_noerror_override_manager.py pylint_django/tests/input/external_model_utils_noerror_override_manager.rc pylint_django/tests/input/external_psycopg2_noerror_postgres_fields.py pylint_django/tests/input/external_psycopg2_noerror_postgres_fields.rc pylint_django/tests/input/func_json_response.py pylint_django/tests/input/func_json_response.txt pylint_django/tests/input/func_model_does_not_use_unicode_py33.py pylint_django/tests/input/func_model_does_not_use_unicode_py33.txt pylint_django/tests/input/func_model_no_explicit_unicode_str_compat.py pylint_django/tests/input/func_model_no_explicit_unicode_str_compat.txt pylint_django/tests/input/func_modelform_exclude.py pylint_django/tests/input/func_modelform_exclude.txt pylint_django/tests/input/func_noerror_classviews.py pylint_django/tests/input/func_noerror_duplicate_except_doesnotexist.py pylint_django/tests/input/func_noerror_factory_post_generation.py pylint_django/tests/input/func_noerror_foreign_key_attributes.py pylint_django/tests/input/func_noerror_foreign_key_ids.py pylint_django/tests/input/func_noerror_foreign_key_key_cls_unbound.py pylint_django/tests/input/func_noerror_foreign_key_package.py pylint_django/tests/input/func_noerror_foreign_key_sets.py pylint_django/tests/input/func_noerror_foreignkeys.py pylint_django/tests/input/func_noerror_form_fields.py pylint_django/tests/input/func_noerror_forms_py33.py pylint_django/tests/input/func_noerror_formview_ancestors.py pylint_django/tests/input/func_noerror_generic_foreign_key.py pylint_django/tests/input/func_noerror_ignore_meta_subclass.py pylint_django/tests/input/func_noerror_import_q.py pylint_django/tests/input/func_noerror_issue_46.py pylint_django/tests/input/func_noerror_managers_return_querysets.py pylint_django/tests/input/func_noerror_manytomanyfield.py pylint_django/tests/input/func_noerror_model_fields.py pylint_django/tests/input/func_noerror_model_methods.py pylint_django/tests/input/func_noerror_model_objects.py pylint_django/tests/input/func_noerror_model_unicode_callable.py pylint_django/tests/input/func_noerror_model_unicode_lambda.py pylint_django/tests/input/func_noerror_models_py33.py pylint_django/tests/input/func_noerror_protected_meta_access.py pylint_django/tests/input/func_noerror_style_members.py pylint_django/tests/input/func_noerror_test_wsgi_request.py pylint_django/tests/input/func_noerror_ugettext_lazy_format.py pylint_django/tests/input/func_noerror_unicode_py2_compatible.py pylint_django/tests/input/func_noerror_urls.py pylint_django/tests/input/func_noerror_uuid_field.py pylint_django/tests/input/func_noerror_views.py pylint_django/tests/input/func_noerror_wsgi.py pylint_django/tests/input/func_unused_arguments.py pylint_django/tests/input/func_unused_arguments.txt pylint_django/tests/input/migrations/0001_noerror_initial.py pylint_django/tests/input/migrations/0002_new_column.py pylint_django/tests/input/migrations/0002_new_column.txt pylint_django/tests/input/migrations/__init__.py pylint_django/tests/input/models/__init__.py pylint_django/tests/input/models/author.py pylint_django/tests/input/models/func_noerror_foreign_key_key_cls_unbound_in_same_package.py pylint_django/transforms/__init__.py pylint_django/transforms/fields.py pylint_django/transforms/foreignkey.py pylint_django/transforms/transforms/__init__.py pylint_django/transforms/transforms/django_db_models_fields_files.py pylint_django/transforms/transforms/django_utils_translation.pypylint-django-2.0.13/LICENSE0000644000175000017500000004317613230127102014725 0ustar josephjosephGNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Pylint plugin for improving code analysis for when using Django Copyright (C) 2013 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 2 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, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. {signature of Ty Coon}, 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. pylint-django-2.0.13/CHANGELOG.rst0000644000175000017500000004154013566222273015753 0ustar josephjosephChangelog ========= Version 2.0.13 (23 Nov 2019), HackBulgaria edition -------------------------------------------------- - Suppress ``too-many-ancestors`` for class-based generic views - Add ``handler400``, ``handler403``, ``handler404`` to good_names. Fix `#248 `_ Version 2.0.12 (04 Nov 2019) ---------------------------- - Fix too broad suppression of ``unused-argument`` warnings for functions and methods where the first argument is named ``request``. Now issues warnings for the rest of the arguments if they are unused. Fix `#249 `_ (Pascal Urban) - Pass arguments of ``scripts/test.sh`` to ``test_func/pytest`` to ease development (Pascal Urban) - Document behavior when ForeignKey fields are referenced as strings. Fix `#241 `_ Version 2.0.11 (10 July 2019) ----------------------------- - Use ``functools.wrap`` to preserve ``leave_module`` info (Mohit Solanki) Version 2.0.10 (07 July 2019), Novi Sad edition ----------------------------------------------- - Suppress ``no-member`` for ``ManyToManyField``. Fix `#192 `_ and `#237 `_ (Pierre Chiquet) - Fix ``UnboundLocalError`` with ``ForeignKey(to=)``. Fix `#232 `_ (Sardorbek Imomaliev) Version 2.0.9 (26 April 2019) ----------------------------- - Fix ``UnboundLocalError: local variable 'key_cls' referenced before assignment`` for cases when models is a python package, the ``to`` argument is a string that is used in this pattern ``app.Model`` and also there is some other ``bool`` const like ``null=True`` right after ``to``. (Sardorbek Imomaliev) - Don't crash if ForeignKey field doesn't have keyword arguments Fix `#230 `_ Version 2.0.8 (18 April 2019) ----------------------------- - Support recursive (self) ForeignKey relations. Fix `#208 `_ (Daniil Kharkov) Version 2.0.7 (16 April 2019) ----------------------------- - Fixed ``AstroidImportError`` for ``DecimalField``. Fix `#221 `_ (Daniil Kharkov) - Add ``load_configuration()`` in ``pylint_django/__init__.py``. Fix #222 `#222 `_ - Support ForeignKey relations with ``to`` keyword. Fix `#223 `_ (Daniil Kharkov) Version 2.0.6 (27 Feb 2019) --------------------------- - Updating dependency version of pylint-plugin-utils as pylint 2.3 release was not compatible `#220 `_ - Improvements to tox.ini: `#217 `_ and `#216 `_ (@aerostitch) - Add support for new load_configuration hook of pylint `#214 `_ (@matusvalo) - 'urlpatterns' no longer reported as an invalid constant name Version 2.0.5 (17 Dec 2018) --------------------------- Bumping the version number because there's been a mix-up between GitHub tags and the versions pushed to PyPI for 2.0.3 and 2.0.4. Please use 2.0.5 which includes the changes mentioned below! Version 2.0.4 (do not use) -------------------------- - Avoid traceback with concurrent execution. Fix `#197 `_ - Suppress ``no-member`` errors for ``LazyFunction`` in factories - Suppress ``no-member`` errors for ``RelatedManager`` fields - Clean up compatibility code: `PR #207 `_ Version 2.0.3 (do not use) -------------------------- - Fixing compatability between ranges of astroid (2.0.4 -> 2.1) and pylint (2.1.1 -> 2.2). `#201 `_ and `#202 `_ Version 2.0.2 (26 Aug 2018) --------------------------- - Suppress false-positive no-self-argument in factory.post_generation. Fix `#190 `_ (Federico Bond) Version 2.0.1 (20 Aug 2018) --------------------------- - Enable testing with Django 2.1 - Add test for Model.objects.get_or_create(). Close `#156 `__ - Add test for objects.exclude(). Close `#177 `__ - Fix Instance of 'Model' has no 'id' member (no-member), fix Class 'UserCreationForm' has no 'declared_fields' member. Close `#184 `__ - Fix for Instance of 'ManyToManyField' has no 'add' member. Close `#163 `__ - Add test & fix for unused arguments on class based views Version 2.0 (25 July 2018) -------------------------- - Requires pylint >= 2.0 which doesn't support Python 2 anymore! - Add modelform-uses-unicode check to flag dangerous use of the exclude attribute in ModelForm.Meta (Federico Bond). Version 0.11.1 (25 May 2018), the DjangoCon Heidelberg edition -------------------------------------------------------------- - Enable test case for ``urlpatterns`` variable which was previously disabled - Disable ``unused-argument`` message for the ``request`` argument passed to view functions. Fix `#155 `__ - Add transformations for ``model_utils`` managers instead of special-casing them. Fix `#160 `__ Version 0.11 (18 April 2018), the TestCon Moscow edition -------------------------------------------------------- - New ``JsonResponseChecker`` that looks for common anti-patterns with http responses returning JSON. This includes:: HttpResponse(json.dumps(data)) HttpResponse(data, content_type='application/json') JsonResponse(data, content_type=...) Version 0.10.0 (10 April 2018) ------------------------------ - Remove the compatibility layer for older astroid versions - Make flake8 happy. Fix `#102 `__ - Fix: compatibility with Python < 3.6 caused by ``ModuleNotFoundError`` not available on older versions of Python (Juan Rial) - Show README and CHANGELOG on PyPI. Fix `#122 `__ - Fix explicit unicode check with ``python_2_unicode_compatible`` base models (Federico Bond) - Suppress ``not-an-iterable`` message for 'objects'. Fix `#117 `__ - Teach pylint_django that ``objects.all()`` is subscriptable. Fix `#144 `__ - Suppress ``invalid-name`` for ``wsgi.application``. Fix `#77 `__ - Add test for ``WSGIRequest.context``. Closes `#78 `__ - Register transforms for ``FileField``. Fix `#60 `__ - New checker ``pylint_django.checkers.db_performance``. Enables checking of migrations and reports when there's an ``AddField`` operation with a default value which may slow down applying migrations on large tables. This may also lead to production tables being locked while migrations are being applied. Fix `#118 `__ - Suppress ``no-member`` for ``factory.SubFactory`` objects. Useful when model factories use ``factory.SubFactory()`` for foreign key relations. Version 0.9.4 (12 March 2018) ----------------------------- - Add an optional dependency on Django - Fix the ``DjangoInstalledChecker`` so it can actually warn when Django isn't available - Fix `#136 `__ by adding automated build and sanity test scripts Version 0.9.3 (removed from PyPI) --------------------------------- - Fix `#133 `__ and `#134 `__ by including package data when building wheel and tar.gz packages for PyPI (Joseph Herlant) Version 0.9.2 (broken) ---------------------- - Fix `#129 `__ - Move tests under ``site-packages/pylint_django`` (Mr. Senko) - Fix `#96 `__ - List Django as a dependency (Mr. Senko) Version 0.9.1 (26 Feb 2018) --------------------------- - Fix `#123 `__ - Update links after the move to PyCQA (Mr. Senko) - Add test for Meta class from django\_tables2 (Mr. Senko) - Fix flake8 complaints (Peter Bittner) - Add missing .txt and .rc test files to MANIFEST.in (Joseph Herlant) Version 0.9 (25 Jan 2018) ------------------------- - Fix `#120 `__ - TypeError: 'NamesConsumer' object does not support indexing (Simone Basso) - Fix `#110 `__ and `#35 `__ - resolve ForeignKey models specified as strings instead of class names (Mr. Senko) Version 0.8.0 (20 Jan 2018) --------------------------- - This is the last version to support Python 2. Issues a deprecation warning! - `#109 `__, adding 'urlpatterns', 'register', 'app\_name' to good names. Obsoletes `#111 `__, fixes `#108 `__ (Vinay Pai) - Add 'handler500' to good names (Mr. Senko) - `#103 `__: Support factory\_boy's DjangoModelFactory Meta class (Konstantinos Koukopoulos) - `#100 `__: Fix E1101:Instance of '**proxy**\ ' has no 'format' member' when using .format() on a ugettext\_lazy translation. Fixes `#80 `__ (canarduck) - `#99 `__: Add tests and transforms for DurationField, fixes `#95 `__ (James M. Allen) - `#92 `__: Add json field to WSGIRequest proxy (sjk4sc) - `#84 `__: Add support for django.contrib.postgres.fields and UUIDField (Villiers Strauss) - Stop testing with older Django versions. Currently testing with Django 1.11.x and 2.0 - Stop testing on Python 2, no functional changes in the source code though - Update tests and require latest version of pylint (>=1.8), fixes `#53 `__, `#97 `__ - `#81 `__ Fix 'duplicate-except' false negative for except blocks which catch the ``DoesNotExist`` exception. Version 0.7.4 ------------- - `#88 `__ Fixed builds with Django 1.10 (thanks to `federicobond `__) - `#91 `__ Fixed race condition when running with pylint parallel execution mode (thanks to `jeremycarroll `__) - `#64 `__ "Meta is old style class" now suppressed on BaseSerializer too (thanks to `unklphil `__) - `#70 `__ Updating to handle newer pylint/astroid versions (thanks to `iXce `__) Version 0.7.2 ------------- - `#76 `__ Better handling of mongoengine querysetmanager - `#73 `__ `#72 `__ Make package zip safe to help fix some path problems - `#68 `__ Suppressed invalid constant warning for "app\_name" in urls.py - `#67 `__ Fix view.args and view.kwargs - `#66 `__ accessing \_meta no longer causes a protected-access warning as this is a public API as of Django 1.8 - `#65 `__ Add support of mongoengine module. - `#59 `__ Silence old-style-class for widget Meta Version 0.7.1 ------------- - `#52 `__ - Fixed stupid mistake when using versioninfo Version 0.7 ----------- - `#51 `__ - Fixed compatibility with pylint 1.5 / astroid 1.4.1 Version 0.6.1 ------------- - `#43 `__ - Foreign key ID access (``somefk_id``) does not raise an 'attribute not found' warning - `#31 `__ - Support for custom model managers (thanks `smirolo `__) - `#48 `__ - Added support for django-restframework (thanks `mbertolacci `__) Version 0.6 ----------- - Pylint 1.4 dropped support for Python 2.6, therefore a constraint is added that pylint-django will only work with Python2.6 if pylint<=1.3 is installed - `#40 `__ - pylint 1.4 warned about View and Model classes not having enough public methods; this is suppressed - `#37 `__ - fixed an infinite loop when using astroid 1.3.3+ - `#36 `__ - no longer warning about lack of ``__unicode__`` method on abstract model classes - `PR #34 `__ - prevent warning about use of ``super()`` on ModelManager classes Version 0.5.5 ------------- - `PR #27 `__ - better ``ForeignKey`` transforms, which now work when of the form ``othermodule.ModelClass``. This also fixes a problem where an inferred type would be ``_Yes`` and pylint would fail - `PR #28 `__ - better knowledge of ``ManyToManyField`` classes Version 0.5.4 ------------- - Improved resiliance to inference failure when Django types cannot be inferred (which can happen if Django is not on the system path Version 0.5.3 ------------- - `Issue #25 `__ Fixing cases where a module defines ``get`` as a method Version 0.5.2 ------------- - Fixed a problem where type inference could get into an infinite loop Version 0.5.1 ------------- - Removed usage of a Django object, as importing it caused Django to try to configure itself and thus throw an ImproperlyConfigured exception. Version 0.5 ----------- - `Issue #7 `__ Improved handling of Django model fields - `Issue #10 `__ No warning about missing **unicode** if the Django python3/2 compatability tools are used - `Issue #11 `__ Improved handling of Django form fields - `Issue #12 `__ Improved handling of Django ImageField and FileField objects - `Issue #14 `__ Models which do not define **unicode** but whose parents do now have a new error (W5103) instead of incorrectly warning about no **unicode** being present. - `Issue #21 `__ ``ForeignKey`` and ``OneToOneField`` fields on models are replaced with instance of the type they refer to in the AST, which allows pylint to generate correct warnings about attributes they may or may not have. Version 0.3 ----------- - Python3 is now supported - ``__unicode__`` warning on models does not appear in Python3 Version 0.2 ----------- - Pylint now recognises ``BaseForm`` as an ancestor of ``Form`` and subclasses - Improved ``Form`` support - `Issue #2 `__ - a subclass of a ``Model`` or ``Form`` also has warnings about a ``Meta`` class suppressed. - `Issue #3 `__ - ``Form`` and ``ModelForm`` subclasses no longer warn about ``Meta`` classes. pylint-django-2.0.13/README.rst0000644000175000017500000001211313560025137015405 0ustar josephjosephpylint-django ============= .. image:: https://travis-ci.org/PyCQA/pylint-django.svg?branch=master :target: https://travis-ci.org/PyCQA/pylint-django .. image:: https://landscape.io/github/landscapeio/pylint-django/master/landscape.png :target: https://landscape.io/github/landscapeio/pylint-django .. image:: https://coveralls.io/repos/PyCQA/pylint-django/badge.svg :target: https://coveralls.io/r/PyCQA/pylint-django .. image:: https://img.shields.io/pypi/v/pylint-django.svg :target: https://pypi.python.org/pypi/pylint-django About ----- ``pylint-django`` is a `Pylint `__ plugin for improving code analysis when analysing code using Django. It is also used by the `Prospector `__ tool. Installation ------------ To install:: pip install pylint-django **WARNING:** ``pylint-django`` will not install ``Django`` by default because this causes more trouble than good, `see discussion `__. If you wish to automatically install the latest version of ``Django`` then:: pip install pylint-django[with_django] otherwise sort out your testing environment and please **DO NOT** report issues about missing Django! Usage ----- Ensure ``pylint-django`` is installed and on your path and then execute:: pylint --load-plugins pylint_django [..other options..] Prospector ---------- If you have ``prospector`` installed, then ``pylint-django`` will already be installed as a dependency, and will be activated automatically if Django is detected:: prospector [..other options..] Features -------- * Prevents warnings about Django-generated attributes such as ``Model.objects`` or ``Views.request``. * Prevents warnings when using ``ForeignKey`` attributes ("Instance of ForeignKey has no member"). * Fixes pylint's knowledge of the types of Model and Form field attributes * Validates ``Model.__unicode__`` methods. * ``Meta`` informational classes on forms and models do not generate errors. * Flags dangerous use of the exclude attribute in ModelForm.Meta. Additional plugins ------------------ ``pylint_django.checkers.db_performance`` looks for migrations which add new model fields and these fields have a default value. According to `Django docs `__ this may have performance penalties especially on large tables. The prefered way is to add a new DB column with ``null=True`` because it will be created instantly and then possibly populate the table with the desired default values. Only the last migration from a sub-directory will be examined! This plugin is disabled by default! To enable it:: pylint --load-plugins pylint_django --load-plugins pylint_django.checkers.db_performance Known issues ------------ If you reference foreign-key models by their name (as string) ``pylint-django`` may not be able to find the model and will report issues because it has no idea what the underlying type of this field is. Supported options are:: - ``self`` and ``Model`` - look for this class in the current module which is being examined - ``app.Model`` - try loading ``app.models`` into the AST parser and look for ``Model`` there If your ``models.py`` itself is not importing the foreign-key class there's probably some import problem (likely circular dependencies) preventing referencing the foreign-key class directly. In this case ``pylint-django`` can't do much about it. We always recommend referencing foreign-key models by their classes. Contributing ------------ Please feel free to add your name to the ``CONTRIBUTORS.rst`` file if you want to be credited when pull requests get merged. You can also add to the ``CHANGELOG.rst`` file if you wish, although we'll also do that when merging. Tests ----- The structure of the test package follows that from pylint itself. It is fairly simple: create a module starting with ``func_`` followed by a test name, and insert into it some code. The tests will run pylint against these modules. If the idea is that no messages now occur, then that is fine, just check to see if it works by running ``scripts/test.sh``. Any command line argument passed to ``scripts/test.sh`` will be passed to the internal invocation of ``pytest``. For example if you want to debug the tests you can execute ``scripts/test.sh --capture=no``. A specific test case can be run by filtering based on the file name of the test case ``./scripts/test.sh -k 'func_noerror_views'``. Ideally, add some pylint error suppression messages to the file to prevent spurious warnings, since these are all tiny little modules not designed to do anything so there's no need to be perfect. It is possible to make tests with expected error output, for example, if adding a new message or simply accepting that pylint is supposed to warn. A ``test_file_name.txt`` file contains a list of expected error messages in the format ``error-type:line number:class name or empty:1st line of detailed error text:confidence or empty``. License ------- ``pylint-django`` is available under the GPLv2 license.