Skip to content
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

validate: Clarify output messages #441

Merged
merged 3 commits into from
Feb 25, 2020
Merged
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
5 changes: 3 additions & 2 deletions augur/export_v2.py
Original file line number Diff line number Diff line change
Expand Up @@ -400,12 +400,13 @@ def set_filters(data_json, config):
def validate_data_json(filename):
print("Validating produced JSON")
try:
validate_v2(json_v2=filename)
validate_v2(main_json=filename)
except ValidateError as e:
print(e)
print("\n------------------------")
print("Validation of {} failed. Please check this in a local instance of `auspice`, as it is not expected to display correctly. ".format(filename))
print("------------------------")
sys.exit(2)


def set_panels(data_json, config, cmd_line_panels):
Expand Down Expand Up @@ -813,7 +814,7 @@ def get_config(args):
config = read_config(args.auspice_config)
try:
print("Validating config file {} against the JSON schema".format(args.auspice_config))
validate_auspice_config_v2(config_json=config)
validate_auspice_config_v2(args.auspice_config)
except ValidateError:
print("Validation of {} failed. Please check the formatting of this file & refer to the augur documentation for further help. ".format(args.auspice_config))
sys.exit(2)
Expand Down
2 changes: 1 addition & 1 deletion augur/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ def read_node_data(fnames, tree=None):
tmp_data = json.load(jfile)
if tmp_data.get("annotations"):
try:
validate(tmp_data.get("annotations"), load_json_schema("schema-annotations.json"))
validate(tmp_data.get("annotations"), load_json_schema("schema-annotations.json"), fname)
except ValidateError as err:
print("{} contains an `annotations` block of an invalid JSON format. "
"Was it produced by different version of augur the one you are currently using ({})? "
Expand Down
53 changes: 33 additions & 20 deletions augur/validate.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@ def load_json(path):
raise ValidateError("Supplied JSON to validate ({}) is not a valid JSON".format(path))
return jsonToValidate

def validate(jsonToValidate, schema):
def validate(jsonToValidate, schema, filename):
print("Validating schema of {!r}...".format(filename))
try:
schema.validate(jsonToValidate) # https://python-jsonschema.readthedocs.io/en/latest/validate/
except jsonschema.exceptions.ValidationError:
Expand All @@ -67,45 +68,57 @@ def validate(jsonToValidate, schema):
trace = ["..."] + trace[-5:]
trace = [str(x) for x in trace]
print("\tERROR: {}. Trace: {}".format(error.message, " - ".join(trace)), file=sys.stderr)
raise ValidateError("Validation failed.")
else:
print("Validation succeeded")
raise ValidateError("Validation of {!r} failed.".format(filename))

def auspice_config_v2(config_json, **kwargs):
schema = load_json_schema("schema-auspice-config-v2.json")
jsonToValidate = load_json(config_json) if isinstance(config_json, str) else config_json
validate(jsonToValidate, schema)
config = load_json(config_json)
validate(config, schema, config_json)

def export_v2(json_v2, **kwargs):
def export_v2(main_json, **kwargs):
# validationWarnings = ValidationWarnings()
# validationErrors = ValidationErrors()
schema = load_json_schema("schema-export-v2.json")
if json_v2.endswith("frequencies.json") or json_v2.endswith("entropy.json") or json_v2.endswith("sequences.json"):
main_schema = load_json_schema("schema-export-v2.json")

if main_json.endswith("frequencies.json") or main_json.endswith("entropy.json") or main_json.endswith("sequences.json"):
raise ValidateError("This validation subfunction is for the main `augur export v2` JSON only.")
jsonToValidate = load_json(json_v2)
validate(jsonToValidate, schema)
verifyMainJSONIsInternallyConsistent(jsonToValidate, ValidateError)

main = load_json(main_json)
validate(main, main_schema, main_json)

if verifyMainJSONIsInternallyConsistent(main, ValidateError):
print("Validation of {!r} succeeded.".format(main_json))
else:
print("Validation of {!r} succeeded, but there were warnings you may want to resolve.".format(main_json))


def export_v1(meta_json, tree_json, **kwargs):
schema_meta = load_json_schema("schema-export-v1-meta.json")
schema_tree = load_json_schema("schema-export-v1-tree.json")
meta_schema = load_json_schema("schema-export-v1-meta.json")
tree_schema = load_json_schema("schema-export-v1-tree.json")

if not meta_json.endswith("_meta.json"):
raise ValidateError("The metadata JSON pathname {} must end with '_meta.json'.".format(meta_json))

if not tree_json.endswith("_tree.json"):
raise ValidateError("The metadata JSON pathname {} must end with '_tree.json'.".format(tree_json))
meta_json = load_json(meta_json)
tree_json = load_json(tree_json)
validate(meta_json, schema_meta)
validate(tree_json, schema_tree)
verifyMetaAndOrTreeJSONsAreInternallyConsistent(meta_json, tree_json, ValidateError)

meta = load_json(meta_json)
tree = load_json(tree_json)

validate(meta, meta_schema, meta_json)
validate(tree, tree_schema, tree_json)

if verifyMetaAndOrTreeJSONsAreInternallyConsistent(meta, tree, ValidateError):
print("Validation of {!r} and {!r} succeeded.".format(meta_json, tree_json))
else:
print("Validation of {!r} and {!r} succeeded, but there were warnings you may want to resolve.".format(meta_json, tree_json))


def register_arguments(parser):
subparsers = parser.add_subparsers(dest="subcommand", help="Which file(s) do you want to validate?")

subparsers.add_parser("export-v2", help="validate JSON intended for auspice v2") \
.add_argument('json_v2', metavar='JSON', help="exported (main) v2 auspice JSON")
.add_argument('main_json', metavar='JSON', help="exported (main) v2 auspice JSON")

export_v1 = subparsers.add_parser("export-v1", help="validate tree+meta JSONs intended for auspice v1")
export_v1.add_argument('meta_json', metavar='META-JSON', help="exported (v1) meta JSON")
Expand Down
14 changes: 8 additions & 6 deletions augur/validate_export.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ def warn(msg):
warnings = True
print("\tWARNING: ", msg, file=sys.stderr)

print("Validating that the JSON is internally consistent")
print("Validating that the JSON is internally consistent...")

if "entropy" in data["meta"]["panels"] and "genome_annotations" not in data["meta"]:
warn("The entropy panel has been specified but annotations don't exist.")
Expand Down Expand Up @@ -144,10 +144,7 @@ def warn(msg):
if gene not in data["meta"]["genome_annotations"]:
warn("The tree defined mutations on gene {} which doesn't appear in the metadata annotations object.".format(gene))

if not warnings:
print("Validation succeeded")
else:
print("Validation failed")
return not warnings


def collectTreeAttrsV1(root):
Expand Down Expand Up @@ -199,11 +196,14 @@ def verifyMetaAndOrTreeJSONsAreInternallyConsistent(meta_json, tree_json, Valida
Check all possible sources of conflict internally & between the metadata & tree JSONs
This is only that which cannot be checked by the schemas
"""
warnings = False
def warn(msg):
nonlocal warnings
warnings = True
print("\tWARNING: ", msg, file=sys.stderr)


print("Validating that meta + tree JSONs are internally consistent... ")
print("Validating that meta + tree JSONs are internally consistent...")
mj = meta_json

if "panels" in mj and "entropy" in mj["panels"] and "annotations" not in mj:
Expand Down Expand Up @@ -260,3 +260,5 @@ def warn(msg):
for gene in genes_with_aa_muts:
if gene not in mj["annotations"]:
warn("The tree defined AA mutations on gene {} which doesn't appear in the metadata annotations object.".format(gene))

return not warnings