From 3bf1a65a8902f9f0e93f6b8828e07682bb8701cf Mon Sep 17 00:00:00 2001 From: Anton Shutik Date: Thu, 31 Oct 2024 08:41:12 +0100 Subject: [PATCH 1/3] Added queries dir support --- shopify_client/__init__.py | 4 ++-- shopify_client/graphql.py | 22 ++++++++++++++++++---- tests/test_graphql.py | 14 +++++++++++++- 3 files changed, 33 insertions(+), 7 deletions(-) diff --git a/shopify_client/__init__.py b/shopify_client/__init__.py index f84db18..31b5fd5 100644 --- a/shopify_client/__init__.py +++ b/shopify_client/__init__.py @@ -16,7 +16,7 @@ class ShopifyClient(requests.Session): - def __init__(self, api_url, api_token, api_version=SHOPIFY_API_VERSION): + def __init__(self, api_url, api_token, api_version=SHOPIFY_API_VERSION, grapgql_queries_dir=None): super().__init__() self.api_url = api_url self.api_version = api_version @@ -109,7 +109,7 @@ def __init__(self, api_url, api_token, api_version=SHOPIFY_API_VERSION): self.webhooks = Endpoint(client=self, endpoint="webhooks") # GraphQL - self.query = GraphQL(client=self) + self.query = GraphQL(client=self, grapgql_queries_dir=grapgql_queries_dir) self.hooks["response"].append(rate_limit) diff --git a/shopify_client/graphql.py b/shopify_client/graphql.py index cb8482e..07b79fa 100644 --- a/shopify_client/graphql.py +++ b/shopify_client/graphql.py @@ -1,5 +1,6 @@ import json import logging +import os import requests @@ -8,19 +9,32 @@ class GraphQL: - def __init__(self, client): + def __init__(self, client, grapgql_queries_dir=None): self.client = client self.endpoint = "graphql.json" + self.grapgql_queries_dir = grapgql_queries_dir def __build_url(self, **params): return self.endpoint def __call__(self, *args, **kwargs): return self.__query(*args, **kwargs) + + def __query_from_name(self, name): + assert self.grapgql_queries_dir, "GraphQL queries directory is not set" + + query_path = os.path.join(self.grapgql_queries_dir, f"{name}.graphql") + with open(query_path, "r") as f: + return f.read() + + def __query(self, query=None, query_name=None, variables=None, operation_name=None, paginate=False, page_size=100): + assert query or query_name, "Either 'query' or 'query_name' must be provided" - def __query(self, query, variables=None, operation_name=None, paginate=False, page_size=100): + if query is None and query_name: + query = self.__query_from_name(query_name) + if paginate: - return self.__paginate(query, variables, operation_name, page_size) + return self.__paginate(query=query, variables=variables, operation_name=operation_name, page_size=page_size) try: response = self.client.post( self.__build_url(), @@ -45,7 +59,7 @@ def __paginate(self, query, variables=None, operation_name=None, page_size=100): while has_next_page: variables["cursor"] = cursor - response = self.__query(query, variables, operation_name) + response = self.__query(query=query, variables=variables, operation_name=operation_name) page_info = self.__find_page_info(response) has_next_page = page_info.get("hasNextPage", False) cursor = page_info.get("endCursor", None) diff --git a/tests/test_graphql.py b/tests/test_graphql.py index 6647054..d6f816b 100644 --- a/tests/test_graphql.py +++ b/tests/test_graphql.py @@ -1,6 +1,6 @@ from copy import deepcopy import json -from unittest.mock import call +from unittest.mock import MagicMock, call, mock_open, patch import requests import pytest from shopify_client.graphql import GraphQL @@ -16,6 +16,18 @@ def test_graphql_query(graphql, mock_client): mock_client.post.assert_called_once_with("graphql.json", json={"query": "query { key }", "variables": None, "operationName": None}) assert response == {"data": {"key": "value"}} +def test_graphql_query_with_query_name(graphql, mock_client): + mock_query_content = "query { items { id } }" + graphql.grapgql_queries_dir = "queries" + with patch("builtins.open", mock_open(read_data=mock_query_content)): + mock_client.post.return_value = {"data": {"items": []}} + response = graphql(query_name="test_query") + mock_client.post.assert_called_once_with( + "graphql.json", + json={"query": mock_query_content, "variables": None, "operationName": None}, + ) + assert response == {"data": {"items": []}} + def test_graphql_query_with_variables(graphql, mock_client): mock_client.post.return_value = {"data": {"key": "value"}} variables = {"var1": "value1"} From 8e4039860c2303d99b6ffeb08c32de2f3f1efb28 Mon Sep 17 00:00:00 2001 From: Anton Shutik Date: Thu, 31 Oct 2024 08:47:06 +0100 Subject: [PATCH 2/3] Updated README --- README.md | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 64d0313..1cb416c 100644 --- a/README.md +++ b/README.md @@ -62,8 +62,10 @@ order = client.orders.close(resource_id=1234) ### GraphQL API ```python -# List products -query = ''' +# Initialize the client +client = ShopifyClient(api_url='your_api_url', api_token='your_token', api_version='your_api_version', grapgql_queries_dir="queries") + +# queries/listProducts.graphql query products($page_size: Int = 100) { products(first: $page_size) { nodes { @@ -72,8 +74,10 @@ query products($page_size: Int = 100) { } } } -''' -response = client.query(query) + + +# List products +response = client.query(query_name="listProducts") # Limit page size response = client.query(query, variables={"page_size": 20}) @@ -95,7 +99,7 @@ query products($page_size: Int = 100, $cursor: String) { } } ''' -for page in client.query(query, paginate=True) +for page in client.query(query=query, paginate=True) print(page) ``` From 7712e3f52e0a5963684792eae2f58e4c835933c1 Mon Sep 17 00:00:00 2001 From: Anton Shutik Date: Thu, 31 Oct 2024 08:57:54 +0100 Subject: [PATCH 3/3] query_from_name public --- shopify_client/graphql.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/shopify_client/graphql.py b/shopify_client/graphql.py index 07b79fa..3815f41 100644 --- a/shopify_client/graphql.py +++ b/shopify_client/graphql.py @@ -20,7 +20,7 @@ def __build_url(self, **params): def __call__(self, *args, **kwargs): return self.__query(*args, **kwargs) - def __query_from_name(self, name): + def query_from_name(self, name): assert self.grapgql_queries_dir, "GraphQL queries directory is not set" query_path = os.path.join(self.grapgql_queries_dir, f"{name}.graphql") @@ -31,7 +31,7 @@ def __query(self, query=None, query_name=None, variables=None, operation_name=No assert query or query_name, "Either 'query' or 'query_name' must be provided" if query is None and query_name: - query = self.__query_from_name(query_name) + query = self.query_from_name(query_name) if paginate: return self.__paginate(query=query, variables=variables, operation_name=operation_name, page_size=page_size)