Skip to content

Commit

Permalink
Replace our use of jsonschema's deprecated RefResolver with the refer…
Browse files Browse the repository at this point in the history
…encing package.
  • Loading branch information
bartfeenstra committed Feb 14, 2024
1 parent 52ed8b3 commit 1bd1f62
Show file tree
Hide file tree
Showing 8 changed files with 85 additions and 77 deletions.
11 changes: 4 additions & 7 deletions betty/assets/public/static/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -123,13 +123,7 @@
"required": [
"$schema",
"id",
"parents",
"children",
"siblings",
"citations",
"links",
"presences",
"private"
"parents"
],
"patternProperties": {
"^@": {
Expand Down Expand Up @@ -600,6 +594,9 @@
"link": {
"type": "object",
"properties": {
"$schema": {
"$ref": "#/definitions/schema"
},
"label": {
"type": "string",
"description": "The human-readable label, or link text."
Expand Down
4 changes: 2 additions & 2 deletions betty/generate.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
from betty.model.ancestry import is_public
from betty.openapi import Specification
from betty.serde.dump import DictDump, Dump
from betty.string import camel_case_to_kebab_case, camel_case_to_snake_case
from betty.string import camel_case_to_kebab_case, camel_case_to_snake_case, upper_camel_case_to_lower_camel_case
from betty.task import Context

_GenerationProcessPoolTaskP = ParamSpec('_GenerationProcessPoolTaskP')
Expand Down Expand Up @@ -314,7 +314,7 @@ async def _generate_entity_type_list_json(
entity_type_name_fs = camel_case_to_kebab_case(get_entity_type_name(entity_type))
entity_type_path = app.project.configuration.www_directory_path / entity_type_name_fs
data: DictDump[Dump] = {
'$schema': app.static_url_generator.generate('schema.json#/definitions/%sCollection' % entity_type_name, absolute=True),
'$schema': app.static_url_generator.generate(f'schema.json#/definitions/{upper_camel_case_to_lower_camel_case(entity_type_name)}Collection', absolute=True),
'collection': []
}
for entity in app.project.ancestry[entity_type]:
Expand Down
23 changes: 14 additions & 9 deletions betty/json.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,29 @@
from os import path
from typing import Any, TypeVar

import jsonschema
from jsonschema import RefResolver
from jsonschema.validators import Draft202012Validator
from referencing import Resource, Registry

from betty.app import App

T = TypeVar('T')


def validate(data: Any, schema_definition: str, app: App) -> None:
def validate(data: Any, app: App) -> None:
"""
Validate JSON against the Betty JSON schema.
"""
with open(path.join(path.dirname(__file__), 'assets', 'public', 'static', 'schema.json'), encoding='utf-8') as f:
json_data = f.read()
schema = stdjson.loads(json_data)
# @todo Can we set the schema ID somehow without making the entire JSON schema file a Jinja2 template?
schema_data = stdjson.loads(json_data)
schema_id = app.static_url_generator.generate('schema.json', absolute=True)
schema['$id'] = schema_id
ref_resolver = RefResolver(schema_id, schema)
jsonschema.validate(
data, schema['definitions'][schema_definition], resolver=ref_resolver)
schema_data['$id'] = schema_id
schema = Resource.from_contents(schema_data)
schema_registry: Registry[Any] = schema @ Registry()
validator = Draft202012Validator(
{
'$ref': data['$schema'],
},
registry=schema_registry,
)
validator.validate(data)
14 changes: 7 additions & 7 deletions betty/model/ancestry.py
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ def label(self) -> Str:

async def dump_linked_data(self, app: App) -> DictDump[Dump]:
dump = await super().dump_linked_data(app)
dump['$schema'] = app.static_url_generator.generate('schema.json#/definitions/note')
dump['$schema'] = app.static_url_generator.generate('schema.json#/definitions/note', absolute=True)
dump['@type'] = 'https://schema.org/Thing'
if self.public:
dump['text'] = self.text
Expand Down Expand Up @@ -463,7 +463,7 @@ def label(self) -> Str:

async def dump_linked_data(self, app: App) -> DictDump[Dump]:
dump = await super().dump_linked_data(app)
dump['$schema'] = app.static_url_generator.generate('schema.json#/definitions/file')
dump['$schema'] = app.static_url_generator.generate('schema.json#/definitions/file', absolute=True)
dump['entities'] = [
app.static_url_generator.generate(f'/{camel_case_to_kebab_case(get_entity_type_name(entity))}/{quote(entity.id)}/index.json')
for entity
Expand Down Expand Up @@ -603,7 +603,7 @@ def label(self) -> Str:

async def dump_linked_data(self, app: App) -> DictDump[Dump]:
dump = await super().dump_linked_data(app)
dump['$schema'] = app.static_url_generator.generate('schema.json#/definitions/source')
dump['$schema'] = app.static_url_generator.generate('schema.json#/definitions/source', absolute=True)
dump['@type'] = 'https://schema.org/Thing'
dump['contains'] = [
app.static_url_generator.generate(f'/source/{quote(contained.id)}/index.json')
Expand Down Expand Up @@ -719,7 +719,7 @@ def label(self) -> Str:

async def dump_linked_data(self, app: App) -> DictDump[Dump]:
dump = await super().dump_linked_data(app)
dump['$schema'] = app.static_url_generator.generate('schema.json#/definitions/citation')
dump['$schema'] = app.static_url_generator.generate('schema.json#/definitions/citation', absolute=True)
dump['@type'] = 'https://schema.org/Thing'
dump['facts'] = [
app.static_url_generator.generate(f'/{camel_case_to_kebab_case(get_entity_type_name(fact))}/{quote(fact.id)}/index.json')
Expand Down Expand Up @@ -938,7 +938,7 @@ def associated_files(self) -> Iterable[File]:

async def dump_linked_data(self, app: App) -> DictDump[Dump]:
dump = await super().dump_linked_data(app)
dump['$schema'] = app.static_url_generator.generate('schema.json#/definitions/place')
dump['$schema'] = app.static_url_generator.generate('schema.json#/definitions/place', absolute=True)
dump_context(
dump,
names='name',
Expand Down Expand Up @@ -1242,7 +1242,7 @@ def associated_files(self) -> Iterable[File]:

async def dump_linked_data(self, app: App) -> DictDump[Dump]:
dump = await super().dump_linked_data(app)
dump['$schema'] = app.static_url_generator.generate('schema.json#/definitions/event')
dump['$schema'] = app.static_url_generator.generate('schema.json#/definitions/event', absolute=True)
dump_context(dump, presences='performer')
dump['@type'] = 'https://schema.org/Event'
dump['type'] = self.event_type.name()
Expand Down Expand Up @@ -1513,7 +1513,7 @@ def label(self) -> Str:

async def dump_linked_data(self, app: App) -> DictDump[Dump]:
dump = await super().dump_linked_data(app)
dump['$schema'] = app.static_url_generator.generate('schema.json#/definitions/person')
dump['$schema'] = app.static_url_generator.generate('schema.json#/definitions/person', absolute=True)
dump_context(
dump,
names='name',
Expand Down
2 changes: 1 addition & 1 deletion betty/tests/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,6 @@ async def assert_betty_json(
betty_json = await f.read()
betty_json_data = stdjson.loads(betty_json)
if schema_definition:
json.validate(betty_json_data, schema_definition, app)
json.validate(betty_json_data, app)

return betty_json_file_path
Loading

0 comments on commit 1bd1f62

Please sign in to comment.