151

I would very much like to integrate pylint into the build process for my python projects, but I have run into one show-stopper: One of the error types that I find extremely useful--:E1101: *%s %r has no %r member*--constantly reports errors when using common django fields, for example:

E1101:125:get_user_tags: Class 'Tag' has no 'objects' member

which is caused by this code:

def get_user_tags(username):
   """
   Gets all the tags that username has used.

   Returns a query set.
   """
   return Tag.objects.filter(  ## This line triggers the error.
       tagownership__users__username__exact=username).distinct()

# Here is the Tag class, models.Model is provided by Django:
class Tag(models.Model):
   """
   Model for user-defined strings that help categorize Events on
   on a per-user basis.
   """
   name = models.CharField(max_length=500, null=False, unique=True)

   def __unicode__(self):
       return self.name

How can I tune Pylint to properly take fields such as objects into account? (I've also looked into the Django source, and I have been unable to find the implementation of objects, so I suspect it is not "just" a class field. On the other hand, I'm fairly new to python, so I may very well have overlooked something.)

Edit: The only way I've found to tell pylint to not warn about these warnings is by blocking all errors of the type (E1101) which is not an acceptable solution, since that is (in my opinion) an extremely useful error. If there is another way, without augmenting the pylint source, please point me to specifics :)

See here for a summary of the problems I've had with pychecker and pyflakes -- they've proven to be far to unstable for general use. (In pychecker's case, the crashes originated in the pychecker code -- not source it was loading/invoking.)

rcreswick
  • 16,483
  • 15
  • 59
  • 70

13 Answers13

171

Do not disable or weaken Pylint functionality by adding ignores or generated-members.
Use an actively developed Pylint plugin that understands Django.
This Pylint plugin for Django works quite well:

pip install pylint-django

and when running pylint add the following flag to the command:

--load-plugins pylint_django

Detailed blog post here.

Tal Weiss
  • 8,889
  • 8
  • 54
  • 62
  • 4
    The link to the blog post is dead (so soon). Here are some archived links from the [Internet Archive](https://web.archive.org/web/20141008054046/http://blog.landscape.io/using-pylint-on-django-projects-with-pylint-django.html) and from [archive.is](http://archive.is/Lb9f0) – Christian Long Sep 23 '15 at 16:06
  • 3
    To make it work with Sublime Text's SublimeLinter plugin, I had to add `--load-plugins=pylint_django` to linters/pylint/args setting. Note the '=' sign, it didn't work without it. – Dennis Golomazov Nov 19 '15 at 13:32
  • it does not work. I get this error: E: 8, 0: No name 'models' in module 'django.db' (no-name-in-module) – max Dec 07 '15 at 17:02
  • @max What's your full command line? Versions of Django and pylint? Full output of the pylint run? – Tal Weiss Dec 08 '15 at 18:11
  • django 1.8 pylint==1.4.3 pylint-django==0.7.1 I dont think it's appropriate to put the stacktrace here... – max Dec 08 '15 at 22:48
  • Using django 1.9, pylint 1.5.2, and pylint-django 0.7.1, pylint_django plugin did not show `models.Manager.get` as a valid method. – kzh Jan 08 '16 at 15:49
  • Can you make an example how I would use it on a Django project? pylint --load-plugins pylint_django (how do I address my Django projekt here?) – caliph Mar 16 '16 at 13:41
  • 11
    You can also add this in your pylintrc: ```[MASTER] load-plugins=pylint_django``` – azmeuk Jun 14 '16 at 15:13
  • 3
    In vs code it dose not work for me until I Put in the following in the user settings: `{"python.linting.pylintArgs": [ "--load-plugins=pylint_django" ],}` [tieuminh2510's answer](https://stackoverflow.com/a/47343542/5697765) – ali-myousefi Jul 14 '19 at 06:16
  • @azmeuk Thank you! I could not figure out the section header! Why is it MASTER? Where is this documented? How would I find out next time what the .pylintrc format and sections should look like? – cammil Dec 03 '20 at 12:07
  • Honestly, I cannot remember where I found this :( – azmeuk Dec 03 '20 at 13:56
64

I use the following: pylint --generated-members=objects

Shai
  • 111,146
  • 38
  • 238
  • 371
  • 1
    [man pylint(1)](http://manpages.ubuntu.com/manpages/precise/en/man1/pylint.1.html) under TYPECHECK `--generated-members=` List of members which are set dynamically and missed by pylint inference system, and so shouldn't trigger E0201 _and E1101_ when accessed. [current: REQUEST,acl_users,aq_parent] – Mark Mikofski May 02 '12 at 06:14
  • I add this in PyDev in eclipse under [preferences in the PyDev/PyLint section](http://pydev.org/manual_adv_pylint.html). – Mark Mikofski May 02 '12 at 06:21
  • 3
    Using generated-members just hides these errors from you, there still can be errors when trying to access objects field on the wrong object. Use pylint-django plugin instead. – Vajk Hermecz Feb 12 '15 at 13:16
  • 6
    This is the wrong way to fix Pylint - by disabling some of its functionality. All you need to do is install a Pylint plugin that **understands** Django. See http://stackoverflow.com/a/31000713/78234 – Tal Weiss Jun 23 '15 at 10:50
38

If you use Visual Studio Code do this:

pip install pylint-django

And add to VSC config:

"python.linting.pylintArgs": [
    "--load-plugins=pylint_django"
],
Thiago Falcao
  • 4,463
  • 39
  • 34
31

My ~/.pylintrc contains

[TYPECHECK]
generated-members=REQUEST,acl_users,aq_parent,objects,_meta,id

the last two are specifically for Django.

Note that there is a bug in PyLint 0.21.1 which needs patching to make this work.

Edit: After messing around with this a little more, I decided to hack PyLint just a tiny bit to allow me to expand the above into:

[TYPECHECK]
generated-members=REQUEST,acl_users,aq_parent,objects,_meta,id,[a-zA-Z]+_set

I simply added:

    import re
    for pattern in self.config.generated_members:
        if re.match(pattern, node.attrname):
            return

after the fix mentioned in the bug report (i.e., at line 129).

Happy days!

simon
  • 15,344
  • 5
  • 45
  • 67
  • You should submit your patch to pylint back to the maintainers. – slacy Jun 17 '11 at 18:51
  • actually they've included this patch in 0.24, but they've started using the `shlex` package, and broken something else now. I had to add `gen.wordchars += "[]-+"` at line 135 to get it to work... – simon Oct 01 '11 at 21:01
  • 4
    Using generated-members just hides these errors from you, there still can be errors when trying to access 'objects' field on the wrong object. Use pylint-django plugin instead. – Vajk Hermecz Feb 12 '15 at 13:17
  • 4
    This is the wrong way to fix Pylint - by disabling some of its functionality. All you need to do is install a Pylint plugin that **understands** Django. See http://stackoverflow.com/a/31000713/78234 – Tal Weiss Jun 23 '15 at 10:50
  • 3
    @TalWeiss -- in fairness, this answer is three years older than `pylint-django`, so the downvote is a bit harsh... – simon Jun 24 '15 at 20:08
19

django-lint is a nice tool which wraps pylint with django specific settings : http://chris-lamb.co.uk/projects/django-lint/

github project: https://github.com/lamby/django-lint

gurney alex
  • 13,247
  • 4
  • 43
  • 57
16

Because of how pylint works (it examines the source itself, without letting Python actually execute it) it's very hard for pylint to figure out how metaclasses and complex baseclasses actually affect a class and its instances. The 'pychecker' tool is a bit better in this regard, because it does actually let Python execute the code; it imports the modules and examines the resulting objects. However, that approach has other problems, because it does actually let Python execute the code :-)

You could extend pylint to teach it about the magic Django uses, or to make it understand metaclasses or complex baseclasses better, or to just ignore such cases after detecting one or more features it doesn't quite understand. I don't think it would be particularly easy. You can also just tell pylint to not warn about these things, through special comments in the source, command-line options or a .pylintrc file.

Thomas Wouters
  • 130,178
  • 23
  • 148
  • 122
  • 3
    It is not easy to teach Pylint about Django, but it has been done: All you need to do is install a Pylint plugin that **understands** Django. See http://stackoverflow.com/a/31000713/78234 – Tal Weiss Jun 23 '15 at 11:18
  • Well I installed it but it still compains about thins like QuerySet has no remove... – Eino Mäkitalo Jun 18 '18 at 14:26
7

I resigned from using pylint/pychecker in favor of using pyflakes with Django code - it just tries to import module and reports any problem it finds, like unused imports or uninitialized local names.

zgoda
  • 12,775
  • 4
  • 37
  • 46
7

This is not a solution, but you can add objects = models.Manager() to your Django models without changing any behavior.

I myself only use pyflakes, primarily due to some dumb defaults in pylint and laziness on my part (not wanting to look up how to change the defaults).

AdamKG
  • 13,678
  • 3
  • 38
  • 46
  • Ah... thanks for the tip. I may try just adding that to Model.models in the local copy of the django source, and see if that does it. – rcreswick Sep 23 '08 at 17:19
  • I think this a great solution because it doesn't compromise on warnings. – Tom Leys Mar 22 '09 at 00:20
  • 1
    This is a *bad* solution. Repeating yourself and replacing something that it is feasible will change later (thus introducing a QA problem), just to fix an incomplete QA tool? – Chris Morgan Jun 11 '12 at 13:20
  • 2
    I wouldn't call this a bad solution: explicit is better than implicit. Perhaps `objects` shouldn't be magically added anyway. – Will Hardy Apr 30 '13 at 13:18
  • 1
    I think that this is the wrong way to fix Pylint - by patching Django in a sense. All you need to do is install a Pylint plugin that **understands** Django. See http://stackoverflow.com/a/31000713/78234 – Tal Weiss Jun 23 '15 at 11:20
5

Try running pylint with

pylint --ignored-classes=Tags

If that works, add all the other Django classes - possibly using a script, in say, python :P

The documentation for --ignore-classes is:

--ignored-classes=<members names>
List of classes names for which member attributes should not be checked (useful for classes with attributes dynamicaly set). [current: %default]

I should add this is not a particular elegant solution in my view, but it should work.

freespace
  • 16,529
  • 4
  • 36
  • 58
  • It only works if I never make any errors in those classes ;). I want to avoid ignoring code if at all possible -- I think it is a very bad idea to have different parts of the codebase analyzed an different degrees of scrutiny. I will forget which is which, and make false assumptions when debugging – rcreswick Sep 22 '08 at 16:55
  • 1
    This is the wrong way to fix Pylint - by disabling some of its functionality. All you need to do is install a Pylint plugin that **understands** Django. See http://stackoverflow.com/a/31000713/78234 – Tal Weiss Jun 23 '15 at 11:22
4

For neovim & vim8 use w0rp's ale plugin. If you have installed everything correctly including w0rp's ale, pylint & pylint-django. In your vimrc add the following line & have fun developing web apps using django. Thanks.

let g:ale_python_pylint_options = '--load-plugins pylint_django'
Ganesh
  • 3,128
  • 2
  • 17
  • 27
3

The solution proposed in this other question it to simply add get_attr to your Tag class. Ugly, but works.

Community
  • 1
  • 1
eric
  • 355
  • 1
  • 3
1

So far I have found no real solution to that but work around:

  • In our company we require a pylint score > 8. This allows coding practices pylint doesn't understand while ensuring that the code isn't too "unusual". So far we havn't seen any instance where E1101 kept us from reaching a score of 8 or higher.
  • Our 'make check' targets filter out "for has no 'objects' member" messages to remove most of the distraction caused by pylint not understanding Django.
max
  • 29,122
  • 12
  • 52
  • 79
0

For heroku users, you can also use Tal Weiss's answer to this question using the following syntax to run pylint with the pylint-django plugin (replace timekeeping with your app/package):

# run on the entire timekeeping app/package
heroku local:run pylint --load-plugins pylint_django timekeeping

# run on the module timekeeping/report.py
heroku local:run pylint --load-plugins pylint_django timekeeping/report.py

# With temporary command line disables
heroku local:run pylint --disable=invalid-name,missing-function-docstring --load-plugins pylint_django timekeeping/report.py

Note: I was unable to run without specifying project/package directories.

If you have issues with E5110: Django was not configured., you can also invoke as follows to try to work around that (again, change timekeeping to your app/package):

heroku local:run python manage.py shell -c 'from pylint import lint; lint.Run(args=["--load-plugins", "pylint_django", "timekeeping"])'

# With temporary command line disables, specific module
heroku local:run python manage.py shell -c 'from pylint import lint; lint.Run(args=["--load-plugins", "pylint_django", "--disable=invalid-name,missing-function-docstring", "timekeeping/report.py"])'
sage
  • 4,863
  • 2
  • 44
  • 47