From 6f2ffeff7a63e6fad706e5662f84966a35b0e11e Mon Sep 17 00:00:00 2001 From: willson-chen Date: Wed, 12 Aug 2020 15:02:06 +0800 Subject: [PATCH 01/11] fix issue_669 --- jsonschema/cli.py | 23 +++++++++++++++++++++-- jsonschema/tests/test_cli.py | 17 +++++++++++++++++ 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/jsonschema/cli.py b/jsonschema/cli.py index 4c2bb4f20..f3632231f 100644 --- a/jsonschema/cli.py +++ b/jsonschema/cli.py @@ -7,6 +7,7 @@ import argparse import errno import json +import os import sys import traceback @@ -15,7 +16,7 @@ from jsonschema import __version__ from jsonschema._reflect import namedAny from jsonschema.exceptions import SchemaError -from jsonschema.validators import validator_for +from jsonschema.validators import validator_for, RefResolver class _CannotLoadFile(Exception): @@ -178,6 +179,15 @@ def _namedAnyWithDefault(name): of the class. """, ) +parser.add_argument( + "-r", "--local-ref", + action="store_true", + help=""" + use this option to indicate that the schema contains some references + to some local files. With this option, the validator will try to + resolve those references as paths relative to the given schema. + """, +) parser.add_argument( "--version", action="version", @@ -251,7 +261,16 @@ def load(_): raise _CannotLoadFile() instances = [""] - validator = arguments["validator"](schema) + if arguments["local_ref"]: + file_prefix = "file:///{}/" if "nt" == os.name else "file://{}/" + schema_dirname = os.path.dirname(arguments["schema"]) + resolver = RefResolver( + base_uri=file_prefix.format(os.path.abspath(schema_dirname)), + referrer=schema, + ) + else: + resolver = None + validator = arguments["validator"](schema, resolver=resolver) exit_code = 0 for each in instances: try: diff --git a/jsonschema/tests/test_cli.py b/jsonschema/tests/test_cli.py index c473e583f..e2e220571 100644 --- a/jsonschema/tests/test_cli.py +++ b/jsonschema/tests/test_cli.py @@ -683,6 +683,23 @@ def test_successful_validation__of_just_the_schema_pretty_output(self): stderr="", ) + def test_successful_validation_with_specifying_base_uri(self): + schema = """\ + {"type": "object", "properties": {"KEY1": + {"$ref": "schema.json#definitions/schemas"}}, + "definitions": {"schemas": {"type": "string"}}} + """ + fp = open("schema.json", "w+") + fp.write(schema) + fp.close() + self.assertOutputs( + files=dict(some_schema=schema, some_instance='{"KEY1": "1"}'), + argv=["-i", "some_instance", "-r", "some_schema"], + stdout="", + stderr="", + ) + os.remove("schema.json") + def test_real_validator(self): self.assertOutputs( files=dict(some_schema='{"minimum": 30}', some_instance="37"), From 1db81c25554853e196747254bde41354f3cbaa9a Mon Sep 17 00:00:00 2001 From: willson-chen Date: Sat, 15 Aug 2020 16:14:19 +0800 Subject: [PATCH 02/11] --base-uri flag instead -r --- jsonschema/cli.py | 4 ++-- jsonschema/tests/test_cli.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/jsonschema/cli.py b/jsonschema/cli.py index f3632231f..46dda03e0 100644 --- a/jsonschema/cli.py +++ b/jsonschema/cli.py @@ -180,7 +180,7 @@ def _namedAnyWithDefault(name): """, ) parser.add_argument( - "-r", "--local-ref", + "--base-uri", action="store_true", help=""" use this option to indicate that the schema contains some references @@ -261,7 +261,7 @@ def load(_): raise _CannotLoadFile() instances = [""] - if arguments["local_ref"]: + if arguments["base_uri"]: file_prefix = "file:///{}/" if "nt" == os.name else "file://{}/" schema_dirname = os.path.dirname(arguments["schema"]) resolver = RefResolver( diff --git a/jsonschema/tests/test_cli.py b/jsonschema/tests/test_cli.py index e2e220571..3e883a48b 100644 --- a/jsonschema/tests/test_cli.py +++ b/jsonschema/tests/test_cli.py @@ -694,7 +694,7 @@ def test_successful_validation_with_specifying_base_uri(self): fp.close() self.assertOutputs( files=dict(some_schema=schema, some_instance='{"KEY1": "1"}'), - argv=["-i", "some_instance", "-r", "some_schema"], + argv=["-i", "some_instance", "--base-uri", "some_schema"], stdout="", stderr="", ) From 646d99b1343461e5ae6c83badb98cb2457398f11 Mon Sep 17 00:00:00 2001 From: willson-chen Date: Tue, 18 Aug 2020 11:34:54 +0800 Subject: [PATCH 03/11] Add the specified base-uri function in the CLI --- jsonschema/cli.py | 21 +++++++++++++-------- jsonschema/tests/test_cli.py | 30 ++++++++++++++++++++---------- 2 files changed, 33 insertions(+), 18 deletions(-) diff --git a/jsonschema/cli.py b/jsonschema/cli.py index 46dda03e0..178ea8762 100644 --- a/jsonschema/cli.py +++ b/jsonschema/cli.py @@ -181,11 +181,10 @@ def _namedAnyWithDefault(name): ) parser.add_argument( "--base-uri", - action="store_true", help=""" use this option to indicate that the schema contains some references - to some local files. With this option, the validator will try to - resolve those references as paths relative to the given schema. + to some local or remote files. With this option, the validator will + try to resolve those references as paths relative to the given schema. """, ) parser.add_argument( @@ -261,15 +260,21 @@ def load(_): raise _CannotLoadFile() instances = [""] - if arguments["base_uri"]: - file_prefix = "file:///{}/" if "nt" == os.name else "file://{}/" - schema_dirname = os.path.dirname(arguments["schema"]) + if arguments["base_uri"] is None: + resolver = None + elif "http:" in arguments["base_uri"] or "https:" in arguments["base_uri"]\ + or "urn:" in arguments["base_uri"]: resolver = RefResolver( - base_uri=file_prefix.format(os.path.abspath(schema_dirname)), + base_uri=arguments["base_uri"], referrer=schema, ) else: - resolver = None + file_prefix = "file:///{}/" if "nt" == os.name else "file://{}/" + resolver = RefResolver( + base_uri=file_prefix.format(os.path.abspath(arguments["base_uri"])), + referrer=schema, + ) + validator = arguments["validator"](schema, resolver=resolver) exit_code = 0 for each in instances: diff --git a/jsonschema/tests/test_cli.py b/jsonschema/tests/test_cli.py index 3e883a48b..8d2fdf7e9 100644 --- a/jsonschema/tests/test_cli.py +++ b/jsonschema/tests/test_cli.py @@ -7,6 +7,7 @@ import os import subprocess import sys +import tempfile from jsonschema import Draft4Validator, cli, __version__ from jsonschema.exceptions import SchemaError, ValidationError @@ -684,21 +685,30 @@ def test_successful_validation__of_just_the_schema_pretty_output(self): ) def test_successful_validation_with_specifying_base_uri(self): - schema = """\ - {"type": "object", "properties": {"KEY1": - {"$ref": "schema.json#definitions/schemas"}}, - "definitions": {"schemas": {"type": "string"}}} - """ - fp = open("schema.json", "w+") - fp.write(schema) - fp.close() + try: + schema_file = tempfile.NamedTemporaryFile( + mode='w+', + prefix='schema', + suffix='.json', + dir='..', + delete=False + ) + self.addCleanup(os.remove, schema_file.name) + schema = """ + {"type": "object", "properties": {"KEY1": + {"$ref": %s%s#definitions/schemas"}}, + "definitions": {"schemas": {"type": "string"}}} + """ % ("\"", os.path.basename(schema_file.name)) + schema_file.write(schema) + finally: + schema_file.close() + self.assertOutputs( files=dict(some_schema=schema, some_instance='{"KEY1": "1"}'), - argv=["-i", "some_instance", "--base-uri", "some_schema"], + argv=["-i", "some_instance", "--base-uri", "..", "some_schema"], stdout="", stderr="", ) - os.remove("schema.json") def test_real_validator(self): self.assertOutputs( From 03868b3316ba2f17fbd091df91bcb06bd89a8552 Mon Sep 17 00:00:00 2001 From: willson-chen Date: Tue, 18 Aug 2020 14:19:11 +0800 Subject: [PATCH 04/11] modify style issues --- jsonschema/cli.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/jsonschema/cli.py b/jsonschema/cli.py index 178ea8762..649273b2f 100644 --- a/jsonschema/cli.py +++ b/jsonschema/cli.py @@ -183,7 +183,7 @@ def _namedAnyWithDefault(name): "--base-uri", help=""" use this option to indicate that the schema contains some references - to some local or remote files. With this option, the validator will + to some local or remote files. With this option, the validator will try to resolve those references as paths relative to the given schema. """, ) @@ -271,7 +271,9 @@ def load(_): else: file_prefix = "file:///{}/" if "nt" == os.name else "file://{}/" resolver = RefResolver( - base_uri=file_prefix.format(os.path.abspath(arguments["base_uri"])), + base_uri=file_prefix.format( + os.path.abspath(arguments["base_uri"]) + ), referrer=schema, ) From b936179ddc60cb88fed0a06f5bb9ebb13f4d0ae3 Mon Sep 17 00:00:00 2001 From: wilson chen Date: Sat, 29 Aug 2020 10:21:30 +0800 Subject: [PATCH 05/11] Resolve conflicts --- jsonschema/tests/test_cli.py | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/jsonschema/tests/test_cli.py b/jsonschema/tests/test_cli.py index 08e92c449..2bf0ac4d7 100644 --- a/jsonschema/tests/test_cli.py +++ b/jsonschema/tests/test_cli.py @@ -7,6 +7,7 @@ import os import subprocess import sys +import tempfile from jsonschema import Draft4Validator, Draft7Validator, __version__, cli from jsonschema.exceptions import SchemaError, ValidationError @@ -683,6 +684,32 @@ def test_successful_validation_of_just_the_schema_pretty_output(self): stderr="", ) + def test_successful_validation_with_specifying_base_uri(self): + try: + schema_file = tempfile.NamedTemporaryFile( + mode='w+', + prefix='schema', + suffix='.json', + dir='..', + delete=False + ) + self.addCleanup(os.remove, schema_file.name) + schema = """ + {"type": "object", "properties": {"KEY1": + {"$ref": %s%s#definitions/schemas"}}, + "definitions": {"schemas": {"type": "string"}}} + """ % ("\"", os.path.basename(schema_file.name)) + schema_file.write(schema) + finally: + schema_file.close() + + self.assertOutputs( + files=dict(some_schema=schema, some_instance='{"KEY1": "1"}'), + argv=["-i", "some_instance", "--base-uri", "..", "some_schema"], + stdout="", + stderr="", + ) + def test_it_validates_using_the_latest_validator_when_unspecified(self): # There isn't a better way now I can think of to ensure that the # latest version was used, given that the call to validator_for @@ -818,4 +845,4 @@ def test_no_arguments_shows_usage_notes(self): [sys.executable, "-m", "jsonschema", "--help"], stderr=subprocess.STDOUT, ) - self.assertEqual(output, output_for_help) \ No newline at end of file + self.assertEqual(output, output_for_help) From 26aa142e78ff7d788f888745ef58f07275ac3bfc Mon Sep 17 00:00:00 2001 From: willson-chen Date: Sat, 29 Aug 2020 16:03:31 +0800 Subject: [PATCH 06/11] support for cli specifying --base-uri local or remote and add test cases --- jsonschema/cli.py | 37 ++++++---- jsonschema/tests/test_cli.py | 129 ++++++++++++++++++++++++++++++++++- 2 files changed, 152 insertions(+), 14 deletions(-) diff --git a/jsonschema/cli.py b/jsonschema/cli.py index 2ae93c2a4..9314a56f8 100644 --- a/jsonschema/cli.py +++ b/jsonschema/cli.py @@ -10,6 +10,7 @@ import os import sys import traceback +import urllib import attr @@ -263,20 +264,30 @@ def load(_): if arguments["base_uri"] is None: resolver = None - elif "http:" in arguments["base_uri"] or "https:" in arguments["base_uri"]\ - or "urn:" in arguments["base_uri"]: - resolver = RefResolver( - base_uri=arguments["base_uri"], - referrer=schema, - ) else: - file_prefix = "file:///{}/" if "nt" == os.name else "file://{}/" - resolver = RefResolver( - base_uri=file_prefix.format( - os.path.abspath(arguments["base_uri"]) - ), - referrer=schema, - ) + scheme = urllib.parse.urlsplit(arguments["base_uri"]).scheme + alphabet_list = [chr(ord('a') + i) for i in range(0, 26)] + local_path_flag = True \ + if scheme == '' or scheme in alphabet_list else False + + if local_path_flag: + file_prefix = "file:///{}/" if "nt" == os.name else "file://{}/" + abs_path_flag = os.path.isabs(arguments["base_uri"]) + + resolver = RefResolver( + base_uri=file_prefix.format(arguments["base_uri"]), + referrer=schema, + ) if abs_path_flag is True else RefResolver( + base_uri=file_prefix.format( + os.path.abspath(arguments["base_uri"]) + ), + referrer=schema, + ) + else: + resolver = RefResolver( + base_uri=arguments["base_uri"], + referrer=schema, + ) validator = arguments["validator"](schema, resolver=resolver) exit_code = 0 diff --git a/jsonschema/tests/test_cli.py b/jsonschema/tests/test_cli.py index 2bf0ac4d7..3b73dce7b 100644 --- a/jsonschema/tests/test_cli.py +++ b/jsonschema/tests/test_cli.py @@ -684,7 +684,7 @@ def test_successful_validation_of_just_the_schema_pretty_output(self): stderr="", ) - def test_successful_validation_with_specifying_base_uri(self): + def test_successful_validate_with_specifying_base_uri_relative_path(self): try: schema_file = tempfile.NamedTemporaryFile( mode='w+', @@ -710,6 +710,133 @@ def test_successful_validation_with_specifying_base_uri(self): stderr="", ) + def test_failure_validate_with_specifying_base_uri_relative_path(self): + try: + schema_file = tempfile.NamedTemporaryFile( + mode='w+', + prefix='schema', + suffix='.json', + dir='..', + delete=False + ) + self.addCleanup(os.remove, schema_file.name) + schema = """ + {"type": "object", "properties": {"KEY1": + {"$ref": %s%s#definitions/schemas"}}, + "definitions": {"schemas": {"type": "string"}}} + """ % ("\"", os.path.basename(schema_file.name)) + schema_file.write(schema) + finally: + schema_file.close() + + self.assertOutputs( + files=dict(some_schema=schema, some_instance='{"KEY1": 1}'), + argv=["-i", "some_instance", "--base-uri", "..", "some_schema"], + exit_code=1, + stdout="", + stderr="1: 1 is not of type 'string'\n", + ) + + def test_successful_validate_with_specifying_base_uri_absolute_path(self): + absolute_path = os.getcwd() + try: + schema_file = tempfile.NamedTemporaryFile( + mode='w+', + prefix='schema', + suffix='.json', + dir=absolute_path, + delete=False + ) + self.addCleanup(os.remove, schema_file.name) + schema = """ + {"type": "object", "properties": {"KEY1": + {"$ref": %s%s#definitions/schemas"}}, + "definitions": {"schemas": {"type": "string"}}} + """ % ("\"", os.path.basename(schema_file.name)) + schema_file.write(schema) + finally: + schema_file.close() + + self.assertOutputs( + files=dict(some_schema=schema, some_instance='{"KEY1": "1"}'), + argv=[ + "-i", "some_instance", + "--base-uri", absolute_path, + "some_schema", + ], + stdout="", + stderr="", + ) + + def test_failure_validate_with_specifying_base_uri_absolute_path(self): + absolute_path = os.getcwd() + try: + schema_file = tempfile.NamedTemporaryFile( + mode='w+', + prefix='schema', + suffix='.json', + dir=absolute_path, + delete=False + ) + self.addCleanup(os.remove, schema_file.name) + schema = """ + {"type": "object", "properties": {"KEY1": + {"$ref": %s%s#definitions/schemas"}}, + "definitions": {"schemas": {"type": "string"}}} + """ % ("\"", os.path.basename(schema_file.name)) + schema_file.write(schema) + finally: + schema_file.close() + + self.assertOutputs( + files=dict(some_schema=schema, some_instance='{"KEY1": 1}'), + argv=[ + "-i", "some_instance", + "--base-uri", absolute_path, + "some_schema", + ], + exit_code=1, + stdout="", + stderr="1: 1 is not of type 'string'\n", + ) + + def test_successful_validate_with_specifying_base_uri_remote_path(self): + schema = """ + {"type": "object", "properties": { + "KEY1":{"$ref": "organization.json"}}} + """ + self.assertOutputs( + files=dict(some_schema=schema, + some_instance='{"KEY1": {"name": "remote"}}' + ), + argv=[ + "-i", "some_instance", + "--base-uri", "https://project-open-data.cio.gov/v1.1/schema/", + "some_schema", + ], + stdout="", + stderr="", + ) + + def test_failure_validate_with_specifying_base_uri_remote_path(self): + schema = """ + {"type": "object", "properties": { + "KEY1":{"$ref": "organization.json"}}} + """ + self.assertOutputs( + files=dict(some_schema=schema, + some_instance='{"KEY1": {"fail": "remote"}}' + ), + argv=[ + "-i", "some_instance", + "--base-uri", "https://project-open-data.cio.gov/v1.1/schema/", + "some_schema", + ], + exit_code=1, + stdout="", + stderr="{'fail': 'remote'}: 'name' is a required property\n", + ) + def test_it_validates_using_the_latest_validator_when_unspecified(self): # There isn't a better way now I can think of to ensure that the # latest version was used, given that the call to validator_for From 0955ad094e725a7c0fc34e145326f6a62f3c5c5a Mon Sep 17 00:00:00 2001 From: willson-chen Date: Thu, 3 Sep 2020 16:25:37 +0800 Subject: [PATCH 07/11] Support --base-uri. and local full path and remote URI --- jsonschema/cli.py | 32 +++++++---------------- jsonschema/tests/test_cli.py | 49 ++++++------------------------------ 2 files changed, 17 insertions(+), 64 deletions(-) diff --git a/jsonschema/cli.py b/jsonschema/cli.py index 9314a56f8..093975cca 100644 --- a/jsonschema/cli.py +++ b/jsonschema/cli.py @@ -10,7 +10,6 @@ import os import sys import traceback -import urllib import attr @@ -264,30 +263,17 @@ def load(_): if arguments["base_uri"] is None: resolver = None - else: - scheme = urllib.parse.urlsplit(arguments["base_uri"]).scheme - alphabet_list = [chr(ord('a') + i) for i in range(0, 26)] - local_path_flag = True \ - if scheme == '' or scheme in alphabet_list else False - - if local_path_flag: - file_prefix = "file:///{}/" if "nt" == os.name else "file://{}/" - abs_path_flag = os.path.isabs(arguments["base_uri"]) - - resolver = RefResolver( - base_uri=file_prefix.format(arguments["base_uri"]), - referrer=schema, - ) if abs_path_flag is True else RefResolver( - base_uri=file_prefix.format( - os.path.abspath(arguments["base_uri"]) - ), + elif arguments["base_uri"] == ".": + file_prefix = "file:///{}/" if "nt" == os.name else "file://{}/" + resolver = RefResolver( + base_uri=file_prefix.format(os.getcwd()), referrer=schema, ) - else: - resolver = RefResolver( - base_uri=arguments["base_uri"], - referrer=schema, - ) + else: + resolver = RefResolver( + base_uri=arguments["base_uri"], + referrer=schema, + ) validator = arguments["validator"](schema, resolver=resolver) exit_code = 0 diff --git a/jsonschema/tests/test_cli.py b/jsonschema/tests/test_cli.py index 3b73dce7b..63499dfe2 100644 --- a/jsonschema/tests/test_cli.py +++ b/jsonschema/tests/test_cli.py @@ -690,7 +690,7 @@ def test_successful_validate_with_specifying_base_uri_relative_path(self): mode='w+', prefix='schema', suffix='.json', - dir='..', + dir='.', delete=False ) self.addCleanup(os.remove, schema_file.name) @@ -705,7 +705,7 @@ def test_successful_validate_with_specifying_base_uri_relative_path(self): self.assertOutputs( files=dict(some_schema=schema, some_instance='{"KEY1": "1"}'), - argv=["-i", "some_instance", "--base-uri", "..", "some_schema"], + argv=["-i", "some_instance", "--base-uri", ".", "some_schema"], stdout="", stderr="", ) @@ -716,7 +716,7 @@ def test_failure_validate_with_specifying_base_uri_relative_path(self): mode='w+', prefix='schema', suffix='.json', - dir='..', + dir='.', delete=False ) self.addCleanup(os.remove, schema_file.name) @@ -731,7 +731,7 @@ def test_failure_validate_with_specifying_base_uri_relative_path(self): self.assertOutputs( files=dict(some_schema=schema, some_instance='{"KEY1": 1}'), - argv=["-i", "some_instance", "--base-uri", "..", "some_schema"], + argv=["-i", "some_instance", "--base-uri", ".", "some_schema"], exit_code=1, stdout="", stderr="1: 1 is not of type 'string'\n", @@ -757,6 +757,8 @@ def test_successful_validate_with_specifying_base_uri_absolute_path(self): finally: schema_file.close() + file_prefix = "file:///{}/" if "nt" == os.name else "file://{}/" + absolute_path = file_prefix.format(absolute_path) self.assertOutputs( files=dict(some_schema=schema, some_instance='{"KEY1": "1"}'), argv=[ @@ -788,6 +790,8 @@ def test_failure_validate_with_specifying_base_uri_absolute_path(self): finally: schema_file.close() + file_prefix = "file:///{}/" if "nt" == os.name else "file://{}/" + absolute_path = file_prefix.format(absolute_path) self.assertOutputs( files=dict(some_schema=schema, some_instance='{"KEY1": 1}'), argv=[ @@ -800,43 +804,6 @@ def test_failure_validate_with_specifying_base_uri_absolute_path(self): stderr="1: 1 is not of type 'string'\n", ) - def test_successful_validate_with_specifying_base_uri_remote_path(self): - schema = """ - {"type": "object", "properties": { - "KEY1":{"$ref": "organization.json"}}} - """ - self.assertOutputs( - files=dict(some_schema=schema, - some_instance='{"KEY1": {"name": "remote"}}' - ), - argv=[ - "-i", "some_instance", - "--base-uri", "https://project-open-data.cio.gov/v1.1/schema/", - "some_schema", - ], - stdout="", - stderr="", - ) - - def test_failure_validate_with_specifying_base_uri_remote_path(self): - schema = """ - {"type": "object", "properties": { - "KEY1":{"$ref": "organization.json"}}} - """ - self.assertOutputs( - files=dict(some_schema=schema, - some_instance='{"KEY1": {"fail": "remote"}}' - ), - argv=[ - "-i", "some_instance", - "--base-uri", "https://project-open-data.cio.gov/v1.1/schema/", - "some_schema", - ], - exit_code=1, - stdout="", - stderr="{'fail': 'remote'}: 'name' is a required property\n", - ) - def test_it_validates_using_the_latest_validator_when_unspecified(self): # There isn't a better way now I can think of to ensure that the # latest version was used, given that the call to validator_for From a0ec5e9dff5c987966efe240f69f49e3c98696f8 Mon Sep 17 00:00:00 2001 From: willson-chen Date: Mon, 14 Sep 2020 20:42:41 +0800 Subject: [PATCH 08/11] Optimize the input parameters of '--base-uri' --- jsonschema/cli.py | 18 +++--------- jsonschema/tests/test_cli.py | 53 ------------------------------------ 2 files changed, 4 insertions(+), 67 deletions(-) diff --git a/jsonschema/cli.py b/jsonschema/cli.py index 093975cca..c33352e15 100644 --- a/jsonschema/cli.py +++ b/jsonschema/cli.py @@ -7,7 +7,6 @@ import argparse import errno import json -import os import sys import traceback @@ -16,7 +15,7 @@ from jsonschema import __version__ from jsonschema._reflect import namedAny from jsonschema.exceptions import SchemaError -from jsonschema.validators import validator_for, RefResolver +from jsonschema.validators import RefResolver, validator_for class _CannotLoadFile(Exception): @@ -261,19 +260,10 @@ def load(_): raise _CannotLoadFile() instances = [""] - if arguments["base_uri"] is None: - resolver = None - elif arguments["base_uri"] == ".": - file_prefix = "file:///{}/" if "nt" == os.name else "file://{}/" - resolver = RefResolver( - base_uri=file_prefix.format(os.getcwd()), + resolver = RefResolver( + base_uri=arguments["base_uri"], referrer=schema, - ) - else: - resolver = RefResolver( - base_uri=arguments["base_uri"], - referrer=schema, - ) + ) if arguments["base_uri"] is not None else None validator = arguments["validator"](schema, resolver=resolver) exit_code = 0 diff --git a/jsonschema/tests/test_cli.py b/jsonschema/tests/test_cli.py index 63499dfe2..d549b6d9e 100644 --- a/jsonschema/tests/test_cli.py +++ b/jsonschema/tests/test_cli.py @@ -684,59 +684,6 @@ def test_successful_validation_of_just_the_schema_pretty_output(self): stderr="", ) - def test_successful_validate_with_specifying_base_uri_relative_path(self): - try: - schema_file = tempfile.NamedTemporaryFile( - mode='w+', - prefix='schema', - suffix='.json', - dir='.', - delete=False - ) - self.addCleanup(os.remove, schema_file.name) - schema = """ - {"type": "object", "properties": {"KEY1": - {"$ref": %s%s#definitions/schemas"}}, - "definitions": {"schemas": {"type": "string"}}} - """ % ("\"", os.path.basename(schema_file.name)) - schema_file.write(schema) - finally: - schema_file.close() - - self.assertOutputs( - files=dict(some_schema=schema, some_instance='{"KEY1": "1"}'), - argv=["-i", "some_instance", "--base-uri", ".", "some_schema"], - stdout="", - stderr="", - ) - - def test_failure_validate_with_specifying_base_uri_relative_path(self): - try: - schema_file = tempfile.NamedTemporaryFile( - mode='w+', - prefix='schema', - suffix='.json', - dir='.', - delete=False - ) - self.addCleanup(os.remove, schema_file.name) - schema = """ - {"type": "object", "properties": {"KEY1": - {"$ref": %s%s#definitions/schemas"}}, - "definitions": {"schemas": {"type": "string"}}} - """ % ("\"", os.path.basename(schema_file.name)) - schema_file.write(schema) - finally: - schema_file.close() - - self.assertOutputs( - files=dict(some_schema=schema, some_instance='{"KEY1": 1}'), - argv=["-i", "some_instance", "--base-uri", ".", "some_schema"], - exit_code=1, - stdout="", - stderr="1: 1 is not of type 'string'\n", - ) - def test_successful_validate_with_specifying_base_uri_absolute_path(self): absolute_path = os.getcwd() try: From 1bfbb9064c0c2da5df5ea0f7ed03623f8418f278 Mon Sep 17 00:00:00 2001 From: willson-chen Date: Wed, 16 Sep 2020 14:29:21 +0800 Subject: [PATCH 09/11] Optimizing test cases and add invalid '--base-uri' test --- jsonschema/tests/test_cli.py | 71 +++++++++++++++++++++++------------- 1 file changed, 45 insertions(+), 26 deletions(-) diff --git a/jsonschema/tests/test_cli.py b/jsonschema/tests/test_cli.py index d549b6d9e..4ba095f8b 100644 --- a/jsonschema/tests/test_cli.py +++ b/jsonschema/tests/test_cli.py @@ -10,7 +10,11 @@ import tempfile from jsonschema import Draft4Validator, Draft7Validator, __version__, cli -from jsonschema.exceptions import SchemaError, ValidationError +from jsonschema.exceptions import ( + RefResolutionError, + SchemaError, + ValidationError, +) from jsonschema.tests._helpers import captured_output from jsonschema.validators import _LATEST_VERSION, validate @@ -685,32 +689,29 @@ def test_successful_validation_of_just_the_schema_pretty_output(self): ) def test_successful_validate_with_specifying_base_uri_absolute_path(self): - absolute_path = os.getcwd() try: schema_file = tempfile.NamedTemporaryFile( mode='w+', - prefix='schema', - suffix='.json', - dir=absolute_path, delete=False ) self.addCleanup(os.remove, schema_file.name) schema = """ - {"type": "object", "properties": {"KEY1": - {"$ref": %s%s#definitions/schemas"}}, - "definitions": {"schemas": {"type": "string"}}} - """ % ("\"", os.path.basename(schema_file.name)) - schema_file.write(schema) + {"$ref": "%s#definitions/num"} + """ % (os.path.basename(schema_file.name)) + tmp_schema = """{"definitions": {"num": {"type": "integer"}}}""" + schema_file.write(tmp_schema) finally: schema_file.close() file_prefix = "file:///{}/" if "nt" == os.name else "file://{}/" - absolute_path = file_prefix.format(absolute_path) + absolute_dir_path = file_prefix.format( + os.path.dirname(schema_file.name) + ) self.assertOutputs( - files=dict(some_schema=schema, some_instance='{"KEY1": "1"}'), + files=dict(some_schema=schema, some_instance='1'), argv=[ "-i", "some_instance", - "--base-uri", absolute_path, + "--base-uri", absolute_dir_path, "some_schema", ], stdout="", @@ -718,39 +719,57 @@ def test_successful_validate_with_specifying_base_uri_absolute_path(self): ) def test_failure_validate_with_specifying_base_uri_absolute_path(self): - absolute_path = os.getcwd() try: schema_file = tempfile.NamedTemporaryFile( mode='w+', - prefix='schema', - suffix='.json', - dir=absolute_path, delete=False ) self.addCleanup(os.remove, schema_file.name) schema = """ - {"type": "object", "properties": {"KEY1": - {"$ref": %s%s#definitions/schemas"}}, - "definitions": {"schemas": {"type": "string"}}} - """ % ("\"", os.path.basename(schema_file.name)) - schema_file.write(schema) + {"$ref": "%s#definitions/num"} + """ % (os.path.basename(schema_file.name)) + tmp_schema = """{"definitions": {"num": {"type": "integer"}}}""" + schema_file.write(tmp_schema) finally: schema_file.close() file_prefix = "file:///{}/" if "nt" == os.name else "file://{}/" - absolute_path = file_prefix.format(absolute_path) + absolute_dir_path = file_prefix.format( + os.path.dirname(schema_file.name) + ) self.assertOutputs( - files=dict(some_schema=schema, some_instance='{"KEY1": 1}'), + files=dict(some_schema=schema, some_instance='"1"'), argv=[ "-i", "some_instance", - "--base-uri", absolute_path, + "--base-uri", absolute_dir_path, "some_schema", ], exit_code=1, stdout="", - stderr="1: 1 is not of type 'string'\n", + stderr="1: '1' is not of type 'integer'\n", ) + def test_validate_with_specifying_invalid_base_uri(self): + schema = """ + {"$ref": "foo.json#definitions/num"} + """ + instance = '1' + + with self.assertRaises(RefResolutionError) as e: + self.assertOutputs( + files=dict( + some_schema=schema, + some_instance=instance, + ), + argv=[ + "-i", "some_instance", + "--base-uri", ".", + "some_schema", + ], + ) + error = str(e.exception) + self.assertEqual(error, "unknown url type: 'foo.json'") + def test_it_validates_using_the_latest_validator_when_unspecified(self): # There isn't a better way now I can think of to ensure that the # latest version was used, given that the call to validator_for From 9502934ca18004712c848f0463d14a014b685420 Mon Sep 17 00:00:00 2001 From: Julian Berman Date: Thu, 15 Oct 2020 10:07:45 -0400 Subject: [PATCH 10/11] Minor formatting and wording. --- jsonschema/cli.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/jsonschema/cli.py b/jsonschema/cli.py index c33352e15..a6ca43c8e 100644 --- a/jsonschema/cli.py +++ b/jsonschema/cli.py @@ -181,9 +181,9 @@ def _namedAnyWithDefault(name): parser.add_argument( "--base-uri", help=""" - use this option to indicate that the schema contains some references - to some local or remote files. With this option, the validator will - try to resolve those references as paths relative to the given schema. + a base URI to assign to the provided schema, even if it does not + declare one (via e.g. $id). This option can be used if you wish to + resolve relative references to a particular URI (or local path) """, ) parser.add_argument( @@ -261,9 +261,9 @@ def load(_): instances = [""] resolver = RefResolver( - base_uri=arguments["base_uri"], - referrer=schema, - ) if arguments["base_uri"] is not None else None + base_uri=arguments["base_uri"], + referrer=schema, + ) if arguments["base_uri"] is not None else None validator = arguments["validator"](schema, resolver=resolver) exit_code = 0 From d106511d9fe06d8744ba7ecae5ab72cc19247e9f Mon Sep 17 00:00:00 2001 From: Julian Berman Date: Thu, 15 Oct 2020 17:30:38 -0400 Subject: [PATCH 11/11] And now tidy up the tests. --- jsonschema/tests/test_cli.py | 90 ++++++++++++++++++------------------ 1 file changed, 45 insertions(+), 45 deletions(-) diff --git a/jsonschema/tests/test_cli.py b/jsonschema/tests/test_cli.py index 4ba095f8b..22528feb5 100644 --- a/jsonschema/tests/test_cli.py +++ b/jsonschema/tests/test_cli.py @@ -1,5 +1,6 @@ from io import StringIO from json import JSONDecodeError +from pathlib import Path from textwrap import dedent from unittest import TestCase import errno @@ -688,60 +689,40 @@ def test_successful_validation_of_just_the_schema_pretty_output(self): stderr="", ) - def test_successful_validate_with_specifying_base_uri_absolute_path(self): - try: - schema_file = tempfile.NamedTemporaryFile( - mode='w+', - delete=False - ) - self.addCleanup(os.remove, schema_file.name) - schema = """ - {"$ref": "%s#definitions/num"} - """ % (os.path.basename(schema_file.name)) - tmp_schema = """{"definitions": {"num": {"type": "integer"}}}""" - schema_file.write(tmp_schema) - finally: - schema_file.close() + def test_successful_validation_via_explicit_base_uri(self): + ref_schema_file = tempfile.NamedTemporaryFile(delete=False) + self.addCleanup(os.remove, ref_schema_file.name) + + ref_path = Path(ref_schema_file.name) + ref_path.write_text('{"definitions": {"num": {"type": "integer"}}}') + + schema = f'{{"$ref": "{ref_path.name}#definitions/num"}}' - file_prefix = "file:///{}/" if "nt" == os.name else "file://{}/" - absolute_dir_path = file_prefix.format( - os.path.dirname(schema_file.name) - ) self.assertOutputs( files=dict(some_schema=schema, some_instance='1'), argv=[ "-i", "some_instance", - "--base-uri", absolute_dir_path, + "--base-uri", ref_path.parent.as_uri() + "/", "some_schema", ], stdout="", stderr="", ) - def test_failure_validate_with_specifying_base_uri_absolute_path(self): - try: - schema_file = tempfile.NamedTemporaryFile( - mode='w+', - delete=False - ) - self.addCleanup(os.remove, schema_file.name) - schema = """ - {"$ref": "%s#definitions/num"} - """ % (os.path.basename(schema_file.name)) - tmp_schema = """{"definitions": {"num": {"type": "integer"}}}""" - schema_file.write(tmp_schema) - finally: - schema_file.close() + def test_unsuccessful_validation_via_explicit_base_uri(self): + ref_schema_file = tempfile.NamedTemporaryFile(delete=False) + self.addCleanup(os.remove, ref_schema_file.name) + + ref_path = Path(ref_schema_file.name) + ref_path.write_text('{"definitions": {"num": {"type": "integer"}}}') + + schema = f'{{"$ref": "{ref_path.name}#definitions/num"}}' - file_prefix = "file:///{}/" if "nt" == os.name else "file://{}/" - absolute_dir_path = file_prefix.format( - os.path.dirname(schema_file.name) - ) self.assertOutputs( files=dict(some_schema=schema, some_instance='"1"'), argv=[ "-i", "some_instance", - "--base-uri", absolute_dir_path, + "--base-uri", ref_path.parent.as_uri() + "/", "some_schema", ], exit_code=1, @@ -749,11 +730,28 @@ def test_failure_validate_with_specifying_base_uri_absolute_path(self): stderr="1: '1' is not of type 'integer'\n", ) - def test_validate_with_specifying_invalid_base_uri(self): - schema = """ - {"$ref": "foo.json#definitions/num"} - """ - instance = '1' + def test_nonexistent_file_with_explicit_base_uri(self): + schema = '{"$ref": "someNonexistentFile.json#definitions/num"}' + instance = "1" + + with self.assertRaises(RefResolutionError) as e: + self.assertOutputs( + files=dict( + some_schema=schema, + some_instance=instance, + ), + argv=[ + "-i", "some_instance", + "--base-uri", Path.cwd().as_uri(), + "some_schema", + ], + ) + error = str(e.exception) + self.assertIn("/someNonexistentFile.json'", error) + + def test_invalid_exlicit_base_uri(self): + schema = '{"$ref": "foo.json#definitions/num"}' + instance = "1" with self.assertRaises(RefResolutionError) as e: self.assertOutputs( @@ -763,12 +761,14 @@ def test_validate_with_specifying_invalid_base_uri(self): ), argv=[ "-i", "some_instance", - "--base-uri", ".", + "--base-uri", "not@UR1", "some_schema", ], ) error = str(e.exception) - self.assertEqual(error, "unknown url type: 'foo.json'") + self.assertEqual( + error, "unknown url type: 'foo.json'", + ) def test_it_validates_using_the_latest_validator_when_unspecified(self): # There isn't a better way now I can think of to ensure that the