pygeai 0.6.0b13__py3-none-any.whl → 0.6.1__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 (217) hide show
  1. pygeai/__init__.py +1 -2
  2. pygeai/_docs/source/content/api_reference/project.rst +392 -0
  3. pygeai/_docs/source/content/authentication.rst +130 -1
  4. pygeai/_docs/source/content/debugger.rst +327 -157
  5. pygeai/_docs/source/content/migration.rst +391 -7
  6. pygeai/_docs/source/pygeai.core.common.rst +8 -0
  7. pygeai/_docs/source/pygeai.tests.auth.rst +56 -0
  8. pygeai/_docs/source/pygeai.tests.cli.rst +8 -0
  9. pygeai/admin/clients.py +1 -3
  10. pygeai/analytics/clients.py +1 -1
  11. pygeai/assistant/clients.py +2 -7
  12. pygeai/assistant/data/clients.py +0 -8
  13. pygeai/assistant/data_analyst/clients.py +0 -2
  14. pygeai/assistant/managers.py +1 -1
  15. pygeai/assistant/rag/clients.py +0 -2
  16. pygeai/assistant/rag/mappers.py +9 -11
  17. pygeai/auth/clients.py +26 -7
  18. pygeai/auth/endpoints.py +2 -1
  19. pygeai/chat/clients.py +2 -2
  20. pygeai/chat/managers.py +1 -1
  21. pygeai/cli/commands/admin.py +13 -25
  22. pygeai/cli/commands/analytics.py +56 -88
  23. pygeai/cli/commands/assistant.py +84 -138
  24. pygeai/cli/commands/auth.py +23 -46
  25. pygeai/cli/commands/base.py +0 -1
  26. pygeai/cli/commands/chat.py +218 -209
  27. pygeai/cli/commands/common.py +5 -5
  28. pygeai/cli/commands/configuration.py +79 -29
  29. pygeai/cli/commands/docs.py +3 -4
  30. pygeai/cli/commands/embeddings.py +13 -19
  31. pygeai/cli/commands/evaluation.py +133 -344
  32. pygeai/cli/commands/feedback.py +7 -15
  33. pygeai/cli/commands/files.py +26 -53
  34. pygeai/cli/commands/gam.py +28 -69
  35. pygeai/cli/commands/lab/ai_lab.py +96 -142
  36. pygeai/cli/commands/lab/common.py +1 -1
  37. pygeai/cli/commands/lab/spec.py +12 -32
  38. pygeai/cli/commands/llm.py +9 -18
  39. pygeai/cli/commands/migrate.py +43 -99
  40. pygeai/cli/commands/organization.py +223 -196
  41. pygeai/cli/commands/rag.py +35 -58
  42. pygeai/cli/commands/rerank.py +21 -25
  43. pygeai/cli/commands/secrets.py +39 -67
  44. pygeai/cli/commands/usage_limits.py +50 -136
  45. pygeai/cli/commands/validators.py +1 -1
  46. pygeai/cli/geai.py +32 -3
  47. pygeai/cli/geai_proxy.py +6 -2
  48. pygeai/cli/install_man.py +1 -1
  49. pygeai/cli/parsers.py +1 -1
  50. pygeai/core/base/clients.py +90 -21
  51. pygeai/core/base/mappers.py +39 -55
  52. pygeai/core/base/session.py +134 -22
  53. pygeai/core/common/config.py +50 -13
  54. pygeai/core/common/constants.py +8 -0
  55. pygeai/core/common/exceptions.py +6 -0
  56. pygeai/core/embeddings/clients.py +0 -1
  57. pygeai/core/embeddings/managers.py +0 -1
  58. pygeai/core/feedback/clients.py +0 -2
  59. pygeai/core/feedback/models.py +1 -1
  60. pygeai/core/files/clients.py +0 -3
  61. pygeai/core/files/managers.py +1 -1
  62. pygeai/core/files/mappers.py +4 -5
  63. pygeai/core/llm/clients.py +0 -1
  64. pygeai/core/models.py +4 -4
  65. pygeai/core/plugins/clients.py +0 -3
  66. pygeai/core/plugins/models.py +2 -2
  67. pygeai/core/rerank/clients.py +0 -2
  68. pygeai/core/secrets/clients.py +0 -2
  69. pygeai/core/services/rest.py +80 -14
  70. pygeai/core/singleton.py +24 -0
  71. pygeai/dbg/__init__.py +2 -2
  72. pygeai/dbg/debugger.py +276 -38
  73. pygeai/evaluation/clients.py +2 -4
  74. pygeai/evaluation/dataset/clients.py +0 -1
  75. pygeai/evaluation/plan/clients.py +0 -2
  76. pygeai/evaluation/result/clients.py +0 -2
  77. pygeai/gam/clients.py +1 -3
  78. pygeai/health/clients.py +1 -3
  79. pygeai/lab/clients.py +0 -1
  80. pygeai/lab/managers.py +0 -1
  81. pygeai/lab/models.py +0 -1
  82. pygeai/lab/strategies/clients.py +1 -2
  83. pygeai/lab/tools/clients.py +2 -2
  84. pygeai/lab/tools/mappers.py +1 -1
  85. pygeai/migration/strategies.py +5 -6
  86. pygeai/migration/tools.py +1 -1
  87. pygeai/organization/clients.py +118 -12
  88. pygeai/organization/endpoints.py +1 -0
  89. pygeai/organization/limits/clients.py +4 -6
  90. pygeai/organization/limits/managers.py +1 -4
  91. pygeai/organization/managers.py +2 -2
  92. pygeai/proxy/config.py +1 -0
  93. pygeai/proxy/managers.py +6 -5
  94. pygeai/tests/admin/test_clients.py +11 -11
  95. pygeai/tests/assistants/rag/test_clients.py +1 -1
  96. pygeai/tests/assistants/rag/test_models.py +1 -2
  97. pygeai/tests/assistants/test_clients.py +1 -1
  98. pygeai/tests/assistants/test_managers.py +1 -3
  99. pygeai/tests/auth/test_cli_configuration.py +252 -0
  100. pygeai/tests/auth/test_client_initialization.py +411 -0
  101. pygeai/tests/auth/test_clients.py +29 -27
  102. pygeai/tests/auth/test_config_manager.py +305 -0
  103. pygeai/tests/auth/test_header_injection.py +294 -0
  104. pygeai/tests/auth/test_oauth.py +3 -1
  105. pygeai/tests/auth/test_session_logging.py +119 -0
  106. pygeai/tests/auth/test_session_validation.py +408 -0
  107. pygeai/tests/auth/test_singleton_reset.py +201 -0
  108. pygeai/tests/chat/test_clients.py +1 -1
  109. pygeai/tests/chat/test_iris.py +1 -1
  110. pygeai/tests/chat/test_ui.py +0 -2
  111. pygeai/tests/cli/commands/lab/test_ai_lab.py +1 -3
  112. pygeai/tests/cli/commands/lab/test_common.py +0 -1
  113. pygeai/tests/cli/commands/test_chat.py +1 -1
  114. pygeai/tests/cli/commands/test_common.py +0 -1
  115. pygeai/tests/cli/commands/test_embeddings.py +2 -2
  116. pygeai/tests/cli/commands/test_evaluation.py +1 -9
  117. pygeai/tests/cli/commands/test_llm.py +1 -1
  118. pygeai/tests/cli/commands/test_migrate.py +1 -1
  119. pygeai/tests/cli/commands/test_rerank.py +0 -1
  120. pygeai/tests/cli/commands/test_secrets.py +1 -1
  121. pygeai/tests/cli/commands/test_show_help.py +0 -1
  122. pygeai/tests/cli/commands/test_validators.py +0 -1
  123. pygeai/tests/cli/test_credentials_flag.py +312 -0
  124. pygeai/tests/cli/test_error_handler.py +0 -1
  125. pygeai/tests/core/base/test_mappers.py +2 -2
  126. pygeai/tests/core/base/test_models.py +4 -4
  127. pygeai/tests/core/common/test_config.py +2 -7
  128. pygeai/tests/core/common/test_decorators.py +0 -1
  129. pygeai/tests/core/embeddings/test_managers.py +1 -1
  130. pygeai/tests/core/feedback/test_clients.py +2 -2
  131. pygeai/tests/core/files/test_clients.py +6 -6
  132. pygeai/tests/core/files/test_models.py +0 -1
  133. pygeai/tests/core/files/test_responses.py +0 -1
  134. pygeai/tests/core/llm/test_clients.py +1 -1
  135. pygeai/tests/core/plugins/test_clients.py +4 -4
  136. pygeai/tests/core/rerank/test_mappers.py +1 -3
  137. pygeai/tests/core/secrets/test_clients.py +2 -3
  138. pygeai/tests/core/services/test_rest.py +10 -10
  139. pygeai/tests/core/utils/test_console.py +0 -1
  140. pygeai/tests/dbg/test_debugger.py +95 -8
  141. pygeai/tests/evaluation/dataset/test_clients.py +24 -27
  142. pygeai/tests/evaluation/plan/test_clients.py +16 -18
  143. pygeai/tests/evaluation/result/test_clients.py +4 -5
  144. pygeai/tests/health/test_clients.py +2 -2
  145. pygeai/tests/integration/lab/agents/test_create_agent.py +1 -3
  146. pygeai/tests/integration/lab/agents/test_get_agent.py +1 -1
  147. pygeai/tests/integration/lab/processes/test_create_process.py +2 -2
  148. pygeai/tests/integration/lab/processes/test_create_task.py +2 -3
  149. pygeai/tests/integration/lab/processes/test_delete_process.py +0 -1
  150. pygeai/tests/integration/lab/processes/test_get_process.py +2 -4
  151. pygeai/tests/integration/lab/processes/test_list_process_instances.py +1 -3
  152. pygeai/tests/integration/lab/processes/test_update_process.py +3 -9
  153. pygeai/tests/integration/lab/reasoning_strategies/test_update_reasoning_strategy.py +1 -2
  154. pygeai/tests/integration/lab/tools/test_delete_tool.py +1 -1
  155. pygeai/tests/integration/lab/tools/test_list_tools.py +1 -1
  156. pygeai/tests/integration/lab/tools/test_update_tool.py +1 -1
  157. pygeai/tests/lab/agents/test_clients.py +17 -17
  158. pygeai/tests/lab/processes/test_clients.py +67 -67
  159. pygeai/tests/lab/processes/test_mappers.py +23 -23
  160. pygeai/tests/lab/spec/test_loader.py +0 -2
  161. pygeai/tests/lab/spec/test_parsers.py +1 -2
  162. pygeai/tests/lab/strategies/test_clients.py +10 -10
  163. pygeai/tests/lab/test_managers.py +3 -5
  164. pygeai/tests/lab/test_mappers.py +1 -4
  165. pygeai/tests/lab/tools/test_clients.py +21 -21
  166. pygeai/tests/lab/tools/test_mappers.py +0 -1
  167. pygeai/tests/organization/limits/test_clients.py +33 -33
  168. pygeai/tests/organization/limits/test_managers.py +7 -7
  169. pygeai/tests/organization/test_clients.py +78 -60
  170. pygeai/tests/proxy/test_clients.py +1 -1
  171. pygeai/tests/proxy/test_integration.py +1 -4
  172. pygeai/tests/proxy/test_managers.py +1 -2
  173. pygeai/tests/proxy/test_servers.py +1 -2
  174. pygeai/tests/snippets/assistants/rag/delete_rag_assistant.py +0 -1
  175. pygeai/tests/snippets/assistants/rag/get_documents.py +0 -1
  176. pygeai/tests/snippets/assistants/rag/get_rag_assistant_data.py +0 -1
  177. pygeai/tests/snippets/chat/get_request_status.py +0 -1
  178. pygeai/tests/snippets/dbg/file_debugging.py +72 -0
  179. pygeai/tests/snippets/dbg/module_debugging.py +60 -0
  180. pygeai/tests/snippets/embeddings/cohere_example.py +2 -2
  181. pygeai/tests/snippets/embeddings/openai_base64_example.py +1 -1
  182. pygeai/tests/snippets/evaluation/dataset/complete_workflow_example.py +8 -8
  183. pygeai/tests/snippets/evaluation/plan/complete_workflow_example.py +5 -5
  184. pygeai/tests/snippets/evaluation/result/complete_workflow_example.py +3 -3
  185. pygeai/tests/snippets/lab/agentic_flow_example_1.py +1 -1
  186. pygeai/tests/snippets/lab/agentic_flow_example_2.py +3 -4
  187. pygeai/tests/snippets/lab/agents/create_agent_with_permissions.py +2 -2
  188. pygeai/tests/snippets/lab/agents/delete_agent.py +1 -2
  189. pygeai/tests/snippets/lab/agents/get_agent.py +1 -1
  190. pygeai/tests/snippets/lab/agents/get_agent_with_new_fields.py +10 -10
  191. pygeai/tests/snippets/lab/agents/get_sharing_link.py +0 -1
  192. pygeai/tests/snippets/lab/agents/list_agents.py +1 -1
  193. pygeai/tests/snippets/lab/agents/publish_agent_revision.py +0 -1
  194. pygeai/tests/snippets/lab/agents/update_agent_properties.py +1 -1
  195. pygeai/tests/snippets/lab/crud_ui.py +3 -5
  196. pygeai/tests/snippets/lab/processes/kbs/get_kb.py +0 -1
  197. pygeai/tests/snippets/lab/processes/kbs/list_kbs.py +0 -1
  198. pygeai/tests/snippets/lab/processes/list_processes.py +1 -1
  199. pygeai/tests/snippets/lab/samples/summarize_files.py +0 -3
  200. pygeai/tests/snippets/lab/strategies/get_reasoning_strategy.py +0 -1
  201. pygeai/tests/snippets/lab/strategies/list_reasoning_strategies.py +1 -1
  202. pygeai/tests/snippets/lab/tools/get_tool.py +1 -1
  203. pygeai/tests/snippets/lab/tools/publish_tool_revision.py +0 -1
  204. pygeai/tests/snippets/lab/tools/set_parameters.py +1 -2
  205. pygeai/tests/snippets/lab/use_cases/c_code_fixer_agent_flow.py +2 -3
  206. pygeai/tests/snippets/lab/use_cases/file_summarizer_example_2.py +1 -1
  207. pygeai/tests/snippets/lab/use_cases/update_cli_expert.py +0 -1
  208. pygeai/tests/snippets/lab/use_cases/update_lab_expert.py +0 -1
  209. pygeai/tests/snippets/lab/use_cases/update_web_designer.py +0 -1
  210. pygeai/tests/snippets/lab/use_cases/update_web_reader.py +0 -1
  211. pygeai/tests/snippets/migrate/orchestrator_examples.py +1 -1
  212. {pygeai-0.6.0b13.dist-info → pygeai-0.6.1.dist-info}/METADATA +32 -7
  213. {pygeai-0.6.0b13.dist-info → pygeai-0.6.1.dist-info}/RECORD +217 -206
  214. {pygeai-0.6.0b13.dist-info → pygeai-0.6.1.dist-info}/WHEEL +0 -0
  215. {pygeai-0.6.0b13.dist-info → pygeai-0.6.1.dist-info}/entry_points.txt +0 -0
  216. {pygeai-0.6.0b13.dist-info → pygeai-0.6.1.dist-info}/licenses/LICENSE +0 -0
  217. {pygeai-0.6.0b13.dist-info → pygeai-0.6.1.dist-info}/top_level.txt +0 -0
@@ -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, APIResponseError
6
+ from pygeai.core.common.exceptions import APIResponseError
7
7
 
8
8
 
9
9
  class TestAuthClient(unittest.TestCase):
@@ -16,7 +16,7 @@ class TestAuthClient(unittest.TestCase):
16
16
  self.mock_response = MagicMock()
17
17
  self.mock_response.status_code = 200 # Default to success status
18
18
 
19
- @patch('pygeai.core.services.rest.ApiService.get')
19
+ @patch('pygeai.core.services.rest.GEAIApiService.get')
20
20
  def test_get_oauth2_access_token_success(self, mock_get):
21
21
  self.mock_response.json.return_value = {"access_token": "token-123", "token_type": "Bearer"}
22
22
  mock_get.return_value = self.mock_response
@@ -35,7 +35,7 @@ class TestAuthClient(unittest.TestCase):
35
35
  self.assertEqual(call_args[1]['params']['scope'], "gam_user_data gam_user_roles")
36
36
  self.assertEqual(result, {"access_token": "token-123", "token_type": "Bearer"})
37
37
 
38
- @patch('pygeai.core.services.rest.ApiService.get')
38
+ @patch('pygeai.core.services.rest.GEAIApiService.get')
39
39
  def test_get_oauth2_access_token_custom_scope(self, mock_get):
40
40
  self.mock_response.json.return_value = {"access_token": "token-123"}
41
41
  self.mock_response.status_code = 200
@@ -51,7 +51,7 @@ class TestAuthClient(unittest.TestCase):
51
51
  call_args = mock_get.call_args
52
52
  self.assertEqual(call_args[1]['params']['scope'], "custom_scope")
53
53
 
54
- @patch('pygeai.core.services.rest.ApiService.get')
54
+ @patch('pygeai.core.services.rest.GEAIApiService.get')
55
55
  def test_get_oauth2_access_token_error_status(self, mock_get):
56
56
  self.mock_response.status_code = 401
57
57
  self.mock_response.text = "Invalid credentials"
@@ -65,44 +65,46 @@ class TestAuthClient(unittest.TestCase):
65
65
  )
66
66
  self.assertIn("API returned an error", str(context.exception)) # "API returned an error", str(context.exception))
67
67
 
68
- @patch.object(AuthClient, 'api_service', create=True)
69
- def test_get_user_profile_information_success(self, mock_api_service):
68
+ @patch('pygeai.core.services.rest.GEAIApiService')
69
+ def test_get_user_profile_information_success(self, mock_api_service_class):
70
70
  self.mock_response.json.return_value = {
71
71
  "user_id": "user-123",
72
72
  "email": "user@example.com",
73
73
  "name": "Test User"
74
74
  }
75
75
  self.mock_response.status_code = 200
76
- mock_api_service.get.return_value = self.mock_response
77
- mock_api_service.token = None
76
+
77
+ mock_api_service_instance = MagicMock()
78
+ mock_api_service_instance.get.return_value = self.mock_response
79
+ mock_api_service_class.return_value = mock_api_service_instance
78
80
 
79
81
  client = AuthClient()
80
- client.api_service = mock_api_service
81
- result = client.get_user_profile_information("access-token-123")
82
+ result = client.get_user_profile_information("access-token-123", project_id="proj-123")
82
83
 
83
- mock_api_service.get.assert_called_once()
84
+ mock_api_service_instance.get.assert_called_once()
84
85
  self.assertEqual(result, {
85
86
  "user_id": "user-123",
86
87
  "email": "user@example.com",
87
88
  "name": "Test User"
88
89
  })
89
90
 
90
- @patch.object(AuthClient, 'api_service', create=True)
91
- def test_get_user_profile_information_json_decode_error(self, mock_api_service):
91
+ @patch('pygeai.core.services.rest.GEAIApiService')
92
+ def test_get_user_profile_information_json_decode_error(self, mock_api_service_class):
92
93
  self.mock_response.json.side_effect = JSONDecodeError("error", "doc", 0)
93
94
  self.mock_response.status_code = 401
94
95
  self.mock_response.text = "Invalid token"
95
- mock_api_service.get.return_value = self.mock_response
96
- mock_api_service.token = None
96
+
97
+ mock_api_service_instance = MagicMock()
98
+ mock_api_service_instance.get.return_value = self.mock_response
99
+ mock_api_service_class.return_value = mock_api_service_instance
97
100
 
98
101
  client = AuthClient()
99
- client.api_service = mock_api_service
100
102
 
101
103
  with self.assertRaises(APIResponseError) as context:
102
- client.get_user_profile_information("invalid-token")
104
+ client.get_user_profile_information("invalid-token", project_id="proj-123")
103
105
  self.assertIn("API returned an error", str(context.exception)) # "API returned an error", str(context.exception))
104
106
 
105
- @patch('pygeai.core.services.rest.ApiService.post')
107
+ @patch('pygeai.core.services.rest.GEAIApiService.post')
106
108
  def test_create_project_api_token_success(self, mock_post):
107
109
  self.mock_response.json.return_value = {
108
110
  "id": "test_token_id",
@@ -138,7 +140,7 @@ class TestAuthClient(unittest.TestCase):
138
140
  self.assertEqual(result['name'], "TestToken")
139
141
  self.assertEqual(result['id'], "test_token_id")
140
142
 
141
- @patch('pygeai.core.services.rest.ApiService.post')
143
+ @patch('pygeai.core.services.rest.GEAIApiService.post')
142
144
  def test_create_project_api_token_without_description(self, mock_post):
143
145
  self.mock_response.json.return_value = {
144
146
  "id": "test_token_id",
@@ -156,7 +158,7 @@ class TestAuthClient(unittest.TestCase):
156
158
  call_args = mock_post.call_args
157
159
  self.assertNotIn('description', call_args[1]['data'])
158
160
 
159
- @patch('pygeai.core.services.rest.ApiService.post')
161
+ @patch('pygeai.core.services.rest.GEAIApiService.post')
160
162
  def test_create_project_api_token_json_decode_error(self, mock_post):
161
163
  self.mock_response.json.side_effect = JSONDecodeError("error", "doc", 0)
162
164
  self.mock_response.status_code = 400
@@ -170,7 +172,7 @@ class TestAuthClient(unittest.TestCase):
170
172
  )
171
173
  self.assertIn("API returned an error", str(context.exception)) # "API returned an error", str(context.exception))
172
174
 
173
- @patch('pygeai.core.services.rest.ApiService.delete')
175
+ @patch('pygeai.core.services.rest.GEAIApiService.delete')
174
176
  def test_delete_project_api_token_success(self, mock_delete):
175
177
  self.mock_response.json.return_value = {}
176
178
  self.mock_response.status_code = 200
@@ -183,7 +185,7 @@ class TestAuthClient(unittest.TestCase):
183
185
  self.assertIn("token-123", call_args[1]['endpoint'])
184
186
  self.assertEqual(result, {})
185
187
 
186
- @patch('pygeai.core.services.rest.ApiService.delete')
188
+ @patch('pygeai.core.services.rest.GEAIApiService.delete')
187
189
  def test_delete_project_api_token_json_decode_error(self, mock_delete):
188
190
  self.mock_response.json.side_effect = JSONDecodeError("error", "doc", 0)
189
191
  self.mock_response.status_code = 404
@@ -194,7 +196,7 @@ class TestAuthClient(unittest.TestCase):
194
196
  self.client.delete_project_api_token(api_token_id="invalid-token")
195
197
  self.assertIn("API returned an error", str(context.exception)) # "API returned an error", str(context.exception))
196
198
 
197
- @patch('pygeai.core.services.rest.ApiService.put')
199
+ @patch('pygeai.core.services.rest.GEAIApiService.put')
198
200
  def test_update_project_api_token_success(self, mock_put):
199
201
  self.mock_response.json.return_value = [
200
202
  {
@@ -218,7 +220,7 @@ class TestAuthClient(unittest.TestCase):
218
220
  self.assertIsInstance(result, list)
219
221
  self.assertEqual(result[0]['type'], "Success")
220
222
 
221
- @patch('pygeai.core.services.rest.ApiService.put')
223
+ @patch('pygeai.core.services.rest.GEAIApiService.put')
222
224
  def test_update_project_api_token_only_description(self, mock_put):
223
225
  self.mock_response.json.return_value = [
224
226
  {
@@ -238,7 +240,7 @@ class TestAuthClient(unittest.TestCase):
238
240
  self.assertEqual(call_args[1]['data']['description'], "New description")
239
241
  self.assertNotIn('status', call_args[1]['data'])
240
242
 
241
- @patch('pygeai.core.services.rest.ApiService.put')
243
+ @patch('pygeai.core.services.rest.GEAIApiService.put')
242
244
  def test_update_project_api_token_json_decode_error(self, mock_put):
243
245
  self.mock_response.json.side_effect = JSONDecodeError("error", "doc", 0)
244
246
  self.mock_response.status_code = 400
@@ -252,7 +254,7 @@ class TestAuthClient(unittest.TestCase):
252
254
  )
253
255
  self.assertIn("API returned an error", str(context.exception)) # "API returned an error", str(context.exception))
254
256
 
255
- @patch('pygeai.core.services.rest.ApiService.get')
257
+ @patch('pygeai.core.services.rest.GEAIApiService.get')
256
258
  def test_get_project_api_token_success(self, mock_get):
257
259
  self.mock_response.json.return_value = {
258
260
  "id": "token-123",
@@ -273,7 +275,7 @@ class TestAuthClient(unittest.TestCase):
273
275
  self.assertEqual(result['id'], "token-123")
274
276
  self.assertEqual(result['status'], "Active")
275
277
 
276
- @patch('pygeai.core.services.rest.ApiService.get')
278
+ @patch('pygeai.core.services.rest.GEAIApiService.get')
277
279
  def test_get_project_api_token_json_decode_error(self, mock_get):
278
280
  self.mock_response.json.side_effect = JSONDecodeError("error", "doc", 0)
279
281
  self.mock_response.status_code = 404
@@ -0,0 +1,305 @@
1
+ import unittest
2
+ import tempfile
3
+ import os
4
+
5
+ from pygeai.core.common.config import SettingsManager, get_settings, reset_settings
6
+
7
+
8
+ class TestSettingsManager(unittest.TestCase):
9
+ """
10
+ Tests for SettingsManager configuration file operations.
11
+
12
+ python -m unittest pygeai.tests.auth.test_config_manager.TestSettingsManager
13
+ """
14
+
15
+ def setUp(self):
16
+ """Set up test fixtures"""
17
+ reset_settings()
18
+ self.temp_creds_file = tempfile.NamedTemporaryFile(mode='w', suffix='_credentials', delete=False)
19
+ self.temp_creds_file.close()
20
+
21
+ def tearDown(self):
22
+ """Clean up test fixtures"""
23
+ if os.path.exists(self.temp_creds_file.name):
24
+ os.unlink(self.temp_creds_file.name)
25
+ reset_settings()
26
+
27
+ def test_creates_empty_credentials_file_if_not_exists(self):
28
+ """Test that SettingsManager creates empty credentials file if it doesn't exist"""
29
+ os.unlink(self.temp_creds_file.name)
30
+
31
+ settings = SettingsManager(credentials_file=self.temp_creds_file.name)
32
+
33
+ self.assertTrue(os.path.exists(self.temp_creds_file.name))
34
+
35
+ def test_set_and_get_api_key(self):
36
+ """Test setting and getting API key for an alias"""
37
+ settings = SettingsManager(credentials_file=self.temp_creds_file.name)
38
+
39
+ settings.set_api_key("test_api_key", alias="test")
40
+ api_key = settings.get_api_key(alias="test")
41
+
42
+ self.assertEqual(api_key, "test_api_key")
43
+
44
+ def test_set_and_get_base_url(self):
45
+ """Test setting and getting base URL for an alias"""
46
+ settings = SettingsManager(credentials_file=self.temp_creds_file.name)
47
+
48
+ settings.set_base_url("https://test.example.com", alias="test")
49
+ base_url = settings.get_base_url(alias="test")
50
+
51
+ self.assertEqual(base_url, "https://test.example.com")
52
+
53
+ def test_set_and_get_access_token(self):
54
+ """Test setting and getting OAuth access token"""
55
+ settings = SettingsManager(credentials_file=self.temp_creds_file.name)
56
+
57
+ settings.set_access_token("oauth_token_123", alias="test")
58
+ access_token = settings.get_access_token(alias="test")
59
+
60
+ self.assertEqual(access_token, "oauth_token_123")
61
+
62
+ def test_set_and_get_project_id(self):
63
+ """Test setting and getting project ID"""
64
+ settings = SettingsManager(credentials_file=self.temp_creds_file.name)
65
+
66
+ settings.set_project_id("project-456", alias="test")
67
+ project_id = settings.get_project_id(alias="test")
68
+
69
+ self.assertEqual(project_id, "project-456")
70
+
71
+ def test_set_and_get_organization_id(self):
72
+ """Test setting and getting organization ID"""
73
+ settings = SettingsManager(credentials_file=self.temp_creds_file.name)
74
+
75
+ settings.set_organization_id("org-789", alias="test")
76
+ org_id = settings.get_organization_id(alias="test")
77
+
78
+ self.assertEqual(org_id, "org-789")
79
+
80
+ def test_set_and_get_eval_url(self):
81
+ """Test setting and getting eval URL"""
82
+ settings = SettingsManager(credentials_file=self.temp_creds_file.name)
83
+
84
+ settings.set_eval_url("https://eval.example.com", alias="test")
85
+ eval_url = settings.get_eval_url(alias="test")
86
+
87
+ self.assertEqual(eval_url, "https://eval.example.com")
88
+
89
+ def test_multiple_aliases(self):
90
+ """Test that multiple aliases can be managed independently"""
91
+ settings = SettingsManager(credentials_file=self.temp_creds_file.name)
92
+
93
+ settings.set_api_key("dev_key", alias="dev")
94
+ settings.set_base_url("https://dev.example.com", alias="dev")
95
+
96
+ settings.set_api_key("prod_key", alias="prod")
97
+ settings.set_base_url("https://prod.example.com", alias="prod")
98
+
99
+ self.assertEqual(settings.get_api_key(alias="dev"), "dev_key")
100
+ self.assertEqual(settings.get_base_url(alias="dev"), "https://dev.example.com")
101
+
102
+ self.assertEqual(settings.get_api_key(alias="prod"), "prod_key")
103
+ self.assertEqual(settings.get_base_url(alias="prod"), "https://prod.example.com")
104
+
105
+ def test_list_aliases(self):
106
+ """Test listing all configured aliases"""
107
+ settings = SettingsManager(credentials_file=self.temp_creds_file.name)
108
+
109
+ settings.set_base_url("https://dev.example.com", alias="dev")
110
+ settings.set_base_url("https://staging.example.com", alias="staging")
111
+ settings.set_base_url("https://prod.example.com", alias="prod")
112
+
113
+ aliases = settings.list_aliases()
114
+
115
+ self.assertEqual(len(aliases), 3)
116
+ self.assertIn("dev", aliases)
117
+ self.assertIn("staging", aliases)
118
+ self.assertIn("prod", aliases)
119
+ self.assertEqual(aliases["dev"], "https://dev.example.com")
120
+
121
+ def test_has_value_returns_true_for_existing(self):
122
+ """Test has_value returns True for existing setting"""
123
+ settings = SettingsManager(credentials_file=self.temp_creds_file.name)
124
+
125
+ settings.set_api_key("test_key", alias="test")
126
+
127
+ self.assertTrue(settings.has_value("GEAI_API_KEY", "test"))
128
+
129
+ def test_has_value_returns_false_for_missing(self):
130
+ """Test has_value returns False for missing setting"""
131
+ settings = SettingsManager(credentials_file=self.temp_creds_file.name)
132
+
133
+ settings.set_api_key("test_key", alias="test")
134
+
135
+ self.assertFalse(settings.has_value("GEAI_API_BASE_URL", "test"))
136
+
137
+ def test_has_value_returns_false_for_missing_alias(self):
138
+ """Test has_value returns False for non-existent alias"""
139
+ settings = SettingsManager(credentials_file=self.temp_creds_file.name)
140
+
141
+ self.assertFalse(settings.has_value("GEAI_API_KEY", "nonexistent"))
142
+
143
+ def test_get_setting_value_returns_empty_for_missing_alias(self):
144
+ """Test get_setting_value returns None and logs warning for missing alias"""
145
+ settings = SettingsManager(credentials_file=self.temp_creds_file.name)
146
+
147
+ value = settings.get_setting_value("GEAI_API_KEY", "nonexistent")
148
+
149
+ self.assertIsNone(value)
150
+
151
+ def test_auto_adds_eval_url_when_missing(self):
152
+ """Test that eval_url is auto-added when requested but missing"""
153
+ settings = SettingsManager(credentials_file=self.temp_creds_file.name)
154
+
155
+ settings.set_api_key("test_key", alias="test")
156
+ settings.set_base_url("https://test.example.com", alias="test")
157
+
158
+ eval_url = settings.get_setting_value("GEAI_API_EVAL_URL", "test")
159
+
160
+ self.assertEqual(eval_url, "")
161
+ self.assertTrue(settings.has_value("GEAI_API_EVAL_URL", "test"))
162
+
163
+ def test_auto_adds_oauth_vars_when_access_token_present(self):
164
+ """Test that OAuth vars are auto-added when access_token is present"""
165
+ settings = SettingsManager(credentials_file=self.temp_creds_file.name)
166
+
167
+ settings.set_access_token("oauth_token_123", alias="test")
168
+
169
+ project_id = settings.get_setting_value("GEAI_PROJECT_ID", "test")
170
+ org_id = settings.get_setting_value("GEAI_ORGANIZATION_ID", "test")
171
+
172
+ self.assertEqual(project_id, "")
173
+ self.assertEqual(org_id, "")
174
+ self.assertTrue(settings.has_value("GEAI_PROJECT_ID", "test"))
175
+ self.assertTrue(settings.has_value("GEAI_ORGANIZATION_ID", "test"))
176
+
177
+
178
+ class TestSettingsManagerEnvironmentVariables(unittest.TestCase):
179
+ """
180
+ Tests for environment variable precedence in SettingsManager.
181
+
182
+ python -m unittest pygeai.tests.auth.test_config_manager.TestSettingsManagerEnvironmentVariables
183
+ """
184
+
185
+ def setUp(self):
186
+ """Set up test fixtures"""
187
+ reset_settings()
188
+ self.temp_creds_file = tempfile.NamedTemporaryFile(mode='w', suffix='_credentials', delete=False)
189
+ self.temp_creds_file.close()
190
+
191
+ self.original_env = {}
192
+ for key in ['GEAI_API_KEY', 'GEAI_API_BASE_URL', 'GEAI_OAUTH_ACCESS_TOKEN',
193
+ 'GEAI_PROJECT_ID', 'GEAI_ORGANIZATION_ID', 'GEAI_API_EVAL_URL']:
194
+ self.original_env[key] = os.environ.get(key)
195
+ if key in os.environ:
196
+ del os.environ[key]
197
+
198
+ def tearDown(self):
199
+ """Clean up test fixtures"""
200
+ for key, value in self.original_env.items():
201
+ if value is not None:
202
+ os.environ[key] = value
203
+ elif key in os.environ:
204
+ del os.environ[key]
205
+
206
+ if os.path.exists(self.temp_creds_file.name):
207
+ os.unlink(self.temp_creds_file.name)
208
+ reset_settings()
209
+
210
+ def test_env_var_overrides_config_for_default_alias(self):
211
+ """Test that environment variable overrides config file for default alias"""
212
+ settings = SettingsManager(credentials_file=self.temp_creds_file.name)
213
+ settings.set_api_key("config_key", alias="default")
214
+
215
+ os.environ['GEAI_API_KEY'] = "env_key"
216
+
217
+ api_key = settings.get_api_key(alias="default")
218
+
219
+ self.assertEqual(api_key, "env_key")
220
+
221
+ def test_env_var_does_not_override_non_default_alias(self):
222
+ """Test that environment variable doesn't override non-default alias"""
223
+ settings = SettingsManager(credentials_file=self.temp_creds_file.name)
224
+ settings.set_api_key("config_key", alias="staging")
225
+
226
+ os.environ['GEAI_API_KEY'] = "env_key"
227
+
228
+ api_key = settings.get_api_key(alias="staging")
229
+
230
+ self.assertEqual(api_key, "config_key")
231
+
232
+ def test_env_var_used_when_no_config_for_default(self):
233
+ """Test that environment variable is used when no config exists for default"""
234
+ settings = SettingsManager(credentials_file=self.temp_creds_file.name)
235
+
236
+ os.environ['GEAI_API_KEY'] = "env_key"
237
+
238
+ api_key = settings.get_api_key(alias="default")
239
+
240
+ self.assertEqual(api_key, "env_key")
241
+
242
+ def test_all_env_vars_work_for_default_alias(self):
243
+ """Test that all supported environment variables work"""
244
+ os.environ['GEAI_API_KEY'] = "env_api_key"
245
+ os.environ['GEAI_API_BASE_URL'] = "https://env.example.com"
246
+ os.environ['GEAI_OAUTH_ACCESS_TOKEN'] = "env_oauth_token"
247
+ os.environ['GEAI_PROJECT_ID'] = "env_project_id"
248
+ os.environ['GEAI_ORGANIZATION_ID'] = "env_org_id"
249
+ os.environ['GEAI_API_EVAL_URL'] = "https://env.eval.example.com"
250
+
251
+ settings = SettingsManager(credentials_file=self.temp_creds_file.name)
252
+
253
+ self.assertEqual(settings.get_api_key(), "env_api_key")
254
+ self.assertEqual(settings.get_base_url(), "https://env.example.com")
255
+ self.assertEqual(settings.get_access_token(), "env_oauth_token")
256
+ self.assertEqual(settings.get_project_id(), "env_project_id")
257
+ self.assertEqual(settings.get_organization_id(), "env_org_id")
258
+ self.assertEqual(settings.get_eval_url(), "https://env.eval.example.com")
259
+
260
+ def test_env_var_only_applies_to_default_alias_query(self):
261
+ """Test that env vars only apply when querying default or no alias"""
262
+ os.environ['GEAI_API_KEY'] = "env_key"
263
+
264
+ settings = SettingsManager(credentials_file=self.temp_creds_file.name)
265
+
266
+ default_key = settings.get_api_key()
267
+ self.assertEqual(default_key, "env_key")
268
+
269
+ explicit_default_key = settings.get_api_key(alias="default")
270
+ self.assertEqual(explicit_default_key, "env_key")
271
+
272
+
273
+ class TestGetSettingsSingleton(unittest.TestCase):
274
+ """
275
+ Tests for get_settings singleton behavior.
276
+
277
+ python -m unittest pygeai.tests.auth.test_config_manager.TestGetSettingsSingleton
278
+ """
279
+
280
+ def setUp(self):
281
+ """Set up test fixtures"""
282
+ reset_settings()
283
+
284
+ def tearDown(self):
285
+ """Clean up test fixtures"""
286
+ reset_settings()
287
+
288
+ def test_get_settings_returns_singleton(self):
289
+ """Test that get_settings returns the same instance"""
290
+ settings1 = get_settings()
291
+ settings2 = get_settings()
292
+
293
+ self.assertIs(settings1, settings2)
294
+
295
+ def test_reset_settings_clears_singleton(self):
296
+ """Test that reset_settings clears the singleton"""
297
+ settings1 = get_settings()
298
+ reset_settings()
299
+ settings2 = get_settings()
300
+
301
+ self.assertIsNot(settings1, settings2)
302
+
303
+
304
+ if __name__ == '__main__':
305
+ unittest.main()