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
@@ -1,7 +1,7 @@
1
1
  import unittest
2
2
  from unittest.mock import Mock
3
3
 
4
- from pygeai.migration.tools import MigrationTool
4
+ from pygeai.migration.tools import MigrationTool, MigrationPlan, MigrationOrchestrator
5
5
  from pygeai.migration.strategies import MigrationStrategy
6
6
 
7
7
 
@@ -11,25 +11,149 @@ class TestMigrationTool(unittest.TestCase):
11
11
  """
12
12
 
13
13
  def setUp(self):
14
- """Set up test fixtures"""
15
14
  self.mock_strategy = Mock(spec=MigrationStrategy)
16
15
 
17
16
  def test_migration_tool_initialization(self):
18
- """Test MigrationTool initialization with a strategy"""
19
17
  tool = MigrationTool(self.mock_strategy)
20
- self.assertEqual(tool.strategy, self.mock_strategy)
18
+ self.assertEqual(tool._strategy, self.mock_strategy)
21
19
 
22
20
  def test_migration_tool_set_strategy(self):
23
- """Test setting a new strategy on MigrationTool"""
24
21
  tool = MigrationTool(self.mock_strategy)
25
22
  new_strategy = Mock(spec=MigrationStrategy)
26
23
  tool.set_strategy(new_strategy)
27
-
28
- self.assertEqual(tool.strategy, new_strategy)
24
+ self.assertEqual(tool._strategy, new_strategy)
29
25
 
30
26
  def test_migration_tool_run_migration(self):
31
- """Test running migration with the strategy"""
32
27
  tool = MigrationTool(self.mock_strategy)
33
28
  tool.run_migration()
29
+ self.mock_strategy.migrate.assert_called_once()
30
+
31
+
32
+ class TestMigrationPlan(unittest.TestCase):
33
+ """
34
+ python -m unittest pygeai.tests.migration.test_tools.TestMigrationPlan
35
+ """
36
+
37
+ def test_migration_plan_initialization(self):
38
+ strategies = [Mock(spec=MigrationStrategy), Mock(spec=MigrationStrategy)]
39
+ plan = MigrationPlan(strategies=strategies)
40
+ self.assertEqual(len(plan.strategies), 2)
41
+ self.assertEqual(plan.dependencies, {})
42
+ self.assertFalse(plan.dry_run)
43
+ self.assertTrue(plan.stop_on_error)
44
+
45
+ def test_migration_plan_with_dependencies(self):
46
+ strategies = [Mock(spec=MigrationStrategy), Mock(spec=MigrationStrategy)]
47
+ dependencies = {1: [0]}
48
+ plan = MigrationPlan(strategies=strategies, dependencies=dependencies)
49
+ self.assertEqual(plan.dependencies, {1: [0]})
50
+
51
+
52
+ class TestMigrationOrchestrator(unittest.TestCase):
53
+ """
54
+ python -m unittest pygeai.tests.migration.test_tools.TestMigrationOrchestrator
55
+ """
56
+
57
+ def setUp(self):
58
+ self.strategy1 = Mock(spec=MigrationStrategy)
59
+ self.strategy2 = Mock(spec=MigrationStrategy)
60
+ self.strategy3 = Mock(spec=MigrationStrategy)
61
+
62
+ def test_orchestrator_simple_execution(self):
63
+ plan = MigrationPlan(strategies=[self.strategy1, self.strategy2])
64
+ orchestrator = MigrationOrchestrator(plan)
65
+
66
+ result = orchestrator.execute()
67
+
68
+ self.strategy1.migrate.assert_called_once()
69
+ self.strategy2.migrate.assert_called_once()
70
+ self.assertEqual(result['total'], 2)
71
+ self.assertEqual(result['completed'], 2)
72
+ self.assertEqual(result['failed'], 0)
73
+ self.assertEqual(result['success_rate'], 1.0)
74
+
75
+ def test_orchestrator_with_dependencies(self):
76
+ plan = MigrationPlan(
77
+ strategies=[self.strategy1, self.strategy2, self.strategy3],
78
+ dependencies={1: [0], 2: [1]}
79
+ )
80
+ orchestrator = MigrationOrchestrator(plan)
81
+
82
+ result = orchestrator.execute()
83
+
84
+ self.assertEqual(result['completed'], 3)
85
+ self.assertEqual(result['completed_indices'], [0, 1, 2])
86
+
87
+ def test_orchestrator_stop_on_error(self):
88
+ self.strategy1.migrate.side_effect = Exception("Migration failed")
89
+ plan = MigrationPlan(
90
+ strategies=[self.strategy1, self.strategy2],
91
+ stop_on_error=True
92
+ )
93
+ orchestrator = MigrationOrchestrator(plan)
94
+
95
+ with self.assertRaises(ValueError) as context:
96
+ orchestrator.execute()
97
+
98
+ self.assertIn("Migration failed at strategy", str(context.exception))
99
+ self.strategy1.migrate.assert_called_once()
100
+ self.strategy2.migrate.assert_not_called()
101
+
102
+ def test_orchestrator_continue_on_error(self):
103
+ self.strategy1.migrate.side_effect = Exception("Migration failed")
104
+ plan = MigrationPlan(
105
+ strategies=[self.strategy1, self.strategy2],
106
+ stop_on_error=False
107
+ )
108
+ orchestrator = MigrationOrchestrator(plan)
109
+
110
+ result = orchestrator.execute()
111
+
112
+ self.strategy1.migrate.assert_called_once()
113
+ self.strategy2.migrate.assert_called_once()
114
+ self.assertEqual(result['completed'], 1)
115
+ self.assertEqual(result['failed'], 1)
116
+ self.assertEqual(result['success_rate'], 0.5)
117
+
118
+ def test_orchestrator_dry_run(self):
119
+ plan = MigrationPlan(
120
+ strategies=[self.strategy1, self.strategy2],
121
+ dry_run=True
122
+ )
123
+ orchestrator = MigrationOrchestrator(plan)
124
+
125
+ result = orchestrator.execute()
126
+
127
+ self.strategy1.migrate.assert_not_called()
128
+ self.strategy2.migrate.assert_not_called()
129
+ self.assertTrue(result['valid'])
130
+ self.assertEqual(result['execution_order'], [0, 1])
131
+
132
+ def test_orchestrator_circular_dependency(self):
133
+ plan = MigrationPlan(
134
+ strategies=[self.strategy1, self.strategy2],
135
+ dependencies={0: [1], 1: [0]}
136
+ )
137
+ orchestrator = MigrationOrchestrator(plan)
138
+
139
+ with self.assertRaises(ValueError) as context:
140
+ orchestrator.execute()
141
+
142
+ self.assertIn("Circular dependency", str(context.exception))
143
+
144
+ def test_orchestrator_dry_run_circular_dependency(self):
145
+ plan = MigrationPlan(
146
+ strategies=[self.strategy1, self.strategy2],
147
+ dependencies={0: [1], 1: [0]},
148
+ dry_run=True
149
+ )
150
+ orchestrator = MigrationOrchestrator(plan)
151
+
152
+ result = orchestrator.execute()
153
+
154
+ self.assertFalse(result['valid'])
155
+ self.assertIn("Circular dependency", result['error'])
156
+
34
157
 
35
- self.mock_strategy.migrate.assert_called_once()
158
+ if __name__ == '__main__':
159
+ unittest.main()
@@ -47,6 +47,7 @@ class TestUsageLimitClient(unittest.TestCase):
47
47
  def test_set_organization_usage_limit_success(self, mock_post):
48
48
  mock_response = mock_post.return_value
49
49
  mock_response.json.return_value = self.valid_response
50
+ mock_response.status_code = 200
50
51
 
51
52
  result = self.client.set_organization_usage_limit(self.organization, self.valid_usage_limit)
52
53
 
@@ -79,6 +80,7 @@ class TestUsageLimitClient(unittest.TestCase):
79
80
  invalid_usage_limit["renewalStatus"] = "InvalidStatus"
80
81
  mock_response = mock_post.return_value
81
82
  mock_response.json.return_value = {"error": "Invalid renewal status"}
83
+ mock_response.status_code = 200
82
84
 
83
85
  result = self.client.set_organization_usage_limit(self.organization, invalid_usage_limit)
84
86
 
@@ -94,6 +96,7 @@ class TestUsageLimitClient(unittest.TestCase):
94
96
  def test_get_organization_latest_usage_limit_success(self, mock_get):
95
97
  mock_response = mock_get.return_value
96
98
  mock_response.json.return_value = self.valid_response
99
+ mock_response.status_code = 200
97
100
 
98
101
  result = self.client.get_organization_latest_usage_limit(self.organization)
99
102
 
@@ -123,6 +126,7 @@ class TestUsageLimitClient(unittest.TestCase):
123
126
  response = {"limits": [self.valid_response]}
124
127
  mock_response = mock_get.return_value
125
128
  mock_response.json.return_value = response
129
+ mock_response.status_code = 200
126
130
 
127
131
  result = self.client.get_all_usage_limits_from_organization(self.organization)
128
132
 
@@ -153,6 +157,7 @@ class TestUsageLimitClient(unittest.TestCase):
153
157
  response = {"status": "deleted"}
154
158
  mock_response = mock_delete.return_value
155
159
  mock_response.json.return_value = response
160
+ mock_response.status_code = 200
156
161
 
157
162
  result = self.client.delete_usage_limit_from_organization(self.organization, self.limit_id)
158
163
 
@@ -183,6 +188,7 @@ class TestUsageLimitClient(unittest.TestCase):
183
188
  response["hardLimit"] = hard_limit
184
189
  mock_response = mock_put.return_value
185
190
  mock_response.json.return_value = response
191
+ mock_response.status_code = 200
186
192
 
187
193
  result = self.client.set_organization_hard_limit(self.organization, self.limit_id, hard_limit)
188
194
 
@@ -217,6 +223,7 @@ class TestUsageLimitClient(unittest.TestCase):
217
223
  response["softLimit"] = soft_limit
218
224
  mock_response = mock_put.return_value
219
225
  mock_response.json.return_value = response
226
+ mock_response.status_code = 200
220
227
 
221
228
  result = self.client.set_organization_soft_limit(self.organization, self.limit_id, soft_limit)
222
229
 
@@ -251,6 +258,7 @@ class TestUsageLimitClient(unittest.TestCase):
251
258
  response["renewalStatus"] = renewal_status
252
259
  mock_response = mock_put.return_value
253
260
  mock_response.json.return_value = response
261
+ mock_response.status_code = 200
254
262
 
255
263
  result = self.client.set_organization_renewal_status(self.organization, self.limit_id, renewal_status)
256
264
 
@@ -282,6 +290,7 @@ class TestUsageLimitClient(unittest.TestCase):
282
290
  def test_set_project_usage_limit_success(self, mock_post):
283
291
  mock_response = mock_post.return_value
284
292
  mock_response.json.return_value = self.valid_response
293
+ mock_response.status_code = 200
285
294
 
286
295
  result = self.client.set_project_usage_limit(self.organization, self.project, self.valid_usage_limit)
287
296
 
@@ -314,6 +323,7 @@ class TestUsageLimitClient(unittest.TestCase):
314
323
  invalid_usage_limit["subscriptionType"] = "InvalidType"
315
324
  mock_response = mock_post.return_value
316
325
  mock_response.json.return_value = {"error": "Invalid subscription type"}
326
+ mock_response.status_code = 200
317
327
 
318
328
  result = self.client.set_project_usage_limit(self.organization, self.project, invalid_usage_limit)
319
329
 
@@ -330,6 +340,7 @@ class TestUsageLimitClient(unittest.TestCase):
330
340
  response = {"limits": [self.valid_response]}
331
341
  mock_response = mock_get.return_value
332
342
  mock_response.json.return_value = response
343
+ mock_response.status_code = 200
333
344
 
334
345
  result = self.client.get_all_usage_limits_from_project(self.organization, self.project)
335
346
 
@@ -359,6 +370,7 @@ class TestUsageLimitClient(unittest.TestCase):
359
370
  def test_get_latest_usage_limit_from_project_success(self, mock_get):
360
371
  mock_response = mock_get.return_value
361
372
  mock_response.json.return_value = self.valid_response
373
+ mock_response.status_code = 200
362
374
 
363
375
  result = self.client.get_latest_usage_limit_from_project(self.organization, self.project)
364
376
 
@@ -387,6 +399,7 @@ class TestUsageLimitClient(unittest.TestCase):
387
399
  def test_get_active_usage_limit_from_project_success(self, mock_get):
388
400
  mock_response = mock_get.return_value
389
401
  mock_response.json.return_value = self.valid_response
402
+ mock_response.status_code = 200
390
403
 
391
404
  result = self.client.get_active_usage_limit_from_project(self.organization, self.project)
392
405
 
@@ -416,6 +429,7 @@ class TestUsageLimitClient(unittest.TestCase):
416
429
  response = {"status": "deleted"}
417
430
  mock_response = mock_delete.return_value
418
431
  mock_response.json.return_value = response
432
+ mock_response.status_code = 200
419
433
 
420
434
  result = self.client.delete_usage_limit_from_project(self.organization, self.project, self.limit_id)
421
435
 
@@ -446,6 +460,7 @@ class TestUsageLimitClient(unittest.TestCase):
446
460
  response["hardLimit"] = hard_limit
447
461
  mock_response = mock_put.return_value
448
462
  mock_response.json.return_value = response
463
+ mock_response.status_code = 200
449
464
 
450
465
  result = self.client.set_hard_limit_for_active_usage_limit_from_project(
451
466
  self.organization, self.project, self.limit_id, hard_limit
@@ -484,6 +499,7 @@ class TestUsageLimitClient(unittest.TestCase):
484
499
  response["softLimit"] = soft_limit
485
500
  mock_response = mock_put.return_value
486
501
  mock_response.json.return_value = response
502
+ mock_response.status_code = 200
487
503
 
488
504
  result = self.client.set_soft_limit_for_active_usage_limit_from_project(
489
505
  self.organization, self.project, self.limit_id, soft_limit
@@ -522,6 +538,7 @@ class TestUsageLimitClient(unittest.TestCase):
522
538
  response["renewalStatus"] = renewal_status
523
539
  mock_response = mock_put.return_value
524
540
  mock_response.json.return_value = response
541
+ mock_response.status_code = 200
525
542
 
526
543
  result = self.client.set_project_renewal_status(self.organization, self.project, self.limit_id, renewal_status)
527
544
 
@@ -5,7 +5,8 @@ from unittest.mock import patch
5
5
  from pygeai.organization.clients import OrganizationClient
6
6
  from pygeai.core.common.exceptions import InvalidAPIResponseException
7
7
  from pygeai.organization.endpoints import GET_ASSISTANT_LIST_V1, GET_PROJECT_LIST_V1, GET_PROJECT_V1, CREATE_PROJECT_V1, \
8
- UPDATE_PROJECT_V1, DELETE_PROJECT_V1, GET_PROJECT_TOKENS_V1, GET_REQUEST_DATA_V1
8
+ UPDATE_PROJECT_V1, DELETE_PROJECT_V1, GET_PROJECT_TOKENS_V1, GET_REQUEST_DATA_V1, GET_MEMBERSHIPS_V2, \
9
+ GET_PROJECT_MEMBERSHIPS_V2, GET_PROJECT_ROLES_V2, GET_PROJECT_MEMBERS_V2, GET_ORGANIZATION_MEMBERS_V2
9
10
 
10
11
 
11
12
  class TestOrganizationClient(unittest.TestCase):
@@ -20,6 +21,7 @@ class TestOrganizationClient(unittest.TestCase):
20
21
  def test_get_assistant_list_success(self, mock_get):
21
22
  mock_response = mock_get.return_value
22
23
  mock_response.json.return_value = {"assistants": [{"name": "assistant1"}, {"name": "assistant2"}]}
24
+ mock_response.status_code = 200
23
25
 
24
26
  result = self.client.get_assistant_list(detail="summary")
25
27
 
@@ -46,6 +48,7 @@ class TestOrganizationClient(unittest.TestCase):
46
48
  def test_get_project_list_success(self, mock_get):
47
49
  mock_response = mock_get.return_value
48
50
  mock_response.json.return_value = {"projects": [{"name": "project1"}, {"name": "project2"}]}
51
+ mock_response.status_code = 200
49
52
 
50
53
  result = self.client.get_project_list(detail="summary")
51
54
 
@@ -59,6 +62,7 @@ class TestOrganizationClient(unittest.TestCase):
59
62
  def test_get_project_list_with_name(self, mock_get):
60
63
  mock_response = mock_get.return_value
61
64
  mock_response.json.return_value = {"projects": [{"name": "specific_project"}]}
65
+ mock_response.status_code = 200
62
66
 
63
67
  result = self.client.get_project_list(detail="full", name="specific_project")
64
68
 
@@ -87,6 +91,7 @@ class TestOrganizationClient(unittest.TestCase):
87
91
  def test_get_project_data_success(self, mock_get):
88
92
  mock_response = mock_get.return_value
89
93
  mock_response.json.return_value = {"project": {"id": "123", "name": "project1"}}
94
+ mock_response.status_code = 200
90
95
 
91
96
  result = self.client.get_project_data(project_id="123")
92
97
 
@@ -111,6 +116,7 @@ class TestOrganizationClient(unittest.TestCase):
111
116
  def test_create_project_success(self, mock_post):
112
117
  mock_response = mock_post.return_value
113
118
  mock_response.json.return_value = {"project": {"id": "123", "name": "project1"}}
119
+ mock_response.status_code = 200
114
120
 
115
121
  result = self.client.create_project(name="project1", email="admin@example.com", description="A test project")
116
122
 
@@ -129,6 +135,7 @@ class TestOrganizationClient(unittest.TestCase):
129
135
  def test_create_project_with_usage_limit(self, mock_post):
130
136
  mock_response = mock_post.return_value
131
137
  mock_response.json.return_value = {"project": {"id": "123", "name": "project1"}}
138
+ mock_response.status_code = 200
132
139
 
133
140
  usage_limit = {"type": "Requests", "threshold": 1000}
134
141
  result = self.client.create_project(
@@ -171,6 +178,7 @@ class TestOrganizationClient(unittest.TestCase):
171
178
  def test_update_project_success(self, mock_put):
172
179
  mock_response = mock_put.return_value
173
180
  mock_response.json.return_value = {"project": {"id": "123", "name": "updated_project"}}
181
+ mock_response.status_code = 200
174
182
 
175
183
  result = self.client.update_project(project_id="123", name="updated_project", description="Updated description")
176
184
 
@@ -201,6 +209,7 @@ class TestOrganizationClient(unittest.TestCase):
201
209
  def test_delete_project_success(self, mock_delete):
202
210
  mock_response = mock_delete.return_value
203
211
  mock_response.json.return_value = {"status": "deleted"}
212
+ mock_response.status_code = 200
204
213
 
205
214
  result = self.client.delete_project(project_id="123")
206
215
 
@@ -225,6 +234,7 @@ class TestOrganizationClient(unittest.TestCase):
225
234
  def test_get_project_tokens_success(self, mock_get):
226
235
  mock_response = mock_get.return_value
227
236
  mock_response.json.return_value = {"tokens": ["token1", "token2"]}
237
+ mock_response.status_code = 200
228
238
 
229
239
  result = self.client.get_project_tokens(project_id="123")
230
240
 
@@ -251,6 +261,7 @@ class TestOrganizationClient(unittest.TestCase):
251
261
  def test_export_request_data_success(self, mock_get):
252
262
  mock_response = mock_get.return_value
253
263
  mock_response.json.return_value = {"requests": [{"id": "1", "status": "pending"}]}
264
+ mock_response.status_code = 200
254
265
 
255
266
  result = self.client.export_request_data()
256
267
 
@@ -266,6 +277,7 @@ class TestOrganizationClient(unittest.TestCase):
266
277
  def test_export_request_data_with_params(self, mock_get):
267
278
  mock_response = mock_get.return_value
268
279
  mock_response.json.return_value = {"requests": [{"id": "1", "status": "completed"}]}
280
+ mock_response.status_code = 200
269
281
 
270
282
  result = self.client.export_request_data(assistant_name="assistant1", status="completed", skip=10, count=5)
271
283
 
@@ -293,3 +305,196 @@ class TestOrganizationClient(unittest.TestCase):
293
305
  )
294
306
  self.assertEqual(str(context.exception), "Unable to export request data: Invalid JSON response")
295
307
 
308
+ @patch("pygeai.core.services.rest.ApiService.get")
309
+ def test_get_memberships_success(self, mock_get):
310
+ mock_response = mock_get.return_value
311
+ mock_response.json.return_value = {
312
+
313
+ "count": 1,
314
+ "pages": 1,
315
+ "organizationsMemberships": [
316
+ {
317
+ "organizationId": "org-123",
318
+ "organizationName": "Test Org",
319
+ "projectsMemberships": []
320
+ }
321
+ ]
322
+ }
323
+ mock_response.status_code = 200
324
+
325
+ result = self.client.get_memberships()
326
+
327
+ mock_get.assert_called_once_with(
328
+ endpoint=GET_MEMBERSHIPS_V2,
329
+ params={"startPage": 1, "pageSize": 20, "orderDirection": "desc"}
330
+ )
331
+ self.assertIsNotNone(result)
332
+ self.assertEqual(result['count'], 1)
333
+
334
+ @patch("pygeai.core.services.rest.ApiService.get")
335
+ def test_get_memberships_with_params(self, mock_get):
336
+ mock_response = mock_get.return_value
337
+ mock_response.json.return_value = {"count": 0, "pages": 0, "organizationsMemberships": []}
338
+ mock_response.status_code = 200
339
+
340
+ result = self.client.get_memberships(
341
+ email="test@example.com",
342
+ start_page=2,
343
+ page_size=10,
344
+ order_key="organizationName",
345
+ order_direction="asc",
346
+ role_types="backend,frontend"
347
+ )
348
+
349
+ mock_get.assert_called_once_with(
350
+ endpoint=GET_MEMBERSHIPS_V2,
351
+ params={
352
+ "email": "test@example.com",
353
+ "startPage": 2,
354
+ "pageSize": 10,
355
+ "orderKey": "organizationName",
356
+ "orderDirection": "asc",
357
+ "roleTypes": "backend,frontend"
358
+ }
359
+ )
360
+ self.assertIsNotNone(result)
361
+
362
+ @patch("pygeai.core.services.rest.ApiService.get")
363
+ def test_get_memberships_json_decode_error(self, mock_get):
364
+ mock_response = mock_get.return_value
365
+ mock_response.status_code = 200
366
+ mock_response.json.side_effect = JSONDecodeError("Invalid JSON", "", 0)
367
+ mock_response.text = "Invalid JSON response"
368
+
369
+ with self.assertRaises(InvalidAPIResponseException) as context:
370
+ self.client.get_memberships()
371
+
372
+ self.assertEqual(str(context.exception), "Unable to get memberships: Invalid JSON response")
373
+
374
+ @patch("pygeai.core.services.rest.ApiService.get")
375
+ def test_get_project_memberships_success(self, mock_get):
376
+ mock_response = mock_get.return_value
377
+ mock_response.json.return_value = {
378
+
379
+ "count": 1,
380
+ "pages": 1,
381
+ "projectsMemberships": [
382
+ {
383
+ "organizationId": "org-123",
384
+ "organizationName": "Test Org",
385
+ "projectId": "proj-456",
386
+ "projectName": "Test Project",
387
+ "roles": []
388
+ }
389
+ ]
390
+ }
391
+ mock_response.status_code = 200
392
+
393
+ result = self.client.get_project_memberships()
394
+
395
+ mock_get.assert_called_once_with(
396
+ endpoint=GET_PROJECT_MEMBERSHIPS_V2,
397
+ params={"startPage": 1, "pageSize": 20, "orderDirection": "desc"}
398
+ )
399
+ self.assertIsNotNone(result)
400
+ self.assertEqual(result['count'], 1)
401
+
402
+ @patch("pygeai.core.services.rest.ApiService.get")
403
+ def test_get_project_memberships_json_decode_error(self, mock_get):
404
+ mock_response = mock_get.return_value
405
+ mock_response.status_code = 200
406
+ mock_response.json.side_effect = JSONDecodeError("Invalid JSON", "", 0)
407
+ mock_response.text = "Invalid JSON response"
408
+
409
+ with self.assertRaises(InvalidAPIResponseException) as context:
410
+ self.client.get_project_memberships()
411
+
412
+ self.assertEqual(str(context.exception), "Unable to get project memberships: Invalid JSON response")
413
+
414
+ @patch("pygeai.core.services.rest.ApiService.get")
415
+ def test_get_project_roles_success(self, mock_get):
416
+ mock_response = mock_get.return_value
417
+ mock_response.json.return_value = {
418
+
419
+ "roles": [
420
+ {"id": "role-1", "name": "Admin", "externalId": "admin-ext", "type": "backend", "origin": "system"}
421
+ ]
422
+ }
423
+ mock_response.status_code = 200
424
+
425
+ result = self.client.get_project_roles(project_id="proj-123")
426
+
427
+ mock_get.assert_called_once_with(endpoint=GET_PROJECT_ROLES_V2, params={"projectId": "proj-123"})
428
+ self.assertIsNotNone(result)
429
+ self.assertEqual(len(result['roles']), 1)
430
+
431
+ @patch("pygeai.core.services.rest.ApiService.get")
432
+ def test_get_project_roles_json_decode_error(self, mock_get):
433
+ mock_response = mock_get.return_value
434
+ mock_response.status_code = 200
435
+ mock_response.json.side_effect = JSONDecodeError("Invalid JSON", "", 0)
436
+ mock_response.text = "Invalid JSON response"
437
+
438
+ with self.assertRaises(InvalidAPIResponseException) as context:
439
+ self.client.get_project_roles(project_id="proj-123")
440
+
441
+ self.assertEqual(str(context.exception), "Unable to get project roles for project 'proj-123': Invalid JSON response")
442
+
443
+ @patch("pygeai.core.services.rest.ApiService.get")
444
+ def test_get_project_members_success(self, mock_get):
445
+ mock_response = mock_get.return_value
446
+ mock_response.json.return_value = {
447
+
448
+ "members": [
449
+ {"email": "user@example.com", "roles": []}
450
+ ]
451
+ }
452
+ mock_response.status_code = 200
453
+
454
+ result = self.client.get_project_members(project_id="proj-123")
455
+
456
+ mock_get.assert_called_once_with(endpoint=GET_PROJECT_MEMBERS_V2, params={"projectId": "proj-123"})
457
+ self.assertIsNotNone(result)
458
+ self.assertEqual(len(result['members']), 1)
459
+
460
+ @patch("pygeai.core.services.rest.ApiService.get")
461
+ def test_get_project_members_json_decode_error(self, mock_get):
462
+ mock_response = mock_get.return_value
463
+ mock_response.status_code = 200
464
+ mock_response.json.side_effect = JSONDecodeError("Invalid JSON", "", 0)
465
+ mock_response.text = "Invalid JSON response"
466
+
467
+ with self.assertRaises(InvalidAPIResponseException) as context:
468
+ self.client.get_project_members(project_id="proj-123")
469
+
470
+ self.assertEqual(str(context.exception), "Unable to get project members for project 'proj-123': Invalid JSON response")
471
+
472
+ @patch("pygeai.core.services.rest.ApiService.get")
473
+ def test_get_organization_members_success(self, mock_get):
474
+ mock_response = mock_get.return_value
475
+ mock_response.json.return_value = {
476
+
477
+ "members": [
478
+ {"email": "user@example.com", "roles": []}
479
+ ]
480
+ }
481
+ mock_response.status_code = 200
482
+
483
+ result = self.client.get_organization_members(organization_id="org-123")
484
+
485
+ mock_get.assert_called_once_with(endpoint=GET_ORGANIZATION_MEMBERS_V2, params={"organizationId": "org-123"})
486
+ self.assertIsNotNone(result)
487
+ self.assertEqual(len(result['members']), 1)
488
+
489
+ @patch("pygeai.core.services.rest.ApiService.get")
490
+ def test_get_organization_members_json_decode_error(self, mock_get):
491
+ mock_response = mock_get.return_value
492
+ mock_response.status_code = 200
493
+ mock_response.json.side_effect = JSONDecodeError("Invalid JSON", "", 0)
494
+ mock_response.text = "Invalid JSON response"
495
+
496
+ with self.assertRaises(InvalidAPIResponseException) as context:
497
+ self.client.get_organization_members(organization_id="org-123")
498
+
499
+ self.assertEqual(str(context.exception), "Unable to get organization members for organization 'org-123': Invalid JSON response")
500
+