haiway 0.18.0__tar.gz → 0.18.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. {haiway-0.18.0 → haiway-0.18.1}/PKG-INFO +1 -1
  2. {haiway-0.18.0 → haiway-0.18.1}/junit/test-results.xml +1 -1
  3. {haiway-0.18.0 → haiway-0.18.1}/pyproject.toml +1 -1
  4. {haiway-0.18.0 → haiway-0.18.1}/src/haiway/__init__.py +6 -2
  5. {haiway-0.18.0 → haiway-0.18.1}/src/haiway/context/__init__.py +4 -0
  6. {haiway-0.18.0 → haiway-0.18.1}/src/haiway/context/access.py +37 -5
  7. {haiway-0.18.0 → haiway-0.18.1}/src/haiway/context/observability.py +75 -1
  8. {haiway-0.18.0 → haiway-0.18.1}/src/haiway/helpers/__init__.py +3 -6
  9. {haiway-0.18.0 → haiway-0.18.1}/src/haiway/helpers/observability.py +27 -2
  10. {haiway-0.18.0 → haiway-0.18.1}/src/haiway/helpers/tracing.py +13 -35
  11. {haiway-0.18.0 → haiway-0.18.1}/src/haiway/opentelemetry/observability.py +33 -1
  12. {haiway-0.18.0 → haiway-0.18.1}/uv.lock +194 -194
  13. {haiway-0.18.0 → haiway-0.18.1}/.github/workflows/ci.yml +0 -0
  14. {haiway-0.18.0 → haiway-0.18.1}/.github/workflows/publish.yml +0 -0
  15. {haiway-0.18.0 → haiway-0.18.1}/.gitignore +0 -0
  16. {haiway-0.18.0 → haiway-0.18.1}/LICENSE +0 -0
  17. {haiway-0.18.0 → haiway-0.18.1}/Makefile +0 -0
  18. {haiway-0.18.0 → haiway-0.18.1}/README.md +0 -0
  19. {haiway-0.18.0 → haiway-0.18.1}/config/pre-push +0 -0
  20. {haiway-0.18.0 → haiway-0.18.1}/examples/fastAPI/.dockerignore +0 -0
  21. {haiway-0.18.0 → haiway-0.18.1}/examples/fastAPI/Dockerfile +0 -0
  22. {haiway-0.18.0 → haiway-0.18.1}/examples/fastAPI/Makefile +0 -0
  23. {haiway-0.18.0 → haiway-0.18.1}/examples/fastAPI/README.md +0 -0
  24. {haiway-0.18.0 → haiway-0.18.1}/examples/fastAPI/config/.env.example +0 -0
  25. {haiway-0.18.0 → haiway-0.18.1}/examples/fastAPI/config/unit.json +0 -0
  26. {haiway-0.18.0 → haiway-0.18.1}/examples/fastAPI/docker-compose.yml +0 -0
  27. {haiway-0.18.0 → haiway-0.18.1}/examples/fastAPI/pyproject.toml +0 -0
  28. {haiway-0.18.0 → haiway-0.18.1}/examples/fastAPI/src/features/__int__.py +0 -0
  29. {haiway-0.18.0 → haiway-0.18.1}/examples/fastAPI/src/features/todos/__init__.py +0 -0
  30. {haiway-0.18.0 → haiway-0.18.1}/examples/fastAPI/src/features/todos/config.py +0 -0
  31. {haiway-0.18.0 → haiway-0.18.1}/examples/fastAPI/src/features/todos/state.py +0 -0
  32. {haiway-0.18.0 → haiway-0.18.1}/examples/fastAPI/src/features/todos/types.py +0 -0
  33. {haiway-0.18.0 → haiway-0.18.1}/examples/fastAPI/src/features/todos/user_tasks.py +0 -0
  34. {haiway-0.18.0 → haiway-0.18.1}/examples/fastAPI/src/integrations/__init__.py +0 -0
  35. {haiway-0.18.0 → haiway-0.18.1}/examples/fastAPI/src/integrations/postgres/__init__.py +0 -0
  36. {haiway-0.18.0 → haiway-0.18.1}/examples/fastAPI/src/integrations/postgres/client.py +0 -0
  37. {haiway-0.18.0 → haiway-0.18.1}/examples/fastAPI/src/integrations/postgres/config.py +0 -0
  38. {haiway-0.18.0 → haiway-0.18.1}/examples/fastAPI/src/integrations/postgres/state.py +0 -0
  39. {haiway-0.18.0 → haiway-0.18.1}/examples/fastAPI/src/integrations/postgres/types.py +0 -0
  40. {haiway-0.18.0 → haiway-0.18.1}/examples/fastAPI/src/migrations/__init__.py +0 -0
  41. {haiway-0.18.0 → haiway-0.18.1}/examples/fastAPI/src/migrations/__main__.py +0 -0
  42. {haiway-0.18.0 → haiway-0.18.1}/examples/fastAPI/src/migrations/postgres/__init__.py +0 -0
  43. {haiway-0.18.0 → haiway-0.18.1}/examples/fastAPI/src/migrations/postgres/execution.py +0 -0
  44. {haiway-0.18.0 → haiway-0.18.1}/examples/fastAPI/src/migrations/postgres/migration_0.py +0 -0
  45. {haiway-0.18.0 → haiway-0.18.1}/examples/fastAPI/src/migrations/postgres/types.py +0 -0
  46. {haiway-0.18.0 → haiway-0.18.1}/examples/fastAPI/src/server/__init__.py +0 -0
  47. {haiway-0.18.0 → haiway-0.18.1}/examples/fastAPI/src/server/__main__.py +0 -0
  48. {haiway-0.18.0 → haiway-0.18.1}/examples/fastAPI/src/server/application.py +0 -0
  49. {haiway-0.18.0 → haiway-0.18.1}/examples/fastAPI/src/server/config.py +0 -0
  50. {haiway-0.18.0 → haiway-0.18.1}/examples/fastAPI/src/server/middlewares/__init__.py +0 -0
  51. {haiway-0.18.0 → haiway-0.18.1}/examples/fastAPI/src/server/middlewares/context.py +0 -0
  52. {haiway-0.18.0 → haiway-0.18.1}/examples/fastAPI/src/server/routes/__init__.py +0 -0
  53. {haiway-0.18.0 → haiway-0.18.1}/examples/fastAPI/src/server/routes/technical.py +0 -0
  54. {haiway-0.18.0 → haiway-0.18.1}/examples/fastAPI/src/server/routes/todos.py +0 -0
  55. {haiway-0.18.0 → haiway-0.18.1}/examples/fastAPI/src/solutions/__init__.py +0 -0
  56. {haiway-0.18.0 → haiway-0.18.1}/examples/fastAPI/src/solutions/user_tasks/__init__.py +0 -0
  57. {haiway-0.18.0 → haiway-0.18.1}/examples/fastAPI/src/solutions/user_tasks/config.py +0 -0
  58. {haiway-0.18.0 → haiway-0.18.1}/examples/fastAPI/src/solutions/user_tasks/postgres.py +0 -0
  59. {haiway-0.18.0 → haiway-0.18.1}/examples/fastAPI/src/solutions/user_tasks/state.py +0 -0
  60. {haiway-0.18.0 → haiway-0.18.1}/examples/fastAPI/src/solutions/user_tasks/types.py +0 -0
  61. {haiway-0.18.0 → haiway-0.18.1}/examples/fastAPI/uv.lock +0 -0
  62. {haiway-0.18.0 → haiway-0.18.1}/guidelines/functionalities.md +0 -0
  63. {haiway-0.18.0 → haiway-0.18.1}/guidelines/packages.md +0 -0
  64. {haiway-0.18.0 → haiway-0.18.1}/src/haiway/context/disposables.py +0 -0
  65. {haiway-0.18.0 → haiway-0.18.1}/src/haiway/context/identifier.py +0 -0
  66. {haiway-0.18.0 → haiway-0.18.1}/src/haiway/context/state.py +0 -0
  67. {haiway-0.18.0 → haiway-0.18.1}/src/haiway/context/tasks.py +0 -0
  68. {haiway-0.18.0 → haiway-0.18.1}/src/haiway/context/types.py +0 -0
  69. {haiway-0.18.0 → haiway-0.18.1}/src/haiway/helpers/asynchrony.py +0 -0
  70. {haiway-0.18.0 → haiway-0.18.1}/src/haiway/helpers/caching.py +0 -0
  71. {haiway-0.18.0 → haiway-0.18.1}/src/haiway/helpers/retries.py +0 -0
  72. {haiway-0.18.0 → haiway-0.18.1}/src/haiway/helpers/throttling.py +0 -0
  73. {haiway-0.18.0 → haiway-0.18.1}/src/haiway/helpers/timeouted.py +0 -0
  74. {haiway-0.18.0 → haiway-0.18.1}/src/haiway/opentelemetry/__init__.py +0 -0
  75. {haiway-0.18.0 → haiway-0.18.1}/src/haiway/py.typed +0 -0
  76. {haiway-0.18.0 → haiway-0.18.1}/src/haiway/state/__init__.py +0 -0
  77. {haiway-0.18.0 → haiway-0.18.1}/src/haiway/state/attributes.py +0 -0
  78. {haiway-0.18.0 → haiway-0.18.1}/src/haiway/state/path.py +0 -0
  79. {haiway-0.18.0 → haiway-0.18.1}/src/haiway/state/requirement.py +0 -0
  80. {haiway-0.18.0 → haiway-0.18.1}/src/haiway/state/structure.py +0 -0
  81. {haiway-0.18.0 → haiway-0.18.1}/src/haiway/state/validation.py +0 -0
  82. {haiway-0.18.0 → haiway-0.18.1}/src/haiway/types/__init__.py +0 -0
  83. {haiway-0.18.0 → haiway-0.18.1}/src/haiway/types/default.py +0 -0
  84. {haiway-0.18.0 → haiway-0.18.1}/src/haiway/types/frozen.py +0 -0
  85. {haiway-0.18.0 → haiway-0.18.1}/src/haiway/types/missing.py +0 -0
  86. {haiway-0.18.0 → haiway-0.18.1}/src/haiway/utils/__init__.py +0 -0
  87. {haiway-0.18.0 → haiway-0.18.1}/src/haiway/utils/always.py +0 -0
  88. {haiway-0.18.0 → haiway-0.18.1}/src/haiway/utils/collections.py +0 -0
  89. {haiway-0.18.0 → haiway-0.18.1}/src/haiway/utils/env.py +0 -0
  90. {haiway-0.18.0 → haiway-0.18.1}/src/haiway/utils/freezing.py +0 -0
  91. {haiway-0.18.0 → haiway-0.18.1}/src/haiway/utils/logs.py +0 -0
  92. {haiway-0.18.0 → haiway-0.18.1}/src/haiway/utils/mimic.py +0 -0
  93. {haiway-0.18.0 → haiway-0.18.1}/src/haiway/utils/noop.py +0 -0
  94. {haiway-0.18.0 → haiway-0.18.1}/src/haiway/utils/queue.py +0 -0
  95. {haiway-0.18.0 → haiway-0.18.1}/src/haiway/utils/stream.py +0 -0
  96. {haiway-0.18.0 → haiway-0.18.1}/tests/__init__.py +0 -0
  97. {haiway-0.18.0 → haiway-0.18.1}/tests/test_async_queue.py +0 -0
  98. {haiway-0.18.0 → haiway-0.18.1}/tests/test_async_stream.py +0 -0
  99. {haiway-0.18.0 → haiway-0.18.1}/tests/test_attribute_path.py +0 -0
  100. {haiway-0.18.0 → haiway-0.18.1}/tests/test_auto_retry.py +0 -0
  101. {haiway-0.18.0 → haiway-0.18.1}/tests/test_cache.py +0 -0
  102. {haiway-0.18.0 → haiway-0.18.1}/tests/test_context.py +0 -0
  103. {haiway-0.18.0 → haiway-0.18.1}/tests/test_state.py +0 -0
  104. {haiway-0.18.0 → haiway-0.18.1}/tests/test_streaming.py +0 -0
  105. {haiway-0.18.0 → haiway-0.18.1}/tests/test_timeout.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: haiway
3
- Version: 0.18.0
3
+ Version: 0.18.1
4
4
  Summary: Framework for dependency injection and state management within structured concurrency model.
5
5
  Project-URL: Homepage, https://miquido.com
6
6
  Project-URL: Repository, https://github.com/miquido/haiway.git
@@ -1 +1 @@
1
- <?xml version="1.0" encoding="utf-8"?><testsuites><testsuite name="pytest" errors="0" failures="0" skipped="0" tests="88" time="1.122" timestamp="2025-05-12T14:08:49.319975+00:00" hostname="pkrvmberfyhpb9w"><testcase classname="tests.test_async_queue" name="test_fails_when_stream_fails" time="0.001" /><testcase classname="tests.test_async_queue" name="test_cancels_when_iteration_cancels" time="0.001" /><testcase classname="tests.test_async_queue" name="test_ends_when_stream_ends" time="0.001" /><testcase classname="tests.test_async_queue" name="test_buffers_values_when_not_reading" time="0.001" /><testcase classname="tests.test_async_queue" name="test_delivers_buffer_when_streaming_fails" time="0.001" /><testcase classname="tests.test_async_queue" name="test_delivers_updates_when_sending" time="0.001" /><testcase classname="tests.test_async_queue" name="test_fails_when_sending_to_finished" time="0.001" /><testcase classname="tests.test_async_queue" name="test_ignores_when_finishing_when_finished" time="0.001" /><testcase classname="tests.test_async_stream" name="test_fails_when_stream_fails" time="0.001" /><testcase classname="tests.test_async_stream" name="test_cancels_when_iteration_cancels" time="0.001" /><testcase classname="tests.test_async_stream" name="test_ends_when_stream_ends" time="0.001" /><testcase classname="tests.test_async_stream" name="test_finishes_without_buffer" time="0.001" /><testcase classname="tests.test_async_stream" name="test_fails_without_buffer" time="0.001" /><testcase classname="tests.test_async_stream" name="test_delivers_updates_when_sending" time="0.001" /><testcase classname="tests.test_async_stream" name="test_ignores_when_sending_to_finished" time="0.001" /><testcase classname="tests.test_async_stream" name="test_ignores_when_sending_to_failed" time="0.001" /><testcase classname="tests.test_async_stream" name="test_ignores_when_finishing_when_finished" time="0.001" /><testcase classname="tests.test_async_stream" name="test_delivers_all_when_sending_async" time="0.001" /><testcase classname="tests.test_attribute_path" name="test_id_path_points_to_self" time="0.000" /><testcase classname="tests.test_attribute_path" name="test_attribute_path_points_to_attribute" time="0.000" /><testcase classname="tests.test_attribute_path" name="test_nested_attribute_path_points_to_nested_attribute" time="0.000" /><testcase classname="tests.test_attribute_path" name="test_recursive_attribute_path_points_to_attribute" time="0.000" /><testcase classname="tests.test_attribute_path" name="test_list_item_path_points_to_item" time="0.000" /><testcase classname="tests.test_attribute_path" name="test_tuple_item_path_points_to_item" time="0.000" /><testcase classname="tests.test_attribute_path" name="test_mixed_tuple_item_path_points_to_item" time="0.000" /><testcase classname="tests.test_attribute_path" name="test_dict_item_path_points_to_item" time="0.000" /><testcase classname="tests.test_attribute_path" name="test_id_path_set_updates_self" time="0.000" /><testcase classname="tests.test_attribute_path" name="test_attribute_path_set_updates_attribute" time="0.000" /><testcase classname="tests.test_attribute_path" name="test_nested_attribute_path_set_updates_nested_attribute" time="0.000" /><testcase classname="tests.test_attribute_path" name="test_recursive_attribute_set_updates_attribute" time="0.000" /><testcase classname="tests.test_attribute_path" name="test_list_item_path_set_updates_item" time="0.000" /><testcase classname="tests.test_attribute_path" name="test_tuple_item_path_set_updates_item" time="0.000" /><testcase classname="tests.test_attribute_path" name="test_mixed_tuple_item_set_updates_item" time="0.000" /><testcase classname="tests.test_attribute_path" name="test_dict_item_path_set_updates_item" time="0.000" /><testcase classname="tests.test_auto_retry" name="test_returns_value_without_errors" time="0.001" /><testcase classname="tests.test_auto_retry" name="test_retries_with_errors" time="0.001" /><testcase classname="tests.test_auto_retry" name="test_logs_issue_with_errors" time="0.007" /><testcase classname="tests.test_auto_retry" name="test_fails_with_exceeding_errors" time="0.001" /><testcase classname="tests.test_auto_retry" name="test_fails_with_cancellation" time="0.001" /><testcase classname="tests.test_auto_retry" name="test_retries_with_selected_errors" time="0.001" /><testcase classname="tests.test_auto_retry" name="test_fails_with_not_selected_errors" time="0.001" /><testcase classname="tests.test_auto_retry" name="test_async_returns_value_without_errors" time="0.001" /><testcase classname="tests.test_auto_retry" name="test_async_retries_with_errors" time="0.001" /><testcase classname="tests.test_auto_retry" name="test_async_fails_with_exceeding_errors" time="0.001" /><testcase classname="tests.test_auto_retry" name="test_async_fails_with_cancellation" time="0.001" /><testcase classname="tests.test_auto_retry" name="test_async_fails_when_cancelled" time="0.021" /><testcase classname="tests.test_auto_retry" name="test_async_uses_delay_with_errors" time="0.102" /><testcase classname="tests.test_auto_retry" name="test_async_uses_computed_delay_with_errors" time="0.107" /><testcase classname="tests.test_auto_retry" name="test_async_logs_issue_with_errors" time="0.001" /><testcase classname="tests.test_auto_retry" name="test_async_retries_with_selected_errors" time="0.001" /><testcase classname="tests.test_auto_retry" name="test_async_fails_with_not_selected_errors" time="0.001" /><testcase classname="tests.test_cache" name="test_returns_cache_value_with_same_argument" time="0.001" /><testcase classname="tests.test_cache" name="test_returns_fresh_value_with_different_argument" time="0.001" /><testcase classname="tests.test_cache" name="test_returns_fresh_value_with_limit_exceed" time="0.001" /><testcase classname="tests.test_cache" name="test_returns_same_value_with_repeating_argument" time="0.001" /><testcase classname="tests.test_cache" name="test_fails_with_error" time="0.001" /><testcase classname="tests.test_cache" name="test_returns_fresh_value_with_expiration_time_exceed" time="0.021" /><testcase classname="tests.test_cache" name="test_async_returns_cache_value_with_same_argument" time="0.001" /><testcase classname="tests.test_cache" name="test_async_returns_fresh_value_with_different_argument" time="0.001" /><testcase classname="tests.test_cache" name="test_async_returns_fresh_value_with_limit_exceed" time="0.001" /><testcase classname="tests.test_cache" name="test_async_returns_same_value_with_repeating_argument" time="0.001" /><testcase classname="tests.test_cache" name="test_async_returns_fresh_value_with_expiration_time_exceed" time="0.021" /><testcase classname="tests.test_cache" name="test_async_cancel_waiting_does_not_cancel_task" time="0.502" /><testcase classname="tests.test_cache" name="test_async_expiration_does_not_cancel_task" time="0.021" /><testcase classname="tests.test_cache" name="test_async_fails_with_error" time="0.001" /><testcase classname="tests.test_context" name="test_state_is_available_according_to_context" time="0.001" /><testcase classname="tests.test_context" name="test_state_update_updates_local_context" time="0.001" /><testcase classname="tests.test_context" name="test_exceptions_are_propagated" time="0.001" /><testcase classname="tests.test_state" name="test_basic_initializes_with_arguments" time="0.002" /><testcase classname="tests.test_state" name="test_basic_initializes_with_defaults" time="0.001" /><testcase classname="tests.test_state" name="test_basic_equals_checks_properties" time="0.000" /><testcase classname="tests.test_state" name="test_basic_initializes_with_arguments_and_defaults" time="0.000" /><testcase classname="tests.test_state" name="test_parametrized_initializes_with_proper_parameters" time="0.000" /><testcase classname="tests.test_state" name="test_nested_initializes_with_proper_arguments" time="0.001" /><testcase classname="tests.test_state" name="test_dict_skips_missing_properties" time="0.000" /><testcase classname="tests.test_state" name="test_initialization_allows_missing_properties" time="0.000" /><testcase classname="tests.test_state" name="test_generic_subtypes_validation" time="0.002" /><testcase classname="tests.test_state" name="test_copying_leaves_same_object" time="0.000" /><testcase classname="tests.test_streaming" name="test_fails_when_generator_fails" time="0.001" /><testcase classname="tests.test_streaming" name="test_cancels_when_iteration_cancels" time="0.001" /><testcase classname="tests.test_streaming" name="test_ends_when_generator_ends" time="0.001" /><testcase classname="tests.test_streaming" name="test_delivers_updates_when_generating" time="0.001" /><testcase classname="tests.test_streaming" name="test_streaming_context_variables_access_is_preserved" time="0.001" /><testcase classname="tests.test_streaming" name="test_nested_streaming_streams_correctly" time="0.001" /><testcase classname="tests.test_timeout" name="test_returns_result_when_returning_value" time="0.001" /><testcase classname="tests.test_timeout" name="test_raises_with_error" time="0.001" /><testcase classname="tests.test_timeout" name="test_raises_with_cancel" time="0.011" /><testcase classname="tests.test_timeout" name="test_raises_with_timeout" time="0.011" /></testsuite></testsuites>
1
+ <?xml version="1.0" encoding="utf-8"?><testsuites><testsuite name="pytest" errors="0" failures="0" skipped="0" tests="88" time="1.104" timestamp="2025-05-12T15:34:00.085428+00:00" hostname="pkrvmberfyhpb9w"><testcase classname="tests.test_async_queue" name="test_fails_when_stream_fails" time="0.001" /><testcase classname="tests.test_async_queue" name="test_cancels_when_iteration_cancels" time="0.001" /><testcase classname="tests.test_async_queue" name="test_ends_when_stream_ends" time="0.001" /><testcase classname="tests.test_async_queue" name="test_buffers_values_when_not_reading" time="0.001" /><testcase classname="tests.test_async_queue" name="test_delivers_buffer_when_streaming_fails" time="0.001" /><testcase classname="tests.test_async_queue" name="test_delivers_updates_when_sending" time="0.001" /><testcase classname="tests.test_async_queue" name="test_fails_when_sending_to_finished" time="0.001" /><testcase classname="tests.test_async_queue" name="test_ignores_when_finishing_when_finished" time="0.001" /><testcase classname="tests.test_async_stream" name="test_fails_when_stream_fails" time="0.001" /><testcase classname="tests.test_async_stream" name="test_cancels_when_iteration_cancels" time="0.001" /><testcase classname="tests.test_async_stream" name="test_ends_when_stream_ends" time="0.001" /><testcase classname="tests.test_async_stream" name="test_finishes_without_buffer" time="0.001" /><testcase classname="tests.test_async_stream" name="test_fails_without_buffer" time="0.001" /><testcase classname="tests.test_async_stream" name="test_delivers_updates_when_sending" time="0.001" /><testcase classname="tests.test_async_stream" name="test_ignores_when_sending_to_finished" time="0.001" /><testcase classname="tests.test_async_stream" name="test_ignores_when_sending_to_failed" time="0.001" /><testcase classname="tests.test_async_stream" name="test_ignores_when_finishing_when_finished" time="0.001" /><testcase classname="tests.test_async_stream" name="test_delivers_all_when_sending_async" time="0.001" /><testcase classname="tests.test_attribute_path" name="test_id_path_points_to_self" time="0.000" /><testcase classname="tests.test_attribute_path" name="test_attribute_path_points_to_attribute" time="0.000" /><testcase classname="tests.test_attribute_path" name="test_nested_attribute_path_points_to_nested_attribute" time="0.000" /><testcase classname="tests.test_attribute_path" name="test_recursive_attribute_path_points_to_attribute" time="0.000" /><testcase classname="tests.test_attribute_path" name="test_list_item_path_points_to_item" time="0.000" /><testcase classname="tests.test_attribute_path" name="test_tuple_item_path_points_to_item" time="0.000" /><testcase classname="tests.test_attribute_path" name="test_mixed_tuple_item_path_points_to_item" time="0.000" /><testcase classname="tests.test_attribute_path" name="test_dict_item_path_points_to_item" time="0.000" /><testcase classname="tests.test_attribute_path" name="test_id_path_set_updates_self" time="0.000" /><testcase classname="tests.test_attribute_path" name="test_attribute_path_set_updates_attribute" time="0.000" /><testcase classname="tests.test_attribute_path" name="test_nested_attribute_path_set_updates_nested_attribute" time="0.000" /><testcase classname="tests.test_attribute_path" name="test_recursive_attribute_set_updates_attribute" time="0.000" /><testcase classname="tests.test_attribute_path" name="test_list_item_path_set_updates_item" time="0.000" /><testcase classname="tests.test_attribute_path" name="test_tuple_item_path_set_updates_item" time="0.000" /><testcase classname="tests.test_attribute_path" name="test_mixed_tuple_item_set_updates_item" time="0.000" /><testcase classname="tests.test_attribute_path" name="test_dict_item_path_set_updates_item" time="0.000" /><testcase classname="tests.test_auto_retry" name="test_returns_value_without_errors" time="0.001" /><testcase classname="tests.test_auto_retry" name="test_retries_with_errors" time="0.001" /><testcase classname="tests.test_auto_retry" name="test_logs_issue_with_errors" time="0.008" /><testcase classname="tests.test_auto_retry" name="test_fails_with_exceeding_errors" time="0.001" /><testcase classname="tests.test_auto_retry" name="test_fails_with_cancellation" time="0.001" /><testcase classname="tests.test_auto_retry" name="test_retries_with_selected_errors" time="0.001" /><testcase classname="tests.test_auto_retry" name="test_fails_with_not_selected_errors" time="0.001" /><testcase classname="tests.test_auto_retry" name="test_async_returns_value_without_errors" time="0.001" /><testcase classname="tests.test_auto_retry" name="test_async_retries_with_errors" time="0.001" /><testcase classname="tests.test_auto_retry" name="test_async_fails_with_exceeding_errors" time="0.001" /><testcase classname="tests.test_auto_retry" name="test_async_fails_with_cancellation" time="0.001" /><testcase classname="tests.test_auto_retry" name="test_async_fails_when_cancelled" time="0.021" /><testcase classname="tests.test_auto_retry" name="test_async_uses_delay_with_errors" time="0.101" /><testcase classname="tests.test_auto_retry" name="test_async_uses_computed_delay_with_errors" time="0.106" /><testcase classname="tests.test_auto_retry" name="test_async_logs_issue_with_errors" time="0.001" /><testcase classname="tests.test_auto_retry" name="test_async_retries_with_selected_errors" time="0.001" /><testcase classname="tests.test_auto_retry" name="test_async_fails_with_not_selected_errors" time="0.001" /><testcase classname="tests.test_cache" name="test_returns_cache_value_with_same_argument" time="0.000" /><testcase classname="tests.test_cache" name="test_returns_fresh_value_with_different_argument" time="0.000" /><testcase classname="tests.test_cache" name="test_returns_fresh_value_with_limit_exceed" time="0.000" /><testcase classname="tests.test_cache" name="test_returns_same_value_with_repeating_argument" time="0.000" /><testcase classname="tests.test_cache" name="test_fails_with_error" time="0.000" /><testcase classname="tests.test_cache" name="test_returns_fresh_value_with_expiration_time_exceed" time="0.021" /><testcase classname="tests.test_cache" name="test_async_returns_cache_value_with_same_argument" time="0.001" /><testcase classname="tests.test_cache" name="test_async_returns_fresh_value_with_different_argument" time="0.001" /><testcase classname="tests.test_cache" name="test_async_returns_fresh_value_with_limit_exceed" time="0.001" /><testcase classname="tests.test_cache" name="test_async_returns_same_value_with_repeating_argument" time="0.001" /><testcase classname="tests.test_cache" name="test_async_returns_fresh_value_with_expiration_time_exceed" time="0.021" /><testcase classname="tests.test_cache" name="test_async_cancel_waiting_does_not_cancel_task" time="0.502" /><testcase classname="tests.test_cache" name="test_async_expiration_does_not_cancel_task" time="0.021" /><testcase classname="tests.test_cache" name="test_async_fails_with_error" time="0.001" /><testcase classname="tests.test_context" name="test_state_is_available_according_to_context" time="0.001" /><testcase classname="tests.test_context" name="test_state_update_updates_local_context" time="0.001" /><testcase classname="tests.test_context" name="test_exceptions_are_propagated" time="0.001" /><testcase classname="tests.test_state" name="test_basic_initializes_with_arguments" time="0.002" /><testcase classname="tests.test_state" name="test_basic_initializes_with_defaults" time="0.001" /><testcase classname="tests.test_state" name="test_basic_equals_checks_properties" time="0.000" /><testcase classname="tests.test_state" name="test_basic_initializes_with_arguments_and_defaults" time="0.000" /><testcase classname="tests.test_state" name="test_parametrized_initializes_with_proper_parameters" time="0.000" /><testcase classname="tests.test_state" name="test_nested_initializes_with_proper_arguments" time="0.001" /><testcase classname="tests.test_state" name="test_dict_skips_missing_properties" time="0.000" /><testcase classname="tests.test_state" name="test_initialization_allows_missing_properties" time="0.000" /><testcase classname="tests.test_state" name="test_generic_subtypes_validation" time="0.002" /><testcase classname="tests.test_state" name="test_copying_leaves_same_object" time="0.000" /><testcase classname="tests.test_streaming" name="test_fails_when_generator_fails" time="0.001" /><testcase classname="tests.test_streaming" name="test_cancels_when_iteration_cancels" time="0.001" /><testcase classname="tests.test_streaming" name="test_ends_when_generator_ends" time="0.001" /><testcase classname="tests.test_streaming" name="test_delivers_updates_when_generating" time="0.001" /><testcase classname="tests.test_streaming" name="test_streaming_context_variables_access_is_preserved" time="0.001" /><testcase classname="tests.test_streaming" name="test_nested_streaming_streams_correctly" time="0.001" /><testcase classname="tests.test_timeout" name="test_returns_result_when_returning_value" time="0.001" /><testcase classname="tests.test_timeout" name="test_raises_with_error" time="0.001" /><testcase classname="tests.test_timeout" name="test_raises_with_cancel" time="0.011" /><testcase classname="tests.test_timeout" name="test_raises_with_timeout" time="0.011" /></testsuite></testsuites>
@@ -5,7 +5,7 @@ build-backend = "hatchling.build"
5
5
  [project]
6
6
  name = "haiway"
7
7
  description = "Framework for dependency injection and state management within structured concurrency model."
8
- version = "0.18.0"
8
+ version = "0.18.1"
9
9
  readme = "README.md"
10
10
  maintainers = [
11
11
  { name = "Kacper Kaliński", email = "kacper.kalinski@miquido.com" },
@@ -4,6 +4,8 @@ from haiway.context import (
4
4
  MissingContext,
5
5
  MissingState,
6
6
  Observability,
7
+ ObservabilityAttribute,
8
+ ObservabilityAttributesRecording,
7
9
  ObservabilityContext,
8
10
  ObservabilityEventRecording,
9
11
  ObservabilityLevel,
@@ -17,7 +19,7 @@ from haiway.context import (
17
19
  ctx,
18
20
  )
19
21
  from haiway.helpers import (
20
- ArgumentsTrace,
22
+ LoggerObservability,
21
23
  ResultTrace,
22
24
  asynchronous,
23
25
  cache,
@@ -63,7 +65,6 @@ from haiway.utils import (
63
65
 
64
66
  __all__ = (
65
67
  "MISSING",
66
- "ArgumentsTrace",
67
68
  "AsyncQueue",
68
69
  "AsyncStream",
69
70
  "AttributePath",
@@ -72,10 +73,13 @@ __all__ = (
72
73
  "DefaultValue",
73
74
  "Disposable",
74
75
  "Disposables",
76
+ "LoggerObservability",
75
77
  "Missing",
76
78
  "MissingContext",
77
79
  "MissingState",
78
80
  "Observability",
81
+ "ObservabilityAttribute",
82
+ "ObservabilityAttributesRecording",
79
83
  "ObservabilityContext",
80
84
  "ObservabilityEventRecording",
81
85
  "ObservabilityLevel",
@@ -3,6 +3,8 @@ from haiway.context.disposables import Disposable, Disposables
3
3
  from haiway.context.identifier import ScopeIdentifier
4
4
  from haiway.context.observability import (
5
5
  Observability,
6
+ ObservabilityAttribute,
7
+ ObservabilityAttributesRecording,
6
8
  ObservabilityContext,
7
9
  ObservabilityEventRecording,
8
10
  ObservabilityLevel,
@@ -20,6 +22,8 @@ __all__ = (
20
22
  "MissingContext",
21
23
  "MissingState",
22
24
  "Observability",
25
+ "ObservabilityAttribute",
26
+ "ObservabilityAttributesRecording",
23
27
  "ObservabilityContext",
24
28
  "ObservabilityEventRecording",
25
29
  "ObservabilityLevel",
@@ -18,7 +18,12 @@ from typing import Any, final, overload
18
18
 
19
19
  from haiway.context.disposables import Disposable, Disposables
20
20
  from haiway.context.identifier import ScopeIdentifier
21
- from haiway.context.observability import Observability, ObservabilityContext, ObservabilityLevel
21
+ from haiway.context.observability import (
22
+ Observability,
23
+ ObservabilityAttribute,
24
+ ObservabilityContext,
25
+ ObservabilityLevel,
26
+ )
22
27
  from haiway.context.state import ScopeState, StateContext
23
28
  from haiway.context.tasks import TaskGroupContext
24
29
  from haiway.state import State
@@ -462,6 +467,7 @@ class ctx:
462
467
  /,
463
468
  *args: Any,
464
469
  exception: BaseException | None = None,
470
+ **extra: Any,
465
471
  ) -> None:
466
472
  """
467
473
  Log using ERROR level within current scope context. When there is no current scope\
@@ -488,6 +494,7 @@ class ctx:
488
494
  message,
489
495
  *args,
490
496
  exception=exception,
497
+ **extra,
491
498
  )
492
499
 
493
500
  @staticmethod
@@ -496,6 +503,7 @@ class ctx:
496
503
  /,
497
504
  *args: Any,
498
505
  exception: Exception | None = None,
506
+ **extra: Any,
499
507
  ) -> None:
500
508
  """
501
509
  Log using WARNING level within current scope context. When there is no current scope\
@@ -522,6 +530,7 @@ class ctx:
522
530
  message,
523
531
  *args,
524
532
  exception=exception,
533
+ **extra,
525
534
  )
526
535
 
527
536
  @staticmethod
@@ -529,6 +538,7 @@ class ctx:
529
538
  message: str,
530
539
  /,
531
540
  *args: Any,
541
+ **extra: Any,
532
542
  ) -> None:
533
543
  """
534
544
  Log using INFO level within current scope context. When there is no current scope\
@@ -552,6 +562,7 @@ class ctx:
552
562
  message,
553
563
  *args,
554
564
  exception=None,
565
+ **extra,
555
566
  )
556
567
 
557
568
  @staticmethod
@@ -560,6 +571,7 @@ class ctx:
560
571
  /,
561
572
  *args: Any,
562
573
  exception: Exception | None = None,
574
+ **extra: Any,
563
575
  ) -> None:
564
576
  """
565
577
  Log using DEBUG level within current scope context. When there is no current scope\
@@ -582,10 +594,7 @@ class ctx:
582
594
  """
583
595
 
584
596
  ObservabilityContext.record_log(
585
- ObservabilityLevel.DEBUG,
586
- message,
587
- *args,
588
- exception=exception,
597
+ ObservabilityLevel.DEBUG, message, *args, exception=exception, **extra
589
598
  )
590
599
 
591
600
  @staticmethod
@@ -594,6 +603,7 @@ class ctx:
594
603
  /,
595
604
  *,
596
605
  level: ObservabilityLevel = ObservabilityLevel.INFO,
606
+ **extra: Any,
597
607
  ) -> None:
598
608
  """
599
609
  Record event within current scope context.
@@ -611,6 +621,7 @@ class ctx:
611
621
  ObservabilityContext.record_event(
612
622
  event,
613
623
  level=level,
624
+ **extra,
614
625
  )
615
626
 
616
627
  @staticmethod
@@ -620,6 +631,7 @@ class ctx:
620
631
  *,
621
632
  value: float | int,
622
633
  unit: str | None = None,
634
+ **extra: Any,
623
635
  ) -> None:
624
636
  """
625
637
  Record metric within current scope context.
@@ -642,4 +654,24 @@ class ctx:
642
654
  metric,
643
655
  value=value,
644
656
  unit=unit,
657
+ **extra,
658
+ )
659
+
660
+ @staticmethod
661
+ def attributes(**attributes: ObservabilityAttribute) -> None:
662
+ """
663
+ Record attributes within current scope context.
664
+
665
+ Parameters
666
+ ----------
667
+ **attributes: ObservabilityAttribute,
668
+ attributes to be recorded within current context.
669
+
670
+ Returns
671
+ -------
672
+ None
673
+ """
674
+
675
+ ObservabilityContext.record_attributes(
676
+ **attributes,
645
677
  )
@@ -1,3 +1,4 @@
1
+ from collections.abc import Sequence
1
2
  from contextvars import ContextVar, Token
2
3
  from enum import IntEnum
3
4
  from logging import DEBUG as DEBUG_LOGGING
@@ -19,6 +20,8 @@ __all__ = (
19
20
  "INFO",
20
21
  "WARNING",
21
22
  "Observability",
23
+ "ObservabilityAttribute",
24
+ "ObservabilityAttributesRecording",
22
25
  "ObservabilityContext",
23
26
  "ObservabilityEventRecording",
24
27
  "ObservabilityLevel",
@@ -42,6 +45,10 @@ WARNING: Final[int] = ObservabilityLevel.WARNING
42
45
  INFO: Final[int] = ObservabilityLevel.INFO
43
46
  DEBUG: Final[int] = ObservabilityLevel.DEBUG
44
47
 
48
+ type ObservabilityAttribute = (
49
+ Sequence[str] | Sequence[float] | Sequence[int] | Sequence[bool] | str | float | int | bool
50
+ )
51
+
45
52
 
46
53
  @runtime_checkable
47
54
  class ObservabilityLogRecording(Protocol):
@@ -53,6 +60,7 @@ class ObservabilityLogRecording(Protocol):
53
60
  message: str,
54
61
  *args: Any,
55
62
  exception: BaseException | None,
63
+ **extra: Any,
56
64
  ) -> None: ...
57
65
 
58
66
 
@@ -65,6 +73,7 @@ class ObservabilityEventRecording(Protocol):
65
73
  *,
66
74
  level: ObservabilityLevel,
67
75
  event: State,
76
+ **extra: Any,
68
77
  ) -> None: ...
69
78
 
70
79
 
@@ -78,6 +87,17 @@ class ObservabilityMetricRecording(Protocol):
78
87
  metric: str,
79
88
  value: float | int,
80
89
  unit: str | None,
90
+ **extra: Any,
91
+ ) -> None: ...
92
+
93
+
94
+ @runtime_checkable
95
+ class ObservabilityAttributesRecording(Protocol):
96
+ def __call__(
97
+ self,
98
+ scope: ScopeIdentifier,
99
+ /,
100
+ **attributes: ObservabilityAttribute,
81
101
  ) -> None: ...
82
102
 
83
103
 
@@ -103,6 +123,7 @@ class ObservabilityScopeExiting(Protocol):
103
123
 
104
124
  class Observability: # avoiding State inheritance to prevent propagation as scope state
105
125
  __slots__ = (
126
+ "attributes_recording",
106
127
  "event_recording",
107
128
  "log_recording",
108
129
  "metric_recording",
@@ -115,6 +136,7 @@ class Observability: # avoiding State inheritance to prevent propagation as sco
115
136
  log_recording: ObservabilityLogRecording,
116
137
  metric_recording: ObservabilityMetricRecording,
117
138
  event_recording: ObservabilityEventRecording,
139
+ attributes_recording: ObservabilityAttributesRecording,
118
140
  scope_entering: ObservabilityScopeEntering,
119
141
  scope_exiting: ObservabilityScopeExiting,
120
142
  ) -> None:
@@ -136,6 +158,13 @@ class Observability: # avoiding State inheritance to prevent propagation as sco
136
158
  "event_recording",
137
159
  event_recording,
138
160
  )
161
+ self.attributes_recording: ObservabilityAttributesRecording
162
+ object.__setattr__(
163
+ self,
164
+ "attributes_recording",
165
+ attributes_recording,
166
+ )
167
+
139
168
  self.scope_entering: ObservabilityScopeEntering
140
169
  object.__setattr__(
141
170
  self,
@@ -180,6 +209,7 @@ def _logger_observability(
180
209
  message: str,
181
210
  *args: Any,
182
211
  exception: BaseException | None,
212
+ **extra: Any,
183
213
  ) -> None:
184
214
  logger.log(
185
215
  level,
@@ -194,6 +224,7 @@ def _logger_observability(
194
224
  *,
195
225
  level: ObservabilityLevel,
196
226
  event: State,
227
+ **extra: Any,
197
228
  ) -> None:
198
229
  logger.log(
199
230
  level,
@@ -207,10 +238,25 @@ def _logger_observability(
207
238
  metric: str,
208
239
  value: float | int,
209
240
  unit: str | None,
241
+ **extra: Any,
242
+ ) -> None:
243
+ logger.log(
244
+ INFO,
245
+ f"{scope.unique_name} Recorded metric: {metric}={value}{unit or ''}",
246
+ )
247
+
248
+ def attributes_recording(
249
+ scope: ScopeIdentifier,
250
+ /,
251
+ **attributes: ObservabilityAttribute,
210
252
  ) -> None:
253
+ if not attributes:
254
+ return
255
+
211
256
  logger.log(
212
257
  INFO,
213
- f"{scope.unique_name} Recorded metric - {metric}:{value}{unit or ''}",
258
+ f"{scope.unique_name} Recorded attributes:"
259
+ f"\n{'\n'.join([f'{k}: {v}' for k, v in attributes.items()])}",
214
260
  )
215
261
 
216
262
  def scope_entering[Metric: State](
@@ -238,6 +284,7 @@ def _logger_observability(
238
284
  log_recording=log_recording,
239
285
  event_recording=event_recording,
240
286
  metric_recording=metric_recording,
287
+ attributes_recording=attributes_recording,
241
288
  scope_entering=scope_entering,
242
289
  scope_exiting=scope_exiting,
243
290
  )
@@ -302,6 +349,7 @@ class ObservabilityContext:
302
349
  /,
303
350
  *args: Any,
304
351
  exception: BaseException | None,
352
+ **extra: Any,
305
353
  ) -> None:
306
354
  try: # catch exceptions - we don't wan't to blow up on observability
307
355
  context: Self = cls._context.get()
@@ -313,6 +361,7 @@ class ObservabilityContext:
313
361
  message,
314
362
  *args,
315
363
  exception=exception,
364
+ **extra,
316
365
  )
317
366
 
318
367
  except LookupError:
@@ -330,6 +379,7 @@ class ObservabilityContext:
330
379
  /,
331
380
  *,
332
381
  level: ObservabilityLevel,
382
+ **extra: Any,
333
383
  ) -> None:
334
384
  try: # catch exceptions - we don't wan't to blow up on observability
335
385
  context: Self = cls._context.get()
@@ -339,6 +389,7 @@ class ObservabilityContext:
339
389
  context._scope,
340
390
  level=level,
341
391
  event=event,
392
+ **extra,
342
393
  )
343
394
 
344
395
  except Exception as exc:
@@ -356,6 +407,7 @@ class ObservabilityContext:
356
407
  *,
357
408
  value: float | int,
358
409
  unit: str | None,
410
+ **extra: Any,
359
411
  ) -> None:
360
412
  try: # catch exceptions - we don't wan't to blow up on observability
361
413
  context: Self = cls._context.get()
@@ -366,6 +418,7 @@ class ObservabilityContext:
366
418
  metric=metric,
367
419
  value=value,
368
420
  unit=unit,
421
+ **extra,
369
422
  )
370
423
 
371
424
  except Exception as exc:
@@ -375,6 +428,27 @@ class ObservabilityContext:
375
428
  exception=exc,
376
429
  )
377
430
 
431
+ @classmethod
432
+ def record_attributes(
433
+ cls,
434
+ **attributes: ObservabilityAttribute,
435
+ ) -> None:
436
+ try: # catch exceptions - we don't wan't to blow up on observability
437
+ context: Self = cls._context.get()
438
+
439
+ if context.observability is not None:
440
+ context.observability.attributes_recording(
441
+ context._scope,
442
+ **attributes,
443
+ )
444
+
445
+ except Exception as exc:
446
+ cls.record_log(
447
+ ERROR,
448
+ f"Failed to record attributes: {attributes}",
449
+ exception=exc,
450
+ )
451
+
378
452
  __slots__ = (
379
453
  "_scope",
380
454
  "_token",
@@ -1,19 +1,16 @@
1
1
  from haiway.helpers.asynchrony import asynchronous, wrap_async
2
2
  from haiway.helpers.caching import CacheMakeKey, CacheRead, CacheWrite, cache
3
+ from haiway.helpers.observability import LoggerObservability
3
4
  from haiway.helpers.retries import retry
4
5
  from haiway.helpers.throttling import throttle
5
6
  from haiway.helpers.timeouted import timeout
6
- from haiway.helpers.tracing import (
7
- ArgumentsTrace,
8
- ResultTrace,
9
- traced,
10
- )
7
+ from haiway.helpers.tracing import ResultTrace, traced
11
8
 
12
9
  __all__ = (
13
- "ArgumentsTrace",
14
10
  "CacheMakeKey",
15
11
  "CacheRead",
16
12
  "CacheWrite",
13
+ "LoggerObservability",
17
14
  "ResultTrace",
18
15
  "asynchronous",
19
16
  "cache",
@@ -1,3 +1,4 @@
1
+ from collections.abc import Sequence
1
2
  from logging import Logger
2
3
  from time import monotonic
3
4
  from typing import Any
@@ -60,7 +61,7 @@ class ScopeStore:
60
61
  return True # successfully completed
61
62
 
62
63
 
63
- def LoggerObservability( # noqa: C901
64
+ def LoggerObservability( # noqa: C901, PLR0915
64
65
  logger: Logger,
65
66
  /,
66
67
  *,
@@ -76,6 +77,7 @@ def LoggerObservability( # noqa: C901
76
77
  message: str,
77
78
  *args: Any,
78
79
  exception: BaseException | None,
80
+ **extra: Any,
79
81
  ) -> None:
80
82
  assert root_scope is not None # nosec: B101
81
83
  assert scope.scope_id in scopes # nosec: B101
@@ -93,6 +95,7 @@ def LoggerObservability( # noqa: C901
93
95
  *,
94
96
  level: ObservabilityLevel,
95
97
  event: State,
98
+ **extra: Any,
96
99
  ) -> None:
97
100
  assert root_scope is not None # nosec: B101
98
101
  assert scope.scope_id in scopes # nosec: B101
@@ -113,11 +116,12 @@ def LoggerObservability( # noqa: C901
113
116
  metric: str,
114
117
  value: float | int,
115
118
  unit: str | None,
119
+ **extra: Any,
116
120
  ) -> None:
117
121
  assert root_scope is not None # nosec: B101
118
122
  assert scope.scope_id in scopes # nosec: B101
119
123
 
120
- metric_str: str = f"Metric - {metric}:{value}{unit or ''}"
124
+ metric_str: str = f"Metric: {metric}={value}{unit or ''}"
121
125
  if summarize_context: # store only for summary
122
126
  scopes[scope.scope_id].store.append(metric_str)
123
127
 
@@ -126,6 +130,26 @@ def LoggerObservability( # noqa: C901
126
130
  f"{scope.unique_name} {metric_str}",
127
131
  )
128
132
 
133
+ def attributes_recording(
134
+ scope: ScopeIdentifier,
135
+ /,
136
+ **attributes: Sequence[str | float | int] | str | float | int,
137
+ ) -> None:
138
+ if not attributes:
139
+ return
140
+
141
+ attributes_str: str = (
142
+ f"{scope.unique_name} Attributes:"
143
+ f"\n{'\n'.join([f'{k}: {v}' for k, v in attributes.items()])}"
144
+ )
145
+ if summarize_context: # store only for summary
146
+ scopes[scope.scope_id].store.append(attributes_str)
147
+
148
+ logger.log(
149
+ ObservabilityLevel.INFO,
150
+ attributes_str,
151
+ )
152
+
129
153
  def scope_entering[Metric: State](
130
154
  scope: ScopeIdentifier,
131
155
  /,
@@ -196,6 +220,7 @@ def LoggerObservability( # noqa: C901
196
220
  log_recording=log_recording,
197
221
  event_recording=event_recording,
198
222
  metric_recording=metric_recording,
223
+ attributes_recording=attributes_recording,
199
224
  scope_entering=scope_entering,
200
225
  scope_exiting=scope_exiting,
201
226
  )
@@ -1,5 +1,5 @@
1
1
  from asyncio import iscoroutinefunction
2
- from collections.abc import Callable, Coroutine, Sequence
2
+ from collections.abc import Callable, Coroutine
3
3
  from typing import Any, Self, cast, overload
4
4
 
5
5
  from haiway.context import ctx
@@ -8,43 +8,11 @@ from haiway.types import MISSING, Missing
8
8
  from haiway.utils import mimic_function
9
9
 
10
10
  __all__ = (
11
- "ArgumentsTrace",
12
11
  "ResultTrace",
13
12
  "traced",
14
13
  )
15
14
 
16
15
 
17
- class ArgumentsTrace(State):
18
- if __debug__:
19
-
20
- @classmethod
21
- def of(
22
- cls,
23
- *args: Any,
24
- **kwargs: Any,
25
- ) -> Self:
26
- return cls(
27
- args=[f"{arg}" for arg in args] if args else MISSING,
28
- kwargs=[f"{key}:{arg}" for key, arg in kwargs.items()] if kwargs else MISSING,
29
- )
30
-
31
- else: # remove tracing for non debug runs to prevent accidental secret leaks
32
-
33
- @classmethod
34
- def of(
35
- cls,
36
- *args: Any,
37
- **kwargs: Any,
38
- ) -> Self:
39
- return cls(
40
- args=MISSING,
41
- kwargs=MISSING,
42
- )
43
-
44
- args: Sequence[str] | Missing
45
- kwargs: Sequence[str] | Missing
46
-
47
-
48
16
  class ResultTrace(State):
49
17
  if __debug__:
50
18
 
@@ -128,7 +96,12 @@ def _traced_sync[**Args, Result](
128
96
  **kwargs: Args.kwargs,
129
97
  ) -> Result:
130
98
  with ctx.scope(label):
131
- ctx.event(ArgumentsTrace.of(*args, **kwargs))
99
+ for idx, arg in enumerate(args):
100
+ ctx.attributes(**{f"[{idx}]": f"{arg}"})
101
+
102
+ for key, arg in kwargs.items():
103
+ ctx.attributes(**{key: f"{arg}"})
104
+
132
105
  try:
133
106
  result: Result = function(*args, **kwargs)
134
107
  ctx.event(ResultTrace.of(result))
@@ -154,7 +127,12 @@ def _traced_async[**Args, Result](
154
127
  **kwargs: Args.kwargs,
155
128
  ) -> Result:
156
129
  with ctx.scope(label):
157
- ctx.event(ArgumentsTrace.of(*args, **kwargs))
130
+ for idx, arg in enumerate(args):
131
+ ctx.attributes(**{f"[{idx}]": f"{arg}"})
132
+
133
+ for key, arg in kwargs.items():
134
+ ctx.attributes(**{key: f"{arg}"})
135
+
158
136
  try:
159
137
  result: Result = await function(*args, **kwargs)
160
138
  ctx.event(ResultTrace.of(result))