1from operator import attrgetter 2from typing import Any, List, Union 3 4from pytest import mark, raises 5 6from graphql.language import parse, DirectiveLocation 7from graphql.pyutils import inspect 8from graphql.type import ( 9 assert_directive, 10 assert_enum_type, 11 assert_input_object_type, 12 assert_interface_type, 13 assert_object_type, 14 assert_scalar_type, 15 assert_union_type, 16 assert_valid_schema, 17 is_input_type, 18 is_output_type, 19 validate_schema, 20 GraphQLArgument, 21 GraphQLDirective, 22 GraphQLEnumType, 23 GraphQLEnumValue, 24 GraphQLField, 25 GraphQLInputField, 26 GraphQLInputType, 27 GraphQLInputObjectType, 28 GraphQLInt, 29 GraphQLInterfaceType, 30 GraphQLList, 31 GraphQLNamedType, 32 GraphQLNonNull, 33 GraphQLObjectType, 34 GraphQLOutputType, 35 GraphQLSchema, 36 GraphQLString, 37 GraphQLUnionType, 38) 39from graphql.utilities import build_schema, extend_schema 40 41from ..utils import dedent 42 43SomeSchema = build_schema( 44 """ 45 scalar SomeScalar 46 47 interface SomeInterface { f: SomeObject } 48 49 type SomeObject implements SomeInterface { f: SomeObject } 50 51 union SomeUnion = SomeObject 52 53 enum SomeEnum { ONLY } 54 55 input SomeInputObject { val: String = "hello" } 56 57 directive @SomeDirective on QUERY 58 """ 59) 60 61get_type = SomeSchema.get_type 62SomeScalarType = assert_scalar_type(get_type("SomeScalar")) 63SomeInterfaceType = assert_interface_type(get_type("SomeInterface")) 64SomeObjectType = assert_object_type(get_type("SomeObject")) 65SomeUnionType = assert_union_type(get_type("SomeUnion")) 66SomeEnumType = assert_enum_type(get_type("SomeEnum")) 67SomeInputObjectType = assert_input_object_type(get_type("SomeInputObject")) 68SomeDirective = assert_directive(SomeSchema.get_directive("SomeDirective")) 69 70 71def with_modifiers( 72 type_: GraphQLNamedType, 73) -> List[Union[GraphQLNamedType, GraphQLNonNull, GraphQLList]]: 74 return [ 75 type_, 76 GraphQLList(type_), 77 GraphQLNonNull(type_), 78 GraphQLNonNull(GraphQLList(type_)), 79 ] 80 81 82output_types = [ 83 *with_modifiers(GraphQLString), 84 *with_modifiers(SomeScalarType), 85 *with_modifiers(SomeEnumType), 86 *with_modifiers(SomeObjectType), 87 *with_modifiers(SomeUnionType), 88 *with_modifiers(SomeInterfaceType), 89] 90 91not_output_types = with_modifiers(SomeInputObjectType) 92 93input_types = [ 94 *with_modifiers(GraphQLString), 95 *with_modifiers(SomeScalarType), 96 *with_modifiers(SomeEnumType), 97 *with_modifiers(SomeInputObjectType), 98] 99 100not_input_types = [ 101 *with_modifiers(SomeObjectType), 102 *with_modifiers(SomeUnionType), 103 *with_modifiers(SomeInterfaceType), 104] 105 106not_graphql_types = [ 107 type("IntType", (int,), {"name": "IntType"}), 108 type("FloatType", (float,), {"name": "FloatType"}), 109 type("StringType", (str,), {"name": "StringType"}), 110] 111 112 113get_name = attrgetter("__class__.__name__") 114 115 116def schema_with_field_type(type_): 117 return GraphQLSchema( 118 query=GraphQLObjectType(name="Query", fields={"f": GraphQLField(type_)}) 119 ) 120 121 122def describe_type_system_a_schema_must_have_object_root_types(): 123 def accepts_a_schema_whose_query_type_is_an_object_type(): 124 schema = build_schema( 125 """ 126 type Query { 127 test: String 128 } 129 """ 130 ) 131 assert validate_schema(schema) == [] 132 133 schema_with_def = build_schema( 134 """ 135 schema { 136 query: QueryRoot 137 } 138 139 type QueryRoot { 140 test: String 141 } 142 """ 143 ) 144 145 assert validate_schema(schema_with_def) == [] 146 147 def accepts_a_schema_whose_query_and_mutation_types_are_object_types(): 148 schema = build_schema( 149 """ 150 type Query { 151 test: String 152 } 153 154 type Mutation { 155 test: String 156 } 157 """ 158 ) 159 assert validate_schema(schema) == [] 160 161 schema_with_def = build_schema( 162 """ 163 schema { 164 query: QueryRoot 165 mutation: MutationRoot 166 } 167 168 type QueryRoot { 169 test: String 170 } 171 172 type MutationRoot { 173 test: String 174 } 175 """ 176 ) 177 assert validate_schema(schema_with_def) == [] 178 179 def accepts_a_schema_whose_query_and_subscription_types_are_object_types(): 180 schema = build_schema( 181 """ 182 type Query { 183 test: String 184 } 185 186 type Subscription { 187 test: String 188 } 189 """ 190 ) 191 assert validate_schema(schema) == [] 192 193 schema_with_def = build_schema( 194 """ 195 schema { 196 query: QueryRoot 197 subscription: SubscriptionRoot 198 } 199 200 type QueryRoot { 201 test: String 202 } 203 204 type SubscriptionRoot { 205 test: String 206 } 207 """ 208 ) 209 assert validate_schema(schema_with_def) == [] 210 211 def rejects_a_schema_without_a_query_type(): 212 schema = build_schema( 213 """ 214 type Mutation { 215 test: String 216 } 217 """ 218 ) 219 assert validate_schema(schema) == [ 220 {"message": "Query root type must be provided.", "locations": None} 221 ] 222 223 schema_with_def = build_schema( 224 """ 225 schema { 226 mutation: MutationRoot 227 } 228 229 type MutationRoot { 230 test: String 231 } 232 """ 233 ) 234 assert validate_schema(schema_with_def) == [ 235 {"message": "Query root type must be provided.", "locations": [(2, 13)]} 236 ] 237 238 def rejects_a_schema_whose_query_root_type_is_not_an_object_type(): 239 schema = build_schema( 240 """ 241 input Query { 242 test: String 243 } 244 """ 245 ) 246 assert validate_schema(schema) == [ 247 { 248 "message": "Query root type must be Object type," 249 " it cannot be Query.", 250 "locations": [(2, 13)], 251 } 252 ] 253 254 schema_with_def = build_schema( 255 """ 256 schema { 257 query: SomeInputObject 258 } 259 260 input SomeInputObject { 261 test: String 262 } 263 """ 264 ) 265 assert validate_schema(schema_with_def) == [ 266 { 267 "message": "Query root type must be Object type," 268 " it cannot be SomeInputObject.", 269 "locations": [(3, 22)], 270 } 271 ] 272 273 def rejects_a_schema_whose_mutation_type_is_an_input_type(): 274 schema = build_schema( 275 """ 276 type Query { 277 field: String 278 } 279 280 input Mutation { 281 test: String 282 } 283 """ 284 ) 285 assert validate_schema(schema) == [ 286 { 287 "message": "Mutation root type must be Object type if provided," 288 " it cannot be Mutation.", 289 "locations": [(6, 13)], 290 } 291 ] 292 293 schema_with_def = build_schema( 294 """ 295 schema { 296 query: Query 297 mutation: SomeInputObject 298 } 299 300 type Query { 301 field: String 302 } 303 304 input SomeInputObject { 305 test: String 306 } 307 """ 308 ) 309 assert validate_schema(schema_with_def) == [ 310 { 311 "message": "Mutation root type must be Object type if provided," 312 " it cannot be SomeInputObject.", 313 "locations": [(4, 25)], 314 } 315 ] 316 317 def rejects_a_schema_whose_subscription_type_is_an_input_type(): 318 schema = build_schema( 319 """ 320 type Query { 321 field: String 322 } 323 324 input Subscription { 325 test: String 326 } 327 """ 328 ) 329 assert validate_schema(schema) == [ 330 { 331 "message": "Subscription root type must be Object type if" 332 " provided, it cannot be Subscription.", 333 "locations": [(6, 13)], 334 } 335 ] 336 337 schema_with_def = build_schema( 338 """ 339 schema { 340 query: Query 341 subscription: SomeInputObject 342 } 343 344 type Query { 345 field: String 346 } 347 348 input SomeInputObject { 349 test: String 350 } 351 """ 352 ) 353 assert validate_schema(schema_with_def) == [ 354 { 355 "message": "Subscription root type must be Object type if" 356 " provided, it cannot be SomeInputObject.", 357 "locations": [(4, 29)], 358 } 359 ] 360 361 def rejects_a_schema_extended_with_invalid_root_types(): 362 schema = build_schema( 363 """ 364 input SomeInputObject { 365 test: String 366 } 367 """ 368 ) 369 schema = extend_schema( 370 schema, 371 parse( 372 """ 373 extend schema { 374 query: SomeInputObject 375 } 376 """ 377 ), 378 ) 379 schema = extend_schema( 380 schema, 381 parse( 382 """ 383 extend schema { 384 mutation: SomeInputObject 385 } 386 """ 387 ), 388 ) 389 schema = extend_schema( 390 schema, 391 parse( 392 """ 393 extend schema { 394 subscription: SomeInputObject 395 } 396 """ 397 ), 398 ) 399 assert validate_schema(schema) == [ 400 { 401 "message": "Query root type must be Object type," 402 " it cannot be SomeInputObject.", 403 "locations": [(3, 26)], 404 }, 405 { 406 "message": "Mutation root type must be Object type" 407 " if provided, it cannot be SomeInputObject.", 408 "locations": [(3, 29)], 409 }, 410 { 411 "message": "Subscription root type must be Object type" 412 " if provided, it cannot be SomeInputObject.", 413 "locations": [(3, 33)], 414 }, 415 ] 416 417 def rejects_a_schema_whose_types_are_incorrectly_type(): 418 # invalid schema cannot be built with Python 419 with raises(TypeError) as exc_info: 420 # noinspection PyTypeChecker 421 GraphQLSchema( 422 SomeObjectType, 423 types=[{"name": "SomeType"}, SomeDirective], # type: ignore 424 ) 425 assert str(exc_info.value) == ( 426 "Schema types must be specified as a collection of GraphQL types." 427 ) 428 # construct invalid schema manually 429 schema = GraphQLSchema(SomeObjectType) 430 schema.type_map = { 431 "SomeType": {"name": "SomeType"}, # type: ignore 432 "SomeDirective": SomeDirective, # type: ignore 433 } 434 assert validate_schema(schema) == [ 435 {"message": "Expected GraphQL named type but got: {'name': 'SomeType'}."}, 436 {"message": "Expected GraphQL named type but got: @SomeDirective."}, 437 ] 438 439 def rejects_a_schema_whose_directives_are_incorrectly_typed(): 440 schema = GraphQLSchema( 441 SomeObjectType, 442 directives=[None, "SomeDirective", SomeScalarType], # type: ignore 443 ) 444 assert validate_schema(schema) == [ 445 {"message": "Expected directive but got: None."}, 446 {"message": "Expected directive but got: 'SomeDirective'."}, 447 {"message": "Expected directive but got: SomeScalar."}, 448 ] 449 450 451def describe_type_system_objects_must_have_fields(): 452 def accepts_an_object_type_with_fields_object(): 453 schema = build_schema( 454 """ 455 type Query { 456 field: SomeObject 457 } 458 459 type SomeObject { 460 field: String 461 } 462 """ 463 ) 464 assert validate_schema(schema) == [] 465 466 def rejects_an_object_type_with_missing_fields(): 467 schema = build_schema( 468 """ 469 type Query { 470 test: IncompleteObject 471 } 472 473 type IncompleteObject 474 """ 475 ) 476 assert validate_schema(schema) == [ 477 { 478 "message": "Type IncompleteObject must define one or more fields.", 479 "locations": [(6, 13)], 480 } 481 ] 482 483 manual_schema = schema_with_field_type( 484 GraphQLObjectType("IncompleteObject", {}) 485 ) 486 msg = validate_schema(manual_schema)[0].message 487 assert msg == "Type IncompleteObject must define one or more fields." 488 489 manual_schema_2 = schema_with_field_type( 490 GraphQLObjectType("IncompleteObject", lambda: {}) 491 ) 492 msg = validate_schema(manual_schema_2)[0].message 493 assert msg == "Type IncompleteObject must define one or more fields." 494 495 def rejects_an_object_type_with_incorrectly_named_fields(): 496 schema = schema_with_field_type( 497 GraphQLObjectType( 498 "SomeObject", {"bad-name-with-dashes": GraphQLField(GraphQLString)} 499 ) 500 ) 501 msg = validate_schema(schema)[0].message 502 assert msg == ( 503 "Names must match /^[_a-zA-Z][_a-zA-Z0-9]*$/" 504 " but 'bad-name-with-dashes' does not." 505 ) 506 507 508def describe_type_system_field_args_must_be_properly_named(): 509 def accepts_field_args_with_valid_names(): 510 schema = schema_with_field_type( 511 GraphQLObjectType( 512 "SomeObject", 513 { 514 "goodField": GraphQLField( 515 GraphQLString, args={"goodArg": GraphQLArgument(GraphQLString)} 516 ) 517 }, 518 ) 519 ) 520 assert validate_schema(schema) == [] 521 522 def rejects_field_args_with_invalid_names(): 523 schema = schema_with_field_type( 524 GraphQLObjectType( 525 "SomeObject", 526 { 527 "badField": GraphQLField( 528 GraphQLString, 529 args={"bad-name-with-dashes": GraphQLArgument(GraphQLString)}, 530 ) 531 }, 532 ) 533 ) 534 535 msg = validate_schema(schema)[0].message 536 assert msg == ( 537 "Names must match /^[_a-zA-Z][_a-zA-Z0-9]*$/" 538 " but 'bad-name-with-dashes' does not." 539 ) 540 541 542def describe_type_system_union_types_must_be_valid(): 543 def accepts_a_union_type_with_member_types(): 544 schema = build_schema( 545 """ 546 type Query { 547 test: GoodUnion 548 } 549 550 type TypeA { 551 field: String 552 } 553 554 type TypeB { 555 field: String 556 } 557 558 union GoodUnion = 559 | TypeA 560 | TypeB 561 """ 562 ) 563 assert validate_schema(schema) == [] 564 565 def rejects_a_union_type_with_empty_types(): 566 schema = build_schema( 567 """ 568 type Query { 569 test: BadUnion 570 } 571 572 union BadUnion 573 """ 574 ) 575 576 schema = extend_schema( 577 schema, 578 parse( 579 """ 580 directive @test on UNION 581 582 extend union BadUnion @test 583 """ 584 ), 585 ) 586 587 assert validate_schema(schema) == [ 588 { 589 "message": "Union type BadUnion must define one or more member types.", 590 "locations": [(6, 13), (4, 17)], 591 } 592 ] 593 594 def rejects_a_union_type_with_duplicated_member_type(): 595 schema = build_schema( 596 """ 597 type Query { 598 test: BadUnion 599 } 600 601 type TypeA { 602 field: String 603 } 604 605 type TypeB { 606 field: String 607 } 608 609 union BadUnion = 610 | TypeA 611 | TypeB 612 | TypeA 613 """ 614 ) 615 616 assert validate_schema(schema) == [ 617 { 618 "message": "Union type BadUnion can only include type TypeA once.", 619 "locations": [(15, 17), (17, 17)], 620 } 621 ] 622 623 schema = extend_schema(schema, parse("extend union BadUnion = TypeB")) 624 625 assert validate_schema(schema) == [ 626 { 627 "message": "Union type BadUnion can only include type TypeA once.", 628 "locations": [(15, 17), (17, 17)], 629 }, 630 { 631 "message": "Union type BadUnion can only include type TypeB once.", 632 "locations": [(16, 17), (1, 25)], 633 }, 634 ] 635 636 def rejects_a_union_type_with_non_object_member_types(): 637 # invalid schema cannot be built with Python 638 with raises(TypeError) as exc_info: 639 build_schema( 640 """ 641 type Query { 642 test: BadUnion 643 } 644 645 type TypeA { 646 field: String 647 } 648 649 type TypeB { 650 field: String 651 } 652 653 union BadUnion = 654 | TypeA 655 | String 656 | TypeB 657 """ 658 ) 659 assert str(exc_info.value) == ( 660 "BadUnion types must be specified" 661 " as a collection of GraphQLObjectType instances." 662 ) 663 # construct invalid schema manually 664 schema = build_schema( 665 """ 666 type Query { 667 test: BadUnion 668 } 669 670 type TypeA { 671 field: String 672 } 673 674 type TypeB { 675 field: String 676 } 677 678 union BadUnion = 679 | TypeA 680 | TypeA 681 | TypeB 682 """ 683 ) 684 with raises(TypeError) as exc_info: 685 extend_schema(schema, parse("extend union BadUnion = Int")) 686 assert str(exc_info.value) == ( 687 "BadUnion types must be specified" 688 " as a collection of GraphQLObjectType instances." 689 ) 690 schema = extend_schema(schema, parse("extend union BadUnion = TypeB")) 691 bad_union: Any = schema.get_type("BadUnion") 692 assert bad_union.types[1].name == "TypeA" 693 bad_union.types[1] = GraphQLString 694 assert bad_union.types[3].name == "TypeB" 695 bad_union.types[3] = GraphQLInt 696 bad_union.ast_node.types[1].name.value = "String" 697 bad_union.extension_ast_nodes[0].types[0].name.value = "Int" 698 assert validate_schema(schema) == [ 699 { 700 "message": "Union type BadUnion can only include Object types," 701 " it cannot include String.", 702 "locations": [(16, 17)], 703 }, 704 { 705 "message": "Union type BadUnion can only include Object types," 706 " it cannot include Int.", 707 "locations": [(1, 25)], 708 }, 709 ] 710 711 bad_union_member_types = [ 712 GraphQLString, 713 GraphQLNonNull(SomeObjectType), 714 GraphQLList(SomeObjectType), 715 SomeInterfaceType, 716 SomeUnionType, 717 SomeEnumType, 718 SomeInputObjectType, 719 ] 720 for member_type in bad_union_member_types: 721 # invalid union type cannot be built with Python 722 bad_union = GraphQLUnionType( 723 "BadUnion", types=[member_type] # type: ignore 724 ) 725 with raises(TypeError) as exc_info: 726 schema_with_field_type(bad_union) 727 assert str(exc_info.value) == ( 728 "BadUnion types must be specified" 729 " as a collection of GraphQLObjectType instances." 730 ) 731 # noinspection PyPropertyAccess 732 bad_union.types = [] 733 bad_schema = schema_with_field_type(bad_union) 734 # noinspection PyPropertyAccess 735 bad_union.types = [member_type] 736 assert validate_schema(bad_schema) == [ 737 { 738 "message": "Union type BadUnion can only include Object types," 739 + f" it cannot include {inspect(member_type)}." 740 } 741 ] 742 743 744def describe_type_system_input_objects_must_have_fields(): 745 def accepts_an_input_object_type_with_fields(): 746 schema = build_schema( 747 """ 748 type Query { 749 field(arg: SomeInputObject): String 750 } 751 752 input SomeInputObject { 753 field: String 754 } 755 """ 756 ) 757 assert validate_schema(schema) == [] 758 759 def rejects_an_input_object_type_with_missing_fields(): 760 schema = build_schema( 761 """ 762 type Query { 763 field(arg: SomeInputObject): String 764 } 765 766 input SomeInputObject 767 """ 768 ) 769 schema = extend_schema( 770 schema, 771 parse( 772 """ 773 directive @test on INPUT_OBJECT 774 775 extend input SomeInputObject @test 776 """ 777 ), 778 ) 779 assert validate_schema(schema) == [ 780 { 781 "message": "Input Object type SomeInputObject" 782 " must define one or more fields.", 783 "locations": [(6, 13), (4, 17)], 784 } 785 ] 786 787 def accepts_an_input_object_with_breakable_circular_reference(): 788 schema = build_schema( 789 """ 790 type Query { 791 field(arg: SomeInputObject): String 792 } 793 794 input SomeInputObject { 795 self: SomeInputObject 796 arrayOfSelf: [SomeInputObject] 797 nonNullArrayOfSelf: [SomeInputObject]! 798 nonNullArrayOfNonNullSelf: [SomeInputObject!]! 799 intermediateSelf: AnotherInputObject 800 } 801 802 input AnotherInputObject { 803 parent: SomeInputObject 804 } 805 """ 806 ) 807 assert validate_schema(schema) == [] 808 809 def rejects_an_input_object_with_non_breakable_circular_reference(): 810 schema = build_schema( 811 """ 812 type Query { 813 field(arg: SomeInputObject): String 814 } 815 816 input SomeInputObject { 817 startLoop: AnotherInputObject! 818 } 819 820 input AnotherInputObject { 821 nextInLoop: YetAnotherInputObject! 822 } 823 824 input YetAnotherInputObject { 825 closeLoop: SomeInputObject! 826 } 827 """ 828 ) 829 assert validate_schema(schema) == [ 830 { 831 "message": "Cannot reference Input Object 'SomeInputObject'" 832 " within itself through a series of non-null fields:" 833 " 'startLoop.nextInLoop.closeLoop'.", 834 "locations": [(7, 15), (11, 15), (15, 15)], 835 } 836 ] 837 838 def rejects_an_input_object_with_multiple_non_breakable_circular_reference(): 839 schema = build_schema( 840 """ 841 type Query { 842 field(arg: SomeInputObject): String 843 } 844 845 input SomeInputObject { 846 startLoop: AnotherInputObject! 847 } 848 849 input AnotherInputObject { 850 closeLoop: SomeInputObject! 851 startSecondLoop: YetAnotherInputObject! 852 } 853 854 input YetAnotherInputObject { 855 closeSecondLoop: AnotherInputObject! 856 nonNullSelf: YetAnotherInputObject! 857 } 858 """ 859 ) 860 assert validate_schema(schema) == [ 861 { 862 "message": "Cannot reference Input Object 'SomeInputObject'" 863 " within itself through a series of non-null fields:" 864 " 'startLoop.closeLoop'.", 865 "locations": [(7, 15), (11, 15)], 866 }, 867 { 868 "message": "Cannot reference Input Object 'AnotherInputObject'" 869 " within itself through a series of non-null fields:" 870 " 'startSecondLoop.closeSecondLoop'.", 871 "locations": [(12, 15), (16, 15)], 872 }, 873 { 874 "message": "Cannot reference Input Object 'YetAnotherInputObject'" 875 " within itself through a series of non-null fields:" 876 " 'nonNullSelf'.", 877 "locations": [(17, 15)], 878 }, 879 ] 880 881 def rejects_an_input_object_type_with_incorrectly_typed_fields(): 882 # invalid schema cannot be built with Python 883 with raises(TypeError) as exc_info: 884 build_schema( 885 """ 886 type Query { 887 field(arg: SomeInputObject): String 888 } 889 890 type SomeObject { 891 field: String 892 } 893 894 union SomeUnion = SomeObject 895 896 input SomeInputObject { 897 badObject: SomeObject 898 badUnion: SomeUnion 899 goodInputObject: SomeInputObject 900 } 901 """ 902 ) 903 assert str(exc_info.value) == ( 904 "SomeInputObject fields cannot be resolved." 905 " Input field type must be a GraphQL input type." 906 ) 907 # construct invalid schema manually 908 schema = build_schema( 909 """ 910 type Query { 911 field(arg: SomeInputObject): String 912 } 913 914 type SomeObject { 915 field: String 916 } 917 918 union SomeUnion = SomeObject 919 920 input SomeInputObject { 921 badObject: SomeInputObject 922 badUnion: SomeInputObject 923 goodInputObject: SomeInputObject 924 } 925 """ 926 ) 927 some_input_obj: Any = schema.get_type("SomeInputObject") 928 some_input_obj.fields["badObject"].type = schema.get_type("SomeObject") 929 some_input_obj.fields["badUnion"].type = schema.get_type("SomeUnion") 930 assert validate_schema(schema) == [ 931 { 932 "message": "The type of SomeInputObject.badObject must be Input Type" 933 " but got: SomeObject.", 934 "locations": [(13, 26)], 935 }, 936 { 937 "message": "The type of SomeInputObject.badUnion must be Input Type" 938 " but got: SomeUnion.", 939 "locations": [(14, 25)], 940 }, 941 ] 942 943 def rejects_an_input_object_type_with_required_arguments_that_is_deprecated(): 944 schema = build_schema( 945 """ 946 type Query { 947 field(arg: SomeInputObject): String 948 } 949 950 input SomeInputObject { 951 badField: String! @deprecated 952 optionalField: String @deprecated 953 anotherOptionalField: String! = "" @deprecated 954 } 955 """ 956 ) 957 assert validate_schema(schema) == [ 958 { 959 "message": "Required input field SomeInputObject.badField" 960 " cannot be deprecated.", 961 "locations": [(7, 33), (7, 25)], 962 } 963 ] 964 965 966def describe_type_system_enum_types_must_be_well_defined(): 967 def rejects_an_enum_type_without_values(): 968 schema = build_schema( 969 """ 970 type Query { 971 field: SomeEnum 972 } 973 974 enum SomeEnum 975 """ 976 ) 977 978 schema = extend_schema( 979 schema, 980 parse( 981 """ 982 directive @test on ENUM 983 984 extend enum SomeEnum @test 985 """ 986 ), 987 ) 988 989 assert validate_schema(schema) == [ 990 { 991 "message": "Enum type SomeEnum must define one or more values.", 992 "locations": [(6, 13), (4, 17)], 993 } 994 ] 995 996 def rejects_an_enum_type_with_incorrectly_named_values(): 997 def schema_with_enum(name: str) -> GraphQLSchema: 998 return schema_with_field_type( 999 GraphQLEnumType("SomeEnum", {name: GraphQLEnumValue(1)}) 1000 ) 1001 1002 schema1 = schema_with_enum("#value") 1003 msg = validate_schema(schema1)[0].message 1004 assert msg == ( 1005 "Names must match /^[_a-zA-Z][_a-zA-Z0-9]*$/ but '#value' does not." 1006 ) 1007 1008 schema2 = schema_with_enum("1value") 1009 msg = validate_schema(schema2)[0].message 1010 assert msg == ( 1011 "Names must match /^[_a-zA-Z][_a-zA-Z0-9]*$/ but '1value' does not." 1012 ) 1013 1014 schema3 = schema_with_enum("KEBAB-CASE") 1015 msg = validate_schema(schema3)[0].message 1016 assert msg == ( 1017 "Names must match /^[_a-zA-Z][_a-zA-Z0-9]*$/ but 'KEBAB-CASE' does not." 1018 ) 1019 1020 schema4 = schema_with_enum("true") 1021 msg = validate_schema(schema4)[0].message 1022 assert msg == "Enum type SomeEnum cannot include value: true." 1023 1024 schema5 = schema_with_enum("false") 1025 msg = validate_schema(schema5)[0].message 1026 assert msg == "Enum type SomeEnum cannot include value: false." 1027 1028 schema6 = schema_with_enum("null") 1029 msg = validate_schema(schema6)[0].message 1030 assert msg == "Enum type SomeEnum cannot include value: null." 1031 1032 1033def describe_type_system_object_fields_must_have_output_types(): 1034 def _schema_with_object_field(type_: GraphQLOutputType) -> GraphQLSchema: 1035 if is_output_type(type_): 1036 field = GraphQLField(type_) 1037 else: 1038 # invalid field cannot be built with Python directly 1039 with raises(TypeError) as exc_info: 1040 GraphQLField(type_) 1041 assert str(exc_info.value) == "Field type must be an output type." 1042 # therefore we need to monkey-patch a valid field 1043 field = GraphQLField(GraphQLString) 1044 field.type = type_ 1045 bad_object_type = GraphQLObjectType("BadObject", {"badField": field}) 1046 return GraphQLSchema( 1047 GraphQLObjectType("Query", {"f": GraphQLField(bad_object_type)}), 1048 types=[SomeObjectType], 1049 ) 1050 1051 @mark.parametrize("type_", output_types, ids=get_name) 1052 def accepts_an_output_type_as_an_object_field_type(type_): 1053 schema = _schema_with_object_field(type_) 1054 assert validate_schema(schema) == [] 1055 1056 def rejects_an_empty_object_field_type(): 1057 # noinspection PyTypeChecker 1058 schema = _schema_with_object_field(None) # type: ignore 1059 assert validate_schema(schema) == [ 1060 { 1061 "message": "The type of BadObject.badField must be Output Type" 1062 " but got: None." 1063 } 1064 ] 1065 1066 @mark.parametrize("type_", not_output_types, ids=get_name) 1067 def rejects_a_non_output_type_as_an_object_field_type(type_): 1068 schema = _schema_with_object_field(type_) 1069 assert validate_schema(schema) == [ 1070 { 1071 "message": "The type of BadObject.badField must be Output Type" 1072 f" but got: {type_}." 1073 } 1074 ] 1075 1076 @mark.parametrize("type_", not_graphql_types, ids=get_name) 1077 def rejects_a_non_type_value_as_an_object_field_type(type_): 1078 schema = _schema_with_object_field(type_) 1079 assert validate_schema(schema) == [ 1080 { 1081 "message": "The type of BadObject.badField must be Output Type" 1082 f" but got: {inspect(type_)}.", 1083 }, 1084 {"message": f"Expected GraphQL named type but got: {inspect(type_)}."}, 1085 ] 1086 1087 def rejects_with_relevant_locations_for_a_non_output_type(): 1088 # invalid schema cannot be built with Python 1089 with raises(TypeError) as exc_info: 1090 build_schema( 1091 """ 1092 type Query { 1093 field: [SomeInputObject] 1094 } 1095 1096 input SomeInputObject { 1097 field: String 1098 } 1099 """ 1100 ) 1101 assert str(exc_info.value) == ( 1102 "Query fields cannot be resolved. Field type must be an output type." 1103 ) 1104 # therefore we need to monkey-patch a valid schema 1105 schema = build_schema( 1106 """ 1107 type Query { 1108 field: [String] 1109 } 1110 1111 input SomeInputObject { 1112 field: String 1113 } 1114 """ 1115 ) 1116 some_input_obj = schema.get_type("SomeInputObject") 1117 schema.query_type.fields["field"].type.of_type = some_input_obj # type: ignore 1118 assert validate_schema(schema) == [ 1119 { 1120 "message": "The type of Query.field must be Output Type" 1121 " but got: [SomeInputObject].", 1122 "locations": [(3, 22)], 1123 } 1124 ] 1125 1126 1127def describe_type_system_objects_can_only_implement_unique_interfaces(): 1128 def rejects_an_object_implementing_a_non_type_values(): 1129 query_type = GraphQLObjectType( 1130 "BadObject", {"f": GraphQLField(GraphQLString)}, interfaces=[] 1131 ) 1132 # noinspection PyTypeChecker 1133 query_type.interfaces.append(None) 1134 schema = GraphQLSchema(query_type) 1135 1136 assert validate_schema(schema) == [ 1137 { 1138 "message": "Type BadObject must only implement Interface types," 1139 " it cannot implement None." 1140 } 1141 ] 1142 1143 def rejects_an_object_implementing_a_non_interface_type(): 1144 # invalid schema cannot be built with Python 1145 with raises(TypeError) as exc_info: 1146 build_schema( 1147 """ 1148 type Query { 1149 test: BadObject 1150 } 1151 1152 input SomeInputObject { 1153 field: String 1154 } 1155 1156 type BadObject implements SomeInputObject { 1157 field: String 1158 } 1159 """ 1160 ) 1161 assert str(exc_info.value) == ( 1162 "BadObject interfaces must be specified" 1163 " as a collection of GraphQLInterfaceType instances." 1164 ) 1165 1166 def rejects_an_object_implementing_the_same_interface_twice(): 1167 schema = build_schema( 1168 """ 1169 type Query { 1170 test: AnotherObject 1171 } 1172 1173 interface AnotherInterface { 1174 field: String 1175 } 1176 1177 type AnotherObject implements AnotherInterface & AnotherInterface { 1178 field: String 1179 } 1180 """ 1181 ) 1182 assert validate_schema(schema) == [ 1183 { 1184 "message": "Type AnotherObject can only implement" 1185 " AnotherInterface once.", 1186 "locations": [(10, 43), (10, 62)], 1187 } 1188 ] 1189 1190 def rejects_an_object_implementing_same_interface_twice_due_to_extension(): 1191 schema = build_schema( 1192 """ 1193 type Query { 1194 test: AnotherObject 1195 } 1196 1197 interface AnotherInterface { 1198 field: String 1199 } 1200 1201 type AnotherObject implements AnotherInterface { 1202 field: String 1203 } 1204 """ 1205 ) 1206 extended_schema = extend_schema( 1207 schema, parse("extend type AnotherObject implements AnotherInterface") 1208 ) 1209 assert validate_schema(extended_schema) == [ 1210 { 1211 "message": "Type AnotherObject can only implement" 1212 " AnotherInterface once.", 1213 "locations": [(10, 43), (1, 38)], 1214 } 1215 ] 1216 1217 1218def describe_type_system_interface_extensions_should_be_valid(): 1219 def rejects_object_implementing_extended_interface_due_to_missing_field(): 1220 schema = build_schema( 1221 """ 1222 type Query { 1223 test: AnotherObject 1224 } 1225 1226 interface AnotherInterface { 1227 field: String 1228 } 1229 1230 type AnotherObject implements AnotherInterface { 1231 field: String 1232 } 1233 """ 1234 ) 1235 extended_schema = extend_schema( 1236 schema, 1237 parse( 1238 """ 1239 extend interface AnotherInterface { 1240 newField: String 1241 } 1242 1243 extend type AnotherObject { 1244 differentNewField: String 1245 } 1246 """ 1247 ), 1248 ) 1249 assert validate_schema(extended_schema) == [ 1250 { 1251 "message": "Interface field AnotherInterface.newField expected" 1252 " but AnotherObject does not provide it.", 1253 "locations": [(3, 19), (10, 13), (6, 17)], 1254 } 1255 ] 1256 1257 def rejects_object_implementing_extended_interface_due_to_missing_args(): 1258 schema = build_schema( 1259 """ 1260 type Query { 1261 test: AnotherObject 1262 } 1263 1264 interface AnotherInterface { 1265 field: String 1266 } 1267 1268 type AnotherObject implements AnotherInterface { 1269 field: String 1270 } 1271 """ 1272 ) 1273 extended_schema = extend_schema( 1274 schema, 1275 parse( 1276 """ 1277 extend interface AnotherInterface { 1278 newField(test: Boolean): String 1279 } 1280 1281 extend type AnotherObject { 1282 newField: String 1283 } 1284 """ 1285 ), 1286 ) 1287 assert validate_schema(extended_schema) == [ 1288 { 1289 "message": "Interface field argument" 1290 " AnotherInterface.newField(test:) expected" 1291 " but AnotherObject.newField does not provide it.", 1292 "locations": [(3, 28), (7, 19)], 1293 } 1294 ] 1295 1296 def rejects_object_implementing_extended_interface_due_to_type_mismatch(): 1297 schema = build_schema( 1298 """ 1299 type Query { 1300 test: AnotherObject 1301 } 1302 1303 interface AnotherInterface { 1304 field: String 1305 } 1306 1307 type AnotherObject implements AnotherInterface { 1308 field: String 1309 } 1310 """ 1311 ) 1312 extended_schema = extend_schema( 1313 schema, 1314 parse( 1315 """ 1316 extend interface AnotherInterface { 1317 newInterfaceField: NewInterface 1318 } 1319 1320 interface NewInterface { 1321 newField: String 1322 } 1323 1324 interface MismatchingInterface { 1325 newField: String 1326 } 1327 1328 extend type AnotherObject { 1329 newInterfaceField: MismatchingInterface 1330 } 1331 1332 # Required to prevent unused interface errors 1333 type DummyObject implements NewInterface & MismatchingInterface { 1334 newField: String 1335 } 1336 """ 1337 ), 1338 ) 1339 assert validate_schema(extended_schema) == [ 1340 { 1341 "message": "Interface field AnotherInterface.newInterfaceField" 1342 " expects type NewInterface" 1343 " but AnotherObject.newInterfaceField" 1344 " is type MismatchingInterface.", 1345 "locations": [(3, 38), (15, 38)], 1346 } 1347 ] 1348 1349 1350def describe_type_system_interface_fields_must_have_output_types(): 1351 def _schema_with_interface_field(type_: GraphQLOutputType) -> GraphQLSchema: 1352 if is_output_type(type_): 1353 field = GraphQLField(type_) 1354 else: 1355 # invalid field cannot be built with Python directly 1356 with raises(TypeError) as exc_info: 1357 GraphQLField(type_) 1358 assert str(exc_info.value) == "Field type must be an output type." 1359 # therefore we need to monkey-patch a valid field 1360 field = GraphQLField(GraphQLString) 1361 field.type = type_ 1362 fields = {"badField": field} 1363 1364 bad_interface_type = GraphQLInterfaceType("BadInterface", fields) 1365 bad_implementing_type = GraphQLObjectType( 1366 "BadImplementing", 1367 fields, 1368 interfaces=[bad_interface_type], 1369 ) 1370 return GraphQLSchema( 1371 GraphQLObjectType("Query", {"f": GraphQLField(bad_interface_type)}), 1372 types=[bad_implementing_type, SomeObjectType], 1373 ) 1374 1375 @mark.parametrize("type_", output_types, ids=get_name) 1376 def accepts_an_output_type_as_an_interface_field_type(type_): 1377 schema = _schema_with_interface_field(type_) 1378 assert validate_schema(schema) == [] 1379 1380 def rejects_an_empty_interface_field_type(): 1381 # noinspection PyTypeChecker 1382 schema = _schema_with_interface_field(None) # type: ignore 1383 assert validate_schema(schema) == [ 1384 { 1385 "message": "The type of BadImplementing.badField must be Output Type" 1386 " but got: None.", 1387 }, 1388 { 1389 "message": "The type of BadInterface.badField must be Output Type" 1390 " but got: None.", 1391 }, 1392 ] 1393 1394 @mark.parametrize("type_", not_output_types, ids=get_name) 1395 def rejects_a_non_output_type_as_an_interface_field_type(type_): 1396 schema = _schema_with_interface_field(type_) 1397 assert validate_schema(schema) == [ 1398 { 1399 "message": "The type of BadImplementing.badField must be Output Type" 1400 f" but got: {type_}.", 1401 }, 1402 { 1403 "message": "The type of BadInterface.badField must be Output Type" 1404 f" but got: {type_}.", 1405 }, 1406 ] 1407 1408 @mark.parametrize("type_", not_graphql_types, ids=get_name) 1409 def rejects_a_non_type_value_as_an_interface_field_type(type_): 1410 schema = _schema_with_interface_field(type_) 1411 assert validate_schema(schema) == [ 1412 { 1413 "message": "The type of BadImplementing.badField must be Output Type" 1414 f" but got: {inspect(type_)}.", 1415 }, 1416 { 1417 "message": "The type of BadInterface.badField must be Output Type" 1418 f" but got: {inspect(type_)}.", 1419 }, 1420 {"message": f"Expected GraphQL named type but got: {inspect(type_)}."}, 1421 ] 1422 1423 def rejects_a_non_output_type_as_an_interface_field_with_locations(): 1424 # invalid schema cannot be built with Python 1425 with raises(TypeError) as exc_info: 1426 build_schema( 1427 """ 1428 type Query { 1429 test: SomeInterface 1430 } 1431 1432 interface SomeInterface { 1433 field: SomeInputObject 1434 } 1435 1436 input SomeInputObject { 1437 foo: String 1438 } 1439 1440 type SomeObject implements SomeInterface { 1441 field: SomeInputObject 1442 } 1443 """ 1444 ) 1445 assert str(exc_info.value) == ( 1446 "SomeInterface fields cannot be resolved." 1447 " Field type must be an output type." 1448 ) 1449 # therefore we need to monkey-patch a valid schema 1450 schema = build_schema( 1451 """ 1452 type Query { 1453 test: SomeInterface 1454 } 1455 1456 interface SomeInterface { 1457 field: String 1458 } 1459 1460 input SomeInputObject { 1461 foo: String 1462 } 1463 1464 type SomeObject implements SomeInterface { 1465 field: String 1466 } 1467 """ 1468 ) 1469 # therefore we need to monkey-patch a valid schema 1470 some_input_obj = schema.get_type("SomeInputObject") 1471 some_interface: Any = schema.get_type("SomeInterface") 1472 some_interface.fields["field"].type = some_input_obj 1473 some_object: Any = schema.get_type("SomeObject") 1474 some_object.fields["field"].type = some_input_obj 1475 assert validate_schema(schema) == [ 1476 { 1477 "message": "The type of SomeInterface.field must be Output Type" 1478 " but got: SomeInputObject.", 1479 "locations": [(7, 22)], 1480 }, 1481 { 1482 "message": "The type of SomeObject.field must be Output Type" 1483 " but got: SomeInputObject.", 1484 "locations": [(15, 22)], 1485 }, 1486 ] 1487 1488 def accepts_an_interface_not_implemented_by_at_least_one_object(): 1489 schema = build_schema( 1490 """ 1491 type Query { 1492 test: SomeInterface 1493 } 1494 1495 interface SomeInterface { 1496 foo: String 1497 } 1498 """ 1499 ) 1500 assert validate_schema(schema) == [] 1501 1502 1503def describe_type_system_arguments_must_have_input_types(): 1504 def _schema_with_arg(type_: GraphQLInputType) -> GraphQLSchema: 1505 if is_input_type(type_): 1506 argument = GraphQLArgument(type_) 1507 else: 1508 # invalid argument cannot be built with Python directly 1509 with raises(TypeError) as exc_info: 1510 GraphQLArgument(type_) 1511 assert str(exc_info.value) == "Argument type must be a GraphQL input type." 1512 # therefore we need to monkey-patch a valid argument 1513 argument = GraphQLArgument(GraphQLString) 1514 argument.type = type_ 1515 args = {"badArg": argument} 1516 bad_object_type = GraphQLObjectType( 1517 "BadObject", 1518 {"badField": GraphQLField(GraphQLString, args)}, 1519 ) 1520 return GraphQLSchema( 1521 GraphQLObjectType("Query", {"f": GraphQLField(bad_object_type)}), 1522 directives=[ 1523 GraphQLDirective( 1524 "BadDirective", 1525 [DirectiveLocation.QUERY], 1526 args, 1527 ) 1528 ], 1529 ) 1530 1531 @mark.parametrize("type_", input_types, ids=get_name) 1532 def accepts_an_input_type_as_a_field_arg_type(type_): 1533 schema = _schema_with_arg(type_) 1534 assert validate_schema(schema) == [] 1535 1536 def rejects_an_empty_field_arg_type(): 1537 # noinspection PyTypeChecker 1538 schema = _schema_with_arg(None) # type: ignore 1539 assert validate_schema(schema) == [ 1540 { 1541 "message": "The type of @BadDirective(badArg:) must be Input Type" 1542 " but got: None." 1543 }, 1544 { 1545 "message": "The type of BadObject.badField(badArg:) must be Input Type" 1546 " but got: None." 1547 }, 1548 ] 1549 1550 @mark.parametrize("type_", not_input_types, ids=get_name) 1551 def rejects_a_non_input_type_as_a_field_arg_type(type_): 1552 schema = _schema_with_arg(type_) 1553 assert validate_schema(schema) == [ 1554 { 1555 "message": "The type of @BadDirective(badArg:) must be Input Type" 1556 f" but got: {type_}." 1557 }, 1558 { 1559 "message": "The type of BadObject.badField(badArg:) must be Input Type" 1560 f" but got: {type_}." 1561 }, 1562 ] 1563 1564 @mark.parametrize("type_", not_graphql_types, ids=get_name) 1565 def rejects_a_non_type_value_as_a_field_arg_type(type_): 1566 schema = _schema_with_arg(type_) 1567 assert validate_schema(schema) == [ 1568 { 1569 "message": "The type of @BadDirective(badArg:) must be Input Type" 1570 f" but got: {inspect(type_)}." 1571 }, 1572 { 1573 "message": "The type of BadObject.badField(badArg:) must be Input Type" 1574 f" but got: {inspect(type_)}." 1575 }, 1576 {"message": f"Expected GraphQL named type but got: {inspect(type_)}."}, 1577 ] 1578 1579 def rejects_a_required_argument_that_is_deprecated(): 1580 schema = build_schema( 1581 """ 1582 directive @BadDirective( 1583 badArg: String! @deprecated 1584 optionalArg: String @deprecated 1585 anotherOptionalArg: String! = "" @deprecated 1586 ) on FIELD 1587 1588 type Query { 1589 test( 1590 badArg: String! @deprecated 1591 optionalArg: String @deprecated 1592 anotherOptionalArg: String! = "" @deprecated 1593 ): String 1594 } 1595 """ 1596 ) 1597 assert validate_schema(schema) == [ 1598 { 1599 "message": "Required argument @BadDirective(badArg:)" 1600 " cannot be deprecated.", 1601 "locations": [(3, 31), (3, 23)], 1602 }, 1603 { 1604 "message": "Required argument Query.test(badArg:)" 1605 " cannot be deprecated.", 1606 "locations": [(10, 33), (10, 25)], 1607 }, 1608 ] 1609 1610 def rejects_a_non_input_type_as_a_field_arg_with_locations(): 1611 # invalid schema cannot be built with Python 1612 with raises(TypeError) as exc_info: 1613 build_schema( 1614 """ 1615 type Query { 1616 test(arg: SomeObject): String 1617 } 1618 1619 type SomeObject { 1620 foo: String 1621 } 1622 """ 1623 ) 1624 assert str(exc_info.value) == ( 1625 "Query fields cannot be resolved." 1626 " Argument type must be a GraphQL input type." 1627 ) 1628 # therefore we need to monkey-patch a valid schema 1629 schema = build_schema( 1630 """ 1631 type Query { 1632 test(arg: String): String 1633 } 1634 1635 type SomeObject { 1636 foo: String 1637 } 1638 """ 1639 ) 1640 some_object = schema.get_type("SomeObject") 1641 schema.query_type.fields["test"].args["arg"].type = some_object # type: ignore 1642 assert validate_schema(schema) == [ 1643 { 1644 "message": "The type of Query.test(arg:) must be Input Type" 1645 " but got: SomeObject.", 1646 "locations": [(3, 25)], 1647 }, 1648 ] 1649 1650 1651def describe_type_system_input_object_fields_must_have_input_types(): 1652 def _schema_with_input_field(type_: GraphQLInputType) -> GraphQLSchema: 1653 if is_input_type(type_): 1654 input_field = GraphQLInputField(type_) 1655 else: 1656 # invalid input field cannot be built with Python directly 1657 with raises(TypeError) as exc_info: 1658 GraphQLInputField(type_) 1659 assert str(exc_info.value) == ( 1660 "Input field type must be a GraphQL input type." 1661 ) 1662 # therefore we need to monkey-patch a valid input field 1663 input_field = GraphQLInputField(GraphQLString) 1664 input_field.type = type_ 1665 bad_input_object_type = GraphQLInputObjectType( 1666 "BadInputObject", {"badField": input_field} 1667 ) 1668 return GraphQLSchema( 1669 GraphQLObjectType( 1670 "Query", 1671 { 1672 "f": GraphQLField( 1673 GraphQLString, 1674 args={"badArg": GraphQLArgument(bad_input_object_type)}, 1675 ) 1676 }, 1677 ) 1678 ) 1679 1680 @mark.parametrize("type_", input_types, ids=get_name) 1681 def accepts_an_input_type_as_an_input_field_type(type_): 1682 schema = _schema_with_input_field(type_) 1683 assert validate_schema(schema) == [] 1684 1685 def rejects_an_empty_input_field_type(): 1686 # noinspection PyTypeChecker 1687 schema = _schema_with_input_field(None) # type: ignore 1688 assert validate_schema(schema) == [ 1689 { 1690 "message": "The type of BadInputObject.badField must be Input Type" 1691 " but got: None." 1692 } 1693 ] 1694 1695 @mark.parametrize("type_", not_input_types, ids=get_name) 1696 def rejects_a_non_input_type_as_an_input_field_type(type_): 1697 schema = _schema_with_input_field(type_) 1698 assert validate_schema(schema) == [ 1699 { 1700 "message": "The type of BadInputObject.badField must be Input Type" 1701 f" but got: {type_}." 1702 } 1703 ] 1704 1705 @mark.parametrize("type_", not_graphql_types, ids=get_name) 1706 def rejects_a_non_type_value_as_an_input_field_type(type_): 1707 schema = _schema_with_input_field(type_) 1708 assert validate_schema(schema) == [ 1709 { 1710 "message": "The type of BadInputObject.badField must be Input Type" 1711 f" but got: {inspect(type_)}." 1712 }, 1713 {"message": f"Expected GraphQL named type but got: {inspect(type_)}."}, 1714 ] 1715 1716 def rejects_with_relevant_locations_for_a_non_input_type(): 1717 # invalid schema cannot be built with Python 1718 with raises(TypeError) as exc_info: 1719 build_schema( 1720 """ 1721 type Query { 1722 test(arg: SomeInputObject): String 1723 } 1724 1725 input SomeInputObject { 1726 foo: SomeObject 1727 } 1728 1729 type SomeObject { 1730 bar: String 1731 } 1732 """ 1733 ) 1734 assert str(exc_info.value) == ( 1735 "SomeInputObject fields cannot be resolved." 1736 " Input field type must be a GraphQL input type." 1737 ) 1738 # therefore we need to monkey-patch a valid schema 1739 schema = build_schema( 1740 """ 1741 type Query { 1742 test(arg: SomeInputObject): String 1743 } 1744 1745 input SomeInputObject { 1746 foo: String 1747 } 1748 1749 type SomeObject { 1750 bar: String 1751 } 1752 """ 1753 ) 1754 some_object = schema.get_type("SomeObject") 1755 some_input_object: Any = schema.get_type("SomeInputObject") 1756 some_input_object.fields["foo"].type = some_object 1757 assert validate_schema(schema) == [ 1758 { 1759 "message": "The type of SomeInputObject.foo must be Input Type" 1760 " but got: SomeObject.", 1761 "locations": [(7, 20)], 1762 } 1763 ] 1764 1765 1766def describe_objects_must_adhere_to_interfaces_they_implement(): 1767 def accepts_an_object_which_implements_an_interface(): 1768 schema = build_schema( 1769 """ 1770 type Query { 1771 test: AnotherObject 1772 } 1773 1774 interface AnotherInterface { 1775 field(input: String): String 1776 } 1777 1778 type AnotherObject implements AnotherInterface { 1779 field(input: String): String 1780 } 1781 """ 1782 ) 1783 assert validate_schema(schema) == [] 1784 1785 def accepts_an_object_which_implements_an_interface_and_with_more_fields(): 1786 schema = build_schema( 1787 """ 1788 type Query { 1789 test: AnotherObject 1790 } 1791 1792 interface AnotherInterface { 1793 field(input: String): String 1794 } 1795 1796 type AnotherObject implements AnotherInterface { 1797 field(input: String): String 1798 anotherField: String 1799 } 1800 """ 1801 ) 1802 assert validate_schema(schema) == [] 1803 1804 def accepts_an_object_which_implements_an_interface_field_with_more_args(): 1805 schema = build_schema( 1806 """ 1807 type Query { 1808 test: AnotherObject 1809 } 1810 1811 interface AnotherInterface { 1812 field(input: String): String 1813 } 1814 1815 type AnotherObject implements AnotherInterface { 1816 field(input: String, anotherInput: String): String 1817 } 1818 """ 1819 ) 1820 assert validate_schema(schema) == [] 1821 1822 def rejects_an_object_missing_an_interface_field(): 1823 schema = build_schema( 1824 """ 1825 type Query { 1826 test: AnotherObject 1827 } 1828 1829 interface AnotherInterface { 1830 field(input: String): String 1831 } 1832 1833 type AnotherObject implements AnotherInterface { 1834 anotherField: String 1835 } 1836 """ 1837 ) 1838 assert validate_schema(schema) == [ 1839 { 1840 "message": "Interface field AnotherInterface.field expected but" 1841 " AnotherObject does not provide it.", 1842 "locations": [(7, 15), (10, 13)], 1843 } 1844 ] 1845 1846 def rejects_an_object_with_an_incorrectly_typed_interface_field(): 1847 schema = build_schema( 1848 """ 1849 type Query { 1850 test: AnotherObject 1851 } 1852 1853 interface AnotherInterface { 1854 field(input: String): String 1855 } 1856 1857 type AnotherObject implements AnotherInterface { 1858 field(input: String): Int 1859 } 1860 """ 1861 ) 1862 assert validate_schema(schema) == [ 1863 { 1864 "message": "Interface field AnotherInterface.field" 1865 " expects type String but" 1866 " AnotherObject.field is type Int.", 1867 "locations": [(7, 37), (11, 37)], 1868 } 1869 ] 1870 1871 def rejects_an_object_with_a_differently_typed_interface_field(): 1872 schema = build_schema( 1873 """ 1874 type Query { 1875 test: AnotherObject 1876 } 1877 1878 type A { foo: String } 1879 type B { foo: String } 1880 1881 interface AnotherInterface { 1882 field: A 1883 } 1884 1885 type AnotherObject implements AnotherInterface { 1886 field: B 1887 } 1888 """ 1889 ) 1890 assert validate_schema(schema) == [ 1891 { 1892 "message": "Interface field AnotherInterface.field" 1893 " expects type A but AnotherObject.field is type B.", 1894 "locations": [(10, 22), (14, 22)], 1895 } 1896 ] 1897 1898 def accepts_an_object_with_a_subtyped_interface_field_interface(): 1899 schema = build_schema( 1900 """ 1901 type Query { 1902 test: AnotherObject 1903 } 1904 1905 interface AnotherInterface { 1906 field: AnotherInterface 1907 } 1908 1909 type AnotherObject implements AnotherInterface { 1910 field: AnotherObject 1911 } 1912 """ 1913 ) 1914 assert validate_schema(schema) == [] 1915 1916 def accepts_an_object_with_a_subtyped_interface_field_union(): 1917 schema = build_schema( 1918 """ 1919 type Query { 1920 test: AnotherObject 1921 } 1922 1923 type SomeObject { 1924 field: String 1925 } 1926 1927 union SomeUnionType = SomeObject 1928 1929 interface AnotherInterface { 1930 field: SomeUnionType 1931 } 1932 1933 type AnotherObject implements AnotherInterface { 1934 field: SomeObject 1935 } 1936 """ 1937 ) 1938 assert validate_schema(schema) == [] 1939 1940 def rejects_an_object_missing_an_interface_argument(): 1941 schema = build_schema( 1942 """ 1943 type Query { 1944 test: AnotherObject 1945 } 1946 1947 interface AnotherInterface { 1948 field(input: String): String 1949 } 1950 1951 type AnotherObject implements AnotherInterface { 1952 field: String 1953 } 1954 """ 1955 ) 1956 assert validate_schema(schema) == [ 1957 { 1958 "message": "Interface field argument" 1959 " AnotherInterface.field(input:) expected" 1960 " but AnotherObject.field does not provide it.", 1961 "locations": [(7, 21), (11, 15)], 1962 } 1963 ] 1964 1965 def rejects_an_object_with_an_incorrectly_typed_interface_argument(): 1966 schema = build_schema( 1967 """ 1968 type Query { 1969 test: AnotherObject 1970 } 1971 1972 interface AnotherInterface { 1973 field(input: String): String 1974 } 1975 1976 type AnotherObject implements AnotherInterface { 1977 field(input: Int): String 1978 } 1979 """ 1980 ) 1981 assert validate_schema(schema) == [ 1982 { 1983 "message": "Interface field argument" 1984 " AnotherInterface.field(input:) expects type String" 1985 " but AnotherObject.field(input:) is type Int.", 1986 "locations": [(7, 28), (11, 28)], 1987 } 1988 ] 1989 1990 def rejects_an_object_with_an_incorrectly_typed_field_and_argument(): 1991 schema = build_schema( 1992 """ 1993 type Query { 1994 test: AnotherObject 1995 } 1996 1997 interface AnotherInterface { 1998 field(input: String): String 1999 } 2000 2001 type AnotherObject implements AnotherInterface { 2002 field(input: Int): Int 2003 } 2004 """ 2005 ) 2006 assert validate_schema(schema) == [ 2007 { 2008 "message": "Interface field AnotherInterface.field expects" 2009 " type String but AnotherObject.field is type Int.", 2010 "locations": [(7, 37), (11, 34)], 2011 }, 2012 { 2013 "message": "Interface field argument" 2014 " AnotherInterface.field(input:) expects type String" 2015 " but AnotherObject.field(input:) is type Int.", 2016 "locations": [(7, 28), (11, 28)], 2017 }, 2018 ] 2019 2020 def rejects_object_implementing_an_interface_field_with_additional_args(): 2021 schema = build_schema( 2022 """ 2023 type Query { 2024 test: AnotherObject 2025 } 2026 2027 interface AnotherInterface { 2028 field(baseArg: String): String 2029 } 2030 2031 type AnotherObject implements AnotherInterface { 2032 field( 2033 baseArg: String, 2034 requiredArg: String! 2035 optionalArg1: String, 2036 optionalArg2: String = "", 2037 ): String 2038 } 2039 """ 2040 ) 2041 assert validate_schema(schema) == [ 2042 { 2043 "message": "Object field AnotherObject.field includes required" 2044 " argument requiredArg that is missing from the" 2045 " Interface field AnotherInterface.field.", 2046 "locations": [(13, 17), (7, 15)], 2047 } 2048 ] 2049 2050 def accepts_an_object_with_an_equivalently_wrapped_interface_field_type(): 2051 schema = build_schema( 2052 """ 2053 type Query { 2054 test: AnotherObject 2055 } 2056 2057 interface AnotherInterface { 2058 field: [String]! 2059 } 2060 2061 type AnotherObject implements AnotherInterface { 2062 field: [String]! 2063 } 2064 """ 2065 ) 2066 assert validate_schema(schema) == [] 2067 2068 def rejects_an_object_with_a_non_list_interface_field_list_type(): 2069 schema = build_schema( 2070 """ 2071 type Query { 2072 test: AnotherObject 2073 } 2074 2075 interface AnotherInterface { 2076 field: [String] 2077 } 2078 2079 type AnotherObject implements AnotherInterface { 2080 field: String 2081 } 2082 """ 2083 ) 2084 assert validate_schema(schema) == [ 2085 { 2086 "message": "Interface field AnotherInterface.field expects type" 2087 " [String] but AnotherObject.field is type String.", 2088 "locations": [(7, 22), (11, 22)], 2089 } 2090 ] 2091 2092 def rejects_an_object_with_a_list_interface_field_non_list_type(): 2093 schema = build_schema( 2094 """ 2095 type Query { 2096 test: AnotherObject 2097 } 2098 2099 interface AnotherInterface { 2100 field: String 2101 } 2102 2103 type AnotherObject implements AnotherInterface { 2104 field: [String] 2105 } 2106 """ 2107 ) 2108 assert validate_schema(schema) == [ 2109 { 2110 "message": "Interface field AnotherInterface.field expects type" 2111 " String but AnotherObject.field is type [String].", 2112 "locations": [(7, 22), (11, 22)], 2113 } 2114 ] 2115 2116 def accepts_an_object_with_a_subset_non_null_interface_field_type(): 2117 schema = build_schema( 2118 """ 2119 type Query { 2120 test: AnotherObject 2121 } 2122 2123 interface AnotherInterface { 2124 field: String 2125 } 2126 2127 type AnotherObject implements AnotherInterface { 2128 field: String! 2129 } 2130 """ 2131 ) 2132 assert validate_schema(schema) == [] 2133 2134 def rejects_an_object_with_a_superset_nullable_interface_field_type(): 2135 schema = build_schema( 2136 """ 2137 type Query { 2138 test: AnotherObject 2139 } 2140 2141 interface AnotherInterface { 2142 field: String! 2143 } 2144 2145 type AnotherObject implements AnotherInterface { 2146 field: String 2147 } 2148 """ 2149 ) 2150 assert validate_schema(schema) == [ 2151 { 2152 "message": "Interface field AnotherInterface.field expects type" 2153 " String! but AnotherObject.field is type String.", 2154 "locations": [(7, 22), (11, 22)], 2155 } 2156 ] 2157 2158 def rejects_an_object_missing_a_transitive_interface(): 2159 schema = build_schema( 2160 """ 2161 type Query { 2162 test: AnotherObject 2163 } 2164 2165 interface SuperInterface { 2166 field: String! 2167 } 2168 2169 interface AnotherInterface implements SuperInterface { 2170 field: String! 2171 } 2172 2173 type AnotherObject implements AnotherInterface { 2174 field: String! 2175 } 2176 """ 2177 ) 2178 assert validate_schema(schema) == [ 2179 { 2180 "message": "Type AnotherObject must implement SuperInterface" 2181 " because it is implemented by AnotherInterface.", 2182 "locations": [(10, 51), (14, 43)], 2183 } 2184 ] 2185 2186 2187def describe_interfaces_must_adhere_to_interface_they_implement(): 2188 def accepts_an_interface_which_implements_an_interface(): 2189 schema = build_schema( 2190 """ 2191 type Query { 2192 test: ChildInterface 2193 } 2194 2195 interface ParentInterface { 2196 field(input: String): String 2197 } 2198 2199 interface ChildInterface implements ParentInterface { 2200 field(input: String): String 2201 } 2202 """ 2203 ) 2204 assert validate_schema(schema) == [] 2205 2206 def accepts_an_interface_which_implements_an_interface_along_with_more_fields(): 2207 schema = build_schema( 2208 """ 2209 type Query { 2210 test: ChildInterface 2211 } 2212 2213 interface ParentInterface { 2214 field(input: String): String 2215 } 2216 2217 interface ChildInterface implements ParentInterface { 2218 field(input: String): String 2219 anotherField: String 2220 } 2221 """ 2222 ) 2223 assert validate_schema(schema) == [] 2224 2225 def accepts_an_interface_which_implements_an_interface_with_additional_args(): 2226 schema = build_schema( 2227 """ 2228 type Query { 2229 test: ChildInterface 2230 } 2231 2232 interface ParentInterface { 2233 field(input: String): String 2234 } 2235 2236 interface ChildInterface implements ParentInterface { 2237 field(input: String, anotherInput: String): String 2238 } 2239 """ 2240 ) 2241 assert validate_schema(schema) == [] 2242 2243 def rejects_an_interface_missing_an_interface_field(): 2244 schema = build_schema( 2245 """ 2246 type Query { 2247 test: ChildInterface 2248 } 2249 2250 interface ParentInterface { 2251 field(input: String): String 2252 } 2253 2254 interface ChildInterface implements ParentInterface { 2255 anotherField: String 2256 } 2257 """ 2258 ) 2259 assert validate_schema(schema) == [ 2260 { 2261 "message": "Interface field ParentInterface.field expected" 2262 " but ChildInterface does not provide it.", 2263 "locations": [(7, 15), (10, 13)], 2264 } 2265 ] 2266 2267 def rejects_an_interface_with_an_incorrectly_typed_interface_field(): 2268 schema = build_schema( 2269 """ 2270 type Query { 2271 test: ChildInterface 2272 } 2273 2274 interface ParentInterface { 2275 field(input: String): String 2276 } 2277 2278 interface ChildInterface implements ParentInterface { 2279 field(input: String): Int 2280 } 2281 """ 2282 ) 2283 assert validate_schema(schema) == [ 2284 { 2285 "message": "Interface field ParentInterface.field expects type String" 2286 " but ChildInterface.field is type Int.", 2287 "locations": [(7, 37), (11, 37)], 2288 } 2289 ] 2290 2291 def rejects_an_interface_with_a_differently_typed_interface_field(): 2292 schema = build_schema( 2293 """ 2294 type Query { 2295 test: ChildInterface 2296 } 2297 2298 type A { foo: String } 2299 type B { foo: String } 2300 2301 interface ParentInterface { 2302 field: A 2303 } 2304 2305 interface ChildInterface implements ParentInterface { 2306 field: B 2307 } 2308 """ 2309 ) 2310 assert validate_schema(schema) == [ 2311 { 2312 "message": "Interface field ParentInterface.field expects type A" 2313 " but ChildInterface.field is type B.", 2314 "locations": [(10, 22), (14, 22)], 2315 } 2316 ] 2317 2318 def accepts_an_interface_with_a_subtyped_interface_field_interface(): 2319 schema = build_schema( 2320 """ 2321 type Query { 2322 test: ChildInterface 2323 } 2324 2325 interface ParentInterface { 2326 field: ParentInterface 2327 } 2328 2329 interface ChildInterface implements ParentInterface { 2330 field: ChildInterface 2331 } 2332 """ 2333 ) 2334 assert validate_schema(schema) == [] 2335 2336 def accepts_an_interface_with_a_subtyped_interface_field_union(): 2337 schema = build_schema( 2338 """ 2339 type Query { 2340 test: ChildInterface 2341 } 2342 2343 type SomeObject { 2344 field: String 2345 } 2346 2347 union SomeUnionType = SomeObject 2348 2349 interface ParentInterface { 2350 field: SomeUnionType 2351 } 2352 2353 interface ChildInterface implements ParentInterface { 2354 field: SomeObject 2355 } 2356 """ 2357 ) 2358 assert validate_schema(schema) == [] 2359 2360 def rejects_an_interface_implementing_a_non_interface_type(): 2361 # invalid schema cannot be built with Python 2362 with raises(TypeError) as exc_info: 2363 build_schema( 2364 """ 2365 type Query { 2366 field: String 2367 } 2368 2369 input SomeInputObject { 2370 field: String 2371 } 2372 2373 interface BadInterface implements SomeInputObject { 2374 field: String 2375 } 2376 """ 2377 ) 2378 assert str(exc_info.value) == ( 2379 "BadInterface interfaces must be specified as a collection" 2380 " of GraphQLInterfaceType instances." 2381 ) 2382 # therefore we construct the invalid schema manually 2383 some_input_obj = GraphQLInputObjectType( 2384 "SomeInputObject", {"field": GraphQLInputField(GraphQLString)} 2385 ) 2386 bad_interface = GraphQLInterfaceType( 2387 "BadInterface", {"field": GraphQLField(GraphQLString)} 2388 ) 2389 # noinspection PyTypeChecker 2390 bad_interface.interfaces.append(some_input_obj) 2391 schema = GraphQLSchema( 2392 GraphQLObjectType("Query", {"field": GraphQLField(GraphQLString)}), 2393 types=[bad_interface], 2394 ) 2395 assert validate_schema(schema) == [ 2396 { 2397 "message": "Type BadInterface must only implement Interface types," 2398 " it cannot implement SomeInputObject.", 2399 } 2400 ] 2401 2402 def rejects_an_interface_missing_an_interface_argument(): 2403 schema = build_schema( 2404 """ 2405 type Query { 2406 test: ChildInterface 2407 } 2408 2409 interface ParentInterface { 2410 field(input: String): String 2411 } 2412 2413 interface ChildInterface implements ParentInterface { 2414 field: String 2415 } 2416 """ 2417 ) 2418 assert validate_schema(schema) == [ 2419 { 2420 "message": "Interface field argument ParentInterface.field(input:)" 2421 " expected but ChildInterface.field does not provide it.", 2422 "locations": [(7, 21), (11, 15)], 2423 } 2424 ] 2425 2426 def rejects_an_interface_with_an_incorrectly_typed_interface_argument(): 2427 schema = build_schema( 2428 """ 2429 type Query { 2430 test: ChildInterface 2431 } 2432 2433 interface ParentInterface { 2434 field(input: String): String 2435 } 2436 2437 interface ChildInterface implements ParentInterface { 2438 field(input: Int): String 2439 } 2440 """ 2441 ) 2442 assert validate_schema(schema) == [ 2443 { 2444 "message": "Interface field argument ParentInterface.field(input:)" 2445 " expects type String but ChildInterface.field(input:) is type Int.", 2446 "locations": [(7, 28), (11, 28)], 2447 } 2448 ] 2449 2450 def rejects_an_interface_with_both_an_incorrectly_typed_field_and_argument(): 2451 schema = build_schema( 2452 """ 2453 type Query { 2454 test: ChildInterface 2455 } 2456 2457 interface ParentInterface { 2458 field(input: String): String 2459 } 2460 2461 interface ChildInterface implements ParentInterface { 2462 field(input: Int): Int 2463 } 2464 """ 2465 ) 2466 assert validate_schema(schema) == [ 2467 { 2468 "message": "Interface field ParentInterface.field expects type String" 2469 " but ChildInterface.field is type Int.", 2470 "locations": [(7, 37), (11, 34)], 2471 }, 2472 { 2473 "message": "Interface field argument ParentInterface.field(input:)" 2474 " expects type String but ChildInterface.field(input:) is type Int.", 2475 "locations": [(7, 28), (11, 28)], 2476 }, 2477 ] 2478 2479 def rejects_an_interface_implementing_an_interface_field_with_additional_args(): 2480 schema = build_schema( 2481 """ 2482 type Query { 2483 test: ChildInterface 2484 } 2485 2486 interface ParentInterface { 2487 field(baseArg: String): String 2488 } 2489 2490 interface ChildInterface implements ParentInterface { 2491 field( 2492 baseArg: String, 2493 requiredArg: String! 2494 optionalArg1: String, 2495 optionalArg2: String = "", 2496 ): String 2497 } 2498 """ 2499 ) 2500 assert validate_schema(schema) == [ 2501 { 2502 "message": "Object field ChildInterface.field includes" 2503 " required argument requiredArg that is missing" 2504 " from the Interface field ParentInterface.field.", 2505 "locations": [(13, 17), (7, 15)], 2506 } 2507 ] 2508 2509 def accepts_an_interface_with_an_equivalently_wrapped_interface_field_type(): 2510 schema = build_schema( 2511 """ 2512 type Query { 2513 test: ChildInterface 2514 } 2515 2516 interface ParentInterface { 2517 field: [String]! 2518 } 2519 2520 interface ChildInterface implements ParentInterface { 2521 field: [String]! 2522 } 2523 """ 2524 ) 2525 assert validate_schema(schema) == [] 2526 2527 def rejects_an_interface_with_a_non_list_interface_field_list_type(): 2528 schema = build_schema( 2529 """ 2530 type Query { 2531 test: ChildInterface 2532 } 2533 2534 interface ParentInterface { 2535 field: [String] 2536 } 2537 2538 interface ChildInterface implements ParentInterface { 2539 field: String 2540 } 2541 """ 2542 ) 2543 assert validate_schema(schema) == [ 2544 { 2545 "message": "Interface field ParentInterface.field" 2546 " expects type [String] but ChildInterface.field is type String.", 2547 "locations": [(7, 22), (11, 22)], 2548 } 2549 ] 2550 2551 def rejects_an_interface_with_a_list_interface_field_non_list_type(): 2552 schema = build_schema( 2553 """ 2554 type Query { 2555 test: ChildInterface 2556 } 2557 2558 interface ParentInterface { 2559 field: String 2560 } 2561 2562 interface ChildInterface implements ParentInterface { 2563 field: [String] 2564 } 2565 """ 2566 ) 2567 assert validate_schema(schema) == [ 2568 { 2569 "message": "Interface field ParentInterface.field expects type String" 2570 " but ChildInterface.field is type [String].", 2571 "locations": [(7, 22), (11, 22)], 2572 } 2573 ] 2574 2575 def accepts_an_interface_with_a_subset_non_null_interface_field_type(): 2576 schema = build_schema( 2577 """ 2578 type Query { 2579 test: ChildInterface 2580 } 2581 2582 interface ParentInterface { 2583 field: String 2584 } 2585 2586 interface ChildInterface implements ParentInterface { 2587 field: String! 2588 } 2589 """ 2590 ) 2591 assert validate_schema(schema) == [] 2592 2593 def rejects_an_interface_with_a_superset_nullable_interface_field_type(): 2594 schema = build_schema( 2595 """ 2596 type Query { 2597 test: ChildInterface 2598 } 2599 2600 interface ParentInterface { 2601 field: String! 2602 } 2603 2604 interface ChildInterface implements ParentInterface { 2605 field: String 2606 } 2607 """ 2608 ) 2609 assert validate_schema(schema) == [ 2610 { 2611 "message": "Interface field ParentInterface.field expects type String!" 2612 " but ChildInterface.field is type String.", 2613 "locations": [(7, 22), (11, 22)], 2614 } 2615 ] 2616 2617 def rejects_an_object_missing_a_transitive_interface(): 2618 schema = build_schema( 2619 """ 2620 type Query { 2621 test: ChildInterface 2622 } 2623 2624 interface SuperInterface { 2625 field: String! 2626 } 2627 2628 interface ParentInterface implements SuperInterface { 2629 field: String! 2630 } 2631 2632 interface ChildInterface implements ParentInterface { 2633 field: String! 2634 } 2635 """ 2636 ) 2637 assert validate_schema(schema) == [ 2638 { 2639 "message": "Type ChildInterface must implement SuperInterface" 2640 " because it is implemented by ParentInterface.", 2641 "locations": [(10, 50), (14, 49)], 2642 } 2643 ] 2644 2645 def rejects_a_self_reference_interface(): 2646 schema = build_schema( 2647 """ 2648 type Query { 2649 test: FooInterface 2650 } 2651 2652 interface FooInterface implements FooInterface { 2653 field: String 2654 } 2655 """ 2656 ) 2657 assert validate_schema(schema) == [ 2658 { 2659 "message": "Type FooInterface cannot implement itself" 2660 " because it would create a circular reference.", 2661 "locations": [(6, 47)], 2662 } 2663 ] 2664 2665 def rejects_a_circular_interface_implementation(): 2666 schema = build_schema( 2667 """ 2668 type Query { 2669 test: FooInterface 2670 } 2671 2672 interface FooInterface implements BarInterface { 2673 field: String 2674 } 2675 2676 interface BarInterface implements FooInterface { 2677 field: String 2678 } 2679 """ 2680 ) 2681 assert validate_schema(schema) == [ 2682 { 2683 "message": "Type FooInterface cannot implement BarInterface" 2684 " because it would create a circular reference.", 2685 "locations": [(10, 47), (6, 47)], 2686 }, 2687 { 2688 "message": "Type BarInterface cannot implement FooInterface" 2689 " because it would create a circular reference.", 2690 "locations": [(6, 47), (10, 47)], 2691 }, 2692 ] 2693 2694 2695def describe_assert_valid_schema(): 2696 def do_not_throw_on_valid_schemas(): 2697 schema = build_schema( 2698 ( 2699 """ 2700 type Query { 2701 foo: String 2702 } 2703 """ 2704 ) 2705 ) 2706 assert_valid_schema(schema) 2707 2708 def include_multiple_errors_into_a_description(): 2709 schema = build_schema("type SomeType") 2710 with raises(TypeError) as exc_info: 2711 assert_valid_schema(schema) 2712 assert ( 2713 str(exc_info.value) 2714 == dedent( 2715 """ 2716 Query root type must be provided. 2717 2718 Type SomeType must define one or more fields. 2719 """ 2720 ).rstrip() 2721 ) 2722