python-saharaclient/saharaclient/tests/hacking/checks.py

139 lines
4.4 KiB
Python

# Copyright (c) 2013 Mirantis Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import re
import tokenize
import pep8
from saharaclient.tests.hacking import commit_message
from saharaclient.tests.hacking import import_checks
from saharaclient.tests.hacking import logging_checks
RE_OSLO_IMPORTS = (re.compile(r"(((from)|(import))\s+oslo\.)"),
re.compile(r"(from\s+oslo\s+import)"))
RE_DICT_CONSTRUCTOR_WITH_LIST_COPY = re.compile(r".*\bdict\((\[)?(\(|\[)")
RE_USE_JSONUTILS_INVALID_LINE = re.compile(r"(import\s+json)")
RE_USE_JSONUTILS_VALID_LINE = re.compile(r"(import\s+jsonschema)")
RE_MUTABLE_DEFAULT_ARGS = re.compile(r"^\s*def .+\((.+=\{\}|.+=\[\])")
def _starts_with_any(line, *prefixes):
for prefix in prefixes:
if line.startswith(prefix):
return True
return False
def _any_in(line, *sublines):
for subline in sublines:
if subline in line:
return True
return False
def import_db_only_in_conductor(logical_line, filename):
"""Check that db calls are only in conductor module and in tests.
S361
"""
if _any_in(filename,
"sahara/conductor",
"sahara/tests",
"sahara/db"):
return
if _starts_with_any(logical_line,
"from sahara import db",
"from sahara.db",
"import sahara.db"):
yield (0, "S361: sahara.db import only allowed in "
"sahara/conductor/*")
def hacking_no_author_attr(logical_line, tokens):
"""__author__ should not be used.
S362: __author__ = slukjanov
"""
for token_type, text, start_index, _, _ in tokens:
if token_type == tokenize.NAME and text == "__author__":
yield (start_index[1],
"S362: __author__ should not be used")
def check_oslo_namespace_imports(logical_line):
"""Check to prevent old oslo namespace usage.
S363
"""
if re.match(RE_OSLO_IMPORTS[0], logical_line):
yield(0, "S363: '%s' must be used instead of '%s'." % (
logical_line.replace('oslo.', 'oslo_'),
logical_line))
if re.match(RE_OSLO_IMPORTS[1], logical_line):
yield(0, "S363: '%s' must be used instead of '%s'" % (
'import oslo_%s' % logical_line.split()[-1],
logical_line))
def dict_constructor_with_list_copy(logical_line):
"""Check to prevent dict constructor with a sequence of key-value pairs.
S368
"""
if RE_DICT_CONSTRUCTOR_WITH_LIST_COPY.match(logical_line):
yield (0, 'S368: Must use a dict comprehension instead of a dict '
'constructor with a sequence of key-value pairs.')
def use_jsonutils(logical_line, filename):
"""Check to prevent importing json in sahara code.
S375
"""
if pep8.noqa(logical_line):
return
if (RE_USE_JSONUTILS_INVALID_LINE.match(logical_line) and
not RE_USE_JSONUTILS_VALID_LINE.match(logical_line)):
yield(0, "S375: Use jsonutils from oslo_serialization instead"
" of json")
def no_mutable_default_args(logical_line):
"""Check to prevent mutable default argument in sahara code.
S360
"""
msg = "S360: Method's default argument shouldn't be mutable!"
if RE_MUTABLE_DEFAULT_ARGS.match(logical_line):
yield (0, msg)
def factory(register):
register(import_db_only_in_conductor)
register(hacking_no_author_attr)
register(check_oslo_namespace_imports)
register(commit_message.OnceGitCheckCommitTitleBug)
register(commit_message.OnceGitCheckCommitTitleLength)
register(import_checks.hacking_import_groups)
register(import_checks.hacking_import_groups_together)
register(dict_constructor_with_list_copy)
register(logging_checks.no_translate_logs)
register(logging_checks.accepted_log_levels)
register(use_jsonutils)
register(no_mutable_default_args)