sinatra-dev 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. sinatra_dev/__init__.py +71 -0
  2. sinatra_dev/_client.py +391 -0
  3. sinatra_dev/_errors.py +53 -0
  4. sinatra_dev/_generated/__init__.py +8 -0
  5. sinatra_dev/_generated/api/__init__.py +1 -0
  6. sinatra_dev/_generated/api/me/__init__.py +1 -0
  7. sinatra_dev/_generated/api/me/me_get.py +156 -0
  8. sinatra_dev/_generated/api/me/me_revoke_token.py +173 -0
  9. sinatra_dev/_generated/api/messages/__init__.py +1 -0
  10. sinatra_dev/_generated/api/messages/messages_create.py +323 -0
  11. sinatra_dev/_generated/api/messages/messages_list.py +332 -0
  12. sinatra_dev/_generated/api/tasks/__init__.py +1 -0
  13. sinatra_dev/_generated/api/tasks/tasks_create.py +337 -0
  14. sinatra_dev/_generated/api/tasks/tasks_get.py +202 -0
  15. sinatra_dev/_generated/api/tasks/tasks_list.py +252 -0
  16. sinatra_dev/_generated/api/tasks/tasks_stop.py +231 -0
  17. sinatra_dev/_generated/api/tickets/__init__.py +1 -0
  18. sinatra_dev/_generated/api/tickets/tickets_delegate.py +273 -0
  19. sinatra_dev/_generated/api/tickets/tickets_search.py +265 -0
  20. sinatra_dev/_generated/client.py +280 -0
  21. sinatra_dev/_generated/errors.py +16 -0
  22. sinatra_dev/_generated/models/__init__.py +47 -0
  23. sinatra_dev/_generated/models/create_message_request.py +62 -0
  24. sinatra_dev/_generated/models/create_message_response.py +62 -0
  25. sinatra_dev/_generated/models/create_task_request.py +106 -0
  26. sinatra_dev/_generated/models/create_task_response.py +76 -0
  27. sinatra_dev/_generated/models/delegate_github_ticket.py +86 -0
  28. sinatra_dev/_generated/models/delegate_linear_ticket.py +78 -0
  29. sinatra_dev/_generated/models/delegate_ticket_response.py +62 -0
  30. sinatra_dev/_generated/models/error.py +168 -0
  31. sinatra_dev/_generated/models/me.py +86 -0
  32. sinatra_dev/_generated/models/me_user.py +98 -0
  33. sinatra_dev/_generated/models/message.py +113 -0
  34. sinatra_dev/_generated/models/message_list.py +91 -0
  35. sinatra_dev/_generated/models/pull_request.py +70 -0
  36. sinatra_dev/_generated/models/stop_task_response.py +62 -0
  37. sinatra_dev/_generated/models/task.py +201 -0
  38. sinatra_dev/_generated/models/task_list.py +91 -0
  39. sinatra_dev/_generated/models/ticket.py +147 -0
  40. sinatra_dev/_generated/models/ticket_search_result.py +97 -0
  41. sinatra_dev/_generated/models/ticket_search_result_github.py +77 -0
  42. sinatra_dev/_generated/models/ticket_search_result_linear.py +79 -0
  43. sinatra_dev/_generated/models/workspace.py +78 -0
  44. sinatra_dev/_generated/types.py +54 -0
  45. sinatra_dev/_retry.py +72 -0
  46. sinatra_dev/py.typed +0 -0
  47. sinatra_dev-0.1.0.dist-info/METADATA +184 -0
  48. sinatra_dev-0.1.0.dist-info/RECORD +50 -0
  49. sinatra_dev-0.1.0.dist-info/WHEEL +4 -0
  50. sinatra_dev-0.1.0.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,91 @@
1
+ from __future__ import annotations
2
+
3
+ from collections.abc import Mapping
4
+ from typing import TYPE_CHECKING, Any, Self, TypeVar, cast
5
+
6
+ from attrs import define as _attrs_define
7
+ from attrs import field as _attrs_field
8
+
9
+ if TYPE_CHECKING:
10
+ from ..models.message import Message
11
+
12
+
13
+ T = TypeVar("T", bound="MessageList")
14
+
15
+
16
+ @_attrs_define
17
+ class MessageList:
18
+ """A page of a task's conversation.
19
+
20
+ Attributes:
21
+ messages (list[Message]): The page's entries, oldest first.
22
+ next_ (None | str): When it isn't `null`, more entries follow: pass it as `after` to get them. `null` on the
23
+ last page.
24
+ """
25
+
26
+ messages: list[Message]
27
+ next_: None | str
28
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
29
+
30
+ def to_dict(self) -> dict[str, Any]:
31
+ messages = []
32
+ for messages_item_data in self.messages:
33
+ messages_item = messages_item_data.to_dict()
34
+ messages.append(messages_item)
35
+
36
+ next_: None | str
37
+ next_ = self.next_
38
+
39
+ field_dict: dict[str, Any] = {}
40
+ field_dict.update(self.additional_properties)
41
+ field_dict.update(
42
+ {
43
+ "messages": messages,
44
+ "next": next_,
45
+ }
46
+ )
47
+
48
+ return field_dict
49
+
50
+ @classmethod
51
+ def from_dict(cls, src_dict: Mapping[str, Any]) -> Self:
52
+ from ..models.message import Message
53
+
54
+ d = dict(src_dict)
55
+ messages = []
56
+ _messages = d.pop("messages")
57
+ for messages_item_data in _messages:
58
+ messages_item = Message.from_dict(messages_item_data)
59
+
60
+ messages.append(messages_item)
61
+
62
+ def _parse_next_(data: object) -> None | str:
63
+ if data is None:
64
+ return data
65
+ return cast(None | str, data)
66
+
67
+ next_ = _parse_next_(d.pop("next"))
68
+
69
+ message_list = cls(
70
+ messages=messages,
71
+ next_=next_,
72
+ )
73
+
74
+ message_list.additional_properties = d
75
+ return message_list
76
+
77
+ @property
78
+ def additional_keys(self) -> list[str]:
79
+ return list(self.additional_properties.keys())
80
+
81
+ def __getitem__(self, key: str) -> Any:
82
+ return self.additional_properties[key]
83
+
84
+ def __setitem__(self, key: str, value: Any) -> None:
85
+ self.additional_properties[key] = value
86
+
87
+ def __delitem__(self, key: str) -> None:
88
+ del self.additional_properties[key]
89
+
90
+ def __contains__(self, key: str) -> bool:
91
+ return key in self.additional_properties
@@ -0,0 +1,70 @@
1
+ from __future__ import annotations
2
+
3
+ from collections.abc import Mapping
4
+ from typing import Any, Self, TypeVar
5
+
6
+ from attrs import define as _attrs_define
7
+ from attrs import field as _attrs_field
8
+
9
+ T = TypeVar("T", bound="PullRequest")
10
+
11
+
12
+ @_attrs_define
13
+ class PullRequest:
14
+ """The pull request a task opened.
15
+
16
+ Attributes:
17
+ url (str): The pull request's address on GitHub.
18
+ merged (bool): `true` once the pull request is merged.
19
+ """
20
+
21
+ url: str
22
+ merged: bool
23
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
24
+
25
+ def to_dict(self) -> dict[str, Any]:
26
+ url = self.url
27
+
28
+ merged = self.merged
29
+
30
+ field_dict: dict[str, Any] = {}
31
+ field_dict.update(self.additional_properties)
32
+ field_dict.update(
33
+ {
34
+ "url": url,
35
+ "merged": merged,
36
+ }
37
+ )
38
+
39
+ return field_dict
40
+
41
+ @classmethod
42
+ def from_dict(cls, src_dict: Mapping[str, Any]) -> Self:
43
+ d = dict(src_dict)
44
+ url = d.pop("url")
45
+
46
+ merged = d.pop("merged")
47
+
48
+ pull_request = cls(
49
+ url=url,
50
+ merged=merged,
51
+ )
52
+
53
+ pull_request.additional_properties = d
54
+ return pull_request
55
+
56
+ @property
57
+ def additional_keys(self) -> list[str]:
58
+ return list(self.additional_properties.keys())
59
+
60
+ def __getitem__(self, key: str) -> Any:
61
+ return self.additional_properties[key]
62
+
63
+ def __setitem__(self, key: str, value: Any) -> None:
64
+ self.additional_properties[key] = value
65
+
66
+ def __delitem__(self, key: str) -> None:
67
+ del self.additional_properties[key]
68
+
69
+ def __contains__(self, key: str) -> bool:
70
+ return key in self.additional_properties
@@ -0,0 +1,62 @@
1
+ from __future__ import annotations
2
+
3
+ from collections.abc import Mapping
4
+ from typing import Any, Self, TypeVar
5
+
6
+ from attrs import define as _attrs_define
7
+ from attrs import field as _attrs_field
8
+
9
+ T = TypeVar("T", bound="StopTaskResponse")
10
+
11
+
12
+ @_attrs_define
13
+ class StopTaskResponse:
14
+ """The stop was accepted.
15
+
16
+ Attributes:
17
+ accepted (bool): Always `true`: the task was told to stop.
18
+ """
19
+
20
+ accepted: bool
21
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
22
+
23
+ def to_dict(self) -> dict[str, Any]:
24
+ accepted = self.accepted
25
+
26
+ field_dict: dict[str, Any] = {}
27
+ field_dict.update(self.additional_properties)
28
+ field_dict.update(
29
+ {
30
+ "accepted": accepted,
31
+ }
32
+ )
33
+
34
+ return field_dict
35
+
36
+ @classmethod
37
+ def from_dict(cls, src_dict: Mapping[str, Any]) -> Self:
38
+ d = dict(src_dict)
39
+ accepted = d.pop("accepted")
40
+
41
+ stop_task_response = cls(
42
+ accepted=accepted,
43
+ )
44
+
45
+ stop_task_response.additional_properties = d
46
+ return stop_task_response
47
+
48
+ @property
49
+ def additional_keys(self) -> list[str]:
50
+ return list(self.additional_properties.keys())
51
+
52
+ def __getitem__(self, key: str) -> Any:
53
+ return self.additional_properties[key]
54
+
55
+ def __setitem__(self, key: str, value: Any) -> None:
56
+ self.additional_properties[key] = value
57
+
58
+ def __delitem__(self, key: str) -> None:
59
+ del self.additional_properties[key]
60
+
61
+ def __contains__(self, key: str) -> bool:
62
+ return key in self.additional_properties
@@ -0,0 +1,201 @@
1
+ from __future__ import annotations
2
+
3
+ import datetime
4
+ from collections.abc import Mapping
5
+ from typing import TYPE_CHECKING, Any, Self, TypeVar, cast
6
+
7
+ from attrs import define as _attrs_define
8
+ from attrs import field as _attrs_field
9
+
10
+ if TYPE_CHECKING:
11
+ from ..models.pull_request import PullRequest
12
+
13
+
14
+ T = TypeVar("T", bound="Task")
15
+
16
+
17
+ @_attrs_define
18
+ class Task:
19
+ """A task: one piece of work Sinatra does, from any source.
20
+
21
+ Attributes:
22
+ id (str): The task's id. Use it as `taskId` in the task endpoints.
23
+ status (str): Where the task is in its life, such as `pending`, `implementing`, `replied`, `pr_open` or
24
+ `completed`. New statuses can appear, so don't treat the list as closed. See [Raw
25
+ statuses](https://docs.sinatra.dev/docs/getting-started/how-it-works#raw-statuses) for each one.
26
+ source (str): Where the task started: `api` for the CLI, MCP, this API or the dashboard, `linear` or
27
+ `github_issue` for an issue, `slack` or `telegram` for a chat. Other sources can appear, so treat an unknown
28
+ value as a task started elsewhere.
29
+ title (None | str): The task's title. `null` for a task whose issue has no title.
30
+ repo (None | str): `owner/name` of the task's repository. `null` until a repository is chosen.
31
+ pull_request (None | PullRequest): The task's pull request. `null` until one opens.
32
+ queued (bool): `true` while a turn waits because the workspace is already running as many tasks at a time as its
33
+ plan allows. The dashboard shows this as Queued.
34
+ created_at (datetime.datetime): When the task was created.
35
+ last_activity_at (datetime.datetime | None): When the task last did something. `null` if it hasn't yet.
36
+ url (None | str): The task's page in the Sinatra dashboard, where anyone in the workspace can follow it. On a
37
+ task started from the CLI, MCP, API or dashboard they can reply there too.
38
+ """
39
+
40
+ id: str
41
+ status: str
42
+ source: str
43
+ title: None | str
44
+ repo: None | str
45
+ pull_request: None | PullRequest
46
+ queued: bool
47
+ created_at: datetime.datetime
48
+ last_activity_at: datetime.datetime | None
49
+ url: None | str
50
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
51
+
52
+ def to_dict(self) -> dict[str, Any]:
53
+ from ..models.pull_request import PullRequest
54
+
55
+ id = self.id
56
+
57
+ status = self.status
58
+
59
+ source = self.source
60
+
61
+ title: None | str
62
+ title = self.title
63
+
64
+ repo: None | str
65
+ repo = self.repo
66
+
67
+ pull_request: dict[str, Any] | None
68
+ if isinstance(self.pull_request, PullRequest):
69
+ pull_request = self.pull_request.to_dict()
70
+ else:
71
+ pull_request = self.pull_request
72
+
73
+ queued = self.queued
74
+
75
+ created_at = self.created_at.isoformat()
76
+
77
+ last_activity_at: None | str
78
+ if isinstance(self.last_activity_at, datetime.datetime):
79
+ last_activity_at = self.last_activity_at.isoformat()
80
+ else:
81
+ last_activity_at = self.last_activity_at
82
+
83
+ url: None | str
84
+ url = self.url
85
+
86
+ field_dict: dict[str, Any] = {}
87
+ field_dict.update(self.additional_properties)
88
+ field_dict.update(
89
+ {
90
+ "id": id,
91
+ "status": status,
92
+ "source": source,
93
+ "title": title,
94
+ "repo": repo,
95
+ "pullRequest": pull_request,
96
+ "queued": queued,
97
+ "createdAt": created_at,
98
+ "lastActivityAt": last_activity_at,
99
+ "url": url,
100
+ }
101
+ )
102
+
103
+ return field_dict
104
+
105
+ @classmethod
106
+ def from_dict(cls, src_dict: Mapping[str, Any]) -> Self:
107
+ from ..models.pull_request import PullRequest
108
+
109
+ d = dict(src_dict)
110
+ id = d.pop("id")
111
+
112
+ status = d.pop("status")
113
+
114
+ source = d.pop("source")
115
+
116
+ def _parse_title(data: object) -> None | str:
117
+ if data is None:
118
+ return data
119
+ return cast(None | str, data)
120
+
121
+ title = _parse_title(d.pop("title"))
122
+
123
+ def _parse_repo(data: object) -> None | str:
124
+ if data is None:
125
+ return data
126
+ return cast(None | str, data)
127
+
128
+ repo = _parse_repo(d.pop("repo"))
129
+
130
+ def _parse_pull_request(data: object) -> None | PullRequest:
131
+ if data is None:
132
+ return data
133
+ try:
134
+ if not isinstance(data, dict):
135
+ raise TypeError()
136
+ pull_request_type_0 = PullRequest.from_dict(data)
137
+
138
+ return pull_request_type_0
139
+ except (TypeError, ValueError, AttributeError, KeyError):
140
+ pass
141
+ return cast(None | PullRequest, data)
142
+
143
+ pull_request = _parse_pull_request(d.pop("pullRequest"))
144
+
145
+ queued = d.pop("queued")
146
+
147
+ created_at = datetime.datetime.fromisoformat(d.pop("createdAt"))
148
+
149
+ def _parse_last_activity_at(data: object) -> datetime.datetime | None:
150
+ if data is None:
151
+ return data
152
+ try:
153
+ if not isinstance(data, str):
154
+ raise TypeError()
155
+ last_activity_at_type_0 = datetime.datetime.fromisoformat(data)
156
+
157
+ return last_activity_at_type_0
158
+ except (TypeError, ValueError, AttributeError, KeyError):
159
+ pass
160
+ return cast(datetime.datetime | None, data)
161
+
162
+ last_activity_at = _parse_last_activity_at(d.pop("lastActivityAt"))
163
+
164
+ def _parse_url(data: object) -> None | str:
165
+ if data is None:
166
+ return data
167
+ return cast(None | str, data)
168
+
169
+ url = _parse_url(d.pop("url"))
170
+
171
+ task = cls(
172
+ id=id,
173
+ status=status,
174
+ source=source,
175
+ title=title,
176
+ repo=repo,
177
+ pull_request=pull_request,
178
+ queued=queued,
179
+ created_at=created_at,
180
+ last_activity_at=last_activity_at,
181
+ url=url,
182
+ )
183
+
184
+ task.additional_properties = d
185
+ return task
186
+
187
+ @property
188
+ def additional_keys(self) -> list[str]:
189
+ return list(self.additional_properties.keys())
190
+
191
+ def __getitem__(self, key: str) -> Any:
192
+ return self.additional_properties[key]
193
+
194
+ def __setitem__(self, key: str, value: Any) -> None:
195
+ self.additional_properties[key] = value
196
+
197
+ def __delitem__(self, key: str) -> None:
198
+ del self.additional_properties[key]
199
+
200
+ def __contains__(self, key: str) -> bool:
201
+ return key in self.additional_properties
@@ -0,0 +1,91 @@
1
+ from __future__ import annotations
2
+
3
+ from collections.abc import Mapping
4
+ from typing import TYPE_CHECKING, Any, Self, TypeVar, cast
5
+
6
+ from attrs import define as _attrs_define
7
+ from attrs import field as _attrs_field
8
+
9
+ if TYPE_CHECKING:
10
+ from ..models.task import Task
11
+
12
+
13
+ T = TypeVar("T", bound="TaskList")
14
+
15
+
16
+ @_attrs_define
17
+ class TaskList:
18
+ """A page of tasks.
19
+
20
+ Attributes:
21
+ tasks (list[Task]): The page's tasks, most recently active first.
22
+ next_cursor (None | str): Pass it back as `cursor` to get the next page. Treat it as opaque. `null` on the last
23
+ page.
24
+ """
25
+
26
+ tasks: list[Task]
27
+ next_cursor: None | str
28
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
29
+
30
+ def to_dict(self) -> dict[str, Any]:
31
+ tasks = []
32
+ for tasks_item_data in self.tasks:
33
+ tasks_item = tasks_item_data.to_dict()
34
+ tasks.append(tasks_item)
35
+
36
+ next_cursor: None | str
37
+ next_cursor = self.next_cursor
38
+
39
+ field_dict: dict[str, Any] = {}
40
+ field_dict.update(self.additional_properties)
41
+ field_dict.update(
42
+ {
43
+ "tasks": tasks,
44
+ "nextCursor": next_cursor,
45
+ }
46
+ )
47
+
48
+ return field_dict
49
+
50
+ @classmethod
51
+ def from_dict(cls, src_dict: Mapping[str, Any]) -> Self:
52
+ from ..models.task import Task
53
+
54
+ d = dict(src_dict)
55
+ tasks = []
56
+ _tasks = d.pop("tasks")
57
+ for tasks_item_data in _tasks:
58
+ tasks_item = Task.from_dict(tasks_item_data)
59
+
60
+ tasks.append(tasks_item)
61
+
62
+ def _parse_next_cursor(data: object) -> None | str:
63
+ if data is None:
64
+ return data
65
+ return cast(None | str, data)
66
+
67
+ next_cursor = _parse_next_cursor(d.pop("nextCursor"))
68
+
69
+ task_list = cls(
70
+ tasks=tasks,
71
+ next_cursor=next_cursor,
72
+ )
73
+
74
+ task_list.additional_properties = d
75
+ return task_list
76
+
77
+ @property
78
+ def additional_keys(self) -> list[str]:
79
+ return list(self.additional_properties.keys())
80
+
81
+ def __getitem__(self, key: str) -> Any:
82
+ return self.additional_properties[key]
83
+
84
+ def __setitem__(self, key: str, value: Any) -> None:
85
+ self.additional_properties[key] = value
86
+
87
+ def __delitem__(self, key: str) -> None:
88
+ del self.additional_properties[key]
89
+
90
+ def __contains__(self, key: str) -> bool:
91
+ return key in self.additional_properties
@@ -0,0 +1,147 @@
1
+ from __future__ import annotations
2
+
3
+ from collections.abc import Mapping
4
+ from typing import Any, Self, TypeVar, cast
5
+
6
+ from attrs import define as _attrs_define
7
+ from attrs import field as _attrs_field
8
+
9
+ T = TypeVar("T", bound="Ticket")
10
+
11
+
12
+ @_attrs_define
13
+ class Ticket:
14
+ """An open issue you could delegate to Sinatra.
15
+
16
+ Attributes:
17
+ id (str): The issue's id on Sinatra's side. For GitHub it looks like `github:owner/name#42`.
18
+ source (str): Where the issue lives: `linear` or `github`. New sources can appear.
19
+ identifier (str): What to delegate it by. A Linear identifier such as `ENG-123` (send it as `id`), or a GitHub
20
+ `owner/name#42` (send `owner/name` as `repo` and `42` as `number`).
21
+ title (str): The issue's title.
22
+ yours (bool): `true` if the issue is assigned to you or you wrote it.
23
+ state (None | str): A GitHub issue's state, such as `open`. `null` for a Linear issue.
24
+ context (None | str): The Linear team's name, or the GitHub repository's name.
25
+ url (str): The issue's address on its tracker.
26
+ workspace_id (str): The id of the workspace that was searched.
27
+ workspace_label (str): The name the dashboard's ticket picker gives that workspace.
28
+ """
29
+
30
+ id: str
31
+ source: str
32
+ identifier: str
33
+ title: str
34
+ yours: bool
35
+ state: None | str
36
+ context: None | str
37
+ url: str
38
+ workspace_id: str
39
+ workspace_label: str
40
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
41
+
42
+ def to_dict(self) -> dict[str, Any]:
43
+ id = self.id
44
+
45
+ source = self.source
46
+
47
+ identifier = self.identifier
48
+
49
+ title = self.title
50
+
51
+ yours = self.yours
52
+
53
+ state: None | str
54
+ state = self.state
55
+
56
+ context: None | str
57
+ context = self.context
58
+
59
+ url = self.url
60
+
61
+ workspace_id = self.workspace_id
62
+
63
+ workspace_label = self.workspace_label
64
+
65
+ field_dict: dict[str, Any] = {}
66
+ field_dict.update(self.additional_properties)
67
+ field_dict.update(
68
+ {
69
+ "id": id,
70
+ "source": source,
71
+ "identifier": identifier,
72
+ "title": title,
73
+ "yours": yours,
74
+ "state": state,
75
+ "context": context,
76
+ "url": url,
77
+ "workspaceId": workspace_id,
78
+ "workspaceLabel": workspace_label,
79
+ }
80
+ )
81
+
82
+ return field_dict
83
+
84
+ @classmethod
85
+ def from_dict(cls, src_dict: Mapping[str, Any]) -> Self:
86
+ d = dict(src_dict)
87
+ id = d.pop("id")
88
+
89
+ source = d.pop("source")
90
+
91
+ identifier = d.pop("identifier")
92
+
93
+ title = d.pop("title")
94
+
95
+ yours = d.pop("yours")
96
+
97
+ def _parse_state(data: object) -> None | str:
98
+ if data is None:
99
+ return data
100
+ return cast(None | str, data)
101
+
102
+ state = _parse_state(d.pop("state"))
103
+
104
+ def _parse_context(data: object) -> None | str:
105
+ if data is None:
106
+ return data
107
+ return cast(None | str, data)
108
+
109
+ context = _parse_context(d.pop("context"))
110
+
111
+ url = d.pop("url")
112
+
113
+ workspace_id = d.pop("workspaceId")
114
+
115
+ workspace_label = d.pop("workspaceLabel")
116
+
117
+ ticket = cls(
118
+ id=id,
119
+ source=source,
120
+ identifier=identifier,
121
+ title=title,
122
+ yours=yours,
123
+ state=state,
124
+ context=context,
125
+ url=url,
126
+ workspace_id=workspace_id,
127
+ workspace_label=workspace_label,
128
+ )
129
+
130
+ ticket.additional_properties = d
131
+ return ticket
132
+
133
+ @property
134
+ def additional_keys(self) -> list[str]:
135
+ return list(self.additional_properties.keys())
136
+
137
+ def __getitem__(self, key: str) -> Any:
138
+ return self.additional_properties[key]
139
+
140
+ def __setitem__(self, key: str, value: Any) -> None:
141
+ self.additional_properties[key] = value
142
+
143
+ def __delitem__(self, key: str) -> None:
144
+ del self.additional_properties[key]
145
+
146
+ def __contains__(self, key: str) -> bool:
147
+ return key in self.additional_properties