tutorflow-content 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (517) hide show
  1. tutorflow_content-0.1.0/PKG-INFO +151 -0
  2. tutorflow_content-0.1.0/README.md +130 -0
  3. tutorflow_content-0.1.0/pyproject.toml +39 -0
  4. tutorflow_content-0.1.0/setup.cfg +4 -0
  5. tutorflow_content-0.1.0/tests/test_errors.py +56 -0
  6. tutorflow_content-0.1.0/tests/test_pagination.py +102 -0
  7. tutorflow_content-0.1.0/tests/test_retry.py +110 -0
  8. tutorflow_content-0.1.0/tests/test_runs.py +136 -0
  9. tutorflow_content-0.1.0/tests/test_webhooks.py +125 -0
  10. tutorflow_content-0.1.0/tutorflow_content/__init__.py +42 -0
  11. tutorflow_content-0.1.0/tutorflow_content/client.py +71 -0
  12. tutorflow_content-0.1.0/tutorflow_content/errors.py +87 -0
  13. tutorflow_content-0.1.0/tutorflow_content/generated/__init__.py +8 -0
  14. tutorflow_content-0.1.0/tutorflow_content/generated/api/__init__.py +1 -0
  15. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_api_keys/__init__.py +1 -0
  16. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_api_keys/content_integration_api_key_controller_create_api_key.py +243 -0
  17. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_api_keys/content_integration_api_key_controller_delete_api_key.py +251 -0
  18. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_api_keys/content_integration_api_key_controller_list_api_keys.py +228 -0
  19. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_api_keys/content_integration_api_key_controller_revoke_api_key.py +232 -0
  20. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_api_keys/content_integration_api_key_controller_rotate_api_key.py +256 -0
  21. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_api_keys/content_integration_api_key_controller_update_api_key.py +283 -0
  22. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_api_keys/content_organization_activity_controller_api_key_labels.py +240 -0
  23. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_assets/__init__.py +1 -0
  24. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_assets/content_asset_upload_controller_complete.py +266 -0
  25. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_assets/content_asset_upload_controller_create.py +350 -0
  26. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_audit_log/__init__.py +1 -0
  27. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_audit_log/content_api_audit_log_controller_list.py +383 -0
  28. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_audit_log/content_organization_activity_controller_audit_log.py +384 -0
  29. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_classrooms/__init__.py +1 -0
  30. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_classrooms/content_integration_classroom_controller_list_classrooms.py +206 -0
  31. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_course_curriculum/__init__.py +1 -0
  32. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_course_curriculum/content_resource_course_curriculum_controller_create_chapter.py +291 -0
  33. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_course_curriculum/content_resource_course_curriculum_controller_create_lesson.py +304 -0
  34. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_course_curriculum/content_resource_course_curriculum_controller_delete_chapter.py +283 -0
  35. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_course_curriculum/content_resource_course_curriculum_controller_delete_lesson.py +283 -0
  36. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_course_curriculum/content_resource_course_curriculum_controller_get_lesson.py +280 -0
  37. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_course_curriculum/content_resource_course_curriculum_controller_list_chapters.py +267 -0
  38. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_course_curriculum/content_resource_course_curriculum_controller_reorder_chapters.py +287 -0
  39. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_course_curriculum/content_resource_course_curriculum_controller_reorder_lessons.py +300 -0
  40. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_course_curriculum/content_resource_course_curriculum_controller_update_chapter.py +300 -0
  41. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_course_curriculum/content_resource_course_curriculum_controller_update_lesson.py +300 -0
  42. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_courses/__init__.py +1 -0
  43. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_courses/content_resource_course_controller_create.py +278 -0
  44. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_courses/content_resource_course_controller_delete.py +270 -0
  45. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_courses/content_resource_course_controller_get.py +315 -0
  46. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_courses/content_resource_course_controller_list.py +379 -0
  47. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_courses/content_resource_course_controller_update.py +295 -0
  48. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_credits/__init__.py +1 -0
  49. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_credits/content_integration_credit_controller_get_balance.py +209 -0
  50. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_credits/content_integration_credit_controller_get_history.py +366 -0
  51. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_credits/content_organization_activity_controller_credit_history.py +371 -0
  52. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_evaluations/__init__.py +1 -0
  53. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_evaluations/content_evaluation_controller_create.py +323 -0
  54. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_evaluations/content_evaluation_controller_download_file.py +277 -0
  55. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_evaluations/content_evaluation_controller_get.py +247 -0
  56. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_evaluations/content_evaluation_controller_list.py +330 -0
  57. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_evaluations/content_learning_controller_get_mastery.py +247 -0
  58. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_evaluations/content_learning_controller_list_concepts.py +234 -0
  59. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_games/__init__.py +1 -0
  60. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_games/content_resource_game_controller_build_game.py +325 -0
  61. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_games/content_resource_game_controller_create.py +278 -0
  62. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_games/content_resource_game_controller_delete.py +274 -0
  63. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_games/content_resource_game_controller_generate_brief.py +338 -0
  64. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_games/content_resource_game_controller_get.py +267 -0
  65. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_games/content_resource_game_controller_get_run_status.py +243 -0
  66. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_games/content_resource_game_controller_list.py +364 -0
  67. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_games/content_resource_game_controller_restore_version.py +287 -0
  68. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_games/content_resource_game_controller_revise_game.py +342 -0
  69. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_games/content_resource_game_controller_update.py +287 -0
  70. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_generation/__init__.py +1 -0
  71. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_generation/content_generation_controller_generate_course.py +337 -0
  72. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_generation/content_generation_controller_generate_module.py +329 -0
  73. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_generation/content_generation_controller_generate_slides.py +353 -0
  74. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_generation/content_generation_controller_generate_test.py +321 -0
  75. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_generation/content_generation_controller_get_run.py +243 -0
  76. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_generation/content_generation_controller_list_runs.py +311 -0
  77. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_generation/content_generation_controller_resume_run.py +341 -0
  78. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_integrations/__init__.py +1 -0
  79. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_integrations/content_integration_controller_create_expansion.py +280 -0
  80. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_integrations/content_integration_controller_get_expansion.py +230 -0
  81. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_integrations/content_integration_controller_get_expansion_result.py +230 -0
  82. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_learners/__init__.py +1 -0
  83. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_learners/content_learner_controller_get.py +251 -0
  84. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_learners/content_learner_controller_invite.py +317 -0
  85. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_learners/content_learner_controller_list.py +318 -0
  86. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_learners/content_learner_controller_progress.py +288 -0
  87. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_learners/content_learner_controller_remove.py +255 -0
  88. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_learners/content_learner_enrollment_controller_enroll.py +303 -0
  89. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_learners/content_learner_enrollment_controller_list.py +288 -0
  90. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_learners/content_learner_enrollment_controller_unenroll.py +264 -0
  91. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_learners/content_test_result_controller_get.py +295 -0
  92. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_learners/content_test_result_controller_list.py +314 -0
  93. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_modules/__init__.py +1 -0
  94. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_modules/content_resource_module_controller_copy_to_course.py +291 -0
  95. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_modules/content_resource_module_controller_create.py +278 -0
  96. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_modules/content_resource_module_controller_delete.py +270 -0
  97. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_modules/content_resource_module_controller_get.py +267 -0
  98. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_modules/content_resource_module_controller_list.py +364 -0
  99. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_modules/content_resource_module_controller_update.py +287 -0
  100. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_organizations/__init__.py +1 -0
  101. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_organizations/content_integration_organization_controller_list_organizations.py +199 -0
  102. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_simulations/__init__.py +1 -0
  103. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_simulations/content_resource_simulation_controller_build_simulation.py +325 -0
  104. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_simulations/content_resource_simulation_controller_create.py +278 -0
  105. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_simulations/content_resource_simulation_controller_delete.py +274 -0
  106. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_simulations/content_resource_simulation_controller_generate_brief.py +338 -0
  107. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_simulations/content_resource_simulation_controller_get.py +267 -0
  108. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_simulations/content_resource_simulation_controller_get_run_status.py +243 -0
  109. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_simulations/content_resource_simulation_controller_list.py +384 -0
  110. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_simulations/content_resource_simulation_controller_restore_version.py +287 -0
  111. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_simulations/content_resource_simulation_controller_revise_simulation.py +342 -0
  112. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_simulations/content_resource_simulation_controller_update.py +287 -0
  113. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_slides/__init__.py +1 -0
  114. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_slides/content_resource_slide_controller_create.py +278 -0
  115. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_slides/content_resource_slide_controller_delete.py +270 -0
  116. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_slides/content_resource_slide_controller_get.py +267 -0
  117. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_slides/content_resource_slide_controller_list.py +364 -0
  118. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_slides/content_resource_slide_controller_update.py +287 -0
  119. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_tests/__init__.py +1 -0
  120. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_tests/content_resource_test_controller_create.py +278 -0
  121. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_tests/content_resource_test_controller_delete.py +270 -0
  122. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_tests/content_resource_test_controller_get.py +287 -0
  123. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_tests/content_resource_test_controller_list.py +379 -0
  124. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_tests/content_resource_test_controller_update.py +287 -0
  125. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_videos/__init__.py +1 -0
  126. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_videos/content_resource_video_controller_add_scene.py +291 -0
  127. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_videos/content_resource_video_controller_create.py +286 -0
  128. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_videos/content_resource_video_controller_delete.py +270 -0
  129. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_videos/content_resource_video_controller_delete_scene.py +283 -0
  130. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_videos/content_resource_video_controller_get.py +267 -0
  131. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_videos/content_resource_video_controller_list.py +364 -0
  132. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_videos/content_resource_video_controller_reorder_scenes.py +287 -0
  133. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_videos/content_resource_video_controller_update.py +287 -0
  134. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_videos/content_resource_video_controller_update_scene.py +300 -0
  135. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_videos/content_resource_video_narration_controller_narrate_missing.py +289 -0
  136. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_videos/content_resource_video_narration_controller_narrate_scene.py +294 -0
  137. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_videos/content_resource_video_render_controller_cancel.py +250 -0
  138. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_videos/content_resource_video_render_controller_get_status.py +243 -0
  139. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_videos/content_resource_video_render_controller_trigger.py +328 -0
  140. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_webhooks/__init__.py +1 -0
  141. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_webhooks/content_integration_webhook_controller_create_webhook.py +243 -0
  142. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_webhooks/content_integration_webhook_controller_delete_webhook.py +236 -0
  143. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_webhooks/content_integration_webhook_controller_get_webhook.py +236 -0
  144. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_webhooks/content_integration_webhook_controller_list_deliveries.py +317 -0
  145. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_webhooks/content_integration_webhook_controller_list_webhooks.py +228 -0
  146. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_webhooks/content_integration_webhook_controller_redeliver.py +249 -0
  147. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_webhooks/content_integration_webhook_controller_rotate_secret.py +280 -0
  148. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_webhooks/content_integration_webhook_controller_send_test_event.py +236 -0
  149. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_webhooks/content_integration_webhook_controller_update_webhook.py +284 -0
  150. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_webhooks/content_webhook_key_controller_create.py +236 -0
  151. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_webhooks/content_webhook_key_controller_delete.py +230 -0
  152. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_webhooks/content_webhook_key_controller_get.py +230 -0
  153. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_webhooks/content_webhook_key_controller_list.py +206 -0
  154. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_webhooks/content_webhook_key_controller_list_deliveries.py +311 -0
  155. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_webhooks/content_webhook_key_controller_redeliver.py +243 -0
  156. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_webhooks/content_webhook_key_controller_rotate_secret.py +270 -0
  157. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_webhooks/content_webhook_key_controller_send_test_event.py +230 -0
  158. tutorflow_content-0.1.0/tutorflow_content/generated/api/content_webhooks/content_webhook_key_controller_update.py +278 -0
  159. tutorflow_content-0.1.0/tutorflow_content/generated/api/v_1_contentclassroomsclassroom_idintegrationsexports/__init__.py +1 -0
  160. tutorflow_content-0.1.0/tutorflow_content/generated/api/v_1_contentclassroomsclassroom_idintegrationsexports/content_integration_export_controller_export_standalone_lesson.py +243 -0
  161. tutorflow_content-0.1.0/tutorflow_content/generated/client.py +271 -0
  162. tutorflow_content-0.1.0/tutorflow_content/generated/errors.py +14 -0
  163. tutorflow_content-0.1.0/tutorflow_content/generated/models/__init__.py +693 -0
  164. tutorflow_content-0.1.0/tutorflow_content/generated/models/add_scene_dto.py +104 -0
  165. tutorflow_content-0.1.0/tutorflow_content/generated/models/chat_course_quiz_dto.py +257 -0
  166. tutorflow_content-0.1.0/tutorflow_content/generated/models/classroom_test_level_type.py +9 -0
  167. tutorflow_content-0.1.0/tutorflow_content/generated/models/classroom_test_visibility_type.py +9 -0
  168. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_api_audit_log_controller_list_source.py +8 -0
  169. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_api_error.py +85 -0
  170. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_api_error_error.py +221 -0
  171. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_api_error_error_details_item.py +87 -0
  172. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_api_key_created_res_dto.py +277 -0
  173. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_api_key_created_res_dto_mode.py +8 -0
  174. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_api_key_expiring_event.py +135 -0
  175. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_api_key_filter_label.py +118 -0
  176. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_api_key_filter_label_mode.py +8 -0
  177. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_api_key_label_type_0.py +109 -0
  178. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_api_key_label_type_0_mode.py +8 -0
  179. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_api_scope.py +12 -0
  180. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_asset_upload.py +169 -0
  181. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_asset_upload_purpose.py +13 -0
  182. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_asset_upload_status.py +11 -0
  183. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_asset_upload_ticket.py +186 -0
  184. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_asset_upload_ticket_headers.py +85 -0
  185. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_asset_upload_ticket_method.py +7 -0
  186. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_asset_upload_ticket_purpose.py +13 -0
  187. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_asset_upload_ticket_status.py +11 -0
  188. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_audit_log_admin_item.py +330 -0
  189. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_audit_log_admin_page.py +108 -0
  190. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_audit_log_item.py +307 -0
  191. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_audit_log_page.py +108 -0
  192. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_build_history_entry.py +124 -0
  193. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_chapter.py +148 -0
  194. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_classroom_res_dto.py +113 -0
  195. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_concept.py +123 -0
  196. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_concept_list.py +94 -0
  197. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_course.py +343 -0
  198. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_course_chapter.py +146 -0
  199. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_course_deleted.py +121 -0
  200. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_course_lesson.py +337 -0
  201. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_course_lesson_stats.py +84 -0
  202. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_course_list.py +137 -0
  203. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_course_progress.py +208 -0
  204. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_course_stats.py +221 -0
  205. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_course_stats_daily_learning_time_item.py +84 -0
  206. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_course_stats_most_behind_learner_type_0.py +108 -0
  207. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_course_stats_top_learners_item.py +119 -0
  208. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_credit_history_item.py +227 -0
  209. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_credit_history_item_kind.py +9 -0
  210. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_credit_history_page.py +108 -0
  211. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_curriculum.py +118 -0
  212. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_cursor_page_meta.py +100 -0
  213. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_deleted.py +101 -0
  214. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_deprecated_success.py +80 -0
  215. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_enrollment.py +177 -0
  216. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_enrollment_change.py +94 -0
  217. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_enrollment_page.py +108 -0
  218. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_evaluation.py +584 -0
  219. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_evaluation_controller_create_files_body.py +413 -0
  220. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_evaluation_controller_download_file_field.py +8 -0
  221. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_evaluation_controller_list_evaluation_type.py +9 -0
  222. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_evaluation_controller_list_status.py +10 -0
  223. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_evaluation_create.py +254 -0
  224. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_evaluation_create_evaluation_type.py +9 -0
  225. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_evaluation_create_feedback_options.py +105 -0
  226. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_evaluation_create_mode.py +8 -0
  227. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_evaluation_create_rubric.py +95 -0
  228. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_evaluation_create_rubric_criteria_item.py +92 -0
  229. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_evaluation_create_submitter.py +87 -0
  230. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_evaluation_event.py +241 -0
  231. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_evaluation_event_status.py +8 -0
  232. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_evaluation_file.py +100 -0
  233. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_evaluation_learner_type_0.py +92 -0
  234. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_evaluation_mode.py +8 -0
  235. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_evaluation_page.py +108 -0
  236. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_evaluation_rubric_breakdown_type_0_item.py +105 -0
  237. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_evaluation_status.py +10 -0
  238. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_game.py +372 -0
  239. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_game_brief_type_0.py +66 -0
  240. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_game_list.py +137 -0
  241. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_game_metadata_type_0.py +64 -0
  242. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_generate_course_request.py +146 -0
  243. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_generate_course_request_level.py +9 -0
  244. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_generate_module_request.py +120 -0
  245. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_generate_module_request_type.py +19 -0
  246. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_generate_slides_request.py +150 -0
  247. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_generate_slides_request_text_length.py +8 -0
  248. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_generate_slides_request_theme_id.py +15 -0
  249. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_generate_test_request.py +196 -0
  250. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_generate_test_request_item_types_item.py +11 -0
  251. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_generate_test_request_level.py +9 -0
  252. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_generate_test_request_passing_value_type.py +8 -0
  253. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_generation_accepted.py +151 -0
  254. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_generation_accepted_kind.py +8 -0
  255. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_generation_accepted_phase.py +9 -0
  256. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_generation_controller_list_runs_kind.py +10 -0
  257. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_generation_controller_list_runs_status.py +10 -0
  258. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_generation_event.py +213 -0
  259. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_generation_event_phase.py +9 -0
  260. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_generation_event_resource_type.py +8 -0
  261. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_generation_event_status.py +8 -0
  262. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_generation_run.py +296 -0
  263. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_generation_run_accepted.py +121 -0
  264. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_generation_run_accepted_kind.py +10 -0
  265. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_generation_run_accepted_status.py +7 -0
  266. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_generation_run_event.py +241 -0
  267. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_generation_run_event_resource_type.py +10 -0
  268. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_generation_run_event_status.py +8 -0
  269. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_generation_run_kind.py +10 -0
  270. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_generation_run_page.py +108 -0
  271. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_generation_run_progress.py +93 -0
  272. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_generation_run_state.py +10 -0
  273. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_generation_run_status.py +135 -0
  274. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_generation_run_status_active_type_0.py +116 -0
  275. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_generation_run_status_active_type_0_phase.py +9 -0
  276. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_generation_run_status_last_type_0.py +148 -0
  277. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_generation_run_status_last_type_0_phase.py +9 -0
  278. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_generation_run_status_last_type_0_status.py +8 -0
  279. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_integration_api_key_controller_delete_api_key_response_200.py +88 -0
  280. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_integration_api_key_dto.py +377 -0
  281. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_integration_api_key_dto_issuer_status.py +9 -0
  282. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_integration_api_key_dto_mode.py +8 -0
  283. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_integration_credit_balance_res_dto.py +117 -0
  284. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_integration_credit_controller_get_history_source.py +8 -0
  285. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_integration_credit_controller_get_history_type.py +54 -0
  286. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_integration_job_res_dto.py +334 -0
  287. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_integration_job_res_dto_error_type_0.py +64 -0
  288. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_integration_organization_res_dto.py +108 -0
  289. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_integration_organization_res_dto_role.py +9 -0
  290. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_integration_output_res_dto.py +302 -0
  291. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_integration_output_res_dto_error_type_0.py +64 -0
  292. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_integration_output_res_dto_manifest_type_0.py +64 -0
  293. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_integration_output_type.py +9 -0
  294. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_integration_result_res_dto.py +122 -0
  295. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_integration_result_res_dto_manifest.py +64 -0
  296. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_integration_source_type.py +8 -0
  297. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_integration_webhook_delivery_status.py +10 -0
  298. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_integration_webhook_event_type.py +35 -0
  299. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_integration_webhook_status.py +8 -0
  300. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_job_event.py +178 -0
  301. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_learner.py +132 -0
  302. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_learner_controller_list_status.py +9 -0
  303. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_learner_course_completed_event.py +141 -0
  304. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_learner_enrolled_event.py +129 -0
  305. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_learner_invitation_result.py +143 -0
  306. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_learner_invitation_result_invitation_type_1.py +104 -0
  307. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_learner_invitation_result_status.py +8 -0
  308. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_learner_mastery.py +131 -0
  309. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_learner_mastery_concepts_item.py +145 -0
  310. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_learner_mastery_learner.py +92 -0
  311. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_learner_page.py +108 -0
  312. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_learner_progress.py +106 -0
  313. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_learner_removed.py +91 -0
  314. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_learner_status.py +9 -0
  315. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_learner_test_submitted_event.py +152 -0
  316. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_lesson_detail.py +265 -0
  317. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_lesson_detail_submission.py +70 -0
  318. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_lesson_progress.py +154 -0
  319. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_lesson_summary.py +205 -0
  320. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_module.py +426 -0
  321. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_module_copy_result.py +99 -0
  322. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_module_list.py +137 -0
  323. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_module_metadata_type_0.py +64 -0
  324. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_module_quiz.py +237 -0
  325. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_organization_activity_controller_audit_log_source.py +8 -0
  326. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_organization_activity_controller_credit_history_source.py +8 -0
  327. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_organization_activity_controller_credit_history_type.py +54 -0
  328. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_page_meta.py +116 -0
  329. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_resource_course_controller_get_days.py +8 -0
  330. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_resource_course_controller_list_field.py +10 -0
  331. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_resource_event.py +328 -0
  332. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_resource_event_resource_type.py +13 -0
  333. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_resource_event_source.py +8 -0
  334. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_resource_event_subresource.py +107 -0
  335. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_resource_event_subresource_op.py +9 -0
  336. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_resource_event_subresource_type.py +11 -0
  337. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_resource_event_subresources_item.py +106 -0
  338. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_resource_event_subresources_item_op.py +9 -0
  339. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_resource_event_subresources_item_type.py +11 -0
  340. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_resource_game_controller_list_field.py +9 -0
  341. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_resource_module_controller_list_field.py +9 -0
  342. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_resource_module_controller_update_response_200.py +437 -0
  343. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_resource_simulation_controller_list_field.py +10 -0
  344. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_resource_slide_controller_list_field.py +9 -0
  345. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_resource_slide_controller_update_response_200.py +311 -0
  346. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_resource_test_controller_list_field.py +11 -0
  347. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_resource_test_controller_update_response_200.py +441 -0
  348. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_resource_video_controller_list_field.py +9 -0
  349. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_resource_video_narration_controller_narrate_missing_response_200.py +110 -0
  350. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_resource_video_narration_controller_narrate_scene_response_200.py +110 -0
  351. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_resource_video_render_controller_trigger_body.py +62 -0
  352. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_scene_subtitle.py +92 -0
  353. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_simulation.py +390 -0
  354. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_simulation_brief_type_0.py +66 -0
  355. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_simulation_list.py +137 -0
  356. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_simulation_metadata_type_0.py +64 -0
  357. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_slide.py +300 -0
  358. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_slide_list.py +137 -0
  359. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_slide_metadata_type_0.py +64 -0
  360. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_success.py +79 -0
  361. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_test.py +429 -0
  362. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_test_item.py +280 -0
  363. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_test_item_stats.py +92 -0
  364. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_test_list.py +137 -0
  365. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_test_metadata_type_0.py +64 -0
  366. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_test_result.py +250 -0
  367. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_test_result_controller_get_include.py +7 -0
  368. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_test_result_detail.py +274 -0
  369. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_test_result_item.py +116 -0
  370. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_test_result_item_status.py +10 -0
  371. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_test_result_page.py +108 -0
  372. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_test_result_status.py +8 -0
  373. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_test_result_taker_type_0.py +93 -0
  374. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_unenrolled.py +102 -0
  375. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_video.py +431 -0
  376. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_video_list.py +116 -0
  377. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_video_metadata_type_0.py +64 -0
  378. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_video_render_accepted.py +145 -0
  379. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_video_render_cancelled.py +79 -0
  380. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_video_render_event.py +195 -0
  381. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_video_render_event_render_status.py +8 -0
  382. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_video_render_state.py +10 -0
  383. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_video_render_status.py +198 -0
  384. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_video_scene.py +623 -0
  385. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_video_scene_visual_metadata_type_0.py +64 -0
  386. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_visual_adjustments.py +181 -0
  387. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_visual_overlay.py +311 -0
  388. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_visual_overlay_animation.py +105 -0
  389. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_visual_overlay_frame_animation.py +87 -0
  390. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_visual_overlay_frames_item.py +87 -0
  391. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_visual_overlay_metadata_type_0.py +64 -0
  392. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_webhook_created_res_dto.py +344 -0
  393. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_webhook_created_res_dto_disabled_reason_type_1.py +8 -0
  394. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_webhook_created_res_dto_disabled_reason_type_2_type_1.py +8 -0
  395. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_webhook_created_res_dto_disabled_reason_type_3_type_1.py +8 -0
  396. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_webhook_created_res_dto_mode.py +8 -0
  397. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_webhook_deleted.py +91 -0
  398. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_webhook_delivery_res_dto.py +325 -0
  399. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_webhook_delivery_res_dto_payload_type_0.py +66 -0
  400. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_webhook_event_envelope.py +102 -0
  401. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_webhook_ping_event.py +115 -0
  402. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_webhook_res_dto.py +336 -0
  403. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_webhook_res_dto_disabled_reason_type_1.py +8 -0
  404. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_webhook_res_dto_disabled_reason_type_2_type_1.py +8 -0
  405. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_webhook_res_dto_disabled_reason_type_3_type_1.py +8 -0
  406. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_webhook_res_dto_mode.py +8 -0
  407. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_webhook_updated_res_dto.py +351 -0
  408. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_webhook_updated_res_dto_disabled_reason_type_1.py +8 -0
  409. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_webhook_updated_res_dto_disabled_reason_type_2_type_1.py +8 -0
  410. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_webhook_updated_res_dto_disabled_reason_type_3_type_1.py +8 -0
  411. tutorflow_content-0.1.0/tutorflow_content/generated/models/content_webhook_updated_res_dto_mode.py +8 -0
  412. tutorflow_content-0.1.0/tutorflow_content/generated/models/copy_standalone_lesson_to_course_req_dto.py +118 -0
  413. tutorflow_content-0.1.0/tutorflow_content/generated/models/course_celebration_trigger.py +9 -0
  414. tutorflow_content-0.1.0/tutorflow_content/generated/models/course_content_type.py +8 -0
  415. tutorflow_content-0.1.0/tutorflow_content/generated/models/create_classroom_course_req_dto.py +176 -0
  416. tutorflow_content-0.1.0/tutorflow_content/generated/models/create_classroom_game_dto.py +150 -0
  417. tutorflow_content-0.1.0/tutorflow_content/generated/models/create_classroom_game_dto_metadata_type_0.py +67 -0
  418. tutorflow_content-0.1.0/tutorflow_content/generated/models/create_classroom_simulation_dto.py +150 -0
  419. tutorflow_content-0.1.0/tutorflow_content/generated/models/create_classroom_simulation_dto_metadata_type_0.py +67 -0
  420. tutorflow_content-0.1.0/tutorflow_content/generated/models/create_classroom_slide_dto.py +190 -0
  421. tutorflow_content-0.1.0/tutorflow_content/generated/models/create_classroom_slide_dto_metadata_type_0.py +64 -0
  422. tutorflow_content-0.1.0/tutorflow_content/generated/models/create_classroom_test_dto.py +162 -0
  423. tutorflow_content-0.1.0/tutorflow_content/generated/models/create_classroom_video_dto.py +108 -0
  424. tutorflow_content-0.1.0/tutorflow_content/generated/models/create_content_api_key_req_dto.py +207 -0
  425. tutorflow_content-0.1.0/tutorflow_content/generated/models/create_content_api_key_req_dto_mode.py +8 -0
  426. tutorflow_content-0.1.0/tutorflow_content/generated/models/create_content_asset_upload_req_dto.py +121 -0
  427. tutorflow_content-0.1.0/tutorflow_content/generated/models/create_content_asset_upload_req_dto_purpose.py +13 -0
  428. tutorflow_content-0.1.0/tutorflow_content/generated/models/create_content_chapter_req_dto.py +86 -0
  429. tutorflow_content-0.1.0/tutorflow_content/generated/models/create_content_expansion_req_dto.py +155 -0
  430. tutorflow_content-0.1.0/tutorflow_content/generated/models/create_content_expansion_req_dto_payload.py +66 -0
  431. tutorflow_content-0.1.0/tutorflow_content/generated/models/create_content_lesson_req_dto.py +143 -0
  432. tutorflow_content-0.1.0/tutorflow_content/generated/models/create_content_lesson_req_dto_submission.py +70 -0
  433. tutorflow_content-0.1.0/tutorflow_content/generated/models/create_content_module_req_dto.py +281 -0
  434. tutorflow_content-0.1.0/tutorflow_content/generated/models/create_content_module_req_dto_metadata_type_0.py +64 -0
  435. tutorflow_content-0.1.0/tutorflow_content/generated/models/create_content_module_req_dto_type.py +19 -0
  436. tutorflow_content-0.1.0/tutorflow_content/generated/models/create_content_webhook_req_dto.py +132 -0
  437. tutorflow_content-0.1.0/tutorflow_content/generated/models/create_content_webhook_req_dto_mode.py +8 -0
  438. tutorflow_content-0.1.0/tutorflow_content/generated/models/create_update_classroom_test_dto.py +449 -0
  439. tutorflow_content-0.1.0/tutorflow_content/generated/models/create_update_classroom_test_dto_metadata_type_0.py +66 -0
  440. tutorflow_content-0.1.0/tutorflow_content/generated/models/create_update_classroom_test_item_dto.py +248 -0
  441. tutorflow_content-0.1.0/tutorflow_content/generated/models/enroll_content_learners_request.py +91 -0
  442. tutorflow_content-0.1.0/tutorflow_content/generated/models/export_classroom_content_req_dto.py +90 -0
  443. tutorflow_content-0.1.0/tutorflow_content/generated/models/game_visibility.py +8 -0
  444. tutorflow_content-0.1.0/tutorflow_content/generated/models/gamesortfields.py +9 -0
  445. tutorflow_content-0.1.0/tutorflow_content/generated/models/generate_game_brief_dto.py +78 -0
  446. tutorflow_content-0.1.0/tutorflow_content/generated/models/generate_simulation_brief_dto.py +78 -0
  447. tutorflow_content-0.1.0/tutorflow_content/generated/models/invite_content_learner_request.py +148 -0
  448. tutorflow_content-0.1.0/tutorflow_content/generated/models/order.py +8 -0
  449. tutorflow_content-0.1.0/tutorflow_content/generated/models/passing_value_type.py +8 -0
  450. tutorflow_content-0.1.0/tutorflow_content/generated/models/problem_type.py +11 -0
  451. tutorflow_content-0.1.0/tutorflow_content/generated/models/quiz_type.py +10 -0
  452. tutorflow_content-0.1.0/tutorflow_content/generated/models/remotion_template_type.py +13 -0
  453. tutorflow_content-0.1.0/tutorflow_content/generated/models/reorder_content_chapters_req_dto.py +91 -0
  454. tutorflow_content-0.1.0/tutorflow_content/generated/models/reorder_content_lessons_req_dto.py +91 -0
  455. tutorflow_content-0.1.0/tutorflow_content/generated/models/reorder_scenes_dto.py +91 -0
  456. tutorflow_content-0.1.0/tutorflow_content/generated/models/revise_game_dto.py +76 -0
  457. tutorflow_content-0.1.0/tutorflow_content/generated/models/revise_simulation_dto.py +76 -0
  458. tutorflow_content-0.1.0/tutorflow_content/generated/models/rotate_content_api_key_req_dto.py +79 -0
  459. tutorflow_content-0.1.0/tutorflow_content/generated/models/rotate_content_webhook_secret_req_dto.py +88 -0
  460. tutorflow_content-0.1.0/tutorflow_content/generated/models/simulation_visibility.py +8 -0
  461. tutorflow_content-0.1.0/tutorflow_content/generated/models/simulationsortfields.py +10 -0
  462. tutorflow_content-0.1.0/tutorflow_content/generated/models/simulationsubjects.py +13 -0
  463. tutorflow_content-0.1.0/tutorflow_content/generated/models/slide_visibility.py +8 -0
  464. tutorflow_content-0.1.0/tutorflow_content/generated/models/test_layout_type.py +8 -0
  465. tutorflow_content-0.1.0/tutorflow_content/generated/models/test_period_type.py +8 -0
  466. tutorflow_content-0.1.0/tutorflow_content/generated/models/update_classroom_course_settings_dto.py +114 -0
  467. tutorflow_content-0.1.0/tutorflow_content/generated/models/update_classroom_course_settings_dto_ai_tutor_defaults.py +64 -0
  468. tutorflow_content-0.1.0/tutorflow_content/generated/models/update_classroom_game_dto.py +205 -0
  469. tutorflow_content-0.1.0/tutorflow_content/generated/models/update_classroom_game_dto_brief_type_0.py +64 -0
  470. tutorflow_content-0.1.0/tutorflow_content/generated/models/update_classroom_game_dto_metadata_type_0.py +67 -0
  471. tutorflow_content-0.1.0/tutorflow_content/generated/models/update_classroom_simulation_dto.py +196 -0
  472. tutorflow_content-0.1.0/tutorflow_content/generated/models/update_classroom_simulation_dto_brief_type_0.py +64 -0
  473. tutorflow_content-0.1.0/tutorflow_content/generated/models/update_classroom_simulation_dto_metadata_type_0.py +67 -0
  474. tutorflow_content-0.1.0/tutorflow_content/generated/models/update_classroom_slide_dto.py +187 -0
  475. tutorflow_content-0.1.0/tutorflow_content/generated/models/update_classroom_slide_dto_metadata_type_0.py +66 -0
  476. tutorflow_content-0.1.0/tutorflow_content/generated/models/update_classroom_video_dto.py +235 -0
  477. tutorflow_content-0.1.0/tutorflow_content/generated/models/update_classroom_video_dto_metadata_type_0.py +66 -0
  478. tutorflow_content-0.1.0/tutorflow_content/generated/models/update_content_api_key_req_dto.py +217 -0
  479. tutorflow_content-0.1.0/tutorflow_content/generated/models/update_content_chapter_req_dto.py +87 -0
  480. tutorflow_content-0.1.0/tutorflow_content/generated/models/update_content_course_req_dto.py +186 -0
  481. tutorflow_content-0.1.0/tutorflow_content/generated/models/update_content_course_req_dto_visibility.py +11 -0
  482. tutorflow_content-0.1.0/tutorflow_content/generated/models/update_content_lesson_req_dto.py +196 -0
  483. tutorflow_content-0.1.0/tutorflow_content/generated/models/update_content_lesson_req_dto_submission.py +70 -0
  484. tutorflow_content-0.1.0/tutorflow_content/generated/models/update_content_webhook_req_dto.py +150 -0
  485. tutorflow_content-0.1.0/tutorflow_content/generated/models/update_standalone_lesson_dto.py +274 -0
  486. tutorflow_content-0.1.0/tutorflow_content/generated/models/update_standalone_lesson_dto_metadata_type_0.py +64 -0
  487. tutorflow_content-0.1.0/tutorflow_content/generated/models/update_standalone_lesson_dto_type.py +19 -0
  488. tutorflow_content-0.1.0/tutorflow_content/generated/models/update_video_scene_dto.py +758 -0
  489. tutorflow_content-0.1.0/tutorflow_content/generated/models/update_video_scene_dto_transition_out_type_1.py +12 -0
  490. tutorflow_content-0.1.0/tutorflow_content/generated/models/update_video_scene_dto_transition_out_type_2_type_1.py +12 -0
  491. tutorflow_content-0.1.0/tutorflow_content/generated/models/update_video_scene_dto_transition_out_type_3_type_1.py +12 -0
  492. tutorflow_content-0.1.0/tutorflow_content/generated/models/update_video_scene_dto_video_effect_type_1.py +14 -0
  493. tutorflow_content-0.1.0/tutorflow_content/generated/models/update_video_scene_dto_video_effect_type_2_type_1.py +14 -0
  494. tutorflow_content-0.1.0/tutorflow_content/generated/models/update_video_scene_dto_video_effect_type_3_type_1.py +14 -0
  495. tutorflow_content-0.1.0/tutorflow_content/generated/models/update_video_scene_dto_visual_effect_type_1.py +14 -0
  496. tutorflow_content-0.1.0/tutorflow_content/generated/models/update_video_scene_dto_visual_effect_type_2_type_1.py +14 -0
  497. tutorflow_content-0.1.0/tutorflow_content/generated/models/update_video_scene_dto_visual_effect_type_3_type_1.py +14 -0
  498. tutorflow_content-0.1.0/tutorflow_content/generated/models/update_video_scene_dto_visual_fit.py +8 -0
  499. tutorflow_content-0.1.0/tutorflow_content/generated/models/update_video_scene_dto_visual_metadata_type_0.py +64 -0
  500. tutorflow_content-0.1.0/tutorflow_content/generated/models/update_video_scene_dto_visual_source_type_1.py +10 -0
  501. tutorflow_content-0.1.0/tutorflow_content/generated/models/update_video_scene_dto_visual_source_type_2_type_1.py +10 -0
  502. tutorflow_content-0.1.0/tutorflow_content/generated/models/update_video_scene_dto_visual_source_type_3_type_1.py +10 -0
  503. tutorflow_content-0.1.0/tutorflow_content/generated/models/update_video_scene_dto_visual_type_type_1.py +9 -0
  504. tutorflow_content-0.1.0/tutorflow_content/generated/models/update_video_scene_dto_visual_type_type_2_type_1.py +9 -0
  505. tutorflow_content-0.1.0/tutorflow_content/generated/models/update_video_scene_dto_visual_type_type_3_type_1.py +9 -0
  506. tutorflow_content-0.1.0/tutorflow_content/generated/models/video_clip_source.py +8 -0
  507. tutorflow_content-0.1.0/tutorflow_content/generated/models/video_visibility.py +9 -0
  508. tutorflow_content-0.1.0/tutorflow_content/generated/types.py +53 -0
  509. tutorflow_content-0.1.0/tutorflow_content/pagination.py +48 -0
  510. tutorflow_content-0.1.0/tutorflow_content/retry.py +129 -0
  511. tutorflow_content-0.1.0/tutorflow_content/runs.py +140 -0
  512. tutorflow_content-0.1.0/tutorflow_content/webhooks.py +97 -0
  513. tutorflow_content-0.1.0/tutorflow_content.egg-info/PKG-INFO +151 -0
  514. tutorflow_content-0.1.0/tutorflow_content.egg-info/SOURCES.txt +515 -0
  515. tutorflow_content-0.1.0/tutorflow_content.egg-info/dependency_links.txt +1 -0
  516. tutorflow_content-0.1.0/tutorflow_content.egg-info/requires.txt +7 -0
  517. tutorflow_content-0.1.0/tutorflow_content.egg-info/top_level.txt +1 -0
@@ -0,0 +1,151 @@
1
+ Metadata-Version: 2.4
2
+ Name: tutorflow-content
3
+ Version: 0.1.0
4
+ Summary: Python client for the TutorFlow Content API: generated routes and models, retries, pagination, run polling and webhook verification.
5
+ License: Proprietary
6
+ Project-URL: Homepage, https://tutorflow.io/resources/integrations/content-api-sdks
7
+ Project-URL: Documentation, https://tutorflow.io/resources/integrations/content-api-sdks
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: Programming Language :: Python :: 3 :: Only
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: Topic :: Software Development :: Libraries
12
+ Classifier: Typing :: Typed
13
+ Requires-Python: >=3.11
14
+ Description-Content-Type: text/markdown
15
+ Requires-Dist: httpx<1,>=0.27
16
+ Requires-Dist: attrs>=22.2
17
+ Requires-Dist: python-dateutil>=2.8
18
+ Provides-Extra: dev
19
+ Requires-Dist: pytest>=8; extra == "dev"
20
+ Requires-Dist: openapi-python-client==0.29.1; extra == "dev"
21
+
22
+ # tutorflow-content
23
+
24
+ A Python client for the TutorFlow Content API (`/v1/content`). Routes and models are generated from the published OpenAPI document with [openapi-python-client](https://github.com/openapi-generators/openapi-python-client), and the package adds what an integration otherwise writes by hand: retries, pagination, waiting for runs, typed errors, and webhook verification. It is built on httpx.
25
+
26
+ ## Install
27
+
28
+ Requires Python 3.11 or later.
29
+
30
+ ```bash
31
+ pip install tutorflow-content
32
+ ```
33
+
34
+ Documentation is at [tutorflow.io/resources/integrations/content-api-sdks](https://tutorflow.io/resources/integrations/content-api-sdks).
35
+
36
+ ## Create a client
37
+
38
+ Keep the key on your server.
39
+
40
+ ```python
41
+ import os
42
+
43
+ from tutorflow_content import create_client, unwrap
44
+ from tutorflow_content.generated.api.content_classrooms import (
45
+ content_integration_classroom_controller_list_classrooms as list_classrooms,
46
+ )
47
+
48
+ client = create_client(os.environ["TUTORFLOW_CONTENT_API_KEY"])
49
+
50
+ for classroom in unwrap(list_classrooms.sync_detailed(client=client)):
51
+ print(classroom.id, classroom.name, classroom.is_sandbox)
52
+ ```
53
+
54
+ Every route is a module under `tutorflow_content.generated.api.<tag>` with `sync`, `sync_detailed`, `asyncio` and `asyncio_detailed`. `unwrap()` takes a `*_detailed` response and returns the parsed model, or raises `ContentApiError` with `code`, `status`, `request_id`, `retry_after_seconds`, `current_etag` and `details` from the error envelope. A 412 raises its subclass `ContentPreconditionFailedError`.
55
+
56
+ A test key (`tf_content_test_...`) works the same way against the sandbox classroom; `is_test_key(api_key)` tells them apart.
57
+
58
+ ## Retries and idempotency
59
+
60
+ `create_client()` installs `RetryTransport` (and `AsyncRetryTransport` for the async calls):
61
+
62
+ - `429`: always retried, after `Retry-After` (up to 60 seconds; a longer wait comes back to you as the 429).
63
+ - `500`, `502`, `503`, `504` and connection failures: retried only for `GET`, `PUT`, `DELETE` and requests that carry an `Idempotency-Key`, so a change is never applied twice.
64
+
65
+ Backoff starts at 0.5 s and doubles with jitter, two retries by default. Tune it with `create_client(key, retry=RetryConfig(max_retries=4))` or turn it off with `retry=None`.
66
+
67
+ Routes that accept an `Idempotency-Key` take it as the `idempotency_key=` argument. Every retry sends the same key, and the API replays the first answer:
68
+
69
+ ```python
70
+ from tutorflow_content import new_idempotency_key
71
+ from tutorflow_content.generated.api.content_generation import content_generation_controller_generate_course as generate_course
72
+ from tutorflow_content.generated.models import ContentGenerateCourseRequest
73
+
74
+ accepted = unwrap(
75
+ generate_course.sync_detailed(
76
+ classroom_id,
77
+ client=client,
78
+ body=ContentGenerateCourseRequest(topic="Fractions for Grade 5", lesson_count=6, language="en"),
79
+ idempotency_key=new_idempotency_key(),
80
+ )
81
+ )
82
+ ```
83
+
84
+ ## Pagination
85
+
86
+ `paginate()` yields every item of a list and reads both envelopes: page-numbered lists get the next `page=`, cursor lists get `cursor=` from `meta.nextCursor`. Pass a function that takes those keyword arguments:
87
+
88
+ ```python
89
+ from tutorflow_content import paginate
90
+ from tutorflow_content.generated.api.content_courses import content_resource_course_controller_list as list_courses
91
+
92
+ for course in paginate(lambda **next: list_courses.sync_detailed(classroom_id, client=client, limit=100, **next)):
93
+ print(course.id, course.title)
94
+ ```
95
+
96
+ ## Waiting for runs
97
+
98
+ These poll until the run settles and return its final status. They do not raise when the run failed; check the status.
99
+
100
+ ```python
101
+ from tutorflow_content import wait_for_build, wait_for_render, wait_for_run
102
+
103
+ run = wait_for_run(client, classroom_id=classroom_id, run_id=accepted.run_id) # tests, modules, courses, slides
104
+ if str(run.status) == "failed":
105
+ raise RuntimeError(run.error)
106
+
107
+ build = wait_for_build(client, kind="game", classroom_id=classroom_id, resource_id=game_id, run_id=run_id)
108
+ render = wait_for_render(client, classroom_id=classroom_id, video_id=video_id)
109
+ ```
110
+
111
+ Options: `interval` (default 3 s), `timeout` (default 30 minutes), `on_poll`. The build status route only knows runs of the server that answers since its last deploy; a run it no longer tracks raises `ContentWaitError` with `reason == "run_not_tracked"`, and the run's webhook is the signal to rely on.
112
+
113
+ ## Webhooks
114
+
115
+ `verify_webhook()` checks the `X-Content-Integration-Signature-V2` header against the raw body and returns the event as a dict, with `livemode` always present:
116
+
117
+ ```python
118
+ from flask import Flask, abort, request
119
+
120
+ from tutorflow_content import WebhookVerificationError, verify_webhook
121
+
122
+ app = Flask(__name__)
123
+ SECRETS = [s for s in (os.environ.get("TUTORFLOW_WEBHOOK_SECRET"), os.environ.get("TUTORFLOW_WEBHOOK_SECRET_PREVIOUS")) if s]
124
+
125
+
126
+ @app.post("/tutorflow/webhooks")
127
+ def tutorflow_webhook():
128
+ try:
129
+ event = verify_webhook(request.get_data(), request.headers.get("X-Content-Integration-Signature-V2"), SECRETS)
130
+ except WebhookVerificationError as error:
131
+ abort(400, error.reason)
132
+
133
+ if event["event"]["type"] == "course.generation.completed" and event["livemode"]:
134
+ queue_course_import(event["event"]["id"], event["resourceId"])
135
+ return "", 204
136
+ ```
137
+
138
+ It accepts the request when `t` is within `tolerance_seconds` (default 300) of now and any `v1=` signature matches any secret you pass. During TutorFlow's secret rotation grace period the header carries a signature for the new and the previous secret. Deliveries are signed again on every retry.
139
+
140
+ ## Development
141
+
142
+ ```bash
143
+ cd sdks/python
144
+ python -m venv .venv && . .venv/bin/activate
145
+ pip install -e ".[dev]"
146
+ pytest # httpx.MockTransport, no network
147
+ python scripts/generate.py # rewrite tutorflow_content/generated
148
+ python scripts/generate.py --check # exit 1 when it is stale against openapi.json
149
+ ```
150
+
151
+ `tutorflow_content/generated` comes from `apps/frontend-admin/public/resources/integrations/openapi.json`, which the backend writes (`pnpm run openapi:content -- <path>` in tutorflow-backend). Regenerate after that file changes and commit both. Do not edit the generated code by hand.
@@ -0,0 +1,130 @@
1
+ # tutorflow-content
2
+
3
+ A Python client for the TutorFlow Content API (`/v1/content`). Routes and models are generated from the published OpenAPI document with [openapi-python-client](https://github.com/openapi-generators/openapi-python-client), and the package adds what an integration otherwise writes by hand: retries, pagination, waiting for runs, typed errors, and webhook verification. It is built on httpx.
4
+
5
+ ## Install
6
+
7
+ Requires Python 3.11 or later.
8
+
9
+ ```bash
10
+ pip install tutorflow-content
11
+ ```
12
+
13
+ Documentation is at [tutorflow.io/resources/integrations/content-api-sdks](https://tutorflow.io/resources/integrations/content-api-sdks).
14
+
15
+ ## Create a client
16
+
17
+ Keep the key on your server.
18
+
19
+ ```python
20
+ import os
21
+
22
+ from tutorflow_content import create_client, unwrap
23
+ from tutorflow_content.generated.api.content_classrooms import (
24
+ content_integration_classroom_controller_list_classrooms as list_classrooms,
25
+ )
26
+
27
+ client = create_client(os.environ["TUTORFLOW_CONTENT_API_KEY"])
28
+
29
+ for classroom in unwrap(list_classrooms.sync_detailed(client=client)):
30
+ print(classroom.id, classroom.name, classroom.is_sandbox)
31
+ ```
32
+
33
+ Every route is a module under `tutorflow_content.generated.api.<tag>` with `sync`, `sync_detailed`, `asyncio` and `asyncio_detailed`. `unwrap()` takes a `*_detailed` response and returns the parsed model, or raises `ContentApiError` with `code`, `status`, `request_id`, `retry_after_seconds`, `current_etag` and `details` from the error envelope. A 412 raises its subclass `ContentPreconditionFailedError`.
34
+
35
+ A test key (`tf_content_test_...`) works the same way against the sandbox classroom; `is_test_key(api_key)` tells them apart.
36
+
37
+ ## Retries and idempotency
38
+
39
+ `create_client()` installs `RetryTransport` (and `AsyncRetryTransport` for the async calls):
40
+
41
+ - `429`: always retried, after `Retry-After` (up to 60 seconds; a longer wait comes back to you as the 429).
42
+ - `500`, `502`, `503`, `504` and connection failures: retried only for `GET`, `PUT`, `DELETE` and requests that carry an `Idempotency-Key`, so a change is never applied twice.
43
+
44
+ Backoff starts at 0.5 s and doubles with jitter, two retries by default. Tune it with `create_client(key, retry=RetryConfig(max_retries=4))` or turn it off with `retry=None`.
45
+
46
+ Routes that accept an `Idempotency-Key` take it as the `idempotency_key=` argument. Every retry sends the same key, and the API replays the first answer:
47
+
48
+ ```python
49
+ from tutorflow_content import new_idempotency_key
50
+ from tutorflow_content.generated.api.content_generation import content_generation_controller_generate_course as generate_course
51
+ from tutorflow_content.generated.models import ContentGenerateCourseRequest
52
+
53
+ accepted = unwrap(
54
+ generate_course.sync_detailed(
55
+ classroom_id,
56
+ client=client,
57
+ body=ContentGenerateCourseRequest(topic="Fractions for Grade 5", lesson_count=6, language="en"),
58
+ idempotency_key=new_idempotency_key(),
59
+ )
60
+ )
61
+ ```
62
+
63
+ ## Pagination
64
+
65
+ `paginate()` yields every item of a list and reads both envelopes: page-numbered lists get the next `page=`, cursor lists get `cursor=` from `meta.nextCursor`. Pass a function that takes those keyword arguments:
66
+
67
+ ```python
68
+ from tutorflow_content import paginate
69
+ from tutorflow_content.generated.api.content_courses import content_resource_course_controller_list as list_courses
70
+
71
+ for course in paginate(lambda **next: list_courses.sync_detailed(classroom_id, client=client, limit=100, **next)):
72
+ print(course.id, course.title)
73
+ ```
74
+
75
+ ## Waiting for runs
76
+
77
+ These poll until the run settles and return its final status. They do not raise when the run failed; check the status.
78
+
79
+ ```python
80
+ from tutorflow_content import wait_for_build, wait_for_render, wait_for_run
81
+
82
+ run = wait_for_run(client, classroom_id=classroom_id, run_id=accepted.run_id) # tests, modules, courses, slides
83
+ if str(run.status) == "failed":
84
+ raise RuntimeError(run.error)
85
+
86
+ build = wait_for_build(client, kind="game", classroom_id=classroom_id, resource_id=game_id, run_id=run_id)
87
+ render = wait_for_render(client, classroom_id=classroom_id, video_id=video_id)
88
+ ```
89
+
90
+ Options: `interval` (default 3 s), `timeout` (default 30 minutes), `on_poll`. The build status route only knows runs of the server that answers since its last deploy; a run it no longer tracks raises `ContentWaitError` with `reason == "run_not_tracked"`, and the run's webhook is the signal to rely on.
91
+
92
+ ## Webhooks
93
+
94
+ `verify_webhook()` checks the `X-Content-Integration-Signature-V2` header against the raw body and returns the event as a dict, with `livemode` always present:
95
+
96
+ ```python
97
+ from flask import Flask, abort, request
98
+
99
+ from tutorflow_content import WebhookVerificationError, verify_webhook
100
+
101
+ app = Flask(__name__)
102
+ SECRETS = [s for s in (os.environ.get("TUTORFLOW_WEBHOOK_SECRET"), os.environ.get("TUTORFLOW_WEBHOOK_SECRET_PREVIOUS")) if s]
103
+
104
+
105
+ @app.post("/tutorflow/webhooks")
106
+ def tutorflow_webhook():
107
+ try:
108
+ event = verify_webhook(request.get_data(), request.headers.get("X-Content-Integration-Signature-V2"), SECRETS)
109
+ except WebhookVerificationError as error:
110
+ abort(400, error.reason)
111
+
112
+ if event["event"]["type"] == "course.generation.completed" and event["livemode"]:
113
+ queue_course_import(event["event"]["id"], event["resourceId"])
114
+ return "", 204
115
+ ```
116
+
117
+ It accepts the request when `t` is within `tolerance_seconds` (default 300) of now and any `v1=` signature matches any secret you pass. During TutorFlow's secret rotation grace period the header carries a signature for the new and the previous secret. Deliveries are signed again on every retry.
118
+
119
+ ## Development
120
+
121
+ ```bash
122
+ cd sdks/python
123
+ python -m venv .venv && . .venv/bin/activate
124
+ pip install -e ".[dev]"
125
+ pytest # httpx.MockTransport, no network
126
+ python scripts/generate.py # rewrite tutorflow_content/generated
127
+ python scripts/generate.py --check # exit 1 when it is stale against openapi.json
128
+ ```
129
+
130
+ `tutorflow_content/generated` comes from `apps/frontend-admin/public/resources/integrations/openapi.json`, which the backend writes (`pnpm run openapi:content -- <path>` in tutorflow-backend). Regenerate after that file changes and commit both. Do not edit the generated code by hand.
@@ -0,0 +1,39 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "tutorflow-content"
7
+ version = "0.1.0"
8
+ description = "Python client for the TutorFlow Content API: generated routes and models, retries, pagination, run polling and webhook verification."
9
+ readme = "README.md"
10
+ requires-python = ">=3.11"
11
+ license = { text = "Proprietary" }
12
+ classifiers = [
13
+ "Programming Language :: Python :: 3",
14
+ "Programming Language :: Python :: 3 :: Only",
15
+ "Intended Audience :: Developers",
16
+ "Topic :: Software Development :: Libraries",
17
+ "Typing :: Typed",
18
+ ]
19
+ dependencies = [
20
+ "httpx>=0.27,<1",
21
+ "attrs>=22.2",
22
+ "python-dateutil>=2.8",
23
+ ]
24
+
25
+ [project.urls]
26
+ Homepage = "https://tutorflow.io/resources/integrations/content-api-sdks"
27
+ Documentation = "https://tutorflow.io/resources/integrations/content-api-sdks"
28
+
29
+ [project.optional-dependencies]
30
+ dev = [
31
+ "pytest>=8",
32
+ "openapi-python-client==0.29.1",
33
+ ]
34
+
35
+ [tool.setuptools.packages.find]
36
+ include = ["tutorflow_content*"]
37
+
38
+ [tool.pytest.ini_options]
39
+ testpaths = ["tests"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,56 @@
1
+ from __future__ import annotations
2
+
3
+ import pytest
4
+
5
+ from tutorflow_content import ContentApiError, ContentPreconditionFailedError, error_from_response
6
+
7
+ from .conftest import error_response, json_response
8
+
9
+
10
+ def test_reads_every_field_of_the_error_envelope():
11
+ # Arrange
12
+ response = error_response(429, "content_rate_limit_exceeded", {"retryAfterSeconds": 30}, {"Retry-After": "30"})
13
+
14
+ # Act
15
+ error = error_from_response(response)
16
+
17
+ # Assert
18
+ assert isinstance(error, ContentApiError)
19
+ assert (error.code, error.status, error.request_id, error.retry_after_seconds) == ("content_rate_limit_exceeded", 429, "req-err", 30.0)
20
+ assert str(error) == "content_rate_limit_exceeded happened"
21
+
22
+
23
+ def test_a_412_is_a_precondition_failure_with_the_current_etag():
24
+ # Act
25
+ error = error_from_response(error_response(412, "content_precondition_failed", {"currentETag": '"v13"'}))
26
+
27
+ # Assert
28
+ assert isinstance(error, ContentPreconditionFailedError)
29
+ assert error.current_etag == '"v13"'
30
+
31
+
32
+ def test_falls_back_to_status_and_headers_without_an_envelope():
33
+ # Arrange
34
+ response = json_response(502, "<html>Bad gateway</html>", {"Request-Id": "edge-9"})
35
+
36
+ # Act
37
+ error = error_from_response(response)
38
+
39
+ # Assert
40
+ assert (error.code, error.status, error.request_id) == ("content_http_error", 502, "edge-9")
41
+
42
+
43
+ def test_unwrap_raises_for_a_generated_error_response():
44
+ # Arrange
45
+ from tutorflow_content import unwrap
46
+
47
+ class Detailed:
48
+ status_code = 404
49
+ content = b'{"error":{"code":"content_not_found","message":"Not found","status":404,"requestId":"r"}}'
50
+ headers = {}
51
+ parsed = None
52
+
53
+ # Act and Assert
54
+ with pytest.raises(ContentApiError) as raised:
55
+ unwrap(Detailed())
56
+ assert raised.value.code == "content_not_found"
@@ -0,0 +1,102 @@
1
+ from __future__ import annotations
2
+
3
+ from urllib.parse import parse_qs
4
+
5
+ from tutorflow_content import create_client, paginate
6
+ from tutorflow_content.generated.api.content_courses import content_resource_course_controller_list as list_courses
7
+ from tutorflow_content.generated.api.content_generation import content_generation_controller_list_runs as list_runs
8
+
9
+ from .conftest import API_KEY, BASE_URL, CLASSROOM_ID, ScriptedTransport, json_response
10
+
11
+ COURSE = {
12
+ "classroomId": CLASSROOM_ID,
13
+ "title": "Fractions",
14
+ "description": None,
15
+ "thumbnail": None,
16
+ "slug": "fractions",
17
+ "level": None,
18
+ "visibility": "PRIVATE",
19
+ "createdAt": "2026-09-01T09:00:00.000Z",
20
+ "updatedAt": "2026-09-02T14:30:00.000Z",
21
+ }
22
+
23
+
24
+ def numbered_page(page: int, ids: list[str], has_next: bool) -> dict:
25
+ data = [{**COURSE, "id": course_id} for course_id in ids]
26
+ meta = {"page": page, "take": 2, "itemCount": 3, "pageCount": 2, "hasPreviousPage": page > 1, "hasNextPage": has_next}
27
+ return {"data": data, "meta": meta, "items": data, "totalCount": 3}
28
+
29
+
30
+ def run(run_id: str) -> dict:
31
+ return {
32
+ "runId": run_id,
33
+ "kind": "course",
34
+ "classroomId": CLASSROOM_ID,
35
+ "status": "completed",
36
+ "stage": None,
37
+ "progress": {"completed": 1, "total": 1, "unit": "lesson"},
38
+ "resourceId": None,
39
+ "creditsCharged": 3,
40
+ "estimatedCredits": 3,
41
+ "error": None,
42
+ "resumedFromRunId": None,
43
+ "createdAt": "2026-09-01T09:00:00.000Z",
44
+ "finishedAt": None,
45
+ }
46
+
47
+
48
+ def query(request) -> dict:
49
+ return {key: values[0] for key, values in parse_qs(request.url.query.decode()).items()}
50
+
51
+
52
+ def test_walks_a_page_numbered_list_with_the_next_page_number():
53
+ # Arrange
54
+ ids = ["3f6c2a1e-7b4d-4c8e-9a10-00000000000" + str(index) for index in range(1, 4)]
55
+ scripted = ScriptedTransport(
56
+ [json_response(200, numbered_page(1, ids[:2], True)), json_response(200, numbered_page(2, ids[2:], False))]
57
+ )
58
+ client = create_client(API_KEY, base_url=BASE_URL, transport=scripted.transport)
59
+
60
+ # Act
61
+ courses = list(
62
+ paginate(lambda **next: list_courses.sync_detailed(CLASSROOM_ID, client=client, limit=2, **next))
63
+ )
64
+
65
+ # Assert
66
+ assert [str(course.id) for course in courses] == ids
67
+ assert [query(request).get("page") for request in scripted.requests] == ["1", "2"]
68
+
69
+
70
+ def test_walks_a_cursor_list_by_sending_next_cursor_back():
71
+ # Arrange
72
+ first = {"data": [run("3f6c2a1e-7b4d-4c8e-9a10-000000000001")], "meta": {"limit": 1, "hasNextPage": True, "nextCursor": "opaque-1"}}
73
+ last = {"data": [run("3f6c2a1e-7b4d-4c8e-9a10-000000000002")], "meta": {"limit": 1, "hasNextPage": False, "nextCursor": None}}
74
+ scripted = ScriptedTransport([json_response(200, first), json_response(200, last)])
75
+ client = create_client(API_KEY, base_url=BASE_URL, transport=scripted.transport)
76
+
77
+ # Act
78
+ runs = list(paginate(lambda **next: list_runs.sync_detailed(CLASSROOM_ID, client=client, limit=1, **next)))
79
+
80
+ # Assert
81
+ assert len(runs) == 2
82
+ assert "cursor" not in query(scripted.requests[0])
83
+ assert query(scripted.requests[1])["cursor"] == "opaque-1"
84
+
85
+
86
+ def test_reads_plain_dict_pages_too():
87
+ # Arrange
88
+ pages = iter([{"data": [1, 2], "meta": {"hasNextPage": True, "nextCursor": "c"}}, {"data": [3], "meta": {"hasNextPage": False, "nextCursor": None}}])
89
+ seen: list[dict] = []
90
+
91
+ def fetch(**next):
92
+ seen.append(next)
93
+ return next_page()
94
+
95
+ next_page = lambda: next(pages) # noqa: E731
96
+
97
+ # Act
98
+ items = list(paginate(fetch))
99
+
100
+ # Assert
101
+ assert items == [1, 2, 3]
102
+ assert seen == [{}, {"cursor": "c"}]
@@ -0,0 +1,110 @@
1
+ from __future__ import annotations
2
+
3
+ import httpx
4
+ import pytest
5
+
6
+ from tutorflow_content import RetryConfig, RetryTransport, create_client, new_idempotency_key, unwrap
7
+ from tutorflow_content.generated.api.content_classrooms import content_integration_classroom_controller_list_classrooms as list_classrooms
8
+
9
+ from .conftest import API_KEY, BASE_URL, ScriptedTransport, error_response, json_response
10
+
11
+
12
+ def client_with(scripted: ScriptedTransport, sleep, **config):
13
+ transport = RetryTransport(scripted.transport, RetryConfig(random=lambda: 0.5, **config), sleep=sleep)
14
+ return httpx.Client(base_url=BASE_URL, transport=transport)
15
+
16
+
17
+ def test_waits_out_retry_after_on_429_and_sends_again(sleep):
18
+ # Arrange
19
+ scripted = ScriptedTransport([error_response(429, "content_rate_limit_exceeded", headers={"Retry-After": "2"}), json_response(200, [])])
20
+ client = client_with(scripted, sleep)
21
+
22
+ # Act
23
+ response = client.get("/v1/content/classrooms")
24
+
25
+ # Assert
26
+ assert response.status_code == 200
27
+ assert sleep.delays == [2.0]
28
+ assert len(scripted.requests) == 2
29
+
30
+
31
+ def test_reuses_the_idempotency_key_and_body_after_a_503(sleep):
32
+ # Arrange
33
+ scripted = ScriptedTransport([error_response(503, "content_internal_error"), json_response(202, {"runId": "r1"})])
34
+ client = client_with(scripted, sleep)
35
+
36
+ # Act
37
+ response = client.post("/v1/content/x", json={"topic": "Fractions"}, headers={"Idempotency-Key": "key-1"})
38
+
39
+ # Assert
40
+ assert response.status_code == 202
41
+ assert [request.headers["Idempotency-Key"] for request in scripted.requests] == ["key-1", "key-1"]
42
+ assert scripted.requests[1].content == b'{"topic":"Fractions"}'
43
+ assert sleep.delays == [0.25]
44
+
45
+
46
+ def test_does_not_repeat_a_post_without_a_key_after_a_500(sleep):
47
+ # Arrange
48
+ scripted = ScriptedTransport([error_response(500, "content_internal_error")])
49
+ client = client_with(scripted, sleep)
50
+
51
+ # Act
52
+ response = client.post("/v1/content/x", json={})
53
+
54
+ # Assert
55
+ assert response.status_code == 500
56
+ assert len(scripted.requests) == 1
57
+
58
+
59
+ def test_retries_a_get_after_a_network_failure_then_gives_up(sleep):
60
+ # Arrange
61
+ failure = httpx.ConnectError("refused")
62
+ scripted = ScriptedTransport([failure, failure, failure])
63
+ client = client_with(scripted, sleep, max_retries=2)
64
+
65
+ # Act and Assert
66
+ with pytest.raises(httpx.ConnectError):
67
+ client.get("/v1/content/classrooms")
68
+ assert len(scripted.requests) == 3
69
+
70
+
71
+ def test_hands_back_a_429_that_asks_for_too_long_a_wait(sleep):
72
+ # Arrange
73
+ scripted = ScriptedTransport([error_response(429, "content_rate_limit_exceeded", headers={"Retry-After": "120"})])
74
+ client = client_with(scripted, sleep)
75
+
76
+ # Act
77
+ response = client.get("/v1/content/classrooms")
78
+
79
+ # Assert
80
+ assert response.status_code == 429
81
+ assert sleep.delays == []
82
+
83
+
84
+ def test_create_client_sends_the_bearer_key_through_the_generated_calls():
85
+ # Arrange
86
+ scripted = ScriptedTransport([json_response(200, [{"id": "3f6c2a1e-7b4d-4c8e-9a10-0000000c0001", "name": "Grade 5 maths", "slug": "grade-5-maths", "locale": "en", "isSandbox": True}])])
87
+ client = create_client(API_KEY, base_url=f"{BASE_URL}/", transport=scripted.transport, retry=None)
88
+
89
+ # Act
90
+ classrooms = unwrap(list_classrooms.sync_detailed(client=client))
91
+
92
+ # Assert
93
+ assert classrooms[0].name == "Grade 5 maths"
94
+ assert scripted.requests[0].headers["Authorization"] == f"Bearer {API_KEY}"
95
+ assert str(scripted.requests[0].url) == f"{BASE_URL}/v1/content/classrooms"
96
+
97
+
98
+ def test_create_client_refuses_a_value_that_is_not_a_content_api_key():
99
+ # Act and Assert
100
+ with pytest.raises(ValueError):
101
+ create_client("sk_live_wrong")
102
+
103
+
104
+ def test_new_idempotency_key_is_a_fresh_uuid():
105
+ # Act
106
+ first, second = new_idempotency_key(), new_idempotency_key()
107
+
108
+ # Assert
109
+ assert first != second
110
+ assert len(first) == 36