Commits

Anonymous committed dbd3b6d

Add a new warning, 'boolean-datetime', emitted when an instance of 'datetime.time' is used in a boolean context. Closes issue #239.

Comments (0)

Files changed (4)

 
     * Order of reporting is consistent.
 
+    * Add a new warning, 'boolean-datetime', emitted when an instance
+      of 'datetime.time' is used in a boolean context. Closes issue #239.
+
 
 2014-07-26  --  1.3.0
 

checkers/stdlib.py

 import sys
 
 import astroid
+from astroid.bases import Instance
 
 from pylint.interfaces import IAstroidChecker
 from pylint.checkers import BaseChecker
                   'bad-open-mode',
                   'Python supports: r, w, a modes with b, +, and U options. '
                   'See http://docs.python.org/2/library/functions.html#open'),
+        'W1502': ('Using datetime.time in a boolean context.',
+                  'boolean-datetime',
+                  'Using datetetime.time in a boolean context can hide '
+                  'subtle bugs when the time they represent matches '
+                  'midnight UTC. This behaviour was fixed in Python 3.5. '
+                  'See http://bugs.python.org/issue13936 for reference.'),
         }
 
     @utils.check_messages('bad-open-mode')
                 if getattr(node.func, 'name', None) in ('open', 'file'):
                     self._check_open_mode(node)
 
+    @utils.check_messages('boolean-datetime')
+    def visit_unaryop(self, node):
+        if node.op == 'not':
+            self._check_datetime(node.operand)
+
+    @utils.check_messages('boolean-datetime')
+    def visit_if(self, node):
+        self._check_datetime(node.test)
+
+    @utils.check_messages('boolean-datetime')
+    def visit_ifexp(self, node):
+        self._check_datetime(node.test)
+
+    @utils.check_messages('boolean-datetime')
+    def visit_boolop(self, node):
+        for value in node.values:
+            self._check_datetime(value)
+
+    def _check_datetime(self, node):
+        """ Check that a datetime was infered.
+        If so, emit boolean-datetime warning.
+        """
+        try:
+            infered = next(node.infer())
+        except astroid.InferenceError:
+            return
+        if (isinstance(infered, Instance) and
+                infered.qname() == 'datetime.time'):
+            self.add_message('boolean-datetime', node=node)
+
     def _check_open_mode(self, node):
         """Check that the mode argument of an open or file call is valid."""
         try:

test/functional/boolean_datetime.py

+""" Checks for boolean uses of datetime.time. """
+
+import datetime
+
+if datetime.time(0, 0, 0): # [boolean-datetime]
+    print("datetime.time(0,0,0) is not a bug!")
+else:
+    print("datetime.time(0,0,0) is a bug!")
+
+if not datetime.time(0, 0, 1): # [boolean-datetime]
+    print("datetime.time(0,0,1) is not a bug!")
+else:
+    print("datetime.time(0,0,1) is a bug!")
+
+DATA = not datetime.time(0, 0, 0) # [boolean-datetime]
+DATA = True if datetime.time(0, 0, 0) else False # [boolean-datetime]
+DATA = datetime.time(0, 0, 0) or True # [boolean-datetime]
+DATA = datetime.time(0, 0, 0) and True # [boolean-datetime]
+DATA = False or True or datetime.time(0, 0, 0) # [boolean-datetime]
+DATA = False and datetime.time(0, 0, 0) or True # [boolean-datetime]
+
+
+def cant_infer(data):
+    """ Can't infer what data is """
+    hophop = not data
+    troptrop = True if data else False
+    toptop = data or True
+    return hophop, troptrop, toptop
+
+cant_infer(datetime.time(0, 0, 0))

test/functional/boolean_datetime.txt

+boolean-datetime:5::Using datetime.time in a boolean context.
+boolean-datetime:10::Using datetime.time in a boolean context.
+boolean-datetime:15::Using datetime.time in a boolean context.
+boolean-datetime:16::Using datetime.time in a boolean context.
+boolean-datetime:17::Using datetime.time in a boolean context.
+boolean-datetime:18::Using datetime.time in a boolean context.
+boolean-datetime:19::Using datetime.time in a boolean context.
+boolean-datetime:20::Using datetime.time in a boolean context.