Skip to content

Commit

Permalink
use jsonschema instead of pydantic
Browse files Browse the repository at this point in the history
  • Loading branch information
jaimergp committed Nov 2, 2023
1 parent 1dd4f09 commit 04dc682
Show file tree
Hide file tree
Showing 6 changed files with 68 additions and 16 deletions.
33 changes: 25 additions & 8 deletions conda_build/post.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Copyright (C) 2014 Anaconda, Inc
# SPDX-License-Identifier: BSD-3-Clause
import json
import locale
import os
import re
Expand Down Expand Up @@ -1688,26 +1689,42 @@ def check_menuinst_json(files, prefix):
print("Validating Menu/*.json files")
log = utils.get_logger(__name__)
try:
from json import JSONDecodeError

from menuinst._schema import validate
from pydantic import ValidationError
import jsonschema
from menuinst.utils import data_path
except ModuleNotFoundError as exc:
log.warning(
"Found 'Menu/*.json' files but couldn't validate:%s",
"Found 'Menu/*.json' files but couldn't validate: %s",
", ".join(json_files),
exc_info=exc,
)
return

try:
schema_path = data_path("menuinst.schema.json")
with open(schema_path) as f:
schema = json.load(f)
ValidatorClass = jsonschema.validators.validator_for(schema)
validator = ValidatorClass(schema)
except (jsonschema.SchemaError, json.JSONDecodeError, OSError) as exc:
log.warning("'%s' is not a valid menuinst schema", schema_path, exc_info=exc)
return

for json_file in json_files:
try:
validate(join(prefix, json_file))
except (ValidationError, JSONDecodeError) as exc:
with open(join(prefix, json_file)) as f:
text = f.read()
if "$schema" not in text:
log.warning("menuinst v1 JSON document '%s' won't be validated.", json_file)
continue
validator.validate(json.loads(text))
except (jsonschema.ValidationError, json.JSONDecodeError) as exc:
log.warning(
"'%s' is not a valid menuinst JSON file!",
"'%s' is not a valid menuinst JSON document!",
json_file,
exc_info=exc,
)
else:
log.info("'%s' is a valid menuinst JSON document", json_file)


def post_build(m, files, build_python, host_prefix=None, is_already_linked=False):
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ dependencies = [
"six",
"tomli ; python_version<'3.11'",
"tqdm",
"pydantic <2.0",
"jsonschema >=4.19",
"menuinst >=2"
]
dynamic = ["version"]
Expand Down
2 changes: 1 addition & 1 deletion recipe/meta.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ requirements:
- tomli # [py<311]
- tqdm
- menuinst >=2
- pydantic <2.0a0
- jsonschema >=4.19
run_constrained:
- conda-verify >=3.1.0

Expand Down
2 changes: 1 addition & 1 deletion tests/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,5 @@ setuptools_scm # needed for devenv version detection
tomli
tqdm
# NEW for menuinst validation
pydantic <2.0a0
jsonschema
conda-forge::menuinst >=2
1 change: 0 additions & 1 deletion tests/test-recipes/metadata/menu_json_validation/menu.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
{
"name": "Example",
"description": "This will install to Windows and Linux with default options. MacOS has a custom option.",
"icon": null,
"command": [
"{{ PYTHON }}",
"-c",
Expand Down
44 changes: 40 additions & 4 deletions tests/test_post.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Copyright (C) 2014 Anaconda, Inc
# SPDX-License-Identifier: BSD-3-Clause
import json
import logging
import os
import shutil
Expand Down Expand Up @@ -96,14 +97,18 @@ def test_pypi_installer_metadata(testing_config):

def test_menuinst_validation_passes(testing_config, caplog):
recipe = os.path.join(metadata_dir, "menu_json_validation")
with caplog.at_level(logging.WARNING):
with caplog.at_level(logging.INFO):
pkg = api.build(recipe, config=testing_config, notest=True)[0]

print(caplog.text)
assert "Found 'Menu/*.json' files but couldn't validate:" not in caplog.text
assert "not a valid menuinst JSON file" not in caplog.text
assert "is a valid menuinst JSON document" in caplog.text
assert package_has_file(pkg, "Menu/menu_json_validation.json")


def test_menuinst_validation_fails(testing_config, caplog):
def test_menuinst_validation_fails_bad_json(testing_config, caplog):
"1st check - non-parsable JSON"
recipe = os.path.join(metadata_dir, "menu_json_validation")
original_content = None

Expand All @@ -113,9 +118,40 @@ def test_menuinst_validation_fails(testing_config, caplog):
f.write("Make this an invalid JSON")

with caplog.at_level(logging.WARNING):
api.build(recipe, config=testing_config, notest=True)[0]
assert "not a valid menuinst JSON file" in caplog.text
api.build(recipe, config=testing_config, notest=True)

print(caplog.text)
assert "Found 'Menu/*.json' files but couldn't validate:" not in caplog.text
assert "not a valid menuinst JSON document" in caplog.text
assert "JSONDecodeError" in caplog.text
finally:
if original_content is not None:
with open(os.path.join(recipe, "menu.json"), "w") as f:
f.write(original_content)


def test_menuinst_validation_fails_bad_schema(testing_config, caplog):
"2nd check - valid JSON, but invalid content fails schema validation"
recipe = os.path.join(metadata_dir, "menu_json_validation")
original_content = None

try:
with open(os.path.join(recipe, "menu.json")) as f:
original_content = f.read()

bad_data = json.loads(original_content)
bad_data["menu_items"][0]["icon"] = None
with open(os.path.join(recipe, "menu.json"), "w") as f:
json.dump(bad_data, f)

with caplog.at_level(logging.WARNING):
api.build(recipe, config=testing_config, notest=True)

print(caplog.text)
assert "Found 'Menu/*.json' files but couldn't validate:" not in caplog.text
assert "not a valid menuinst JSON document" in caplog.text
assert "ValidationError" in caplog.text
assert "is a valid menuinst JSON document" not in caplog.text
finally:
if original_content is not None:
with open(os.path.join(recipe, "menu.json"), "w") as f:
Expand Down

0 comments on commit 04dc682

Please sign in to comment.