pygeai 0.6.0b6__py3-none-any.whl → 0.6.0b10__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 (227) hide show
  1. pygeai/_docs/source/conf.py +78 -6
  2. pygeai/_docs/source/content/api_reference/admin.rst +161 -0
  3. pygeai/_docs/source/content/api_reference/assistant.rst +326 -0
  4. pygeai/_docs/source/content/api_reference/auth.rst +379 -0
  5. pygeai/_docs/source/content/api_reference/embeddings.rst +31 -1
  6. pygeai/_docs/source/content/api_reference/evaluation.rst +590 -0
  7. pygeai/_docs/source/content/api_reference/feedback.rst +237 -0
  8. pygeai/_docs/source/content/api_reference/files.rst +592 -0
  9. pygeai/_docs/source/content/api_reference/gam.rst +401 -0
  10. pygeai/_docs/source/content/api_reference/health.rst +58 -0
  11. pygeai/_docs/source/content/api_reference/project.rst +20 -18
  12. pygeai/_docs/source/content/api_reference/proxy.rst +318 -0
  13. pygeai/_docs/source/content/api_reference/rerank.rst +94 -0
  14. pygeai/_docs/source/content/api_reference/secrets.rst +495 -0
  15. pygeai/_docs/source/content/api_reference/usage_limits.rst +390 -0
  16. pygeai/_docs/source/content/api_reference.rst +13 -1
  17. pygeai/_docs/source/content/debugger.rst +376 -83
  18. pygeai/_docs/source/content/migration.rst +528 -0
  19. pygeai/_docs/source/content/modules.rst +1 -1
  20. pygeai/_docs/source/index.rst +59 -7
  21. pygeai/_docs/source/pygeai.auth.rst +29 -0
  22. pygeai/_docs/source/pygeai.cli.commands.rst +16 -0
  23. pygeai/_docs/source/pygeai.cli.rst +8 -0
  24. pygeai/_docs/source/pygeai.core.utils.rst +16 -0
  25. pygeai/_docs/source/pygeai.rst +1 -0
  26. pygeai/_docs/source/pygeai.tests.auth.rst +21 -0
  27. pygeai/_docs/source/pygeai.tests.cli.commands.rst +16 -0
  28. pygeai/_docs/source/pygeai.tests.cli.rst +16 -0
  29. pygeai/_docs/source/pygeai.tests.core.base.rst +8 -0
  30. pygeai/_docs/source/pygeai.tests.core.embeddings.rst +16 -0
  31. pygeai/_docs/source/pygeai.tests.core.files.rst +8 -0
  32. pygeai/_docs/source/pygeai.tests.core.plugins.rst +21 -0
  33. pygeai/_docs/source/pygeai.tests.core.rst +1 -0
  34. pygeai/_docs/source/pygeai.tests.evaluation.dataset.rst +21 -0
  35. pygeai/_docs/source/pygeai.tests.evaluation.plan.rst +21 -0
  36. pygeai/_docs/source/pygeai.tests.evaluation.result.rst +21 -0
  37. pygeai/_docs/source/pygeai.tests.evaluation.rst +20 -0
  38. pygeai/_docs/source/pygeai.tests.integration.lab.processes.rst +8 -0
  39. pygeai/_docs/source/pygeai.tests.organization.rst +8 -0
  40. pygeai/_docs/source/pygeai.tests.rst +2 -0
  41. pygeai/_docs/source/pygeai.tests.snippets.auth.rst +10 -0
  42. pygeai/_docs/source/pygeai.tests.snippets.chat.rst +40 -0
  43. pygeai/_docs/source/pygeai.tests.snippets.dbg.rst +45 -0
  44. pygeai/_docs/source/pygeai.tests.snippets.embeddings.rst +40 -0
  45. pygeai/_docs/source/pygeai.tests.snippets.evaluation.dataset.rst +197 -0
  46. pygeai/_docs/source/pygeai.tests.snippets.evaluation.plan.rst +133 -0
  47. pygeai/_docs/source/pygeai.tests.snippets.evaluation.result.rst +37 -0
  48. pygeai/_docs/source/pygeai.tests.snippets.evaluation.rst +10 -0
  49. pygeai/_docs/source/pygeai.tests.snippets.organization.rst +40 -0
  50. pygeai/_docs/source/pygeai.tests.snippets.rst +2 -0
  51. pygeai/admin/clients.py +12 -32
  52. pygeai/assistant/clients.py +16 -44
  53. pygeai/assistant/data/clients.py +1 -0
  54. pygeai/assistant/data_analyst/clients.py +6 -13
  55. pygeai/assistant/rag/clients.py +24 -67
  56. pygeai/auth/clients.py +88 -14
  57. pygeai/auth/endpoints.py +4 -0
  58. pygeai/chat/clients.py +192 -25
  59. pygeai/chat/endpoints.py +2 -1
  60. pygeai/cli/commands/auth.py +178 -2
  61. pygeai/cli/commands/chat.py +227 -1
  62. pygeai/cli/commands/embeddings.py +56 -8
  63. pygeai/cli/commands/lab/ai_lab.py +0 -2
  64. pygeai/cli/commands/migrate.py +994 -434
  65. pygeai/cli/commands/organization.py +241 -0
  66. pygeai/cli/error_handler.py +116 -0
  67. pygeai/cli/geai.py +28 -10
  68. pygeai/cli/parsers.py +8 -2
  69. pygeai/core/base/clients.py +4 -1
  70. pygeai/core/common/exceptions.py +11 -10
  71. pygeai/core/embeddings/__init__.py +19 -0
  72. pygeai/core/embeddings/clients.py +20 -9
  73. pygeai/core/embeddings/mappers.py +16 -2
  74. pygeai/core/embeddings/responses.py +9 -2
  75. pygeai/core/feedback/clients.py +4 -8
  76. pygeai/core/files/clients.py +10 -25
  77. pygeai/core/files/managers.py +42 -0
  78. pygeai/core/llm/clients.py +11 -26
  79. pygeai/core/models.py +107 -0
  80. pygeai/core/plugins/clients.py +4 -7
  81. pygeai/core/rerank/clients.py +4 -8
  82. pygeai/core/secrets/clients.py +14 -37
  83. pygeai/core/services/rest.py +1 -1
  84. pygeai/core/utils/parsers.py +32 -0
  85. pygeai/core/utils/validators.py +10 -0
  86. pygeai/dbg/__init__.py +3 -0
  87. pygeai/dbg/debugger.py +565 -70
  88. pygeai/evaluation/clients.py +2 -1
  89. pygeai/evaluation/dataset/clients.py +46 -44
  90. pygeai/evaluation/plan/clients.py +28 -26
  91. pygeai/evaluation/result/clients.py +38 -5
  92. pygeai/gam/clients.py +10 -25
  93. pygeai/health/clients.py +4 -7
  94. pygeai/lab/agents/clients.py +21 -54
  95. pygeai/lab/agents/endpoints.py +2 -0
  96. pygeai/lab/clients.py +1 -0
  97. pygeai/lab/models.py +3 -3
  98. pygeai/lab/processes/clients.py +45 -127
  99. pygeai/lab/strategies/clients.py +11 -25
  100. pygeai/lab/tools/clients.py +23 -67
  101. pygeai/lab/tools/endpoints.py +3 -0
  102. pygeai/migration/__init__.py +31 -0
  103. pygeai/migration/strategies.py +404 -155
  104. pygeai/migration/tools.py +170 -3
  105. pygeai/organization/clients.py +135 -51
  106. pygeai/organization/endpoints.py +6 -1
  107. pygeai/organization/limits/clients.py +32 -91
  108. pygeai/organization/managers.py +157 -1
  109. pygeai/organization/mappers.py +76 -2
  110. pygeai/organization/responses.py +25 -1
  111. pygeai/proxy/clients.py +4 -1
  112. pygeai/tests/admin/test_clients.py +16 -11
  113. pygeai/tests/assistants/rag/test_clients.py +35 -23
  114. pygeai/tests/assistants/test_clients.py +22 -15
  115. pygeai/tests/auth/test_clients.py +191 -7
  116. pygeai/tests/chat/test_clients.py +211 -1
  117. pygeai/tests/cli/commands/test_embeddings.py +32 -9
  118. pygeai/tests/cli/commands/test_evaluation.py +7 -0
  119. pygeai/tests/cli/commands/test_migrate.py +112 -243
  120. pygeai/tests/cli/test_error_handler.py +225 -0
  121. pygeai/tests/cli/test_geai_driver.py +154 -0
  122. pygeai/tests/cli/test_parsers.py +5 -5
  123. pygeai/tests/core/embeddings/test_clients.py +144 -0
  124. pygeai/tests/core/embeddings/test_managers.py +171 -0
  125. pygeai/tests/core/embeddings/test_mappers.py +142 -0
  126. pygeai/tests/core/feedback/test_clients.py +2 -0
  127. pygeai/tests/core/files/test_clients.py +1 -0
  128. pygeai/tests/core/llm/test_clients.py +14 -9
  129. pygeai/tests/core/plugins/test_clients.py +5 -3
  130. pygeai/tests/core/rerank/test_clients.py +1 -0
  131. pygeai/tests/core/secrets/test_clients.py +19 -13
  132. pygeai/tests/dbg/test_debugger.py +453 -75
  133. pygeai/tests/evaluation/dataset/test_clients.py +3 -1
  134. pygeai/tests/evaluation/plan/test_clients.py +4 -2
  135. pygeai/tests/evaluation/result/test_clients.py +7 -5
  136. pygeai/tests/gam/test_clients.py +1 -1
  137. pygeai/tests/health/test_clients.py +1 -0
  138. pygeai/tests/lab/agents/test_clients.py +9 -0
  139. pygeai/tests/lab/processes/test_clients.py +36 -0
  140. pygeai/tests/lab/processes/test_mappers.py +3 -0
  141. pygeai/tests/lab/strategies/test_clients.py +14 -9
  142. pygeai/tests/migration/test_strategies.py +45 -218
  143. pygeai/tests/migration/test_tools.py +133 -9
  144. pygeai/tests/organization/limits/test_clients.py +17 -0
  145. pygeai/tests/organization/test_clients.py +206 -1
  146. pygeai/tests/organization/test_managers.py +122 -1
  147. pygeai/tests/proxy/test_clients.py +2 -0
  148. pygeai/tests/proxy/test_integration.py +1 -0
  149. pygeai/tests/snippets/auth/__init__.py +0 -0
  150. pygeai/tests/snippets/chat/chat_completion_with_reasoning_effort.py +18 -0
  151. pygeai/tests/snippets/chat/get_response.py +15 -0
  152. pygeai/tests/snippets/chat/get_response_streaming.py +20 -0
  153. pygeai/tests/snippets/chat/get_response_with_files.py +16 -0
  154. pygeai/tests/snippets/chat/get_response_with_tools.py +36 -0
  155. pygeai/tests/snippets/dbg/__init__.py +0 -0
  156. pygeai/tests/snippets/dbg/basic_debugging.py +32 -0
  157. pygeai/tests/snippets/dbg/breakpoint_management.py +48 -0
  158. pygeai/tests/snippets/dbg/stack_navigation.py +45 -0
  159. pygeai/tests/snippets/dbg/stepping_example.py +40 -0
  160. pygeai/tests/snippets/embeddings/cache_example.py +31 -0
  161. pygeai/tests/snippets/embeddings/cohere_example.py +41 -0
  162. pygeai/tests/snippets/embeddings/openai_base64_example.py +27 -0
  163. pygeai/tests/snippets/embeddings/openai_example.py +30 -0
  164. pygeai/tests/snippets/embeddings/similarity_example.py +42 -0
  165. pygeai/tests/snippets/evaluation/dataset/__init__.py +0 -0
  166. pygeai/tests/snippets/evaluation/dataset/complete_workflow_example.py +195 -0
  167. pygeai/tests/snippets/evaluation/dataset/create_dataset.py +26 -0
  168. pygeai/tests/snippets/evaluation/dataset/create_dataset_from_file.py +11 -0
  169. pygeai/tests/snippets/evaluation/dataset/create_dataset_row.py +17 -0
  170. pygeai/tests/snippets/evaluation/dataset/create_expected_source.py +18 -0
  171. pygeai/tests/snippets/evaluation/dataset/create_filter_variable.py +19 -0
  172. pygeai/tests/snippets/evaluation/dataset/delete_dataset.py +9 -0
  173. pygeai/tests/snippets/evaluation/dataset/delete_dataset_row.py +10 -0
  174. pygeai/tests/snippets/evaluation/dataset/delete_expected_source.py +15 -0
  175. pygeai/tests/snippets/evaluation/dataset/delete_filter_variable.py +15 -0
  176. pygeai/tests/snippets/evaluation/dataset/get_dataset.py +9 -0
  177. pygeai/tests/snippets/evaluation/dataset/get_dataset_row.py +10 -0
  178. pygeai/tests/snippets/evaluation/dataset/get_expected_source.py +15 -0
  179. pygeai/tests/snippets/evaluation/dataset/get_filter_variable.py +15 -0
  180. pygeai/tests/snippets/evaluation/dataset/list_dataset_rows.py +9 -0
  181. pygeai/tests/snippets/evaluation/dataset/list_datasets.py +6 -0
  182. pygeai/tests/snippets/evaluation/dataset/list_expected_sources.py +10 -0
  183. pygeai/tests/snippets/evaluation/dataset/list_filter_variables.py +10 -0
  184. pygeai/tests/snippets/evaluation/dataset/update_dataset.py +15 -0
  185. pygeai/tests/snippets/evaluation/dataset/update_dataset_row.py +20 -0
  186. pygeai/tests/snippets/evaluation/dataset/update_expected_source.py +18 -0
  187. pygeai/tests/snippets/evaluation/dataset/update_filter_variable.py +19 -0
  188. pygeai/tests/snippets/evaluation/dataset/upload_dataset_rows_file.py +10 -0
  189. pygeai/tests/snippets/evaluation/plan/__init__.py +0 -0
  190. pygeai/tests/snippets/evaluation/plan/add_plan_system_metric.py +13 -0
  191. pygeai/tests/snippets/evaluation/plan/complete_workflow_example.py +136 -0
  192. pygeai/tests/snippets/evaluation/plan/create_evaluation_plan.py +24 -0
  193. pygeai/tests/snippets/evaluation/plan/create_rag_evaluation_plan.py +22 -0
  194. pygeai/tests/snippets/evaluation/plan/delete_evaluation_plan.py +9 -0
  195. pygeai/tests/snippets/evaluation/plan/delete_plan_system_metric.py +13 -0
  196. pygeai/tests/snippets/evaluation/plan/execute_evaluation_plan.py +11 -0
  197. pygeai/tests/snippets/evaluation/plan/get_evaluation_plan.py +9 -0
  198. pygeai/tests/snippets/evaluation/plan/get_plan_system_metric.py +13 -0
  199. pygeai/tests/snippets/evaluation/plan/get_system_metric.py +9 -0
  200. pygeai/tests/snippets/evaluation/plan/list_evaluation_plans.py +7 -0
  201. pygeai/tests/snippets/evaluation/plan/list_plan_system_metrics.py +9 -0
  202. pygeai/tests/snippets/evaluation/plan/list_system_metrics.py +7 -0
  203. pygeai/tests/snippets/evaluation/plan/update_evaluation_plan.py +22 -0
  204. pygeai/tests/snippets/evaluation/plan/update_plan_system_metric.py +14 -0
  205. pygeai/tests/snippets/evaluation/result/__init__.py +0 -0
  206. pygeai/tests/snippets/evaluation/result/complete_workflow_example.py +150 -0
  207. pygeai/tests/snippets/evaluation/result/get_evaluation_result.py +26 -0
  208. pygeai/tests/snippets/evaluation/result/list_evaluation_results.py +17 -0
  209. pygeai/tests/snippets/migrate/__init__.py +45 -0
  210. pygeai/tests/snippets/migrate/agent_migration.py +110 -0
  211. pygeai/tests/snippets/migrate/assistant_migration.py +64 -0
  212. pygeai/tests/snippets/migrate/orchestrator_examples.py +179 -0
  213. pygeai/tests/snippets/migrate/process_migration.py +64 -0
  214. pygeai/tests/snippets/migrate/project_migration.py +42 -0
  215. pygeai/tests/snippets/migrate/tool_migration.py +64 -0
  216. pygeai/tests/snippets/organization/create_project.py +2 -2
  217. pygeai/tests/snippets/organization/get_memberships.py +12 -0
  218. pygeai/tests/snippets/organization/get_organization_members.py +6 -0
  219. pygeai/tests/snippets/organization/get_project_members.py +6 -0
  220. pygeai/tests/snippets/organization/get_project_memberships.py +12 -0
  221. pygeai/tests/snippets/organization/get_project_roles.py +6 -0
  222. {pygeai-0.6.0b6.dist-info → pygeai-0.6.0b10.dist-info}/METADATA +1 -1
  223. {pygeai-0.6.0b6.dist-info → pygeai-0.6.0b10.dist-info}/RECORD +227 -124
  224. {pygeai-0.6.0b6.dist-info → pygeai-0.6.0b10.dist-info}/WHEEL +0 -0
  225. {pygeai-0.6.0b6.dist-info → pygeai-0.6.0b10.dist-info}/entry_points.txt +0 -0
  226. {pygeai-0.6.0b6.dist-info → pygeai-0.6.0b10.dist-info}/licenses/LICENSE +0 -0
  227. {pygeai-0.6.0b6.dist-info → pygeai-0.6.0b10.dist-info}/top_level.txt +0 -0
@@ -2,7 +2,7 @@ import unittest
2
2
  from unittest.mock import patch, MagicMock
3
3
  from json import JSONDecodeError
4
4
  from pygeai.assistant.rag.clients import RAGAssistantClient
5
- from pygeai.core.common.exceptions import InvalidAPIResponseException
5
+ from pygeai.core.common.exceptions import InvalidAPIResponseException, APIResponseError, APIResponseError
6
6
 
7
7
 
8
8
  class TestRAGAssistantClient(unittest.TestCase):
@@ -29,6 +29,7 @@ class TestRAGAssistantClient(unittest.TestCase):
29
29
  def test_get_assistants_from_project_successful_json_response(self):
30
30
  expected_response = {"assistants": []}
31
31
  self.mock_response.json.return_value = expected_response
32
+ self.mock_response.status_code = 200
32
33
  self.client.api_service.get.return_value = self.mock_response
33
34
 
34
35
  result = self.client.get_assistants_from_project()
@@ -42,15 +43,16 @@ class TestRAGAssistantClient(unittest.TestCase):
42
43
  self.mock_response.status_code = 500
43
44
  self.client.api_service.get.return_value = self.mock_response
44
45
 
45
- with self.assertRaises(InvalidAPIResponseException) as context:
46
+ with self.assertRaises(APIResponseError) as context:
46
47
  self.client.get_assistants_from_project()
47
48
 
48
49
  self.client.api_service.get.assert_called_once()
49
- self.assertIn("Unable to get assistants from project", str(context.exception))
50
+ self.assertIn("API returned an error", str(context.exception)) # "Unable to get assistants from project", str(context.exception))
50
51
 
51
52
  def test_get_assistant_data_successful_json_response(self):
52
53
  expected_response = {"name": self.assistant_name, "details": "test"}
53
54
  self.mock_response.json.return_value = expected_response
55
+ self.mock_response.status_code = 200
54
56
  self.client.api_service.get.return_value = self.mock_response
55
57
 
56
58
  result = self.client.get_assistant_data(self.assistant_name)
@@ -64,17 +66,18 @@ class TestRAGAssistantClient(unittest.TestCase):
64
66
  self.mock_response.status_code = 500
65
67
  self.client.api_service.get.return_value = self.mock_response
66
68
 
67
- with self.assertRaises(InvalidAPIResponseException) as context:
69
+ with self.assertRaises(APIResponseError) as context:
68
70
  self.client.get_assistant_data(self.assistant_name)
69
71
 
70
72
  self.client.api_service.get.assert_called_once()
71
- self.assertIn("Unable to get assistant data", str(context.exception))
73
+ self.assertIn("API returned an error", str(context.exception)) # "Unable to get assistant data", str(context.exception))
72
74
 
73
75
  def test_create_assistant_successful_json_response(self):
74
76
  name = "new_assistant"
75
77
  description = "Test description"
76
78
  expected_response = {"id": "new_id", "name": name}
77
79
  self.mock_response.json.return_value = expected_response
80
+ self.mock_response.status_code = 200
78
81
  self.client.api_service.post.return_value = self.mock_response
79
82
 
80
83
  result = self.client.create_assistant(name, description)
@@ -90,17 +93,18 @@ class TestRAGAssistantClient(unittest.TestCase):
90
93
  self.mock_response.status_code = 500
91
94
  self.client.api_service.post.return_value = self.mock_response
92
95
 
93
- with self.assertRaises(InvalidAPIResponseException) as context:
96
+ with self.assertRaises(APIResponseError) as context:
94
97
  self.client.create_assistant(name, description)
95
98
 
96
99
  self.client.api_service.post.assert_called_once()
97
- self.assertIn("Unable to create assistant", str(context.exception))
100
+ self.assertIn("API returned an error", str(context.exception)) # "Unable to create assistant", str(context.exception))
98
101
 
99
102
  def test_update_assistant_successful_json_response(self):
100
103
  name = "test_assistant"
101
104
  status = 1
102
105
  expected_response = {"name": name, "status": status}
103
106
  self.mock_response.json.return_value = expected_response
107
+ self.mock_response.status_code = 200
104
108
  self.client.api_service.put.return_value = self.mock_response
105
109
 
106
110
  result = self.client.update_assistant(name, status)
@@ -116,16 +120,17 @@ class TestRAGAssistantClient(unittest.TestCase):
116
120
  self.mock_response.status_code = 500
117
121
  self.client.api_service.put.return_value = self.mock_response
118
122
 
119
- with self.assertRaises(InvalidAPIResponseException) as context:
123
+ with self.assertRaises(APIResponseError) as context:
120
124
  self.client.update_assistant(name, status)
121
125
 
122
126
  self.client.api_service.put.assert_called_once()
123
- self.assertIn("Unable to update assistant", str(context.exception))
127
+ self.assertIn("API returned an error", str(context.exception)) # "Unable to update assistant", str(context.exception))
124
128
 
125
129
  def test_delete_assistant_successful_json_response(self):
126
130
  name = "test_assistant"
127
131
  expected_response = {"message": "Assistant deleted"}
128
132
  self.mock_response.json.return_value = expected_response
133
+ self.mock_response.status_code = 200
129
134
  self.client.api_service.delete.return_value = self.mock_response
130
135
 
131
136
  result = self.client.delete_assistant(name)
@@ -140,11 +145,11 @@ class TestRAGAssistantClient(unittest.TestCase):
140
145
  self.mock_response.status_code = 500
141
146
  self.client.api_service.delete.return_value = self.mock_response
142
147
 
143
- with self.assertRaises(InvalidAPIResponseException) as context:
148
+ with self.assertRaises(APIResponseError) as context:
144
149
  self.client.delete_assistant(name)
145
150
 
146
151
  self.client.api_service.delete.assert_called_once()
147
- self.assertIn("Unable to delete assistant", str(context.exception))
152
+ self.assertIn("API returned an error", str(context.exception)) # "Unable to delete assistant", str(context.exception))
148
153
 
149
154
  def test_get_documents_successful_json_response(self):
150
155
  name = "test_assistant"
@@ -152,6 +157,7 @@ class TestRAGAssistantClient(unittest.TestCase):
152
157
  count = 10
153
158
  expected_response = {"documents": []}
154
159
  self.mock_response.json.return_value = expected_response
160
+ self.mock_response.status_code = 200
155
161
  self.client.api_service.get.return_value = self.mock_response
156
162
 
157
163
  result = self.client.get_documents(name, skip, count)
@@ -168,16 +174,17 @@ class TestRAGAssistantClient(unittest.TestCase):
168
174
  self.mock_response.status_code = 500
169
175
  self.client.api_service.get.return_value = self.mock_response
170
176
 
171
- with self.assertRaises(InvalidAPIResponseException) as context:
177
+ with self.assertRaises(APIResponseError) as context:
172
178
  self.client.get_documents(name, skip, count)
173
179
 
174
180
  self.client.api_service.get.assert_called_once()
175
- self.assertIn("Unable to get documents", str(context.exception))
181
+ self.assertIn("API returned an error", str(context.exception)) # "Unable to get documents", str(context.exception))
176
182
 
177
183
  def test_delete_all_documents_successful_json_response(self):
178
184
  name = "test_assistant"
179
185
  expected_response = {"message": "All documents deleted"}
180
186
  self.mock_response.json.return_value = expected_response
187
+ self.mock_response.status_code = 200
181
188
  self.client.api_service.delete.return_value = self.mock_response
182
189
 
183
190
  result = self.client.delete_all_documents(name)
@@ -192,17 +199,18 @@ class TestRAGAssistantClient(unittest.TestCase):
192
199
  self.mock_response.status_code = 500
193
200
  self.client.api_service.delete.return_value = self.mock_response
194
201
 
195
- with self.assertRaises(InvalidAPIResponseException) as context:
202
+ with self.assertRaises(APIResponseError) as context:
196
203
  self.client.delete_all_documents(name)
197
204
 
198
205
  self.client.api_service.delete.assert_called_once()
199
- self.assertIn("Unable to delete all documents", str(context.exception))
206
+ self.assertIn("API returned an error", str(context.exception)) # "Unable to delete all documents", str(context.exception))
200
207
 
201
208
  def test_retrieve_document_successful_json_response(self):
202
209
  name = "test_assistant"
203
210
  document_id = "doc_123"
204
211
  expected_response = {"id": document_id, "content": "test content"}
205
212
  self.mock_response.json.return_value = expected_response
213
+ self.mock_response.status_code = 200
206
214
  self.client.api_service.get.return_value = self.mock_response
207
215
 
208
216
  result = self.client.retrieve_document(name, document_id)
@@ -218,11 +226,11 @@ class TestRAGAssistantClient(unittest.TestCase):
218
226
  self.mock_response.status_code = 500
219
227
  self.client.api_service.get.return_value = self.mock_response
220
228
 
221
- with self.assertRaises(InvalidAPIResponseException) as context:
229
+ with self.assertRaises(APIResponseError) as context:
222
230
  self.client.retrieve_document(name, document_id)
223
231
 
224
232
  self.client.api_service.get.assert_called_once()
225
- self.assertIn("Unable to retrieve document", str(context.exception))
233
+ self.assertIn("API returned an error", str(context.exception)) # "Unable to retrieve document", str(context.exception))
226
234
 
227
235
  def test_upload_document_binary_successful_json_response(self):
228
236
  name = "test_assistant"
@@ -231,6 +239,7 @@ class TestRAGAssistantClient(unittest.TestCase):
231
239
  content_type = "application/pdf"
232
240
  expected_response = {"id": "uploaded_doc", "status": "success"}
233
241
  self.mock_response.json.return_value = expected_response
242
+ self.mock_response.status_code = 200
234
243
  self.client.api_service.post_file_binary.return_value = self.mock_response
235
244
 
236
245
  with patch('builtins.open', return_value=MagicMock()):
@@ -247,6 +256,7 @@ class TestRAGAssistantClient(unittest.TestCase):
247
256
  metadata = {"key": "value"}
248
257
  expected_response = {"id": "uploaded_doc", "status": "success"}
249
258
  self.mock_response.json.return_value = expected_response
259
+ self.mock_response.status_code = 200
250
260
  self.client.api_service.post_files_multipart.return_value = self.mock_response
251
261
 
252
262
  with patch('builtins.open', return_value=MagicMock()), \
@@ -277,17 +287,18 @@ class TestRAGAssistantClient(unittest.TestCase):
277
287
  self.client.api_service.post_file_binary.return_value = self.mock_response
278
288
 
279
289
  with patch('builtins.open', return_value=MagicMock()):
280
- with self.assertRaises(InvalidAPIResponseException) as context:
290
+ with self.assertRaises(APIResponseError) as context:
281
291
  self.client.upload_document(name, file_path, upload_type, content_type=content_type)
282
292
 
283
293
  self.client.api_service.post_file_binary.assert_called_once()
284
- self.assertIn("Unable to upload document", str(context.exception))
294
+ self.assertIn("API returned an error", str(context.exception)) # "Unable to upload document", str(context.exception))
285
295
 
286
296
  def test_delete_document_successful_json_response(self):
287
297
  name = "test_assistant"
288
298
  document_id = "doc_123"
289
299
  expected_response = {"message": "Document deleted"}
290
300
  self.mock_response.json.return_value = expected_response
301
+ self.mock_response.status_code = 200
291
302
  self.client.api_service.delete.return_value = self.mock_response
292
303
 
293
304
  result = self.client.delete_document(name, document_id)
@@ -303,16 +314,17 @@ class TestRAGAssistantClient(unittest.TestCase):
303
314
  self.mock_response.status_code = 500
304
315
  self.client.api_service.delete.return_value = self.mock_response
305
316
 
306
- with self.assertRaises(InvalidAPIResponseException) as context:
317
+ with self.assertRaises(APIResponseError) as context:
307
318
  self.client.delete_document(name, document_id)
308
319
 
309
320
  self.client.api_service.delete.assert_called_once()
310
- self.assertIn("Unable to delete document", str(context.exception))
321
+ self.assertIn("API returned an error", str(context.exception)) # "Unable to delete document", str(context.exception))
311
322
 
312
323
  def test_execute_query_successful_json_response(self):
313
324
  query = {"text": "test query"}
314
325
  expected_response = {"result": "query response"}
315
326
  self.mock_response.json.return_value = expected_response
327
+ self.mock_response.status_code = 200
316
328
  self.client.api_service.post.return_value = self.mock_response
317
329
 
318
330
  result = self.client.execute_query(query)
@@ -327,8 +339,8 @@ class TestRAGAssistantClient(unittest.TestCase):
327
339
  self.mock_response.status_code = 500
328
340
  self.client.api_service.post.return_value = self.mock_response
329
341
 
330
- with self.assertRaises(InvalidAPIResponseException) as context:
342
+ with self.assertRaises(APIResponseError) as context:
331
343
  self.client.execute_query(query)
332
344
 
333
345
  self.client.api_service.post.assert_called_once()
334
- self.assertIn("Unable to execute query", str(context.exception))
346
+ self.assertIn("API returned an error", str(context.exception)) # "Unable to execute query", str(context.exception))
@@ -2,7 +2,7 @@ import unittest
2
2
  from unittest.mock import patch, MagicMock
3
3
  from json import JSONDecodeError
4
4
  from pygeai.assistant.clients import AssistantClient
5
- from pygeai.core.common.exceptions import InvalidAPIResponseException
5
+ from pygeai.core.common.exceptions import InvalidAPIResponseException, APIResponseError, APIResponseError
6
6
 
7
7
 
8
8
  class TestAssistantClient(unittest.TestCase):
@@ -22,6 +22,7 @@ class TestAssistantClient(unittest.TestCase):
22
22
  detail = "summary"
23
23
  expected_response = {"id": self.assistant_id, "name": "Test Assistant"}
24
24
  self.mock_response.json.return_value = expected_response
25
+ self.mock_response.status_code = 200
25
26
  self.client.api_service.get.return_value = self.mock_response
26
27
 
27
28
  result = self.client.get_assistant_data(self.assistant_id, detail)
@@ -36,11 +37,11 @@ class TestAssistantClient(unittest.TestCase):
36
37
  self.mock_response.status_code = 500
37
38
  self.client.api_service.get.return_value = self.mock_response
38
39
 
39
- with self.assertRaises(InvalidAPIResponseException) as context:
40
+ with self.assertRaises(APIResponseError) as context:
40
41
  self.client.get_assistant_data(self.assistant_id, detail)
41
42
 
42
43
  self.client.api_service.get.assert_called_once()
43
- self.assertIn("Unable to get assistant data", str(context.exception))
44
+ self.assertIn("API returned an error", str(context.exception)) # "Unable to get assistant data", str(context.exception))
44
45
 
45
46
  def test_create_assistant_successful_json_response(self):
46
47
  assistant_type = "text"
@@ -48,6 +49,7 @@ class TestAssistantClient(unittest.TestCase):
48
49
  prompt = "Help with text"
49
50
  expected_response = {"id": "new_id", "name": name}
50
51
  self.mock_response.json.return_value = expected_response
52
+ self.mock_response.status_code = 200
51
53
  self.client.api_service.post.return_value = self.mock_response
52
54
 
53
55
  result = self.client.create_assistant(assistant_type, name, prompt)
@@ -64,17 +66,18 @@ class TestAssistantClient(unittest.TestCase):
64
66
  self.mock_response.status_code = 500
65
67
  self.client.api_service.post.return_value = self.mock_response
66
68
 
67
- with self.assertRaises(InvalidAPIResponseException) as context:
69
+ with self.assertRaises(APIResponseError) as context:
68
70
  self.client.create_assistant(assistant_type, name, prompt)
69
71
 
70
72
  self.client.api_service.post.assert_called_once()
71
- self.assertIn("Unable to create assistant", str(context.exception))
73
+ self.assertIn("API returned an error", str(context.exception)) # "Unable to create assistant", str(context.exception))
72
74
 
73
75
  def test_update_assistant_successful_json_response(self):
74
76
  status = 1
75
77
  action = "save"
76
78
  expected_response = {"id": self.assistant_id, "status": status}
77
79
  self.mock_response.json.return_value = expected_response
80
+ self.mock_response.status_code = 200
78
81
  self.client.api_service.put.return_value = self.mock_response
79
82
 
80
83
  result = self.client.update_assistant(self.assistant_id, status, action)
@@ -90,15 +93,16 @@ class TestAssistantClient(unittest.TestCase):
90
93
  self.mock_response.status_code = 500
91
94
  self.client.api_service.put.return_value = self.mock_response
92
95
 
93
- with self.assertRaises(InvalidAPIResponseException) as context:
96
+ with self.assertRaises(APIResponseError) as context:
94
97
  self.client.update_assistant(self.assistant_id, status, action)
95
98
 
96
99
  self.client.api_service.put.assert_called_once()
97
- self.assertIn("Unable to update assistant", str(context.exception))
100
+ self.assertIn("API returned an error", str(context.exception)) # "Unable to update assistant", str(context.exception))
98
101
 
99
102
  def test_delete_assistant_successful_json_response(self):
100
103
  expected_response = {"message": "Assistant deleted"}
101
104
  self.mock_response.json.return_value = expected_response
105
+ self.mock_response.status_code = 200
102
106
  self.client.api_service.delete.return_value = self.mock_response
103
107
 
104
108
  result = self.client.delete_assistant(self.assistant_id)
@@ -112,16 +116,17 @@ class TestAssistantClient(unittest.TestCase):
112
116
  self.mock_response.status_code = 500
113
117
  self.client.api_service.delete.return_value = self.mock_response
114
118
 
115
- with self.assertRaises(InvalidAPIResponseException) as context:
119
+ with self.assertRaises(APIResponseError) as context:
116
120
  self.client.delete_assistant(self.assistant_id)
117
121
 
118
122
  self.client.api_service.delete.assert_called_once()
119
- self.assertIn("Unable to delete assistant", str(context.exception))
123
+ self.assertIn("API returned an error", str(context.exception)) # "Unable to delete assistant", str(context.exception))
120
124
 
121
125
  def test_send_chat_request_successful_json_response(self):
122
126
  messages = [{"role": "user", "content": "Hello"}]
123
127
  expected_response = {"response": "Hi there!"}
124
128
  self.mock_response.json.return_value = expected_response
129
+ self.mock_response.status_code = 200
125
130
  self.client.api_service.post.return_value = self.mock_response
126
131
 
127
132
  result = self.client.send_chat_request(self.assistant_name, messages)
@@ -136,15 +141,16 @@ class TestAssistantClient(unittest.TestCase):
136
141
  self.mock_response.status_code = 500
137
142
  self.client.api_service.post.return_value = self.mock_response
138
143
 
139
- with self.assertRaises(InvalidAPIResponseException) as context:
144
+ with self.assertRaises(APIResponseError) as context:
140
145
  self.client.send_chat_request(self.assistant_name, messages)
141
146
 
142
147
  self.client.api_service.post.assert_called_once()
143
- self.assertIn("Unable to send chat request", str(context.exception))
148
+ self.assertIn("API returned an error", str(context.exception)) # "Unable to send chat request", str(context.exception))
144
149
 
145
150
  def test_get_request_status_successful_json_response(self):
146
151
  expected_response = {"status": "completed"}
147
152
  self.mock_response.json.return_value = expected_response
153
+ self.mock_response.status_code = 200
148
154
  self.client.api_service.get.return_value = self.mock_response
149
155
 
150
156
  result = self.client.get_request_status(self.request_id)
@@ -158,15 +164,16 @@ class TestAssistantClient(unittest.TestCase):
158
164
  self.mock_response.status_code = 500
159
165
  self.client.api_service.get.return_value = self.mock_response
160
166
 
161
- with self.assertRaises(InvalidAPIResponseException) as context:
167
+ with self.assertRaises(APIResponseError) as context:
162
168
  self.client.get_request_status(self.request_id)
163
169
 
164
170
  self.client.api_service.get.assert_called_once()
165
- self.assertIn("Unable to get request status", str(context.exception))
171
+ self.assertIn("API returned an error", str(context.exception)) # "Unable to get request status", str(context.exception))
166
172
 
167
173
  def test_cancel_request_successful_json_response(self):
168
174
  expected_response = {"message": "Request cancelled"}
169
175
  self.mock_response.json.return_value = expected_response
176
+ self.mock_response.status_code = 200
170
177
  self.client.api_service.post.return_value = self.mock_response
171
178
 
172
179
  result = self.client.cancel_request(self.request_id)
@@ -180,9 +187,9 @@ class TestAssistantClient(unittest.TestCase):
180
187
  self.mock_response.status_code = 500
181
188
  self.client.api_service.post.return_value = self.mock_response
182
189
 
183
- with self.assertRaises(InvalidAPIResponseException) as context:
190
+ with self.assertRaises(APIResponseError) as context:
184
191
  self.client.cancel_request(self.request_id)
185
192
 
186
193
  self.client.api_service.post.assert_called_once()
187
- self.assertIn("Unable to cancel request", str(context.exception))
194
+ self.assertIn("API returned an error", str(context.exception)) # "Unable to cancel request", str(context.exception))
188
195
 
@@ -3,7 +3,7 @@ from unittest.mock import patch, MagicMock
3
3
  from json import JSONDecodeError
4
4
 
5
5
  from pygeai.auth.clients import AuthClient
6
- from pygeai.core.common.exceptions import InvalidAPIResponseException
6
+ from pygeai.core.common.exceptions import InvalidAPIResponseException, APIResponseError
7
7
 
8
8
 
9
9
  class TestAuthClient(unittest.TestCase):
@@ -14,6 +14,7 @@ class TestAuthClient(unittest.TestCase):
14
14
  def setUp(self):
15
15
  self.client = AuthClient()
16
16
  self.mock_response = MagicMock()
17
+ self.mock_response.status_code = 200 # Default to success status
17
18
 
18
19
  @patch('pygeai.core.services.rest.ApiService.get')
19
20
  def test_get_oauth2_access_token_success(self, mock_get):
@@ -37,6 +38,7 @@ class TestAuthClient(unittest.TestCase):
37
38
  @patch('pygeai.core.services.rest.ApiService.get')
38
39
  def test_get_oauth2_access_token_custom_scope(self, mock_get):
39
40
  self.mock_response.json.return_value = {"access_token": "token-123"}
41
+ self.mock_response.status_code = 200
40
42
  mock_get.return_value = self.mock_response
41
43
 
42
44
  result = self.client.get_oauth2_access_token(
@@ -50,19 +52,18 @@ class TestAuthClient(unittest.TestCase):
50
52
  self.assertEqual(call_args[1]['params']['scope'], "custom_scope")
51
53
 
52
54
  @patch('pygeai.core.services.rest.ApiService.get')
53
- def test_get_oauth2_access_token_json_decode_error(self, mock_get):
54
- self.mock_response.json.side_effect = JSONDecodeError("error", "doc", 0)
55
+ def test_get_oauth2_access_token_error_status(self, mock_get):
55
56
  self.mock_response.status_code = 401
56
57
  self.mock_response.text = "Invalid credentials"
57
58
  mock_get.return_value = self.mock_response
58
59
 
59
- with self.assertRaises(InvalidAPIResponseException) as context:
60
+ with self.assertRaises(APIResponseError) as context:
60
61
  self.client.get_oauth2_access_token(
61
62
  client_id="client-123",
62
63
  username="user@example.com",
63
64
  password="wrong"
64
65
  )
65
- self.assertIn("Unable to obtain Oauth2 access token", str(context.exception))
66
+ self.assertIn("API returned an error", str(context.exception)) # "API returned an error", str(context.exception))
66
67
 
67
68
  @patch.object(AuthClient, 'api_service', create=True)
68
69
  def test_get_user_profile_information_success(self, mock_api_service):
@@ -71,6 +72,7 @@ class TestAuthClient(unittest.TestCase):
71
72
  "email": "user@example.com",
72
73
  "name": "Test User"
73
74
  }
75
+ self.mock_response.status_code = 200
74
76
  mock_api_service.get.return_value = self.mock_response
75
77
  mock_api_service.token = None
76
78
 
@@ -96,9 +98,191 @@ class TestAuthClient(unittest.TestCase):
96
98
  client = AuthClient()
97
99
  client.api_service = mock_api_service
98
100
 
99
- with self.assertRaises(InvalidAPIResponseException) as context:
101
+ with self.assertRaises(APIResponseError) as context:
100
102
  client.get_user_profile_information("invalid-token")
101
- self.assertIn("Unable to retrieve user profile information", str(context.exception))
103
+ self.assertIn("API returned an error", str(context.exception)) # "API returned an error", str(context.exception))
104
+
105
+ @patch('pygeai.core.services.rest.ApiService.post')
106
+ def test_create_project_api_token_success(self, mock_post):
107
+ self.mock_response.json.return_value = {
108
+ "id": "test_token_id",
109
+ "name": "TestToken",
110
+ "description": "Test Token",
111
+ "status": "Active",
112
+ "scope": "Pia.Data.Organization",
113
+ "organization": "org-123",
114
+ "project": "project-123",
115
+ "messages": [
116
+ {
117
+ "id": 0,
118
+ "description": "Token created successfully",
119
+ "type": "Success"
120
+ }
121
+ ],
122
+ "errors": []
123
+ }
124
+ self.mock_response.status_code = 200
125
+ mock_post.return_value = self.mock_response
126
+
127
+ result = self.client.create_project_api_token(
128
+ project_id="project-123",
129
+ name="TestToken",
130
+ description="Test Token"
131
+ )
132
+
133
+ mock_post.assert_called_once()
134
+ call_args = mock_post.call_args
135
+ self.assertEqual(call_args[1]['data']['name'], "TestToken")
136
+ self.assertEqual(call_args[1]['data']['description'], "Test Token")
137
+ self.assertEqual(call_args[1]['headers']['project-id'], "project-123")
138
+ self.assertEqual(result['name'], "TestToken")
139
+ self.assertEqual(result['id'], "test_token_id")
140
+
141
+ @patch('pygeai.core.services.rest.ApiService.post')
142
+ def test_create_project_api_token_without_description(self, mock_post):
143
+ self.mock_response.json.return_value = {
144
+ "id": "test_token_id",
145
+ "name": "TestToken",
146
+ "status": "Active"
147
+ }
148
+ self.mock_response.status_code = 200
149
+ mock_post.return_value = self.mock_response
150
+
151
+ result = self.client.create_project_api_token(
152
+ project_id="project-123",
153
+ name="TestToken"
154
+ )
155
+
156
+ call_args = mock_post.call_args
157
+ self.assertNotIn('description', call_args[1]['data'])
158
+
159
+ @patch('pygeai.core.services.rest.ApiService.post')
160
+ def test_create_project_api_token_json_decode_error(self, mock_post):
161
+ self.mock_response.json.side_effect = JSONDecodeError("error", "doc", 0)
162
+ self.mock_response.status_code = 400
163
+ self.mock_response.text = "Bad request"
164
+ mock_post.return_value = self.mock_response
165
+
166
+ with self.assertRaises(APIResponseError) as context:
167
+ self.client.create_project_api_token(
168
+ project_id="project-123",
169
+ name="TestToken"
170
+ )
171
+ self.assertIn("API returned an error", str(context.exception)) # "API returned an error", str(context.exception))
172
+
173
+ @patch('pygeai.core.services.rest.ApiService.delete')
174
+ def test_delete_project_api_token_success(self, mock_delete):
175
+ self.mock_response.json.return_value = {}
176
+ self.mock_response.status_code = 200
177
+ mock_delete.return_value = self.mock_response
178
+
179
+ result = self.client.delete_project_api_token(api_token_id="token-123")
180
+
181
+ mock_delete.assert_called_once()
182
+ call_args = mock_delete.call_args
183
+ self.assertIn("token-123", call_args[1]['endpoint'])
184
+ self.assertEqual(result, {})
185
+
186
+ @patch('pygeai.core.services.rest.ApiService.delete')
187
+ def test_delete_project_api_token_json_decode_error(self, mock_delete):
188
+ self.mock_response.json.side_effect = JSONDecodeError("error", "doc", 0)
189
+ self.mock_response.status_code = 404
190
+ self.mock_response.text = "Not found"
191
+ mock_delete.return_value = self.mock_response
192
+
193
+ with self.assertRaises(APIResponseError) as context:
194
+ self.client.delete_project_api_token(api_token_id="invalid-token")
195
+ self.assertIn("API returned an error", str(context.exception)) # "API returned an error", str(context.exception))
196
+
197
+ @patch('pygeai.core.services.rest.ApiService.put')
198
+ def test_update_project_api_token_success(self, mock_put):
199
+ self.mock_response.json.return_value = [
200
+ {
201
+ "description": "Token updated successfully",
202
+ "type": "Success"
203
+ }
204
+ ]
205
+ self.mock_response.status_code = 200
206
+ mock_put.return_value = self.mock_response
207
+
208
+ result = self.client.update_project_api_token(
209
+ api_token_id="token-123",
210
+ description="Updated description",
211
+ status="blocked"
212
+ )
213
+
214
+ mock_put.assert_called_once()
215
+ call_args = mock_put.call_args
216
+ self.assertEqual(call_args[1]['data']['description'], "Updated description")
217
+ self.assertEqual(call_args[1]['data']['status'], "blocked")
218
+ self.assertIsInstance(result, list)
219
+ self.assertEqual(result[0]['type'], "Success")
220
+
221
+ @patch('pygeai.core.services.rest.ApiService.put')
222
+ def test_update_project_api_token_only_description(self, mock_put):
223
+ self.mock_response.json.return_value = [
224
+ {
225
+ "description": "Token updated successfully",
226
+ "type": "Success"
227
+ }
228
+ ]
229
+ self.mock_response.status_code = 200
230
+ mock_put.return_value = self.mock_response
231
+
232
+ result = self.client.update_project_api_token(
233
+ api_token_id="token-123",
234
+ description="New description"
235
+ )
236
+
237
+ call_args = mock_put.call_args
238
+ self.assertEqual(call_args[1]['data']['description'], "New description")
239
+ self.assertNotIn('status', call_args[1]['data'])
240
+
241
+ @patch('pygeai.core.services.rest.ApiService.put')
242
+ def test_update_project_api_token_json_decode_error(self, mock_put):
243
+ self.mock_response.json.side_effect = JSONDecodeError("error", "doc", 0)
244
+ self.mock_response.status_code = 400
245
+ self.mock_response.text = "Bad request"
246
+ mock_put.return_value = self.mock_response
247
+
248
+ with self.assertRaises(APIResponseError) as context:
249
+ self.client.update_project_api_token(
250
+ api_token_id="token-123",
251
+ description="New description"
252
+ )
253
+ self.assertIn("API returned an error", str(context.exception)) # "API returned an error", str(context.exception))
254
+
255
+ @patch('pygeai.core.services.rest.ApiService.get')
256
+ def test_get_project_api_token_success(self, mock_get):
257
+ self.mock_response.json.return_value = {
258
+ "id": "token-123",
259
+ "name": "Default",
260
+ "description": "Default token",
261
+ "status": "Active",
262
+ "scope": "Pia.Data.Organization",
263
+ "timestamp": "2024-07-22T18:37:32.341"
264
+ }
265
+ self.mock_response.status_code = 200
266
+ mock_get.return_value = self.mock_response
267
+
268
+ result = self.client.get_project_api_token(api_token_id="token-123")
269
+
270
+ mock_get.assert_called_once()
271
+ call_args = mock_get.call_args
272
+ self.assertIn("token-123", call_args[1]['endpoint'])
273
+ self.assertEqual(result['id'], "token-123")
274
+ self.assertEqual(result['status'], "Active")
275
+
276
+ @patch('pygeai.core.services.rest.ApiService.get')
277
+ def test_get_project_api_token_json_decode_error(self, mock_get):
278
+ self.mock_response.json.side_effect = JSONDecodeError("error", "doc", 0)
279
+ self.mock_response.status_code = 404
280
+ self.mock_response.text = "Not found"
281
+ mock_get.return_value = self.mock_response
282
+
283
+ with self.assertRaises(APIResponseError) as context:
284
+ self.client.get_project_api_token(api_token_id="invalid-token")
285
+ self.assertIn("API returned an error", str(context.exception)) # "API returned an error", str(context.exception))
102
286
 
103
287
 
104
288
  if __name__ == '__main__':