airbyte-agent-asana 0.19.27__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.
Potentially problematic release.
This version of airbyte-agent-asana might be problematic. Click here for more details.
- airbyte_agent_asana/__init__.py +145 -0
- airbyte_agent_asana/_vendored/__init__.py +1 -0
- airbyte_agent_asana/_vendored/connector_sdk/__init__.py +82 -0
- airbyte_agent_asana/_vendored/connector_sdk/auth_strategies.py +1123 -0
- airbyte_agent_asana/_vendored/connector_sdk/auth_template.py +135 -0
- airbyte_agent_asana/_vendored/connector_sdk/cloud_utils/__init__.py +5 -0
- airbyte_agent_asana/_vendored/connector_sdk/cloud_utils/client.py +213 -0
- airbyte_agent_asana/_vendored/connector_sdk/connector_model_loader.py +957 -0
- airbyte_agent_asana/_vendored/connector_sdk/constants.py +78 -0
- airbyte_agent_asana/_vendored/connector_sdk/exceptions.py +23 -0
- airbyte_agent_asana/_vendored/connector_sdk/executor/__init__.py +31 -0
- airbyte_agent_asana/_vendored/connector_sdk/executor/hosted_executor.py +197 -0
- airbyte_agent_asana/_vendored/connector_sdk/executor/local_executor.py +1504 -0
- airbyte_agent_asana/_vendored/connector_sdk/executor/models.py +190 -0
- airbyte_agent_asana/_vendored/connector_sdk/extensions.py +655 -0
- airbyte_agent_asana/_vendored/connector_sdk/http/__init__.py +37 -0
- airbyte_agent_asana/_vendored/connector_sdk/http/adapters/__init__.py +9 -0
- airbyte_agent_asana/_vendored/connector_sdk/http/adapters/httpx_adapter.py +251 -0
- airbyte_agent_asana/_vendored/connector_sdk/http/config.py +98 -0
- airbyte_agent_asana/_vendored/connector_sdk/http/exceptions.py +119 -0
- airbyte_agent_asana/_vendored/connector_sdk/http/protocols.py +114 -0
- airbyte_agent_asana/_vendored/connector_sdk/http/response.py +102 -0
- airbyte_agent_asana/_vendored/connector_sdk/http_client.py +686 -0
- airbyte_agent_asana/_vendored/connector_sdk/logging/__init__.py +11 -0
- airbyte_agent_asana/_vendored/connector_sdk/logging/logger.py +264 -0
- airbyte_agent_asana/_vendored/connector_sdk/logging/types.py +92 -0
- airbyte_agent_asana/_vendored/connector_sdk/observability/__init__.py +11 -0
- airbyte_agent_asana/_vendored/connector_sdk/observability/models.py +19 -0
- airbyte_agent_asana/_vendored/connector_sdk/observability/redactor.py +81 -0
- airbyte_agent_asana/_vendored/connector_sdk/observability/session.py +94 -0
- airbyte_agent_asana/_vendored/connector_sdk/performance/__init__.py +6 -0
- airbyte_agent_asana/_vendored/connector_sdk/performance/instrumentation.py +57 -0
- airbyte_agent_asana/_vendored/connector_sdk/performance/metrics.py +93 -0
- airbyte_agent_asana/_vendored/connector_sdk/schema/__init__.py +75 -0
- airbyte_agent_asana/_vendored/connector_sdk/schema/base.py +161 -0
- airbyte_agent_asana/_vendored/connector_sdk/schema/components.py +238 -0
- airbyte_agent_asana/_vendored/connector_sdk/schema/connector.py +131 -0
- airbyte_agent_asana/_vendored/connector_sdk/schema/extensions.py +109 -0
- airbyte_agent_asana/_vendored/connector_sdk/schema/operations.py +146 -0
- airbyte_agent_asana/_vendored/connector_sdk/schema/security.py +213 -0
- airbyte_agent_asana/_vendored/connector_sdk/secrets.py +182 -0
- airbyte_agent_asana/_vendored/connector_sdk/telemetry/__init__.py +10 -0
- airbyte_agent_asana/_vendored/connector_sdk/telemetry/config.py +32 -0
- airbyte_agent_asana/_vendored/connector_sdk/telemetry/events.py +58 -0
- airbyte_agent_asana/_vendored/connector_sdk/telemetry/tracker.py +151 -0
- airbyte_agent_asana/_vendored/connector_sdk/types.py +241 -0
- airbyte_agent_asana/_vendored/connector_sdk/utils.py +60 -0
- airbyte_agent_asana/_vendored/connector_sdk/validation.py +822 -0
- airbyte_agent_asana/connector.py +1770 -0
- airbyte_agent_asana/connector_model.py +1863 -0
- airbyte_agent_asana/models.py +744 -0
- airbyte_agent_asana/types.py +195 -0
- airbyte_agent_asana-0.19.27.dist-info/METADATA +144 -0
- airbyte_agent_asana-0.19.27.dist-info/RECORD +55 -0
- airbyte_agent_asana-0.19.27.dist-info/WHEEL +4 -0
|
@@ -0,0 +1,1770 @@
|
|
|
1
|
+
"""
|
|
2
|
+
asana connector.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
from typing import TYPE_CHECKING, Any, AsyncIterator, overload
|
|
8
|
+
try:
|
|
9
|
+
from typing import Literal
|
|
10
|
+
except ImportError:
|
|
11
|
+
from typing_extensions import Literal
|
|
12
|
+
|
|
13
|
+
from .connector_model import AsanaConnectorModel
|
|
14
|
+
|
|
15
|
+
from .types import (
|
|
16
|
+
AttachmentsDownloadParams,
|
|
17
|
+
AttachmentsGetParams,
|
|
18
|
+
AttachmentsListParams,
|
|
19
|
+
ProjectSectionsListParams,
|
|
20
|
+
ProjectTasksListParams,
|
|
21
|
+
ProjectsGetParams,
|
|
22
|
+
ProjectsListParams,
|
|
23
|
+
SectionsGetParams,
|
|
24
|
+
TagsGetParams,
|
|
25
|
+
TaskDependenciesListParams,
|
|
26
|
+
TaskDependentsListParams,
|
|
27
|
+
TaskProjectsListParams,
|
|
28
|
+
TaskSubtasksListParams,
|
|
29
|
+
TasksGetParams,
|
|
30
|
+
TasksListParams,
|
|
31
|
+
TeamProjectsListParams,
|
|
32
|
+
TeamUsersListParams,
|
|
33
|
+
TeamsGetParams,
|
|
34
|
+
UserTeamsListParams,
|
|
35
|
+
UsersGetParams,
|
|
36
|
+
UsersListParams,
|
|
37
|
+
WorkspaceProjectsListParams,
|
|
38
|
+
WorkspaceTagsListParams,
|
|
39
|
+
WorkspaceTaskSearchListParams,
|
|
40
|
+
WorkspaceTeamsListParams,
|
|
41
|
+
WorkspaceUsersListParams,
|
|
42
|
+
WorkspacesGetParams,
|
|
43
|
+
WorkspacesListParams,
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
if TYPE_CHECKING:
|
|
47
|
+
from .models import AsanaAuthConfig
|
|
48
|
+
# Import specific auth config classes for multi-auth isinstance checks
|
|
49
|
+
from .models import AsanaOauth2AuthConfig, AsanaPersonalAccessTokenAuthConfig
|
|
50
|
+
# Import response models and envelope models at runtime
|
|
51
|
+
from .models import (
|
|
52
|
+
AsanaExecuteResult,
|
|
53
|
+
AsanaExecuteResultWithMeta,
|
|
54
|
+
TasksListResult,
|
|
55
|
+
ProjectTasksListResult,
|
|
56
|
+
TasksGetResult,
|
|
57
|
+
WorkspaceTaskSearchListResult,
|
|
58
|
+
ProjectsListResult,
|
|
59
|
+
ProjectsGetResult,
|
|
60
|
+
TaskProjectsListResult,
|
|
61
|
+
TeamProjectsListResult,
|
|
62
|
+
WorkspaceProjectsListResult,
|
|
63
|
+
WorkspacesListResult,
|
|
64
|
+
WorkspacesGetResult,
|
|
65
|
+
UsersListResult,
|
|
66
|
+
UsersGetResult,
|
|
67
|
+
WorkspaceUsersListResult,
|
|
68
|
+
TeamUsersListResult,
|
|
69
|
+
TeamsGetResult,
|
|
70
|
+
WorkspaceTeamsListResult,
|
|
71
|
+
UserTeamsListResult,
|
|
72
|
+
AttachmentsListResult,
|
|
73
|
+
AttachmentsGetResult,
|
|
74
|
+
WorkspaceTagsListResult,
|
|
75
|
+
TagsGetResult,
|
|
76
|
+
ProjectSectionsListResult,
|
|
77
|
+
SectionsGetResult,
|
|
78
|
+
TaskSubtasksListResult,
|
|
79
|
+
TaskDependenciesListResult,
|
|
80
|
+
TaskDependentsListResult,
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
class AsanaConnector:
|
|
85
|
+
"""
|
|
86
|
+
Type-safe Asana API connector.
|
|
87
|
+
|
|
88
|
+
Auto-generated from OpenAPI specification with full type safety.
|
|
89
|
+
"""
|
|
90
|
+
|
|
91
|
+
connector_name = "asana"
|
|
92
|
+
connector_version = "0.1.6"
|
|
93
|
+
vendored_sdk_version = "0.1.0" # Version of vendored connector-sdk
|
|
94
|
+
|
|
95
|
+
# Map of (entity, action) -> has_extractors for envelope wrapping decision
|
|
96
|
+
_EXTRACTOR_MAP = {
|
|
97
|
+
("tasks", "list"): True,
|
|
98
|
+
("project_tasks", "list"): True,
|
|
99
|
+
("tasks", "get"): True,
|
|
100
|
+
("workspace_task_search", "list"): True,
|
|
101
|
+
("projects", "list"): True,
|
|
102
|
+
("projects", "get"): True,
|
|
103
|
+
("task_projects", "list"): True,
|
|
104
|
+
("team_projects", "list"): True,
|
|
105
|
+
("workspace_projects", "list"): True,
|
|
106
|
+
("workspaces", "list"): True,
|
|
107
|
+
("workspaces", "get"): True,
|
|
108
|
+
("users", "list"): True,
|
|
109
|
+
("users", "get"): True,
|
|
110
|
+
("workspace_users", "list"): True,
|
|
111
|
+
("team_users", "list"): True,
|
|
112
|
+
("teams", "get"): True,
|
|
113
|
+
("workspace_teams", "list"): True,
|
|
114
|
+
("user_teams", "list"): True,
|
|
115
|
+
("attachments", "list"): True,
|
|
116
|
+
("attachments", "get"): True,
|
|
117
|
+
("attachments", "download"): False,
|
|
118
|
+
("workspace_tags", "list"): True,
|
|
119
|
+
("tags", "get"): True,
|
|
120
|
+
("project_sections", "list"): True,
|
|
121
|
+
("sections", "get"): True,
|
|
122
|
+
("task_subtasks", "list"): True,
|
|
123
|
+
("task_dependencies", "list"): True,
|
|
124
|
+
("task_dependents", "list"): True,
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
# Map of (entity, action) -> {python_param_name: api_param_name}
|
|
128
|
+
# Used to convert snake_case TypedDict keys to API parameter names in execute()
|
|
129
|
+
_PARAM_MAP = {
|
|
130
|
+
('tasks', 'list'): {'limit': 'limit', 'offset': 'offset', 'project': 'project', 'workspace': 'workspace', 'section': 'section', 'assignee': 'assignee', 'completed_since': 'completed_since', 'modified_since': 'modified_since'},
|
|
131
|
+
('project_tasks', 'list'): {'project_gid': 'project_gid', 'limit': 'limit', 'offset': 'offset', 'completed_since': 'completed_since'},
|
|
132
|
+
('tasks', 'get'): {'task_gid': 'task_gid'},
|
|
133
|
+
('workspace_task_search', 'list'): {'workspace_gid': 'workspace_gid', 'limit': 'limit', 'offset': 'offset', 'text': 'text', 'completed': 'completed', 'assignee_any': 'assignee.any', 'projects_any': 'projects.any', 'sections_any': 'sections.any', 'teams_any': 'teams.any', 'followers_any': 'followers.any', 'created_at_after': 'created_at.after', 'created_at_before': 'created_at.before', 'modified_at_after': 'modified_at.after', 'modified_at_before': 'modified_at.before', 'due_on_after': 'due_on.after', 'due_on_before': 'due_on.before', 'resource_subtype': 'resource_subtype', 'sort_by': 'sort_by', 'sort_ascending': 'sort_ascending'},
|
|
134
|
+
('projects', 'list'): {'limit': 'limit', 'offset': 'offset', 'workspace': 'workspace', 'team': 'team', 'archived': 'archived'},
|
|
135
|
+
('projects', 'get'): {'project_gid': 'project_gid'},
|
|
136
|
+
('task_projects', 'list'): {'task_gid': 'task_gid', 'limit': 'limit', 'offset': 'offset'},
|
|
137
|
+
('team_projects', 'list'): {'team_gid': 'team_gid', 'limit': 'limit', 'offset': 'offset', 'archived': 'archived'},
|
|
138
|
+
('workspace_projects', 'list'): {'workspace_gid': 'workspace_gid', 'limit': 'limit', 'offset': 'offset', 'archived': 'archived'},
|
|
139
|
+
('workspaces', 'list'): {'limit': 'limit', 'offset': 'offset'},
|
|
140
|
+
('workspaces', 'get'): {'workspace_gid': 'workspace_gid'},
|
|
141
|
+
('users', 'list'): {'limit': 'limit', 'offset': 'offset', 'workspace': 'workspace', 'team': 'team'},
|
|
142
|
+
('users', 'get'): {'user_gid': 'user_gid'},
|
|
143
|
+
('workspace_users', 'list'): {'workspace_gid': 'workspace_gid', 'limit': 'limit', 'offset': 'offset'},
|
|
144
|
+
('team_users', 'list'): {'team_gid': 'team_gid', 'limit': 'limit', 'offset': 'offset'},
|
|
145
|
+
('teams', 'get'): {'team_gid': 'team_gid'},
|
|
146
|
+
('workspace_teams', 'list'): {'workspace_gid': 'workspace_gid', 'limit': 'limit', 'offset': 'offset'},
|
|
147
|
+
('user_teams', 'list'): {'user_gid': 'user_gid', 'organization': 'organization', 'limit': 'limit', 'offset': 'offset'},
|
|
148
|
+
('attachments', 'list'): {'parent': 'parent', 'limit': 'limit', 'offset': 'offset'},
|
|
149
|
+
('attachments', 'get'): {'attachment_gid': 'attachment_gid'},
|
|
150
|
+
('attachments', 'download'): {'attachment_gid': 'attachment_gid', 'range_header': 'range_header'},
|
|
151
|
+
('workspace_tags', 'list'): {'workspace_gid': 'workspace_gid', 'limit': 'limit', 'offset': 'offset'},
|
|
152
|
+
('tags', 'get'): {'tag_gid': 'tag_gid'},
|
|
153
|
+
('project_sections', 'list'): {'project_gid': 'project_gid', 'limit': 'limit', 'offset': 'offset'},
|
|
154
|
+
('sections', 'get'): {'section_gid': 'section_gid'},
|
|
155
|
+
('task_subtasks', 'list'): {'task_gid': 'task_gid', 'limit': 'limit', 'offset': 'offset'},
|
|
156
|
+
('task_dependencies', 'list'): {'task_gid': 'task_gid', 'limit': 'limit', 'offset': 'offset'},
|
|
157
|
+
('task_dependents', 'list'): {'task_gid': 'task_gid', 'limit': 'limit', 'offset': 'offset'},
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
def __init__(
|
|
161
|
+
self,
|
|
162
|
+
auth_config: AsanaAuthConfig | None = None,
|
|
163
|
+
external_user_id: str | None = None,
|
|
164
|
+
airbyte_client_id: str | None = None,
|
|
165
|
+
airbyte_client_secret: str | None = None,
|
|
166
|
+
on_token_refresh: Any | None = None ):
|
|
167
|
+
"""
|
|
168
|
+
Initialize a new asana connector instance.
|
|
169
|
+
|
|
170
|
+
Supports both local and hosted execution modes:
|
|
171
|
+
- Local mode: Provide `auth_config` for direct API calls
|
|
172
|
+
- Hosted mode: Provide `external_user_id`, `airbyte_client_id`, and `airbyte_client_secret` for hosted execution
|
|
173
|
+
|
|
174
|
+
Args:
|
|
175
|
+
auth_config: Typed authentication configuration (required for local mode)
|
|
176
|
+
external_user_id: External user ID (required for hosted mode)
|
|
177
|
+
airbyte_client_id: Airbyte OAuth client ID (required for hosted mode)
|
|
178
|
+
airbyte_client_secret: Airbyte OAuth client secret (required for hosted mode)
|
|
179
|
+
on_token_refresh: Optional callback for OAuth2 token refresh persistence.
|
|
180
|
+
Called with new_tokens dict when tokens are refreshed. Can be sync or async.
|
|
181
|
+
Example: lambda tokens: save_to_database(tokens)
|
|
182
|
+
Examples:
|
|
183
|
+
# Local mode (direct API calls)
|
|
184
|
+
connector = AsanaConnector(auth_config=AsanaAuthConfig(access_token="...", refresh_token="...", client_id="...", client_secret="..."))
|
|
185
|
+
# Hosted mode (executed on Airbyte cloud)
|
|
186
|
+
connector = AsanaConnector(
|
|
187
|
+
external_user_id="user-123",
|
|
188
|
+
airbyte_client_id="client_abc123",
|
|
189
|
+
airbyte_client_secret="secret_xyz789"
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
# Local mode with OAuth2 token refresh callback
|
|
193
|
+
def save_tokens(new_tokens: dict) -> None:
|
|
194
|
+
# Persist updated tokens to your storage (file, database, etc.)
|
|
195
|
+
with open("tokens.json", "w") as f:
|
|
196
|
+
json.dump(new_tokens, f)
|
|
197
|
+
|
|
198
|
+
connector = AsanaConnector(
|
|
199
|
+
auth_config=AsanaAuthConfig(access_token="...", refresh_token="..."),
|
|
200
|
+
on_token_refresh=save_tokens
|
|
201
|
+
)
|
|
202
|
+
"""
|
|
203
|
+
# Hosted mode: external_user_id, airbyte_client_id, and airbyte_client_secret provided
|
|
204
|
+
if external_user_id and airbyte_client_id and airbyte_client_secret:
|
|
205
|
+
from ._vendored.connector_sdk.executor import HostedExecutor
|
|
206
|
+
self._executor = HostedExecutor(
|
|
207
|
+
external_user_id=external_user_id,
|
|
208
|
+
airbyte_client_id=airbyte_client_id,
|
|
209
|
+
airbyte_client_secret=airbyte_client_secret,
|
|
210
|
+
connector_definition_id=str(AsanaConnectorModel.id),
|
|
211
|
+
)
|
|
212
|
+
else:
|
|
213
|
+
# Local mode: auth_config required
|
|
214
|
+
if not auth_config:
|
|
215
|
+
raise ValueError(
|
|
216
|
+
"Either provide (external_user_id, airbyte_client_id, airbyte_client_secret) for hosted mode "
|
|
217
|
+
"or auth_config for local mode"
|
|
218
|
+
)
|
|
219
|
+
|
|
220
|
+
from ._vendored.connector_sdk.executor import LocalExecutor
|
|
221
|
+
|
|
222
|
+
# Build config_values dict from server variables
|
|
223
|
+
config_values = None
|
|
224
|
+
|
|
225
|
+
# Multi-auth connector: detect auth scheme from auth_config type
|
|
226
|
+
auth_scheme: str | None = None
|
|
227
|
+
if auth_config:
|
|
228
|
+
if isinstance(auth_config, AsanaOauth2AuthConfig):
|
|
229
|
+
auth_scheme = "oauth2"
|
|
230
|
+
if isinstance(auth_config, AsanaPersonalAccessTokenAuthConfig):
|
|
231
|
+
auth_scheme = "personalAccessToken"
|
|
232
|
+
|
|
233
|
+
self._executor = LocalExecutor(
|
|
234
|
+
model=AsanaConnectorModel,
|
|
235
|
+
auth_config=auth_config.model_dump() if auth_config else None,
|
|
236
|
+
auth_scheme=auth_scheme,
|
|
237
|
+
config_values=config_values,
|
|
238
|
+
on_token_refresh=on_token_refresh
|
|
239
|
+
)
|
|
240
|
+
|
|
241
|
+
# Update base_url with server variables if provided
|
|
242
|
+
|
|
243
|
+
# Initialize entity query objects
|
|
244
|
+
self.tasks = TasksQuery(self)
|
|
245
|
+
self.project_tasks = ProjectTasksQuery(self)
|
|
246
|
+
self.workspace_task_search = WorkspaceTaskSearchQuery(self)
|
|
247
|
+
self.projects = ProjectsQuery(self)
|
|
248
|
+
self.task_projects = TaskProjectsQuery(self)
|
|
249
|
+
self.team_projects = TeamProjectsQuery(self)
|
|
250
|
+
self.workspace_projects = WorkspaceProjectsQuery(self)
|
|
251
|
+
self.workspaces = WorkspacesQuery(self)
|
|
252
|
+
self.users = UsersQuery(self)
|
|
253
|
+
self.workspace_users = WorkspaceUsersQuery(self)
|
|
254
|
+
self.team_users = TeamUsersQuery(self)
|
|
255
|
+
self.teams = TeamsQuery(self)
|
|
256
|
+
self.workspace_teams = WorkspaceTeamsQuery(self)
|
|
257
|
+
self.user_teams = UserTeamsQuery(self)
|
|
258
|
+
self.attachments = AttachmentsQuery(self)
|
|
259
|
+
self.workspace_tags = WorkspaceTagsQuery(self)
|
|
260
|
+
self.tags = TagsQuery(self)
|
|
261
|
+
self.project_sections = ProjectSectionsQuery(self)
|
|
262
|
+
self.sections = SectionsQuery(self)
|
|
263
|
+
self.task_subtasks = TaskSubtasksQuery(self)
|
|
264
|
+
self.task_dependencies = TaskDependenciesQuery(self)
|
|
265
|
+
self.task_dependents = TaskDependentsQuery(self)
|
|
266
|
+
|
|
267
|
+
# ===== TYPED EXECUTE METHOD (Recommended Interface) =====
|
|
268
|
+
|
|
269
|
+
@overload
|
|
270
|
+
async def execute(
|
|
271
|
+
self,
|
|
272
|
+
entity: Literal["tasks"],
|
|
273
|
+
action: Literal["list"],
|
|
274
|
+
params: "TasksListParams"
|
|
275
|
+
) -> "TasksListResult": ...
|
|
276
|
+
|
|
277
|
+
@overload
|
|
278
|
+
async def execute(
|
|
279
|
+
self,
|
|
280
|
+
entity: Literal["project_tasks"],
|
|
281
|
+
action: Literal["list"],
|
|
282
|
+
params: "ProjectTasksListParams"
|
|
283
|
+
) -> "ProjectTasksListResult": ...
|
|
284
|
+
|
|
285
|
+
@overload
|
|
286
|
+
async def execute(
|
|
287
|
+
self,
|
|
288
|
+
entity: Literal["tasks"],
|
|
289
|
+
action: Literal["get"],
|
|
290
|
+
params: "TasksGetParams"
|
|
291
|
+
) -> "TasksGetResult": ...
|
|
292
|
+
|
|
293
|
+
@overload
|
|
294
|
+
async def execute(
|
|
295
|
+
self,
|
|
296
|
+
entity: Literal["workspace_task_search"],
|
|
297
|
+
action: Literal["list"],
|
|
298
|
+
params: "WorkspaceTaskSearchListParams"
|
|
299
|
+
) -> "WorkspaceTaskSearchListResult": ...
|
|
300
|
+
|
|
301
|
+
@overload
|
|
302
|
+
async def execute(
|
|
303
|
+
self,
|
|
304
|
+
entity: Literal["projects"],
|
|
305
|
+
action: Literal["list"],
|
|
306
|
+
params: "ProjectsListParams"
|
|
307
|
+
) -> "ProjectsListResult": ...
|
|
308
|
+
|
|
309
|
+
@overload
|
|
310
|
+
async def execute(
|
|
311
|
+
self,
|
|
312
|
+
entity: Literal["projects"],
|
|
313
|
+
action: Literal["get"],
|
|
314
|
+
params: "ProjectsGetParams"
|
|
315
|
+
) -> "ProjectsGetResult": ...
|
|
316
|
+
|
|
317
|
+
@overload
|
|
318
|
+
async def execute(
|
|
319
|
+
self,
|
|
320
|
+
entity: Literal["task_projects"],
|
|
321
|
+
action: Literal["list"],
|
|
322
|
+
params: "TaskProjectsListParams"
|
|
323
|
+
) -> "TaskProjectsListResult": ...
|
|
324
|
+
|
|
325
|
+
@overload
|
|
326
|
+
async def execute(
|
|
327
|
+
self,
|
|
328
|
+
entity: Literal["team_projects"],
|
|
329
|
+
action: Literal["list"],
|
|
330
|
+
params: "TeamProjectsListParams"
|
|
331
|
+
) -> "TeamProjectsListResult": ...
|
|
332
|
+
|
|
333
|
+
@overload
|
|
334
|
+
async def execute(
|
|
335
|
+
self,
|
|
336
|
+
entity: Literal["workspace_projects"],
|
|
337
|
+
action: Literal["list"],
|
|
338
|
+
params: "WorkspaceProjectsListParams"
|
|
339
|
+
) -> "WorkspaceProjectsListResult": ...
|
|
340
|
+
|
|
341
|
+
@overload
|
|
342
|
+
async def execute(
|
|
343
|
+
self,
|
|
344
|
+
entity: Literal["workspaces"],
|
|
345
|
+
action: Literal["list"],
|
|
346
|
+
params: "WorkspacesListParams"
|
|
347
|
+
) -> "WorkspacesListResult": ...
|
|
348
|
+
|
|
349
|
+
@overload
|
|
350
|
+
async def execute(
|
|
351
|
+
self,
|
|
352
|
+
entity: Literal["workspaces"],
|
|
353
|
+
action: Literal["get"],
|
|
354
|
+
params: "WorkspacesGetParams"
|
|
355
|
+
) -> "WorkspacesGetResult": ...
|
|
356
|
+
|
|
357
|
+
@overload
|
|
358
|
+
async def execute(
|
|
359
|
+
self,
|
|
360
|
+
entity: Literal["users"],
|
|
361
|
+
action: Literal["list"],
|
|
362
|
+
params: "UsersListParams"
|
|
363
|
+
) -> "UsersListResult": ...
|
|
364
|
+
|
|
365
|
+
@overload
|
|
366
|
+
async def execute(
|
|
367
|
+
self,
|
|
368
|
+
entity: Literal["users"],
|
|
369
|
+
action: Literal["get"],
|
|
370
|
+
params: "UsersGetParams"
|
|
371
|
+
) -> "UsersGetResult": ...
|
|
372
|
+
|
|
373
|
+
@overload
|
|
374
|
+
async def execute(
|
|
375
|
+
self,
|
|
376
|
+
entity: Literal["workspace_users"],
|
|
377
|
+
action: Literal["list"],
|
|
378
|
+
params: "WorkspaceUsersListParams"
|
|
379
|
+
) -> "WorkspaceUsersListResult": ...
|
|
380
|
+
|
|
381
|
+
@overload
|
|
382
|
+
async def execute(
|
|
383
|
+
self,
|
|
384
|
+
entity: Literal["team_users"],
|
|
385
|
+
action: Literal["list"],
|
|
386
|
+
params: "TeamUsersListParams"
|
|
387
|
+
) -> "TeamUsersListResult": ...
|
|
388
|
+
|
|
389
|
+
@overload
|
|
390
|
+
async def execute(
|
|
391
|
+
self,
|
|
392
|
+
entity: Literal["teams"],
|
|
393
|
+
action: Literal["get"],
|
|
394
|
+
params: "TeamsGetParams"
|
|
395
|
+
) -> "TeamsGetResult": ...
|
|
396
|
+
|
|
397
|
+
@overload
|
|
398
|
+
async def execute(
|
|
399
|
+
self,
|
|
400
|
+
entity: Literal["workspace_teams"],
|
|
401
|
+
action: Literal["list"],
|
|
402
|
+
params: "WorkspaceTeamsListParams"
|
|
403
|
+
) -> "WorkspaceTeamsListResult": ...
|
|
404
|
+
|
|
405
|
+
@overload
|
|
406
|
+
async def execute(
|
|
407
|
+
self,
|
|
408
|
+
entity: Literal["user_teams"],
|
|
409
|
+
action: Literal["list"],
|
|
410
|
+
params: "UserTeamsListParams"
|
|
411
|
+
) -> "UserTeamsListResult": ...
|
|
412
|
+
|
|
413
|
+
@overload
|
|
414
|
+
async def execute(
|
|
415
|
+
self,
|
|
416
|
+
entity: Literal["attachments"],
|
|
417
|
+
action: Literal["list"],
|
|
418
|
+
params: "AttachmentsListParams"
|
|
419
|
+
) -> "AttachmentsListResult": ...
|
|
420
|
+
|
|
421
|
+
@overload
|
|
422
|
+
async def execute(
|
|
423
|
+
self,
|
|
424
|
+
entity: Literal["attachments"],
|
|
425
|
+
action: Literal["get"],
|
|
426
|
+
params: "AttachmentsGetParams"
|
|
427
|
+
) -> "AttachmentsGetResult": ...
|
|
428
|
+
|
|
429
|
+
@overload
|
|
430
|
+
async def execute(
|
|
431
|
+
self,
|
|
432
|
+
entity: Literal["attachments"],
|
|
433
|
+
action: Literal["download"],
|
|
434
|
+
params: "AttachmentsDownloadParams"
|
|
435
|
+
) -> "AsyncIterator[bytes]": ...
|
|
436
|
+
|
|
437
|
+
@overload
|
|
438
|
+
async def execute(
|
|
439
|
+
self,
|
|
440
|
+
entity: Literal["workspace_tags"],
|
|
441
|
+
action: Literal["list"],
|
|
442
|
+
params: "WorkspaceTagsListParams"
|
|
443
|
+
) -> "WorkspaceTagsListResult": ...
|
|
444
|
+
|
|
445
|
+
@overload
|
|
446
|
+
async def execute(
|
|
447
|
+
self,
|
|
448
|
+
entity: Literal["tags"],
|
|
449
|
+
action: Literal["get"],
|
|
450
|
+
params: "TagsGetParams"
|
|
451
|
+
) -> "TagsGetResult": ...
|
|
452
|
+
|
|
453
|
+
@overload
|
|
454
|
+
async def execute(
|
|
455
|
+
self,
|
|
456
|
+
entity: Literal["project_sections"],
|
|
457
|
+
action: Literal["list"],
|
|
458
|
+
params: "ProjectSectionsListParams"
|
|
459
|
+
) -> "ProjectSectionsListResult": ...
|
|
460
|
+
|
|
461
|
+
@overload
|
|
462
|
+
async def execute(
|
|
463
|
+
self,
|
|
464
|
+
entity: Literal["sections"],
|
|
465
|
+
action: Literal["get"],
|
|
466
|
+
params: "SectionsGetParams"
|
|
467
|
+
) -> "SectionsGetResult": ...
|
|
468
|
+
|
|
469
|
+
@overload
|
|
470
|
+
async def execute(
|
|
471
|
+
self,
|
|
472
|
+
entity: Literal["task_subtasks"],
|
|
473
|
+
action: Literal["list"],
|
|
474
|
+
params: "TaskSubtasksListParams"
|
|
475
|
+
) -> "TaskSubtasksListResult": ...
|
|
476
|
+
|
|
477
|
+
@overload
|
|
478
|
+
async def execute(
|
|
479
|
+
self,
|
|
480
|
+
entity: Literal["task_dependencies"],
|
|
481
|
+
action: Literal["list"],
|
|
482
|
+
params: "TaskDependenciesListParams"
|
|
483
|
+
) -> "TaskDependenciesListResult": ...
|
|
484
|
+
|
|
485
|
+
@overload
|
|
486
|
+
async def execute(
|
|
487
|
+
self,
|
|
488
|
+
entity: Literal["task_dependents"],
|
|
489
|
+
action: Literal["list"],
|
|
490
|
+
params: "TaskDependentsListParams"
|
|
491
|
+
) -> "TaskDependentsListResult": ...
|
|
492
|
+
|
|
493
|
+
|
|
494
|
+
@overload
|
|
495
|
+
async def execute(
|
|
496
|
+
self,
|
|
497
|
+
entity: str,
|
|
498
|
+
action: str,
|
|
499
|
+
params: dict[str, Any]
|
|
500
|
+
) -> AsanaExecuteResult[Any] | AsanaExecuteResultWithMeta[Any, Any] | Any: ...
|
|
501
|
+
|
|
502
|
+
async def execute(
|
|
503
|
+
self,
|
|
504
|
+
entity: str,
|
|
505
|
+
action: str,
|
|
506
|
+
params: dict[str, Any] | None = None
|
|
507
|
+
) -> Any:
|
|
508
|
+
"""
|
|
509
|
+
Execute an entity operation with full type safety.
|
|
510
|
+
|
|
511
|
+
This is the recommended interface for blessed connectors as it:
|
|
512
|
+
- Uses the same signature as non-blessed connectors
|
|
513
|
+
- Provides full IDE autocomplete for entity/action/params
|
|
514
|
+
- Makes migration from generic to blessed connectors seamless
|
|
515
|
+
|
|
516
|
+
Args:
|
|
517
|
+
entity: Entity name (e.g., "customers")
|
|
518
|
+
action: Operation action (e.g., "create", "get", "list")
|
|
519
|
+
params: Operation parameters (typed based on entity+action)
|
|
520
|
+
|
|
521
|
+
Returns:
|
|
522
|
+
Typed response based on the operation
|
|
523
|
+
|
|
524
|
+
Example:
|
|
525
|
+
customer = await connector.execute(
|
|
526
|
+
entity="customers",
|
|
527
|
+
action="get",
|
|
528
|
+
params={"id": "cus_123"}
|
|
529
|
+
)
|
|
530
|
+
"""
|
|
531
|
+
from ._vendored.connector_sdk.executor import ExecutionConfig
|
|
532
|
+
|
|
533
|
+
# Remap parameter names from snake_case (TypedDict keys) to API parameter names
|
|
534
|
+
if params:
|
|
535
|
+
param_map = self._PARAM_MAP.get((entity, action), {})
|
|
536
|
+
if param_map:
|
|
537
|
+
params = {param_map.get(k, k): v for k, v in params.items()}
|
|
538
|
+
|
|
539
|
+
# Use ExecutionConfig for both local and hosted executors
|
|
540
|
+
config = ExecutionConfig(
|
|
541
|
+
entity=entity,
|
|
542
|
+
action=action,
|
|
543
|
+
params=params
|
|
544
|
+
)
|
|
545
|
+
|
|
546
|
+
result = await self._executor.execute(config)
|
|
547
|
+
|
|
548
|
+
if not result.success:
|
|
549
|
+
raise RuntimeError(f"Execution failed: {result.error}")
|
|
550
|
+
|
|
551
|
+
# Check if this operation has extractors configured
|
|
552
|
+
has_extractors = self._EXTRACTOR_MAP.get((entity, action), False)
|
|
553
|
+
|
|
554
|
+
if has_extractors:
|
|
555
|
+
# With extractors - return Pydantic envelope with data and meta
|
|
556
|
+
if result.meta is not None:
|
|
557
|
+
return AsanaExecuteResultWithMeta[Any, Any](
|
|
558
|
+
data=result.data,
|
|
559
|
+
meta=result.meta
|
|
560
|
+
)
|
|
561
|
+
else:
|
|
562
|
+
return AsanaExecuteResult[Any](data=result.data)
|
|
563
|
+
else:
|
|
564
|
+
# No extractors - return raw response data
|
|
565
|
+
return result.data
|
|
566
|
+
|
|
567
|
+
|
|
568
|
+
|
|
569
|
+
class TasksQuery:
|
|
570
|
+
"""
|
|
571
|
+
Query class for Tasks entity operations.
|
|
572
|
+
"""
|
|
573
|
+
|
|
574
|
+
def __init__(self, connector: AsanaConnector):
|
|
575
|
+
"""Initialize query with connector reference."""
|
|
576
|
+
self._connector = connector
|
|
577
|
+
|
|
578
|
+
async def list(
|
|
579
|
+
self,
|
|
580
|
+
limit: int | None = None,
|
|
581
|
+
offset: str | None = None,
|
|
582
|
+
project: str | None = None,
|
|
583
|
+
workspace: str | None = None,
|
|
584
|
+
section: str | None = None,
|
|
585
|
+
assignee: str | None = None,
|
|
586
|
+
completed_since: str | None = None,
|
|
587
|
+
modified_since: str | None = None,
|
|
588
|
+
**kwargs
|
|
589
|
+
) -> TasksListResult:
|
|
590
|
+
"""
|
|
591
|
+
Returns a paginated list of tasks. Must include either a project OR a section OR a workspace AND assignee parameter.
|
|
592
|
+
|
|
593
|
+
Args:
|
|
594
|
+
limit: Number of items to return per page
|
|
595
|
+
offset: Pagination offset token
|
|
596
|
+
project: The project to filter tasks on
|
|
597
|
+
workspace: The workspace to filter tasks on
|
|
598
|
+
section: The workspace to filter tasks on
|
|
599
|
+
assignee: The assignee to filter tasks on
|
|
600
|
+
completed_since: Only return tasks that have been completed since this time
|
|
601
|
+
modified_since: Only return tasks that have been completed since this time
|
|
602
|
+
**kwargs: Additional parameters
|
|
603
|
+
|
|
604
|
+
Returns:
|
|
605
|
+
TasksListResult
|
|
606
|
+
"""
|
|
607
|
+
params = {k: v for k, v in {
|
|
608
|
+
"limit": limit,
|
|
609
|
+
"offset": offset,
|
|
610
|
+
"project": project,
|
|
611
|
+
"workspace": workspace,
|
|
612
|
+
"section": section,
|
|
613
|
+
"assignee": assignee,
|
|
614
|
+
"completed_since": completed_since,
|
|
615
|
+
"modified_since": modified_since,
|
|
616
|
+
**kwargs
|
|
617
|
+
}.items() if v is not None}
|
|
618
|
+
|
|
619
|
+
result = await self._connector.execute("tasks", "list", params)
|
|
620
|
+
# Cast generic envelope to concrete typed result
|
|
621
|
+
return TasksListResult(
|
|
622
|
+
data=result.data,
|
|
623
|
+
meta=result.meta )
|
|
624
|
+
|
|
625
|
+
|
|
626
|
+
|
|
627
|
+
async def get(
|
|
628
|
+
self,
|
|
629
|
+
task_gid: str,
|
|
630
|
+
**kwargs
|
|
631
|
+
) -> TasksGetResult:
|
|
632
|
+
"""
|
|
633
|
+
Get a single task by its ID
|
|
634
|
+
|
|
635
|
+
Args:
|
|
636
|
+
task_gid: Task GID
|
|
637
|
+
**kwargs: Additional parameters
|
|
638
|
+
|
|
639
|
+
Returns:
|
|
640
|
+
TasksGetResult
|
|
641
|
+
"""
|
|
642
|
+
params = {k: v for k, v in {
|
|
643
|
+
"task_gid": task_gid,
|
|
644
|
+
**kwargs
|
|
645
|
+
}.items() if v is not None}
|
|
646
|
+
|
|
647
|
+
result = await self._connector.execute("tasks", "get", params)
|
|
648
|
+
# Cast generic envelope to concrete typed result
|
|
649
|
+
return TasksGetResult(
|
|
650
|
+
data=result.data )
|
|
651
|
+
|
|
652
|
+
|
|
653
|
+
|
|
654
|
+
class ProjectTasksQuery:
|
|
655
|
+
"""
|
|
656
|
+
Query class for ProjectTasks entity operations.
|
|
657
|
+
"""
|
|
658
|
+
|
|
659
|
+
def __init__(self, connector: AsanaConnector):
|
|
660
|
+
"""Initialize query with connector reference."""
|
|
661
|
+
self._connector = connector
|
|
662
|
+
|
|
663
|
+
async def list(
|
|
664
|
+
self,
|
|
665
|
+
project_gid: str,
|
|
666
|
+
limit: int | None = None,
|
|
667
|
+
offset: str | None = None,
|
|
668
|
+
completed_since: str | None = None,
|
|
669
|
+
**kwargs
|
|
670
|
+
) -> ProjectTasksListResult:
|
|
671
|
+
"""
|
|
672
|
+
Returns all tasks in a project
|
|
673
|
+
|
|
674
|
+
Args:
|
|
675
|
+
project_gid: Project GID to list tasks from
|
|
676
|
+
limit: Number of items to return per page
|
|
677
|
+
offset: Pagination offset token
|
|
678
|
+
completed_since: Only return tasks that have been completed since this time
|
|
679
|
+
**kwargs: Additional parameters
|
|
680
|
+
|
|
681
|
+
Returns:
|
|
682
|
+
ProjectTasksListResult
|
|
683
|
+
"""
|
|
684
|
+
params = {k: v for k, v in {
|
|
685
|
+
"project_gid": project_gid,
|
|
686
|
+
"limit": limit,
|
|
687
|
+
"offset": offset,
|
|
688
|
+
"completed_since": completed_since,
|
|
689
|
+
**kwargs
|
|
690
|
+
}.items() if v is not None}
|
|
691
|
+
|
|
692
|
+
result = await self._connector.execute("project_tasks", "list", params)
|
|
693
|
+
# Cast generic envelope to concrete typed result
|
|
694
|
+
return ProjectTasksListResult(
|
|
695
|
+
data=result.data,
|
|
696
|
+
meta=result.meta )
|
|
697
|
+
|
|
698
|
+
|
|
699
|
+
|
|
700
|
+
class WorkspaceTaskSearchQuery:
|
|
701
|
+
"""
|
|
702
|
+
Query class for WorkspaceTaskSearch entity operations.
|
|
703
|
+
"""
|
|
704
|
+
|
|
705
|
+
def __init__(self, connector: AsanaConnector):
|
|
706
|
+
"""Initialize query with connector reference."""
|
|
707
|
+
self._connector = connector
|
|
708
|
+
|
|
709
|
+
async def list(
|
|
710
|
+
self,
|
|
711
|
+
workspace_gid: str,
|
|
712
|
+
limit: int | None = None,
|
|
713
|
+
offset: str | None = None,
|
|
714
|
+
text: str | None = None,
|
|
715
|
+
completed: bool | None = None,
|
|
716
|
+
assignee_any: str | None = None,
|
|
717
|
+
projects_any: str | None = None,
|
|
718
|
+
sections_any: str | None = None,
|
|
719
|
+
teams_any: str | None = None,
|
|
720
|
+
followers_any: str | None = None,
|
|
721
|
+
created_at_after: str | None = None,
|
|
722
|
+
created_at_before: str | None = None,
|
|
723
|
+
modified_at_after: str | None = None,
|
|
724
|
+
modified_at_before: str | None = None,
|
|
725
|
+
due_on_after: str | None = None,
|
|
726
|
+
due_on_before: str | None = None,
|
|
727
|
+
resource_subtype: str | None = None,
|
|
728
|
+
sort_by: str | None = None,
|
|
729
|
+
sort_ascending: bool | None = None,
|
|
730
|
+
**kwargs
|
|
731
|
+
) -> WorkspaceTaskSearchListResult:
|
|
732
|
+
"""
|
|
733
|
+
Returns tasks that match the specified search criteria. Note - This endpoint requires a premium Asana account. At least one search parameter must be provided.
|
|
734
|
+
|
|
735
|
+
Args:
|
|
736
|
+
workspace_gid: Workspace GID to search tasks in
|
|
737
|
+
limit: Number of items to return per page
|
|
738
|
+
offset: Pagination offset token
|
|
739
|
+
text: Search text to filter tasks
|
|
740
|
+
completed: Filter by completion status
|
|
741
|
+
assignee_any: Comma-separated list of assignee GIDs
|
|
742
|
+
projects_any: Comma-separated list of project GIDs
|
|
743
|
+
sections_any: Comma-separated list of section GIDs
|
|
744
|
+
teams_any: Comma-separated list of team GIDs
|
|
745
|
+
followers_any: Comma-separated list of follower GIDs
|
|
746
|
+
created_at_after: Filter tasks created after this date (ISO 8601 format)
|
|
747
|
+
created_at_before: Filter tasks created before this date (ISO 8601 format)
|
|
748
|
+
modified_at_after: Filter tasks modified after this date (ISO 8601 format)
|
|
749
|
+
modified_at_before: Filter tasks modified before this date (ISO 8601 format)
|
|
750
|
+
due_on_after: Filter tasks due after this date (ISO 8601 date format)
|
|
751
|
+
due_on_before: Filter tasks due before this date (ISO 8601 date format)
|
|
752
|
+
resource_subtype: Filter by task resource subtype (e.g., default_task, milestone)
|
|
753
|
+
sort_by: Field to sort by (e.g., created_at, modified_at, due_date)
|
|
754
|
+
sort_ascending: Sort order (true for ascending, false for descending)
|
|
755
|
+
**kwargs: Additional parameters
|
|
756
|
+
|
|
757
|
+
Returns:
|
|
758
|
+
WorkspaceTaskSearchListResult
|
|
759
|
+
"""
|
|
760
|
+
params = {k: v for k, v in {
|
|
761
|
+
"workspace_gid": workspace_gid,
|
|
762
|
+
"limit": limit,
|
|
763
|
+
"offset": offset,
|
|
764
|
+
"text": text,
|
|
765
|
+
"completed": completed,
|
|
766
|
+
"assignee.any": assignee_any,
|
|
767
|
+
"projects.any": projects_any,
|
|
768
|
+
"sections.any": sections_any,
|
|
769
|
+
"teams.any": teams_any,
|
|
770
|
+
"followers.any": followers_any,
|
|
771
|
+
"created_at.after": created_at_after,
|
|
772
|
+
"created_at.before": created_at_before,
|
|
773
|
+
"modified_at.after": modified_at_after,
|
|
774
|
+
"modified_at.before": modified_at_before,
|
|
775
|
+
"due_on.after": due_on_after,
|
|
776
|
+
"due_on.before": due_on_before,
|
|
777
|
+
"resource_subtype": resource_subtype,
|
|
778
|
+
"sort_by": sort_by,
|
|
779
|
+
"sort_ascending": sort_ascending,
|
|
780
|
+
**kwargs
|
|
781
|
+
}.items() if v is not None}
|
|
782
|
+
|
|
783
|
+
result = await self._connector.execute("workspace_task_search", "list", params)
|
|
784
|
+
# Cast generic envelope to concrete typed result
|
|
785
|
+
return WorkspaceTaskSearchListResult(
|
|
786
|
+
data=result.data,
|
|
787
|
+
meta=result.meta )
|
|
788
|
+
|
|
789
|
+
|
|
790
|
+
|
|
791
|
+
class ProjectsQuery:
|
|
792
|
+
"""
|
|
793
|
+
Query class for Projects entity operations.
|
|
794
|
+
"""
|
|
795
|
+
|
|
796
|
+
def __init__(self, connector: AsanaConnector):
|
|
797
|
+
"""Initialize query with connector reference."""
|
|
798
|
+
self._connector = connector
|
|
799
|
+
|
|
800
|
+
async def list(
|
|
801
|
+
self,
|
|
802
|
+
limit: int | None = None,
|
|
803
|
+
offset: str | None = None,
|
|
804
|
+
workspace: str | None = None,
|
|
805
|
+
team: str | None = None,
|
|
806
|
+
archived: bool | None = None,
|
|
807
|
+
**kwargs
|
|
808
|
+
) -> ProjectsListResult:
|
|
809
|
+
"""
|
|
810
|
+
Returns a paginated list of projects
|
|
811
|
+
|
|
812
|
+
Args:
|
|
813
|
+
limit: Number of items to return per page
|
|
814
|
+
offset: Pagination offset token
|
|
815
|
+
workspace: The workspace to filter projects on
|
|
816
|
+
team: The team to filter projects on
|
|
817
|
+
archived: Filter by archived status
|
|
818
|
+
**kwargs: Additional parameters
|
|
819
|
+
|
|
820
|
+
Returns:
|
|
821
|
+
ProjectsListResult
|
|
822
|
+
"""
|
|
823
|
+
params = {k: v for k, v in {
|
|
824
|
+
"limit": limit,
|
|
825
|
+
"offset": offset,
|
|
826
|
+
"workspace": workspace,
|
|
827
|
+
"team": team,
|
|
828
|
+
"archived": archived,
|
|
829
|
+
**kwargs
|
|
830
|
+
}.items() if v is not None}
|
|
831
|
+
|
|
832
|
+
result = await self._connector.execute("projects", "list", params)
|
|
833
|
+
# Cast generic envelope to concrete typed result
|
|
834
|
+
return ProjectsListResult(
|
|
835
|
+
data=result.data,
|
|
836
|
+
meta=result.meta )
|
|
837
|
+
|
|
838
|
+
|
|
839
|
+
|
|
840
|
+
async def get(
|
|
841
|
+
self,
|
|
842
|
+
project_gid: str,
|
|
843
|
+
**kwargs
|
|
844
|
+
) -> ProjectsGetResult:
|
|
845
|
+
"""
|
|
846
|
+
Get a single project by its ID
|
|
847
|
+
|
|
848
|
+
Args:
|
|
849
|
+
project_gid: Project GID
|
|
850
|
+
**kwargs: Additional parameters
|
|
851
|
+
|
|
852
|
+
Returns:
|
|
853
|
+
ProjectsGetResult
|
|
854
|
+
"""
|
|
855
|
+
params = {k: v for k, v in {
|
|
856
|
+
"project_gid": project_gid,
|
|
857
|
+
**kwargs
|
|
858
|
+
}.items() if v is not None}
|
|
859
|
+
|
|
860
|
+
result = await self._connector.execute("projects", "get", params)
|
|
861
|
+
# Cast generic envelope to concrete typed result
|
|
862
|
+
return ProjectsGetResult(
|
|
863
|
+
data=result.data )
|
|
864
|
+
|
|
865
|
+
|
|
866
|
+
|
|
867
|
+
class TaskProjectsQuery:
|
|
868
|
+
"""
|
|
869
|
+
Query class for TaskProjects entity operations.
|
|
870
|
+
"""
|
|
871
|
+
|
|
872
|
+
def __init__(self, connector: AsanaConnector):
|
|
873
|
+
"""Initialize query with connector reference."""
|
|
874
|
+
self._connector = connector
|
|
875
|
+
|
|
876
|
+
async def list(
|
|
877
|
+
self,
|
|
878
|
+
task_gid: str,
|
|
879
|
+
limit: int | None = None,
|
|
880
|
+
offset: str | None = None,
|
|
881
|
+
**kwargs
|
|
882
|
+
) -> TaskProjectsListResult:
|
|
883
|
+
"""
|
|
884
|
+
Returns all projects a task is in
|
|
885
|
+
|
|
886
|
+
Args:
|
|
887
|
+
task_gid: Task GID to list projects from
|
|
888
|
+
limit: Number of items to return per page
|
|
889
|
+
offset: Pagination offset token
|
|
890
|
+
**kwargs: Additional parameters
|
|
891
|
+
|
|
892
|
+
Returns:
|
|
893
|
+
TaskProjectsListResult
|
|
894
|
+
"""
|
|
895
|
+
params = {k: v for k, v in {
|
|
896
|
+
"task_gid": task_gid,
|
|
897
|
+
"limit": limit,
|
|
898
|
+
"offset": offset,
|
|
899
|
+
**kwargs
|
|
900
|
+
}.items() if v is not None}
|
|
901
|
+
|
|
902
|
+
result = await self._connector.execute("task_projects", "list", params)
|
|
903
|
+
# Cast generic envelope to concrete typed result
|
|
904
|
+
return TaskProjectsListResult(
|
|
905
|
+
data=result.data,
|
|
906
|
+
meta=result.meta )
|
|
907
|
+
|
|
908
|
+
|
|
909
|
+
|
|
910
|
+
class TeamProjectsQuery:
|
|
911
|
+
"""
|
|
912
|
+
Query class for TeamProjects entity operations.
|
|
913
|
+
"""
|
|
914
|
+
|
|
915
|
+
def __init__(self, connector: AsanaConnector):
|
|
916
|
+
"""Initialize query with connector reference."""
|
|
917
|
+
self._connector = connector
|
|
918
|
+
|
|
919
|
+
async def list(
|
|
920
|
+
self,
|
|
921
|
+
team_gid: str,
|
|
922
|
+
limit: int | None = None,
|
|
923
|
+
offset: str | None = None,
|
|
924
|
+
archived: bool | None = None,
|
|
925
|
+
**kwargs
|
|
926
|
+
) -> TeamProjectsListResult:
|
|
927
|
+
"""
|
|
928
|
+
Returns all projects for a team
|
|
929
|
+
|
|
930
|
+
Args:
|
|
931
|
+
team_gid: Team GID to list projects from
|
|
932
|
+
limit: Number of items to return per page
|
|
933
|
+
offset: Pagination offset token
|
|
934
|
+
archived: Filter by archived status
|
|
935
|
+
**kwargs: Additional parameters
|
|
936
|
+
|
|
937
|
+
Returns:
|
|
938
|
+
TeamProjectsListResult
|
|
939
|
+
"""
|
|
940
|
+
params = {k: v for k, v in {
|
|
941
|
+
"team_gid": team_gid,
|
|
942
|
+
"limit": limit,
|
|
943
|
+
"offset": offset,
|
|
944
|
+
"archived": archived,
|
|
945
|
+
**kwargs
|
|
946
|
+
}.items() if v is not None}
|
|
947
|
+
|
|
948
|
+
result = await self._connector.execute("team_projects", "list", params)
|
|
949
|
+
# Cast generic envelope to concrete typed result
|
|
950
|
+
return TeamProjectsListResult(
|
|
951
|
+
data=result.data,
|
|
952
|
+
meta=result.meta )
|
|
953
|
+
|
|
954
|
+
|
|
955
|
+
|
|
956
|
+
class WorkspaceProjectsQuery:
|
|
957
|
+
"""
|
|
958
|
+
Query class for WorkspaceProjects entity operations.
|
|
959
|
+
"""
|
|
960
|
+
|
|
961
|
+
def __init__(self, connector: AsanaConnector):
|
|
962
|
+
"""Initialize query with connector reference."""
|
|
963
|
+
self._connector = connector
|
|
964
|
+
|
|
965
|
+
async def list(
|
|
966
|
+
self,
|
|
967
|
+
workspace_gid: str,
|
|
968
|
+
limit: int | None = None,
|
|
969
|
+
offset: str | None = None,
|
|
970
|
+
archived: bool | None = None,
|
|
971
|
+
**kwargs
|
|
972
|
+
) -> WorkspaceProjectsListResult:
|
|
973
|
+
"""
|
|
974
|
+
Returns all projects in a workspace
|
|
975
|
+
|
|
976
|
+
Args:
|
|
977
|
+
workspace_gid: Workspace GID to list projects from
|
|
978
|
+
limit: Number of items to return per page
|
|
979
|
+
offset: Pagination offset token
|
|
980
|
+
archived: Filter by archived status
|
|
981
|
+
**kwargs: Additional parameters
|
|
982
|
+
|
|
983
|
+
Returns:
|
|
984
|
+
WorkspaceProjectsListResult
|
|
985
|
+
"""
|
|
986
|
+
params = {k: v for k, v in {
|
|
987
|
+
"workspace_gid": workspace_gid,
|
|
988
|
+
"limit": limit,
|
|
989
|
+
"offset": offset,
|
|
990
|
+
"archived": archived,
|
|
991
|
+
**kwargs
|
|
992
|
+
}.items() if v is not None}
|
|
993
|
+
|
|
994
|
+
result = await self._connector.execute("workspace_projects", "list", params)
|
|
995
|
+
# Cast generic envelope to concrete typed result
|
|
996
|
+
return WorkspaceProjectsListResult(
|
|
997
|
+
data=result.data,
|
|
998
|
+
meta=result.meta )
|
|
999
|
+
|
|
1000
|
+
|
|
1001
|
+
|
|
1002
|
+
class WorkspacesQuery:
|
|
1003
|
+
"""
|
|
1004
|
+
Query class for Workspaces entity operations.
|
|
1005
|
+
"""
|
|
1006
|
+
|
|
1007
|
+
def __init__(self, connector: AsanaConnector):
|
|
1008
|
+
"""Initialize query with connector reference."""
|
|
1009
|
+
self._connector = connector
|
|
1010
|
+
|
|
1011
|
+
async def list(
|
|
1012
|
+
self,
|
|
1013
|
+
limit: int | None = None,
|
|
1014
|
+
offset: str | None = None,
|
|
1015
|
+
**kwargs
|
|
1016
|
+
) -> WorkspacesListResult:
|
|
1017
|
+
"""
|
|
1018
|
+
Returns a paginated list of workspaces
|
|
1019
|
+
|
|
1020
|
+
Args:
|
|
1021
|
+
limit: Number of items to return per page
|
|
1022
|
+
offset: Pagination offset token
|
|
1023
|
+
**kwargs: Additional parameters
|
|
1024
|
+
|
|
1025
|
+
Returns:
|
|
1026
|
+
WorkspacesListResult
|
|
1027
|
+
"""
|
|
1028
|
+
params = {k: v for k, v in {
|
|
1029
|
+
"limit": limit,
|
|
1030
|
+
"offset": offset,
|
|
1031
|
+
**kwargs
|
|
1032
|
+
}.items() if v is not None}
|
|
1033
|
+
|
|
1034
|
+
result = await self._connector.execute("workspaces", "list", params)
|
|
1035
|
+
# Cast generic envelope to concrete typed result
|
|
1036
|
+
return WorkspacesListResult(
|
|
1037
|
+
data=result.data,
|
|
1038
|
+
meta=result.meta )
|
|
1039
|
+
|
|
1040
|
+
|
|
1041
|
+
|
|
1042
|
+
async def get(
|
|
1043
|
+
self,
|
|
1044
|
+
workspace_gid: str,
|
|
1045
|
+
**kwargs
|
|
1046
|
+
) -> WorkspacesGetResult:
|
|
1047
|
+
"""
|
|
1048
|
+
Get a single workspace by its ID
|
|
1049
|
+
|
|
1050
|
+
Args:
|
|
1051
|
+
workspace_gid: Workspace GID
|
|
1052
|
+
**kwargs: Additional parameters
|
|
1053
|
+
|
|
1054
|
+
Returns:
|
|
1055
|
+
WorkspacesGetResult
|
|
1056
|
+
"""
|
|
1057
|
+
params = {k: v for k, v in {
|
|
1058
|
+
"workspace_gid": workspace_gid,
|
|
1059
|
+
**kwargs
|
|
1060
|
+
}.items() if v is not None}
|
|
1061
|
+
|
|
1062
|
+
result = await self._connector.execute("workspaces", "get", params)
|
|
1063
|
+
# Cast generic envelope to concrete typed result
|
|
1064
|
+
return WorkspacesGetResult(
|
|
1065
|
+
data=result.data )
|
|
1066
|
+
|
|
1067
|
+
|
|
1068
|
+
|
|
1069
|
+
class UsersQuery:
|
|
1070
|
+
"""
|
|
1071
|
+
Query class for Users entity operations.
|
|
1072
|
+
"""
|
|
1073
|
+
|
|
1074
|
+
def __init__(self, connector: AsanaConnector):
|
|
1075
|
+
"""Initialize query with connector reference."""
|
|
1076
|
+
self._connector = connector
|
|
1077
|
+
|
|
1078
|
+
async def list(
|
|
1079
|
+
self,
|
|
1080
|
+
limit: int | None = None,
|
|
1081
|
+
offset: str | None = None,
|
|
1082
|
+
workspace: str | None = None,
|
|
1083
|
+
team: str | None = None,
|
|
1084
|
+
**kwargs
|
|
1085
|
+
) -> UsersListResult:
|
|
1086
|
+
"""
|
|
1087
|
+
Returns a paginated list of users
|
|
1088
|
+
|
|
1089
|
+
Args:
|
|
1090
|
+
limit: Number of items to return per page
|
|
1091
|
+
offset: Pagination offset token
|
|
1092
|
+
workspace: The workspace to filter users on
|
|
1093
|
+
team: The team to filter users on
|
|
1094
|
+
**kwargs: Additional parameters
|
|
1095
|
+
|
|
1096
|
+
Returns:
|
|
1097
|
+
UsersListResult
|
|
1098
|
+
"""
|
|
1099
|
+
params = {k: v for k, v in {
|
|
1100
|
+
"limit": limit,
|
|
1101
|
+
"offset": offset,
|
|
1102
|
+
"workspace": workspace,
|
|
1103
|
+
"team": team,
|
|
1104
|
+
**kwargs
|
|
1105
|
+
}.items() if v is not None}
|
|
1106
|
+
|
|
1107
|
+
result = await self._connector.execute("users", "list", params)
|
|
1108
|
+
# Cast generic envelope to concrete typed result
|
|
1109
|
+
return UsersListResult(
|
|
1110
|
+
data=result.data,
|
|
1111
|
+
meta=result.meta )
|
|
1112
|
+
|
|
1113
|
+
|
|
1114
|
+
|
|
1115
|
+
async def get(
|
|
1116
|
+
self,
|
|
1117
|
+
user_gid: str,
|
|
1118
|
+
**kwargs
|
|
1119
|
+
) -> UsersGetResult:
|
|
1120
|
+
"""
|
|
1121
|
+
Get a single user by their ID
|
|
1122
|
+
|
|
1123
|
+
Args:
|
|
1124
|
+
user_gid: User GID
|
|
1125
|
+
**kwargs: Additional parameters
|
|
1126
|
+
|
|
1127
|
+
Returns:
|
|
1128
|
+
UsersGetResult
|
|
1129
|
+
"""
|
|
1130
|
+
params = {k: v for k, v in {
|
|
1131
|
+
"user_gid": user_gid,
|
|
1132
|
+
**kwargs
|
|
1133
|
+
}.items() if v is not None}
|
|
1134
|
+
|
|
1135
|
+
result = await self._connector.execute("users", "get", params)
|
|
1136
|
+
# Cast generic envelope to concrete typed result
|
|
1137
|
+
return UsersGetResult(
|
|
1138
|
+
data=result.data )
|
|
1139
|
+
|
|
1140
|
+
|
|
1141
|
+
|
|
1142
|
+
class WorkspaceUsersQuery:
|
|
1143
|
+
"""
|
|
1144
|
+
Query class for WorkspaceUsers entity operations.
|
|
1145
|
+
"""
|
|
1146
|
+
|
|
1147
|
+
def __init__(self, connector: AsanaConnector):
|
|
1148
|
+
"""Initialize query with connector reference."""
|
|
1149
|
+
self._connector = connector
|
|
1150
|
+
|
|
1151
|
+
async def list(
|
|
1152
|
+
self,
|
|
1153
|
+
workspace_gid: str,
|
|
1154
|
+
limit: int | None = None,
|
|
1155
|
+
offset: str | None = None,
|
|
1156
|
+
**kwargs
|
|
1157
|
+
) -> WorkspaceUsersListResult:
|
|
1158
|
+
"""
|
|
1159
|
+
Returns all users in a workspace
|
|
1160
|
+
|
|
1161
|
+
Args:
|
|
1162
|
+
workspace_gid: Workspace GID to list users from
|
|
1163
|
+
limit: Number of items to return per page
|
|
1164
|
+
offset: Pagination offset token
|
|
1165
|
+
**kwargs: Additional parameters
|
|
1166
|
+
|
|
1167
|
+
Returns:
|
|
1168
|
+
WorkspaceUsersListResult
|
|
1169
|
+
"""
|
|
1170
|
+
params = {k: v for k, v in {
|
|
1171
|
+
"workspace_gid": workspace_gid,
|
|
1172
|
+
"limit": limit,
|
|
1173
|
+
"offset": offset,
|
|
1174
|
+
**kwargs
|
|
1175
|
+
}.items() if v is not None}
|
|
1176
|
+
|
|
1177
|
+
result = await self._connector.execute("workspace_users", "list", params)
|
|
1178
|
+
# Cast generic envelope to concrete typed result
|
|
1179
|
+
return WorkspaceUsersListResult(
|
|
1180
|
+
data=result.data,
|
|
1181
|
+
meta=result.meta )
|
|
1182
|
+
|
|
1183
|
+
|
|
1184
|
+
|
|
1185
|
+
class TeamUsersQuery:
|
|
1186
|
+
"""
|
|
1187
|
+
Query class for TeamUsers entity operations.
|
|
1188
|
+
"""
|
|
1189
|
+
|
|
1190
|
+
def __init__(self, connector: AsanaConnector):
|
|
1191
|
+
"""Initialize query with connector reference."""
|
|
1192
|
+
self._connector = connector
|
|
1193
|
+
|
|
1194
|
+
async def list(
|
|
1195
|
+
self,
|
|
1196
|
+
team_gid: str,
|
|
1197
|
+
limit: int | None = None,
|
|
1198
|
+
offset: str | None = None,
|
|
1199
|
+
**kwargs
|
|
1200
|
+
) -> TeamUsersListResult:
|
|
1201
|
+
"""
|
|
1202
|
+
Returns all users in a team
|
|
1203
|
+
|
|
1204
|
+
Args:
|
|
1205
|
+
team_gid: Team GID to list users from
|
|
1206
|
+
limit: Number of items to return per page
|
|
1207
|
+
offset: Pagination offset token
|
|
1208
|
+
**kwargs: Additional parameters
|
|
1209
|
+
|
|
1210
|
+
Returns:
|
|
1211
|
+
TeamUsersListResult
|
|
1212
|
+
"""
|
|
1213
|
+
params = {k: v for k, v in {
|
|
1214
|
+
"team_gid": team_gid,
|
|
1215
|
+
"limit": limit,
|
|
1216
|
+
"offset": offset,
|
|
1217
|
+
**kwargs
|
|
1218
|
+
}.items() if v is not None}
|
|
1219
|
+
|
|
1220
|
+
result = await self._connector.execute("team_users", "list", params)
|
|
1221
|
+
# Cast generic envelope to concrete typed result
|
|
1222
|
+
return TeamUsersListResult(
|
|
1223
|
+
data=result.data,
|
|
1224
|
+
meta=result.meta )
|
|
1225
|
+
|
|
1226
|
+
|
|
1227
|
+
|
|
1228
|
+
class TeamsQuery:
|
|
1229
|
+
"""
|
|
1230
|
+
Query class for Teams entity operations.
|
|
1231
|
+
"""
|
|
1232
|
+
|
|
1233
|
+
def __init__(self, connector: AsanaConnector):
|
|
1234
|
+
"""Initialize query with connector reference."""
|
|
1235
|
+
self._connector = connector
|
|
1236
|
+
|
|
1237
|
+
async def get(
|
|
1238
|
+
self,
|
|
1239
|
+
team_gid: str,
|
|
1240
|
+
**kwargs
|
|
1241
|
+
) -> TeamsGetResult:
|
|
1242
|
+
"""
|
|
1243
|
+
Get a single team by its ID
|
|
1244
|
+
|
|
1245
|
+
Args:
|
|
1246
|
+
team_gid: Team GID
|
|
1247
|
+
**kwargs: Additional parameters
|
|
1248
|
+
|
|
1249
|
+
Returns:
|
|
1250
|
+
TeamsGetResult
|
|
1251
|
+
"""
|
|
1252
|
+
params = {k: v for k, v in {
|
|
1253
|
+
"team_gid": team_gid,
|
|
1254
|
+
**kwargs
|
|
1255
|
+
}.items() if v is not None}
|
|
1256
|
+
|
|
1257
|
+
result = await self._connector.execute("teams", "get", params)
|
|
1258
|
+
# Cast generic envelope to concrete typed result
|
|
1259
|
+
return TeamsGetResult(
|
|
1260
|
+
data=result.data )
|
|
1261
|
+
|
|
1262
|
+
|
|
1263
|
+
|
|
1264
|
+
class WorkspaceTeamsQuery:
|
|
1265
|
+
"""
|
|
1266
|
+
Query class for WorkspaceTeams entity operations.
|
|
1267
|
+
"""
|
|
1268
|
+
|
|
1269
|
+
def __init__(self, connector: AsanaConnector):
|
|
1270
|
+
"""Initialize query with connector reference."""
|
|
1271
|
+
self._connector = connector
|
|
1272
|
+
|
|
1273
|
+
async def list(
|
|
1274
|
+
self,
|
|
1275
|
+
workspace_gid: str,
|
|
1276
|
+
limit: int | None = None,
|
|
1277
|
+
offset: str | None = None,
|
|
1278
|
+
**kwargs
|
|
1279
|
+
) -> WorkspaceTeamsListResult:
|
|
1280
|
+
"""
|
|
1281
|
+
Returns all teams in a workspace
|
|
1282
|
+
|
|
1283
|
+
Args:
|
|
1284
|
+
workspace_gid: Workspace GID to list teams from
|
|
1285
|
+
limit: Number of items to return per page
|
|
1286
|
+
offset: Pagination offset token
|
|
1287
|
+
**kwargs: Additional parameters
|
|
1288
|
+
|
|
1289
|
+
Returns:
|
|
1290
|
+
WorkspaceTeamsListResult
|
|
1291
|
+
"""
|
|
1292
|
+
params = {k: v for k, v in {
|
|
1293
|
+
"workspace_gid": workspace_gid,
|
|
1294
|
+
"limit": limit,
|
|
1295
|
+
"offset": offset,
|
|
1296
|
+
**kwargs
|
|
1297
|
+
}.items() if v is not None}
|
|
1298
|
+
|
|
1299
|
+
result = await self._connector.execute("workspace_teams", "list", params)
|
|
1300
|
+
# Cast generic envelope to concrete typed result
|
|
1301
|
+
return WorkspaceTeamsListResult(
|
|
1302
|
+
data=result.data,
|
|
1303
|
+
meta=result.meta )
|
|
1304
|
+
|
|
1305
|
+
|
|
1306
|
+
|
|
1307
|
+
class UserTeamsQuery:
|
|
1308
|
+
"""
|
|
1309
|
+
Query class for UserTeams entity operations.
|
|
1310
|
+
"""
|
|
1311
|
+
|
|
1312
|
+
def __init__(self, connector: AsanaConnector):
|
|
1313
|
+
"""Initialize query with connector reference."""
|
|
1314
|
+
self._connector = connector
|
|
1315
|
+
|
|
1316
|
+
async def list(
|
|
1317
|
+
self,
|
|
1318
|
+
user_gid: str,
|
|
1319
|
+
organization: str,
|
|
1320
|
+
limit: int | None = None,
|
|
1321
|
+
offset: str | None = None,
|
|
1322
|
+
**kwargs
|
|
1323
|
+
) -> UserTeamsListResult:
|
|
1324
|
+
"""
|
|
1325
|
+
Returns all teams a user is a member of
|
|
1326
|
+
|
|
1327
|
+
Args:
|
|
1328
|
+
user_gid: User GID to list teams from
|
|
1329
|
+
organization: The workspace or organization to filter teams on
|
|
1330
|
+
limit: Number of items to return per page
|
|
1331
|
+
offset: Pagination offset token
|
|
1332
|
+
**kwargs: Additional parameters
|
|
1333
|
+
|
|
1334
|
+
Returns:
|
|
1335
|
+
UserTeamsListResult
|
|
1336
|
+
"""
|
|
1337
|
+
params = {k: v for k, v in {
|
|
1338
|
+
"user_gid": user_gid,
|
|
1339
|
+
"organization": organization,
|
|
1340
|
+
"limit": limit,
|
|
1341
|
+
"offset": offset,
|
|
1342
|
+
**kwargs
|
|
1343
|
+
}.items() if v is not None}
|
|
1344
|
+
|
|
1345
|
+
result = await self._connector.execute("user_teams", "list", params)
|
|
1346
|
+
# Cast generic envelope to concrete typed result
|
|
1347
|
+
return UserTeamsListResult(
|
|
1348
|
+
data=result.data,
|
|
1349
|
+
meta=result.meta )
|
|
1350
|
+
|
|
1351
|
+
|
|
1352
|
+
|
|
1353
|
+
class AttachmentsQuery:
|
|
1354
|
+
"""
|
|
1355
|
+
Query class for Attachments entity operations.
|
|
1356
|
+
"""
|
|
1357
|
+
|
|
1358
|
+
def __init__(self, connector: AsanaConnector):
|
|
1359
|
+
"""Initialize query with connector reference."""
|
|
1360
|
+
self._connector = connector
|
|
1361
|
+
|
|
1362
|
+
async def list(
|
|
1363
|
+
self,
|
|
1364
|
+
parent: str,
|
|
1365
|
+
limit: int | None = None,
|
|
1366
|
+
offset: str | None = None,
|
|
1367
|
+
**kwargs
|
|
1368
|
+
) -> AttachmentsListResult:
|
|
1369
|
+
"""
|
|
1370
|
+
Returns a list of attachments for an object (task, project, etc.)
|
|
1371
|
+
|
|
1372
|
+
Args:
|
|
1373
|
+
parent: Globally unique identifier for the object to fetch attachments for (e.g., a task GID)
|
|
1374
|
+
limit: Number of items to return per page
|
|
1375
|
+
offset: Pagination offset token
|
|
1376
|
+
**kwargs: Additional parameters
|
|
1377
|
+
|
|
1378
|
+
Returns:
|
|
1379
|
+
AttachmentsListResult
|
|
1380
|
+
"""
|
|
1381
|
+
params = {k: v for k, v in {
|
|
1382
|
+
"parent": parent,
|
|
1383
|
+
"limit": limit,
|
|
1384
|
+
"offset": offset,
|
|
1385
|
+
**kwargs
|
|
1386
|
+
}.items() if v is not None}
|
|
1387
|
+
|
|
1388
|
+
result = await self._connector.execute("attachments", "list", params)
|
|
1389
|
+
# Cast generic envelope to concrete typed result
|
|
1390
|
+
return AttachmentsListResult(
|
|
1391
|
+
data=result.data,
|
|
1392
|
+
meta=result.meta )
|
|
1393
|
+
|
|
1394
|
+
|
|
1395
|
+
|
|
1396
|
+
async def get(
|
|
1397
|
+
self,
|
|
1398
|
+
attachment_gid: str,
|
|
1399
|
+
**kwargs
|
|
1400
|
+
) -> AttachmentsGetResult:
|
|
1401
|
+
"""
|
|
1402
|
+
Get details for a single attachment by its GID
|
|
1403
|
+
|
|
1404
|
+
Args:
|
|
1405
|
+
attachment_gid: Globally unique identifier for the attachment
|
|
1406
|
+
**kwargs: Additional parameters
|
|
1407
|
+
|
|
1408
|
+
Returns:
|
|
1409
|
+
AttachmentsGetResult
|
|
1410
|
+
"""
|
|
1411
|
+
params = {k: v for k, v in {
|
|
1412
|
+
"attachment_gid": attachment_gid,
|
|
1413
|
+
**kwargs
|
|
1414
|
+
}.items() if v is not None}
|
|
1415
|
+
|
|
1416
|
+
result = await self._connector.execute("attachments", "get", params)
|
|
1417
|
+
# Cast generic envelope to concrete typed result
|
|
1418
|
+
return AttachmentsGetResult(
|
|
1419
|
+
data=result.data )
|
|
1420
|
+
|
|
1421
|
+
|
|
1422
|
+
|
|
1423
|
+
async def download(
|
|
1424
|
+
self,
|
|
1425
|
+
attachment_gid: str,
|
|
1426
|
+
range_header: str | None = None,
|
|
1427
|
+
**kwargs
|
|
1428
|
+
) -> AsyncIterator[bytes]:
|
|
1429
|
+
"""
|
|
1430
|
+
Downloads the file content of an attachment. This operation first retrieves the attachment
|
|
1431
|
+
metadata to get the download_url, then downloads the file from that URL.
|
|
1432
|
+
|
|
1433
|
+
|
|
1434
|
+
Args:
|
|
1435
|
+
attachment_gid: Globally unique identifier for the attachment
|
|
1436
|
+
range_header: Optional Range header for partial downloads (e.g., 'bytes=0-99')
|
|
1437
|
+
**kwargs: Additional parameters
|
|
1438
|
+
|
|
1439
|
+
Returns:
|
|
1440
|
+
AsyncIterator[bytes]
|
|
1441
|
+
"""
|
|
1442
|
+
params = {k: v for k, v in {
|
|
1443
|
+
"attachment_gid": attachment_gid,
|
|
1444
|
+
"range_header": range_header,
|
|
1445
|
+
**kwargs
|
|
1446
|
+
}.items() if v is not None}
|
|
1447
|
+
|
|
1448
|
+
result = await self._connector.execute("attachments", "download", params)
|
|
1449
|
+
return result
|
|
1450
|
+
|
|
1451
|
+
|
|
1452
|
+
async def download_local(
|
|
1453
|
+
self,
|
|
1454
|
+
attachment_gid: str,
|
|
1455
|
+
path: str,
|
|
1456
|
+
range_header: str | None = None,
|
|
1457
|
+
**kwargs
|
|
1458
|
+
) -> Path:
|
|
1459
|
+
"""
|
|
1460
|
+
Downloads the file content of an attachment. This operation first retrieves the attachment
|
|
1461
|
+
metadata to get the download_url, then downloads the file from that URL.
|
|
1462
|
+
and save to file.
|
|
1463
|
+
|
|
1464
|
+
Args:
|
|
1465
|
+
attachment_gid: Globally unique identifier for the attachment
|
|
1466
|
+
range_header: Optional Range header for partial downloads (e.g., 'bytes=0-99')
|
|
1467
|
+
path: File path to save downloaded content
|
|
1468
|
+
**kwargs: Additional parameters
|
|
1469
|
+
|
|
1470
|
+
Returns:
|
|
1471
|
+
str: Path to the downloaded file
|
|
1472
|
+
"""
|
|
1473
|
+
from ._vendored.connector_sdk import save_download
|
|
1474
|
+
|
|
1475
|
+
# Get the async iterator
|
|
1476
|
+
content_iterator = await self.download(
|
|
1477
|
+
attachment_gid=attachment_gid,
|
|
1478
|
+
range_header=range_header,
|
|
1479
|
+
**kwargs
|
|
1480
|
+
)
|
|
1481
|
+
|
|
1482
|
+
return await save_download(content_iterator, path)
|
|
1483
|
+
|
|
1484
|
+
|
|
1485
|
+
class WorkspaceTagsQuery:
|
|
1486
|
+
"""
|
|
1487
|
+
Query class for WorkspaceTags entity operations.
|
|
1488
|
+
"""
|
|
1489
|
+
|
|
1490
|
+
def __init__(self, connector: AsanaConnector):
|
|
1491
|
+
"""Initialize query with connector reference."""
|
|
1492
|
+
self._connector = connector
|
|
1493
|
+
|
|
1494
|
+
async def list(
|
|
1495
|
+
self,
|
|
1496
|
+
workspace_gid: str,
|
|
1497
|
+
limit: int | None = None,
|
|
1498
|
+
offset: str | None = None,
|
|
1499
|
+
**kwargs
|
|
1500
|
+
) -> WorkspaceTagsListResult:
|
|
1501
|
+
"""
|
|
1502
|
+
Returns all tags in a workspace
|
|
1503
|
+
|
|
1504
|
+
Args:
|
|
1505
|
+
workspace_gid: Workspace GID to list tags from
|
|
1506
|
+
limit: Number of items to return per page
|
|
1507
|
+
offset: Pagination offset token
|
|
1508
|
+
**kwargs: Additional parameters
|
|
1509
|
+
|
|
1510
|
+
Returns:
|
|
1511
|
+
WorkspaceTagsListResult
|
|
1512
|
+
"""
|
|
1513
|
+
params = {k: v for k, v in {
|
|
1514
|
+
"workspace_gid": workspace_gid,
|
|
1515
|
+
"limit": limit,
|
|
1516
|
+
"offset": offset,
|
|
1517
|
+
**kwargs
|
|
1518
|
+
}.items() if v is not None}
|
|
1519
|
+
|
|
1520
|
+
result = await self._connector.execute("workspace_tags", "list", params)
|
|
1521
|
+
# Cast generic envelope to concrete typed result
|
|
1522
|
+
return WorkspaceTagsListResult(
|
|
1523
|
+
data=result.data,
|
|
1524
|
+
meta=result.meta )
|
|
1525
|
+
|
|
1526
|
+
|
|
1527
|
+
|
|
1528
|
+
class TagsQuery:
|
|
1529
|
+
"""
|
|
1530
|
+
Query class for Tags entity operations.
|
|
1531
|
+
"""
|
|
1532
|
+
|
|
1533
|
+
def __init__(self, connector: AsanaConnector):
|
|
1534
|
+
"""Initialize query with connector reference."""
|
|
1535
|
+
self._connector = connector
|
|
1536
|
+
|
|
1537
|
+
async def get(
|
|
1538
|
+
self,
|
|
1539
|
+
tag_gid: str,
|
|
1540
|
+
**kwargs
|
|
1541
|
+
) -> TagsGetResult:
|
|
1542
|
+
"""
|
|
1543
|
+
Get a single tag by its ID
|
|
1544
|
+
|
|
1545
|
+
Args:
|
|
1546
|
+
tag_gid: Tag GID
|
|
1547
|
+
**kwargs: Additional parameters
|
|
1548
|
+
|
|
1549
|
+
Returns:
|
|
1550
|
+
TagsGetResult
|
|
1551
|
+
"""
|
|
1552
|
+
params = {k: v for k, v in {
|
|
1553
|
+
"tag_gid": tag_gid,
|
|
1554
|
+
**kwargs
|
|
1555
|
+
}.items() if v is not None}
|
|
1556
|
+
|
|
1557
|
+
result = await self._connector.execute("tags", "get", params)
|
|
1558
|
+
# Cast generic envelope to concrete typed result
|
|
1559
|
+
return TagsGetResult(
|
|
1560
|
+
data=result.data )
|
|
1561
|
+
|
|
1562
|
+
|
|
1563
|
+
|
|
1564
|
+
class ProjectSectionsQuery:
|
|
1565
|
+
"""
|
|
1566
|
+
Query class for ProjectSections entity operations.
|
|
1567
|
+
"""
|
|
1568
|
+
|
|
1569
|
+
def __init__(self, connector: AsanaConnector):
|
|
1570
|
+
"""Initialize query with connector reference."""
|
|
1571
|
+
self._connector = connector
|
|
1572
|
+
|
|
1573
|
+
async def list(
|
|
1574
|
+
self,
|
|
1575
|
+
project_gid: str,
|
|
1576
|
+
limit: int | None = None,
|
|
1577
|
+
offset: str | None = None,
|
|
1578
|
+
**kwargs
|
|
1579
|
+
) -> ProjectSectionsListResult:
|
|
1580
|
+
"""
|
|
1581
|
+
Returns all sections in a project
|
|
1582
|
+
|
|
1583
|
+
Args:
|
|
1584
|
+
project_gid: Project GID to list sections from
|
|
1585
|
+
limit: Number of items to return per page
|
|
1586
|
+
offset: Pagination offset token
|
|
1587
|
+
**kwargs: Additional parameters
|
|
1588
|
+
|
|
1589
|
+
Returns:
|
|
1590
|
+
ProjectSectionsListResult
|
|
1591
|
+
"""
|
|
1592
|
+
params = {k: v for k, v in {
|
|
1593
|
+
"project_gid": project_gid,
|
|
1594
|
+
"limit": limit,
|
|
1595
|
+
"offset": offset,
|
|
1596
|
+
**kwargs
|
|
1597
|
+
}.items() if v is not None}
|
|
1598
|
+
|
|
1599
|
+
result = await self._connector.execute("project_sections", "list", params)
|
|
1600
|
+
# Cast generic envelope to concrete typed result
|
|
1601
|
+
return ProjectSectionsListResult(
|
|
1602
|
+
data=result.data,
|
|
1603
|
+
meta=result.meta )
|
|
1604
|
+
|
|
1605
|
+
|
|
1606
|
+
|
|
1607
|
+
class SectionsQuery:
|
|
1608
|
+
"""
|
|
1609
|
+
Query class for Sections entity operations.
|
|
1610
|
+
"""
|
|
1611
|
+
|
|
1612
|
+
def __init__(self, connector: AsanaConnector):
|
|
1613
|
+
"""Initialize query with connector reference."""
|
|
1614
|
+
self._connector = connector
|
|
1615
|
+
|
|
1616
|
+
async def get(
|
|
1617
|
+
self,
|
|
1618
|
+
section_gid: str,
|
|
1619
|
+
**kwargs
|
|
1620
|
+
) -> SectionsGetResult:
|
|
1621
|
+
"""
|
|
1622
|
+
Get a single section by its ID
|
|
1623
|
+
|
|
1624
|
+
Args:
|
|
1625
|
+
section_gid: Section GID
|
|
1626
|
+
**kwargs: Additional parameters
|
|
1627
|
+
|
|
1628
|
+
Returns:
|
|
1629
|
+
SectionsGetResult
|
|
1630
|
+
"""
|
|
1631
|
+
params = {k: v for k, v in {
|
|
1632
|
+
"section_gid": section_gid,
|
|
1633
|
+
**kwargs
|
|
1634
|
+
}.items() if v is not None}
|
|
1635
|
+
|
|
1636
|
+
result = await self._connector.execute("sections", "get", params)
|
|
1637
|
+
# Cast generic envelope to concrete typed result
|
|
1638
|
+
return SectionsGetResult(
|
|
1639
|
+
data=result.data )
|
|
1640
|
+
|
|
1641
|
+
|
|
1642
|
+
|
|
1643
|
+
class TaskSubtasksQuery:
|
|
1644
|
+
"""
|
|
1645
|
+
Query class for TaskSubtasks entity operations.
|
|
1646
|
+
"""
|
|
1647
|
+
|
|
1648
|
+
def __init__(self, connector: AsanaConnector):
|
|
1649
|
+
"""Initialize query with connector reference."""
|
|
1650
|
+
self._connector = connector
|
|
1651
|
+
|
|
1652
|
+
async def list(
|
|
1653
|
+
self,
|
|
1654
|
+
task_gid: str,
|
|
1655
|
+
limit: int | None = None,
|
|
1656
|
+
offset: str | None = None,
|
|
1657
|
+
**kwargs
|
|
1658
|
+
) -> TaskSubtasksListResult:
|
|
1659
|
+
"""
|
|
1660
|
+
Returns all subtasks of a task
|
|
1661
|
+
|
|
1662
|
+
Args:
|
|
1663
|
+
task_gid: Task GID to list subtasks from
|
|
1664
|
+
limit: Number of items to return per page
|
|
1665
|
+
offset: Pagination offset token
|
|
1666
|
+
**kwargs: Additional parameters
|
|
1667
|
+
|
|
1668
|
+
Returns:
|
|
1669
|
+
TaskSubtasksListResult
|
|
1670
|
+
"""
|
|
1671
|
+
params = {k: v for k, v in {
|
|
1672
|
+
"task_gid": task_gid,
|
|
1673
|
+
"limit": limit,
|
|
1674
|
+
"offset": offset,
|
|
1675
|
+
**kwargs
|
|
1676
|
+
}.items() if v is not None}
|
|
1677
|
+
|
|
1678
|
+
result = await self._connector.execute("task_subtasks", "list", params)
|
|
1679
|
+
# Cast generic envelope to concrete typed result
|
|
1680
|
+
return TaskSubtasksListResult(
|
|
1681
|
+
data=result.data,
|
|
1682
|
+
meta=result.meta )
|
|
1683
|
+
|
|
1684
|
+
|
|
1685
|
+
|
|
1686
|
+
class TaskDependenciesQuery:
|
|
1687
|
+
"""
|
|
1688
|
+
Query class for TaskDependencies entity operations.
|
|
1689
|
+
"""
|
|
1690
|
+
|
|
1691
|
+
def __init__(self, connector: AsanaConnector):
|
|
1692
|
+
"""Initialize query with connector reference."""
|
|
1693
|
+
self._connector = connector
|
|
1694
|
+
|
|
1695
|
+
async def list(
|
|
1696
|
+
self,
|
|
1697
|
+
task_gid: str,
|
|
1698
|
+
limit: int | None = None,
|
|
1699
|
+
offset: str | None = None,
|
|
1700
|
+
**kwargs
|
|
1701
|
+
) -> TaskDependenciesListResult:
|
|
1702
|
+
"""
|
|
1703
|
+
Returns all tasks that this task depends on
|
|
1704
|
+
|
|
1705
|
+
Args:
|
|
1706
|
+
task_gid: Task GID to list dependencies from
|
|
1707
|
+
limit: Number of items to return per page
|
|
1708
|
+
offset: Pagination offset token
|
|
1709
|
+
**kwargs: Additional parameters
|
|
1710
|
+
|
|
1711
|
+
Returns:
|
|
1712
|
+
TaskDependenciesListResult
|
|
1713
|
+
"""
|
|
1714
|
+
params = {k: v for k, v in {
|
|
1715
|
+
"task_gid": task_gid,
|
|
1716
|
+
"limit": limit,
|
|
1717
|
+
"offset": offset,
|
|
1718
|
+
**kwargs
|
|
1719
|
+
}.items() if v is not None}
|
|
1720
|
+
|
|
1721
|
+
result = await self._connector.execute("task_dependencies", "list", params)
|
|
1722
|
+
# Cast generic envelope to concrete typed result
|
|
1723
|
+
return TaskDependenciesListResult(
|
|
1724
|
+
data=result.data,
|
|
1725
|
+
meta=result.meta )
|
|
1726
|
+
|
|
1727
|
+
|
|
1728
|
+
|
|
1729
|
+
class TaskDependentsQuery:
|
|
1730
|
+
"""
|
|
1731
|
+
Query class for TaskDependents entity operations.
|
|
1732
|
+
"""
|
|
1733
|
+
|
|
1734
|
+
def __init__(self, connector: AsanaConnector):
|
|
1735
|
+
"""Initialize query with connector reference."""
|
|
1736
|
+
self._connector = connector
|
|
1737
|
+
|
|
1738
|
+
async def list(
|
|
1739
|
+
self,
|
|
1740
|
+
task_gid: str,
|
|
1741
|
+
limit: int | None = None,
|
|
1742
|
+
offset: str | None = None,
|
|
1743
|
+
**kwargs
|
|
1744
|
+
) -> TaskDependentsListResult:
|
|
1745
|
+
"""
|
|
1746
|
+
Returns all tasks that depend on this task
|
|
1747
|
+
|
|
1748
|
+
Args:
|
|
1749
|
+
task_gid: Task GID to list dependents from
|
|
1750
|
+
limit: Number of items to return per page
|
|
1751
|
+
offset: Pagination offset token
|
|
1752
|
+
**kwargs: Additional parameters
|
|
1753
|
+
|
|
1754
|
+
Returns:
|
|
1755
|
+
TaskDependentsListResult
|
|
1756
|
+
"""
|
|
1757
|
+
params = {k: v for k, v in {
|
|
1758
|
+
"task_gid": task_gid,
|
|
1759
|
+
"limit": limit,
|
|
1760
|
+
"offset": offset,
|
|
1761
|
+
**kwargs
|
|
1762
|
+
}.items() if v is not None}
|
|
1763
|
+
|
|
1764
|
+
result = await self._connector.execute("task_dependents", "list", params)
|
|
1765
|
+
# Cast generic envelope to concrete typed result
|
|
1766
|
+
return TaskDependentsListResult(
|
|
1767
|
+
data=result.data,
|
|
1768
|
+
meta=result.meta )
|
|
1769
|
+
|
|
1770
|
+
|