We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
minor fix for influxdb
- fix documenation for CaptureBuildDurationAllBuilders
- fix when influxdb python is not installed. 

```
2016-03-16 11:08:01+0100 [-] error while parsing config file:
    Traceback (most recent call last):
      File "/home/xdelannoy/Projects/prototype/env/local/lib/python2.7/site-packages/Twisted-15.5.0-py2.7-linux-x86_64.egg/twisted/python/threadpool.py", line 246, in inContext
        result = inContext.theWork()
      File "/home/xdelannoy/Projects/prototype/env/local/lib/python2.7/site-packages/Twisted-15.5.0-py2.7-linux-x86_64.egg/twisted/python/threadpool.py", line 262, in <lambda>
        inContext.theWork = lambda: context.call(ctx, func, *args, **kw)
      File "/home/xdelannoy/Projects/prototype/env/local/lib/python2.7/site-packages/Twisted-15.5.0-py2.7-linux-x86_64.egg/twisted/python/context.py", line 118, in callWithContext
        return self.currentContext().callWithContext(ctx, func, *args, **kw)
      File "/home/xdelannoy/Projects/prototype/env/local/lib/python2.7/site-packages/Twisted-15.5.0-py2.7-linux-x86_64.egg/twisted/python/context.py", line 81, in callWithContext
        return func(*args,**kw)
    --- <exception caught here> ---
      File "/home/xdelannoy/Projects/myGitHub/buildbot-work/src/master/buildbot/config.py", line 204, in loadConfig
        exec(f, localDict)
      File "/home/xdelannoy/Projects/prototype/basedir/master.cfg", line 10, in <module>
        from config import services
      File "config/services.py", line 24, in <module>
        InfluxStorageService('localhost', 8086, 'root', 'root', 'test', captures)
      File "/home/xdelannoy/Projects/myGitHub/buildbot-work/src/master/buildbot/statistics/storage_backends/influxdb_client.py", line 46, in __init__
        self.password, self.db)
    exceptions.TypeError: 'NoneType' object is not callable
```


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `master/buildbot/steps/python.py`
Content:
```
1 # This file is part of Buildbot.  Buildbot is free software: you can
2 # redistribute it and/or modify it under the terms of the GNU General Public
3 # License as published by the Free Software Foundation, version 2.
4 #
5 # This program is distributed in the hope that it will be useful, but WITHOUT
6 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
7 # FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
8 # details.
9 #
10 # You should have received a copy of the GNU General Public License along with
11 # this program; if not, write to the Free Software Foundation, Inc., 51
12 # Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
13 #
14 # Copyright Buildbot Team Members
15 
16 
17 from buildbot.status.results import SUCCESS, FAILURE, WARNINGS
18 from buildbot.steps.shell import ShellCommand
19 import re
20 
21 try:
22     import cStringIO
23     StringIO = cStringIO.StringIO
24 except ImportError:
25     from StringIO import StringIO
26 
27 
28 class BuildEPYDoc(ShellCommand):
29     name = "epydoc"
30     command = ["make", "epydocs"]
31     description = ["building", "epydocs"]
32     descriptionDone = ["epydoc"]
33 
34     def createSummary(self, log):
35         import_errors = 0
36         warnings = 0
37         errors = 0
38 
39         for line in StringIO(log.getText()):
40             if line.startswith("Error importing "):
41                 import_errors += 1
42             if line.find("Warning: ") != -1:
43                 warnings += 1
44             if line.find("Error: ") != -1:
45                 errors += 1
46 
47         self.descriptionDone = self.descriptionDone[:]
48         if import_errors:
49             self.descriptionDone.append("ierr=%d" % import_errors)
50         if warnings:
51             self.descriptionDone.append("warn=%d" % warnings)
52         if errors:
53             self.descriptionDone.append("err=%d" % errors)
54 
55         self.import_errors = import_errors
56         self.warnings = warnings
57         self.errors = errors
58 
59     def evaluateCommand(self, cmd):
60         if cmd.rc != 0:
61             return FAILURE
62         if self.warnings or self.errors:
63             return WARNINGS
64         return SUCCESS
65 
66 
67 class PyFlakes(ShellCommand):
68     name = "pyflakes"
69     command = ["make", "pyflakes"]
70     description = ["running", "pyflakes"]
71     descriptionDone = ["pyflakes"]
72     flunkOnFailure = False
73     flunkingIssues = ["undefined"] # any pyflakes lines like this cause FAILURE
74 
75     MESSAGES = ("unused", "undefined", "redefs", "import*", "misc")
76 
77     def createSummary(self, log):
78         counts = {}
79         summaries = {}
80         for m in self.MESSAGES:
81             counts[m] = 0
82             summaries[m] = []
83 
84         first = True
85         for line in StringIO(log.getText()).readlines():
86             # the first few lines might contain echoed commands from a 'make
87             # pyflakes' step, so don't count these as warnings. Stop ignoring
88             # the initial lines as soon as we see one with a colon.
89             if first:
90                 if line.find(":") != -1:
91                     # there's the colon, this is the first real line
92                     first = False
93                     # fall through and parse the line
94                 else:
95                     # skip this line, keep skipping non-colon lines
96                     continue
97             if line.find("imported but unused") != -1:
98                 m = "unused"
99             elif line.find("*' used; unable to detect undefined names") != -1:
100                 m = "import*"
101             elif line.find("undefined name") != -1:
102                 m = "undefined"
103             elif line.find("redefinition of unused") != -1:
104                 m = "redefs"
105             else:
106                 m = "misc"
107             summaries[m].append(line)
108             counts[m] += 1
109 
110         self.descriptionDone = self.descriptionDone[:]
111         for m in self.MESSAGES:
112             if counts[m]:
113                 self.descriptionDone.append("%s=%d" % (m, counts[m]))
114                 self.addCompleteLog(m, "".join(summaries[m]))
115             self.setProperty("pyflakes-%s" % m, counts[m], "pyflakes")
116         self.setProperty("pyflakes-total", sum(counts.values()), "pyflakes")
117 
118 
119     def evaluateCommand(self, cmd):
120         if cmd.rc != 0:
121             return FAILURE
122         for m in self.flunkingIssues:
123             if self.getProperty("pyflakes-%s" % m):
124                 return FAILURE
125         if self.getProperty("pyflakes-total"):
126             return WARNINGS
127         return SUCCESS
128 
129 class PyLint(ShellCommand):
130     '''A command that knows about pylint output.
131     It's a good idea to add --output-format=parseable to your
132     command, since it includes the filename in the message.
133     '''
134     name = "pylint"
135     description = ["running", "pylint"]
136     descriptionDone = ["pylint"]
137 
138     # pylint's return codes (see pylint(1) for details)
139     # 1 - 16 will be bit-ORed
140 
141     RC_OK = 0
142     RC_FATAL = 1
143     RC_ERROR = 2
144     RC_WARNING = 4
145     RC_REFACTOR = 8
146     RC_CONVENTION = 16
147     RC_USAGE = 32
148 
149     # Using the default text output, the message format is :
150     # MESSAGE_TYPE: LINE_NUM:[OBJECT:] MESSAGE
151     # with --output-format=parseable it is: (the outer brackets are literal)
152     # FILE_NAME:LINE_NUM: [MESSAGE_TYPE[, OBJECT]] MESSAGE
153     # message type consists of the type char and 4 digits
154     # The message types:
155 
156     MESSAGES = {
157             'C': "convention", # for programming standard violation
158             'R': "refactor", # for bad code smell
159             'W': "warning", # for python specific problems
160             'E': "error", # for much probably bugs in the code
161             'F': "fatal", # error prevented pylint from further processing.
162             'I': "info",
163         }
164 
165     flunkingIssues = ["F", "E"] # msg categories that cause FAILURE
166 
167     _re_groupname = 'errtype'
168     _msgtypes_re_str = '(?P<%s>[%s])' % (_re_groupname, ''.join(MESSAGES.keys()))
169     _default_line_re = re.compile(r'^%s: *\d+:.+' % _msgtypes_re_str)
170     _parseable_line_re = re.compile(r'[^:]+:\d+: \[%s[,\]] .+' % _msgtypes_re_str)
171 
172     def createSummary(self, log):
173         counts = {}
174         summaries = {}
175         for m in self.MESSAGES:
176             counts[m] = 0
177             summaries[m] = []
178 
179         line_re = None # decide after first match
180         for line in StringIO(log.getText()).readlines():
181             if not line_re:
182                 # need to test both and then decide on one
183                 if self._parseable_line_re.match(line):
184                     line_re = self._parseable_line_re
185                 elif self._default_line_re.match(line):
186                     line_re = self._default_line_re
187                 else: # no match yet
188                     continue
189             mo = line_re.match(line)
190             if mo:
191                 msgtype = mo.group(self._re_groupname)
192                 assert msgtype in self.MESSAGES
193             summaries[msgtype].append(line)
194             counts[msgtype] += 1
195 
196         self.descriptionDone = self.descriptionDone[:]
197         for msg, fullmsg in self.MESSAGES.items():
198             if counts[msg]:
199                 self.descriptionDone.append("%s=%d" % (fullmsg, counts[msg]))
200                 self.addCompleteLog(fullmsg, "".join(summaries[msg]))
201             self.setProperty("pylint-%s" % fullmsg, counts[msg])
202         self.setProperty("pylint-total", sum(counts.values()))
203 
204     def evaluateCommand(self, cmd):
205         if cmd.rc & (self.RC_FATAL|self.RC_ERROR|self.RC_USAGE):
206             return FAILURE
207         for msg in self.flunkingIssues:
208             if self.getProperty("pylint-%s" % self.MESSAGES[msg]):
209                 return FAILURE
210         if self.getProperty("pylint-total"):
211             return WARNINGS
212         return SUCCESS
213 
214
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/master/buildbot/steps/python.py b/master/buildbot/steps/python.py
--- a/master/buildbot/steps/python.py
+++ b/master/buildbot/steps/python.py
@@ -166,8 +166,8 @@
 
     _re_groupname = 'errtype'
     _msgtypes_re_str = '(?P<%s>[%s])' % (_re_groupname, ''.join(MESSAGES.keys()))
-    _default_line_re = re.compile(r'^%s: *\d+:.+' % _msgtypes_re_str)
-    _parseable_line_re = re.compile(r'[^:]+:\d+: \[%s[,\]] .+' % _msgtypes_re_str)
+    _default_line_re = re.compile(r'^%s(\d{4})?: *\d+(,\d+)?:.+' % _msgtypes_re_str)
+    _parseable_line_re = re.compile(r'[^:]+:\d+: \[%s(\d{4})?[,\]] .+' % _msgtypes_re_str)
 
     def createSummary(self, log):
         counts = {}

{"golden_diff": "diff --git a/master/buildbot/steps/python.py b/master/buildbot/steps/python.py\n--- a/master/buildbot/steps/python.py\n+++ b/master/buildbot/steps/python.py\n@@ -166,8 +166,8 @@\n \n     _re_groupname = 'errtype'\n     _msgtypes_re_str = '(?P<%s>[%s])' % (_re_groupname, ''.join(MESSAGES.keys()))\n-    _default_line_re = re.compile(r'^%s: *\\d+:.+' % _msgtypes_re_str)\n-    _parseable_line_re = re.compile(r'[^:]+:\\d+: \\[%s[,\\]] .+' % _msgtypes_re_str)\n+    _default_line_re = re.compile(r'^%s(\\d{4})?: *\\d+(,\\d+)?:.+' % _msgtypes_re_str)\n+    _parseable_line_re = re.compile(r'[^:]+:\\d+: \\[%s(\\d{4})?[,\\]] .+' % _msgtypes_re_str)\n \n     def createSummary(self, log):\n         counts = {}\n", "issue": "minor fix for influxdb\n- fix documenation for CaptureBuildDurationAllBuilders\n- fix when influxdb python is not installed. \n\n```\n2016-03-16 11:08:01+0100 [-] error while parsing config file:\n    Traceback (most recent call last):\n      File \"/home/xdelannoy/Projects/prototype/env/local/lib/python2.7/site-packages/Twisted-15.5.0-py2.7-linux-x86_64.egg/twisted/python/threadpool.py\", line 246, in inContext\n        result = inContext.theWork()\n      File \"/home/xdelannoy/Projects/prototype/env/local/lib/python2.7/site-packages/Twisted-15.5.0-py2.7-linux-x86_64.egg/twisted/python/threadpool.py\", line 262, in <lambda>\n        inContext.theWork = lambda: context.call(ctx, func, *args, **kw)\n      File \"/home/xdelannoy/Projects/prototype/env/local/lib/python2.7/site-packages/Twisted-15.5.0-py2.7-linux-x86_64.egg/twisted/python/context.py\", line 118, in callWithContext\n        return self.currentContext().callWithContext(ctx, func, *args, **kw)\n      File \"/home/xdelannoy/Projects/prototype/env/local/lib/python2.7/site-packages/Twisted-15.5.0-py2.7-linux-x86_64.egg/twisted/python/context.py\", line 81, in callWithContext\n        return func(*args,**kw)\n    --- <exception caught here> ---\n      File \"/home/xdelannoy/Projects/myGitHub/buildbot-work/src/master/buildbot/config.py\", line 204, in loadConfig\n        exec(f, localDict)\n      File \"/home/xdelannoy/Projects/prototype/basedir/master.cfg\", line 10, in <module>\n        from config import services\n      File \"config/services.py\", line 24, in <module>\n        InfluxStorageService('localhost', 8086, 'root', 'root', 'test', captures)\n      File \"/home/xdelannoy/Projects/myGitHub/buildbot-work/src/master/buildbot/statistics/storage_backends/influxdb_client.py\", line 46, in __init__\n        self.password, self.db)\n    exceptions.TypeError: 'NoneType' object is not callable\n```\n\n", "before_files": [{"content": "# This file is part of Buildbot.  Buildbot is free software: you can\n# redistribute it and/or modify it under the terms of the GNU General Public\n# License as published by the Free Software Foundation, version 2.\n#\n# This program is distributed in the hope that it will be useful, but WITHOUT\n# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS\n# FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more\n# details.\n#\n# You should have received a copy of the GNU General Public License along with\n# this program; if not, write to the Free Software Foundation, Inc., 51\n# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n#\n# Copyright Buildbot Team Members\n\n\nfrom buildbot.status.results import SUCCESS, FAILURE, WARNINGS\nfrom buildbot.steps.shell import ShellCommand\nimport re\n\ntry:\n    import cStringIO\n    StringIO = cStringIO.StringIO\nexcept ImportError:\n    from StringIO import StringIO\n\n\nclass BuildEPYDoc(ShellCommand):\n    name = \"epydoc\"\n    command = [\"make\", \"epydocs\"]\n    description = [\"building\", \"epydocs\"]\n    descriptionDone = [\"epydoc\"]\n\n    def createSummary(self, log):\n        import_errors = 0\n        warnings = 0\n        errors = 0\n\n        for line in StringIO(log.getText()):\n            if line.startswith(\"Error importing \"):\n                import_errors += 1\n            if line.find(\"Warning: \") != -1:\n                warnings += 1\n            if line.find(\"Error: \") != -1:\n                errors += 1\n\n        self.descriptionDone = self.descriptionDone[:]\n        if import_errors:\n            self.descriptionDone.append(\"ierr=%d\" % import_errors)\n        if warnings:\n            self.descriptionDone.append(\"warn=%d\" % warnings)\n        if errors:\n            self.descriptionDone.append(\"err=%d\" % errors)\n\n        self.import_errors = import_errors\n        self.warnings = warnings\n        self.errors = errors\n\n    def evaluateCommand(self, cmd):\n        if cmd.rc != 0:\n            return FAILURE\n        if self.warnings or self.errors:\n            return WARNINGS\n        return SUCCESS\n\n\nclass PyFlakes(ShellCommand):\n    name = \"pyflakes\"\n    command = [\"make\", \"pyflakes\"]\n    description = [\"running\", \"pyflakes\"]\n    descriptionDone = [\"pyflakes\"]\n    flunkOnFailure = False\n    flunkingIssues = [\"undefined\"] # any pyflakes lines like this cause FAILURE\n\n    MESSAGES = (\"unused\", \"undefined\", \"redefs\", \"import*\", \"misc\")\n\n    def createSummary(self, log):\n        counts = {}\n        summaries = {}\n        for m in self.MESSAGES:\n            counts[m] = 0\n            summaries[m] = []\n\n        first = True\n        for line in StringIO(log.getText()).readlines():\n            # the first few lines might contain echoed commands from a 'make\n            # pyflakes' step, so don't count these as warnings. Stop ignoring\n            # the initial lines as soon as we see one with a colon.\n            if first:\n                if line.find(\":\") != -1:\n                    # there's the colon, this is the first real line\n                    first = False\n                    # fall through and parse the line\n                else:\n                    # skip this line, keep skipping non-colon lines\n                    continue\n            if line.find(\"imported but unused\") != -1:\n                m = \"unused\"\n            elif line.find(\"*' used; unable to detect undefined names\") != -1:\n                m = \"import*\"\n            elif line.find(\"undefined name\") != -1:\n                m = \"undefined\"\n            elif line.find(\"redefinition of unused\") != -1:\n                m = \"redefs\"\n            else:\n                m = \"misc\"\n            summaries[m].append(line)\n            counts[m] += 1\n\n        self.descriptionDone = self.descriptionDone[:]\n        for m in self.MESSAGES:\n            if counts[m]:\n                self.descriptionDone.append(\"%s=%d\" % (m, counts[m]))\n                self.addCompleteLog(m, \"\".join(summaries[m]))\n            self.setProperty(\"pyflakes-%s\" % m, counts[m], \"pyflakes\")\n        self.setProperty(\"pyflakes-total\", sum(counts.values()), \"pyflakes\")\n\n\n    def evaluateCommand(self, cmd):\n        if cmd.rc != 0:\n            return FAILURE\n        for m in self.flunkingIssues:\n            if self.getProperty(\"pyflakes-%s\" % m):\n                return FAILURE\n        if self.getProperty(\"pyflakes-total\"):\n            return WARNINGS\n        return SUCCESS\n\nclass PyLint(ShellCommand):\n    '''A command that knows about pylint output.\n    It's a good idea to add --output-format=parseable to your\n    command, since it includes the filename in the message.\n    '''\n    name = \"pylint\"\n    description = [\"running\", \"pylint\"]\n    descriptionDone = [\"pylint\"]\n\n    # pylint's return codes (see pylint(1) for details)\n    # 1 - 16 will be bit-ORed\n\n    RC_OK = 0\n    RC_FATAL = 1\n    RC_ERROR = 2\n    RC_WARNING = 4\n    RC_REFACTOR = 8\n    RC_CONVENTION = 16\n    RC_USAGE = 32\n\n    # Using the default text output, the message format is :\n    # MESSAGE_TYPE: LINE_NUM:[OBJECT:] MESSAGE\n    # with --output-format=parseable it is: (the outer brackets are literal)\n    # FILE_NAME:LINE_NUM: [MESSAGE_TYPE[, OBJECT]] MESSAGE\n    # message type consists of the type char and 4 digits\n    # The message types:\n\n    MESSAGES = {\n            'C': \"convention\", # for programming standard violation\n            'R': \"refactor\", # for bad code smell\n            'W': \"warning\", # for python specific problems\n            'E': \"error\", # for much probably bugs in the code\n            'F': \"fatal\", # error prevented pylint from further processing.\n            'I': \"info\",\n        }\n\n    flunkingIssues = [\"F\", \"E\"] # msg categories that cause FAILURE\n\n    _re_groupname = 'errtype'\n    _msgtypes_re_str = '(?P<%s>[%s])' % (_re_groupname, ''.join(MESSAGES.keys()))\n    _default_line_re = re.compile(r'^%s: *\\d+:.+' % _msgtypes_re_str)\n    _parseable_line_re = re.compile(r'[^:]+:\\d+: \\[%s[,\\]] .+' % _msgtypes_re_str)\n\n    def createSummary(self, log):\n        counts = {}\n        summaries = {}\n        for m in self.MESSAGES:\n            counts[m] = 0\n            summaries[m] = []\n\n        line_re = None # decide after first match\n        for line in StringIO(log.getText()).readlines():\n            if not line_re:\n                # need to test both and then decide on one\n                if self._parseable_line_re.match(line):\n                    line_re = self._parseable_line_re\n                elif self._default_line_re.match(line):\n                    line_re = self._default_line_re\n                else: # no match yet\n                    continue\n            mo = line_re.match(line)\n            if mo:\n                msgtype = mo.group(self._re_groupname)\n                assert msgtype in self.MESSAGES\n            summaries[msgtype].append(line)\n            counts[msgtype] += 1\n\n        self.descriptionDone = self.descriptionDone[:]\n        for msg, fullmsg in self.MESSAGES.items():\n            if counts[msg]:\n                self.descriptionDone.append(\"%s=%d\" % (fullmsg, counts[msg]))\n                self.addCompleteLog(fullmsg, \"\".join(summaries[msg]))\n            self.setProperty(\"pylint-%s\" % fullmsg, counts[msg])\n        self.setProperty(\"pylint-total\", sum(counts.values()))\n\n    def evaluateCommand(self, cmd):\n        if cmd.rc & (self.RC_FATAL|self.RC_ERROR|self.RC_USAGE):\n            return FAILURE\n        for msg in self.flunkingIssues:\n            if self.getProperty(\"pylint-%s\" % self.MESSAGES[msg]):\n                return FAILURE\n        if self.getProperty(\"pylint-total\"):\n            return WARNINGS\n        return SUCCESS\n\n", "path": "master/buildbot/steps/python.py"}], "after_files": [{"content": "# This file is part of Buildbot.  Buildbot is free software: you can\n# redistribute it and/or modify it under the terms of the GNU General Public\n# License as published by the Free Software Foundation, version 2.\n#\n# This program is distributed in the hope that it will be useful, but WITHOUT\n# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS\n# FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more\n# details.\n#\n# You should have received a copy of the GNU General Public License along with\n# this program; if not, write to the Free Software Foundation, Inc., 51\n# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n#\n# Copyright Buildbot Team Members\n\n\nfrom buildbot.status.results import SUCCESS, FAILURE, WARNINGS\nfrom buildbot.steps.shell import ShellCommand\nimport re\n\ntry:\n    import cStringIO\n    StringIO = cStringIO.StringIO\nexcept ImportError:\n    from StringIO import StringIO\n\n\nclass BuildEPYDoc(ShellCommand):\n    name = \"epydoc\"\n    command = [\"make\", \"epydocs\"]\n    description = [\"building\", \"epydocs\"]\n    descriptionDone = [\"epydoc\"]\n\n    def createSummary(self, log):\n        import_errors = 0\n        warnings = 0\n        errors = 0\n\n        for line in StringIO(log.getText()):\n            if line.startswith(\"Error importing \"):\n                import_errors += 1\n            if line.find(\"Warning: \") != -1:\n                warnings += 1\n            if line.find(\"Error: \") != -1:\n                errors += 1\n\n        self.descriptionDone = self.descriptionDone[:]\n        if import_errors:\n            self.descriptionDone.append(\"ierr=%d\" % import_errors)\n        if warnings:\n            self.descriptionDone.append(\"warn=%d\" % warnings)\n        if errors:\n            self.descriptionDone.append(\"err=%d\" % errors)\n\n        self.import_errors = import_errors\n        self.warnings = warnings\n        self.errors = errors\n\n    def evaluateCommand(self, cmd):\n        if cmd.rc != 0:\n            return FAILURE\n        if self.warnings or self.errors:\n            return WARNINGS\n        return SUCCESS\n\n\nclass PyFlakes(ShellCommand):\n    name = \"pyflakes\"\n    command = [\"make\", \"pyflakes\"]\n    description = [\"running\", \"pyflakes\"]\n    descriptionDone = [\"pyflakes\"]\n    flunkOnFailure = False\n    flunkingIssues = [\"undefined\"] # any pyflakes lines like this cause FAILURE\n\n    MESSAGES = (\"unused\", \"undefined\", \"redefs\", \"import*\", \"misc\")\n\n    def createSummary(self, log):\n        counts = {}\n        summaries = {}\n        for m in self.MESSAGES:\n            counts[m] = 0\n            summaries[m] = []\n\n        first = True\n        for line in StringIO(log.getText()).readlines():\n            # the first few lines might contain echoed commands from a 'make\n            # pyflakes' step, so don't count these as warnings. Stop ignoring\n            # the initial lines as soon as we see one with a colon.\n            if first:\n                if line.find(\":\") != -1:\n                    # there's the colon, this is the first real line\n                    first = False\n                    # fall through and parse the line\n                else:\n                    # skip this line, keep skipping non-colon lines\n                    continue\n            if line.find(\"imported but unused\") != -1:\n                m = \"unused\"\n            elif line.find(\"*' used; unable to detect undefined names\") != -1:\n                m = \"import*\"\n            elif line.find(\"undefined name\") != -1:\n                m = \"undefined\"\n            elif line.find(\"redefinition of unused\") != -1:\n                m = \"redefs\"\n            else:\n                m = \"misc\"\n            summaries[m].append(line)\n            counts[m] += 1\n\n        self.descriptionDone = self.descriptionDone[:]\n        for m in self.MESSAGES:\n            if counts[m]:\n                self.descriptionDone.append(\"%s=%d\" % (m, counts[m]))\n                self.addCompleteLog(m, \"\".join(summaries[m]))\n            self.setProperty(\"pyflakes-%s\" % m, counts[m], \"pyflakes\")\n        self.setProperty(\"pyflakes-total\", sum(counts.values()), \"pyflakes\")\n\n\n    def evaluateCommand(self, cmd):\n        if cmd.rc != 0:\n            return FAILURE\n        for m in self.flunkingIssues:\n            if self.getProperty(\"pyflakes-%s\" % m):\n                return FAILURE\n        if self.getProperty(\"pyflakes-total\"):\n            return WARNINGS\n        return SUCCESS\n\nclass PyLint(ShellCommand):\n    '''A command that knows about pylint output.\n    It's a good idea to add --output-format=parseable to your\n    command, since it includes the filename in the message.\n    '''\n    name = \"pylint\"\n    description = [\"running\", \"pylint\"]\n    descriptionDone = [\"pylint\"]\n\n    # pylint's return codes (see pylint(1) for details)\n    # 1 - 16 will be bit-ORed\n\n    RC_OK = 0\n    RC_FATAL = 1\n    RC_ERROR = 2\n    RC_WARNING = 4\n    RC_REFACTOR = 8\n    RC_CONVENTION = 16\n    RC_USAGE = 32\n\n    # Using the default text output, the message format is :\n    # MESSAGE_TYPE: LINE_NUM:[OBJECT:] MESSAGE\n    # with --output-format=parseable it is: (the outer brackets are literal)\n    # FILE_NAME:LINE_NUM: [MESSAGE_TYPE[, OBJECT]] MESSAGE\n    # message type consists of the type char and 4 digits\n    # The message types:\n\n    MESSAGES = {\n            'C': \"convention\", # for programming standard violation\n            'R': \"refactor\", # for bad code smell\n            'W': \"warning\", # for python specific problems\n            'E': \"error\", # for much probably bugs in the code\n            'F': \"fatal\", # error prevented pylint from further processing.\n            'I': \"info\",\n        }\n\n    flunkingIssues = [\"F\", \"E\"] # msg categories that cause FAILURE\n\n    _re_groupname = 'errtype'\n    _msgtypes_re_str = '(?P<%s>[%s])' % (_re_groupname, ''.join(MESSAGES.keys()))\n    _default_line_re = re.compile(r'^%s(\\d{4})?: *\\d+(,\\d+)?:.+' % _msgtypes_re_str)\n    _parseable_line_re = re.compile(r'[^:]+:\\d+: \\[%s(\\d{4})?[,\\]] .+' % _msgtypes_re_str)\n\n    def createSummary(self, log):\n        counts = {}\n        summaries = {}\n        for m in self.MESSAGES:\n            counts[m] = 0\n            summaries[m] = []\n\n        line_re = None # decide after first match\n        for line in StringIO(log.getText()).readlines():\n            if not line_re:\n                # need to test both and then decide on one\n                if self._parseable_line_re.match(line):\n                    line_re = self._parseable_line_re\n                elif self._default_line_re.match(line):\n                    line_re = self._default_line_re\n                else: # no match yet\n                    continue\n            mo = line_re.match(line)\n            if mo:\n                msgtype = mo.group(self._re_groupname)\n                assert msgtype in self.MESSAGES\n            summaries[msgtype].append(line)\n            counts[msgtype] += 1\n\n        self.descriptionDone = self.descriptionDone[:]\n        for msg, fullmsg in self.MESSAGES.items():\n            if counts[msg]:\n                self.descriptionDone.append(\"%s=%d\" % (fullmsg, counts[msg]))\n                self.addCompleteLog(fullmsg, \"\".join(summaries[msg]))\n            self.setProperty(\"pylint-%s\" % fullmsg, counts[msg])\n        self.setProperty(\"pylint-total\", sum(counts.values()))\n\n    def evaluateCommand(self, cmd):\n        if cmd.rc & (self.RC_FATAL|self.RC_ERROR|self.RC_USAGE):\n            return FAILURE\n        for msg in self.flunkingIssues:\n            if self.getProperty(\"pylint-%s\" % self.MESSAGES[msg]):\n                return FAILURE\n        if self.getProperty(\"pylint-total\"):\n            return WARNINGS\n        return SUCCESS\n\n", "path": "master/buildbot/steps/python.py"}]}