hotdata 0.2.5__tar.gz → 0.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (350) hide show
  1. {hotdata-0.2.5 → hotdata-0.3.0}/PKG-INFO +1 -1
  2. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/__init__.py +10 -0
  3. hotdata-0.3.0/hotdata/_auth.py +233 -0
  4. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/api/connections_api.py +617 -0
  5. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/api/databases_api.py +620 -3
  6. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/api/datasets_api.py +21 -3
  7. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/api/query_api.py +9 -9
  8. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/api/saved_queries_api.py +21 -3
  9. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/api_client.py +1 -1
  10. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/configuration.py +40 -4
  11. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/__init__.py +5 -0
  12. hotdata-0.3.0/hotdata/models/add_managed_schema_request.py +98 -0
  13. hotdata-0.3.0/hotdata/models/add_managed_table_decl.py +88 -0
  14. hotdata-0.3.0/hotdata/models/add_managed_table_request.py +88 -0
  15. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/create_database_request.py +18 -4
  16. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/create_database_response.py +3 -1
  17. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/database_detail_response.py +3 -1
  18. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/database_summary.py +4 -2
  19. hotdata-0.3.0/hotdata/models/managed_schema_response.py +92 -0
  20. hotdata-0.3.0/hotdata/models/managed_table_response.py +92 -0
  21. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/query_request.py +22 -1
  22. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata.egg-info/PKG-INFO +1 -1
  23. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata.egg-info/SOURCES.txt +12 -0
  24. {hotdata-0.2.5 → hotdata-0.3.0}/pyproject.toml +1 -1
  25. hotdata-0.3.0/test/test_add_managed_schema_request.py +57 -0
  26. hotdata-0.3.0/test/test_add_managed_table_decl.py +53 -0
  27. hotdata-0.3.0/test/test_add_managed_table_request.py +53 -0
  28. hotdata-0.3.0/test/test_managed_schema_response.py +61 -0
  29. hotdata-0.3.0/test/test_managed_table_response.py +57 -0
  30. {hotdata-0.2.5 → hotdata-0.3.0}/tests/test_arrow.py +5 -0
  31. hotdata-0.3.0/tests/test_auth.py +616 -0
  32. {hotdata-0.2.5 → hotdata-0.3.0}/README.md +0 -0
  33. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/api/__init__.py +0 -0
  34. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/api/connection_types_api.py +0 -0
  35. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/api/database_context_api.py +0 -0
  36. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/api/embedding_providers_api.py +0 -0
  37. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/api/indexes_api.py +0 -0
  38. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/api/information_schema_api.py +0 -0
  39. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/api/jobs_api.py +0 -0
  40. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/api/query_runs_api.py +0 -0
  41. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/api/refresh_api.py +0 -0
  42. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/api/results_api.py +0 -0
  43. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/api/sandboxes_api.py +0 -0
  44. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/api/secrets_api.py +0 -0
  45. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/api/uploads_api.py +0 -0
  46. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/api/workspace_context_api.py +0 -0
  47. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/api/workspaces_api.py +0 -0
  48. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/api_response.py +0 -0
  49. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/arrow.py +0 -0
  50. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/exceptions.py +0 -0
  51. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/api_error_detail.py +0 -0
  52. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/api_error_response.py +0 -0
  53. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/async_query_response.py +0 -0
  54. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/attach_database_catalog_request.py +0 -0
  55. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/boolean_profile_detail.py +0 -0
  56. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/categorical_profile_detail.py +0 -0
  57. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/category_value_info.py +0 -0
  58. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/column_definition.py +0 -0
  59. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/column_info.py +0 -0
  60. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/column_profile_detail.py +0 -0
  61. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/column_profile_detail_one_of.py +0 -0
  62. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/column_profile_detail_one_of1.py +0 -0
  63. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/column_profile_detail_one_of2.py +0 -0
  64. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/column_profile_detail_one_of3.py +0 -0
  65. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/column_profile_detail_one_of4.py +0 -0
  66. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/column_profile_info.py +0 -0
  67. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/column_type_spec.py +0 -0
  68. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/connection_health_response.py +0 -0
  69. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/connection_info.py +0 -0
  70. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/connection_refresh_result.py +0 -0
  71. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/connection_schema_error.py +0 -0
  72. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/connection_type_detail.py +0 -0
  73. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/connection_type_summary.py +0 -0
  74. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/create_connection_request.py +0 -0
  75. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/create_connection_response.py +0 -0
  76. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/create_dataset_request.py +0 -0
  77. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/create_dataset_response.py +0 -0
  78. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/create_embedding_provider_request.py +0 -0
  79. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/create_embedding_provider_response.py +0 -0
  80. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/create_index_request.py +0 -0
  81. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/create_sandbox_request.py +0 -0
  82. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/create_saved_query_request.py +0 -0
  83. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/create_secret_request.py +0 -0
  84. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/create_secret_response.py +0 -0
  85. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/create_workspace201_response.py +0 -0
  86. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/create_workspace_request.py +0 -0
  87. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/create_workspace_response.py +0 -0
  88. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/database_attachment_info.py +0 -0
  89. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/database_context_entry.py +0 -0
  90. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/database_default_schema_decl.py +0 -0
  91. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/database_default_table_decl.py +0 -0
  92. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/dataset_source.py +0 -0
  93. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/dataset_source_one_of.py +0 -0
  94. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/dataset_source_one_of1.py +0 -0
  95. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/dataset_source_one_of2.py +0 -0
  96. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/dataset_source_one_of3.py +0 -0
  97. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/dataset_source_one_of4.py +0 -0
  98. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/dataset_summary.py +0 -0
  99. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/dataset_version_summary.py +0 -0
  100. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/delete_sandbox_response.py +0 -0
  101. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/discovery_status.py +0 -0
  102. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/embedding_provider_response.py +0 -0
  103. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/error.py +0 -0
  104. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/execute_saved_query_request.py +0 -0
  105. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/get_connection_response.py +0 -0
  106. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/get_database_context_response.py +0 -0
  107. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/get_dataset_response.py +0 -0
  108. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/get_result_response.py +0 -0
  109. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/get_secret_response.py +0 -0
  110. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/get_workspace_context_response.py +0 -0
  111. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/index_info_response.py +0 -0
  112. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/index_status.py +0 -0
  113. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/information_schema_response.py +0 -0
  114. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/inline_data.py +0 -0
  115. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/inline_dataset_source.py +0 -0
  116. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/job_result.py +0 -0
  117. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/job_status.py +0 -0
  118. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/job_status_response.py +0 -0
  119. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/job_type.py +0 -0
  120. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/list_connection_types_response.py +0 -0
  121. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/list_connections_response.py +0 -0
  122. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/list_database_contexts_response.py +0 -0
  123. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/list_databases_response.py +0 -0
  124. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/list_dataset_versions_response.py +0 -0
  125. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/list_datasets_response.py +0 -0
  126. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/list_embedding_providers_response.py +0 -0
  127. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/list_indexes_response.py +0 -0
  128. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/list_jobs_response.py +0 -0
  129. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/list_query_runs_response.py +0 -0
  130. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/list_results_response.py +0 -0
  131. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/list_sandboxes_response.py +0 -0
  132. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/list_saved_queries_response.py +0 -0
  133. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/list_saved_query_versions_response.py +0 -0
  134. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/list_secrets_response.py +0 -0
  135. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/list_uploads_response.py +0 -0
  136. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/list_workspace_contexts_response.py +0 -0
  137. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/list_workspaces200_response.py +0 -0
  138. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/list_workspaces_response.py +0 -0
  139. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/load_managed_table_request.py +0 -0
  140. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/load_managed_table_response.py +0 -0
  141. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/numeric_profile_detail.py +0 -0
  142. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/query_response.py +0 -0
  143. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/query_run_info.py +0 -0
  144. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/refresh_dataset_response.py +0 -0
  145. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/refresh_request.py +0 -0
  146. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/refresh_response.py +0 -0
  147. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/refresh_warning.py +0 -0
  148. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/result_info.py +0 -0
  149. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/results_format_query.py +0 -0
  150. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/sandbox.py +0 -0
  151. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/sandbox_response.py +0 -0
  152. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/saved_query_dataset_source.py +0 -0
  153. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/saved_query_detail.py +0 -0
  154. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/saved_query_summary.py +0 -0
  155. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/saved_query_version_info.py +0 -0
  156. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/schema_refresh_result.py +0 -0
  157. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/secret_metadata_response.py +0 -0
  158. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/sql_query_dataset_source.py +0 -0
  159. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/submit_job_response.py +0 -0
  160. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/table_info.py +0 -0
  161. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/table_profile_response.py +0 -0
  162. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/table_refresh_error.py +0 -0
  163. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/table_refresh_result.py +0 -0
  164. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/temporal_profile_detail.py +0 -0
  165. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/text_profile_detail.py +0 -0
  166. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/update_dataset_request.py +0 -0
  167. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/update_dataset_response.py +0 -0
  168. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/update_embedding_provider_request.py +0 -0
  169. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/update_embedding_provider_response.py +0 -0
  170. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/update_sandbox_request.py +0 -0
  171. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/update_saved_query_request.py +0 -0
  172. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/update_secret_request.py +0 -0
  173. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/update_secret_response.py +0 -0
  174. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/upload_dataset_source.py +0 -0
  175. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/upload_info.py +0 -0
  176. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/upload_response.py +0 -0
  177. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/upsert_database_context_request.py +0 -0
  178. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/upsert_database_context_response.py +0 -0
  179. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/upsert_workspace_context_request.py +0 -0
  180. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/upsert_workspace_context_response.py +0 -0
  181. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/url_dataset_source.py +0 -0
  182. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/workspace_context_entry.py +0 -0
  183. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/workspace_detail.py +0 -0
  184. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/models/workspace_list_item.py +0 -0
  185. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/py.typed +0 -0
  186. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata/rest.py +0 -0
  187. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata.egg-info/dependency_links.txt +0 -0
  188. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata.egg-info/requires.txt +0 -0
  189. {hotdata-0.2.5 → hotdata-0.3.0}/hotdata.egg-info/top_level.txt +0 -0
  190. {hotdata-0.2.5 → hotdata-0.3.0}/setup.cfg +0 -0
  191. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_api_client_close.py +0 -0
  192. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_api_error_detail.py +0 -0
  193. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_api_error_response.py +0 -0
  194. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_async_query_response.py +0 -0
  195. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_attach_database_catalog_request.py +0 -0
  196. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_boolean_profile_detail.py +0 -0
  197. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_categorical_profile_detail.py +0 -0
  198. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_category_value_info.py +0 -0
  199. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_column_definition.py +0 -0
  200. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_column_info.py +0 -0
  201. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_column_profile_detail.py +0 -0
  202. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_column_profile_detail_one_of.py +0 -0
  203. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_column_profile_detail_one_of1.py +0 -0
  204. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_column_profile_detail_one_of2.py +0 -0
  205. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_column_profile_detail_one_of3.py +0 -0
  206. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_column_profile_detail_one_of4.py +0 -0
  207. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_column_profile_info.py +0 -0
  208. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_column_type_spec.py +0 -0
  209. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_connection_health_response.py +0 -0
  210. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_connection_info.py +0 -0
  211. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_connection_refresh_result.py +0 -0
  212. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_connection_schema_error.py +0 -0
  213. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_connection_type_detail.py +0 -0
  214. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_connection_type_summary.py +0 -0
  215. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_connection_types_api.py +0 -0
  216. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_connections_api.py +0 -0
  217. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_create_connection_request.py +0 -0
  218. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_create_connection_response.py +0 -0
  219. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_create_database_request.py +0 -0
  220. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_create_database_response.py +0 -0
  221. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_create_dataset_request.py +0 -0
  222. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_create_dataset_response.py +0 -0
  223. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_create_embedding_provider_request.py +0 -0
  224. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_create_embedding_provider_response.py +0 -0
  225. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_create_index_request.py +0 -0
  226. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_create_sandbox_request.py +0 -0
  227. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_create_saved_query_request.py +0 -0
  228. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_create_secret_request.py +0 -0
  229. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_create_secret_response.py +0 -0
  230. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_create_workspace201_response.py +0 -0
  231. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_create_workspace_request.py +0 -0
  232. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_create_workspace_response.py +0 -0
  233. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_database_attachment_info.py +0 -0
  234. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_database_context_api.py +0 -0
  235. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_database_context_entry.py +0 -0
  236. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_database_default_schema_decl.py +0 -0
  237. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_database_default_table_decl.py +0 -0
  238. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_database_detail_response.py +0 -0
  239. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_database_summary.py +0 -0
  240. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_databases_api.py +0 -0
  241. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_dataset_source.py +0 -0
  242. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_dataset_source_one_of.py +0 -0
  243. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_dataset_source_one_of1.py +0 -0
  244. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_dataset_source_one_of2.py +0 -0
  245. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_dataset_source_one_of3.py +0 -0
  246. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_dataset_source_one_of4.py +0 -0
  247. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_dataset_summary.py +0 -0
  248. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_dataset_version_summary.py +0 -0
  249. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_datasets_api.py +0 -0
  250. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_delete_sandbox_response.py +0 -0
  251. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_discovery_status.py +0 -0
  252. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_embedding_provider_response.py +0 -0
  253. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_embedding_providers_api.py +0 -0
  254. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_error.py +0 -0
  255. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_execute_saved_query_request.py +0 -0
  256. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_get_connection_response.py +0 -0
  257. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_get_database_context_response.py +0 -0
  258. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_get_dataset_response.py +0 -0
  259. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_get_result_response.py +0 -0
  260. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_get_secret_response.py +0 -0
  261. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_get_workspace_context_response.py +0 -0
  262. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_index_info_response.py +0 -0
  263. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_index_status.py +0 -0
  264. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_indexes_api.py +0 -0
  265. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_information_schema_api.py +0 -0
  266. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_information_schema_response.py +0 -0
  267. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_inline_data.py +0 -0
  268. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_inline_dataset_source.py +0 -0
  269. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_job_result.py +0 -0
  270. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_job_status.py +0 -0
  271. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_job_status_response.py +0 -0
  272. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_job_type.py +0 -0
  273. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_jobs_api.py +0 -0
  274. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_list_connection_types_response.py +0 -0
  275. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_list_connections_response.py +0 -0
  276. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_list_database_contexts_response.py +0 -0
  277. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_list_databases_response.py +0 -0
  278. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_list_dataset_versions_response.py +0 -0
  279. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_list_datasets_response.py +0 -0
  280. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_list_embedding_providers_response.py +0 -0
  281. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_list_indexes_response.py +0 -0
  282. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_list_jobs_response.py +0 -0
  283. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_list_query_runs_response.py +0 -0
  284. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_list_results_response.py +0 -0
  285. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_list_sandboxes_response.py +0 -0
  286. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_list_saved_queries_response.py +0 -0
  287. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_list_saved_query_versions_response.py +0 -0
  288. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_list_secrets_response.py +0 -0
  289. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_list_uploads_response.py +0 -0
  290. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_list_workspace_contexts_response.py +0 -0
  291. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_list_workspaces200_response.py +0 -0
  292. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_list_workspaces_response.py +0 -0
  293. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_load_managed_table_request.py +0 -0
  294. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_load_managed_table_response.py +0 -0
  295. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_numeric_profile_detail.py +0 -0
  296. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_query_api.py +0 -0
  297. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_query_request.py +0 -0
  298. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_query_response.py +0 -0
  299. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_query_run_info.py +0 -0
  300. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_query_runs_api.py +0 -0
  301. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_refresh_api.py +0 -0
  302. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_refresh_dataset_response.py +0 -0
  303. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_refresh_request.py +0 -0
  304. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_refresh_response.py +0 -0
  305. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_refresh_warning.py +0 -0
  306. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_result_info.py +0 -0
  307. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_results_api.py +0 -0
  308. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_results_format_query.py +0 -0
  309. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_sandbox.py +0 -0
  310. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_sandbox_response.py +0 -0
  311. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_sandboxes_api.py +0 -0
  312. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_saved_queries_api.py +0 -0
  313. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_saved_query_dataset_source.py +0 -0
  314. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_saved_query_detail.py +0 -0
  315. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_saved_query_summary.py +0 -0
  316. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_saved_query_version_info.py +0 -0
  317. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_schema_refresh_result.py +0 -0
  318. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_secret_metadata_response.py +0 -0
  319. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_secrets_api.py +0 -0
  320. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_sql_query_dataset_source.py +0 -0
  321. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_submit_job_response.py +0 -0
  322. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_table_info.py +0 -0
  323. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_table_profile_response.py +0 -0
  324. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_table_refresh_error.py +0 -0
  325. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_table_refresh_result.py +0 -0
  326. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_temporal_profile_detail.py +0 -0
  327. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_text_profile_detail.py +0 -0
  328. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_update_dataset_request.py +0 -0
  329. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_update_dataset_response.py +0 -0
  330. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_update_embedding_provider_request.py +0 -0
  331. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_update_embedding_provider_response.py +0 -0
  332. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_update_sandbox_request.py +0 -0
  333. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_update_saved_query_request.py +0 -0
  334. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_update_secret_request.py +0 -0
  335. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_update_secret_response.py +0 -0
  336. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_upload_dataset_source.py +0 -0
  337. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_upload_info.py +0 -0
  338. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_upload_response.py +0 -0
  339. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_uploads_api.py +0 -0
  340. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_upsert_database_context_request.py +0 -0
  341. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_upsert_database_context_response.py +0 -0
  342. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_upsert_workspace_context_request.py +0 -0
  343. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_upsert_workspace_context_response.py +0 -0
  344. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_url_dataset_source.py +0 -0
  345. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_workspace_context_api.py +0 -0
  346. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_workspace_context_entry.py +0 -0
  347. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_workspace_detail.py +0 -0
  348. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_workspace_list_item.py +0 -0
  349. {hotdata-0.2.5 → hotdata-0.3.0}/test/test_workspaces_api.py +0 -0
  350. {hotdata-0.2.5 → hotdata-0.3.0}/tests/test_update_changelog.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hotdata
3
- Version: 0.2.5
3
+ Version: 0.3.0
4
4
  Summary: Hotdata API
5
5
  Author-email: Hotdata <developers@hotdata.dev>
6
6
  License: MIT
@@ -51,6 +51,9 @@ __all__ = [
51
51
  "ApiKeyError",
52
52
  "ApiAttributeError",
53
53
  "ApiException",
54
+ "AddManagedSchemaRequest",
55
+ "AddManagedTableDecl",
56
+ "AddManagedTableRequest",
54
57
  "ApiErrorDetail",
55
58
  "ApiErrorResponse",
56
59
  "AsyncQueryResponse",
@@ -140,6 +143,8 @@ __all__ = [
140
143
  "ListWorkspacesResponse",
141
144
  "LoadManagedTableRequest",
142
145
  "LoadManagedTableResponse",
146
+ "ManagedSchemaResponse",
147
+ "ManagedTableResponse",
143
148
  "NumericProfileDetail",
144
149
  "QueryRequest",
145
150
  "QueryResponse",
@@ -216,6 +221,9 @@ from hotdata.exceptions import ApiAttributeError as ApiAttributeError
216
221
  from hotdata.exceptions import ApiException as ApiException
217
222
 
218
223
  # import models into sdk package
224
+ from hotdata.models.add_managed_schema_request import AddManagedSchemaRequest as AddManagedSchemaRequest
225
+ from hotdata.models.add_managed_table_decl import AddManagedTableDecl as AddManagedTableDecl
226
+ from hotdata.models.add_managed_table_request import AddManagedTableRequest as AddManagedTableRequest
219
227
  from hotdata.models.api_error_detail import ApiErrorDetail as ApiErrorDetail
220
228
  from hotdata.models.api_error_response import ApiErrorResponse as ApiErrorResponse
221
229
  from hotdata.models.async_query_response import AsyncQueryResponse as AsyncQueryResponse
@@ -305,6 +313,8 @@ from hotdata.models.list_uploads_response import ListUploadsResponse as ListUplo
305
313
  from hotdata.models.list_workspaces_response import ListWorkspacesResponse as ListWorkspacesResponse
306
314
  from hotdata.models.load_managed_table_request import LoadManagedTableRequest as LoadManagedTableRequest
307
315
  from hotdata.models.load_managed_table_response import LoadManagedTableResponse as LoadManagedTableResponse
316
+ from hotdata.models.managed_schema_response import ManagedSchemaResponse as ManagedSchemaResponse
317
+ from hotdata.models.managed_table_response import ManagedTableResponse as ManagedTableResponse
308
318
  from hotdata.models.numeric_profile_detail import NumericProfileDetail as NumericProfileDetail
309
319
  from hotdata.models.query_request import QueryRequest as QueryRequest
310
320
  from hotdata.models.query_response import QueryResponse as QueryResponse
@@ -0,0 +1,233 @@
1
+ """Transparent API-token -> JWT exchange for the Hotdata Python SDK.
2
+
3
+ Hotdata is moving API authentication to short-lived JWTs. Users still configure
4
+ the SDK with their long-lived ``hd_`` API token, but every request should carry
5
+ a fresh JWT instead. This module is the hand-written, regeneration-immune piece
6
+ that makes that happen behind the scenes: :class:`_TokenManager` exchanges the
7
+ API token for a JWT at ``POST {host}/v1/auth/jwt`` and keeps it fresh, mirroring
8
+ the CLI's ``jwt.rs`` logic so the CLI and SDK behave identically.
9
+
10
+ OpenAPI Generator only rewrites the files it generates, so a hand-added module
11
+ like this one (precedent: :mod:`hotdata.arrow`) survives regeneration. It is
12
+ additionally listed in ``.openapi-generator-ignore`` as belt-and-suspenders.
13
+
14
+ Key behaviors:
15
+
16
+ * **Pass-through** -- a credential that already looks like a JWT (``eyJ``
17
+ prefix, matching the Gateway's own ``^Bearer eyJ.*`` detection) is returned
18
+ unchanged and never exchanged. Every other (opaque) credential is treated as
19
+ an API token and exchanged; set ``HOTDATA_DISABLE_JWT_EXCHANGE`` to force a
20
+ raw, non-JWT credential through as-is (local/dev setups, rollback).
21
+ * **Opt-out** -- if ``HOTDATA_DISABLE_JWT_EXCHANGE`` is set to an affirmative
22
+ value (``1``/``true``/``yes``/``on``), the credential is always returned
23
+ as-is (hard escape hatch for rollout); ``0``/``false``/empty do not opt out.
24
+ * **In-memory cache only** -- no disk writes. The server already de-duplicates
25
+ mints (keyed by ``sha256(api_token)``), so per-process caching is sufficient.
26
+ * **Thread-safe** -- a :class:`threading.Lock` with single-flight mint covers
27
+ the case where a shared ``ApiClient`` is hit from many threads at once.
28
+ * **Refresh, then re-mint** -- prefer the refresh token when available; on
29
+ refresh failure, re-mint from the held API token (always possible since the
30
+ SDK holds it). Matches the CLI.
31
+ * **TLS/proxy reuse** -- the exchange call reuses the SDK's configured TLS,
32
+ client cert and proxy settings (see :func:`_pool_from_config`) so it behaves
33
+ like every other SDK request, with a bounded timeout so a stalled token
34
+ endpoint fails fast instead of hanging every call.
35
+ """
36
+
37
+ import json
38
+ import os
39
+ import ssl
40
+ import threading
41
+ import time
42
+ from urllib.parse import urlencode
43
+
44
+ import urllib3
45
+
46
+ _LEEWAY = 30 # refresh when <30s of life remains
47
+ _TIMEOUT = 30.0 # seconds -- never let a stalled token endpoint hang every request
48
+ _CLIENT_ID = "hotdata-python-sdk"
49
+
50
+ # Env var that disables exchange entirely. Used as a hard escape hatch during
51
+ # the rollout window and for local/dev setups. Only affirmative values opt out
52
+ # (see _DISABLE_VALUES) so that ``=0`` / ``=false`` do NOT silently disable it.
53
+ _DISABLE_ENV = "HOTDATA_DISABLE_JWT_EXCHANGE"
54
+ _DISABLE_VALUES = {"1", "true", "yes", "on"}
55
+
56
+ # The SOCKS schemes urllib3 routes through SOCKSProxyManager rather than the
57
+ # plain ProxyManager. Mirrors hotdata/rest.py's SUPPORTED_SOCKS_PROXIES.
58
+ _SUPPORTED_SOCKS_PROXIES = {"socks5", "socks5h", "socks4", "socks4a"}
59
+
60
+
61
+ class TokenExchangeError(Exception):
62
+ """Raised when an API token cannot be exchanged for a JWT.
63
+
64
+ Surfacing ``invalid_grant`` (expired/revoked API token) here keeps the
65
+ failure clear instead of a confusing downstream 401.
66
+ """
67
+
68
+
69
+ def _is_socks_proxy_url(url):
70
+ # Mirror hotdata/rest.py.is_socks_proxy_url so the exchange pool routes
71
+ # SOCKS proxies the same way the generated REST client does.
72
+ if url is None:
73
+ return False
74
+ split_section = url.split("://")
75
+ if len(split_section) < 2:
76
+ return False
77
+ return split_section[0].lower() in _SUPPORTED_SOCKS_PROXIES
78
+
79
+
80
+ def _pool_from_config(configuration):
81
+ """Build a urllib3 pool manager from the SDK's TLS/proxy configuration.
82
+
83
+ Deliberately parallels ``RESTClientObject.__init__`` in
84
+ :mod:`hotdata.rest` so the token-exchange call honors the same
85
+ ``ssl_ca_cert`` / ``ca_cert_data`` / ``cert_file`` / ``key_file`` /
86
+ ``proxy`` / ``verify_ssl`` settings as every other SDK request. We build a
87
+ fresh, lightweight pool here rather than reaching into the ``ApiClient``'s
88
+ REST client (which the ``Configuration`` does not hold a reference to).
89
+ """
90
+ # cert_reqs -- honor verify_ssl exactly as the generated client does.
91
+ if configuration.verify_ssl:
92
+ cert_reqs = ssl.CERT_REQUIRED
93
+ else:
94
+ cert_reqs = ssl.CERT_NONE
95
+
96
+ pool_args = {
97
+ "cert_reqs": cert_reqs,
98
+ "ca_certs": configuration.ssl_ca_cert,
99
+ "cert_file": configuration.cert_file,
100
+ "key_file": configuration.key_file,
101
+ "ca_cert_data": configuration.ca_cert_data,
102
+ }
103
+ # Mirror rest.py's hostname/SNI handling so the exchange call does not
104
+ # silently fail for users who customize them (corporate MITM proxies set
105
+ # assert_hostname; some gateways require an explicit tls_server_name/SNI).
106
+ if configuration.assert_hostname is not None:
107
+ pool_args["assert_hostname"] = configuration.assert_hostname
108
+ if configuration.tls_server_name:
109
+ pool_args["server_hostname"] = configuration.tls_server_name
110
+ if configuration.socket_options is not None:
111
+ pool_args["socket_options"] = configuration.socket_options
112
+ # `retries`/`maxsize` are intentionally not mirrored: the exchange is a
113
+ # single bounded-timeout request that fails fast rather than retrying.
114
+
115
+ if configuration.proxy:
116
+ if _is_socks_proxy_url(configuration.proxy):
117
+ from urllib3.contrib.socks import SOCKSProxyManager
118
+ pool_args["proxy_url"] = configuration.proxy
119
+ pool_args["headers"] = configuration.proxy_headers
120
+ return SOCKSProxyManager(**pool_args)
121
+ pool_args["proxy_url"] = configuration.proxy
122
+ pool_args["proxy_headers"] = configuration.proxy_headers
123
+ return urllib3.ProxyManager(**pool_args)
124
+
125
+ return urllib3.PoolManager(**pool_args)
126
+
127
+
128
+ class _TokenManager:
129
+ """Exchanges an API token for short-lived JWTs and keeps them fresh.
130
+
131
+ A credential that already looks like a JWT (``eyJ`` prefix) is passed
132
+ through unchanged, as is any credential when
133
+ ``HOTDATA_DISABLE_JWT_EXCHANGE`` is set; every other (opaque) API token is
134
+ exchanged.
135
+ """
136
+
137
+ def __init__(self, credential, configuration, pool=None):
138
+ self._credential = credential
139
+ self._config = configuration # read host + TLS lazily at mint time
140
+ self._pool = pool # injected in tests; else built from config TLS
141
+ self._lock = threading.Lock()
142
+ self._jwt = None
143
+ self._exp = 0.0
144
+ self._refresh = None
145
+
146
+ @property
147
+ def _needs_exchange(self):
148
+ # Opt-out wins outright: an affirmative HOTDATA_DISABLE_JWT_EXCHANGE
149
+ # (1/true/yes/on) means send the credential as-is, never touching the
150
+ # token endpoint. Other values (incl. 0/false/empty) do not opt out.
151
+ if os.environ.get(_DISABLE_ENV, "").strip().lower() in _DISABLE_VALUES:
152
+ return False
153
+ # A compact JWT always starts with "eyJ" (base64 of '{"'), matching the
154
+ # Gateway's own ``^Bearer eyJ.*`` detection -- those already are what we
155
+ # want on the wire, so pass them through. Everything else is an opaque
156
+ # API token to be exchanged. (Hotdata API tokens are bare hex; the
157
+ # ``hd_`` prefix seen in docs/comments is cosmetic and not enforced by
158
+ # the server, so we must not gate on it.) Use HOTDATA_DISABLE_JWT_EXCHANGE
159
+ # to force a raw, non-JWT credential through unchanged (local/dev).
160
+ return isinstance(self._credential, str) and not self._credential.startswith("eyJ")
161
+
162
+ def bearer_value(self):
163
+ """Return a live JWT (exchanging + caching), or the credential as-is.
164
+
165
+ Returns the credential unchanged when it is already a JWT or when
166
+ exchange is disabled; otherwise returns a cached JWT, refreshing or
167
+ re-minting it when it is within ``_LEEWAY`` seconds of expiry.
168
+ """
169
+ if not self._needs_exchange:
170
+ return self._credential # already a JWT (or opt-out) -> unchanged
171
+ with self._lock:
172
+ # Fast path: a still-valid cached JWT, no network call.
173
+ if self._jwt and time.time() < self._exp - _LEEWAY:
174
+ return self._jwt
175
+ # Prefer the refresh token; on failure, drop it and re-mint below.
176
+ if self._refresh and not self._mint(
177
+ {"grant_type": "refresh_token", "refresh_token": self._refresh}
178
+ ):
179
+ self._refresh = None # refresh failed -> fall through to re-mint
180
+ # Re-mint from the held API token if we still lack a fresh JWT.
181
+ if not self._jwt or time.time() >= self._exp - _LEEWAY:
182
+ self._mint({"grant_type": "api_token", "api_token": self._credential})
183
+ return self._jwt
184
+
185
+ def _mint(self, params):
186
+ # Returns True on success. The refresh path is best-effort: ANY failure
187
+ # -- a non-200, a transport error, or a malformed/missing-token body --
188
+ # returns False so the caller re-mints from the held API token. An
189
+ # api_token mint instead raises TokenExchangeError on any failure, since
190
+ # there is no further fallback.
191
+ params["client_id"] = _CLIENT_ID
192
+ is_refresh = params["grant_type"] == "refresh_token"
193
+ try:
194
+ pool = self._pool or _pool_from_config(self._config) # reuses ssl_ca_cert/cert/proxy
195
+ host = self._config.host.rstrip("/") # read host lazily -- may be set post-construct
196
+ resp = pool.request(
197
+ "POST",
198
+ f"{host}/v1/auth/jwt",
199
+ body=urlencode(params),
200
+ headers={"Content-Type": "application/x-www-form-urlencoded"},
201
+ timeout=_TIMEOUT,
202
+ )
203
+ if resp.status != 200:
204
+ raise TokenExchangeError(
205
+ f"token exchange failed: {resp.status} {resp.data[:200]!r}"
206
+ )
207
+ data = json.loads(resp.data)
208
+ token = data["access_token"]
209
+ expires_in = float(data.get("expires_in", 300))
210
+ except (
211
+ TokenExchangeError,
212
+ urllib3.exceptions.HTTPError,
213
+ ValueError,
214
+ TypeError,
215
+ KeyError,
216
+ ) as exc:
217
+ if is_refresh:
218
+ return False # let caller re-mint from the API token
219
+ if isinstance(exc, TokenExchangeError):
220
+ raise
221
+ raise TokenExchangeError(f"token exchange failed: {exc!r}") from exc
222
+ self._jwt = token
223
+ self._exp = time.time() + expires_in
224
+ self._refresh = data.get("refresh_token") or self._refresh
225
+ return True
226
+
227
+
228
+ __all__ = [
229
+ "TokenExchangeError",
230
+ "_TokenManager",
231
+ "_CLIENT_ID",
232
+ "_pool_from_config",
233
+ ]