llama-cloud 0.1.41__py3-none-any.whl → 1.0.0b4__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 (714) hide show
  1. llama_cloud/__init__.py +101 -816
  2. llama_cloud/_base_client.py +2124 -0
  3. llama_cloud/_client.py +795 -0
  4. llama_cloud/_compat.py +219 -0
  5. llama_cloud/_constants.py +14 -0
  6. llama_cloud/_exceptions.py +108 -0
  7. llama_cloud/_files.py +127 -0
  8. llama_cloud/_models.py +872 -0
  9. llama_cloud/_polling.py +182 -0
  10. llama_cloud/_qs.py +150 -0
  11. llama_cloud/_resource.py +43 -0
  12. llama_cloud/_response.py +832 -0
  13. llama_cloud/_streaming.py +333 -0
  14. llama_cloud/_types.py +270 -0
  15. llama_cloud/_utils/__init__.py +64 -0
  16. llama_cloud/_utils/_compat.py +45 -0
  17. llama_cloud/_utils/_datetime_parse.py +136 -0
  18. llama_cloud/_utils/_logs.py +25 -0
  19. llama_cloud/_utils/_proxy.py +65 -0
  20. llama_cloud/_utils/_reflection.py +42 -0
  21. llama_cloud/_utils/_resources_proxy.py +24 -0
  22. llama_cloud/_utils/_streams.py +12 -0
  23. llama_cloud/_utils/_sync.py +58 -0
  24. llama_cloud/_utils/_transform.py +457 -0
  25. llama_cloud/_utils/_typing.py +156 -0
  26. llama_cloud/_utils/_utils.py +421 -0
  27. llama_cloud/_version.py +4 -0
  28. llama_cloud/lib/__init__.py +0 -0
  29. llama_cloud/lib/index/__init__.py +13 -0
  30. llama_cloud/lib/index/api_utils.py +300 -0
  31. llama_cloud/lib/index/base.py +1041 -0
  32. llama_cloud/lib/index/composite_retriever.py +272 -0
  33. llama_cloud/lib/index/retriever.py +233 -0
  34. llama_cloud/pagination.py +465 -0
  35. llama_cloud/py.typed +0 -0
  36. llama_cloud/resources/__init__.py +136 -107
  37. llama_cloud/resources/beta/__init__.py +102 -1
  38. llama_cloud/resources/beta/agent_data.py +1041 -0
  39. llama_cloud/resources/beta/batch/__init__.py +33 -0
  40. llama_cloud/resources/beta/batch/batch.py +664 -0
  41. llama_cloud/resources/beta/batch/job_items.py +348 -0
  42. llama_cloud/resources/beta/beta.py +262 -0
  43. llama_cloud/resources/beta/directories/__init__.py +33 -0
  44. llama_cloud/resources/beta/directories/directories.py +719 -0
  45. llama_cloud/resources/beta/directories/files.py +913 -0
  46. llama_cloud/resources/beta/parse_configurations.py +743 -0
  47. llama_cloud/resources/beta/sheets.py +1130 -0
  48. llama_cloud/resources/beta/split.py +917 -0
  49. llama_cloud/resources/classifier/__init__.py +32 -1
  50. llama_cloud/resources/classifier/classifier.py +588 -0
  51. llama_cloud/resources/classifier/jobs.py +563 -0
  52. llama_cloud/resources/data_sinks.py +579 -0
  53. llama_cloud/resources/data_sources.py +651 -0
  54. llama_cloud/resources/extraction/__init__.py +61 -0
  55. llama_cloud/resources/extraction/extraction.py +609 -0
  56. llama_cloud/resources/extraction/extraction_agents/__init__.py +33 -0
  57. llama_cloud/resources/extraction/extraction_agents/extraction_agents.py +633 -0
  58. llama_cloud/resources/extraction/extraction_agents/schema.py +308 -0
  59. llama_cloud/resources/extraction/jobs.py +1106 -0
  60. llama_cloud/resources/extraction/runs.py +498 -0
  61. llama_cloud/resources/files.py +784 -0
  62. llama_cloud/resources/parsing.py +1296 -0
  63. llama_cloud/resources/pipelines/__init__.py +98 -24
  64. llama_cloud/resources/pipelines/data_sources.py +529 -0
  65. llama_cloud/resources/pipelines/documents.py +810 -0
  66. llama_cloud/resources/pipelines/files.py +682 -0
  67. llama_cloud/resources/pipelines/images.py +513 -0
  68. llama_cloud/resources/pipelines/metadata.py +265 -0
  69. llama_cloud/resources/pipelines/pipelines.py +1525 -0
  70. llama_cloud/resources/pipelines/sync.py +243 -0
  71. llama_cloud/resources/projects.py +276 -0
  72. llama_cloud/resources/retrievers/__init__.py +32 -1
  73. llama_cloud/resources/retrievers/retriever.py +238 -0
  74. llama_cloud/resources/retrievers/retrievers.py +920 -0
  75. llama_cloud/types/__init__.py +171 -721
  76. llama_cloud/types/advanced_mode_transform_config.py +102 -38
  77. llama_cloud/types/advanced_mode_transform_config_param.py +102 -0
  78. llama_cloud/types/auto_transform_config.py +11 -25
  79. llama_cloud/types/auto_transform_config_param.py +17 -0
  80. llama_cloud/types/azure_openai_embedding.py +62 -0
  81. llama_cloud/types/azure_openai_embedding_config.py +17 -0
  82. llama_cloud/types/azure_openai_embedding_config_param.py +17 -0
  83. llama_cloud/types/azure_openai_embedding_param.py +61 -0
  84. llama_cloud/types/b_box.py +37 -0
  85. llama_cloud/types/bedrock_embedding.py +49 -46
  86. llama_cloud/types/bedrock_embedding_config.py +10 -27
  87. llama_cloud/types/bedrock_embedding_config_param.py +17 -0
  88. llama_cloud/types/bedrock_embedding_param.py +48 -0
  89. llama_cloud/types/beta/__init__.py +59 -0
  90. llama_cloud/types/beta/agent_data.py +26 -0
  91. llama_cloud/types/beta/agent_data_agent_data_params.py +20 -0
  92. llama_cloud/types/beta/agent_data_aggregate_params.py +79 -0
  93. llama_cloud/types/beta/agent_data_aggregate_response.py +17 -0
  94. llama_cloud/types/beta/agent_data_delete_by_query_params.py +43 -0
  95. llama_cloud/types/beta/agent_data_delete_by_query_response.py +11 -0
  96. llama_cloud/types/beta/agent_data_delete_params.py +14 -0
  97. llama_cloud/types/beta/agent_data_delete_response.py +8 -0
  98. llama_cloud/types/beta/agent_data_get_params.py +14 -0
  99. llama_cloud/types/beta/agent_data_search_params.py +69 -0
  100. llama_cloud/types/beta/agent_data_update_params.py +16 -0
  101. llama_cloud/types/beta/batch/__init__.py +12 -0
  102. llama_cloud/types/beta/batch/job_item_get_processing_results_params.py +17 -0
  103. llama_cloud/types/beta/batch/job_item_get_processing_results_response.py +409 -0
  104. llama_cloud/types/beta/batch/job_item_list_params.py +23 -0
  105. llama_cloud/types/beta/batch/job_item_list_response.py +42 -0
  106. llama_cloud/types/beta/batch_cancel_params.py +21 -0
  107. llama_cloud/types/beta/batch_cancel_response.py +23 -0
  108. llama_cloud/types/beta/batch_create_params.py +399 -0
  109. llama_cloud/types/beta/batch_create_response.py +63 -0
  110. llama_cloud/types/beta/batch_get_status_params.py +14 -0
  111. llama_cloud/types/beta/batch_get_status_response.py +73 -0
  112. llama_cloud/types/beta/batch_list_params.py +29 -0
  113. llama_cloud/types/beta/batch_list_response.py +63 -0
  114. llama_cloud/types/beta/directories/__init__.py +15 -0
  115. llama_cloud/types/beta/directories/file_add_params.py +26 -0
  116. llama_cloud/types/beta/directories/file_add_response.py +42 -0
  117. llama_cloud/types/beta/directories/file_delete_params.py +16 -0
  118. llama_cloud/types/beta/directories/file_get_params.py +16 -0
  119. llama_cloud/types/beta/directories/file_get_response.py +42 -0
  120. llama_cloud/types/beta/directories/file_list_params.py +28 -0
  121. llama_cloud/types/beta/directories/file_list_response.py +42 -0
  122. llama_cloud/types/beta/directories/file_update_params.py +27 -0
  123. llama_cloud/types/beta/directories/file_update_response.py +42 -0
  124. llama_cloud/types/beta/directories/file_upload_params.py +24 -0
  125. llama_cloud/types/beta/directories/file_upload_response.py +42 -0
  126. llama_cloud/types/beta/directory_create_params.py +23 -0
  127. llama_cloud/types/beta/directory_create_response.py +36 -0
  128. llama_cloud/types/beta/directory_delete_params.py +14 -0
  129. llama_cloud/types/beta/directory_get_params.py +14 -0
  130. llama_cloud/types/beta/directory_get_response.py +36 -0
  131. llama_cloud/types/beta/directory_list_params.py +24 -0
  132. llama_cloud/types/beta/directory_list_response.py +36 -0
  133. llama_cloud/types/beta/directory_update_params.py +20 -0
  134. llama_cloud/types/beta/directory_update_response.py +36 -0
  135. llama_cloud/types/beta/parse_configuration.py +40 -0
  136. llama_cloud/types/beta/parse_configuration_create_params.py +34 -0
  137. llama_cloud/types/beta/parse_configuration_delete_params.py +14 -0
  138. llama_cloud/types/beta/parse_configuration_get_params.py +14 -0
  139. llama_cloud/types/beta/parse_configuration_list_params.py +24 -0
  140. llama_cloud/types/beta/parse_configuration_query_response.py +28 -0
  141. llama_cloud/types/beta/parse_configuration_update_params.py +22 -0
  142. llama_cloud/types/beta/sheet_create_params.py +22 -0
  143. llama_cloud/types/beta/sheet_delete_job_params.py +14 -0
  144. llama_cloud/types/beta/sheet_get_params.py +16 -0
  145. llama_cloud/types/beta/sheet_get_result_table_params.py +20 -0
  146. llama_cloud/types/beta/sheet_list_params.py +20 -0
  147. llama_cloud/types/beta/sheets_job.py +88 -0
  148. llama_cloud/types/beta/sheets_parsing_config.py +49 -0
  149. llama_cloud/types/beta/sheets_parsing_config_param.py +51 -0
  150. llama_cloud/types/beta/split_category.py +17 -0
  151. llama_cloud/types/beta/split_category_param.py +18 -0
  152. llama_cloud/types/beta/split_create_params.py +36 -0
  153. llama_cloud/types/beta/split_create_response.py +48 -0
  154. llama_cloud/types/beta/split_document_input.py +15 -0
  155. llama_cloud/types/beta/split_document_input_param.py +17 -0
  156. llama_cloud/types/beta/split_get_params.py +14 -0
  157. llama_cloud/types/beta/split_get_response.py +48 -0
  158. llama_cloud/types/beta/split_list_params.py +18 -0
  159. llama_cloud/types/beta/split_list_response.py +48 -0
  160. llama_cloud/types/beta/split_result_response.py +15 -0
  161. llama_cloud/types/beta/split_segment_response.py +20 -0
  162. llama_cloud/types/classifier/__init__.py +15 -0
  163. llama_cloud/types/classifier/classifier_rule.py +25 -0
  164. llama_cloud/types/classifier/classifier_rule_param.py +27 -0
  165. llama_cloud/types/classifier/classify_job.py +51 -0
  166. llama_cloud/types/classifier/classify_job_param.py +53 -0
  167. llama_cloud/types/classifier/classify_parsing_configuration.py +21 -0
  168. llama_cloud/types/classifier/classify_parsing_configuration_param.py +23 -0
  169. llama_cloud/types/classifier/job_create_params.py +30 -0
  170. llama_cloud/types/classifier/job_get_params.py +14 -0
  171. llama_cloud/types/classifier/job_get_results_params.py +14 -0
  172. llama_cloud/types/classifier/job_get_results_response.py +66 -0
  173. llama_cloud/types/classifier/job_list_params.py +18 -0
  174. llama_cloud/types/cohere_embedding.py +37 -40
  175. llama_cloud/types/cohere_embedding_config.py +10 -27
  176. llama_cloud/types/cohere_embedding_config_param.py +17 -0
  177. llama_cloud/types/cohere_embedding_param.py +36 -0
  178. llama_cloud/types/composite_retrieval_mode.py +4 -18
  179. llama_cloud/types/composite_retrieval_result.py +52 -37
  180. llama_cloud/types/data_sink.py +46 -39
  181. llama_cloud/types/data_sink_create_param.py +41 -0
  182. llama_cloud/types/data_sink_create_params.py +44 -0
  183. llama_cloud/types/data_sink_list_params.py +14 -0
  184. llama_cloud/types/data_sink_list_response.py +10 -0
  185. llama_cloud/types/data_sink_update_params.py +40 -0
  186. llama_cloud/types/data_source.py +67 -39
  187. llama_cloud/types/data_source_create_params.py +65 -0
  188. llama_cloud/types/data_source_list_params.py +14 -0
  189. llama_cloud/types/data_source_list_response.py +10 -0
  190. llama_cloud/types/data_source_reader_version_metadata.py +8 -27
  191. llama_cloud/types/data_source_update_params.py +61 -0
  192. llama_cloud/types/extraction/__init__.py +25 -0
  193. llama_cloud/types/extraction/extract_agent.py +41 -0
  194. llama_cloud/types/extraction/extract_config.py +118 -0
  195. llama_cloud/types/extraction/extract_config_param.py +118 -0
  196. llama_cloud/types/extraction/extract_job.py +32 -0
  197. llama_cloud/types/extraction/extract_run.py +64 -0
  198. llama_cloud/types/extraction/extraction_agent_create_params.py +25 -0
  199. llama_cloud/types/extraction/extraction_agent_list_params.py +17 -0
  200. llama_cloud/types/extraction/extraction_agent_list_response.py +10 -0
  201. llama_cloud/types/extraction/extraction_agent_update_params.py +18 -0
  202. llama_cloud/types/extraction/extraction_agents/__init__.py +8 -0
  203. llama_cloud/types/extraction/extraction_agents/schema_generate_schema_params.py +23 -0
  204. llama_cloud/types/extraction/extraction_agents/schema_generate_schema_response.py +14 -0
  205. llama_cloud/types/extraction/extraction_agents/schema_validate_schema_params.py +12 -0
  206. llama_cloud/types/extraction/extraction_agents/schema_validate_schema_response.py +13 -0
  207. llama_cloud/types/extraction/job_create_params.py +38 -0
  208. llama_cloud/types/extraction/job_file_params.py +29 -0
  209. llama_cloud/types/extraction/job_get_result_params.py +14 -0
  210. llama_cloud/types/extraction/job_get_result_response.py +27 -0
  211. llama_cloud/types/extraction/job_list_params.py +11 -0
  212. llama_cloud/types/extraction/job_list_response.py +10 -0
  213. llama_cloud/types/extraction/run_delete_params.py +14 -0
  214. llama_cloud/types/extraction/run_get_by_job_params.py +14 -0
  215. llama_cloud/types/extraction/run_get_params.py +14 -0
  216. llama_cloud/types/extraction/run_list_params.py +15 -0
  217. llama_cloud/types/extraction/webhook_configuration.py +43 -0
  218. llama_cloud/types/extraction/webhook_configuration_param.py +43 -0
  219. llama_cloud/types/extraction_run_params.py +45 -0
  220. llama_cloud/types/fail_page_mode.py +4 -26
  221. llama_cloud/types/file.py +48 -40
  222. llama_cloud/types/file_create_params.py +28 -0
  223. llama_cloud/types/file_create_response.py +38 -0
  224. llama_cloud/types/file_delete_params.py +14 -0
  225. llama_cloud/types/file_get_params.py +16 -0
  226. llama_cloud/types/file_list_params.py +40 -0
  227. llama_cloud/types/file_list_response.py +38 -0
  228. llama_cloud/types/file_query_params.py +61 -0
  229. llama_cloud/types/file_query_response.py +47 -27
  230. llama_cloud/types/gemini_embedding.py +40 -39
  231. llama_cloud/types/gemini_embedding_config.py +10 -27
  232. llama_cloud/types/gemini_embedding_config_param.py +17 -0
  233. llama_cloud/types/gemini_embedding_param.py +39 -0
  234. llama_cloud/types/hugging_face_inference_api_embedding.py +62 -46
  235. llama_cloud/types/hugging_face_inference_api_embedding_config.py +11 -28
  236. llama_cloud/types/hugging_face_inference_api_embedding_config_param.py +17 -0
  237. llama_cloud/types/hugging_face_inference_api_embedding_param.py +60 -0
  238. llama_cloud/types/list_item.py +48 -0
  239. llama_cloud/types/llama_parse_parameters.py +251 -130
  240. llama_cloud/types/llama_parse_parameters_param.py +261 -0
  241. llama_cloud/types/llama_parse_supported_file_extensions.py +84 -310
  242. llama_cloud/types/managed_ingestion_status_response.py +39 -37
  243. llama_cloud/types/message_role.py +4 -46
  244. llama_cloud/types/metadata_filters.py +45 -29
  245. llama_cloud/types/metadata_filters_param.py +58 -0
  246. llama_cloud/types/openai_embedding.py +56 -0
  247. llama_cloud/types/openai_embedding_config.py +17 -0
  248. llama_cloud/types/openai_embedding_config_param.py +17 -0
  249. llama_cloud/types/openai_embedding_param.py +55 -0
  250. llama_cloud/types/page_figure_node_with_score.py +32 -29
  251. llama_cloud/types/page_screenshot_node_with_score.py +23 -29
  252. llama_cloud/types/parsing_create_params.py +586 -0
  253. llama_cloud/types/parsing_create_response.py +33 -0
  254. llama_cloud/types/parsing_get_params.py +27 -0
  255. llama_cloud/types/parsing_get_response.py +364 -0
  256. llama_cloud/types/parsing_languages.py +94 -0
  257. llama_cloud/types/parsing_list_params.py +23 -0
  258. llama_cloud/types/parsing_list_response.py +33 -0
  259. llama_cloud/types/parsing_mode.py +13 -46
  260. llama_cloud/types/parsing_upload_file_params.py +14 -0
  261. llama_cloud/types/parsing_upload_file_response.py +33 -0
  262. llama_cloud/types/pipeline.py +180 -62
  263. llama_cloud/types/pipeline_create_params.py +95 -0
  264. llama_cloud/types/pipeline_get_status_params.py +12 -0
  265. llama_cloud/types/pipeline_list_params.py +23 -0
  266. llama_cloud/types/pipeline_list_response.py +12 -0
  267. llama_cloud/types/pipeline_metadata_config.py +9 -30
  268. llama_cloud/types/pipeline_metadata_config_param.py +17 -0
  269. llama_cloud/types/pipeline_retrieve_params.py +74 -0
  270. llama_cloud/types/pipeline_retrieve_response.py +63 -0
  271. llama_cloud/types/pipeline_type.py +4 -18
  272. llama_cloud/types/pipeline_update_params.py +90 -0
  273. llama_cloud/types/pipeline_upsert_params.py +95 -0
  274. llama_cloud/types/pipelines/__init__.py +38 -0
  275. llama_cloud/types/pipelines/cloud_document.py +29 -0
  276. llama_cloud/types/pipelines/cloud_document_create_param.py +30 -0
  277. llama_cloud/types/pipelines/data_source_get_data_sources_response.py +10 -0
  278. llama_cloud/types/pipelines/data_source_sync_params.py +16 -0
  279. llama_cloud/types/pipelines/data_source_update_data_sources_params.py +25 -0
  280. llama_cloud/types/pipelines/data_source_update_data_sources_response.py +10 -0
  281. llama_cloud/types/pipelines/data_source_update_params.py +15 -0
  282. llama_cloud/types/pipelines/document_create_params.py +14 -0
  283. llama_cloud/types/pipelines/document_create_response.py +10 -0
  284. llama_cloud/types/pipelines/document_get_chunks_response.py +10 -0
  285. llama_cloud/types/pipelines/document_list_params.py +22 -0
  286. llama_cloud/types/pipelines/document_upsert_params.py +14 -0
  287. llama_cloud/types/pipelines/document_upsert_response.py +10 -0
  288. llama_cloud/types/pipelines/file_create_params.py +22 -0
  289. llama_cloud/types/pipelines/file_create_response.py +10 -0
  290. llama_cloud/types/pipelines/file_get_status_counts_params.py +14 -0
  291. llama_cloud/types/pipelines/file_get_status_counts_response.py +24 -0
  292. llama_cloud/types/pipelines/file_list_params.py +22 -0
  293. llama_cloud/types/pipelines/file_update_params.py +15 -0
  294. llama_cloud/types/pipelines/image_get_page_figure_params.py +18 -0
  295. llama_cloud/types/pipelines/image_get_page_screenshot_params.py +16 -0
  296. llama_cloud/types/pipelines/image_list_page_figures_params.py +14 -0
  297. llama_cloud/types/pipelines/image_list_page_figures_response.py +34 -0
  298. llama_cloud/types/pipelines/image_list_page_screenshots_params.py +14 -0
  299. llama_cloud/types/pipelines/image_list_page_screenshots_response.py +25 -0
  300. llama_cloud/types/pipelines/metadata_create_params.py +13 -0
  301. llama_cloud/types/pipelines/metadata_create_response.py +8 -0
  302. llama_cloud/types/pipelines/pipeline_data_source.py +96 -0
  303. llama_cloud/types/pipelines/pipeline_file.py +70 -0
  304. llama_cloud/types/pipelines/text_node.py +89 -0
  305. llama_cloud/types/preset_retrieval_params.py +61 -49
  306. llama_cloud/types/preset_retrieval_params_param.py +71 -0
  307. llama_cloud/types/presigned_url.py +13 -29
  308. llama_cloud/types/project.py +24 -36
  309. llama_cloud/types/project_get_params.py +12 -0
  310. llama_cloud/types/project_list_params.py +14 -0
  311. llama_cloud/types/project_list_response.py +10 -0
  312. llama_cloud/types/re_rank_config_param.py +18 -0
  313. llama_cloud/types/retrieval_mode.py +4 -26
  314. llama_cloud/types/retriever.py +31 -38
  315. llama_cloud/types/retriever_create_params.py +26 -0
  316. llama_cloud/types/retriever_get_params.py +14 -0
  317. llama_cloud/types/retriever_list_params.py +16 -0
  318. llama_cloud/types/retriever_list_response.py +12 -0
  319. llama_cloud/types/retriever_pipeline.py +26 -34
  320. llama_cloud/types/retriever_pipeline_param.py +28 -0
  321. llama_cloud/types/retriever_search_params.py +38 -0
  322. llama_cloud/types/retriever_update_params.py +19 -0
  323. llama_cloud/types/retriever_upsert_params.py +26 -0
  324. llama_cloud/types/retrievers/__init__.py +5 -0
  325. llama_cloud/types/retrievers/retriever_search_params.py +32 -0
  326. llama_cloud/types/shared/__init__.py +21 -0
  327. llama_cloud/types/shared/cloud_astra_db_vector_store.py +39 -0
  328. llama_cloud/types/shared/cloud_az_storage_blob_data_source.py +34 -0
  329. llama_cloud/types/shared/cloud_azure_ai_search_vector_store.py +30 -0
  330. llama_cloud/types/shared/cloud_box_data_source.py +31 -0
  331. llama_cloud/types/shared/cloud_confluence_data_source.py +53 -0
  332. llama_cloud/types/shared/cloud_jira_data_source.py +30 -0
  333. llama_cloud/types/shared/cloud_jira_data_source_v2.py +49 -0
  334. llama_cloud/types/shared/cloud_milvus_vector_store.py +21 -0
  335. llama_cloud/types/shared/cloud_mongodb_atlas_vector_search.py +36 -0
  336. llama_cloud/types/shared/cloud_notion_page_data_source.py +19 -0
  337. llama_cloud/types/shared/cloud_one_drive_data_source.py +32 -0
  338. llama_cloud/types/shared/cloud_pinecone_vector_store.py +32 -0
  339. llama_cloud/types/shared/cloud_postgres_vector_store.py +35 -0
  340. llama_cloud/types/shared/cloud_qdrant_vector_store.py +35 -0
  341. llama_cloud/types/shared/cloud_s3_data_source.py +28 -0
  342. llama_cloud/types/shared/cloud_sharepoint_data_source.py +55 -0
  343. llama_cloud/types/shared/cloud_slack_data_source.py +31 -0
  344. llama_cloud/types/shared/failure_handling_config.py +16 -0
  345. llama_cloud/types/shared/pg_vector_hnsw_settings.py +27 -0
  346. llama_cloud/types/shared_params/__init__.py +21 -0
  347. llama_cloud/types/shared_params/cloud_astra_db_vector_store.py +42 -0
  348. llama_cloud/types/shared_params/cloud_az_storage_blob_data_source.py +41 -0
  349. llama_cloud/types/shared_params/cloud_azure_ai_search_vector_store.py +34 -0
  350. llama_cloud/types/shared_params/cloud_box_data_source.py +40 -0
  351. llama_cloud/types/shared_params/cloud_confluence_data_source.py +58 -0
  352. llama_cloud/types/shared_params/cloud_jira_data_source.py +34 -0
  353. llama_cloud/types/shared_params/cloud_jira_data_source_v2.py +54 -0
  354. llama_cloud/types/shared_params/cloud_milvus_vector_store.py +24 -0
  355. llama_cloud/types/shared_params/cloud_mongodb_atlas_vector_search.py +39 -0
  356. llama_cloud/types/shared_params/cloud_notion_page_data_source.py +23 -0
  357. llama_cloud/types/shared_params/cloud_one_drive_data_source.py +37 -0
  358. llama_cloud/types/shared_params/cloud_pinecone_vector_store.py +35 -0
  359. llama_cloud/types/shared_params/cloud_postgres_vector_store.py +39 -0
  360. llama_cloud/types/shared_params/cloud_qdrant_vector_store.py +37 -0
  361. llama_cloud/types/shared_params/cloud_s3_data_source.py +32 -0
  362. llama_cloud/types/shared_params/cloud_sharepoint_data_source.py +60 -0
  363. llama_cloud/types/shared_params/cloud_slack_data_source.py +35 -0
  364. llama_cloud/types/shared_params/failure_handling_config.py +16 -0
  365. llama_cloud/types/shared_params/pg_vector_hnsw_settings.py +26 -0
  366. llama_cloud/types/sparse_model_config.py +16 -30
  367. llama_cloud/types/sparse_model_config_param.py +25 -0
  368. llama_cloud/types/status_enum.py +4 -34
  369. llama_cloud/types/vertex_ai_embedding_config.py +10 -27
  370. llama_cloud/types/vertex_ai_embedding_config_param.py +17 -0
  371. llama_cloud/types/vertex_text_embedding.py +47 -45
  372. llama_cloud/types/vertex_text_embedding_param.py +45 -0
  373. llama_cloud-1.0.0b4.dist-info/METADATA +546 -0
  374. llama_cloud-1.0.0b4.dist-info/RECORD +376 -0
  375. {llama_cloud-0.1.41.dist-info → llama_cloud-1.0.0b4.dist-info}/WHEEL +1 -1
  376. llama_cloud-1.0.0b4.dist-info/licenses/LICENSE +7 -0
  377. llama_cloud/client.py +0 -108
  378. llama_cloud/core/__init__.py +0 -17
  379. llama_cloud/core/api_error.py +0 -15
  380. llama_cloud/core/client_wrapper.py +0 -51
  381. llama_cloud/core/datetime_utils.py +0 -28
  382. llama_cloud/core/jsonable_encoder.py +0 -106
  383. llama_cloud/core/remove_none_from_dict.py +0 -11
  384. llama_cloud/environment.py +0 -7
  385. llama_cloud/errors/__init__.py +0 -5
  386. llama_cloud/errors/unprocessable_entity_error.py +0 -9
  387. llama_cloud/resources/admin/__init__.py +0 -2
  388. llama_cloud/resources/admin/client.py +0 -196
  389. llama_cloud/resources/agent_deployments/__init__.py +0 -2
  390. llama_cloud/resources/agent_deployments/client.py +0 -160
  391. llama_cloud/resources/alpha/__init__.py +0 -2
  392. llama_cloud/resources/alpha/client.py +0 -112
  393. llama_cloud/resources/beta/client.py +0 -2664
  394. llama_cloud/resources/chat_apps/__init__.py +0 -2
  395. llama_cloud/resources/chat_apps/client.py +0 -616
  396. llama_cloud/resources/classifier/client.py +0 -444
  397. llama_cloud/resources/data_sinks/__init__.py +0 -5
  398. llama_cloud/resources/data_sinks/client.py +0 -535
  399. llama_cloud/resources/data_sinks/types/__init__.py +0 -5
  400. llama_cloud/resources/data_sinks/types/data_sink_update_component.py +0 -22
  401. llama_cloud/resources/data_sources/__init__.py +0 -5
  402. llama_cloud/resources/data_sources/client.py +0 -548
  403. llama_cloud/resources/data_sources/types/__init__.py +0 -6
  404. llama_cloud/resources/data_sources/types/data_source_update_component.py +0 -28
  405. llama_cloud/resources/data_sources/types/data_source_update_custom_metadata_value.py +0 -7
  406. llama_cloud/resources/embedding_model_configs/__init__.py +0 -23
  407. llama_cloud/resources/embedding_model_configs/client.py +0 -420
  408. llama_cloud/resources/embedding_model_configs/types/__init__.py +0 -23
  409. llama_cloud/resources/embedding_model_configs/types/embedding_model_config_create_embedding_config.py +0 -89
  410. llama_cloud/resources/evals/__init__.py +0 -2
  411. llama_cloud/resources/evals/client.py +0 -85
  412. llama_cloud/resources/files/__init__.py +0 -5
  413. llama_cloud/resources/files/client.py +0 -1454
  414. llama_cloud/resources/files/types/__init__.py +0 -5
  415. llama_cloud/resources/files/types/file_create_from_url_resource_info_value.py +0 -7
  416. llama_cloud/resources/jobs/__init__.py +0 -2
  417. llama_cloud/resources/jobs/client.py +0 -164
  418. llama_cloud/resources/llama_extract/__init__.py +0 -27
  419. llama_cloud/resources/llama_extract/client.py +0 -2082
  420. llama_cloud/resources/llama_extract/types/__init__.py +0 -25
  421. llama_cloud/resources/llama_extract/types/extract_agent_create_data_schema.py +0 -9
  422. llama_cloud/resources/llama_extract/types/extract_agent_create_data_schema_zero_value.py +0 -7
  423. llama_cloud/resources/llama_extract/types/extract_agent_update_data_schema.py +0 -9
  424. llama_cloud/resources/llama_extract/types/extract_agent_update_data_schema_zero_value.py +0 -7
  425. llama_cloud/resources/llama_extract/types/extract_job_create_batch_data_schema_override.py +0 -9
  426. llama_cloud/resources/llama_extract/types/extract_job_create_batch_data_schema_override_zero_value.py +0 -7
  427. llama_cloud/resources/llama_extract/types/extract_schema_validate_request_data_schema.py +0 -9
  428. llama_cloud/resources/llama_extract/types/extract_schema_validate_request_data_schema_zero_value.py +0 -7
  429. llama_cloud/resources/llama_extract/types/extract_stateless_request_data_schema.py +0 -9
  430. llama_cloud/resources/llama_extract/types/extract_stateless_request_data_schema_zero_value.py +0 -7
  431. llama_cloud/resources/organizations/__init__.py +0 -2
  432. llama_cloud/resources/organizations/client.py +0 -1448
  433. llama_cloud/resources/parsing/__init__.py +0 -2
  434. llama_cloud/resources/parsing/client.py +0 -2392
  435. llama_cloud/resources/pipelines/client.py +0 -3436
  436. llama_cloud/resources/pipelines/types/__init__.py +0 -29
  437. llama_cloud/resources/pipelines/types/pipeline_file_update_custom_metadata_value.py +0 -7
  438. llama_cloud/resources/pipelines/types/pipeline_update_embedding_config.py +0 -89
  439. llama_cloud/resources/pipelines/types/pipeline_update_transform_config.py +0 -8
  440. llama_cloud/resources/pipelines/types/retrieval_params_search_filters_inference_schema_value.py +0 -7
  441. llama_cloud/resources/projects/__init__.py +0 -2
  442. llama_cloud/resources/projects/client.py +0 -636
  443. llama_cloud/resources/retrievers/client.py +0 -837
  444. llama_cloud/resources/users/__init__.py +0 -2
  445. llama_cloud/resources/users/client.py +0 -155
  446. llama_cloud/types/advanced_mode_transform_config_chunking_config.py +0 -67
  447. llama_cloud/types/advanced_mode_transform_config_segmentation_config.py +0 -45
  448. llama_cloud/types/agent_data.py +0 -40
  449. llama_cloud/types/agent_deployment_list.py +0 -32
  450. llama_cloud/types/agent_deployment_summary.py +0 -39
  451. llama_cloud/types/aggregate_group.py +0 -37
  452. llama_cloud/types/azure_open_ai_embedding.py +0 -49
  453. llama_cloud/types/azure_open_ai_embedding_config.py +0 -34
  454. llama_cloud/types/base_plan.py +0 -53
  455. llama_cloud/types/base_plan_metronome_plan_type.py +0 -17
  456. llama_cloud/types/base_plan_name.py +0 -57
  457. llama_cloud/types/base_plan_plan_frequency.py +0 -25
  458. llama_cloud/types/batch.py +0 -47
  459. llama_cloud/types/batch_item.py +0 -40
  460. llama_cloud/types/batch_paginated_list.py +0 -35
  461. llama_cloud/types/batch_public_output.py +0 -36
  462. llama_cloud/types/billing_period.py +0 -32
  463. llama_cloud/types/box_auth_mechanism.py +0 -17
  464. llama_cloud/types/character_chunking_config.py +0 -32
  465. llama_cloud/types/chat_app.py +0 -46
  466. llama_cloud/types/chat_app_response.py +0 -43
  467. llama_cloud/types/chat_data.py +0 -35
  468. llama_cloud/types/chat_message.py +0 -43
  469. llama_cloud/types/chunk_mode.py +0 -29
  470. llama_cloud/types/classification_result.py +0 -39
  471. llama_cloud/types/classifier_rule.py +0 -43
  472. llama_cloud/types/classify_job.py +0 -47
  473. llama_cloud/types/classify_job_results.py +0 -38
  474. llama_cloud/types/classify_parsing_configuration.py +0 -38
  475. llama_cloud/types/cloud_astra_db_vector_store.py +0 -51
  476. llama_cloud/types/cloud_az_storage_blob_data_source.py +0 -41
  477. llama_cloud/types/cloud_azure_ai_search_vector_store.py +0 -45
  478. llama_cloud/types/cloud_box_data_source.py +0 -42
  479. llama_cloud/types/cloud_confluence_data_source.py +0 -59
  480. llama_cloud/types/cloud_document.py +0 -40
  481. llama_cloud/types/cloud_document_create.py +0 -40
  482. llama_cloud/types/cloud_jira_data_source.py +0 -42
  483. llama_cloud/types/cloud_jira_data_source_v_2.py +0 -52
  484. llama_cloud/types/cloud_jira_data_source_v_2_api_version.py +0 -21
  485. llama_cloud/types/cloud_milvus_vector_store.py +0 -40
  486. llama_cloud/types/cloud_mongo_db_atlas_vector_search.py +0 -52
  487. llama_cloud/types/cloud_notion_page_data_source.py +0 -35
  488. llama_cloud/types/cloud_one_drive_data_source.py +0 -39
  489. llama_cloud/types/cloud_pinecone_vector_store.py +0 -49
  490. llama_cloud/types/cloud_postgres_vector_store.py +0 -44
  491. llama_cloud/types/cloud_qdrant_vector_store.py +0 -51
  492. llama_cloud/types/cloud_s_3_data_source.py +0 -39
  493. llama_cloud/types/cloud_sharepoint_data_source.py +0 -42
  494. llama_cloud/types/cloud_slack_data_source.py +0 -39
  495. llama_cloud/types/composite_retrieved_text_node.py +0 -42
  496. llama_cloud/types/composite_retrieved_text_node_with_score.py +0 -34
  497. llama_cloud/types/configurable_data_sink_names.py +0 -41
  498. llama_cloud/types/configurable_data_source_names.py +0 -57
  499. llama_cloud/types/credit_type.py +0 -32
  500. llama_cloud/types/data_sink_component.py +0 -22
  501. llama_cloud/types/data_sink_create.py +0 -39
  502. llama_cloud/types/data_sink_create_component.py +0 -22
  503. llama_cloud/types/data_source_component.py +0 -28
  504. llama_cloud/types/data_source_create.py +0 -41
  505. llama_cloud/types/data_source_create_component.py +0 -28
  506. llama_cloud/types/data_source_create_custom_metadata_value.py +0 -7
  507. llama_cloud/types/data_source_custom_metadata_value.py +0 -7
  508. llama_cloud/types/data_source_reader_version_metadata_reader_version.py +0 -25
  509. llama_cloud/types/data_source_update_dispatcher_config.py +0 -38
  510. llama_cloud/types/delete_params.py +0 -39
  511. llama_cloud/types/document_chunk_mode.py +0 -17
  512. llama_cloud/types/document_ingestion_job_params.py +0 -43
  513. llama_cloud/types/element_segmentation_config.py +0 -29
  514. llama_cloud/types/embedding_model_config.py +0 -43
  515. llama_cloud/types/embedding_model_config_embedding_config.py +0 -89
  516. llama_cloud/types/embedding_model_config_update.py +0 -33
  517. llama_cloud/types/embedding_model_config_update_embedding_config.py +0 -89
  518. llama_cloud/types/eval_execution_params.py +0 -41
  519. llama_cloud/types/extract_agent.py +0 -48
  520. llama_cloud/types/extract_agent_data_schema_value.py +0 -5
  521. llama_cloud/types/extract_config.py +0 -66
  522. llama_cloud/types/extract_config_priority.py +0 -29
  523. llama_cloud/types/extract_job.py +0 -38
  524. llama_cloud/types/extract_job_create.py +0 -46
  525. llama_cloud/types/extract_job_create_data_schema_override.py +0 -9
  526. llama_cloud/types/extract_job_create_data_schema_override_zero_value.py +0 -7
  527. llama_cloud/types/extract_job_create_priority.py +0 -29
  528. llama_cloud/types/extract_mode.py +0 -29
  529. llama_cloud/types/extract_models.py +0 -53
  530. llama_cloud/types/extract_resultset.py +0 -42
  531. llama_cloud/types/extract_resultset_data.py +0 -11
  532. llama_cloud/types/extract_resultset_data_item_value.py +0 -7
  533. llama_cloud/types/extract_resultset_data_zero_value.py +0 -7
  534. llama_cloud/types/extract_resultset_extraction_metadata_value.py +0 -7
  535. llama_cloud/types/extract_run.py +0 -55
  536. llama_cloud/types/extract_run_data.py +0 -11
  537. llama_cloud/types/extract_run_data_item_value.py +0 -5
  538. llama_cloud/types/extract_run_data_schema_value.py +0 -5
  539. llama_cloud/types/extract_run_data_zero_value.py +0 -5
  540. llama_cloud/types/extract_run_extraction_metadata_value.py +0 -7
  541. llama_cloud/types/extract_schema_generate_response.py +0 -38
  542. llama_cloud/types/extract_schema_generate_response_data_schema_value.py +0 -7
  543. llama_cloud/types/extract_schema_validate_response.py +0 -32
  544. llama_cloud/types/extract_schema_validate_response_data_schema_value.py +0 -7
  545. llama_cloud/types/extract_state.py +0 -29
  546. llama_cloud/types/extract_target.py +0 -17
  547. llama_cloud/types/failure_handling_config.py +0 -37
  548. llama_cloud/types/file_classification.py +0 -41
  549. llama_cloud/types/file_count_by_status_response.py +0 -37
  550. llama_cloud/types/file_create.py +0 -41
  551. llama_cloud/types/file_create_permission_info_value.py +0 -7
  552. llama_cloud/types/file_create_resource_info_value.py +0 -5
  553. llama_cloud/types/file_data.py +0 -36
  554. llama_cloud/types/file_filter.py +0 -40
  555. llama_cloud/types/file_id_presigned_url.py +0 -38
  556. llama_cloud/types/file_parse_public.py +0 -36
  557. llama_cloud/types/file_permission_info_value.py +0 -5
  558. llama_cloud/types/file_resource_info_value.py +0 -5
  559. llama_cloud/types/file_store_info_response.py +0 -34
  560. llama_cloud/types/file_store_info_response_status.py +0 -25
  561. llama_cloud/types/filter_condition.py +0 -29
  562. llama_cloud/types/filter_operation.py +0 -46
  563. llama_cloud/types/filter_operation_eq.py +0 -6
  564. llama_cloud/types/filter_operation_gt.py +0 -6
  565. llama_cloud/types/filter_operation_gte.py +0 -6
  566. llama_cloud/types/filter_operation_includes_item.py +0 -6
  567. llama_cloud/types/filter_operation_lt.py +0 -6
  568. llama_cloud/types/filter_operation_lte.py +0 -6
  569. llama_cloud/types/filter_operator.py +0 -73
  570. llama_cloud/types/free_credits_usage.py +0 -34
  571. llama_cloud/types/http_validation_error.py +0 -32
  572. llama_cloud/types/hugging_face_inference_api_embedding_token.py +0 -5
  573. llama_cloud/types/ingestion_error_response.py +0 -34
  574. llama_cloud/types/input_message.py +0 -40
  575. llama_cloud/types/job_name_mapping.py +0 -49
  576. llama_cloud/types/job_names.py +0 -81
  577. llama_cloud/types/job_record.py +0 -58
  578. llama_cloud/types/job_record_parameters.py +0 -111
  579. llama_cloud/types/job_record_with_usage_metrics.py +0 -36
  580. llama_cloud/types/l_lama_parse_transform_config.py +0 -37
  581. llama_cloud/types/legacy_parse_job_config.py +0 -207
  582. llama_cloud/types/license_info_response.py +0 -34
  583. llama_cloud/types/llama_extract_feature_availability.py +0 -34
  584. llama_cloud/types/llama_extract_mode_availability.py +0 -38
  585. llama_cloud/types/llama_extract_mode_availability_status.py +0 -17
  586. llama_cloud/types/llama_extract_settings.py +0 -67
  587. llama_cloud/types/llama_parse_parameters_priority.py +0 -29
  588. llama_cloud/types/llm_model_data.py +0 -38
  589. llama_cloud/types/llm_parameters.py +0 -39
  590. llama_cloud/types/load_files_job_config.py +0 -35
  591. llama_cloud/types/managed_ingestion_status.py +0 -41
  592. llama_cloud/types/managed_open_ai_embedding.py +0 -36
  593. llama_cloud/types/managed_open_ai_embedding_config.py +0 -34
  594. llama_cloud/types/message_annotation.py +0 -33
  595. llama_cloud/types/metadata_filter.py +0 -44
  596. llama_cloud/types/metadata_filter_value.py +0 -5
  597. llama_cloud/types/metadata_filters_filters_item.py +0 -8
  598. llama_cloud/types/multimodal_parse_resolution.py +0 -17
  599. llama_cloud/types/node_relationship.py +0 -44
  600. llama_cloud/types/none_chunking_config.py +0 -29
  601. llama_cloud/types/none_segmentation_config.py +0 -29
  602. llama_cloud/types/object_type.py +0 -33
  603. llama_cloud/types/open_ai_embedding.py +0 -47
  604. llama_cloud/types/open_ai_embedding_config.py +0 -34
  605. llama_cloud/types/organization.py +0 -43
  606. llama_cloud/types/organization_create.py +0 -35
  607. llama_cloud/types/page_figure_metadata.py +0 -37
  608. llama_cloud/types/page_screenshot_metadata.py +0 -34
  609. llama_cloud/types/page_segmentation_config.py +0 -31
  610. llama_cloud/types/paginated_extract_runs_response.py +0 -39
  611. llama_cloud/types/paginated_jobs_history_with_metrics.py +0 -35
  612. llama_cloud/types/paginated_list_cloud_documents_response.py +0 -35
  613. llama_cloud/types/paginated_list_pipeline_files_response.py +0 -35
  614. llama_cloud/types/paginated_response_agent_data.py +0 -34
  615. llama_cloud/types/paginated_response_aggregate_group.py +0 -34
  616. llama_cloud/types/paginated_response_classify_job.py +0 -34
  617. llama_cloud/types/paginated_response_quota_configuration.py +0 -36
  618. llama_cloud/types/parse_configuration.py +0 -44
  619. llama_cloud/types/parse_configuration_create.py +0 -41
  620. llama_cloud/types/parse_configuration_filter.py +0 -40
  621. llama_cloud/types/parse_configuration_query_response.py +0 -38
  622. llama_cloud/types/parse_job_config.py +0 -149
  623. llama_cloud/types/parse_job_config_priority.py +0 -29
  624. llama_cloud/types/parse_plan_level.py +0 -21
  625. llama_cloud/types/parser_languages.py +0 -361
  626. llama_cloud/types/parsing_history_item.py +0 -39
  627. llama_cloud/types/parsing_job.py +0 -35
  628. llama_cloud/types/parsing_job_json_result.py +0 -32
  629. llama_cloud/types/parsing_job_markdown_result.py +0 -32
  630. llama_cloud/types/parsing_job_structured_result.py +0 -32
  631. llama_cloud/types/parsing_job_text_result.py +0 -32
  632. llama_cloud/types/partition_names.py +0 -45
  633. llama_cloud/types/permission.py +0 -40
  634. llama_cloud/types/pg_vector_distance_method.py +0 -43
  635. llama_cloud/types/pg_vector_hnsw_settings.py +0 -45
  636. llama_cloud/types/pg_vector_vector_type.py +0 -35
  637. llama_cloud/types/pipeline_configuration_hashes.py +0 -37
  638. llama_cloud/types/pipeline_create.py +0 -65
  639. llama_cloud/types/pipeline_create_embedding_config.py +0 -89
  640. llama_cloud/types/pipeline_create_transform_config.py +0 -8
  641. llama_cloud/types/pipeline_data_source.py +0 -55
  642. llama_cloud/types/pipeline_data_source_component.py +0 -28
  643. llama_cloud/types/pipeline_data_source_create.py +0 -36
  644. llama_cloud/types/pipeline_data_source_custom_metadata_value.py +0 -7
  645. llama_cloud/types/pipeline_data_source_status.py +0 -33
  646. llama_cloud/types/pipeline_deployment.py +0 -37
  647. llama_cloud/types/pipeline_embedding_config.py +0 -100
  648. llama_cloud/types/pipeline_file.py +0 -58
  649. llama_cloud/types/pipeline_file_config_hash_value.py +0 -5
  650. llama_cloud/types/pipeline_file_create.py +0 -37
  651. llama_cloud/types/pipeline_file_create_custom_metadata_value.py +0 -7
  652. llama_cloud/types/pipeline_file_custom_metadata_value.py +0 -7
  653. llama_cloud/types/pipeline_file_permission_info_value.py +0 -7
  654. llama_cloud/types/pipeline_file_resource_info_value.py +0 -7
  655. llama_cloud/types/pipeline_file_status.py +0 -33
  656. llama_cloud/types/pipeline_file_update_dispatcher_config.py +0 -38
  657. llama_cloud/types/pipeline_file_updater_config.py +0 -44
  658. llama_cloud/types/pipeline_managed_ingestion_job_params.py +0 -37
  659. llama_cloud/types/pipeline_status.py +0 -17
  660. llama_cloud/types/pipeline_transform_config.py +0 -31
  661. llama_cloud/types/plan_limits.py +0 -53
  662. llama_cloud/types/playground_session.py +0 -51
  663. llama_cloud/types/pooling.py +0 -29
  664. llama_cloud/types/preset_composite_retrieval_params.py +0 -37
  665. llama_cloud/types/preset_retrieval_params_search_filters_inference_schema_value.py +0 -7
  666. llama_cloud/types/project_create.py +0 -35
  667. llama_cloud/types/prompt_conf.py +0 -38
  668. llama_cloud/types/public_model_name.py +0 -97
  669. llama_cloud/types/quota_configuration.py +0 -53
  670. llama_cloud/types/quota_configuration_configuration_type.py +0 -33
  671. llama_cloud/types/quota_configuration_status.py +0 -21
  672. llama_cloud/types/quota_rate_limit_configuration_value.py +0 -38
  673. llama_cloud/types/quota_rate_limit_configuration_value_denominator_units.py +0 -29
  674. llama_cloud/types/re_rank_config.py +0 -35
  675. llama_cloud/types/re_ranker_type.py +0 -41
  676. llama_cloud/types/recurring_credit_grant.py +0 -44
  677. llama_cloud/types/related_node_info.py +0 -36
  678. llama_cloud/types/related_node_info_node_type.py +0 -7
  679. llama_cloud/types/retrieve_results.py +0 -56
  680. llama_cloud/types/retriever_create.py +0 -37
  681. llama_cloud/types/role.py +0 -40
  682. llama_cloud/types/schema_generation_availability.py +0 -33
  683. llama_cloud/types/schema_generation_availability_status.py +0 -17
  684. llama_cloud/types/schema_relax_mode.py +0 -25
  685. llama_cloud/types/semantic_chunking_config.py +0 -32
  686. llama_cloud/types/sentence_chunking_config.py +0 -34
  687. llama_cloud/types/sparse_model_type.py +0 -33
  688. llama_cloud/types/struct_mode.py +0 -33
  689. llama_cloud/types/struct_parse_conf.py +0 -63
  690. llama_cloud/types/supported_llm_model.py +0 -40
  691. llama_cloud/types/supported_llm_model_names.py +0 -69
  692. llama_cloud/types/text_node.py +0 -67
  693. llama_cloud/types/text_node_relationships_value.py +0 -7
  694. llama_cloud/types/text_node_with_score.py +0 -39
  695. llama_cloud/types/token_chunking_config.py +0 -33
  696. llama_cloud/types/update_user_response.py +0 -33
  697. llama_cloud/types/usage_and_plan.py +0 -34
  698. llama_cloud/types/usage_metric_response.py +0 -34
  699. llama_cloud/types/usage_response.py +0 -43
  700. llama_cloud/types/usage_response_active_alerts_item.py +0 -37
  701. llama_cloud/types/user_job_record.py +0 -32
  702. llama_cloud/types/user_organization.py +0 -47
  703. llama_cloud/types/user_organization_create.py +0 -38
  704. llama_cloud/types/user_organization_delete.py +0 -37
  705. llama_cloud/types/user_organization_role.py +0 -42
  706. llama_cloud/types/user_summary.py +0 -38
  707. llama_cloud/types/validation_error.py +0 -34
  708. llama_cloud/types/validation_error_loc_item.py +0 -5
  709. llama_cloud/types/vertex_embedding_mode.py +0 -38
  710. llama_cloud/types/webhook_configuration.py +0 -39
  711. llama_cloud/types/webhook_configuration_webhook_events_item.py +0 -57
  712. llama_cloud-0.1.41.dist-info/LICENSE +0 -21
  713. llama_cloud-0.1.41.dist-info/METADATA +0 -106
  714. llama_cloud-0.1.41.dist-info/RECORD +0 -385
@@ -0,0 +1,2124 @@
1
+ from __future__ import annotations
2
+
3
+ import sys
4
+ import json
5
+ import time
6
+ import uuid
7
+ import email
8
+ import asyncio
9
+ import inspect
10
+ import logging
11
+ import platform
12
+ import warnings
13
+ import email.utils
14
+ from types import TracebackType
15
+ from random import random
16
+ from typing import (
17
+ TYPE_CHECKING,
18
+ Any,
19
+ Dict,
20
+ Type,
21
+ Union,
22
+ Generic,
23
+ Mapping,
24
+ TypeVar,
25
+ Iterable,
26
+ Iterator,
27
+ Optional,
28
+ Generator,
29
+ AsyncIterator,
30
+ cast,
31
+ overload,
32
+ )
33
+ from typing_extensions import Literal, override, get_origin
34
+
35
+ import anyio
36
+ import httpx
37
+ import distro
38
+ import pydantic
39
+ from httpx import URL
40
+ from pydantic import PrivateAttr
41
+
42
+ from . import _exceptions
43
+ from ._qs import Querystring
44
+ from ._files import to_httpx_files, async_to_httpx_files
45
+ from ._types import (
46
+ Body,
47
+ Omit,
48
+ Query,
49
+ Headers,
50
+ Timeout,
51
+ NotGiven,
52
+ ResponseT,
53
+ AnyMapping,
54
+ PostParser,
55
+ BinaryTypes,
56
+ RequestFiles,
57
+ HttpxSendArgs,
58
+ RequestOptions,
59
+ AsyncBinaryTypes,
60
+ HttpxRequestFiles,
61
+ ModelBuilderProtocol,
62
+ not_given,
63
+ )
64
+ from ._utils import is_dict, is_list, asyncify, is_given, lru_cache, is_mapping
65
+ from ._compat import PYDANTIC_V1, model_copy, model_dump
66
+ from ._models import GenericModel, FinalRequestOptions, validate_type, construct_type
67
+ from ._response import (
68
+ APIResponse,
69
+ BaseAPIResponse,
70
+ AsyncAPIResponse,
71
+ extract_response_type,
72
+ )
73
+ from ._constants import (
74
+ DEFAULT_TIMEOUT,
75
+ MAX_RETRY_DELAY,
76
+ DEFAULT_MAX_RETRIES,
77
+ INITIAL_RETRY_DELAY,
78
+ RAW_RESPONSE_HEADER,
79
+ OVERRIDE_CAST_TO_HEADER,
80
+ DEFAULT_CONNECTION_LIMITS,
81
+ )
82
+ from ._streaming import Stream, SSEDecoder, AsyncStream, SSEBytesDecoder
83
+ from ._exceptions import (
84
+ APIStatusError,
85
+ APITimeoutError,
86
+ APIConnectionError,
87
+ APIResponseValidationError,
88
+ )
89
+
90
+ log: logging.Logger = logging.getLogger(__name__)
91
+
92
+ # TODO: make base page type vars covariant
93
+ SyncPageT = TypeVar("SyncPageT", bound="BaseSyncPage[Any]")
94
+ AsyncPageT = TypeVar("AsyncPageT", bound="BaseAsyncPage[Any]")
95
+
96
+
97
+ _T = TypeVar("_T")
98
+ _T_co = TypeVar("_T_co", covariant=True)
99
+
100
+ _StreamT = TypeVar("_StreamT", bound=Stream[Any])
101
+ _AsyncStreamT = TypeVar("_AsyncStreamT", bound=AsyncStream[Any])
102
+
103
+ if TYPE_CHECKING:
104
+ from httpx._config import (
105
+ DEFAULT_TIMEOUT_CONFIG, # pyright: ignore[reportPrivateImportUsage]
106
+ )
107
+
108
+ HTTPX_DEFAULT_TIMEOUT = DEFAULT_TIMEOUT_CONFIG
109
+ else:
110
+ try:
111
+ from httpx._config import DEFAULT_TIMEOUT_CONFIG as HTTPX_DEFAULT_TIMEOUT
112
+ except ImportError:
113
+ # taken from https://github.com/encode/httpx/blob/3ba5fe0d7ac70222590e759c31442b1cab263791/httpx/_config.py#L366
114
+ HTTPX_DEFAULT_TIMEOUT = Timeout(5.0)
115
+
116
+
117
+ class PageInfo:
118
+ """Stores the necessary information to build the request to retrieve the next page.
119
+
120
+ Either `url` or `params` must be set.
121
+ """
122
+
123
+ url: URL | NotGiven
124
+ params: Query | NotGiven
125
+ json: Body | NotGiven
126
+
127
+ @overload
128
+ def __init__(
129
+ self,
130
+ *,
131
+ url: URL,
132
+ ) -> None: ...
133
+
134
+ @overload
135
+ def __init__(
136
+ self,
137
+ *,
138
+ params: Query,
139
+ ) -> None: ...
140
+
141
+ @overload
142
+ def __init__(
143
+ self,
144
+ *,
145
+ json: Body,
146
+ ) -> None: ...
147
+
148
+ def __init__(
149
+ self,
150
+ *,
151
+ url: URL | NotGiven = not_given,
152
+ json: Body | NotGiven = not_given,
153
+ params: Query | NotGiven = not_given,
154
+ ) -> None:
155
+ self.url = url
156
+ self.json = json
157
+ self.params = params
158
+
159
+ @override
160
+ def __repr__(self) -> str:
161
+ if self.url:
162
+ return f"{self.__class__.__name__}(url={self.url})"
163
+ if self.json:
164
+ return f"{self.__class__.__name__}(json={self.json})"
165
+ return f"{self.__class__.__name__}(params={self.params})"
166
+
167
+
168
+ class BasePage(GenericModel, Generic[_T]):
169
+ """
170
+ Defines the core interface for pagination.
171
+
172
+ Type Args:
173
+ ModelT: The pydantic model that represents an item in the response.
174
+
175
+ Methods:
176
+ has_next_page(): Check if there is another page available
177
+ next_page_info(): Get the necessary information to make a request for the next page
178
+ """
179
+
180
+ _options: FinalRequestOptions = PrivateAttr()
181
+ _model: Type[_T] = PrivateAttr()
182
+
183
+ def has_next_page(self) -> bool:
184
+ items = self._get_page_items()
185
+ if not items:
186
+ return False
187
+ return self.next_page_info() is not None
188
+
189
+ def next_page_info(self) -> Optional[PageInfo]: ...
190
+
191
+ def _get_page_items(self) -> Iterable[_T]: # type: ignore[empty-body]
192
+ ...
193
+
194
+ def _params_from_url(self, url: URL) -> httpx.QueryParams:
195
+ # TODO: do we have to preprocess params here?
196
+ return httpx.QueryParams(cast(Any, self._options.params)).merge(url.params)
197
+
198
+ def _info_to_options(self, info: PageInfo) -> FinalRequestOptions:
199
+ options = model_copy(self._options)
200
+ options._strip_raw_response_header()
201
+
202
+ if not isinstance(info.params, NotGiven):
203
+ options.params = {**options.params, **info.params}
204
+ return options
205
+
206
+ if not isinstance(info.url, NotGiven):
207
+ params = self._params_from_url(info.url)
208
+ url = info.url.copy_with(params=params)
209
+ options.params = dict(url.params)
210
+ options.url = str(url)
211
+ return options
212
+
213
+ if not isinstance(info.json, NotGiven):
214
+ if not is_mapping(info.json):
215
+ raise TypeError("Pagination is only supported with mappings")
216
+
217
+ if not options.json_data:
218
+ options.json_data = {**info.json}
219
+ else:
220
+ if not is_mapping(options.json_data):
221
+ raise TypeError("Pagination is only supported with mappings")
222
+
223
+ options.json_data = {**options.json_data, **info.json}
224
+ return options
225
+
226
+ raise ValueError("Unexpected PageInfo state")
227
+
228
+
229
+ class BaseSyncPage(BasePage[_T], Generic[_T]):
230
+ _client: SyncAPIClient = pydantic.PrivateAttr()
231
+
232
+ def _set_private_attributes(
233
+ self,
234
+ client: SyncAPIClient,
235
+ model: Type[_T],
236
+ options: FinalRequestOptions,
237
+ ) -> None:
238
+ if (not PYDANTIC_V1) and getattr(self, "__pydantic_private__", None) is None:
239
+ self.__pydantic_private__ = {}
240
+
241
+ self._model = model
242
+ self._client = client
243
+ self._options = options
244
+
245
+ # Pydantic uses a custom `__iter__` method to support casting BaseModels
246
+ # to dictionaries. e.g. dict(model).
247
+ # As we want to support `for item in page`, this is inherently incompatible
248
+ # with the default pydantic behaviour. It is not possible to support both
249
+ # use cases at once. Fortunately, this is not a big deal as all other pydantic
250
+ # methods should continue to work as expected as there is an alternative method
251
+ # to cast a model to a dictionary, model.dict(), which is used internally
252
+ # by pydantic.
253
+ def __iter__(self) -> Iterator[_T]: # type: ignore
254
+ for page in self.iter_pages():
255
+ for item in page._get_page_items():
256
+ yield item
257
+
258
+ def iter_pages(self: SyncPageT) -> Iterator[SyncPageT]:
259
+ page = self
260
+ while True:
261
+ yield page
262
+ if page.has_next_page():
263
+ page = page.get_next_page()
264
+ else:
265
+ return
266
+
267
+ def get_next_page(self: SyncPageT) -> SyncPageT:
268
+ info = self.next_page_info()
269
+ if not info:
270
+ raise RuntimeError(
271
+ "No next page expected; please check `.has_next_page()` before calling `.get_next_page()`."
272
+ )
273
+
274
+ options = self._info_to_options(info)
275
+ return self._client._request_api_list(self._model, page=self.__class__, options=options)
276
+
277
+
278
+ class AsyncPaginator(Generic[_T, AsyncPageT]):
279
+ def __init__(
280
+ self,
281
+ client: AsyncAPIClient,
282
+ options: FinalRequestOptions,
283
+ page_cls: Type[AsyncPageT],
284
+ model: Type[_T],
285
+ ) -> None:
286
+ self._model = model
287
+ self._client = client
288
+ self._options = options
289
+ self._page_cls = page_cls
290
+
291
+ def __await__(self) -> Generator[Any, None, AsyncPageT]:
292
+ return self._get_page().__await__()
293
+
294
+ async def _get_page(self) -> AsyncPageT:
295
+ def _parser(resp: AsyncPageT) -> AsyncPageT:
296
+ resp._set_private_attributes(
297
+ model=self._model,
298
+ options=self._options,
299
+ client=self._client,
300
+ )
301
+ return resp
302
+
303
+ self._options.post_parser = _parser
304
+
305
+ return await self._client.request(self._page_cls, self._options)
306
+
307
+ async def __aiter__(self) -> AsyncIterator[_T]:
308
+ # https://github.com/microsoft/pyright/issues/3464
309
+ page = cast(
310
+ AsyncPageT,
311
+ await self, # type: ignore
312
+ )
313
+ async for item in page:
314
+ yield item
315
+
316
+
317
+ class BaseAsyncPage(BasePage[_T], Generic[_T]):
318
+ _client: AsyncAPIClient = pydantic.PrivateAttr()
319
+
320
+ def _set_private_attributes(
321
+ self,
322
+ model: Type[_T],
323
+ client: AsyncAPIClient,
324
+ options: FinalRequestOptions,
325
+ ) -> None:
326
+ if (not PYDANTIC_V1) and getattr(self, "__pydantic_private__", None) is None:
327
+ self.__pydantic_private__ = {}
328
+
329
+ self._model = model
330
+ self._client = client
331
+ self._options = options
332
+
333
+ async def __aiter__(self) -> AsyncIterator[_T]:
334
+ async for page in self.iter_pages():
335
+ for item in page._get_page_items():
336
+ yield item
337
+
338
+ async def iter_pages(self: AsyncPageT) -> AsyncIterator[AsyncPageT]:
339
+ page = self
340
+ while True:
341
+ yield page
342
+ if page.has_next_page():
343
+ page = await page.get_next_page()
344
+ else:
345
+ return
346
+
347
+ async def get_next_page(self: AsyncPageT) -> AsyncPageT:
348
+ info = self.next_page_info()
349
+ if not info:
350
+ raise RuntimeError(
351
+ "No next page expected; please check `.has_next_page()` before calling `.get_next_page()`."
352
+ )
353
+
354
+ options = self._info_to_options(info)
355
+ return await self._client._request_api_list(self._model, page=self.__class__, options=options)
356
+
357
+
358
+ _HttpxClientT = TypeVar("_HttpxClientT", bound=Union[httpx.Client, httpx.AsyncClient])
359
+ _DefaultStreamT = TypeVar("_DefaultStreamT", bound=Union[Stream[Any], AsyncStream[Any]])
360
+
361
+
362
+ class BaseClient(Generic[_HttpxClientT, _DefaultStreamT]):
363
+ _client: _HttpxClientT
364
+ _version: str
365
+ _base_url: URL
366
+ max_retries: int
367
+ timeout: Union[float, Timeout, None]
368
+ _strict_response_validation: bool
369
+ _idempotency_header: str | None
370
+ _default_stream_cls: type[_DefaultStreamT] | None = None
371
+
372
+ def __init__(
373
+ self,
374
+ *,
375
+ version: str,
376
+ base_url: str | URL,
377
+ _strict_response_validation: bool,
378
+ max_retries: int = DEFAULT_MAX_RETRIES,
379
+ timeout: float | Timeout | None = DEFAULT_TIMEOUT,
380
+ custom_headers: Mapping[str, str] | None = None,
381
+ custom_query: Mapping[str, object] | None = None,
382
+ ) -> None:
383
+ self._version = version
384
+ self._base_url = self._enforce_trailing_slash(URL(base_url))
385
+ self.max_retries = max_retries
386
+ self.timeout = timeout
387
+ self._custom_headers = custom_headers or {}
388
+ self._custom_query = custom_query or {}
389
+ self._strict_response_validation = _strict_response_validation
390
+ self._idempotency_header = None
391
+ self._platform: Platform | None = None
392
+
393
+ if max_retries is None: # pyright: ignore[reportUnnecessaryComparison]
394
+ raise TypeError(
395
+ "max_retries cannot be None. If you want to disable retries, pass `0`; if you want unlimited retries, pass `math.inf` or a very high number; if you want the default behavior, pass `llama_cloud.DEFAULT_MAX_RETRIES`"
396
+ )
397
+
398
+ def _enforce_trailing_slash(self, url: URL) -> URL:
399
+ if url.raw_path.endswith(b"/"):
400
+ return url
401
+ return url.copy_with(raw_path=url.raw_path + b"/")
402
+
403
+ def _make_status_error_from_response(
404
+ self,
405
+ response: httpx.Response,
406
+ ) -> APIStatusError:
407
+ if response.is_closed and not response.is_stream_consumed:
408
+ # We can't read the response body as it has been closed
409
+ # before it was read. This can happen if an event hook
410
+ # raises a status error.
411
+ body = None
412
+ err_msg = f"Error code: {response.status_code}"
413
+ else:
414
+ err_text = response.text.strip()
415
+ body = err_text
416
+
417
+ try:
418
+ body = json.loads(err_text)
419
+ err_msg = f"Error code: {response.status_code} - {body}"
420
+ except Exception:
421
+ err_msg = err_text or f"Error code: {response.status_code}"
422
+
423
+ return self._make_status_error(err_msg, body=body, response=response)
424
+
425
+ def _make_status_error(
426
+ self,
427
+ err_msg: str,
428
+ *,
429
+ body: object,
430
+ response: httpx.Response,
431
+ ) -> _exceptions.APIStatusError:
432
+ raise NotImplementedError()
433
+
434
+ def _build_headers(self, options: FinalRequestOptions, *, retries_taken: int = 0) -> httpx.Headers:
435
+ custom_headers = options.headers or {}
436
+ headers_dict = _merge_mappings(self.default_headers, custom_headers)
437
+ self._validate_headers(headers_dict, custom_headers)
438
+
439
+ # headers are case-insensitive while dictionaries are not.
440
+ headers = httpx.Headers(headers_dict)
441
+
442
+ idempotency_header = self._idempotency_header
443
+ if idempotency_header and options.idempotency_key and idempotency_header not in headers:
444
+ headers[idempotency_header] = options.idempotency_key
445
+
446
+ # Don't set these headers if they were already set or removed by the caller. We check
447
+ # `custom_headers`, which can contain `Omit()`, instead of `headers` to account for the removal case.
448
+ lower_custom_headers = [header.lower() for header in custom_headers]
449
+ if "x-stainless-retry-count" not in lower_custom_headers:
450
+ headers["x-stainless-retry-count"] = str(retries_taken)
451
+ if "x-stainless-read-timeout" not in lower_custom_headers:
452
+ timeout = self.timeout if isinstance(options.timeout, NotGiven) else options.timeout
453
+ if isinstance(timeout, Timeout):
454
+ timeout = timeout.read
455
+ if timeout is not None:
456
+ headers["x-stainless-read-timeout"] = str(timeout)
457
+
458
+ return headers
459
+
460
+ def _prepare_url(self, url: str) -> URL:
461
+ """
462
+ Merge a URL argument together with any 'base_url' on the client,
463
+ to create the URL used for the outgoing request.
464
+ """
465
+ # Copied from httpx's `_merge_url` method.
466
+ merge_url = URL(url)
467
+ if merge_url.is_relative_url:
468
+ merge_raw_path = self.base_url.raw_path + merge_url.raw_path.lstrip(b"/")
469
+ return self.base_url.copy_with(raw_path=merge_raw_path)
470
+
471
+ return merge_url
472
+
473
+ def _make_sse_decoder(self) -> SSEDecoder | SSEBytesDecoder:
474
+ return SSEDecoder()
475
+
476
+ def _build_request(
477
+ self,
478
+ options: FinalRequestOptions,
479
+ *,
480
+ retries_taken: int = 0,
481
+ ) -> httpx.Request:
482
+ if log.isEnabledFor(logging.DEBUG):
483
+ log.debug(
484
+ "Request options: %s",
485
+ model_dump(
486
+ options,
487
+ exclude_unset=True,
488
+ # Pydantic v1 can't dump every type we support in content, so we exclude it for now.
489
+ exclude={
490
+ "content",
491
+ }
492
+ if PYDANTIC_V1
493
+ else {},
494
+ ),
495
+ )
496
+ kwargs: dict[str, Any] = {}
497
+
498
+ json_data = options.json_data
499
+ if options.extra_json is not None:
500
+ if json_data is None:
501
+ json_data = cast(Body, options.extra_json)
502
+ elif is_mapping(json_data):
503
+ json_data = _merge_mappings(json_data, options.extra_json)
504
+ else:
505
+ raise RuntimeError(f"Unexpected JSON data type, {type(json_data)}, cannot merge with `extra_body`")
506
+
507
+ headers = self._build_headers(options, retries_taken=retries_taken)
508
+ params = _merge_mappings(self.default_query, options.params)
509
+ content_type = headers.get("Content-Type")
510
+ files = options.files
511
+
512
+ # If the given Content-Type header is multipart/form-data then it
513
+ # has to be removed so that httpx can generate the header with
514
+ # additional information for us as it has to be in this form
515
+ # for the server to be able to correctly parse the request:
516
+ # multipart/form-data; boundary=---abc--
517
+ if content_type is not None and content_type.startswith("multipart/form-data"):
518
+ if "boundary" not in content_type:
519
+ # only remove the header if the boundary hasn't been explicitly set
520
+ # as the caller doesn't want httpx to come up with their own boundary
521
+ headers.pop("Content-Type")
522
+
523
+ # As we are now sending multipart/form-data instead of application/json
524
+ # we need to tell httpx to use it, https://www.python-httpx.org/advanced/clients/#multipart-file-encoding
525
+ if json_data:
526
+ if not is_dict(json_data):
527
+ raise TypeError(
528
+ f"Expected query input to be a dictionary for multipart requests but got {type(json_data)} instead."
529
+ )
530
+ kwargs["data"] = self._serialize_multipartform(json_data)
531
+
532
+ # httpx determines whether or not to send a "multipart/form-data"
533
+ # request based on the truthiness of the "files" argument.
534
+ # This gets around that issue by generating a dict value that
535
+ # evaluates to true.
536
+ #
537
+ # https://github.com/encode/httpx/discussions/2399#discussioncomment-3814186
538
+ if not files:
539
+ files = cast(HttpxRequestFiles, ForceMultipartDict())
540
+
541
+ prepared_url = self._prepare_url(options.url)
542
+ if "_" in prepared_url.host:
543
+ # work around https://github.com/encode/httpx/discussions/2880
544
+ kwargs["extensions"] = {"sni_hostname": prepared_url.host.replace("_", "-")}
545
+
546
+ is_body_allowed = options.method.lower() != "get"
547
+
548
+ if is_body_allowed:
549
+ if options.content is not None and json_data is not None:
550
+ raise TypeError("Passing both `content` and `json_data` is not supported")
551
+ if options.content is not None and files is not None:
552
+ raise TypeError("Passing both `content` and `files` is not supported")
553
+ if options.content is not None:
554
+ kwargs["content"] = options.content
555
+ elif isinstance(json_data, bytes):
556
+ kwargs["content"] = json_data
557
+ else:
558
+ kwargs["json"] = json_data if is_given(json_data) else None
559
+ kwargs["files"] = files
560
+ else:
561
+ headers.pop("Content-Type", None)
562
+ kwargs.pop("data", None)
563
+
564
+ # TODO: report this error to httpx
565
+ return self._client.build_request( # pyright: ignore[reportUnknownMemberType]
566
+ headers=headers,
567
+ timeout=self.timeout if isinstance(options.timeout, NotGiven) else options.timeout,
568
+ method=options.method,
569
+ url=prepared_url,
570
+ # the `Query` type that we use is incompatible with qs'
571
+ # `Params` type as it needs to be typed as `Mapping[str, object]`
572
+ # so that passing a `TypedDict` doesn't cause an error.
573
+ # https://github.com/microsoft/pyright/issues/3526#event-6715453066
574
+ params=self.qs.stringify(cast(Mapping[str, Any], params)) if params else None,
575
+ **kwargs,
576
+ )
577
+
578
+ def _serialize_multipartform(self, data: Mapping[object, object]) -> dict[str, object]:
579
+ items = self.qs.stringify_items(
580
+ # TODO: type ignore is required as stringify_items is well typed but we can't be
581
+ # well typed without heavy validation.
582
+ data, # type: ignore
583
+ array_format="brackets",
584
+ )
585
+ serialized: dict[str, object] = {}
586
+ for key, value in items:
587
+ existing = serialized.get(key)
588
+
589
+ if not existing:
590
+ serialized[key] = value
591
+ continue
592
+
593
+ # If a value has already been set for this key then that
594
+ # means we're sending data like `array[]=[1, 2, 3]` and we
595
+ # need to tell httpx that we want to send multiple values with
596
+ # the same key which is done by using a list or a tuple.
597
+ #
598
+ # Note: 2d arrays should never result in the same key at both
599
+ # levels so it's safe to assume that if the value is a list,
600
+ # it was because we changed it to be a list.
601
+ if is_list(existing):
602
+ existing.append(value)
603
+ else:
604
+ serialized[key] = [existing, value]
605
+
606
+ return serialized
607
+
608
+ def _maybe_override_cast_to(self, cast_to: type[ResponseT], options: FinalRequestOptions) -> type[ResponseT]:
609
+ if not is_given(options.headers):
610
+ return cast_to
611
+
612
+ # make a copy of the headers so we don't mutate user-input
613
+ headers = dict(options.headers)
614
+
615
+ # we internally support defining a temporary header to override the
616
+ # default `cast_to` type for use with `.with_raw_response` and `.with_streaming_response`
617
+ # see _response.py for implementation details
618
+ override_cast_to = headers.pop(OVERRIDE_CAST_TO_HEADER, not_given)
619
+ if is_given(override_cast_to):
620
+ options.headers = headers
621
+ return cast(Type[ResponseT], override_cast_to)
622
+
623
+ return cast_to
624
+
625
+ def _should_stream_response_body(self, request: httpx.Request) -> bool:
626
+ return request.headers.get(RAW_RESPONSE_HEADER) == "stream" # type: ignore[no-any-return]
627
+
628
+ def _process_response_data(
629
+ self,
630
+ *,
631
+ data: object,
632
+ cast_to: type[ResponseT],
633
+ response: httpx.Response,
634
+ ) -> ResponseT:
635
+ if data is None:
636
+ return cast(ResponseT, None)
637
+
638
+ if cast_to is object:
639
+ return cast(ResponseT, data)
640
+
641
+ try:
642
+ if inspect.isclass(cast_to) and issubclass(cast_to, ModelBuilderProtocol):
643
+ return cast(ResponseT, cast_to.build(response=response, data=data))
644
+
645
+ if self._strict_response_validation:
646
+ return cast(ResponseT, validate_type(type_=cast_to, value=data))
647
+
648
+ return cast(ResponseT, construct_type(type_=cast_to, value=data))
649
+ except pydantic.ValidationError as err:
650
+ raise APIResponseValidationError(response=response, body=data) from err
651
+
652
+ @property
653
+ def qs(self) -> Querystring:
654
+ return Querystring()
655
+
656
+ @property
657
+ def custom_auth(self) -> httpx.Auth | None:
658
+ return None
659
+
660
+ @property
661
+ def auth_headers(self) -> dict[str, str]:
662
+ return {}
663
+
664
+ @property
665
+ def default_headers(self) -> dict[str, str | Omit]:
666
+ return {
667
+ "Accept": "application/json",
668
+ "Content-Type": "application/json",
669
+ "User-Agent": self.user_agent,
670
+ **self.platform_headers(),
671
+ **self.auth_headers,
672
+ **self._custom_headers,
673
+ }
674
+
675
+ @property
676
+ def default_query(self) -> dict[str, object]:
677
+ return {
678
+ **self._custom_query,
679
+ }
680
+
681
+ def _validate_headers(
682
+ self,
683
+ headers: Headers, # noqa: ARG002
684
+ custom_headers: Headers, # noqa: ARG002
685
+ ) -> None:
686
+ """Validate the given default headers and custom headers.
687
+
688
+ Does nothing by default.
689
+ """
690
+ return
691
+
692
+ @property
693
+ def user_agent(self) -> str:
694
+ return f"{self.__class__.__name__}/Python {self._version}"
695
+
696
+ @property
697
+ def base_url(self) -> URL:
698
+ return self._base_url
699
+
700
+ @base_url.setter
701
+ def base_url(self, url: URL | str) -> None:
702
+ self._base_url = self._enforce_trailing_slash(url if isinstance(url, URL) else URL(url))
703
+
704
+ def platform_headers(self) -> Dict[str, str]:
705
+ # the actual implementation is in a separate `lru_cache` decorated
706
+ # function because adding `lru_cache` to methods will leak memory
707
+ # https://github.com/python/cpython/issues/88476
708
+ return platform_headers(self._version, platform=self._platform)
709
+
710
+ def _parse_retry_after_header(self, response_headers: Optional[httpx.Headers] = None) -> float | None:
711
+ """Returns a float of the number of seconds (not milliseconds) to wait after retrying, or None if unspecified.
712
+
713
+ About the Retry-After header: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After
714
+ See also https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After#syntax
715
+ """
716
+ if response_headers is None:
717
+ return None
718
+
719
+ # First, try the non-standard `retry-after-ms` header for milliseconds,
720
+ # which is more precise than integer-seconds `retry-after`
721
+ try:
722
+ retry_ms_header = response_headers.get("retry-after-ms", None)
723
+ return float(retry_ms_header) / 1000
724
+ except (TypeError, ValueError):
725
+ pass
726
+
727
+ # Next, try parsing `retry-after` header as seconds (allowing nonstandard floats).
728
+ retry_header = response_headers.get("retry-after")
729
+ try:
730
+ # note: the spec indicates that this should only ever be an integer
731
+ # but if someone sends a float there's no reason for us to not respect it
732
+ return float(retry_header)
733
+ except (TypeError, ValueError):
734
+ pass
735
+
736
+ # Last, try parsing `retry-after` as a date.
737
+ retry_date_tuple = email.utils.parsedate_tz(retry_header)
738
+ if retry_date_tuple is None:
739
+ return None
740
+
741
+ retry_date = email.utils.mktime_tz(retry_date_tuple)
742
+ return float(retry_date - time.time())
743
+
744
+ def _calculate_retry_timeout(
745
+ self,
746
+ remaining_retries: int,
747
+ options: FinalRequestOptions,
748
+ response_headers: Optional[httpx.Headers] = None,
749
+ ) -> float:
750
+ max_retries = options.get_max_retries(self.max_retries)
751
+
752
+ # If the API asks us to wait a certain amount of time (and it's a reasonable amount), just do what it says.
753
+ retry_after = self._parse_retry_after_header(response_headers)
754
+ if retry_after is not None and 0 < retry_after <= 60:
755
+ return retry_after
756
+
757
+ # Also cap retry count to 1000 to avoid any potential overflows with `pow`
758
+ nb_retries = min(max_retries - remaining_retries, 1000)
759
+
760
+ # Apply exponential backoff, but not more than the max.
761
+ sleep_seconds = min(INITIAL_RETRY_DELAY * pow(2.0, nb_retries), MAX_RETRY_DELAY)
762
+
763
+ # Apply some jitter, plus-or-minus half a second.
764
+ jitter = 1 - 0.25 * random()
765
+ timeout = sleep_seconds * jitter
766
+ return timeout if timeout >= 0 else 0
767
+
768
+ def _should_retry(self, response: httpx.Response) -> bool:
769
+ # Note: this is not a standard header
770
+ should_retry_header = response.headers.get("x-should-retry")
771
+
772
+ # If the server explicitly says whether or not to retry, obey.
773
+ if should_retry_header == "true":
774
+ log.debug("Retrying as header `x-should-retry` is set to `true`")
775
+ return True
776
+ if should_retry_header == "false":
777
+ log.debug("Not retrying as header `x-should-retry` is set to `false`")
778
+ return False
779
+
780
+ # Retry on request timeouts.
781
+ if response.status_code == 408:
782
+ log.debug("Retrying due to status code %i", response.status_code)
783
+ return True
784
+
785
+ # Retry on lock timeouts.
786
+ if response.status_code == 409:
787
+ log.debug("Retrying due to status code %i", response.status_code)
788
+ return True
789
+
790
+ # Retry on rate limits.
791
+ if response.status_code == 429:
792
+ log.debug("Retrying due to status code %i", response.status_code)
793
+ return True
794
+
795
+ # Retry internal errors.
796
+ if response.status_code >= 500:
797
+ log.debug("Retrying due to status code %i", response.status_code)
798
+ return True
799
+
800
+ log.debug("Not retrying")
801
+ return False
802
+
803
+ def _idempotency_key(self) -> str:
804
+ return f"stainless-python-retry-{uuid.uuid4()}"
805
+
806
+
807
+ class _DefaultHttpxClient(httpx.Client):
808
+ def __init__(self, **kwargs: Any) -> None:
809
+ kwargs.setdefault("timeout", DEFAULT_TIMEOUT)
810
+ kwargs.setdefault("limits", DEFAULT_CONNECTION_LIMITS)
811
+ kwargs.setdefault("follow_redirects", True)
812
+ super().__init__(**kwargs)
813
+
814
+
815
+ if TYPE_CHECKING:
816
+ DefaultHttpxClient = httpx.Client
817
+ """An alias to `httpx.Client` that provides the same defaults that this SDK
818
+ uses internally.
819
+
820
+ This is useful because overriding the `http_client` with your own instance of
821
+ `httpx.Client` will result in httpx's defaults being used, not ours.
822
+ """
823
+ else:
824
+ DefaultHttpxClient = _DefaultHttpxClient
825
+
826
+
827
+ class SyncHttpxClientWrapper(DefaultHttpxClient):
828
+ def __del__(self) -> None:
829
+ if self.is_closed:
830
+ return
831
+
832
+ try:
833
+ self.close()
834
+ except Exception:
835
+ pass
836
+
837
+
838
+ class SyncAPIClient(BaseClient[httpx.Client, Stream[Any]]):
839
+ _client: httpx.Client
840
+ _default_stream_cls: type[Stream[Any]] | None = None
841
+
842
+ def __init__(
843
+ self,
844
+ *,
845
+ version: str,
846
+ base_url: str | URL,
847
+ max_retries: int = DEFAULT_MAX_RETRIES,
848
+ timeout: float | Timeout | None | NotGiven = not_given,
849
+ http_client: httpx.Client | None = None,
850
+ custom_headers: Mapping[str, str] | None = None,
851
+ custom_query: Mapping[str, object] | None = None,
852
+ _strict_response_validation: bool,
853
+ ) -> None:
854
+ if not is_given(timeout):
855
+ # if the user passed in a custom http client with a non-default
856
+ # timeout set then we use that timeout.
857
+ #
858
+ # note: there is an edge case here where the user passes in a client
859
+ # where they've explicitly set the timeout to match the default timeout
860
+ # as this check is structural, meaning that we'll think they didn't
861
+ # pass in a timeout and will ignore it
862
+ if http_client and http_client.timeout != HTTPX_DEFAULT_TIMEOUT:
863
+ timeout = http_client.timeout
864
+ else:
865
+ timeout = DEFAULT_TIMEOUT
866
+
867
+ if http_client is not None and not isinstance(http_client, httpx.Client): # pyright: ignore[reportUnnecessaryIsInstance]
868
+ raise TypeError(
869
+ f"Invalid `http_client` argument; Expected an instance of `httpx.Client` but got {type(http_client)}"
870
+ )
871
+
872
+ super().__init__(
873
+ version=version,
874
+ # cast to a valid type because mypy doesn't understand our type narrowing
875
+ timeout=cast(Timeout, timeout),
876
+ base_url=base_url,
877
+ max_retries=max_retries,
878
+ custom_query=custom_query,
879
+ custom_headers=custom_headers,
880
+ _strict_response_validation=_strict_response_validation,
881
+ )
882
+ self._client = http_client or SyncHttpxClientWrapper(
883
+ base_url=base_url,
884
+ # cast to a valid type because mypy doesn't understand our type narrowing
885
+ timeout=cast(Timeout, timeout),
886
+ )
887
+
888
+ def is_closed(self) -> bool:
889
+ return self._client.is_closed
890
+
891
+ def close(self) -> None:
892
+ """Close the underlying HTTPX client.
893
+
894
+ The client will *not* be usable after this.
895
+ """
896
+ # If an error is thrown while constructing a client, self._client
897
+ # may not be present
898
+ if hasattr(self, "_client"):
899
+ self._client.close()
900
+
901
+ def __enter__(self: _T) -> _T:
902
+ return self
903
+
904
+ def __exit__(
905
+ self,
906
+ exc_type: type[BaseException] | None,
907
+ exc: BaseException | None,
908
+ exc_tb: TracebackType | None,
909
+ ) -> None:
910
+ self.close()
911
+
912
+ def _prepare_options(
913
+ self,
914
+ options: FinalRequestOptions, # noqa: ARG002
915
+ ) -> FinalRequestOptions:
916
+ """Hook for mutating the given options"""
917
+ return options
918
+
919
+ def _prepare_request(
920
+ self,
921
+ request: httpx.Request, # noqa: ARG002
922
+ ) -> None:
923
+ """This method is used as a callback for mutating the `Request` object
924
+ after it has been constructed.
925
+ This is useful for cases where you want to add certain headers based off of
926
+ the request properties, e.g. `url`, `method` etc.
927
+ """
928
+ return None
929
+
930
+ @overload
931
+ def request(
932
+ self,
933
+ cast_to: Type[ResponseT],
934
+ options: FinalRequestOptions,
935
+ *,
936
+ stream: Literal[True],
937
+ stream_cls: Type[_StreamT],
938
+ ) -> _StreamT: ...
939
+
940
+ @overload
941
+ def request(
942
+ self,
943
+ cast_to: Type[ResponseT],
944
+ options: FinalRequestOptions,
945
+ *,
946
+ stream: Literal[False] = False,
947
+ ) -> ResponseT: ...
948
+
949
+ @overload
950
+ def request(
951
+ self,
952
+ cast_to: Type[ResponseT],
953
+ options: FinalRequestOptions,
954
+ *,
955
+ stream: bool = False,
956
+ stream_cls: Type[_StreamT] | None = None,
957
+ ) -> ResponseT | _StreamT: ...
958
+
959
+ def request(
960
+ self,
961
+ cast_to: Type[ResponseT],
962
+ options: FinalRequestOptions,
963
+ *,
964
+ stream: bool = False,
965
+ stream_cls: type[_StreamT] | None = None,
966
+ ) -> ResponseT | _StreamT:
967
+ cast_to = self._maybe_override_cast_to(cast_to, options)
968
+
969
+ # create a copy of the options we were given so that if the
970
+ # options are mutated later & we then retry, the retries are
971
+ # given the original options
972
+ input_options = model_copy(options)
973
+ if input_options.idempotency_key is None and input_options.method.lower() != "get":
974
+ # ensure the idempotency key is reused between requests
975
+ input_options.idempotency_key = self._idempotency_key()
976
+
977
+ response: httpx.Response | None = None
978
+ max_retries = input_options.get_max_retries(self.max_retries)
979
+
980
+ retries_taken = 0
981
+ for retries_taken in range(max_retries + 1):
982
+ options = model_copy(input_options)
983
+ options = self._prepare_options(options)
984
+
985
+ remaining_retries = max_retries - retries_taken
986
+ request = self._build_request(options, retries_taken=retries_taken)
987
+ self._prepare_request(request)
988
+
989
+ kwargs: HttpxSendArgs = {}
990
+ if self.custom_auth is not None:
991
+ kwargs["auth"] = self.custom_auth
992
+
993
+ if options.follow_redirects is not None:
994
+ kwargs["follow_redirects"] = options.follow_redirects
995
+
996
+ log.debug("Sending HTTP Request: %s %s", request.method, request.url)
997
+
998
+ response = None
999
+ try:
1000
+ response = self._client.send(
1001
+ request,
1002
+ stream=stream or self._should_stream_response_body(request=request),
1003
+ **kwargs,
1004
+ )
1005
+ except httpx.TimeoutException as err:
1006
+ log.debug("Encountered httpx.TimeoutException", exc_info=True)
1007
+
1008
+ if remaining_retries > 0:
1009
+ self._sleep_for_retry(
1010
+ retries_taken=retries_taken,
1011
+ max_retries=max_retries,
1012
+ options=input_options,
1013
+ response=None,
1014
+ )
1015
+ continue
1016
+
1017
+ log.debug("Raising timeout error")
1018
+ raise APITimeoutError(request=request) from err
1019
+ except Exception as err:
1020
+ log.debug("Encountered Exception", exc_info=True)
1021
+
1022
+ if remaining_retries > 0:
1023
+ self._sleep_for_retry(
1024
+ retries_taken=retries_taken,
1025
+ max_retries=max_retries,
1026
+ options=input_options,
1027
+ response=None,
1028
+ )
1029
+ continue
1030
+
1031
+ log.debug("Raising connection error")
1032
+ raise APIConnectionError(request=request) from err
1033
+
1034
+ log.debug(
1035
+ 'HTTP Response: %s %s "%i %s" %s',
1036
+ request.method,
1037
+ request.url,
1038
+ response.status_code,
1039
+ response.reason_phrase,
1040
+ response.headers,
1041
+ )
1042
+
1043
+ try:
1044
+ response.raise_for_status()
1045
+ except httpx.HTTPStatusError as err: # thrown on 4xx and 5xx status code
1046
+ log.debug("Encountered httpx.HTTPStatusError", exc_info=True)
1047
+
1048
+ if remaining_retries > 0 and self._should_retry(err.response):
1049
+ err.response.close()
1050
+ self._sleep_for_retry(
1051
+ retries_taken=retries_taken,
1052
+ max_retries=max_retries,
1053
+ options=input_options,
1054
+ response=response,
1055
+ )
1056
+ continue
1057
+
1058
+ # If the response is streamed then we need to explicitly read the response
1059
+ # to completion before attempting to access the response text.
1060
+ if not err.response.is_closed:
1061
+ err.response.read()
1062
+
1063
+ log.debug("Re-raising status error")
1064
+ raise self._make_status_error_from_response(err.response) from None
1065
+
1066
+ break
1067
+
1068
+ assert response is not None, "could not resolve response (should never happen)"
1069
+ return self._process_response(
1070
+ cast_to=cast_to,
1071
+ options=options,
1072
+ response=response,
1073
+ stream=stream,
1074
+ stream_cls=stream_cls,
1075
+ retries_taken=retries_taken,
1076
+ )
1077
+
1078
+ def _sleep_for_retry(
1079
+ self, *, retries_taken: int, max_retries: int, options: FinalRequestOptions, response: httpx.Response | None
1080
+ ) -> None:
1081
+ remaining_retries = max_retries - retries_taken
1082
+ if remaining_retries == 1:
1083
+ log.debug("1 retry left")
1084
+ else:
1085
+ log.debug("%i retries left", remaining_retries)
1086
+
1087
+ timeout = self._calculate_retry_timeout(remaining_retries, options, response.headers if response else None)
1088
+ log.info("Retrying request to %s in %f seconds", options.url, timeout)
1089
+
1090
+ time.sleep(timeout)
1091
+
1092
+ def _process_response(
1093
+ self,
1094
+ *,
1095
+ cast_to: Type[ResponseT],
1096
+ options: FinalRequestOptions,
1097
+ response: httpx.Response,
1098
+ stream: bool,
1099
+ stream_cls: type[Stream[Any]] | type[AsyncStream[Any]] | None,
1100
+ retries_taken: int = 0,
1101
+ ) -> ResponseT:
1102
+ origin = get_origin(cast_to) or cast_to
1103
+
1104
+ if (
1105
+ inspect.isclass(origin)
1106
+ and issubclass(origin, BaseAPIResponse)
1107
+ # we only want to actually return the custom BaseAPIResponse class if we're
1108
+ # returning the raw response, or if we're not streaming SSE, as if we're streaming
1109
+ # SSE then `cast_to` doesn't actively reflect the type we need to parse into
1110
+ and (not stream or bool(response.request.headers.get(RAW_RESPONSE_HEADER)))
1111
+ ):
1112
+ if not issubclass(origin, APIResponse):
1113
+ raise TypeError(f"API Response types must subclass {APIResponse}; Received {origin}")
1114
+
1115
+ response_cls = cast("type[BaseAPIResponse[Any]]", cast_to)
1116
+ return cast(
1117
+ ResponseT,
1118
+ response_cls(
1119
+ raw=response,
1120
+ client=self,
1121
+ cast_to=extract_response_type(response_cls),
1122
+ stream=stream,
1123
+ stream_cls=stream_cls,
1124
+ options=options,
1125
+ retries_taken=retries_taken,
1126
+ ),
1127
+ )
1128
+
1129
+ if cast_to == httpx.Response:
1130
+ return cast(ResponseT, response)
1131
+
1132
+ api_response = APIResponse(
1133
+ raw=response,
1134
+ client=self,
1135
+ cast_to=cast("type[ResponseT]", cast_to), # pyright: ignore[reportUnnecessaryCast]
1136
+ stream=stream,
1137
+ stream_cls=stream_cls,
1138
+ options=options,
1139
+ retries_taken=retries_taken,
1140
+ )
1141
+ if bool(response.request.headers.get(RAW_RESPONSE_HEADER)):
1142
+ return cast(ResponseT, api_response)
1143
+
1144
+ return api_response.parse()
1145
+
1146
+ def _request_api_list(
1147
+ self,
1148
+ model: Type[object],
1149
+ page: Type[SyncPageT],
1150
+ options: FinalRequestOptions,
1151
+ ) -> SyncPageT:
1152
+ def _parser(resp: SyncPageT) -> SyncPageT:
1153
+ resp._set_private_attributes(
1154
+ client=self,
1155
+ model=model,
1156
+ options=options,
1157
+ )
1158
+ return resp
1159
+
1160
+ options.post_parser = _parser
1161
+
1162
+ return self.request(page, options, stream=False)
1163
+
1164
+ @overload
1165
+ def get(
1166
+ self,
1167
+ path: str,
1168
+ *,
1169
+ cast_to: Type[ResponseT],
1170
+ options: RequestOptions = {},
1171
+ stream: Literal[False] = False,
1172
+ ) -> ResponseT: ...
1173
+
1174
+ @overload
1175
+ def get(
1176
+ self,
1177
+ path: str,
1178
+ *,
1179
+ cast_to: Type[ResponseT],
1180
+ options: RequestOptions = {},
1181
+ stream: Literal[True],
1182
+ stream_cls: type[_StreamT],
1183
+ ) -> _StreamT: ...
1184
+
1185
+ @overload
1186
+ def get(
1187
+ self,
1188
+ path: str,
1189
+ *,
1190
+ cast_to: Type[ResponseT],
1191
+ options: RequestOptions = {},
1192
+ stream: bool,
1193
+ stream_cls: type[_StreamT] | None = None,
1194
+ ) -> ResponseT | _StreamT: ...
1195
+
1196
+ def get(
1197
+ self,
1198
+ path: str,
1199
+ *,
1200
+ cast_to: Type[ResponseT],
1201
+ options: RequestOptions = {},
1202
+ stream: bool = False,
1203
+ stream_cls: type[_StreamT] | None = None,
1204
+ ) -> ResponseT | _StreamT:
1205
+ opts = FinalRequestOptions.construct(method="get", url=path, **options)
1206
+ # cast is required because mypy complains about returning Any even though
1207
+ # it understands the type variables
1208
+ return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls))
1209
+
1210
+ @overload
1211
+ def post(
1212
+ self,
1213
+ path: str,
1214
+ *,
1215
+ cast_to: Type[ResponseT],
1216
+ body: Body | None = None,
1217
+ content: BinaryTypes | None = None,
1218
+ options: RequestOptions = {},
1219
+ files: RequestFiles | None = None,
1220
+ stream: Literal[False] = False,
1221
+ ) -> ResponseT: ...
1222
+
1223
+ @overload
1224
+ def post(
1225
+ self,
1226
+ path: str,
1227
+ *,
1228
+ cast_to: Type[ResponseT],
1229
+ body: Body | None = None,
1230
+ content: BinaryTypes | None = None,
1231
+ options: RequestOptions = {},
1232
+ files: RequestFiles | None = None,
1233
+ stream: Literal[True],
1234
+ stream_cls: type[_StreamT],
1235
+ ) -> _StreamT: ...
1236
+
1237
+ @overload
1238
+ def post(
1239
+ self,
1240
+ path: str,
1241
+ *,
1242
+ cast_to: Type[ResponseT],
1243
+ body: Body | None = None,
1244
+ content: BinaryTypes | None = None,
1245
+ options: RequestOptions = {},
1246
+ files: RequestFiles | None = None,
1247
+ stream: bool,
1248
+ stream_cls: type[_StreamT] | None = None,
1249
+ ) -> ResponseT | _StreamT: ...
1250
+
1251
+ def post(
1252
+ self,
1253
+ path: str,
1254
+ *,
1255
+ cast_to: Type[ResponseT],
1256
+ body: Body | None = None,
1257
+ content: BinaryTypes | None = None,
1258
+ options: RequestOptions = {},
1259
+ files: RequestFiles | None = None,
1260
+ stream: bool = False,
1261
+ stream_cls: type[_StreamT] | None = None,
1262
+ ) -> ResponseT | _StreamT:
1263
+ if body is not None and content is not None:
1264
+ raise TypeError("Passing both `body` and `content` is not supported")
1265
+ if files is not None and content is not None:
1266
+ raise TypeError("Passing both `files` and `content` is not supported")
1267
+ if isinstance(body, bytes):
1268
+ warnings.warn(
1269
+ "Passing raw bytes as `body` is deprecated and will be removed in a future version. "
1270
+ "Please pass raw bytes via the `content` parameter instead.",
1271
+ DeprecationWarning,
1272
+ stacklevel=2,
1273
+ )
1274
+ opts = FinalRequestOptions.construct(
1275
+ method="post", url=path, json_data=body, content=content, files=to_httpx_files(files), **options
1276
+ )
1277
+ return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls))
1278
+
1279
+ def patch(
1280
+ self,
1281
+ path: str,
1282
+ *,
1283
+ cast_to: Type[ResponseT],
1284
+ body: Body | None = None,
1285
+ content: BinaryTypes | None = None,
1286
+ files: RequestFiles | None = None,
1287
+ options: RequestOptions = {},
1288
+ ) -> ResponseT:
1289
+ if body is not None and content is not None:
1290
+ raise TypeError("Passing both `body` and `content` is not supported")
1291
+ if files is not None and content is not None:
1292
+ raise TypeError("Passing both `files` and `content` is not supported")
1293
+ if isinstance(body, bytes):
1294
+ warnings.warn(
1295
+ "Passing raw bytes as `body` is deprecated and will be removed in a future version. "
1296
+ "Please pass raw bytes via the `content` parameter instead.",
1297
+ DeprecationWarning,
1298
+ stacklevel=2,
1299
+ )
1300
+ opts = FinalRequestOptions.construct(
1301
+ method="patch", url=path, json_data=body, content=content, files=to_httpx_files(files), **options
1302
+ )
1303
+ return self.request(cast_to, opts)
1304
+
1305
+ def put(
1306
+ self,
1307
+ path: str,
1308
+ *,
1309
+ cast_to: Type[ResponseT],
1310
+ body: Body | None = None,
1311
+ content: BinaryTypes | None = None,
1312
+ files: RequestFiles | None = None,
1313
+ options: RequestOptions = {},
1314
+ ) -> ResponseT:
1315
+ if body is not None and content is not None:
1316
+ raise TypeError("Passing both `body` and `content` is not supported")
1317
+ if files is not None and content is not None:
1318
+ raise TypeError("Passing both `files` and `content` is not supported")
1319
+ if isinstance(body, bytes):
1320
+ warnings.warn(
1321
+ "Passing raw bytes as `body` is deprecated and will be removed in a future version. "
1322
+ "Please pass raw bytes via the `content` parameter instead.",
1323
+ DeprecationWarning,
1324
+ stacklevel=2,
1325
+ )
1326
+ opts = FinalRequestOptions.construct(
1327
+ method="put", url=path, json_data=body, content=content, files=to_httpx_files(files), **options
1328
+ )
1329
+ return self.request(cast_to, opts)
1330
+
1331
+ def delete(
1332
+ self,
1333
+ path: str,
1334
+ *,
1335
+ cast_to: Type[ResponseT],
1336
+ body: Body | None = None,
1337
+ content: BinaryTypes | None = None,
1338
+ options: RequestOptions = {},
1339
+ ) -> ResponseT:
1340
+ if body is not None and content is not None:
1341
+ raise TypeError("Passing both `body` and `content` is not supported")
1342
+ if isinstance(body, bytes):
1343
+ warnings.warn(
1344
+ "Passing raw bytes as `body` is deprecated and will be removed in a future version. "
1345
+ "Please pass raw bytes via the `content` parameter instead.",
1346
+ DeprecationWarning,
1347
+ stacklevel=2,
1348
+ )
1349
+ opts = FinalRequestOptions.construct(method="delete", url=path, json_data=body, content=content, **options)
1350
+ return self.request(cast_to, opts)
1351
+
1352
+ def get_api_list(
1353
+ self,
1354
+ path: str,
1355
+ *,
1356
+ model: Type[object],
1357
+ page: Type[SyncPageT],
1358
+ body: Body | None = None,
1359
+ options: RequestOptions = {},
1360
+ method: str = "get",
1361
+ ) -> SyncPageT:
1362
+ opts = FinalRequestOptions.construct(method=method, url=path, json_data=body, **options)
1363
+ return self._request_api_list(model, page, opts)
1364
+
1365
+
1366
+ class _DefaultAsyncHttpxClient(httpx.AsyncClient):
1367
+ def __init__(self, **kwargs: Any) -> None:
1368
+ kwargs.setdefault("timeout", DEFAULT_TIMEOUT)
1369
+ kwargs.setdefault("limits", DEFAULT_CONNECTION_LIMITS)
1370
+ kwargs.setdefault("follow_redirects", True)
1371
+ super().__init__(**kwargs)
1372
+
1373
+
1374
+ try:
1375
+ import httpx_aiohttp
1376
+ except ImportError:
1377
+
1378
+ class _DefaultAioHttpClient(httpx.AsyncClient):
1379
+ def __init__(self, **_kwargs: Any) -> None:
1380
+ raise RuntimeError("To use the aiohttp client you must have installed the package with the `aiohttp` extra")
1381
+ else:
1382
+
1383
+ class _DefaultAioHttpClient(httpx_aiohttp.HttpxAiohttpClient): # type: ignore
1384
+ def __init__(self, **kwargs: Any) -> None:
1385
+ kwargs.setdefault("timeout", DEFAULT_TIMEOUT)
1386
+ kwargs.setdefault("limits", DEFAULT_CONNECTION_LIMITS)
1387
+ kwargs.setdefault("follow_redirects", True)
1388
+
1389
+ super().__init__(**kwargs)
1390
+
1391
+
1392
+ if TYPE_CHECKING:
1393
+ DefaultAsyncHttpxClient = httpx.AsyncClient
1394
+ """An alias to `httpx.AsyncClient` that provides the same defaults that this SDK
1395
+ uses internally.
1396
+
1397
+ This is useful because overriding the `http_client` with your own instance of
1398
+ `httpx.AsyncClient` will result in httpx's defaults being used, not ours.
1399
+ """
1400
+
1401
+ DefaultAioHttpClient = httpx.AsyncClient
1402
+ """An alias to `httpx.AsyncClient` that changes the default HTTP transport to `aiohttp`."""
1403
+ else:
1404
+ DefaultAsyncHttpxClient = _DefaultAsyncHttpxClient
1405
+ DefaultAioHttpClient = _DefaultAioHttpClient
1406
+
1407
+
1408
+ class AsyncHttpxClientWrapper(DefaultAsyncHttpxClient):
1409
+ def __del__(self) -> None:
1410
+ if self.is_closed:
1411
+ return
1412
+
1413
+ try:
1414
+ # TODO(someday): support non asyncio runtimes here
1415
+ asyncio.get_running_loop().create_task(self.aclose())
1416
+ except Exception:
1417
+ pass
1418
+
1419
+
1420
+ class AsyncAPIClient(BaseClient[httpx.AsyncClient, AsyncStream[Any]]):
1421
+ _client: httpx.AsyncClient
1422
+ _default_stream_cls: type[AsyncStream[Any]] | None = None
1423
+
1424
+ def __init__(
1425
+ self,
1426
+ *,
1427
+ version: str,
1428
+ base_url: str | URL,
1429
+ _strict_response_validation: bool,
1430
+ max_retries: int = DEFAULT_MAX_RETRIES,
1431
+ timeout: float | Timeout | None | NotGiven = not_given,
1432
+ http_client: httpx.AsyncClient | None = None,
1433
+ custom_headers: Mapping[str, str] | None = None,
1434
+ custom_query: Mapping[str, object] | None = None,
1435
+ ) -> None:
1436
+ if not is_given(timeout):
1437
+ # if the user passed in a custom http client with a non-default
1438
+ # timeout set then we use that timeout.
1439
+ #
1440
+ # note: there is an edge case here where the user passes in a client
1441
+ # where they've explicitly set the timeout to match the default timeout
1442
+ # as this check is structural, meaning that we'll think they didn't
1443
+ # pass in a timeout and will ignore it
1444
+ if http_client and http_client.timeout != HTTPX_DEFAULT_TIMEOUT:
1445
+ timeout = http_client.timeout
1446
+ else:
1447
+ timeout = DEFAULT_TIMEOUT
1448
+
1449
+ if http_client is not None and not isinstance(http_client, httpx.AsyncClient): # pyright: ignore[reportUnnecessaryIsInstance]
1450
+ raise TypeError(
1451
+ f"Invalid `http_client` argument; Expected an instance of `httpx.AsyncClient` but got {type(http_client)}"
1452
+ )
1453
+
1454
+ super().__init__(
1455
+ version=version,
1456
+ base_url=base_url,
1457
+ # cast to a valid type because mypy doesn't understand our type narrowing
1458
+ timeout=cast(Timeout, timeout),
1459
+ max_retries=max_retries,
1460
+ custom_query=custom_query,
1461
+ custom_headers=custom_headers,
1462
+ _strict_response_validation=_strict_response_validation,
1463
+ )
1464
+ self._client = http_client or AsyncHttpxClientWrapper(
1465
+ base_url=base_url,
1466
+ # cast to a valid type because mypy doesn't understand our type narrowing
1467
+ timeout=cast(Timeout, timeout),
1468
+ )
1469
+
1470
+ def is_closed(self) -> bool:
1471
+ return self._client.is_closed
1472
+
1473
+ async def close(self) -> None:
1474
+ """Close the underlying HTTPX client.
1475
+
1476
+ The client will *not* be usable after this.
1477
+ """
1478
+ await self._client.aclose()
1479
+
1480
+ async def __aenter__(self: _T) -> _T:
1481
+ return self
1482
+
1483
+ async def __aexit__(
1484
+ self,
1485
+ exc_type: type[BaseException] | None,
1486
+ exc: BaseException | None,
1487
+ exc_tb: TracebackType | None,
1488
+ ) -> None:
1489
+ await self.close()
1490
+
1491
+ async def _prepare_options(
1492
+ self,
1493
+ options: FinalRequestOptions, # noqa: ARG002
1494
+ ) -> FinalRequestOptions:
1495
+ """Hook for mutating the given options"""
1496
+ return options
1497
+
1498
+ async def _prepare_request(
1499
+ self,
1500
+ request: httpx.Request, # noqa: ARG002
1501
+ ) -> None:
1502
+ """This method is used as a callback for mutating the `Request` object
1503
+ after it has been constructed.
1504
+ This is useful for cases where you want to add certain headers based off of
1505
+ the request properties, e.g. `url`, `method` etc.
1506
+ """
1507
+ return None
1508
+
1509
+ @overload
1510
+ async def request(
1511
+ self,
1512
+ cast_to: Type[ResponseT],
1513
+ options: FinalRequestOptions,
1514
+ *,
1515
+ stream: Literal[False] = False,
1516
+ ) -> ResponseT: ...
1517
+
1518
+ @overload
1519
+ async def request(
1520
+ self,
1521
+ cast_to: Type[ResponseT],
1522
+ options: FinalRequestOptions,
1523
+ *,
1524
+ stream: Literal[True],
1525
+ stream_cls: type[_AsyncStreamT],
1526
+ ) -> _AsyncStreamT: ...
1527
+
1528
+ @overload
1529
+ async def request(
1530
+ self,
1531
+ cast_to: Type[ResponseT],
1532
+ options: FinalRequestOptions,
1533
+ *,
1534
+ stream: bool,
1535
+ stream_cls: type[_AsyncStreamT] | None = None,
1536
+ ) -> ResponseT | _AsyncStreamT: ...
1537
+
1538
+ async def request(
1539
+ self,
1540
+ cast_to: Type[ResponseT],
1541
+ options: FinalRequestOptions,
1542
+ *,
1543
+ stream: bool = False,
1544
+ stream_cls: type[_AsyncStreamT] | None = None,
1545
+ ) -> ResponseT | _AsyncStreamT:
1546
+ if self._platform is None:
1547
+ # `get_platform` can make blocking IO calls so we
1548
+ # execute it earlier while we are in an async context
1549
+ self._platform = await asyncify(get_platform)()
1550
+
1551
+ cast_to = self._maybe_override_cast_to(cast_to, options)
1552
+
1553
+ # create a copy of the options we were given so that if the
1554
+ # options are mutated later & we then retry, the retries are
1555
+ # given the original options
1556
+ input_options = model_copy(options)
1557
+ if input_options.idempotency_key is None and input_options.method.lower() != "get":
1558
+ # ensure the idempotency key is reused between requests
1559
+ input_options.idempotency_key = self._idempotency_key()
1560
+
1561
+ response: httpx.Response | None = None
1562
+ max_retries = input_options.get_max_retries(self.max_retries)
1563
+
1564
+ retries_taken = 0
1565
+ for retries_taken in range(max_retries + 1):
1566
+ options = model_copy(input_options)
1567
+ options = await self._prepare_options(options)
1568
+
1569
+ remaining_retries = max_retries - retries_taken
1570
+ request = self._build_request(options, retries_taken=retries_taken)
1571
+ await self._prepare_request(request)
1572
+
1573
+ kwargs: HttpxSendArgs = {}
1574
+ if self.custom_auth is not None:
1575
+ kwargs["auth"] = self.custom_auth
1576
+
1577
+ if options.follow_redirects is not None:
1578
+ kwargs["follow_redirects"] = options.follow_redirects
1579
+
1580
+ log.debug("Sending HTTP Request: %s %s", request.method, request.url)
1581
+
1582
+ response = None
1583
+ try:
1584
+ response = await self._client.send(
1585
+ request,
1586
+ stream=stream or self._should_stream_response_body(request=request),
1587
+ **kwargs,
1588
+ )
1589
+ except httpx.TimeoutException as err:
1590
+ log.debug("Encountered httpx.TimeoutException", exc_info=True)
1591
+
1592
+ if remaining_retries > 0:
1593
+ await self._sleep_for_retry(
1594
+ retries_taken=retries_taken,
1595
+ max_retries=max_retries,
1596
+ options=input_options,
1597
+ response=None,
1598
+ )
1599
+ continue
1600
+
1601
+ log.debug("Raising timeout error")
1602
+ raise APITimeoutError(request=request) from err
1603
+ except Exception as err:
1604
+ log.debug("Encountered Exception", exc_info=True)
1605
+
1606
+ if remaining_retries > 0:
1607
+ await self._sleep_for_retry(
1608
+ retries_taken=retries_taken,
1609
+ max_retries=max_retries,
1610
+ options=input_options,
1611
+ response=None,
1612
+ )
1613
+ continue
1614
+
1615
+ log.debug("Raising connection error")
1616
+ raise APIConnectionError(request=request) from err
1617
+
1618
+ log.debug(
1619
+ 'HTTP Response: %s %s "%i %s" %s',
1620
+ request.method,
1621
+ request.url,
1622
+ response.status_code,
1623
+ response.reason_phrase,
1624
+ response.headers,
1625
+ )
1626
+
1627
+ try:
1628
+ response.raise_for_status()
1629
+ except httpx.HTTPStatusError as err: # thrown on 4xx and 5xx status code
1630
+ log.debug("Encountered httpx.HTTPStatusError", exc_info=True)
1631
+
1632
+ if remaining_retries > 0 and self._should_retry(err.response):
1633
+ await err.response.aclose()
1634
+ await self._sleep_for_retry(
1635
+ retries_taken=retries_taken,
1636
+ max_retries=max_retries,
1637
+ options=input_options,
1638
+ response=response,
1639
+ )
1640
+ continue
1641
+
1642
+ # If the response is streamed then we need to explicitly read the response
1643
+ # to completion before attempting to access the response text.
1644
+ if not err.response.is_closed:
1645
+ await err.response.aread()
1646
+
1647
+ log.debug("Re-raising status error")
1648
+ raise self._make_status_error_from_response(err.response) from None
1649
+
1650
+ break
1651
+
1652
+ assert response is not None, "could not resolve response (should never happen)"
1653
+ return await self._process_response(
1654
+ cast_to=cast_to,
1655
+ options=options,
1656
+ response=response,
1657
+ stream=stream,
1658
+ stream_cls=stream_cls,
1659
+ retries_taken=retries_taken,
1660
+ )
1661
+
1662
+ async def _sleep_for_retry(
1663
+ self, *, retries_taken: int, max_retries: int, options: FinalRequestOptions, response: httpx.Response | None
1664
+ ) -> None:
1665
+ remaining_retries = max_retries - retries_taken
1666
+ if remaining_retries == 1:
1667
+ log.debug("1 retry left")
1668
+ else:
1669
+ log.debug("%i retries left", remaining_retries)
1670
+
1671
+ timeout = self._calculate_retry_timeout(remaining_retries, options, response.headers if response else None)
1672
+ log.info("Retrying request to %s in %f seconds", options.url, timeout)
1673
+
1674
+ await anyio.sleep(timeout)
1675
+
1676
+ async def _process_response(
1677
+ self,
1678
+ *,
1679
+ cast_to: Type[ResponseT],
1680
+ options: FinalRequestOptions,
1681
+ response: httpx.Response,
1682
+ stream: bool,
1683
+ stream_cls: type[Stream[Any]] | type[AsyncStream[Any]] | None,
1684
+ retries_taken: int = 0,
1685
+ ) -> ResponseT:
1686
+ origin = get_origin(cast_to) or cast_to
1687
+
1688
+ if (
1689
+ inspect.isclass(origin)
1690
+ and issubclass(origin, BaseAPIResponse)
1691
+ # we only want to actually return the custom BaseAPIResponse class if we're
1692
+ # returning the raw response, or if we're not streaming SSE, as if we're streaming
1693
+ # SSE then `cast_to` doesn't actively reflect the type we need to parse into
1694
+ and (not stream or bool(response.request.headers.get(RAW_RESPONSE_HEADER)))
1695
+ ):
1696
+ if not issubclass(origin, AsyncAPIResponse):
1697
+ raise TypeError(f"API Response types must subclass {AsyncAPIResponse}; Received {origin}")
1698
+
1699
+ response_cls = cast("type[BaseAPIResponse[Any]]", cast_to)
1700
+ return cast(
1701
+ "ResponseT",
1702
+ response_cls(
1703
+ raw=response,
1704
+ client=self,
1705
+ cast_to=extract_response_type(response_cls),
1706
+ stream=stream,
1707
+ stream_cls=stream_cls,
1708
+ options=options,
1709
+ retries_taken=retries_taken,
1710
+ ),
1711
+ )
1712
+
1713
+ if cast_to == httpx.Response:
1714
+ return cast(ResponseT, response)
1715
+
1716
+ api_response = AsyncAPIResponse(
1717
+ raw=response,
1718
+ client=self,
1719
+ cast_to=cast("type[ResponseT]", cast_to), # pyright: ignore[reportUnnecessaryCast]
1720
+ stream=stream,
1721
+ stream_cls=stream_cls,
1722
+ options=options,
1723
+ retries_taken=retries_taken,
1724
+ )
1725
+ if bool(response.request.headers.get(RAW_RESPONSE_HEADER)):
1726
+ return cast(ResponseT, api_response)
1727
+
1728
+ return await api_response.parse()
1729
+
1730
+ def _request_api_list(
1731
+ self,
1732
+ model: Type[_T],
1733
+ page: Type[AsyncPageT],
1734
+ options: FinalRequestOptions,
1735
+ ) -> AsyncPaginator[_T, AsyncPageT]:
1736
+ return AsyncPaginator(client=self, options=options, page_cls=page, model=model)
1737
+
1738
+ @overload
1739
+ async def get(
1740
+ self,
1741
+ path: str,
1742
+ *,
1743
+ cast_to: Type[ResponseT],
1744
+ options: RequestOptions = {},
1745
+ stream: Literal[False] = False,
1746
+ ) -> ResponseT: ...
1747
+
1748
+ @overload
1749
+ async def get(
1750
+ self,
1751
+ path: str,
1752
+ *,
1753
+ cast_to: Type[ResponseT],
1754
+ options: RequestOptions = {},
1755
+ stream: Literal[True],
1756
+ stream_cls: type[_AsyncStreamT],
1757
+ ) -> _AsyncStreamT: ...
1758
+
1759
+ @overload
1760
+ async def get(
1761
+ self,
1762
+ path: str,
1763
+ *,
1764
+ cast_to: Type[ResponseT],
1765
+ options: RequestOptions = {},
1766
+ stream: bool,
1767
+ stream_cls: type[_AsyncStreamT] | None = None,
1768
+ ) -> ResponseT | _AsyncStreamT: ...
1769
+
1770
+ async def get(
1771
+ self,
1772
+ path: str,
1773
+ *,
1774
+ cast_to: Type[ResponseT],
1775
+ options: RequestOptions = {},
1776
+ stream: bool = False,
1777
+ stream_cls: type[_AsyncStreamT] | None = None,
1778
+ ) -> ResponseT | _AsyncStreamT:
1779
+ opts = FinalRequestOptions.construct(method="get", url=path, **options)
1780
+ return await self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)
1781
+
1782
+ @overload
1783
+ async def post(
1784
+ self,
1785
+ path: str,
1786
+ *,
1787
+ cast_to: Type[ResponseT],
1788
+ body: Body | None = None,
1789
+ content: AsyncBinaryTypes | None = None,
1790
+ files: RequestFiles | None = None,
1791
+ options: RequestOptions = {},
1792
+ stream: Literal[False] = False,
1793
+ ) -> ResponseT: ...
1794
+
1795
+ @overload
1796
+ async def post(
1797
+ self,
1798
+ path: str,
1799
+ *,
1800
+ cast_to: Type[ResponseT],
1801
+ body: Body | None = None,
1802
+ content: AsyncBinaryTypes | None = None,
1803
+ files: RequestFiles | None = None,
1804
+ options: RequestOptions = {},
1805
+ stream: Literal[True],
1806
+ stream_cls: type[_AsyncStreamT],
1807
+ ) -> _AsyncStreamT: ...
1808
+
1809
+ @overload
1810
+ async def post(
1811
+ self,
1812
+ path: str,
1813
+ *,
1814
+ cast_to: Type[ResponseT],
1815
+ body: Body | None = None,
1816
+ content: AsyncBinaryTypes | None = None,
1817
+ files: RequestFiles | None = None,
1818
+ options: RequestOptions = {},
1819
+ stream: bool,
1820
+ stream_cls: type[_AsyncStreamT] | None = None,
1821
+ ) -> ResponseT | _AsyncStreamT: ...
1822
+
1823
+ async def post(
1824
+ self,
1825
+ path: str,
1826
+ *,
1827
+ cast_to: Type[ResponseT],
1828
+ body: Body | None = None,
1829
+ content: AsyncBinaryTypes | None = None,
1830
+ files: RequestFiles | None = None,
1831
+ options: RequestOptions = {},
1832
+ stream: bool = False,
1833
+ stream_cls: type[_AsyncStreamT] | None = None,
1834
+ ) -> ResponseT | _AsyncStreamT:
1835
+ if body is not None and content is not None:
1836
+ raise TypeError("Passing both `body` and `content` is not supported")
1837
+ if files is not None and content is not None:
1838
+ raise TypeError("Passing both `files` and `content` is not supported")
1839
+ if isinstance(body, bytes):
1840
+ warnings.warn(
1841
+ "Passing raw bytes as `body` is deprecated and will be removed in a future version. "
1842
+ "Please pass raw bytes via the `content` parameter instead.",
1843
+ DeprecationWarning,
1844
+ stacklevel=2,
1845
+ )
1846
+ opts = FinalRequestOptions.construct(
1847
+ method="post", url=path, json_data=body, content=content, files=await async_to_httpx_files(files), **options
1848
+ )
1849
+ return await self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)
1850
+
1851
+ async def patch(
1852
+ self,
1853
+ path: str,
1854
+ *,
1855
+ cast_to: Type[ResponseT],
1856
+ body: Body | None = None,
1857
+ content: AsyncBinaryTypes | None = None,
1858
+ files: RequestFiles | None = None,
1859
+ options: RequestOptions = {},
1860
+ ) -> ResponseT:
1861
+ if body is not None and content is not None:
1862
+ raise TypeError("Passing both `body` and `content` is not supported")
1863
+ if files is not None and content is not None:
1864
+ raise TypeError("Passing both `files` and `content` is not supported")
1865
+ if isinstance(body, bytes):
1866
+ warnings.warn(
1867
+ "Passing raw bytes as `body` is deprecated and will be removed in a future version. "
1868
+ "Please pass raw bytes via the `content` parameter instead.",
1869
+ DeprecationWarning,
1870
+ stacklevel=2,
1871
+ )
1872
+ opts = FinalRequestOptions.construct(
1873
+ method="patch",
1874
+ url=path,
1875
+ json_data=body,
1876
+ content=content,
1877
+ files=await async_to_httpx_files(files),
1878
+ **options,
1879
+ )
1880
+ return await self.request(cast_to, opts)
1881
+
1882
+ async def put(
1883
+ self,
1884
+ path: str,
1885
+ *,
1886
+ cast_to: Type[ResponseT],
1887
+ body: Body | None = None,
1888
+ content: AsyncBinaryTypes | None = None,
1889
+ files: RequestFiles | None = None,
1890
+ options: RequestOptions = {},
1891
+ ) -> ResponseT:
1892
+ if body is not None and content is not None:
1893
+ raise TypeError("Passing both `body` and `content` is not supported")
1894
+ if files is not None and content is not None:
1895
+ raise TypeError("Passing both `files` and `content` is not supported")
1896
+ if isinstance(body, bytes):
1897
+ warnings.warn(
1898
+ "Passing raw bytes as `body` is deprecated and will be removed in a future version. "
1899
+ "Please pass raw bytes via the `content` parameter instead.",
1900
+ DeprecationWarning,
1901
+ stacklevel=2,
1902
+ )
1903
+ opts = FinalRequestOptions.construct(
1904
+ method="put", url=path, json_data=body, content=content, files=await async_to_httpx_files(files), **options
1905
+ )
1906
+ return await self.request(cast_to, opts)
1907
+
1908
+ async def delete(
1909
+ self,
1910
+ path: str,
1911
+ *,
1912
+ cast_to: Type[ResponseT],
1913
+ body: Body | None = None,
1914
+ content: AsyncBinaryTypes | None = None,
1915
+ options: RequestOptions = {},
1916
+ ) -> ResponseT:
1917
+ if body is not None and content is not None:
1918
+ raise TypeError("Passing both `body` and `content` is not supported")
1919
+ if isinstance(body, bytes):
1920
+ warnings.warn(
1921
+ "Passing raw bytes as `body` is deprecated and will be removed in a future version. "
1922
+ "Please pass raw bytes via the `content` parameter instead.",
1923
+ DeprecationWarning,
1924
+ stacklevel=2,
1925
+ )
1926
+ opts = FinalRequestOptions.construct(method="delete", url=path, json_data=body, content=content, **options)
1927
+ return await self.request(cast_to, opts)
1928
+
1929
+ def get_api_list(
1930
+ self,
1931
+ path: str,
1932
+ *,
1933
+ model: Type[_T],
1934
+ page: Type[AsyncPageT],
1935
+ body: Body | None = None,
1936
+ options: RequestOptions = {},
1937
+ method: str = "get",
1938
+ ) -> AsyncPaginator[_T, AsyncPageT]:
1939
+ opts = FinalRequestOptions.construct(method=method, url=path, json_data=body, **options)
1940
+ return self._request_api_list(model, page, opts)
1941
+
1942
+
1943
+ def make_request_options(
1944
+ *,
1945
+ query: Query | None = None,
1946
+ extra_headers: Headers | None = None,
1947
+ extra_query: Query | None = None,
1948
+ extra_body: Body | None = None,
1949
+ idempotency_key: str | None = None,
1950
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
1951
+ post_parser: PostParser | NotGiven = not_given,
1952
+ ) -> RequestOptions:
1953
+ """Create a dict of type RequestOptions without keys of NotGiven values."""
1954
+ options: RequestOptions = {}
1955
+ if extra_headers is not None:
1956
+ options["headers"] = extra_headers
1957
+
1958
+ if extra_body is not None:
1959
+ options["extra_json"] = cast(AnyMapping, extra_body)
1960
+
1961
+ if query is not None:
1962
+ options["params"] = query
1963
+
1964
+ if extra_query is not None:
1965
+ options["params"] = {**options.get("params", {}), **extra_query}
1966
+
1967
+ if not isinstance(timeout, NotGiven):
1968
+ options["timeout"] = timeout
1969
+
1970
+ if idempotency_key is not None:
1971
+ options["idempotency_key"] = idempotency_key
1972
+
1973
+ if is_given(post_parser):
1974
+ # internal
1975
+ options["post_parser"] = post_parser # type: ignore
1976
+
1977
+ return options
1978
+
1979
+
1980
+ class ForceMultipartDict(Dict[str, None]):
1981
+ def __bool__(self) -> bool:
1982
+ return True
1983
+
1984
+
1985
+ class OtherPlatform:
1986
+ def __init__(self, name: str) -> None:
1987
+ self.name = name
1988
+
1989
+ @override
1990
+ def __str__(self) -> str:
1991
+ return f"Other:{self.name}"
1992
+
1993
+
1994
+ Platform = Union[
1995
+ OtherPlatform,
1996
+ Literal[
1997
+ "MacOS",
1998
+ "Linux",
1999
+ "Windows",
2000
+ "FreeBSD",
2001
+ "OpenBSD",
2002
+ "iOS",
2003
+ "Android",
2004
+ "Unknown",
2005
+ ],
2006
+ ]
2007
+
2008
+
2009
+ def get_platform() -> Platform:
2010
+ try:
2011
+ system = platform.system().lower()
2012
+ platform_name = platform.platform().lower()
2013
+ except Exception:
2014
+ return "Unknown"
2015
+
2016
+ if "iphone" in platform_name or "ipad" in platform_name:
2017
+ # Tested using Python3IDE on an iPhone 11 and Pythonista on an iPad 7
2018
+ # system is Darwin and platform_name is a string like:
2019
+ # - Darwin-21.6.0-iPhone12,1-64bit
2020
+ # - Darwin-21.6.0-iPad7,11-64bit
2021
+ return "iOS"
2022
+
2023
+ if system == "darwin":
2024
+ return "MacOS"
2025
+
2026
+ if system == "windows":
2027
+ return "Windows"
2028
+
2029
+ if "android" in platform_name:
2030
+ # Tested using Pydroid 3
2031
+ # system is Linux and platform_name is a string like 'Linux-5.10.81-android12-9-00001-geba40aecb3b7-ab8534902-aarch64-with-libc'
2032
+ return "Android"
2033
+
2034
+ if system == "linux":
2035
+ # https://distro.readthedocs.io/en/latest/#distro.id
2036
+ distro_id = distro.id()
2037
+ if distro_id == "freebsd":
2038
+ return "FreeBSD"
2039
+
2040
+ if distro_id == "openbsd":
2041
+ return "OpenBSD"
2042
+
2043
+ return "Linux"
2044
+
2045
+ if platform_name:
2046
+ return OtherPlatform(platform_name)
2047
+
2048
+ return "Unknown"
2049
+
2050
+
2051
+ @lru_cache(maxsize=None)
2052
+ def platform_headers(version: str, *, platform: Platform | None) -> Dict[str, str]:
2053
+ return {
2054
+ "X-Stainless-Lang": "python",
2055
+ "X-Stainless-Package-Version": version,
2056
+ "X-Stainless-OS": str(platform or get_platform()),
2057
+ "X-Stainless-Arch": str(get_architecture()),
2058
+ "X-Stainless-Runtime": get_python_runtime(),
2059
+ "X-Stainless-Runtime-Version": get_python_version(),
2060
+ }
2061
+
2062
+
2063
+ class OtherArch:
2064
+ def __init__(self, name: str) -> None:
2065
+ self.name = name
2066
+
2067
+ @override
2068
+ def __str__(self) -> str:
2069
+ return f"other:{self.name}"
2070
+
2071
+
2072
+ Arch = Union[OtherArch, Literal["x32", "x64", "arm", "arm64", "unknown"]]
2073
+
2074
+
2075
+ def get_python_runtime() -> str:
2076
+ try:
2077
+ return platform.python_implementation()
2078
+ except Exception:
2079
+ return "unknown"
2080
+
2081
+
2082
+ def get_python_version() -> str:
2083
+ try:
2084
+ return platform.python_version()
2085
+ except Exception:
2086
+ return "unknown"
2087
+
2088
+
2089
+ def get_architecture() -> Arch:
2090
+ try:
2091
+ machine = platform.machine().lower()
2092
+ except Exception:
2093
+ return "unknown"
2094
+
2095
+ if machine in ("arm64", "aarch64"):
2096
+ return "arm64"
2097
+
2098
+ # TODO: untested
2099
+ if machine == "arm":
2100
+ return "arm"
2101
+
2102
+ if machine == "x86_64":
2103
+ return "x64"
2104
+
2105
+ # TODO: untested
2106
+ if sys.maxsize <= 2**32:
2107
+ return "x32"
2108
+
2109
+ if machine:
2110
+ return OtherArch(machine)
2111
+
2112
+ return "unknown"
2113
+
2114
+
2115
+ def _merge_mappings(
2116
+ obj1: Mapping[_T_co, Union[_T, Omit]],
2117
+ obj2: Mapping[_T_co, Union[_T, Omit]],
2118
+ ) -> Dict[_T_co, _T]:
2119
+ """Merge two mappings of the same type, removing any values that are instances of `Omit`.
2120
+
2121
+ In cases with duplicate keys the second mapping takes precedence.
2122
+ """
2123
+ merged = {**obj1, **obj2}
2124
+ return {key: value for key, value in merged.items() if not isinstance(value, Omit)}