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.
- pygeai/_docs/source/conf.py +78 -6
- pygeai/_docs/source/content/api_reference/admin.rst +161 -0
- pygeai/_docs/source/content/api_reference/assistant.rst +326 -0
- pygeai/_docs/source/content/api_reference/auth.rst +379 -0
- pygeai/_docs/source/content/api_reference/embeddings.rst +31 -1
- pygeai/_docs/source/content/api_reference/evaluation.rst +590 -0
- pygeai/_docs/source/content/api_reference/feedback.rst +237 -0
- pygeai/_docs/source/content/api_reference/files.rst +592 -0
- pygeai/_docs/source/content/api_reference/gam.rst +401 -0
- pygeai/_docs/source/content/api_reference/health.rst +58 -0
- pygeai/_docs/source/content/api_reference/project.rst +20 -18
- pygeai/_docs/source/content/api_reference/proxy.rst +318 -0
- pygeai/_docs/source/content/api_reference/rerank.rst +94 -0
- pygeai/_docs/source/content/api_reference/secrets.rst +495 -0
- pygeai/_docs/source/content/api_reference/usage_limits.rst +390 -0
- pygeai/_docs/source/content/api_reference.rst +13 -1
- pygeai/_docs/source/content/debugger.rst +376 -83
- pygeai/_docs/source/content/migration.rst +528 -0
- pygeai/_docs/source/content/modules.rst +1 -1
- pygeai/_docs/source/index.rst +59 -7
- pygeai/_docs/source/pygeai.auth.rst +29 -0
- pygeai/_docs/source/pygeai.cli.commands.rst +16 -0
- pygeai/_docs/source/pygeai.cli.rst +8 -0
- pygeai/_docs/source/pygeai.core.utils.rst +16 -0
- pygeai/_docs/source/pygeai.rst +1 -0
- pygeai/_docs/source/pygeai.tests.auth.rst +21 -0
- pygeai/_docs/source/pygeai.tests.cli.commands.rst +16 -0
- pygeai/_docs/source/pygeai.tests.cli.rst +16 -0
- pygeai/_docs/source/pygeai.tests.core.base.rst +8 -0
- pygeai/_docs/source/pygeai.tests.core.embeddings.rst +16 -0
- pygeai/_docs/source/pygeai.tests.core.files.rst +8 -0
- pygeai/_docs/source/pygeai.tests.core.plugins.rst +21 -0
- pygeai/_docs/source/pygeai.tests.core.rst +1 -0
- pygeai/_docs/source/pygeai.tests.evaluation.dataset.rst +21 -0
- pygeai/_docs/source/pygeai.tests.evaluation.plan.rst +21 -0
- pygeai/_docs/source/pygeai.tests.evaluation.result.rst +21 -0
- pygeai/_docs/source/pygeai.tests.evaluation.rst +20 -0
- pygeai/_docs/source/pygeai.tests.integration.lab.processes.rst +8 -0
- pygeai/_docs/source/pygeai.tests.organization.rst +8 -0
- pygeai/_docs/source/pygeai.tests.rst +2 -0
- pygeai/_docs/source/pygeai.tests.snippets.auth.rst +10 -0
- pygeai/_docs/source/pygeai.tests.snippets.chat.rst +40 -0
- pygeai/_docs/source/pygeai.tests.snippets.dbg.rst +45 -0
- pygeai/_docs/source/pygeai.tests.snippets.embeddings.rst +40 -0
- pygeai/_docs/source/pygeai.tests.snippets.evaluation.dataset.rst +197 -0
- pygeai/_docs/source/pygeai.tests.snippets.evaluation.plan.rst +133 -0
- pygeai/_docs/source/pygeai.tests.snippets.evaluation.result.rst +37 -0
- pygeai/_docs/source/pygeai.tests.snippets.evaluation.rst +10 -0
- pygeai/_docs/source/pygeai.tests.snippets.organization.rst +40 -0
- pygeai/_docs/source/pygeai.tests.snippets.rst +2 -0
- pygeai/admin/clients.py +12 -32
- pygeai/assistant/clients.py +16 -44
- pygeai/assistant/data/clients.py +1 -0
- pygeai/assistant/data_analyst/clients.py +6 -13
- pygeai/assistant/rag/clients.py +24 -67
- pygeai/auth/clients.py +88 -14
- pygeai/auth/endpoints.py +4 -0
- pygeai/chat/clients.py +192 -25
- pygeai/chat/endpoints.py +2 -1
- pygeai/cli/commands/auth.py +178 -2
- pygeai/cli/commands/chat.py +227 -1
- pygeai/cli/commands/embeddings.py +56 -8
- pygeai/cli/commands/lab/ai_lab.py +0 -2
- pygeai/cli/commands/migrate.py +994 -434
- pygeai/cli/commands/organization.py +241 -0
- pygeai/cli/error_handler.py +116 -0
- pygeai/cli/geai.py +28 -10
- pygeai/cli/parsers.py +8 -2
- pygeai/core/base/clients.py +4 -1
- pygeai/core/common/exceptions.py +11 -10
- pygeai/core/embeddings/__init__.py +19 -0
- pygeai/core/embeddings/clients.py +20 -9
- pygeai/core/embeddings/mappers.py +16 -2
- pygeai/core/embeddings/responses.py +9 -2
- pygeai/core/feedback/clients.py +4 -8
- pygeai/core/files/clients.py +10 -25
- pygeai/core/files/managers.py +42 -0
- pygeai/core/llm/clients.py +11 -26
- pygeai/core/models.py +107 -0
- pygeai/core/plugins/clients.py +4 -7
- pygeai/core/rerank/clients.py +4 -8
- pygeai/core/secrets/clients.py +14 -37
- pygeai/core/services/rest.py +1 -1
- pygeai/core/utils/parsers.py +32 -0
- pygeai/core/utils/validators.py +10 -0
- pygeai/dbg/__init__.py +3 -0
- pygeai/dbg/debugger.py +565 -70
- pygeai/evaluation/clients.py +2 -1
- pygeai/evaluation/dataset/clients.py +46 -44
- pygeai/evaluation/plan/clients.py +28 -26
- pygeai/evaluation/result/clients.py +38 -5
- pygeai/gam/clients.py +10 -25
- pygeai/health/clients.py +4 -7
- pygeai/lab/agents/clients.py +21 -54
- pygeai/lab/agents/endpoints.py +2 -0
- pygeai/lab/clients.py +1 -0
- pygeai/lab/models.py +3 -3
- pygeai/lab/processes/clients.py +45 -127
- pygeai/lab/strategies/clients.py +11 -25
- pygeai/lab/tools/clients.py +23 -67
- pygeai/lab/tools/endpoints.py +3 -0
- pygeai/migration/__init__.py +31 -0
- pygeai/migration/strategies.py +404 -155
- pygeai/migration/tools.py +170 -3
- pygeai/organization/clients.py +135 -51
- pygeai/organization/endpoints.py +6 -1
- pygeai/organization/limits/clients.py +32 -91
- pygeai/organization/managers.py +157 -1
- pygeai/organization/mappers.py +76 -2
- pygeai/organization/responses.py +25 -1
- pygeai/proxy/clients.py +4 -1
- pygeai/tests/admin/test_clients.py +16 -11
- pygeai/tests/assistants/rag/test_clients.py +35 -23
- pygeai/tests/assistants/test_clients.py +22 -15
- pygeai/tests/auth/test_clients.py +191 -7
- pygeai/tests/chat/test_clients.py +211 -1
- pygeai/tests/cli/commands/test_embeddings.py +32 -9
- pygeai/tests/cli/commands/test_evaluation.py +7 -0
- pygeai/tests/cli/commands/test_migrate.py +112 -243
- pygeai/tests/cli/test_error_handler.py +225 -0
- pygeai/tests/cli/test_geai_driver.py +154 -0
- pygeai/tests/cli/test_parsers.py +5 -5
- pygeai/tests/core/embeddings/test_clients.py +144 -0
- pygeai/tests/core/embeddings/test_managers.py +171 -0
- pygeai/tests/core/embeddings/test_mappers.py +142 -0
- pygeai/tests/core/feedback/test_clients.py +2 -0
- pygeai/tests/core/files/test_clients.py +1 -0
- pygeai/tests/core/llm/test_clients.py +14 -9
- pygeai/tests/core/plugins/test_clients.py +5 -3
- pygeai/tests/core/rerank/test_clients.py +1 -0
- pygeai/tests/core/secrets/test_clients.py +19 -13
- pygeai/tests/dbg/test_debugger.py +453 -75
- pygeai/tests/evaluation/dataset/test_clients.py +3 -1
- pygeai/tests/evaluation/plan/test_clients.py +4 -2
- pygeai/tests/evaluation/result/test_clients.py +7 -5
- pygeai/tests/gam/test_clients.py +1 -1
- pygeai/tests/health/test_clients.py +1 -0
- pygeai/tests/lab/agents/test_clients.py +9 -0
- pygeai/tests/lab/processes/test_clients.py +36 -0
- pygeai/tests/lab/processes/test_mappers.py +3 -0
- pygeai/tests/lab/strategies/test_clients.py +14 -9
- pygeai/tests/migration/test_strategies.py +45 -218
- pygeai/tests/migration/test_tools.py +133 -9
- pygeai/tests/organization/limits/test_clients.py +17 -0
- pygeai/tests/organization/test_clients.py +206 -1
- pygeai/tests/organization/test_managers.py +122 -1
- pygeai/tests/proxy/test_clients.py +2 -0
- pygeai/tests/proxy/test_integration.py +1 -0
- pygeai/tests/snippets/auth/__init__.py +0 -0
- pygeai/tests/snippets/chat/chat_completion_with_reasoning_effort.py +18 -0
- pygeai/tests/snippets/chat/get_response.py +15 -0
- pygeai/tests/snippets/chat/get_response_streaming.py +20 -0
- pygeai/tests/snippets/chat/get_response_with_files.py +16 -0
- pygeai/tests/snippets/chat/get_response_with_tools.py +36 -0
- pygeai/tests/snippets/dbg/__init__.py +0 -0
- pygeai/tests/snippets/dbg/basic_debugging.py +32 -0
- pygeai/tests/snippets/dbg/breakpoint_management.py +48 -0
- pygeai/tests/snippets/dbg/stack_navigation.py +45 -0
- pygeai/tests/snippets/dbg/stepping_example.py +40 -0
- pygeai/tests/snippets/embeddings/cache_example.py +31 -0
- pygeai/tests/snippets/embeddings/cohere_example.py +41 -0
- pygeai/tests/snippets/embeddings/openai_base64_example.py +27 -0
- pygeai/tests/snippets/embeddings/openai_example.py +30 -0
- pygeai/tests/snippets/embeddings/similarity_example.py +42 -0
- pygeai/tests/snippets/evaluation/dataset/__init__.py +0 -0
- pygeai/tests/snippets/evaluation/dataset/complete_workflow_example.py +195 -0
- pygeai/tests/snippets/evaluation/dataset/create_dataset.py +26 -0
- pygeai/tests/snippets/evaluation/dataset/create_dataset_from_file.py +11 -0
- pygeai/tests/snippets/evaluation/dataset/create_dataset_row.py +17 -0
- pygeai/tests/snippets/evaluation/dataset/create_expected_source.py +18 -0
- pygeai/tests/snippets/evaluation/dataset/create_filter_variable.py +19 -0
- pygeai/tests/snippets/evaluation/dataset/delete_dataset.py +9 -0
- pygeai/tests/snippets/evaluation/dataset/delete_dataset_row.py +10 -0
- pygeai/tests/snippets/evaluation/dataset/delete_expected_source.py +15 -0
- pygeai/tests/snippets/evaluation/dataset/delete_filter_variable.py +15 -0
- pygeai/tests/snippets/evaluation/dataset/get_dataset.py +9 -0
- pygeai/tests/snippets/evaluation/dataset/get_dataset_row.py +10 -0
- pygeai/tests/snippets/evaluation/dataset/get_expected_source.py +15 -0
- pygeai/tests/snippets/evaluation/dataset/get_filter_variable.py +15 -0
- pygeai/tests/snippets/evaluation/dataset/list_dataset_rows.py +9 -0
- pygeai/tests/snippets/evaluation/dataset/list_datasets.py +6 -0
- pygeai/tests/snippets/evaluation/dataset/list_expected_sources.py +10 -0
- pygeai/tests/snippets/evaluation/dataset/list_filter_variables.py +10 -0
- pygeai/tests/snippets/evaluation/dataset/update_dataset.py +15 -0
- pygeai/tests/snippets/evaluation/dataset/update_dataset_row.py +20 -0
- pygeai/tests/snippets/evaluation/dataset/update_expected_source.py +18 -0
- pygeai/tests/snippets/evaluation/dataset/update_filter_variable.py +19 -0
- pygeai/tests/snippets/evaluation/dataset/upload_dataset_rows_file.py +10 -0
- pygeai/tests/snippets/evaluation/plan/__init__.py +0 -0
- pygeai/tests/snippets/evaluation/plan/add_plan_system_metric.py +13 -0
- pygeai/tests/snippets/evaluation/plan/complete_workflow_example.py +136 -0
- pygeai/tests/snippets/evaluation/plan/create_evaluation_plan.py +24 -0
- pygeai/tests/snippets/evaluation/plan/create_rag_evaluation_plan.py +22 -0
- pygeai/tests/snippets/evaluation/plan/delete_evaluation_plan.py +9 -0
- pygeai/tests/snippets/evaluation/plan/delete_plan_system_metric.py +13 -0
- pygeai/tests/snippets/evaluation/plan/execute_evaluation_plan.py +11 -0
- pygeai/tests/snippets/evaluation/plan/get_evaluation_plan.py +9 -0
- pygeai/tests/snippets/evaluation/plan/get_plan_system_metric.py +13 -0
- pygeai/tests/snippets/evaluation/plan/get_system_metric.py +9 -0
- pygeai/tests/snippets/evaluation/plan/list_evaluation_plans.py +7 -0
- pygeai/tests/snippets/evaluation/plan/list_plan_system_metrics.py +9 -0
- pygeai/tests/snippets/evaluation/plan/list_system_metrics.py +7 -0
- pygeai/tests/snippets/evaluation/plan/update_evaluation_plan.py +22 -0
- pygeai/tests/snippets/evaluation/plan/update_plan_system_metric.py +14 -0
- pygeai/tests/snippets/evaluation/result/__init__.py +0 -0
- pygeai/tests/snippets/evaluation/result/complete_workflow_example.py +150 -0
- pygeai/tests/snippets/evaluation/result/get_evaluation_result.py +26 -0
- pygeai/tests/snippets/evaluation/result/list_evaluation_results.py +17 -0
- pygeai/tests/snippets/migrate/__init__.py +45 -0
- pygeai/tests/snippets/migrate/agent_migration.py +110 -0
- pygeai/tests/snippets/migrate/assistant_migration.py +64 -0
- pygeai/tests/snippets/migrate/orchestrator_examples.py +179 -0
- pygeai/tests/snippets/migrate/process_migration.py +64 -0
- pygeai/tests/snippets/migrate/project_migration.py +42 -0
- pygeai/tests/snippets/migrate/tool_migration.py +64 -0
- pygeai/tests/snippets/organization/create_project.py +2 -2
- pygeai/tests/snippets/organization/get_memberships.py +12 -0
- pygeai/tests/snippets/organization/get_organization_members.py +6 -0
- pygeai/tests/snippets/organization/get_project_members.py +6 -0
- pygeai/tests/snippets/organization/get_project_memberships.py +12 -0
- pygeai/tests/snippets/organization/get_project_roles.py +6 -0
- {pygeai-0.6.0b6.dist-info → pygeai-0.6.0b10.dist-info}/METADATA +1 -1
- {pygeai-0.6.0b6.dist-info → pygeai-0.6.0b10.dist-info}/RECORD +227 -124
- {pygeai-0.6.0b6.dist-info → pygeai-0.6.0b10.dist-info}/WHEEL +0 -0
- {pygeai-0.6.0b6.dist-info → pygeai-0.6.0b10.dist-info}/entry_points.txt +0 -0
- {pygeai-0.6.0b6.dist-info → pygeai-0.6.0b10.dist-info}/licenses/LICENSE +0 -0
- {pygeai-0.6.0b6.dist-info → pygeai-0.6.0b10.dist-info}/top_level.txt +0 -0
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
from json import JSONDecodeError
|
|
2
1
|
|
|
3
2
|
from pygeai import logger
|
|
4
3
|
from pygeai.core.base.clients import BaseClient
|
|
5
4
|
from pygeai.core.common.exceptions import InvalidAPIResponseException
|
|
5
|
+
from pygeai.core.utils.validators import validate_status_code
|
|
6
|
+
from pygeai.core.utils.parsers import parse_json_response
|
|
6
7
|
from pygeai.organization.limits.endpoints import SET_ORGANIZATION_USAGE_LIMIT_V2, GET_ORGANIZATION_LATEST_USAGE_LIMIT_V2, \
|
|
7
8
|
GET_ALL_ORGANIZATION_USAGE_LIMITS_V2, DELETE_ORGANIZATION_USAGE_LIMIT_V2, SET_ORGANIZATION_HARD_LIMIT_V2, \
|
|
8
9
|
SET_ORGANIZATION_SOFT_LIMIT_V2, SET_ORGANIZATION_RENEWAL_STATUS_V2, SET_PROJECT_USAGE_LIMIT_V2, \
|
|
@@ -33,12 +34,8 @@ class UsageLimitClient(BaseClient):
|
|
|
33
34
|
endpoint=endpoint,
|
|
34
35
|
data=usage_limit
|
|
35
36
|
)
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
return result
|
|
39
|
-
except JSONDecodeError as e:
|
|
40
|
-
logger.error(f"Unable to set usage limit for organization '{organization}': JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
|
|
41
|
-
raise InvalidAPIResponseException(f"Unable to set usage limit for organization '{organization}': {response.text}")
|
|
37
|
+
validate_status_code(response)
|
|
38
|
+
return parse_json_response(response, f"set usage limit for organization", organization=organization)
|
|
42
39
|
|
|
43
40
|
def get_organization_latest_usage_limit(self, organization: str) -> dict:
|
|
44
41
|
"""
|
|
@@ -49,12 +46,8 @@ class UsageLimitClient(BaseClient):
|
|
|
49
46
|
"""
|
|
50
47
|
endpoint = GET_ORGANIZATION_LATEST_USAGE_LIMIT_V2.format(organization=organization)
|
|
51
48
|
response = self.api_service.get(endpoint=endpoint)
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
return result
|
|
55
|
-
except JSONDecodeError as e:
|
|
56
|
-
logger.error(f"Unable to get latest usage limit for organization '{organization}': JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
|
|
57
|
-
raise InvalidAPIResponseException(f"Unable to get latest usage limit for organization '{organization}': {response.text}")
|
|
49
|
+
validate_status_code(response)
|
|
50
|
+
return parse_json_response(response, f"get latest usage limit for organization", organization=organization)
|
|
58
51
|
|
|
59
52
|
def get_all_usage_limits_from_organization(self, organization: str) -> dict:
|
|
60
53
|
"""
|
|
@@ -65,12 +58,8 @@ class UsageLimitClient(BaseClient):
|
|
|
65
58
|
"""
|
|
66
59
|
endpoint = GET_ALL_ORGANIZATION_USAGE_LIMITS_V2.format(organization=organization)
|
|
67
60
|
response = self.api_service.get(endpoint=endpoint)
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
return result
|
|
71
|
-
except JSONDecodeError as e:
|
|
72
|
-
logger.error(f"Unable to get all usage limits for organization '{organization}': JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
|
|
73
|
-
raise InvalidAPIResponseException(f"Unable to get all usage limits for organization '{organization}': {response.text}")
|
|
61
|
+
validate_status_code(response)
|
|
62
|
+
return parse_json_response(response, f"get all usage limits for organization", organization=organization)
|
|
74
63
|
|
|
75
64
|
def delete_usage_limit_from_organization(self, organization: str, limit_id: str) -> dict:
|
|
76
65
|
"""
|
|
@@ -82,12 +71,8 @@ class UsageLimitClient(BaseClient):
|
|
|
82
71
|
"""
|
|
83
72
|
endpoint = DELETE_ORGANIZATION_USAGE_LIMIT_V2.format(organization=organization, id=limit_id)
|
|
84
73
|
response = self.api_service.delete(endpoint=endpoint)
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
return result
|
|
88
|
-
except JSONDecodeError as e:
|
|
89
|
-
logger.error(f"Unable to delete usage limit with ID '{limit_id}' from organization '{organization}': JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
|
|
90
|
-
raise InvalidAPIResponseException(f"Unable to delete usage limit with ID '{limit_id}' from organization '{organization}': {response.text}")
|
|
74
|
+
validate_status_code(response)
|
|
75
|
+
return parse_json_response(response, f"delete usage limit with ID '{limit_id}' from organization", organization=organization)
|
|
91
76
|
|
|
92
77
|
def set_organization_hard_limit(self, organization: str, limit_id: str, hard_limit: float) -> dict:
|
|
93
78
|
"""
|
|
@@ -105,12 +90,8 @@ class UsageLimitClient(BaseClient):
|
|
|
105
90
|
"hardLimit": hard_limit
|
|
106
91
|
}
|
|
107
92
|
)
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
return result
|
|
111
|
-
except JSONDecodeError as e:
|
|
112
|
-
logger.error(f"Unable to set hard limit for usage limit ID '{limit_id}' in organization '{organization}': JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
|
|
113
|
-
raise InvalidAPIResponseException(f"Unable to set hard limit for usage limit ID '{limit_id}' in organization '{organization}': {response.text}")
|
|
93
|
+
validate_status_code(response)
|
|
94
|
+
return parse_json_response(response, f"set hard limit for usage limit ID '{limit_id}' in organization", organization=organization)
|
|
114
95
|
|
|
115
96
|
def set_organization_soft_limit(self, organization: str, limit_id: str, soft_limit: float) -> dict:
|
|
116
97
|
"""
|
|
@@ -128,12 +109,8 @@ class UsageLimitClient(BaseClient):
|
|
|
128
109
|
"softLimit": soft_limit
|
|
129
110
|
}
|
|
130
111
|
)
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
return result
|
|
134
|
-
except JSONDecodeError as e:
|
|
135
|
-
logger.error(f"Unable to set soft limit for usage limit ID '{limit_id}' in organization '{organization}': JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
|
|
136
|
-
raise InvalidAPIResponseException(f"Unable to set soft limit for usage limit ID '{limit_id}' in organization '{organization}': {response.text}")
|
|
112
|
+
validate_status_code(response)
|
|
113
|
+
return parse_json_response(response, f"set soft limit for usage limit ID '{limit_id}' in organization", organization=organization)
|
|
137
114
|
|
|
138
115
|
def set_organization_renewal_status(self, organization: str, limit_id: str, renewal_status: str) -> dict:
|
|
139
116
|
"""
|
|
@@ -151,12 +128,8 @@ class UsageLimitClient(BaseClient):
|
|
|
151
128
|
"renewalStatus": renewal_status
|
|
152
129
|
}
|
|
153
130
|
)
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
return result
|
|
157
|
-
except JSONDecodeError as e:
|
|
158
|
-
logger.error(f"Unable to set renewal status for usage limit ID '{limit_id}' in organization '{organization}': JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
|
|
159
|
-
raise InvalidAPIResponseException(f"Unable to set renewal status for usage limit ID '{limit_id}' in organization '{organization}': {response.text}")
|
|
131
|
+
validate_status_code(response)
|
|
132
|
+
return parse_json_response(response, f"set renewal status for usage limit ID '{limit_id}' in organization", organization=organization)
|
|
160
133
|
|
|
161
134
|
def set_project_usage_limit(self, organization: str, project: str, usage_limit: dict) -> dict:
|
|
162
135
|
"""
|
|
@@ -179,12 +152,8 @@ class UsageLimitClient(BaseClient):
|
|
|
179
152
|
endpoint=endpoint,
|
|
180
153
|
data=usage_limit
|
|
181
154
|
)
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
return result
|
|
185
|
-
except JSONDecodeError as e:
|
|
186
|
-
logger.error(f"Unable to set usage limit for project '{project}' in organization '{organization}': JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
|
|
187
|
-
raise InvalidAPIResponseException(f"Unable to set usage limit for project '{project}' in organization '{organization}': {response.text}")
|
|
155
|
+
validate_status_code(response)
|
|
156
|
+
return parse_json_response(response, f"set usage limit for project '{project}' in organization", organization=organization)
|
|
188
157
|
|
|
189
158
|
def get_all_usage_limits_from_project(self, organization: str, project: str) -> dict:
|
|
190
159
|
"""
|
|
@@ -196,12 +165,8 @@ class UsageLimitClient(BaseClient):
|
|
|
196
165
|
"""
|
|
197
166
|
endpoint = GET_ALL_PROJECT_USAGE_LIMIT_V2.format(organization=organization, project=project)
|
|
198
167
|
response = self.api_service.get(endpoint=endpoint)
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
return result
|
|
202
|
-
except JSONDecodeError as e:
|
|
203
|
-
logger.error(f"Unable to get all usage limits for project '{project}' in organization '{organization}': JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
|
|
204
|
-
raise InvalidAPIResponseException(f"Unable to get all usage limits for project '{project}' in organization '{organization}': {response.text}")
|
|
168
|
+
validate_status_code(response)
|
|
169
|
+
return parse_json_response(response, f"get all usage limits for project '{project}' in organization", organization=organization)
|
|
205
170
|
|
|
206
171
|
def get_latest_usage_limit_from_project(self, organization: str, project: str) -> dict:
|
|
207
172
|
"""
|
|
@@ -213,12 +178,8 @@ class UsageLimitClient(BaseClient):
|
|
|
213
178
|
"""
|
|
214
179
|
endpoint = GET_LATEST_PROJECT_USAGE_LIMIT_V2.format(organization=organization, project=project)
|
|
215
180
|
response = self.api_service.get(endpoint=endpoint)
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
return result
|
|
219
|
-
except JSONDecodeError as e:
|
|
220
|
-
logger.error(f"Unable to get latest usage limit for project '{project}' in organization '{organization}': JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
|
|
221
|
-
raise InvalidAPIResponseException(f"Unable to get latest usage limit for project '{project}' in organization '{organization}': {response.text}")
|
|
181
|
+
validate_status_code(response)
|
|
182
|
+
return parse_json_response(response, f"get latest usage limit for project '{project}' in organization", organization=organization)
|
|
222
183
|
|
|
223
184
|
def get_active_usage_limit_from_project(self, organization: str, project: str) -> dict:
|
|
224
185
|
"""
|
|
@@ -230,12 +191,8 @@ class UsageLimitClient(BaseClient):
|
|
|
230
191
|
"""
|
|
231
192
|
endpoint = GET_PROJECT_ACTIVE_USAGE_LIMIT_V2.format(organization=organization, project=project)
|
|
232
193
|
response = self.api_service.get(endpoint=endpoint)
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
return result
|
|
236
|
-
except JSONDecodeError as e:
|
|
237
|
-
logger.error(f"Unable to get active usage limit for project '{project}' in organization '{organization}': JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
|
|
238
|
-
raise InvalidAPIResponseException(f"Unable to get active usage limit for project '{project}' in organization '{organization}': {response.text}")
|
|
194
|
+
validate_status_code(response)
|
|
195
|
+
return parse_json_response(response, f"get active usage limit for project '{project}' in organization", organization=organization)
|
|
239
196
|
|
|
240
197
|
def delete_usage_limit_from_project(self, organization: str, project: str, limit_id: str) -> dict:
|
|
241
198
|
"""
|
|
@@ -248,12 +205,8 @@ class UsageLimitClient(BaseClient):
|
|
|
248
205
|
"""
|
|
249
206
|
endpoint = DELETE_PROJECT_USAGE_LIMIT_V2.format(organization=organization, project=project, id=limit_id)
|
|
250
207
|
response = self.api_service.delete(endpoint=endpoint)
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
return result
|
|
254
|
-
except JSONDecodeError as e:
|
|
255
|
-
logger.error(f"Unable to delete usage limit with ID '{limit_id}' for project '{project}' in organization '{organization}': JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
|
|
256
|
-
raise InvalidAPIResponseException(f"Unable to delete usage limit with ID '{limit_id}' for project '{project}' in organization '{organization}': {response.text}")
|
|
208
|
+
validate_status_code(response)
|
|
209
|
+
return parse_json_response(response, f"delete usage limit with ID '{limit_id}' for project '{project}' in organization", organization=organization)
|
|
257
210
|
|
|
258
211
|
def set_hard_limit_for_active_usage_limit_from_project(
|
|
259
212
|
self,
|
|
@@ -278,12 +231,8 @@ class UsageLimitClient(BaseClient):
|
|
|
278
231
|
"hardLimit": hard_limit
|
|
279
232
|
}
|
|
280
233
|
)
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
return result
|
|
284
|
-
except JSONDecodeError as e:
|
|
285
|
-
logger.error(f"Unable to set hard limit for usage limit ID '{limit_id}' for project '{project}' in organization '{organization}': JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
|
|
286
|
-
raise InvalidAPIResponseException(f"Unable to set hard limit for usage limit ID '{limit_id}' for project '{project}' in organization '{organization}': {response.text}")
|
|
234
|
+
validate_status_code(response)
|
|
235
|
+
return parse_json_response(response, f"set hard limit for usage limit ID '{limit_id}' for project '{project}' in organization", organization=organization)
|
|
287
236
|
|
|
288
237
|
def set_soft_limit_for_active_usage_limit_from_project(
|
|
289
238
|
self,
|
|
@@ -308,12 +257,8 @@ class UsageLimitClient(BaseClient):
|
|
|
308
257
|
"softLimit": soft_limit
|
|
309
258
|
}
|
|
310
259
|
)
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
return result
|
|
314
|
-
except JSONDecodeError as e:
|
|
315
|
-
logger.error(f"Unable to set soft limit for usage limit ID '{limit_id}' for project '{project}' in organization '{organization}': JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
|
|
316
|
-
raise InvalidAPIResponseException(f"Unable to set soft limit for usage limit ID '{limit_id}' for project '{project}' in organization '{organization}': {response.text}")
|
|
260
|
+
validate_status_code(response)
|
|
261
|
+
return parse_json_response(response, f"set soft limit for usage limit ID '{limit_id}' for project '{project}' in organization", organization=organization)
|
|
317
262
|
|
|
318
263
|
def set_project_renewal_status(self, organization: str, project: str, limit_id: str, renewal_status: str) -> dict:
|
|
319
264
|
"""
|
|
@@ -332,9 +277,5 @@ class UsageLimitClient(BaseClient):
|
|
|
332
277
|
"renewalStatus": renewal_status
|
|
333
278
|
}
|
|
334
279
|
)
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
return result
|
|
338
|
-
except JSONDecodeError as e:
|
|
339
|
-
logger.error(f"Unable to set renewal status for usage limit ID '{limit_id}' for project '{project}' in organization '{organization}': JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
|
|
340
|
-
raise InvalidAPIResponseException(f"Unable to set renewal status for usage limit ID '{limit_id}' for project '{project}' in organization '{organization}': {response.text}")
|
|
280
|
+
validate_status_code(response)
|
|
281
|
+
return parse_json_response(response, f"set renewal status for usage limit ID '{limit_id}' for project '{project}' in organization", organization=organization)
|
pygeai/organization/managers.py
CHANGED
|
@@ -6,7 +6,8 @@ from pygeai.core.base.responses import EmptyResponse
|
|
|
6
6
|
from pygeai.organization.clients import OrganizationClient
|
|
7
7
|
from pygeai.organization.mappers import OrganizationResponseMapper
|
|
8
8
|
from pygeai.organization.responses import AssistantListResponse, ProjectListResponse, ProjectDataResponse, \
|
|
9
|
-
ProjectTokensResponse, ProjectItemListResponse
|
|
9
|
+
ProjectTokensResponse, ProjectItemListResponse, MembershipsResponse, ProjectMembershipsResponse, \
|
|
10
|
+
ProjectRolesResponse, ProjectMembersResponse, OrganizationMembersResponse
|
|
10
11
|
from pygeai.core.common.exceptions import APIError
|
|
11
12
|
|
|
12
13
|
|
|
@@ -247,3 +248,158 @@ class OrganizationManager:
|
|
|
247
248
|
|
|
248
249
|
result = OrganizationResponseMapper.map_to_item_list_response(response_data)
|
|
249
250
|
return result
|
|
251
|
+
|
|
252
|
+
def get_memberships(
|
|
253
|
+
self,
|
|
254
|
+
email: str = None,
|
|
255
|
+
start_page: int = 1,
|
|
256
|
+
page_size: int = 20,
|
|
257
|
+
order_key: str = None,
|
|
258
|
+
order_direction: str = "desc",
|
|
259
|
+
role_types: str = None
|
|
260
|
+
) -> MembershipsResponse:
|
|
261
|
+
"""
|
|
262
|
+
Retrieves a list of Organizations and Projects a user belongs to with their Roles.
|
|
263
|
+
|
|
264
|
+
This method calls `OrganizationClient.get_memberships` to fetch membership data
|
|
265
|
+
and maps the response using `OrganizationResponseMapper.map_to_memberships_response`.
|
|
266
|
+
|
|
267
|
+
:param email: str, optional - The email address of the user to search for (case-insensitive).
|
|
268
|
+
:param start_page: int - The page number for pagination (default is 1).
|
|
269
|
+
:param page_size: int - The number of items per page (default is 20).
|
|
270
|
+
:param order_key: str, optional - Field for sorting. Only 'organizationName' is supported.
|
|
271
|
+
:param order_direction: str - Sort direction: 'asc' or 'desc' (default is 'desc').
|
|
272
|
+
:param role_types: str, optional - Comma-separated list of role types: 'backend', 'frontend' (case-insensitive).
|
|
273
|
+
:return: MembershipsResponse - The mapped response containing organizations and projects with roles.
|
|
274
|
+
:raises APIError: If the API returns errors.
|
|
275
|
+
"""
|
|
276
|
+
response_data = self.__organization_client.get_memberships(
|
|
277
|
+
email=email,
|
|
278
|
+
start_page=start_page,
|
|
279
|
+
page_size=page_size,
|
|
280
|
+
order_key=order_key,
|
|
281
|
+
order_direction=order_direction,
|
|
282
|
+
role_types=role_types
|
|
283
|
+
)
|
|
284
|
+
if ErrorHandler.has_errors(response_data):
|
|
285
|
+
error = ErrorHandler.extract_error(response_data)
|
|
286
|
+
logger.error(f"Error received while retrieving memberships: {error}")
|
|
287
|
+
raise APIError(f"Error received while retrieving memberships: {error}")
|
|
288
|
+
|
|
289
|
+
result = OrganizationResponseMapper.map_to_memberships_response(response_data)
|
|
290
|
+
return result
|
|
291
|
+
|
|
292
|
+
def get_project_memberships(
|
|
293
|
+
self,
|
|
294
|
+
email: str = None,
|
|
295
|
+
start_page: int = 1,
|
|
296
|
+
page_size: int = 20,
|
|
297
|
+
order_key: str = None,
|
|
298
|
+
order_direction: str = "desc",
|
|
299
|
+
role_types: str = None
|
|
300
|
+
) -> ProjectMembershipsResponse:
|
|
301
|
+
"""
|
|
302
|
+
Retrieves a list of Projects and Roles for a user within a specific Organization.
|
|
303
|
+
|
|
304
|
+
This method calls `OrganizationClient.get_project_memberships` to fetch project membership data
|
|
305
|
+
and maps the response using `OrganizationResponseMapper.map_to_project_memberships_response`.
|
|
306
|
+
|
|
307
|
+
:param email: str, optional - The email address of the user to search for (case-insensitive).
|
|
308
|
+
:param start_page: int - The page number for pagination (default is 1).
|
|
309
|
+
:param page_size: int - The number of items per page (default is 20).
|
|
310
|
+
:param order_key: str, optional - Field for sorting. Only 'projectName' is supported.
|
|
311
|
+
:param order_direction: str - Sort direction: 'asc' or 'desc' (default is 'desc').
|
|
312
|
+
:param role_types: str, optional - Comma-separated list of role types: 'backend', 'frontend' (case-insensitive).
|
|
313
|
+
:return: ProjectMembershipsResponse - The mapped response containing projects with roles.
|
|
314
|
+
:raises APIError: If the API returns errors.
|
|
315
|
+
"""
|
|
316
|
+
response_data = self.__organization_client.get_project_memberships(
|
|
317
|
+
email=email,
|
|
318
|
+
start_page=start_page,
|
|
319
|
+
page_size=page_size,
|
|
320
|
+
order_key=order_key,
|
|
321
|
+
order_direction=order_direction,
|
|
322
|
+
role_types=role_types
|
|
323
|
+
)
|
|
324
|
+
if ErrorHandler.has_errors(response_data):
|
|
325
|
+
error = ErrorHandler.extract_error(response_data)
|
|
326
|
+
logger.error(f"Error received while retrieving project memberships: {error}")
|
|
327
|
+
raise APIError(f"Error received while retrieving project memberships: {error}")
|
|
328
|
+
|
|
329
|
+
result = OrganizationResponseMapper.map_to_project_memberships_response(response_data)
|
|
330
|
+
return result
|
|
331
|
+
|
|
332
|
+
def get_project_roles(
|
|
333
|
+
self,
|
|
334
|
+
project_id: str
|
|
335
|
+
) -> ProjectRolesResponse:
|
|
336
|
+
"""
|
|
337
|
+
Retrieves all Roles supported by a specific Project.
|
|
338
|
+
|
|
339
|
+
This method calls `OrganizationClient.get_project_roles` to fetch project roles
|
|
340
|
+
and maps the response using `OrganizationResponseMapper.map_to_project_roles_response`.
|
|
341
|
+
|
|
342
|
+
:param project_id: str - The unique identifier of the project.
|
|
343
|
+
:return: ProjectRolesResponse - The mapped response containing the list of roles.
|
|
344
|
+
:raises APIError: If the API returns errors.
|
|
345
|
+
"""
|
|
346
|
+
response_data = self.__organization_client.get_project_roles(
|
|
347
|
+
project_id=project_id
|
|
348
|
+
)
|
|
349
|
+
if ErrorHandler.has_errors(response_data):
|
|
350
|
+
error = ErrorHandler.extract_error(response_data)
|
|
351
|
+
logger.error(f"Error received while retrieving project roles: {error}")
|
|
352
|
+
raise APIError(f"Error received while retrieving project roles: {error}")
|
|
353
|
+
|
|
354
|
+
result = OrganizationResponseMapper.map_to_project_roles_response(response_data)
|
|
355
|
+
return result
|
|
356
|
+
|
|
357
|
+
def get_project_members(
|
|
358
|
+
self,
|
|
359
|
+
project_id: str
|
|
360
|
+
) -> ProjectMembersResponse:
|
|
361
|
+
"""
|
|
362
|
+
Retrieves all members and their Roles for a specific Project.
|
|
363
|
+
|
|
364
|
+
This method calls `OrganizationClient.get_project_members` to fetch project members
|
|
365
|
+
and maps the response using `OrganizationResponseMapper.map_to_project_members_response`.
|
|
366
|
+
|
|
367
|
+
:param project_id: str - The unique identifier of the project.
|
|
368
|
+
:return: ProjectMembersResponse - The mapped response containing members with their roles.
|
|
369
|
+
:raises APIError: If the API returns errors.
|
|
370
|
+
"""
|
|
371
|
+
response_data = self.__organization_client.get_project_members(
|
|
372
|
+
project_id=project_id
|
|
373
|
+
)
|
|
374
|
+
if ErrorHandler.has_errors(response_data):
|
|
375
|
+
error = ErrorHandler.extract_error(response_data)
|
|
376
|
+
logger.error(f"Error received while retrieving project members: {error}")
|
|
377
|
+
raise APIError(f"Error received while retrieving project members: {error}")
|
|
378
|
+
|
|
379
|
+
result = OrganizationResponseMapper.map_to_project_members_response(response_data)
|
|
380
|
+
return result
|
|
381
|
+
|
|
382
|
+
def get_organization_members(
|
|
383
|
+
self,
|
|
384
|
+
organization_id: str
|
|
385
|
+
) -> OrganizationMembersResponse:
|
|
386
|
+
"""
|
|
387
|
+
Retrieves all members and their Roles for a specific Organization.
|
|
388
|
+
|
|
389
|
+
This method calls `OrganizationClient.get_organization_members` to fetch organization members
|
|
390
|
+
and maps the response using `OrganizationResponseMapper.map_to_organization_members_response`.
|
|
391
|
+
|
|
392
|
+
:param organization_id: str - The unique identifier of the organization.
|
|
393
|
+
:return: OrganizationMembersResponse - The mapped response containing members with their roles.
|
|
394
|
+
:raises APIError: If the API returns errors.
|
|
395
|
+
"""
|
|
396
|
+
response_data = self.__organization_client.get_organization_members(
|
|
397
|
+
organization_id=organization_id
|
|
398
|
+
)
|
|
399
|
+
if ErrorHandler.has_errors(response_data):
|
|
400
|
+
error = ErrorHandler.extract_error(response_data)
|
|
401
|
+
logger.error(f"Error received while retrieving organization members: {error}")
|
|
402
|
+
raise APIError(f"Error received while retrieving organization members: {error}")
|
|
403
|
+
|
|
404
|
+
result = OrganizationResponseMapper.map_to_organization_members_response(response_data)
|
|
405
|
+
return result
|
pygeai/organization/mappers.py
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
from pygeai.core.base.mappers import ModelMapper
|
|
2
|
-
from pygeai.core.models import Assistant, Project
|
|
2
|
+
from pygeai.core.models import Assistant, Project, Role, Member, OrganizationMembership, ProjectMembership
|
|
3
3
|
from pygeai.organization.responses import AssistantListResponse, ProjectListResponse, ProjectDataResponse, \
|
|
4
|
-
ProjectTokensResponse, ProjectItemListResponse
|
|
4
|
+
ProjectTokensResponse, ProjectItemListResponse, MembershipsResponse, ProjectMembershipsResponse, \
|
|
5
|
+
ProjectRolesResponse, ProjectMembersResponse, OrganizationMembersResponse
|
|
5
6
|
|
|
6
7
|
|
|
7
8
|
class OrganizationResponseMapper:
|
|
@@ -76,3 +77,76 @@ class OrganizationResponseMapper:
|
|
|
76
77
|
items=item_list
|
|
77
78
|
)
|
|
78
79
|
|
|
80
|
+
@classmethod
|
|
81
|
+
def map_to_memberships_response(cls, data: dict) -> MembershipsResponse:
|
|
82
|
+
count = data.get("count", 0)
|
|
83
|
+
pages = data.get("pages", 0)
|
|
84
|
+
organizations_data = data.get("organizations", [])
|
|
85
|
+
organizations = []
|
|
86
|
+
|
|
87
|
+
for org_data in organizations_data:
|
|
88
|
+
org = OrganizationMembership.model_validate(org_data)
|
|
89
|
+
organizations.append(org)
|
|
90
|
+
|
|
91
|
+
return MembershipsResponse(
|
|
92
|
+
count=count,
|
|
93
|
+
pages=pages,
|
|
94
|
+
organizations=organizations
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
@classmethod
|
|
98
|
+
def map_to_project_memberships_response(cls, data: dict) -> ProjectMembershipsResponse:
|
|
99
|
+
count = data.get("count", 0)
|
|
100
|
+
pages = data.get("pages", 0)
|
|
101
|
+
projects_data = data.get("projects", [])
|
|
102
|
+
projects = []
|
|
103
|
+
|
|
104
|
+
for project_data in projects_data:
|
|
105
|
+
project = ProjectMembership.model_validate(project_data)
|
|
106
|
+
projects.append(project)
|
|
107
|
+
|
|
108
|
+
return ProjectMembershipsResponse(
|
|
109
|
+
count=count,
|
|
110
|
+
pages=pages,
|
|
111
|
+
projects=projects
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
@classmethod
|
|
115
|
+
def map_to_project_roles_response(cls, data: dict) -> ProjectRolesResponse:
|
|
116
|
+
roles_data = data.get("roles", [])
|
|
117
|
+
roles = []
|
|
118
|
+
|
|
119
|
+
for role_data in roles_data:
|
|
120
|
+
role = Role.model_validate(role_data)
|
|
121
|
+
roles.append(role)
|
|
122
|
+
|
|
123
|
+
return ProjectRolesResponse(
|
|
124
|
+
roles=roles
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
@classmethod
|
|
128
|
+
def map_to_project_members_response(cls, data: dict) -> ProjectMembersResponse:
|
|
129
|
+
members_data = data.get("members", [])
|
|
130
|
+
members = []
|
|
131
|
+
|
|
132
|
+
for member_data in members_data:
|
|
133
|
+
member = Member.model_validate(member_data)
|
|
134
|
+
members.append(member)
|
|
135
|
+
|
|
136
|
+
return ProjectMembersResponse(
|
|
137
|
+
members=members
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
@classmethod
|
|
141
|
+
def map_to_organization_members_response(cls, data: dict) -> OrganizationMembersResponse:
|
|
142
|
+
members_data = data.get("members", [])
|
|
143
|
+
members = []
|
|
144
|
+
|
|
145
|
+
for member_data in members_data:
|
|
146
|
+
member = Member.model_validate(member_data)
|
|
147
|
+
members.append(member)
|
|
148
|
+
|
|
149
|
+
return OrganizationMembersResponse(
|
|
150
|
+
members=members
|
|
151
|
+
)
|
|
152
|
+
|
pygeai/organization/responses.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from pydantic.main import BaseModel
|
|
2
2
|
|
|
3
3
|
from pygeai.core.models import Assistant, Project, ProjectToken, \
|
|
4
|
-
RequestItem
|
|
4
|
+
RequestItem, Role, Member, OrganizationMembership, ProjectMembership
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
class AssistantListResponse(BaseModel):
|
|
@@ -45,3 +45,27 @@ class ProjectItemListResponse(BaseModel):
|
|
|
45
45
|
if self.items is None:
|
|
46
46
|
self.items = []
|
|
47
47
|
self.items.append(item)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class MembershipsResponse(BaseModel):
|
|
51
|
+
count: int
|
|
52
|
+
pages: int
|
|
53
|
+
organizations: list[OrganizationMembership]
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class ProjectMembershipsResponse(BaseModel):
|
|
57
|
+
count: int
|
|
58
|
+
pages: int
|
|
59
|
+
projects: list[ProjectMembership]
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class ProjectRolesResponse(BaseModel):
|
|
63
|
+
roles: list[Role]
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class ProjectMembersResponse(BaseModel):
|
|
67
|
+
members: list[Member]
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
class OrganizationMembersResponse(BaseModel):
|
|
71
|
+
members: list[Member]
|
pygeai/proxy/clients.py
CHANGED
|
@@ -4,6 +4,8 @@ import uuid
|
|
|
4
4
|
import requests
|
|
5
5
|
from urllib3.exceptions import MaxRetryError
|
|
6
6
|
from pygeai.proxy.tool import ProxiedTool
|
|
7
|
+
from pygeai.core.utils.validators import validate_status_code
|
|
8
|
+
from pygeai.core.utils.parsers import parse_json_response
|
|
7
9
|
|
|
8
10
|
|
|
9
11
|
@dataclass
|
|
@@ -150,7 +152,8 @@ class ProxyClient:
|
|
|
150
152
|
response = self.session.request(method, url, **kwargs)
|
|
151
153
|
response.raise_for_status()
|
|
152
154
|
try:
|
|
153
|
-
|
|
155
|
+
validate_status_code(response)
|
|
156
|
+
return parse_json_response(response, "unknown operation")
|
|
154
157
|
except ValueError:
|
|
155
158
|
return response.text
|
|
156
159
|
except requests.exceptions.Timeout:
|
|
@@ -3,7 +3,7 @@ from unittest.mock import patch, MagicMock
|
|
|
3
3
|
from json import JSONDecodeError
|
|
4
4
|
|
|
5
5
|
from pygeai.admin.clients import AdminClient
|
|
6
|
-
from pygeai.core.common.exceptions import InvalidAPIResponseException
|
|
6
|
+
from pygeai.core.common.exceptions import InvalidAPIResponseException, APIResponseError, APIResponseError
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
class TestAdminClient(unittest.TestCase):
|
|
@@ -18,6 +18,7 @@ class TestAdminClient(unittest.TestCase):
|
|
|
18
18
|
@patch('pygeai.core.services.rest.ApiService.get')
|
|
19
19
|
def test_validate_api_token_success(self, mock_get):
|
|
20
20
|
self.mock_response.json.return_value = {"organizationId": "org-123", "projectId": "proj-123"}
|
|
21
|
+
self.mock_response.status_code = 200
|
|
21
22
|
mock_get.return_value = self.mock_response
|
|
22
23
|
|
|
23
24
|
result = self.client.validate_api_token()
|
|
@@ -32,13 +33,14 @@ class TestAdminClient(unittest.TestCase):
|
|
|
32
33
|
self.mock_response.text = "Invalid response"
|
|
33
34
|
mock_get.return_value = self.mock_response
|
|
34
35
|
|
|
35
|
-
with self.assertRaises(
|
|
36
|
+
with self.assertRaises(APIResponseError) as context:
|
|
36
37
|
self.client.validate_api_token()
|
|
37
|
-
self.assertIn("Unable to validate API token", str(context.exception))
|
|
38
|
+
self.assertIn("API returned an error", str(context.exception)) # "Unable to validate API token", str(context.exception))
|
|
38
39
|
|
|
39
40
|
@patch('pygeai.core.services.rest.ApiService.get')
|
|
40
41
|
def test_get_authorized_organizations_success(self, mock_get):
|
|
41
42
|
self.mock_response.json.return_value = {"organizations": ["org1", "org2"]}
|
|
43
|
+
self.mock_response.status_code = 200
|
|
42
44
|
mock_get.return_value = self.mock_response
|
|
43
45
|
|
|
44
46
|
result = self.client.get_authorized_organizations()
|
|
@@ -53,13 +55,14 @@ class TestAdminClient(unittest.TestCase):
|
|
|
53
55
|
self.mock_response.text = "Invalid response"
|
|
54
56
|
mock_get.return_value = self.mock_response
|
|
55
57
|
|
|
56
|
-
with self.assertRaises(
|
|
58
|
+
with self.assertRaises(APIResponseError) as context:
|
|
57
59
|
self.client.get_authorized_organizations()
|
|
58
|
-
self.assertIn("Unable to retrieve authorized organizations", str(context.exception))
|
|
60
|
+
self.assertIn("API returned an error", str(context.exception)) # "Unable to retrieve authorized organizations", str(context.exception))
|
|
59
61
|
|
|
60
62
|
@patch('pygeai.core.services.rest.ApiService.get')
|
|
61
63
|
def test_get_authorized_projects_by_organization_success(self, mock_get):
|
|
62
64
|
self.mock_response.json.return_value = {"projects": ["proj1", "proj2"]}
|
|
65
|
+
self.mock_response.status_code = 200
|
|
63
66
|
mock_get.return_value = self.mock_response
|
|
64
67
|
|
|
65
68
|
result = self.client.get_authorized_projects_by_organization("org-123")
|
|
@@ -76,13 +79,14 @@ class TestAdminClient(unittest.TestCase):
|
|
|
76
79
|
self.mock_response.text = "Invalid response"
|
|
77
80
|
mock_get.return_value = self.mock_response
|
|
78
81
|
|
|
79
|
-
with self.assertRaises(
|
|
82
|
+
with self.assertRaises(APIResponseError) as context:
|
|
80
83
|
self.client.get_authorized_projects_by_organization("org-123")
|
|
81
|
-
self.assertIn("Unable to retrieve authorized projects for organization", str(context.exception))
|
|
84
|
+
self.assertIn("API returned an error", str(context.exception)) # "Unable to retrieve authorized projects for organization", str(context.exception))
|
|
82
85
|
|
|
83
86
|
@patch('pygeai.core.services.rest.ApiService.get')
|
|
84
87
|
def test_get_project_visibility_success(self, mock_get):
|
|
85
88
|
self.mock_response.json.return_value = {}
|
|
89
|
+
self.mock_response.status_code = 200
|
|
86
90
|
mock_get.return_value = self.mock_response
|
|
87
91
|
|
|
88
92
|
result = self.client.get_project_visibility(
|
|
@@ -105,13 +109,14 @@ class TestAdminClient(unittest.TestCase):
|
|
|
105
109
|
self.mock_response.text = "Forbidden"
|
|
106
110
|
mock_get.return_value = self.mock_response
|
|
107
111
|
|
|
108
|
-
with self.assertRaises(
|
|
112
|
+
with self.assertRaises(APIResponseError) as context:
|
|
109
113
|
self.client.get_project_visibility("org-123", "proj-456", "token-789")
|
|
110
|
-
self.assertIn("Unable to retrieve project visibility", str(context.exception))
|
|
114
|
+
self.assertIn("API returned an error", str(context.exception)) # "Unable to retrieve project visibility", str(context.exception))
|
|
111
115
|
|
|
112
116
|
@patch('pygeai.core.services.rest.ApiService.get')
|
|
113
117
|
def test_get_project_api_token_success(self, mock_get):
|
|
114
118
|
self.mock_response.json.return_value = {"apiToken": "api-token-123"}
|
|
119
|
+
self.mock_response.status_code = 200
|
|
115
120
|
mock_get.return_value = self.mock_response
|
|
116
121
|
|
|
117
122
|
result = self.client.get_project_api_token(
|
|
@@ -134,9 +139,9 @@ class TestAdminClient(unittest.TestCase):
|
|
|
134
139
|
self.mock_response.text = "Unauthorized"
|
|
135
140
|
mock_get.return_value = self.mock_response
|
|
136
141
|
|
|
137
|
-
with self.assertRaises(
|
|
142
|
+
with self.assertRaises(APIResponseError) as context:
|
|
138
143
|
self.client.get_project_api_token("org-123", "proj-456", "token-789")
|
|
139
|
-
self.assertIn("Unable to retrieve project API token", str(context.exception))
|
|
144
|
+
self.assertIn("API returned an error", str(context.exception)) # "Unable to retrieve project API token", str(context.exception))
|
|
140
145
|
|
|
141
146
|
|
|
142
147
|
if __name__ == '__main__':
|