honeycomb-api 0.1.0__py3-none-any.whl → 0.5.3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (443) hide show
  1. honeycomb/__init__.py +9 -0
  2. honeycomb/_generated/api/auth/get_auth.py +2 -5
  3. honeycomb/_generated/api/auth/get_v2_auth.py +2 -5
  4. honeycomb/_generated/api/boards/create_board.py +6 -5
  5. honeycomb/_generated/api/boards/create_board_view.py +14 -9
  6. honeycomb/_generated/api/boards/delete_board.py +2 -5
  7. honeycomb/_generated/api/boards/delete_board_view.py +2 -5
  8. honeycomb/_generated/api/boards/get_board.py +2 -5
  9. honeycomb/_generated/api/boards/get_board_view.py +2 -5
  10. honeycomb/_generated/api/boards/list_board_views.py +10 -9
  11. honeycomb/_generated/api/boards/list_boards.py +2 -5
  12. honeycomb/_generated/api/boards/update_board.py +10 -5
  13. honeycomb/_generated/api/boards/update_board_view.py +2 -5
  14. honeycomb/_generated/api/burn_alerts/create_burn_alert.py +6 -8
  15. honeycomb/_generated/api/burn_alerts/delete_burn_alert.py +2 -5
  16. honeycomb/_generated/api/burn_alerts/get_burn_alert.py +2 -5
  17. honeycomb/_generated/api/burn_alerts/list_burn_alerts_by_slo.py +2 -5
  18. honeycomb/_generated/api/calculated_fields/create_calculated_field.py +2 -5
  19. honeycomb/_generated/api/calculated_fields/delete_calculated_field.py +2 -5
  20. honeycomb/_generated/api/calculated_fields/get_calculated_field.py +2 -5
  21. honeycomb/_generated/api/calculated_fields/list_calculated_fields.py +2 -8
  22. honeycomb/_generated/api/calculated_fields/update_calculated_field.py +2 -5
  23. honeycomb/_generated/api/columns/create_column.py +2 -5
  24. honeycomb/_generated/api/columns/delete_column.py +2 -5
  25. honeycomb/_generated/api/columns/get_column.py +2 -5
  26. honeycomb/_generated/api/columns/list_columns.py +2 -8
  27. honeycomb/_generated/api/columns/update_column.py +2 -5
  28. honeycomb/_generated/api/dataset_definitions/list_dataset_definitions.py +2 -5
  29. honeycomb/_generated/api/dataset_definitions/patch_dataset_definitions.py +2 -5
  30. honeycomb/_generated/api/datasets/create_dataset.py +2 -5
  31. honeycomb/_generated/api/datasets/delete_dataset.py +2 -5
  32. honeycomb/_generated/api/datasets/get_dataset.py +2 -5
  33. honeycomb/_generated/api/datasets/list_datasets.py +2 -5
  34. honeycomb/_generated/api/datasets/update_dataset.py +2 -5
  35. honeycomb/_generated/api/enhance/record_enhance_indexer_usage.py +4 -6
  36. honeycomb/_generated/api/environments/create_environment.py +2 -5
  37. honeycomb/_generated/api/environments/delete_environment.py +2 -5
  38. honeycomb/_generated/api/environments/get_environment.py +2 -5
  39. honeycomb/_generated/api/environments/list_environments.py +2 -7
  40. honeycomb/_generated/api/environments/update_environment.py +2 -5
  41. honeycomb/_generated/api/events/create_event.py +2 -7
  42. honeycomb/_generated/api/events/create_events.py +7 -11
  43. honeycomb/_generated/api/key_management/create_api_key.py +2 -5
  44. honeycomb/_generated/api/key_management/delete_api_key.py +2 -5
  45. honeycomb/_generated/api/key_management/get_api_key.py +2 -5
  46. honeycomb/_generated/api/key_management/list_api_keys.py +2 -7
  47. honeycomb/_generated/api/key_management/update_api_key.py +2 -5
  48. honeycomb/_generated/api/kinesis_events/create_kinesis_events.py +2 -5
  49. honeycomb/_generated/api/marker_settings/create_marker_setting.py +2 -5
  50. honeycomb/_generated/api/marker_settings/delete_marker_settings.py +2 -5
  51. honeycomb/_generated/api/marker_settings/list_marker_settings.py +2 -5
  52. honeycomb/_generated/api/marker_settings/update_marker_settings.py +2 -5
  53. honeycomb/_generated/api/markers/create_marker.py +2 -5
  54. honeycomb/_generated/api/markers/create_marker_v2.py +2 -5
  55. honeycomb/_generated/api/markers/delete_marker.py +2 -5
  56. honeycomb/_generated/api/markers/get_marker.py +2 -5
  57. honeycomb/_generated/api/markers/update_marker.py +2 -5
  58. honeycomb/_generated/api/markers/update_marker_v2.py +2 -5
  59. honeycomb/_generated/api/pipelines/get_pipeline_configuration.py +4 -8
  60. honeycomb/_generated/api/pipelines/record_pipeline_usage.py +4 -6
  61. honeycomb/_generated/api/pipelines/update_pipeline_configuration_rollout.py +6 -7
  62. honeycomb/_generated/api/queries/create_query.py +2 -5
  63. honeycomb/_generated/api/queries/get_query.py +2 -5
  64. honeycomb/_generated/api/query_annotations/create_query_annotation.py +2 -5
  65. honeycomb/_generated/api/query_annotations/delete_query_annotation.py +2 -5
  66. honeycomb/_generated/api/query_annotations/get_query_annotation.py +2 -5
  67. honeycomb/_generated/api/query_annotations/list_query_annotations.py +2 -7
  68. honeycomb/_generated/api/query_annotations/update_query_annotation.py +2 -5
  69. honeycomb/_generated/api/query_data/create_query_result.py +2 -5
  70. honeycomb/_generated/api/query_data/get_query_result.py +2 -5
  71. honeycomb/_generated/api/recipients/create_recipient.py +2 -6
  72. honeycomb/_generated/api/recipients/delete_recipient.py +2 -5
  73. honeycomb/_generated/api/recipients/get_recipient.py +2 -6
  74. honeycomb/_generated/api/recipients/list_recipients.py +2 -6
  75. honeycomb/_generated/api/recipients/update_recipient.py +2 -6
  76. honeycomb/_generated/api/reporting/get_slo_history.py +2 -5
  77. honeycomb/_generated/api/service_maps/create_map_dependency_request.py +6 -9
  78. honeycomb/_generated/api/service_maps/get_map_dependencies.py +2 -7
  79. honeycomb/_generated/api/sl_os/create_slo.py +2 -5
  80. honeycomb/_generated/api/sl_os/delete_slo.py +2 -5
  81. honeycomb/_generated/api/sl_os/get_slo.py +2 -8
  82. honeycomb/_generated/api/sl_os/list_slos.py +2 -5
  83. honeycomb/_generated/api/sl_os/update_slo.py +2 -5
  84. honeycomb/_generated/api/triggers/create_trigger.py +2 -6
  85. honeycomb/_generated/api/triggers/delete_trigger.py +2 -5
  86. honeycomb/_generated/api/triggers/get_trigger.py +2 -5
  87. honeycomb/_generated/api/triggers/list_triggers.py +2 -5
  88. honeycomb/_generated/api/triggers/list_triggers_with_recipient.py +2 -5
  89. honeycomb/_generated/api/triggers/update_trigger.py +2 -5
  90. honeycomb/_generated/client.py +2 -5
  91. honeycomb/_generated/models/__init__.py +195 -88
  92. honeycomb/_generated/models/api_key_create_request.py +6 -5
  93. honeycomb/_generated/models/api_key_create_request_data.py +15 -11
  94. honeycomb/_generated/models/api_key_create_request_data_relationships.py +2 -3
  95. honeycomb/_generated/models/api_key_create_request_data_type.py +1 -0
  96. honeycomb/_generated/models/api_key_list_response.py +2 -5
  97. honeycomb/_generated/models/api_key_object.py +14 -14
  98. honeycomb/_generated/models/api_key_object_links.py +2 -9
  99. honeycomb/_generated/models/api_key_object_relationships.py +5 -9
  100. honeycomb/_generated/models/api_key_object_type.py +1 -0
  101. honeycomb/_generated/models/api_key_response.py +2 -3
  102. honeycomb/_generated/models/api_key_update_request.py +15 -17
  103. honeycomb/_generated/models/auth.py +2 -5
  104. honeycomb/_generated/models/auth_api_key_access.py +2 -9
  105. honeycomb/_generated/models/auth_environment.py +2 -9
  106. honeycomb/_generated/models/auth_team.py +2 -9
  107. honeycomb/_generated/models/auth_type.py +1 -0
  108. honeycomb/_generated/models/auth_v2_response.py +5 -8
  109. honeycomb/_generated/models/auth_v2_response_data.py +14 -11
  110. honeycomb/_generated/models/auth_v2_response_data_attributes.py +10 -9
  111. honeycomb/_generated/models/auth_v2_response_data_attributes_key_type.py +1 -0
  112. honeycomb/_generated/models/auth_v2_response_data_attributes_timestamps.py +4 -12
  113. honeycomb/_generated/models/auth_v2_response_data_relationships.py +1 -7
  114. honeycomb/_generated/models/auth_v2_response_data_type.py +1 -0
  115. honeycomb/_generated/models/base_trigger.py +21 -18
  116. honeycomb/_generated/models/base_trigger_alert_type.py +1 -0
  117. honeycomb/_generated/models/base_trigger_baseline_details_type_0.py +5 -9
  118. honeycomb/_generated/models/base_trigger_baseline_details_type_0_offset_minutes.py +1 -0
  119. honeycomb/_generated/models/base_trigger_baseline_details_type_0_type.py +1 -0
  120. honeycomb/_generated/models/base_trigger_evaluation_schedule.py +8 -6
  121. honeycomb/_generated/models/base_trigger_evaluation_schedule_type.py +1 -0
  122. honeycomb/_generated/models/base_trigger_evaluation_schedule_window.py +4 -9
  123. honeycomb/_generated/models/base_trigger_evaluation_schedule_window_days_of_week_item.py +1 -0
  124. honeycomb/_generated/models/base_trigger_threshold.py +2 -9
  125. honeycomb/_generated/models/base_trigger_threshold_op.py +1 -0
  126. honeycomb/_generated/models/batch_event.py +2 -5
  127. honeycomb/_generated/models/board.py +15 -17
  128. honeycomb/_generated/models/board_layout_generation.py +1 -0
  129. honeycomb/_generated/models/board_links.py +2 -9
  130. honeycomb/_generated/models/board_panel_position.py +2 -9
  131. honeycomb/_generated/models/board_query_visualization_settings.py +8 -8
  132. honeycomb/_generated/models/board_query_visualization_settings_charts_item.py +4 -10
  133. honeycomb/_generated/models/board_query_visualization_settings_charts_item_chart_type.py +1 -0
  134. honeycomb/_generated/models/board_type.py +1 -0
  135. honeycomb/_generated/models/board_view_filter.py +2 -9
  136. honeycomb/_generated/models/board_view_filter_operation.py +1 -0
  137. honeycomb/_generated/models/board_view_response.py +2 -5
  138. honeycomb/_generated/models/budget_rate.py +4 -12
  139. honeycomb/_generated/models/budget_rate_alert_type.py +1 -0
  140. honeycomb/_generated/models/burn_alert_shared_params.py +4 -12
  141. honeycomb/_generated/models/calculated_field.py +2 -9
  142. honeycomb/_generated/models/configuration_key_attributes.py +16 -12
  143. honeycomb/_generated/models/configuration_key_attributes_key_type.py +1 -0
  144. honeycomb/_generated/models/configuration_key_attributes_permissions.py +172 -0
  145. honeycomb/_generated/models/configuration_key_attributes_timestamps.py +4 -12
  146. honeycomb/_generated/models/configuration_key_request.py +101 -0
  147. honeycomb/_generated/models/configuration_key_request_attributes.py +107 -0
  148. honeycomb/_generated/models/configuration_key_request_attributes_permissions.py +168 -0
  149. honeycomb/_generated/models/configuration_key_request_type.py +8 -0
  150. honeycomb/_generated/models/create_board_view_request.py +2 -3
  151. honeycomb/_generated/models/create_budget_rate_burn_alert_request.py +10 -10
  152. honeycomb/_generated/models/create_budget_rate_burn_alert_request_slo.py +1 -7
  153. honeycomb/_generated/models/create_column.py +2 -9
  154. honeycomb/_generated/models/create_column_type.py +1 -0
  155. honeycomb/_generated/models/create_enhance_indexer_usage_record_request.py +8 -6
  156. honeycomb/_generated/models/create_enhance_indexer_usage_record_request_data.py +10 -7
  157. honeycomb/_generated/models/create_enhance_indexer_usage_record_request_data_attributes.py +8 -8
  158. honeycomb/_generated/models/create_enhance_indexer_usage_record_request_data_attributes_usage_data.py +8 -6
  159. honeycomb/_generated/models/create_enhance_indexer_usage_record_request_data_attributes_usage_data_resource_metrics_item.py +8 -6
  160. honeycomb/_generated/models/create_enhance_indexer_usage_record_request_data_attributes_usage_data_resource_metrics_item_scope_metrics_item.py +8 -6
  161. honeycomb/_generated/models/create_enhance_indexer_usage_record_request_data_attributes_usage_data_resource_metrics_item_scope_metrics_item_metrics_item.py +8 -8
  162. honeycomb/_generated/models/create_enhance_indexer_usage_record_request_data_attributes_usage_data_resource_metrics_item_scope_metrics_item_metrics_item_sum.py +10 -7
  163. honeycomb/_generated/models/create_enhance_indexer_usage_record_request_data_attributes_usage_data_resource_metrics_item_scope_metrics_item_metrics_item_sum_aggregation_temporality.py +1 -0
  164. honeycomb/_generated/models/create_enhance_indexer_usage_record_request_data_attributes_usage_data_resource_metrics_item_scope_metrics_item_metrics_item_sum_datapoints_item.py +8 -6
  165. honeycomb/_generated/models/create_enhance_indexer_usage_record_request_data_attributes_usage_data_resource_metrics_item_scope_metrics_item_metrics_item_sum_datapoints_item_attributes_item.py +8 -6
  166. honeycomb/_generated/models/create_enhance_indexer_usage_record_request_data_attributes_usage_data_resource_metrics_item_scope_metrics_item_metrics_item_sum_datapoints_item_attributes_item_value.py +2 -9
  167. honeycomb/_generated/models/create_enhance_indexer_usage_record_request_data_type.py +1 -0
  168. honeycomb/_generated/models/create_environment_request.py +8 -6
  169. honeycomb/_generated/models/create_environment_request_data.py +10 -7
  170. honeycomb/_generated/models/create_environment_request_data_attributes.py +2 -9
  171. honeycomb/_generated/models/create_environment_request_data_type.py +1 -0
  172. honeycomb/_generated/models/create_events_content_encoding.py +1 -0
  173. honeycomb/_generated/models/create_events_response_200_item.py +2 -9
  174. honeycomb/_generated/models/create_exhaustion_time_burn_alert_request.py +10 -10
  175. honeycomb/_generated/models/create_exhaustion_time_burn_alert_request_slo.py +1 -7
  176. honeycomb/_generated/models/create_map_dependencies_request.py +2 -5
  177. honeycomb/_generated/models/create_map_dependencies_response.py +4 -10
  178. honeycomb/_generated/models/create_map_dependencies_response_status.py +1 -0
  179. honeycomb/_generated/models/create_pipeline_health_record_request.py +8 -6
  180. honeycomb/_generated/models/create_pipeline_health_record_request_data.py +10 -7
  181. honeycomb/_generated/models/create_pipeline_health_record_request_data_attributes.py +8 -8
  182. honeycomb/_generated/models/create_pipeline_health_record_request_data_attributes_usage_data.py +8 -6
  183. honeycomb/_generated/models/create_pipeline_health_record_request_data_attributes_usage_data_resource_metrics_item.py +8 -6
  184. honeycomb/_generated/models/create_pipeline_health_record_request_data_attributes_usage_data_resource_metrics_item_scope_metrics_item.py +8 -6
  185. honeycomb/_generated/models/create_pipeline_health_record_request_data_attributes_usage_data_resource_metrics_item_scope_metrics_item_metrics_item.py +8 -8
  186. honeycomb/_generated/models/create_pipeline_health_record_request_data_attributes_usage_data_resource_metrics_item_scope_metrics_item_metrics_item_sum.py +10 -7
  187. honeycomb/_generated/models/create_pipeline_health_record_request_data_attributes_usage_data_resource_metrics_item_scope_metrics_item_metrics_item_sum_aggregation_temporality.py +1 -0
  188. honeycomb/_generated/models/create_pipeline_health_record_request_data_attributes_usage_data_resource_metrics_item_scope_metrics_item_metrics_item_sum_datapoints_item.py +8 -6
  189. honeycomb/_generated/models/create_pipeline_health_record_request_data_attributes_usage_data_resource_metrics_item_scope_metrics_item_metrics_item_sum_datapoints_item_attributes_item.py +8 -6
  190. honeycomb/_generated/models/create_pipeline_health_record_request_data_attributes_usage_data_resource_metrics_item_scope_metrics_item_metrics_item_sum_datapoints_item_attributes_item_value.py +2 -9
  191. honeycomb/_generated/models/create_pipeline_health_record_request_data_type.py +1 -0
  192. honeycomb/_generated/models/create_query_result_request.py +2 -9
  193. honeycomb/_generated/models/dataset.py +2 -6
  194. honeycomb/_generated/models/dataset_creation_payload.py +2 -9
  195. honeycomb/_generated/models/dataset_definition_type_1.py +4 -10
  196. honeycomb/_generated/models/dataset_definition_type_1_column_type.py +1 -0
  197. honeycomb/_generated/models/dataset_definitions.py +2 -6
  198. honeycomb/_generated/models/dataset_relationship.py +2 -3
  199. honeycomb/_generated/models/dataset_relationship_data.py +2 -8
  200. honeycomb/_generated/models/dataset_relationship_data_type.py +1 -0
  201. honeycomb/_generated/models/dataset_settings.py +2 -9
  202. honeycomb/_generated/models/dataset_update_payload.py +8 -8
  203. honeycomb/_generated/models/dataset_update_payload_settings.py +2 -9
  204. honeycomb/_generated/models/detailed_error.py +2 -9
  205. honeycomb/_generated/models/email_recipient.py +4 -7
  206. honeycomb/_generated/models/email_recipient_details.py +1 -7
  207. honeycomb/_generated/models/email_recipient_type.py +1 -0
  208. honeycomb/_generated/models/environment.py +6 -7
  209. honeycomb/_generated/models/environment_attributes.py +11 -9
  210. honeycomb/_generated/models/environment_attributes_color_type_1.py +1 -0
  211. honeycomb/_generated/models/environment_attributes_settings.py +1 -7
  212. honeycomb/_generated/models/environment_color.py +1 -0
  213. honeycomb/_generated/models/environment_links.py +1 -7
  214. honeycomb/_generated/models/environment_list_response.py +2 -5
  215. honeycomb/_generated/models/environment_relationship.py +8 -6
  216. honeycomb/_generated/models/environment_relationship_data.py +3 -8
  217. honeycomb/_generated/models/environment_relationship_data_type.py +1 -0
  218. honeycomb/_generated/models/environment_response.py +2 -3
  219. honeycomb/_generated/models/environment_type.py +1 -0
  220. honeycomb/_generated/models/error.py +2 -9
  221. honeycomb/_generated/models/event.py +2 -8
  222. honeycomb/_generated/models/exhaustion_time.py +4 -12
  223. honeycomb/_generated/models/exhaustion_time_alert_type.py +1 -0
  224. honeycomb/_generated/models/exhaustion_time_burn_alert_list_response.py +10 -10
  225. honeycomb/_generated/models/exhaustion_time_burn_alert_list_response_slo.py +2 -9
  226. honeycomb/_generated/models/filter_op.py +1 -0
  227. honeycomb/_generated/models/get_map_dependencies_response.py +7 -10
  228. honeycomb/_generated/models/get_map_dependencies_response_status.py +1 -0
  229. honeycomb/_generated/models/having_calculate_op.py +1 -0
  230. honeycomb/_generated/models/having_op.py +1 -0
  231. honeycomb/_generated/models/included_resource.py +6 -7
  232. honeycomb/_generated/models/included_resource_attributes.py +1 -7
  233. honeycomb/_generated/models/ingest_key_attributes.py +14 -11
  234. honeycomb/_generated/models/ingest_key_attributes_key_type.py +1 -0
  235. honeycomb/_generated/models/ingest_key_attributes_permissions.py +2 -9
  236. honeycomb/_generated/models/ingest_key_attributes_timestamps.py +4 -12
  237. honeycomb/_generated/models/ingest_key_request.py +100 -0
  238. honeycomb/_generated/models/ingest_key_request_attributes.py +75 -0
  239. honeycomb/_generated/models/ingest_key_request_type.py +8 -0
  240. honeycomb/_generated/models/ingest_key_type.py +2 -9
  241. honeycomb/_generated/models/ingest_key_type_key_type.py +1 -0
  242. honeycomb/_generated/models/jsonapi_error_source.py +2 -9
  243. honeycomb/_generated/models/kinesis_event.py +2 -5
  244. honeycomb/_generated/models/kinesis_event_record.py +2 -9
  245. honeycomb/_generated/models/kinesis_response.py +2 -9
  246. honeycomb/_generated/models/list_api_keys_filtertype.py +1 -0
  247. honeycomb/_generated/models/map_dependency.py +2 -5
  248. honeycomb/_generated/models/map_node.py +2 -9
  249. honeycomb/_generated/models/map_node_type.py +1 -0
  250. honeycomb/_generated/models/marker.py +2 -9
  251. honeycomb/_generated/models/marker_create_request.py +2 -3
  252. honeycomb/_generated/models/marker_create_request_data.py +16 -10
  253. honeycomb/_generated/models/marker_create_request_data_attributes.py +2 -9
  254. honeycomb/_generated/models/marker_create_request_data_relationships.py +2 -3
  255. honeycomb/_generated/models/marker_create_request_data_type.py +1 -0
  256. honeycomb/_generated/models/marker_object.py +7 -8
  257. honeycomb/_generated/models/marker_object_attributes.py +8 -8
  258. honeycomb/_generated/models/marker_object_attributes_timestamps.py +4 -12
  259. honeycomb/_generated/models/marker_object_links.py +2 -9
  260. honeycomb/_generated/models/marker_object_relationships.py +8 -8
  261. honeycomb/_generated/models/marker_object_relationships_dataset.py +8 -9
  262. honeycomb/_generated/models/marker_object_relationships_dataset_data_type_0.py +4 -10
  263. honeycomb/_generated/models/marker_object_relationships_dataset_data_type_0_type.py +1 -0
  264. honeycomb/_generated/models/marker_object_type.py +1 -0
  265. honeycomb/_generated/models/marker_response.py +2 -3
  266. honeycomb/_generated/models/marker_setting.py +2 -10
  267. honeycomb/_generated/models/marker_update_request.py +2 -3
  268. honeycomb/_generated/models/marker_update_request_data.py +16 -10
  269. honeycomb/_generated/models/marker_update_request_data_attributes.py +2 -9
  270. honeycomb/_generated/models/marker_update_request_data_relationships.py +2 -3
  271. honeycomb/_generated/models/marker_update_request_data_type.py +1 -0
  272. honeycomb/_generated/models/ms_teams_recipient.py +4 -7
  273. honeycomb/_generated/models/ms_teams_recipient_details.py +1 -7
  274. honeycomb/_generated/models/ms_teams_recipient_type.py +1 -0
  275. honeycomb/_generated/models/ms_teams_workflow_recipient.py +12 -11
  276. honeycomb/_generated/models/ms_teams_workflow_recipient_details.py +1 -7
  277. honeycomb/_generated/models/ms_teams_workflow_recipient_type.py +1 -0
  278. honeycomb/_generated/models/notification_recipient.py +8 -8
  279. honeycomb/_generated/models/notification_recipient_details.py +10 -9
  280. honeycomb/_generated/models/notification_recipient_details_pagerduty_severity.py +1 -0
  281. honeycomb/_generated/models/notification_recipient_details_variables_item.py +2 -9
  282. honeycomb/_generated/models/pager_duty_recipient.py +8 -9
  283. honeycomb/_generated/models/pager_duty_recipient_details.py +1 -7
  284. honeycomb/_generated/models/pager_duty_recipient_type.py +1 -0
  285. honeycomb/_generated/models/pagination_links.py +2 -8
  286. honeycomb/_generated/models/payload_template.py +2 -9
  287. honeycomb/_generated/models/pipeline_configuration_response.py +16 -10
  288. honeycomb/_generated/models/pipeline_configuration_response_attributes.py +8 -8
  289. honeycomb/_generated/models/pipeline_configuration_response_attributes_configs_item.py +1 -7
  290. honeycomb/_generated/models/pipeline_configuration_response_links.py +2 -9
  291. honeycomb/_generated/models/pipeline_configuration_response_type.py +1 -0
  292. honeycomb/_generated/models/pipeline_configuration_rollout.py +16 -10
  293. honeycomb/_generated/models/pipeline_configuration_rollout_attributes.py +3 -8
  294. honeycomb/_generated/models/pipeline_configuration_rollout_attributes_status.py +1 -0
  295. honeycomb/_generated/models/pipeline_configuration_rollout_links.py +2 -9
  296. honeycomb/_generated/models/pipeline_configuration_rollout_type.py +1 -0
  297. honeycomb/_generated/models/preset_filter.py +1 -7
  298. honeycomb/_generated/models/query.py +11 -11
  299. honeycomb/_generated/models/query_annotation.py +4 -12
  300. honeycomb/_generated/models/query_annotation_source.py +1 -0
  301. honeycomb/_generated/models/query_calculated_fields_item.py +1 -7
  302. honeycomb/_generated/models/query_calculations_item.py +2 -10
  303. honeycomb/_generated/models/query_compare_time_offset_seconds.py +1 -0
  304. honeycomb/_generated/models/query_filter_combination.py +1 -0
  305. honeycomb/_generated/models/query_filters_item.py +2 -11
  306. honeycomb/_generated/models/query_havings_item.py +2 -10
  307. honeycomb/_generated/models/query_op.py +1 -0
  308. honeycomb/_generated/models/query_orders_item.py +2 -9
  309. honeycomb/_generated/models/query_orders_item_order.py +1 -0
  310. honeycomb/_generated/models/query_panel.py +2 -6
  311. honeycomb/_generated/models/query_panel_query_panel.py +10 -9
  312. honeycomb/_generated/models/query_panel_query_panel_query_style.py +1 -0
  313. honeycomb/_generated/models/query_result.py +2 -5
  314. honeycomb/_generated/models/query_result_details.py +5 -8
  315. honeycomb/_generated/models/query_result_details_data.py +5 -8
  316. honeycomb/_generated/models/query_result_details_links.py +2 -9
  317. honeycomb/_generated/models/query_result_links.py +2 -9
  318. honeycomb/_generated/models/query_results_data.py +2 -5
  319. honeycomb/_generated/models/query_results_data_data.py +2 -8
  320. honeycomb/_generated/models/query_results_series.py +2 -5
  321. honeycomb/_generated/models/recipient_properties.py +4 -12
  322. honeycomb/_generated/models/recipient_type.py +1 -0
  323. honeycomb/_generated/models/slack_recipient.py +4 -7
  324. honeycomb/_generated/models/slack_recipient_details.py +1 -7
  325. honeycomb/_generated/models/slack_recipient_type.py +1 -0
  326. honeycomb/_generated/models/slo.py +4 -8
  327. honeycomb/_generated/models/slo_create.py +4 -8
  328. honeycomb/_generated/models/slo_create_sli.py +1 -7
  329. honeycomb/_generated/models/slo_detailed_response.py +4 -8
  330. honeycomb/_generated/models/slo_detailed_response_status.py +1 -0
  331. honeycomb/_generated/models/slo_history.py +2 -9
  332. honeycomb/_generated/models/slo_history_request.py +2 -8
  333. honeycomb/_generated/models/slo_history_response.py +2 -3
  334. honeycomb/_generated/models/slo_panel.py +2 -6
  335. honeycomb/_generated/models/slo_panel_slo_panel.py +2 -9
  336. honeycomb/_generated/models/slo_sli.py +1 -7
  337. honeycomb/_generated/models/tag.py +1 -7
  338. honeycomb/_generated/models/team_relationship.py +2 -3
  339. honeycomb/_generated/models/team_relationship_team.py +6 -5
  340. honeycomb/_generated/models/team_relationship_team_data.py +3 -8
  341. honeycomb/_generated/models/team_relationship_team_data_type.py +1 -0
  342. honeycomb/_generated/models/template_variable_definition.py +2 -9
  343. honeycomb/_generated/models/text_panel.py +2 -6
  344. honeycomb/_generated/models/text_panel_text_panel.py +1 -7
  345. honeycomb/_generated/models/trigger_response.py +27 -21
  346. honeycomb/_generated/models/trigger_with_inline_query.py +27 -21
  347. honeycomb/_generated/models/trigger_with_inline_query_query.py +1 -7
  348. honeycomb/_generated/models/trigger_with_query_reference.py +21 -18
  349. honeycomb/_generated/models/update_board_view_request.py +2 -5
  350. honeycomb/_generated/models/update_environment_request.py +8 -6
  351. honeycomb/_generated/models/update_environment_request_data.py +10 -7
  352. honeycomb/_generated/models/update_environment_request_data_attributes.py +8 -8
  353. honeycomb/_generated/models/update_environment_request_data_attributes_settings.py +2 -9
  354. honeycomb/_generated/models/update_environment_request_data_type.py +1 -0
  355. honeycomb/_generated/models/update_exhaustion_time_burn_alert_request.py +4 -7
  356. honeycomb/_generated/models/update_pipeline_configuration_rollout.py +10 -7
  357. honeycomb/_generated/models/update_pipeline_configuration_rollout_attributes.py +3 -8
  358. honeycomb/_generated/models/update_pipeline_configuration_rollout_attributes_status.py +1 -0
  359. honeycomb/_generated/models/update_pipeline_configuration_rollout_request.py +8 -6
  360. honeycomb/_generated/models/update_pipeline_configuration_rollout_request_data.py +10 -7
  361. honeycomb/_generated/models/update_pipeline_configuration_rollout_request_data_attributes.py +3 -8
  362. honeycomb/_generated/models/update_pipeline_configuration_rollout_request_data_attributes_status.py +1 -0
  363. honeycomb/_generated/models/update_pipeline_configuration_rollout_request_data_type.py +1 -0
  364. honeycomb/_generated/models/update_pipeline_configuration_rollout_response.py +8 -6
  365. honeycomb/_generated/models/update_pipeline_configuration_rollout_type.py +1 -0
  366. honeycomb/_generated/models/user_relationship.py +2 -3
  367. honeycomb/_generated/models/user_relationship_data.py +2 -8
  368. honeycomb/_generated/models/user_relationship_data_type.py +1 -0
  369. honeycomb/_generated/models/validation_error.py +8 -8
  370. honeycomb/_generated/models/validation_error_type_detail_item.py +4 -10
  371. honeycomb/_generated/models/validation_error_type_detail_item_code.py +1 -0
  372. honeycomb/_generated/models/webhook_header.py +2 -9
  373. honeycomb/_generated/models/webhook_recipient.py +4 -7
  374. honeycomb/_generated/models/webhook_recipient_details.py +8 -8
  375. honeycomb/_generated/models/webhook_recipient_details_webhook_payloads.py +12 -10
  376. honeycomb/_generated/models/webhook_recipient_details_webhook_payloads_payload_templates.py +2 -5
  377. honeycomb/_generated/models/webhook_recipient_type.py +1 -0
  378. honeycomb/_generated/types.py +1 -1
  379. honeycomb/cli/__init__.py +85 -0
  380. honeycomb/cli/api_keys.py +205 -0
  381. honeycomb/cli/auth.py +70 -0
  382. honeycomb/cli/boards.py +203 -0
  383. honeycomb/cli/columns.py +256 -0
  384. honeycomb/cli/config.py +259 -0
  385. honeycomb/cli/datasets.py +186 -0
  386. honeycomb/cli/derived_columns.py +222 -0
  387. honeycomb/cli/environments.py +240 -0
  388. honeycomb/cli/formatters.py +242 -0
  389. honeycomb/cli/markers.py +151 -0
  390. honeycomb/cli/queries.py +380 -0
  391. honeycomb/cli/recipients.py +211 -0
  392. honeycomb/cli/slos.py +338 -0
  393. honeycomb/cli/triggers.py +271 -0
  394. honeycomb/client.py +13 -7
  395. honeycomb/models/__init__.py +18 -3
  396. honeycomb/models/api_keys.py +49 -5
  397. honeycomb/models/auth.py +71 -0
  398. honeycomb/models/board_builder.py +97 -25
  399. honeycomb/models/boards.py +95 -1
  400. honeycomb/models/datasets.py +42 -0
  401. honeycomb/models/queries.py +21 -0
  402. honeycomb/models/query_builder.py +119 -59
  403. honeycomb/models/recipient_builder.py +51 -4
  404. honeycomb/models/slo_builder.py +24 -19
  405. honeycomb/models/slos.py +50 -3
  406. honeycomb/models/tool_inputs.py +630 -0
  407. honeycomb/models/triggers.py +39 -9
  408. honeycomb/resources/__init__.py +2 -0
  409. honeycomb/resources/api_keys.py +66 -29
  410. honeycomb/resources/auth.py +97 -0
  411. honeycomb/resources/boards.py +272 -18
  412. honeycomb/resources/datasets.py +49 -11
  413. honeycomb/resources/environments.py +54 -31
  414. honeycomb/resources/slos.py +87 -61
  415. honeycomb/tools/__main__.py +40 -4
  416. honeycomb/tools/builders.py +235 -150
  417. honeycomb/tools/descriptions.py +175 -7
  418. honeycomb/tools/executor.py +212 -25
  419. honeycomb/tools/generator.py +61 -2264
  420. honeycomb/tools/resources/__init__.py +42 -0
  421. honeycomb/tools/resources/api_keys.py +249 -0
  422. honeycomb/tools/resources/auth.py +98 -0
  423. honeycomb/tools/resources/boards.py +313 -0
  424. honeycomb/tools/resources/burn_alerts.py +278 -0
  425. honeycomb/tools/resources/columns.py +257 -0
  426. honeycomb/tools/resources/datasets.py +215 -0
  427. honeycomb/tools/resources/derived_columns.py +311 -0
  428. honeycomb/tools/resources/environments.py +211 -0
  429. honeycomb/tools/resources/events.py +158 -0
  430. honeycomb/tools/resources/marker_settings.py +216 -0
  431. honeycomb/tools/resources/markers.py +197 -0
  432. honeycomb/tools/resources/queries.py +220 -0
  433. honeycomb/tools/resources/recipients.py +297 -0
  434. honeycomb/tools/resources/service_map.py +110 -0
  435. honeycomb/tools/resources/slos.py +276 -0
  436. honeycomb/tools/resources/triggers.py +328 -0
  437. honeycomb/tools/schemas.py +81 -0
  438. {honeycomb_api-0.1.0.dist-info → honeycomb_api-0.5.3.dist-info}/METADATA +33 -8
  439. honeycomb_api-0.5.3.dist-info/RECORD +497 -0
  440. honeycomb_api-0.5.3.dist-info/entry_points.txt +5 -0
  441. honeycomb_api-0.1.0.dist-info/RECORD +0 -453
  442. {honeycomb_api-0.1.0.dist-info → honeycomb_api-0.5.3.dist-info}/WHEEL +0 -0
  443. {honeycomb_api-0.1.0.dist-info → honeycomb_api-0.5.3.dist-info}/licenses/LICENSE +0 -0
@@ -8,6 +8,7 @@ from typing import TYPE_CHECKING, Any
8
8
  from pydantic import BaseModel, Field, field_validator
9
9
 
10
10
  from honeycomb.models.query_builder import (
11
+ VALID_COMPARE_OFFSETS,
11
12
  Calculation,
12
13
  Filter,
13
14
  FilterCombination,
@@ -91,6 +92,15 @@ class QuerySpec(BaseModel):
91
92
  havings: list[Having | dict[str, Any]] | None = Field(
92
93
  default=None, description="Having clauses"
93
94
  )
95
+ calculated_fields: list[dict[str, str]] | None = Field(
96
+ default=None,
97
+ description="Inline calculated fields (derived columns) for this query",
98
+ )
99
+ compare_time_offset_seconds: int | None = Field(
100
+ default=None,
101
+ description="Compare against historical data offset by N seconds "
102
+ "(1800, 3600, 7200, 28800, 86400, 604800, 2419200, 15724800)",
103
+ )
94
104
 
95
105
  @field_validator("limit")
96
106
  @classmethod
@@ -104,6 +114,17 @@ class QuerySpec(BaseModel):
104
114
  )
105
115
  return v
106
116
 
117
+ @field_validator("compare_time_offset_seconds")
118
+ @classmethod
119
+ def validate_compare_time_offset(cls, v: int | None) -> int | None:
120
+ """Validate that compare_time_offset_seconds is a valid offset value."""
121
+ if v is not None and v not in VALID_COMPARE_OFFSETS:
122
+ raise ValueError(
123
+ f"Invalid compare_time_offset_seconds: {v}. "
124
+ f"Must be one of: {sorted(VALID_COMPARE_OFFSETS)}"
125
+ )
126
+ return v
127
+
107
128
  @classmethod
108
129
  def builder(cls) -> QueryBuilder:
109
130
  """Create a QueryBuilder for fluent query construction.
@@ -11,12 +11,18 @@ from __future__ import annotations
11
11
  from enum import Enum
12
12
  from typing import TYPE_CHECKING, Any
13
13
 
14
- from pydantic import BaseModel, Field
14
+ from pydantic import BaseModel, ConfigDict, Field
15
15
 
16
16
  if TYPE_CHECKING:
17
17
  from honeycomb.models.queries import QuerySpec
18
18
  from honeycomb.models.triggers import TriggerQuery
19
19
 
20
+ # Valid time offset values for compare queries (in seconds)
21
+ # 30min, 1hr, 2hr, 8hr, 24hr, 7d, 28d, 6mo
22
+ VALID_COMPARE_OFFSETS: frozenset[int] = frozenset(
23
+ {1800, 3600, 7200, 28800, 86400, 604800, 2419200, 15724800}
24
+ )
25
+
20
26
 
21
27
  # =============================================================================
22
28
  # Enums
@@ -51,7 +57,7 @@ class CalcOp(str, Enum):
51
57
 
52
58
 
53
59
  class FilterOp(str, Enum):
54
- """Filter operations for Honeycomb queries."""
60
+ """Filter operations for Honeycomb queries and board views."""
55
61
 
56
62
  EQUALS = "="
57
63
  NOT_EQUALS = "!="
@@ -61,6 +67,8 @@ class FilterOp(str, Enum):
61
67
  LESS_THAN_OR_EQUAL = "<="
62
68
  STARTS_WITH = "starts-with"
63
69
  DOES_NOT_START_WITH = "does-not-start-with"
70
+ ENDS_WITH = "ends-with"
71
+ DOES_NOT_END_WITH = "does-not-end-with"
64
72
  CONTAINS = "contains"
65
73
  DOES_NOT_CONTAIN = "does-not-contain"
66
74
  EXISTS = "exists"
@@ -94,21 +102,19 @@ class Calculation(BaseModel):
94
102
  Examples:
95
103
  >>> Calculation(op=CalcOp.COUNT)
96
104
  >>> Calculation(op=CalcOp.P99, column="duration_ms")
97
- >>> Calculation(op="AVG", column="response_time", alias="avg_response")
105
+ >>> Calculation(op="AVG", column="response_time")
98
106
  """
99
107
 
100
- op: CalcOp | str = Field(description="Calculation operation (COUNT, AVG, P99, etc.)")
108
+ model_config = ConfigDict(extra="forbid")
109
+
110
+ op: CalcOp = Field(description="Calculation operation (COUNT, AVG, P99, etc.)")
101
111
  column: str | None = Field(default=None, description="Column to calculate on")
102
- alias: str | None = Field(default=None, description="Alias for the result column")
103
112
 
104
113
  def to_dict(self) -> dict[str, Any]:
105
114
  """Convert to API dict format."""
106
- op_value = self.op.value if isinstance(self.op, CalcOp) else self.op
107
- result: dict[str, Any] = {"op": op_value}
115
+ result: dict[str, Any] = {"op": self.op.value}
108
116
  if self.column is not None:
109
117
  result["column"] = self.column
110
- if self.alias is not None:
111
- result["alias"] = self.alias
112
118
  return result
113
119
 
114
120
 
@@ -121,14 +127,15 @@ class Filter(BaseModel):
121
127
  >>> Filter(column="service", op="in", value=["api", "web"])
122
128
  """
123
129
 
130
+ model_config = ConfigDict(extra="forbid")
131
+
124
132
  column: str = Field(description="Column to filter on")
125
- op: FilterOp | str = Field(description="Filter operator (=, !=, >, <, contains, etc.)")
133
+ op: FilterOp = Field(description="Filter operator (=, !=, >, <, contains, etc.)")
126
134
  value: Any = Field(description="Filter value")
127
135
 
128
136
  def to_dict(self) -> dict[str, Any]:
129
137
  """Convert to API dict format."""
130
- op_value = self.op.value if isinstance(self.op, FilterOp) else self.op
131
- return {"column": self.column, "op": op_value, "value": self.value}
138
+ return {"column": self.column, "op": self.op.value, "value": self.value}
132
139
 
133
140
 
134
141
  class Order(BaseModel):
@@ -139,17 +146,15 @@ class Order(BaseModel):
139
146
  >>> Order(op=CalcOp.AVG, column="duration_ms", order=OrderDirection.ASCENDING)
140
147
  """
141
148
 
142
- op: CalcOp | str = Field(description="Calculation to order by")
149
+ model_config = ConfigDict(extra="forbid")
150
+
151
+ op: CalcOp = Field(description="Calculation to order by")
143
152
  column: str | None = Field(default=None, description="Column for the calculation")
144
- order: OrderDirection | str = Field(
145
- default=OrderDirection.DESCENDING, description="Sort direction"
146
- )
153
+ order: OrderDirection = Field(default=OrderDirection.DESCENDING, description="Sort direction")
147
154
 
148
155
  def to_dict(self) -> dict[str, Any]:
149
156
  """Convert to API dict format."""
150
- op_value = self.op.value if isinstance(self.op, CalcOp) else self.op
151
- order_value = self.order.value if isinstance(self.order, OrderDirection) else self.order
152
- result: dict[str, Any] = {"op": op_value, "order": order_value}
157
+ result: dict[str, Any] = {"op": self.op.value, "order": self.order.value}
153
158
  if self.column is not None:
154
159
  result["column"] = self.column
155
160
  return result
@@ -163,20 +168,18 @@ class Having(BaseModel):
163
168
  >>> Having(calculate_op=CalcOp.AVG, column="duration_ms", op=">", value=500.0)
164
169
  """
165
170
 
166
- calculate_op: CalcOp | str = Field(description="Calculation to filter on")
171
+ model_config = ConfigDict(extra="forbid")
172
+
173
+ calculate_op: CalcOp = Field(description="Calculation to filter on")
167
174
  column: str | None = Field(default=None, description="Column for the calculation")
168
- op: FilterOp | str = Field(description="Comparison operator")
175
+ op: FilterOp = Field(description="Comparison operator")
169
176
  value: float = Field(description="Threshold value")
170
177
 
171
178
  def to_dict(self) -> dict[str, Any]:
172
179
  """Convert to API dict format."""
173
- calc_op_value = (
174
- self.calculate_op.value if isinstance(self.calculate_op, CalcOp) else self.calculate_op
175
- )
176
- op_value = self.op.value if isinstance(self.op, FilterOp) else self.op
177
180
  result: dict[str, Any] = {
178
- "calculate_op": calc_op_value,
179
- "op": op_value,
181
+ "calculate_op": self.calculate_op.value,
182
+ "op": self.op.value,
180
183
  "value": self.value,
181
184
  }
182
185
  if self.column is not None:
@@ -243,6 +246,8 @@ class QueryBuilder:
243
246
  self._orders: list[Order] = []
244
247
  self._limit: int | None = None
245
248
  self._havings: list[Having] = []
249
+ self._calculated_fields: list[dict[str, str]] = []
250
+ self._compare_time_offset_seconds: int | None = None
246
251
  # Query metadata (for board integration)
247
252
  self._dataset: str | None = None
248
253
  self._query_name: str | None = name
@@ -381,69 +386,66 @@ class QueryBuilder:
381
386
  # Calculation Methods (additive - each call adds to the list)
382
387
  # -------------------------------------------------------------------------
383
388
 
384
- def calculate(
385
- self, op: CalcOp | str, column: str | None = None, alias: str | None = None
386
- ) -> QueryBuilder:
389
+ def calculate(self, op: CalcOp | str, column: str | None = None) -> QueryBuilder:
387
390
  """Add a calculation to the query.
388
391
 
389
392
  Args:
390
393
  op: Calculation operation (e.g., CalcOp.COUNT, "AVG")
391
394
  column: Column to calculate on (optional for COUNT)
392
- alias: Alias for the result column
393
395
 
394
396
  Returns:
395
397
  self for chaining
396
398
  """
397
- self._calculations.append(Calculation(op=op, column=column, alias=alias))
399
+ self._calculations.append(Calculation(op=op, column=column))
398
400
  return self
399
401
 
400
- def count(self, alias: str | None = None) -> QueryBuilder:
402
+ def count(self) -> QueryBuilder:
401
403
  """Add a COUNT calculation."""
402
- return self.calculate(CalcOp.COUNT, alias=alias)
404
+ return self.calculate(CalcOp.COUNT)
403
405
 
404
- def sum(self, column: str, alias: str | None = None) -> QueryBuilder:
406
+ def sum(self, column: str) -> QueryBuilder:
405
407
  """Add a SUM calculation on a column."""
406
- return self.calculate(CalcOp.SUM, column=column, alias=alias)
408
+ return self.calculate(CalcOp.SUM, column=column)
407
409
 
408
- def avg(self, column: str, alias: str | None = None) -> QueryBuilder:
410
+ def avg(self, column: str) -> QueryBuilder:
409
411
  """Add an AVG calculation on a column."""
410
- return self.calculate(CalcOp.AVG, column=column, alias=alias)
412
+ return self.calculate(CalcOp.AVG, column=column)
411
413
 
412
- def min(self, column: str, alias: str | None = None) -> QueryBuilder:
414
+ def min(self, column: str) -> QueryBuilder:
413
415
  """Add a MIN calculation on a column."""
414
- return self.calculate(CalcOp.MIN, column=column, alias=alias)
416
+ return self.calculate(CalcOp.MIN, column=column)
415
417
 
416
- def max(self, column: str, alias: str | None = None) -> QueryBuilder:
418
+ def max(self, column: str) -> QueryBuilder:
417
419
  """Add a MAX calculation on a column."""
418
- return self.calculate(CalcOp.MAX, column=column, alias=alias)
420
+ return self.calculate(CalcOp.MAX, column=column)
419
421
 
420
- def count_distinct(self, column: str, alias: str | None = None) -> QueryBuilder:
422
+ def count_distinct(self, column: str) -> QueryBuilder:
421
423
  """Add a COUNT_DISTINCT calculation on a column."""
422
- return self.calculate(CalcOp.COUNT_DISTINCT, column=column, alias=alias)
424
+ return self.calculate(CalcOp.COUNT_DISTINCT, column=column)
423
425
 
424
- def p50(self, column: str, alias: str | None = None) -> QueryBuilder:
426
+ def p50(self, column: str) -> QueryBuilder:
425
427
  """Add a P50 (median) calculation on a column."""
426
- return self.calculate(CalcOp.P50, column=column, alias=alias)
428
+ return self.calculate(CalcOp.P50, column=column)
427
429
 
428
- def p90(self, column: str, alias: str | None = None) -> QueryBuilder:
430
+ def p90(self, column: str) -> QueryBuilder:
429
431
  """Add a P90 calculation on a column."""
430
- return self.calculate(CalcOp.P90, column=column, alias=alias)
432
+ return self.calculate(CalcOp.P90, column=column)
431
433
 
432
- def p95(self, column: str, alias: str | None = None) -> QueryBuilder:
434
+ def p95(self, column: str) -> QueryBuilder:
433
435
  """Add a P95 calculation on a column."""
434
- return self.calculate(CalcOp.P95, column=column, alias=alias)
436
+ return self.calculate(CalcOp.P95, column=column)
435
437
 
436
- def p99(self, column: str, alias: str | None = None) -> QueryBuilder:
438
+ def p99(self, column: str) -> QueryBuilder:
437
439
  """Add a P99 calculation on a column."""
438
- return self.calculate(CalcOp.P99, column=column, alias=alias)
440
+ return self.calculate(CalcOp.P99, column=column)
439
441
 
440
- def heatmap(self, column: str, alias: str | None = None) -> QueryBuilder:
442
+ def heatmap(self, column: str) -> QueryBuilder:
441
443
  """Add a HEATMAP calculation on a column."""
442
- return self.calculate(CalcOp.HEATMAP, column=column, alias=alias)
444
+ return self.calculate(CalcOp.HEATMAP, column=column)
443
445
 
444
- def concurrency(self, alias: str | None = None) -> QueryBuilder:
446
+ def concurrency(self) -> QueryBuilder:
445
447
  """Add a CONCURRENCY calculation."""
446
- return self.calculate(CalcOp.CONCURRENCY, alias=alias)
448
+ return self.calculate(CalcOp.CONCURRENCY)
447
449
 
448
450
  # -------------------------------------------------------------------------
449
451
  # Filter Methods
@@ -568,10 +570,10 @@ class QueryBuilder:
568
570
  Returns:
569
571
  self for chaining
570
572
  """
571
- if isinstance(combination, str):
572
- self._filter_combination = FilterCombination(combination)
573
- else:
573
+ if isinstance(combination, FilterCombination):
574
574
  self._filter_combination = combination
575
+ else:
576
+ self._filter_combination = FilterCombination(combination)
575
577
  return self
576
578
 
577
579
  # -------------------------------------------------------------------------
@@ -678,6 +680,62 @@ class QueryBuilder:
678
680
  self._havings.append(Having(calculate_op=calculate_op, column=column, op=op, value=value))
679
681
  return self
680
682
 
683
+ # -------------------------------------------------------------------------
684
+ # Calculated Fields (Inline Derived Columns)
685
+ # -------------------------------------------------------------------------
686
+
687
+ def calculated_field(self, name: str, expression: str) -> QueryBuilder:
688
+ """Add an inline calculated field (derived column) for this query only.
689
+
690
+ Creates a computed column available within this query. For reusable
691
+ derived columns, use the Derived Columns API instead.
692
+
693
+ Args:
694
+ name: Field name/alias to reference in calculations and breakdowns
695
+ expression: Formula using $column_name syntax
696
+ See https://docs.honeycomb.io/reference/derived-column-formula/
697
+
698
+ Returns:
699
+ self for chaining
700
+
701
+ Example:
702
+ >>> (QueryBuilder()
703
+ ... .calculated_field("latency_bucket",
704
+ ... "IF(LTE($duration_ms, 100), 'fast', 'slow')")
705
+ ... .group_by("latency_bucket")
706
+ ... .count())
707
+ """
708
+ self._calculated_fields.append({"name": name, "expression": expression})
709
+ return self
710
+
711
+ # -------------------------------------------------------------------------
712
+ # Compare Time Offset (Historical Comparison)
713
+ # -------------------------------------------------------------------------
714
+
715
+ def compare_time_offset(self, seconds: int) -> QueryBuilder:
716
+ """Compare against historical data offset by N seconds.
717
+
718
+ When set, the query results will include comparison data from
719
+ the specified time in the past.
720
+
721
+ Args:
722
+ seconds: Offset in seconds. Must be one of:
723
+ 1800 (30min), 3600 (1hr), 7200 (2hr), 28800 (8hr),
724
+ 86400 (24hr), 604800 (7d), 2419200 (28d), 15724800 (6mo)
725
+
726
+ Returns:
727
+ self for chaining
728
+
729
+ Example:
730
+ >>> QueryBuilder().last_1_hour().count().compare_time_offset(86400) # Compare to 24h ago
731
+ """
732
+ if seconds not in VALID_COMPARE_OFFSETS:
733
+ raise ValueError(
734
+ f"Invalid compare_time_offset: {seconds}. Must be one of: {sorted(VALID_COMPARE_OFFSETS)}"
735
+ )
736
+ self._compare_time_offset_seconds = seconds
737
+ return self
738
+
681
739
  # -------------------------------------------------------------------------
682
740
  # Dataset Scoping
683
741
  # -------------------------------------------------------------------------
@@ -803,6 +861,8 @@ class QueryBuilder:
803
861
  orders=self._orders if self._orders else None,
804
862
  limit=self._limit,
805
863
  havings=self._havings if self._havings else None,
864
+ calculated_fields=self._calculated_fields if self._calculated_fields else None,
865
+ compare_time_offset_seconds=self._compare_time_offset_seconds,
806
866
  )
807
867
 
808
868
  def build_for_trigger(self) -> TriggerQuery:
@@ -78,13 +78,22 @@ class RecipientMixin:
78
78
  )
79
79
  return self
80
80
 
81
- def webhook(self, url: str, name: str = "Webhook", secret: str | None = None) -> Self:
81
+ def webhook(
82
+ self,
83
+ url: str,
84
+ name: str = "Webhook",
85
+ secret: str | None = None,
86
+ headers: list[dict[str, str]] | None = None,
87
+ ) -> Self:
82
88
  """Add a webhook recipient (inline format for triggers/burn alerts).
83
89
 
84
90
  Args:
85
91
  url: Webhook URL to POST to.
86
92
  name: A name for this webhook (default: "Webhook").
87
93
  secret: Optional webhook secret for signing.
94
+ headers: Optional HTTP headers (max 5). Each dict should have
95
+ 'header' (required) and optionally 'value'.
96
+ Example: [{"header": "Authorization", "value": "Bearer xyz"}]
88
97
 
89
98
  Returns:
90
99
  Self for method chaining.
@@ -99,6 +108,8 @@ class RecipientMixin:
99
108
  }
100
109
  if secret:
101
110
  details["webhook_secret"] = secret
111
+ if headers:
112
+ details["webhook_headers"] = headers
102
113
 
103
114
  self._new_recipients.append(
104
115
  {
@@ -209,16 +220,43 @@ class RecipientBuilder:
209
220
  url: str,
210
221
  name: str = "Webhook",
211
222
  secret: str | None = None,
223
+ headers: list[dict[str, str]] | None = None,
224
+ payload_templates: dict[str, dict[str, str]] | None = None,
225
+ template_variables: list[dict[str, str]] | None = None,
212
226
  ) -> RecipientCreate:
213
227
  """Create a webhook recipient.
214
228
 
215
229
  Args:
216
- url: Webhook URL to POST to.
217
- name: A name for this webhook.
218
- secret: Optional webhook secret for signing.
230
+ url: Webhook URL to POST to (max 2048 chars).
231
+ name: A name for this webhook (max 255 chars).
232
+ secret: Optional webhook secret for signing (max 255 chars).
233
+ headers: Optional HTTP headers (max 5). Each dict should have
234
+ 'header' (required, max 64 chars) and optionally 'value' (max 750 chars).
235
+ Example: [{"header": "Authorization", "value": "Bearer xyz"}]
236
+ payload_templates: Optional custom payload templates for different alert types.
237
+ Example: {"trigger": {"body": "{\"custom\": \"json\"}"}}
238
+ template_variables: Optional template variables for payload substitution (max 10).
239
+ Example: [{"name": "severity", "default_value": "warning"}]
219
240
 
220
241
  Returns:
221
242
  RecipientCreate object.
243
+
244
+ Example:
245
+ >>> # Basic webhook
246
+ >>> RecipientBuilder.webhook("https://example.com/webhook")
247
+
248
+ >>> # Webhook with auth header
249
+ >>> RecipientBuilder.webhook(
250
+ ... "https://example.com/webhook",
251
+ ... headers=[{"header": "Authorization", "value": "Bearer token123"}]
252
+ ... )
253
+
254
+ >>> # Advanced webhook with custom payload
255
+ >>> RecipientBuilder.webhook(
256
+ ... "https://example.com/webhook",
257
+ ... template_variables=[{"name": "env", "default_value": "prod"}],
258
+ ... payload_templates={"trigger": {"body": "{\"environment\": \"{{env}}\"}"}}
259
+ ... )
222
260
  """
223
261
  details: dict[str, Any] = {
224
262
  "webhook_url": url,
@@ -226,6 +264,15 @@ class RecipientBuilder:
226
264
  }
227
265
  if secret:
228
266
  details["webhook_secret"] = secret
267
+ if headers:
268
+ details["webhook_headers"] = headers
269
+ if template_variables or payload_templates:
270
+ webhook_payloads: dict[str, Any] = {}
271
+ if template_variables:
272
+ webhook_payloads["template_variables"] = template_variables
273
+ if payload_templates:
274
+ webhook_payloads["payload_templates"] = payload_templates
275
+ details["webhook_payloads"] = webhook_payloads
229
276
  return RecipientCreate(type=RecipientType.WEBHOOK, details=details)
230
277
 
231
278
  @staticmethod
@@ -195,7 +195,7 @@ class SLOBuilder:
195
195
  slo = (
196
196
  SLOBuilder("Cross-Service Availability")
197
197
  .datasets(["api-logs", "web-logs", "worker-logs"])
198
- .target_nines(3) # 99.9%
198
+ .target_percentage(99.9)
199
199
  .sli(
200
200
  alias="service_success",
201
201
  expression="IF(EQUALS($status, 200), 1, 0)",
@@ -219,6 +219,7 @@ class SLOBuilder:
219
219
  self._time_period_days: int = 30
220
220
  self._sli: SLIDefinition | None = None
221
221
  self._burn_alerts: list[BurnAlertDefinition] = []
222
+ self._tags: list[dict[str, str]] = []
222
223
 
223
224
  # -------------------------------------------------------------------------
224
225
  # Basic configuration
@@ -229,6 +230,25 @@ class SLOBuilder:
229
230
  self._description = desc
230
231
  return self
231
232
 
233
+ def tag(self, key: str, value: str) -> SLOBuilder:
234
+ """Add a tag key-value pair for organizing the SLO.
235
+
236
+ Tags are useful for filtering and grouping SLOs by team, service,
237
+ criticality, or other dimensions.
238
+
239
+ Args:
240
+ key: Tag key (lowercase letters, max 32 chars)
241
+ value: Tag value (alphanumeric, /, -, max 128 chars)
242
+
243
+ Example:
244
+ >>> builder.tag("team", "platform").tag("service", "api")
245
+
246
+ Returns:
247
+ self for chaining
248
+ """
249
+ self._tags.append({"key": key, "value": value})
250
+ return self
251
+
232
252
  # -------------------------------------------------------------------------
233
253
  # Dataset scope
234
254
  # -------------------------------------------------------------------------
@@ -267,20 +287,6 @@ class SLOBuilder:
267
287
  self._target_per_million = int(percent * 10000)
268
288
  return self
269
289
 
270
- def target_nines(self, nines: int) -> SLOBuilder:
271
- """Set target by number of nines.
272
-
273
- Examples:
274
- 2 nines = 99%
275
- 3 nines = 99.9%
276
- 4 nines = 99.99%
277
-
278
- Args:
279
- nines: Number of nines (1-5)
280
- """
281
- percentage = 100 - (100 / (10**nines))
282
- return self.target_percentage(percentage)
283
-
284
290
  def target_per_million(self, value: int) -> SLOBuilder:
285
291
  """Set target directly as per-million value.
286
292
 
@@ -422,10 +428,7 @@ class SLOBuilder:
422
428
  raise ValueError("At least one dataset is required. Use dataset() or datasets().")
423
429
 
424
430
  if self._target_per_million is None:
425
- raise ValueError(
426
- "Target is required. Use target_percentage(), "
427
- "target_nines(), or target_per_million()."
428
- )
431
+ raise ValueError("Target is required. Use target_percentage() or target_per_million().")
429
432
 
430
433
  if self._sli is None:
431
434
  raise ValueError("SLI is required. Use sli(alias=...) to define it.")
@@ -452,6 +455,8 @@ class SLOBuilder:
452
455
  sli=SLI(alias=self._sli.alias),
453
456
  time_period_days=self._time_period_days,
454
457
  target_per_million=self._target_per_million,
458
+ tags=self._tags if self._tags else None,
459
+ dataset_slugs=self._datasets if is_multi_dataset else None,
455
460
  )
456
461
 
457
462
  return SLOBundle(
honeycomb/models/slos.py CHANGED
@@ -7,11 +7,32 @@ from typing import Any
7
7
 
8
8
  from pydantic import BaseModel, Field
9
9
 
10
+ from honeycomb.models.tool_inputs import TagInput
11
+
10
12
 
11
13
  class SLI(BaseModel):
12
- """Service Level Indicator configuration."""
14
+ """Service Level Indicator configuration.
15
+
16
+ The SLI references a derived column by alias. You can either:
17
+ 1. Reference an existing derived column: just provide alias
18
+ 2. Create a new derived column inline: provide alias + expression
19
+
20
+ When expression is provided, a new derived column will be created automatically
21
+ before the SLO is created.
22
+ """
13
23
 
14
- alias: str | None = Field(default=None, description="Alias for the SLI")
24
+ alias: str | None = Field(
25
+ default=None, description="Alias for the derived column (existing or new)"
26
+ )
27
+ expression: str | None = Field(
28
+ default=None,
29
+ description="If provided, creates a new derived column with this expression. "
30
+ "If omitted, uses an existing derived column with the given alias.",
31
+ )
32
+ description: str | None = Field(
33
+ default=None,
34
+ description="Description for the new derived column (only used when expression is provided)",
35
+ )
15
36
 
16
37
 
17
38
  class SLOCreate(BaseModel):
@@ -28,9 +49,17 @@ class SLOCreate(BaseModel):
28
49
  )
29
50
  target_per_million: int = Field(
30
51
  ge=0,
31
- le=1000000,
52
+ le=999999,
32
53
  description="Target success rate per million (e.g., 999000 = 99.9%)",
33
54
  )
55
+ tags: list[TagInput] | None = Field(
56
+ default=None,
57
+ description="Key-value pairs for organizing SLOs (max 10 tags)",
58
+ )
59
+ dataset_slugs: list[str] | None = Field(
60
+ default=None,
61
+ description="Dataset slugs for multi-dataset SLOs (used with __all__ endpoint)",
62
+ )
34
63
 
35
64
  def model_dump_for_api(self) -> dict[str, Any]:
36
65
  """Serialize for API request."""
@@ -47,6 +76,12 @@ class SLOCreate(BaseModel):
47
76
  if self.sli.alias:
48
77
  data["sli"]["alias"] = self.sli.alias
49
78
 
79
+ if self.tags:
80
+ data["tags"] = [{"key": tag.key, "value": tag.value} for tag in self.tags]
81
+
82
+ if self.dataset_slugs:
83
+ data["dataset_slugs"] = self.dataset_slugs
84
+
50
85
  return data
51
86
 
52
87
 
@@ -64,3 +99,15 @@ class SLO(BaseModel):
64
99
  updated_at: datetime | None = Field(default=None, description="Last update timestamp")
65
100
 
66
101
  model_config = {"extra": "allow"}
102
+
103
+ @property
104
+ def dataset(self) -> str | None:
105
+ """Return the first dataset slug for convenience (SLOs can span multiple datasets)."""
106
+ if self.dataset_slugs and len(self.dataset_slugs) > 0:
107
+ return self.dataset_slugs[0]
108
+ return None
109
+
110
+ @property
111
+ def target_percentage(self) -> float:
112
+ """Convert target_per_million to percentage for display (e.g., 999000 → 99.9)."""
113
+ return self.target_per_million / 10000