costfluent 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (481) hide show
  1. costfluent/__init__.py +32 -0
  2. costfluent/_contract.py +27 -0
  3. costfluent/_sdk.py +392 -0
  4. costfluent/_version.py +1 -0
  5. costfluent/api/__init__.py +1 -0
  6. costfluent/api/allocation/__init__.py +1 -0
  7. costfluent/api/allocation/create_allocation_rule.py +239 -0
  8. costfluent/api/allocation/create_segment.py +239 -0
  9. costfluent/api/allocation/delete_allocation_rule.py +248 -0
  10. costfluent/api/allocation/delete_segment.py +257 -0
  11. costfluent/api/allocation/get_allocation_coverage.py +257 -0
  12. costfluent/api/allocation/list_allocation_rules.py +250 -0
  13. costfluent/api/allocation/list_segments.py +244 -0
  14. costfluent/api/allocation/preview_allocation_rule.py +238 -0
  15. costfluent/api/allocation/reorder_allocation_rules.py +219 -0
  16. costfluent/api/allocation/update_allocation_rule.py +270 -0
  17. costfluent/api/allocation/update_segment.py +283 -0
  18. costfluent/api/anomalies/__init__.py +1 -0
  19. costfluent/api/anomalies/acknowledge_anomaly.py +200 -0
  20. costfluent/api/anomalies/list_anomalies.py +329 -0
  21. costfluent/api/apps/__init__.py +1 -0
  22. costfluent/api/apps/create_app.py +259 -0
  23. costfluent/api/apps/delete_app.py +231 -0
  24. costfluent/api/apps/get_app.py +202 -0
  25. costfluent/api/apps/list_apps.py +227 -0
  26. costfluent/api/apps/update_app.py +270 -0
  27. costfluent/api/audit_logs/__init__.py +1 -0
  28. costfluent/api/audit_logs/list_audit_logs.py +356 -0
  29. costfluent/api/billing/__init__.py +1 -0
  30. costfluent/api/billing/get_entitlement.py +179 -0
  31. costfluent/api/billing/get_usage.py +179 -0
  32. costfluent/api/budgets/__init__.py +1 -0
  33. costfluent/api/budgets/create_budget.py +259 -0
  34. costfluent/api/budgets/delete_budget.py +223 -0
  35. costfluent/api/budgets/get_budget.py +202 -0
  36. costfluent/api/budgets/list_budgets.py +249 -0
  37. costfluent/api/budgets/update_budget.py +270 -0
  38. costfluent/api/business_metrics/__init__.py +1 -0
  39. costfluent/api/business_metrics/create_business_metric.py +251 -0
  40. costfluent/api/business_metrics/delete_business_metric.py +248 -0
  41. costfluent/api/business_metrics/get_business_metric.py +228 -0
  42. costfluent/api/business_metrics/import_business_metric_values.py +277 -0
  43. costfluent/api/business_metrics/list_business_metric_values.py +307 -0
  44. costfluent/api/business_metrics/list_business_metrics.py +246 -0
  45. costfluent/api/business_metrics/update_business_metric.py +278 -0
  46. costfluent/api/contracting/__init__.py +1 -0
  47. costfluent/api/contracting/get_data_processing_agreement.py +183 -0
  48. costfluent/api/cost_alerts/__init__.py +1 -0
  49. costfluent/api/cost_alerts/create_cost_alert.py +267 -0
  50. costfluent/api/cost_alerts/delete_cost_alert.py +248 -0
  51. costfluent/api/cost_alerts/get_cost_alert.py +228 -0
  52. costfluent/api/cost_alerts/get_cost_alert_events.py +262 -0
  53. costfluent/api/cost_alerts/list_cost_alerts.py +244 -0
  54. costfluent/api/cost_alerts/pause_cost_alert.py +248 -0
  55. costfluent/api/cost_alerts/resume_cost_alert.py +248 -0
  56. costfluent/api/cost_alerts/update_cost_alert.py +298 -0
  57. costfluent/api/cost_data/__init__.py +1 -0
  58. costfluent/api/cost_data/get_cost_data.py +491 -0
  59. costfluent/api/cost_data/get_cost_forecast.py +232 -0
  60. costfluent/api/cost_data/get_cost_summary.py +362 -0
  61. costfluent/api/cost_filters/__init__.py +1 -0
  62. costfluent/api/cost_filters/translate_cost_filter.py +224 -0
  63. costfluent/api/cost_reports/__init__.py +1 -0
  64. costfluent/api/cost_reports/create_cost_report.py +247 -0
  65. costfluent/api/cost_reports/delete_cost_report.py +266 -0
  66. costfluent/api/cost_reports/get_cost_report.py +228 -0
  67. costfluent/api/cost_reports/get_cost_report_data.py +237 -0
  68. costfluent/api/cost_reports/list_cost_reports.py +264 -0
  69. costfluent/api/cost_reports/update_cost_report.py +278 -0
  70. costfluent/api/custom_provider/__init__.py +1 -0
  71. costfluent/api/custom_provider/delete_custom_cost_upload.py +218 -0
  72. costfluent/api/custom_provider/get_custom_cost_upload.py +216 -0
  73. costfluent/api/custom_provider/list_custom_cost_uploads.py +247 -0
  74. costfluent/api/custom_provider/submit_costs.py +291 -0
  75. costfluent/api/custom_provider/upload_custom_costs.py +271 -0
  76. costfluent/api/dashboards/__init__.py +1 -0
  77. costfluent/api/dashboards/create_dashboard.py +247 -0
  78. costfluent/api/dashboards/create_dashboard_widget.py +287 -0
  79. costfluent/api/dashboards/delete_dashboard.py +248 -0
  80. costfluent/api/dashboards/delete_dashboard_widget.py +275 -0
  81. costfluent/api/dashboards/get_dashboard.py +228 -0
  82. costfluent/api/dashboards/get_dashboard_widget.py +242 -0
  83. costfluent/api/dashboards/list_dashboards.py +244 -0
  84. costfluent/api/dashboards/set_dashboard_default.py +266 -0
  85. costfluent/api/dashboards/set_dashboard_saved_filter.py +262 -0
  86. costfluent/api/dashboards/update_dashboard.py +278 -0
  87. costfluent/api/dashboards/update_dashboard_widget.py +305 -0
  88. costfluent/api/exchange_rates/__init__.py +1 -0
  89. costfluent/api/exchange_rates/get_available_currencies.py +227 -0
  90. costfluent/api/exchange_rates/get_exchange_rate.py +258 -0
  91. costfluent/api/exchange_rates/get_fx_policy.py +206 -0
  92. costfluent/api/exchange_rates/list_exchange_rates.py +320 -0
  93. costfluent/api/folders/__init__.py +1 -0
  94. costfluent/api/folders/create_folder.py +247 -0
  95. costfluent/api/folders/delete_folder.py +252 -0
  96. costfluent/api/folders/get_folder.py +228 -0
  97. costfluent/api/folders/list_folders.py +244 -0
  98. costfluent/api/folders/set_folder_saved_filter.py +266 -0
  99. costfluent/api/folders/update_folder.py +262 -0
  100. costfluent/api/kubernetes/__init__.py +1 -0
  101. costfluent/api/kubernetes/report_kubernetes_usage.py +264 -0
  102. costfluent/api/providers/__init__.py +1 -0
  103. costfluent/api/providers/connect_provider.py +247 -0
  104. costfluent/api/providers/delete_provider.py +240 -0
  105. costfluent/api/providers/get_available_providers.py +231 -0
  106. costfluent/api/providers/get_aws_connector.py +179 -0
  107. costfluent/api/providers/get_provider.py +202 -0
  108. costfluent/api/providers/get_provider_sync_history.py +251 -0
  109. costfluent/api/providers/list_providers.py +249 -0
  110. costfluent/api/providers/provision_gcp_service_account.py +179 -0
  111. costfluent/api/providers/test_provider_connection.py +219 -0
  112. costfluent/api/providers/trigger_provider_sync.py +243 -0
  113. costfluent/api/providers/update_provider.py +275 -0
  114. costfluent/api/report_notifications/__init__.py +1 -0
  115. costfluent/api/report_notifications/activate_cost_report_subscription.py +248 -0
  116. costfluent/api/report_notifications/create_cost_report_subscription.py +251 -0
  117. costfluent/api/report_notifications/deactivate_cost_report_subscription.py +248 -0
  118. costfluent/api/report_notifications/delete_cost_report_subscription.py +248 -0
  119. costfluent/api/report_notifications/get_cost_report_subscription.py +228 -0
  120. costfluent/api/report_notifications/list_cost_report_subscriptions.py +266 -0
  121. costfluent/api/report_notifications/update_cost_report_subscription.py +260 -0
  122. costfluent/api/saved_filters/__init__.py +1 -0
  123. costfluent/api/saved_filters/create_saved_filter.py +247 -0
  124. costfluent/api/saved_filters/delete_saved_filter.py +248 -0
  125. costfluent/api/saved_filters/get_saved_filter.py +228 -0
  126. costfluent/api/saved_filters/list_saved_filters.py +244 -0
  127. costfluent/api/saved_filters/update_saved_filter.py +278 -0
  128. costfluent/api/tags/__init__.py +1 -0
  129. costfluent/api/tags/delete_tag_key.py +200 -0
  130. costfluent/api/tags/get_tag_key.py +202 -0
  131. costfluent/api/tags/get_tag_policy.py +210 -0
  132. costfluent/api/tags/list_tag_keys.py +249 -0
  133. costfluent/api/tags/update_tag_policy.py +250 -0
  134. costfluent/api/teams/__init__.py +1 -0
  135. costfluent/api/teams/add_team_member.py +236 -0
  136. costfluent/api/teams/create_team.py +247 -0
  137. costfluent/api/teams/delete_team.py +223 -0
  138. costfluent/api/teams/get_team.py +206 -0
  139. costfluent/api/teams/list_team_workspace_access.py +251 -0
  140. costfluent/api/teams/list_teams.py +229 -0
  141. costfluent/api/teams/remove_team_member.py +214 -0
  142. costfluent/api/teams/remove_team_workspace_access.py +214 -0
  143. costfluent/api/teams/set_team_workspace_access.py +250 -0
  144. costfluent/api/teams/update_team.py +258 -0
  145. costfluent/api/teams/update_team_member.py +250 -0
  146. costfluent/api/users/__init__.py +1 -0
  147. costfluent/api/users/get_user.py +202 -0
  148. costfluent/api/users/invite_user.py +259 -0
  149. costfluent/api/users/list_users.py +249 -0
  150. costfluent/api/utility/__init__.py +1 -0
  151. costfluent/api/utility/me.py +175 -0
  152. costfluent/api/utility/ping.py +165 -0
  153. costfluent/api/virtual_tags/__init__.py +1 -0
  154. costfluent/api/virtual_tags/create_virtual_tag.py +247 -0
  155. costfluent/api/virtual_tags/delete_virtual_tag.py +257 -0
  156. costfluent/api/virtual_tags/get_virtual_tag.py +228 -0
  157. costfluent/api/virtual_tags/list_virtual_tags.py +248 -0
  158. costfluent/api/virtual_tags/update_virtual_tag.py +258 -0
  159. costfluent/api/workspace_providers/__init__.py +1 -0
  160. costfluent/api/workspace_providers/create_workspace_provider.py +255 -0
  161. costfluent/api/workspace_providers/delete_workspace_provider.py +230 -0
  162. costfluent/api/workspace_providers/get_workspace_provider.py +228 -0
  163. costfluent/api/workspace_providers/list_workspace_providers.py +246 -0
  164. costfluent/api/workspace_providers/update_workspace_provider.py +254 -0
  165. costfluent/api/workspaces/__init__.py +1 -0
  166. costfluent/api/workspaces/create_workspace.py +247 -0
  167. costfluent/api/workspaces/delete_workspace.py +227 -0
  168. costfluent/api/workspaces/get_workspace.py +202 -0
  169. costfluent/api/workspaces/list_workspaces.py +229 -0
  170. costfluent/api/workspaces/update_workspace.py +258 -0
  171. costfluent/client.py +280 -0
  172. costfluent/errors.py +16 -0
  173. costfluent/models/__init__.py +671 -0
  174. costfluent/models/acknowledge_anomaly_request.py +23 -0
  175. costfluent/models/activate_cost_report_subscription_request.py +23 -0
  176. costfluent/models/add_team_member_request.py +50 -0
  177. costfluent/models/allocation_coverage_currency.py +160 -0
  178. costfluent/models/allocation_coverage_pool.py +112 -0
  179. costfluent/models/allocation_coverage_response.py +81 -0
  180. costfluent/models/allocation_coverage_segment.py +90 -0
  181. costfluent/models/allocation_coverage_share.py +50 -0
  182. costfluent/models/allocation_dry_run_response.py +102 -0
  183. costfluent/models/allocation_dry_run_segment_change_response.py +74 -0
  184. costfluent/models/allocation_rule_response.py +171 -0
  185. costfluent/models/anomaly_response.py +247 -0
  186. costfluent/models/api_error.py +183 -0
  187. costfluent/models/api_error_entry.py +110 -0
  188. costfluent/models/api_error_entry_params_type_0.py +45 -0
  189. costfluent/models/app_response.py +111 -0
  190. costfluent/models/app_response_config.py +45 -0
  191. costfluent/models/audit_log_entry_response.py +232 -0
  192. costfluent/models/aws_connector_response.py +80 -0
  193. costfluent/models/budget_alert_request.py +42 -0
  194. costfluent/models/budget_alert_response.py +91 -0
  195. costfluent/models/budget_interval_unit_value.py +11 -0
  196. costfluent/models/budget_measure_value.py +9 -0
  197. costfluent/models/budget_period_request.py +75 -0
  198. costfluent/models/budget_period_response.py +59 -0
  199. costfluent/models/budget_response.py +435 -0
  200. costfluent/models/business_metric_import_response.py +58 -0
  201. costfluent/models/business_metric_request.py +23 -0
  202. costfluent/models/business_metric_response.py +107 -0
  203. costfluent/models/business_metric_value_request.py +105 -0
  204. costfluent/models/business_metric_value_request_labels_type_0.py +45 -0
  205. costfluent/models/business_metric_value_response.py +69 -0
  206. costfluent/models/business_metric_value_response_labels.py +45 -0
  207. costfluent/models/chart_type.py +13 -0
  208. costfluent/models/comparison_period.py +11 -0
  209. costfluent/models/connect_provider_request.py +193 -0
  210. costfluent/models/connect_provider_request_credentials.py +45 -0
  211. costfluent/models/connect_provider_request_settings_type_0.py +45 -0
  212. costfluent/models/connection_test_response.py +110 -0
  213. costfluent/models/connection_test_response_metadata_type_0.py +45 -0
  214. costfluent/models/cost_alert_created_response.py +50 -0
  215. costfluent/models/cost_alert_event_response.py +212 -0
  216. costfluent/models/cost_alert_response.py +252 -0
  217. costfluent/models/cost_data_meta.py +199 -0
  218. costfluent/models/cost_data_point.py +131 -0
  219. costfluent/models/cost_data_point_dimensions.py +45 -0
  220. costfluent/models/cost_data_response.py +76 -0
  221. costfluent/models/cost_entry.py +545 -0
  222. costfluent/models/cost_entry_tags_type_0.py +45 -0
  223. costfluent/models/cost_filter_translation_response.py +74 -0
  224. costfluent/models/cost_forecast_response.py +221 -0
  225. costfluent/models/cost_group_dimension.py +30 -0
  226. costfluent/models/cost_report_created_response.py +50 -0
  227. costfluent/models/cost_report_data_response.py +230 -0
  228. costfluent/models/cost_report_response.py +255 -0
  229. costfluent/models/cost_report_settings_request.py +324 -0
  230. costfluent/models/cost_report_settings_response.py +207 -0
  231. costfluent/models/cost_report_subscription_created_response.py +50 -0
  232. costfluent/models/cost_report_subscription_response.py +199 -0
  233. costfluent/models/cost_summary_response.py +301 -0
  234. costfluent/models/cost_validation_error.py +58 -0
  235. costfluent/models/create_allocation_rule_request.py +86 -0
  236. costfluent/models/create_app_request.py +64 -0
  237. costfluent/models/create_app_request_config.py +45 -0
  238. costfluent/models/create_budget_request.py +335 -0
  239. costfluent/models/create_business_metric_request.py +91 -0
  240. costfluent/models/create_cost_alert_request.py +210 -0
  241. costfluent/models/create_cost_report_request.py +291 -0
  242. costfluent/models/create_cost_report_subscription_request.py +116 -0
  243. costfluent/models/create_dashboard_request.py +140 -0
  244. costfluent/models/create_dashboard_widget_request.py +127 -0
  245. costfluent/models/create_folder_request.py +72 -0
  246. costfluent/models/create_saved_filter_request.py +69 -0
  247. costfluent/models/create_segment_request.py +169 -0
  248. costfluent/models/create_team_request.py +42 -0
  249. costfluent/models/create_virtual_tag_request.py +130 -0
  250. costfluent/models/create_workspace_provider_request.py +83 -0
  251. costfluent/models/create_workspace_request.py +72 -0
  252. costfluent/models/currency_amount.py +50 -0
  253. costfluent/models/currency_conversion.py +82 -0
  254. costfluent/models/currency_presentation.py +92 -0
  255. costfluent/models/custom_cost_upload_error.py +58 -0
  256. costfluent/models/custom_cost_upload_request.py +23 -0
  257. costfluent/models/custom_cost_upload_response.py +282 -0
  258. costfluent/models/custom_cost_upload_response_billed_totals_type_0.py +45 -0
  259. costfluent/models/dashboard_created_response.py +50 -0
  260. costfluent/models/dashboard_response.py +187 -0
  261. costfluent/models/dashboard_widget_created_response.py +50 -0
  262. costfluent/models/deactivate_cost_report_subscription_request.py +23 -0
  263. costfluent/models/delete_allocation_rule_request.py +23 -0
  264. costfluent/models/delete_app_request.py +23 -0
  265. costfluent/models/delete_budget_request.py +23 -0
  266. costfluent/models/delete_cost_alert_request.py +23 -0
  267. costfluent/models/delete_cost_report_request.py +23 -0
  268. costfluent/models/delete_cost_report_subscription_request.py +23 -0
  269. costfluent/models/delete_dashboard_request.py +23 -0
  270. costfluent/models/delete_dashboard_widget_request.py +23 -0
  271. costfluent/models/delete_folder_request.py +23 -0
  272. costfluent/models/delete_provider_request.py +23 -0
  273. costfluent/models/delete_saved_filter_request.py +23 -0
  274. costfluent/models/delete_segment_request.py +23 -0
  275. costfluent/models/delete_tag_key_request.py +23 -0
  276. costfluent/models/delete_team_request.py +23 -0
  277. costfluent/models/delete_virtual_tag_request.py +23 -0
  278. costfluent/models/delete_workspace_provider_request.py +23 -0
  279. costfluent/models/delete_workspace_request.py +23 -0
  280. costfluent/models/dpa_execution_response.py +116 -0
  281. costfluent/models/dpa_status_response.py +113 -0
  282. costfluent/models/entitlement_response.py +303 -0
  283. costfluent/models/exchange_rate_response.py +75 -0
  284. costfluent/models/folder_created_response.py +50 -0
  285. costfluent/models/folder_response.py +141 -0
  286. costfluent/models/forecast_month_response.py +66 -0
  287. costfluent/models/fx_policy_response.py +126 -0
  288. costfluent/models/fx_policy_status_response.py +91 -0
  289. costfluent/models/gcp_service_account_response.py +86 -0
  290. costfluent/models/get_allocation_coverage_request.py +23 -0
  291. costfluent/models/get_app_request.py +23 -0
  292. costfluent/models/get_budget_request.py +23 -0
  293. costfluent/models/get_cost_alert_events_request.py +45 -0
  294. costfluent/models/get_cost_alert_request.py +23 -0
  295. costfluent/models/get_cost_data_request.py +45 -0
  296. costfluent/models/get_cost_forecast_request.py +23 -0
  297. costfluent/models/get_cost_report_data_request.py +23 -0
  298. costfluent/models/get_cost_report_request.py +23 -0
  299. costfluent/models/get_cost_report_subscription_request.py +23 -0
  300. costfluent/models/get_cost_summary_request.py +23 -0
  301. costfluent/models/get_dashboard_request.py +23 -0
  302. costfluent/models/get_dashboard_widget_request.py +23 -0
  303. costfluent/models/get_exchange_rate_request.py +23 -0
  304. costfluent/models/get_folder_request.py +23 -0
  305. costfluent/models/get_fx_policy_request.py +23 -0
  306. costfluent/models/get_provider_request.py +23 -0
  307. costfluent/models/get_provider_sync_history_request.py +45 -0
  308. costfluent/models/get_saved_filter_request.py +23 -0
  309. costfluent/models/get_tag_key_request.py +23 -0
  310. costfluent/models/get_tag_policy_request.py +23 -0
  311. costfluent/models/get_team_request.py +23 -0
  312. costfluent/models/get_user_request.py +23 -0
  313. costfluent/models/get_virtual_tag_request.py +23 -0
  314. costfluent/models/get_workspace_provider_request.py +23 -0
  315. costfluent/models/get_workspace_request.py +23 -0
  316. costfluent/models/import_business_metric_values_request.py +83 -0
  317. costfluent/models/invitation_role.py +10 -0
  318. costfluent/models/invite_user_request.py +68 -0
  319. costfluent/models/kubernetes_report.py +152 -0
  320. costfluent/models/kubernetes_report_accepted_response.py +58 -0
  321. costfluent/models/kubernetes_report_container.py +132 -0
  322. costfluent/models/kubernetes_report_node.py +274 -0
  323. costfluent/models/kubernetes_report_node_annotations_type_0.py +45 -0
  324. costfluent/models/kubernetes_report_node_labels_type_0.py +45 -0
  325. costfluent/models/kubernetes_report_pod.py +255 -0
  326. costfluent/models/kubernetes_report_pod_annotations_type_0.py +45 -0
  327. costfluent/models/kubernetes_report_pod_labels_type_0.py +45 -0
  328. costfluent/models/kubernetes_report_pod_namespace_labels_type_0.py +45 -0
  329. costfluent/models/list_allocation_rules_request.py +45 -0
  330. costfluent/models/list_anomalies_request.py +45 -0
  331. costfluent/models/list_apps_request.py +45 -0
  332. costfluent/models/list_audit_logs_request.py +45 -0
  333. costfluent/models/list_budgets_request.py +45 -0
  334. costfluent/models/list_business_metric_values_request.py +45 -0
  335. costfluent/models/list_business_metrics_request.py +45 -0
  336. costfluent/models/list_cost_alerts_request.py +45 -0
  337. costfluent/models/list_cost_report_subscriptions_request.py +45 -0
  338. costfluent/models/list_cost_reports_request.py +45 -0
  339. costfluent/models/list_custom_cost_uploads_request.py +45 -0
  340. costfluent/models/list_dashboards_request.py +45 -0
  341. costfluent/models/list_exchange_rates_request.py +45 -0
  342. costfluent/models/list_folders_request.py +45 -0
  343. costfluent/models/list_providers_request.py +45 -0
  344. costfluent/models/list_saved_filters_request.py +45 -0
  345. costfluent/models/list_segments_request.py +45 -0
  346. costfluent/models/list_tag_keys_request.py +45 -0
  347. costfluent/models/list_team_workspace_access_request.py +45 -0
  348. costfluent/models/list_teams_request.py +45 -0
  349. costfluent/models/list_users_request.py +45 -0
  350. costfluent/models/list_virtual_tags_request.py +45 -0
  351. costfluent/models/list_workspace_providers_request.py +45 -0
  352. costfluent/models/me_response.py +130 -0
  353. costfluent/models/paginated_request.py +23 -0
  354. costfluent/models/paginated_response_of_allocation_rule_response.py +66 -0
  355. costfluent/models/paginated_response_of_anomaly_response.py +66 -0
  356. costfluent/models/paginated_response_of_app_response.py +66 -0
  357. costfluent/models/paginated_response_of_audit_log_entry_response.py +66 -0
  358. costfluent/models/paginated_response_of_budget_response.py +66 -0
  359. costfluent/models/paginated_response_of_business_metric_response.py +66 -0
  360. costfluent/models/paginated_response_of_business_metric_value_response.py +66 -0
  361. costfluent/models/paginated_response_of_cost_alert_event_response.py +66 -0
  362. costfluent/models/paginated_response_of_cost_alert_response.py +66 -0
  363. costfluent/models/paginated_response_of_cost_report_response.py +66 -0
  364. costfluent/models/paginated_response_of_cost_report_subscription_response.py +70 -0
  365. costfluent/models/paginated_response_of_custom_cost_upload_response.py +66 -0
  366. costfluent/models/paginated_response_of_dashboard_response.py +66 -0
  367. costfluent/models/paginated_response_of_exchange_rate_response.py +66 -0
  368. costfluent/models/paginated_response_of_folder_response.py +66 -0
  369. costfluent/models/paginated_response_of_provider_definition_response.py +66 -0
  370. costfluent/models/paginated_response_of_provider_response.py +66 -0
  371. costfluent/models/paginated_response_of_saved_filter_response.py +66 -0
  372. costfluent/models/paginated_response_of_segment_response.py +66 -0
  373. costfluent/models/paginated_response_of_string.py +56 -0
  374. costfluent/models/paginated_response_of_sync_history_entry_response.py +66 -0
  375. costfluent/models/paginated_response_of_tag_key_response.py +66 -0
  376. costfluent/models/paginated_response_of_team_response.py +66 -0
  377. costfluent/models/paginated_response_of_team_workspace_access_response.py +66 -0
  378. costfluent/models/paginated_response_of_user_response.py +66 -0
  379. costfluent/models/paginated_response_of_virtual_tag_response.py +66 -0
  380. costfluent/models/paginated_response_of_workspace_provider_response.py +66 -0
  381. costfluent/models/paginated_response_of_workspace_response.py +66 -0
  382. costfluent/models/pagination_links.py +124 -0
  383. costfluent/models/pause_cost_alert_request.py +23 -0
  384. costfluent/models/ping_response.py +59 -0
  385. costfluent/models/plan_ladder_entry_response.py +166 -0
  386. costfluent/models/preview_allocation_rule_request.py +86 -0
  387. costfluent/models/provider_cost_breakdown.py +66 -0
  388. costfluent/models/provider_created_response.py +66 -0
  389. costfluent/models/provider_definition_response.py +112 -0
  390. costfluent/models/provider_response.py +283 -0
  391. costfluent/models/remove_team_member_request.py +23 -0
  392. costfluent/models/remove_team_workspace_access_request.py +23 -0
  393. costfluent/models/reorder_allocation_rules_request.py +55 -0
  394. costfluent/models/report_breakdown_response.py +108 -0
  395. costfluent/models/report_comparison_point_response.py +59 -0
  396. costfluent/models/report_comparison_response.py +75 -0
  397. costfluent/models/report_group_response.py +100 -0
  398. costfluent/models/report_grouping_request.py +65 -0
  399. costfluent/models/report_grouping_response.py +64 -0
  400. costfluent/models/report_summary_response.py +243 -0
  401. costfluent/models/report_time_series_response.py +65 -0
  402. costfluent/models/report_unit_cost_point_response.py +85 -0
  403. costfluent/models/report_unit_cost_response.py +122 -0
  404. costfluent/models/resume_cost_alert_request.py +23 -0
  405. costfluent/models/saved_filter_created_response.py +50 -0
  406. costfluent/models/saved_filter_response.py +75 -0
  407. costfluent/models/segment_response.py +201 -0
  408. costfluent/models/segment_split_method_value.py +10 -0
  409. costfluent/models/segment_split_request.py +77 -0
  410. costfluent/models/segment_split_response.py +64 -0
  411. costfluent/models/segment_split_target_request.py +64 -0
  412. costfluent/models/segment_split_target_response.py +64 -0
  413. costfluent/models/service_cost_breakdown.py +58 -0
  414. costfluent/models/set_dashboard_default_request.py +50 -0
  415. costfluent/models/set_dashboard_saved_filter_request.py +64 -0
  416. costfluent/models/set_folder_saved_filter_request.py +64 -0
  417. costfluent/models/set_team_workspace_access_request.py +42 -0
  418. costfluent/models/submit_costs_request.py +67 -0
  419. costfluent/models/submit_costs_response.py +115 -0
  420. costfluent/models/sync_history_entry_response.py +131 -0
  421. costfluent/models/sync_trigger_response.py +64 -0
  422. costfluent/models/tag_key_response.py +115 -0
  423. costfluent/models/tag_policy_response.py +109 -0
  424. costfluent/models/tag_policy_rule_request.py +75 -0
  425. costfluent/models/tag_policy_rule_response.py +72 -0
  426. costfluent/models/team_detail_response.py +109 -0
  427. costfluent/models/team_member_response.py +83 -0
  428. costfluent/models/team_response.py +75 -0
  429. costfluent/models/team_workspace_access_response.py +58 -0
  430. costfluent/models/test_provider_connection_request.py +23 -0
  431. costfluent/models/translate_cost_filter_request.py +23 -0
  432. costfluent/models/trigger_provider_sync_request.py +42 -0
  433. costfluent/models/unit_cost_label_condition_request.py +50 -0
  434. costfluent/models/unit_cost_label_condition_response.py +50 -0
  435. costfluent/models/unit_quantity.py +50 -0
  436. costfluent/models/update_allocation_rule_request.py +100 -0
  437. costfluent/models/update_app_request.py +96 -0
  438. costfluent/models/update_app_request_config_type_0.py +45 -0
  439. costfluent/models/update_budget_request.py +230 -0
  440. costfluent/models/update_business_metric_request.py +74 -0
  441. costfluent/models/update_cost_alert_route_request.py +276 -0
  442. costfluent/models/update_cost_report_request.py +343 -0
  443. costfluent/models/update_cost_report_subscription_route_request.py +155 -0
  444. costfluent/models/update_dashboard_request.py +155 -0
  445. costfluent/models/update_dashboard_widget_request.py +132 -0
  446. costfluent/models/update_folder_request.py +93 -0
  447. costfluent/models/update_provider_request.py +223 -0
  448. costfluent/models/update_provider_request_credentials_type_0.py +45 -0
  449. costfluent/models/update_provider_request_settings_type_0.py +45 -0
  450. costfluent/models/update_saved_filter_request.py +94 -0
  451. costfluent/models/update_segment_request.py +172 -0
  452. costfluent/models/update_tag_policy_request.py +56 -0
  453. costfluent/models/update_team_member_request.py +42 -0
  454. costfluent/models/update_team_request.py +42 -0
  455. costfluent/models/update_virtual_tag_route_request.py +200 -0
  456. costfluent/models/update_workspace_provider_request.py +95 -0
  457. costfluent/models/update_workspace_request.py +296 -0
  458. costfluent/models/upload_custom_costs_request.py +88 -0
  459. costfluent/models/usage_history_entry_response.py +67 -0
  460. costfluent/models/usage_response.py +203 -0
  461. costfluent/models/user_invited_response.py +50 -0
  462. costfluent/models/user_response.py +153 -0
  463. costfluent/models/virtual_tag_created_response.py +50 -0
  464. costfluent/models/virtual_tag_response.py +161 -0
  465. costfluent/models/virtual_tag_rule_request.py +50 -0
  466. costfluent/models/virtual_tag_rule_response.py +50 -0
  467. costfluent/models/widget_position_request.py +69 -0
  468. costfluent/models/widget_position_response.py +66 -0
  469. costfluent/models/widget_response.py +168 -0
  470. costfluent/models/widget_response_config_type_0.py +45 -0
  471. costfluent/models/workspace_created_response.py +50 -0
  472. costfluent/models/workspace_provider_response.py +113 -0
  473. costfluent/models/workspace_report_defaults_request.py +196 -0
  474. costfluent/models/workspace_report_defaults_response.py +98 -0
  475. costfluent/models/workspace_response.py +205 -0
  476. costfluent/py.typed +0 -0
  477. costfluent/types.py +54 -0
  478. costfluent-1.0.0.dist-info/METADATA +112 -0
  479. costfluent-1.0.0.dist-info/RECORD +481 -0
  480. costfluent-1.0.0.dist-info/WHEEL +4 -0
  481. costfluent-1.0.0.dist-info/licenses/LICENSE +202 -0
costfluent/__init__.py ADDED
@@ -0,0 +1,32 @@
1
+ """Python client for the Costfluent Public API.
2
+
3
+ Every operation is a generated module under ``costfluent.api``, its models under
4
+ ``costfluent.models``; ``create_client`` builds the client they take::
5
+
6
+ from costfluent import create_client, paginate
7
+ from costfluent.api.workspaces import list_workspaces
8
+
9
+ client = create_client(token)
10
+ for workspace in paginate(list_workspaces.sync, client=client, limit=100):
11
+ print(workspace.name)
12
+ """
13
+
14
+ from ._contract import CONTRACT_SHA256
15
+ from ._sdk import DEFAULT_BASE_URL, CostfluentError, apaginate, create_client, paginate
16
+ from ._version import __version__
17
+ from .client import AuthenticatedClient
18
+ from .types import UNSET, Response, Unset
19
+
20
+ __all__ = [
21
+ "CONTRACT_SHA256",
22
+ "DEFAULT_BASE_URL",
23
+ "UNSET",
24
+ "AuthenticatedClient",
25
+ "CostfluentError",
26
+ "Response",
27
+ "Unset",
28
+ "__version__",
29
+ "apaginate",
30
+ "create_client",
31
+ "paginate",
32
+ ]
@@ -0,0 +1,27 @@
1
+ """Generated from the Public API document. Do not edit."""
2
+
3
+ CONTRACT_SHA256 = "0b9a6864ae2611a073fa0ae842ea3ef2d93f3ddc716b7c59fbd2de0618cddb5f"
4
+ """SHA-256 of the Public API document this package was generated from."""
5
+
6
+ IDEMPOTENT_CREATES: tuple[str, ...] = (
7
+ "/v1/allocation/rules",
8
+ "/v1/apps",
9
+ "/v1/budgets",
10
+ "/v1/business-metrics",
11
+ "/v1/cost-alerts",
12
+ "/v1/cost-report-subscriptions",
13
+ "/v1/cost-reports",
14
+ "/v1/custom-providers/{providerId}/costs",
15
+ "/v1/dashboards",
16
+ "/v1/dashboards/{dashboardId}/widgets",
17
+ "/v1/folders",
18
+ "/v1/providers",
19
+ "/v1/saved-filters",
20
+ "/v1/segments",
21
+ "/v1/teams",
22
+ "/v1/users",
23
+ "/v1/virtual-tags",
24
+ "/v1/workspace-providers",
25
+ "/v1/workspaces",
26
+ )
27
+ """The creates that take an Idempotency-Key; create_client sends a fresh one with each."""
costfluent/_sdk.py ADDED
@@ -0,0 +1,392 @@
1
+ """The hand-written layer over the generated client: authentication, retries, idempotency keys,
2
+ typed errors and pagination, with the same rules as the Costfluent Go client."""
3
+
4
+ from __future__ import annotations
5
+
6
+ import asyncio
7
+ import email.utils
8
+ import itertools
9
+ import random
10
+ import time
11
+ import uuid
12
+ from collections.abc import AsyncIterator, Awaitable, Callable, Iterator, Mapping, Sequence
13
+ from datetime import UTC, datetime
14
+ from typing import Any, Protocol, Self, TypeVar
15
+
16
+ import httpx
17
+
18
+ from ._contract import IDEMPOTENT_CREATES
19
+ from ._version import __version__
20
+ from .client import AuthenticatedClient
21
+ from .models.api_error import ApiError
22
+ from .models.api_error_entry import ApiErrorEntry
23
+ from .types import Unset
24
+
25
+ DEFAULT_BASE_URL = "https://api.costfluent.com"
26
+ DEFAULT_TIMEOUT = 30.0
27
+ USER_AGENT = f"costfluent-python/{__version__}"
28
+
29
+ MAX_RETRIES = 3
30
+ BASE_DELAY = 1.0
31
+ MAX_DELAY = 30.0
32
+ # The longest Retry-After a request waits out. A longer one means the token's hourly quota is spent,
33
+ # and the 429 is raised rather than held for most of an hour.
34
+ MAX_RETRY_WAIT = 60.0
35
+
36
+ IDEMPOTENCY_KEY = "Idempotency-Key"
37
+ PROBLEM_MEDIA_TYPE = "application/problem+json"
38
+ # The name the API files an error under when it names no request field.
39
+ GENERAL_ERRORS_FIELD = "generalErrors"
40
+
41
+ # Seams the tests replace, so a retry never really waits and an HTTP date has a fixed now.
42
+ _sleep: Callable[[float], None] = time.sleep
43
+ _async_sleep: Callable[[float], Awaitable[None]] = asyncio.sleep
44
+
45
+
46
+ def _now() -> datetime:
47
+ return datetime.now(UTC)
48
+
49
+
50
+ def _segment_pattern(template: str) -> Callable[[str], bool]:
51
+ segments = template.strip("/").split("/")
52
+
53
+ def matches(path: str) -> bool:
54
+ parts = path.strip("/").split("/")
55
+ # A base URL with a path prefix puts it before the API's own path.
56
+ parts = parts[len(parts) - len(segments) :] if len(parts) >= len(segments) else []
57
+ return bool(parts) and all(
58
+ segment.startswith("{") or segment == part for segment, part in zip(segments, parts, strict=True)
59
+ )
60
+
61
+ return matches
62
+
63
+
64
+ _CREATES = tuple(_segment_pattern(template) for template in IDEMPOTENT_CREATES)
65
+
66
+
67
+ class CostfluentError(Exception):
68
+ """An error status from the API, raised by every call once its retries are spent.
69
+
70
+ ``problem`` is the API's problem details when the response carried them; a response without
71
+ them (a proxy's plain 404 or 502) leaves it ``None`` and ``code`` empty.
72
+ """
73
+
74
+ def __init__(self, status: int, problem: ApiError | None = None, request_id: str | None = None) -> None:
75
+ self.status = status
76
+ self.problem = problem
77
+ self.request_id = request_id
78
+ super().__init__(self._message())
79
+
80
+ @classmethod
81
+ def from_response(cls, response: httpx.Response) -> Self:
82
+ problem = None
83
+ if _is_problem(response):
84
+ try:
85
+ problem = ApiError.from_dict(response.json())
86
+ except (KeyError, TypeError, ValueError):
87
+ problem = None
88
+ return cls(response.status_code, problem, response.headers.get("X-Request-Id"))
89
+
90
+ @property
91
+ def code(self) -> str:
92
+ """The problem's snake_case code, such as ``not_found`` or ``idempotency_key_reused``."""
93
+ return self.problem.code if self.problem else ""
94
+
95
+ @property
96
+ def detail(self) -> str | None:
97
+ detail = self.problem.detail if self.problem else None
98
+ return detail if isinstance(detail, str) else None
99
+
100
+ @property
101
+ def retryable(self) -> bool:
102
+ return self.problem.retryable if self.problem else False
103
+
104
+ @property
105
+ def trace_id(self) -> str | None:
106
+ trace_id = self.problem.trace_id if self.problem else None
107
+ return trace_id if isinstance(trace_id, str) else None
108
+
109
+ @property
110
+ def field_errors(self) -> list[ApiErrorEntry]:
111
+ errors = self.problem.errors if self.problem else None
112
+ return errors if isinstance(errors, list) else []
113
+
114
+ @property
115
+ def is_not_found(self) -> bool:
116
+ """The API found no such object. A proxy's plain 404 says nothing about the object, so it is not one."""
117
+ return self.status == 404 and self.problem is not None
118
+
119
+ @property
120
+ def is_rate_limited(self) -> bool:
121
+ return self.status == 429
122
+
123
+ @property
124
+ def is_idempotency_key_reused(self) -> bool:
125
+ return self.code == "idempotency_key_reused"
126
+
127
+ def _message(self) -> str:
128
+ if self.problem is None:
129
+ return f"Costfluent API answered {self.status}"
130
+ # The detail, then each field error the detail does not already state. A refused command's
131
+ # detail is only "One or more validation errors occurred", so the fields are what says what
132
+ # to change; a single refusal's detail repeats its one entry, and a missing capability's
133
+ # names it in another case.
134
+ detail = self.detail or ""
135
+ parts = [detail] if detail else []
136
+ for entry in self.field_errors:
137
+ if entry.reason and entry.reason.lower() not in detail.lower():
138
+ named = entry.name and entry.name != GENERAL_ERRORS_FIELD
139
+ parts.append(f"{entry.name}: {entry.reason}" if named else entry.reason)
140
+ text = "; ".join(parts) or self.problem.title
141
+ return f"Costfluent API answered {self.status} {self.problem.code}: {text}"
142
+
143
+
144
+ def _is_problem(response: httpx.Response) -> bool:
145
+ return response.headers.get("Content-Type", "").split(";")[0].strip().lower() == PROBLEM_MEDIA_TYPE
146
+
147
+
148
+ def _retryable(request: httpx.Request) -> bool:
149
+ """Whether a request is safe to resend after a lost response or a 5xx. A POST triggers, so
150
+ resending one the server may have run could run it twice unless it carries an Idempotency-Key,
151
+ and a request with If-Match the server applied would be refused by its own now stale precondition."""
152
+ if "If-Match" in request.headers:
153
+ return False
154
+ if request.method in ("GET", "HEAD", "PUT", "DELETE"):
155
+ return True
156
+ return request.method == "POST" and IDEMPOTENCY_KEY in request.headers
157
+
158
+
159
+ def _should_retry(request: httpx.Request, response: httpx.Response) -> bool:
160
+ """A 429 is retried for every method: the rate limiter refuses a request before any endpoint runs
161
+ it. A 404 without problem details is the proxy's, not the API's, and is retried as a 5xx is."""
162
+ edge_not_found = response.status_code == 404 and not _is_problem(response)
163
+ return response.status_code == 429 or ((response.status_code >= 500 or edge_not_found) and _retryable(request))
164
+
165
+
166
+ def _retry_after(headers: httpx.Headers, now: datetime) -> float | None:
167
+ """Retry-After in seconds or as an HTTP date, or else the RateLimit-Reset seconds the API sends
168
+ beside it on a 429."""
169
+ value = headers.get("Retry-After") or headers.get("RateLimit-Reset")
170
+ if not value:
171
+ return None
172
+ try:
173
+ return max(float(int(value)), 0.0)
174
+ except ValueError:
175
+ pass
176
+ try:
177
+ at = email.utils.parsedate_to_datetime(value)
178
+ except (TypeError, ValueError):
179
+ return None
180
+ if at.tzinfo is None:
181
+ at = at.replace(tzinfo=UTC)
182
+ return max((at - now).total_seconds(), 0.0)
183
+
184
+
185
+ def _delay(attempt: int, response: httpx.Response | None) -> float:
186
+ if response is not None and (after := _retry_after(response.headers, _now())) is not None:
187
+ return after
188
+ delay = min(BASE_DELAY * 2**attempt, MAX_DELAY)
189
+ return delay + random.uniform(0, delay / 4)
190
+
191
+
192
+ class _RetryTransport(httpx.BaseTransport):
193
+ def __init__(self, inner: httpx.BaseTransport, max_retries: int) -> None:
194
+ self._inner = inner
195
+ self._max_retries = max_retries
196
+
197
+ def handle_request(self, request: httpx.Request) -> httpx.Response:
198
+ for attempt in itertools.count():
199
+ last = attempt >= self._max_retries
200
+ response: httpx.Response | None
201
+ try:
202
+ response = self._inner.handle_request(request)
203
+ except httpx.TimeoutException:
204
+ # The timeout bounds the call, not each try: three more would quadruple it.
205
+ raise
206
+ except httpx.TransportError:
207
+ if last or not _retryable(request):
208
+ raise
209
+ response = None
210
+ else:
211
+ if last or not _should_retry(request, response):
212
+ return response
213
+ delay = _delay(attempt, response)
214
+ if response is not None:
215
+ if delay > MAX_RETRY_WAIT:
216
+ return response
217
+ response.close()
218
+ _sleep(delay)
219
+ raise AssertionError("unreachable")
220
+
221
+ def close(self) -> None:
222
+ self._inner.close()
223
+
224
+
225
+ class _AsyncRetryTransport(httpx.AsyncBaseTransport):
226
+ def __init__(self, inner: httpx.AsyncBaseTransport, max_retries: int) -> None:
227
+ self._inner = inner
228
+ self._max_retries = max_retries
229
+
230
+ async def handle_async_request(self, request: httpx.Request) -> httpx.Response:
231
+ for attempt in itertools.count():
232
+ last = attempt >= self._max_retries
233
+ response: httpx.Response | None
234
+ try:
235
+ response = await self._inner.handle_async_request(request)
236
+ except httpx.TimeoutException:
237
+ # The timeout bounds the call, not each try: three more would quadruple it.
238
+ raise
239
+ except httpx.TransportError:
240
+ if last or not _retryable(request):
241
+ raise
242
+ response = None
243
+ else:
244
+ if last or not _should_retry(request, response):
245
+ return response
246
+ delay = _delay(attempt, response)
247
+ if response is not None:
248
+ if delay > MAX_RETRY_WAIT:
249
+ return response
250
+ await response.aclose()
251
+ await _async_sleep(delay)
252
+ raise AssertionError("unreachable")
253
+
254
+ async def aclose(self) -> None:
255
+ await self._inner.aclose()
256
+
257
+
258
+ def _add_idempotency_key(request: httpx.Request) -> None:
259
+ """Every create gets a fresh key unless the caller gave one, so a retry is answered with the
260
+ first response instead of creating twice."""
261
+ if (
262
+ request.method == "POST"
263
+ and IDEMPOTENCY_KEY not in request.headers
264
+ and any(matches(request.url.path) for matches in _CREATES)
265
+ ):
266
+ request.headers[IDEMPOTENCY_KEY] = str(uuid.uuid4())
267
+
268
+
269
+ def _raise_for_status(response: httpx.Response) -> None:
270
+ if response.status_code >= 400:
271
+ response.read()
272
+ raise CostfluentError.from_response(response)
273
+
274
+
275
+ async def _async_add_idempotency_key(request: httpx.Request) -> None:
276
+ _add_idempotency_key(request)
277
+
278
+
279
+ async def _async_raise_for_status(response: httpx.Response) -> None:
280
+ if response.status_code >= 400:
281
+ await response.aread()
282
+ raise CostfluentError.from_response(response)
283
+
284
+
285
+ def create_client(
286
+ token: str,
287
+ *,
288
+ base_url: str = DEFAULT_BASE_URL,
289
+ timeout: float = DEFAULT_TIMEOUT,
290
+ max_retries: int = MAX_RETRIES,
291
+ transport: httpx.BaseTransport | None = None,
292
+ async_transport: httpx.AsyncBaseTransport | None = None,
293
+ ) -> AuthenticatedClient:
294
+ """A client for every generated operation, sync and async, sending ``token`` as a bearer token.
295
+
296
+ Calls retry as described in the README, give each create an Idempotency-Key, and raise
297
+ ``CostfluentError`` for any error status. ``transport`` and ``async_transport`` replace httpx's
298
+ own, as ``httpx.MockTransport`` does in a test.
299
+ """
300
+ headers = {
301
+ "Authorization": f"Bearer {token}",
302
+ "User-Agent": USER_AGENT,
303
+ "Accept": "application/json",
304
+ }
305
+ client = AuthenticatedClient(base_url=base_url, token=token, raise_on_unexpected_status=True)
306
+ client.set_httpx_client(
307
+ httpx.Client(
308
+ base_url=base_url,
309
+ headers=headers,
310
+ timeout=timeout,
311
+ transport=_RetryTransport(transport or httpx.HTTPTransport(), max_retries),
312
+ event_hooks={"request": [_add_idempotency_key], "response": [_raise_for_status]},
313
+ )
314
+ )
315
+ client.set_async_httpx_client(
316
+ httpx.AsyncClient(
317
+ base_url=base_url,
318
+ headers=headers,
319
+ timeout=timeout,
320
+ transport=_AsyncRetryTransport(async_transport or httpx.AsyncHTTPTransport(), max_retries),
321
+ event_hooks={"request": [_async_add_idempotency_key], "response": [_async_raise_for_status]},
322
+ )
323
+ )
324
+ return client
325
+
326
+
327
+ T = TypeVar("T")
328
+ T_co = TypeVar("T_co", covariant=True)
329
+
330
+
331
+ class _Links(Protocol):
332
+ @property
333
+ def next_(self) -> str | None | Unset: ...
334
+
335
+
336
+ class _Page(Protocol[T_co]):
337
+ @property
338
+ def links(self) -> _Links: ...
339
+
340
+ @property
341
+ def data(self) -> Sequence[T_co]: ...
342
+
343
+ @classmethod
344
+ def from_dict(cls, src_dict: Mapping[str, Any]) -> Self: ...
345
+
346
+
347
+ def _as_page(result: object) -> _Page[Any]:
348
+ if not (hasattr(result, "links") and hasattr(result, "data")):
349
+ raise TypeError(f"expected a page with links and data, got {type(result).__name__}")
350
+ return result # type: ignore[return-value]
351
+
352
+
353
+ def _next_url(page: _Page[Any], base_url: httpx.URL) -> httpx.URL | None:
354
+ """The next page on the client's own origin: the token goes only where the client was pointed,
355
+ whatever host the link names."""
356
+ link = page.links.next_
357
+ if not isinstance(link, str) or not link:
358
+ return None
359
+ return base_url.copy_with(raw_path=httpx.URL(link).raw_path)
360
+
361
+
362
+ def paginate(
363
+ operation: Callable[..., _Page[T] | ApiError | None], /, *, client: AuthenticatedClient, **kwargs: Any
364
+ ) -> Iterator[T]:
365
+ """Every item of a list, following ``links.next`` page by page.
366
+
367
+ ``operation`` is a generated ``sync`` function, called once with ``client`` and ``kwargs``:
368
+ ``paginate(list_workspaces.sync, client=client, limit=100)``.
369
+ """
370
+ page = _as_page(operation(client=client, **kwargs))
371
+ httpx_client = client.get_httpx_client()
372
+ while True:
373
+ yield from page.data
374
+ url = _next_url(page, httpx_client.base_url)
375
+ if url is None:
376
+ return
377
+ page = type(page).from_dict(httpx_client.get(url).json())
378
+
379
+
380
+ async def apaginate(
381
+ operation: Callable[..., Awaitable[_Page[T] | ApiError | None]], /, *, client: AuthenticatedClient, **kwargs: Any
382
+ ) -> AsyncIterator[T]:
383
+ """``paginate`` for a generated ``asyncio`` function."""
384
+ page = _as_page(await operation(client=client, **kwargs))
385
+ httpx_client = client.get_async_httpx_client()
386
+ while True:
387
+ for item in page.data:
388
+ yield item
389
+ url = _next_url(page, httpx_client.base_url)
390
+ if url is None:
391
+ return
392
+ page = type(page).from_dict((await httpx_client.get(url)).json())
costfluent/_version.py ADDED
@@ -0,0 +1 @@
1
+ __version__ = "1.0.0"
@@ -0,0 +1 @@
1
+ """Contains methods for accessing the API"""
@@ -0,0 +1 @@
1
+ """Contains endpoint functions for accessing the API"""
@@ -0,0 +1,239 @@
1
+ from http import HTTPStatus
2
+ from typing import Any
3
+
4
+ import httpx
5
+
6
+ from ... import errors
7
+ from ...client import AuthenticatedClient, Client
8
+ from ...models.allocation_rule_response import AllocationRuleResponse
9
+ from ...models.api_error import ApiError
10
+ from ...models.create_allocation_rule_request import CreateAllocationRuleRequest
11
+ from ...types import UNSET, Response, Unset
12
+
13
+
14
+ def _get_kwargs(
15
+ *,
16
+ body: CreateAllocationRuleRequest,
17
+ idempotency_key: str | Unset = UNSET,
18
+ ) -> dict[str, Any]:
19
+ headers: dict[str, Any] = {}
20
+ if not isinstance(idempotency_key, Unset):
21
+ headers["Idempotency-Key"] = idempotency_key
22
+
23
+ _kwargs: dict[str, Any] = {
24
+ "method": "post",
25
+ "url": "/v1/allocation/rules",
26
+ }
27
+
28
+ _kwargs["json"] = body.to_dict()
29
+
30
+ headers["Content-Type"] = "application/json"
31
+
32
+ _kwargs["headers"] = headers
33
+ return _kwargs
34
+
35
+
36
+ def _parse_response(
37
+ *, client: AuthenticatedClient | Client, response: httpx.Response
38
+ ) -> AllocationRuleResponse | ApiError | None:
39
+ if response.status_code == 201:
40
+ response_201 = AllocationRuleResponse.from_dict(response.json())
41
+
42
+ return response_201
43
+
44
+ if response.status_code == 400:
45
+ response_400 = ApiError.from_dict(response.json())
46
+
47
+ return response_400
48
+
49
+ if response.status_code == 401:
50
+ response_401 = ApiError.from_dict(response.json())
51
+
52
+ return response_401
53
+
54
+ if response.status_code == 403:
55
+ response_403 = ApiError.from_dict(response.json())
56
+
57
+ return response_403
58
+
59
+ if response.status_code == 404:
60
+ response_404 = ApiError.from_dict(response.json())
61
+
62
+ return response_404
63
+
64
+ if response.status_code == 408:
65
+ response_408 = ApiError.from_dict(response.json())
66
+
67
+ return response_408
68
+
69
+ if response.status_code == 409:
70
+ response_409 = ApiError.from_dict(response.json())
71
+
72
+ return response_409
73
+
74
+ if response.status_code == 413:
75
+ response_413 = ApiError.from_dict(response.json())
76
+
77
+ return response_413
78
+
79
+ if response.status_code == 422:
80
+ response_422 = ApiError.from_dict(response.json())
81
+
82
+ return response_422
83
+
84
+ if response.status_code == 429:
85
+ response_429 = ApiError.from_dict(response.json())
86
+
87
+ return response_429
88
+
89
+ if response.status_code == 500:
90
+ response_500 = ApiError.from_dict(response.json())
91
+
92
+ return response_500
93
+
94
+ if response.status_code == 503:
95
+ response_503 = ApiError.from_dict(response.json())
96
+
97
+ return response_503
98
+
99
+ if client.raise_on_unexpected_status:
100
+ raise errors.UnexpectedStatus(response.status_code, response.content)
101
+ else:
102
+ return None
103
+
104
+
105
+ def _build_response(
106
+ *, client: AuthenticatedClient | Client, response: httpx.Response
107
+ ) -> Response[AllocationRuleResponse | ApiError]:
108
+ return Response(
109
+ status_code=HTTPStatus(response.status_code),
110
+ content=response.content,
111
+ headers=response.headers,
112
+ parsed=_parse_response(client=client, response=response),
113
+ )
114
+
115
+
116
+ def sync_detailed(
117
+ *,
118
+ client: AuthenticatedClient,
119
+ body: CreateAllocationRuleRequest,
120
+ idempotency_key: str | Unset = UNSET,
121
+ ) -> Response[AllocationRuleResponse | ApiError]:
122
+ """Create an allocation rule
123
+
124
+ Needs a token with `manageCostAllocation` on the workspace.
125
+
126
+ Args:
127
+ idempotency_key (str | Unset):
128
+ body (CreateAllocationRuleRequest):
129
+
130
+ Raises:
131
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
132
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
133
+
134
+ Returns:
135
+ Response[AllocationRuleResponse | ApiError]
136
+ """
137
+
138
+ kwargs = _get_kwargs(
139
+ body=body,
140
+ idempotency_key=idempotency_key,
141
+ )
142
+
143
+ response = client.get_httpx_client().request(
144
+ **kwargs,
145
+ )
146
+
147
+ return _build_response(client=client, response=response)
148
+
149
+
150
+ def sync(
151
+ *,
152
+ client: AuthenticatedClient,
153
+ body: CreateAllocationRuleRequest,
154
+ idempotency_key: str | Unset = UNSET,
155
+ ) -> AllocationRuleResponse | ApiError | None:
156
+ """Create an allocation rule
157
+
158
+ Needs a token with `manageCostAllocation` on the workspace.
159
+
160
+ Args:
161
+ idempotency_key (str | Unset):
162
+ body (CreateAllocationRuleRequest):
163
+
164
+ Raises:
165
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
166
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
167
+
168
+ Returns:
169
+ AllocationRuleResponse | ApiError
170
+ """
171
+
172
+ return sync_detailed(
173
+ client=client,
174
+ body=body,
175
+ idempotency_key=idempotency_key,
176
+ ).parsed
177
+
178
+
179
+ async def asyncio_detailed(
180
+ *,
181
+ client: AuthenticatedClient,
182
+ body: CreateAllocationRuleRequest,
183
+ idempotency_key: str | Unset = UNSET,
184
+ ) -> Response[AllocationRuleResponse | ApiError]:
185
+ """Create an allocation rule
186
+
187
+ Needs a token with `manageCostAllocation` on the workspace.
188
+
189
+ Args:
190
+ idempotency_key (str | Unset):
191
+ body (CreateAllocationRuleRequest):
192
+
193
+ Raises:
194
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
195
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
196
+
197
+ Returns:
198
+ Response[AllocationRuleResponse | ApiError]
199
+ """
200
+
201
+ kwargs = _get_kwargs(
202
+ body=body,
203
+ idempotency_key=idempotency_key,
204
+ )
205
+
206
+ response = await client.get_async_httpx_client().request(**kwargs)
207
+
208
+ return _build_response(client=client, response=response)
209
+
210
+
211
+ async def asyncio(
212
+ *,
213
+ client: AuthenticatedClient,
214
+ body: CreateAllocationRuleRequest,
215
+ idempotency_key: str | Unset = UNSET,
216
+ ) -> AllocationRuleResponse | ApiError | None:
217
+ """Create an allocation rule
218
+
219
+ Needs a token with `manageCostAllocation` on the workspace.
220
+
221
+ Args:
222
+ idempotency_key (str | Unset):
223
+ body (CreateAllocationRuleRequest):
224
+
225
+ Raises:
226
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
227
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
228
+
229
+ Returns:
230
+ AllocationRuleResponse | ApiError
231
+ """
232
+
233
+ return (
234
+ await asyncio_detailed(
235
+ client=client,
236
+ body=body,
237
+ idempotency_key=idempotency_key,
238
+ )
239
+ ).parsed