]> git.droids-corp.org - imapami.git/commitdiff
port to python3 tmp
authorOlivier Matz <olivier.matz@6wind.com>
Mon, 23 Jan 2023 15:09:24 +0000 (16:09 +0100)
committerOlivier Matz <olivier.matz@6wind.com>
Mon, 23 Jan 2023 15:49:13 +0000 (16:49 +0100)
imapami/__init__.py
imapami/actions.py
imapami/conditions.py
imapami/mail.py
imapami/rules.py
imapami/utils.py
pylintrc

index 48542104d9f2678f4079909fae5d40801c842caf..d7576694c23fde5265e2f21498b1f5b892527974 100644 (file)
@@ -27,9 +27,9 @@
 # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #
 
-import imapami.actions
-import imapami.conditions
-import imapami.rules
+"""
+Main entry point for imapami.
+"""
 
 import argparse
 import getpass
@@ -43,10 +43,14 @@ import sys
 import time
 import yaml
 
+import imapami.actions
+import imapami.conditions
+import imapami.rules
+
 _LOGLEVELS = [logging.CRITICAL, logging.ERROR, logging.WARNING,
               logging.INFO, logging.DEBUG]
 
-class Imapami(object):
+class Imapami:
     """
     The yaml configuration is a collection (dictionary). The following keys
     are reserved:
@@ -195,14 +199,14 @@ class Imapami(object):
         """
         Connect and login to the remote IMAP server.
         """
-        if self.config.get("ssl") == True:
+        if self.config.get("ssl"):
             imap_class = imaplib.IMAP4_SSL
         else:
             imap_class = imaplib.IMAP4
 
         login = self.config.get("login")
         if login is None:
-            login = raw_input("Username: ")
+            login = input("Username: ")
         password = self.config.get("password")
         if password is None:
             password = getpass.getpass()
@@ -235,10 +239,10 @@ class Imapami(object):
             self.imap.select(m)
             typ, dat = self.imap.status(m, "(UIDNEXT)")
             if typ != 'OK':
-                raise ValueError("cannot get UIDNEXT: %s", typ)
-            match = re.match("[^ ]* \(UIDNEXT ([0-9]+)\)", dat[0])
+                raise ValueError("cannot get UIDNEXT: %s" % typ)
+            match = re.match(br"[^ ]* \(UIDNEXT ([0-9]+)\)", dat[0])
             if match is None:
-                raise ValueError("cannot match UIDNEXT: %s", typ)
+                raise ValueError("cannot match UIDNEXT: %s" % typ)
             self.uidnext[m] = int(match.groups()[0])
         self.logger.info('Done: %r', self.uidnext)
 
@@ -284,7 +288,7 @@ Configuration parameters and variables
     helptxt += doc + '\n\n'
 
     conds = imapami.conditions.get()
-    conds_list = conds.keys()
+    conds_list = list(conds.keys())
     conds_list.sort()
     helptxt += 'Conditions\n'
     helptxt += '==========\n\n'
@@ -298,7 +302,7 @@ Configuration parameters and variables
             helptxt += 'No help\n\n'
 
     actions = imapami.actions.get()
-    actions_list = actions.keys()
+    actions_list = list(actions.keys())
     actions_list.sort()
     helptxt += 'Actions\n'
     helptxt += '=======\n\n'
@@ -338,7 +342,7 @@ def main():
         type=int, default=3)
 
     args = parser.parse_args()
-    if args.config_help == True:
+    if args.config_help:
         show_config_help()
         sys.exit(0)
 
@@ -349,7 +353,7 @@ def main():
 
     password = os.getenv("IMAPAMI_PASSWORD")
     p = Imapami(open(args.config).read(), args.debug, password=password)
-    if args.check == True:
+    if args.check:
         sys.stderr.write('Configuration parsing ok\n')
         sys.exit(0)
 
@@ -361,7 +365,8 @@ def main():
                 p.get_uidnext()
                 p.process_rules()
                 p.close()
-            except:
+            # pylint: disable=broad-except
+            except Exception:
                 p.logger.error("Exception during processing", exc_info=True)
             time.sleep(args.refresh)
             # XXX why needed?
index 4991f07f037f66a5f61efcf4a4b2d0c960afd935..1d8587f91e6cea25a8dda9162b1e5ea110c8c7c6 100644 (file)
@@ -27,7 +27,9 @@
 # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #
 
-import imapami.utils
+"""
+Actions in imapami. Ex: forward, pipe to file, set variable, ...
+"""
 
 import copy
 from email.mime.multipart import MIMEMultipart
@@ -38,6 +40,8 @@ import shlex
 import smtplib
 import subprocess
 
+import imapami.utils
+
 _all_actions = {}
 _LOGLEVELS = [logging.CRITICAL, logging.ERROR, logging.WARNING,
               logging.INFO, logging.DEBUG]
@@ -54,7 +58,7 @@ def register(action_class):
                          action_class.name)
     _all_actions[action_class.name] = action_class
 
-class ImapamiAction(object):
+class ImapamiAction:
     """
     This is the parent class for actions.
 
@@ -78,6 +82,7 @@ class ImapamiAction(object):
         self.fetch = fetch or "no"
         self.terminal = terminal
 
+    # pylint: disable=no-self-use
     def evaluate(self, arg, ami, hdrs):
         """
         Evaluate a string argument
@@ -94,16 +99,17 @@ class ImapamiAction(object):
         :returns:
           The evaluated argument.
         """
-        if hdrs is not None:
-            variables = imapami.utils.headers_to_unicode(hdrs)
-        else:
+        if hdrs is None:
             variables = {}
+        else:
+            variables = dict(hdrs)
         variables.update(ami.variables)
         fmt = imapami.utils.VarFormatter()
-        arg = fmt.format(unicode(arg), **variables)
+        arg = fmt.format(str(arg), **variables)
         return arg
 
-    def process(self, imap, mail):
+    # pylint: disable=unused-argument,no-self-use
+    def process(self, ami, mail):
         """
         Process the action
 
@@ -136,7 +142,7 @@ class ImapamiActionList(ImapamiAction):
     def __init__(self, *action_list):
         action_list = [new(a) for a in action_list]
         for a in action_list[:-1]:
-            if a.terminal == True:
+            if a.terminal is True:
                 raise ValueError("terminal action in the middle of an action list")
         fetch = imapami.utils.highest_fetch_level(
             [a.fetch for a in action_list])
@@ -146,7 +152,7 @@ class ImapamiActionList(ImapamiAction):
     def process(self, ami, mail):
         ret = True
         for a in self.action_list:
-            if a.process(ami, mail) == False:
+            if a.process(ami, mail) is False:
                 ret = False
         return ret
 register(ImapamiActionList)
@@ -200,7 +206,7 @@ class ImapamiActionChangeFlag(ImapamiAction):
         self.flag = flag
     def process(self, ami, mail):
         imap = ami.imap
-        if self.enable == True:
+        if self.enable is True:
             cmd = '+FLAGS'
         else:
             cmd = '-FLAGS'
@@ -316,8 +322,8 @@ class ImapamiActionLog(ImapamiAction):
         self.level = level
     def process(self, ami, mail):
         msg = self.evaluate(self.msg, ami, mail.msg)
-        l = _LOGLEVELS[self.level]
-        ami.logger.log(l, msg)
+        level = _LOGLEVELS[self.level]
+        ami.logger.log(level, msg)
         return True
 register(ImapamiActionLog)
 
@@ -346,7 +352,7 @@ class ImapamiActionPipe(ImapamiAction):
     def __init__(self, command, what='headers', shell=False):
         valid = ['headers', 'body_part1', 'body_all',
                  'headers+body_part1', 'headers+body_all']
-        if not what in valid:
+        if what not in valid:
             raise ValueError("invalid 'what' field. Valid values are: %s" %
                              valid)
         if what in ['headers']:
@@ -360,7 +366,7 @@ class ImapamiActionPipe(ImapamiAction):
         self.what = what
         self.shell = shell
     def process(self, ami, mail):
-        if self.shell == True:
+        if self.shell is True:
             command = self.command
         else:
             command = shlex.split(self.command)
@@ -420,7 +426,7 @@ class ImapamiActionSetHeader(ImapamiAction):
         for cmd in args:
             if not isinstance(cmd, dict):
                 raise ValueError("set-header command is not a dict")
-            if not cmd.has_key("mode"):
+            if "mode" not in cmd:
                 raise ValueError("set-header command has no mode")
             if cmd["mode"] not in ['add', 'del', 'replace']:
                 raise ValueError("invalid mode for set-header command")
@@ -432,13 +438,13 @@ class ImapamiActionSetHeader(ImapamiAction):
             mode = cmd.pop("mode")
             fields = cmd
             if mode == "add":
-                for k, v in fields.iteritems():
+                for k, v in fields.items():
                     parsed_headers[k] = v
             elif mode == "del":
-                for k, v in fields.iteritems():
+                for k, v in fields.items():
                     del parsed_headers[k]
             elif mode == "replace":
-                for k, v in fields.iteritems():
+                for k, v in fields.items():
                     parsed_headers.replace_header(k, v)
 
         ami.imap.append(mail.inbox, mail.flags, mail.internal_date,
@@ -446,7 +452,8 @@ class ImapamiActionSetHeader(ImapamiAction):
         return True
 register(ImapamiActionSetHeader)
 
-class ImapamiSmtpSender(object):
+# pylint: disable=too-few-public-methods
+class ImapamiSmtpSender:
     """
     A SMTP sender using smtp lib
     """
@@ -500,7 +507,7 @@ class ImapamiSmtpSender(object):
             if self.encryption == "starttls":
                 smtp.starttls()
             if self.login is not None:
-                smtp.login(self.loging, self.password)
+                smtp.login(self.login, self.password)
             smtp.sendmail(sender, to, mail)
             smtp.close()
         except smtplib.SMTPAuthenticationError as e:
@@ -631,7 +638,7 @@ class ImapamiActionSetVar(ImapamiAction):
         ImapamiAction.__init__(self)
         self.kwargs = kwargs
     def process(self, ami, mail):
-        for k, v in self.kwargs.iteritems():
+        for k, v in self.kwargs.items():
             k = self.evaluate(k, ami, mail.msg)
             if v is None and ami.variables.get(k) is not None:
                 ami.variables.pop(k)
@@ -655,7 +662,7 @@ def new(config):
     if len(config) != 1:
         raise ValueError("the action config must be a dictionary whose only "
                          "key is the action name")
-    action_name = next(iter(config.keys()))
+    action_name = next(iter(list(config.keys())))
     argslist = []
     argsdict = {}
     if isinstance(config[action_name], list):
index 157229435937e1a9772b7387e6eb00b409ea3d34..97a42b6f7d2e1e84ac9a9bd4424815dbc9ea1abf 100644 (file)
 # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #
 
-import imapami.utils
+"""
+Conditions in imapami. Examples: sender is x, mail is unread, ...
+"""
 
 import logging
 import re
 import time
 
+import imapami.utils
+
 _all_conditions = {}
 
 def register(cond_class):
@@ -47,7 +51,7 @@ def register(cond_class):
                          cond_class.name)
     _all_conditions[cond_class.name] = cond_class
 
-class ImapamiCond(object):
+class ImapamiCond:
     """
     This is the parent class for conditions.
 
@@ -69,6 +73,7 @@ class ImapamiCond(object):
         self.fetch = fetch or "no"
         self.criteria = criteria or set()
 
+    # pylint: disable=unused-argument,no-self-use
     def evaluate(self, arg, ami, hdrs):
         """
         Evaluate a string argument
@@ -86,14 +91,15 @@ class ImapamiCond(object):
           The evaluated argument.
         """
         if hdrs is not None:
-            variables = imapami.utils.headers_to_unicode(hdrs)
+            variables = dict(hdrs)
         else:
             variables = {}
         variables.update(ami.variables)
         fmt = imapami.utils.VarFormatter()
-        arg = fmt.format(unicode(arg), **variables)
+        arg = fmt.format(str(arg), **variables)
         return arg
 
+    # pylint: disable=unused-argument,no-self-use
     def check(self, ami, mail):
         """
         Check the condition.
@@ -401,6 +407,7 @@ class ImapamiCondRecent(ImapamiCond):
       recent: {}
     """
     name = "recent"
+    # pylint: disable=unused-argument
     def __init__(self, substr):
         ImapamiCond.__init__(self, criteria=set(['RECENT']))
 register(ImapamiCondRecent)
@@ -419,6 +426,7 @@ class ImapamiCondAnswered(ImapamiCond):
       answered: {}
     """
     name = "answered"
+    # pylint: disable=unused-argument
     def __init__(self, substr):
         ImapamiCond.__init__(self, criteria=set(['ANSWERED']))
 register(ImapamiCondAnswered)
@@ -437,6 +445,7 @@ class ImapamiCondUnanswered(ImapamiCond):
       unanswered: {}
     """
     name = "unanswered"
+    # pylint: disable=unused-argument
     def __init__(self, substr):
         ImapamiCond.__init__(self, criteria=set(['UNANSWERED']))
 register(ImapamiCondUnanswered)
@@ -455,6 +464,7 @@ class ImapamiCondFlagged(ImapamiCond):
       flagged: {}
     """
     name = "flagged"
+    # pylint: disable=unused-argument
     def __init__(self, substr):
         ImapamiCond.__init__(self, criteria=set(['FLAGGED']))
 register(ImapamiCondFlagged)
@@ -473,6 +483,7 @@ class ImapamiCondUnflagged(ImapamiCond):
       unflagged: {}
     """
     name = "unflagged"
+    # pylint: disable=unused-argument
     def __init__(self, substr):
         ImapamiCond.__init__(self, criteria=set(['UNFLAGGED']))
 register(ImapamiCondUnflagged)
@@ -491,6 +502,7 @@ class ImapamiCondDraft(ImapamiCond):
       draft: {}
     """
     name = "draft"
+    # pylint: disable=unused-argument
     def __init__(self, substr):
         ImapamiCond.__init__(self, criteria=set(['DRAFT']))
 register(ImapamiCondDraft)
@@ -509,6 +521,7 @@ class ImapamiCondUndraft(ImapamiCond):
       undraft: {}
     """
     name = "undraft"
+    # pylint: disable=unused-argument
     def __init__(self, substr):
         ImapamiCond.__init__(self, criteria=set(['UNDRAFT']))
 register(ImapamiCondUndraft)
@@ -770,7 +783,7 @@ def new(config):
     if len(config) != 1:
         raise ValueError("the condition config must be a dictionary whose only "
                          "key is the condition name")
-    cond_name = next(iter(config.keys()))
+    cond_name = next(iter(list(config.keys())))
     argslist = []
     argsdict = {}
     if isinstance(config[cond_name], list):
index 29c4a029e5de644c690aa26364166f1e577dd8a1..fa0d28a98945af54f98e1035e8c4d1bd66fa4bc6 100644 (file)
 # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #
 
+"""
+A mail description in imapami.
+"""
+
 import email
 
-class ImapamiMail(object):
+# pylint: disable=too-few-public-methods,too-many-instance-attributes
+class ImapamiMail:
     """
     An email, fetched from the IMAP server
 
@@ -58,15 +63,15 @@ class ImapamiMail(object):
         # always filled
         self.item = item
         self.inbox = inbox
-        msg = ''
+        msg = b''
         if headers is not None:
             msg += headers
-        self.msghdrs = email.message_from_string(msg)
+        self.msghdrs = email.message_from_bytes(msg)
         if body_all is not None:
             msg += body_all
         elif body_part1 is not None:
             msg += body_part1
-        self.msg = email.message_from_string(msg)
+        self.msg = email.message_from_bytes(msg)
         # fetch level >= headers
         self.flags = flags
         self.internal_date = internal_date
index fc51da97100eb84c7fd4a0d1c46569c323aab38d..693d1587b481df03a41bf849ee6e2defc3af87d5 100644 (file)
 # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #
 
-import imapami.actions
-import imapami.conditions
-import imapami.mail
-import imapami.utils
+"""
+Rules in imapami. A rule is a list of conditions and actions.
+"""
 
 import imaplib
 import logging
 import re
 
-class ImapamiRule(object):
+import imapami.actions
+import imapami.conditions
+import imapami.mail
+import imapami.utils
+
+class ImapamiRule:
     """
     A rule is composed of a list of conditions, and a list of actions that are
     executed on the mails which match the conditions.
@@ -164,7 +168,7 @@ class ImapamiRule(object):
         if resp != 'OK':
             ami.logger.warning(
                 "search failed: server response = %s, skip rule", resp)
-            return
+            return []
 
         item_list = items[0].split()
         item_list = [i for i in item_list if int(i) < ami.uidnext[inbox]]
@@ -197,6 +201,7 @@ class ImapamiRule(object):
         ami.logger.debug('get imap parts = %s', parts_str)
         return parts_str, parts
 
+    # pylint: disable=too-many-locals
     def process(self, ami):
         """
         Process the rule.
@@ -230,14 +235,14 @@ class ImapamiRule(object):
                 for i, part in enumerate(parts):
                     mail_data[part[0]] = data[i][1]
 
-                m = re.match(r'^.*FLAGS \(([^)]*)\) INTERNALDATE ("[^"]*").*$',
-                             data[0][0])
-                if m is None:
+                m = re.match(br'^.*FLAGS \(([^)]*)\).*$', data[0][0])
+                m2 = re.match(br'^.*INTERNALDATE ("[^"]*").*$', data[0][0])
+                if not m or not m2:
                     ami.logger.warning("cannot parse flags and date %s" %
                                        data[0][0])
                     flags, internal_date = '', ''
                 else:
-                    flags, internal_date = m.groups()
+                    flags, internal_date = m.group(1), m2.group(1)
                 mail_data['flags'] = flags
                 mail_data['internal_date'] = internal_date
 
@@ -252,7 +257,7 @@ class ImapamiRule(object):
                 ami.logger.debug("item %s does not match conditions", item)
                 success = self.nomatch_action.process(ami, mail)
 
-            if success == False:
+            if success is False:
                 ami.logger.warning(
                     "at least one action failed for item %s", item)
                 self.error_action.process(ami, mail)
index 375910ce6fc8de29e4120c13d41a4d4e811231c8..ddae053ef539c7ddfbc458e87051394469ea31d7 100644 (file)
 # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #
 
+"""
+Utilities.
+"""
+
 import email.header
 import re
-
-# pylint: disable=deprecated-module
-# see https://www.logilab.org/ticket/2481
 import string
 
 class VarFormatter(string.Formatter):
@@ -49,36 +50,10 @@ class VarFormatter(string.Formatter):
         except (KeyError, AttributeError):
             return None, field_name
 
-    def format_field(self, value, spec):
+    def format_field(self, value, format_spec):
         if value is None:
             return ''
-        return string.Formatter.format_field(self, value, spec)
-
-def headers_to_unicode(headers):
-    """
-    Convert mail headers into a unicode dictionary
-
-    :arg email.message.Message headers:
-      The email headers
-    """
-    unicode_headers = {}
-    for key, hdr in headers.items():
-        try:
-            value, encoding = email.header.decode_header(hdr)[0]
-        except email.header.HeaderParseError:
-            try:
-                # try to workaround badly formatted RFC2047 tokens
-                hdr = re.sub(r"(==)(?!$)", u"= =", hdr)
-                value, encoding = email.header.decode_header(hdr)[0]
-            except email.header.HeaderParseError:
-                # fallback to wrong decoding
-                value, encoding = hdr, 'utf-8'
-        if encoding is None:
-            value = unicode(value, errors="replace")
-        else:
-            value = value.decode(encoding, errors="replace")
-        unicode_headers[key] = value
-    return unicode_headers
+        return string.Formatter.format_field(self, value, format_spec)
 
 def highest_fetch_level(fetch_list):
     """
index 34d8f3a7f3d11e0de8fab0f045d1bfee8f32e322..1c83c4e6e2987f12cc6794cc1e6b3f63a66c07ff 100644 (file)
--- a/pylintrc
+++ b/pylintrc
-# Copyright 2014-2015, 6WIND S.A.
-
 [MASTER]
 
-# Specify a configuration file.
-#rcfile=
+# A comma-separated list of package or module names from where C extensions may
+# be loaded. Extensions are loading into the active Python interpreter and may
+# run arbitrary code.
+extension-pkg-whitelist=
+
+# Specify a score threshold to be exceeded before program exits with error.
+fail-under=10.0
+
+# Add files or directories to the blacklist. They should be base names, not
+# paths.
+ignore=CVS
+
+# Add files or directories matching the regex patterns to the blacklist. The
+# regex matches against base names, not paths.
+ignore-patterns=
 
 # Python code to execute, usually for sys.path manipulation such as
 # pygtk.require().
 #init-hook=
 
-# Profiled execution.
-profile=no
+# Use multiple processes to speed up Pylint. Specifying 0 will auto-detect the
+# number of processors available to use.
+jobs=1
 
-# Add files or directories to the blacklist. They should be base names, not
-# paths.
-ignore=CVS,.git
+# Control the amount of potential inferred values when inferring a single
+# object. This can help the performance when dealing with large functions or
+# complex, nested conditions.
+limit-inference-results=100
+
+# List of plugins (as comma separated values of python module names) to load,
+# usually to register additional checkers.
+load-plugins=
 
 # Pickle collected data for later comparisons.
 persistent=yes
 
-# List of plugins (as comma separated values of python modules names) to load,
-# usually to register additional checkers.
-load-plugins=
+# When enabled, pylint would attempt to guess common misconfiguration and emit
+# user-friendly hints instead of false-positive error messages.
+suggestion-mode=yes
+
+# Allow loading of arbitrary C extensions. Extensions are imported into the
+# active Python interpreter and may run arbitrary code.
+unsafe-load-any-extension=no
 
 
 [MESSAGES CONTROL]
 
-# Enable the message, report, category or checker with the given id(s). You can
-# either give multiple identifier separated by comma (,) or put this option
-# multiple time.
-#enable=
+# Only show warnings with the listed confidence levels. Leave empty to show
+# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED.
+confidence=
 
 # Disable the message, report, category or checker with the given id(s). You
-# can either give multiple identifier separated by comma (,) or put this option
+# can either give multiple identifiers separated by comma (,) or put this
+# option multiple times (only on the command line, not in the configuration
+# file where it should appear only once). You can also use "--disable=all" to
+# disable everything first and then reenable specific checks. For example, if
+# you want to run only the similarities checker, you can use "--disable=all
+# --enable=similarities". If you want to run only the classes checker, but have
+# no Warning level messages displayed, use "--disable=all --enable=classes
+# --disable=W".
+disable=print-statement,
+        parameter-unpacking,
+        unpacking-in-except,
+        old-raise-syntax,
+        backtick,
+        long-suffix,
+        old-ne-operator,
+        old-octal-literal,
+        import-star-module-level,
+        non-ascii-bytes-literal,
+        raw-checker-failed,
+        bad-inline-option,
+        locally-disabled,
+        file-ignored,
+        suppressed-message,
+        useless-suppression,
+        deprecated-pragma,
+        use-symbolic-message-instead,
+        apply-builtin,
+        basestring-builtin,
+        buffer-builtin,
+        cmp-builtin,
+        coerce-builtin,
+        execfile-builtin,
+        file-builtin,
+        long-builtin,
+        raw_input-builtin,
+        reduce-builtin,
+        standarderror-builtin,
+        unicode-builtin,
+        xrange-builtin,
+        coerce-method,
+        delslice-method,
+        getslice-method,
+        setslice-method,
+        no-absolute-import,
+        old-division,
+        dict-iter-method,
+        dict-view-method,
+        next-method-called,
+        metaclass-assignment,
+        indexing-exception,
+        raising-string,
+        reload-builtin,
+        oct-method,
+        hex-method,
+        nonzero-method,
+        cmp-method,
+        input-builtin,
+        round-builtin,
+        intern-builtin,
+        unichr-builtin,
+        map-builtin-not-iterating,
+        zip-builtin-not-iterating,
+        range-builtin-not-iterating,
+        filter-builtin-not-iterating,
+        using-cmp-argument,
+        eq-without-hash,
+        div-method,
+        idiv-method,
+        rdiv-method,
+        exception-message-attribute,
+        invalid-str-codec,
+        sys-max-int,
+        bad-python3-import,
+        deprecated-string-function,
+        deprecated-str-translate-call,
+        deprecated-itertools-function,
+        deprecated-types-field,
+        next-method-defined,
+        dict-items-not-iterating,
+        dict-keys-not-iterating,
+        dict-values-not-iterating,
+        deprecated-operator-function,
+        deprecated-urllib-function,
+        xreadlines-attribute,
+        deprecated-sys-function,
+        exception-escape,
+        comprehension-escape
+
+# Enable the message, report, category or checker with the given id(s). You can
+# either give multiple identifier separated by comma (,) or put this option
 # multiple time (only on the command line, not in the configuration file where
-# it should appear only once).
-disable=attribute-defined-outside-init,
-       bare-except,
-       cyclic-import,
-       duplicate-code,
-       fixme,
-       interface-not-implemented,
-       line-too-long,
-       locally-disabled,
-       missing-docstring,
-       no-member,
-       no-self-use,
-       super-init-not-called,
-       unused-argument,
+# it should appear only once). See also the "--disable" option for examples.
+enable=c-extension-no-member
 
 
 [REPORTS]
 
-# Set the output format. Available formats are text, parseable, colorized, msvs
-# (visual studio) and html
-output-format=text
+# Python expression which should return a score less than or equal to 10. You
+# have access to the variables 'error', 'warning', 'refactor', and 'convention'
+# which contain the number of messages in each category, as well as 'statement'
+# which is the total number of statements analyzed. This score is used by the
+# global evaluation report (RP0004).
+evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
 
-# Put messages in a separate file for each module / package specified on the
-# command line instead of printing them on stdout. Reports (if any) will be
-# written in a file name "pylint_global.[txt|html]".
-files-output=no
+# Template used to display messages. This is a python new-style format string
+# used to format the message information. See doc for all details.
+#msg-template=
 
-# Tells whether to display a full report or only the messages
+# Set the output format. Available formats are text, parseable, colorized, json
+# and msvs (visual studio). You can also give a reporter class, e.g.
+# mypackage.mymodule.MyReporterClass.
+output-format=text
+
+# Tells whether to display a full report or only the messages.
 reports=no
 
-# Python expression which should return a note less than 10 (10 is the highest
-# note). You have access to the variables errors warning, statement which
-# respectively contain the number of errors / warnings messages and the total
-# number of statements analyzed. This is used by the global evaluation report
-# (RP0004).
-evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
+# Activate the evaluation score.
+score=yes
+
 
-# Add a comment according to your evaluation note. This is used by the global
-# evaluation report (RP0004).
-comment=no
+[REFACTORING]
+
+# Maximum number of nested blocks for function / method body
+max-nested-blocks=5
+
+# Complete name of functions that never returns. When checking for
+# inconsistent-return-statements if a never returning function is called then
+# it will be considered as an explicit return statement and no message will be
+# printed.
+never-returning-functions=sys.exit
+
+
+[STRING]
+
+# This flag controls whether inconsistent-quotes generates a warning when the
+# character used as a quote delimiter is used inconsistently within a module.
+check-quote-consistency=no
+
+# This flag controls whether the implicit-str-concat should generate a warning
+# on implicit string concatenation in sequences defined over several lines.
+check-str-concat-over-line-jumps=no
 
-msg-template={path}:{line} {msg} [{symbol}]
 
 [TYPECHECK]
 
+# List of decorators that produce context managers, such as
+# contextlib.contextmanager. Add to this list to register other decorators that
+# produce valid context managers.
+contextmanager-decorators=contextlib.contextmanager
+
+# List of members which are set dynamically and missed by pylint inference
+# system, and so shouldn't trigger E1101 when accessed. Python regular
+# expressions are accepted.
+generated-members=
+
 # Tells whether missing members accessed in mixin class should be ignored. A
 # mixin class is detected if its name ends with "mixin" (case insensitive).
 ignore-mixin-members=yes
 
-# List of classes names for which member attributes should not be checked
-# (useful for classes with attributes dynamically set).
-ignored-classes=SQLObject
+# Tells whether to warn about missing members when the owner of the attribute
+# is inferred to be None.
+ignore-none=yes
 
-# When zope mode is activated, add a predefined set of Zope acquired attributes
-# to generated-members.
-zope=no
+# This flag controls whether pylint should warn about no-member and similar
+# checks whenever an opaque object is returned when inferring. The inference
+# can return multiple potential results while evaluating a Python object, but
+# some branches might not be evaluated, which results in partial inference. In
+# that case, it might be useful to still emit no-member and other checks for
+# the rest of the inferred objects.
+ignore-on-opaque-inference=yes
 
-# List of members which are set dynamically and missed by pylint inference
-# system, and so shouldn't trigger E0201 when accessed. Python regular
-# expressions are accepted.
-generated-members=REQUEST,acl_users,aq_parent
+# List of class names for which member attributes should not be checked (useful
+# for classes with dynamically set attributes). This supports the use of
+# qualified names.
+ignored-classes=optparse.Values,thread._local,_thread._local
+
+# List of module names for which member attributes should not be checked
+# (useful for modules/projects where namespaces are manipulated during runtime
+# and thus existing member attributes cannot be deduced by static analysis). It
+# supports qualified module names, as well as Unix pattern matching.
+ignored-modules=
+
+# Show a hint with possible names when a member name was not found. The aspect
+# of finding the hint is based on edit distance.
+missing-member-hint=yes
+
+# The minimum edit distance a name should have in order to be considered a
+# similar match for a missing member name.
+missing-member-hint-distance=1
+
+# The total number of similar names that should be taken in consideration when
+# showing a hint for a missing member.
+missing-member-max-choices=1
+
+# List of decorators that change the signature of a decorated function.
+signature-mutators=
+
+
+[FORMAT]
+
+# Expected format of line ending, e.g. empty (any line ending), LF or CRLF.
+expected-line-ending-format=
+
+# Regexp for a line that is allowed to be longer than the limit.
+ignore-long-lines=^\s*(# )?<?https?://\S+>?$
+
+# Number of spaces of indent required inside a hanging or continued line.
+indent-after-paren=4
+
+# String used as indentation unit. This is usually "    " (4 spaces) or "\t" (1
+# tab).
+indent-string='    '
+
+# Maximum number of characters on a single line.
+max-line-length=100
+
+# Maximum number of lines in a module.
+max-module-lines=1000
+
+# Allow the body of a class to be on the same line as the declaration if body
+# contains single statement.
+single-line-class-stmt=no
+
+# Allow the body of an if to be on the same line as the test if there is no
+# else.
+single-line-if-stmt=no
 
 
 [BASIC]
 
-# Required attributes for module, separated by a comma
-required-attributes=
+# Naming style matching correct argument names.
+argument-naming-style=snake_case
+
+# Regular expression matching correct argument names. Overrides argument-
+# naming-style.
+#argument-rgx=
+
+# Naming style matching correct attribute names.
+attr-naming-style=snake_case
+
+# Regular expression matching correct attribute names. Overrides attr-naming-
+# style.
+#attr-rgx=
+
+# Bad variable names which should always be refused, separated by a comma.
+bad-names=foo,
+          bar,
+          baz,
+          toto,
+          tutu,
+          tata
+
+# Bad variable names regexes, separated by a comma. If names match any regex,
+# they will always be refused
+bad-names-rgxs=
 
-# List of builtins function names that should not be used, separated by a comma
-bad-functions=map,filter,apply,input
+# Naming style matching correct class attribute names.
+class-attribute-naming-style=any
 
-# Regular expression which should only match correct module names
-module-rgx=[a-z_][a-z0-9_]*$
+# Regular expression matching correct class attribute names. Overrides class-
+# attribute-naming-style.
+#class-attribute-rgx=
 
-# Regular expression which should only match correct module level names
-const-rgx=[A-Z_][A-Z0-9_]*|__all__$
+# Naming style matching correct class names.
+class-naming-style=PascalCase
 
-# Regular expression which should only match correct class names
-class-rgx=[A-Z_][a-zA-Z0-9]+$
+# Regular expression matching correct class names. Overrides class-naming-
+# style.
+#class-rgx=
 
-# Regular expression which should only match correct function names
-function-rgx=[a-z_][a-z0-9_]{2,30}$
+# Naming style matching correct constant names.
+const-naming-style=UPPER_CASE
 
-# Regular expression which should only match correct method names
-method-rgx=[a-z_][a-z0-9_]{2,30}$
+# Regular expression matching correct constant names. Overrides const-naming-
+# style.
+#const-rgx=
 
-# Regular expression which should only match correct instance attribute names
-attr-rgx=[a-z_][a-z0-9_]{0,30}$
+# Minimum line length for functions/classes that require docstrings, shorter
+# ones are exempt.
+docstring-min-length=-1
 
-# Regular expression which should only match correct argument names
-argument-rgx=[a-z_][a-z0-9_]{0,30}$
+# Naming style matching correct function names.
+function-naming-style=snake_case
 
-# Regular expression which should only match correct variable names
-variable-rgx=[a-z_][a-z0-9_]{0,30}$
+# Regular expression matching correct function names. Overrides function-
+# naming-style.
+#function-rgx=
 
-# Regular expression which should only match correct list comprehension /
-# generator expression variable names
-inlinevar-rgx=[a-z_][a-z0-9_]*$
+# Good variable names which should always be accepted, separated by a comma.
+good-names=i,
+           j,
+           k,
+           v,
+           ex,
+           Run,
+           _,
+           e,
+           m,
+           c,
+           p,
+           a,
+           t,
+           s,
+           to
 
-# Good variable names which should always be accepted, separated by a comma
-good-names=i,j,k,ex,Run,_
+# Good variable names regexes, separated by a comma. If names match any regex,
+# they will always be accepted
+good-names-rgxs=
 
-# Bad variable names which should always be refused, separated by a comma
-bad-names=foo,bar,baz,toto,tutu,tata
+# Include a hint for the correct naming format with invalid-name.
+include-naming-hint=no
 
-# Regular expression which should only match functions or classes name which do
-# not require a docstring
-no-docstring-rgx=__.*__
+# Naming style matching correct inline iteration names.
+inlinevar-naming-style=any
 
+# Regular expression matching correct inline iteration names. Overrides
+# inlinevar-naming-style.
+#inlinevar-rgx=
 
-[FORMAT]
+# Naming style matching correct method names.
+method-naming-style=snake_case
 
-# Maximum number of characters on a single line.
-max-line-length=80
+# Regular expression matching correct method names. Overrides method-naming-
+# style.
+#method-rgx=
 
-# Maximum number of lines in a module
-max-module-lines=1500
+# Naming style matching correct module names.
+module-naming-style=snake_case
 
-# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
-# tab).
-indent-string='    '
+# Regular expression matching correct module names. Overrides module-naming-
+# style.
+#module-rgx=
 
-# List of optional constructs for which whitespace checking is disabled
-no-space-check=
+# Colon-delimited sets of names that determine each other's naming style when
+# the name regexes allow several styles.
+name-group=
 
+# Regular expression which should only match function or class names that do
+# not require a docstring.
+no-docstring-rgx=^_
 
-[SIMILARITIES]
+# List of decorators that produce properties, such as abc.abstractproperty. Add
+# to this list to register other decorators that produce valid properties.
+# These decorators are taken in consideration only for invalid-name.
+property-classes=abc.abstractproperty
 
-# Minimum lines number of a similarity.
-min-similarity-lines=4
+# Naming style matching correct variable names.
+variable-naming-style=snake_case
 
-# Ignore comments when computing similarities.
-ignore-comments=yes
+# Regular expression matching correct variable names. Overrides variable-
+# naming-style.
+#variable-rgx=
 
-# Ignore docstrings when computing similarities.
-ignore-docstrings=yes
+
+[SPELLING]
+
+# Limits count of emitted suggestions for spelling mistakes.
+max-spelling-suggestions=4
+
+# Spelling dictionary name. Available dictionaries: none. To make it work,
+# install the python-enchant package.
+spelling-dict=
+
+# List of comma separated words that should not be checked.
+spelling-ignore-words=
+
+# A path to a file that contains the private dictionary; one word per line.
+spelling-private-dict-file=
+
+# Tells whether to store unknown words to the private dictionary (see the
+# --spelling-private-dict-file option) instead of raising a message.
+spelling-store-unknown-words=no
 
 
 [MISCELLANEOUS]
 
 # List of note tags to take in consideration, separated by a comma.
-notes=FIXME,XXX,TODO
+notes=FIXME,
+      XXX,
+      TODO
 
+# Regular expression of note tags to take in consideration.
+#notes-rgx=
 
-[VARIABLES]
 
-# Tells whether we should check for unused import in __init__ files.
-init-import=yes
+[LOGGING]
 
-# A regular expression matching the beginning of the name of dummy variables
-# (i.e. not used).
-dummy-variables-rgx=_|dummy
+# The type of string formatting that logging methods do. `old` means using %
+# formatting, `new` is for `{}` formatting.
+logging-format-style=old
+
+# Logging modules to check that the string format arguments are in logging
+# function parameter format.
+logging-modules=logging
+
+
+[SIMILARITIES]
+
+# Ignore comments when computing similarities.
+ignore-comments=yes
+
+# Ignore docstrings when computing similarities.
+ignore-docstrings=yes
+
+# Ignore imports when computing similarities.
+ignore-imports=no
+
+# Minimum lines number of a similarity.
+min-similarity-lines=4
+
+
+[VARIABLES]
 
 # List of additional names supposed to be defined in builtins. Remember that
-# you should avoid to define new builtins when possible.
+# you should avoid defining new builtins when possible.
 additional-builtins=
 
+# Tells whether unused global variables should be treated as a violation.
+allow-global-unused-variables=yes
+
+# List of strings which can identify a callback function by name. A callback
+# name must start or end with one of those strings.
+callbacks=cb_,
+          _cb
+
+# A regular expression matching the name of dummy variables (i.e. expected to
+# not be used).
+dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_
+
+# Argument names that match this expression will be ignored. Default to name
+# with leading underscore.
+ignored-argument-names=_.*|^ignored_|^unused_
+
+# Tells whether we should check for unused import in __init__ files.
+init-import=no
+
+# List of qualified module names which can have objects that can redefine
+# builtins.
+redefining-builtins-modules=six.moves,past.builtins,future.builtins,builtins,io
+
 
 [IMPORTS]
 
-# Deprecated modules which should not be used, separated by a comma
-deprecated-modules=regsub,string,TERMIOS,Bastion,rexec
+# List of modules that can be imported at any level, not just the top level
+# one.
+allow-any-import-level=
 
-# Create a graph of every (i.e. internal and external) dependencies in the
-# given file (report RP0402 must not be disabled)
-import-graph=
+# Allow wildcard imports from modules that define __all__.
+allow-wildcard-with-all=no
+
+# Analyse import fallback blocks. This can be used to support both Python 2 and
+# 3 compatible code, which means that the block might have code that exists
+# only in one or another interpreter, leading to false positives when analysed.
+analyse-fallback-blocks=no
+
+# Deprecated modules which should not be used, separated by a comma.
+deprecated-modules=optparse,tkinter.tix
 
 # Create a graph of external dependencies in the given file (report RP0402 must
-# not be disabled)
+# not be disabled).
 ext-import-graph=
 
+# Create a graph of every (i.e. internal and external) dependencies in the
+# given file (report RP0402 must not be disabled).
+import-graph=
+
 # Create a graph of internal dependencies in the given file (report RP0402 must
-# not be disabled)
+# not be disabled).
 int-import-graph=
 
+# Force import order to recognize a module as part of the standard
+# compatibility libraries.
+known-standard-library=
 
-[DESIGN]
+# Force import order to recognize a module as part of a third party library.
+known-third-party=enchant
 
-# Maximum number of arguments for function / method
-max-args=15
+# Couples of modules and preferred modules, separated by a comma.
+preferred-modules=
 
-# Argument names that match this expression will be ignored. Default to name
-# with leading underscore
-ignored-argument-names=_.*
 
-# Maximum number of locals for function / method body
-max-locals=20
+[CLASSES]
 
-# Maximum number of return / yield for function / method body
-max-returns=6
+# Warn about protected attribute access inside special methods
+check-protected-access-in-special-methods=no
 
-# Maximum number of branch for function / method body
-max-branches=20
+# List of method names used to declare (i.e. assign) instance attributes.
+defining-attr-methods=__init__,
+                      __new__,
+                      setUp,
+                      __post_init__
+
+# List of member names, which should be excluded from the protected access
+# warning.
+exclude-protected=_asdict,
+                  _fields,
+                  _replace,
+                  _source,
+                  _make
 
-# Maximum number of statements in function / method body
-max-statements=80
+# List of valid names for the first argument in a class method.
+valid-classmethod-first-arg=cls
 
-# Maximum number of parents for a class (see R0901).
-max-parents=7
+# List of valid names for the first argument in a metaclass class method.
+valid-metaclass-classmethod-first-arg=cls
+
+
+[DESIGN]
+
+# Maximum number of arguments for function / method.
+max-args=10
 
 # Maximum number of attributes for a class (see R0902).
-max-attributes=30
+max-attributes=7
 
-# Minimum number of public methods for a class (see R0903).
-min-public-methods=0
+# Maximum number of boolean expressions in an if statement (see R0916).
+max-bool-expr=5
 
-# Maximum number of public methods for a class (see R0904).
-max-public-methods=100
+# Maximum number of branch for function / method body.
+max-branches=12
 
+# Maximum number of locals for function / method body.
+max-locals=15
 
-[CLASSES]
+# Maximum number of parents for a class (see R0901).
+max-parents=7
 
-# List of interface methods to ignore, separated by a comma. This is used for
-# instance to not check methods defines in Zope's Interface base class.
-#ignore-iface-methods=isImplementedBy,deferred,extends,names,namesAndDescriptions,queryDescriptionFor,getBases,getDescriptionFor,getDoc,getName,getTaggedValue,getTaggedValueTags,isEqualOrExtendedBy,setTaggedValue,isImplementedByInstancesOf,adaptWith,is_implemented_by
+# Maximum number of public methods for a class (see R0904).
+max-public-methods=20
 
-# List of method names used to declare (i.e. assign) instance attributes.
-defining-attr-methods=__init__,__new__
+# Maximum number of return / yield for function / method body.
+max-returns=6
 
-# List of valid names for the first argument in a class method.
-valid-classmethod-first-arg=cls
+# Maximum number of statements in function / method body.
+max-statements=50
+
+# Minimum number of public methods for a class (see R0903).
+min-public-methods=2
 
 
 [EXCEPTIONS]
 
 # Exceptions that will emit a warning when being caught. Defaults to
-# "Exception"
-overgeneral-exceptions=Exception
+# "BaseException, Exception".
+overgeneral-exceptions=BaseException,
+                       Exception