예제 #1
0
def test_none_json_value_input_in_dsl_argument():

    ds = DSLSchema(schema)

    with pytest.raises(GraphQLError) as exc_info:
        ds.Mutation.addPlayer(player=None)

    assert "Received Null value for a Non-Null type JSON." in str(
        exc_info.value)
예제 #2
0
 def mutation_domain(self, domain: str, lang: str, phrases: list):
     ds = DSLSchema(self.client.schema)
     mutation = dsl_gql(
         DSLMutation(
             ds.Mutation.register_domain.args(
                 domain=domain, lang=lang,
                 phrases=phrases).select(ds.MatcherResponse.success,
                                         ds.MatcherResponse.errors,
                                         ds.MatcherResponse.domain,
                                         ds.MatcherResponse.errors,
                                         ds.MatcherResponse.lang)))
     return mutation
예제 #3
0
    def __init__(self, **kwargs):
        schemes = {"http": "ws", "https": "wss"}
        self.headers: Dict[str, str] = {}
        endpoint = os.getenv(URL_VAR, "http://localhost:8080/api")
        url = kwargs.pop("url", endpoint)
        split_url = urlsplit(url)
        ws_url = urlunsplit(
            split_url._replace(scheme=schemes[split_url.scheme]))

        transport = RequestsHTTPTransport(url=url, headers=self.headers)
        client = Client(transport=transport, schema=schema)
        self.ds = DSLSchema(client)

        ws_transport = WebsocketsTransport(url=ws_url)
        self.ws_client = Client(transport=ws_transport, schema=schema)

        self.token = kwargs.pop("token", os.getenv(TOKEN_VAR))
        username = kwargs.pop("username", os.getenv(USERNAME_VAR))
        password = kwargs.pop("password", os.getenv(PASSWORD_VAR))
        if self.token is not None:
            self.headers = {"Authorization": f"Bearer {self.token}"}
        elif all((username, password)):
            self.login(username, password)

        # Mapping for nested fields
        self.field_map = {
            "Job": {
                "outputMetadata": self.ds.Metadata,
                "parameters": self.ds.Parameter,
                "user": self.ds.User,
                "worker": self.ds.Worker,
            },
            "Service": {
                "parameters": self.ds.ServiceParameter,
                "fileType": self.ds.FileType,
            },
        }
예제 #4
0
    async def refresh_token(self) -> str:
        """Refresh an expired access token

        Returns:
            str: New access token
        """
        q = self.ds.Mutation.refresh.args(token=self.refresh)
        async with Client(transport=self.transport, schema=schema) as sess:
            ds = DSLSchema(sess)
            resp = await ds.mutate(q)
        if resp["refresh"] is None:
            raise ValueError("Token refresh failed")
        token = resp["refresh"]["token"]
        self.token = token
        self.headers["Authorization"] = f"Bearer {self.token}"
        return token
예제 #5
0
async def main():

    transport = AIOHTTPTransport(
        url="https://countries.trevorblades.com/graphql")

    client = Client(transport=transport, fetch_schema_from_transport=True)

    # Using `async with` on the client will start a connection on the transport
    # and provide a `session` variable to execute queries on this connection.
    # Because we requested to fetch the schema from the transport,
    # GQL will fetch the schema just after the establishment of the first session
    async with client as session:

        # Instanciate the root of the DSL Schema as ds
        ds = DSLSchema(client.schema)

        # Create the query using dynamically generated attributes from ds
        query = dsl_gql(
            DSLQuery(
                ds.Query.continents(filter={
                    "code": {
                        "eq": "EU"
                    }
                }).select(ds.Continent.code, ds.Continent.name)))

        result = await session.execute(query)
        print(result)

        # This can also be written as:

        # I want to query the continents
        query_continents = ds.Query.continents

        # I want to get only the continents with code equal to "EU"
        query_continents(filter={"code": {"eq": "EU"}})

        # I want this query to return the code and name fields
        query_continents.select(ds.Continent.code)
        query_continents.select(ds.Continent.name)

        # I generate a document from my query to be able to execute it
        query = dsl_gql(DSLQuery(query_continents))

        # Execute the query
        result = await session.execute(query)
        print(result)
예제 #6
0
def test_json_value_input_with_none_list_in_dsl_argument():

    ds = DSLSchema(schema)

    new_player = {
        "name": "Bob",
        "level": 9001,
        "is_connected": True,
        "score": 666.66,
        "friends": None,
    }

    query = ds.Mutation.addPlayer(player=new_player)

    print(str(query))

    assert (str(query) == """addPlayer(
  player: {name: "Bob", level: 9001, is_connected: true, score: 666.66, friends: null}
)""")
예제 #7
0
    async def submit(self) -> str:
        """Submit a job request to the service endpoint

        Returns:
            str: The unique job identifier
        """
        q = self.client.ds.Mutation.submit_job.args(
            request=self.req_args).select(
                self.client.ds.JobRequestResponse.job.select(
                    self.client.ds.Job.job_id, self.client.ds.Job.status))
        async with Client(transport=self.client.transport,
                          schema=self.client.schema) as sess:
            ds = DSLSchema(sess)
            resp = await ds.mutate(q)
        if "errors" in resp:
            raise ValueError("Error submitting job request: " + resp["errors"])
        self.job_id = resp["submitJob"]["job"]["jobId"]
        self.status = resp["submitJob"]["job"]["status"]
        return self.job_id
예제 #8
0
    async def login(
            self,
            username: Optional[str] = None,
            password: Optional[str] = None) -> Tuple[str, Optional[str]]:
        """Retrieve a web token from MOTHR

        Args:
            username (str, optional): Username used to login, the library will look
                for ``MOTHR_USERNAME`` in the environment as a fallback.
            password (str, optional): Password used to login, the library will look
                for ``MOTHR_PASSWORD`` in the environment as a fallback.

        Returns:
            str: An access token to pass with future requests
            str: A refresh token for receiving a new access token
                after the current token expires

        Raises:
            ValueError: If a username or password are not provided and are not found
                in the current environment
        """
        username = username if username is not None else os.getenv(
            "MOTHR_USERNAME")
        password = password if password is not None else os.getenv(
            "MOTHR_PASSWORD")
        if username is None:
            raise ValueError("Username not provided")
        if password is None:
            raise ValueError("Password not provided")

        credentials = {"username": username, "password": password}
        q = self.ds.Mutation.login.args(**credentials).select(
            self.ds.LoginResponse.token, self.ds.LoginResponse.refresh)
        async with Client(transport=self.transport, schema=schema) as sess:
            ds = DSLSchema(sess)
            resp = await ds.mutate(q)
        tokens = resp["login"]
        if tokens is None:
            raise ValueError("Login failed")
        self.token = tokens["token"]
        self.refresh = tokens["refresh"]
        self.headers["Authorization"] = f"Bearer {self.token}"
        return self.token, self.refresh
예제 #9
0
def test_json_value_input_in_dsl_argument():

    ds = DSLSchema(schema)

    new_player = {
        "name": "Tim",
        "level": 0,
        "is_connected": False,
        "score": 5,
        "friends": ["Lea"],
    }

    query = ds.Mutation.addPlayer(player=new_player)

    print(str(query))

    assert (str(query) == """addPlayer(
  player: {name: "Tim", level: 0, is_connected: false, score: 5, friends: ["Lea"]}
)""")
예제 #10
0
    async def services(self, fields: Optional[List[str]] = None) -> List[Dict]:
        """Retrieve all services registered with MOTHR

        Args:
            fields (list<str>, optional): Fields to return in the query response,
                default is `name` and `version`

        Returns:
            list<dict>: All services registered with MOTHR
        """
        fields = fields if fields is not None else ["name", "version"]
        fields = [
            self.resolve_field(self.ds.Service, field) for field in fields
        ]
        q = self.ds.Query.services.select(*fields)
        async with Client(transport=self.transport, schema=schema) as sess:
            ds = DSLSchema(sess)
            resp = await ds.query(q)
        return resp["services"]
예제 #11
0
 def mutation_skill(self, domain: str, call_back: str, lang: str,
                    matchers: list):
     ''' Args:
         ----
         call_back: the callback method registered as <domain>/<method>
         lang: The language iso code
         matchers: A list of Matcher rules on the form [{'ORTH': "vær", 'OP': "?"},
                                                        {'ORTH': "været", 'OP': "?"}]
     '''
     ds = DSLSchema(self.client.schema)
     mutation = dsl_gql(
         DSLMutation(
             ds.Mutation.register_skill.args(
                 domain=domain,
                 call_back=call_back,
                 lang=lang,
                 matcher=matchers).select(ds.MatcherResponse.success,
                                          ds.MatcherResponse.errors,
                                          ds.MatcherResponse.domain,
                                          ds.MatcherResponse.errors,
                                          ds.MatcherResponse.lang,
                                          ds.MatcherResponse.call_back)))
     return mutation
예제 #12
0
def ds():
    return DSLSchema(NestedInputSchema)
예제 #13
0
def ds():
    client = Client(schema=NestedInputSchema)
    ds = DSLSchema(client)
    return ds
예제 #14
0
def ds():
    return DSLSchema(StarWarsSchema)
예제 #15
0
def test_DSLSchema_requires_a_schema(client):
    with pytest.raises(TypeError,
                       match="DSLSchema needs a schema as parameter"):
        DSLSchema(client)
def get_introspection_query_ast(
    descriptions: bool = True,
    specified_by_url: bool = False,
    directive_is_repeatable: bool = False,
    schema_description: bool = False,
    type_recursion_level: int = 7,
) -> DocumentNode:
    """Get a query for introspection as a document using the DSL module.

    Equivalent to the get_introspection_query function from graphql-core
    but using the DSL module and allowing to select the recursion level.

    Optionally, you can exclude descriptions, include specification URLs,
    include repeatability of directives, and specify whether to include
    the schema description as well.
    """

    ds = DSLSchema(GraphQLSchema())

    fragment_FullType = DSLFragment("FullType").on(ds.__Type)
    fragment_InputValue = DSLFragment("InputValue").on(ds.__InputValue)
    fragment_TypeRef = DSLFragment("TypeRef").on(ds.__Type)

    schema = DSLMetaField("__schema")

    if descriptions and schema_description:
        schema.select(ds.__Schema.description)

    schema.select(
        ds.__Schema.queryType.select(ds.__Type.name),
        ds.__Schema.mutationType.select(ds.__Type.name),
        ds.__Schema.subscriptionType.select(ds.__Type.name),
    )

    schema.select(ds.__Schema.types.select(fragment_FullType))

    directives = ds.__Schema.directives.select(ds.__Directive.name)

    if descriptions:
        directives.select(ds.__Directive.description)
    if directive_is_repeatable:
        directives.select(ds.__Directive.isRepeatable)
    directives.select(
        ds.__Directive.locations,
        ds.__Directive.args.select(fragment_InputValue),
    )

    schema.select(directives)

    fragment_FullType.select(
        ds.__Type.kind,
        ds.__Type.name,
    )
    if descriptions:
        fragment_FullType.select(ds.__Type.description)
    if specified_by_url:
        fragment_FullType.select(ds.__Type.specifiedByURL)

    fields = ds.__Type.fields(includeDeprecated=True).select(ds.__Field.name)

    if descriptions:
        fields.select(ds.__Field.description)

    fields.select(
        ds.__Field.args.select(fragment_InputValue),
        ds.__Field.type.select(fragment_TypeRef),
        ds.__Field.isDeprecated,
        ds.__Field.deprecationReason,
    )

    enum_values = ds.__Type.enumValues(includeDeprecated=True).select(
        ds.__EnumValue.name
    )

    if descriptions:
        enum_values.select(ds.__EnumValue.description)

    enum_values.select(
        ds.__EnumValue.isDeprecated,
        ds.__EnumValue.deprecationReason,
    )

    fragment_FullType.select(
        fields,
        ds.__Type.inputFields.select(fragment_InputValue),
        ds.__Type.interfaces.select(fragment_TypeRef),
        enum_values,
        ds.__Type.possibleTypes.select(fragment_TypeRef),
    )

    fragment_InputValue.select(ds.__InputValue.name)

    if descriptions:
        fragment_InputValue.select(ds.__InputValue.description)

    fragment_InputValue.select(
        ds.__InputValue.type.select(fragment_TypeRef),
        ds.__InputValue.defaultValue,
    )

    fragment_TypeRef.select(
        ds.__Type.kind,
        ds.__Type.name,
    )

    if type_recursion_level >= 1:
        current_field = ds.__Type.ofType.select(ds.__Type.kind, ds.__Type.name)
        fragment_TypeRef.select(current_field)

        for _ in repeat(None, type_recursion_level - 1):
            new_oftype = ds.__Type.ofType.select(ds.__Type.kind, ds.__Type.name)
            current_field.select(new_oftype)
            current_field = new_oftype

    query = DSLQuery(schema)

    query.name = "IntrospectionQuery"

    dsl_query = dsl_gql(query, fragment_FullType, fragment_InputValue, fragment_TypeRef)

    return dsl_query
예제 #17
0
class MothrClient:
    """Client for connecting to MOTHR

    Args:
        url (str, optional): Endpoint to send the job request,
            checks for ``MOTHR_ENDPOINT`` in environment variables otherwise
            defaults to ``http://localhost:8080/query``
        token (str, optional): Access token to use for authentication, the library
            also looks for ``MOTHR_ACCESS_TOKEN`` in the environment as a fallback
        username (str, optional): Username for logging in, if not given the library
            will attempt to use ``MOTHR_USERNAME`` environment variable. If neither
            are found the request will be made without authentication.
        password (str, optional): Password for logging in, if not given the library
            will attempt to use the ``MOTHR_PASSWORD`` environment variable. If
            neither are found the request will be made without authentication.
    """
    def __init__(self, **kwargs):
        schemes = {"http": "ws", "https": "wss"}
        self.headers: Dict[str, str] = {}
        endpoint = os.getenv(URL_VAR, "http://localhost:8080/api")
        url = kwargs.pop("url", endpoint)
        split_url = urlsplit(url)
        ws_url = urlunsplit(
            split_url._replace(scheme=schemes[split_url.scheme]))

        transport = RequestsHTTPTransport(url=url, headers=self.headers)
        client = Client(transport=transport, schema=schema)
        self.ds = DSLSchema(client)

        ws_transport = WebsocketsTransport(url=ws_url)
        self.ws_client = Client(transport=ws_transport, schema=schema)

        self.token = kwargs.pop("token", os.getenv(TOKEN_VAR))
        username = kwargs.pop("username", os.getenv(USERNAME_VAR))
        password = kwargs.pop("password", os.getenv(PASSWORD_VAR))
        if self.token is not None:
            self.headers = {"Authorization": f"Bearer {self.token}"}
        elif all((username, password)):
            self.login(username, password)

        # Mapping for nested fields
        self.field_map = {
            "Job": {
                "outputMetadata": self.ds.Metadata,
                "parameters": self.ds.Parameter,
                "user": self.ds.User,
                "worker": self.ds.Worker,
            },
            "Service": {
                "parameters": self.ds.ServiceParameter,
                "fileType": self.ds.FileType,
            },
        }

    def login(self,
              username: Optional[str] = None,
              password: Optional[str] = None) -> Tuple[str, str]:
        """Retrieve a web token from MOTHR

        Args:
            username (str, optional): Username used to login, the library will look
                for ``MOTHR_USERNAME`` in the environment as a fallback.
            password (str, optional): Password used to login, the library will look
                for ``MOTHR_PASSWORD`` in the environment as a fallback.

        Returns:
            str: An access token to pass with future requests
            str: A refresh token for receiving a new access token
                after the current token expires

        Raises:
            ValueError: If a username or password are not provided and are not found
                in the current environment
        """
        username = username if username is not None else os.getenv(
            "MOTHR_USERNAME")
        password = password if password is not None else os.getenv(
            "MOTHR_PASSWORD")
        if username is None:
            raise ValueError("Username not provided")
        if password is None:
            raise ValueError("Password not provided")

        credentials = {"username": username, "password": password}
        q = self.ds.Mutation.login.args(**credentials).select(
            self.ds.LoginResponse.token, self.ds.LoginResponse.refresh)
        resp = self.ds.mutate(q)
        tokens = resp["login"]
        if tokens is None:
            raise ValueError("Login failed")
        self.access = tokens["token"]
        self.refresh = tokens["refresh"]
        self.headers["Authorization"] = f"Bearer {self.token}"
        return self.access, self.refresh

    def refresh_token(self) -> str:
        """Refresh an expired access token

        Returns:
            str: New access token
        """
        q = self.ds.Mutation.refresh.args(token=self.refresh).select(
            self.ds.RefreshResponse.token)
        resp = self.ds.mutate(q)
        if resp["refresh"] is None:
            raise ValueError("Token refresh failed")
        token = resp["refresh"]["token"]
        self.token = token
        self.headers["Authorization"] = f"Bearer {self.token}"
        return token

    def service(
        self,
        name: str,
        version: Optional[str] = "*",
        fields: Optional[List[str]] = None,
    ) -> List[Dict]:
        """Query a service by name

        Args:
            name (str): Name of the service
            version (str, optional): Version to retrieve.
                If no version is given all versions of the service will be returned.
                Wildcards are also accepted.
            fields (list<str>, optional): Fields to return in the query response,
                default is `name` and `version`

        Returns:
            list<dict>: Service records matching the query
        """
        fields = fields if fields is not None else ["name", "version"]
        fields = [
            self.resolve_field(self.ds.Service, field) for field in fields
        ]
        q = self.ds.Query.service.args(name=name,
                                       version=version).select(*fields)
        resp = self.ds.query(q)
        return resp["service"]

    def services(self, fields: Optional[List[str]] = None) -> List[Dict]:
        """Retrieve all services registered with MOTHR

        Args:
            fields (list<str>, optional): Fields to return in the query response,
                default is `name` and `version`

        Returns:
            list<dict>: All services registered with MOTHR
        """
        fields = fields if fields is not None else ["name", "version"]
        fields = [
            self.resolve_field(self.ds.Service, field) for field in fields
        ]
        q = self.ds.Query.services.select(*fields)
        resp = self.ds.query(q)
        return resp["services"]

    def resolve_field(self, obj: DSLType, field: str) -> DSLField:
        """Resolve paths to nested fields

        Args:
            obj (`gql.dsl.DSLType`): Root type belonging to the field
            field (str): Field to resolve, nested fields are specified using
                dot notation

        Returns: `gql.dsl.DSLField`
        """
        if "." in field:
            nested_fields = self.field_map[str(obj._type)]
            f_split = field.split(".")
            return self.select_field(nested_fields, getattr(obj, f_split[0]),
                                     f_split[1:])
        return getattr(obj, field)

    def select_field(self, field_map: Dict, field_obj: DSLField,
                     field: List[str]) -> DSLField:
        """Select nested fields

        Args:
            field_map (dict<str, `gql.dsl.DSLType`>): Dictionary mapping field names
                to their associated DSLType. See `self.field_map`
            field_obj (`gql.dsl.DSLField`): Field object to select subfields from
            field (list<str>): Field name split into individual components

        Returns: `gql.dsl.DSLField`
        """
        field_key = str(field_obj)
        for char in ["{", "}", "\n"]:
            field_key = field_key.replace(char, "")
        field_key = field_key.split(" ")[-1]
        field_name = field.pop(0)
        if len(field) > 0:
            return field_obj.select(
                self.select_field(field_map,
                                  getattr(field_map[field_key], field_name),
                                  field))
        return field_obj.select(getattr(field_map[field_key], field_name))
예제 #18
0
from gql.dsl import DSLQuery, DSLSchema, dsl_gql
from gql.transport.requests import RequestsHTTPTransport

transport = RequestsHTTPTransport(
    url="https://countries.trevorblades.com/",
    verify=True,
    retries=3,
)

client = Client(transport=transport, fetch_schema_from_transport=True)

# Using `with` on the sync client will start a connection on the transport
# and provide a `session` variable to execute queries on this connection.
# Because we requested to fetch the schema from the transport,
# GQL will fetch the schema just after the establishment of the first session
with client as session:

    # We should have received the schema now that the session is established
    assert client.schema is not None

    # Instantiate the root of the DSL Schema as ds
    ds = DSLSchema(client.schema)

    # Create the query using dynamically generated attributes from ds
    query = dsl_gql(
        DSLQuery(
            ds.Query.continents.select(ds.Continent.code, ds.Continent.name)))

    result = session.execute(query)
    print(result)
예제 #19
0
파일: test_dsl.py 프로젝트: tony/gql
def ds():
    client = Client(schema=StarWarsSchema)
    ds = DSLSchema(client)
    return ds
예제 #20
0
 def _get_schema(self):
     """ Gets GQL schema """
     return DSLSchema(self._gql_client.schema)