def test__cli__formatters__violation(): """ NB Position is 1 + start_pos """ c = PositionedChunk('foobarbar', 10, 20, 'context') r = RuleGhost('A', 'DESC') v = RuleViolation(c, r, []) f = format_violation(v) assert escape_ansi(f) == "L: 20 | P: 11 | A | DESC"
def test__cli__formatters__violation(): """Test formatting violations. NB Position is 1 + start_pos. """ s = RawSegment("foobarbar", FilePositionMarker(0, 20, 11, 100)) r = RuleGhost("A", "DESC") v = SQLLintError(segment=s, rule=r) f = format_violation(v) assert escape_ansi(f) == "L: 20 | P: 11 | A | DESC"
def _print_out_violations_and_timing( bench: bool, code_only: bool, total_time: float, verbose: int, parsed_strings: List[ParsedString], ) -> int: """Used by human formatting during the parse.""" violations_count = 0 timing = TimingSummary() for parsed_string in parsed_strings: timing.add(parsed_string.time_dict) if parsed_string.tree: click.echo(parsed_string.tree.stringify(code_only=code_only)) else: # TODO: Make this prettier click.echo("...Failed to Parse...") # pragma: no cover violations_count += len(parsed_string.violations) if parsed_string.violations: click.echo("==== parsing violations ====") # pragma: no cover for v in parsed_string.violations: click.echo(format_violation(v)) # pragma: no cover if parsed_string.violations and parsed_string.config.get( "dialect") == "ansi": click.echo(format_dialect_warning()) # pragma: no cover if verbose >= 2: click.echo("==== timings ====") click.echo(cli_table(parsed_string.time_dict.items())) if verbose >= 2 or bench: click.echo("==== overall timings ====") click.echo(cli_table([("Clock time", total_time)])) timing_summary = timing.summary() for step in timing_summary: click.echo(f"=== {step} ===") click.echo(cli_table(timing_summary[step].items())) return violations_count
def test__cli__formatters__violation(): """Test formatting violations. NB Position is 1 + start_pos. """ s = RawSegment( "foobarbar", PositionMarker( slice(10, 19), slice(10, 19), TemplatedFile.from_string(" \n\n foobarbar"), ), ) r = RuleGhost("A", "DESC") v = SQLLintError(segment=s, rule=r) f = format_violation(v) # Position is 3, 3 becase foobarbar is on the third # line (i.e. it has two newlines preceding it) and # it's at the third position in that line (i.e. there # are two characters between it and the preceeding # newline). assert escape_ansi(f) == "L: 3 | P: 3 | A | DESC"
def parse(path, code_only, format, profiler, bench, nofail, logger=None, **kwargs): """Parse SQL files and just spit out the result. PATH is the path to a sql file or directory to lint. This can be either a file ('path/to/file.sql'), a path ('directory/of/sql/files'), a single ('-') character to indicate reading from *stdin* or a dot/blank ('.'/' ') which will be interpreted like passing the current working directory as a path argument. """ # Initialise the benchmarker bencher = BenchIt() # starts the timer c = get_config(**kwargs) # We don't want anything else to be logged if we want json or yaml output non_human_output = format in ("json", "yaml") lnt, formatter = get_linter_and_formatter(c, silent=non_human_output) verbose = c.get("verbose") recurse = c.get("recurse") formatter.dispatch_config(lnt) # Set up logging. set_logging_level(verbosity=verbose, logger=logger, stderr_output=non_human_output) # TODO: do this better nv = 0 if profiler: # Set up the profiler if required try: import cProfile except ImportError: click.echo("The cProfiler is not available on your platform.") sys.exit(1) pr = cProfile.Profile() pr.enable() bencher("Parse setup") try: # handle stdin if specified via lone '-' if "-" == path: # put the parser result in a list to iterate later result = [ lnt.parse_string(sys.stdin.read(), "stdin", recurse=recurse, config=lnt.config), ] else: # A single path must be specified for this command # TODO: Remove verbose result = lnt.parse_path(path, recurse=recurse) # iterative print for human readout if format == "human": for parsed_string in result: if parsed_string.tree: click.echo( parsed_string.tree.stringify(code_only=code_only)) else: # TODO: Make this prettier click.echo("...Failed to Parse...") nv += len(parsed_string.violations) if parsed_string.violations: click.echo("==== parsing violations ====") for v in parsed_string.violations: click.echo(format_violation(v)) if (parsed_string.violations and parsed_string.config.get("dialect") == "ansi"): click.echo(format_dialect_warning()) if verbose >= 2: click.echo("==== timings ====") click.echo(cli_table(parsed_string.time_dict.items())) bencher("Output details for file") else: # collect result and print as single payload # will need to zip in the file paths filepaths = ["stdin"] if "-" == path else lnt.paths_from_path(path) result = [ dict( filepath=filepath, segments=parsed.as_record(code_only=code_only, show_raw=True) if parsed else None, ) for filepath, (parsed, _, _, _, _) in zip(filepaths, result) ] if format == "yaml": # For yaml dumping always dump double quoted strings if they contain tabs or newlines. yaml.add_representer(str, quoted_presenter) click.echo(yaml.dump(result)) elif format == "json": click.echo(json.dumps(result)) except IOError: click.echo( colorize( "The path {0!r} could not be accessed. Check it exists.". format(path), "red", )) sys.exit(1) if profiler: pr.disable() profiler_buffer = StringIO() ps = pstats.Stats(pr, stream=profiler_buffer).sort_stats("cumulative") ps.print_stats() click.echo("==== profiler stats ====") # Only print the first 50 lines of it click.echo("\n".join(profiler_buffer.getvalue().split("\n")[:50])) if bench: click.echo("\n\n==== bencher stats ====") bencher.display() if nv > 0 and not nofail: sys.exit(66) else: sys.exit(0)
def parse( path, code_only, include_meta, format, profiler, bench, nofail, logger=None, **kwargs, ): """Parse SQL files and just spit out the result. PATH is the path to a sql file or directory to lint. This can be either a file ('path/to/file.sql'), a path ('directory/of/sql/files'), a single ('-') character to indicate reading from *stdin* or a dot/blank ('.'/' ') which will be interpreted like passing the current working directory as a path argument. """ c = get_config(**kwargs) # We don't want anything else to be logged if we want json or yaml output non_human_output = format in ("json", "yaml") lnt, formatter = get_linter_and_formatter(c, silent=non_human_output) verbose = c.get("verbose") recurse = c.get("recurse") formatter.dispatch_config(lnt) # Set up logging. set_logging_level(verbosity=verbose, logger=logger, stderr_output=non_human_output) # TODO: do this better nv = 0 if profiler: # Set up the profiler if required try: import cProfile except ImportError: # pragma: no cover click.echo("The cProfiler is not available on your platform.") sys.exit(1) pr = cProfile.Profile() pr.enable() try: t0 = time.monotonic() # handle stdin if specified via lone '-' if "-" == path: # put the parser result in a list to iterate later result = [ lnt.parse_string( sys.stdin.read(), "stdin", recurse=recurse, config=lnt.config ), ] else: # A single path must be specified for this command result = lnt.parse_path(path, recurse=recurse) total_time = time.monotonic() - t0 # iterative print for human readout if format == "human": timing = TimingSummary() for parsed_string in result: timing.add(parsed_string.time_dict) if parsed_string.tree: click.echo(parsed_string.tree.stringify(code_only=code_only)) else: # TODO: Make this prettier click.echo("...Failed to Parse...") # pragma: no cover nv += len(parsed_string.violations) if parsed_string.violations: click.echo("==== parsing violations ====") # pragma: no cover for v in parsed_string.violations: click.echo(format_violation(v)) # pragma: no cover if ( parsed_string.violations and parsed_string.config.get("dialect") == "ansi" ): click.echo(format_dialect_warning()) # pragma: no cover if verbose >= 2: click.echo("==== timings ====") click.echo(cli_table(parsed_string.time_dict.items())) if verbose >= 2 or bench: click.echo("==== overall timings ====") click.echo(cli_table([("Clock time", total_time)])) timing_summary = timing.summary() for step in timing_summary: click.echo(f"=== {step} ===") click.echo(cli_table(timing_summary[step].items())) else: result = [ dict( filepath=linted_result.fname, segments=linted_result.tree.as_record( code_only=code_only, show_raw=True, include_meta=include_meta ) if linted_result.tree else None, ) for linted_result in result ] if format == "yaml": # For yaml dumping always dump double quoted strings if they contain tabs or newlines. yaml.add_representer(str, quoted_presenter) click.echo(yaml.dump(result)) elif format == "json": click.echo(json.dumps(result)) except OSError: # pragma: no cover click.echo( colorize( f"The path {path!r} could not be accessed. Check it exists.", "red", ), err=True, ) sys.exit(1) if profiler: pr.disable() profiler_buffer = StringIO() ps = pstats.Stats(pr, stream=profiler_buffer).sort_stats("cumulative") ps.print_stats() click.echo("==== profiler stats ====") # Only print the first 50 lines of it click.echo("\n".join(profiler_buffer.getvalue().split("\n")[:50])) if nv > 0 and not nofail: sys.exit(66) # pragma: no cover else: sys.exit(0)