[Python-modules-commits] [pylint-django] 01/06: Import pylint-django_0.7.1.orig.tar.xz
Daniel Stender
danstender-guest at moszumanska.debian.org
Sun Jan 24 12:52:47 UTC 2016
This is an automated email from the git hooks/post-receive script.
danstender-guest pushed a commit to branch master
in repository pylint-django.
commit 71a6acc8e41a8cb313121cfc79f7a0e88b083bf9
Author: Daniel Stender <debian at danielstender.com>
Date: Tue Jan 19 15:55:41 2016 +0100
Import pylint-django_0.7.1.orig.tar.xz
---
.landscape.yaml | 6 +-
.travis.yml | 8 +-
CHANGELOG.md | 11 +
CONTRIBUTORS.md | 2 +
README.md | 3 +-
pylint_django/augmentations/__init__.py | 227 +++++++++++++--------
pylint_django/checkers/__init__.py | 2 +-
pylint_django/checkers/models.py | 31 ++-
pylint_django/compat.py | 31 +++
pylint_django/transforms/__init__.py | 2 +-
pylint_django/transforms/fields.py | 37 +++-
pylint_django/transforms/foreignkey.py | 7 +-
.../transforms/transforms/django_db_models.py | 6 +-
pylint_django/utils.py | 19 +-
scripts/travis-build.sh | 2 +-
scripts/travis-install.sh | 10 +-
scripts/{travis-skip.py => travis_skip.py} | 3 +-
setup.py | 5 +-
test/external_drf/func_noerror_serializer.py | 11 +
test/input/func_noerror_foreign_key_ids.py | 17 ++
test/input/func_noerror_foreignkeys.py | 2 +-
test/input/func_noerror_forms_py33.py | 2 +-
test/input/func_noerror_forms_py_28.py | 1 -
test/input/func_noerror_issue_46.py | 11 +
test/input/func_noerror_model_fields.py | 3 +-
test/input/func_noerror_model_unicode_callable.py | 2 +-
test/input/func_noerror_model_unicode_lambda.py | 2 +-
test/test_func.py | 27 ++-
tox.ini | 2 +-
29 files changed, 335 insertions(+), 157 deletions(-)
diff --git a/.landscape.yaml b/.landscape.yaml
index f2b5591..4b8bab3 100644
--- a/.landscape.yaml
+++ b/.landscape.yaml
@@ -1,6 +1,8 @@
-uses: django
+uses:
+ - django
strictness: high
doc-warnings: no
max-line-length: 120
ignore-paths:
- - ^scripts/
+ - scripts/
+ - pylint_django/compat.py
diff --git a/.travis.yml b/.travis.yml
index 814080f..096ab17 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -5,11 +5,13 @@ python:
- "2.7"
- "3.3"
- "3.4"
+ - "3.5"
env:
- - DJANGO='Django>=1.4,<1.5' SKIP='3.3 3.4'
- - DJANGO='Django>=1.5,<1.6' SKIP='3.3 3.4'
- - DJANGO='Django>=1.6,<1.7' SKIP='3.4'
+ - DJANGO='Django>=1.4,<1.5' SKIP='3.3 3.4,3.5'
+ - DJANGO='Django>=1.5,<1.6' SKIP='3.3 3.4,3.5'
+ - DJANGO='Django>=1.6,<1.7' SKIP='3.4,3.5'
- DJANGO='Django>=1.7,<1.8' SKIP='2.6'
+ - DJANGO='Django>=1.8,<1.9' SKIP='2.6'
install:
scripts/travis-install.sh
script:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c4df9cb..2cfa0ad 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,16 @@
# Changelog
+## Version 0.7.1
+* [#52](https://github.com/landscapeio/pylint-django/issues/52) - Fixed stupid mistake when using versioninfo
+
+## Version 0.7
+* [#51](https://github.com/landscapeio/pylint-django/issues/51) - Fixed compatibility with pylint 1.5 / astroid 1.4.1
+
+## Version 0.6.1
+* [#43](https://github.com/landscapeio/pylint-django/issues/43) - Foreign key ID access (`somefk_id`) does not raise an 'attribute not found' warning
+* [#31](https://github.com/landscapeio/pylint-django/issues/31) - Support for custom model managers (thanks [smirolo](https://github.com/smirolo))
+* [#48](https://github.com/landscapeio/pylint-django/pull/48) - Added support for django-restframework (thanks [mbertolacci](https://github.com/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](https://github.com/landscapeio/pylint-django/issues/40) - pylint 1.4 warned about View and Model classes not having enough public methods; this is suppressed
diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md
index bf44b92..e3515a8 100644
--- a/CONTRIBUTORS.md
+++ b/CONTRIBUTORS.md
@@ -4,3 +4,5 @@
* [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)
\ No newline at end of file
diff --git a/README.md b/README.md
index 140550c..e1a5da6 100644
--- a/README.md
+++ b/README.md
@@ -4,8 +4,7 @@ pylint-django
[](https://travis-ci.org/landscapeio/pylint-django)
[](https://landscape.io/github/landscapeio/pylint-django)
[](https://coveralls.io/r/landscapeio/pylint-django)
-[](https://crate.io/packages/pylint-django)
-[](https://crate.io/packages/pylint-django)
+[](https://pypi.python.org/pypi/pylint-django)
# About
diff --git a/pylint_django/augmentations/__init__.py b/pylint_django/augmentations/__init__.py
index 1150bd6..61600f2 100644
--- a/pylint_django/augmentations/__init__.py
+++ b/pylint_django/augmentations/__init__.py
@@ -1,14 +1,17 @@
"""Augmentations."""
+# pylint: disable=invalid-name
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 astroid import InferenceError, Getattr
-from astroid.nodes import Class, From
+from astroid import InferenceError
+from pylint_django.compat import ClassDef, ImportFrom, Attribute
from astroid.scoped_nodes import Class as ScopedClass, Module
+from pylint.__pkginfo__ import numversion as PYLINT_VERSION
from pylint.checkers.typecheck import TypeChecker
from pylint_django.utils import node_is_subclass, PY3
+from pylint_django.compat import inferred
from pylint_plugin_utils import augment_visit, suppress_message
@@ -30,7 +33,7 @@ def ignore_import_warnings_for_related_fields(orig_method, self, node):
iterat = to_consume[0].items if PY3 else to_consume[0].iteritems
for name, stmts in iterat():
- if isinstance(stmts[0], From):
+ if isinstance(stmts[0], ImportFrom):
if any([n[0] in ('ForeignKey', 'OneToOneField') for n in stmts[0].names]):
continue
new_things[name] = stmts
@@ -63,55 +66,53 @@ def foreign_key_sets(chain, node):
warn.
"""
quack = False
-
- if node.attrname.endswith('_set'):
+ # 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',
+ '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',
+ )
+
+ 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, Getattr):
+ if isinstance(node.parent, Attribute):
func_name = getattr(node.parent, 'attrname', None)
-
- # 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',
- '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',
- )
-
if func_name in manager_attrs:
quack = True
@@ -119,12 +120,15 @@ def foreign_key_sets(chain, node):
children = list(node.get_children())
for child in children:
try:
- inferred = child.infered()
+ inferred_cls = inferred(child)()
except InferenceError:
pass
else:
- for cls in inferred:
- if node_is_subclass(cls, 'django.db.models.base.Model'):
+ for cls in inferred_cls:
+ if (node_is_subclass(cls,
+ 'django.db.models.manager.Manager',
+ 'django.db.models.base.Model',
+ '.Model')):
# This means that we are looking at a subclass of models.Model
# and something is trying to access a <something>_set attribute.
# Since this could exist, we will return so as not to raise an
@@ -133,9 +137,15 @@ def foreign_key_sets(chain, node):
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, Class):
+ if node.name[-5:] != 'Admin' or isinstance(node.parent, ClassDef):
return False
return node_is_subclass(node, 'django.contrib.admin.options.ModelAdmin')
@@ -143,42 +153,56 @@ def is_model_admin_subclass(node):
def is_model_media_subclass(node):
"""Checks that node is derivative of Media class."""
- if node.name != 'Media' or not isinstance(node.parent, 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',
- 'django.forms.models.ModelForm')
- return any([node_is_subclass(node.parent, parent) for parent in parents])
+ '.Form',
+ '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, Class):
+ if node.name != 'Meta' or not isinstance(node.parent, ClassDef):
return False
- parents = ('django.db.models.base.Model',
+ parents = ('.Model', # for the transformed version used here
+ 'django.db.models.base.Model',
+ '.Form',
'django.forms.forms.Form',
- 'django.forms.models.ModelForm')
- return any([node_is_subclass(node.parent, parent) for parent in parents])
+ '.ModelForm',
+ 'django.forms.models.ModelForm',
+ 'rest_framework.serializers.ModelSerializer',
+ 'rest_framework.generics.GenericAPIView',
+ 'rest_framework.viewsets.ReadOnlyModelViewSet',
+ 'rest_framework.viewsets.ModelViewSet',
+ 'django_filters.filterset.FilterSet',)
+ return node_is_subclass(node.parent, *parents)
def is_model_mpttmeta_subclass(node):
"""Checks that node is derivative of MPTTMeta class."""
- if node.name != 'MPTTMeta' or not isinstance(node.parent, 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',
- 'django.forms.models.ModelForm')
- return any([node_is_subclass(node.parent, parent) for parent in parents])
+ '.Form',
+ 'django.forms.models.ModelForm',
+ '.ModelForm')
+ return node_is_subclass(node.parent, *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, Class):
+ if not node.name.endswith('Test') and not isinstance(node.parent, ClassDef):
return False
return node_is_subclass(node, 'django.test.testcases.TestCase')
@@ -220,8 +244,8 @@ def is_model_field_display_method(node):
# TODO: could validate the names of the fields on the model rather than
# blindly accepting get_*_display
try:
- for cls in node.last_child().infered():
- if node_is_subclass(cls, 'django.db.models.base.Model'):
+ for cls in inferred(node.last_child())():
+ if node_is_subclass(cls, 'django.db.models.base.Model', '.Model'):
return True
except InferenceError:
return False
@@ -284,41 +308,66 @@ def wrap(orig_method, with_method):
return wrap_func
+# The names of some visit functions changed in this commit:
+# https://bitbucket.org/logilab/pylint/commits/c94ee95abaa5737f13b91626fe321150c0ddd140
+
+def _visit_class(checker):
+ return getattr(checker, 'visit_classdef' if PYLINT_VERSION >= (1, 5) else 'visit_class')
+
+
+def _visit_attribute(checker):
+ return getattr(checker, 'visit_attribute' if PYLINT_VERSION >= (1, 5) else 'visit_getattr')
+
+
+def _leave_class(checker):
+ return getattr(checker, 'leave_classdef' if PYLINT_VERSION >= (1, 5) else 'leave_class')
+
+
+def _leave_function(checker):
+ return getattr(checker, 'leave_functiondef' if PYLINT_VERSION >= (1, 5) else 'leave_function')
+
+
+def _visit_assignname(checker):
+ return getattr(checker, 'visit_assignname' if PYLINT_VERSION >= (1, 5) else 'visit_assname')
+
+
def apply_augmentations(linter):
"""Apply augmentation and suppression rules."""
- augment_visit(linter, TypeChecker.visit_getattr, foreign_key_sets)
- suppress_message(linter, TypeChecker.visit_getattr, 'E1101', is_model_field_display_method)
+ augment_visit(linter, _visit_attribute(TypeChecker), foreign_key_sets)
+ augment_visit(linter, _visit_attribute(TypeChecker), foreign_key_ids)
+ suppress_message(linter, _visit_attribute(TypeChecker), 'E1101', is_model_field_display_method)
# formviews have too many ancestors, there's nothing the user of the library can do about that
- suppress_message(linter, MisdesignChecker.visit_class, 'R0901', is_class('django.views.generic.edit.FormView'))
+ suppress_message(linter, _visit_class(MisdesignChecker), 'R0901', is_class('django.views.generic.edit.FormView'))
# model forms have no __init__ method anywhere in their bases
- suppress_message(linter, ClassChecker.visit_class, 'W0232', is_class('django.forms.models.ModelForm'))
+ suppress_message(linter, _visit_class(ClassChecker), 'W0232', is_class('django.forms.models.ModelForm'))
# forms implement __getitem__ but not __len__, thus raising a "Badly implemented container" warning which
# we will suppress.
- suppress_message(linter, MisdesignChecker.leave_class, 'R0924', is_class('django.forms.forms.Form'))
- suppress_message(linter, MisdesignChecker.leave_class, 'R0924', is_class('django.forms.models.ModelForm'))
+ suppress_message(linter, _leave_class(MisdesignChecker), 'R0924', is_class('django.forms.forms.Form'))
+ suppress_message(linter, _leave_class(MisdesignChecker), 'R0924', is_class('django.forms.models.ModelForm'))
# Meta
- suppress_message(linter, DocStringChecker.visit_class, 'C0111', is_model_meta_subclass)
- suppress_message(linter, NewStyleConflictChecker.visit_class, 'C1001', is_model_meta_subclass)
- suppress_message(linter, ClassChecker.visit_class, 'W0232', is_model_meta_subclass)
- suppress_message(linter, MisdesignChecker.leave_class, 'R0903', is_model_meta_subclass)
+ suppress_message(linter, _visit_class(DocStringChecker), 'missing-docstring', is_model_meta_subclass)
+ suppress_message(linter, _visit_class(NewStyleConflictChecker), 'old-style-class', is_model_meta_subclass)
+ suppress_message(linter, _visit_class(ClassChecker), 'no-init', is_model_meta_subclass)
+ suppress_message(linter, _leave_class(MisdesignChecker), 'too-few-public-methods', is_model_meta_subclass)
# Media
- suppress_message(linter, NameChecker.visit_assname, 'C0103', is_model_media_valid_attributes)
- suppress_message(linter, DocStringChecker.visit_class, 'C0111', is_model_media_subclass)
- suppress_message(linter, NewStyleConflictChecker.visit_class, 'C1001', is_model_media_subclass)
- suppress_message(linter, ClassChecker.visit_class, 'W0232', is_model_media_subclass)
- suppress_message(linter, MisdesignChecker.leave_class, 'R0903', is_model_media_subclass)
+ suppress_message(linter, _visit_assignname(NameChecker), 'C0103', is_model_media_valid_attributes)
+ suppress_message(linter, _visit_class(DocStringChecker), 'missing-docstring', is_model_media_subclass)
+ suppress_message(linter, _visit_class(NewStyleConflictChecker), 'old-style-class', is_model_media_subclass)
+ #suppress_message(linter, _visit_class(ClassChecker), 'W0232', is_model_media_subclass)
+ suppress_message(linter, _leave_class(MisdesignChecker), 'too-few-public-methods', is_model_media_subclass)
# Too few public methods started appearing for Views and Models as part of Pylint>=1.4 / astroid>=1.3.3
# Not sure why, suspect this is a failure to get the parent classes somewhere
# For now, just suppress it on models and views
- suppress_message(linter, MisdesignChecker.leave_class, 'R0903', is_class('django.db.models.base.Model'))
- # TODO: why does this not work with the fqn of 'View'? Must be something to do with the overriding and transforms
- suppress_message(linter, MisdesignChecker.leave_class, 'R0903', is_class('.View'))
+ suppress_message(linter, _leave_class(MisdesignChecker), 'too-few-public-methods',
+ is_class('.Model'))
+ suppress_message(linter, _leave_class(MisdesignChecker), 'too-few-public-methods',
+ is_class('.View'))
# Admin
# Too many public methods (40+/20)
@@ -328,22 +377,22 @@ def apply_augmentations(linter):
#for method in node.methods():
# if not method.name.startswith('_'):
# nb_public_methods += 1
- suppress_message(linter, MisdesignChecker.leave_class, 'R0904', is_model_admin_subclass)
+ suppress_message(linter, _leave_class(MisdesignChecker), 'R0904', is_model_admin_subclass)
# Tests
- suppress_message(linter, MisdesignChecker.leave_class, 'R0904', is_model_test_case_subclass)
+ suppress_message(linter, _leave_class(MisdesignChecker), 'R0904', is_model_test_case_subclass)
# View
# Method could be a function (get, post)
- suppress_message(linter, ClassChecker.leave_function, 'R0201', is_model_view_subclass_method_shouldnt_be_function)
+ suppress_message(linter, _leave_function(ClassChecker), 'R0201', is_model_view_subclass_method_shouldnt_be_function)
# Unused argument 'request' (get, post)
- suppress_message(linter, VariablesChecker.leave_function, 'W0613', is_model_view_subclass_unused_argument)
+ suppress_message(linter, _leave_function(VariablesChecker), 'W0613', is_model_view_subclass_unused_argument)
# django-mptt
- suppress_message(linter, DocStringChecker.visit_class, 'C0111', is_model_mpttmeta_subclass)
- suppress_message(linter, NewStyleConflictChecker.visit_class, 'C1001', is_model_mpttmeta_subclass)
- suppress_message(linter, ClassChecker.visit_class, 'W0232', is_model_mpttmeta_subclass)
- suppress_message(linter, MisdesignChecker.leave_class, 'R0903', is_model_mpttmeta_subclass)
+ suppress_message(linter, _visit_class(DocStringChecker), 'missing-docstring', is_model_mpttmeta_subclass)
+ suppress_message(linter, _visit_class(NewStyleConflictChecker), 'old-style-class', is_model_mpttmeta_subclass)
+ suppress_message(linter, _visit_class(ClassChecker), 'W0232', is_model_mpttmeta_subclass)
+ suppress_message(linter, _leave_class(MisdesignChecker), 'too-few-public-methods', is_model_mpttmeta_subclass)
# ForeignKey and OneToOneField
VariablesChecker.leave_module = wrap(VariablesChecker.leave_module, ignore_import_warnings_for_related_fields)
diff --git a/pylint_django/checkers/__init__.py b/pylint_django/checkers/__init__.py
index 3a81763..57698ce 100644
--- a/pylint_django/checkers/__init__.py
+++ b/pylint_django/checkers/__init__.py
@@ -6,4 +6,4 @@ from pylint_django.checkers.models import ModelChecker
def register_checkers(linter):
"""Register checkers."""
linter.register_checker(ModelChecker(linter))
- linter.register_checker(DjangoInstalledChecker(linter))
+ linter.register_checker(DjangoInstalledChecker(linter))
\ No newline at end of file
diff --git a/pylint_django/checkers/models.py b/pylint_django/checkers/models.py
index b3100a2..ffb8350 100644
--- a/pylint_django/checkers/models.py
+++ b/pylint_django/checkers/models.py
@@ -1,9 +1,11 @@
"""Models."""
from astroid import Const
-from astroid.nodes import Assign, Function, AssName, Class
+from pylint_django.compat import ClassDef, FunctionDef, inferred, AssignName
+from astroid.nodes import Assign
from pylint.interfaces import IAstroidChecker
from pylint.checkers.utils import check_messages
from pylint.checkers import BaseChecker
+from pylint.__pkginfo__ import numversion as PYLINT_VERSION
from pylint_django.__pkginfo__ import BASE_ID
from pylint_django.utils import node_is_subclass, PY3
@@ -27,7 +29,7 @@ MESSAGES = {
def _is_meta_with_abstract(node):
- if isinstance(node, Class) and node.name == 'Meta':
+ if isinstance(node, ClassDef) and node.name == 'Meta':
for meta_child in node.get_children():
if not isinstance(meta_child, Assign):
continue
@@ -51,10 +53,21 @@ class ModelChecker(BaseChecker):
name = 'django-model-checker'
msgs = MESSAGES
- @check_messages('model-missing-unicode')
- def visit_class(self, node):
+ # XXX: there's a bug in pylint's backwards compatability logic after changing
+ # visit method names from visit_class to visit_classdef, see
+ # https://bitbucket.org/logilab/pylint/issues/711/new-node-visit-methods-not-backwards
+ if PYLINT_VERSION < (1, 5):
+ @check_messages('model-missing-unicode')
+ def visit_class(self, node):
+ return self._visit_classdef(node)
+ else:
+ @check_messages('model-missing-unicode')
+ def visit_classdef(self, node):
+ return self._visit_classdef(node)
+
+ def _visit_classdef(self, node):
"""Class visitor."""
- if not node_is_subclass(node, 'django.db.models.base.Model'):
+ if not node_is_subclass(node, 'django.db.models.base.Model', '.Model'):
# we only care about models
return
@@ -65,21 +78,23 @@ class ModelChecker(BaseChecker):
if isinstance(child, Assign):
grandchildren = list(child.get_children())
- if not isinstance(grandchildren[0], AssName):
+ if not isinstance(grandchildren[0], AssignName):
continue
name = grandchildren[0].name
if name != '__unicode__':
continue
- assigned = grandchildren[1].infered()[0]
+ grandchild = grandchildren[1]
+ assigned = inferred(grandchild)()[0]
+
if assigned.callable():
return
self.add_message('E%s01' % BASE_ID, args=node.name, node=node)
return
- if isinstance(child, Function) and child.name == '__unicode__':
+ if isinstance(child, FunctionDef) and child.name == '__unicode__':
if PY3:
self.add_message('W%s02' % BASE_ID, args=node.name, node=node)
return
diff --git a/pylint_django/compat.py b/pylint_django/compat.py
new file mode 100644
index 0000000..bb4f365
--- /dev/null
+++ b/pylint_django/compat.py
@@ -0,0 +1,31 @@
+
+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
+
+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
+
+
+def inferred(node):
+ if hasattr(node, 'inferred'):
+ return node.inferred
+ else:
+ return node.infered
+
+
+def instantiate_class(node):
+ if hasattr(node, 'instantiate_class'):
+ return node.instantiate_class
+ else:
+ return node.instanciate_class
diff --git a/pylint_django/transforms/__init__.py b/pylint_django/transforms/__init__.py
index fad380b..25cae97 100644
--- a/pylint_django/transforms/__init__.py
+++ b/pylint_django/transforms/__init__.py
@@ -26,7 +26,7 @@ def _add_transform(package_name, *class_names):
if module.name != package_name:
return
for class_name in class_names:
- module.locals[class_name] = fake.locals[class_name]
+ module._locals[class_name] = fake._locals[class_name] # pylint: disable=protected-access
MANAGER.register_transform(nodes.Module, set_fake_locals)
diff --git a/pylint_django/transforms/fields.py b/pylint_django/transforms/fields.py
index ba1b1e8..568a767 100644
--- a/pylint_django/transforms/fields.py
+++ b/pylint_django/transforms/fields.py
@@ -1,4 +1,6 @@
from astroid import MANAGER, scoped_nodes, nodes, inference_tip
+import sys
+from pylint_django import utils
_STR_FIELDS = ('CharField', 'SlugField', 'URLField', 'TextField', 'EmailField',
@@ -24,29 +26,42 @@ def is_model_or_form_field(cls):
def apply_type_shim(cls, context=None):
if cls.name in _STR_FIELDS:
- base_node = scoped_nodes.builtin_lookup('str')
+ base_nodes = scoped_nodes.builtin_lookup('str')
elif cls.name in _INT_FIELDS:
- base_node = scoped_nodes.builtin_lookup('int')
+ base_nodes = scoped_nodes.builtin_lookup('int')
elif cls.name in _BOOL_FIELDS:
- base_node = scoped_nodes.builtin_lookup('bool')
+ base_nodes = scoped_nodes.builtin_lookup('bool')
elif cls.name == 'FloatField':
- base_node = scoped_nodes.builtin_lookup('float')
+ base_nodes = scoped_nodes.builtin_lookup('float')
elif cls.name == 'DecimalField':
- base_node = MANAGER.ast_from_module_name('decimal').lookup('Decimal')
+ if sys.version_info >= (3, 5):
+ # I dunno, I'm tired and this works :(
+ base_nodes = MANAGER.ast_from_module_name('_decimal').lookup('Decimal')
+ else:
+ base_nodes = MANAGER.ast_from_module_name('decimal').lookup('Decimal')
elif cls.name in ('SplitDateTimeField', 'DateTimeField'):
- base_node = MANAGER.ast_from_module_name('datetime').lookup('datetime')
+ base_nodes = MANAGER.ast_from_module_name('datetime').lookup('datetime')
elif cls.name == 'TimeField':
- base_node = MANAGER.ast_from_module_name('datetime').lookup('time')
+ base_nodes = MANAGER.ast_from_module_name('datetime').lookup('time')
elif cls.name == 'DateField':
- base_node = MANAGER.ast_from_module_name('datetime').lookup('date')
+ base_nodes = MANAGER.ast_from_module_name('datetime').lookup('date')
elif cls.name == 'ManyToManyField':
- base_node = MANAGER.ast_from_module_name('django.db.models.query').lookup('QuerySet')
+ base_nodes = MANAGER.ast_from_module_name('django.db.models.query').lookup('QuerySet')
elif cls.name in ('ImageField', 'FileField'):
- base_node = MANAGER.ast_from_module_name('django.core.files.base').lookup('File')
+ base_nodes = MANAGER.ast_from_module_name('django.core.files.base').lookup('File')
else:
return iter([cls])
- return iter([cls] + base_node[1])
+ # 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):
diff --git a/pylint_django/transforms/foreignkey.py b/pylint_django/transforms/foreignkey.py
index 206783f..cd5ab31 100644
--- a/pylint_django/transforms/foreignkey.py
+++ b/pylint_django/transforms/foreignkey.py
@@ -1,14 +1,15 @@
from astroid import nodes, InferenceError, inference_tip, UseInferenceDefault
+from pylint_django.compat import ClassDef, instantiate_class, Attribute
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, nodes.Class):
+ if not isinstance(node.parent.parent, ClassDef):
return False
- if isinstance(node.func, nodes.Getattr):
+ if isinstance(node.func, Attribute):
attr = node.func.attrname
elif isinstance(node.func, nodes.Name):
attr = node.func.name
@@ -34,7 +35,7 @@ def infer_key_classes(node, context=None):
break
else:
raise UseInferenceDefault
- return iter([key_cls.instanciate_class()])
+ return iter([instantiate_class(key_cls)()])
def add_transform(manager):
diff --git a/pylint_django/transforms/transforms/django_db_models.py b/pylint_django/transforms/transforms/django_db_models.py
index ec2f183..005a741 100644
--- a/pylint_django/transforms/transforms/django_db_models.py
+++ b/pylint_django/transforms/transforms/django_db_models.py
@@ -1,3 +1,5 @@
+from django.core.exceptions import MultipleObjectsReturned, ObjectDoesNotExist
+
class Model(object):
_meta = None
objects = None
@@ -5,8 +7,8 @@ class Model(object):
id = None
pk = None
- MultipleObjectsReturned = None
- DoesNotExist = None
+ MultipleObjectsReturned = MultipleObjectsReturned
+ DoesNotExist = ObjectDoesNotExist
# eliminate E1002 for Manager object
diff --git a/pylint_django/utils.py b/pylint_django/utils.py
index e977a24..70dcaf5 100644
--- a/pylint_django/utils.py
+++ b/pylint_django/utils.py
@@ -1,28 +1,27 @@
"""Utils."""
from astroid.exceptions import InferenceError
-from astroid.bases import YES, Instance
-from astroid.nodes import Class
+from astroid.bases import Instance
+from pylint_django.compat import Uninferable, inferred, ClassDef
import sys
PY3 = sys.version_info >= (3, 0)
-def node_is_subclass(cls, subclass_name):
+def node_is_subclass(cls, *subclass_names):
"""Checks if cls node has parent with subclass_name."""
- if not isinstance(cls, (Class, Instance)):
+ if not isinstance(cls, (ClassDef, Instance)):
return False
- if cls.bases == YES:
- # ???
+ if cls.bases == Uninferable:
return False
for base_cls in cls.bases:
try:
- for inf in base_cls.infered():
- if inf.qname() == subclass_name:
+ for inf in inferred(base_cls)():
+ if inf.qname() in subclass_names:
return True
- if inf != cls and node_is_subclass(inf, subclass_name):
- # check up the hierachy in case we are a subclass of
+ 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:
diff --git a/scripts/travis-build.sh b/scripts/travis-build.sh
index 7747d7e..02251ca 100755
--- a/scripts/travis-build.sh
+++ b/scripts/travis-build.sh
@@ -1,5 +1,5 @@
#!/bin/bash
-python scripts/travis-skip.py
+python scripts/travis_skip.py
if [ "$?" -eq "0" ]
then
diff --git a/scripts/travis-install.sh b/scripts/travis-install.sh
index 9a7d029..a977c10 100755
--- a/scripts/travis-install.sh
+++ b/scripts/travis-install.sh
@@ -1,12 +1,12 @@
#!/bin/bash
-python scripts/travis-skip.py
+python scripts/travis_skip.py
if [ "$?" -eq "0" ]
then
- pip install --use-mirrors coverage coveralls
- pip install --use-mirrors $DJANGO
- pip install --use-mirrors git+https://github.com/landscapeio/pylint-plugin-utils.git@develop
- pip install --use-mirrors --editable .
+ pip install coverage coveralls
+ pip install $DJANGO
+ pip install git+https://github.com/landscapeio/pylint-plugin-utils.git@develop
+ pip install --editable .
else
echo "Skipping"
fi
diff --git a/scripts/travis-skip.py b/scripts/travis_skip.py
similarity index 90%
rename from scripts/travis-skip.py
rename to scripts/travis_skip.py
index f4675a3..8b0932b 100755
--- a/scripts/travis-skip.py
+++ b/scripts/travis_skip.py
@@ -1,5 +1,6 @@
#!/usr/bin/env python
-import os, sys
+import os
+import sys
for skip_ver in os.environ.get('SKIP', '').split():
skip_ver = tuple(map(int, skip_ver.split('.')))
if skip_ver == sys.version_info[:len(skip_ver)]:
diff --git a/setup.py b/setup.py
index 1eb982e..cdf4d35 100644
--- a/setup.py
+++ b/setup.py
@@ -5,7 +5,7 @@ import os
import sys
-_version = '0.6'
+_version = '0.7.1'
_packages = find_packages(exclude=["*.tests", "*.tests.*", "tests.*", "tests"])
_short_description = "pylint-django is a Pylint plugin to aid Pylint in recognising and understanding" \
@@ -29,6 +29,7 @@ _classifiers = (
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3.3',
'Programming Language :: Python :: 3.4',
+ 'Programming Language :: Python :: 3.5',
)
@@ -47,8 +48,6 @@ if sys.version_info < (2, 7):
else:
_install_requires += [
'pylint>=1.0',
- 'astroid>=1.0',
- 'logilab-common>=0.60.0',
]
setup(
diff --git a/test/external_drf/func_noerror_serializer.py b/test/external_drf/func_noerror_serializer.py
new file mode 100644
index 0000000..5b045a3
--- /dev/null
+++ b/test/external_drf/func_noerror_serializer.py
@@ -0,0 +1,11 @@
+"""
+Checks that Pylint does not complain about DRF serializers
+"""
+# pylint: disable=C0111,W5101,R0903
+
+from rest_framework import serializers
+
+class TestSerializerSubclass(serializers.ModelSerializer):
+ class Meta:
+ pass
+
diff --git a/test/input/func_noerror_foreign_key_ids.py b/test/input/func_noerror_foreign_key_ids.py
new file mode 100644
index 0000000..201403b
--- /dev/null
+++ b/test/input/func_noerror_foreign_key_ids.py
@@ -0,0 +1,17 @@
+"""
+Checks that Pylint does not complain about foreign key id access
+"""
+# pylint: disable=C0111,W5101,wrong-import-position
+from django.db import models
+
+
+class SomeModel(models.Model):
+ count = models.IntegerField()
+
+
+class SomeOtherModel(models.Model):
+ some_model = models.ForeignKey(SomeModel)
+ number = models.IntegerField()
+
+ def do_something(self):
+ self.number = self.some_model_id
diff --git a/test/input/func_noerror_foreignkeys.py b/test/input/func_noerror_foreignkeys.py
index 1ac4261..fa82df5 100644
--- a/test/input/func_noerror_foreignkeys.py
+++ b/test/input/func_noerror_foreignkeys.py
@@ -2,7 +2,7 @@
Checks that Pylint does not complain about various
methods on Django model fields.
"""
-# pylint: disable=C0111,W5101
+# pylint: disable=C0111,W5101,wrong-import-position
from django.db import models
from django.db.models import ForeignKey, OneToOneField
diff --git a/test/input/func_noerror_forms_py33.py b/test/input/func_noerror_forms_py33.py
index 3cd82c7..0520668 100644
--- a/test/input/func_noerror_forms_py33.py
+++ b/test/input/func_noerror_forms_py33.py
@@ -1,7 +1,7 @@
"""
Checks that Pylint does not complain about django Forms
"""
-# pylint: disable=C0111,W5101,R0903
+# pylint: disable=C0111,W5101,R0903,wrong-import-position
from django import forms
diff --git a/test/input/func_noerror_forms_py_28.py b/test/input/func_noerror_forms_py_28.py
index a506c73..b972f52 100644
--- a/test/input/func_noerror_forms_py_28.py
+++ b/test/input/func_noerror_forms_py_28.py
@@ -31,4 +31,3 @@ class TestFormSubclass(forms.Form):
class TestModelFormSubclass(forms.ModelForm):
class Meta:
pass
-
diff --git a/test/input/func_noerror_issue_46.py b/test/input/func_noerror_issue_46.py
new file mode 100644
index 0000000..1adb597
--- /dev/null
+++ b/test/input/func_noerror_issue_46.py
@@ -0,0 +1,11 @@
+"""
+Checks that Pylint does not complain about raising DoesNotExist
+"""
+# pylint: disable=C0111,W5101,W5103
+from django.db import models
+
+
+class SomeModel(models.Model):
+ pass
+
+raise SomeModel.DoesNotExist
diff --git a/test/input/func_noerror_model_fields.py b/test/input/func_noerror_model_fields.py
index 1390748..7009814 100644
--- a/test/input/func_noerror_model_fields.py
+++ b/test/input/func_noerror_model_fields.py
@@ -5,6 +5,7 @@ methods on Django model fields.
# pylint: disable=C0111,W5101
from __future__ import print_function
from datetime import datetime, date
+from decimal import Decimal
from django.db import models
@@ -66,7 +67,7 @@ class LotsOfFieldsModel(models.Model):
print(self.datefield.isoformat())
def decimalfield_tests(self):
- print(self.decimalfield.adjusted())
+ print(self.decimalfield.compare(Decimal('1.4')))
def filefield_tests(self):
print(self.filefield.file)
diff --git a/test/input/func_noerror_model_unicode_callable.py b/test/input/func_noerror_model_unicode_callable.py
index 94449dd..0ef1406 100644
--- a/test/input/func_noerror_model_unicode_callable.py
+++ b/test/input/func_noerror_model_unicode_callable.py
@@ -1,7 +1,7 @@
"""
Ensures that django models without a __unicode__ method are flagged
"""
-# pylint: disable=C0111
+# pylint: disable=C0111,wrong-import-position
from django.db import models
diff --git a/test/input/func_noerror_model_unicode_lambda.py b/test/input/func_noerror_model_unicode_lambda.py
index 51ef89c..22ad0e7 100644
--- a/test/input/func_noerror_model_unicode_lambda.py
+++ b/test/input/func_noerror_model_unicode_lambda.py
@@ -1,7 +1,7 @@
"""
Ensures that django models without a __unicode__ method are flagged
"""
-# pylint: disable=C0111
+# pylint: disable=C0111,wrong-import-position
from django.db import models
diff --git a/test/test_func.py b/test/test_func.py
index 9c4694f..9d628c0 100644
--- a/test/test_func.py
+++ b/test/test_func.py
@@ -2,7 +2,6 @@
... 60 lines suppressed ...
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/pylint-django.git
More information about the Python-modules-commits
mailing list