Module schemadiff.validation_rules
Expand source code
import typing
from abc import ABC, abstractmethod
from typing import List, Set
from graphql import GraphQLObjectType
from schemadiff.changes.enum import EnumValueAdded, EnumValueDescriptionChanged
from schemadiff.changes.field import FieldDescriptionChanged, FieldArgumentAdded
from schemadiff.changes.object import ObjectTypeFieldAdded
from schemadiff.changes.type import AddedType, TypeDescriptionChanged
class ValidationRule(ABC):
"""Abstract class for creating schema Validation Rules."""
name: str = ""
def __init__(self, change):
self.change = change
@abstractmethod
def is_valid(self) -> bool:
"""Evaluate the change regarding the rule class defined.
Returns:
bool: True if change is valid, False otherwise
"""
@property
@abstractmethod
def message(self) -> str:
"""Formatted change message"""
@classmethod
def get_subclasses_by_names(cls, names: List[str]) -> Set[typing.Type['ValidationRule']]:
if not names:
return set()
return {subclass for subclass in cls.__subclasses__() if subclass.name in names}
@classmethod
def get_rules_list(cls) -> Set[str]:
return {subclass.name for subclass in cls.__subclasses__()}
class AddTypeWithoutDescription(ValidationRule):
"""Restrict adding new GraphQL types without entering
a non-empty description."""
name = "add-type-without-description"
def is_valid(self) -> bool:
EMPTY = (None, "")
if not isinstance(self.change, AddedType):
return True
added_type = self.change.type
type_has_description = added_type.description not in EMPTY
if isinstance(added_type, GraphQLObjectType):
all_its_fields_have_description = all(
field.description not in EMPTY
for field in added_type.fields.values()
)
return type_has_description and all_its_fields_have_description
else:
return type_has_description
@property
def message(self):
return f"{self.change.message} without a description for {self.change.path} (rule: `{self.name}`)."
class RemoveTypeDescription(ValidationRule):
"""Restrict removing the description from an existing
GraphQL type."""
name = "remove-type-description"
def is_valid(self) -> bool:
if isinstance(self.change, TypeDescriptionChanged):
return self.change.new_desc not in (None, "")
return True
@property
def message(self):
return (
f"Description for type `{self.change.type}` was "
f"removed (rule: `{self.name}`)"
)
class AddFieldWithoutDescription(ValidationRule):
"""Restrict adding fields without description."""
name = "add-field-without-description"
def is_valid(self) -> bool:
if isinstance(self.change, ObjectTypeFieldAdded):
return self.change.description not in (None, "")
return True
@property
def message(self):
return f"{self.change.message} without a description for {self.change.path} (rule: `{self.name}`)."
class RemoveFieldDescription(ValidationRule):
"""Restrict removing field description."""
name = "remove-field-description"
def is_valid(self) -> bool:
if isinstance(self.change, FieldDescriptionChanged):
return self.change.new_field.description not in (None, "")
return True
@property
def message(self):
return (
f"`{self.change.type.name}.{self.change.field_name}` description was "
f"removed (rule: `{self.name}`)"
)
class AddEnumValueWithoutDescription(ValidationRule):
"""Restrict adding enum value without description."""
name = "add-enum-value-without-description"
def is_valid(self) -> bool:
if isinstance(self.change, EnumValueAdded):
return self.change.description not in (None, "")
return True
@property
def message(self):
return f"{self.change.message} without a description (rule: `{self.name}`)"
class RemoveEnumValueDescription(ValidationRule):
"""Restrict adding enum value without description."""
name = "remove-enum-value-description"
def is_valid(self) -> bool:
if isinstance(self.change, EnumValueDescriptionChanged):
return self.change.new_value.description not in (None, "")
return True
@property
def message(self):
return f"Description for enum value `{self.change.name}` was removed (rule: `{self.name}`)"
Classes
class AddEnumValueWithoutDescription (change)
-
Restrict adding enum value without description.
Expand source code
class AddEnumValueWithoutDescription(ValidationRule): """Restrict adding enum value without description.""" name = "add-enum-value-without-description" def is_valid(self) -> bool: if isinstance(self.change, EnumValueAdded): return self.change.description not in (None, "") return True @property def message(self): return f"{self.change.message} without a description (rule: `{self.name}`)"
Ancestors
- ValidationRule
- abc.ABC
Class variables
var name : str
Inherited members
class AddFieldWithoutDescription (change)
-
Restrict adding fields without description.
Expand source code
class AddFieldWithoutDescription(ValidationRule): """Restrict adding fields without description.""" name = "add-field-without-description" def is_valid(self) -> bool: if isinstance(self.change, ObjectTypeFieldAdded): return self.change.description not in (None, "") return True @property def message(self): return f"{self.change.message} without a description for {self.change.path} (rule: `{self.name}`)."
Ancestors
- ValidationRule
- abc.ABC
Class variables
var name : str
Inherited members
class AddTypeWithoutDescription (change)
-
Restrict adding new GraphQL types without entering a non-empty description.
Expand source code
class AddTypeWithoutDescription(ValidationRule): """Restrict adding new GraphQL types without entering a non-empty description.""" name = "add-type-without-description" def is_valid(self) -> bool: EMPTY = (None, "") if not isinstance(self.change, AddedType): return True added_type = self.change.type type_has_description = added_type.description not in EMPTY if isinstance(added_type, GraphQLObjectType): all_its_fields_have_description = all( field.description not in EMPTY for field in added_type.fields.values() ) return type_has_description and all_its_fields_have_description else: return type_has_description @property def message(self): return f"{self.change.message} without a description for {self.change.path} (rule: `{self.name}`)."
Ancestors
- ValidationRule
- abc.ABC
Class variables
var name : str
Inherited members
class RemoveEnumValueDescription (change)
-
Restrict adding enum value without description.
Expand source code
class RemoveEnumValueDescription(ValidationRule): """Restrict adding enum value without description.""" name = "remove-enum-value-description" def is_valid(self) -> bool: if isinstance(self.change, EnumValueDescriptionChanged): return self.change.new_value.description not in (None, "") return True @property def message(self): return f"Description for enum value `{self.change.name}` was removed (rule: `{self.name}`)"
Ancestors
- ValidationRule
- abc.ABC
Class variables
var name : str
Inherited members
class RemoveFieldDescription (change)
-
Restrict removing field description.
Expand source code
class RemoveFieldDescription(ValidationRule): """Restrict removing field description.""" name = "remove-field-description" def is_valid(self) -> bool: if isinstance(self.change, FieldDescriptionChanged): return self.change.new_field.description not in (None, "") return True @property def message(self): return ( f"`{self.change.type.name}.{self.change.field_name}` description was " f"removed (rule: `{self.name}`)" )
Ancestors
- ValidationRule
- abc.ABC
Class variables
var name : str
Inherited members
class RemoveTypeDescription (change)
-
Restrict removing the description from an existing GraphQL type.
Expand source code
class RemoveTypeDescription(ValidationRule): """Restrict removing the description from an existing GraphQL type.""" name = "remove-type-description" def is_valid(self) -> bool: if isinstance(self.change, TypeDescriptionChanged): return self.change.new_desc not in (None, "") return True @property def message(self): return ( f"Description for type `{self.change.type}` was " f"removed (rule: `{self.name}`)" )
Ancestors
- ValidationRule
- abc.ABC
Class variables
var name : str
Inherited members
class ValidationRule (change)
-
Abstract class for creating schema Validation Rules.
Expand source code
class ValidationRule(ABC): """Abstract class for creating schema Validation Rules.""" name: str = "" def __init__(self, change): self.change = change @abstractmethod def is_valid(self) -> bool: """Evaluate the change regarding the rule class defined. Returns: bool: True if change is valid, False otherwise """ @property @abstractmethod def message(self) -> str: """Formatted change message""" @classmethod def get_subclasses_by_names(cls, names: List[str]) -> Set[typing.Type['ValidationRule']]: if not names: return set() return {subclass for subclass in cls.__subclasses__() if subclass.name in names} @classmethod def get_rules_list(cls) -> Set[str]: return {subclass.name for subclass in cls.__subclasses__()}
Ancestors
- abc.ABC
Subclasses
- AddEnumValueWithoutDescription
- AddFieldWithoutDescription
- AddTypeWithoutDescription
- RemoveEnumValueDescription
- RemoveFieldDescription
- RemoveTypeDescription
Class variables
var name : str
Static methods
def get_rules_list() ‑> Set[str]
-
Expand source code
@classmethod def get_rules_list(cls) -> Set[str]: return {subclass.name for subclass in cls.__subclasses__()}
def get_subclasses_by_names(names: List[str]) ‑> Set[Type[ValidationRule]]
-
Expand source code
@classmethod def get_subclasses_by_names(cls, names: List[str]) -> Set[typing.Type['ValidationRule']]: if not names: return set() return {subclass for subclass in cls.__subclasses__() if subclass.name in names}
Instance variables
var message : str
-
Formatted change message
Expand source code
@property @abstractmethod def message(self) -> str: """Formatted change message"""
Methods
def is_valid(self) ‑> bool
-
Evaluate the change regarding the rule class defined.
Returns
bool
- True if change is valid, False otherwise
Expand source code
@abstractmethod def is_valid(self) -> bool: """Evaluate the change regarding the rule class defined. Returns: bool: True if change is valid, False otherwise """