hotdata 0.9.0__tar.gz → 0.9.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (326) hide show
  1. {hotdata-0.9.0 → hotdata-0.9.1}/PKG-INFO +1 -1
  2. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/__init__.py +14 -0
  3. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/_auth.py +138 -4
  4. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/api/connections_api.py +9 -6
  5. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/api/databases_api.py +1151 -32
  6. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/api/uploads_api.py +12 -12
  7. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/api/usage_api.py +3 -3
  8. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/api_client.py +93 -0
  9. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/__init__.py +7 -0
  10. hotdata-0.9.1/hotdata/models/bulk_create_databases_request.py +134 -0
  11. hotdata-0.9.1/hotdata/models/bulk_create_databases_result.py +95 -0
  12. hotdata-0.9.1/hotdata/models/column_definition.py +141 -0
  13. hotdata-0.9.1/hotdata/models/column_type_spec.py +103 -0
  14. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/create_connection_request.py +2 -2
  15. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/create_database_response.py +1 -1
  16. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/create_embedding_provider_request.py +1 -6
  17. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/create_index_request.py +15 -5
  18. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/create_upload_request.py +3 -3
  19. hotdata-0.9.1/hotdata/models/database_batch_response.py +116 -0
  20. hotdata-0.9.1/hotdata/models/database_count_response.py +88 -0
  21. hotdata-0.9.1/hotdata/models/delete_database_batch_response.py +90 -0
  22. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/finalize_upload_part.py +3 -3
  23. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/finalize_upload_request.py +1 -1
  24. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/index_entry_response.py +1 -1
  25. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/job_result.py +22 -8
  26. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/job_type.py +3 -0
  27. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/load_managed_table_request.py +36 -7
  28. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/mint_upload_parts_request.py +1 -1
  29. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/query_request.py +2 -2
  30. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/query_response.py +3 -3
  31. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/refresh_request.py +6 -6
  32. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/upload_session_response.py +2 -2
  33. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata.egg-info/PKG-INFO +1 -1
  34. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata.egg-info/SOURCES.txt +14 -0
  35. {hotdata-0.9.0 → hotdata-0.9.1}/pyproject.toml +1 -1
  36. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_add_managed_schema_request.py +9 -11
  37. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_add_managed_table_decl.py +8 -10
  38. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_add_managed_table_request.py +8 -10
  39. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_attach_database_catalog_request.py +3 -3
  40. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_batch_create_upload_request.py +2 -20
  41. hotdata-0.9.1/test/test_bulk_create_databases_request.py +78 -0
  42. hotdata-0.9.1/test/test_bulk_create_databases_result.py +59 -0
  43. hotdata-0.9.1/test/test_column_definition.py +55 -0
  44. hotdata-0.9.1/test/test_column_type_spec.py +55 -0
  45. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_connections_api.py +1 -1
  46. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_create_connection_request.py +7 -11
  47. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_create_database_request.py +8 -10
  48. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_create_embedding_provider_request.py +6 -6
  49. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_create_index_request.py +5 -9
  50. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_create_saved_query_request.py +6 -8
  51. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_create_secret_request.py +4 -4
  52. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_create_upload_request.py +6 -6
  53. hotdata-0.9.1/test/test_database_batch_response.py +62 -0
  54. hotdata-0.9.1/test/test_database_count_response.py +53 -0
  55. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_database_default_schema_decl.py +9 -11
  56. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_database_default_table_decl.py +8 -10
  57. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_databases_api.py +29 -1
  58. hotdata-0.9.1/test/test_delete_database_batch_response.py +55 -0
  59. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_finalize_upload_part.py +4 -4
  60. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_finalize_upload_request.py +2 -2
  61. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_information_schema_response.py +10 -10
  62. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_job_result.py +9 -1
  63. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_load_managed_table_request.py +9 -3
  64. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_mint_upload_parts_request.py +2 -6
  65. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_query_request.py +5 -5
  66. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_table_info.py +10 -10
  67. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_table_partition_key.py +4 -4
  68. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_table_sort_key.py +4 -4
  69. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_update_secret_request.py +2 -2
  70. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_upsert_database_context_request.py +4 -4
  71. {hotdata-0.9.0 → hotdata-0.9.1}/tests/test_auth.py +324 -0
  72. {hotdata-0.9.0 → hotdata-0.9.1}/README.md +0 -0
  73. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/_retry.py +0 -0
  74. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/_upload_watchdog.py +0 -0
  75. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/api/__init__.py +0 -0
  76. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/api/connection_types_api.py +0 -0
  77. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/api/database_context_api.py +0 -0
  78. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/api/embedding_providers_api.py +0 -0
  79. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/api/indexes_api.py +0 -0
  80. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/api/information_schema_api.py +0 -0
  81. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/api/jobs_api.py +0 -0
  82. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/api/query_api.py +0 -0
  83. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/api/query_runs_api.py +0 -0
  84. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/api/refresh_api.py +0 -0
  85. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/api/results_api.py +0 -0
  86. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/api/saved_queries_api.py +0 -0
  87. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/api/secrets_api.py +0 -0
  88. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/api/workspaces_api.py +0 -0
  89. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/api_response.py +0 -0
  90. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/arrow.py +0 -0
  91. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/configuration.py +0 -0
  92. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/exceptions.py +0 -0
  93. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/add_managed_schema_request.py +0 -0
  94. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/add_managed_table_decl.py +0 -0
  95. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/add_managed_table_request.py +0 -0
  96. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/api_error_detail.py +0 -0
  97. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/api_error_response.py +0 -0
  98. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/async_query_response.py +0 -0
  99. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/attach_database_catalog_request.py +0 -0
  100. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/batch_create_upload_request.py +0 -0
  101. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/batch_create_upload_response.py +0 -0
  102. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/boolean_profile_detail.py +0 -0
  103. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/categorical_profile_detail.py +0 -0
  104. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/category_value_info.py +0 -0
  105. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/column_info.py +0 -0
  106. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/column_profile_detail.py +0 -0
  107. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/column_profile_detail_one_of.py +0 -0
  108. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/column_profile_detail_one_of1.py +0 -0
  109. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/column_profile_detail_one_of2.py +0 -0
  110. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/column_profile_detail_one_of3.py +0 -0
  111. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/column_profile_detail_one_of4.py +0 -0
  112. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/column_profile_info.py +0 -0
  113. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/connection_health_response.py +0 -0
  114. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/connection_info.py +0 -0
  115. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/connection_refresh_result.py +0 -0
  116. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/connection_schema_error.py +0 -0
  117. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/connection_type_detail.py +0 -0
  118. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/connection_type_summary.py +0 -0
  119. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/create_connection_response.py +0 -0
  120. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/create_database_request.py +0 -0
  121. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/create_embedding_provider_response.py +0 -0
  122. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/create_saved_query_request.py +0 -0
  123. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/create_secret_request.py +0 -0
  124. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/create_secret_response.py +0 -0
  125. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/create_workspace_request.py +0 -0
  126. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/create_workspace_response.py +0 -0
  127. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/database_attachment_info.py +0 -0
  128. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/database_context_entry.py +0 -0
  129. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/database_default_schema_decl.py +0 -0
  130. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/database_default_table_decl.py +0 -0
  131. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/database_detail_response.py +0 -0
  132. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/database_summary.py +0 -0
  133. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/discovery_status.py +0 -0
  134. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/embedding_provider_response.py +0 -0
  135. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/error.py +0 -0
  136. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/execute_saved_query_request.py +0 -0
  137. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/finalize_upload_response.py +0 -0
  138. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/fork_database_request.py +0 -0
  139. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/get_connection_response.py +0 -0
  140. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/get_database_context_response.py +0 -0
  141. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/get_result_response.py +0 -0
  142. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/get_secret_response.py +0 -0
  143. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/index_info_response.py +0 -0
  144. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/index_status.py +0 -0
  145. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/information_schema_response.py +0 -0
  146. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/job_status.py +0 -0
  147. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/job_status_response.py +0 -0
  148. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/list_connection_types_response.py +0 -0
  149. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/list_connections_response.py +0 -0
  150. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/list_database_contexts_response.py +0 -0
  151. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/list_databases_response.py +0 -0
  152. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/list_embedding_providers_response.py +0 -0
  153. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/list_indexes_page_response.py +0 -0
  154. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/list_indexes_response.py +0 -0
  155. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/list_jobs_response.py +0 -0
  156. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/list_query_runs_response.py +0 -0
  157. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/list_results_response.py +0 -0
  158. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/list_saved_queries_response.py +0 -0
  159. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/list_saved_query_versions_response.py +0 -0
  160. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/list_secrets_response.py +0 -0
  161. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/list_workspaces_response.py +0 -0
  162. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/load_managed_table_response.py +0 -0
  163. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/managed_schema_response.py +0 -0
  164. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/managed_table_response.py +0 -0
  165. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/mint_upload_parts_response.py +0 -0
  166. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/minted_upload_part_response.py +0 -0
  167. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/numeric_profile_detail.py +0 -0
  168. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/query_run_info.py +0 -0
  169. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/refresh_response.py +0 -0
  170. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/refresh_warning.py +0 -0
  171. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/result_info.py +0 -0
  172. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/results_format_query.py +0 -0
  173. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/saved_query_detail.py +0 -0
  174. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/saved_query_summary.py +0 -0
  175. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/saved_query_version_info.py +0 -0
  176. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/schema_refresh_result.py +0 -0
  177. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/secret_metadata_response.py +0 -0
  178. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/submit_job_response.py +0 -0
  179. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/table_info.py +0 -0
  180. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/table_partition_key.py +0 -0
  181. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/table_profile_response.py +0 -0
  182. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/table_refresh_error.py +0 -0
  183. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/table_refresh_result.py +0 -0
  184. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/table_sort_key.py +0 -0
  185. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/temporal_profile_detail.py +0 -0
  186. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/text_profile_detail.py +0 -0
  187. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/update_embedding_provider_request.py +0 -0
  188. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/update_embedding_provider_response.py +0 -0
  189. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/update_saved_query_request.py +0 -0
  190. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/update_secret_request.py +0 -0
  191. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/update_secret_response.py +0 -0
  192. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/upsert_database_context_request.py +0 -0
  193. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/upsert_database_context_response.py +0 -0
  194. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/workspace_detail.py +0 -0
  195. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/workspace_list_item.py +0 -0
  196. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/models/workspace_usage_response.py +0 -0
  197. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/py.typed +0 -0
  198. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/query.py +0 -0
  199. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/rest.py +0 -0
  200. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata/uploads.py +0 -0
  201. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata.egg-info/dependency_links.txt +0 -0
  202. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata.egg-info/requires.txt +0 -0
  203. {hotdata-0.9.0 → hotdata-0.9.1}/hotdata.egg-info/top_level.txt +0 -0
  204. {hotdata-0.9.0 → hotdata-0.9.1}/setup.cfg +0 -0
  205. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_api_client_close.py +0 -0
  206. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_api_error_detail.py +0 -0
  207. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_api_error_response.py +0 -0
  208. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_async_query_response.py +0 -0
  209. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_batch_create_upload_response.py +0 -0
  210. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_boolean_profile_detail.py +0 -0
  211. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_categorical_profile_detail.py +0 -0
  212. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_category_value_info.py +0 -0
  213. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_column_info.py +0 -0
  214. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_column_profile_detail.py +0 -0
  215. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_column_profile_detail_one_of.py +0 -0
  216. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_column_profile_detail_one_of1.py +0 -0
  217. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_column_profile_detail_one_of2.py +0 -0
  218. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_column_profile_detail_one_of3.py +0 -0
  219. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_column_profile_detail_one_of4.py +0 -0
  220. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_column_profile_info.py +0 -0
  221. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_connection_health_response.py +0 -0
  222. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_connection_info.py +0 -0
  223. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_connection_refresh_result.py +0 -0
  224. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_connection_schema_error.py +0 -0
  225. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_connection_type_detail.py +0 -0
  226. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_connection_type_summary.py +0 -0
  227. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_connection_types_api.py +0 -0
  228. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_create_connection_response.py +0 -0
  229. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_create_database_response.py +0 -0
  230. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_create_embedding_provider_response.py +0 -0
  231. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_create_secret_response.py +0 -0
  232. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_create_workspace_request.py +0 -0
  233. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_create_workspace_response.py +0 -0
  234. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_database_attachment_info.py +0 -0
  235. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_database_context_api.py +0 -0
  236. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_database_context_entry.py +0 -0
  237. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_database_detail_response.py +0 -0
  238. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_database_summary.py +0 -0
  239. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_discovery_status.py +0 -0
  240. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_embedding_provider_response.py +0 -0
  241. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_embedding_providers_api.py +0 -0
  242. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_error.py +0 -0
  243. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_execute_saved_query_request.py +0 -0
  244. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_finalize_upload_response.py +0 -0
  245. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_fork_database_request.py +0 -0
  246. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_get_connection_response.py +0 -0
  247. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_get_database_context_response.py +0 -0
  248. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_get_result_response.py +0 -0
  249. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_get_secret_response.py +0 -0
  250. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_index_entry_response.py +0 -0
  251. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_index_info_response.py +0 -0
  252. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_index_status.py +0 -0
  253. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_indexes_api.py +0 -0
  254. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_information_schema_api.py +0 -0
  255. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_job_status.py +0 -0
  256. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_job_status_response.py +0 -0
  257. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_job_type.py +0 -0
  258. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_jobs_api.py +0 -0
  259. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_list_connection_types_response.py +0 -0
  260. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_list_connections_response.py +0 -0
  261. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_list_database_contexts_response.py +0 -0
  262. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_list_databases_response.py +0 -0
  263. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_list_embedding_providers_response.py +0 -0
  264. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_list_indexes_page_response.py +0 -0
  265. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_list_indexes_response.py +0 -0
  266. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_list_jobs_response.py +0 -0
  267. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_list_query_runs_response.py +0 -0
  268. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_list_results_response.py +0 -0
  269. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_list_saved_queries_response.py +0 -0
  270. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_list_saved_query_versions_response.py +0 -0
  271. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_list_secrets_response.py +0 -0
  272. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_list_workspaces_response.py +0 -0
  273. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_load_managed_table_response.py +0 -0
  274. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_managed_schema_response.py +0 -0
  275. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_managed_table_response.py +0 -0
  276. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_mint_upload_parts_response.py +0 -0
  277. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_minted_upload_part_response.py +0 -0
  278. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_numeric_profile_detail.py +0 -0
  279. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_query_api.py +0 -0
  280. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_query_response.py +0 -0
  281. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_query_run_info.py +0 -0
  282. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_query_runs_api.py +0 -0
  283. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_refresh_api.py +0 -0
  284. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_refresh_request.py +0 -0
  285. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_refresh_response.py +0 -0
  286. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_refresh_warning.py +0 -0
  287. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_result_info.py +0 -0
  288. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_results_api.py +0 -0
  289. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_results_format_query.py +0 -0
  290. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_saved_queries_api.py +0 -0
  291. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_saved_query_detail.py +0 -0
  292. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_saved_query_summary.py +0 -0
  293. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_saved_query_version_info.py +0 -0
  294. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_schema_refresh_result.py +0 -0
  295. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_secret_metadata_response.py +0 -0
  296. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_secrets_api.py +0 -0
  297. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_submit_job_response.py +0 -0
  298. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_table_profile_response.py +0 -0
  299. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_table_refresh_error.py +0 -0
  300. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_table_refresh_result.py +0 -0
  301. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_temporal_profile_detail.py +0 -0
  302. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_text_profile_detail.py +0 -0
  303. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_update_embedding_provider_request.py +0 -0
  304. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_update_embedding_provider_response.py +0 -0
  305. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_update_saved_query_request.py +0 -0
  306. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_update_secret_response.py +0 -0
  307. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_upload_session_response.py +0 -0
  308. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_uploads_api.py +0 -0
  309. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_upsert_database_context_response.py +0 -0
  310. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_usage_api.py +0 -0
  311. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_workspace_detail.py +0 -0
  312. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_workspace_list_item.py +0 -0
  313. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_workspace_usage_response.py +0 -0
  314. {hotdata-0.9.0 → hotdata-0.9.1}/test/test_workspaces_api.py +0 -0
  315. {hotdata-0.9.0 → hotdata-0.9.1}/tests/test_arrow.py +0 -0
  316. {hotdata-0.9.0 → hotdata-0.9.1}/tests/test_config_auth_surface.py +0 -0
  317. {hotdata-0.9.0 → hotdata-0.9.1}/tests/test_query.py +0 -0
  318. {hotdata-0.9.0 → hotdata-0.9.1}/tests/test_retry.py +0 -0
  319. {hotdata-0.9.0 → hotdata-0.9.1}/tests/test_update_changelog.py +0 -0
  320. {hotdata-0.9.0 → hotdata-0.9.1}/tests/test_upload_codex_fixes.py +0 -0
  321. {hotdata-0.9.0 → hotdata-0.9.1}/tests/test_upload_multipart_resilient.py +0 -0
  322. {hotdata-0.9.0 → hotdata-0.9.1}/tests/test_upload_parity_fixes.py +0 -0
  323. {hotdata-0.9.0 → hotdata-0.9.1}/tests/test_upload_resilient.py +0 -0
  324. {hotdata-0.9.0 → hotdata-0.9.1}/tests/test_upload_retry_policy.py +0 -0
  325. {hotdata-0.9.0 → hotdata-0.9.1}/tests/test_upload_watchdog.py +0 -0
  326. {hotdata-0.9.0 → hotdata-0.9.1}/tests/test_uploads.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hotdata
3
- Version: 0.9.0
3
+ Version: 0.9.1
4
4
  Summary: Hotdata API
5
5
  Author-email: Hotdata <developers@hotdata.dev>
6
6
  License: MIT
@@ -60,8 +60,11 @@ __all__ = [
60
60
  "BatchCreateUploadRequest",
61
61
  "BatchCreateUploadResponse",
62
62
  "BooleanProfileDetail",
63
+ "BulkCreateDatabasesRequest",
64
+ "BulkCreateDatabasesResult",
63
65
  "CategoricalProfileDetail",
64
66
  "CategoryValueInfo",
67
+ "ColumnDefinition",
65
68
  "ColumnInfo",
66
69
  "ColumnProfileDetail",
67
70
  "ColumnProfileDetailOneOf",
@@ -70,6 +73,7 @@ __all__ = [
70
73
  "ColumnProfileDetailOneOf3",
71
74
  "ColumnProfileDetailOneOf4",
72
75
  "ColumnProfileInfo",
76
+ "ColumnTypeSpec",
73
77
  "ConnectionHealthResponse",
74
78
  "ConnectionInfo",
75
79
  "ConnectionRefreshResult",
@@ -90,11 +94,14 @@ __all__ = [
90
94
  "CreateWorkspaceRequest",
91
95
  "CreateWorkspaceResponse",
92
96
  "DatabaseAttachmentInfo",
97
+ "DatabaseBatchResponse",
93
98
  "DatabaseContextEntry",
99
+ "DatabaseCountResponse",
94
100
  "DatabaseDefaultSchemaDecl",
95
101
  "DatabaseDefaultTableDecl",
96
102
  "DatabaseDetailResponse",
97
103
  "DatabaseSummary",
104
+ "DeleteDatabaseBatchResponse",
98
105
  "DiscoveryStatus",
99
106
  "EmbeddingProviderResponse",
100
107
  "Error",
@@ -213,8 +220,11 @@ from hotdata.models.attach_database_catalog_request import AttachDatabaseCatalog
213
220
  from hotdata.models.batch_create_upload_request import BatchCreateUploadRequest as BatchCreateUploadRequest
214
221
  from hotdata.models.batch_create_upload_response import BatchCreateUploadResponse as BatchCreateUploadResponse
215
222
  from hotdata.models.boolean_profile_detail import BooleanProfileDetail as BooleanProfileDetail
223
+ from hotdata.models.bulk_create_databases_request import BulkCreateDatabasesRequest as BulkCreateDatabasesRequest
224
+ from hotdata.models.bulk_create_databases_result import BulkCreateDatabasesResult as BulkCreateDatabasesResult
216
225
  from hotdata.models.categorical_profile_detail import CategoricalProfileDetail as CategoricalProfileDetail
217
226
  from hotdata.models.category_value_info import CategoryValueInfo as CategoryValueInfo
227
+ from hotdata.models.column_definition import ColumnDefinition as ColumnDefinition
218
228
  from hotdata.models.column_info import ColumnInfo as ColumnInfo
219
229
  from hotdata.models.column_profile_detail import ColumnProfileDetail as ColumnProfileDetail
220
230
  from hotdata.models.column_profile_detail_one_of import ColumnProfileDetailOneOf as ColumnProfileDetailOneOf
@@ -223,6 +233,7 @@ from hotdata.models.column_profile_detail_one_of2 import ColumnProfileDetailOneO
223
233
  from hotdata.models.column_profile_detail_one_of3 import ColumnProfileDetailOneOf3 as ColumnProfileDetailOneOf3
224
234
  from hotdata.models.column_profile_detail_one_of4 import ColumnProfileDetailOneOf4 as ColumnProfileDetailOneOf4
225
235
  from hotdata.models.column_profile_info import ColumnProfileInfo as ColumnProfileInfo
236
+ from hotdata.models.column_type_spec import ColumnTypeSpec as ColumnTypeSpec
226
237
  from hotdata.models.connection_health_response import ConnectionHealthResponse as ConnectionHealthResponse
227
238
  from hotdata.models.connection_info import ConnectionInfo as ConnectionInfo
228
239
  from hotdata.models.connection_refresh_result import ConnectionRefreshResult as ConnectionRefreshResult
@@ -243,11 +254,14 @@ from hotdata.models.create_upload_request import CreateUploadRequest as CreateUp
243
254
  from hotdata.models.create_workspace_request import CreateWorkspaceRequest as CreateWorkspaceRequest
244
255
  from hotdata.models.create_workspace_response import CreateWorkspaceResponse as CreateWorkspaceResponse
245
256
  from hotdata.models.database_attachment_info import DatabaseAttachmentInfo as DatabaseAttachmentInfo
257
+ from hotdata.models.database_batch_response import DatabaseBatchResponse as DatabaseBatchResponse
246
258
  from hotdata.models.database_context_entry import DatabaseContextEntry as DatabaseContextEntry
259
+ from hotdata.models.database_count_response import DatabaseCountResponse as DatabaseCountResponse
247
260
  from hotdata.models.database_default_schema_decl import DatabaseDefaultSchemaDecl as DatabaseDefaultSchemaDecl
248
261
  from hotdata.models.database_default_table_decl import DatabaseDefaultTableDecl as DatabaseDefaultTableDecl
249
262
  from hotdata.models.database_detail_response import DatabaseDetailResponse as DatabaseDetailResponse
250
263
  from hotdata.models.database_summary import DatabaseSummary as DatabaseSummary
264
+ from hotdata.models.delete_database_batch_response import DeleteDatabaseBatchResponse as DeleteDatabaseBatchResponse
251
265
  from hotdata.models.discovery_status import DiscoveryStatus as DiscoveryStatus
252
266
  from hotdata.models.embedding_provider_response import EmbeddingProviderResponse as EmbeddingProviderResponse
253
267
  from hotdata.models.error import Error as Error
@@ -39,6 +39,7 @@ Key behaviors:
39
39
  endpoint fails fast instead of hanging every call.
40
40
  """
41
41
 
42
+ import base64
42
43
  import json
43
44
  import os
44
45
  import random
@@ -81,6 +82,32 @@ class TokenExchangeError(Exception):
81
82
  """
82
83
 
83
84
 
85
+ def _exp_from_jwt(token):
86
+ """The `exp` claim of a compact JWT, as a UNIX timestamp, or None.
87
+
88
+ The claim is AUTHORITATIVE where `expires_in` is only a promise. A mint
89
+ endpoint that replays a cached token is required by RFC 6749 s4.2.2 to
90
+ report the REMAINING lifetime ("the value 3600 denotes that the access token
91
+ will expire in one hour from the time the response was generated"); one that
92
+ reports the original TTL instead hands back a token with seconds of life
93
+ stamped as good for minutes. Reading the claim costs a base64 decode and
94
+ removes the need to trust that.
95
+
96
+ Deliberately does NOT verify the signature: this is the SDK reading a token
97
+ it was just handed, to decide when to refresh it. Whether the token is
98
+ genuine is the server's call on the next request, and a forged `exp` can
99
+ only make this client refresh sooner. Any malformed token returns None and
100
+ the caller falls back to `expires_in`.
101
+ """
102
+ try:
103
+ payload = token.split(".")[1]
104
+ payload += "=" * (-len(payload) % 4)
105
+ exp = json.loads(base64.urlsafe_b64decode(payload)).get("exp")
106
+ return float(exp) if exp is not None else None
107
+ except Exception: # noqa: BLE001 -- any malformed token falls back
108
+ return None
109
+
110
+
84
111
  def _is_socks_proxy_url(url):
85
112
  # Mirror hotdata/rest.py.is_socks_proxy_url so the exchange pool routes
86
113
  # SOCKS proxies the same way the generated REST client does.
@@ -184,6 +211,13 @@ class _TokenManager:
184
211
  self._jwt = None
185
212
  self._exp = 0.0
186
213
  self._refresh = None
214
+ # The token this manager last served before it was invalidated. Lets a
215
+ # request that carried it be told apart from one carrying a credential
216
+ # this manager never issued -- see `ApiClient._remint_bearer`.
217
+ self._prev_jwt = None
218
+ # True when the last mint handed back the token we already held, i.e. the
219
+ # server has nothing newer to give. See `_refresh_margin`.
220
+ self._replayed = False
187
221
 
188
222
  @property
189
223
  def _needs_exchange(self):
@@ -217,12 +251,12 @@ class _TokenManager:
217
251
  # under the lock, and the _LEEWAY margin keeps a token read here valid on
218
252
  # the wire even if it is about to be rotated.
219
253
  jwt = self._jwt
220
- if jwt and time.time() < self._exp - _LEEWAY:
254
+ if jwt and time.time() < self._exp - self._refresh_margin():
221
255
  return jwt
222
256
  with self._lock:
223
257
  # Re-check under the lock: another thread may have minted a fresh JWT
224
258
  # while we waited (double-checked locking).
225
- if self._jwt and time.time() < self._exp - _LEEWAY:
259
+ if self._jwt and time.time() < self._exp - self._refresh_margin():
226
260
  return self._jwt
227
261
  # Prefer the refresh token; on failure, drop it and re-mint below.
228
262
  if self._refresh and not self._mint(
@@ -230,10 +264,63 @@ class _TokenManager:
230
264
  ):
231
265
  self._refresh = None # refresh failed -> fall through to re-mint
232
266
  # Re-mint from the held API token if we still lack a fresh JWT.
233
- if not self._jwt or time.time() >= self._exp - _LEEWAY:
267
+ if not self._jwt or time.time() >= self._exp - self._refresh_margin():
234
268
  self._mint({"grant_type": "api_token", "api_token": self._credential})
235
269
  return self._jwt
236
270
 
271
+ def _refresh_margin(self):
272
+ """How early to refresh: `_LEEWAY`, or nothing once the server replays.
273
+
274
+ The leeway exists to rotate a token before it dies. That only helps if a
275
+ mint can produce something newer -- and a server that replays a cached
276
+ token has just demonstrated it cannot. Refreshing anyway costs two token
277
+ endpoint round trips per request (the refresh grant returns the same
278
+ token, so `_refresh` survives and the api_token grant runs too), taken
279
+ under the lock, for the whole leeway window of every cycle.
280
+
281
+ Reading the honest `exp` is what exposes this: the inflated
282
+ `now + expires_in` never entered the window at all, because it had
283
+ already sailed past the real expiry -- a dead token instead of a slow
284
+ one. Dropping the margin for a replayed token keeps the honest expiry
285
+ without paying for advice the server has said it does not have, and the
286
+ 401 retry remains the backstop for when the token really does die.
287
+
288
+ Clock skew is NOT handled here -- this margin only ever suppresses the
289
+ window `(_exp - _LEEWAY, _exp)`, and a skewed client's `_exp` is already
290
+ behind `now`, so nothing is left to suppress. `_mint` handles that case by
291
+ declining a claim that has already elapsed.
292
+ """
293
+ return 0 if self._replayed else _LEEWAY
294
+
295
+ def invalidate(self, only_if=None):
296
+ """Drop the cached JWT so the next `bearer_value()` mints a fresh one.
297
+
298
+ For the ONE case the proactive `_exp` check cannot cover: the server
299
+ rejected a token this client still believed in. Clears the refresh token
300
+ too -- a refresh is exactly what would hand back the same replayed JWT
301
+ that was just refused, so the next mint must go to the API token.
302
+
303
+ `only_if` makes it a COMPARE-AND-CLEAR, which is what keeps concurrent
304
+ 401s from fighting. Several in-flight requests can carry the same doomed
305
+ token and 401 together; without the guard the second one clears the fresh
306
+ JWT the first just minted, and they take turns invalidating each other's
307
+ work. Passing the token that actually failed means a thread only clears
308
+ the state it observed.
309
+
310
+ Returns True when it cleared, False when another thread had already
311
+ replaced the token -- in which case the caller should use that one rather
312
+ than mint again.
313
+ """
314
+ with self._lock:
315
+ if only_if is not None and self._jwt != only_if:
316
+ return False
317
+ self._prev_jwt = self._jwt
318
+ self._replayed = False
319
+ self._jwt = None
320
+ self._exp = 0.0
321
+ self._refresh = None
322
+ return True
323
+
237
324
  def _mint(self, params):
238
325
  # Returns True on success. The refresh path is best-effort: ANY failure
239
326
  # -- a non-200, a transport error, or a malformed/missing-token body --
@@ -259,8 +346,55 @@ class _TokenManager:
259
346
  if isinstance(exc, TokenExchangeError):
260
347
  raise
261
348
  raise TokenExchangeError(f"token exchange failed: {exc!r}") from exc
349
+ # A mint that returns the token we already hold is the server saying it
350
+ # has nothing newer; `_refresh_margin` stops asking again until this one
351
+ # has actually expired.
352
+ self._replayed = token == self._jwt
262
353
  self._jwt = token
263
- self._exp = time.time() + expires_in
354
+ # The JWT's own `exp` WINS when it is sooner than what `expires_in`
355
+ # promises. A mint that replays a cached token while still reporting the
356
+ # full TTL would otherwise push `_exp` past the token's real expiry, and
357
+ # each refresh pushes it further -- so the proactive `_exp - _LEEWAY`
358
+ # check never fires and an expired token goes on the wire. Observed in
359
+ # production: four consecutive mints returned the same `jti` with
360
+ # `expires_in=300` each time, while the token's true remaining life fell
361
+ # 300s -> 289s. Any load running longer than one token lifetime then
362
+ # fails at whatever it happens to be doing when the token dies.
363
+ #
364
+ # `min`, not "prefer the claim": a claim FURTHER out than `expires_in`
365
+ # would extend the client's trust past what the server offered, which is
366
+ # the opposite of the guarantee wanted here.
367
+ now = time.time()
368
+ by_expires_in = now + expires_in
369
+ claim = _exp_from_jwt(token)
370
+ if claim is not None and (claim > now or self._replayed):
371
+ self._exp = min(by_expires_in, claim)
372
+ else:
373
+ # No readable claim, or one already elapsed on a token we had NOT seen
374
+ # before. Two causes produce an elapsed claim and they want opposite
375
+ # answers, so `_replayed` -- set just above -- separates them:
376
+ #
377
+ # replayed the server keeps handing back one cached token, and its
378
+ # `exp` has finally passed. The token really is dead.
379
+ # Honour the claim: this manager accepted the same claim as
380
+ # FUTURE on an earlier mint, so the clock is not the
381
+ # explanation, and pretending otherwise would put `_exp` at
382
+ # `now + 300` on a corpse -- the pre-fix behaviour, leaving
383
+ # the 401 retry to pay a round trip that a proactive mint
384
+ # would have avoided.
385
+ #
386
+ # first seen the clocks disagree. The server validates `exp` against
387
+ # its own clock, so the token is fine and only this client
388
+ # disbelieves it. Honouring the claim would pin `_exp` in
389
+ # the past and run both grants on every request forever.
390
+ # `expires_in` is always in the future, which is what makes
391
+ # it the safe fallback.
392
+ #
393
+ # A skewed clock AND a replaying server together fall to the first
394
+ # branch, i.e. back to both grants per request. That union is the case
395
+ # being traded away, knowingly: it is rarer than either alone and the
396
+ # 401 retry still covers it.
397
+ self._exp = by_expires_in
264
398
  self._refresh = data.get("refresh_token") or self._refresh
265
399
  return True
266
400
 
@@ -2601,9 +2601,9 @@ class ConnectionsApi:
2601
2601
  _headers: Optional[Dict[StrictStr, Any]] = None,
2602
2602
  _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0,
2603
2603
  ) -> LoadManagedTableResponse:
2604
- """Load managed table from upload or query result
2604
+ """Load managed table from inline data, upload, or query result
2605
2605
 
2606
- Publish data as the new contents of a managed table from one of two sources — provide exactly one. With `upload_id`, a previously-uploaded file is published: CSV, JSON, and Parquet are supported; the format is auto-detected from the upload's `Content-Type` and file contents, or set explicitly via the `format` field. With `result_id`, a persisted query result is copied into the table, so the table keeps its data even after the result expires; a result can be loaded into any number of tables. If the target table (or its schema) has not been declared yet, it is created automatically as part of the load — declaring tables up front is optional. `mode` selects how the data is applied: `replace` overwrites the table's contents, `append` inserts the new rows on top of the existing data. Concurrent loads against the same upload return 409. For an upload, set `async` to run the load in the background and get back a job ID to poll; add `async_after_ms` to wait briefly for it to finish before falling back to a job ID. A `result_id` load runs synchronously.
2606
+ Publish data as the new contents of a managed table from one of three sources — provide exactly one. With `data`, CSV text is sent inline in this request, up to 2 MiB; column types are detected from the data unless `columns` declares them, and a larger payload is rejected with 413 and the error code `INLINE_DATA_TOO_LARGE`, at which point the data should be uploaded and loaded by `upload_id` instead. With `upload_id`, a previously-uploaded file is published: CSV, JSON, and Parquet are supported; the format is auto-detected from the upload's `Content-Type` and file contents, or set explicitly via the `format` field. With `result_id`, a persisted query result is copied into the table, so the table keeps its data even after the result expires; a result can be loaded into any number of tables. If the target table (or its schema) has not been declared yet, it is created automatically as part of the load — declaring tables up front is optional. `mode` selects how the data is applied: `replace` overwrites the table's contents, `append` inserts the new rows on top of the existing data. Concurrent loads against the same upload return 409. For an upload or inline data, set `async` to run the load in the background and get back a job ID to poll; add `async_after_ms` to wait briefly for it to finish before falling back to a job ID. A `result_id` load runs synchronously.
2607
2607
 
2608
2608
  :param connection_id: Connection ID (required)
2609
2609
  :type connection_id: str
@@ -2652,6 +2652,7 @@ class ConnectionsApi:
2652
2652
  '400': "ApiErrorResponse",
2653
2653
  '404': "ApiErrorResponse",
2654
2654
  '409': "ApiErrorResponse",
2655
+ '413': "ApiErrorResponse",
2655
2656
  }
2656
2657
  response_data = self.api_client.call_api(
2657
2658
  *_param,
@@ -2684,9 +2685,9 @@ class ConnectionsApi:
2684
2685
  _headers: Optional[Dict[StrictStr, Any]] = None,
2685
2686
  _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0,
2686
2687
  ) -> ApiResponse[LoadManagedTableResponse]:
2687
- """Load managed table from upload or query result
2688
+ """Load managed table from inline data, upload, or query result
2688
2689
 
2689
- Publish data as the new contents of a managed table from one of two sources — provide exactly one. With `upload_id`, a previously-uploaded file is published: CSV, JSON, and Parquet are supported; the format is auto-detected from the upload's `Content-Type` and file contents, or set explicitly via the `format` field. With `result_id`, a persisted query result is copied into the table, so the table keeps its data even after the result expires; a result can be loaded into any number of tables. If the target table (or its schema) has not been declared yet, it is created automatically as part of the load — declaring tables up front is optional. `mode` selects how the data is applied: `replace` overwrites the table's contents, `append` inserts the new rows on top of the existing data. Concurrent loads against the same upload return 409. For an upload, set `async` to run the load in the background and get back a job ID to poll; add `async_after_ms` to wait briefly for it to finish before falling back to a job ID. A `result_id` load runs synchronously.
2690
+ Publish data as the new contents of a managed table from one of three sources — provide exactly one. With `data`, CSV text is sent inline in this request, up to 2 MiB; column types are detected from the data unless `columns` declares them, and a larger payload is rejected with 413 and the error code `INLINE_DATA_TOO_LARGE`, at which point the data should be uploaded and loaded by `upload_id` instead. With `upload_id`, a previously-uploaded file is published: CSV, JSON, and Parquet are supported; the format is auto-detected from the upload's `Content-Type` and file contents, or set explicitly via the `format` field. With `result_id`, a persisted query result is copied into the table, so the table keeps its data even after the result expires; a result can be loaded into any number of tables. If the target table (or its schema) has not been declared yet, it is created automatically as part of the load — declaring tables up front is optional. `mode` selects how the data is applied: `replace` overwrites the table's contents, `append` inserts the new rows on top of the existing data. Concurrent loads against the same upload return 409. For an upload or inline data, set `async` to run the load in the background and get back a job ID to poll; add `async_after_ms` to wait briefly for it to finish before falling back to a job ID. A `result_id` load runs synchronously.
2690
2691
 
2691
2692
  :param connection_id: Connection ID (required)
2692
2693
  :type connection_id: str
@@ -2735,6 +2736,7 @@ class ConnectionsApi:
2735
2736
  '400': "ApiErrorResponse",
2736
2737
  '404': "ApiErrorResponse",
2737
2738
  '409': "ApiErrorResponse",
2739
+ '413': "ApiErrorResponse",
2738
2740
  }
2739
2741
  response_data = self.api_client.call_api(
2740
2742
  *_param,
@@ -2767,9 +2769,9 @@ class ConnectionsApi:
2767
2769
  _headers: Optional[Dict[StrictStr, Any]] = None,
2768
2770
  _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0,
2769
2771
  ) -> RESTResponseType:
2770
- """Load managed table from upload or query result
2772
+ """Load managed table from inline data, upload, or query result
2771
2773
 
2772
- Publish data as the new contents of a managed table from one of two sources — provide exactly one. With `upload_id`, a previously-uploaded file is published: CSV, JSON, and Parquet are supported; the format is auto-detected from the upload's `Content-Type` and file contents, or set explicitly via the `format` field. With `result_id`, a persisted query result is copied into the table, so the table keeps its data even after the result expires; a result can be loaded into any number of tables. If the target table (or its schema) has not been declared yet, it is created automatically as part of the load — declaring tables up front is optional. `mode` selects how the data is applied: `replace` overwrites the table's contents, `append` inserts the new rows on top of the existing data. Concurrent loads against the same upload return 409. For an upload, set `async` to run the load in the background and get back a job ID to poll; add `async_after_ms` to wait briefly for it to finish before falling back to a job ID. A `result_id` load runs synchronously.
2774
+ Publish data as the new contents of a managed table from one of three sources — provide exactly one. With `data`, CSV text is sent inline in this request, up to 2 MiB; column types are detected from the data unless `columns` declares them, and a larger payload is rejected with 413 and the error code `INLINE_DATA_TOO_LARGE`, at which point the data should be uploaded and loaded by `upload_id` instead. With `upload_id`, a previously-uploaded file is published: CSV, JSON, and Parquet are supported; the format is auto-detected from the upload's `Content-Type` and file contents, or set explicitly via the `format` field. With `result_id`, a persisted query result is copied into the table, so the table keeps its data even after the result expires; a result can be loaded into any number of tables. If the target table (or its schema) has not been declared yet, it is created automatically as part of the load — declaring tables up front is optional. `mode` selects how the data is applied: `replace` overwrites the table's contents, `append` inserts the new rows on top of the existing data. Concurrent loads against the same upload return 409. For an upload or inline data, set `async` to run the load in the background and get back a job ID to poll; add `async_after_ms` to wait briefly for it to finish before falling back to a job ID. A `result_id` load runs synchronously.
2773
2775
 
2774
2776
  :param connection_id: Connection ID (required)
2775
2777
  :type connection_id: str
@@ -2818,6 +2820,7 @@ class ConnectionsApi:
2818
2820
  '400': "ApiErrorResponse",
2819
2821
  '404': "ApiErrorResponse",
2820
2822
  '409': "ApiErrorResponse",
2823
+ '413': "ApiErrorResponse",
2821
2824
  }
2822
2825
  response_data = self.api_client.call_api(
2823
2826
  *_param,