clear-skies 2.0.27__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of clear-skies might be problematic. Click here for more details.

Files changed (270) hide show
  1. clear_skies-2.0.27.dist-info/METADATA +78 -0
  2. clear_skies-2.0.27.dist-info/RECORD +270 -0
  3. clear_skies-2.0.27.dist-info/WHEEL +4 -0
  4. clear_skies-2.0.27.dist-info/licenses/LICENSE +7 -0
  5. clearskies/__init__.py +69 -0
  6. clearskies/action.py +7 -0
  7. clearskies/authentication/__init__.py +15 -0
  8. clearskies/authentication/authentication.py +44 -0
  9. clearskies/authentication/authorization.py +23 -0
  10. clearskies/authentication/authorization_pass_through.py +22 -0
  11. clearskies/authentication/jwks.py +165 -0
  12. clearskies/authentication/public.py +5 -0
  13. clearskies/authentication/secret_bearer.py +551 -0
  14. clearskies/autodoc/__init__.py +8 -0
  15. clearskies/autodoc/formats/__init__.py +5 -0
  16. clearskies/autodoc/formats/oai3_json/__init__.py +7 -0
  17. clearskies/autodoc/formats/oai3_json/oai3_json.py +87 -0
  18. clearskies/autodoc/formats/oai3_json/oai3_schema_resolver.py +15 -0
  19. clearskies/autodoc/formats/oai3_json/parameter.py +35 -0
  20. clearskies/autodoc/formats/oai3_json/request.py +68 -0
  21. clearskies/autodoc/formats/oai3_json/response.py +28 -0
  22. clearskies/autodoc/formats/oai3_json/schema/__init__.py +11 -0
  23. clearskies/autodoc/formats/oai3_json/schema/array.py +9 -0
  24. clearskies/autodoc/formats/oai3_json/schema/default.py +13 -0
  25. clearskies/autodoc/formats/oai3_json/schema/enum.py +7 -0
  26. clearskies/autodoc/formats/oai3_json/schema/object.py +35 -0
  27. clearskies/autodoc/formats/oai3_json/test.json +1985 -0
  28. clearskies/autodoc/py.typed +0 -0
  29. clearskies/autodoc/request/__init__.py +15 -0
  30. clearskies/autodoc/request/header.py +6 -0
  31. clearskies/autodoc/request/json_body.py +6 -0
  32. clearskies/autodoc/request/parameter.py +8 -0
  33. clearskies/autodoc/request/request.py +47 -0
  34. clearskies/autodoc/request/url_parameter.py +6 -0
  35. clearskies/autodoc/request/url_path.py +6 -0
  36. clearskies/autodoc/response/__init__.py +5 -0
  37. clearskies/autodoc/response/response.py +9 -0
  38. clearskies/autodoc/schema/__init__.py +31 -0
  39. clearskies/autodoc/schema/array.py +10 -0
  40. clearskies/autodoc/schema/base64.py +8 -0
  41. clearskies/autodoc/schema/boolean.py +5 -0
  42. clearskies/autodoc/schema/date.py +5 -0
  43. clearskies/autodoc/schema/datetime.py +5 -0
  44. clearskies/autodoc/schema/double.py +5 -0
  45. clearskies/autodoc/schema/enum.py +17 -0
  46. clearskies/autodoc/schema/integer.py +6 -0
  47. clearskies/autodoc/schema/long.py +5 -0
  48. clearskies/autodoc/schema/number.py +6 -0
  49. clearskies/autodoc/schema/object.py +13 -0
  50. clearskies/autodoc/schema/password.py +5 -0
  51. clearskies/autodoc/schema/schema.py +11 -0
  52. clearskies/autodoc/schema/string.py +5 -0
  53. clearskies/backends/__init__.py +67 -0
  54. clearskies/backends/api_backend.py +1194 -0
  55. clearskies/backends/backend.py +137 -0
  56. clearskies/backends/cursor_backend.py +339 -0
  57. clearskies/backends/graphql_backend.py +977 -0
  58. clearskies/backends/memory_backend.py +794 -0
  59. clearskies/backends/secrets_backend.py +100 -0
  60. clearskies/clients/__init__.py +5 -0
  61. clearskies/clients/graphql_client.py +182 -0
  62. clearskies/column.py +1221 -0
  63. clearskies/columns/__init__.py +71 -0
  64. clearskies/columns/audit.py +306 -0
  65. clearskies/columns/belongs_to_id.py +478 -0
  66. clearskies/columns/belongs_to_model.py +145 -0
  67. clearskies/columns/belongs_to_self.py +109 -0
  68. clearskies/columns/boolean.py +110 -0
  69. clearskies/columns/category_tree.py +274 -0
  70. clearskies/columns/category_tree_ancestors.py +51 -0
  71. clearskies/columns/category_tree_children.py +125 -0
  72. clearskies/columns/category_tree_descendants.py +48 -0
  73. clearskies/columns/created.py +92 -0
  74. clearskies/columns/created_by_authorization_data.py +114 -0
  75. clearskies/columns/created_by_header.py +103 -0
  76. clearskies/columns/created_by_ip.py +90 -0
  77. clearskies/columns/created_by_routing_data.py +102 -0
  78. clearskies/columns/created_by_user_agent.py +89 -0
  79. clearskies/columns/date.py +232 -0
  80. clearskies/columns/datetime.py +284 -0
  81. clearskies/columns/email.py +78 -0
  82. clearskies/columns/float.py +149 -0
  83. clearskies/columns/has_many.py +552 -0
  84. clearskies/columns/has_many_self.py +62 -0
  85. clearskies/columns/has_one.py +21 -0
  86. clearskies/columns/integer.py +158 -0
  87. clearskies/columns/json.py +126 -0
  88. clearskies/columns/many_to_many_ids.py +335 -0
  89. clearskies/columns/many_to_many_ids_with_data.py +281 -0
  90. clearskies/columns/many_to_many_models.py +163 -0
  91. clearskies/columns/many_to_many_pivots.py +132 -0
  92. clearskies/columns/phone.py +162 -0
  93. clearskies/columns/select.py +95 -0
  94. clearskies/columns/string.py +102 -0
  95. clearskies/columns/timestamp.py +164 -0
  96. clearskies/columns/updated.py +107 -0
  97. clearskies/columns/uuid.py +83 -0
  98. clearskies/configs/README.md +105 -0
  99. clearskies/configs/__init__.py +170 -0
  100. clearskies/configs/actions.py +43 -0
  101. clearskies/configs/any.py +15 -0
  102. clearskies/configs/any_dict.py +24 -0
  103. clearskies/configs/any_dict_or_callable.py +25 -0
  104. clearskies/configs/authentication.py +23 -0
  105. clearskies/configs/authorization.py +23 -0
  106. clearskies/configs/boolean.py +18 -0
  107. clearskies/configs/boolean_or_callable.py +20 -0
  108. clearskies/configs/callable_config.py +20 -0
  109. clearskies/configs/columns.py +34 -0
  110. clearskies/configs/conditions.py +30 -0
  111. clearskies/configs/config.py +26 -0
  112. clearskies/configs/datetime.py +20 -0
  113. clearskies/configs/datetime_or_callable.py +21 -0
  114. clearskies/configs/email.py +10 -0
  115. clearskies/configs/email_list.py +17 -0
  116. clearskies/configs/email_list_or_callable.py +17 -0
  117. clearskies/configs/email_or_email_list_or_callable.py +59 -0
  118. clearskies/configs/endpoint.py +23 -0
  119. clearskies/configs/endpoint_list.py +29 -0
  120. clearskies/configs/float.py +18 -0
  121. clearskies/configs/float_or_callable.py +20 -0
  122. clearskies/configs/headers.py +28 -0
  123. clearskies/configs/integer.py +18 -0
  124. clearskies/configs/integer_or_callable.py +20 -0
  125. clearskies/configs/joins.py +30 -0
  126. clearskies/configs/list_any_dict.py +32 -0
  127. clearskies/configs/list_any_dict_or_callable.py +33 -0
  128. clearskies/configs/model_class.py +35 -0
  129. clearskies/configs/model_column.py +67 -0
  130. clearskies/configs/model_columns.py +58 -0
  131. clearskies/configs/model_destination_name.py +26 -0
  132. clearskies/configs/model_to_id_column.py +45 -0
  133. clearskies/configs/readable_model_column.py +11 -0
  134. clearskies/configs/readable_model_columns.py +11 -0
  135. clearskies/configs/schema.py +23 -0
  136. clearskies/configs/searchable_model_columns.py +11 -0
  137. clearskies/configs/security_headers.py +39 -0
  138. clearskies/configs/select.py +28 -0
  139. clearskies/configs/select_list.py +49 -0
  140. clearskies/configs/string.py +31 -0
  141. clearskies/configs/string_dict.py +34 -0
  142. clearskies/configs/string_list.py +47 -0
  143. clearskies/configs/string_list_or_callable.py +48 -0
  144. clearskies/configs/string_or_callable.py +18 -0
  145. clearskies/configs/timedelta.py +20 -0
  146. clearskies/configs/timezone.py +20 -0
  147. clearskies/configs/url.py +25 -0
  148. clearskies/configs/validators.py +45 -0
  149. clearskies/configs/writeable_model_column.py +11 -0
  150. clearskies/configs/writeable_model_columns.py +11 -0
  151. clearskies/configurable.py +78 -0
  152. clearskies/contexts/__init__.py +11 -0
  153. clearskies/contexts/cli.py +130 -0
  154. clearskies/contexts/context.py +99 -0
  155. clearskies/contexts/wsgi.py +79 -0
  156. clearskies/contexts/wsgi_ref.py +87 -0
  157. clearskies/cursors/__init__.py +10 -0
  158. clearskies/cursors/cursor.py +161 -0
  159. clearskies/cursors/from_environment/__init__.py +5 -0
  160. clearskies/cursors/from_environment/mysql.py +51 -0
  161. clearskies/cursors/from_environment/postgresql.py +49 -0
  162. clearskies/cursors/from_environment/sqlite.py +35 -0
  163. clearskies/cursors/mysql.py +61 -0
  164. clearskies/cursors/postgresql.py +61 -0
  165. clearskies/cursors/sqlite.py +62 -0
  166. clearskies/decorators.py +33 -0
  167. clearskies/decorators.pyi +10 -0
  168. clearskies/di/__init__.py +15 -0
  169. clearskies/di/additional_config.py +130 -0
  170. clearskies/di/additional_config_auto_import.py +17 -0
  171. clearskies/di/di.py +948 -0
  172. clearskies/di/inject/__init__.py +25 -0
  173. clearskies/di/inject/akeyless_sdk.py +16 -0
  174. clearskies/di/inject/by_class.py +24 -0
  175. clearskies/di/inject/by_name.py +22 -0
  176. clearskies/di/inject/di.py +16 -0
  177. clearskies/di/inject/environment.py +15 -0
  178. clearskies/di/inject/input_output.py +19 -0
  179. clearskies/di/inject/logger.py +16 -0
  180. clearskies/di/inject/now.py +16 -0
  181. clearskies/di/inject/requests.py +16 -0
  182. clearskies/di/inject/secrets.py +15 -0
  183. clearskies/di/inject/utcnow.py +16 -0
  184. clearskies/di/inject/uuid.py +16 -0
  185. clearskies/di/injectable.py +32 -0
  186. clearskies/di/injectable_properties.py +131 -0
  187. clearskies/end.py +219 -0
  188. clearskies/endpoint.py +1303 -0
  189. clearskies/endpoint_group.py +333 -0
  190. clearskies/endpoints/__init__.py +25 -0
  191. clearskies/endpoints/advanced_search.py +519 -0
  192. clearskies/endpoints/callable.py +382 -0
  193. clearskies/endpoints/create.py +201 -0
  194. clearskies/endpoints/delete.py +133 -0
  195. clearskies/endpoints/get.py +267 -0
  196. clearskies/endpoints/health_check.py +181 -0
  197. clearskies/endpoints/list.py +567 -0
  198. clearskies/endpoints/restful_api.py +417 -0
  199. clearskies/endpoints/schema.py +185 -0
  200. clearskies/endpoints/simple_search.py +279 -0
  201. clearskies/endpoints/update.py +188 -0
  202. clearskies/environment.py +106 -0
  203. clearskies/exceptions/__init__.py +19 -0
  204. clearskies/exceptions/authentication.py +2 -0
  205. clearskies/exceptions/authorization.py +2 -0
  206. clearskies/exceptions/client_error.py +2 -0
  207. clearskies/exceptions/input_errors.py +4 -0
  208. clearskies/exceptions/missing_dependency.py +2 -0
  209. clearskies/exceptions/moved_permanently.py +3 -0
  210. clearskies/exceptions/moved_temporarily.py +3 -0
  211. clearskies/exceptions/not_found.py +2 -0
  212. clearskies/functional/__init__.py +7 -0
  213. clearskies/functional/json.py +47 -0
  214. clearskies/functional/routing.py +92 -0
  215. clearskies/functional/string.py +112 -0
  216. clearskies/functional/validations.py +76 -0
  217. clearskies/input_outputs/__init__.py +13 -0
  218. clearskies/input_outputs/cli.py +157 -0
  219. clearskies/input_outputs/exceptions/__init__.py +7 -0
  220. clearskies/input_outputs/exceptions/cli_input_error.py +2 -0
  221. clearskies/input_outputs/exceptions/cli_not_found.py +2 -0
  222. clearskies/input_outputs/headers.py +54 -0
  223. clearskies/input_outputs/input_output.py +116 -0
  224. clearskies/input_outputs/programmatic.py +62 -0
  225. clearskies/input_outputs/py.typed +0 -0
  226. clearskies/input_outputs/wsgi.py +80 -0
  227. clearskies/loggable.py +19 -0
  228. clearskies/model.py +2039 -0
  229. clearskies/py.typed +0 -0
  230. clearskies/query/__init__.py +12 -0
  231. clearskies/query/condition.py +228 -0
  232. clearskies/query/join.py +136 -0
  233. clearskies/query/query.py +195 -0
  234. clearskies/query/sort.py +27 -0
  235. clearskies/schema.py +82 -0
  236. clearskies/secrets/__init__.py +7 -0
  237. clearskies/secrets/additional_configs/__init__.py +32 -0
  238. clearskies/secrets/additional_configs/mysql_connection_dynamic_producer.py +61 -0
  239. clearskies/secrets/additional_configs/mysql_connection_dynamic_producer_via_ssh_cert_bastion.py +160 -0
  240. clearskies/secrets/akeyless.py +507 -0
  241. clearskies/secrets/exceptions/__init__.py +7 -0
  242. clearskies/secrets/exceptions/not_found_error.py +2 -0
  243. clearskies/secrets/exceptions/permissions_error.py +2 -0
  244. clearskies/secrets/secrets.py +39 -0
  245. clearskies/security_header.py +17 -0
  246. clearskies/security_headers/__init__.py +11 -0
  247. clearskies/security_headers/cache_control.py +68 -0
  248. clearskies/security_headers/cors.py +51 -0
  249. clearskies/security_headers/csp.py +95 -0
  250. clearskies/security_headers/hsts.py +23 -0
  251. clearskies/security_headers/x_content_type_options.py +0 -0
  252. clearskies/security_headers/x_frame_options.py +0 -0
  253. clearskies/typing.py +11 -0
  254. clearskies/validator.py +36 -0
  255. clearskies/validators/__init__.py +33 -0
  256. clearskies/validators/after_column.py +61 -0
  257. clearskies/validators/before_column.py +15 -0
  258. clearskies/validators/in_the_future.py +29 -0
  259. clearskies/validators/in_the_future_at_least.py +13 -0
  260. clearskies/validators/in_the_future_at_most.py +12 -0
  261. clearskies/validators/in_the_past.py +29 -0
  262. clearskies/validators/in_the_past_at_least.py +12 -0
  263. clearskies/validators/in_the_past_at_most.py +12 -0
  264. clearskies/validators/maximum_length.py +25 -0
  265. clearskies/validators/maximum_value.py +28 -0
  266. clearskies/validators/minimum_length.py +25 -0
  267. clearskies/validators/minimum_value.py +28 -0
  268. clearskies/validators/required.py +32 -0
  269. clearskies/validators/timedelta.py +58 -0
  270. clearskies/validators/unique.py +28 -0
@@ -0,0 +1,100 @@
1
+ from typing import TYPE_CHECKING, Any, Callable
2
+
3
+ from clearskies.autodoc.schema import Schema as AutoDocSchema
4
+ from clearskies.backends.backend import Backend
5
+ from clearskies.di import inject
6
+ from clearskies.query import Condition, Query
7
+
8
+ if TYPE_CHECKING:
9
+ from clearskies import Model
10
+
11
+
12
+ class SecretsBackend(Backend):
13
+ """
14
+ Fetch and store data from a secret provider.
15
+
16
+ ## Installing Dependencies
17
+
18
+ Clearskies uses Akeyless by default to manage the secrets.
19
+ This is not installed by default, but is a named extra that you can install when needed via:
20
+
21
+ ```bash
22
+ pip install clear-skies[secrets]
23
+ ```
24
+ """
25
+
26
+ """The secrets instance."""
27
+ secrets = inject.Secrets()
28
+
29
+ can_count: bool = False
30
+
31
+ def __init__(self):
32
+ pass
33
+
34
+ def check_query(self, query: Query) -> None:
35
+ if not query.conditions:
36
+ raise KeyError(f"You must search by an id when using the secrets backend.")
37
+
38
+ def update(self, id: str, data: dict[str, Any], model: Model) -> dict[str, Any]: # type: ignore[override]
39
+ """Update the record with the given id with the information from the data dictionary."""
40
+ folder_path = self._make_folder_path(model, id)
41
+ for key, value in data.items():
42
+ if key == model.id_column_name:
43
+ continue
44
+ self.secrets.update(f"{folder_path}{key}", value)
45
+
46
+ # and now query again to fetch the updated record.
47
+ return self.records(Query(model.__class__, conditions=[Condition(f"{model.id_column_name}={id}")]))[0]
48
+
49
+ def create(self, data: dict[str, Any], model: Model) -> dict[str, Any]:
50
+ if not model.id_column_name in data:
51
+ raise ValueError(
52
+ f"You must provide '{model.id_column_name}' when creating a record with the secrets backend"
53
+ )
54
+ return self.update(data[model.id_column_name], data, model)
55
+
56
+ def delete(self, id: str, model: Model) -> bool: # type: ignore[override]
57
+ """
58
+ Delete the record with the given id.
59
+
60
+ Note that this isn't implemented yet, and always returns True.
61
+ """
62
+ return True
63
+
64
+ def records(self, query: Query, next_page_data: dict[str, str | int] | None = None) -> list[dict[str, Any]]:
65
+ """Return a list of records that match the given query configuration."""
66
+ self.check_query(query)
67
+ for condition in query.conditions:
68
+ if condition.operator != "=":
69
+ raise ValueError(
70
+ f"I'm not very smart and only know how to search with the equals operator, but I received a condition of {condition.parsed}. If you need to support this, you'll have to extend the ApiBackend and overwrite the build_records_request method."
71
+ )
72
+ if condition.column_name == query.model_class.id_column_name:
73
+ id = condition.values[0]
74
+ break
75
+ if id is None:
76
+ raise ValueError(f"You must search by '{query.model_class.id_column_name}' when using the secrets backend")
77
+
78
+ folder_path = self._make_folder_path(query.model_class, id)
79
+ data = {query.model_class.id_column_name: id}
80
+ for path in self.secrets.list_secrets(folder_path):
81
+ data[path[len(folder_path) :]] = self.secrets.get(path)
82
+ return [data]
83
+
84
+ def _make_folder_path(self, model, id):
85
+ return model.table_name().rstrip("/") + "/" + id.strip("/") + "/"
86
+
87
+ def validate_pagination_data(self, data: dict[str, Any], case_mapping: Callable[[str], str]) -> str:
88
+ return ""
89
+
90
+ def allowed_pagination_keys(self) -> list[str]:
91
+ return []
92
+
93
+ def documentation_pagination_next_page_response(self, case_mapping: Callable) -> list[Any]:
94
+ return []
95
+
96
+ def documentation_pagination_parameters(self, case_mapping: Callable) -> list[tuple[AutoDocSchema, str]]:
97
+ return []
98
+
99
+ def documentation_pagination_next_page_example(self, case_mapping: Callable) -> dict[str, Any]:
100
+ return {}
@@ -0,0 +1,5 @@
1
+ from clearskies.clients.graphql_client import GraphqlClient
2
+
3
+ __all__ = [
4
+ "GraphqlClient",
5
+ ]
@@ -0,0 +1,182 @@
1
+ from typing import TYPE_CHECKING, Any
2
+
3
+ from clearskies import configs, configurable, decorators, loggable
4
+ from clearskies.authentication import Authentication
5
+ from clearskies.di import InjectableProperties, inject
6
+
7
+ if TYPE_CHECKING:
8
+ from gql import Client
9
+
10
+
11
+ class GraphqlClient(configurable.Configurable, loggable.Loggable, InjectableProperties):
12
+ """
13
+ A simple GraphQL client wrapper using gql library.
14
+
15
+ This client handles the connection to GraphQL APIs and provides methods to execute
16
+ queries and mutations. It supports authentication, custom headers, and configurable timeouts.
17
+
18
+ Example usage:
19
+ ```python
20
+ import clearskies
21
+
22
+ client = clearskies.clients.GraphqlClient(
23
+ endpoint="https://api.example.com/graphql",
24
+ authentication=clearskies.authentication.SecretBearer(
25
+ environment_key="API_TOKEN", header_prefix="Bearer "
26
+ ),
27
+ headers={"X-Custom-Header": "value"},
28
+ timeout=30,
29
+ )
30
+
31
+ # Execute a query
32
+ result = client.execute('''
33
+ query {
34
+ projects {
35
+ id
36
+ name
37
+ }
38
+ }
39
+ ''')
40
+ ```
41
+ """
42
+
43
+ """
44
+ The GraphQL API endpoint URL.
45
+
46
+ The full URL to your GraphQL API endpoint. Example:
47
+
48
+ ```python
49
+ client = clearskies.clients.GraphqlClient(
50
+ endpoint="https://api.example.com/graphql"
51
+ )
52
+ ```
53
+
54
+ Defaults to "http://localhost:4000/graphql" for local development.
55
+ """
56
+ endpoint = configs.String(default="http://localhost:4000/graphql")
57
+
58
+ """
59
+ Authentication mechanism for the GraphQL API.
60
+
61
+ An instance of a clearskies authentication class that provides credentials for the API.
62
+ The authentication object's headers() method will be called to add authorization headers
63
+ to requests. Example:
64
+
65
+ ```python
66
+ client = clearskies.clients.GraphqlClient(
67
+ endpoint="https://api.example.com/graphql",
68
+ authentication=clearskies.authentication.SecretBearer(
69
+ environment_key="GRAPHQL_TOKEN",
70
+ header_prefix="Bearer "
71
+ )
72
+ )
73
+ ```
74
+
75
+ Set to None for public APIs that don't require authentication.
76
+ """
77
+ authentication = configs.Authentication(default=None)
78
+
79
+ """
80
+ Additional HTTP headers to include in requests.
81
+
82
+ A dictionary of header names and values to send with every request. These headers
83
+ are merged with any headers provided by the authentication mechanism. Example:
84
+
85
+ ```python
86
+ client = clearskies.clients.GraphqlClient(
87
+ endpoint="https://api.example.com/graphql",
88
+ headers={
89
+ "X-API-Version": "v1",
90
+ "X-Client-Name": "my-app"
91
+ }
92
+ )
93
+ ```
94
+
95
+ Defaults to an empty dictionary.
96
+ """
97
+ headers = configs.AnyDict(default={})
98
+
99
+ """
100
+ Request timeout in seconds.
101
+
102
+ Maximum time to wait for a response from the GraphQL API before raising a timeout error.
103
+ Applies to both connection and read timeouts. Example:
104
+
105
+ ```python
106
+ client = clearskies.clients.GraphqlClient(
107
+ endpoint="https://api.example.com/graphql",
108
+ timeout=60 # Wait up to 60 seconds for responses
109
+ )
110
+ ```
111
+
112
+ Defaults to 10 seconds.
113
+ """
114
+ timeout = configs.Integer(default=10)
115
+
116
+ di = inject.Di()
117
+
118
+ _client: Any
119
+
120
+ @decorators.parameters_to_properties
121
+ def __init__(
122
+ self,
123
+ endpoint="http://localhost:4000/graphql",
124
+ headers={},
125
+ authentication: Authentication | None = None,
126
+ timeout=10,
127
+ ):
128
+ self.finalize_and_validate_configuration()
129
+
130
+ @property
131
+ def client(self) -> "Client":
132
+ """
133
+ Get the underlying gql Client instance.
134
+
135
+ Lazily creates and caches a gql Client with the configured endpoint, authentication,
136
+ headers, and timeout. The client handles the HTTP transport layer for GraphQL requests.
137
+
138
+ This property is primarily used internally by the execute() method, but can be accessed
139
+ directly if you need lower-level control over GraphQL operations.
140
+
141
+ Returns:
142
+ Client: A gql Client instance configured with this GraphqlClient's settings.
143
+ """
144
+ from gql import Client
145
+ from gql.transport.requests import RequestsHTTPTransport
146
+
147
+ if hasattr(self, "_client"):
148
+ return self._client # type: ignore
149
+
150
+ if self.authentication:
151
+ # Inject dependencies if the authentication object supports it
152
+ if hasattr(self.authentication, "injectable_properties"):
153
+ self.authentication.injectable_properties(self.di) # type: ignore[attr-defined]
154
+ transport = RequestsHTTPTransport(
155
+ url=self.endpoint,
156
+ headers=self.headers,
157
+ auth=self.authentication,
158
+ timeout=self.timeout,
159
+ )
160
+ self._client = Client(transport=transport, fetch_schema_from_transport=False)
161
+ return self._client
162
+
163
+ def execute(self, query: str, variable_values: dict[str, Any] | None = None) -> dict[str, Any]:
164
+ """
165
+ Execute a GraphQL query or mutation.
166
+
167
+ Args:
168
+ query (str): The GraphQL query or mutation string.
169
+ variable_values (dict, optional): Variables for the query/mutation. Defaults to None
170
+ Returns:
171
+ dict: The response data from the GraphQL API.
172
+ """
173
+ from gql import gql
174
+
175
+ client = self.client
176
+ prepared_query = gql(query)
177
+ self.logger.debug(
178
+ f"Executing GraphQL query: {prepared_query} on endpoint: {self.endpoint} with variables: {variable_values}"
179
+ )
180
+ result = client.execute(prepared_query, variable_values=variable_values)
181
+ self.logger.debug(f"GraphQL response: {result}")
182
+ return result