blob: fa2766ff228c229367031e05dc08607b74414a55 [file] [log] [blame]
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you 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 astroid
from pylint.checkers import BaseChecker, utils
from pylint.interfaces import IAstroidChecker
def register(linter):
linter.register_checker(ExposedAPIHasKwargs(linter))
# FIXME?
BASE_ID = 76 # taken from https://github.com/edx/edx-lint/tree/master/edx_lint/pylint
class ExposedAPIHasKwargs(BaseChecker):
__implements__ = (IAstroidChecker,)
name = 'exposed-api-needs-kwargs'
MESSAGE_ID = name
msgs = {
'E%d10' % BASE_ID: (
"@expose'd method %s() looks like an API and needs **kwargs",
MESSAGE_ID,
"@expose'd API methods should have **kwargs to avoid an error when accessed with ?access_token=XYZ",
),
}
@utils.check_messages(MESSAGE_ID)
def visit_function(self, node):
# special TurboGears method name, doesn't need **kw
if node.name == '_lookup':
return
# Assume @expose('json:') means its an API endpoint. Not a perfect assumption:
# - could be an API endpoint used only for PUT/POST with no json result)
# - there are non-API endpoints that return json (for ajax)
has_json_expose = False
if node.decorators:
for dec in node.decorators.nodes:
if hasattr(dec, 'func'): # otherwise its a @deco without parens
if getattr(dec.func, 'name', '') == 'expose':
for arg in dec.args:
if getattr(arg, 'value', '') in ('json', 'json:'):
has_json_expose = True
if not has_json_expose:
return
if node.args.kwarg:
return
if not self.linter.is_message_enabled(self.MESSAGE_ID, line=node.fromlineno):
return
self.add_message(self.MESSAGE_ID, args=node.name, node=node)