magic_hour 0.9.5__py3-none-any.whl → 0.44.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (264) hide show
  1. magic_hour/README.md +34 -0
  2. magic_hour/__init__.py +1 -1
  3. magic_hour/client.py +8 -17
  4. magic_hour/environment.py +13 -1
  5. magic_hour/helpers/__init__.py +4 -0
  6. magic_hour/helpers/download.py +77 -0
  7. magic_hour/helpers/logger.py +8 -0
  8. magic_hour/resources/v1/README.md +32 -0
  9. magic_hour/resources/v1/ai_clothes_changer/README.md +94 -5
  10. magic_hour/resources/v1/ai_clothes_changer/client.py +161 -16
  11. magic_hour/resources/v1/ai_face_editor/README.md +195 -0
  12. magic_hour/resources/v1/ai_face_editor/__init__.py +4 -0
  13. magic_hour/resources/v1/ai_face_editor/client.py +324 -0
  14. magic_hour/resources/v1/ai_gif_generator/README.md +116 -0
  15. magic_hour/resources/v1/ai_gif_generator/__init__.py +4 -0
  16. magic_hour/resources/v1/ai_gif_generator/client.py +257 -0
  17. magic_hour/resources/v1/ai_headshot_generator/README.md +81 -3
  18. magic_hour/resources/v1/ai_headshot_generator/client.py +167 -18
  19. magic_hour/resources/v1/ai_image_editor/README.md +125 -0
  20. magic_hour/resources/v1/ai_image_editor/__init__.py +4 -0
  21. magic_hour/resources/v1/ai_image_editor/client.py +290 -0
  22. magic_hour/resources/v1/ai_image_generator/README.md +99 -5
  23. magic_hour/resources/v1/ai_image_generator/client.py +170 -24
  24. magic_hour/resources/v1/ai_image_upscaler/README.md +89 -3
  25. magic_hour/resources/v1/ai_image_upscaler/client.py +173 -20
  26. magic_hour/resources/v1/ai_meme_generator/README.md +129 -0
  27. magic_hour/resources/v1/ai_meme_generator/__init__.py +4 -0
  28. magic_hour/resources/v1/ai_meme_generator/client.py +253 -0
  29. magic_hour/resources/v1/ai_photo_editor/README.md +119 -4
  30. magic_hour/resources/v1/ai_photo_editor/client.py +199 -18
  31. magic_hour/resources/v1/ai_qr_code_generator/README.md +84 -3
  32. magic_hour/resources/v1/ai_qr_code_generator/client.py +140 -18
  33. magic_hour/resources/v1/ai_talking_photo/README.md +137 -0
  34. magic_hour/resources/v1/ai_talking_photo/__init__.py +4 -0
  35. magic_hour/resources/v1/ai_talking_photo/client.py +326 -0
  36. magic_hour/resources/v1/ai_voice_cloner/README.md +62 -0
  37. magic_hour/resources/v1/ai_voice_cloner/__init__.py +4 -0
  38. magic_hour/resources/v1/ai_voice_cloner/client.py +272 -0
  39. magic_hour/resources/v1/ai_voice_generator/README.md +112 -0
  40. magic_hour/resources/v1/ai_voice_generator/__init__.py +4 -0
  41. magic_hour/resources/v1/ai_voice_generator/client.py +241 -0
  42. magic_hour/resources/v1/animation/README.md +128 -6
  43. magic_hour/resources/v1/animation/client.py +247 -22
  44. magic_hour/resources/v1/audio_projects/README.md +135 -0
  45. magic_hour/resources/v1/audio_projects/__init__.py +12 -0
  46. magic_hour/resources/v1/audio_projects/client.py +310 -0
  47. magic_hour/resources/v1/audio_projects/client_test.py +520 -0
  48. magic_hour/resources/v1/auto_subtitle_generator/README.md +128 -0
  49. magic_hour/resources/v1/auto_subtitle_generator/__init__.py +4 -0
  50. magic_hour/resources/v1/auto_subtitle_generator/client.py +346 -0
  51. magic_hour/resources/v1/client.py +75 -1
  52. magic_hour/resources/v1/face_detection/README.md +157 -0
  53. magic_hour/resources/v1/face_detection/__init__.py +12 -0
  54. magic_hour/resources/v1/face_detection/client.py +380 -0
  55. magic_hour/resources/v1/face_swap/README.md +137 -9
  56. magic_hour/resources/v1/face_swap/client.py +329 -38
  57. magic_hour/resources/v1/face_swap_photo/README.md +118 -3
  58. magic_hour/resources/v1/face_swap_photo/client.py +199 -14
  59. magic_hour/resources/v1/files/README.md +39 -0
  60. magic_hour/resources/v1/files/client.py +351 -1
  61. magic_hour/resources/v1/files/client_test.py +414 -0
  62. magic_hour/resources/v1/files/upload_urls/README.md +38 -17
  63. magic_hour/resources/v1/files/upload_urls/client.py +38 -34
  64. magic_hour/resources/v1/image_background_remover/README.md +96 -5
  65. magic_hour/resources/v1/image_background_remover/client.py +151 -16
  66. magic_hour/resources/v1/image_projects/README.md +82 -10
  67. magic_hour/resources/v1/image_projects/__init__.py +10 -2
  68. magic_hour/resources/v1/image_projects/client.py +154 -16
  69. magic_hour/resources/v1/image_projects/client_test.py +527 -0
  70. magic_hour/resources/v1/image_to_video/README.md +96 -11
  71. magic_hour/resources/v1/image_to_video/client.py +282 -38
  72. magic_hour/resources/v1/lip_sync/README.md +112 -9
  73. magic_hour/resources/v1/lip_sync/client.py +288 -34
  74. magic_hour/resources/v1/photo_colorizer/README.md +107 -0
  75. magic_hour/resources/v1/photo_colorizer/__init__.py +4 -0
  76. magic_hour/resources/v1/photo_colorizer/client.py +248 -0
  77. magic_hour/resources/v1/text_to_video/README.md +96 -7
  78. magic_hour/resources/v1/text_to_video/client.py +204 -18
  79. magic_hour/resources/v1/video_projects/README.md +81 -9
  80. magic_hour/resources/v1/video_projects/__init__.py +10 -2
  81. magic_hour/resources/v1/video_projects/client.py +151 -14
  82. magic_hour/resources/v1/video_projects/client_test.py +527 -0
  83. magic_hour/resources/v1/video_to_video/README.md +119 -15
  84. magic_hour/resources/v1/video_to_video/client.py +299 -46
  85. magic_hour/types/models/__init__.py +92 -56
  86. magic_hour/types/models/v1_ai_clothes_changer_create_response.py +33 -0
  87. magic_hour/types/models/v1_ai_face_editor_create_response.py +33 -0
  88. magic_hour/types/models/v1_ai_gif_generator_create_response.py +33 -0
  89. magic_hour/types/models/v1_ai_headshot_generator_create_response.py +33 -0
  90. magic_hour/types/models/v1_ai_image_editor_create_response.py +33 -0
  91. magic_hour/types/models/v1_ai_image_generator_create_response.py +33 -0
  92. magic_hour/types/models/v1_ai_image_upscaler_create_response.py +33 -0
  93. magic_hour/types/models/v1_ai_meme_generator_create_response.py +33 -0
  94. magic_hour/types/models/v1_ai_photo_editor_create_response.py +33 -0
  95. magic_hour/types/models/v1_ai_qr_code_generator_create_response.py +33 -0
  96. magic_hour/types/models/v1_ai_talking_photo_create_response.py +35 -0
  97. magic_hour/types/models/v1_ai_voice_cloner_create_response.py +27 -0
  98. magic_hour/types/models/v1_ai_voice_generator_create_response.py +27 -0
  99. magic_hour/types/models/v1_animation_create_response.py +35 -0
  100. magic_hour/types/models/v1_audio_projects_get_response.py +72 -0
  101. magic_hour/types/models/v1_audio_projects_get_response_downloads_item.py +19 -0
  102. magic_hour/types/models/{get_v1_image_projects_id_response_error.py → v1_audio_projects_get_response_error.py} +2 -2
  103. magic_hour/types/models/v1_auto_subtitle_generator_create_response.py +35 -0
  104. magic_hour/types/models/v1_face_detection_create_response.py +25 -0
  105. magic_hour/types/models/v1_face_detection_get_response.py +45 -0
  106. magic_hour/types/models/v1_face_detection_get_response_faces_item.py +25 -0
  107. magic_hour/types/models/v1_face_swap_create_response.py +35 -0
  108. magic_hour/types/models/v1_face_swap_photo_create_response.py +33 -0
  109. magic_hour/types/models/v1_files_upload_urls_create_response.py +24 -0
  110. magic_hour/types/models/{post_v1_files_upload_urls_response_items_item.py → v1_files_upload_urls_create_response_items_item.py} +2 -2
  111. magic_hour/types/models/v1_image_background_remover_create_response.py +33 -0
  112. magic_hour/types/models/{get_v1_image_projects_id_response.py → v1_image_projects_get_response.py} +20 -18
  113. magic_hour/types/models/{get_v1_video_projects_id_response_downloads_item.py → v1_image_projects_get_response_downloads_item.py} +1 -1
  114. magic_hour/types/models/{get_v1_video_projects_id_response_error.py → v1_image_projects_get_response_error.py} +2 -2
  115. magic_hour/types/models/v1_image_to_video_create_response.py +35 -0
  116. magic_hour/types/models/v1_lip_sync_create_response.py +35 -0
  117. magic_hour/types/models/v1_photo_colorizer_create_response.py +33 -0
  118. magic_hour/types/models/v1_text_to_video_create_response.py +35 -0
  119. magic_hour/types/models/{get_v1_video_projects_id_response.py → v1_video_projects_get_response.py} +26 -23
  120. magic_hour/types/models/{get_v1_video_projects_id_response_download.py → v1_video_projects_get_response_download.py} +1 -1
  121. magic_hour/types/models/{get_v1_image_projects_id_response_downloads_item.py → v1_video_projects_get_response_downloads_item.py} +1 -1
  122. magic_hour/types/models/v1_video_projects_get_response_error.py +25 -0
  123. magic_hour/types/models/v1_video_to_video_create_response.py +35 -0
  124. magic_hour/types/params/__init__.py +422 -176
  125. magic_hour/types/params/v1_ai_clothes_changer_create_body.py +40 -0
  126. magic_hour/types/params/v1_ai_clothes_changer_create_body_assets.py +58 -0
  127. magic_hour/types/params/v1_ai_clothes_changer_generate_body_assets.py +33 -0
  128. magic_hour/types/params/v1_ai_face_editor_create_body.py +52 -0
  129. magic_hour/types/params/v1_ai_face_editor_create_body_assets.py +33 -0
  130. magic_hour/types/params/v1_ai_face_editor_create_body_style.py +137 -0
  131. magic_hour/types/params/v1_ai_face_editor_generate_body_assets.py +17 -0
  132. magic_hour/types/params/v1_ai_gif_generator_create_body.py +47 -0
  133. magic_hour/types/params/{post_v1_ai_image_generator_body_style.py → v1_ai_gif_generator_create_body_style.py} +5 -5
  134. magic_hour/types/params/v1_ai_headshot_generator_create_body.py +49 -0
  135. magic_hour/types/params/v1_ai_headshot_generator_create_body_assets.py +33 -0
  136. magic_hour/types/params/v1_ai_headshot_generator_create_body_style.py +27 -0
  137. magic_hour/types/params/v1_ai_headshot_generator_generate_body_assets.py +17 -0
  138. magic_hour/types/params/v1_ai_image_editor_create_body.py +49 -0
  139. magic_hour/types/params/v1_ai_image_editor_create_body_assets.py +47 -0
  140. magic_hour/types/params/v1_ai_image_editor_create_body_style.py +41 -0
  141. magic_hour/types/params/v1_ai_image_editor_generate_body_assets.py +28 -0
  142. magic_hour/types/params/{post_v1_ai_image_generator_body.py → v1_ai_image_generator_create_body.py} +17 -11
  143. magic_hour/types/params/v1_ai_image_generator_create_body_style.py +127 -0
  144. magic_hour/types/params/v1_ai_image_upscaler_create_body.py +59 -0
  145. magic_hour/types/params/v1_ai_image_upscaler_create_body_assets.py +33 -0
  146. magic_hour/types/params/{post_v1_ai_image_upscaler_body_style.py → v1_ai_image_upscaler_create_body_style.py} +4 -4
  147. magic_hour/types/params/v1_ai_image_upscaler_generate_body_assets.py +17 -0
  148. magic_hour/types/params/v1_ai_meme_generator_create_body.py +37 -0
  149. magic_hour/types/params/v1_ai_meme_generator_create_body_style.py +73 -0
  150. magic_hour/types/params/{post_v1_ai_photo_editor_body.py → v1_ai_photo_editor_create_body.py} +15 -15
  151. magic_hour/types/params/v1_ai_photo_editor_create_body_assets.py +33 -0
  152. magic_hour/types/params/{post_v1_ai_photo_editor_body_style.py → v1_ai_photo_editor_create_body_style.py} +20 -4
  153. magic_hour/types/params/v1_ai_photo_editor_generate_body_assets.py +17 -0
  154. magic_hour/types/params/v1_ai_qr_code_generator_create_body.py +45 -0
  155. magic_hour/types/params/{post_v1_ai_qr_code_generator_body_style.py → v1_ai_qr_code_generator_create_body_style.py} +4 -4
  156. magic_hour/types/params/v1_ai_talking_photo_create_body.py +68 -0
  157. magic_hour/types/params/v1_ai_talking_photo_create_body_assets.py +46 -0
  158. magic_hour/types/params/v1_ai_talking_photo_create_body_style.py +44 -0
  159. magic_hour/types/params/v1_ai_talking_photo_generate_body_assets.py +26 -0
  160. magic_hour/types/params/v1_ai_voice_cloner_create_body.py +49 -0
  161. magic_hour/types/params/v1_ai_voice_cloner_create_body_assets.py +33 -0
  162. magic_hour/types/params/v1_ai_voice_cloner_create_body_style.py +28 -0
  163. magic_hour/types/params/v1_ai_voice_cloner_generate_body_assets.py +28 -0
  164. magic_hour/types/params/v1_ai_voice_generator_create_body.py +40 -0
  165. magic_hour/types/params/v1_ai_voice_generator_create_body_style.py +440 -0
  166. magic_hour/types/params/{post_v1_animation_body.py → v1_animation_create_body.py} +16 -16
  167. magic_hour/types/params/{post_v1_animation_body_assets.py → v1_animation_create_body_assets.py} +15 -5
  168. magic_hour/types/params/{post_v1_animation_body_style.py → v1_animation_create_body_style.py} +13 -10
  169. magic_hour/types/params/v1_animation_generate_body_assets.py +39 -0
  170. magic_hour/types/params/v1_auto_subtitle_generator_create_body.py +78 -0
  171. magic_hour/types/params/v1_auto_subtitle_generator_create_body_assets.py +33 -0
  172. magic_hour/types/params/v1_auto_subtitle_generator_create_body_style.py +56 -0
  173. magic_hour/types/params/v1_auto_subtitle_generator_create_body_style_custom_config.py +86 -0
  174. magic_hour/types/params/v1_auto_subtitle_generator_generate_body_assets.py +17 -0
  175. magic_hour/types/params/v1_face_detection_create_body.py +44 -0
  176. magic_hour/types/params/v1_face_detection_create_body_assets.py +33 -0
  177. magic_hour/types/params/v1_face_detection_generate_body_assets.py +17 -0
  178. magic_hour/types/params/v1_face_swap_create_body.py +92 -0
  179. magic_hour/types/params/v1_face_swap_create_body_assets.py +91 -0
  180. magic_hour/types/params/v1_face_swap_create_body_assets_face_mappings_item.py +44 -0
  181. magic_hour/types/params/v1_face_swap_create_body_style.py +33 -0
  182. magic_hour/types/params/v1_face_swap_generate_body_assets.py +56 -0
  183. magic_hour/types/params/v1_face_swap_generate_body_assets_face_mappings_item.py +25 -0
  184. magic_hour/types/params/v1_face_swap_photo_create_body.py +40 -0
  185. magic_hour/types/params/v1_face_swap_photo_create_body_assets.py +76 -0
  186. magic_hour/types/params/v1_face_swap_photo_create_body_assets_face_mappings_item.py +44 -0
  187. magic_hour/types/params/v1_face_swap_photo_generate_body_assets.py +47 -0
  188. magic_hour/types/params/v1_face_swap_photo_generate_body_assets_face_mappings_item.py +25 -0
  189. magic_hour/types/params/v1_files_upload_urls_create_body.py +36 -0
  190. magic_hour/types/params/v1_files_upload_urls_create_body_items_item.py +38 -0
  191. magic_hour/types/params/v1_image_background_remover_create_body.py +40 -0
  192. magic_hour/types/params/v1_image_background_remover_create_body_assets.py +49 -0
  193. magic_hour/types/params/v1_image_background_remover_generate_body_assets.py +27 -0
  194. magic_hour/types/params/v1_image_to_video_create_body.py +101 -0
  195. magic_hour/types/params/v1_image_to_video_create_body_assets.py +33 -0
  196. magic_hour/types/params/v1_image_to_video_create_body_style.py +53 -0
  197. magic_hour/types/params/v1_image_to_video_generate_body_assets.py +17 -0
  198. magic_hour/types/params/v1_lip_sync_create_body.py +100 -0
  199. magic_hour/types/params/{post_v1_lip_sync_body_assets.py → v1_lip_sync_create_body_assets.py} +15 -5
  200. magic_hour/types/params/v1_lip_sync_create_body_style.py +37 -0
  201. magic_hour/types/params/v1_lip_sync_generate_body_assets.py +36 -0
  202. magic_hour/types/params/v1_photo_colorizer_create_body.py +40 -0
  203. magic_hour/types/params/v1_photo_colorizer_create_body_assets.py +33 -0
  204. magic_hour/types/params/v1_photo_colorizer_generate_body_assets.py +17 -0
  205. magic_hour/types/params/v1_text_to_video_create_body.py +78 -0
  206. magic_hour/types/params/v1_text_to_video_create_body_style.py +43 -0
  207. magic_hour/types/params/v1_video_to_video_create_body.py +101 -0
  208. magic_hour/types/params/{post_v1_video_to_video_body_assets.py → v1_video_to_video_create_body_assets.py} +9 -4
  209. magic_hour/types/params/{post_v1_video_to_video_body_style.py → v1_video_to_video_create_body_style.py} +68 -26
  210. magic_hour/types/params/v1_video_to_video_generate_body_assets.py +27 -0
  211. magic_hour-0.44.0.dist-info/METADATA +328 -0
  212. magic_hour-0.44.0.dist-info/RECORD +231 -0
  213. magic_hour/core/__init__.py +0 -52
  214. magic_hour/core/api_error.py +0 -56
  215. magic_hour/core/auth.py +0 -314
  216. magic_hour/core/base_client.py +0 -618
  217. magic_hour/core/binary_response.py +0 -23
  218. magic_hour/core/query.py +0 -106
  219. magic_hour/core/request.py +0 -156
  220. magic_hour/core/response.py +0 -293
  221. magic_hour/core/type_utils.py +0 -28
  222. magic_hour/core/utils.py +0 -55
  223. magic_hour/types/models/post_v1_ai_clothes_changer_response.py +0 -25
  224. magic_hour/types/models/post_v1_ai_headshot_generator_response.py +0 -25
  225. magic_hour/types/models/post_v1_ai_image_generator_response.py +0 -25
  226. magic_hour/types/models/post_v1_ai_image_upscaler_response.py +0 -25
  227. magic_hour/types/models/post_v1_ai_photo_editor_response.py +0 -25
  228. magic_hour/types/models/post_v1_ai_qr_code_generator_response.py +0 -25
  229. magic_hour/types/models/post_v1_animation_response.py +0 -25
  230. magic_hour/types/models/post_v1_face_swap_photo_response.py +0 -25
  231. magic_hour/types/models/post_v1_face_swap_response.py +0 -25
  232. magic_hour/types/models/post_v1_files_upload_urls_response.py +0 -21
  233. magic_hour/types/models/post_v1_image_background_remover_response.py +0 -25
  234. magic_hour/types/models/post_v1_image_to_video_response.py +0 -25
  235. magic_hour/types/models/post_v1_lip_sync_response.py +0 -25
  236. magic_hour/types/models/post_v1_text_to_video_response.py +0 -25
  237. magic_hour/types/models/post_v1_video_to_video_response.py +0 -25
  238. magic_hour/types/params/post_v1_ai_clothes_changer_body.py +0 -40
  239. magic_hour/types/params/post_v1_ai_clothes_changer_body_assets.py +0 -45
  240. magic_hour/types/params/post_v1_ai_headshot_generator_body.py +0 -40
  241. magic_hour/types/params/post_v1_ai_headshot_generator_body_assets.py +0 -28
  242. magic_hour/types/params/post_v1_ai_image_upscaler_body.py +0 -57
  243. magic_hour/types/params/post_v1_ai_image_upscaler_body_assets.py +0 -28
  244. magic_hour/types/params/post_v1_ai_photo_editor_body_assets.py +0 -28
  245. magic_hour/types/params/post_v1_ai_qr_code_generator_body.py +0 -45
  246. magic_hour/types/params/post_v1_face_swap_body.py +0 -72
  247. magic_hour/types/params/post_v1_face_swap_body_assets.py +0 -52
  248. magic_hour/types/params/post_v1_face_swap_photo_body.py +0 -40
  249. magic_hour/types/params/post_v1_face_swap_photo_body_assets.py +0 -36
  250. magic_hour/types/params/post_v1_files_upload_urls_body.py +0 -31
  251. magic_hour/types/params/post_v1_files_upload_urls_body_items_item.py +0 -38
  252. magic_hour/types/params/post_v1_image_background_remover_body.py +0 -40
  253. magic_hour/types/params/post_v1_image_background_remover_body_assets.py +0 -28
  254. magic_hour/types/params/post_v1_image_to_video_body.py +0 -73
  255. magic_hour/types/params/post_v1_image_to_video_body_assets.py +0 -28
  256. magic_hour/types/params/post_v1_image_to_video_body_style.py +0 -37
  257. magic_hour/types/params/post_v1_lip_sync_body.py +0 -80
  258. magic_hour/types/params/post_v1_text_to_video_body.py +0 -57
  259. magic_hour/types/params/post_v1_text_to_video_body_style.py +0 -28
  260. magic_hour/types/params/post_v1_video_to_video_body.py +0 -93
  261. magic_hour-0.9.5.dist-info/METADATA +0 -133
  262. magic_hour-0.9.5.dist-info/RECORD +0 -132
  263. {magic_hour-0.9.5.dist-info → magic_hour-0.44.0.dist-info}/LICENSE +0 -0
  264. {magic_hour-0.9.5.dist-info → magic_hour-0.44.0.dist-info}/WHEEL +0 -0
@@ -1,618 +0,0 @@
1
- from typing import (
2
- Any,
3
- List,
4
- TypeVar,
5
- Dict,
6
- Optional,
7
- Type,
8
- Union,
9
- cast,
10
- )
11
- from typing_extensions import TypeGuard
12
-
13
- import httpx
14
- from pydantic import BaseModel
15
-
16
- from .api_error import ApiError
17
- from .auth import AuthProvider
18
- from .request import RequestConfig, RequestOptions, default_request_options, QueryParams
19
- from .response import from_encodable, AsyncStreamResponse, StreamResponse
20
- from .utils import get_response_type, filter_binary_response
21
- from .binary_response import BinaryResponse
22
-
23
- NoneType = type(None)
24
- T = TypeVar(
25
- "T",
26
- bound=Union[object, None, str, "BaseModel", List[Any], Dict[str, Any], Any],
27
- )
28
-
29
-
30
- class BaseClient:
31
- """Base client class providing core HTTP client functionality.
32
-
33
- Handles authentication, request building, and response processing for HTTP API clients.
34
- Serves as the foundation for both synchronous and asynchronous client implementations.
35
-
36
- Attributes:
37
- _base_url: Base URL for the API endpoint
38
- _auths: Dictionary mapping auth provider IDs to AuthProvider instances
39
- """
40
-
41
- def __init__(
42
- self,
43
- *,
44
- base_url: str,
45
- ):
46
- """Initialize the base client.
47
-
48
- Args:
49
- base_url: Base URL for the API endpoint
50
- """
51
- self._base_url = base_url
52
- self._auths: Dict[str, AuthProvider] = {}
53
-
54
- def register_auth(self, auth_id: str, provider: AuthProvider):
55
- """Register an authentication provider.
56
-
57
- Args:
58
- auth_id: Unique identifier for the auth provider
59
- provider: AuthProvider instance to handle authentication
60
- """
61
- self._auths[auth_id] = provider
62
-
63
- def default_headers(self) -> Dict[str, str]:
64
- """Get default headers for requests.
65
-
66
- Returns:
67
- Dictionary of default headers
68
- """
69
- headers: Dict[str, str] = {
70
- "x-sideko-sdk-language": "Python",
71
- }
72
- return headers
73
-
74
- def get_base_url(self) -> str:
75
- """Get the base URL for the API endpoint.
76
-
77
- Returns:
78
- Base URL string
79
- """
80
- return self._base_url
81
-
82
- def build_url(self, path: str) -> str:
83
- """Build a complete URL by combining base URL and path.
84
-
85
- Args:
86
- path: API endpoint path
87
-
88
- Returns:
89
- Complete URL string
90
- """
91
- base = self._base_url
92
- if base.endswith("/"):
93
- base = base[:-1]
94
- if path.startswith("/"):
95
- path = path[1:]
96
-
97
- return f"{base}/{path}"
98
-
99
- def _cast_to_raw_response(
100
- self, res: httpx.Response, cast_to: Union[Type[T], Any]
101
- ) -> TypeGuard[T]:
102
- """Determines if the provided cast_to is an httpx.Response"""
103
- try:
104
- return issubclass(cast_to, httpx.Response)
105
- except TypeError:
106
- return False
107
-
108
- def _apply_auth(
109
- self, *, cfg: RequestConfig, auth_names: List[str]
110
- ) -> RequestConfig:
111
- """Apply authentication to the request configuration.
112
-
113
- Args:
114
- cfg: Request configuration to modify
115
- auth_names: List of auth provider IDs to apply
116
-
117
- Returns:
118
- Modified request configuration
119
- """
120
- for auth_name in auth_names:
121
- auth_provider = self._auths.get(auth_name)
122
- if auth_provider is not None:
123
- cfg = auth_provider.add_to_request(cfg)
124
-
125
- return cfg
126
-
127
- def _apply_headers(
128
- self,
129
- *,
130
- cfg: RequestConfig,
131
- opts: RequestOptions,
132
- content_type: Optional[str] = None,
133
- explicit_headers: Optional[Dict[str, str]] = None,
134
- ) -> RequestConfig:
135
- """Apply headers to the request configuration.
136
-
137
- Args:
138
- cfg: Request configuration to modify
139
- opts: Request options containing additional headers
140
- content_type: Optional content type header
141
- explicit_headers: Optional explicitly specified headers
142
-
143
- Returns:
144
- Modified request configuration
145
- """
146
- headers = cfg.get("headers", {})
147
- headers.update(self.default_headers())
148
-
149
- if content_type is not None:
150
- headers["content-type"] = content_type
151
-
152
- if explicit_headers is not None:
153
- headers.update(explicit_headers)
154
-
155
- additional_headers = opts.get("additional_headers", None)
156
- if additional_headers is not None:
157
- headers.update(additional_headers)
158
-
159
- if len(headers) > 0:
160
- cfg["headers"] = headers
161
-
162
- return cfg
163
-
164
- def _apply_query_params(
165
- self,
166
- *,
167
- cfg: RequestConfig,
168
- opts: RequestOptions,
169
- query_params: Optional[QueryParams] = None,
170
- ) -> RequestConfig:
171
- """Apply query parameters to the request configuration.
172
-
173
- Args:
174
- cfg: Request configuration to modify
175
- opts: Request options containing additional parameters
176
- query_params: Optional query parameters to add
177
-
178
- Returns:
179
- Modified request configuration
180
- """
181
- params = cfg.get("params", {})
182
-
183
- if query_params is not None:
184
- params.update(query_params)
185
-
186
- additional_params = opts.get("additional_params", None)
187
- if additional_params is not None:
188
- params.update(additional_params)
189
-
190
- if len(params) > 0:
191
- cfg["params"] = params
192
-
193
- return cfg
194
-
195
- def _apply_timeout(
196
- self,
197
- *,
198
- cfg: RequestConfig,
199
- opts: RequestOptions,
200
- ) -> RequestConfig:
201
- """Apply timeout settings to the request configuration.
202
-
203
- Args:
204
- cfg: Request configuration to modify
205
- opts: Request options containing timeout settings
206
-
207
- Returns:
208
- Modified request configuration
209
- """
210
- timeout = opts.get("timeout", None)
211
-
212
- if timeout is not None:
213
- cfg["timeout"] = timeout
214
-
215
- return cfg
216
-
217
- def _apply_body(
218
- self,
219
- *,
220
- cfg: RequestConfig,
221
- data: Optional[httpx._types.RequestData] = None,
222
- files: Optional[httpx._types.RequestFiles] = None,
223
- json: Optional[Any] = None,
224
- content: Optional[httpx._types.RequestContent] = None,
225
- ) -> RequestConfig:
226
- """Apply request body content to the request configuration.
227
-
228
- Args:
229
- cfg: Request configuration to modify
230
- data: Optional form data
231
- files: Optional files to upload
232
- json: Optional JSON data
233
- content: Optional raw content
234
-
235
- Returns:
236
- Modified request configuration
237
- """
238
- if data is not None:
239
- cfg["data"] = data
240
-
241
- if files is not None:
242
- cfg["files"] = files
243
-
244
- if json is not None:
245
- cfg["json"] = json
246
-
247
- if content is not None:
248
- cfg["content"] = content
249
-
250
- return cfg
251
-
252
- def build_request(
253
- self,
254
- *,
255
- method: str,
256
- path: str,
257
- auth_names: Optional[List[str]] = None,
258
- query_params: Optional[QueryParams] = None,
259
- headers: Optional[Dict[str, str]] = None,
260
- data: Optional[httpx._types.RequestData] = None,
261
- files: Optional[httpx._types.RequestFiles] = None,
262
- json: Optional[Any] = None,
263
- content_type: Optional[str] = None,
264
- content: Optional[httpx._types.RequestContent] = None,
265
- request_options: Optional[RequestOptions] = None,
266
- ) -> RequestConfig:
267
- """Build a complete request configuration.
268
-
269
- Args:
270
- method: HTTP method
271
- path: API endpoint path
272
- auth_names: List of auth provider IDs
273
- query_params: Query parameters
274
- headers: Request headers
275
- data: Form data
276
- files: Files to upload
277
- json: JSON data
278
- content_type: Content type header
279
- content: Raw content
280
- request_options: Additional request options
281
-
282
- Returns:
283
- Complete request configuration
284
- """
285
- opts = request_options or default_request_options()
286
- req_cfg: RequestConfig = {"method": method, "url": self.build_url(path)}
287
- req_cfg = self._apply_auth(cfg=req_cfg, auth_names=auth_names or [])
288
- req_cfg = self._apply_headers(
289
- cfg=req_cfg, opts=opts, content_type=content_type, explicit_headers=headers
290
- )
291
- req_cfg = self._apply_query_params(
292
- cfg=req_cfg, opts=opts, query_params=query_params
293
- )
294
- req_cfg = self._apply_body(
295
- cfg=req_cfg, data=data, files=files, json=json, content=content
296
- )
297
- req_cfg = self._apply_timeout(cfg=req_cfg, opts=opts)
298
-
299
- return req_cfg
300
-
301
- def process_response(
302
- self,
303
- *,
304
- response=httpx.Response,
305
- cast_to: Union[Type[T], Any],
306
- ) -> T:
307
- """Process an HTTP response and convert it to the desired type.
308
-
309
- Args:
310
- response: HTTP response to process
311
- cast_to: Type to cast the response data to
312
-
313
- Returns:
314
- Processed response data of the specified type
315
-
316
- Raises:
317
- ApiError: If the response indicates an error
318
- """
319
-
320
- if response.status_code == 204 or cast_to == NoneType:
321
- return cast(T, None)
322
- elif cast_to == BinaryResponse:
323
- return cast(
324
- T,
325
- BinaryResponse(content=response.content, headers=response.headers),
326
- )
327
-
328
- response_type = get_response_type(response.headers)
329
-
330
- if response_type == "json":
331
- if cast_to is type(Any):
332
- return response.json()
333
- return from_encodable(
334
- data=response.json(), load_with=filter_binary_response(cast_to=cast_to)
335
- )
336
- elif response_type == "text":
337
- return cast(T, response.text)
338
- else:
339
- return cast(
340
- T,
341
- BinaryResponse(content=response.content, headers=response.headers),
342
- )
343
-
344
-
345
- class SyncBaseClient(BaseClient):
346
- """Synchronous HTTP client implementation.
347
-
348
- Provides synchronous HTTP request capabilities building on the base client functionality.
349
- """
350
-
351
- def __init__(
352
- self,
353
- *,
354
- base_url: str,
355
- httpx_client: httpx.Client,
356
- ):
357
- """Initialize the synchronous client.
358
-
359
- Args:
360
- base_url: Base URL for the API endpoint
361
- httpx_client: Synchronous HTTPX client instance
362
- """
363
- super().__init__(base_url=base_url)
364
- self.httpx_client = httpx_client
365
-
366
- def request(
367
- self,
368
- *,
369
- method: str,
370
- path: str,
371
- cast_to: Union[Type[T], Any],
372
- auth_names: Optional[List[str]] = None,
373
- query_params: Optional[QueryParams] = None,
374
- headers: Optional[Dict[str, str]] = None,
375
- data: Optional[httpx._types.RequestData] = None,
376
- files: Optional[httpx._types.RequestFiles] = None,
377
- json: Optional[Any] = None,
378
- content_type: Optional[str] = None,
379
- content: Optional[httpx._types.RequestContent] = None,
380
- request_options: Optional[RequestOptions] = None,
381
- ) -> T:
382
- """Make a synchronous HTTP request.
383
-
384
- Args:
385
- method: HTTP method
386
- path: API endpoint path
387
- cast_to: Type to cast the response to
388
- auth_names: List of auth provider IDs
389
- query_params: Query parameters
390
- headers: Request headers
391
- data: Form data
392
- files: Files to upload
393
- json: JSON data
394
- content_type: Content type header
395
- content: Raw content
396
- request_options: Additional request options
397
-
398
- Returns:
399
- Response data of the specified type
400
-
401
- Raises:
402
- ApiError: If the request fails
403
- """
404
- req_cfg = self.build_request(
405
- method=method,
406
- path=path,
407
- auth_names=auth_names,
408
- query_params=query_params,
409
- headers=headers,
410
- data=data,
411
- files=files,
412
- json=json,
413
- content_type=content_type,
414
- content=content,
415
- request_options=request_options,
416
- )
417
- response = self.httpx_client.request(**req_cfg)
418
-
419
- if not response.is_success:
420
- raise ApiError(response=response)
421
-
422
- if self._cast_to_raw_response(res=response, cast_to=cast_to):
423
- return response
424
-
425
- return self.process_response(response=response, cast_to=cast_to)
426
-
427
- def stream_request(
428
- self,
429
- *,
430
- method: str,
431
- path: str,
432
- cast_to: Union[Type[T], Any],
433
- auth_names: Optional[List[str]] = None,
434
- query_params: Optional[QueryParams] = None,
435
- headers: Optional[Dict[str, str]] = None,
436
- data: Optional[httpx._types.RequestData] = None,
437
- files: Optional[httpx._types.RequestFiles] = None,
438
- json: Optional[Any] = None,
439
- content_type: Optional[str] = None,
440
- content: Optional[httpx._types.RequestContent] = None,
441
- request_options: Optional[RequestOptions] = None,
442
- ) -> StreamResponse[T]:
443
- """Make a streaming synchronous HTTP request.
444
-
445
- Args:
446
- method: HTTP method
447
- path: API endpoint path
448
- cast_to: Type to cast the response to
449
- auth_names: List of auth provider IDs
450
- query_params: Query parameters
451
- headers: Request headers
452
- data: Form data
453
- files: Files to upload
454
- json: JSON data
455
- content_type: Content type header
456
- content: Raw content
457
- request_options: Additional request options
458
-
459
- Returns:
460
- StreamResponse containing the streaming response
461
-
462
- Raises:
463
- ApiError: If the request fails
464
- """
465
- req_cfg = self.build_request(
466
- method=method,
467
- path=path,
468
- auth_names=auth_names,
469
- query_params=query_params,
470
- headers=headers,
471
- data=data,
472
- files=files,
473
- json=json,
474
- content_type=content_type,
475
- content=content,
476
- request_options=request_options,
477
- )
478
- context = self.httpx_client.stream(**req_cfg)
479
- response = context.__enter__()
480
- return StreamResponse(response, context, cast_to)
481
-
482
-
483
- class AsyncBaseClient(BaseClient):
484
- """Asynchronous HTTP client implementation.
485
-
486
- Provides asynchronous HTTP request capabilities building on the base client functionality.
487
- """
488
-
489
- def __init__(
490
- self,
491
- *,
492
- base_url: str,
493
- httpx_client: httpx.AsyncClient,
494
- ):
495
- """Initialize the asynchronous client.
496
-
497
- Args:
498
- base_url: Base URL for the API endpoint
499
- httpx_client: Asynchronous HTTPX client instance
500
- """
501
- super().__init__(base_url=base_url)
502
- self.httpx_client = httpx_client
503
-
504
- async def request(
505
- self,
506
- *,
507
- method: str,
508
- path: str,
509
- cast_to: Union[Type[T], Any],
510
- auth_names: Optional[List[str]] = None,
511
- query_params: Optional[QueryParams] = None,
512
- headers: Optional[Dict[str, str]] = None,
513
- data: Optional[httpx._types.RequestData] = None,
514
- files: Optional[httpx._types.RequestFiles] = None,
515
- json: Optional[Any] = None,
516
- content_type: Optional[str] = None,
517
- content: Optional[httpx._types.RequestContent] = None,
518
- request_options: Optional[RequestOptions] = None,
519
- ) -> T:
520
- """Make an asynchronous HTTP request.
521
-
522
- Args:
523
- method: HTTP method
524
- path: API endpoint path
525
- cast_to: Type to cast the response to
526
- auth_names: List of auth provider IDs
527
- query_params: Query parameters
528
- headers: Request headers
529
- data: Form data
530
- files: Files to upload
531
- json: JSON data
532
- content_type: Content type header
533
- content: Raw content
534
- request_options: Additional request options
535
-
536
- Returns:
537
- Response data of the specified type
538
-
539
- Raises:
540
- ApiError: If the request fails
541
- """
542
- req_cfg = self.build_request(
543
- method=method,
544
- path=path,
545
- auth_names=auth_names,
546
- query_params=query_params,
547
- headers=headers,
548
- data=data,
549
- files=files,
550
- json=json,
551
- content_type=content_type,
552
- content=content,
553
- request_options=request_options,
554
- )
555
- response = await self.httpx_client.request(**req_cfg)
556
-
557
- if not response.is_success:
558
- raise ApiError(response=response)
559
-
560
- if self._cast_to_raw_response(res=response, cast_to=cast_to):
561
- return response
562
-
563
- return self.process_response(response=response, cast_to=cast_to)
564
-
565
- async def stream_request(
566
- self,
567
- *,
568
- method: str,
569
- path: str,
570
- cast_to: Union[Type[T], Any],
571
- auth_names: Optional[List[str]] = None,
572
- query_params: Optional[QueryParams] = None,
573
- headers: Optional[Dict[str, str]] = None,
574
- data: Optional[httpx._types.RequestData] = None,
575
- files: Optional[httpx._types.RequestFiles] = None,
576
- json: Optional[Any] = None,
577
- content_type: Optional[str] = None,
578
- content: Optional[httpx._types.RequestContent] = None,
579
- request_options: Optional[RequestOptions] = None,
580
- ) -> AsyncStreamResponse[T]:
581
- """Make a streaming asynchronous HTTP request.
582
-
583
- Args:
584
- method: HTTP method
585
- path: API endpoint path
586
- cast_to: Type to cast the response to
587
- auth_names: List of auth provider IDs
588
- query_params: Query parameters
589
- headers: Request headers
590
- data: Form data
591
- files: Files to upload
592
- json: JSON data
593
- content_type: Content type header
594
- content: Raw content
595
- request_options: Additional request options
596
-
597
- Returns:
598
- AsyncStreamResponse containing the streaming response
599
-
600
- Raises:
601
- ApiError: If the request fails
602
- """
603
- req_cfg = self.build_request(
604
- method=method,
605
- path=path,
606
- auth_names=auth_names,
607
- query_params=query_params,
608
- headers=headers,
609
- data=data,
610
- files=files,
611
- json=json,
612
- content_type=content_type,
613
- content=content,
614
- request_options=request_options,
615
- )
616
- context = self.httpx_client.stream(**req_cfg)
617
- response = await context.__aenter__()
618
- return AsyncStreamResponse(response, context, cast_to)
@@ -1,23 +0,0 @@
1
- from httpx._models import Headers
2
-
3
-
4
- class BinaryResponse:
5
- """
6
- Represents a binary HTTP response.
7
-
8
- A lightweight wrapper for binary content and its associated HTTP headers,
9
- typically used for handling file downloads or raw binary data from HTTP requests.
10
- """
11
-
12
- content: bytes
13
- headers: Headers
14
-
15
- def __init__(self, content: bytes, headers: Headers) -> None:
16
- """
17
- Initialize a binary response with content and headers.
18
-
19
- The content represents the raw binary data received in the response,
20
- while headers contain the associated HTTP response headers.
21
- """
22
- self.content = content
23
- self.headers = headers