1from typing import Any 2 3from .location import SourceLocation 4 5__all__ = ["Source", "is_source"] 6 7 8class Source: 9 """A representation of source input to GraphQL.""" 10 11 # allow custom attributes and weak references (not used internally) 12 __slots__ = "__weakref__", "__dict__", "body", "name", "location_offset" 13 14 def __init__( 15 self, 16 body: str, 17 name: str = "GraphQL request", 18 location_offset: SourceLocation = SourceLocation(1, 1), 19 ) -> None: 20 """Initialize source input. 21 22 The ``name`` and ``location_offset`` parameters are optional, but they are 23 useful for clients who store GraphQL documents in source files. For example, 24 if the GraphQL input starts at line 40 in a file named ``Foo.graphql``, it might 25 be useful for ``name`` to be ``"Foo.graphql"`` and location to be ``(40, 0)``. 26 27 The ``line`` and ``column`` attributes in ``location_offset`` are 1-indexed. 28 """ 29 self.body = body 30 self.name = name 31 if not isinstance(location_offset, SourceLocation): 32 location_offset = SourceLocation._make(location_offset) 33 if location_offset.line <= 0: 34 raise ValueError( 35 "line in location_offset is 1-indexed and must be positive." 36 ) 37 if location_offset.column <= 0: 38 raise ValueError( 39 "column in location_offset is 1-indexed and must be positive." 40 ) 41 self.location_offset = location_offset 42 43 def get_location(self, position: int) -> SourceLocation: 44 lines = self.body[:position].splitlines() 45 if lines: 46 line = len(lines) 47 column = len(lines[-1]) + 1 48 else: 49 line = 1 50 column = 1 51 return SourceLocation(line, column) 52 53 def __repr__(self) -> str: 54 return f"<{self.__class__.__name__} name={self.name!r}>" 55 56 def __eq__(self, other: Any) -> bool: 57 return (isinstance(other, Source) and other.body == self.body) or ( 58 isinstance(other, str) and other == self.body 59 ) 60 61 def __ne__(self, other: Any) -> bool: 62 return not self == other 63 64 65def is_source(source: Any) -> bool: 66 """Test if the given value is a Source object. 67 68 For internal use only. 69 """ 70 return isinstance(source, Source) 71