# Config file for pylint for CleverHans
# Used by cleverhans.devtools

[FORMAT]
# TensorFlow 2 space style
indent-string='  '


max-line-length=120
# pylint should print out the file path, line number, and ID code for the
# messages it prints. This is partly so we can turn off the ID codes that
# we do not actually want to enforce.
msg-template='{path}:{line}: [{msg_id}({symbol}), {obj}] {msg}'

# ID codes to disable
# E1130: has a bug.
#   The type of the output of softmax_cross_entropy_with_logits is weird
#   and pylint does not realize it is safe to negate it.
# C0103: Complains about the variable name 'x'
# W0613: Unused argument
#  This one is disabled because pylint does not implement it well.
#  In many cases we use all arguments via `locals()` and pylint does not
#  detect them as used.
# E1101: pylint seems to have a bug. Says numpy.random has no member RandomState
# R0913: Too many arguments
# R0914: Too many local variables
# W0223: doesn't allow subclass of an abstract base class to still be abstract
# E0203: pylint seems to have a bug. Doesn't know self.x can be defined before
#        method call.
# W0201: doesn't let any attributes be added outside __init__
# C1801: do not use len(s) to tell if s is empty
# E1129: a check on context managers
#  This is disabled because it complains about "with sess.as_default".
#  pylint does not seem to believe that that is a real context manager.
# C0325: unnecessary parens (sometimes we use them to be extra-explicit)
# R1705: "unnecessary else after return"
#  We disable this one because it is annoying. It forbids
#  if a:
#    return b
#  else:
#    return c
#  The name "unnecessary else after return" seems misleading, and it would be
#  annoying and use more lines to rewrite everything as:
#  if a:
#    out = b
#  else:
#    out = c
#  return out
# W0703: catching too general exception
# W0101: unreachable code
#  We disable this one because it does not allow:
#
#  class A(object):
#    def f(self):
#      raise NotImplementedError("Subclass must implement f")
#      return 0
#
#  W0101 complains that the `return 0` is never reached.
#  However, if we do not have the return statement, we get E1111 on lines
#  such as:
#
#  x = a.f()
#
#  because pylint sees no return statement in f.
#  We can't have both W0101 and E1111, and between them, it is better to
#  disable W0101 because dead code is less likely to be a bug than using a
#  null return value. Also, as of this writing, the only instance of W0101 is
#  an abstract method like in the example shown here, so we are not writing
#  any dead code by accident in practice.
#
# W0122: use of exec
# R0912: too many branches
# R0903: too few public methods
# W0221: parameters differ from overridden method
# W0212: protected access
# R1703: simplifiable if statement
# R0201: method could be a function
# W0603: global statement
# R0915: too many statements
# R0902: too many attributes
# C0200: consider using enumerate
# W1201: logging not lazy
#  Disabled because it forbids things like
#    logging.info('#' * pad + msg + '#' * pad)
#  Doesn't seem useful to refactor this to
#    padded_msg = '#' * pad + msg + '#' * pad
#    logging.info(padded_msg)
#  or to refactor it to
#    logging.info('%s%s%s', pad, msg, pad)
#  The speedup of avoiding a string concatenation is presumably negligible
#  compared to most of the ML operations we do to generate log messages.
# C0302: too many lines in module
# W0511: forbids TODOs
# R0911: too many return statements
# E0401: cannot import module
# R0205: this one is apparently asking us to drop python 2 support?
# R1714: use x in [a,b] instead of x == a or x == b
# R0801: duplicate code across files
#        (We have a lot of intentional duplication, like the tutorials)
disable=C0103,W0613,E1101,R0913,R0914,W0223,E0203,W0201,C1801,E1129,C0325,R1705,W0622,W0703,W0101,W0122,R0912,R0903,W0221,W0212,R1703,R0201,W0603,R0915,R0902,C0200,W1201,C0302,W0511,R0911,E0401,R0205,R1714,R0801,E1130

[IMPORTS]
# Explicitly specifying this helps pylint to behave more consistently across multiple platforms.
# If not specified, the method used to install each library seems to change whether it is considered third party, etc.
known-third-party=joblib,keras,numpy,PIL,six,tensorflow
