From 616dfc277ec1e1bc7943781550adb07a89a91162 Mon Sep 17 00:00:00 2001 From: Sassan Haradji Date: Thu, 15 Aug 2024 15:59:35 +0400 Subject: [PATCH] feat(core): add blocking `wait_for_event_handlers` method to `Store` to wait for all event handlers to finish --- CHANGELOG.md | 136 +++++++++++++------------------------- poetry.lock | 46 ++++++------- pyproject.toml | 6 +- redux/autorun.py | 8 ++- redux/combine_reducers.py | 5 +- redux/main.py | 18 +++-- 6 files changed, 88 insertions(+), 131 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ba0ed9d..8105672 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,34 +1,30 @@ # Changelog +## Version 0.16.0 + +- feat(core): add blocking `wait_for_event_handlers` method to `Store` to wait for all event handlers to finish + ## Version 0.15.10 - feat(test): add arguments for `wait_for`'s `check` ## Version 0.15.9 -- refactor(core): use `str_to_bool` of `python-strtobool` instead of `strtobool` - of `distutils` +- refactor(core): use `str_to_bool` of `python-strtobool` instead of `strtobool` of `distutils` - feat(test-snapshot): add prefix to snapshot fixture ## Version 0.15.8 -- feat(test-snapshot): the `selector` function can signal the `monitor` it should - ignore a particular snapshot of the state by returning `None` +- feat(test-snapshot): the `selector` function can signal the `monitor` it should ignore a particular snapshot of the state by returning `None` ## Version 0.15.7 -- refactor(test-snapshot): make it aligned with `pyfakefs` by using `try`/`except` - instead of checking `Path().exists()` as `pyfakefs` doesn't seem to respect `skip_names` - for `Path().exists()` +- refactor(test-snapshot): make it aligned with `pyfakefs` by using `try`/`except` instead of checking `Path().exists()` as `pyfakefs` doesn't seem to respect `skip_names` for `Path().exists()` ## Version 0.15.5 -- feat(test-snapshot): while still taking snapshots of the whole state of the - store, one can narrow this down by providing a selector to the `snapshot` method - (used to be a property) -- feat(test-snapshot): new `monitor` method to let a test automatically take snapshots - of the store whenever it is changed. Takes an optional selector to narrow down - the snapshot. +- feat(test-snapshot): while still taking snapshots of the whole state of the store, one can narrow this down by providing a selector to the `snapshot` method (used to be a property) +- feat(test-snapshot): new `monitor` method to let a test automatically take snapshots of the store whenever it is changed. Takes an optional selector to narrow down the snapshot. ## Version 0.15.4 @@ -40,29 +36,20 @@ ## Version 0.15.2 -- refactor(autorun): improve type-hints so that its final return value has the correct - type, regardless `default_value` is provided or not -- refactor(view): improve type-hints so that its final return value has the correct - type, regardless `default_value` is provided or not +- refactor(autorun): improve type-hints so that its final return value has the correct type, regardless `default_value` is provided or not +- refactor(view): improve type-hints so that its final return value has the correct type, regardless `default_value` is provided or not - refactor(combine_reducers): use `make_immutable` instead of `make_dataclass` - test(view): write tests for `store.view` ## Version 0.15.1 -- feat(core): add `view` method to `Store` to allow computing a derived value from - the state only when it is accessed and caching the result until the relevant parts - of the state change +- feat(core): add `view` method to `Store` to allow computing a derived value from the state only when it is accessed and caching the result until the relevant parts of the state change - feat(test): add performance tests to check it doesn't timeout in edge cases ## Version 0.15.0 -- refactor(autorun)!: setting `initial_run` option of autorun to `False` used to - make the autorun simply not call the function on initialization, now it makes - sure the function is not called until the selector's value actually changes -- feat(autorun): add `auto_call` and `reactive` options to autorun to control whether - the autorun should call the function automatically when the comparator's value - changes and whether it shouldn't automatically call it but yet register a change - so that when it is manually called the next time, it will call the function. +- refactor(autorun)!: setting `initial_run` option of autorun to `False` used to make the autorun simply not call the function on initialization, now it makes sure the function is not called until the selector's value actually changes +- feat(autorun): add `auto_call` and `reactive` options to autorun to control whether the autorun should call the function automatically when the comparator's value changes and whether it shouldn't automatically call it but yet register a change so that when it is manually called the next time, it will call the function. ## Version 0.14.5 @@ -82,23 +69,17 @@ ## Version 0.14.1 -- feat: introduce `grace_time_in_seconds` parameter to `Store` to allow a grace - period for the store to finish its work before calling `cleanup` and `on_finish` +- feat: introduce `grace_time_in_seconds` parameter to `Store` to allow a grace period for the store to finish its work before calling `cleanup` and `on_finish` ## Version 0.14.0 -- refactor: `Store` no longer aggregates changes, it now calls listeners with every - change -- refactor: `SideEffectRunnerThread` now runs async side effects in the event loop - of the thread in which it was instantiated in (it used to create its own event - loop) -- refactor(test): `event_loop` fixture now sets the global event loop on setup and - restores it on teardown +- refactor: `Store` no longer aggregates changes, it now calls listeners with every change +- refactor: `SideEffectRunnerThread` now runs async side effects in the event loop of the thread in which it was instantiated in (it used to create its own event loop) +- refactor(test): `event_loop` fixture now sets the global event loop on setup and restores it on teardown ## Version 0.13.2 -- fix: initial snapshot cleanup which used to mistakenly remove files with store:... - filenames now removes files with store-... filenames +- fix: initial snapshot cleanup which used to mistakenly remove files with store:... filenames now removes files with store-... filenames ## Version 0.13.1 @@ -111,10 +92,8 @@ - test: add tests for scheduler and fixtures - refactor: `SideEffectRunnerThread` now runs async side effects in its own event-loop - refactor: removed `immediate_run` from event subscriptions -- refactor: removed `EventSubscriptionOptions` as the only option left was `keep_ref`, - it's now a parameter of `subscribe_event` -- feat: new `on_finish` callback for the store, it runs when all worker threads are - joined and resources are freed +- refactor: removed `EventSubscriptionOptions` as the only option left was `keep_ref`, it's now a parameter of `subscribe_event` +- feat: new `on_finish` callback for the store, it runs when all worker threads are joined and resources are freed ## Version 0.12.7 @@ -127,26 +106,21 @@ ## Version 0.12.5 -- refactor: add cleanup to `FinishEvent` handler to clean workers, listeners, subscriptions, - autoruns, etc +- refactor: add cleanup to `FinishEvent` handler to clean workers, listeners, subscriptions, autoruns, etc - refactor: `TaskCreator` add `TaskCreatorCallback` protocols -- refactor: `Store._create_task` now has a callback parameter to report the created - task -- refactor: move serialization methods and side_effect_runner class to separate - files +- refactor: `Store._create_task` now has a callback parameter to report the created task +- refactor: move serialization methods and side_effect_runner class to separate files ## Version 0.12.4 -- fix: serialization class methods of `Store` use `cls` instead of `Store` for the - sake of extensibility via inheritance +- fix: serialization class methods of `Store` use `cls` instead of `Store` for the sake of extensibility via inheritance - refactor: `pytest_addoption` moved to `test.py` to make reusable ## Version 0.12.3 - test: write tests for different features of the api - refactor: rename certain names in the api to better reflect their job -- refactor: store_snapshot now puts snapshot files in a hierarchical directory structure - based on the test module and test name +- refactor: store_snapshot now puts snapshot files in a hierarchical directory structure based on the test module and test name - fix: sort JSON keys in `snapshot_store`'s `json_snapshot` - test: cover most features with tests @@ -162,16 +136,14 @@ ## Version 0.12.0 -- refactor: improve creating new state classes in `combine_reducers` upon registering/unregistering - sub-reducers +- refactor: improve creating new state classes in `combine_reducers` upon registering/unregistering sub-reducers - feat: add test fixture for snapshot testing the store - chore(test): add test infrastructure for snapshot testing the store - test: move demo files to test files and update the to use snapshot fixture ## Version 0.11.0 -- feat: add `keep_ref` parameter to subscriptions and autoruns, defaulting to `True`, - if set to `False`, the subscription/autorun will not keep a reference to the callback +- feat: add `keep_ref` parameter to subscriptions and autoruns, defaulting to `True`, if set to `False`, the subscription/autorun will not keep a reference to the callback - refacotr: general housekeeping ## Version 0.10.7 @@ -195,8 +167,7 @@ ## Version 0.10.0 -- refactor: remove `create_store` closure in favor of `Store` class with identical - api +- refactor: remove `create_store` closure in favor of `Store` class with identical api ## Version 0.9.25 @@ -208,13 +179,11 @@ ## Version 0.9.23 -- feat(combine_reducers): initialization of sub-reducers is done with `CombineReducerInitAction` - containing `_id` instead of normal `InitAction` +- feat(combine_reducers): initialization of sub-reducers is done with `CombineReducerInitAction` containing `_id` instead of normal `InitAction` ## Version 0.9.22 -- fix: `CombineReducerRegisterAction` should take care of `CompleteReducerResult` - returned by the sub-reducer on its initialization. +- fix: `CombineReducerRegisterAction` should take care of `CompleteReducerResult` returned by the sub-reducer on its initialization. ## Version 0.9.21 @@ -222,11 +191,9 @@ ## Version 0.9.20 -- refactor: encapsulate autorun options previously provided as multiple keyword arguments, - in a single `AutorunOptions` immutable class +- refactor: encapsulate autorun options previously provided as multiple keyword arguments, in a single `AutorunOptions` immutable class - refactor: rename `immediate` to `immediate_run` in autorun subscribers -- feat: default value of `immediate_run` can be set for all subscribers of an autorun - instance by settings `subscribers_immediate_run` option for the autorun +- feat: default value of `immediate_run` can be set for all subscribers of an autorun instance by settings `subscribers_immediate_run` option for the autorun ## Version 0.9.19 @@ -239,8 +206,7 @@ ## Version 0.9.17 -- refactor: make `dispatch` accept a `with_state(store)` function as parameter, if - provided it will dispatch return value of this function +- refactor: make `dispatch` accept a `with_state(store)` function as parameter, if provided it will dispatch return value of this function ## Version 0.9.15 @@ -252,8 +218,7 @@ ## Version 0.9.13 -- feat: make `subscribe` method of `autorun`'s return value, call its callback with - the latest value immediately +- feat: make `subscribe` method of `autorun`'s return value, call its callback with the latest value immediately ## Version 0.9.12 @@ -261,9 +226,7 @@ ## Version 0.9.11 -- feat: the provided `scheduler`, if any, should have a `interval` parameter, if - set to `False`, it should schedule only once, otherwise it should periodically - call the `callback` +- feat: the provided `scheduler`, if any, should have a `interval` parameter, if set to `False`, it should schedule only once, otherwise it should periodically call the `callback` ## Version 0.9.10 @@ -272,8 +235,7 @@ ## Version 0.9.9 -- refactor: improve typehints and allow dispatch to get multiple actions/events - via `*args` +- refactor: improve typehints and allow dispatch to get multiple actions/events via `*args` ## Version 0.9.8 @@ -298,13 +260,11 @@ ## Version 0.9.3 -- refactor: add `subscribe` property to the type of the return value of an - autorun decorator +- refactor: add `subscribe` property to the type of the return value of an autorun decorator ## Version 0.9.2 -- refactor: use `Immutable` from python-immutable package (extracted and created - based on `Immutable` class of this package) +- refactor: use `Immutable` from python-immutable package (extracted and created based on `Immutable` class of this package) ## Version 0.9.1 @@ -313,8 +273,7 @@ ## Version 0.9.0 - feat: add `scheduler` option to schedule running actions in the main loop of frameworks -- feat: add `threads` option to run event handlers asynchronous in `threads` - number of threads +- feat: add `threads` option to run event handlers asynchronous in `threads` number of threads - refacotr: allow `Any` return type for event handler and subscriber functions - feat: add `subscribe` property to the returned function of `autorun` @@ -328,13 +287,11 @@ ## Version 0.8.0 -- feat: drop `type` field in actions and events altogether, recognition is done - by `isinstance` +- feat: drop `type` field in actions and events altogether, recognition is done by `isinstance` ## Version 0.7.3 -- fix: loosen `subscribe_event` typing constraints as python doesn't have enough - type narrowing mechanism at the moment +- fix: loosen `subscribe_event` typing constraints as python doesn't have enough type narrowing mechanism at the moment ## Version 0.7.2 @@ -350,8 +307,7 @@ ## Version 0.6.3 -- fix: let input reducers of `combine_reducers` have arbitrary action types - irrelevant to each other +- fix: let input reducers of `combine_reducers` have arbitrary action types irrelevant to each other ## Version 0.6.2 @@ -368,12 +324,10 @@ ## Version 0.5.0 -- feat: introduce `immutable` decorator as a shortcut of - `dataclass(kw_only=True, frozen=True)` +- feat: introduce `immutable` decorator as a shortcut of `dataclass(kw_only=True, frozen=True)` - feat: introduce `Immutable` class, its subclasses automatically become `immutable` - refactor: `BaseAction` now inherits from `Immutable` -- refactor: Removed `BaseState`, state classes, payload classes, etc should now - inherit `Immutable` +- refactor: Removed `BaseState`, state classes, payload classes, etc should now inherit `Immutable` ## Version 0.4.0 diff --git a/poetry.lock b/poetry.lock index 54a89a3..55625cf 100644 --- a/poetry.lock +++ b/poetry.lock @@ -154,13 +154,13 @@ poetry-plugin = ["poetry (>=1.0,<2.0)"] [[package]] name = "pyright" -version = "1.1.373" +version = "1.1.376" description = "Command line wrapper for pyright" optional = false python-versions = ">=3.7" files = [ - {file = "pyright-1.1.373-py3-none-any.whl", hash = "sha256:b805413227f2c209f27b14b55da27fe5e9fb84129c9f1eb27708a5d12f6f000e"}, - {file = "pyright-1.1.373.tar.gz", hash = "sha256:f41bcfc8b9d1802b09921a394d6ae1ce19694957b628bc657629688daf8a83ff"}, + {file = "pyright-1.1.376-py3-none-any.whl", hash = "sha256:0f2473b12c15c46b3207f0eec224c3cea2bdc07cd45dd4a037687cbbca0fbeff"}, + {file = "pyright-1.1.376.tar.gz", hash = "sha256:bffd63b197cd0810395bb3245c06b01f95a85ddf6bfa0e5644ed69c841e954dd"}, ] [package.dependencies] @@ -266,29 +266,29 @@ files = [ [[package]] name = "ruff" -version = "0.5.4" +version = "0.5.7" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" files = [ - {file = "ruff-0.5.4-py3-none-linux_armv6l.whl", hash = "sha256:82acef724fc639699b4d3177ed5cc14c2a5aacd92edd578a9e846d5b5ec18ddf"}, - {file = "ruff-0.5.4-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:da62e87637c8838b325e65beee485f71eb36202ce8e3cdbc24b9fcb8b99a37be"}, - {file = "ruff-0.5.4-py3-none-macosx_11_0_arm64.whl", hash = "sha256:e98ad088edfe2f3b85a925ee96da652028f093d6b9b56b76fc242d8abb8e2059"}, - {file = "ruff-0.5.4-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4c55efbecc3152d614cfe6c2247a3054cfe358cefbf794f8c79c8575456efe19"}, - {file = "ruff-0.5.4-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f9b85eaa1f653abd0a70603b8b7008d9e00c9fa1bbd0bf40dad3f0c0bdd06793"}, - {file = "ruff-0.5.4-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0cf497a47751be8c883059c4613ba2f50dd06ec672692de2811f039432875278"}, - {file = "ruff-0.5.4-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:09c14ed6a72af9ccc8d2e313d7acf7037f0faff43cde4b507e66f14e812e37f7"}, - {file = "ruff-0.5.4-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:628f6b8f97b8bad2490240aa84f3e68f390e13fabc9af5c0d3b96b485921cd60"}, - {file = "ruff-0.5.4-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3520a00c0563d7a7a7c324ad7e2cde2355733dafa9592c671fb2e9e3cd8194c1"}, - {file = "ruff-0.5.4-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:93789f14ca2244fb91ed481456f6d0bb8af1f75a330e133b67d08f06ad85b516"}, - {file = "ruff-0.5.4-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:029454e2824eafa25b9df46882f7f7844d36fd8ce51c1b7f6d97e2615a57bbcc"}, - {file = "ruff-0.5.4-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:9492320eed573a13a0bc09a2957f17aa733fff9ce5bf00e66e6d4a88ec33813f"}, - {file = "ruff-0.5.4-py3-none-musllinux_1_2_i686.whl", hash = "sha256:a6e1f62a92c645e2919b65c02e79d1f61e78a58eddaebca6c23659e7c7cb4ac7"}, - {file = "ruff-0.5.4-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:768fa9208df2bec4b2ce61dbc7c2ddd6b1be9fb48f1f8d3b78b3332c7d71c1ff"}, - {file = "ruff-0.5.4-py3-none-win32.whl", hash = "sha256:e1e7393e9c56128e870b233c82ceb42164966f25b30f68acbb24ed69ce9c3a4e"}, - {file = "ruff-0.5.4-py3-none-win_amd64.whl", hash = "sha256:58b54459221fd3f661a7329f177f091eb35cf7a603f01d9eb3eb11cc348d38c4"}, - {file = "ruff-0.5.4-py3-none-win_arm64.whl", hash = "sha256:bd53da65f1085fb5b307c38fd3c0829e76acf7b2a912d8d79cadcdb4875c1eb7"}, - {file = "ruff-0.5.4.tar.gz", hash = "sha256:2795726d5f71c4f4e70653273d1c23a8182f07dd8e48c12de5d867bfb7557eed"}, + {file = "ruff-0.5.7-py3-none-linux_armv6l.whl", hash = "sha256:548992d342fc404ee2e15a242cdbea4f8e39a52f2e7752d0e4cbe88d2d2f416a"}, + {file = "ruff-0.5.7-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:00cc8872331055ee017c4f1071a8a31ca0809ccc0657da1d154a1d2abac5c0be"}, + {file = "ruff-0.5.7-py3-none-macosx_11_0_arm64.whl", hash = "sha256:eaf3d86a1fdac1aec8a3417a63587d93f906c678bb9ed0b796da7b59c1114a1e"}, + {file = "ruff-0.5.7-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a01c34400097b06cf8a6e61b35d6d456d5bd1ae6961542de18ec81eaf33b4cb8"}, + {file = "ruff-0.5.7-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fcc8054f1a717e2213500edaddcf1dbb0abad40d98e1bd9d0ad364f75c763eea"}, + {file = "ruff-0.5.7-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7f70284e73f36558ef51602254451e50dd6cc479f8b6f8413a95fcb5db4a55fc"}, + {file = "ruff-0.5.7-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:a78ad870ae3c460394fc95437d43deb5c04b5c29297815a2a1de028903f19692"}, + {file = "ruff-0.5.7-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9ccd078c66a8e419475174bfe60a69adb36ce04f8d4e91b006f1329d5cd44bcf"}, + {file = "ruff-0.5.7-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7e31c9bad4ebf8fdb77b59cae75814440731060a09a0e0077d559a556453acbb"}, + {file = "ruff-0.5.7-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d796327eed8e168164346b769dd9a27a70e0298d667b4ecee6877ce8095ec8e"}, + {file = "ruff-0.5.7-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:4a09ea2c3f7778cc635e7f6edf57d566a8ee8f485f3c4454db7771efb692c499"}, + {file = "ruff-0.5.7-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:a36d8dcf55b3a3bc353270d544fb170d75d2dff41eba5df57b4e0b67a95bb64e"}, + {file = "ruff-0.5.7-py3-none-musllinux_1_2_i686.whl", hash = "sha256:9369c218f789eefbd1b8d82a8cf25017b523ac47d96b2f531eba73770971c9e5"}, + {file = "ruff-0.5.7-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:b88ca3db7eb377eb24fb7c82840546fb7acef75af4a74bd36e9ceb37a890257e"}, + {file = "ruff-0.5.7-py3-none-win32.whl", hash = "sha256:33d61fc0e902198a3e55719f4be6b375b28f860b09c281e4bdbf783c0566576a"}, + {file = "ruff-0.5.7-py3-none-win_amd64.whl", hash = "sha256:083bbcbe6fadb93cd86709037acc510f86eed5a314203079df174c40bbbca6b3"}, + {file = "ruff-0.5.7-py3-none-win_arm64.whl", hash = "sha256:2dca26154ff9571995107221d0aeaad0e75a77b5a682d6236cf89a58c70b76f4"}, + {file = "ruff-0.5.7.tar.gz", hash = "sha256:8dfc0a458797f5d9fb622dd0efc52d796f23f0a1493a9527f4e49a550ae9a7e5"}, ] [[package]] @@ -331,4 +331,4 @@ files = [ [metadata] lock-version = "2.0" python-versions = "^3.11" -content-hash = "98d56cdd3df5b5aa15df8ebd19d0ecb25fe2abc128a75ed9fae7e46bc7623f9f" +content-hash = "15050b0eb2eec2ad7205dece0029bc7da8441773a3b266ad0a2be6da16e4de88" diff --git a/pyproject.toml b/pyproject.toml index d18de95..fbfec5a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "python-redux" -version = "0.15.10" +version = "0.16.0" description = "Redux implementation for Python" authors = ["Sassan Haradji "] license = "Apache-2.0" @@ -20,8 +20,8 @@ optional = true [tool.poetry.group.dev.dependencies] poethepoet = "^0.24.4" -pyright = "^1.1.373" -ruff = "^0.5.4" +pyright = "^1.1.376" +ruff = "^0.5.7" pytest = "^8.1.1" pytest-cov = "^4.1.0" pytest-timeout = "^2.3.1" diff --git a/redux/autorun.py b/redux/autorun.py index c5eb677..82d4ce6 100644 --- a/redux/autorun.py +++ b/redux/autorun.py @@ -181,7 +181,7 @@ def _call( ) -> None: self._should_be_called = False func = self._func() if isinstance(self._func, weakref.ref) else self._func - if func: + if func and self._last_selector_result is not None: value: AutorunOriginalReturnType = func( self._last_selector_result, *args, @@ -231,8 +231,10 @@ def __repr__( AutorunArgs, ], ) -> str: - return f"""{super().__repr__()}(func: {self._func}, last_value: { - self._latest_value})""" + return ( + super().__repr__() + + f'(func: {self._func}, last_value: {self._latest_value})' + ) @property def value( diff --git a/redux/combine_reducers.py b/redux/combine_reducers.py index b2e70e7..2d443ca 100644 --- a/redux/combine_reducers.py +++ b/redux/combine_reducers.py @@ -46,10 +46,7 @@ def combine_reducers( reducers = reducers.copy() _id = uuid.uuid4().hex - state_class = cast( - type[state_type], - make_immutable(state_type.__name__, (('_id', str), *reducers.keys())), - ) + state_class = make_immutable(state_type.__name__, (('_id', str), *reducers.keys())) def combined_reducer( state: CombineReducerState | None, diff --git a/redux/main.py b/redux/main.py index 3b4b82e..319e3ea 100644 --- a/redux/main.py +++ b/redux/main.py @@ -102,7 +102,7 @@ def __init__( self._is_running = Lock() - self.subscribe_event(cast(type[Event], FinishEvent), self._handle_finish_event) + self.subscribe_event(FinishEvent, self._handle_finish_event) if self.store_options.auto_init: if self.store_options.scheduler: @@ -164,16 +164,20 @@ def run(self: Store[State, Action, Event]) -> None: def clean_up(self: Store[State, Action, Event]) -> None: """Clean up the store.""" - self._event_handlers_queue.join() + self.wait_for_event_handlers() for _ in range(self.store_options.threads): self._event_handlers_queue.put_nowait(None) - self._event_handlers_queue.join() + self.wait_for_event_handlers() for worker in self._workers: worker.join() self._workers.clear() self._listeners.clear() self._event_handlers.clear() + def wait_for_event_handlers(self: Store[State, Action, Event]) -> None: + """Wait for the event handlers to finish.""" + self._event_handlers_queue.join() + def dispatch( self: Store[State, Action, Event], *parameters: DispatchParameters[Action, Event], @@ -245,14 +249,14 @@ def subscribe_event( else: handler_ref = weakref.ref(handler) - self._event_handlers[cast(type[Event], event_type)].add(handler_ref) + self._event_handlers[cast(Any, event_type)].add(handler_ref) def unsubscribe() -> None: - self._event_handlers[cast(type[Event], event_type)].discard(handler_ref) + self._event_handlers[cast(Any, event_type)].discard(handler_ref) return unsubscribe - def wait_for_store_to_finish(self: Store[State, Action, Event]) -> None: + def _wait_for_store_to_finish(self: Store[State, Action, Event]) -> None: """Wait for the store to finish.""" import time @@ -270,7 +274,7 @@ def wait_for_store_to_finish(self: Store[State, Action, Event]) -> None: time.sleep(0.1) def _handle_finish_event(self: Store[State, Action, Event]) -> None: - Thread(target=self.wait_for_store_to_finish).start() + Thread(target=self._wait_for_store_to_finish).start() @overload def autorun(