def check_union_name(self, ann: types.AUnion) -> None: """Raise SchemaError if `ann` does not have a proper name.""" name = ann.name from graphql.utils.assert_valid_name import COMPILED_NAME_PATTERN if name is None or not isinstance( name, str) or not COMPILED_NAME_PATTERN.match(name): args = [types.type_repr(of_t.t) for of_t in ann.of_types] defined_at = f"Defined at {ann.origin.classname}.{ann.origin.fieldname}.\n" if ann.origin else "" raise SchemaError(f"""Could not find a name for Union{args}. {defined_at} In GraphQL, any union needs a name, so all unions must be forward-referenced, e.g.: Person = Union[Manager, Employee] def person(self) -> Optional['Person']: ... """)
def check_type_name_is_valid(name): """Check if input is a valid, nonreserved GraphQL type name. Args: name: str Raises: - InvalidTypeNameError if the name doesn't consist of only alphanumeric characters and underscores, starts with a numeric character, or starts with double underscores """ if not isinstance(name, str): raise InvalidTypeNameError(u'Name "{}" is not a string.'.format(name)) if not COMPILED_NAME_PATTERN.match(name): raise InvalidTypeNameError( u'"{}" is not a valid GraphQL name.'.format(name)) if name.startswith('__'): raise InvalidTypeNameError( u'"{}" starts with two underscores, which is reserved for ' u'GraphQL internal use and is not allowed.'.format(name))
def _get_fields_for_class(schema_graph, graphql_types, field_type_overrides, hidden_classes, cls_name): """Return a dict from field name to GraphQL field type, for the specified graph class.""" properties = schema_graph.get_element_by_class_name(cls_name).properties # Add leaf GraphQL fields (class properties). all_properties = {} for property_name, property_obj in six.iteritems(properties): if COMPILED_NAME_PATTERN.match(property_name): all_properties[property_name] = property_obj.type else: warnings.warn( u'Ignoring property {} of class {} with invalid name. ' u'Property names must match /{}/.'.format( property_name, cls_name, COMPILED_NAME_PATTERN)) collections_of_non_graphql_scalars = { property_name for property_name, graphql_type in six.iteritems(all_properties) if (isinstance(strip_non_null_from_type(graphql_type), GraphQLList) and not isinstance(strip_non_null_from_type(graphql_type.of_type), GraphQLScalarType)) } if len(collections_of_non_graphql_scalars) > 0: warnings.warn( 'The fields {} of class {} were ignored since they are GraphQLLists of ' 'non-GraphQLScalarTypes. GraphQLLists of non-GraphQLScalarTypes are not ' 'currently supported in the GraphQLSchema.'.format( collections_of_non_graphql_scalars, cls_name)) # Filter collections of non-GraphQLScalarTypes. They are currently not supported. result = { property_name: graphql_type for property_name, graphql_type in six.iteritems(all_properties) if property_name not in collections_of_non_graphql_scalars } # Add edge GraphQL fields. schema_element = schema_graph.get_element_by_class_name(cls_name) outbound_edges = (('out_{}'.format(out_edge_name), schema_graph.get_element_by_class_name( out_edge_name).base_out_connection) for out_edge_name in schema_element.out_connections) inbound_edges = (('in_{}'.format(in_edge_name), schema_graph.get_element_by_class_name( in_edge_name).base_in_connection) for in_edge_name in schema_element.in_connections) for field_name, to_type_name in chain(outbound_edges, inbound_edges): edge_endpoint_type_name = None subclasses = schema_graph.get_subclass_set(to_type_name) to_type_abstract = schema_graph.get_element_by_class_name( to_type_name).abstract if not to_type_abstract and len(subclasses) > 1: # If the edge endpoint type has no subclasses, it can't be coerced into any other # type. If the edge endpoint type is abstract (an interface type), we can already # coerce it to the proper type with a GraphQL fragment. However, if the endpoint # type is non-abstract and has subclasses, we need to return its subclasses as an # union type. This is because GraphQL fragments cannot be applied on concrete # types, and GraphQL does not support inheritance of concrete types. type_names_to_union = [ subclass for subclass in subclasses if subclass not in hidden_classes ] if type_names_to_union: edge_endpoint_type_name = _get_union_type_name( type_names_to_union) else: if to_type_name not in hidden_classes: edge_endpoint_type_name = to_type_name if edge_endpoint_type_name is not None: # If we decided to not hide this edge due to its endpoint type being # non-representable, represent the edge field as the GraphQL type # List(edge_endpoint_type_name). result[field_name] = GraphQLList( graphql_types[edge_endpoint_type_name]) for field_name, field_type in six.iteritems(field_type_overrides): if field_name not in result: raise AssertionError( u'Attempting to override field "{}" from class "{}", but the ' u'class does not contain said field'.format( field_name, cls_name)) else: result[field_name] = field_type return result