aeri-python 4.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 (391) hide show
  1. aeri/__init__.py +72 -0
  2. aeri/_client/_validation.py +204 -0
  3. aeri/_client/attributes.py +188 -0
  4. aeri/_client/client.py +3761 -0
  5. aeri/_client/constants.py +65 -0
  6. aeri/_client/datasets.py +302 -0
  7. aeri/_client/environment_variables.py +158 -0
  8. aeri/_client/get_client.py +149 -0
  9. aeri/_client/observe.py +661 -0
  10. aeri/_client/propagation.py +475 -0
  11. aeri/_client/resource_manager.py +510 -0
  12. aeri/_client/span.py +1519 -0
  13. aeri/_client/span_filter.py +76 -0
  14. aeri/_client/span_processor.py +206 -0
  15. aeri/_client/utils.py +132 -0
  16. aeri/_task_manager/media_manager.py +331 -0
  17. aeri/_task_manager/media_upload_consumer.py +44 -0
  18. aeri/_task_manager/media_upload_queue.py +12 -0
  19. aeri/_task_manager/score_ingestion_consumer.py +208 -0
  20. aeri/_task_manager/task_manager.py +475 -0
  21. aeri/_utils/__init__.py +19 -0
  22. aeri/_utils/environment.py +34 -0
  23. aeri/_utils/error_logging.py +47 -0
  24. aeri/_utils/parse_error.py +99 -0
  25. aeri/_utils/prompt_cache.py +188 -0
  26. aeri/_utils/request.py +137 -0
  27. aeri/_utils/serializer.py +205 -0
  28. aeri/api/.fern/metadata.json +14 -0
  29. aeri/api/__init__.py +836 -0
  30. aeri/api/annotation_queues/__init__.py +82 -0
  31. aeri/api/annotation_queues/client.py +1111 -0
  32. aeri/api/annotation_queues/raw_client.py +2288 -0
  33. aeri/api/annotation_queues/types/__init__.py +84 -0
  34. aeri/api/annotation_queues/types/annotation_queue.py +28 -0
  35. aeri/api/annotation_queues/types/annotation_queue_assignment_request.py +16 -0
  36. aeri/api/annotation_queues/types/annotation_queue_item.py +34 -0
  37. aeri/api/annotation_queues/types/annotation_queue_object_type.py +26 -0
  38. aeri/api/annotation_queues/types/annotation_queue_status.py +22 -0
  39. aeri/api/annotation_queues/types/create_annotation_queue_assignment_response.py +18 -0
  40. aeri/api/annotation_queues/types/create_annotation_queue_item_request.py +25 -0
  41. aeri/api/annotation_queues/types/create_annotation_queue_request.py +20 -0
  42. aeri/api/annotation_queues/types/delete_annotation_queue_assignment_response.py +14 -0
  43. aeri/api/annotation_queues/types/delete_annotation_queue_item_response.py +15 -0
  44. aeri/api/annotation_queues/types/paginated_annotation_queue_items.py +17 -0
  45. aeri/api/annotation_queues/types/paginated_annotation_queues.py +17 -0
  46. aeri/api/annotation_queues/types/update_annotation_queue_item_request.py +15 -0
  47. aeri/api/blob_storage_integrations/__init__.py +73 -0
  48. aeri/api/blob_storage_integrations/client.py +550 -0
  49. aeri/api/blob_storage_integrations/raw_client.py +976 -0
  50. aeri/api/blob_storage_integrations/types/__init__.py +77 -0
  51. aeri/api/blob_storage_integrations/types/blob_storage_export_frequency.py +26 -0
  52. aeri/api/blob_storage_integrations/types/blob_storage_export_mode.py +26 -0
  53. aeri/api/blob_storage_integrations/types/blob_storage_integration_deletion_response.py +14 -0
  54. aeri/api/blob_storage_integrations/types/blob_storage_integration_file_type.py +26 -0
  55. aeri/api/blob_storage_integrations/types/blob_storage_integration_response.py +64 -0
  56. aeri/api/blob_storage_integrations/types/blob_storage_integration_status_response.py +50 -0
  57. aeri/api/blob_storage_integrations/types/blob_storage_integration_type.py +26 -0
  58. aeri/api/blob_storage_integrations/types/blob_storage_integrations_response.py +15 -0
  59. aeri/api/blob_storage_integrations/types/blob_storage_sync_status.py +47 -0
  60. aeri/api/blob_storage_integrations/types/create_blob_storage_integration_request.py +91 -0
  61. aeri/api/client.py +679 -0
  62. aeri/api/comments/__init__.py +44 -0
  63. aeri/api/comments/client.py +407 -0
  64. aeri/api/comments/raw_client.py +750 -0
  65. aeri/api/comments/types/__init__.py +46 -0
  66. aeri/api/comments/types/create_comment_request.py +47 -0
  67. aeri/api/comments/types/create_comment_response.py +17 -0
  68. aeri/api/comments/types/get_comments_response.py +17 -0
  69. aeri/api/commons/__init__.py +210 -0
  70. aeri/api/commons/errors/__init__.py +56 -0
  71. aeri/api/commons/errors/access_denied_error.py +12 -0
  72. aeri/api/commons/errors/error.py +12 -0
  73. aeri/api/commons/errors/method_not_allowed_error.py +12 -0
  74. aeri/api/commons/errors/not_found_error.py +12 -0
  75. aeri/api/commons/errors/unauthorized_error.py +12 -0
  76. aeri/api/commons/types/__init__.py +190 -0
  77. aeri/api/commons/types/base_score.py +90 -0
  78. aeri/api/commons/types/base_score_v1.py +70 -0
  79. aeri/api/commons/types/boolean_score.py +26 -0
  80. aeri/api/commons/types/boolean_score_v1.py +26 -0
  81. aeri/api/commons/types/categorical_score.py +26 -0
  82. aeri/api/commons/types/categorical_score_v1.py +26 -0
  83. aeri/api/commons/types/comment.py +36 -0
  84. aeri/api/commons/types/comment_object_type.py +30 -0
  85. aeri/api/commons/types/config_category.py +15 -0
  86. aeri/api/commons/types/correction_score.py +26 -0
  87. aeri/api/commons/types/create_score_value.py +5 -0
  88. aeri/api/commons/types/dataset.py +49 -0
  89. aeri/api/commons/types/dataset_item.py +58 -0
  90. aeri/api/commons/types/dataset_run.py +63 -0
  91. aeri/api/commons/types/dataset_run_item.py +40 -0
  92. aeri/api/commons/types/dataset_run_with_items.py +19 -0
  93. aeri/api/commons/types/dataset_status.py +22 -0
  94. aeri/api/commons/types/map_value.py +11 -0
  95. aeri/api/commons/types/model.py +125 -0
  96. aeri/api/commons/types/model_price.py +14 -0
  97. aeri/api/commons/types/model_usage_unit.py +42 -0
  98. aeri/api/commons/types/numeric_score.py +17 -0
  99. aeri/api/commons/types/numeric_score_v1.py +17 -0
  100. aeri/api/commons/types/observation.py +142 -0
  101. aeri/api/commons/types/observation_level.py +30 -0
  102. aeri/api/commons/types/observation_v2.py +235 -0
  103. aeri/api/commons/types/observations_view.py +89 -0
  104. aeri/api/commons/types/pricing_tier.py +91 -0
  105. aeri/api/commons/types/pricing_tier_condition.py +68 -0
  106. aeri/api/commons/types/pricing_tier_input.py +76 -0
  107. aeri/api/commons/types/pricing_tier_operator.py +42 -0
  108. aeri/api/commons/types/score.py +201 -0
  109. aeri/api/commons/types/score_config.py +66 -0
  110. aeri/api/commons/types/score_config_data_type.py +26 -0
  111. aeri/api/commons/types/score_data_type.py +30 -0
  112. aeri/api/commons/types/score_source.py +26 -0
  113. aeri/api/commons/types/score_v1.py +131 -0
  114. aeri/api/commons/types/session.py +25 -0
  115. aeri/api/commons/types/session_with_traces.py +15 -0
  116. aeri/api/commons/types/trace.py +84 -0
  117. aeri/api/commons/types/trace_with_details.py +43 -0
  118. aeri/api/commons/types/trace_with_full_details.py +45 -0
  119. aeri/api/commons/types/usage.py +59 -0
  120. aeri/api/core/__init__.py +111 -0
  121. aeri/api/core/api_error.py +23 -0
  122. aeri/api/core/client_wrapper.py +141 -0
  123. aeri/api/core/datetime_utils.py +30 -0
  124. aeri/api/core/enum.py +20 -0
  125. aeri/api/core/file.py +70 -0
  126. aeri/api/core/force_multipart.py +18 -0
  127. aeri/api/core/http_client.py +711 -0
  128. aeri/api/core/http_response.py +55 -0
  129. aeri/api/core/http_sse/__init__.py +48 -0
  130. aeri/api/core/http_sse/_api.py +114 -0
  131. aeri/api/core/http_sse/_decoders.py +66 -0
  132. aeri/api/core/http_sse/_exceptions.py +7 -0
  133. aeri/api/core/http_sse/_models.py +17 -0
  134. aeri/api/core/jsonable_encoder.py +102 -0
  135. aeri/api/core/pydantic_utilities.py +310 -0
  136. aeri/api/core/query_encoder.py +60 -0
  137. aeri/api/core/remove_none_from_dict.py +11 -0
  138. aeri/api/core/request_options.py +35 -0
  139. aeri/api/core/serialization.py +282 -0
  140. aeri/api/dataset_items/__init__.py +52 -0
  141. aeri/api/dataset_items/client.py +499 -0
  142. aeri/api/dataset_items/raw_client.py +973 -0
  143. aeri/api/dataset_items/types/__init__.py +50 -0
  144. aeri/api/dataset_items/types/create_dataset_item_request.py +37 -0
  145. aeri/api/dataset_items/types/delete_dataset_item_response.py +17 -0
  146. aeri/api/dataset_items/types/paginated_dataset_items.py +17 -0
  147. aeri/api/dataset_run_items/__init__.py +43 -0
  148. aeri/api/dataset_run_items/client.py +323 -0
  149. aeri/api/dataset_run_items/raw_client.py +547 -0
  150. aeri/api/dataset_run_items/types/__init__.py +44 -0
  151. aeri/api/dataset_run_items/types/create_dataset_run_item_request.py +51 -0
  152. aeri/api/dataset_run_items/types/paginated_dataset_run_items.py +17 -0
  153. aeri/api/datasets/__init__.py +55 -0
  154. aeri/api/datasets/client.py +661 -0
  155. aeri/api/datasets/raw_client.py +1368 -0
  156. aeri/api/datasets/types/__init__.py +53 -0
  157. aeri/api/datasets/types/create_dataset_request.py +31 -0
  158. aeri/api/datasets/types/delete_dataset_run_response.py +14 -0
  159. aeri/api/datasets/types/paginated_dataset_runs.py +17 -0
  160. aeri/api/datasets/types/paginated_datasets.py +17 -0
  161. aeri/api/health/__init__.py +44 -0
  162. aeri/api/health/client.py +112 -0
  163. aeri/api/health/errors/__init__.py +42 -0
  164. aeri/api/health/errors/service_unavailable_error.py +13 -0
  165. aeri/api/health/raw_client.py +227 -0
  166. aeri/api/health/types/__init__.py +40 -0
  167. aeri/api/health/types/health_response.py +30 -0
  168. aeri/api/ingestion/__init__.py +169 -0
  169. aeri/api/ingestion/client.py +221 -0
  170. aeri/api/ingestion/raw_client.py +293 -0
  171. aeri/api/ingestion/types/__init__.py +169 -0
  172. aeri/api/ingestion/types/base_event.py +27 -0
  173. aeri/api/ingestion/types/create_event_body.py +14 -0
  174. aeri/api/ingestion/types/create_event_event.py +15 -0
  175. aeri/api/ingestion/types/create_generation_body.py +40 -0
  176. aeri/api/ingestion/types/create_generation_event.py +15 -0
  177. aeri/api/ingestion/types/create_observation_event.py +15 -0
  178. aeri/api/ingestion/types/create_span_body.py +19 -0
  179. aeri/api/ingestion/types/create_span_event.py +15 -0
  180. aeri/api/ingestion/types/ingestion_error.py +17 -0
  181. aeri/api/ingestion/types/ingestion_event.py +155 -0
  182. aeri/api/ingestion/types/ingestion_response.py +17 -0
  183. aeri/api/ingestion/types/ingestion_success.py +15 -0
  184. aeri/api/ingestion/types/ingestion_usage.py +8 -0
  185. aeri/api/ingestion/types/observation_body.py +53 -0
  186. aeri/api/ingestion/types/observation_type.py +54 -0
  187. aeri/api/ingestion/types/open_ai_completion_usage_schema.py +26 -0
  188. aeri/api/ingestion/types/open_ai_response_usage_schema.py +24 -0
  189. aeri/api/ingestion/types/open_ai_usage.py +28 -0
  190. aeri/api/ingestion/types/optional_observation_body.py +36 -0
  191. aeri/api/ingestion/types/score_body.py +75 -0
  192. aeri/api/ingestion/types/score_event.py +15 -0
  193. aeri/api/ingestion/types/sdk_log_body.py +14 -0
  194. aeri/api/ingestion/types/sdk_log_event.py +15 -0
  195. aeri/api/ingestion/types/trace_body.py +36 -0
  196. aeri/api/ingestion/types/trace_event.py +15 -0
  197. aeri/api/ingestion/types/update_event_body.py +14 -0
  198. aeri/api/ingestion/types/update_generation_body.py +40 -0
  199. aeri/api/ingestion/types/update_generation_event.py +15 -0
  200. aeri/api/ingestion/types/update_observation_event.py +15 -0
  201. aeri/api/ingestion/types/update_span_body.py +19 -0
  202. aeri/api/ingestion/types/update_span_event.py +15 -0
  203. aeri/api/ingestion/types/usage_details.py +10 -0
  204. aeri/api/legacy/__init__.py +61 -0
  205. aeri/api/legacy/client.py +105 -0
  206. aeri/api/legacy/metrics_v1/__init__.py +40 -0
  207. aeri/api/legacy/metrics_v1/client.py +214 -0
  208. aeri/api/legacy/metrics_v1/raw_client.py +322 -0
  209. aeri/api/legacy/metrics_v1/types/__init__.py +40 -0
  210. aeri/api/legacy/metrics_v1/types/metrics_response.py +19 -0
  211. aeri/api/legacy/observations_v1/__init__.py +43 -0
  212. aeri/api/legacy/observations_v1/client.py +523 -0
  213. aeri/api/legacy/observations_v1/raw_client.py +759 -0
  214. aeri/api/legacy/observations_v1/types/__init__.py +44 -0
  215. aeri/api/legacy/observations_v1/types/observations.py +17 -0
  216. aeri/api/legacy/observations_v1/types/observations_views.py +17 -0
  217. aeri/api/legacy/raw_client.py +13 -0
  218. aeri/api/legacy/score_v1/__init__.py +43 -0
  219. aeri/api/legacy/score_v1/client.py +329 -0
  220. aeri/api/legacy/score_v1/raw_client.py +545 -0
  221. aeri/api/legacy/score_v1/types/__init__.py +44 -0
  222. aeri/api/legacy/score_v1/types/create_score_request.py +75 -0
  223. aeri/api/legacy/score_v1/types/create_score_response.py +17 -0
  224. aeri/api/llm_connections/__init__.py +55 -0
  225. aeri/api/llm_connections/client.py +311 -0
  226. aeri/api/llm_connections/raw_client.py +541 -0
  227. aeri/api/llm_connections/types/__init__.py +53 -0
  228. aeri/api/llm_connections/types/llm_adapter.py +38 -0
  229. aeri/api/llm_connections/types/llm_connection.py +77 -0
  230. aeri/api/llm_connections/types/paginated_llm_connections.py +17 -0
  231. aeri/api/llm_connections/types/upsert_llm_connection_request.py +69 -0
  232. aeri/api/media/__init__.py +58 -0
  233. aeri/api/media/client.py +427 -0
  234. aeri/api/media/raw_client.py +739 -0
  235. aeri/api/media/types/__init__.py +56 -0
  236. aeri/api/media/types/get_media_response.py +55 -0
  237. aeri/api/media/types/get_media_upload_url_request.py +51 -0
  238. aeri/api/media/types/get_media_upload_url_response.py +28 -0
  239. aeri/api/media/types/media_content_type.py +232 -0
  240. aeri/api/media/types/patch_media_body.py +43 -0
  241. aeri/api/metrics/__init__.py +40 -0
  242. aeri/api/metrics/client.py +422 -0
  243. aeri/api/metrics/raw_client.py +530 -0
  244. aeri/api/metrics/types/__init__.py +40 -0
  245. aeri/api/metrics/types/metrics_v2response.py +19 -0
  246. aeri/api/models/__init__.py +43 -0
  247. aeri/api/models/client.py +523 -0
  248. aeri/api/models/raw_client.py +993 -0
  249. aeri/api/models/types/__init__.py +44 -0
  250. aeri/api/models/types/create_model_request.py +103 -0
  251. aeri/api/models/types/paginated_models.py +17 -0
  252. aeri/api/observations/__init__.py +43 -0
  253. aeri/api/observations/client.py +522 -0
  254. aeri/api/observations/raw_client.py +641 -0
  255. aeri/api/observations/types/__init__.py +44 -0
  256. aeri/api/observations/types/observations_v2meta.py +21 -0
  257. aeri/api/observations/types/observations_v2response.py +28 -0
  258. aeri/api/opentelemetry/__init__.py +67 -0
  259. aeri/api/opentelemetry/client.py +276 -0
  260. aeri/api/opentelemetry/raw_client.py +291 -0
  261. aeri/api/opentelemetry/types/__init__.py +65 -0
  262. aeri/api/opentelemetry/types/otel_attribute.py +27 -0
  263. aeri/api/opentelemetry/types/otel_attribute_value.py +46 -0
  264. aeri/api/opentelemetry/types/otel_resource.py +24 -0
  265. aeri/api/opentelemetry/types/otel_resource_span.py +32 -0
  266. aeri/api/opentelemetry/types/otel_scope.py +34 -0
  267. aeri/api/opentelemetry/types/otel_scope_span.py +28 -0
  268. aeri/api/opentelemetry/types/otel_span.py +76 -0
  269. aeri/api/opentelemetry/types/otel_trace_response.py +16 -0
  270. aeri/api/organizations/__init__.py +73 -0
  271. aeri/api/organizations/client.py +756 -0
  272. aeri/api/organizations/raw_client.py +1707 -0
  273. aeri/api/organizations/types/__init__.py +71 -0
  274. aeri/api/organizations/types/delete_membership_request.py +16 -0
  275. aeri/api/organizations/types/membership_deletion_response.py +17 -0
  276. aeri/api/organizations/types/membership_request.py +18 -0
  277. aeri/api/organizations/types/membership_response.py +20 -0
  278. aeri/api/organizations/types/membership_role.py +30 -0
  279. aeri/api/organizations/types/memberships_response.py +15 -0
  280. aeri/api/organizations/types/organization_api_key.py +31 -0
  281. aeri/api/organizations/types/organization_api_keys_response.py +19 -0
  282. aeri/api/organizations/types/organization_project.py +25 -0
  283. aeri/api/organizations/types/organization_projects_response.py +15 -0
  284. aeri/api/projects/__init__.py +67 -0
  285. aeri/api/projects/client.py +760 -0
  286. aeri/api/projects/raw_client.py +1577 -0
  287. aeri/api/projects/types/__init__.py +65 -0
  288. aeri/api/projects/types/api_key_deletion_response.py +18 -0
  289. aeri/api/projects/types/api_key_list.py +23 -0
  290. aeri/api/projects/types/api_key_response.py +30 -0
  291. aeri/api/projects/types/api_key_summary.py +35 -0
  292. aeri/api/projects/types/organization.py +22 -0
  293. aeri/api/projects/types/project.py +34 -0
  294. aeri/api/projects/types/project_deletion_response.py +15 -0
  295. aeri/api/projects/types/projects.py +15 -0
  296. aeri/api/prompt_version/__init__.py +4 -0
  297. aeri/api/prompt_version/client.py +157 -0
  298. aeri/api/prompt_version/raw_client.py +264 -0
  299. aeri/api/prompts/__init__.py +100 -0
  300. aeri/api/prompts/client.py +550 -0
  301. aeri/api/prompts/raw_client.py +987 -0
  302. aeri/api/prompts/types/__init__.py +96 -0
  303. aeri/api/prompts/types/base_prompt.py +42 -0
  304. aeri/api/prompts/types/chat_message.py +17 -0
  305. aeri/api/prompts/types/chat_message_type.py +15 -0
  306. aeri/api/prompts/types/chat_message_with_placeholders.py +8 -0
  307. aeri/api/prompts/types/chat_prompt.py +15 -0
  308. aeri/api/prompts/types/create_chat_prompt_request.py +37 -0
  309. aeri/api/prompts/types/create_chat_prompt_type.py +15 -0
  310. aeri/api/prompts/types/create_prompt_request.py +8 -0
  311. aeri/api/prompts/types/create_text_prompt_request.py +36 -0
  312. aeri/api/prompts/types/create_text_prompt_type.py +15 -0
  313. aeri/api/prompts/types/placeholder_message.py +16 -0
  314. aeri/api/prompts/types/placeholder_message_type.py +15 -0
  315. aeri/api/prompts/types/prompt.py +58 -0
  316. aeri/api/prompts/types/prompt_meta.py +35 -0
  317. aeri/api/prompts/types/prompt_meta_list_response.py +17 -0
  318. aeri/api/prompts/types/prompt_type.py +20 -0
  319. aeri/api/prompts/types/text_prompt.py +14 -0
  320. aeri/api/scim/__init__.py +94 -0
  321. aeri/api/scim/client.py +686 -0
  322. aeri/api/scim/raw_client.py +1528 -0
  323. aeri/api/scim/types/__init__.py +92 -0
  324. aeri/api/scim/types/authentication_scheme.py +20 -0
  325. aeri/api/scim/types/bulk_config.py +22 -0
  326. aeri/api/scim/types/empty_response.py +16 -0
  327. aeri/api/scim/types/filter_config.py +17 -0
  328. aeri/api/scim/types/resource_meta.py +17 -0
  329. aeri/api/scim/types/resource_type.py +27 -0
  330. aeri/api/scim/types/resource_types_response.py +21 -0
  331. aeri/api/scim/types/schema_extension.py +17 -0
  332. aeri/api/scim/types/schema_resource.py +19 -0
  333. aeri/api/scim/types/schemas_response.py +21 -0
  334. aeri/api/scim/types/scim_email.py +16 -0
  335. aeri/api/scim/types/scim_feature_support.py +14 -0
  336. aeri/api/scim/types/scim_name.py +14 -0
  337. aeri/api/scim/types/scim_user.py +24 -0
  338. aeri/api/scim/types/scim_users_list_response.py +25 -0
  339. aeri/api/scim/types/service_provider_config.py +36 -0
  340. aeri/api/scim/types/user_meta.py +20 -0
  341. aeri/api/score_configs/__init__.py +44 -0
  342. aeri/api/score_configs/client.py +526 -0
  343. aeri/api/score_configs/raw_client.py +1012 -0
  344. aeri/api/score_configs/types/__init__.py +46 -0
  345. aeri/api/score_configs/types/create_score_config_request.py +46 -0
  346. aeri/api/score_configs/types/score_configs.py +17 -0
  347. aeri/api/score_configs/types/update_score_config_request.py +53 -0
  348. aeri/api/scores/__init__.py +76 -0
  349. aeri/api/scores/client.py +420 -0
  350. aeri/api/scores/raw_client.py +656 -0
  351. aeri/api/scores/types/__init__.py +76 -0
  352. aeri/api/scores/types/get_scores_response.py +17 -0
  353. aeri/api/scores/types/get_scores_response_data.py +211 -0
  354. aeri/api/scores/types/get_scores_response_data_boolean.py +15 -0
  355. aeri/api/scores/types/get_scores_response_data_categorical.py +15 -0
  356. aeri/api/scores/types/get_scores_response_data_correction.py +15 -0
  357. aeri/api/scores/types/get_scores_response_data_numeric.py +15 -0
  358. aeri/api/scores/types/get_scores_response_trace_data.py +38 -0
  359. aeri/api/sessions/__init__.py +40 -0
  360. aeri/api/sessions/client.py +262 -0
  361. aeri/api/sessions/raw_client.py +500 -0
  362. aeri/api/sessions/types/__init__.py +40 -0
  363. aeri/api/sessions/types/paginated_sessions.py +17 -0
  364. aeri/api/trace/__init__.py +44 -0
  365. aeri/api/trace/client.py +728 -0
  366. aeri/api/trace/raw_client.py +1208 -0
  367. aeri/api/trace/types/__init__.py +46 -0
  368. aeri/api/trace/types/delete_trace_response.py +14 -0
  369. aeri/api/trace/types/sort.py +14 -0
  370. aeri/api/trace/types/traces.py +17 -0
  371. aeri/api/utils/__init__.py +44 -0
  372. aeri/api/utils/pagination/__init__.py +40 -0
  373. aeri/api/utils/pagination/types/__init__.py +40 -0
  374. aeri/api/utils/pagination/types/meta_response.py +38 -0
  375. aeri/batch_evaluation.py +1643 -0
  376. aeri/experiment.py +1044 -0
  377. aeri/langchain/CallbackHandler.py +1377 -0
  378. aeri/langchain/__init__.py +5 -0
  379. aeri/langchain/utils.py +212 -0
  380. aeri/logger.py +28 -0
  381. aeri/media.py +352 -0
  382. aeri/model.py +477 -0
  383. aeri/openai.py +1124 -0
  384. aeri/py.typed +0 -0
  385. aeri/span_filter.py +17 -0
  386. aeri/types.py +79 -0
  387. aeri/version.py +3 -0
  388. aeri_python-4.0.0.dist-info/METADATA +51 -0
  389. aeri_python-4.0.0.dist-info/RECORD +391 -0
  390. aeri_python-4.0.0.dist-info/WHEEL +4 -0
  391. aeri_python-4.0.0.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,214 @@
1
+ # This file was auto-generated by Fern from our API Definition.
2
+
3
+ import typing
4
+
5
+ from ...core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
6
+ from ...core.request_options import RequestOptions
7
+ from .raw_client import AsyncRawMetricsV1Client, RawMetricsV1Client
8
+ from .types.metrics_response import MetricsResponse
9
+
10
+
11
+ class MetricsV1Client:
12
+ def __init__(self, *, client_wrapper: SyncClientWrapper):
13
+ self._raw_client = RawMetricsV1Client(client_wrapper=client_wrapper)
14
+
15
+ @property
16
+ def with_raw_response(self) -> RawMetricsV1Client:
17
+ """
18
+ Retrieves a raw implementation of this client that returns raw responses.
19
+
20
+ Returns
21
+ -------
22
+ RawMetricsV1Client
23
+ """
24
+ return self._raw_client
25
+
26
+ def metrics(
27
+ self, *, query: str, request_options: typing.Optional[RequestOptions] = None
28
+ ) -> MetricsResponse:
29
+ """
30
+ Get metrics from the Aeri project using a query object.
31
+
32
+ Consider using the [v2 metrics endpoint](/api-reference#tag/metricsv2/GET/api/public/v2/metrics) for better performance.
33
+
34
+ For more details, see the [Metrics API documentation](https://aeri.com/docs/metrics/features/metrics-api).
35
+
36
+ Parameters
37
+ ----------
38
+ query : str
39
+ JSON string containing the query parameters with the following structure:
40
+ ```json
41
+ {
42
+ "view": string, // Required. One of "traces", "observations", "scores-numeric", "scores-categorical"
43
+ "dimensions": [ // Optional. Default: []
44
+ {
45
+ "field": string // Field to group by, e.g. "name", "userId", "sessionId"
46
+ }
47
+ ],
48
+ "metrics": [ // Required. At least one metric must be provided
49
+ {
50
+ "measure": string, // What to measure, e.g. "count", "latency", "value"
51
+ "aggregation": string // How to aggregate, e.g. "count", "sum", "avg", "p95", "histogram"
52
+ }
53
+ ],
54
+ "filters": [ // Optional. Default: []
55
+ {
56
+ "column": string, // Column to filter on
57
+ "operator": string, // Operator, e.g. "=", ">", "<", "contains"
58
+ "value": any, // Value to compare against
59
+ "type": string, // Data type, e.g. "string", "number", "stringObject"
60
+ "key": string // Required only when filtering on metadata
61
+ }
62
+ ],
63
+ "timeDimension": { // Optional. Default: null. If provided, results will be grouped by time
64
+ "granularity": string // One of "minute", "hour", "day", "week", "month", "auto"
65
+ },
66
+ "fromTimestamp": string, // Required. ISO datetime string for start of time range
67
+ "toTimestamp": string, // Required. ISO datetime string for end of time range
68
+ "orderBy": [ // Optional. Default: null
69
+ {
70
+ "field": string, // Field to order by
71
+ "direction": string // "asc" or "desc"
72
+ }
73
+ ],
74
+ "config": { // Optional. Query-specific configuration
75
+ "bins": number, // Optional. Number of bins for histogram (1-100), default: 10
76
+ "row_limit": number // Optional. Row limit for results (1-1000)
77
+ }
78
+ }
79
+ ```
80
+
81
+ request_options : typing.Optional[RequestOptions]
82
+ Request-specific configuration.
83
+
84
+ Returns
85
+ -------
86
+ MetricsResponse
87
+
88
+ Examples
89
+ --------
90
+ from aeri import AeriAPI
91
+
92
+ client = AeriAPI(
93
+ x_aeri_sdk_name="YOUR_X_AERI_SDK_NAME",
94
+ x_aeri_sdk_version="YOUR_X_AERI_SDK_VERSION",
95
+ x_aeri_public_key="YOUR_X_AERI_PUBLIC_KEY",
96
+ username="YOUR_USERNAME",
97
+ password="YOUR_PASSWORD",
98
+ base_url="https://yourhost.com/path/to/api",
99
+ )
100
+ client.legacy.metrics_v1.metrics(
101
+ query="query",
102
+ )
103
+ """
104
+ _response = self._raw_client.metrics(
105
+ query=query, request_options=request_options
106
+ )
107
+ return _response.data
108
+
109
+
110
+ class AsyncMetricsV1Client:
111
+ def __init__(self, *, client_wrapper: AsyncClientWrapper):
112
+ self._raw_client = AsyncRawMetricsV1Client(client_wrapper=client_wrapper)
113
+
114
+ @property
115
+ def with_raw_response(self) -> AsyncRawMetricsV1Client:
116
+ """
117
+ Retrieves a raw implementation of this client that returns raw responses.
118
+
119
+ Returns
120
+ -------
121
+ AsyncRawMetricsV1Client
122
+ """
123
+ return self._raw_client
124
+
125
+ async def metrics(
126
+ self, *, query: str, request_options: typing.Optional[RequestOptions] = None
127
+ ) -> MetricsResponse:
128
+ """
129
+ Get metrics from the Aeri project using a query object.
130
+
131
+ Consider using the [v2 metrics endpoint](/api-reference#tag/metricsv2/GET/api/public/v2/metrics) for better performance.
132
+
133
+ For more details, see the [Metrics API documentation](https://aeri.com/docs/metrics/features/metrics-api).
134
+
135
+ Parameters
136
+ ----------
137
+ query : str
138
+ JSON string containing the query parameters with the following structure:
139
+ ```json
140
+ {
141
+ "view": string, // Required. One of "traces", "observations", "scores-numeric", "scores-categorical"
142
+ "dimensions": [ // Optional. Default: []
143
+ {
144
+ "field": string // Field to group by, e.g. "name", "userId", "sessionId"
145
+ }
146
+ ],
147
+ "metrics": [ // Required. At least one metric must be provided
148
+ {
149
+ "measure": string, // What to measure, e.g. "count", "latency", "value"
150
+ "aggregation": string // How to aggregate, e.g. "count", "sum", "avg", "p95", "histogram"
151
+ }
152
+ ],
153
+ "filters": [ // Optional. Default: []
154
+ {
155
+ "column": string, // Column to filter on
156
+ "operator": string, // Operator, e.g. "=", ">", "<", "contains"
157
+ "value": any, // Value to compare against
158
+ "type": string, // Data type, e.g. "string", "number", "stringObject"
159
+ "key": string // Required only when filtering on metadata
160
+ }
161
+ ],
162
+ "timeDimension": { // Optional. Default: null. If provided, results will be grouped by time
163
+ "granularity": string // One of "minute", "hour", "day", "week", "month", "auto"
164
+ },
165
+ "fromTimestamp": string, // Required. ISO datetime string for start of time range
166
+ "toTimestamp": string, // Required. ISO datetime string for end of time range
167
+ "orderBy": [ // Optional. Default: null
168
+ {
169
+ "field": string, // Field to order by
170
+ "direction": string // "asc" or "desc"
171
+ }
172
+ ],
173
+ "config": { // Optional. Query-specific configuration
174
+ "bins": number, // Optional. Number of bins for histogram (1-100), default: 10
175
+ "row_limit": number // Optional. Row limit for results (1-1000)
176
+ }
177
+ }
178
+ ```
179
+
180
+ request_options : typing.Optional[RequestOptions]
181
+ Request-specific configuration.
182
+
183
+ Returns
184
+ -------
185
+ MetricsResponse
186
+
187
+ Examples
188
+ --------
189
+ import asyncio
190
+
191
+ from aeri import AsyncAeriAPI
192
+
193
+ client = AsyncAeriAPI(
194
+ x_aeri_sdk_name="YOUR_X_AERI_SDK_NAME",
195
+ x_aeri_sdk_version="YOUR_X_AERI_SDK_VERSION",
196
+ x_aeri_public_key="YOUR_X_AERI_PUBLIC_KEY",
197
+ username="YOUR_USERNAME",
198
+ password="YOUR_PASSWORD",
199
+ base_url="https://yourhost.com/path/to/api",
200
+ )
201
+
202
+
203
+ async def main() -> None:
204
+ await client.legacy.metrics_v1.metrics(
205
+ query="query",
206
+ )
207
+
208
+
209
+ asyncio.run(main())
210
+ """
211
+ _response = await self._raw_client.metrics(
212
+ query=query, request_options=request_options
213
+ )
214
+ return _response.data
@@ -0,0 +1,322 @@
1
+ # This file was auto-generated by Fern from our API Definition.
2
+
3
+ import typing
4
+ from json.decoder import JSONDecodeError
5
+
6
+ from ...commons.errors.access_denied_error import AccessDeniedError
7
+ from ...commons.errors.error import Error
8
+ from ...commons.errors.method_not_allowed_error import MethodNotAllowedError
9
+ from ...commons.errors.not_found_error import NotFoundError
10
+ from ...commons.errors.unauthorized_error import UnauthorizedError
11
+ from ...core.api_error import ApiError
12
+ from ...core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
13
+ from ...core.http_response import AsyncHttpResponse, HttpResponse
14
+ from ...core.pydantic_utilities import parse_obj_as
15
+ from ...core.request_options import RequestOptions
16
+ from .types.metrics_response import MetricsResponse
17
+
18
+
19
+ class RawMetricsV1Client:
20
+ def __init__(self, *, client_wrapper: SyncClientWrapper):
21
+ self._client_wrapper = client_wrapper
22
+
23
+ def metrics(
24
+ self, *, query: str, request_options: typing.Optional[RequestOptions] = None
25
+ ) -> HttpResponse[MetricsResponse]:
26
+ """
27
+ Get metrics from the Aeri project using a query object.
28
+
29
+ Consider using the [v2 metrics endpoint](/api-reference#tag/metricsv2/GET/api/public/v2/metrics) for better performance.
30
+
31
+ For more details, see the [Metrics API documentation](https://aeri.com/docs/metrics/features/metrics-api).
32
+
33
+ Parameters
34
+ ----------
35
+ query : str
36
+ JSON string containing the query parameters with the following structure:
37
+ ```json
38
+ {
39
+ "view": string, // Required. One of "traces", "observations", "scores-numeric", "scores-categorical"
40
+ "dimensions": [ // Optional. Default: []
41
+ {
42
+ "field": string // Field to group by, e.g. "name", "userId", "sessionId"
43
+ }
44
+ ],
45
+ "metrics": [ // Required. At least one metric must be provided
46
+ {
47
+ "measure": string, // What to measure, e.g. "count", "latency", "value"
48
+ "aggregation": string // How to aggregate, e.g. "count", "sum", "avg", "p95", "histogram"
49
+ }
50
+ ],
51
+ "filters": [ // Optional. Default: []
52
+ {
53
+ "column": string, // Column to filter on
54
+ "operator": string, // Operator, e.g. "=", ">", "<", "contains"
55
+ "value": any, // Value to compare against
56
+ "type": string, // Data type, e.g. "string", "number", "stringObject"
57
+ "key": string // Required only when filtering on metadata
58
+ }
59
+ ],
60
+ "timeDimension": { // Optional. Default: null. If provided, results will be grouped by time
61
+ "granularity": string // One of "minute", "hour", "day", "week", "month", "auto"
62
+ },
63
+ "fromTimestamp": string, // Required. ISO datetime string for start of time range
64
+ "toTimestamp": string, // Required. ISO datetime string for end of time range
65
+ "orderBy": [ // Optional. Default: null
66
+ {
67
+ "field": string, // Field to order by
68
+ "direction": string // "asc" or "desc"
69
+ }
70
+ ],
71
+ "config": { // Optional. Query-specific configuration
72
+ "bins": number, // Optional. Number of bins for histogram (1-100), default: 10
73
+ "row_limit": number // Optional. Row limit for results (1-1000)
74
+ }
75
+ }
76
+ ```
77
+
78
+ request_options : typing.Optional[RequestOptions]
79
+ Request-specific configuration.
80
+
81
+ Returns
82
+ -------
83
+ HttpResponse[MetricsResponse]
84
+ """
85
+ _response = self._client_wrapper.httpx_client.request(
86
+ "api/public/metrics",
87
+ method="GET",
88
+ params={
89
+ "query": query,
90
+ },
91
+ request_options=request_options,
92
+ )
93
+ try:
94
+ if 200 <= _response.status_code < 300:
95
+ _data = typing.cast(
96
+ MetricsResponse,
97
+ parse_obj_as(
98
+ type_=MetricsResponse, # type: ignore
99
+ object_=_response.json(),
100
+ ),
101
+ )
102
+ return HttpResponse(response=_response, data=_data)
103
+ if _response.status_code == 400:
104
+ raise Error(
105
+ headers=dict(_response.headers),
106
+ body=typing.cast(
107
+ typing.Any,
108
+ parse_obj_as(
109
+ type_=typing.Any, # type: ignore
110
+ object_=_response.json(),
111
+ ),
112
+ ),
113
+ )
114
+ if _response.status_code == 401:
115
+ raise UnauthorizedError(
116
+ headers=dict(_response.headers),
117
+ body=typing.cast(
118
+ typing.Any,
119
+ parse_obj_as(
120
+ type_=typing.Any, # type: ignore
121
+ object_=_response.json(),
122
+ ),
123
+ ),
124
+ )
125
+ if _response.status_code == 403:
126
+ raise AccessDeniedError(
127
+ headers=dict(_response.headers),
128
+ body=typing.cast(
129
+ typing.Any,
130
+ parse_obj_as(
131
+ type_=typing.Any, # type: ignore
132
+ object_=_response.json(),
133
+ ),
134
+ ),
135
+ )
136
+ if _response.status_code == 405:
137
+ raise MethodNotAllowedError(
138
+ headers=dict(_response.headers),
139
+ body=typing.cast(
140
+ typing.Any,
141
+ parse_obj_as(
142
+ type_=typing.Any, # type: ignore
143
+ object_=_response.json(),
144
+ ),
145
+ ),
146
+ )
147
+ if _response.status_code == 404:
148
+ raise NotFoundError(
149
+ headers=dict(_response.headers),
150
+ body=typing.cast(
151
+ typing.Any,
152
+ parse_obj_as(
153
+ type_=typing.Any, # type: ignore
154
+ object_=_response.json(),
155
+ ),
156
+ ),
157
+ )
158
+ _response_json = _response.json()
159
+ except JSONDecodeError:
160
+ raise ApiError(
161
+ status_code=_response.status_code,
162
+ headers=dict(_response.headers),
163
+ body=_response.text,
164
+ )
165
+ raise ApiError(
166
+ status_code=_response.status_code,
167
+ headers=dict(_response.headers),
168
+ body=_response_json,
169
+ )
170
+
171
+
172
+ class AsyncRawMetricsV1Client:
173
+ def __init__(self, *, client_wrapper: AsyncClientWrapper):
174
+ self._client_wrapper = client_wrapper
175
+
176
+ async def metrics(
177
+ self, *, query: str, request_options: typing.Optional[RequestOptions] = None
178
+ ) -> AsyncHttpResponse[MetricsResponse]:
179
+ """
180
+ Get metrics from the Aeri project using a query object.
181
+
182
+ Consider using the [v2 metrics endpoint](/api-reference#tag/metricsv2/GET/api/public/v2/metrics) for better performance.
183
+
184
+ For more details, see the [Metrics API documentation](https://aeri.com/docs/metrics/features/metrics-api).
185
+
186
+ Parameters
187
+ ----------
188
+ query : str
189
+ JSON string containing the query parameters with the following structure:
190
+ ```json
191
+ {
192
+ "view": string, // Required. One of "traces", "observations", "scores-numeric", "scores-categorical"
193
+ "dimensions": [ // Optional. Default: []
194
+ {
195
+ "field": string // Field to group by, e.g. "name", "userId", "sessionId"
196
+ }
197
+ ],
198
+ "metrics": [ // Required. At least one metric must be provided
199
+ {
200
+ "measure": string, // What to measure, e.g. "count", "latency", "value"
201
+ "aggregation": string // How to aggregate, e.g. "count", "sum", "avg", "p95", "histogram"
202
+ }
203
+ ],
204
+ "filters": [ // Optional. Default: []
205
+ {
206
+ "column": string, // Column to filter on
207
+ "operator": string, // Operator, e.g. "=", ">", "<", "contains"
208
+ "value": any, // Value to compare against
209
+ "type": string, // Data type, e.g. "string", "number", "stringObject"
210
+ "key": string // Required only when filtering on metadata
211
+ }
212
+ ],
213
+ "timeDimension": { // Optional. Default: null. If provided, results will be grouped by time
214
+ "granularity": string // One of "minute", "hour", "day", "week", "month", "auto"
215
+ },
216
+ "fromTimestamp": string, // Required. ISO datetime string for start of time range
217
+ "toTimestamp": string, // Required. ISO datetime string for end of time range
218
+ "orderBy": [ // Optional. Default: null
219
+ {
220
+ "field": string, // Field to order by
221
+ "direction": string // "asc" or "desc"
222
+ }
223
+ ],
224
+ "config": { // Optional. Query-specific configuration
225
+ "bins": number, // Optional. Number of bins for histogram (1-100), default: 10
226
+ "row_limit": number // Optional. Row limit for results (1-1000)
227
+ }
228
+ }
229
+ ```
230
+
231
+ request_options : typing.Optional[RequestOptions]
232
+ Request-specific configuration.
233
+
234
+ Returns
235
+ -------
236
+ AsyncHttpResponse[MetricsResponse]
237
+ """
238
+ _response = await self._client_wrapper.httpx_client.request(
239
+ "api/public/metrics",
240
+ method="GET",
241
+ params={
242
+ "query": query,
243
+ },
244
+ request_options=request_options,
245
+ )
246
+ try:
247
+ if 200 <= _response.status_code < 300:
248
+ _data = typing.cast(
249
+ MetricsResponse,
250
+ parse_obj_as(
251
+ type_=MetricsResponse, # type: ignore
252
+ object_=_response.json(),
253
+ ),
254
+ )
255
+ return AsyncHttpResponse(response=_response, data=_data)
256
+ if _response.status_code == 400:
257
+ raise Error(
258
+ headers=dict(_response.headers),
259
+ body=typing.cast(
260
+ typing.Any,
261
+ parse_obj_as(
262
+ type_=typing.Any, # type: ignore
263
+ object_=_response.json(),
264
+ ),
265
+ ),
266
+ )
267
+ if _response.status_code == 401:
268
+ raise UnauthorizedError(
269
+ headers=dict(_response.headers),
270
+ body=typing.cast(
271
+ typing.Any,
272
+ parse_obj_as(
273
+ type_=typing.Any, # type: ignore
274
+ object_=_response.json(),
275
+ ),
276
+ ),
277
+ )
278
+ if _response.status_code == 403:
279
+ raise AccessDeniedError(
280
+ headers=dict(_response.headers),
281
+ body=typing.cast(
282
+ typing.Any,
283
+ parse_obj_as(
284
+ type_=typing.Any, # type: ignore
285
+ object_=_response.json(),
286
+ ),
287
+ ),
288
+ )
289
+ if _response.status_code == 405:
290
+ raise MethodNotAllowedError(
291
+ headers=dict(_response.headers),
292
+ body=typing.cast(
293
+ typing.Any,
294
+ parse_obj_as(
295
+ type_=typing.Any, # type: ignore
296
+ object_=_response.json(),
297
+ ),
298
+ ),
299
+ )
300
+ if _response.status_code == 404:
301
+ raise NotFoundError(
302
+ headers=dict(_response.headers),
303
+ body=typing.cast(
304
+ typing.Any,
305
+ parse_obj_as(
306
+ type_=typing.Any, # type: ignore
307
+ object_=_response.json(),
308
+ ),
309
+ ),
310
+ )
311
+ _response_json = _response.json()
312
+ except JSONDecodeError:
313
+ raise ApiError(
314
+ status_code=_response.status_code,
315
+ headers=dict(_response.headers),
316
+ body=_response.text,
317
+ )
318
+ raise ApiError(
319
+ status_code=_response.status_code,
320
+ headers=dict(_response.headers),
321
+ body=_response_json,
322
+ )
@@ -0,0 +1,40 @@
1
+ # This file was auto-generated by Fern from our API Definition.
2
+
3
+ # isort: skip_file
4
+
5
+ import typing
6
+ from importlib import import_module
7
+
8
+ if typing.TYPE_CHECKING:
9
+ from .metrics_response import MetricsResponse
10
+ _dynamic_imports: typing.Dict[str, str] = {"MetricsResponse": ".metrics_response"}
11
+
12
+
13
+ def __getattr__(attr_name: str) -> typing.Any:
14
+ module_name = _dynamic_imports.get(attr_name)
15
+ if module_name is None:
16
+ raise AttributeError(
17
+ f"No {attr_name} found in _dynamic_imports for module name -> {__name__}"
18
+ )
19
+ try:
20
+ module = import_module(module_name, __package__)
21
+ if module_name == f".{attr_name}":
22
+ return module
23
+ else:
24
+ return getattr(module, attr_name)
25
+ except ImportError as e:
26
+ raise ImportError(
27
+ f"Failed to import {attr_name} from {module_name}: {e}"
28
+ ) from e
29
+ except AttributeError as e:
30
+ raise AttributeError(
31
+ f"Failed to get {attr_name} from {module_name}: {e}"
32
+ ) from e
33
+
34
+
35
+ def __dir__():
36
+ lazy_attrs = list(_dynamic_imports.keys())
37
+ return sorted(lazy_attrs)
38
+
39
+
40
+ __all__ = ["MetricsResponse"]
@@ -0,0 +1,19 @@
1
+ # This file was auto-generated by Fern from our API Definition.
2
+
3
+ import typing
4
+
5
+ import pydantic
6
+ from ....core.pydantic_utilities import UniversalBaseModel
7
+
8
+
9
+ class MetricsResponse(UniversalBaseModel):
10
+ data: typing.List[typing.Dict[str, typing.Any]] = pydantic.Field()
11
+ """
12
+ The metrics data. Each item in the list contains the metric values and dimensions requested in the query.
13
+ Format varies based on the query parameters.
14
+ Histograms will return an array with [lower, upper, height] tuples.
15
+ """
16
+
17
+ model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(
18
+ extra="allow", frozen=True
19
+ )
@@ -0,0 +1,43 @@
1
+ # This file was auto-generated by Fern from our API Definition.
2
+
3
+ # isort: skip_file
4
+
5
+ import typing
6
+ from importlib import import_module
7
+
8
+ if typing.TYPE_CHECKING:
9
+ from .types import Observations, ObservationsViews
10
+ _dynamic_imports: typing.Dict[str, str] = {
11
+ "Observations": ".types",
12
+ "ObservationsViews": ".types",
13
+ }
14
+
15
+
16
+ def __getattr__(attr_name: str) -> typing.Any:
17
+ module_name = _dynamic_imports.get(attr_name)
18
+ if module_name is None:
19
+ raise AttributeError(
20
+ f"No {attr_name} found in _dynamic_imports for module name -> {__name__}"
21
+ )
22
+ try:
23
+ module = import_module(module_name, __package__)
24
+ if module_name == f".{attr_name}":
25
+ return module
26
+ else:
27
+ return getattr(module, attr_name)
28
+ except ImportError as e:
29
+ raise ImportError(
30
+ f"Failed to import {attr_name} from {module_name}: {e}"
31
+ ) from e
32
+ except AttributeError as e:
33
+ raise AttributeError(
34
+ f"Failed to get {attr_name} from {module_name}: {e}"
35
+ ) from e
36
+
37
+
38
+ def __dir__():
39
+ lazy_attrs = list(_dynamic_imports.keys())
40
+ return sorted(lazy_attrs)
41
+
42
+
43
+ __all__ = ["Observations", "ObservationsViews"]