assertion helper added

This commit is contained in:
Kacppian 2018-07-29 18:04:01 +05:30 committed by Kaushik ASP
parent 131cbebc88
commit f38fc5136f
19 changed files with 201 additions and 91 deletions

View File

@ -3,6 +3,7 @@ from __future__ import unicode_literals
import datetime import datetime
import os import os
import subprocess import subprocess
from ..utils.comparison_helper import raise_assertion_if_not
def get_version(version=None): def get_version(version=None):
@ -44,8 +45,14 @@ def get_complete_version(version=None):
if version is None: if version is None:
from graphene import VERSION as version from graphene import VERSION as version
else: else:
assert len(version) == 5 raise_assertion_if_not(
assert version[3] in ("alpha", "beta", "rc", "final") condition=len(version) is 5,
message="Wrong tuple provided"
)
raise_assertion_if_not(
condition=version[3] in ("alpha", "beta", "rc", "final"),
message="Version not correct."
)
return version return version

View File

@ -9,6 +9,7 @@ from ..types.field import Field
from ..types.objecttype import ObjectType, ObjectTypeOptions from ..types.objecttype import ObjectType, ObjectTypeOptions
from ..utils.thenables import maybe_thenable from ..utils.thenables import maybe_thenable
from .node import is_node from .node import is_node
from ..utils.comparison_helper import raise_assertion_if_not
class PageInfo(ObjectType): class PageInfo(ObjectType):
@ -52,11 +53,17 @@ class Connection(ObjectType):
@classmethod @classmethod
def __init_subclass_with_meta__(cls, node=None, name=None, **options): def __init_subclass_with_meta__(cls, node=None, name=None, **options):
_meta = ConnectionOptions(cls) _meta = ConnectionOptions(cls)
assert node, "You have to provide a node in {}.Meta".format(cls.__name__) raise_assertion_if_not(
assert issubclass( condition=node,
node, (Scalar, Enum, ObjectType, Interface, Union, NonNull) message="You have to provide a node in {}.Meta".format(cls.__name__)
), ('Received incompatible node "{}" for Connection {}.').format( )
node, cls.__name__ raise_assertion_if_not(
condition=issubclass(
node, (Scalar, Enum, ObjectType, Interface, Union, NonNull)
),
message=('Received incompatible node "{}" for Connection {}.').format(
node, cls.__name__
)
) )
base_name = re.sub("Connection$", "", name or cls.__name__) or node._meta.name base_name = re.sub("Connection$", "", name or cls.__name__) or node._meta.name
@ -132,9 +139,12 @@ class IterableConnectionField(Field):
"Read more: https://github.com/graphql-python/graphene/blob/v2.0.0/UPGRADE-v2.0.md#node-connections" "Read more: https://github.com/graphql-python/graphene/blob/v2.0.0/UPGRADE-v2.0.md#node-connections"
) )
assert issubclass(connection_type, Connection), ( raise_assertion_if_not(
'{} type have to be a subclass of Connection. Received "{}".' condition=issubclass(connection_type, Connection),
).format(self.__class__.__name__, connection_type) message='{} type have to be a subclass of Connection. Received "{}".'.format(
self.__class__.__name__, connection_type
)
)
return type return type
@classmethod @classmethod
@ -142,10 +152,16 @@ class IterableConnectionField(Field):
if isinstance(resolved, connection_type): if isinstance(resolved, connection_type):
return resolved return resolved
assert isinstance(resolved, Iterable), ( raise_assertion_if_not(
"Resolved value from the connection field have to be iterable or instance of {}. " condition=isinstance(resolved, Iterable),
'Received "{}"' message="""
).format(connection_type, resolved) Resolved value from the connection field have to be iterable or instance of {}.
Received "{}"
""".format(
connection_type, resolved
)
)
connection = connection_from_list( connection = connection_from_list(
resolved, resolved,
args, args,

View File

@ -17,8 +17,15 @@ class ClientIDMutation(Mutation):
input_class = getattr(cls, "Input", None) input_class = getattr(cls, "Input", None)
base_name = re.sub("Payload$", "", name or cls.__name__) base_name = re.sub("Payload$", "", name or cls.__name__)
assert not output, "Can't specify any output" raise_assertion_if_not(
assert not arguments, "Can't specify any arguments" condition=not output,
message="Can't specify any output"
)
raise_assertion_if_not(
condition=not arguments,
message="Can't specify any arguments"
)
bases = (InputObjectType,) bases = (InputObjectType,)
if input_class: if input_class:
@ -41,10 +48,13 @@ class ClientIDMutation(Mutation):
) )
mutate_and_get_payload = getattr(cls, "mutate_and_get_payload", None) mutate_and_get_payload = getattr(cls, "mutate_and_get_payload", None)
if cls.mutate and cls.mutate.__func__ == ClientIDMutation.mutate.__func__: if cls.mutate and cls.mutate.__func__ == ClientIDMutation.mutate.__func__:
assert mutate_and_get_payload, ( raise_assertion_if_not(
"{name}.mutate_and_get_payload method is required" condition=mutate_and_get_payload,
" in a ClientIDMutation." message="{name}.mutate_and_get_payload method is required" \
).format(name=name or cls.__name__) " in a ClientIDMutation.".format(
name=name or cls.__name__
)
)
if not name: if not name:
name = "{}Payload".format(base_name) name = "{}Payload".format(base_name)

View File

@ -7,6 +7,7 @@ from graphql_relay import from_global_id, to_global_id
from ..types import ID, Field, Interface, ObjectType from ..types import ID, Field, Interface, ObjectType
from ..types.interface import InterfaceOptions from ..types.interface import InterfaceOptions
from ..types.utils import get_type from ..types.utils import get_type
from ..utils.comparison_helper import raise_assertion_if_not
def is_node(objecttype): def is_node(objecttype):

View File

@ -5,6 +5,7 @@ from .dynamic import Dynamic
from .mountedtype import MountedType from .mountedtype import MountedType
from .structures import NonNull from .structures import NonNull
from .utils import get_type from .utils import get_type
from ..utils.comparison_helper import raise_assertion_if_not
class Argument(MountedType): class Argument(MountedType):
@ -73,10 +74,11 @@ def to_arguments(args, extra_args=None):
raise ValueError('Unknown argument "{}".'.format(default_name)) raise ValueError('Unknown argument "{}".'.format(default_name))
arg_name = default_name or arg.name arg_name = default_name or arg.name
assert ( raise_assertion_if_not(
arg_name not in arguments condition=arg_name not in arguments,
), 'More than one Argument have same name "{}".'.format( message='More than one Argument have same name "{}".'.format(
arg_name arg_name
)
) )
arguments[arg_name] = arg arguments[arg_name] = arg

View File

@ -1,5 +1,6 @@
from ..utils.subclass_with_meta import SubclassWithMeta from ..utils.subclass_with_meta import SubclassWithMeta
from ..utils.trim_docstring import trim_docstring from ..utils.trim_docstring import trim_docstring
from ..utils.comparison_helper import raise_assertion_if_not
class BaseOptions(object): class BaseOptions(object):
@ -31,7 +32,10 @@ class BaseType(SubclassWithMeta):
@classmethod @classmethod
def __init_subclass_with_meta__(cls, name=None, description=None, _meta=None): def __init_subclass_with_meta__(cls, name=None, description=None, _meta=None):
assert "_meta" not in cls.__dict__, "Can't assign directly meta" raise_assertion_if_not(
condition="_meta" not in cls.__dict__,
message="Can't assign directly meta"
)
if not _meta: if not _meta:
return return
_meta.name = name or cls.__name__ _meta.name = name or cls.__name__

View File

@ -6,6 +6,7 @@ from aniso8601 import parse_date, parse_datetime, parse_time
from graphql.language import ast from graphql.language import ast
from .scalars import Scalar from .scalars import Scalar
from ..utils.comparison_helper import raise_assertion_if_not
class Date(Scalar): class Date(Scalar):
@ -19,9 +20,10 @@ class Date(Scalar):
def serialize(date): def serialize(date):
if isinstance(date, datetime.datetime): if isinstance(date, datetime.datetime):
date = date.date() date = date.date()
assert isinstance( raise_assertion_if_not(
date, datetime.date condition=isinstance(date, datetime.date),
), 'Received not compatible date "{}"'.format(repr(date)) message='Received not compatible date "{}"'.format(repr(date))
)
return date.isoformat() return date.isoformat()
@classmethod @classmethod
@ -46,9 +48,10 @@ class DateTime(Scalar):
@staticmethod @staticmethod
def serialize(dt): def serialize(dt):
assert isinstance( raise_assertion_if_not(
dt, (datetime.datetime, datetime.date) condition=isinstance(dt, (datetime.datetime, datetime.date)),
), 'Received not compatible datetime "{}"'.format(repr(dt)) message='Received not compatible datetime "{}"'.format(repr(dt))
)
return dt.isoformat() return dt.isoformat()
@classmethod @classmethod
@ -73,9 +76,10 @@ class Time(Scalar):
@staticmethod @staticmethod
def serialize(time): def serialize(time):
assert isinstance( raise_assertion_if_not(
time, datetime.time condition=isinstance(time, datetime.time),
), 'Received not compatible time "{}"'.format(repr(time)) message='Received not compatible time "{}"'.format(repr(time))
)
return time.isoformat() return time.isoformat()
@classmethod @classmethod

View File

@ -7,6 +7,7 @@ from .mountedtype import MountedType
from .structures import NonNull from .structures import NonNull
from .unmountedtype import UnmountedType from .unmountedtype import UnmountedType
from .utils import get_type from .utils import get_type
from ..utils.comparison_helper import raise_assertion_if_not
base_type = type base_type = type
@ -34,15 +35,24 @@ class Field(MountedType):
**extra_args **extra_args
): ):
super(Field, self).__init__(_creation_counter=_creation_counter) super(Field, self).__init__(_creation_counter=_creation_counter)
assert not args or isinstance(args, Mapping), ( raise_assertion_if_not(
'Arguments in a field have to be a mapping, received "{}".' condition=not args or isinstance(args, Mapping),
).format(args) message='Arguments in a field have to be a mapping, received "{}".'.format(
assert not ( args
source and resolver )
), "A Field cannot have a source and a resolver in at the same time." )
assert not callable(default_value), (
'The default value can not be a function but received "{}".' raise_assertion_if_not(
).format(base_type(default_value)) condition=not(source and resolver),
message="A Field cannot have a source and a resolver in at the same time."
)
raise_assertion_if_not(
condition=not callable(default_value),
message='The default value can not be a function but received "{}".'.format(
base_type(default_value)
)
)
if required: if required:
type = NonNull(type) type = NonNull(type)

View File

@ -1,5 +1,6 @@
from ..utils.orderedtype import OrderedType from ..utils.orderedtype import OrderedType
from .unmountedtype import UnmountedType from .unmountedtype import UnmountedType
from ..utils.comparison_helper import raise_assertion_if_not
class MountedType(OrderedType): class MountedType(OrderedType):
@ -8,8 +9,9 @@ class MountedType(OrderedType):
""" """
Mount the UnmountedType instance Mount the UnmountedType instance
""" """
assert isinstance(unmounted, UnmountedType), ("{} can't mount {}").format( raise_assertion_if_not(
cls.__name__, repr(unmounted) condition=isinstance(unmounted, UnmountedType),
message="{} can't mount {}".format(cls.__name__, repr(unmounted))
) )
return cls( return cls(

View File

@ -6,6 +6,7 @@ from ..utils.props import props
from .field import Field from .field import Field
from .objecttype import ObjectType, ObjectTypeOptions from .objecttype import ObjectType, ObjectTypeOptions
from .utils import yank_fields_from_attrs from .utils import yank_fields_from_attrs
from ..utils.comparison_helper import raise_assertion_if_not
# For static type checking with Mypy # For static type checking with Mypy
MYPY = False MYPY = False
@ -62,7 +63,10 @@ class Mutation(ObjectType):
if not resolver: if not resolver:
mutate = getattr(cls, "mutate", None) mutate = getattr(cls, "mutate", None)
assert mutate, "All mutations must define a mutate method in it" raise_assertion_if_not(
condition=mutate,
message="All mutations must define a mutate method in it"
)
resolver = get_unbound_function(mutate) resolver = get_unbound_function(mutate)
if _meta.fields: if _meta.fields:

View File

@ -4,6 +4,7 @@ from .base import BaseOptions, BaseType
from .field import Field from .field import Field
from .interface import Interface from .interface import Interface
from .utils import yank_fields_from_attrs from .utils import yank_fields_from_attrs
from ..utils.comparison_helper import raise_assertion_if_not
# For static type checking with Mypy # For static type checking with Mypy
MYPY = False MYPY = False
@ -39,18 +40,25 @@ class ObjectType(BaseType):
fields = OrderedDict() fields = OrderedDict()
for interface in interfaces: for interface in interfaces:
assert issubclass(interface, Interface), ( raise_assertion_if_not(
'All interfaces of {} must be a subclass of Interface. Received "{}".' condition=issubclass(interface, Interface),
).format(cls.__name__, interface) message='All interfaces of {} must be a subclass of Interface. Received "{}".'.format(
cls.__name__, interface
)
)
fields.update(interface._meta.fields) fields.update(interface._meta.fields)
for base in reversed(cls.__mro__): for base in reversed(cls.__mro__):
fields.update(yank_fields_from_attrs(base.__dict__, _as=Field)) fields.update(yank_fields_from_attrs(base.__dict__, _as=Field))
assert not (possible_types and cls.is_type_of), ( raise_assertion_if_not(
"{name}.Meta.possible_types will cause type collision with {name}.is_type_of. " condition=not (possible_types and cls.is_type_of),
"Please use one or other." message=("{name}.Meta.possible_types will cause type collision with {name}.is_type_of. " \
).format(name=cls.__name__) "Please use one or other.".format(
name=cls.__name__
)
)
)
if _meta.fields: if _meta.fields:
_meta.fields.update(fields) _meta.fields.update(fields)

View File

@ -13,6 +13,7 @@ from graphql.utils.schema_printer import print_schema
from .definitions import GrapheneGraphQLType from .definitions import GrapheneGraphQLType
from .objecttype import ObjectType from .objecttype import ObjectType
from .typemap import TypeMap, is_graphene_type from .typemap import TypeMap, is_graphene_type
from ..utils.comparison_helper import raise_assertion_if_not
def assert_valid_root_type(_type): def assert_valid_root_type(_type):
@ -20,9 +21,10 @@ def assert_valid_root_type(_type):
return return
is_graphene_objecttype = inspect.isclass(_type) and issubclass(_type, ObjectType) is_graphene_objecttype = inspect.isclass(_type) and issubclass(_type, ObjectType)
is_graphql_objecttype = isinstance(_type, GraphQLObjectType) is_graphql_objecttype = isinstance(_type, GraphQLObjectType)
assert is_graphene_objecttype or is_graphql_objecttype, ( raise_assertion_if_not(
"Type {} is not a valid ObjectType." condition=is_graphene_objecttype or is_graphql_objecttype,
).format(_type) message="Type {} is not a valid ObjectType.".format(_type)
)
class Schema(GraphQLSchema): class Schema(GraphQLSchema):
@ -53,10 +55,11 @@ class Schema(GraphQLSchema):
if directives is None: if directives is None:
directives = [GraphQLIncludeDirective, GraphQLSkipDirective] directives = [GraphQLIncludeDirective, GraphQLSkipDirective]
assert all( raise_assertion_if_not(
isinstance(d, GraphQLDirective) for d in directives condition=all(isinstance(d, GraphQLDirective) for d in directives),
), "Schema directives must be List[GraphQLDirective] if provided but got: {}.".format( message="Schema directives must be List[GraphQLDirective] if provided but got: {}.".format(
directives directives
)
) )
self._directives = directives self._directives = directives
self.build_typemap() self.build_typemap()

View File

@ -1,5 +1,6 @@
from .unmountedtype import UnmountedType from .unmountedtype import UnmountedType
from .utils import get_type from .utils import get_type
from ..utils.comparison_helper import raise_assertion_if_not
class Structure(UnmountedType): class Structure(UnmountedType):
@ -67,9 +68,12 @@ class NonNull(Structure):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(NonNull, self).__init__(*args, **kwargs) super(NonNull, self).__init__(*args, **kwargs)
assert not isinstance(self._of_type, NonNull), ( raise_assertion_if_not(
"Can only create NonNull of a Nullable GraphQLType but got: {}." condition=not isinstance(self._of_type, NonNull),
).format(self._of_type) message="Can only create NonNull of a Nullable GraphQLType but got: {}.".format(
self._of_type
)
)
def __str__(self): def __str__(self):
return "{}!".format(self.of_type) return "{}!".format(self.of_type)

View File

@ -40,6 +40,7 @@ from .scalars import ID, Boolean, Float, Int, Scalar, String
from .structures import List, NonNull from .structures import List, NonNull
from .union import Union from .union import Union
from .utils import get_field_as from .utils import get_field_as
from ..utils.comparison_helper import raise_assertion_if_not
def is_graphene_type(_type): def is_graphene_type(_type):
@ -60,10 +61,16 @@ def resolve_type(resolve_type_func, map, type_name, root, info):
if inspect.isclass(_type) and issubclass(_type, ObjectType): if inspect.isclass(_type) and issubclass(_type, ObjectType):
graphql_type = map.get(_type._meta.name) graphql_type = map.get(_type._meta.name)
assert graphql_type, "Can't find type {} in schema".format(_type._meta.name) raise_assertion_if_not(
assert graphql_type.graphene_type == _type, ( condition=graphql_type,
"The type {} does not match with the associated graphene type {}." message="Can't find type {} in schema".format(_type._meta.name)
).format(_type, graphql_type.graphene_type) )
raise_assertion_if_not(
condition=graphql_type.graphene_type is _type,
message="The type {} does not match with the associated graphene type {}.".format(
_type, graphql_type.graphene_type
)
)
return graphql_type return graphql_type
return _type return _type
@ -94,9 +101,12 @@ class TypeMap(GraphQLTypeMap):
if type._meta.name in map: if type._meta.name in map:
_type = map[type._meta.name] _type = map[type._meta.name]
if isinstance(_type, GrapheneGraphQLType): if isinstance(_type, GrapheneGraphQLType):
assert _type.graphene_type == type, ( raise_assertion_if_not(
"Found different types with the same name in the schema: {}, {}." condition=_type.graphene_type is type,
).format(_type.graphene_type, type) message="Found different types with the same name in the schema: {}, {}.".format(
_type.graphene_type, type
)
)
return map return map
if issubclass(type, ObjectType): if issubclass(type, ObjectType):
@ -173,9 +183,12 @@ class TypeMap(GraphQLTypeMap):
if type._meta.name in map: if type._meta.name in map:
_type = map[type._meta.name] _type = map[type._meta.name]
if isinstance(_type, GrapheneGraphQLType): if isinstance(_type, GrapheneGraphQLType):
assert _type.graphene_type == type, ( raise_assertion_if_not(
"Found different types with the same name in the schema: {}, {}." condition=_type.graphene_type is type,
).format(_type.graphene_type, type) message="Found different types with the same name in the schema: {}, {}.".format(
_type.graphene_type, type
)
)
return _type return _type
def interfaces(): def interfaces():
@ -183,7 +196,9 @@ class TypeMap(GraphQLTypeMap):
for interface in type._meta.interfaces: for interface in type._meta.interfaces:
self.graphene_reducer(map, interface) self.graphene_reducer(map, interface)
internal_type = map[interface._meta.name] internal_type = map[interface._meta.name]
assert internal_type.graphene_type == interface raise_assertion_if_not(
condition=internal_type.graphene_type is interface
)
interfaces.append(internal_type) interfaces.append(internal_type)
return interfaces return interfaces
@ -207,9 +222,12 @@ class TypeMap(GraphQLTypeMap):
if type._meta.name in map: if type._meta.name in map:
_type = map[type._meta.name] _type = map[type._meta.name]
if isinstance(_type, GrapheneInterfaceType): if isinstance(_type, GrapheneInterfaceType):
assert _type.graphene_type == type, ( raise_assertion_if_not(
"Found different types with the same name in the schema: {}, {}." condition=_type.graphene_type is type,
).format(_type.graphene_type, type) message="Found different types with the same name in the schema: {}, {}.".format(
_type.graphene_type, type
)
)
return _type return _type
_resolve_type = None _resolve_type = None
@ -248,7 +266,9 @@ class TypeMap(GraphQLTypeMap):
for objecttype in type._meta.types: for objecttype in type._meta.types:
self.graphene_reducer(map, objecttype) self.graphene_reducer(map, objecttype)
internal_type = map[objecttype._meta.name] internal_type = map[objecttype._meta.name]
assert internal_type.graphene_type == objecttype raise_assertion_if_not(
condition=internal_type.graphene_type is objecttype
)
union_types.append(internal_type) union_types.append(internal_type)
return union_types return union_types

View File

@ -1,5 +1,6 @@
from .base import BaseOptions, BaseType from .base import BaseOptions, BaseType
from .unmountedtype import UnmountedType from .unmountedtype import UnmountedType
from ..utils.comparison_helper import raise_assertion_if_not
# For static type checking with Mypy # For static type checking with Mypy
MYPY = False MYPY = False
@ -23,10 +24,10 @@ class Union(UnmountedType, BaseType):
@classmethod @classmethod
def __init_subclass_with_meta__(cls, types=None, **options): def __init_subclass_with_meta__(cls, types=None, **options):
assert ( raise_assertion_if_not(
isinstance(types, (list, tuple)) and len(types) > 0 condition=isinstance(types, (list, tuple)) and len(types) > 0,
), "Must provide types for Union {name}.".format(name=cls.__name__) message="Must provide types for Union {name}.".format(name=cls.__name__)
)
_meta = UnionOptions(cls) _meta = UnionOptions(cls)
_meta.types = types _meta.types = types
super(Union, cls).__init_subclass_with_meta__(_meta=_meta, **options) super(Union, cls).__init_subclass_with_meta__(_meta=_meta, **options)

View File

@ -5,6 +5,7 @@ from uuid import UUID as _UUID
from graphql.language import ast from graphql.language import ast
from .scalars import Scalar from .scalars import Scalar
from ..utils.comparison_helper import raise_assertion_if_not
class UUID(Scalar): class UUID(Scalar):
@ -14,8 +15,9 @@ class UUID(Scalar):
def serialize(uuid): def serialize(uuid):
if isinstance(uuid, str): if isinstance(uuid, str):
uuid = _UUID(uuid) uuid = _UUID(uuid)
assert isinstance(uuid, _UUID), "Expected UUID instance, received {}".format( raise_assertion_if_not(
uuid condition=isinstance(uuid, _UUID),
message="Expected UUID instance, received {}".format(uuid)
) )
return str(uuid) return str(uuid)

View File

@ -2,6 +2,7 @@ import six
from ..pyutils.compat import func_name, signature from ..pyutils.compat import func_name, signature
from .deprecated import warn_deprecation from .deprecated import warn_deprecation
from .comparison_helper import raise_assertion_if_not
def annotate(_func=None, _trigger_warning=True, **annotations): def annotate(_func=None, _trigger_warning=True, **annotations):
@ -22,9 +23,12 @@ def annotate(_func=None, _trigger_warning=True, **annotations):
# We make sure the annotations are valid # We make sure the annotations are valid
for key, value in annotations.items(): for key, value in annotations.items():
assert key in func_signature.parameters, ( raise_assertion_if_not(
'The key {key} is not a function parameter in the function "{func_name}".' condition= key in func_signature.parameters,
).format(key=key, func_name=func_name(_func)) message='The key {key} is not a function parameter in the function "{func_name}".'.format(
key=key, func_name=func_name(_func)
)
)
func_annotations = getattr(_func, "__annotations__", None) func_annotations = getattr(_func, "__annotations__", None)
if func_annotations is None: if func_annotations is None:

View File

@ -0,0 +1,3 @@
def raise_assertion_if_not(condition=None, message=None):
if not condition:
raise AssertionError(message)

View File

@ -4,6 +4,8 @@ import six
from ..pyutils.init_subclass import InitSubclassMeta from ..pyutils.init_subclass import InitSubclassMeta
from .props import props from .props import props
from .comparison_helper import raise_assertion_if_not
class SubclassWithMeta_Meta(InitSubclassMeta): class SubclassWithMeta_Meta(InitSubclassMeta):
@ -42,10 +44,13 @@ class SubclassWithMeta(six.with_metaclass(SubclassWithMeta_Meta)):
abstract = options.pop("abstract", False) abstract = options.pop("abstract", False)
if abstract: if abstract:
assert not options, ( raise_assertion_if_not(
"Abstract types can only contain the abstract attribute. " condition=not options,
"Received: abstract, {option_keys}" message="Abstract types can only contain the abstract attribute. " \
).format(option_keys=", ".join(options.keys())) "Received: abstract, {option_keys}".format(
option_keys=", ".join(options.keys())
)
)
else: else:
super_class = super(cls, cls) super_class = super(cls, cls)
if hasattr(super_class, "__init_subclass_with_meta__"): if hasattr(super_class, "__init_subclass_with_meta__"):