Skip to content

Commit

Permalink
Migrate RefResolver to referencing.Registry (#80)
Browse files Browse the repository at this point in the history
Co-authored-by: Julian Berman <[email protected]>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Steven Silvester <[email protected]>
  • Loading branch information
4 people authored Jul 29, 2023
1 parent 0b5e0e8 commit 56e7d26
Show file tree
Hide file tree
Showing 5 changed files with 49 additions and 22 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/python-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
python-version: ["3.7", "3.11"]
python-version: ["3.8", "3.12"]
include:
- os: windows-latest
python-version: "3.9"
Expand All @@ -27,7 +27,7 @@ jobs:
- os: ubuntu-latest
python-version: "3.10"
- os: macos-latest
python-version: "3.8"
python-version: "3.11"
steps:
- uses: actions/checkout@v3
- uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
Expand Down
16 changes: 11 additions & 5 deletions jupyter_events/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
from pathlib import Path, PurePath
from typing import Optional, Type, Union

from jsonschema import FormatChecker, RefResolver, validators
from jsonschema import FormatChecker, validators
from referencing import Registry
from referencing.jsonschema import DRAFT7

try:
from jsonschema.protocols import Validator
Expand Down Expand Up @@ -55,23 +57,27 @@ class EventSchema:
any schema registered here follows the expected form
of Jupyter Events.
resolver:
RefResolver for nested JSON schema references.
registry:
Registry for nested JSON schema references.
"""

def __init__(
self,
schema: SchemaType,
validator_class: Type[Validator] = validators.Draft7Validator, # type:ignore[assignment]
format_checker: FormatChecker = draft7_format_checker,
resolver: Optional[RefResolver] = None,
registry: Optional[Registry] = None,
):
"""Initialize an event schema."""
_schema = self._load_schema(schema)
# Validate the schema against Jupyter Events metaschema.
validate_schema(_schema)

if registry is None:
registry = DRAFT7.create_resource(_schema) @ Registry()

# Create a validator for this schema
self._validator = validator_class(_schema, resolver=resolver, format_checker=format_checker)
self._validator = validator_class(_schema, registry=registry, format_checker=format_checker) # type: ignore
self._schema = _schema

def __repr__(self):
Expand Down
20 changes: 12 additions & 8 deletions jupyter_events/validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
import pathlib

import jsonschema
from jsonschema import Draft7Validator, RefResolver, ValidationError
from jsonschema import Draft7Validator, ValidationError
from referencing import Registry
from referencing.jsonschema import DRAFT7

from . import yaml

Expand Down Expand Up @@ -30,19 +32,21 @@
EVENT_CORE_SCHEMA["$id"]: EVENT_CORE_SCHEMA,
}

METASCHEMA_RESOLVER = RefResolver(
base_uri=EVENT_METASCHEMA["$id"], referrer=EVENT_METASCHEMA, store=SCHEMA_STORE
)
resources = [
DRAFT7.create_resource(each)
for each in (EVENT_METASCHEMA, PROPERTY_METASCHEMA, EVENT_CORE_SCHEMA)
]
METASCHEMA_REGISTRY: Registry = resources @ Registry()

JUPYTER_EVENTS_SCHEMA_VALIDATOR = Draft7Validator(
JUPYTER_EVENTS_SCHEMA_VALIDATOR = Draft7Validator( # type: ignore
schema=EVENT_METASCHEMA,
resolver=METASCHEMA_RESOLVER,
registry=METASCHEMA_REGISTRY,
format_checker=draft7_format_checker,
)

JUPYTER_EVENTS_CORE_VALIDATOR = Draft7Validator(
JUPYTER_EVENTS_CORE_VALIDATOR = Draft7Validator( # type: ignore
schema=EVENT_CORE_SCHEMA,
resolver=METASCHEMA_RESOLVER,
registry=METASCHEMA_REGISTRY,
format_checker=draft7_format_checker,
)

Expand Down
5 changes: 3 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ build-backend = "hatchling.build"
name = "jupyter-events"
description = "Jupyter Event System library"
readme = "README.md"
requires-python = ">=3.7"
requires-python = ">=3.8"
authors = [
{ name = "Jupyter Development Team", email = "[email protected]" },
]
Expand All @@ -23,7 +23,8 @@ classifiers = [
"Programming Language :: Python :: 3",
]
dependencies = [
"jsonschema[format-nongpl,format_nongpl]>=3.2.0",
"referencing",
"jsonschema[format-nongpl,format_nongpl]>=4.18.0",
"python-json-logger>=2.0.4",
"pyyaml>=5.3",
"traitlets>=5.3",
Expand Down
26 changes: 21 additions & 5 deletions tests/test_logger.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import io
import json
import logging
import sys
from datetime import datetime, timedelta, timezone
from unittest.mock import MagicMock

Expand Down Expand Up @@ -158,12 +159,15 @@ def test_emit():
assert "__timestamp__" in event_capsule
# Remove timestamp from capsule when checking equality, since it is gonna vary
del event_capsule["__timestamp__"]
assert event_capsule == {
expected = {
"__schema__": "http://test/test",
"__schema_version__": 1,
"__metadata_version__": 1,
"something": "blah",
}
if sys.version_info >= (3, 12):
expected["taskName"] = None
assert event_capsule == expected


def test_message_field():
Expand Down Expand Up @@ -202,13 +206,16 @@ def test_message_field():
assert "__timestamp__" in event_capsule
# Remove timestamp from capsule when checking equality, since it is gonna vary
del event_capsule["__timestamp__"]
assert event_capsule == {
expected = {
"__schema__": "http://test/test",
"__schema_version__": 1,
"__metadata_version__": 1,
"something": "blah",
"message": "a message was seen",
}
if sys.version_info >= (3, 12):
expected["taskName"] = None
assert event_capsule == expected


def test_nested_message_field():
Expand Down Expand Up @@ -249,12 +256,15 @@ def test_nested_message_field():
assert "__timestamp__" in event_capsule
# Remove timestamp from capsule when checking equality, since it is gonna vary
del event_capsule["__timestamp__"]
assert event_capsule == {
expected = {
"__schema__": "http://test/test",
"__schema_version__": 1,
"__metadata_version__": 1,
"thing": {"message": "a nested message was seen"},
}
if sys.version_info >= (3, 12):
expected["taskName"] = None
assert event_capsule == expected


def test_register_event_schema(tmp_path):
Expand Down Expand Up @@ -411,24 +421,30 @@ def test_unique_logger_instances():
assert "__timestamp__" in event_capsule0
# Remove timestamp from capsule when checking equality, since it is gonna vary
del event_capsule0["__timestamp__"]
assert event_capsule0 == {
expected = {
"__schema__": "http://test/test0",
"__schema_version__": 1,
"__metadata_version__": 1,
"something": "blah",
}
if sys.version_info >= (3, 12):
expected["taskName"] = None
assert event_capsule0 == expected

event_capsule1 = json.loads(output1.getvalue())

assert "__timestamp__" in event_capsule1
# Remove timestamp from capsule when checking equality, since it is gonna vary
del event_capsule1["__timestamp__"]
assert event_capsule1 == {
expected = {
"__schema__": "http://test/test1",
"__schema_version__": 1,
"__metadata_version__": 1,
"something": "blah",
}
if sys.version_info >= (3, 12):
expected["taskName"] = None
assert event_capsule1 == expected


def test_register_duplicate_schemas():
Expand Down

0 comments on commit 56e7d26

Please sign in to comment.