Adds a hacking check looking for Logger.warn usage

Python3 has deprecated Logger.warn in favor of Logger.warning. Let's not
allow Logger.warn to be used in our codebase.

Change-Id: I271662ee8ab5f6843180cbde173aec9135ddb529
Related-Bug: #1530742
This commit is contained in:
David Stanek 2016-01-06 19:13:53 +00:00
parent 624675f694
commit 1bb3e8fa8d
3 changed files with 38 additions and 8 deletions

View File

@ -144,6 +144,7 @@ class CheckForLoggingIssues(BaseASTChecker):
DEBUG_CHECK_DESC = 'K005 Using translated string in debug logging'
NONDEBUG_CHECK_DESC = 'K006 Not using translating helper for logging'
EXCESS_HELPER_CHECK_DESC = 'K007 Using hints when _ is necessary'
USING_DEPRECATED_WARN = 'K009 Using the deprecated Logger.warn'
LOG_MODULES = ('logging', 'oslo_log.log')
I18N_MODULES = (
'keystone.i18n._',
@ -155,7 +156,6 @@ class CheckForLoggingIssues(BaseASTChecker):
TRANS_HELPER_MAP = {
'debug': None,
'info': '_LI',
'warn': '_LW',
'warning': '_LW',
'error': '_LE',
'exception': '_LE',
@ -294,6 +294,11 @@ class CheckForLoggingIssues(BaseASTChecker):
else: # could be Subscript, Call or many more
return super(CheckForLoggingIssues, self).generic_visit(node)
# if dealing with a logger the method can't be "warn"
if obj_name in self.logger_names and method_name == 'warn':
msg = node.args[0] # first arg to a logging method is the msg
self.add_error(msg, message=self.USING_DEPRECATED_WARN)
# must be a logger instance and one of the support logging methods
if (obj_name not in self.logger_names
or method_name not in self.TRANS_HELPER_MAP):

View File

@ -409,3 +409,15 @@ class HackingLogging(fixtures.Fixture):
'expected_errors': [],
},
]
assert_not_using_deprecated_warn = {
'code': """
# Logger.warn has been deprecated in Python3 in favor of
# Logger.warning
LOG = log.getLogger(__name__)
LOG.warn(_LW('text'))
""",
'expected_errors': [
(4, 9, 'K009'),
],
}

View File

@ -98,7 +98,7 @@ class TestCheckForDebugLoggingIssues(BaseStyleCheck):
self.assert_has_errors(code, expected_errors=errors)
class TestCheckForNonDebugLoggingIssues(BaseStyleCheck):
class BaseLoggingCheck(BaseStyleCheck):
def get_checker(self):
return checks.CheckForLoggingIssues
@ -106,13 +106,8 @@ class TestCheckForNonDebugLoggingIssues(BaseStyleCheck):
def get_fixture(self):
return hacking_fixtures.HackingLogging()
def test_for_translations(self):
for example in self.code_ex.examples:
code = self.code_ex.shared_imports + example['code']
errors = example['expected_errors']
self.assert_has_errors(code, expected_errors=errors)
def assert_has_errors(self, code, expected_errors=None):
# pull out the parts of the error that we'll match against
actual_errors = (e[:3] for e in self.run_check(code))
# adjust line numbers to make the fixture data more readable.
@ -122,6 +117,24 @@ class TestCheckForNonDebugLoggingIssues(BaseStyleCheck):
self.assertEqual(expected_errors or [], actual_errors)
class TestLoggingWithWarn(BaseLoggingCheck):
def test(self):
data = self.code_ex.assert_not_using_deprecated_warn
code = self.code_ex.shared_imports + data['code']
errors = data['expected_errors']
self.assert_has_errors(code, expected_errors=errors)
class TestCheckForNonDebugLoggingIssues(BaseLoggingCheck):
def test_for_translations(self):
for example in self.code_ex.examples:
code = self.code_ex.shared_imports + example['code']
errors = example['expected_errors']
self.assert_has_errors(code, expected_errors=errors)
class TestDictConstructorWithSequenceCopy(BaseStyleCheck):
def get_checker(self):