Skip to content

Commit 8936df8

Browse files
authored
fix: refactor OpenHexaClient to allow usage in both CLI and SDK without circular dependency (HEXA-1314) (#279)
1 parent bd8b8f1 commit 8936df8

22 files changed

Lines changed: 104 additions & 33 deletions

README.md

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,40 @@ You can run the tests using pytest:
148148
pytest
149149
```
150150

151+
### Codegen from the GraphQL schema
152+
153+
We use code generation to create Python client code from our GraphQL schema. This involves one tools:
154+
155+
- [**ariadne-codegen**](https://github.com/mirumee/ariadne-codegen): Generates typed Python GraphQL client code from GraphQL files
156+
157+
The code generation process:
158+
159+
1. The GraphQL schema is manually taken from the [Openhexa Monorepo](https://github.com/BLSQ/openhexa-app/blob/main/frontend/schema.generated.graphql) and saved in [`openhexa/graphql/schema.generated.graphql`](https://github.com/BLSQ/openhexa-sdk-python/blob/main/openhexa/graphql/schema.generated.graphql)
160+
2`ariadne-codegen` uses both the schema and queries to generate typed Python client code
161+
162+
To run code generation manually:
163+
164+
```shell
165+
pip install ariadne-codegen
166+
ariadne-codegen
167+
```
168+
169+
ariadne-codegen runs automatically via pre-commit hooks and CI/CD when GraphQL files are modified.
170+
171+
You can add new queries or mutations in the [`openhexa/graphql/queries.graphql`](https://github.com/BLSQ/openhexa-sdk-python/blob/main/openhexa/graphql/queries.graphql) directory, and they will be picked up by the code generation process.
172+
173+
Example of usage of the generated code:
174+
175+
```python
176+
from sdk import OpenHexaClient
177+
178+
# connect to OpenHEXA backend using environment variables
179+
OpenHexaClient().get_countries(workspace_slug="workspace_slug_example")
180+
181+
# or explicitly pass the URL and token
182+
OpenHexaClient(server_url="app.demo.openhexa.org", token="supersecuretoken")
183+
```
184+
151185
## Release
152186

153187
This project uses [release-please](https://github.com/googleapis/release-please) to manage releases using conventional commits.

openhexa/cli/api.py

Lines changed: 4 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@
2121
from graphql.utilities import find_breaking_changes
2222
from jinja2 import Template
2323

24-
from openhexa.cli.graphql.graphql_client import Client
2524
from openhexa.cli.settings import settings
25+
from openhexa.graphql import BaseOpenHexaClient
2626
from openhexa.sdk.pipelines import get_local_workspace_config
2727
from openhexa.sdk.pipelines.runtime import get_pipeline
2828
from openhexa.utils import create_requests_session, stringcase
@@ -747,31 +747,16 @@ def is_dhis2_connection_up(workspace_slug: str, connection_slug: str) -> bool:
747747
return response["data"]["connectionBySlug"]["status"] == "UP"
748748

749749

750-
class OpenHexaClient(Client):
750+
class OpenHexaClient(BaseOpenHexaClient):
751751
"""OpenHexaClient is a class that provides methods to interact with the OpenHexa GraphQL API."""
752752

753753
def __init__(self, token=None):
754754
"""Initialize the OpenHexaClient with the OpenHexa API URL and headers."""
755-
self._url = settings.api_url + "/graphql/"
756-
self._token = token or settings.access_token
757-
758-
if not self._token:
759-
raise InvalidTokenError("No token found for workspace")
760-
761-
super().__init__(
762-
url=self._url,
763-
headers={
764-
"User-Agent": f"openhexa-cli/{version('openhexa.sdk')}",
765-
"Authorization": f"Bearer {self._token}",
766-
},
767-
)
768-
logging.getLogger("httpx").setLevel(
769-
logging.WARNING
770-
) # HTTPX logs queries by default, we disable them here with WARNING level
755+
super().__init__(url=settings.api_url + "/graphql/", token=settings.access_token)
771756

772757
def execute(self, query, **kwargs):
773758
"""Decorate parent execute method to log the GraphQL query and response."""
774-
_detect_graphql_breaking_changes(token=self._token)
759+
_detect_graphql_breaking_changes(token=self.token)
775760

776761
if settings.debug:
777762
click.echo("")

openhexa/graphql/__init__.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
"""GraphQL package."""
2+
3+
4+
from .base_openhexa_client import BaseOpenHexaClient # noqa: F401 -> Expose base client class
5+
from .graphql_client import * # noqa: F403 -> Expose autogenerated types
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
"""OpenHexaClient implementation for GraphQL API interaction."""
2+
3+
import logging
4+
from importlib.metadata import version
5+
6+
from openhexa.graphql.graphql_client import Client
7+
8+
9+
class BaseOpenHexaClient(Client):
10+
"""OpenHexaClient is a class that provides methods to interact with the OpenHexa GraphQL API."""
11+
12+
def __init__(self, url: str, token: str):
13+
"""Initialize the OpenHexaClient with the OpenHexa API URL and headers.
14+
15+
Args:
16+
url: GraphQL API URL.
17+
token: Authentication token.
18+
"""
19+
self.token = token
20+
super().__init__(
21+
url=url,
22+
headers={
23+
"User-Agent": f"openhexa-sdk/{version('openhexa.sdk')}",
24+
"Authorization": f"Bearer {self.token}",
25+
},
26+
)
27+
logging.getLogger("httpx").setLevel(
28+
logging.WARNING
29+
) # HTTPX logs queries by default, we disable them here with WARNING level
File renamed without changes.

openhexa/cli/graphql/graphql_client/async_base_client.py renamed to openhexa/graphql/graphql_client/async_base_client.py

File renamed without changes.
File renamed without changes.
File renamed without changes.

openhexa/cli/graphql/graphql_client/client.py renamed to openhexa/graphql/graphql_client/client.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# Generated by ariadne-codegen
2-
# Source: openhexa/cli/graphql/queries.graphql
2+
# Source: openhexa/graphql/queries.graphql
33

44
from typing import Any, Dict, Optional, Union
55

openhexa/cli/graphql/graphql_client/enums.py renamed to openhexa/graphql/graphql_client/enums.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# Generated by ariadne-codegen
2-
# Source: openhexa/cli/graphql/schema.generated.graphql
2+
# Source: openhexa/graphql/schema.generated.graphql
33

44
from enum import Enum
55

0 commit comments

Comments
 (0)