diff options
Diffstat (limited to 'patternutils/commands/pjson.py')
| -rw-r--r-- | patternutils/commands/pjson.py | 111 |
1 files changed, 111 insertions, 0 deletions
diff --git a/patternutils/commands/pjson.py b/patternutils/commands/pjson.py new file mode 100644 index 0000000..d114d4c --- /dev/null +++ b/patternutils/commands/pjson.py @@ -0,0 +1,111 @@ +import json +import re +from typing import Any, Dict, Pattern + +import click + +from .. import match as mat +from .. import utils + + +def apply_regex( + data: Dict[str, str], key: str, regex_pattern: Pattern[str] +) -> Dict[str, str]: + try: + subject = data[key] + except KeyError: + click.secho(f"{key} can not be found in data!", fg="red", err=True) + raise + + try: + match = mat.apply(data[key], regex_pattern) + except ValueError: + click.secho(f"{subject} did not match", fg="red", err=True) + raise + else: + return match + + +@click.command(context_settings={"help_option_names": ("-h", "--help", "-?")}) +@click.option("--read-from", default="-", type=click.File("r")) +@click.option( + "--stream", + is_flag=True, + default=False, + help="Input is a stream of JSON objects and output will also be a stream of JSON objects", +) +@click.option( + "--abort-on-no-key", + is_flag=True, + default=False, + help="exit if a key does not exist", +) +@click.option( + "--abort-on-no-match", + is_flag=True, + default=False, + help="exit if a value does not match the REGEX_PATTERN", +) +@click.option( + "--human-readable", + is_flag=True, + default=False, + help="output the JSON in a human readable format", +) +@click.option( + "-v", "--verbose", is_flag=True, default=False, help="explain what is being done" +) +@click.version_option() +@click.argument("key") +@click.argument("regex-pattern") +def pjson( + key: str, + regex_pattern: str, + read_from: click.File, + stream: bool, + abort_on_no_key: bool, + abort_on_no_match: bool, + human_readable: bool, + verbose: bool, +) -> None: + + try: + regex_pattern_c = re.compile(regex_pattern) + except re.error as e: + if verbose: + click.secho("Regular expression could not be compiled!", fg="red", err=True) + click.secho(e.msg, fg="red", err=True) + raise SystemExit + + has_no_key = False + has_no_match = False + + if stream: + data = map(utils.json_loads, read_from) # type: ignore + else: + data = utils.json_loads(read_from) + + matches = [] + + for line in data: + try: + match = apply_regex(line, key, regex_pattern_c) + except KeyError: + has_no_key = True + if stream and abort_on_no_key: + raise SystemExit + except ValueError: + has_no_match = True + if stream and abort_on_no_match: + raise SystemExit + else: + line.update(match) + if stream: + click.echo(utils.json_dumps(line, human_readable)) + else: + matches.append(line) + + if (abort_on_no_key and has_no_key) or (abort_on_no_match and has_no_match): + raise SystemExit + + click.echo(utils.json_dumps(matches, human_readable)) |
