@cli.command()
@common_options
@core_options
@click.argument('path', nargs=1)
@click.option('--recurse', default=0, help='The depth to recursively parse to (0 for unlimited)')
@click.option('-c', '--code-only', is_flag=True, help='Output only the code elements of the parse tree.')
@click.option('-f', '--format', default='human', type=click.Choice(['human', 'json', 'yaml'], case_sensitive=False), help='What format to return the parse result in.')
@click.option('--profiler', is_flag=True, help='Set this flag to engage the python profiler.')
@click.option('--nofail', is_flag=True, help='If set, the exit code will always be zero, regardless of violations found. This is potentially useful during rollout.')
def parse(path, code_only, format, profiler, bench, nofail, logger=None, **kwargs):
    "Parse SQL files and just spit out the result.\n\n    PATH is the path to a sql file or directory to lint. This can be either a\n    file ('path/to/file.sql'), a path ('directory/of/sql/files'), a single ('-')\n    character to indicate reading from *stdin* or a dot/blank ('.'/' ') which will\n    be interpreted like passing the current working directory as a path argument.\n    "
    c = get_config(**kwargs)
    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_logging_level(verbosity=verbose, logger=logger, stderr_output=non_human_output)
    nv = 0
    if profiler:
        try:
            import cProfile
        except ImportError:
            click.echo('The cProfiler is not available on your platform.')
            sys.exit(1)
        pr = cProfile.Profile()
        pr.enable()
    try:
        if ('-' == path):
            result = [lnt.parse_string(sys.stdin.read(), 'stdin', recurse=recurse, config=lnt.config)]
        else:
            result = lnt.parse_path(path, recurse=recurse)
        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:
                    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()))
            if ((verbose >= 2) or bench):
                click.echo('==== overall timings ====')
                timing_summary = timing.summary()
                for step in timing_summary:
                    click.echo(f'=== {step} ===')
                    click.echo(cli_table(timing_summary[step].items()))
        else:
            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'):
                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 ====')
        click.echo('\n'.join(profiler_buffer.getvalue().split('\n')[:50]))
    if ((nv > 0) and (not nofail)):
        sys.exit(66)
    else:
        sys.exit(0)
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.
@cli.command()
@common_options
@core_options
@click.argument('path', nargs=1)
@click.option('--recurse', default=0, help='The depth to recursively parse to (0 for unlimited)')
@click.option('-c', '--code-only', is_flag=True, help='Output only the code elements of the parse tree.')
@click.option('-f', '--format', default='human', type=click.Choice(['human', 'json', 'yaml'], case_sensitive=False), help='What format to return the parse result in.')
@click.option('--profiler', is_flag=True, help='Set this flag to engage the python profiler.')
@click.option('--nofail', is_flag=True, help='If set, the exit code will always be zero, regardless of violations found. This is potentially useful during rollout.')
def parse(path, code_only, format, profiler, bench, nofail, logger=None, **kwargs):
    "Parse SQL files and just spit out the result.\n\n    PATH is the path to a sql file or directory to lint. This can be either a\n    file ('path/to/file.sql'), a path ('directory/of/sql/files'), a single ('-')\n    character to indicate reading from *stdin* or a dot/blank ('.'/' ') which will\n    be interpreted like passing the current working directory as a path argument.\n    "
    c = get_config(**kwargs)
    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_logging_level(verbosity=verbose, logger=logger, stderr_output=non_human_output)
    nv = 0
    if profiler:
        try:
            import cProfile
        except ImportError:
            click.echo('The cProfiler is not available on your platform.')
            sys.exit(1)
        pr = cProfile.Profile()
        pr.enable()
    try:
        if ('-' == path):
            result = [lnt.parse_string(sys.stdin.read(), 'stdin', recurse=recurse, config=lnt.config)]
        else:
            result = lnt.parse_path(path, recurse=recurse)
        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:
                    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()))
            if ((verbose >= 2) or bench):
                click.echo('==== overall timings ====')
                timing_summary = timing.summary()
                for step in timing_summary:
                    click.echo(f'=== {step} ===')
                    click.echo(cli_table(timing_summary[step].items()))
        else:
            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'):
                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 ====')
        click.echo('\n'.join(profiler_buffer.getvalue().split('\n')[:50]))
    if ((nv > 0) and (not nofail)):
        sys.exit(66)
    else:
        sys.exit(0)