summaryrefslogtreecommitdiff
path: root/patternutils/commands/pjson.py
diff options
context:
space:
mode:
Diffstat (limited to 'patternutils/commands/pjson.py')
-rw-r--r--patternutils/commands/pjson.py111
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))