Skip to content

CLI option --filter: validate multiple instances from stdin. #213

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 19 additions & 5 deletions jsonschema/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,21 @@ def _json_file(path):
parser = argparse.ArgumentParser(
description="JSON Schema Validation CLI",
)
parser.add_argument(
input_group = parser.add_mutually_exclusive_group()
input_group.add_argument(
"-i", "--instance",
action="append",
dest="instances",
type=_json_file,
help="a path to a JSON instance to validate "
"(may be specified multiple times)",
)
input_group.add_argument(
"-f", "--filter",
action="store_true",
help="read instances one to a line from stdin, output those that validate "
"in compact form and log to stderr those that do not."
)
parser.add_argument(
"-F", "--error-format",
default="{error.instance}: {error.message}\n",
Expand All @@ -43,6 +50,7 @@ def _json_file(path):
"validators that are registered with jsonschema, simply the name "
"of the class.",
)

parser.add_argument(
"schema",
help="the JSON Schema to validate with",
Expand All @@ -61,12 +69,18 @@ def main(args=sys.argv[1:]):
sys.exit(run(arguments=parse_args(args=args)))


def run(arguments, stdout=sys.stdout, stderr=sys.stderr):
def run(arguments, stdin=sys.stdin, stdout=sys.stdout, stderr=sys.stderr):
error_format = arguments["error_format"]
validator = arguments["validator"](schema=arguments["schema"])
errored = False
for instance in arguments["instances"] or ():
for error in validator.iter_errors(instance):
stderr.write(error_format.format(error=error))
instances = (json.loads(line) for line in stdin) if arguments.get("filter") else (arguments.get("instances") or ())
for instance in instances:
errors = tuple(validator.iter_errors(instance))
if errors:
errored = True
for error in errors:
stderr.write(error_format.format(error=error))
elif arguments.get("filter"):
json.dump(instance, stdout, separators=(',', ':'))
stdout.write('\n')
return errored
35 changes: 35 additions & 0 deletions jsonschema/tests/test_cli.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import json

from jsonschema import Draft4Validator, ValidationError, cli
from jsonschema.compat import StringIO
from jsonschema.tests.compat import mock, unittest
Expand All @@ -17,6 +19,11 @@ def iter_errors(self, instance):
return FakeValidator


def serialize_instances(*instances):
""":Return: a string with `instances` serialized to JSON, one per line."""
return '\n'.join(json.dumps(instance, separators=(',', ':')) for instance in instances) + '\n'


class TestParser(unittest.TestCase):
FakeValidator = fake_validator()

Expand Down Expand Up @@ -108,3 +115,31 @@ def test_unsuccessful_validation_multiple_instances(self):
self.assertFalse(stdout.getvalue())
self.assertEqual(stderr.getvalue(), "1 - 9\t1 - 8\t2 - 7\t")
self.assertEqual(exit_code, 1)

def test_filter_valid(self):
serialized = serialize_instances(1, [2], {3: 4})
stdin, stdout, stderr = StringIO(serialized), StringIO(), StringIO()
exit_code = cli.run({
"validator": fake_validator(),
"schema": {},
"error_format": "{error.message}",
"filter": True,
}, stdin=stdin, stdout=stdout, stderr=stderr)
self.assertFalse(stderr.getvalue())
self.assertEquals(stdout.getvalue(), serialized)
self.assertEqual(exit_code, 0)

def test_filter_invalid(self):
schema = {"type": "object"}
serialized_in = serialize_instances({}, [2], {3: 4})
serialized_out = serialize_instances({}, {3: 4})
stdin, stdout, stderr = StringIO(serialized_in), StringIO(), StringIO()
exit_code = cli.run({
"validator": Draft4Validator,
"schema": schema,
"error_format": "{error.message}",
"filter": True,
}, stdin=stdin, stdout=stdout, stderr=stderr)
self.assertEquals(stderr.getvalue(), "[2] is not of type 'object'")
self.assertEquals(stdout.getvalue(), serialized_out)
self.assertEqual(exit_code, 1)