def visit_Call(self, node, parents, context=None): # noqa (N802) name = dotify_ast_name(node.func) if name == "InternalIdentifierField": return if name == "TranslatedFields": for kw in node.keywords: if isinstance(kw.value, ast.Call): self.visit_Call(kw.value, parents, context=kw.arg) return if not any( name.endswith(suffix) for suffix in ("ForeignKey", "Field")): return if not context: if isinstance(parents[-1], ast.Assign): context = get_assign_first_target(parents[-1]) if context and (context.startswith("_") or context.endswith("data")): return kwmap = dict((kw.arg, kw.value) for kw in node.keywords) kw_value = None needle = None for needle in ("verbose_name", "label"): kw_value = kwmap.get(needle) if kw_value: break if not kw_value: if node.kwargs: # Assume dynamic use (has **kwargs) return self.errors.append( "%d: %s call missing verbose_name or label (ctx: %s)" % (node.lineno, name, context)) return if isinstance(kw_value, ast.BinOp) and isinstance( kw_value.op, ast.Mod): # It's an interpolation operation; use the lvalue (probably the call) kw_value = kw_value.left if isinstance(kw_value, ast.Call) and dotify_ast_name( kw_value.func) == "_": arg = kw_value.args[0] if isinstance(arg, ast.Str) and needle == "verbose_name": if not arg.s[0].islower() and not any( arg.s.startswith(acronym) for acronym in KNOWN_ACRONYMS): self.errors.append( "%d: %s `%s` not lower-case (value: %r) (ctx: %s)" % (node.lineno, name, needle, arg.s, context)) return if isinstance(kw_value, ast.Name): # It's a variable return self.errors.append( "%d: %s `%s` present but not translatable (ctx: %s)" % (node.lineno, name, needle, context))
def visit_Call(self, node, parents, context=None): # noqa (N802) name = dotify_ast_name(node.func) if name == "InternalIdentifierField": return if name == "TranslatedFields": for kw in node.keywords: if isinstance(kw.value, ast.Call): self.visit_Call(kw.value, parents, context=kw.arg) return if not any(name.endswith(suffix) for suffix in ("ForeignKey", "Field")): return if not context: if isinstance(parents[-1], ast.Assign): context = get_assign_first_target(parents[-1]) if context and (context.startswith("_") or context.endswith("data")): return kwmap = dict((kw.arg, kw.value) for kw in node.keywords) kw_value = None needle = None for needle in ("verbose_name", "label"): kw_value = kwmap.get(needle) if kw_value: break if not kw_value: if node.kwargs: # Assume dynamic use (has **kwargs) return self.errors.append("%d: %s call missing verbose_name or label (ctx: %s)" % (node.lineno, name, context)) return if isinstance(kw_value, ast.BinOp) and isinstance(kw_value.op, ast.Mod): # It's an interpolation operation; use the lvalue (probably the call) kw_value = kw_value.left if isinstance(kw_value, ast.Call) and dotify_ast_name(kw_value.func) == "_": arg = kw_value.args[0] if isinstance(arg, ast.Str) and needle == "verbose_name": if not arg.s[0].islower() and not any(arg.s.startswith(acronym) for acronym in KNOWN_ACRONYMS): self.errors.append("%d: %s `%s` not lower-case (value: %r) (ctx: %s)" % ( node.lineno, name, needle, arg.s, context) ) return if isinstance(kw_value, ast.Name): # It's a variable return self.errors.append( "%d: %s `%s` present but not translatable (ctx: %s)" % (node.lineno, name, needle, context))