codemie-sdk-python 0.1.418__tar.gz → 0.1.419__tar.gz
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.
- {codemie_sdk_python-0.1.418 → codemie_sdk_python-0.1.419}/PKG-INFO +1 -1
- {codemie_sdk_python-0.1.418 → codemie_sdk_python-0.1.419}/pyproject.toml +1 -1
- {codemie_sdk_python-0.1.418 → codemie_sdk_python-0.1.419}/src/codemie_sdk/client/client.py +4 -0
- codemie_sdk_python-0.1.419/src/codemie_sdk/models/project.py +233 -0
- {codemie_sdk_python-0.1.418 → codemie_sdk_python-0.1.419}/src/codemie_sdk/models/user.py +1 -0
- codemie_sdk_python-0.1.419/src/codemie_sdk/services/project.py +390 -0
- {codemie_sdk_python-0.1.418 → codemie_sdk_python-0.1.419}/src/codemie_sdk/utils/http.py +39 -1
- {codemie_sdk_python-0.1.418 → codemie_sdk_python-0.1.419}/README.md +0 -0
- {codemie_sdk_python-0.1.418 → codemie_sdk_python-0.1.419}/src/codemie_sdk/__init__.py +0 -0
- {codemie_sdk_python-0.1.418 → codemie_sdk_python-0.1.419}/src/codemie_sdk/auth/__init__.py +0 -0
- {codemie_sdk_python-0.1.418 → codemie_sdk_python-0.1.419}/src/codemie_sdk/auth/credentials.py +0 -0
- {codemie_sdk_python-0.1.418 → codemie_sdk_python-0.1.419}/src/codemie_sdk/client/__init__.py +0 -0
- {codemie_sdk_python-0.1.418 → codemie_sdk_python-0.1.419}/src/codemie_sdk/exceptions.py +0 -0
- {codemie_sdk_python-0.1.418 → codemie_sdk_python-0.1.419}/src/codemie_sdk/models/__init__.py +0 -0
- {codemie_sdk_python-0.1.418 → codemie_sdk_python-0.1.419}/src/codemie_sdk/models/admin.py +0 -0
- {codemie_sdk_python-0.1.418 → codemie_sdk_python-0.1.419}/src/codemie_sdk/models/analytics.py +0 -0
- {codemie_sdk_python-0.1.418 → codemie_sdk_python-0.1.419}/src/codemie_sdk/models/assistant.py +0 -0
- {codemie_sdk_python-0.1.418 → codemie_sdk_python-0.1.419}/src/codemie_sdk/models/categories.py +0 -0
- {codemie_sdk_python-0.1.418 → codemie_sdk_python-0.1.419}/src/codemie_sdk/models/common.py +0 -0
- {codemie_sdk_python-0.1.418 → codemie_sdk_python-0.1.419}/src/codemie_sdk/models/conversation.py +0 -0
- {codemie_sdk_python-0.1.418 → codemie_sdk_python-0.1.419}/src/codemie_sdk/models/datasource.py +0 -0
- {codemie_sdk_python-0.1.418 → codemie_sdk_python-0.1.419}/src/codemie_sdk/models/errors.py +0 -0
- {codemie_sdk_python-0.1.418 → codemie_sdk_python-0.1.419}/src/codemie_sdk/models/file_operation.py +0 -0
- {codemie_sdk_python-0.1.418 → codemie_sdk_python-0.1.419}/src/codemie_sdk/models/guardrails.py +0 -0
- {codemie_sdk_python-0.1.418 → codemie_sdk_python-0.1.419}/src/codemie_sdk/models/integration.py +0 -0
- {codemie_sdk_python-0.1.418 → codemie_sdk_python-0.1.419}/src/codemie_sdk/models/llm.py +0 -0
- {codemie_sdk_python-0.1.418 → codemie_sdk_python-0.1.419}/src/codemie_sdk/models/mermaid.py +0 -0
- {codemie_sdk_python-0.1.418 → codemie_sdk_python-0.1.419}/src/codemie_sdk/models/skill.py +0 -0
- {codemie_sdk_python-0.1.418 → codemie_sdk_python-0.1.419}/src/codemie_sdk/models/task.py +0 -0
- {codemie_sdk_python-0.1.418 → codemie_sdk_python-0.1.419}/src/codemie_sdk/models/vendor_assistant.py +0 -0
- {codemie_sdk_python-0.1.418 → codemie_sdk_python-0.1.419}/src/codemie_sdk/models/vendor_guardrail.py +0 -0
- {codemie_sdk_python-0.1.418 → codemie_sdk_python-0.1.419}/src/codemie_sdk/models/vendor_knowledgebase.py +0 -0
- {codemie_sdk_python-0.1.418 → codemie_sdk_python-0.1.419}/src/codemie_sdk/models/vendor_workflow.py +0 -0
- {codemie_sdk_python-0.1.418 → codemie_sdk_python-0.1.419}/src/codemie_sdk/models/workflow.py +0 -0
- {codemie_sdk_python-0.1.418 → codemie_sdk_python-0.1.419}/src/codemie_sdk/models/workflow_execution_payload.py +0 -0
- {codemie_sdk_python-0.1.418 → codemie_sdk_python-0.1.419}/src/codemie_sdk/models/workflow_state.py +0 -0
- {codemie_sdk_python-0.1.418 → codemie_sdk_python-0.1.419}/src/codemie_sdk/models/workflow_thoughts.py +0 -0
- {codemie_sdk_python-0.1.418 → codemie_sdk_python-0.1.419}/src/codemie_sdk/services/admin.py +0 -0
- {codemie_sdk_python-0.1.418 → codemie_sdk_python-0.1.419}/src/codemie_sdk/services/analytics.py +0 -0
- {codemie_sdk_python-0.1.418 → codemie_sdk_python-0.1.419}/src/codemie_sdk/services/assistant.py +0 -0
- {codemie_sdk_python-0.1.418 → codemie_sdk_python-0.1.419}/src/codemie_sdk/services/categories.py +0 -0
- {codemie_sdk_python-0.1.418 → codemie_sdk_python-0.1.419}/src/codemie_sdk/services/codemie_guardrails.py +0 -0
- {codemie_sdk_python-0.1.418 → codemie_sdk_python-0.1.419}/src/codemie_sdk/services/conversation.py +0 -0
- {codemie_sdk_python-0.1.418 → codemie_sdk_python-0.1.419}/src/codemie_sdk/services/datasource.py +0 -0
- {codemie_sdk_python-0.1.418 → codemie_sdk_python-0.1.419}/src/codemie_sdk/services/files.py +0 -0
- {codemie_sdk_python-0.1.418 → codemie_sdk_python-0.1.419}/src/codemie_sdk/services/integration.py +0 -0
- {codemie_sdk_python-0.1.418 → codemie_sdk_python-0.1.419}/src/codemie_sdk/services/llm.py +0 -0
- {codemie_sdk_python-0.1.418 → codemie_sdk_python-0.1.419}/src/codemie_sdk/services/mermaid.py +0 -0
- {codemie_sdk_python-0.1.418 → codemie_sdk_python-0.1.419}/src/codemie_sdk/services/skill.py +0 -0
- {codemie_sdk_python-0.1.418 → codemie_sdk_python-0.1.419}/src/codemie_sdk/services/task.py +0 -0
- {codemie_sdk_python-0.1.418 → codemie_sdk_python-0.1.419}/src/codemie_sdk/services/user.py +0 -0
- {codemie_sdk_python-0.1.418 → codemie_sdk_python-0.1.419}/src/codemie_sdk/services/vendor_assistant.py +0 -0
- {codemie_sdk_python-0.1.418 → codemie_sdk_python-0.1.419}/src/codemie_sdk/services/vendor_guardrail.py +0 -0
- {codemie_sdk_python-0.1.418 → codemie_sdk_python-0.1.419}/src/codemie_sdk/services/vendor_knowledgebase.py +0 -0
- {codemie_sdk_python-0.1.418 → codemie_sdk_python-0.1.419}/src/codemie_sdk/services/vendor_workflow.py +0 -0
- {codemie_sdk_python-0.1.418 → codemie_sdk_python-0.1.419}/src/codemie_sdk/services/webhook.py +0 -0
- {codemie_sdk_python-0.1.418 → codemie_sdk_python-0.1.419}/src/codemie_sdk/services/workflow.py +0 -0
- {codemie_sdk_python-0.1.418 → codemie_sdk_python-0.1.419}/src/codemie_sdk/services/workflow_execution.py +0 -0
- {codemie_sdk_python-0.1.418 → codemie_sdk_python-0.1.419}/src/codemie_sdk/services/workflow_execution_state.py +0 -0
- {codemie_sdk_python-0.1.418 → codemie_sdk_python-0.1.419}/src/codemie_sdk/utils/__init__.py +0 -0
|
@@ -12,6 +12,7 @@ from ..services.datasource import DatasourceService
|
|
|
12
12
|
from ..services.llm import LLMService
|
|
13
13
|
from ..services.integration import IntegrationService
|
|
14
14
|
from ..services.mermaid import MermaidService
|
|
15
|
+
from ..services.project import ProjectService
|
|
15
16
|
from ..services.skill import SkillService
|
|
16
17
|
from ..services.task import TaskService
|
|
17
18
|
from ..services.user import UserService
|
|
@@ -98,6 +99,9 @@ class CodeMieClient:
|
|
|
98
99
|
self.integrations = IntegrationService(
|
|
99
100
|
self._api_domain, self._token, verify_ssl=verify_ssl
|
|
100
101
|
)
|
|
102
|
+
self.projects = ProjectService(
|
|
103
|
+
self._api_domain, self._token, verify_ssl=verify_ssl
|
|
104
|
+
)
|
|
101
105
|
self.skills = SkillService(self._api_domain, self._token, verify_ssl=verify_ssl)
|
|
102
106
|
self.tasks = TaskService(self._api_domain, self._token, verify_ssl=verify_ssl)
|
|
103
107
|
self.users = UserService(self._api_domain, self._token, verify_ssl=verify_ssl)
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
# Copyright 2026 EPAM Systems, Inc. ("EPAM")
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
"""Project management models for the CodeMie SDK."""
|
|
16
|
+
|
|
17
|
+
from datetime import datetime
|
|
18
|
+
from typing import Literal, Optional
|
|
19
|
+
from uuid import UUID
|
|
20
|
+
|
|
21
|
+
from pydantic import BaseModel, ConfigDict, Field
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class ProjectCounters(BaseModel):
|
|
25
|
+
"""Resource counters for a project."""
|
|
26
|
+
|
|
27
|
+
model_config = ConfigDict(extra="ignore")
|
|
28
|
+
|
|
29
|
+
assistants_count: int = 0
|
|
30
|
+
workflows_count: int = 0
|
|
31
|
+
integrations_count: int = 0
|
|
32
|
+
datasources_count: int = 0
|
|
33
|
+
skills_count: int = 0
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class ProjectMember(BaseModel):
|
|
37
|
+
"""Project member with role."""
|
|
38
|
+
|
|
39
|
+
model_config = ConfigDict(extra="ignore")
|
|
40
|
+
|
|
41
|
+
user_id: str
|
|
42
|
+
is_project_admin: bool
|
|
43
|
+
date: Optional[datetime] = None
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class ProjectListItem(BaseModel):
|
|
47
|
+
"""Project list response item."""
|
|
48
|
+
|
|
49
|
+
model_config = ConfigDict(extra="ignore")
|
|
50
|
+
|
|
51
|
+
name: str
|
|
52
|
+
description: Optional[str] = None
|
|
53
|
+
project_type: str
|
|
54
|
+
created_by: Optional[str] = None
|
|
55
|
+
user_count: int
|
|
56
|
+
admin_count: int
|
|
57
|
+
created_at: Optional[datetime] = None
|
|
58
|
+
counters: Optional[ProjectCounters] = None
|
|
59
|
+
cost_center_id: Optional[UUID] = None
|
|
60
|
+
cost_center_name: Optional[str] = None
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
class PaginationInfo(BaseModel):
|
|
64
|
+
"""Pagination metadata for list responses."""
|
|
65
|
+
|
|
66
|
+
model_config = ConfigDict(extra="ignore")
|
|
67
|
+
|
|
68
|
+
total: int
|
|
69
|
+
page: int
|
|
70
|
+
per_page: int
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
class PaginatedProjectListResponse(BaseModel):
|
|
74
|
+
"""Paginated project list response."""
|
|
75
|
+
|
|
76
|
+
model_config = ConfigDict(extra="ignore")
|
|
77
|
+
|
|
78
|
+
data: list[ProjectListItem]
|
|
79
|
+
pagination: PaginationInfo
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
class ProjectDetailResponse(BaseModel):
|
|
83
|
+
"""Project detail response with member list."""
|
|
84
|
+
|
|
85
|
+
model_config = ConfigDict(extra="ignore")
|
|
86
|
+
|
|
87
|
+
name: str
|
|
88
|
+
description: Optional[str] = None
|
|
89
|
+
project_type: str
|
|
90
|
+
created_by: Optional[str] = None
|
|
91
|
+
user_count: int
|
|
92
|
+
admin_count: int
|
|
93
|
+
created_at: Optional[datetime] = None
|
|
94
|
+
cost_center_id: Optional[UUID] = None
|
|
95
|
+
cost_center_name: Optional[str] = None
|
|
96
|
+
members: list[ProjectMember]
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
class ProjectCreateRequest(BaseModel):
|
|
100
|
+
"""Request to create a new project."""
|
|
101
|
+
|
|
102
|
+
model_config = ConfigDict(extra="ignore")
|
|
103
|
+
|
|
104
|
+
name: str
|
|
105
|
+
description: str = Field(description="Project description")
|
|
106
|
+
cost_center_id: Optional[UUID] = None
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
class ProjectCreateResponse(BaseModel):
|
|
110
|
+
"""Response after creating a project."""
|
|
111
|
+
|
|
112
|
+
model_config = ConfigDict(extra="ignore")
|
|
113
|
+
|
|
114
|
+
name: str
|
|
115
|
+
description: str
|
|
116
|
+
project_type: str
|
|
117
|
+
created_by: str
|
|
118
|
+
created_at: datetime
|
|
119
|
+
cost_center_id: Optional[UUID] = None
|
|
120
|
+
cost_center_name: Optional[str] = None
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
# PATCH /v1/projects/{name} returns the same shape as the create response
|
|
124
|
+
ProjectUpdateResponse = ProjectCreateResponse
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
class ProjectUpdateRequest(BaseModel):
|
|
128
|
+
"""Request to update a project."""
|
|
129
|
+
|
|
130
|
+
model_config = ConfigDict(extra="ignore")
|
|
131
|
+
|
|
132
|
+
name: Optional[str] = None
|
|
133
|
+
description: Optional[str] = None
|
|
134
|
+
cost_center_id: Optional[UUID] = None
|
|
135
|
+
clear_cost_center: bool = False
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
class ProjectDeleteResponse(BaseModel):
|
|
139
|
+
"""Response after deleting a project."""
|
|
140
|
+
|
|
141
|
+
model_config = ConfigDict(extra="ignore")
|
|
142
|
+
|
|
143
|
+
message: str
|
|
144
|
+
name: str
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
class ProjectAssignmentRequest(BaseModel):
|
|
148
|
+
"""Request to assign a user to a project."""
|
|
149
|
+
|
|
150
|
+
model_config = ConfigDict(extra="ignore")
|
|
151
|
+
|
|
152
|
+
user_id: str
|
|
153
|
+
is_project_admin: bool
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
class ProjectAssignmentUpdateRequest(BaseModel):
|
|
157
|
+
"""Request to update a user's project role."""
|
|
158
|
+
|
|
159
|
+
model_config = ConfigDict(extra="ignore")
|
|
160
|
+
|
|
161
|
+
is_project_admin: bool
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
class ProjectAssignmentResponse(BaseModel):
|
|
165
|
+
"""Response after project assignment operation."""
|
|
166
|
+
|
|
167
|
+
model_config = ConfigDict(extra="ignore")
|
|
168
|
+
|
|
169
|
+
message: str
|
|
170
|
+
user_id: str
|
|
171
|
+
project_name: str
|
|
172
|
+
is_project_admin: Optional[bool] = None
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
class BulkAssignmentUserItem(BaseModel):
|
|
176
|
+
"""Single user entry in bulk assignment request."""
|
|
177
|
+
|
|
178
|
+
model_config = ConfigDict(extra="ignore")
|
|
179
|
+
|
|
180
|
+
user_id: str
|
|
181
|
+
is_project_admin: bool
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
class BulkAssignmentRequest(BaseModel):
|
|
185
|
+
"""Bulk assignment request body."""
|
|
186
|
+
|
|
187
|
+
model_config = ConfigDict(extra="ignore")
|
|
188
|
+
|
|
189
|
+
users: list[BulkAssignmentUserItem] = Field(
|
|
190
|
+
...,
|
|
191
|
+
min_length=1,
|
|
192
|
+
max_length=1000,
|
|
193
|
+
description="List of users to assign/update (1-1000)",
|
|
194
|
+
)
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
class BulkAssignmentResultItem(BaseModel):
|
|
198
|
+
"""Per-user result in bulk assignment response."""
|
|
199
|
+
|
|
200
|
+
model_config = ConfigDict(extra="ignore")
|
|
201
|
+
|
|
202
|
+
user_id: str
|
|
203
|
+
action: Literal["assigned", "updated", "removed"]
|
|
204
|
+
is_project_admin: Optional[bool] = None
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
class BulkAssignmentResponse(BaseModel):
|
|
208
|
+
"""Response for bulk assignment operations."""
|
|
209
|
+
|
|
210
|
+
model_config = ConfigDict(extra="ignore")
|
|
211
|
+
|
|
212
|
+
message: str
|
|
213
|
+
project_name: str
|
|
214
|
+
total: int
|
|
215
|
+
results: list[BulkAssignmentResultItem]
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
class CsvImportRowResult(BaseModel):
|
|
219
|
+
"""Per-row result from a CSV import validation."""
|
|
220
|
+
|
|
221
|
+
model_config = ConfigDict(extra="ignore")
|
|
222
|
+
|
|
223
|
+
email: str
|
|
224
|
+
role: str
|
|
225
|
+
error: Optional[str] = None
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
class CsvImportValidationResponse(BaseModel):
|
|
229
|
+
"""Response for CSV import dry-run validation."""
|
|
230
|
+
|
|
231
|
+
model_config = ConfigDict(extra="ignore")
|
|
232
|
+
|
|
233
|
+
users: list[CsvImportRowResult]
|
|
@@ -14,6 +14,7 @@ class User(BaseModel):
|
|
|
14
14
|
)
|
|
15
15
|
name: str = Field(description="Full name of the user")
|
|
16
16
|
username: str = Field(description="Username for authentication")
|
|
17
|
+
email: str = Field(description="User email")
|
|
17
18
|
is_admin: bool = Field(
|
|
18
19
|
description="Whether the user has admin privileges", validation_alias="isAdmin"
|
|
19
20
|
)
|
|
@@ -0,0 +1,390 @@
|
|
|
1
|
+
# Copyright 2026 EPAM Systems, Inc. ("EPAM")
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
"""Project management service for the CodeMie SDK."""
|
|
16
|
+
|
|
17
|
+
from typing import Literal, Optional
|
|
18
|
+
from uuid import UUID
|
|
19
|
+
|
|
20
|
+
from ..models.project import (
|
|
21
|
+
BulkAssignmentRequest,
|
|
22
|
+
BulkAssignmentResponse,
|
|
23
|
+
BulkAssignmentUserItem,
|
|
24
|
+
CsvImportValidationResponse,
|
|
25
|
+
PaginatedProjectListResponse,
|
|
26
|
+
ProjectAssignmentRequest,
|
|
27
|
+
ProjectAssignmentResponse,
|
|
28
|
+
ProjectAssignmentUpdateRequest,
|
|
29
|
+
ProjectCreateRequest,
|
|
30
|
+
ProjectCreateResponse,
|
|
31
|
+
ProjectDeleteResponse,
|
|
32
|
+
ProjectDetailResponse,
|
|
33
|
+
ProjectUpdateRequest,
|
|
34
|
+
ProjectUpdateResponse,
|
|
35
|
+
)
|
|
36
|
+
from ..utils.http import ApiRequestHandler
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class ProjectService:
|
|
40
|
+
"""Service for managing projects in CodeMie."""
|
|
41
|
+
|
|
42
|
+
def __init__(self, api_domain: str, token: str, verify_ssl: bool = True):
|
|
43
|
+
"""Initialize the ProjectService.
|
|
44
|
+
|
|
45
|
+
Args:
|
|
46
|
+
api_domain: Base URL for the CodeMie API
|
|
47
|
+
token: Authentication token
|
|
48
|
+
verify_ssl: Whether to verify SSL certificates
|
|
49
|
+
"""
|
|
50
|
+
self._api = ApiRequestHandler(api_domain, token, verify_ssl)
|
|
51
|
+
|
|
52
|
+
def create_project(
|
|
53
|
+
self,
|
|
54
|
+
name: str,
|
|
55
|
+
description: str,
|
|
56
|
+
cost_center_id: Optional[UUID] = None,
|
|
57
|
+
) -> ProjectCreateResponse:
|
|
58
|
+
"""Create a new shared project.
|
|
59
|
+
|
|
60
|
+
Args:
|
|
61
|
+
name: Project name
|
|
62
|
+
description: Project description
|
|
63
|
+
cost_center_id: Optional cost center ID
|
|
64
|
+
|
|
65
|
+
Returns:
|
|
66
|
+
ProjectCreateResponse with project details
|
|
67
|
+
|
|
68
|
+
Raises:
|
|
69
|
+
HTTPException: If project creation fails
|
|
70
|
+
"""
|
|
71
|
+
payload = ProjectCreateRequest(
|
|
72
|
+
name=name,
|
|
73
|
+
description=description,
|
|
74
|
+
cost_center_id=cost_center_id,
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
return self._api.post(
|
|
78
|
+
"/v1/projects",
|
|
79
|
+
response_model=ProjectCreateResponse,
|
|
80
|
+
json_data=payload.model_dump(exclude_none=True),
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
def list_projects(
|
|
84
|
+
self,
|
|
85
|
+
search: Optional[str] = None,
|
|
86
|
+
page: int = 0,
|
|
87
|
+
per_page: int = 20,
|
|
88
|
+
include_counters: bool = True,
|
|
89
|
+
sort_by: Optional[Literal["name", "created_at"]] = None,
|
|
90
|
+
sort_order: Literal["asc", "desc"] = "asc",
|
|
91
|
+
) -> PaginatedProjectListResponse:
|
|
92
|
+
"""List projects visible to current user with pagination and search.
|
|
93
|
+
|
|
94
|
+
Args:
|
|
95
|
+
search: Search by project name or description (substring match)
|
|
96
|
+
page: Page number (0-indexed)
|
|
97
|
+
per_page: Items per page (10-100)
|
|
98
|
+
sort_by: Sort field (name or created_at); ignored when search is active
|
|
99
|
+
sort_order: Sort direction (asc or desc)
|
|
100
|
+
|
|
101
|
+
Returns:
|
|
102
|
+
PaginatedProjectListResponse with projects and pagination info
|
|
103
|
+
"""
|
|
104
|
+
params = {
|
|
105
|
+
"page": page,
|
|
106
|
+
"per_page": per_page,
|
|
107
|
+
"include_counters": include_counters,
|
|
108
|
+
"sort_order": sort_order,
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if search is not None:
|
|
112
|
+
params["search"] = search
|
|
113
|
+
if sort_by is not None:
|
|
114
|
+
params["sort_by"] = sort_by
|
|
115
|
+
|
|
116
|
+
return self._api.get(
|
|
117
|
+
"/v1/projects",
|
|
118
|
+
response_model=PaginatedProjectListResponse,
|
|
119
|
+
params=params,
|
|
120
|
+
wrap_response=False,
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
def get_project_detail(
|
|
124
|
+
self,
|
|
125
|
+
project_name: str,
|
|
126
|
+
) -> ProjectDetailResponse:
|
|
127
|
+
"""Get project detail with member list.
|
|
128
|
+
|
|
129
|
+
Args:
|
|
130
|
+
project_name: Project name
|
|
131
|
+
|
|
132
|
+
Returns:
|
|
133
|
+
ProjectDetailResponse with project details and member list
|
|
134
|
+
|
|
135
|
+
Raises:
|
|
136
|
+
HTTPException: If project not found or user doesn't have access (404)
|
|
137
|
+
"""
|
|
138
|
+
return self._api.get(
|
|
139
|
+
f"/v1/projects/{project_name}",
|
|
140
|
+
response_model=ProjectDetailResponse,
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
def update_project(
|
|
144
|
+
self,
|
|
145
|
+
project_name: str,
|
|
146
|
+
name: Optional[str] = None,
|
|
147
|
+
description: Optional[str] = None,
|
|
148
|
+
cost_center_id: Optional[UUID] = None,
|
|
149
|
+
clear_cost_center: bool = False,
|
|
150
|
+
) -> ProjectUpdateResponse:
|
|
151
|
+
"""Update a project.
|
|
152
|
+
|
|
153
|
+
Args:
|
|
154
|
+
project_name: Current project name
|
|
155
|
+
name: New project name (optional)
|
|
156
|
+
description: New description (optional)
|
|
157
|
+
cost_center_id: New cost center ID (optional)
|
|
158
|
+
clear_cost_center: Set to True to remove cost center
|
|
159
|
+
|
|
160
|
+
Returns:
|
|
161
|
+
ProjectUpdateResponse with updated project details
|
|
162
|
+
|
|
163
|
+
Raises:
|
|
164
|
+
HTTPException: If project update fails
|
|
165
|
+
"""
|
|
166
|
+
payload = ProjectUpdateRequest(
|
|
167
|
+
name=name,
|
|
168
|
+
description=description,
|
|
169
|
+
cost_center_id=cost_center_id,
|
|
170
|
+
clear_cost_center=clear_cost_center,
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
return self._api.patch(
|
|
174
|
+
f"/v1/projects/{project_name}",
|
|
175
|
+
response_model=ProjectUpdateResponse,
|
|
176
|
+
json_data=payload.model_dump(exclude_none=True),
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
def delete_project(self, project_name: str) -> ProjectDeleteResponse:
|
|
180
|
+
"""Hard-delete a project if it has no assigned resources.
|
|
181
|
+
|
|
182
|
+
Args:
|
|
183
|
+
project_name: Project name
|
|
184
|
+
|
|
185
|
+
Returns:
|
|
186
|
+
ProjectDeleteResponse with deletion confirmation
|
|
187
|
+
|
|
188
|
+
Raises:
|
|
189
|
+
HTTPException: If project has assigned resources (409) or is personal (403)
|
|
190
|
+
"""
|
|
191
|
+
return self._api.delete(
|
|
192
|
+
f"/v1/projects/{project_name}",
|
|
193
|
+
response_model=ProjectDeleteResponse,
|
|
194
|
+
)
|
|
195
|
+
|
|
196
|
+
# Assignment endpoints
|
|
197
|
+
|
|
198
|
+
def assign_user_to_project(
|
|
199
|
+
self,
|
|
200
|
+
project_name: str,
|
|
201
|
+
user_id: str,
|
|
202
|
+
is_project_admin: bool,
|
|
203
|
+
) -> ProjectAssignmentResponse:
|
|
204
|
+
"""Assign a user to a project.
|
|
205
|
+
|
|
206
|
+
Args:
|
|
207
|
+
project_name: Project name
|
|
208
|
+
user_id: User ID to assign
|
|
209
|
+
is_project_admin: Whether user should be project admin
|
|
210
|
+
|
|
211
|
+
Returns:
|
|
212
|
+
ProjectAssignmentResponse with assignment details
|
|
213
|
+
|
|
214
|
+
Raises:
|
|
215
|
+
HTTPException: If assignment fails
|
|
216
|
+
"""
|
|
217
|
+
payload = ProjectAssignmentRequest(
|
|
218
|
+
user_id=user_id,
|
|
219
|
+
is_project_admin=is_project_admin,
|
|
220
|
+
)
|
|
221
|
+
|
|
222
|
+
return self._api.post(
|
|
223
|
+
f"/v1/projects/{project_name}/assignment",
|
|
224
|
+
response_model=ProjectAssignmentResponse,
|
|
225
|
+
json_data=payload.model_dump(exclude_none=True),
|
|
226
|
+
)
|
|
227
|
+
|
|
228
|
+
def update_user_project_assignment(
|
|
229
|
+
self,
|
|
230
|
+
project_name: str,
|
|
231
|
+
user_id: str,
|
|
232
|
+
is_project_admin: bool,
|
|
233
|
+
) -> ProjectAssignmentResponse:
|
|
234
|
+
"""Update a user's project-admin flag.
|
|
235
|
+
|
|
236
|
+
Args:
|
|
237
|
+
project_name: Project name
|
|
238
|
+
user_id: User ID to update
|
|
239
|
+
is_project_admin: New project admin flag value
|
|
240
|
+
|
|
241
|
+
Returns:
|
|
242
|
+
ProjectAssignmentResponse with updated assignment
|
|
243
|
+
|
|
244
|
+
Raises:
|
|
245
|
+
HTTPException: If user is not assigned to project (404)
|
|
246
|
+
"""
|
|
247
|
+
payload = ProjectAssignmentUpdateRequest(is_project_admin=is_project_admin)
|
|
248
|
+
|
|
249
|
+
return self._api.put(
|
|
250
|
+
f"/v1/projects/{project_name}/assignment/{user_id}",
|
|
251
|
+
response_model=ProjectAssignmentResponse,
|
|
252
|
+
json_data=payload.model_dump(exclude_none=True),
|
|
253
|
+
)
|
|
254
|
+
|
|
255
|
+
def remove_user_from_project(
|
|
256
|
+
self,
|
|
257
|
+
project_name: str,
|
|
258
|
+
user_id: str,
|
|
259
|
+
) -> ProjectAssignmentResponse:
|
|
260
|
+
"""Remove a user from a project.
|
|
261
|
+
|
|
262
|
+
Args:
|
|
263
|
+
project_name: Project name
|
|
264
|
+
user_id: User ID to remove
|
|
265
|
+
|
|
266
|
+
Returns:
|
|
267
|
+
ProjectAssignmentResponse with removal confirmation
|
|
268
|
+
|
|
269
|
+
Raises:
|
|
270
|
+
HTTPException: If user is not assigned to project (404)
|
|
271
|
+
"""
|
|
272
|
+
return self._api.delete(
|
|
273
|
+
f"/v1/projects/{project_name}/assignment/{user_id}",
|
|
274
|
+
response_model=ProjectAssignmentResponse,
|
|
275
|
+
)
|
|
276
|
+
|
|
277
|
+
def bulk_assign_users_to_project(
|
|
278
|
+
self,
|
|
279
|
+
project_name: str,
|
|
280
|
+
users: list[BulkAssignmentUserItem],
|
|
281
|
+
) -> BulkAssignmentResponse:
|
|
282
|
+
"""Bulk assign/upsert users to a project.
|
|
283
|
+
|
|
284
|
+
Assigns new users and updates roles for existing members in a single
|
|
285
|
+
atomic operation.
|
|
286
|
+
|
|
287
|
+
Args:
|
|
288
|
+
project_name: Project name
|
|
289
|
+
users: List of BulkAssignmentUserItem with user_id and is_project_admin (1-1000)
|
|
290
|
+
|
|
291
|
+
Returns:
|
|
292
|
+
BulkAssignmentResponse with per-user results
|
|
293
|
+
|
|
294
|
+
Raises:
|
|
295
|
+
HTTPException: If bulk assignment fails
|
|
296
|
+
"""
|
|
297
|
+
payload = BulkAssignmentRequest(users=users)
|
|
298
|
+
|
|
299
|
+
return self._api.post(
|
|
300
|
+
f"/v1/projects/{project_name}/assignments",
|
|
301
|
+
response_model=BulkAssignmentResponse,
|
|
302
|
+
json_data=payload.model_dump(),
|
|
303
|
+
)
|
|
304
|
+
|
|
305
|
+
def bulk_remove_users_from_project(
|
|
306
|
+
self,
|
|
307
|
+
project_name: str,
|
|
308
|
+
user_ids: list[str],
|
|
309
|
+
) -> BulkAssignmentResponse:
|
|
310
|
+
"""Bulk remove users from a project.
|
|
311
|
+
|
|
312
|
+
Args:
|
|
313
|
+
project_name: Project name
|
|
314
|
+
user_ids: List of user IDs to remove (1-100)
|
|
315
|
+
|
|
316
|
+
Returns:
|
|
317
|
+
BulkAssignmentResponse with per-user results
|
|
318
|
+
|
|
319
|
+
Raises:
|
|
320
|
+
HTTPException: If bulk removal fails
|
|
321
|
+
"""
|
|
322
|
+
params = [("user_id", user_id) for user_id in user_ids]
|
|
323
|
+
|
|
324
|
+
return self._api.delete(
|
|
325
|
+
f"/v1/projects/{project_name}/assignments",
|
|
326
|
+
response_model=BulkAssignmentResponse,
|
|
327
|
+
params=params,
|
|
328
|
+
)
|
|
329
|
+
|
|
330
|
+
# CSV import endpoints
|
|
331
|
+
|
|
332
|
+
def validate_users_from_csv(
|
|
333
|
+
self,
|
|
334
|
+
project_name: str,
|
|
335
|
+
file_content: bytes,
|
|
336
|
+
filename: str = "users.csv",
|
|
337
|
+
) -> CsvImportValidationResponse:
|
|
338
|
+
"""Dry-run validation of a CSV file for user import.
|
|
339
|
+
|
|
340
|
+
Validates each row (email format, role, system user existence) without
|
|
341
|
+
modifying any data.
|
|
342
|
+
|
|
343
|
+
Args:
|
|
344
|
+
project_name: Project name
|
|
345
|
+
file_content: CSV file content as bytes
|
|
346
|
+
filename: CSV filename
|
|
347
|
+
|
|
348
|
+
Returns:
|
|
349
|
+
CsvImportValidationResponse with per-row validation results
|
|
350
|
+
|
|
351
|
+
Raises:
|
|
352
|
+
HTTPException: If file too large (413) or structural CSV error (422)
|
|
353
|
+
"""
|
|
354
|
+
files = {"file": (filename, file_content, "text/csv")}
|
|
355
|
+
|
|
356
|
+
return self._api.post_multipart(
|
|
357
|
+
f"/v1/projects/{project_name}/import-users/validate",
|
|
358
|
+
response_model=CsvImportValidationResponse,
|
|
359
|
+
files=files,
|
|
360
|
+
)
|
|
361
|
+
|
|
362
|
+
def import_users_from_csv(
|
|
363
|
+
self,
|
|
364
|
+
project_name: str,
|
|
365
|
+
file_content: bytes,
|
|
366
|
+
filename: str = "users.csv",
|
|
367
|
+
) -> BulkAssignmentResponse:
|
|
368
|
+
"""Assign users to a project from a CSV file upload.
|
|
369
|
+
|
|
370
|
+
CSV must include a header row with 'email' and 'role' columns.
|
|
371
|
+
Allowed roles: 'administrator' (project admin), 'user' (regular member).
|
|
372
|
+
|
|
373
|
+
Args:
|
|
374
|
+
project_name: Project name
|
|
375
|
+
file_content: CSV file content as bytes
|
|
376
|
+
filename: CSV filename
|
|
377
|
+
|
|
378
|
+
Returns:
|
|
379
|
+
BulkAssignmentResponse with per-user results
|
|
380
|
+
|
|
381
|
+
Raises:
|
|
382
|
+
HTTPException: If file too large (413) or validation fails (422)
|
|
383
|
+
"""
|
|
384
|
+
files = {"file": (filename, file_content, "text/csv")}
|
|
385
|
+
|
|
386
|
+
return self._api.post_multipart(
|
|
387
|
+
f"/v1/projects/{project_name}/import-users",
|
|
388
|
+
response_model=BulkAssignmentResponse,
|
|
389
|
+
files=files,
|
|
390
|
+
)
|
|
@@ -292,15 +292,52 @@ class ApiRequestHandler:
|
|
|
292
292
|
response.raise_for_status()
|
|
293
293
|
return self._parse_response(response, response_model, wrap_response)
|
|
294
294
|
|
|
295
|
+
@log_request
|
|
296
|
+
def patch(
|
|
297
|
+
self,
|
|
298
|
+
endpoint: str,
|
|
299
|
+
response_model: Type[T],
|
|
300
|
+
json_data: Dict[str, Any],
|
|
301
|
+
params: Optional[Dict[str, Any]] = None,
|
|
302
|
+
wrap_response: bool = True,
|
|
303
|
+
) -> T:
|
|
304
|
+
"""Makes a PATCH request and parses the response.
|
|
305
|
+
|
|
306
|
+
Args:
|
|
307
|
+
endpoint: API endpoint path
|
|
308
|
+
response_model: Pydantic model class or List[Model] for response
|
|
309
|
+
json_data: JSON request body
|
|
310
|
+
params: Optional query parameters (e.g., filters, pagination)
|
|
311
|
+
wrap_response: Whether response is wrapped in 'data' field
|
|
312
|
+
|
|
313
|
+
Returns:
|
|
314
|
+
Parsed response object or list of objects
|
|
315
|
+
"""
|
|
316
|
+
logger.debug(f"Request body: {json_data}")
|
|
317
|
+
response = requests.patch(
|
|
318
|
+
url=f"{self._base_url}{endpoint}",
|
|
319
|
+
headers=self._get_headers(),
|
|
320
|
+
json=json_data,
|
|
321
|
+
params=params,
|
|
322
|
+
verify=self._verify_ssl,
|
|
323
|
+
)
|
|
324
|
+
response.raise_for_status()
|
|
325
|
+
return self._parse_response(response, response_model, wrap_response)
|
|
326
|
+
|
|
295
327
|
@log_request
|
|
296
328
|
def delete(
|
|
297
|
-
self,
|
|
329
|
+
self,
|
|
330
|
+
endpoint: str,
|
|
331
|
+
response_model: Type[T],
|
|
332
|
+
params: Optional[Dict[str, Any]] = None,
|
|
333
|
+
wrap_response: bool = True,
|
|
298
334
|
) -> T:
|
|
299
335
|
"""Makes a DELETE request and parses the response.
|
|
300
336
|
|
|
301
337
|
Args:
|
|
302
338
|
endpoint: API endpoint path
|
|
303
339
|
response_model: Pydantic model class or List[Model] for response
|
|
340
|
+
params: Query parameters (for passing multiple user_id params for bulk delete)
|
|
304
341
|
wrap_response: Whether response is wrapped in 'data' field
|
|
305
342
|
|
|
306
343
|
Returns:
|
|
@@ -309,6 +346,7 @@ class ApiRequestHandler:
|
|
|
309
346
|
response = requests.delete(
|
|
310
347
|
url=f"{self._base_url}{endpoint}",
|
|
311
348
|
headers=self._get_headers(),
|
|
349
|
+
params=params,
|
|
312
350
|
verify=self._verify_ssl,
|
|
313
351
|
)
|
|
314
352
|
response.raise_for_status()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{codemie_sdk_python-0.1.418 → codemie_sdk_python-0.1.419}/src/codemie_sdk/auth/credentials.py
RENAMED
|
File without changes
|
{codemie_sdk_python-0.1.418 → codemie_sdk_python-0.1.419}/src/codemie_sdk/client/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{codemie_sdk_python-0.1.418 → codemie_sdk_python-0.1.419}/src/codemie_sdk/models/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{codemie_sdk_python-0.1.418 → codemie_sdk_python-0.1.419}/src/codemie_sdk/models/analytics.py
RENAMED
|
File without changes
|
{codemie_sdk_python-0.1.418 → codemie_sdk_python-0.1.419}/src/codemie_sdk/models/assistant.py
RENAMED
|
File without changes
|
{codemie_sdk_python-0.1.418 → codemie_sdk_python-0.1.419}/src/codemie_sdk/models/categories.py
RENAMED
|
File without changes
|
|
File without changes
|
{codemie_sdk_python-0.1.418 → codemie_sdk_python-0.1.419}/src/codemie_sdk/models/conversation.py
RENAMED
|
File without changes
|
{codemie_sdk_python-0.1.418 → codemie_sdk_python-0.1.419}/src/codemie_sdk/models/datasource.py
RENAMED
|
File without changes
|
|
File without changes
|
{codemie_sdk_python-0.1.418 → codemie_sdk_python-0.1.419}/src/codemie_sdk/models/file_operation.py
RENAMED
|
File without changes
|
{codemie_sdk_python-0.1.418 → codemie_sdk_python-0.1.419}/src/codemie_sdk/models/guardrails.py
RENAMED
|
File without changes
|
{codemie_sdk_python-0.1.418 → codemie_sdk_python-0.1.419}/src/codemie_sdk/models/integration.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{codemie_sdk_python-0.1.418 → codemie_sdk_python-0.1.419}/src/codemie_sdk/models/vendor_assistant.py
RENAMED
|
File without changes
|
{codemie_sdk_python-0.1.418 → codemie_sdk_python-0.1.419}/src/codemie_sdk/models/vendor_guardrail.py
RENAMED
|
File without changes
|
|
File without changes
|
{codemie_sdk_python-0.1.418 → codemie_sdk_python-0.1.419}/src/codemie_sdk/models/vendor_workflow.py
RENAMED
|
File without changes
|
{codemie_sdk_python-0.1.418 → codemie_sdk_python-0.1.419}/src/codemie_sdk/models/workflow.py
RENAMED
|
File without changes
|
|
File without changes
|
{codemie_sdk_python-0.1.418 → codemie_sdk_python-0.1.419}/src/codemie_sdk/models/workflow_state.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{codemie_sdk_python-0.1.418 → codemie_sdk_python-0.1.419}/src/codemie_sdk/services/analytics.py
RENAMED
|
File without changes
|
{codemie_sdk_python-0.1.418 → codemie_sdk_python-0.1.419}/src/codemie_sdk/services/assistant.py
RENAMED
|
File without changes
|
{codemie_sdk_python-0.1.418 → codemie_sdk_python-0.1.419}/src/codemie_sdk/services/categories.py
RENAMED
|
File without changes
|
|
File without changes
|
{codemie_sdk_python-0.1.418 → codemie_sdk_python-0.1.419}/src/codemie_sdk/services/conversation.py
RENAMED
|
File without changes
|
{codemie_sdk_python-0.1.418 → codemie_sdk_python-0.1.419}/src/codemie_sdk/services/datasource.py
RENAMED
|
File without changes
|
|
File without changes
|
{codemie_sdk_python-0.1.418 → codemie_sdk_python-0.1.419}/src/codemie_sdk/services/integration.py
RENAMED
|
File without changes
|
|
File without changes
|
{codemie_sdk_python-0.1.418 → codemie_sdk_python-0.1.419}/src/codemie_sdk/services/mermaid.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{codemie_sdk_python-0.1.418 → codemie_sdk_python-0.1.419}/src/codemie_sdk/services/webhook.py
RENAMED
|
File without changes
|
{codemie_sdk_python-0.1.418 → codemie_sdk_python-0.1.419}/src/codemie_sdk/services/workflow.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|