Merge lp:~jaypipes/nova/pylint into lp:~hudson-openstack/nova/trunk

Proposed by Jay Pipes
Status: Merged
Approved by: Eric Day
Approved revision: 216
Merge reported by: OpenStack Infra
Merged at revision: not available
Proposed branch: lp:~jaypipes/nova/pylint
Merge into: lp:~hudson-openstack/nova/trunk
Diff against target: 330 lines (+74/-58)
3 files modified
nova/server.py (+11/-11)
nova/test.py (+53/-47)
pylintrc (+10/-0)
To merge this branch: bzr merge lp:~jaypipes/nova/pylint
Reviewer Review Type Date Requested Status
Eric Day (community) Approve
Monty Taylor Pending
Review via email: mp+32106@code.launchpad.net

Commit message

pylint fixes for /nova/test.py

Description of the change

pylint fixes for /nova/test.py

To post a comment you must log in.
Revision history for this message
Eric Day (eday) wrote :

Looks good! Just one thing... the disables at the top of the file. I would rather see them localized for a specific line (ie, one method name that can't change due to base names or something), or a global pylintrc rule. Can you give more info on the two disable msgs at the top?

review: Needs Fixing
Revision history for this message
Jay Pipes (jaypipes) wrote :

> Looks good! Just one thing... the disables at the top of the file. I would
> rather see them localized for a specific line (ie, one method name that can't
> change due to base names or something), or a global pylintrc rule. Can you
> give more info on the two disable msgs at the top?

Sure. :)

The C0103 is for non-conventional variable names. python's (and twisted's Trials) unittest module uses methods names that don't jive with our standards. Namely, they use camelCasing instead of underscore_lowered names because of its genesis from JUnit.

The W0511 is generated every time a TODO(xxx) is placed in code comments. We have these all over the place, and I suggest putting it in the global pylintrc file.

Thoughts?

-jay

Revision history for this message
Eric Day (eday) wrote :

For the camelCase methods, I was just disabling them on the line they appear on to make sure other cases get caught/fixed:

    def setUp(self): # pylint: disable-msg=C0103

I was leaving all the TODO() messages in there for now since those are valid that pylint can report for us. We can always disable those globally in pylintrc as you mention if we decide pylint isn't the best place to report them.

Revision history for this message
Jay Pipes (jaypipes) wrote :

> For the camelCase methods, I was just disabling them on the line they appear
> on to make sure other cases get caught/fixed:
>
> def setUp(self): # pylint: disable-msg=C0103

Done

> I was leaving all the TODO() messages in there for now since those are valid
> that pylint can report for us. We can always disable those globally in
> pylintrc as you mention if we decide pylint isn't the best place to report
> them.

I'd prefer to disable them and then to run a report, just do --enable-msg=R0511 on the command line.

-jay

Revision history for this message
Eric Day (eday) wrote :

Looks good! I like the idea of running reports separately as needed for TODOs. I've been changing the one-char variable names to conform to be more verbose, but I guess there are cases where we want to allow this. It should be avoided though for clarity.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'nova/server.py'
2--- nova/server.py 2010-07-15 23:13:48 +0000
3+++ nova/server.py 2010-08-09 16:39:45 +0000
4@@ -52,13 +52,8 @@
5 """
6 # Get the pid from the pidfile
7 try:
8- pf = file(pidfile,'r')
9- pid = int(pf.read().strip())
10- pf.close()
11+ pid = int(open(pidfile,'r').read().strip())
12 except IOError:
13- pid = None
14-
15- if not pid:
16 message = "pidfile %s does not exist. Daemon not running?\n"
17 sys.stderr.write(message % pidfile)
18 return # not an error in a restart
19@@ -79,14 +74,15 @@
20
21
22 def serve(name, main):
23+ """Controller for server"""
24 argv = FLAGS(sys.argv)
25
26 if not FLAGS.pidfile:
27 FLAGS.pidfile = '%s.pid' % name
28
29- logging.debug("Full set of FLAGS: \n\n\n" )
30+ logging.debug("Full set of FLAGS: \n\n\n")
31 for flag in FLAGS:
32- logging.debug("%s : %s" % (flag, FLAGS.get(flag, None) ))
33+ logging.debug("%s : %s", flag, FLAGS.get(flag, None))
34
35 action = 'start'
36 if len(argv) > 1:
37@@ -102,7 +98,11 @@
38 else:
39 print 'usage: %s [options] [start|stop|restart]' % argv[0]
40 sys.exit(1)
41-
42+ daemonize(argv, name, main)
43+
44+
45+def daemonize(args, name, main):
46+ """Does the work of daemonizing the process"""
47 logging.getLogger('amqplib').setLevel(logging.WARN)
48 if FLAGS.daemonize:
49 logger = logging.getLogger()
50@@ -115,7 +115,7 @@
51 else:
52 if not FLAGS.logfile:
53 FLAGS.logfile = '%s.log' % name
54- logfile = logging.handlers.FileHandler(FLAGS.logfile)
55+ logfile = logging.FileHandler(FLAGS.logfile)
56 logfile.setFormatter(formatter)
57 logger.addHandler(logfile)
58 stdin, stdout, stderr = None, None, None
59@@ -137,4 +137,4 @@
60 stdout=stdout,
61 stderr=stderr
62 ):
63- main(argv)
64+ main(args)
65
66=== modified file 'nova/test.py'
67--- nova/test.py 2010-07-23 22:27:18 +0000
68+++ nova/test.py 2010-08-09 16:39:45 +0000
69@@ -22,15 +22,14 @@
70 and some black magic for inline callbacks.
71 """
72
73-import logging
74 import mox
75 import stubout
76+import sys
77 import time
78-import unittest
79+
80 from tornado import ioloop
81 from twisted.internet import defer
82-from twisted.python import failure
83-from twisted.trial import unittest as trial_unittest
84+from twisted.trial import unittest
85
86 from nova import fakerabbit
87 from nova import flags
88@@ -41,20 +40,21 @@
89 'should we use everything for testing')
90
91
92-def skip_if_fake(f):
93+def skip_if_fake(func):
94+ """Decorator that skips a test if running in fake mode"""
95 def _skipper(*args, **kw):
96+ """Wrapped skipper function"""
97 if FLAGS.fake_tests:
98- raise trial_unittest.SkipTest('Test cannot be run in fake mode')
99+ raise unittest.SkipTest('Test cannot be run in fake mode')
100 else:
101- return f(*args, **kw)
102-
103- _skipper.func_name = f.func_name
104+ return func(*args, **kw)
105 return _skipper
106
107
108-class TrialTestCase(trial_unittest.TestCase):
109-
110- def setUp(self):
111+class TrialTestCase(unittest.TestCase):
112+ """Test case base class for all unit tests"""
113+ def setUp(self): # pylint: disable-msg=C0103
114+ """Run before each test method to initialize test environment"""
115 super(TrialTestCase, self).setUp()
116
117 # emulate some of the mox stuff, we can't use the metaclass
118@@ -63,7 +63,8 @@
119 self.stubs = stubout.StubOutForTesting()
120 self.flag_overrides = {}
121
122- def tearDown(self):
123+ def tearDown(self): # pylint: disable-msg=C0103
124+ """Runs after each test method to finalize/tear down test environment"""
125 super(TrialTestCase, self).tearDown()
126 self.reset_flags()
127 self.mox.UnsetStubs()
128@@ -75,6 +76,7 @@
129 fakerabbit.reset_all()
130
131 def flags(self, **kw):
132+ """Override flag variables for a test"""
133 for k, v in kw.iteritems():
134 if k in self.flag_overrides:
135 self.reset_flags()
136@@ -84,13 +86,17 @@
137 setattr(FLAGS, k, v)
138
139 def reset_flags(self):
140+ """Resets all flag variables for the test. Runs after each test"""
141 for k, v in self.flag_overrides.iteritems():
142 setattr(FLAGS, k, v)
143
144
145
146 class BaseTestCase(TrialTestCase):
147- def setUp(self):
148+ # TODO(jaypipes): Can this be moved into the TrialTestCase class?
149+ """Base test case class for all unit tests."""
150+ def setUp(self): # pylint: disable-msg=C0103
151+ """Run before each test method to initialize test environment"""
152 super(BaseTestCase, self).setUp()
153 # TODO(termie): we could possibly keep a more global registry of
154 # the injected listeners... this is fine for now though
155@@ -98,33 +104,27 @@
156 self.ioloop = ioloop.IOLoop.instance()
157
158 self._waiting = None
159- self._doneWaiting = False
160- self._timedOut = False
161- self.set_up()
162-
163- def set_up(self):
164- pass
165-
166- def tear_down(self):
167- pass
168-
169- def tearDown(self):
170+ self._done_waiting = False
171+ self._timed_out = False
172+
173+ def tearDown(self):# pylint: disable-msg=C0103
174+ """Runs after each test method to finalize/tear down test environment"""
175 super(BaseTestCase, self).tearDown()
176 for x in self.injected:
177 x.stop()
178 if FLAGS.fake_rabbit:
179 fakerabbit.reset_all()
180- self.tear_down()
181
182- def _waitForTest(self, timeout=60):
183+ def _wait_for_test(self, timeout=60):
184 """ Push the ioloop along to wait for our test to complete. """
185 self._waiting = self.ioloop.add_timeout(time.time() + timeout,
186 self._timeout)
187 def _wait():
188- if self._timedOut:
189+ """Wrapped wait function. Called on timeout."""
190+ if self._timed_out:
191 self.fail('test timed out')
192 self._done()
193- if self._doneWaiting:
194+ if self._done_waiting:
195 self.ioloop.stop()
196 return
197 # we can use add_callback here but this uses less cpu when testing
198@@ -134,15 +134,18 @@
199 self.ioloop.start()
200
201 def _done(self):
202+ """Callback used for cleaning up deferred test methods."""
203 if self._waiting:
204 try:
205 self.ioloop.remove_timeout(self._waiting)
206- except Exception:
207+ except Exception: # pylint: disable-msg=W0703
208+ # TODO(jaypipes): This produces a pylint warning. Should
209+ # we really be catching Exception and then passing here?
210 pass
211 self._waiting = None
212- self._doneWaiting = True
213+ self._done_waiting = True
214
215- def _maybeInlineCallbacks(self, f):
216+ def _maybe_inline_callbacks(self, func):
217 """ If we're doing async calls in our tests, wait on them.
218
219 This is probably the most complicated hunk of code we have so far.
220@@ -165,7 +168,7 @@
221 d.addCallback(_describe)
222 d.addCallback(_checkDescribe)
223 d.addCallback(lambda x: self._done())
224- self._waitForTest()
225+ self._wait_for_test()
226
227 Example (inline callbacks! yay!):
228
229@@ -179,16 +182,17 @@
230 # TODO(termie): this can be a wrapper function instead and
231 # and we can make a metaclass so that we don't
232 # have to copy all that "run" code below.
233- g = f()
234+ g = func()
235 if not hasattr(g, 'send'):
236 self._done()
237 return defer.succeed(g)
238
239- inlined = defer.inlineCallbacks(f)
240+ inlined = defer.inlineCallbacks(func)
241 d = inlined()
242 return d
243
244- def _catchExceptions(self, result, failure):
245+ def _catch_exceptions(self, result, failure):
246+ """Catches all exceptions and handles keyboard interrupts."""
247 exc = (failure.type, failure.value, failure.getTracebackObject())
248 if isinstance(failure.value, self.failureException):
249 result.addFailure(self, exc)
250@@ -200,44 +204,46 @@
251 self._done()
252
253 def _timeout(self):
254+ """Helper method which trips the timeouts"""
255 self._waiting = False
256- self._timedOut = True
257+ self._timed_out = True
258
259 def run(self, result=None):
260- if result is None: result = self.defaultTestResult()
261+ """Runs the test case"""
262
263 result.startTest(self)
264- testMethod = getattr(self, self._testMethodName)
265+ test_method = getattr(self, self._testMethodName)
266 try:
267 try:
268 self.setUp()
269 except KeyboardInterrupt:
270 raise
271 except:
272- result.addError(self, self._exc_info())
273+ result.addError(self, sys.exc_info())
274 return
275
276 ok = False
277 try:
278- d = self._maybeInlineCallbacks(testMethod)
279- d.addErrback(lambda x: self._catchExceptions(result, x))
280+ d = self._maybe_inline_callbacks(test_method)
281+ d.addErrback(lambda x: self._catch_exceptions(result, x))
282 d.addBoth(lambda x: self._done() and x)
283- self._waitForTest()
284+ self._wait_for_test()
285 ok = True
286 except self.failureException:
287- result.addFailure(self, self._exc_info())
288+ result.addFailure(self, sys.exc_info())
289 except KeyboardInterrupt:
290 raise
291 except:
292- result.addError(self, self._exc_info())
293+ result.addError(self, sys.exc_info())
294
295 try:
296 self.tearDown()
297 except KeyboardInterrupt:
298 raise
299 except:
300- result.addError(self, self._exc_info())
301+ result.addError(self, sys.exc_info())
302 ok = False
303- if ok: result.addSuccess(self)
304+ if ok:
305+ result.addSuccess(self)
306 finally:
307 result.stopTest(self)
308
309=== modified file 'pylintrc'
310--- pylintrc 2010-08-08 02:51:17 +0000
311+++ pylintrc 2010-08-09 16:39:45 +0000
312@@ -2,8 +2,18 @@
313 disable-msg=C0103
314
315 [Basic]
316+# Variables can be 1 to 31 characters long, with
317+# lowercase and underscores
318+variable-rgx=[a-z_][a-z0-9_]{0,30}$
319+
320+# Method names should be at least 3 characters long
321+# and be lowecased with underscores
322 method-rgx=[a-z_][a-z0-9_]{2,50}$
323
324+[MESSAGES CONTROL]
325+# TODOs in code comments are fine...
326+disable-msg=W0511
327+
328 [Design]
329 max-public-methods=100
330 min-public-methods=0