"""Linting for Python using Aspects.""" # Hacked up from https://github.com/bazelbuild/rules_rust/blob/main/rust/private/clippy.bzl # # Usage: # bazel build --aspects="//tools/flake8:flake8.bzl%flake8_aspect" --output_groups=flake8_checks # # Note that the build directive can be inserted to .bazelrc to make it part of the default behavior def _black_aspect_impl(target, ctx): if hasattr(ctx.rule.attr, 'srcs'): black = ctx.attr._black.files_to_run config = ctx.attr._config.files.to_list()[0] files = [] for src in ctx.rule.attr.srcs: for f in src.files.to_list(): if f.extension == "py": files.append(f) if files: report = ctx.actions.declare_file(ctx.label.name + ".black.report") else: return [] args = ["--check", "--output-file", report.path] for f in files: args.append(f.path) ctx.actions.run( executable = black, inputs = files, tools = ctx.attr._config.files.to_list() + ctx.attr._black.files.to_list(), arguments = args, outputs = [report], mnemonic = "Black", ) return [ OutputGroupInfo(black_checks = depset([report])) ] return [] black_aspect = aspect( implementation = _black_aspect_impl, attr_aspects = ['deps'], attrs = { '_black': attr.label(default=":black"), '_config': attr.label( default="//:setup.cfg", executable=False, allow_single_file=True ), } ) def _black_rule_impl(ctx): ready_targets = [dep for dep in ctx.attr.deps if "black_checks" in dir(dep[OutputGroupInfo])] files = depset([], transitive = [dep[OutputGroupInfo].black_checks for dep in ready_targets]) return [DefaultInfo(files = files)] black = rule( implementation = _black_rule_impl, attrs = { 'deps' : attr.label_list(aspects = [black_aspect]), }, )