Source code for py_gql.schema.differ.changes

# -*- coding: utf-8 -*-

from enum import IntEnum
from typing import Any, Type, Union

from .. import (
    Argument,
    Directive,
    EnumType,
    EnumValue,
    Field,
    InputField,
    InputObjectType,
    InterfaceType,
    NamedType,
    ObjectType,
    UnionType,
)


[docs]class SchemaChangeSeverity(IntEnum): """ Severity level of a schema change. """ #: Change should be safe for all clients. COMPATIBLE = 0 #: Change could break some clients or create silent issues depending on #: which part of the schema they use. DANGEROUS = 1 #: Change will break most clients. BREAKING = 2
# TODO: Add docstring describing the reasoning behind every change on each # SchemaChange subclass.
[docs]class SchemaChange: severity = NotImplemented # type: SchemaChangeSeverity format_str = NotImplemented # type: str @property def message(self) -> str: return self.format_str.format(self=self) def __eq__(self, other: Any) -> bool: return isinstance(other, type(self)) and str(self) == str(other)
[docs]class TypeChangedKind(SchemaChange): severity = SchemaChangeSeverity.BREAKING format_str = ( "{self.type_name} changed from " "{self.old_kind_name} type to {self.new_kind_name} type." ) def __init__( self, type_name: str, old_kind: Type[NamedType], new_kind: Type[NamedType], ): self.type_name = type_name self.old_kind = old_kind self.new_kind = new_kind self.old_kind_name = old_kind.__name__[:-4] self.new_kind_name = new_kind.__name__[:-4]
[docs]class TypeRemoved(SchemaChange): severity = SchemaChangeSeverity.BREAKING format_str = "Type {self.type_name} was removed." def __init__(self, type_name: str): self.type_name = type_name
[docs]class TypeAdded(SchemaChange): severity = SchemaChangeSeverity.COMPATIBLE format_str = "Type {self.type_name} was added." def __init__(self, type_name: str): self.type_name = type_name
[docs]class TypeRemovedFromUnion(SchemaChange): severity = SchemaChangeSeverity.BREAKING format_str = ( "{self.type_name} was removed from union type {self.union.name}." ) def __init__(self, type_name: str, union: UnionType): self.type_name = type_name self.union = union
[docs]class TypeAddedToUnion(SchemaChange): severity = SchemaChangeSeverity.DANGEROUS format_str = "{self.type_name} was added to union type {self.union.name}." def __init__(self, type_name: str, union: UnionType): self.type_name = type_name self.union = union
[docs]class TypeRemovedFromInterface(SchemaChange): severity = SchemaChangeSeverity.BREAKING format_str = "{self.type.name} no longer implements {self.interface.name}." def __init__(self, interface: InterfaceType, object_type: ObjectType): self.interface = interface self.type = object_type
[docs]class TypeAddedToInterface(SchemaChange): severity = SchemaChangeSeverity.DANGEROUS format_str = "{self.type.name} now implements {self.interface.name}." def __init__(self, interface: InterfaceType, object_type: ObjectType): self.interface = interface self.type = object_type
[docs]class EnumValueRemoved(SchemaChange): severity = SchemaChangeSeverity.BREAKING format_str = "{self.value.name} was removed from enum {self.enum.name}." def __init__(self, enum: EnumType, value: EnumValue): self.enum = enum self.value = value
[docs]class EnumValueAdded(SchemaChange): severity = SchemaChangeSeverity.DANGEROUS format_str = "{self.value.name} was added to enum {self.enum.name}." def __init__(self, enum: EnumType, value: EnumValue): self.enum = enum self.value = value
[docs]class EnumValueDeprecated(SchemaChange): severity = SchemaChangeSeverity.COMPATIBLE format_str = ( "{self.old_value.name} from enum {self.enum.name} was deprecated." ) def __init__( self, enum: EnumType, old_value: EnumValue, new_value: EnumValue ): self.enum = enum self.old_value = old_value self.new_value = new_value
[docs]class EnumValueDeprecationRemoved(SchemaChange): severity = SchemaChangeSeverity.COMPATIBLE format_str = ( "{self.old_value.name} from enum {self.enum.name} " "is no longer deprecated." ) def __init__( self, enum: EnumType, old_value: EnumValue, new_value: EnumValue ): self.enum = enum self.old_value = old_value self.new_value = new_value
[docs]class EnumValueDeprecationReasonChanged(SchemaChange): severity = SchemaChangeSeverity.COMPATIBLE format_str = ( "{self.old_value.name} from enum {self.enum.name} " "has changed deprecation reason." ) def __init__( self, enum: EnumType, old_value: EnumValue, new_value: EnumValue ): self.enum = enum self.old_value = old_value self.new_value = new_value
[docs]class DirectiveRemoved(SchemaChange): severity = SchemaChangeSeverity.BREAKING format_str = "Directive {self.directive.name} was removed." def __init__(self, directive: Directive): self.directive = directive
[docs]class DirectiveAdded(SchemaChange): severity = SchemaChangeSeverity.COMPATIBLE format_str = "Directive {self.directive.name} was added." def __init__(self, directive: Directive): self.directive = directive
[docs]class DirectiveLocationRemoved(SchemaChange): severity = SchemaChangeSeverity.BREAKING format_str = ( "Location {self.location} was removed from directive " "{self.directive.name}." ) def __init__(self, directive: Directive, location: str): self.directive = directive self.location = location
[docs]class DirectiveLocationAdded(SchemaChange): severity = SchemaChangeSeverity.COMPATIBLE format_str = ( "Location {self.location} was added to directive " "{self.directive.name}." ) def __init__(self, directive: Directive, location: str): self.directive = directive self.location = location
[docs]class DirectiveArgumentRemoved(SchemaChange): severity = SchemaChangeSeverity.BREAKING format_str = ( "Argument {self.argument.name} was removed from directive " "{self.directive.name}." ) def __init__(self, directive: Directive, argument: Argument): self.directive = directive self.argument = argument
[docs]class DirectiveArgumentAdded(SchemaChange): format_str = ( "{self.required_str} argument {self.argument.name} was added to " "directive {self.directive.name}." ) def __init__(self, directive: Directive, argument: Argument): self.directive = directive self.argument = argument self.required_str = "Required" if argument.required else "Optional" self.severity = ( SchemaChangeSeverity.BREAKING if argument.required else SchemaChangeSeverity.COMPATIBLE )
[docs]class DirectiveArgumentDefaultValueChange(SchemaChange): severity = SchemaChangeSeverity.DANGEROUS format_str = ( "Argument {self.old_argument.name} of directive " "{self.directive.name} has changed default value." ) def __init__( self, directive: Directive, old_argument: Argument, new_argument: Argument, ): self.directive = directive self.old_argument = old_argument self.new_argument = new_argument
[docs]class DirectiveArgumentChangedType(SchemaChange): severity = SchemaChangeSeverity.BREAKING format_str = ( "Argument {self.old_argument.name} of directive {self.directive.name} " "has changed type from {self.old_argument.type} to {self.new_argument.type}." ) def __init__( self, directive: Directive, old_argument: Argument, new_argument: Argument, ): self.directive = directive self.old_argument = old_argument self.new_argument = new_argument
[docs]class FieldArgumentRemoved(SchemaChange): severity = SchemaChangeSeverity.BREAKING format_str = ( "Argument {self.argument.name} was removed from field " "{self.field.name} of {self.context_str} {self.type.name}." ) def __init__( self, parent_type: Union[ObjectType, InterfaceType], field: Field, argument: Argument, ): self.type = parent_type self.context_str = ( "type" if isinstance(parent_type, ObjectType) else "interface" ) self.field = field self.argument = argument
[docs]class FieldArgumentAdded(SchemaChange): format_str = ( "{self.required_str} argument {self.argument.name} was added to field " "{self.field.name} of {self.context_str} {self.type.name}." ) def __init__( self, parent_type: Union[ObjectType, InterfaceType], field: Field, argument: Argument, ): self.type = parent_type self.context_str = ( "type" if isinstance(parent_type, ObjectType) else "interface" ) self.field = field self.argument = argument self.required_str = "Required" if argument.required else "Optional" self.severity = ( SchemaChangeSeverity.BREAKING if argument.required else SchemaChangeSeverity.COMPATIBLE )
[docs]class FieldArgumentDefaultValueChange(SchemaChange): severity = SchemaChangeSeverity.DANGEROUS format_str = ( "Argument {self.old_argument.name} of field " "{self.field.name} of {self.context_str} {self.type.name} " "has changed default value." ) def __init__( self, parent_type: Union[ObjectType, InterfaceType], field: Field, old_argument: Argument, new_argument: Argument, ): self.type = parent_type self.context_str = ( "type" if isinstance(parent_type, ObjectType) else "interface" ) self.field = field self.old_argument = old_argument self.new_argument = new_argument
[docs]class FieldArgumentChangedType(SchemaChange): severity = SchemaChangeSeverity.BREAKING format_str = ( "Argument {self.old_argument.name} of field " "{self.field.name} of {self.context_str} {self.type.name} " "has changed type from {self.old_argument.type} " "to {self.new_argument.type}." ) def __init__( self, parent_type: Union[ObjectType, InterfaceType], field: Field, old_argument: Argument, new_argument: Argument, ): self.type = parent_type self.context_str = ( "type" if isinstance(parent_type, ObjectType) else "interface" ) self.field = field self.old_argument = old_argument self.new_argument = new_argument
[docs]class FieldChangedType(SchemaChange): severity = SchemaChangeSeverity.BREAKING format_str = ( "Field {self.old_field.name} of {self.context_str} {self.type.name} has " "changed type from {self.old_field.type} to {self.new_field.type}." ) def __init__( self, parent_type: Union[ObjectType, InterfaceType], old_field: Field, new_field: Field, ): self.type = parent_type self.context_str = ( "type" if isinstance(parent_type, ObjectType) else "interface" ) self.old_field = old_field self.new_field = new_field
[docs]class FieldRemoved(SchemaChange): severity = SchemaChangeSeverity.BREAKING format_str = ( "Field {self.field.name} was removed " "from {self.context_str} {self.type.name}." ) def __init__( self, parent_type: Union[ObjectType, InterfaceType], field: Field ): self.type = parent_type self.context_str = ( "type" if isinstance(parent_type, ObjectType) else "interface" ) self.field = field
[docs]class FieldAdded(SchemaChange): severity = SchemaChangeSeverity.COMPATIBLE format_str = ( "Field {self.field.name} was added to " "{self.context_str} {self.type.name}." ) def __init__( self, parent_type: Union[ObjectType, InterfaceType], field: Field ): self.type = parent_type self.context_str = ( "type" if isinstance(parent_type, ObjectType) else "interface" ) self.field = field
[docs]class FieldDeprecated(SchemaChange): severity = SchemaChangeSeverity.COMPATIBLE format_str = ( "Field {self.old_field.name} of {self.context_str} {self.type.name} " "was deprecated." ) def __init__( self, parent_type: Union[ObjectType, InterfaceType], old_field: Field, new_field: Field, ): self.type = parent_type self.context_str = ( "type" if isinstance(parent_type, ObjectType) else "interface" ) self.old_field = old_field self.new_field = new_field
[docs]class FieldDeprecationRemoved(SchemaChange): severity = SchemaChangeSeverity.COMPATIBLE format_str = ( "Field {self.old_field.name} of {self.context_str} {self.type.name} " "is no longer deprecated." ) def __init__( self, parent_type: Union[ObjectType, InterfaceType], old_field: Field, new_field: Field, ): self.type = parent_type self.context_str = ( "type" if isinstance(parent_type, ObjectType) else "interface" ) self.old_field = old_field self.new_field = new_field
[docs]class FieldDeprecationReasonChanged(SchemaChange): severity = SchemaChangeSeverity.COMPATIBLE format_str = ( "Field {self.old_field.name} of {self.context_str} {self.type.name} has " "changed deprecation reason." ) def __init__( self, parent_type: Union[ObjectType, InterfaceType], old_field: Field, new_field: Field, ): self.type = parent_type self.context_str = ( "type" if isinstance(parent_type, ObjectType) else "interface" ) self.old_field = old_field self.new_field = new_field
[docs]class InputFieldRemoved(SchemaChange): severity = SchemaChangeSeverity.BREAKING format_str = ( "Input field {self.field.name} was removed from {self.type.name}." ) def __init__(self, input_type: InputObjectType, field: InputField): self.type = input_type self.field = field
[docs]class InputFieldAdded(SchemaChange): severity = SchemaChangeSeverity.BREAKING format_str = ( "{self.required_str} input field {self.field.name} was added " "to {self.type.name}." ) def __init__(self, input_type: InputObjectType, field: InputField): self.type = input_type self.field = field self.required_str = "Required" if field.required else "Optional" self.severity = ( SchemaChangeSeverity.BREAKING if field.required else SchemaChangeSeverity.COMPATIBLE )
[docs]class InputFieldDefaultValueChange(SchemaChange): severity = SchemaChangeSeverity.DANGEROUS format_str = ( "Input field {self.old_field.name} of {self.type.name} " "has changed default value." ) def __init__( self, input_type: InputObjectType, old_field: InputField, new_field: InputField, ): self.type = input_type self.old_field = old_field self.new_field = new_field
[docs]class InputFieldChangedType(SchemaChange): severity = SchemaChangeSeverity.BREAKING format_str = ( "Input field {self.old_field.name} of {self.type.name} " "has changed type from {self.old_field.type} to {self.new_field.type}." ) def __init__( self, input_type: InputObjectType, old_field: InputField, new_field: InputField, ): self.type = input_type self.old_field = old_field self.new_field = new_field