def lint(module: Module) -> List: """ @cc 5 @desc lint the given module! @arg module: the module to lint @ret a list of issues found in this module """ issues = [] state = get_state() state.module_count += 1 if module.doc and module.doc.no_lint: state.module_nolint_count += 1 return [] for rule in state.module_rules: if rule.check(module): issues.append(Issue(rule, module)) for class_def in module.classes: issues.extend(class_lint(class_def)) for function in module.functions: issues.extend(function_lint(function)) return issues
def class_lint(class_def: Class) -> List: """ @cc 5 @desc class specific lint @arg class_def: the Class object to lint @ret a list of issues found in this class """ state = get_state() issues = [] state.class_count += 1 if class_def.doc and class_def.doc.no_lint: state.class_nolint_count += 1 return [] # check this class for rules for rule in state.class_rules: if rule.check(class_def): issues.append(Issue(rule, class_def)) # check nested classes for sub_class in class_def.classes: issues.extend(class_lint(sub_class)) # check functions within this class for function in class_def.functions: issues.extend(function_lint(function)) return issues
def parse_module(filename: str) -> Module: """ @cc 5 @desc parse a module into our archives' models @arg filename: the python file to parse @ret a parsed Module object of the given file """ state = get_state() contents = "" if str(filename)[-2:] == "/-": contents, _, __ = decode_bytes(sys.stdin.buffer.read()) elif not os.path.isfile(filename): raise Exception("file does not exist") else: with open(filename, encoding="utf-8", errors="replace") as file_to_read: contents += file_to_read.read() try: ast = ast3.parse(contents) except: # noqa out("error in parsing", color="red") if state.ignore_exceptions: sys.exit(0) module = Module(ast, filename) # type: ignore return module
def msg(data: Union[str, Dict, List]) -> None: """ @cc 2 @desc prints something to standard out in blue @arg data: either a string to print, or a list/dict to print nicely """ state = get_state() if not state.quiet: if isinstance(data, (dict, list)): data = json.dumps(data, indent=2, sort_keys=True, default=str) click.secho(data, fg="blue")
def debug(data: Union[str, Dict, List], force: bool = False) -> None: """ @cc 2 @desc only prints if verbose mode is on, formatting nicely if list/dict @arg data: either a string to print, or a list/dict to print nicely @arg force: force this debug to print, regardless of state/flags """ state = get_state() if state.verbose or force: if isinstance(data, (dict, list)): data = json.dumps(data, indent=2, sort_keys=True, default=str) click.echo(click.style(data, fg="green"), err=True)
def path_empty(src: Tuple[str], ctx: click.Context) -> None: """ @cc 4 @desc Exit if there is no src provided for formatting @arg src: a list of source files to lint @arg ctx: the context of the click cli application """ state = get_state() if not src: if state.verbose or not state.quiet: err("no paths provided!") ctx.exit(2)
def out(data: Union[str, Dict, List], force: bool = False, color: str = "green") -> None: """ @cc 2 @desc prints something to standard out @arg data: either a string to print, or a list/dict to print nicely @arg color: what color to print in @arg force: force this debug to print, regardless of state/flags """ state = get_state() if not state.quiet or force: if isinstance(data, (dict, list)): data = json.dumps(data, indent=2, sort_keys=True, default=str) click.echo(click.style(data, fg=color))
def function_lint(function: Function) -> List: """ @cc 16 @desc function specific lint @arg function: the Function object to lint @ret a list of issues found in this function """ state = get_state() issues = [] state.function_count += 1 if function.doc and function.doc.no_lint: state.function_nolint_count += 1 return [] # check this function for rules for rule in state.function_rules: if rule.check(function): issues.append(Issue(rule, function)) # check for missing args if MISSING_ARG.code not in state.disable_list: for arg_name in function.missing_args: issues.append(Issue(MISSING_ARG, function, dict(arg=arg_name))) # check for unexpected args if UNEXPECTED_ARG.code not in state.disable_list: for arg_name in function.unexpected_args: issues.append(Issue(UNEXPECTED_ARG, function, dict(arg=arg_name))) # check for untyped args if UNTYPED_ARG.code not in state.disable_list: for arg in [ x for x in function.args if not x.typed and x.name not in DEFAULT_ARG_IGNORE ]: issues.append(Issue(UNTYPED_ARG, function, dict(arg=arg))) # check nested classes for sub_class in function.classes: issues.extend(class_lint(sub_class)) # check all sub functions for sub_function in function.functions: issues.extend(function_lint(sub_function)) return issues