groundx 2.0.15__py3-none-any.whl → 2.7.7__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.
Files changed (147) hide show
  1. groundx/__init__.py +73 -21
  2. groundx/buckets/__init__.py +2 -0
  3. groundx/buckets/client.py +55 -388
  4. groundx/buckets/raw_client.py +628 -0
  5. groundx/client.py +22 -21
  6. groundx/core/__init__.py +5 -0
  7. groundx/core/api_error.py +13 -5
  8. groundx/core/client_wrapper.py +4 -3
  9. groundx/core/force_multipart.py +16 -0
  10. groundx/core/http_client.py +76 -32
  11. groundx/core/http_response.py +55 -0
  12. groundx/core/jsonable_encoder.py +0 -1
  13. groundx/core/pydantic_utilities.py +71 -112
  14. groundx/core/serialization.py +7 -3
  15. groundx/csv_splitter.py +64 -0
  16. groundx/customer/__init__.py +2 -0
  17. groundx/customer/client.py +31 -43
  18. groundx/customer/raw_client.py +91 -0
  19. groundx/documents/__init__.py +1 -2
  20. groundx/documents/client.py +455 -953
  21. groundx/documents/raw_client.py +1450 -0
  22. groundx/errors/__init__.py +2 -0
  23. groundx/errors/bad_request_error.py +4 -3
  24. groundx/errors/unauthorized_error.py +4 -3
  25. groundx/extract/__init__.py +48 -0
  26. groundx/extract/agents/__init__.py +7 -0
  27. groundx/extract/agents/agent.py +202 -0
  28. groundx/extract/classes/__init__.py +24 -0
  29. groundx/extract/classes/agent.py +23 -0
  30. groundx/extract/classes/api.py +15 -0
  31. groundx/extract/classes/document.py +338 -0
  32. groundx/extract/classes/field.py +88 -0
  33. groundx/extract/classes/groundx.py +147 -0
  34. groundx/extract/classes/prompt.py +36 -0
  35. groundx/extract/classes/test_document.py +109 -0
  36. groundx/extract/classes/test_field.py +43 -0
  37. groundx/extract/classes/test_groundx.py +223 -0
  38. groundx/extract/classes/test_prompt.py +68 -0
  39. groundx/extract/post_process/__init__.py +7 -0
  40. groundx/extract/post_process/post_process.py +33 -0
  41. groundx/extract/services/.DS_Store +0 -0
  42. groundx/extract/services/__init__.py +14 -0
  43. groundx/extract/services/csv.py +76 -0
  44. groundx/extract/services/logger.py +126 -0
  45. groundx/extract/services/logging_cfg.py +53 -0
  46. groundx/extract/services/ratelimit.py +104 -0
  47. groundx/extract/services/sheets_client.py +160 -0
  48. groundx/extract/services/status.py +197 -0
  49. groundx/extract/services/upload.py +68 -0
  50. groundx/extract/services/upload_minio.py +122 -0
  51. groundx/extract/services/upload_s3.py +91 -0
  52. groundx/extract/services/utility.py +52 -0
  53. groundx/extract/settings/__init__.py +15 -0
  54. groundx/extract/settings/settings.py +212 -0
  55. groundx/extract/settings/test_settings.py +512 -0
  56. groundx/extract/tasks/__init__.py +6 -0
  57. groundx/extract/tasks/utility.py +27 -0
  58. groundx/extract/utility/__init__.py +15 -0
  59. groundx/extract/utility/classes.py +193 -0
  60. groundx/extract/utility/test_utility.py +81 -0
  61. groundx/groups/__init__.py +2 -0
  62. groundx/groups/client.py +63 -550
  63. groundx/groups/raw_client.py +901 -0
  64. groundx/health/__init__.py +2 -0
  65. groundx/health/client.py +35 -101
  66. groundx/health/raw_client.py +193 -0
  67. groundx/ingest.py +771 -0
  68. groundx/search/__init__.py +2 -0
  69. groundx/search/client.py +94 -227
  70. groundx/search/raw_client.py +442 -0
  71. groundx/search/types/__init__.py +2 -0
  72. groundx/types/__init__.py +68 -16
  73. groundx/types/bounding_box_detail.py +4 -4
  74. groundx/types/bucket_detail.py +5 -5
  75. groundx/types/bucket_list_response.py +17 -3
  76. groundx/types/bucket_response.py +3 -3
  77. groundx/types/bucket_update_detail.py +4 -4
  78. groundx/types/bucket_update_response.py +3 -3
  79. groundx/types/customer_detail.py +2 -2
  80. groundx/types/customer_response.py +3 -3
  81. groundx/types/document.py +54 -0
  82. groundx/types/document_detail.py +16 -4
  83. groundx/types/document_list_response.py +4 -4
  84. groundx/types/document_local_ingest_request.py +7 -0
  85. groundx/types/document_lookup_response.py +8 -3
  86. groundx/types/document_response.py +3 -3
  87. groundx/types/document_type.py +21 -1
  88. groundx/types/group_detail.py +4 -4
  89. groundx/types/group_list_response.py +17 -3
  90. groundx/types/group_response.py +3 -3
  91. groundx/types/health_response.py +3 -3
  92. groundx/types/health_response_health.py +3 -3
  93. groundx/types/health_service.py +5 -5
  94. groundx/types/ingest_local_document.py +25 -0
  95. groundx/types/ingest_local_document_metadata.py +51 -0
  96. groundx/types/ingest_remote_document.py +15 -6
  97. groundx/types/ingest_response.py +4 -4
  98. groundx/types/{process_status_response_ingest.py → ingest_status.py} +8 -7
  99. groundx/types/{ingest_response_ingest.py → ingest_status_light.py} +7 -5
  100. groundx/types/ingest_status_progress.py +26 -0
  101. groundx/types/{process_status_response_ingest_progress_errors.py → ingest_status_progress_cancelled.py} +4 -4
  102. groundx/types/{process_status_response_ingest_progress_complete.py → ingest_status_progress_complete.py} +4 -4
  103. groundx/types/{process_status_response_ingest_progress_cancelled.py → ingest_status_progress_errors.py} +4 -4
  104. groundx/types/{process_status_response_ingest_progress_processing.py → ingest_status_progress_processing.py} +4 -4
  105. groundx/types/message_response.py +2 -2
  106. groundx/types/meter_detail.py +2 -2
  107. groundx/types/process_level.py +5 -0
  108. groundx/types/{process_status_response.py → processes_status_response.py} +8 -5
  109. groundx/types/processing_status.py +3 -1
  110. groundx/types/search_response.py +3 -3
  111. groundx/types/search_response_search.py +3 -3
  112. groundx/types/search_result_item.py +7 -5
  113. groundx/types/search_result_item_pages_item.py +41 -0
  114. groundx/types/subscription_detail.py +3 -3
  115. groundx/types/subscription_detail_meters.py +5 -5
  116. groundx/{documents/types/website_crawl_request_websites_item.py → types/website_source.py} +7 -7
  117. groundx/types/workflow_apply_request.py +24 -0
  118. groundx/types/workflow_detail.py +59 -0
  119. groundx/types/workflow_detail_chunk_strategy.py +5 -0
  120. groundx/types/workflow_detail_relationships.py +36 -0
  121. groundx/types/workflow_engine.py +58 -0
  122. groundx/types/workflow_engine_reasoning_effort.py +5 -0
  123. groundx/types/workflow_engine_service.py +7 -0
  124. groundx/types/workflow_prompt.py +37 -0
  125. groundx/types/workflow_prompt_group.py +25 -0
  126. groundx/types/workflow_prompt_role.py +5 -0
  127. groundx/types/workflow_request.py +31 -0
  128. groundx/types/workflow_request_chunk_strategy.py +5 -0
  129. groundx/types/workflow_response.py +20 -0
  130. groundx/types/workflow_step.py +33 -0
  131. groundx/types/workflow_step_config.py +33 -0
  132. groundx/types/workflow_step_config_field.py +8 -0
  133. groundx/types/workflow_steps.py +38 -0
  134. groundx/types/workflows_response.py +20 -0
  135. groundx/workflows/__init__.py +7 -0
  136. groundx/workflows/client.py +736 -0
  137. groundx/workflows/raw_client.py +841 -0
  138. groundx/workflows/types/__init__.py +7 -0
  139. groundx/workflows/types/workflows_get_request_id.py +5 -0
  140. {groundx-2.0.15.dist-info → groundx-2.7.7.dist-info}/LICENSE +1 -1
  141. {groundx-2.0.15.dist-info → groundx-2.7.7.dist-info}/METADATA +39 -22
  142. groundx-2.7.7.dist-info/RECORD +155 -0
  143. groundx/documents/types/__init__.py +0 -6
  144. groundx/documents/types/documents_ingest_local_request_files_item.py +0 -43
  145. groundx/types/process_status_response_ingest_progress.py +0 -26
  146. groundx-2.0.15.dist-info/RECORD +0 -82
  147. {groundx-2.0.15.dist-info → groundx-2.7.7.dist-info}/WHEEL +0 -0
@@ -0,0 +1,512 @@
1
+ import typing, os, unittest
2
+
3
+ from .settings import (
4
+ AgentSettings,
5
+ ContainerSettings,
6
+ ContainerUploadSettings,
7
+ GroundXSettings,
8
+ AWS_REGION,
9
+ CALLBACK_KEY,
10
+ GX_AGENT_KEY,
11
+ GX_API_KEY,
12
+ GX_KEY,
13
+ GX_REGION,
14
+ GX_SECRET,
15
+ VALID_KEYS,
16
+ )
17
+
18
+
19
+ AWS_KEY: str = "AWS_ACCESS_KEY_ID"
20
+ AWS_SECRET: str = "AWS_SECRET_ACCESS_KEY"
21
+ AWS_TOKEN: str = "AWS_SESSION_TOKEN"
22
+
23
+
24
+ def clearEnv() -> None:
25
+ os.environ.clear()
26
+
27
+
28
+ class TestAgentSettings(unittest.TestCase):
29
+ def test(self) -> None:
30
+ tsts: typing.List[typing.Dict[str, typing.Any]] = [
31
+ {
32
+ "expect": {
33
+ "api_base": None,
34
+ "api_key": Exception,
35
+ "max_steps": 7,
36
+ "model_id": "gpt-5-mini",
37
+ },
38
+ },
39
+ {
40
+ "api_base": "http://test.com",
41
+ "api_key": "mykey",
42
+ "api_key_env_val": "val",
43
+ "max_steps": 4,
44
+ "model_id": "gpt-5",
45
+ "expect": {
46
+ "api_base": "http://test.com",
47
+ "api_key": "mykey",
48
+ "max_steps": 4,
49
+ "model_id": "gpt-5",
50
+ },
51
+ },
52
+ {
53
+ "api_key_env_val": "val",
54
+ "expect": {
55
+ "api_base": None,
56
+ "api_key": "val",
57
+ "max_steps": 7,
58
+ "model_id": "gpt-5-mini",
59
+ },
60
+ },
61
+ ]
62
+
63
+ for _, tst in enumerate(tsts):
64
+ clearEnv()
65
+
66
+ input: typing.Dict[str, typing.Any] = {}
67
+ if "api_base" in tst:
68
+ input["api_base"] = tst["api_base"]
69
+ if "api_key" in tst:
70
+ input["api_key"] = tst["api_key"]
71
+ if "api_key_env_val" in tst:
72
+ os.environ.update({GX_AGENT_KEY: tst["api_key_env_val"]})
73
+ if "max_steps" in tst:
74
+ input["max_steps"] = tst["max_steps"]
75
+ if "model_id" in tst:
76
+ input["model_id"] = tst["model_id"]
77
+
78
+ settings = AgentSettings(**input)
79
+
80
+ self.assertIsInstance(settings, AgentSettings)
81
+
82
+ self.assertEqual(settings.api_base, tst["expect"]["api_base"])
83
+
84
+ if tst["expect"]["api_key"] == Exception:
85
+ self.assertRaises(Exception, settings.get_api_key)
86
+ else:
87
+ self.assertEqual(settings.get_api_key(), tst["expect"]["api_key"])
88
+
89
+ self.assertEqual(settings.max_steps, tst["expect"]["max_steps"])
90
+
91
+ self.assertEqual(settings.model_id, tst["expect"]["model_id"])
92
+
93
+
94
+ class TestContainerUploadSettings(unittest.TestCase):
95
+ def test(self) -> None:
96
+ tsts: typing.List[typing.Dict[str, typing.Any]] = [
97
+ {
98
+ "base_domain": "https://base.com",
99
+ "bucket": "test-bucket",
100
+ "type": "s3",
101
+ "url": "https://test.com",
102
+ "aws_key_env_val": "valk",
103
+ "aws_region_env_val": "vale",
104
+ "aws_secret_env_val": "vals",
105
+ "expect": {
106
+ "base_domain": "https://base.com",
107
+ "base_path": "layout/processed/",
108
+ "bucket": "test-bucket",
109
+ "ssl": False,
110
+ "type": "s3",
111
+ "url": "https://test.com",
112
+ "key": None,
113
+ "region": "vale",
114
+ "secret": None,
115
+ },
116
+ },
117
+ {
118
+ "base_domain": "https://base.com",
119
+ "bucket": "test-bucket",
120
+ "type": "s3",
121
+ "url": "https://test.com",
122
+ "expect": {
123
+ "base_domain": "https://base.com",
124
+ "base_path": "layout/processed/",
125
+ "bucket": "test-bucket",
126
+ "ssl": False,
127
+ "type": "s3",
128
+ "url": "https://test.com",
129
+ "key": None,
130
+ "region": None,
131
+ "secret": None,
132
+ },
133
+ },
134
+ {
135
+ "base_domain": "https://base.com",
136
+ "base_path": "layout/",
137
+ "bucket": "test-bucket",
138
+ "ssl": True,
139
+ "type": "s3",
140
+ "url": "https://test.com",
141
+ "key": "mykey",
142
+ "gx_key_env_val": "valk",
143
+ "region": "myregion",
144
+ "gx_region_env_val": "vale",
145
+ "secret": "mysecret",
146
+ "gx_secret_env_val": "vals",
147
+ "expect": {
148
+ "base_domain": "https://base.com",
149
+ "base_path": "layout/",
150
+ "bucket": "test-bucket",
151
+ "ssl": True,
152
+ "type": "s3",
153
+ "url": "https://test.com",
154
+ "key": "mykey",
155
+ "region": "myregion",
156
+ "secret": "mysecret",
157
+ },
158
+ },
159
+ {
160
+ "base_domain": "https://base.com",
161
+ "bucket": "test-bucket",
162
+ "type": "s3",
163
+ "url": "https://test.com",
164
+ "gx_key_env_val": "valk",
165
+ "gx_region_env_val": "vale",
166
+ "gx_secret_env_val": "vals",
167
+ "expect": {
168
+ "base_domain": "https://base.com",
169
+ "base_path": "layout/processed/",
170
+ "bucket": "test-bucket",
171
+ "ssl": False,
172
+ "type": "s3",
173
+ "url": "https://test.com",
174
+ "key": "valk",
175
+ "region": "vale",
176
+ "secret": "vals",
177
+ },
178
+ },
179
+ {
180
+ "base_domain": "https://base.com",
181
+ "bucket": "test-bucket",
182
+ "type": "s3",
183
+ "url": "https://test.com",
184
+ "gx_key_env_val": "valk",
185
+ "gx_region_env_val": "vale",
186
+ "gx_secret_env_val": "vals",
187
+ "expect": {
188
+ "base_domain": "https://base.com",
189
+ "base_path": "layout/processed/",
190
+ "bucket": "test-bucket",
191
+ "ssl": False,
192
+ "type": "s3",
193
+ "url": "https://test.com",
194
+ "key": "valk",
195
+ "region": "vale",
196
+ "secret": "vals",
197
+ },
198
+ },
199
+ ]
200
+
201
+ for _, tst in enumerate(tsts):
202
+ clearEnv()
203
+
204
+ input: typing.Dict[str, typing.Any] = {}
205
+ if "base_domain" in tst:
206
+ input["base_domain"] = tst["base_domain"]
207
+ if "base_path" in tst:
208
+ input["base_path"] = tst["base_path"]
209
+ if "bucket" in tst:
210
+ input["bucket"] = tst["bucket"]
211
+ if "ssl" in tst:
212
+ input["ssl"] = tst["ssl"]
213
+ if "type" in tst:
214
+ input["type"] = tst["type"]
215
+ if "url" in tst:
216
+ input["url"] = tst["url"]
217
+ if "key" in tst:
218
+ input["key"] = tst["key"]
219
+ if "gx_key_env_val" in tst:
220
+ os.environ.update({GX_KEY: tst["gx_key_env_val"]})
221
+ if "aws_key_env_val" in tst:
222
+ os.environ.update({AWS_KEY: tst["aws_key_env_val"]})
223
+ if "region" in tst:
224
+ input["region"] = tst["region"]
225
+ if "gx_region_env_val" in tst:
226
+ os.environ.update({GX_REGION: tst["gx_region_env_val"]})
227
+ if "aws_region_env_val" in tst:
228
+ os.environ.update({AWS_REGION: tst["aws_region_env_val"]})
229
+ if "secret" in tst:
230
+ input["secret"] = tst["secret"]
231
+ if "gx_secret_env_val" in tst:
232
+ os.environ.update({GX_SECRET: tst["gx_secret_env_val"]})
233
+ if "aws_secret_env_val" in tst:
234
+ os.environ.update({AWS_SECRET: tst["aws_secret_env_val"]})
235
+
236
+ settings = ContainerUploadSettings(**input)
237
+
238
+ self.assertIsInstance(settings, ContainerUploadSettings)
239
+
240
+ self.assertEqual(settings.base_domain, tst["expect"]["base_domain"])
241
+
242
+ self.assertEqual(settings.base_path, tst["expect"]["base_path"])
243
+
244
+ self.assertEqual(settings.bucket, tst["expect"]["bucket"])
245
+
246
+ self.assertEqual(settings.ssl, tst["expect"]["ssl"])
247
+
248
+ self.assertEqual(settings.type, tst["expect"]["type"])
249
+
250
+ self.assertEqual(settings.url, tst["expect"]["url"])
251
+
252
+ if tst["expect"]["key"] == None:
253
+ self.assertIsNone(settings.get_key())
254
+ else:
255
+ self.assertEqual(settings.get_key(), tst["expect"]["key"])
256
+
257
+ if tst["expect"]["region"] == None:
258
+ self.assertIsNone(settings.get_region())
259
+ else:
260
+ self.assertEqual(settings.get_region(), tst["expect"]["region"])
261
+
262
+ if tst["expect"]["secret"] == None:
263
+ self.assertIsNone(settings.get_secret())
264
+ else:
265
+ self.assertEqual(settings.get_secret(), tst["expect"]["secret"])
266
+
267
+
268
+ class TestContainerSettings(unittest.TestCase):
269
+ def test(self) -> None:
270
+ tsts: typing.List[typing.Dict[str, typing.Any]] = [
271
+ {
272
+ "broker": "mybroker",
273
+ "service": "myservice",
274
+ "workers": 1,
275
+ "upload": {
276
+ "base_domain": "https://base.com",
277
+ "bucket": "test-bucket",
278
+ "type": "s3",
279
+ "url": "https://test.com",
280
+ },
281
+ "expect": {
282
+ "broker": "mybroker",
283
+ "cache_to": 300,
284
+ "google_sheets_drive_id": None,
285
+ "google_sheets_template_id": None,
286
+ "log_level": "info",
287
+ "metrics_broker": None,
288
+ "refresh_to": 60,
289
+ "service": "myservice",
290
+ "task_to": 600,
291
+ "workers": 1,
292
+ "callback_api_key": Exception,
293
+ "valid_api_keys": Exception,
294
+ "loglevel": "INFO",
295
+ "status_broker": "mybroker",
296
+ },
297
+ },
298
+ {
299
+ "broker": "mybroker",
300
+ "cache_to": 100,
301
+ "google_sheets_drive_id": "drive_id",
302
+ "google_sheets_template_id": "template_id",
303
+ "log_level": "error",
304
+ "metrics_broker": "mymetrics",
305
+ "refresh_to": 30,
306
+ "service": "myservice",
307
+ "task_to": 300,
308
+ "workers": 1,
309
+ "upload": {
310
+ "base_domain": "https://base.com",
311
+ "bucket": "test-bucket",
312
+ "type": "s3",
313
+ "url": "https://test.com",
314
+ },
315
+ "callback_api_key": "cbkey",
316
+ "callback_api_key_env_val": "vale",
317
+ "valid_api_keys": ["vkeys"],
318
+ "valid_api_keys_env_val": '["valv"]',
319
+ "expect": {
320
+ "broker": "mybroker",
321
+ "cache_to": 100,
322
+ "google_sheets_drive_id": "drive_id",
323
+ "google_sheets_template_id": "template_id",
324
+ "log_level": "error",
325
+ "metrics_broker": "mymetrics",
326
+ "refresh_to": 30,
327
+ "service": "myservice",
328
+ "task_to": 300,
329
+ "workers": 1,
330
+ "callback_api_key": "cbkey",
331
+ "valid_api_keys": ["vkeys"],
332
+ "loglevel": "ERROR",
333
+ "status_broker": "mymetrics",
334
+ },
335
+ },
336
+ {
337
+ "broker": "mybroker",
338
+ "service": "myservice",
339
+ "workers": 1,
340
+ "upload": {
341
+ "base_domain": "https://base.com",
342
+ "bucket": "test-bucket",
343
+ "type": "s3",
344
+ "url": "https://test.com",
345
+ },
346
+ "callback_api_key_env_val": "vale",
347
+ "valid_api_keys_env_val": '["valv"]',
348
+ "expect": {
349
+ "broker": "mybroker",
350
+ "cache_to": 300,
351
+ "google_sheets_drive_id": None,
352
+ "google_sheets_template_id": None,
353
+ "log_level": "info",
354
+ "metrics_broker": None,
355
+ "refresh_to": 60,
356
+ "service": "myservice",
357
+ "task_to": 600,
358
+ "workers": 1,
359
+ "callback_api_key": "vale",
360
+ "valid_api_keys": ["valv"],
361
+ "loglevel": "INFO",
362
+ "status_broker": "mybroker",
363
+ },
364
+ },
365
+ ]
366
+
367
+ for _, tst in enumerate(tsts):
368
+ clearEnv()
369
+
370
+ input: typing.Dict[str, typing.Any] = {}
371
+ if "broker" in tst:
372
+ input["broker"] = tst["broker"]
373
+ if "cache_to" in tst:
374
+ input["cache_to"] = tst["cache_to"]
375
+ if "google_sheets_drive_id" in tst:
376
+ input["google_sheets_drive_id"] = tst["google_sheets_drive_id"]
377
+ if "google_sheets_template_id" in tst:
378
+ input["google_sheets_template_id"] = tst["google_sheets_template_id"]
379
+ if "log_level" in tst:
380
+ input["log_level"] = tst["log_level"]
381
+ if "metrics_broker" in tst:
382
+ input["metrics_broker"] = tst["metrics_broker"]
383
+ if "refresh_to" in tst:
384
+ input["refresh_to"] = tst["refresh_to"]
385
+ if "service" in tst:
386
+ input["service"] = tst["service"]
387
+ if "task_to" in tst:
388
+ input["task_to"] = tst["task_to"]
389
+ if "upload" in tst:
390
+ input["upload"] = tst["upload"]
391
+ if "workers" in tst:
392
+ input["workers"] = tst["workers"]
393
+ if "callback_api_key" in tst:
394
+ input["callback_api_key"] = tst["callback_api_key"]
395
+ if "callback_api_key_env_val" in tst:
396
+ os.environ.update({CALLBACK_KEY: tst["callback_api_key_env_val"]})
397
+ if "valid_api_keys" in tst:
398
+ input["valid_api_keys"] = tst["valid_api_keys"]
399
+ if "valid_api_keys_env_val" in tst:
400
+ os.environ.update({VALID_KEYS: tst["valid_api_keys_env_val"]})
401
+
402
+ settings = ContainerSettings(**input)
403
+
404
+ self.assertIsInstance(settings, ContainerSettings)
405
+
406
+ self.assertEqual(settings.broker, tst["expect"]["broker"])
407
+
408
+ self.assertEqual(settings.cache_to, tst["expect"]["cache_to"])
409
+
410
+ self.assertEqual(
411
+ settings.google_sheets_drive_id, tst["expect"]["google_sheets_drive_id"]
412
+ )
413
+
414
+ self.assertEqual(
415
+ settings.google_sheets_template_id,
416
+ tst["expect"]["google_sheets_template_id"],
417
+ )
418
+
419
+ self.assertEqual(settings.log_level, tst["expect"]["log_level"])
420
+
421
+ self.assertEqual(settings.metrics_broker, tst["expect"]["metrics_broker"])
422
+
423
+ self.assertEqual(settings.refresh_to, tst["expect"]["refresh_to"])
424
+
425
+ self.assertEqual(settings.service, tst["expect"]["service"])
426
+
427
+ self.assertEqual(settings.task_to, tst["expect"]["task_to"])
428
+
429
+ self.assertEqual(settings.workers, tst["expect"]["workers"])
430
+
431
+ if tst["expect"]["callback_api_key"] == Exception:
432
+ self.assertRaises(Exception, settings.get_callback_api_key)
433
+ else:
434
+ self.assertEqual(
435
+ settings.get_callback_api_key(), tst["expect"]["callback_api_key"]
436
+ )
437
+
438
+ if tst["expect"]["valid_api_keys"] == Exception:
439
+ self.assertRaises(Exception, settings.get_valid_api_keys)
440
+ else:
441
+ self.assertEqual(
442
+ settings.get_valid_api_keys(), tst["expect"]["valid_api_keys"]
443
+ )
444
+
445
+ self.assertEqual(settings.loglevel(), tst["expect"]["loglevel"])
446
+
447
+ self.assertEqual(settings.status_broker(), tst["expect"]["status_broker"])
448
+
449
+
450
+ class TestGroundXSettings(unittest.TestCase):
451
+ def test(self) -> None:
452
+ tsts: typing.List[typing.Dict[str, typing.Any]] = [
453
+ {
454
+ "expect": {
455
+ "api_key": Exception,
456
+ "base_url": None,
457
+ "upload_url": "https://upload.eyelevel.ai",
458
+ },
459
+ },
460
+ {
461
+ "api_key": "mykey",
462
+ "api_key_env_val": "val",
463
+ "base_url": "http://api.example.com",
464
+ "upload_url": "http://upload.example.com",
465
+ "expect": {
466
+ "api_key": "mykey",
467
+ "base_url": "http://api.example.com",
468
+ "upload_url": "http://upload.example.com",
469
+ },
470
+ },
471
+ {
472
+ "api_key_env_val": "val",
473
+ "expect": {
474
+ "api_key": "val",
475
+ "base_url": None,
476
+ "upload_url": "https://upload.eyelevel.ai",
477
+ },
478
+ },
479
+ ]
480
+
481
+ for _, tst in enumerate(tsts):
482
+ clearEnv()
483
+
484
+ input: typing.Dict[str, str] = {}
485
+ if "api_key" in tst:
486
+ input["api_key"] = tst["api_key"]
487
+ if "api_key_env_val" in tst:
488
+ os.environ.update({GX_API_KEY: tst["api_key_env_val"]})
489
+ if "base_url" in tst:
490
+ input["base_url"] = tst["base_url"]
491
+ if "upload_url" in tst:
492
+ input["upload_url"] = tst["upload_url"]
493
+
494
+ settings = GroundXSettings(**input)
495
+
496
+ self.assertIsInstance(settings, GroundXSettings)
497
+
498
+ if tst["expect"]["api_key"] == Exception:
499
+ self.assertRaises(Exception, settings.get_api_key)
500
+ else:
501
+ self.assertEqual(settings.get_api_key(), tst["expect"]["api_key"])
502
+
503
+ if tst["expect"]["base_url"]:
504
+ self.assertEqual(settings.base_url, tst["expect"]["base_url"])
505
+ else:
506
+ self.assertIsNone(settings.base_url)
507
+
508
+ self.assertEqual(settings.upload_url, tst["expect"]["upload_url"])
509
+
510
+
511
+ if __name__ == "__main__":
512
+ unittest.main()
@@ -0,0 +1,6 @@
1
+ from .utility import error_response, success_response
2
+
3
+ __all__ = [
4
+ "error_response",
5
+ "success_response",
6
+ ]
@@ -0,0 +1,27 @@
1
+ import typing
2
+
3
+ from ..classes.api import ErrorResponse
4
+ from ..classes.document import DocumentRequest
5
+ from ..classes.groundx import GroundXResponse
6
+
7
+
8
+ def error_response(req: DocumentRequest, msg: str) -> typing.Dict[str, typing.Any]:
9
+ return ErrorResponse(
10
+ code=500,
11
+ documentID=req.document_id,
12
+ message=msg,
13
+ taskID=req.task_id,
14
+ ).model_dump(by_alias=True)
15
+
16
+
17
+ def success_response(
18
+ req: DocumentRequest, result_url: str
19
+ ) -> typing.Dict[str, typing.Any]:
20
+ return GroundXResponse(
21
+ code=200,
22
+ documentID=req.document_id,
23
+ modelID=req.model_id,
24
+ processorID=req.processor_id,
25
+ resultURL=result_url,
26
+ taskID=req.task_id,
27
+ ).model_dump(by_alias=True)
@@ -0,0 +1,15 @@
1
+ from .classes import (
2
+ class_fields,
3
+ clean_json,
4
+ coerce_numeric_string,
5
+ from_attr_name,
6
+ from_key,
7
+ )
8
+
9
+ __all__ = [
10
+ "class_fields",
11
+ "clean_json",
12
+ "coerce_numeric_string",
13
+ "from_attr_name",
14
+ "from_key",
15
+ ]