diff --git a/docs/demo/demo-notebook.ipynb b/docs/demo/demo-notebook.ipynb index 12a109c..cc2a872 100644 --- a/docs/demo/demo-notebook.ipynb +++ b/docs/demo/demo-notebook.ipynb @@ -47,7 +47,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -72,7 +72,7 @@ "source": [ "schema = \"\"\"\n", "$id: http://myapplication.org/example-event\n", - "version: 1\n", + "version: \"1\"\n", "title: Example Event\n", "description: An interesting event to collect\n", "properties:\n", diff --git a/docs/user_guide/application.md b/docs/user_guide/application.md index 9a7f693..7248760 100644 --- a/docs/user_guide/application.md +++ b/docs/user_guide/application.md @@ -22,7 +22,7 @@ Register an event schema with the logger. ```python schema = """ $id: http://myapplication.org/my-method - version: 1 + version: "1" title: My Method Executed description: My method was executed one time. properties: diff --git a/docs/user_guide/defining-schema.md b/docs/user_guide/defining-schema.md index ea312ac..b40f644 100644 --- a/docs/user_guide/defining-schema.md +++ b/docs/user_guide/defining-schema.md @@ -27,7 +27,7 @@ Beyond these required items, any valid JSON should be possible. Here is a simple ```yaml $id: https://event.jupyter.org/example-event -version: 1 +version: "1" title: My Event description: | Some information about my event @@ -67,7 +67,7 @@ The output will look like this, if it passes: { "$id": "http://event.jupyter.org/test", - "version": 1, + "version": "1", "title": "Simple Test Schema", "description": "A simple schema for testing\n", "type": "object", @@ -92,7 +92,7 @@ or this if fails: { "$id": "http://event.jupyter.org/test", - "version": 1, + "version": "1", "title": "Simple Test Schema", "description": "A simple schema for testing\n", "type": "object", diff --git a/docs/user_guide/event-schemas.md b/docs/user_guide/event-schemas.md index ab253bd..7334534 100644 --- a/docs/user_guide/event-schemas.md +++ b/docs/user_guide/event-schemas.md @@ -13,7 +13,7 @@ from jupyter_events.logger import EventLogger schema = """ $id: http://myapplication.org/example-event -version: 1 +version: "1" title: Example Event description: An interesting event to collect properties: @@ -38,7 +38,7 @@ print(logger.schemas) Validator class: Draft7Validator Schema: { "$id": "myapplication.org/example-event", - "version": 1, + ""version": 1", "title": "Example Event", "description": "An interesting event to collect", "properties": { diff --git a/docs/user_guide/first-event.md b/docs/user_guide/first-event.md index bd62a7e..5e83f78 100644 --- a/docs/user_guide/first-event.md +++ b/docs/user_guide/first-event.md @@ -15,7 +15,7 @@ To begin emitting events from a Python application, you need to tell the `EventL ```python schema = """ $id: http://myapplication.org/example-event -version: 1 +version: "1" title: Example Event description: An interesting event to collect properties: diff --git a/jupyter_events/schemas/event-core-schema.yml b/jupyter_events/schemas/event-core-schema.yml index 5ae07b6..b5ef500 100644 --- a/jupyter_events/schemas/event-core-schema.yml +++ b/jupyter_events/schemas/event-core-schema.yml @@ -1,6 +1,6 @@ $schema: http://json-schema.org/draft-07/schema $id: http://event.jupyter.org/event-schema -version: 1 +version: "1" title: Event Schema description: | A schema for validating any Jupyter Event. @@ -12,7 +12,7 @@ properties: const: 1 __schema_version__: title: Schema Version - type: integer + type: string __schema__: title: Schema ID type: string diff --git a/jupyter_events/schemas/event-metaschema.yml b/jupyter_events/schemas/event-metaschema.yml index 4fc1aa7..e6cc2d1 100644 --- a/jupyter_events/schemas/event-metaschema.yml +++ b/jupyter_events/schemas/event-metaschema.yml @@ -1,6 +1,6 @@ $schema: http://json-schema.org/draft-07/schema $id: http://event.jupyter.org/event-metaschema -version: 1 +version: "1" title: Event Metaschema description: | A meta schema for validating that all registered Jupyter Event @@ -8,7 +8,7 @@ description: | type: object properties: version: - type: integer + type: string title: type: string description: diff --git a/jupyter_events/schemas/property-metaschema.yml b/jupyter_events/schemas/property-metaschema.yml index 64e2e82..f8fad08 100644 --- a/jupyter_events/schemas/property-metaschema.yml +++ b/jupyter_events/schemas/property-metaschema.yml @@ -1,6 +1,6 @@ $schema: http://json-schema.org/draft-07/schema $id: http://event.jupyter.org/property-metaschema -version: 1 +version: "1" title: Property Metaschema description: | A metaschema for validating properties within diff --git a/jupyter_events/utils.py b/jupyter_events/utils.py new file mode 100644 index 0000000..9df3412 --- /dev/null +++ b/jupyter_events/utils.py @@ -0,0 +1,8 @@ +""" +Various utilities +""" +from __future__ import annotations + + +class JupyterEventsVersionWarning(UserWarning): + """Emitted when an event schema version is an `int` when it should be `str`.""" diff --git a/jupyter_events/validators.py b/jupyter_events/validators.py index f68897d..bd7a161 100644 --- a/jupyter_events/validators.py +++ b/jupyter_events/validators.py @@ -2,6 +2,7 @@ from __future__ import annotations import pathlib +import warnings from typing import Any import jsonschema @@ -10,6 +11,7 @@ from referencing.jsonschema import DRAFT7 from . import yaml +from .utils import JupyterEventsVersionWarning draft7_format_checker = ( Draft7Validator.FORMAT_CHECKER @@ -57,6 +59,17 @@ def validate_schema(schema: dict[str, Any]) -> None: """Validate a schema dict.""" try: + # If the `version` attribute is an integer, coerce to string. + # TODO: remove this in a future version. + if "version" in schema and isinstance(schema["version"], int): + schema["version"] = str(schema["version"]) + msg = ( + "The `version` property of an event schema must be a string. " + "It has been type coerced, but in a future version of this " + "library, it will fail to validate. Please update schema: " + f"{schema['$id']}" + ) + warnings.warn(JupyterEventsVersionWarning(msg), stacklevel=2) # Validate the schema against Jupyter Events metaschema. JUPYTER_EVENTS_SCHEMA_VALIDATOR.validate(schema) except ValidationError as err: diff --git a/pyproject.toml b/pyproject.toml index d879aa8..804fca9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -129,6 +129,7 @@ filterwarnings= [ "module:datetime.datetime.utc:DeprecationWarning", # Ignore importwarning on pypy for yaml "module:can't resolve package from __spec__ or __package__:ImportWarning", + "ignore::jupyter_events.utils.JupyterEventsVersionWarning", ] [tool.coverage.report] diff --git a/tests/schemas/bad/bad-id.yaml b/tests/schemas/bad/bad-id.yaml index dd561ac..5bc663e 100644 --- a/tests/schemas/bad/bad-id.yaml +++ b/tests/schemas/bad/bad-id.yaml @@ -1,5 +1,5 @@ $id: not-a-uri -version: 1 +version: "1" title: Schema with a Bad URI ID description: | A schema with a bad id diff --git a/tests/schemas/bad/nested-reserved-property.yaml b/tests/schemas/bad/nested-reserved-property.yaml index 4ea004d..e7f8c36 100644 --- a/tests/schemas/bad/nested-reserved-property.yaml +++ b/tests/schemas/bad/nested-reserved-property.yaml @@ -1,5 +1,5 @@ $id: http://event.jupyter.org/test -version: 1 +version: "1" title: Schema with Array description: | A schema for an array of objects. diff --git a/tests/schemas/good/array.yaml b/tests/schemas/good/array.yaml index a917374..250201e 100644 --- a/tests/schemas/good/array.yaml +++ b/tests/schemas/good/array.yaml @@ -1,5 +1,5 @@ $id: http://event.jupyter.org/test -version: 1 +version: "1" title: Schema with Array description: | A schema for an array of objects. diff --git a/tests/schemas/good/basic.json b/tests/schemas/good/basic.json index b303a5c..d9e2cf0 100644 --- a/tests/schemas/good/basic.json +++ b/tests/schemas/good/basic.json @@ -1,6 +1,6 @@ { "$id": "http://event.jupyter.org/test", - "version": 1, + "version": "1", "title": "Simple Test Schema", "description": "A simple schema for testing", "type": "object", diff --git a/tests/schemas/good/basic.yaml b/tests/schemas/good/basic.yaml index 33a73e4..d07f0be 100644 --- a/tests/schemas/good/basic.yaml +++ b/tests/schemas/good/basic.yaml @@ -1,5 +1,5 @@ $id: http://event.jupyter.org/test -version: 1 +version: "1" title: Simple Test Schema description: | A simple schema for testing diff --git a/tests/schemas/good/nested-array.yaml b/tests/schemas/good/nested-array.yaml index f54c3cf..c7bd6b1 100644 --- a/tests/schemas/good/nested-array.yaml +++ b/tests/schemas/good/nested-array.yaml @@ -1,5 +1,5 @@ $id: http://event.jupyter.org/test -version: 1 +version: "1" title: Schema with Array description: | A schema for an array of objects. diff --git a/tests/schemas/good/user.yaml b/tests/schemas/good/user.yaml index 15ca873..930c027 100644 --- a/tests/schemas/good/user.yaml +++ b/tests/schemas/good/user.yaml @@ -1,5 +1,5 @@ $id: http://event.jupyter.org/user -version: 1 +version: "1" title: User description: | A User model. diff --git a/tests/test_logger.py b/tests/test_logger.py index 28a8fc6..e58487c 100644 --- a/tests/test_logger.py +++ b/tests/test_logger.py @@ -100,7 +100,7 @@ def test_timestamp_override(): """ schema = { "$id": "http://test/test", - "version": 1, + "version": "1", "properties": { "something": { "type": "string", @@ -132,7 +132,7 @@ def test_emit(): """ schema = { "$id": "http://test/test", - "version": 1, + "version": "1", "properties": { "something": { "type": "string", @@ -161,7 +161,7 @@ def test_emit(): del event_capsule["__timestamp__"] expected = { "__schema__": "http://test/test", - "__schema_version__": 1, + "__schema_version__": "1", "__metadata_version__": 1, "something": "blah", } @@ -175,7 +175,7 @@ def test_message_field(): """ schema = { "$id": "http://test/test", - "version": 1, + "version": "1", "properties": { "something": { "type": "string", @@ -206,7 +206,7 @@ def test_message_field(): del event_capsule["__timestamp__"] expected = { "__schema__": "http://test/test", - "__schema_version__": 1, + "__schema_version__": "1", "__metadata_version__": 1, "something": "blah", "message": "a message was seen", @@ -221,7 +221,7 @@ def test_nested_message_field(): """ schema = { "$id": "http://test/test", - "version": 1, + "version": "1", "properties": { "thing": { "type": "object", @@ -254,7 +254,7 @@ def test_nested_message_field(): del event_capsule["__timestamp__"] expected = { "__schema__": "http://test/test", - "__schema_version__": 1, + "__schema_version__": "1", "__metadata_version__": 1, "thing": {"message": "a nested message was seen"}, } @@ -267,7 +267,7 @@ def test_register_event_schema(tmp_path): """ schema = { "$id": "http://test/test", - "version": 1, + "version": "1", "type": "object", "properties": { "something": { @@ -290,7 +290,7 @@ def test_register_event_schema_object(tmp_path): """ schema = { "$id": "http://test/test", - "version": 1, + "version": "1", "type": "object", "properties": { "something": { @@ -314,7 +314,7 @@ def test_emit_badschema(): """ schema = { "$id": "http://test/test", - "version": 1, + "version": "1", "type": "object", "properties": { "something": { @@ -343,7 +343,7 @@ def test_emit_badschema_format(): """ schema = { "$id": "http://test/test", - "version": 1, + "version": "1", "type": "object", "properties": { "something": {"type": "string", "title": "test", "format": "date-time"}, @@ -362,7 +362,7 @@ def test_emit_badschema_format(): def test_unique_logger_instances(): schema0 = { "$id": "http://test/test0", - "version": 1, + "version": "1", "type": "object", "properties": { "something": { @@ -374,7 +374,7 @@ def test_unique_logger_instances(): schema1 = { "$id": "http://test/test1", - "version": 1, + "version": "1", "type": "object", "properties": { "something": { @@ -417,7 +417,7 @@ def test_unique_logger_instances(): del event_capsule0["__timestamp__"] expected = { "__schema__": "http://test/test0", - "__schema_version__": 1, + "__schema_version__": "1", "__metadata_version__": 1, "something": "blah", } @@ -430,7 +430,7 @@ def test_unique_logger_instances(): del event_capsule1["__timestamp__"] expected = { "__schema__": "http://test/test1", - "__schema_version__": 1, + "__schema_version__": "1", "__metadata_version__": 1, "something": "blah", } @@ -440,7 +440,7 @@ def test_unique_logger_instances(): def test_register_duplicate_schemas(): schema0 = { "$id": "http://test/test", - "version": 1, + "version": "1", "type": "object", "properties": { "something": { @@ -452,7 +452,7 @@ def test_register_duplicate_schemas(): schema1 = { "$id": "http://test/test", - "version": 1, + "version": "1", "type": "object", "properties": { "something": { @@ -484,7 +484,7 @@ async def test_noop_emit(): schema_id1 = "http://test/test" schema1 = { "$id": schema_id1, - "version": 1, + "version": "1", "type": "object", "properties": { "something": { @@ -496,7 +496,7 @@ async def test_noop_emit(): schema_id2 = "http://test/test2" schema2 = { "$id": schema_id2, - "version": 1, + "version": "1", "type": "object", "properties": { "something_elss": {