holder-python 0.2.5__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 (391) hide show
  1. holder/__init__.py +21 -0
  2. holder/client.py +182 -0
  3. holder/collections.py +70 -0
  4. holder/events.py +238 -0
  5. holder/exceptions.py +35 -0
  6. holder/generated/__init__.py +8 -0
  7. holder/generated/api/__init__.py +1 -0
  8. holder/generated/api/default/__init__.py +1 -0
  9. holder/generated/api/default/delete_ai_messages_message_id.py +166 -0
  10. holder/generated/api/default/delete_ai_messages_message_id_links.py +205 -0
  11. holder/generated/api/default/delete_ai_providers_credentials_provider.py +168 -0
  12. holder/generated/api/default/delete_ai_threads_thread_id.py +166 -0
  13. holder/generated/api/default/delete_cards_card_id.py +225 -0
  14. holder/generated/api/default/delete_cards_card_id_links.py +205 -0
  15. holder/generated/api/default/delete_cards_card_id_milestones_milestone_id.py +175 -0
  16. holder/generated/api/default/delete_cards_card_id_resources.py +197 -0
  17. holder/generated/api/default/delete_cards_card_id_tags.py +197 -0
  18. holder/generated/api/default/delete_locations_location_id.py +105 -0
  19. holder/generated/api/default/delete_locations_location_id_binding.py +102 -0
  20. holder/generated/api/default/delete_projects_project_id.py +187 -0
  21. holder/generated/api/default/delete_resources_resource_id.py +161 -0
  22. holder/generated/api/default/delete_trash.py +181 -0
  23. holder/generated/api/default/delete_trash_type_id.py +175 -0
  24. holder/generated/api/default/get_ai_capabilities.py +166 -0
  25. holder/generated/api/default/get_ai_catalog_json.py +134 -0
  26. holder/generated/api/default/get_ai_catalog_yaml.py +132 -0
  27. holder/generated/api/default/get_ai_local_models_config.py +134 -0
  28. holder/generated/api/default/get_ai_messages.py +186 -0
  29. holder/generated/api/default/get_ai_messages_message_id.py +166 -0
  30. holder/generated/api/default/get_ai_messages_message_id_backlinks.py +194 -0
  31. holder/generated/api/default/get_ai_messages_message_id_links.py +194 -0
  32. holder/generated/api/default/get_ai_providers_catalog.py +139 -0
  33. holder/generated/api/default/get_ai_providers_credentials.py +136 -0
  34. holder/generated/api/default/get_ai_runner_pull_job_id.py +171 -0
  35. holder/generated/api/default/get_ai_runner_pull_job_id_events.py +218 -0
  36. holder/generated/api/default/get_ai_runs.py +186 -0
  37. holder/generated/api/default/get_ai_runs_run_id.py +166 -0
  38. holder/generated/api/default/get_ai_runs_run_id_events.py +213 -0
  39. holder/generated/api/default/get_ai_status.py +134 -0
  40. holder/generated/api/default/get_ai_threads.py +171 -0
  41. holder/generated/api/default/get_ai_threads_thread_id.py +166 -0
  42. holder/generated/api/default/get_calendar.py +221 -0
  43. holder/generated/api/default/get_cards.py +286 -0
  44. holder/generated/api/default/get_cards_card_id.py +166 -0
  45. holder/generated/api/default/get_cards_card_id_backlinks.py +194 -0
  46. holder/generated/api/default/get_cards_card_id_links.py +194 -0
  47. holder/generated/api/default/get_cards_card_id_milestones.py +173 -0
  48. holder/generated/api/default/get_cards_context.py +226 -0
  49. holder/generated/api/default/get_event_cursor.py +198 -0
  50. holder/generated/api/default/get_git_providers_json.py +134 -0
  51. holder/generated/api/default/get_git_providers_yaml.py +132 -0
  52. holder/generated/api/default/get_health.py +134 -0
  53. holder/generated/api/default/get_imports_job_id.py +159 -0
  54. holder/generated/api/default/get_locations.py +160 -0
  55. holder/generated/api/default/get_locations_location_id.py +157 -0
  56. holder/generated/api/default/get_openapi_yaml.py +132 -0
  57. holder/generated/api/default/get_ping.py +128 -0
  58. holder/generated/api/default/get_projects.py +261 -0
  59. holder/generated/api/default/get_projects_project_id.py +166 -0
  60. holder/generated/api/default/get_projects_project_id_cards.py +321 -0
  61. holder/generated/api/default/get_projects_project_id_encryption_check.py +166 -0
  62. holder/generated/api/default/get_projects_project_id_git_sync_status.py +171 -0
  63. holder/generated/api/default/get_projects_project_id_history.py +246 -0
  64. holder/generated/api/default/get_projects_project_id_history_cards_card_id.py +243 -0
  65. holder/generated/api/default/get_projects_project_id_history_cards_card_id_compare.py +286 -0
  66. holder/generated/api/default/get_projects_project_id_history_cards_card_id_snapshot.py +225 -0
  67. holder/generated/api/default/get_projects_project_id_tags.py +171 -0
  68. holder/generated/api/default/get_resources.py +242 -0
  69. holder/generated/api/default/get_resources_resource_id.py +161 -0
  70. holder/generated/api/default/get_resources_resource_id_assets_asset_id_content.py +247 -0
  71. holder/generated/api/default/get_search_ai.py +216 -0
  72. holder/generated/api/default/get_search_cards.py +216 -0
  73. holder/generated/api/default/get_trash.py +181 -0
  74. holder/generated/api/default/patch_ai_messages_message_id.py +192 -0
  75. holder/generated/api/default/patch_ai_threads_thread_id.py +192 -0
  76. holder/generated/api/default/patch_cards_card_id.py +192 -0
  77. holder/generated/api/default/patch_cards_card_id_milestones_milestone_id.py +214 -0
  78. holder/generated/api/default/patch_locations_location_id.py +117 -0
  79. holder/generated/api/default/patch_projects_project_id.py +192 -0
  80. holder/generated/api/default/patch_resources_resource_id.py +192 -0
  81. holder/generated/api/default/post_ai_messages.py +176 -0
  82. holder/generated/api/default/post_ai_messages_capture.py +181 -0
  83. holder/generated/api/default/post_ai_messages_message_id_links.py +192 -0
  84. holder/generated/api/default/post_ai_messages_message_id_restore.py +166 -0
  85. holder/generated/api/default/post_ai_runner_pull.py +181 -0
  86. holder/generated/api/default/post_ai_runner_retry.py +139 -0
  87. holder/generated/api/default/post_ai_runs.py +194 -0
  88. holder/generated/api/default/post_ai_threads.py +176 -0
  89. holder/generated/api/default/post_bye.py +166 -0
  90. holder/generated/api/default/post_card_references_resolve.py +181 -0
  91. holder/generated/api/default/post_cards.py +176 -0
  92. holder/generated/api/default/post_cards_card_id_links.py +192 -0
  93. holder/generated/api/default/post_cards_card_id_milestones.py +199 -0
  94. holder/generated/api/default/post_cards_card_id_move.py +222 -0
  95. holder/generated/api/default/post_cards_card_id_resources.py +197 -0
  96. holder/generated/api/default/post_cards_card_id_restore.py +186 -0
  97. holder/generated/api/default/post_cards_card_id_tags.py +197 -0
  98. holder/generated/api/default/post_imports.py +160 -0
  99. holder/generated/api/default/post_locations.py +160 -0
  100. holder/generated/api/default/post_locations_location_id_test.py +105 -0
  101. holder/generated/api/default/post_projects.py +171 -0
  102. holder/generated/api/default/post_projects_project_id_git_pull.py +211 -0
  103. holder/generated/api/default/post_projects_project_id_git_push.py +193 -0
  104. holder/generated/api/default/post_projects_project_id_git_sync.py +207 -0
  105. holder/generated/api/default/post_projects_project_id_git_test_remote.py +205 -0
  106. holder/generated/api/default/post_projects_project_id_history_cards_card_id_restore.py +240 -0
  107. holder/generated/api/default/post_projects_project_id_recovery_token_export.py +196 -0
  108. holder/generated/api/default/post_projects_project_id_recovery_token_import.py +196 -0
  109. holder/generated/api/default/post_projects_project_id_repair_hierarchy.py +240 -0
  110. holder/generated/api/default/post_rebuild.py +176 -0
  111. holder/generated/api/default/post_recovery_token_import.py +185 -0
  112. holder/generated/api/default/post_reindex.py +139 -0
  113. holder/generated/api/default/post_resources.py +176 -0
  114. holder/generated/api/default/put_ai_local_models_config.py +173 -0
  115. holder/generated/api/default/put_ai_providers_credentials.py +175 -0
  116. holder/generated/api/default/put_locations_location_id_binding.py +117 -0
  117. holder/generated/api/default/put_locations_preferred.py +107 -0
  118. holder/generated/api/default/stream_changes.py +256 -0
  119. holder/generated/client.py +280 -0
  120. holder/generated/errors.py +16 -0
  121. holder/generated/models/__init__.py +569 -0
  122. holder/generated/models/ai_local_model_config_data.py +111 -0
  123. holder/generated/models/ai_local_model_config_response.py +78 -0
  124. holder/generated/models/ai_local_model_config_update_request.py +134 -0
  125. holder/generated/models/ai_message.py +204 -0
  126. holder/generated/models/ai_message_capture_request.py +246 -0
  127. holder/generated/models/ai_message_capture_request_context_type_0.py +46 -0
  128. holder/generated/models/ai_message_capture_response.py +78 -0
  129. holder/generated/models/ai_message_capture_response_data.py +78 -0
  130. holder/generated/models/ai_message_create_request.py +186 -0
  131. holder/generated/models/ai_message_create_response.py +78 -0
  132. holder/generated/models/ai_message_create_response_data.py +62 -0
  133. holder/generated/models/ai_message_get_response.py +76 -0
  134. holder/generated/models/ai_message_list_response.py +84 -0
  135. holder/generated/models/ai_message_update_request.py +203 -0
  136. holder/generated/models/ai_message_update_response.py +78 -0
  137. holder/generated/models/ai_message_update_response_data.py +62 -0
  138. holder/generated/models/ai_provider_catalog_provider.py +265 -0
  139. holder/generated/models/ai_provider_catalog_provider_api_type_0.py +46 -0
  140. holder/generated/models/ai_provider_catalog_provider_auth_type_0.py +46 -0
  141. holder/generated/models/ai_provider_catalog_provider_models_item.py +46 -0
  142. holder/generated/models/ai_provider_catalog_response.py +78 -0
  143. holder/generated/models/ai_provider_catalog_response_data.py +100 -0
  144. holder/generated/models/ai_provider_credential.py +94 -0
  145. holder/generated/models/ai_provider_credential_delete_response.py +80 -0
  146. holder/generated/models/ai_provider_credential_delete_response_data.py +62 -0
  147. holder/generated/models/ai_provider_credential_upsert_request.py +92 -0
  148. holder/generated/models/ai_provider_credential_upsert_response.py +78 -0
  149. holder/generated/models/ai_provider_credentials_list_response.py +80 -0
  150. holder/generated/models/ai_provider_credentials_list_response_data.py +78 -0
  151. holder/generated/models/ai_run_create_request.py +133 -0
  152. holder/generated/models/ai_run_create_request_context.py +46 -0
  153. holder/generated/models/ai_run_event_data.py +146 -0
  154. holder/generated/models/ai_run_get_response.py +76 -0
  155. holder/generated/models/ai_run_item.py +328 -0
  156. holder/generated/models/ai_run_item_policy_trace_type_0.py +46 -0
  157. holder/generated/models/ai_run_list_response.py +84 -0
  158. holder/generated/models/ai_status_data.py +186 -0
  159. holder/generated/models/ai_status_pull_job.py +130 -0
  160. holder/generated/models/ai_status_response.py +76 -0
  161. holder/generated/models/ai_thread.py +116 -0
  162. holder/generated/models/ai_thread_create_request.py +119 -0
  163. holder/generated/models/ai_thread_create_response.py +78 -0
  164. holder/generated/models/ai_thread_create_response_data.py +62 -0
  165. holder/generated/models/ai_thread_get_response.py +76 -0
  166. holder/generated/models/ai_thread_list_response.py +84 -0
  167. holder/generated/models/ai_thread_patch_response.py +78 -0
  168. holder/generated/models/ai_thread_patch_response_data.py +62 -0
  169. holder/generated/models/ai_thread_update_request.py +104 -0
  170. holder/generated/models/asset_import_job.py +141 -0
  171. holder/generated/models/asset_import_job_response.py +76 -0
  172. holder/generated/models/asset_import_job_status.py +13 -0
  173. holder/generated/models/asset_import_request.py +86 -0
  174. holder/generated/models/asset_placement.py +96 -0
  175. holder/generated/models/asset_placement_encoding.py +9 -0
  176. holder/generated/models/bye_response.py +62 -0
  177. holder/generated/models/calendar_card_activity.py +86 -0
  178. holder/generated/models/card_context_breadcrumb.py +113 -0
  179. holder/generated/models/card_context_breadcrumb_type.py +9 -0
  180. holder/generated/models/card_context_card.py +161 -0
  181. holder/generated/models/card_context_data.py +124 -0
  182. holder/generated/models/card_context_data_project.py +70 -0
  183. holder/generated/models/card_context_response.py +76 -0
  184. holder/generated/models/card_create_request.py +147 -0
  185. holder/generated/models/card_create_response.py +78 -0
  186. holder/generated/models/card_create_response_data.py +70 -0
  187. holder/generated/models/card_data.py +160 -0
  188. holder/generated/models/card_get_response.py +76 -0
  189. holder/generated/models/card_history_author.py +70 -0
  190. holder/generated/models/card_history_comparison_data.py +110 -0
  191. holder/generated/models/card_history_comparison_response.py +78 -0
  192. holder/generated/models/card_history_diff_line.py +100 -0
  193. holder/generated/models/card_history_diff_line_origin.py +10 -0
  194. holder/generated/models/card_history_entry.py +172 -0
  195. holder/generated/models/card_history_entry_kind.py +16 -0
  196. holder/generated/models/card_history_entry_saves_item.py +94 -0
  197. holder/generated/models/card_history_page_data.py +114 -0
  198. holder/generated/models/card_history_page_response.py +76 -0
  199. holder/generated/models/card_history_restore_response.py +80 -0
  200. holder/generated/models/card_history_restore_response_data.py +108 -0
  201. holder/generated/models/card_history_snapshot_response.py +80 -0
  202. holder/generated/models/card_history_snapshot_response_data.py +76 -0
  203. holder/generated/models/card_history_version.py +86 -0
  204. holder/generated/models/card_link.py +116 -0
  205. holder/generated/models/card_link_create_request.py +111 -0
  206. holder/generated/models/card_link_create_response.py +76 -0
  207. holder/generated/models/card_link_delete_request.py +80 -0
  208. holder/generated/models/card_link_list_response.py +84 -0
  209. holder/generated/models/card_list_item.py +161 -0
  210. holder/generated/models/card_list_response.py +84 -0
  211. holder/generated/models/card_move_intent.py +15 -0
  212. holder/generated/models/card_move_request.py +134 -0
  213. holder/generated/models/card_move_response.py +76 -0
  214. holder/generated/models/card_move_result.py +114 -0
  215. holder/generated/models/card_page.py +90 -0
  216. holder/generated/models/card_page_item.py +170 -0
  217. holder/generated/models/card_page_response.py +76 -0
  218. holder/generated/models/card_patch_response.py +78 -0
  219. holder/generated/models/card_patch_response_data.py +62 -0
  220. holder/generated/models/card_reference_candidate.py +84 -0
  221. holder/generated/models/card_reference_resolve_data.py +129 -0
  222. holder/generated/models/card_reference_resolve_data_match_kind.py +10 -0
  223. holder/generated/models/card_reference_resolve_data_status.py +10 -0
  224. holder/generated/models/card_reference_resolve_request.py +82 -0
  225. holder/generated/models/card_reference_resolve_request_scope.py +10 -0
  226. holder/generated/models/card_reference_resolve_response.py +78 -0
  227. holder/generated/models/card_tag_mutation_request.py +70 -0
  228. holder/generated/models/card_tag_mutation_response.py +78 -0
  229. holder/generated/models/card_tag_mutation_result.py +88 -0
  230. holder/generated/models/card_tag_mutation_result_outcome.py +12 -0
  231. holder/generated/models/card_update_request.py +122 -0
  232. holder/generated/models/caste_info.py +85 -0
  233. holder/generated/models/caste_info_name.py +12 -0
  234. holder/generated/models/caste_recommended_model.py +143 -0
  235. holder/generated/models/caste_recommended_model_required_caste.py +12 -0
  236. holder/generated/models/change_event_data.py +109 -0
  237. holder/generated/models/change_event_data_entity.py +14 -0
  238. holder/generated/models/delete_cards_card_id_children.py +9 -0
  239. holder/generated/models/delete_cards_card_id_resources_body.py +70 -0
  240. holder/generated/models/error.py +70 -0
  241. holder/generated/models/error_response.py +76 -0
  242. holder/generated/models/event_checkpoint.py +92 -0
  243. holder/generated/models/event_checkpoint_git_revisions.py +66 -0
  244. holder/generated/models/event_checkpoint_history_urls.py +48 -0
  245. holder/generated/models/event_checkpoint_response.py +76 -0
  246. holder/generated/models/event_resync_data.py +116 -0
  247. holder/generated/models/event_resync_data_reason.py +9 -0
  248. holder/generated/models/get_ai_catalog_json_response_200.py +46 -0
  249. holder/generated/models/get_ai_messages_message_id_backlinks_include_deleted.py +9 -0
  250. holder/generated/models/get_ai_messages_message_id_links_include_deleted.py +9 -0
  251. holder/generated/models/get_cards_card_id_backlinks_include_deleted.py +9 -0
  252. holder/generated/models/get_cards_card_id_links_include_deleted.py +9 -0
  253. holder/generated/models/get_cards_context_order.py +10 -0
  254. holder/generated/models/get_cards_order.py +10 -0
  255. holder/generated/models/get_cards_view.py +9 -0
  256. holder/generated/models/get_git_providers_json_response_200.py +46 -0
  257. holder/generated/models/get_locations_location_id_response_200.py +46 -0
  258. holder/generated/models/get_ping_response_200.py +8 -0
  259. holder/generated/models/get_projects_order.py +13 -0
  260. holder/generated/models/get_projects_project_id_cards_order.py +9 -0
  261. holder/generated/models/get_projects_project_id_cards_parent_type_0.py +8 -0
  262. holder/generated/models/get_projects_project_id_history_cards_card_id_compare_mode.py +9 -0
  263. holder/generated/models/get_projects_project_id_history_kind.py +13 -0
  264. holder/generated/models/health_data.py +110 -0
  265. holder/generated/models/health_data_crypt_filter.py +78 -0
  266. holder/generated/models/health_response.py +76 -0
  267. holder/generated/models/hierarchy_repair.py +100 -0
  268. holder/generated/models/hierarchy_repair_move.py +76 -0
  269. holder/generated/models/hierarchy_repair_request.py +62 -0
  270. holder/generated/models/hierarchy_repair_response.py +76 -0
  271. holder/generated/models/local_model.py +91 -0
  272. holder/generated/models/location_binding_request.py +81 -0
  273. holder/generated/models/location_binding_request_values.py +46 -0
  274. holder/generated/models/milestone.py +177 -0
  275. holder/generated/models/milestone_create_request.py +135 -0
  276. holder/generated/models/milestone_list_response.py +84 -0
  277. holder/generated/models/milestone_remove_response.py +78 -0
  278. holder/generated/models/milestone_remove_result.py +79 -0
  279. holder/generated/models/milestone_response.py +76 -0
  280. holder/generated/models/milestone_update_request.py +116 -0
  281. holder/generated/models/patch_locations_location_id_body.py +90 -0
  282. holder/generated/models/patch_locations_location_id_body_configuration.py +46 -0
  283. holder/generated/models/post_ai_runner_pull_body.py +62 -0
  284. holder/generated/models/post_cards_card_id_resources_body.py +70 -0
  285. holder/generated/models/post_locations_response_201.py +46 -0
  286. holder/generated/models/project.py +197 -0
  287. holder/generated/models/project_calendar_response.py +78 -0
  288. holder/generated/models/project_calendar_response_data.py +136 -0
  289. holder/generated/models/project_create_request.py +177 -0
  290. holder/generated/models/project_create_request_privacy_mode.py +9 -0
  291. holder/generated/models/project_create_response.py +78 -0
  292. holder/generated/models/project_create_response_data.py +62 -0
  293. holder/generated/models/project_delete_response.py +78 -0
  294. holder/generated/models/project_delete_response_data.py +62 -0
  295. holder/generated/models/project_encryption_check.py +94 -0
  296. holder/generated/models/project_encryption_check_response.py +80 -0
  297. holder/generated/models/project_encryption_check_response_data.py +92 -0
  298. holder/generated/models/project_encryption_check_response_data_privacy_mode.py +9 -0
  299. holder/generated/models/project_get_response.py +76 -0
  300. holder/generated/models/project_git_push_request.py +95 -0
  301. holder/generated/models/project_git_push_response.py +78 -0
  302. holder/generated/models/project_git_push_response_data.py +199 -0
  303. holder/generated/models/project_git_push_response_data_status.py +15 -0
  304. holder/generated/models/project_git_sync_operation_response.py +80 -0
  305. holder/generated/models/project_git_sync_operation_response_data.py +163 -0
  306. holder/generated/models/project_git_sync_operation_response_data_pull.py +96 -0
  307. holder/generated/models/project_git_sync_operation_response_data_pull_status.py +11 -0
  308. holder/generated/models/project_git_sync_operation_response_data_push.py +118 -0
  309. holder/generated/models/project_git_sync_operation_response_data_push_status.py +15 -0
  310. holder/generated/models/project_git_sync_operation_response_data_status.py +9 -0
  311. holder/generated/models/project_git_sync_request.py +94 -0
  312. holder/generated/models/project_git_sync_status_response.py +80 -0
  313. holder/generated/models/project_git_sync_status_response_data.py +76 -0
  314. holder/generated/models/project_git_test_remote_request.py +96 -0
  315. holder/generated/models/project_git_test_remote_response.py +80 -0
  316. holder/generated/models/project_git_test_remote_response_data.py +151 -0
  317. holder/generated/models/project_git_test_remote_response_data_status.py +14 -0
  318. holder/generated/models/project_history_activity.py +138 -0
  319. holder/generated/models/project_history_affected_object.py +74 -0
  320. holder/generated/models/project_history_affected_object_kind.py +13 -0
  321. holder/generated/models/project_history_page_data.py +115 -0
  322. holder/generated/models/project_history_page_response.py +78 -0
  323. holder/generated/models/project_list_response.py +84 -0
  324. holder/generated/models/project_privacy_mode.py +9 -0
  325. holder/generated/models/project_recovery_token_export_request.py +62 -0
  326. holder/generated/models/project_recovery_token_export_response.py +80 -0
  327. holder/generated/models/project_recovery_token_export_response_data.py +78 -0
  328. holder/generated/models/project_recovery_token_import_request.py +70 -0
  329. holder/generated/models/project_recovery_token_import_response.py +80 -0
  330. holder/generated/models/project_recovery_token_import_response_data.py +62 -0
  331. holder/generated/models/project_sync.py +227 -0
  332. holder/generated/models/project_tag.py +70 -0
  333. holder/generated/models/project_tag_list_response.py +84 -0
  334. holder/generated/models/project_update_request.py +181 -0
  335. holder/generated/models/project_update_request_privacy_mode.py +9 -0
  336. holder/generated/models/project_update_response.py +78 -0
  337. holder/generated/models/project_update_response_data.py +75 -0
  338. holder/generated/models/put_locations_preferred_body.py +70 -0
  339. holder/generated/models/rebuild_data.py +94 -0
  340. holder/generated/models/rebuild_request.py +62 -0
  341. holder/generated/models/rebuild_response.py +76 -0
  342. holder/generated/models/recovery_token_import_auto_response.py +80 -0
  343. holder/generated/models/recovery_token_import_auto_response_data.py +141 -0
  344. holder/generated/models/recovery_token_import_auto_response_data_pull_status.py +10 -0
  345. holder/generated/models/reindex_data.py +62 -0
  346. holder/generated/models/reindex_response.py +76 -0
  347. holder/generated/models/resource.py +134 -0
  348. holder/generated/models/resource_asset.py +140 -0
  349. holder/generated/models/resource_attachment_response.py +80 -0
  350. holder/generated/models/resource_attachment_response_data.py +90 -0
  351. holder/generated/models/resource_attachment_response_data_outcome.py +11 -0
  352. holder/generated/models/resource_create_request.py +129 -0
  353. holder/generated/models/resource_delete_response.py +78 -0
  354. holder/generated/models/resource_delete_response_data.py +62 -0
  355. holder/generated/models/resource_list_response.py +134 -0
  356. holder/generated/models/resource_metadata.py +55 -0
  357. holder/generated/models/resource_response.py +76 -0
  358. holder/generated/models/resource_update_request.py +102 -0
  359. holder/generated/models/runner_capabilities_data.py +220 -0
  360. holder/generated/models/runner_capabilities_response.py +78 -0
  361. holder/generated/models/runner_pull_job.py +122 -0
  362. holder/generated/models/runner_pull_progress.py +86 -0
  363. holder/generated/models/runner_pull_start_response.py +78 -0
  364. holder/generated/models/runner_pull_start_response_data.py +78 -0
  365. holder/generated/models/runner_pull_status_response.py +76 -0
  366. holder/generated/models/search_card_item.py +102 -0
  367. holder/generated/models/search_cards_response.py +84 -0
  368. holder/generated/models/search_message_item.py +86 -0
  369. holder/generated/models/search_messages_response.py +84 -0
  370. holder/generated/models/storage_location.py +149 -0
  371. holder/generated/models/storage_location_configuration.py +48 -0
  372. holder/generated/models/storage_location_list_response.py +100 -0
  373. holder/generated/models/storage_location_provider.py +9 -0
  374. holder/generated/models/storage_location_request.py +118 -0
  375. holder/generated/models/storage_location_request_configuration.py +46 -0
  376. holder/generated/models/storage_location_request_provider.py +9 -0
  377. holder/generated/models/trash_delete_response.py +78 -0
  378. holder/generated/models/trash_delete_response_data.py +46 -0
  379. holder/generated/models/trash_item.py +211 -0
  380. holder/generated/models/trash_list_response.py +84 -0
  381. holder/generated/types.py +54 -0
  382. holder/library.py +15 -0
  383. holder/models/__init__.py +15 -0
  384. holder/models/card.py +272 -0
  385. holder/models/project.py +207 -0
  386. holder/models/search.py +66 -0
  387. holder/models/tag.py +117 -0
  388. holder/py.typed +0 -0
  389. holder_python-0.2.5.dist-info/METADATA +120 -0
  390. holder_python-0.2.5.dist-info/RECORD +391 -0
  391. holder_python-0.2.5.dist-info/WHEEL +4 -0
@@ -0,0 +1,211 @@
1
+ from __future__ import annotations
2
+
3
+ from collections.abc import Mapping
4
+ from typing import Any, TypeVar, cast
5
+
6
+ from attrs import define as _attrs_define
7
+ from attrs import field as _attrs_field
8
+ from typing_extensions import Self
9
+
10
+ from ..types import UNSET, Unset
11
+
12
+ T = TypeVar("T", bound="TrashItem")
13
+
14
+
15
+ @_attrs_define
16
+ class TrashItem:
17
+ """
18
+ Attributes:
19
+ type_ (str):
20
+ card_id (None | str | Unset):
21
+ message_id (None | str | Unset):
22
+ thread_id (None | str | Unset):
23
+ project_id (str | Unset):
24
+ title (None | str | Unset):
25
+ role (None | str | Unset):
26
+ deleted_at (int | Unset):
27
+ created_at (int | Unset):
28
+ rel_path (None | str | Unset):
29
+ """
30
+
31
+ type_: str
32
+ card_id: None | str | Unset = UNSET
33
+ message_id: None | str | Unset = UNSET
34
+ thread_id: None | str | Unset = UNSET
35
+ project_id: str | Unset = UNSET
36
+ title: None | str | Unset = UNSET
37
+ role: None | str | Unset = UNSET
38
+ deleted_at: int | Unset = UNSET
39
+ created_at: int | Unset = UNSET
40
+ rel_path: None | str | Unset = UNSET
41
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
42
+
43
+ def to_dict(self) -> dict[str, Any]:
44
+ type_ = self.type_
45
+
46
+ card_id: None | str | Unset
47
+ if isinstance(self.card_id, Unset):
48
+ card_id = UNSET
49
+ else:
50
+ card_id = self.card_id
51
+
52
+ message_id: None | str | Unset
53
+ if isinstance(self.message_id, Unset):
54
+ message_id = UNSET
55
+ else:
56
+ message_id = self.message_id
57
+
58
+ thread_id: None | str | Unset
59
+ if isinstance(self.thread_id, Unset):
60
+ thread_id = UNSET
61
+ else:
62
+ thread_id = self.thread_id
63
+
64
+ project_id = self.project_id
65
+
66
+ title: None | str | Unset
67
+ if isinstance(self.title, Unset):
68
+ title = UNSET
69
+ else:
70
+ title = self.title
71
+
72
+ role: None | str | Unset
73
+ if isinstance(self.role, Unset):
74
+ role = UNSET
75
+ else:
76
+ role = self.role
77
+
78
+ deleted_at = self.deleted_at
79
+
80
+ created_at = self.created_at
81
+
82
+ rel_path: None | str | Unset
83
+ if isinstance(self.rel_path, Unset):
84
+ rel_path = UNSET
85
+ else:
86
+ rel_path = self.rel_path
87
+
88
+ field_dict: dict[str, Any] = {}
89
+ field_dict.update(self.additional_properties)
90
+ field_dict.update(
91
+ {
92
+ "type": type_,
93
+ }
94
+ )
95
+ if card_id is not UNSET:
96
+ field_dict["card_id"] = card_id
97
+ if message_id is not UNSET:
98
+ field_dict["message_id"] = message_id
99
+ if thread_id is not UNSET:
100
+ field_dict["thread_id"] = thread_id
101
+ if project_id is not UNSET:
102
+ field_dict["project_id"] = project_id
103
+ if title is not UNSET:
104
+ field_dict["title"] = title
105
+ if role is not UNSET:
106
+ field_dict["role"] = role
107
+ if deleted_at is not UNSET:
108
+ field_dict["deleted_at"] = deleted_at
109
+ if created_at is not UNSET:
110
+ field_dict["created_at"] = created_at
111
+ if rel_path is not UNSET:
112
+ field_dict["rel_path"] = rel_path
113
+
114
+ return field_dict
115
+
116
+ @classmethod
117
+ def from_dict(cls, src_dict: Mapping[str, Any]) -> Self:
118
+ d = dict(src_dict)
119
+ type_ = d.pop("type")
120
+
121
+ def _parse_card_id(data: object) -> None | str | Unset:
122
+ if data is None:
123
+ return data
124
+ if isinstance(data, Unset):
125
+ return data
126
+ return cast(None | str | Unset, data)
127
+
128
+ card_id = _parse_card_id(d.pop("card_id", UNSET))
129
+
130
+ def _parse_message_id(data: object) -> None | str | Unset:
131
+ if data is None:
132
+ return data
133
+ if isinstance(data, Unset):
134
+ return data
135
+ return cast(None | str | Unset, data)
136
+
137
+ message_id = _parse_message_id(d.pop("message_id", UNSET))
138
+
139
+ def _parse_thread_id(data: object) -> None | str | Unset:
140
+ if data is None:
141
+ return data
142
+ if isinstance(data, Unset):
143
+ return data
144
+ return cast(None | str | Unset, data)
145
+
146
+ thread_id = _parse_thread_id(d.pop("thread_id", UNSET))
147
+
148
+ project_id = d.pop("project_id", UNSET)
149
+
150
+ def _parse_title(data: object) -> None | str | Unset:
151
+ if data is None:
152
+ return data
153
+ if isinstance(data, Unset):
154
+ return data
155
+ return cast(None | str | Unset, data)
156
+
157
+ title = _parse_title(d.pop("title", UNSET))
158
+
159
+ def _parse_role(data: object) -> None | str | Unset:
160
+ if data is None:
161
+ return data
162
+ if isinstance(data, Unset):
163
+ return data
164
+ return cast(None | str | Unset, data)
165
+
166
+ role = _parse_role(d.pop("role", UNSET))
167
+
168
+ deleted_at = d.pop("deleted_at", UNSET)
169
+
170
+ created_at = d.pop("created_at", UNSET)
171
+
172
+ def _parse_rel_path(data: object) -> None | str | Unset:
173
+ if data is None:
174
+ return data
175
+ if isinstance(data, Unset):
176
+ return data
177
+ return cast(None | str | Unset, data)
178
+
179
+ rel_path = _parse_rel_path(d.pop("rel_path", UNSET))
180
+
181
+ trash_item = cls(
182
+ type_=type_,
183
+ card_id=card_id,
184
+ message_id=message_id,
185
+ thread_id=thread_id,
186
+ project_id=project_id,
187
+ title=title,
188
+ role=role,
189
+ deleted_at=deleted_at,
190
+ created_at=created_at,
191
+ rel_path=rel_path,
192
+ )
193
+
194
+ trash_item.additional_properties = d
195
+ return trash_item
196
+
197
+ @property
198
+ def additional_keys(self) -> list[str]:
199
+ return list(self.additional_properties.keys())
200
+
201
+ def __getitem__(self, key: str) -> Any:
202
+ return self.additional_properties[key]
203
+
204
+ def __setitem__(self, key: str, value: Any) -> None:
205
+ self.additional_properties[key] = value
206
+
207
+ def __delitem__(self, key: str) -> None:
208
+ del self.additional_properties[key]
209
+
210
+ def __contains__(self, key: str) -> bool:
211
+ return key in self.additional_properties
@@ -0,0 +1,84 @@
1
+ from __future__ import annotations
2
+
3
+ from collections.abc import Mapping
4
+ from typing import TYPE_CHECKING, Any, TypeVar
5
+
6
+ from attrs import define as _attrs_define
7
+ from attrs import field as _attrs_field
8
+ from typing_extensions import Self
9
+
10
+ if TYPE_CHECKING:
11
+ from ..models.trash_item import TrashItem
12
+
13
+
14
+ T = TypeVar("T", bound="TrashListResponse")
15
+
16
+
17
+ @_attrs_define
18
+ class TrashListResponse:
19
+ """
20
+ Attributes:
21
+ ok (bool):
22
+ data (list[TrashItem]):
23
+ """
24
+
25
+ ok: bool
26
+ data: list[TrashItem]
27
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
28
+
29
+ def to_dict(self) -> dict[str, Any]:
30
+ ok = self.ok
31
+
32
+ data = []
33
+ for data_item_data in self.data:
34
+ data_item = data_item_data.to_dict()
35
+ data.append(data_item)
36
+
37
+ field_dict: dict[str, Any] = {}
38
+ field_dict.update(self.additional_properties)
39
+ field_dict.update(
40
+ {
41
+ "ok": ok,
42
+ "data": data,
43
+ }
44
+ )
45
+
46
+ return field_dict
47
+
48
+ @classmethod
49
+ def from_dict(cls, src_dict: Mapping[str, Any]) -> Self:
50
+ from ..models.trash_item import TrashItem
51
+
52
+ d = dict(src_dict)
53
+ ok = d.pop("ok")
54
+
55
+ data = []
56
+ _data = d.pop("data")
57
+ for data_item_data in _data:
58
+ data_item = TrashItem.from_dict(data_item_data)
59
+
60
+ data.append(data_item)
61
+
62
+ trash_list_response = cls(
63
+ ok=ok,
64
+ data=data,
65
+ )
66
+
67
+ trash_list_response.additional_properties = d
68
+ return trash_list_response
69
+
70
+ @property
71
+ def additional_keys(self) -> list[str]:
72
+ return list(self.additional_properties.keys())
73
+
74
+ def __getitem__(self, key: str) -> Any:
75
+ return self.additional_properties[key]
76
+
77
+ def __setitem__(self, key: str, value: Any) -> None:
78
+ self.additional_properties[key] = value
79
+
80
+ def __delitem__(self, key: str) -> None:
81
+ del self.additional_properties[key]
82
+
83
+ def __contains__(self, key: str) -> bool:
84
+ return key in self.additional_properties
@@ -0,0 +1,54 @@
1
+ """Contains some shared types for properties"""
2
+
3
+ from collections.abc import Mapping, MutableMapping
4
+ from http import HTTPStatus
5
+ from typing import IO, BinaryIO, Generic, Literal, TypeVar
6
+
7
+ from attrs import define
8
+
9
+
10
+ class Unset:
11
+ def __bool__(self) -> Literal[False]:
12
+ return False
13
+
14
+
15
+ UNSET: Unset = Unset()
16
+
17
+ # The types that `httpx.Client(files=)` can accept, copied from that library.
18
+ FileContent = IO[bytes] | bytes | str
19
+ FileTypes = (
20
+ # (filename, file (or bytes), content_type)
21
+ tuple[str | None, FileContent, str | None]
22
+ # (filename, file (or bytes), content_type, headers)
23
+ | tuple[str | None, FileContent, str | None, Mapping[str, str]]
24
+ )
25
+ RequestFiles = list[tuple[str, FileTypes]]
26
+
27
+
28
+ @define
29
+ class File:
30
+ """Contains information for file uploads"""
31
+
32
+ payload: BinaryIO
33
+ file_name: str | None = None
34
+ mime_type: str | None = None
35
+
36
+ def to_tuple(self) -> FileTypes:
37
+ """Return a tuple representation that httpx will accept for multipart/form-data"""
38
+ return self.file_name, self.payload, self.mime_type
39
+
40
+
41
+ T = TypeVar("T")
42
+
43
+
44
+ @define
45
+ class Response(Generic[T]):
46
+ """A response from an endpoint"""
47
+
48
+ status_code: HTTPStatus
49
+ content: bytes
50
+ headers: MutableMapping[str, str]
51
+ parsed: T | None
52
+
53
+
54
+ __all__ = ["UNSET", "File", "FileTypes", "RequestFiles", "Response", "Unset"]
holder/library.py ADDED
@@ -0,0 +1,15 @@
1
+ """Compatibility imports for the original synchronous library module."""
2
+
3
+ from .client import Holder
4
+ from .collections import Collection
5
+ from .models.card import Card, CardCollection
6
+ from .models.project import Project, ProjectCollection
7
+
8
+ __all__ = [
9
+ "Card",
10
+ "CardCollection",
11
+ "Collection",
12
+ "Holder",
13
+ "Project",
14
+ "ProjectCollection",
15
+ ]
@@ -0,0 +1,15 @@
1
+ """Project, card, tag and search result models for the Holder client."""
2
+
3
+ from .card import Card
4
+ from .project import HierarchyRepair, Project, RepairedCard
5
+ from .search import CardSearchResult
6
+ from .tag import Tag
7
+
8
+ __all__ = [
9
+ "Card",
10
+ "CardSearchResult",
11
+ "HierarchyRepair",
12
+ "Project",
13
+ "RepairedCard",
14
+ "Tag",
15
+ ]
holder/models/card.py ADDED
@@ -0,0 +1,272 @@
1
+ """Cards and their project-scoped synchronous collection queries."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import time
6
+ from dataclasses import dataclass, field, fields
7
+ from functools import cached_property
8
+ from typing import TYPE_CHECKING, Any, Self
9
+
10
+ from ..collections import Collection
11
+ from ..exceptions import NotFoundError, ProtocolError
12
+ from ..generated.api.default import (
13
+ delete_cards_card_id,
14
+ get_cards_card_id,
15
+ get_projects_project_id_cards,
16
+ patch_cards_card_id,
17
+ post_cards,
18
+ post_cards_card_id_move,
19
+ post_cards_card_id_restore,
20
+ )
21
+ from ..generated.models import (
22
+ CardCreateRequest,
23
+ CardMoveIntent,
24
+ CardMoveRequest,
25
+ CardUpdateRequest,
26
+ DeleteCardsCardIdChildren,
27
+ )
28
+ from ..generated.models.get_projects_project_id_cards_parent_type_0 import (
29
+ GetProjectsProjectIdCardsParentType0 as CardParent,
30
+ )
31
+ from ..generated.types import UNSET, Unset
32
+ from .search import CardSearchCollection
33
+ from .tag import CardTagCollection
34
+
35
+ if TYPE_CHECKING:
36
+ from .project import Project
37
+
38
+
39
+ class CardCollection(Collection["Card"]):
40
+ def __init__(self, project: Project, query: dict[str, Any] | None = None) -> None:
41
+ self._project = project
42
+ super().__init__(project._holder, query)
43
+
44
+ def create(self, *, title: str, content: str = "") -> Card:
45
+ """Create a root card, or a child when called on a children collection.
46
+
47
+ Tag filters do not add tags to the content. Cached listings remain
48
+ unchanged until refreshed. The write is never retried; if the subsequent
49
+ fetch fails, the card may already exist.
50
+ """
51
+ if not isinstance(title, str):
52
+ raise TypeError("title must be a string")
53
+ if not isinstance(content, str):
54
+ raise TypeError("content must be a string")
55
+ parent = self._query.get("parent", UNSET)
56
+ if parent == CardParent.ROOTS:
57
+ parent = UNSET
58
+ data = self._holder._call(
59
+ post_cards,
60
+ body=CardCreateRequest(
61
+ project_id=self._project.id,
62
+ title=title,
63
+ content=content,
64
+ parent_card_id=parent,
65
+ ),
66
+ write=True,
67
+ )
68
+ return self.get(data.card_id)
69
+
70
+ def _clone(self, query: dict[str, Any]) -> Self:
71
+ return type(self)(self._project, query)
72
+
73
+ def filter(self, *, tag: str) -> Self:
74
+ if not isinstance(tag, str) or not tag.strip():
75
+ raise ValueError("tag must be a nonempty string")
76
+ return self._clone({**self._query, "tag": tag})
77
+
78
+ def roots(self) -> Self:
79
+ return self._clone({**self._query, "parent": CardParent.ROOTS})
80
+
81
+ def search(self, query: str) -> CardSearchCollection:
82
+ """Search this project's cards using the daemon's full-text query syntax.
83
+
84
+ Tag and hierarchy filters cannot be combined with the search endpoint.
85
+ """
86
+ if not isinstance(query, str):
87
+ raise TypeError("query must be a string")
88
+ if not query.strip():
89
+ raise ValueError("query must be nonempty")
90
+ if self._query:
91
+ raise ValueError("Search does not support tag or hierarchy filters")
92
+ return CardSearchCollection(self._project, query)
93
+
94
+ def _fetch_page(self) -> tuple[list[Card], str | None]:
95
+ data = self._holder._call(
96
+ get_projects_project_id_cards,
97
+ self._project.id,
98
+ limit=200,
99
+ cursor=self._next or UNSET,
100
+ **self._query,
101
+ )
102
+ rows = [Card._from(self._project, item) for item in data.items]
103
+ if any(card.project_id != self._project.id for card in rows):
104
+ raise ProtocolError("Card listing returned an object from another project")
105
+ cursor = data.next_cursor
106
+ if cursor is not None and (
107
+ not isinstance(cursor, str)
108
+ or not cursor
109
+ or not rows
110
+ or cursor == self._next
111
+ ):
112
+ raise ProtocolError("Card pagination did not advance")
113
+ return rows, cursor
114
+
115
+ def get(self, card_id: str) -> Card:
116
+ data = self._holder._call(get_cards_card_id, card_id)
117
+ if data.project_id != self._project.id:
118
+ raise NotFoundError(404, "not_found", "Card not found in this project")
119
+ return Card._from(self._project, data)
120
+
121
+
122
+ @dataclass(frozen=True, eq=False)
123
+ class Card:
124
+ card_id: str
125
+ project_id: str
126
+ title: str
127
+ rel_path: str
128
+ sort_key: float
129
+ created_at: int
130
+ updated_at: int
131
+ parent_card_id: str | None
132
+ deleted_at: int | None
133
+ child_count: int | None
134
+ _project: Project = field(repr=False, compare=False)
135
+ _content: str | None = field(default=None, repr=False, compare=False)
136
+
137
+ @property
138
+ def id(self) -> str:
139
+ return self.card_id
140
+
141
+ @property
142
+ def content(self) -> str:
143
+ self._project._holder._active()
144
+ if self._content is None:
145
+ self.refresh()
146
+ if self._content is None:
147
+ raise ProtocolError("Card response did not include content")
148
+ return self._content
149
+
150
+ @cached_property
151
+ def children(self) -> CardCollection:
152
+ return CardCollection(self._project, {"parent": self.id})
153
+
154
+ @cached_property
155
+ def tags(self) -> CardTagCollection:
156
+ return CardTagCollection(self)
157
+
158
+ @classmethod
159
+ def _from(cls, project: Project, data: Any) -> Self:
160
+ values: dict[str, Any] = {
161
+ f.name: getattr(data, f.name, None)
162
+ for f in fields(cls)
163
+ if not f.name.startswith("_")
164
+ }
165
+ values = {k: None if isinstance(v, Unset) else v for k, v in values.items()}
166
+ # Collection pages carry content only when asked; an absent field means "not loaded".
167
+ content = getattr(data, "content", None)
168
+ if isinstance(content, Unset):
169
+ content = None
170
+ return cls(**values, _project=project, _content=content)
171
+
172
+ def refresh(self) -> Self:
173
+ fresh = self._project.cards.get(self.id)
174
+ for f in fields(self):
175
+ if f.name != "_project":
176
+ object.__setattr__(self, f.name, getattr(fresh, f.name))
177
+ if "tags" in self.__dict__:
178
+ self.tags.refresh()
179
+ return self
180
+
181
+ def update(
182
+ self, *, title: str | None | Unset = UNSET, content: str | Unset = UNSET
183
+ ) -> Self:
184
+ if isinstance(title, Unset) and isinstance(content, Unset):
185
+ raise TypeError("Supply title or content")
186
+ if not isinstance(title, (str, Unset)) and title is not None:
187
+ raise TypeError("title must be a string or None")
188
+ if not isinstance(content, (str, Unset)):
189
+ raise TypeError("content must be a string")
190
+ # Verify membership and obtain fresh content before any write.
191
+ current = self._project.cards.get(self.id)
192
+ if isinstance(content, Unset):
193
+ content = current.content
194
+ body = CardUpdateRequest(
195
+ updated_at=int(time.time()), title=title, content=content
196
+ )
197
+ self._project._holder._call(patch_cards_card_id, self.id, body=body, write=True)
198
+ return self.refresh()
199
+
200
+ def move(
201
+ self,
202
+ *,
203
+ parent: Card | None | Unset = UNSET,
204
+ before: Card | Unset = UNSET,
205
+ after: Card | Unset = UNSET,
206
+ ) -> Self:
207
+ """Move into a parent or immediately before/after a target card.
208
+
209
+ Supply exactly one Card, or parent=None to append the card to the
210
+ project's top level. Relative moves adopt the target's parent.
211
+ The daemon enforces project membership and prevents hierarchy cycles.
212
+ The moved card is refreshed; evaluated listings need explicit refresh.
213
+ Writes are never retried, even if the subsequent refresh fails.
214
+ """
215
+ supplied = [
216
+ (intent, target)
217
+ for intent, target in (
218
+ (CardMoveIntent.INTO, parent),
219
+ (CardMoveIntent.BEFORE, before),
220
+ (CardMoveIntent.AFTER, after),
221
+ )
222
+ if not isinstance(target, Unset)
223
+ ]
224
+ if len(supplied) != 1:
225
+ raise TypeError("Supply exactly one of parent, before or after")
226
+ intent, target = supplied[0]
227
+ if intent is CardMoveIntent.INTO and target is None:
228
+ # An explicit null parent is the project's top level.
229
+ body = CardMoveRequest(
230
+ project_id=self._project.id,
231
+ intent=CardMoveIntent.TO_END,
232
+ parent_card_id=None,
233
+ )
234
+ elif isinstance(target, Card):
235
+ body = CardMoveRequest(
236
+ project_id=self._project.id,
237
+ intent=intent,
238
+ target_card_id=target.id,
239
+ )
240
+ else:
241
+ raise TypeError("The move target must be a Card")
242
+ self._project._holder._call(
243
+ post_cards_card_id_move, self.id, body=body, write=True
244
+ )
245
+ return self.refresh()
246
+
247
+ def trash(self, *, children: str = "promote") -> None:
248
+ """Move this card to Trash.
249
+
250
+ With children="promote" (the default), its live children take its place
251
+ among its siblings, keeping their own descendants. With
252
+ children="trash_subtree", every live descendant goes to Trash with it.
253
+ A trashed card cannot be read again until restored, so this object is
254
+ not refreshed. The write is never retried.
255
+ """
256
+ try:
257
+ policy = DeleteCardsCardIdChildren(children)
258
+ except ValueError:
259
+ raise ValueError('children must be "promote" or "trash_subtree"') from None
260
+ self._project._holder._call(
261
+ delete_cards_card_id, self.id, children=policy, write=True
262
+ )
263
+
264
+ def restore(self) -> Self:
265
+ """Restore this card from Trash, and refresh it.
266
+
267
+ Restoring is single-card: it returns to its saved parent when that
268
+ parent is live, otherwise to its nearest live ancestor or the top level.
269
+ Children promoted when it was trashed stay where they are.
270
+ """
271
+ self._project._holder._call(post_cards_card_id_restore, self.id, write=True)
272
+ return self.refresh()