PK!mH::typegql/__init__.pyfrom .core.arguments import GraphArgument, GraphArgumentList, Argument, ArgumentList from .core.connection import Connection from .core.fields import Field, ListField, InputField, ConnectionField from .core.graph import Graph, InputGraph from .core.info import GraphInfo from .core.schema import Schema from .core.types import ID, DateTime __all__ = ( 'Graph', 'InputGraph', 'GraphInfo', 'GraphArgument', 'GraphArgumentList', 'Argument', 'ArgumentList', 'Connection', 'Field', 'ListField', 'InputField', 'ConnectionField', 'Schema', 'ID', 'DateTime' ) PK!3typegql/client/__init__.pyfrom .client import Client PK!Y typegql/client/client.pyfrom typing import overload, Dict, Tuple import aiohttp from graphql import get_introspection_query, build_client_schema, DocumentNode, ExecutionResult from typegql.client.dsl import DSLSchema class Client: """ Usage: async with Client(url) as client: await client.introspection() dsl = client.dsl query = dsl.Query.clients_connection.select(dsl.ClientConnection.total_count) doc = dsl.query(query) result = await client.execute(doc) """ def __init__(self, url: str, auth=None, headers: Dict = None, use_json=True, timeout=None, camelcase=True): self.url = url self.session: aiohttp.ClientSession = None self.dsl: DSLSchema = None self.auth = auth self.headers = headers self.use_json = use_json self.timeout = timeout self.camelcase = camelcase async def init(self): self.session = self.session or aiohttp.ClientSession() async def __aenter__(self): await self.init() return self async def __aexit__(self, exc_type, exc_val, exc_tb): await self.close() async def close(self): await self.session.close() async def introspection(self): status, result = await self.execute(get_introspection_query()) assert status == 200 schema = build_client_schema(result.data) self.dsl = DSLSchema(schema, camelcase=self.camelcase) return schema @overload async def execute(self, document: DocumentNode, variable_values=None, timeout=None) -> ExecutionResult: pass @overload async def execute(self, query: str, variable_values=None, timeout=None) -> ExecutionResult: pass async def execute(self, query: str, variable_values=None, timeout=None) -> Tuple[int, ExecutionResult]: if isinstance(query, DocumentNode): query = self.dsl.as_string(query) payload = { 'query': query, 'variables': variable_values or {} } if self.use_json: body = {'json': payload} else: body = {'data': payload} async with self.session.post(self.url, auth=self.auth, headers=self.headers, timeout=timeout or self.timeout, **body) as response: result = await response.json() if self.use_json else response.text() assert 'errors' in result or 'data' in result, f'Received non-compatible response "{result}"' return response.status, ExecutionResult( errors=result.get('errors'), data=result.get('data') ) PK!""QQtypegql/client/dsl.pyimport collections import decimal from functools import partial from graphql import GraphQLField, print_ast, ast_from_value, GraphQLNonNull, GraphQLInputField, GraphQLList, \ GraphQLEnumType, GraphQLInputObjectType, OperationType, GraphQLString from graphql.language import ast from graphql.pyutils import snake_to_camel class DSLField: def __init__(self, name, f, camelcase=True): self.field = f self.ast_field = ast.FieldNode(name=ast.NameNode(value=name), arguments=[]) self.selection_set = None self.camelcase = camelcase def select(self, *fields): if not self.ast_field.selection_set: self.ast_field.selection_set = ast.SelectionSetNode(selections=[]) self.ast_field.selection_set.selections.extend(selections(*fields)) return self def __call__(self, *args, **kwargs): return self.args(*args, **kwargs) def alias(self, alias): self.ast_field.alias = ast.NameNode(value=alias) return self def args(self, **kwargs): if self.camelcase: self.args_to_camelcase(kwargs) for name, value in kwargs.items(): arg = self.field.args.get(name) assert arg, f'Invalid argument {name} for field {self.name}' arg_type_serializer = get_arg_serializer(arg.type) value = arg_type_serializer(value) self.ast_field.arguments.append( ast.ArgumentNode( name=ast.NameNode(value=name), value=get_ast_value(value) ) ) return self def args_to_camelcase(self, arguments): if not isinstance(arguments, dict): return keys = [k for k in arguments.keys()] for key in keys: if isinstance(arguments[key], list): for arg in arguments[key]: self.args_to_camelcase(arg) arguments[snake_to_camel(key, upper=False)] = arguments.pop(key) @property def ast(self): return self.ast_field @property def name(self): return self.ast.name.value class DSLType(object): def __init__(self, _type, camelcase=True): self.type = _type self.camelcase = camelcase def __getattr__(self, name): formatted_name, field_def = self.get_field(name) return DSLField(formatted_name, field_def, camelcase=self.camelcase) def get_field(self, name): if self.camelcase: name = snake_to_camel(name, upper=False) if name in self.type.fields: return name, self.type.fields[name] raise KeyError('Field {} doesnt exist in type {}.'.format(name, self.type.name)) class DSLSchema(object): def __init__(self, schema, camelcase=True): self.schema = schema self.camelcase = camelcase def __getattr__(self, name): type_def = self.schema.get_type(name) return DSLType(type_def, self.camelcase) def query(self, *fields, operation=OperationType.QUERY) -> ast.DocumentNode: return ast.DocumentNode( definitions=[ast.OperationDefinitionNode( operation=operation, selection_set=ast.SelectionSetNode( selections=list(selections(*fields)) ) )] ) def mutation(self, *fields) -> ast.DocumentNode: return self.query(*fields, operation=OperationType.MUTATION) def as_string(self, doc): return print_ast(doc) def field(f, **args): if isinstance(f, GraphQLField): return DSLField(f).args(**args) elif isinstance(f, DSLField): return f raise Exception('Received incompatible query field: "{}".'.format(field)) def selections(*fields): for _field in fields: yield field(_field).ast def get_ast_value(value): if isinstance(value, ast.Node): return value if isinstance(value, ast.ValueNode): return value if isinstance(value, str): return ast.StringValueNode(value=value) elif isinstance(value, bool): return ast.BooleanValueNode(value=value) elif isinstance(value, (float, decimal.Decimal)): return ast.FloatValueNode(value=value) elif isinstance(value, int): return ast.IntValueNode(value=value) elif isinstance(value, list): return ast.ListValueNode(values=[get_ast_value(v) for v in value]) return None def serialize_list(serializer, values): assert isinstance(values, collections.Iterable), 'Expected iterable, received "{}"'.format(repr(values)) result = list() for val in values: result.append(serializer(val)) return result def serialize_string(value): return ast.StringValueNode(value=value) def serialize_enum(arg_type, value): return ast.EnumValueNode(value=arg_type.serialize(value)) def serialize_input_object(arg_type, value): serializers = {k: get_arg_serializer(v) for k, v in arg_type.fields.items()} result = ast_from_value(value, arg_type) for f in result.fields: serialized = serializers[f.name.value](value[f.name.value]) if isinstance(f.value, ast.ListValueNode): f.value = ast.ListValueNode(values=serialized) else: f.value = serialized return result def get_arg_serializer(arg_type): if isinstance(arg_type, GraphQLNonNull): return get_arg_serializer(arg_type.of_type) if arg_type == GraphQLString: return serialize_string if isinstance(arg_type, GraphQLInputField): return get_arg_serializer(arg_type.type) if isinstance(arg_type, GraphQLList): inner_serializer = get_arg_serializer(arg_type.of_type) return partial(serialize_list, inner_serializer) if isinstance(arg_type, GraphQLEnumType): return partial(serialize_enum, arg_type) if isinstance(arg_type, GraphQLInputObjectType): return partial(serialize_input_object, arg_type) return partial(serialize_value, arg_type) def serialize_value(arg_type, value): return ast_from_value( str(value) if arg_type.serialize(value) is None else arg_type.serialize(value), arg_type ) PK!typegql/core/__init__.pyPK!%xxtypegql/core/arguments.pyimport dataclasses from typing import Generic, TypeVar, List T = TypeVar('T', bound='Graph') @dataclasses.dataclass class GraphArgument(Generic[T]): name: str description: str = '' required: bool = False is_input: bool = False @property def type(self): return self.__orig_class__.__args__[0] @dataclasses.dataclass class GraphArgumentList(Generic[T]): name: str description: str = '' required: bool = False is_input: bool = False @property def type(self): return List[self.__orig_class__.__args__[0]] Argument = GraphArgument ArgumentList = GraphArgumentList PK!C!!typegql/core/builder.pyfrom typing import get_type_hints, Type, Any, Dict import graphql from graphql.pyutils import snake_to_camel from .arguments import Argument, ArgumentList from .connection import Connection, Node, Edge, PageInfo, T from .fields import Field from .graph import Graph from .info import GraphInfo from .types import DateTime, Dictionary from .utils import is_enum, is_list, is_graph, is_connection class SchemaBuilder: def __init__(self, camelcase: bool, types: Dict = None): self.camelcase = camelcase self.types = types or { 'ID': graphql.GraphQLID, 'bool': graphql.GraphQLBoolean, 'int': graphql.GraphQLInt, 'float': graphql.GraphQLFloat, 'str': graphql.GraphQLString, 'datetime': DateTime(), 'Dict': Dictionary() } def get_fields(self, graph: Type[Graph], is_mutation=False): result = dict() meta = getattr(graph, 'Meta', None) exclude = getattr(meta, 'graph_exclude', tuple()) for name, _type in get_type_hints(graph).items(): if name in exclude: continue if isinstance(_type, Field): info = _type.info _type = _type.type else: info = getattr(meta, name, GraphInfo()) assert isinstance(info, GraphInfo), f'{graph.__name__} info for `{name}` MUST be of type `GraphInfo`' if is_mutation and not info.mutation: continue graph_type = self.map_type(_type, is_mutation=is_mutation) if not graph_type: continue if info.required: graph_type = graphql.GraphQLNonNull(graph_type) if is_connection(_type): info.arguments.extend(_type.page_arguments()) args = self.arguments(info, self.camelcase) field_name = info.name or name if self.camelcase: field_name = snake_to_camel(field_name, upper=False) if is_mutation: result[field_name] = graph_type else: result[field_name] = graphql.GraphQLField(graph_type, description=info.description, args=args) return result def map_type(self, _type: Any, is_mutation=False): if isinstance(_type, graphql.GraphQLType): return _type try: type_name = _type.__name__ except AttributeError: type_name = _type._name if not type_name: type_name = _type.__origin__.__name__ if is_connection(_type): return self.get_connection_fields(_type) if is_enum(_type): if type_name in self.types: return self.types.get(type_name) enum_type = graphql.GraphQLEnumType(type_name, _type) self.types[type_name] = enum_type return enum_type if is_list(_type): inner = self.map_type(_type.__args__[0], is_mutation=is_mutation) return graphql.GraphQLList(inner) if is_graph(_type): return self.build_object_type(type_name, _type, is_mutation=is_mutation) return self.types.get(type_name) def build_object_type(self, type_name, _type, info: GraphInfo = None, is_mutation=False): if is_mutation: type_name = f'{type_name}Mutation' if type_name in self.types: return self.types[type_name] fields = self.get_fields(_type, is_mutation=is_mutation) if not is_mutation: graph_type = graphql.GraphQLObjectType(type_name, description=_type.__doc__, fields=fields) else: graph_type = graphql.GraphQLInputObjectType(type_name, description=_type.__doc__, fields=fields) if isinstance(info, GraphInfo): if info.required: graph_type = graphql.GraphQLNonNull(graph_type) self.types[type_name] = graph_type return graph_type def arguments(self, info: GraphInfo, camelcase=True): result: graphql.GraphQLArgumentMap = dict() arguments = getattr(info, 'arguments') if not isinstance(arguments, (list, tuple)): return for arg in arguments: if not isinstance(arg, (Argument, ArgumentList)): continue _type = self.map_type(arg.type, is_mutation=arg.is_input) if arg.required: _type = graphql.GraphQLNonNull(_type) arg_name = snake_to_camel(arg.name, False) if camelcase else arg.name result[arg_name] = graphql.GraphQLArgument(_type, description=arg.description) return result def get_connection_fields(self, graph: Type[Connection]): if not is_connection(graph): return self.get_fields(graph) self.build_connection_interface() connection_class = graph.__origin__ wrapped = graph.__args__[0] fields = {} meta = getattr(graph, 'Meta', None) for name, _type in get_type_hints(connection_class).items(): info = getattr(meta, name, GraphInfo()) if is_list(_type) and _type.__args__[0] is Edge[T]: inner = _type.__args__[0] graph_type = graphql.GraphQLList(self.get_edge_field(inner.__origin__, wrapped)) else: graph_type = self.map_type(_type) if info.required: graph_type = graphql.GraphQLNonNull(graph_type) arguments = self.arguments(info, self.camelcase) field_name = info.name or name if self.camelcase: field_name = snake_to_camel(field_name, upper=False) fields[field_name] = graphql.GraphQLField(graph_type, description=info.description, args=arguments) type_name = f'{wrapped.__name__}Connection' if type_name in self.types: return self.types.get(type_name) result = graphql.GraphQLObjectType(type_name, fields=fields, interfaces=(self.types.get('Connection'),)) self.types[type_name] = result return result def get_edge_field(self, edge_type, inner: Type[T], camelcase=True): fields = dict() meta = getattr(edge_type, 'Meta', None) for name, _type in get_type_hints(edge_type).items(): info = getattr(meta, name, GraphInfo()) if _type is Node[T]: graph_type = self.get_node_fields(inner) else: graph_type = self.map_type(_type) if info.required: graph_type = graphql.GraphQLNonNull(graph_type) field_name = info.name or name if camelcase: field_name = snake_to_camel(field_name, upper=False) fields[field_name] = graph_type type_name = f'{inner.__name__}Edge' if type_name in self.types: return self.types.get(type_name) result = graphql.GraphQLNonNull(graphql.GraphQLObjectType( f'{inner.__name__}Edge', fields=fields, interfaces=(self.types.get('Edge'),) )) self.types[type_name] = result return result def get_node_fields(self, _type: Type[T]): type_name = f'{_type.__name__}Node' if type_name in self.types: return self.types.get(type_name) result = graphql.GraphQLObjectType( type_name, description=_type.__doc__, fields=self.get_fields(_type), interfaces=(self.types.get('Node'),) ) self.types[type_name] = result return result def build_connection_interface(self): if 'Node' not in self.types: self.types['Node'] = graphql.GraphQLInterfaceType('Node', self.get_fields(Node)) if 'Edge' not in self.types: self.types['Edge'] = graphql.GraphQLInterfaceType('Edge', self.get_fields(Edge)) if 'PageInfo' not in self.types: self.types['PageInfo'] = graphql.GraphQLObjectType('PageInfo', self.get_fields(PageInfo)) if 'Connection' not in self.types: self.types['Connection'] = graphql.GraphQLInterfaceType('Connection', self.get_fields(Connection)) PK!-dtypegql/core/connection.pyfrom typing import Type, get_type_hints, TypeVar, Generic, List import graphql from graphql.pyutils import snake_to_camel from typegql import GraphArgument from .graph import Graph from .types import ID from .info import GraphInfo T = TypeVar('T', bound=Graph) class Node(Graph, Generic[T]): id: ID class Meta: id = GraphInfo(required=True) class Edge(Graph, Generic[T]): node: Node[T] cursor: str class Meta: node = GraphInfo(required=True, description='Scalar representing your data') cursor = GraphInfo(required=True, description='Pagination cursor') class PageInfo(Graph): has_next: bool has_previous: bool start_cursor: str end_cursor: str class Meta: has_next = GraphInfo(required=True, description='When paginating forwards, are there more items?') has_previous = GraphInfo(required=True, description='When paginating backwards, are there more items?') class Connection(Graph, Generic[T]): edges: List[Edge[T]] page_info: PageInfo class Meta: edges = GraphInfo(required=True, description='Connection edges') page_info = GraphInfo(required=True, description='Pagination information') @classmethod def page_arguments(cls): return [ GraphArgument[int]('first', description='Retrieve only the first `n` nodes of this connection'), GraphArgument[int]('last', description='Retrieve only the last `n` nodes of this connection'), GraphArgument[str]('before', description='Retrieve nodes for this connection before this cursor'), GraphArgument[str]('after', description='Retrieve nodes for this connection after this cursor') ] PK!:4h::typegql/core/execution.pyfrom inspect import isawaitable from typing import List, Any, Union from graphql import ExecutionContext, GraphQLField, FieldNode, GraphQLFieldResolver, GraphQLResolveInfo, GraphQLError, \ GraphQLSchema, is_introspection_type from graphql.execution.values import get_argument_values from graphql.pyutils import camel_to_snake class TGQLExecutionContext(ExecutionContext): async def await_result(self, result): return await result def resolve_field_value_or_error( self, field_def: GraphQLField, field_nodes: List[FieldNode], resolve_fn: GraphQLFieldResolver, source: Any, info: GraphQLResolveInfo ) -> Union[Exception, Any]: try: camelcase = getattr(info.schema, 'camelcase', False) arguments = get_argument_values(field_def, field_nodes[0], self.variable_values) if camelcase and not is_introspection_type(info.parent_type): self.to_snake(info, arguments) result = resolve_fn(source, info, **arguments) if isawaitable(result): return self.await_result(result) return result except GraphQLError as e: return e def to_snake(self, info, arguments): if not isinstance(arguments, dict): return keys = [k for k in arguments.keys()] for key in keys: if isinstance(arguments[key], list): for arg in arguments[key]: self.to_snake(info, arg) arguments[camel_to_snake(key)] = arguments.pop(key) PK!ytypegql/core/fields.pyimport functools from typing import List, Any, Type from .arguments import Argument from .connection import Connection from .info import GraphInfo _cleanups = [] def cache(func): cached = functools.lru_cache()(func) _cleanups.append(cached.cache_clear) @functools.wraps(func) def inner(*args, **kwds): try: return cached(*args, **kwds) except TypeError: pass # All real errors (not unhashable args) are raised below. return func(*args, **kwds) return inner class Field: def __init__(self, _type: Type[Any], name: str = None, description: str = None, required: bool = False, arguments: List[Argument] = None, mutation: bool = True): """ Wraps a field intro a GraphQLField :param _type: original type :param name: field name as it should show in introspection :param description: field description as it should show in introspection :param required: is it nullable? :param arguments: GraphQL arguments for this field :param mutation: Should it be available for GraphQL mutations? """ self._type = _type self._name = name self._description = description self.required = required self.arguments = arguments self.mutation = mutation @cache def __class_getitem__(cls, *args): assert len(args) == 1, 'Field container accepts a single argument' item = args[0] return cls(item) def __call__(self, *args, **kwargs): self._name = kwargs.get('name') description = kwargs.get('description') if description: self._description = description self.required = kwargs.get('required', False) self.arguments = kwargs.get('arguments', list()) return self @property def type(self): return self._type @property def name(self) -> str: return self._name @property def description(self) -> str: return self._description @property def info(self) -> GraphInfo: return GraphInfo(name=self.name, description=self.description, required=self.required, arguments=self.arguments, mutation=self.mutation) class ListField(Field): """GraphQL list field""" def __init__(self, _type: Type[Any], name: str = None, description: str = None, required: bool = False, arguments: List[Argument] = None): _type = List[_type] super().__init__(_type, name, description, required, arguments) class InputField(Field): """GraphQL field which can also be used in mutations""" def __init__(self, _type: Type[Any], name: str = None, description: str = None, required: bool = False, arguments: List[Argument] = None): super().__init__(_type, name, description, required, arguments, mutation=True) class RequiredField(Field): """GraphQL Non NULL field""" def __init__(self, _type: Type[Any], name: str = None, description: str = None, required: bool = True, arguments: List[Argument] = None): super().__init__(_type, name, description, required, arguments) class ReadonlyField(Field): """GraphQL Field that can't be used in mutations""" def __init__(self, _type: Type[Any], name: str = None, description: str = None, required: bool = False, arguments: List[Argument] = None): super().__init__(_type, name, description, required, arguments, mutation=False) class ConnectionField(Field): """Relay connection field""" def __call__(self, *args, **kwargs): connection_class = kwargs.get('connection_class', Connection) self._type = connection_class[self._type] return super().__call__(*args, **kwargs) PK!COtypegql/core/graph.pyfrom typing import get_type_hints class Graph: def __init__(self, **kwargs): for name, _ in get_type_hints(self.__class__).items(): if name not in kwargs: continue setattr(self, name, kwargs.get(name)) InputGraph = Graph PK!ݠtypegql/core/info.pyimport dataclasses from typing import List from .arguments import GraphArgument @dataclasses.dataclass class GraphInfo: name: str = dataclasses.field(default='') required: bool = dataclasses.field(default=False) mutation: bool = dataclasses.field(default=True) description: str = dataclasses.field(default='') arguments: List[GraphArgument] = dataclasses.field(default_factory=list) PK!q typegql/core/schema.pyimport logging from typing import Type, Callable, Any from graphql import GraphQLSchema, GraphQLObjectType, graphql, OperationType, validate_schema from graphql.pyutils import camel_to_snake from .builder import SchemaBuilder from .execution import TGQLExecutionContext from .graph import Graph from .utils import is_graph, is_connection logger = logging.getLogger(__name__) class Schema(GraphQLSchema): def __init__(self, query: Type[Graph] = None, mutation: Type[Graph] = None, subscription: Type[Graph] = None, camelcase=True): super().__init__() self.camelcase = camelcase builder = SchemaBuilder(self.camelcase) if query: self.query: Callable = query query_fields = builder.get_fields(query) query = GraphQLObjectType( 'Query', fields=query_fields, ) if mutation: self.mutation: Callable = mutation mutation_fields = builder.get_fields(mutation) mutation = GraphQLObjectType( 'Mutation', fields=mutation_fields ) if subscription: self.subscription: Callable = subscription subscription_fields = builder.get_fields(subscription) subscription = GraphQLObjectType( 'Subscription', fields=subscription_fields ) super().__init__(query, mutation, subscription) errors = validate_schema(self) if errors: raise errors[0] def _field_resolver(self, source, info, **kwargs): field_name = info.field_name if self.camelcase: field_name = camel_to_snake(field_name) if info.operation.operation == OperationType.MUTATION and is_graph(source.__class__): try: mutation = getattr(source, f'mutate_{field_name}') return mutation(info, **kwargs) except AttributeError: return if is_graph(source.__class__): _type = source.__annotations__.get(field_name) if is_connection(_type): method = getattr(_type, 'resolve', None) if method: return method(source, field_name, _type.__args__[0], info, **kwargs) value = ( source.get(field_name) if isinstance(source, dict) else getattr(source, f'resolve_{field_name}', getattr(source, field_name, None)) ) if callable(value): return value(info, **kwargs) return value async def run(self, query: str, root: Graph = None, operation: str = None, context: Any = None, variables=None, middleware=None): if query.startswith('mutation') and not root: root = self.mutation() elif not root: root = self.query() result = await graphql(self, query, root_value=root, field_resolver=self._field_resolver, operation_name=operation, context_value=context, variable_values=variables, middleware=middleware, execution_context_class=TGQLExecutionContext) return result PK!XBtypegql/core/types.pyimport base64 from datetime import datetime from typing import Dict import graphql from graphql.language import ast class DateTime(graphql.GraphQLScalarType): def __init__(self, name='DateTime'): super().__init__( name=name, description='The `DateTime` scalar type represents a DateTime value as specified by ' '[iso8601](https://en.wikipedia.org/wiki/ISO_8601).', serialize=DateTime.serialize, parse_value=DateTime.parse_value, parse_literal=DateTime.parse_literal, ) @staticmethod def serialize(value: datetime): assert isinstance(value, datetime), 'datetime value expected' return value.isoformat() @staticmethod def parse_literal(node): if isinstance(node, ast.StringValueNode): try: return datetime.fromisoformat(node.value) except ValueError: pass @staticmethod def parse_value(value: str): try: return datetime.fromisoformat(value) except ValueError: pass class ID(graphql.GraphQLScalarType): @classmethod def encode(cls, value): if not isinstance(value, str): value = str(value) return base64.b64encode(value.encode()).decode() @classmethod def decode(cls, value): return base64.b64decode(value).decode() class Dictionary(graphql.GraphQLScalarType): def __init__(self, name='Dictionary'): super().__init__( name=name, description='Dictionary type / HashMap', serialize=Dictionary.serialize, parse_value=Dictionary.parse_value, parse_literal=Dictionary.parse_literal, ) @staticmethod def serialize(value: Dict): assert isinstance(value, dict), 'dict value expected' return value @staticmethod def parse_literal(node): if isinstance(node, ast.StringValueNode): try: return eval(node.value) except ValueError: pass @staticmethod def parse_value(value: str): try: return eval(value) except ValueError: pass PK!rtypegql/core/utils.pyfrom enum import Enum from typing import Any, List from .connection import Connection from .graph import Graph def is_list(_type: Any) -> bool: try: return issubclass(_type.__origin__, List) except AttributeError: return False def is_enum(_type: Any) -> bool: try: return issubclass(_type, Enum) except TypeError: return False def is_graph(_type: Any) -> bool: try: return issubclass(_type, Graph) except TypeError: return False def is_connection(_type: Any) -> bool: try: return _type.__origin__ is Connection or issubclass(_type.__origin__, Connection) except (TypeError, AttributeError): return False PK!HlUTtypegql-1.0.9.dist-info/WHEEL HM K-*ϳR03rOK-J,/R(O-)T0343 /, (-JLR()*M IL*4KM̫PK!HMn typegql-1.0.9.dist-info/METADATAYs۸οsdEǾIҺS+_יW#C$$& mkŃI~S}A`a94⢈atJs*. ꥃ]spY9/+$i:&IX!zI5-SRaEмXZ$ERIɊdETUBj2RBժHP(ElPȶԺTT(~K)PJMcBUwz2U1YwYXBsLD$ +X19vSdj`Aɇ]pQ3$$qL>_qYJqRrg)@ Ժa`z㙟3$"1٧aHW)$6fEz Mp:ө39(l6E -DRqG6Oc,LY4cjkZm|:gڻ1F,O]mM$e5˸Z28 V4C;AzoP+` ux ˵-hᕬNZ\=T\۰&2`@ݨ6M#&J$!>;)%9w.OZAy{(Lg)%1y7PHvqnug:J!D41qa^ı!ݭYnSm~TqᯢXO/can]15(Lm$7 6-gYgn/0{`s.+ "MLC"}#7M73I#]d A$8Fj9`#0klBtU hQVڍ LGeϹOq}ncRԑ ZL f:Jibj@yC vA;["+laНuvH5ۡ>v;z'$Zu!ףI߸>z!+mBޓ5;ҋild:m͉MW&A 謟_QUJHi52Gzjsq*c7kVv^تPd[͉I:͊1 O;i~[\vָ3-6#A+UEeLT@!ѝ38;}|/b^ۥHBb50~#E,[c=Cfy Ҏ&70SZ!4V|so~Ll* ԡaF50YHd.FRus*{sDQ/x뇹8EnM}XH hBchS]pݜp Ԓ Fb~ xOqpp8xdK Ȭ]0 4¿͢bw~6‘\ y0idɲҽ`%' PK!H5h:otypegql-1.0.9.dist-info/RECORDuɲX}= Bf`TAxootW7UgE柙i_GVd>JI}frafkSs'.:&R;IZ!DPȏ_*'j"pPc.nSTHbzJ<"i<FBOgIF+Ez*G#xAK4ib͑O0Fs*@%+,#pKк"9E Z;ĿxA Zb>rđ'=6ʚ8iqXvD B5HU"pUSJ>-ԞOAWhVլqH })xN7w{[MS ˲fc~)=~8{a4q8m!NeߘnRxhm{g-aձЏ%V9Y(w,\(M<;2nQIh2GIW6f[hg*ƴ|OphԚNP-K6Z+^4B+1)wem+.b_GcyX # v^1}ui$ْL fD` !-fqoYi+ëSvK#0U#|OX6?F*YVH*h: VyPXE^#Z„JeQJ`_ēڭ$?C8jg2D!a E9~: ;a |2Yr|-MM01_lO벓3uv3lX,ω쏰!pgPK!mH::typegql/__init__.pyPK!3ktypegql/client/__init__.pyPK!Y typegql/client/client.pyPK!""QQ typegql/client/dsl.pyPK!I&typegql/core/__init__.pyPK!%xx&typegql/core/arguments.pyPK!C!!.)typegql/core/builder.pyPK!-dsJtypegql/core/connection.pyPK!:4h::eQtypegql/core/execution.pyPK!yWtypegql/core/fields.pyPK!CO gtypegql/core/graph.pyPK!ݠQhtypegql/core/info.pyPK!q jtypegql/core/schema.pyPK!XBwtypegql/core/types.pyPK!rtypegql/core/utils.pyPK!HlUTރtypegql-1.0.9.dist-info/WHEELPK!HMn ntypegql-1.0.9.dist-info/METADATAPK!H5h:otypegql-1.0.9.dist-info/RECORDPK