|
31 | 31 | FUNC_NODES = (ast.FunctionDef, ast.AsyncFunctionDef)
|
32 | 32 |
|
33 | 33 |
|
34 |
| -def get_arg_name_tuples(node): |
35 |
| - groups = (node.args.posonlyargs, node.args.args, node.args.kwonlyargs) |
36 |
| - return [(arg, arg.arg) for args in groups for arg in args] |
37 |
| - |
38 |
| - |
39 | 34 | class _ASTCheckMeta(type):
|
40 | 35 | def __init__(cls, class_name, bases, namespace):
|
41 | 36 | cls.codes = tuple(code for code in namespace if code.startswith('N'))
|
@@ -347,33 +342,36 @@ class FunctionArgNamesCheck(BaseASTCheck):
|
347 | 342 | N805 = "first argument of a method should be named 'self'"
|
348 | 343 |
|
349 | 344 | def visit_functiondef(self, node, parents: Iterable, ignore=None):
|
350 |
| - |
351 |
| - def arg_name(arg): |
352 |
| - return (arg, arg.arg) if arg else (node, arg) |
353 |
| - |
354 |
| - for arg, name in arg_name(node.args.vararg), arg_name(node.args.kwarg): |
355 |
| - if name is None or _ignored(name, ignore): |
356 |
| - continue |
357 |
| - if name.lower() != name: |
358 |
| - yield self.err(arg, 'N803', name=name) |
359 |
| - return |
360 |
| - |
361 |
| - arg_name_tuples = get_arg_name_tuples(node) |
362 |
| - if not arg_name_tuples: |
363 |
| - return |
364 |
| - arg0, name0 = arg_name_tuples[0] |
365 |
| - function_type = getattr(node, 'function_type', _FunctionType.FUNCTION) |
366 |
| - |
367 |
| - if function_type == _FunctionType.METHOD: |
368 |
| - if name0 != 'self' and not _ignored(name0, ignore): |
369 |
| - yield self.err(arg0, 'N805') |
370 |
| - elif function_type == _FunctionType.CLASSMETHOD: |
371 |
| - if name0 != 'cls' and not _ignored(name0, ignore): |
372 |
| - yield self.err(arg0, 'N804') |
373 |
| - for arg, name in arg_name_tuples: |
| 345 | + args = node.args.posonlyargs + node.args.args + node.args.kwonlyargs |
| 346 | + |
| 347 | + # Start by applying checks that are specific to the first argument. |
| 348 | + # |
| 349 | + # Note: The `ignore` check shouldn't be necessary here because we'd |
| 350 | + # expect users to explicitly ignore N804/N805 when using names |
| 351 | + # other than `self` and `cls` rather than ignoring names like |
| 352 | + # `klass` to get around these checks. However, a previous |
| 353 | + # implementation allowed for that, so we retain that behavior |
| 354 | + # for backwards compatibility. |
| 355 | + if args and (name := args[0].arg) and not _ignored(name, ignore): |
| 356 | + function_type = getattr(node, 'function_type', None) |
| 357 | + if function_type == _FunctionType.METHOD and name != 'self': |
| 358 | + yield self.err(args[0], 'N805') |
| 359 | + elif function_type == _FunctionType.CLASSMETHOD and name != 'cls': |
| 360 | + yield self.err(args[0], 'N804') |
| 361 | + |
| 362 | + # Also add the special *arg and **kwarg arguments for the rest of the |
| 363 | + # checks when they're present. We didn't include them above because |
| 364 | + # the "first argument" naming checks shouldn't be applied to them |
| 365 | + # when they're the function's only argument(s). |
| 366 | + if node.args.vararg: |
| 367 | + args.append(node.args.vararg) |
| 368 | + if node.args.kwarg: |
| 369 | + args.append(node.args.kwarg) |
| 370 | + |
| 371 | + for arg in args: |
| 372 | + name = arg.arg |
374 | 373 | if name.lower() != name and not _ignored(name, ignore):
|
375 | 374 | yield self.err(arg, 'N803', name=name)
|
376 |
| - return |
377 | 375 |
|
378 | 376 | visit_asyncfunctiondef = visit_functiondef
|
379 | 377 |
|
|
0 commit comments