You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			103 lines
		
	
	
		
			3.0 KiB
		
	
	
	
		
			Python
		
	
			
		
		
	
	
			103 lines
		
	
	
		
			3.0 KiB
		
	
	
	
		
			Python
		
	
"""The cli for jupyter events."""
 | 
						|
from __future__ import annotations
 | 
						|
 | 
						|
import json
 | 
						|
import pathlib
 | 
						|
import platform
 | 
						|
 | 
						|
import click
 | 
						|
from jsonschema import ValidationError
 | 
						|
from rich.console import Console
 | 
						|
from rich.json import JSON
 | 
						|
from rich.markup import escape
 | 
						|
from rich.padding import Padding
 | 
						|
from rich.style import Style
 | 
						|
 | 
						|
from jupyter_events.schema import EventSchema, EventSchemaFileAbsent, EventSchemaLoadingError
 | 
						|
 | 
						|
WIN = platform.system() == "Windows"
 | 
						|
 | 
						|
 | 
						|
class RC:
 | 
						|
    """Return code enum."""
 | 
						|
 | 
						|
    OK = 0
 | 
						|
    INVALID = 1
 | 
						|
    UNPARSABLE = 2
 | 
						|
    NOT_FOUND = 3
 | 
						|
 | 
						|
 | 
						|
class EMOJI:
 | 
						|
    """Terminal emoji enum"""
 | 
						|
 | 
						|
    X = "XX" if WIN else "\u274c"
 | 
						|
    OK = "OK" if WIN else "\u2714"
 | 
						|
 | 
						|
 | 
						|
console = Console()
 | 
						|
error_console = Console(stderr=True)
 | 
						|
 | 
						|
 | 
						|
@click.group()
 | 
						|
@click.version_option()
 | 
						|
def main() -> None:
 | 
						|
    """A simple CLI tool to quickly validate JSON schemas against
 | 
						|
    Jupyter Event's custom validator.
 | 
						|
 | 
						|
    You can see Jupyter Event's meta-schema here:
 | 
						|
 | 
						|
        https://raw.githubusercontent.com/jupyter/jupyter_events/main/jupyter_events/schemas/event-metaschema.yml
 | 
						|
    """
 | 
						|
 | 
						|
 | 
						|
@click.command()
 | 
						|
@click.argument("schema")
 | 
						|
@click.pass_context
 | 
						|
def validate(ctx: click.Context, schema: str) -> int:
 | 
						|
    """Validate a SCHEMA against Jupyter Event's meta schema.
 | 
						|
 | 
						|
    SCHEMA can be a JSON/YAML string or filepath to a schema.
 | 
						|
    """
 | 
						|
    console.rule("Validating the following schema", style=Style(color="blue"))
 | 
						|
 | 
						|
    _schema = None
 | 
						|
    try:
 | 
						|
        # attempt to read schema as a serialized string
 | 
						|
        _schema = EventSchema._load_schema(schema)
 | 
						|
    except EventSchemaLoadingError:
 | 
						|
        # pass here to avoid printing traceback of this exception if next block
 | 
						|
        # excepts
 | 
						|
        pass
 | 
						|
 | 
						|
    # if not a serialized schema string, try to interpret it as a path to schema file
 | 
						|
    if _schema is None:
 | 
						|
        schema_path = pathlib.Path(schema)
 | 
						|
        try:
 | 
						|
            _schema = EventSchema._load_schema(schema_path)
 | 
						|
        except (EventSchemaLoadingError, EventSchemaFileAbsent) as e:
 | 
						|
            # no need for full tracestack for user error exceptions. just print
 | 
						|
            # the error message and return
 | 
						|
            error_console.print(f"[bold red]ERROR[/]: {e}")
 | 
						|
            return ctx.exit(RC.UNPARSABLE)
 | 
						|
 | 
						|
    # Print what was found.
 | 
						|
    schema_json = JSON(json.dumps(_schema))
 | 
						|
    console.print(Padding(schema_json, (1, 0, 1, 4)))
 | 
						|
    # Now validate this schema against the meta-schema.
 | 
						|
    try:
 | 
						|
        EventSchema(_schema)
 | 
						|
        console.rule("Results", style=Style(color="green"))
 | 
						|
        out = Padding(f"[green]{EMOJI.OK}[white] Nice work! This schema is valid.", (1, 0, 1, 0))
 | 
						|
        console.print(out)
 | 
						|
        return ctx.exit(RC.OK)
 | 
						|
    except ValidationError as err:
 | 
						|
        error_console.rule("Results", style=Style(color="red"))
 | 
						|
        error_console.print(f"[red]{EMOJI.X} [white]The schema failed to validate.")
 | 
						|
        error_console.print("\nWe found the following error with your schema:")
 | 
						|
        out = escape(str(err))  # type:ignore[assignment]
 | 
						|
        error_console.print(Padding(out, (1, 0, 1, 4)))
 | 
						|
        return ctx.exit(RC.INVALID)
 | 
						|
 | 
						|
 | 
						|
main.add_command(validate)
 |