haiway 0.22.0__tar.gz → 0.22.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.
- {haiway-0.22.0 → haiway-0.22.1}/PKG-INFO +1 -1
- {haiway-0.22.0 → haiway-0.22.1}/junit/test-results.xml +1 -1
- {haiway-0.22.0 → haiway-0.22.1}/pyproject.toml +1 -1
- {haiway-0.22.0 → haiway-0.22.1}/src/haiway/context/access.py +9 -1
- {haiway-0.22.0 → haiway-0.22.1}/src/haiway/context/disposables.py +32 -5
- {haiway-0.22.0 → haiway-0.22.1}/src/haiway/context/state.py +17 -2
- {haiway-0.22.0 → haiway-0.22.1}/src/haiway/helpers/__init__.py +1 -1
- {haiway-0.22.0 → haiway-0.22.1}/src/haiway/state/structure.py +16 -6
- {haiway-0.22.0 → haiway-0.22.1}/src/haiway/utils/__init__.py +0 -2
- {haiway-0.22.0 → haiway-0.22.1}/tests/test_disposables.py +2 -2
- {haiway-0.22.0 → haiway-0.22.1}/tests/test_state.py +178 -1
- {haiway-0.22.0 → haiway-0.22.1}/uv.lock +1 -1
- haiway-0.22.0/examples/fastAPI/.dockerignore +0 -5
- haiway-0.22.0/examples/fastAPI/Dockerfile +0 -63
- haiway-0.22.0/examples/fastAPI/Makefile +0 -90
- haiway-0.22.0/examples/fastAPI/README.md +0 -3
- haiway-0.22.0/examples/fastAPI/config/.env.example +0 -11
- haiway-0.22.0/examples/fastAPI/config/unit.json +0 -50
- haiway-0.22.0/examples/fastAPI/docker-compose.yml +0 -68
- haiway-0.22.0/examples/fastAPI/pyproject.toml +0 -62
- haiway-0.22.0/examples/fastAPI/src/features/__int__.py +0 -0
- haiway-0.22.0/examples/fastAPI/src/features/todos/__init__.py +0 -5
- haiway-0.22.0/examples/fastAPI/src/features/todos/config.py +0 -1
- haiway-0.22.0/examples/fastAPI/src/features/todos/state.py +0 -23
- haiway-0.22.0/examples/fastAPI/src/features/todos/types.py +0 -15
- haiway-0.22.0/examples/fastAPI/src/features/todos/user_tasks.py +0 -19
- haiway-0.22.0/examples/fastAPI/src/integrations/postgres/__init__.py +0 -12
- haiway-0.22.0/examples/fastAPI/src/integrations/postgres/client.py +0 -171
- haiway-0.22.0/examples/fastAPI/src/integrations/postgres/config.py +0 -19
- haiway-0.22.0/examples/fastAPI/src/integrations/postgres/state.py +0 -77
- haiway-0.22.0/examples/fastAPI/src/integrations/postgres/types.py +0 -69
- haiway-0.22.0/examples/fastAPI/src/migrations/__init__.py +0 -3
- haiway-0.22.0/examples/fastAPI/src/migrations/__main__.py +0 -26
- haiway-0.22.0/examples/fastAPI/src/migrations/postgres/__init__.py +0 -5
- haiway-0.22.0/examples/fastAPI/src/migrations/postgres/execution.py +0 -80
- haiway-0.22.0/examples/fastAPI/src/migrations/postgres/migration_0.py +0 -17
- haiway-0.22.0/examples/fastAPI/src/migrations/postgres/types.py +0 -9
- haiway-0.22.0/examples/fastAPI/src/server/__init__.py +0 -10
- haiway-0.22.0/examples/fastAPI/src/server/__main__.py +0 -10
- haiway-0.22.0/examples/fastAPI/src/server/application.py +0 -54
- haiway-0.22.0/examples/fastAPI/src/server/config.py +0 -11
- haiway-0.22.0/examples/fastAPI/src/server/middlewares/__init__.py +0 -5
- haiway-0.22.0/examples/fastAPI/src/server/middlewares/context.py +0 -133
- haiway-0.22.0/examples/fastAPI/src/server/routes/__init__.py +0 -7
- haiway-0.22.0/examples/fastAPI/src/server/routes/technical.py +0 -21
- haiway-0.22.0/examples/fastAPI/src/server/routes/todos.py +0 -32
- haiway-0.22.0/examples/fastAPI/src/solutions/__init__.py +0 -0
- haiway-0.22.0/examples/fastAPI/src/solutions/user_tasks/__init__.py +0 -7
- haiway-0.22.0/examples/fastAPI/src/solutions/user_tasks/config.py +0 -1
- haiway-0.22.0/examples/fastAPI/src/solutions/user_tasks/postgres.py +0 -218
- haiway-0.22.0/examples/fastAPI/src/solutions/user_tasks/state.py +0 -77
- haiway-0.22.0/examples/fastAPI/src/solutions/user_tasks/types.py +0 -71
- haiway-0.22.0/examples/fastAPI/uv.lock +0 -448
- haiway-0.22.0/src/haiway/utils/freezing.py +0 -46
- haiway-0.22.0/tests/__init__.py +0 -0
- {haiway-0.22.0 → haiway-0.22.1}/.github/workflows/ci.yml +0 -0
- {haiway-0.22.0 → haiway-0.22.1}/.github/workflows/publish.yml +0 -0
- {haiway-0.22.0 → haiway-0.22.1}/.gitignore +0 -0
- {haiway-0.22.0 → haiway-0.22.1}/CLAUDE.md +0 -0
- {haiway-0.22.0 → haiway-0.22.1}/LICENSE +0 -0
- {haiway-0.22.0 → haiway-0.22.1}/Makefile +0 -0
- {haiway-0.22.0 → haiway-0.22.1}/README.md +0 -0
- {haiway-0.22.0 → haiway-0.22.1}/config/pre-push +0 -0
- {haiway-0.22.0 → haiway-0.22.1}/guidelines/functionalities.md +0 -0
- {haiway-0.22.0 → haiway-0.22.1}/guidelines/llms.txt +0 -0
- {haiway-0.22.0 → haiway-0.22.1}/guidelines/packages.md +0 -0
- {haiway-0.22.0 → haiway-0.22.1}/guidelines/state.md +0 -0
- {haiway-0.22.0 → haiway-0.22.1}/src/haiway/__init__.py +0 -0
- {haiway-0.22.0 → haiway-0.22.1}/src/haiway/context/__init__.py +0 -0
- {haiway-0.22.0 → haiway-0.22.1}/src/haiway/context/identifier.py +0 -0
- {haiway-0.22.0 → haiway-0.22.1}/src/haiway/context/observability.py +0 -0
- {haiway-0.22.0 → haiway-0.22.1}/src/haiway/context/tasks.py +0 -0
- {haiway-0.22.0 → haiway-0.22.1}/src/haiway/context/types.py +0 -0
- {haiway-0.22.0 → haiway-0.22.1}/src/haiway/helpers/asynchrony.py +0 -0
- {haiway-0.22.0 → haiway-0.22.1}/src/haiway/helpers/caching.py +0 -0
- {haiway-0.22.0 → haiway-0.22.1}/src/haiway/helpers/concurrent.py +0 -0
- {haiway-0.22.0 → haiway-0.22.1}/src/haiway/helpers/files.py +0 -0
- {haiway-0.22.0 → haiway-0.22.1}/src/haiway/helpers/observability.py +0 -0
- {haiway-0.22.0 → haiway-0.22.1}/src/haiway/helpers/retries.py +0 -0
- {haiway-0.22.0 → haiway-0.22.1}/src/haiway/helpers/throttling.py +0 -0
- /haiway-0.22.0/src/haiway/helpers/timeouted.py → /haiway-0.22.1/src/haiway/helpers/timeouting.py +0 -0
- {haiway-0.22.0 → haiway-0.22.1}/src/haiway/helpers/tracing.py +0 -0
- {haiway-0.22.0 → haiway-0.22.1}/src/haiway/opentelemetry/__init__.py +0 -0
- {haiway-0.22.0 → haiway-0.22.1}/src/haiway/opentelemetry/observability.py +0 -0
- {haiway-0.22.0 → haiway-0.22.1}/src/haiway/py.typed +0 -0
- {haiway-0.22.0 → haiway-0.22.1}/src/haiway/state/__init__.py +0 -0
- {haiway-0.22.0 → haiway-0.22.1}/src/haiway/state/attributes.py +0 -0
- {haiway-0.22.0 → haiway-0.22.1}/src/haiway/state/path.py +0 -0
- {haiway-0.22.0 → haiway-0.22.1}/src/haiway/state/requirement.py +0 -0
- {haiway-0.22.0 → haiway-0.22.1}/src/haiway/state/validation.py +0 -0
- {haiway-0.22.0 → haiway-0.22.1}/src/haiway/types/__init__.py +0 -0
- {haiway-0.22.0 → haiway-0.22.1}/src/haiway/types/default.py +0 -0
- {haiway-0.22.0 → haiway-0.22.1}/src/haiway/types/missing.py +0 -0
- {haiway-0.22.0 → haiway-0.22.1}/src/haiway/utils/always.py +0 -0
- {haiway-0.22.0 → haiway-0.22.1}/src/haiway/utils/collections.py +0 -0
- {haiway-0.22.0 → haiway-0.22.1}/src/haiway/utils/env.py +0 -0
- {haiway-0.22.0 → haiway-0.22.1}/src/haiway/utils/formatting.py +0 -0
- {haiway-0.22.0 → haiway-0.22.1}/src/haiway/utils/logs.py +0 -0
- {haiway-0.22.0 → haiway-0.22.1}/src/haiway/utils/mimic.py +0 -0
- {haiway-0.22.0 → haiway-0.22.1}/src/haiway/utils/noop.py +0 -0
- {haiway-0.22.0 → haiway-0.22.1}/src/haiway/utils/queue.py +0 -0
- {haiway-0.22.0 → haiway-0.22.1}/src/haiway/utils/stream.py +0 -0
- {haiway-0.22.0/examples/fastAPI/src/integrations → haiway-0.22.1/tests}/__init__.py +0 -0
- {haiway-0.22.0 → haiway-0.22.1}/tests/test_async_queue.py +0 -0
- {haiway-0.22.0 → haiway-0.22.1}/tests/test_async_stream.py +0 -0
- {haiway-0.22.0 → haiway-0.22.1}/tests/test_attribute_path.py +0 -0
- {haiway-0.22.0 → haiway-0.22.1}/tests/test_attribute_requirement.py +0 -0
- {haiway-0.22.0 → haiway-0.22.1}/tests/test_auto_retry.py +0 -0
- {haiway-0.22.0 → haiway-0.22.1}/tests/test_cache.py +0 -0
- {haiway-0.22.0 → haiway-0.22.1}/tests/test_context.py +0 -0
- {haiway-0.22.0 → haiway-0.22.1}/tests/test_process_concurrently.py +0 -0
- {haiway-0.22.0 → haiway-0.22.1}/tests/test_state_validation.py +0 -0
- {haiway-0.22.0 → haiway-0.22.1}/tests/test_streaming.py +0 -0
- {haiway-0.22.0 → haiway-0.22.1}/tests/test_timeout.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: haiway
|
3
|
-
Version: 0.22.
|
3
|
+
Version: 0.22.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 name="pytest tests"><testsuite name="pytest" errors="0" failures="0" skipped="0" tests="151" time="1.947" timestamp="2025-06-18T09:04:02.496497+00:00" hostname="pkrvmxyh4eaekms"><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_attribute_requirement" name="test_equal_requirement" time="0.000" /><testcase classname="tests.test_attribute_requirement" name="test_not_equal_requirement" time="0.000" /><testcase classname="tests.test_attribute_requirement" name="test_contains_requirement" time="0.000" /><testcase classname="tests.test_attribute_requirement" name="test_contains_any_requirement" time="0.000" /><testcase classname="tests.test_attribute_requirement" name="test_contained_in_requirement" time="0.000" /><testcase classname="tests.test_attribute_requirement" name="test_logical_and_or_requirements" time="0.000" /><testcase classname="tests.test_attribute_requirement" name="test_filter" time="0.000" /><testcase classname="tests.test_attribute_requirement" name="test_immutability" 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.002" /><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.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_disposables" name="test_empty_initialization" time="0.000" /><testcase classname="tests.test_disposables" name="test_single_disposable_initialization" time="0.000" /><testcase classname="tests.test_disposables" name="test_multiple_disposables_initialization" time="0.000" /><testcase classname="tests.test_disposables" name="test_cannot_set_attributes" time="0.001" /><testcase classname="tests.test_disposables" name="test_cannot_delete_attributes" time="0.000" /><testcase classname="tests.test_disposables" name="test_empty_disposables_is_falsy" time="0.000" /><testcase classname="tests.test_disposables" name="test_non_empty_disposables_is_truthy" time="0.000" /><testcase classname="tests.test_disposables" name="test_setup_with_no_disposables" time="0.001" /><testcase classname="tests.test_disposables" name="test_setup_with_disposable_returning_none" time="0.001" /><testcase classname="tests.test_disposables" name="test_setup_with_disposable_returning_single_state" time="0.001" /><testcase classname="tests.test_disposables" name="test_setup_with_disposable_returning_multiple_states" time="0.001" /><testcase classname="tests.test_disposables" name="test_setup_with_multiple_disposables_mixed_returns" time="0.001" /><testcase classname="tests.test_disposables" name="test_setup_sets_loop_correctly" time="0.001" /><testcase classname="tests.test_disposables" name="test_dispose_with_no_disposables" time="0.001" /><testcase classname="tests.test_disposables" name="test_dispose_with_successful_cleanup" time="0.001" /><testcase classname="tests.test_disposables" name="test_dispose_with_exception_context" time="0.001" /><testcase classname="tests.test_disposables" name="test_dispose_with_multiple_exceptions_creates_group" time="0.001" /><testcase classname="tests.test_disposables" name="test_dispose_with_single_exception_is_risen" time="0.001" /><testcase classname="tests.test_disposables" name="test_dispose_resets_loop_even_on_exception" time="0.001" /><testcase classname="tests.test_disposables" name="test_same_loop_cleanup" time="0.001" /><testcase classname="tests.test_disposables" name="test_with_real_async_context_managers" time="0.001" /><testcase classname="tests.test_disposables" name="test_nested_disposables_usage" time="0.001" /><testcase classname="tests.test_disposables" name="test_exception_during_setup_phase" time="0.001" /><testcase classname="tests.test_disposables" name="test_assertion_on_doubleprepare" time="0.001" /><testcase classname="tests.test_disposables" name="test_assertion_on_dispose_withoutprepare" time="0.001" /><testcase classname="tests.test_process_concurrently" name="test_processes_all_elements" time="0.001" /><testcase classname="tests.test_process_concurrently" name="test_processes_elements_concurrently" time="0.302" /><testcase classname="tests.test_process_concurrently" name="test_handles_empty_source" time="0.001" /><testcase classname="tests.test_process_concurrently" name="test_propagates_handler_exceptions" time="0.001" /><testcase classname="tests.test_process_concurrently" name="test_ignores_handler_exceptions_when_configured" time="0.001" /><testcase classname="tests.test_process_concurrently" name="test_handles_source_exception" time="0.001" /><testcase classname="tests.test_process_concurrently" name="test_cancels_running_tasks_on_cancellation" time="0.101" /><testcase classname="tests.test_process_concurrently" name="test_respects_concurrency_limit" time="0.202" /><testcase classname="tests.test_process_concurrently" name="test_processes_elements_from_queue" time="0.052" /><testcase classname="tests.test_state" name="test_basic_initializes_with_arguments" time="0.001" /><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.001" /><testcase classname="tests.test_state" name="test_generic_subtypes_validation" time="0.001" /><testcase classname="tests.test_state" name="test_copying_leaves_same_object" time="0.000" /><testcase classname="tests.test_state_validation" name="test_validator_basic_types" time="0.001" /><testcase classname="tests.test_state_validation" name="test_validator_none_type" time="0.001" /><testcase classname="tests.test_state_validation" name="test_validator_missing_type" time="0.000" /><testcase classname="tests.test_state_validation" name="test_validator_literal_type" time="0.001" /><testcase classname="tests.test_state_validation" name="test_validator_enum_type" time="0.000" /><testcase classname="tests.test_state_validation" name="test_validator_sequence_type" time="0.000" /><testcase classname="tests.test_state_validation" name="test_validator_set_type" time="0.000" /><testcase classname="tests.test_state_validation" name="test_validator_mapping_type" time="0.000" /><testcase classname="tests.test_state_validation" name="test_validator_tuple_type" time="0.000" /><testcase classname="tests.test_state_validation" name="test_validator_union_type" time="0.001" /><testcase classname="tests.test_state_validation" name="test_validator_callable_type" time="0.000" /><testcase classname="tests.test_state_validation" name="test_validator_typed_dict" time="0.000" /><testcase classname="tests.test_state_validation" name="test_validator_state_type" time="0.000" /><testcase classname="tests.test_state_validation" name="test_validator_complex_types" time="0.001" /><testcase classname="tests.test_state_validation" name="test_validator_recursive_state" time="0.000" /><testcase classname="tests.test_state_validation" name="test_validator_generic_state" time="0.001" /><testcase classname="tests.test_state_validation" name="test_validation_error_messages" time="0.001" /><testcase classname="tests.test_state_validation" name="test_validation_any_type" time="0.000" /><testcase classname="tests.test_state_validation" name="test_validator_with_defaults" time="0.000" /><testcase classname="tests.test_state_validation" name="test_attribute_validator_direct_usage" time="0.000" /><testcase classname="tests.test_state_validation" name="test_unsupported_type_annotation" 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.012" /><testcase classname="tests.test_timeout" name="test_raises_with_timeout" time="0.011" /></testsuite></testsuites>
|
1
|
+
<?xml version="1.0" encoding="utf-8"?><testsuites name="pytest tests"><testsuite name="pytest" errors="0" failures="0" skipped="0" tests="159" time="1.948" timestamp="2025-06-18T12:25:24.482293+00:00" hostname="pkrvmxyh4eaekms"><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_attribute_requirement" name="test_equal_requirement" time="0.000" /><testcase classname="tests.test_attribute_requirement" name="test_not_equal_requirement" time="0.000" /><testcase classname="tests.test_attribute_requirement" name="test_contains_requirement" time="0.000" /><testcase classname="tests.test_attribute_requirement" name="test_contains_any_requirement" time="0.000" /><testcase classname="tests.test_attribute_requirement" name="test_contained_in_requirement" time="0.000" /><testcase classname="tests.test_attribute_requirement" name="test_logical_and_or_requirements" time="0.000" /><testcase classname="tests.test_attribute_requirement" name="test_filter" time="0.000" /><testcase classname="tests.test_attribute_requirement" name="test_immutability" 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.001" /><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.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.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.020" /><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_disposables" name="test_empty_initialization" time="0.000" /><testcase classname="tests.test_disposables" name="test_single_disposable_initialization" time="0.000" /><testcase classname="tests.test_disposables" name="test_multiple_disposables_initialization" time="0.000" /><testcase classname="tests.test_disposables" name="test_cannot_set_attributes" time="0.001" /><testcase classname="tests.test_disposables" name="test_cannot_delete_attributes" time="0.000" /><testcase classname="tests.test_disposables" name="test_empty_disposables_is_falsy" time="0.000" /><testcase classname="tests.test_disposables" name="test_non_empty_disposables_is_truthy" time="0.000" /><testcase classname="tests.test_disposables" name="test_setup_with_no_disposables" time="0.001" /><testcase classname="tests.test_disposables" name="test_setup_with_disposable_returning_none" time="0.001" /><testcase classname="tests.test_disposables" name="test_setup_with_disposable_returning_single_state" time="0.001" /><testcase classname="tests.test_disposables" name="test_setup_with_disposable_returning_multiple_states" time="0.001" /><testcase classname="tests.test_disposables" name="test_setup_with_multiple_disposables_mixed_returns" time="0.001" /><testcase classname="tests.test_disposables" name="test_setup_sets_loop_correctly" time="0.001" /><testcase classname="tests.test_disposables" name="test_dispose_with_no_disposables" time="0.001" /><testcase classname="tests.test_disposables" name="test_dispose_with_successful_cleanup" time="0.001" /><testcase classname="tests.test_disposables" name="test_dispose_with_exception_context" time="0.001" /><testcase classname="tests.test_disposables" name="test_dispose_with_multiple_exceptions_creates_group" time="0.001" /><testcase classname="tests.test_disposables" name="test_dispose_with_single_exception_is_risen" time="0.001" /><testcase classname="tests.test_disposables" name="test_dispose_resets_loop_even_on_exception" time="0.001" /><testcase classname="tests.test_disposables" name="test_same_loop_cleanup" time="0.001" /><testcase classname="tests.test_disposables" name="test_with_real_async_context_managers" time="0.001" /><testcase classname="tests.test_disposables" name="test_nested_disposables_usage" time="0.001" /><testcase classname="tests.test_disposables" name="test_exception_during_setup_phase" time="0.001" /><testcase classname="tests.test_disposables" name="test_assertion_on_doubleprepare" time="0.001" /><testcase classname="tests.test_disposables" name="test_assertion_on_dispose_withoutprepare" time="0.001" /><testcase classname="tests.test_process_concurrently" name="test_processes_all_elements" time="0.001" /><testcase classname="tests.test_process_concurrently" name="test_processes_elements_concurrently" time="0.302" /><testcase classname="tests.test_process_concurrently" name="test_handles_empty_source" time="0.001" /><testcase classname="tests.test_process_concurrently" name="test_propagates_handler_exceptions" time="0.001" /><testcase classname="tests.test_process_concurrently" name="test_ignores_handler_exceptions_when_configured" time="0.001" /><testcase classname="tests.test_process_concurrently" name="test_handles_source_exception" time="0.001" /><testcase classname="tests.test_process_concurrently" name="test_cancels_running_tasks_on_cancellation" time="0.101" /><testcase classname="tests.test_process_concurrently" name="test_respects_concurrency_limit" time="0.202" /><testcase classname="tests.test_process_concurrently" name="test_processes_elements_from_queue" time="0.052" /><testcase classname="tests.test_state" name="test_basic_initializes_with_arguments" time="0.001" /><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.001" /><testcase classname="tests.test_state" name="test_generic_subtypes_validation" time="0.001" /><testcase classname="tests.test_state" name="test_copying_leaves_same_object" time="0.001" /><testcase classname="tests.test_state" name="test_hash_consistency_with_missing_values" time="0.001" /><testcase classname="tests.test_state" name="test_hash_with_unhashable_attributes" time="0.001" /><testcase classname="tests.test_state" name="test_hash_with_dict_key_order_independence" time="0.000" /><testcase classname="tests.test_state" name="test_hash_with_custom_objects" time="0.000" /><testcase classname="tests.test_state" name="test_hash_performance_with_many_attributes" time="0.001" /><testcase classname="tests.test_state" name="test_hash_with_nested_unhashable_collections" time="0.000" /><testcase classname="tests.test_state" name="test_hash_stability_across_instances" time="0.000" /><testcase classname="tests.test_state" name="test_hash_excludes_missing_values" time="0.001" /><testcase classname="tests.test_state_validation" name="test_validator_basic_types" time="0.001" /><testcase classname="tests.test_state_validation" name="test_validator_none_type" time="0.000" /><testcase classname="tests.test_state_validation" name="test_validator_missing_type" time="0.000" /><testcase classname="tests.test_state_validation" name="test_validator_literal_type" time="0.001" /><testcase classname="tests.test_state_validation" name="test_validator_enum_type" time="0.000" /><testcase classname="tests.test_state_validation" name="test_validator_sequence_type" time="0.000" /><testcase classname="tests.test_state_validation" name="test_validator_set_type" time="0.000" /><testcase classname="tests.test_state_validation" name="test_validator_mapping_type" time="0.001" /><testcase classname="tests.test_state_validation" name="test_validator_tuple_type" time="0.001" /><testcase classname="tests.test_state_validation" name="test_validator_union_type" time="0.000" /><testcase classname="tests.test_state_validation" name="test_validator_callable_type" time="0.000" /><testcase classname="tests.test_state_validation" name="test_validator_typed_dict" time="0.000" /><testcase classname="tests.test_state_validation" name="test_validator_state_type" time="0.000" /><testcase classname="tests.test_state_validation" name="test_validator_complex_types" time="0.001" /><testcase classname="tests.test_state_validation" name="test_validator_recursive_state" time="0.001" /><testcase classname="tests.test_state_validation" name="test_validator_generic_state" time="0.001" /><testcase classname="tests.test_state_validation" name="test_validation_error_messages" time="0.000" /><testcase classname="tests.test_state_validation" name="test_validation_any_type" time="0.000" /><testcase classname="tests.test_state_validation" name="test_validator_with_defaults" time="0.000" /><testcase classname="tests.test_state_validation" name="test_attribute_validator_direct_usage" time="0.000" /><testcase classname="tests.test_state_validation" name="test_unsupported_type_annotation" 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.22.
|
8
|
+
version = "0.22.1"
|
9
9
|
readme = "README.md"
|
10
10
|
maintainers = [
|
11
11
|
{ name = "Kacper Kaliński", email = "kacper.kalinski@miquido.com" },
|
@@ -539,6 +539,8 @@ class ctx:
|
|
539
539
|
def check_state[StateType: State](
|
540
540
|
state: type[StateType],
|
541
541
|
/,
|
542
|
+
*,
|
543
|
+
instantiate_defaults: bool = False,
|
542
544
|
) -> bool:
|
543
545
|
"""
|
544
546
|
Check if state object is available in the current context.
|
@@ -551,12 +553,18 @@ class ctx:
|
|
551
553
|
state: type[StateType]
|
552
554
|
The type of state to check
|
553
555
|
|
556
|
+
instantiate_defaults: bool = False
|
557
|
+
Control if default value should be instantiated during check.
|
558
|
+
|
554
559
|
Returns
|
555
560
|
-------
|
556
561
|
bool
|
557
562
|
True if state is available, otherwise False.
|
558
563
|
"""
|
559
|
-
return StateContext.check_state(
|
564
|
+
return StateContext.check_state(
|
565
|
+
state,
|
566
|
+
instantiate_defaults=instantiate_defaults,
|
567
|
+
)
|
560
568
|
|
561
569
|
@staticmethod
|
562
570
|
def state[StateType: State](
|
@@ -12,7 +12,7 @@ from itertools import chain
|
|
12
12
|
from types import TracebackType
|
13
13
|
from typing import Any, final
|
14
14
|
|
15
|
-
from haiway.context.state import
|
15
|
+
from haiway.context.state import StateContext
|
16
16
|
from haiway.state import State
|
17
17
|
from haiway.utils.mimic import mimic_function
|
18
18
|
|
@@ -195,19 +195,25 @@ class Disposables:
|
|
195
195
|
return multiple
|
196
196
|
|
197
197
|
async def prepare(self) -> Iterable[State]:
|
198
|
+
"""
|
199
|
+
Enter all contained disposables asynchronously.
|
200
|
+
|
201
|
+
Enters all disposables in parallel and collects any State objects they return.
|
202
|
+
"""
|
198
203
|
assert self._loop is None # nosec: B101
|
199
204
|
object.__setattr__(
|
200
205
|
self,
|
201
206
|
"_loop",
|
202
207
|
get_running_loop(),
|
203
208
|
)
|
204
|
-
|
205
|
-
|
209
|
+
|
210
|
+
return tuple(
|
211
|
+
chain.from_iterable(
|
206
212
|
await gather(
|
207
213
|
*[self._setup(disposable) for disposable in self._disposables],
|
208
214
|
)
|
209
215
|
)
|
210
|
-
|
216
|
+
)
|
211
217
|
|
212
218
|
async def __aenter__(self) -> None:
|
213
219
|
"""
|
@@ -218,7 +224,7 @@ class Disposables:
|
|
218
224
|
"""
|
219
225
|
|
220
226
|
assert self._state_context is None, "Context reentrance is not allowed" # nosec: B101
|
221
|
-
state_context = StateContext(
|
227
|
+
state_context = StateContext.updated(await self.prepare())
|
222
228
|
state_context.__enter__()
|
223
229
|
object.__setattr__(
|
224
230
|
self,
|
@@ -252,6 +258,26 @@ class Disposables:
|
|
252
258
|
exc_val: BaseException | None = None,
|
253
259
|
exc_tb: TracebackType | None = None,
|
254
260
|
) -> None:
|
261
|
+
"""
|
262
|
+
Exit all contained disposables asynchronously.
|
263
|
+
|
264
|
+
Properly disposes of all resources by calling their __aexit__ methods in parallel.
|
265
|
+
If multiple disposables raise exceptions, they are collected into a BaseExceptionGroup.
|
266
|
+
|
267
|
+
Parameters
|
268
|
+
----------
|
269
|
+
exc_type: type[BaseException] | None
|
270
|
+
The type of exception that caused the context to be exited
|
271
|
+
exc_val: BaseException | None
|
272
|
+
The exception that caused the context to be exited
|
273
|
+
exc_tb: TracebackType | None
|
274
|
+
The traceback for the exception that caused the context to be exited
|
275
|
+
|
276
|
+
Raises
|
277
|
+
------
|
278
|
+
BaseExceptionGroup
|
279
|
+
If multiple disposables raise exceptions during exit
|
280
|
+
"""
|
255
281
|
assert self._loop is not None # nosec: B101
|
256
282
|
results: list[bool | BaseException | None]
|
257
283
|
|
@@ -306,6 +332,7 @@ class Disposables:
|
|
306
332
|
|
307
333
|
Properly disposes of all resources by calling their __aexit__ methods in parallel.
|
308
334
|
If multiple disposables raise exceptions, they are collected into a BaseExceptionGroup.
|
335
|
+
Additionally, produced state context will be also exited resetting state to previous.
|
309
336
|
|
310
337
|
Parameters
|
311
338
|
----------
|
@@ -67,6 +67,8 @@ class ScopeState:
|
|
67
67
|
self,
|
68
68
|
state: type[StateType],
|
69
69
|
/,
|
70
|
+
*,
|
71
|
+
instantiate_defaults: bool = False,
|
70
72
|
) -> bool:
|
71
73
|
"""
|
72
74
|
Check state object availability by its type.
|
@@ -79,6 +81,9 @@ class ScopeState:
|
|
79
81
|
state: type[StateType]
|
80
82
|
The type of state to check
|
81
83
|
|
84
|
+
instantiate_defaults: bool = False
|
85
|
+
Control if default value should be instantiated during check.
|
86
|
+
|
82
87
|
Returns
|
83
88
|
-------
|
84
89
|
bool
|
@@ -87,7 +92,7 @@ class ScopeState:
|
|
87
92
|
if state in self._state:
|
88
93
|
return True
|
89
94
|
|
90
|
-
|
95
|
+
elif instantiate_defaults:
|
91
96
|
with self._lock:
|
92
97
|
if state in self._state:
|
93
98
|
return True
|
@@ -100,6 +105,9 @@ class ScopeState:
|
|
100
105
|
except BaseException:
|
101
106
|
return False # unavailable, we don't care the exception
|
102
107
|
|
108
|
+
else:
|
109
|
+
return False
|
110
|
+
|
103
111
|
def state[StateType: State](
|
104
112
|
self,
|
105
113
|
state: type[StateType],
|
@@ -201,6 +209,7 @@ class StateContext:
|
|
201
209
|
cls,
|
202
210
|
state: type[StateType],
|
203
211
|
/,
|
212
|
+
instantiate_defaults: bool = False,
|
204
213
|
) -> bool:
|
205
214
|
"""
|
206
215
|
Check if state object is available in the current context.
|
@@ -212,13 +221,19 @@ class StateContext:
|
|
212
221
|
state: type[StateType]
|
213
222
|
The type of state to check
|
214
223
|
|
224
|
+
instantiate_defaults: bool = False
|
225
|
+
Control if default value should be instantiated during check.
|
226
|
+
|
215
227
|
Returns
|
216
228
|
-------
|
217
229
|
bool
|
218
230
|
True if state is available, otherwise False.
|
219
231
|
"""
|
220
232
|
try:
|
221
|
-
return cls._context.get().check_state(
|
233
|
+
return cls._context.get().check_state(
|
234
|
+
state,
|
235
|
+
instantiate_defaults=instantiate_defaults,
|
236
|
+
)
|
222
237
|
|
223
238
|
except LookupError:
|
224
239
|
return False # no context no state
|
@@ -5,7 +5,7 @@ from haiway.helpers.files import File, FileAccess
|
|
5
5
|
from haiway.helpers.observability import LoggerObservability
|
6
6
|
from haiway.helpers.retries import retry
|
7
7
|
from haiway.helpers.throttling import throttle
|
8
|
-
from haiway.helpers.
|
8
|
+
from haiway.helpers.timeouting import timeout
|
9
9
|
from haiway.helpers.tracing import traced
|
10
10
|
|
11
11
|
__all__ = (
|
@@ -729,12 +729,22 @@ class State(metaclass=StateMeta):
|
|
729
729
|
)
|
730
730
|
|
731
731
|
def __hash__(self) -> int:
|
732
|
-
|
733
|
-
|
734
|
-
|
735
|
-
|
736
|
-
|
737
|
-
|
732
|
+
hash_values: list[int] = []
|
733
|
+
for key in self.__ATTRIBUTES__.keys():
|
734
|
+
value: Any = getattr(self, key, MISSING)
|
735
|
+
|
736
|
+
# Skip MISSING values to ensure consistent hashing
|
737
|
+
if value is MISSING:
|
738
|
+
continue
|
739
|
+
|
740
|
+
# Convert to hashable representation
|
741
|
+
try:
|
742
|
+
hash_values.append(hash(value))
|
743
|
+
|
744
|
+
except TypeError:
|
745
|
+
continue # skip unhashable
|
746
|
+
|
747
|
+
return hash((self.__class__, tuple(hash_values)))
|
738
748
|
|
739
749
|
def __setattr__(
|
740
750
|
self,
|
@@ -9,7 +9,6 @@ from haiway.utils.env import (
|
|
9
9
|
load_env,
|
10
10
|
)
|
11
11
|
from haiway.utils.formatting import format_str
|
12
|
-
from haiway.utils.freezing import freeze
|
13
12
|
from haiway.utils.logs import setup_logging
|
14
13
|
from haiway.utils.mimic import mimic_function
|
15
14
|
from haiway.utils.noop import async_noop, noop
|
@@ -27,7 +26,6 @@ __all__ = (
|
|
27
26
|
"async_always",
|
28
27
|
"async_noop",
|
29
28
|
"format_str",
|
30
|
-
"freeze",
|
31
29
|
"getenv_base64",
|
32
30
|
"getenv_bool",
|
33
31
|
"getenv_float",
|
@@ -128,7 +128,7 @@ def test_non_empty_disposables_is_truthy():
|
|
128
128
|
async def test_setup_with_no_disposables():
|
129
129
|
disposables = Disposables()
|
130
130
|
result = await disposables.prepare()
|
131
|
-
assert result ==
|
131
|
+
assert result == ()
|
132
132
|
assert disposables._loop is not None
|
133
133
|
|
134
134
|
|
@@ -137,7 +137,7 @@ async def test_setup_with_disposable_returning_none():
|
|
137
137
|
mock = MockDisposable(enter_return=None)
|
138
138
|
disposables = Disposables(mock)
|
139
139
|
result = await disposables.prepare()
|
140
|
-
assert result ==
|
140
|
+
assert result == ()
|
141
141
|
assert mock.enter_called
|
142
142
|
assert disposables._loop is not None
|
143
143
|
|
@@ -1,4 +1,4 @@
|
|
1
|
-
from collections.abc import Callable, Sequence, Set
|
1
|
+
from collections.abc import Callable, Mapping, Sequence, Set
|
2
2
|
from copy import copy, deepcopy
|
3
3
|
from datetime import date, datetime
|
4
4
|
from enum import StrEnum
|
@@ -240,3 +240,180 @@ def test_copying_leaves_same_object() -> None:
|
|
240
240
|
origin = Copied(string="42", nested=Nested(string="answer"))
|
241
241
|
assert copy(origin) is origin
|
242
242
|
assert deepcopy(origin) is origin
|
243
|
+
|
244
|
+
|
245
|
+
def test_hash_consistency_with_missing_values() -> None:
|
246
|
+
class HashTest(State):
|
247
|
+
required: str
|
248
|
+
optional: int | Missing
|
249
|
+
nullable: str | None
|
250
|
+
|
251
|
+
# Test that hash is consistent regardless of how MISSING values are specified
|
252
|
+
obj1 = HashTest(required="test", optional=MISSING, nullable=None)
|
253
|
+
obj2 = HashTest(required="test", nullable=None) # optional omitted
|
254
|
+
obj3 = HashTest(**{"required": "test", "nullable": None}) # optional missing from dict
|
255
|
+
|
256
|
+
assert hash(obj1) == hash(obj2) == hash(obj3)
|
257
|
+
assert obj1 == obj2 == obj3
|
258
|
+
|
259
|
+
|
260
|
+
def test_hash_with_unhashable_attributes() -> None:
|
261
|
+
class UnhashableTest(State):
|
262
|
+
name: str
|
263
|
+
data_list: Sequence[int]
|
264
|
+
data_dict: Mapping[str, int]
|
265
|
+
data_set: Set[str]
|
266
|
+
function: Callable[..., Any] | None
|
267
|
+
|
268
|
+
obj1 = UnhashableTest(
|
269
|
+
name="test",
|
270
|
+
data_list=[1, 2, 3],
|
271
|
+
data_dict={"a": 1, "b": 2},
|
272
|
+
data_set={"x", "y"},
|
273
|
+
function=None,
|
274
|
+
)
|
275
|
+
|
276
|
+
# Should not raise TypeError
|
277
|
+
hash_value = hash(obj1)
|
278
|
+
assert isinstance(hash_value, int)
|
279
|
+
|
280
|
+
# Objects with same data should have same hash
|
281
|
+
obj2 = UnhashableTest(
|
282
|
+
name="test",
|
283
|
+
data_list=[1, 2, 3],
|
284
|
+
data_dict={"a": 1, "b": 2},
|
285
|
+
data_set={"x", "y"},
|
286
|
+
function=None,
|
287
|
+
)
|
288
|
+
assert hash(obj1) == hash(obj2)
|
289
|
+
|
290
|
+
# Objects with different data should have different hashes (usually)
|
291
|
+
obj3 = UnhashableTest(
|
292
|
+
name="test",
|
293
|
+
data_list=[1, 2, 3],
|
294
|
+
data_dict={"a": 1, "b": 2},
|
295
|
+
data_set={"x", "y"},
|
296
|
+
function=lambda: ..., # Different function
|
297
|
+
)
|
298
|
+
obj4 = UnhashableTest(
|
299
|
+
name="test",
|
300
|
+
data_list=[1, 2, 3],
|
301
|
+
data_dict={"a": 1, "b": 2},
|
302
|
+
data_set={"x", "y"},
|
303
|
+
function=lambda: ..., # Different function
|
304
|
+
)
|
305
|
+
# Note: Hash collisions are possible but unlikely
|
306
|
+
assert hash(obj3) != hash(obj4)
|
307
|
+
|
308
|
+
|
309
|
+
def test_hash_with_dict_key_order_independence() -> None:
|
310
|
+
class DictTest(State):
|
311
|
+
data: Mapping[str, int]
|
312
|
+
|
313
|
+
# Dictionaries with same content but different creation order should hash the same
|
314
|
+
obj1 = DictTest(data={"a": 1, "b": 2, "c": 3})
|
315
|
+
obj2 = DictTest(data={"c": 3, "a": 1, "b": 2})
|
316
|
+
|
317
|
+
assert hash(obj1) == hash(obj2)
|
318
|
+
assert obj1 == obj2
|
319
|
+
|
320
|
+
|
321
|
+
def test_hash_with_custom_objects() -> None:
|
322
|
+
# Test with a simple custom object that can go through Any validation
|
323
|
+
class CustomTest(State):
|
324
|
+
name: str
|
325
|
+
custom: Any # Use Any to allow custom objects
|
326
|
+
|
327
|
+
custom_obj1 = {"value": "test"} # Use dict as custom object
|
328
|
+
custom_obj2 = {"value": "test"} # Same content
|
329
|
+
|
330
|
+
obj1 = CustomTest(name="test", custom=custom_obj1)
|
331
|
+
obj2 = CustomTest(name="test", custom=custom_obj2)
|
332
|
+
|
333
|
+
# Should not raise TypeError
|
334
|
+
hash_value1 = hash(obj1)
|
335
|
+
hash_value2 = hash(obj2)
|
336
|
+
|
337
|
+
assert isinstance(hash_value1, int)
|
338
|
+
assert isinstance(hash_value2, int)
|
339
|
+
# Objects with same content should have same hash
|
340
|
+
assert hash_value1 == hash_value2
|
341
|
+
|
342
|
+
|
343
|
+
def test_hash_performance_with_many_attributes() -> None:
|
344
|
+
# Test that the optimized hash function performs well with many attributes
|
345
|
+
class ManyAttrs(State):
|
346
|
+
attr_0: int = 0
|
347
|
+
attr_1: int = 1
|
348
|
+
attr_2: int = 2
|
349
|
+
attr_3: int = 3
|
350
|
+
attr_4: int = 4
|
351
|
+
attr_5: int = 5
|
352
|
+
attr_6: int = 6
|
353
|
+
attr_7: int = 7
|
354
|
+
attr_8: int = 8
|
355
|
+
attr_9: int = 9
|
356
|
+
|
357
|
+
obj = ManyAttrs()
|
358
|
+
|
359
|
+
# Should compute hash without issues
|
360
|
+
hash_value = hash(obj)
|
361
|
+
assert isinstance(hash_value, int)
|
362
|
+
|
363
|
+
|
364
|
+
def test_hash_with_nested_unhashable_collections() -> None:
|
365
|
+
class NestedTest(State):
|
366
|
+
nested_list: Sequence[Sequence[int]]
|
367
|
+
nested_dict: Mapping[str, Mapping[str, int]]
|
368
|
+
|
369
|
+
obj = NestedTest(nested_list=[[1, 2], [3, 4]], nested_dict={"outer": {"inner": 42}})
|
370
|
+
|
371
|
+
# Should handle nested unhashable collections
|
372
|
+
hash_value = hash(obj)
|
373
|
+
assert isinstance(hash_value, int)
|
374
|
+
|
375
|
+
|
376
|
+
def test_hash_stability_across_instances() -> None:
|
377
|
+
class StabilityTest(State):
|
378
|
+
value: str
|
379
|
+
number: int
|
380
|
+
|
381
|
+
# Same data should always produce same hash
|
382
|
+
obj1 = StabilityTest(value="test", number=42)
|
383
|
+
obj2 = StabilityTest(value="test", number=42)
|
384
|
+
|
385
|
+
assert hash(obj1) == hash(obj2)
|
386
|
+
|
387
|
+
# Hash should be stable across multiple calls
|
388
|
+
hash1 = hash(obj1)
|
389
|
+
hash2 = hash(obj1)
|
390
|
+
hash3 = hash(obj1)
|
391
|
+
|
392
|
+
assert hash1 == hash2 == hash3
|
393
|
+
|
394
|
+
|
395
|
+
def test_hash_excludes_missing_values() -> None:
|
396
|
+
class MissingTest(State):
|
397
|
+
always_present: str
|
398
|
+
sometimes_missing: int | Missing
|
399
|
+
sometimes_none: str | None
|
400
|
+
|
401
|
+
# Test various combinations of missing values
|
402
|
+
obj1 = MissingTest(always_present="test", sometimes_missing=42, sometimes_none="value")
|
403
|
+
obj2 = MissingTest(always_present="test", sometimes_missing=MISSING, sometimes_none="value")
|
404
|
+
obj3 = MissingTest(always_present="test", sometimes_missing=MISSING, sometimes_none=None)
|
405
|
+
|
406
|
+
# All should be hashable
|
407
|
+
hash1 = hash(obj1)
|
408
|
+
hash2 = hash(obj2)
|
409
|
+
hash3 = hash(obj3)
|
410
|
+
|
411
|
+
assert isinstance(hash1, int)
|
412
|
+
assert isinstance(hash2, int)
|
413
|
+
assert isinstance(hash3, int)
|
414
|
+
|
415
|
+
# obj2 should have different hash from obj1 since it's missing a value
|
416
|
+
assert hash1 != hash2
|
417
|
+
|
418
|
+
# obj3 should have different hash from obj2 since None != MISSING
|
419
|
+
assert hash2 != hash3
|
@@ -1,63 +0,0 @@
|
|
1
|
-
ARG PYTHON_TAG=3.12
|
2
|
-
ARG UNIT_TAG=1.32.1-python${PYTHON_TAG}
|
3
|
-
|
4
|
-
# SERVER #
|
5
|
-
|
6
|
-
FROM unit:${UNIT_TAG} AS server_builder
|
7
|
-
|
8
|
-
# copy only the parts needed for production
|
9
|
-
COPY ./src/integrations ./src/integrations
|
10
|
-
COPY ./src/solutions ./src/solutions
|
11
|
-
COPY ./src/features ./src/features
|
12
|
-
COPY ./src/server ./src/server
|
13
|
-
|
14
|
-
# install dependencies and packages
|
15
|
-
COPY --from=ghcr.io/astral-sh/uv:0.6.8 /uv /uvx /bin/
|
16
|
-
|
17
|
-
ENV UV_PROJECT_ENVIRONMENT="/usr/local/"
|
18
|
-
|
19
|
-
RUN --mount=type=bind,source=./uv.lock,target=./uv.lock --mount=type=bind,source=./pyproject.toml,target=./pyproject.toml uv sync --python python${PYTHON_TAG} --locked --no-editable --no-python-downloads --link-mode copy --compile-bytecode --only-group server
|
20
|
-
|
21
|
-
FROM server_builder AS server
|
22
|
-
|
23
|
-
# allow access to home directory for asyncpg library
|
24
|
-
RUN chgrp -R unit ${HOME} && chmod -R 050 ${HOME}
|
25
|
-
|
26
|
-
RUN apt-get update \
|
27
|
-
&& apt-get upgrade -y \
|
28
|
-
&& apt-get -y autoremove \
|
29
|
-
&& apt-get clean \
|
30
|
-
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
|
31
|
-
|
32
|
-
# copy configuration
|
33
|
-
COPY ./config/unit.json /docker-entrypoint.d/config.json
|
34
|
-
|
35
|
-
CMD ["unitd", "--no-daemon", "--log", "/dev/stdout"]
|
36
|
-
|
37
|
-
# port 80 is already exposed by nginx unit image, can't change it...
|
38
|
-
|
39
|
-
# MIGRATIONS #
|
40
|
-
|
41
|
-
FROM python:${PYTHON_TAG} AS migrations_builder
|
42
|
-
|
43
|
-
# copy only the parts needed for production
|
44
|
-
COPY ./src/integrations ./src/integrations
|
45
|
-
COPY ./src/solutions ./src/solutions
|
46
|
-
COPY ./src/features ./src/features
|
47
|
-
COPY ./src/migrations ./src/migrations
|
48
|
-
# install dependencies and packages
|
49
|
-
COPY --from=ghcr.io/astral-sh/uv:0.6.8 /uv /uvx /bin/
|
50
|
-
|
51
|
-
ENV UV_PROJECT_ENVIRONMENT="/usr/local/"
|
52
|
-
|
53
|
-
RUN --mount=type=bind,source=./uv.lock,target=./uv.lock --mount=type=bind,source=./pyproject.toml,target=./pyproject.toml uv sync --python python${PYTHON_TAG} --locked --no-editable --no-python-downloads --link-mode copy --compile-bytecode --only-group server
|
54
|
-
|
55
|
-
FROM migrations_builder AS migrations
|
56
|
-
|
57
|
-
RUN apt-get update \
|
58
|
-
&& apt-get upgrade -y \
|
59
|
-
&& apt-get -y autoremove \
|
60
|
-
&& apt-get clean \
|
61
|
-
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
|
62
|
-
|
63
|
-
CMD ["python", "-m", "migrations"]
|