Skip to content

Commit

Permalink
docs: update path of demos migrated to tests in README.md
Browse files Browse the repository at this point in the history
refactor: remove `set_customer_serializer` in favor of overridable `serialize_value`
  • Loading branch information
sassanh committed Mar 16, 2024
1 parent 9de215e commit fcc6d6e
Show file tree
Hide file tree
Showing 4 changed files with 27 additions and 20 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Changelog

## Version 0.12.2

- docs: update path of demos migrated to tests in `README.md`
- refactor: remove `set_customer_serializer` in favor of overridable `serialize_value`

## Version 0.12.1

- refactor: move store serializer from test framework to code `Store` class
Expand Down
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,8 @@ side effects.
This concept fills the gap in handling side effects within Redux's ecosystem, offering
a more nuanced and integrated approach to state and side effect management.

See todo sample below or check the [demo](demo.py) to see it in action.
See todo sample below or check the [todo demo](/tests/test_todo.py) or
[features demo](/tests/test_features.py) to see it in action.

### Autorun Decorator

Expand All @@ -97,7 +98,8 @@ selector's return value. This mechanism ensures that the decorated function runs
in response to relevant state changes, enhancing efficiency and responsiveness in
the application.

See todo sample below or check the [demo](demo.py) to see it in action.
See todo sample below or check the [todo demo](/tests/test_todo.py) or
[features demo](/tests/test_features.py) to see it in action.

### Combining reducers - `combine_reducers`

Expand Down Expand Up @@ -241,7 +243,7 @@ store.dispatch(FinishAction())

## 🎉 Demo

For a detailed example, see `demo.py` in the [GitHub repository](https://github.com/sassanh/python-redux).
For a detailed example, see [features demo](/tests/test_features.py).

## 🤝 Contributing

Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "python-redux"
version = "0.12.1"
version = "0.12.2"
description = "Redux implementation for Python"
authors = ["Sassan Haradji <[email protected]>"]
license = "Apache-2.0"
Expand Down
32 changes: 16 additions & 16 deletions redux/main.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# ruff: noqa: D100, D101, D102, D103, D104, D105, D107
"""Redux store for managing state and side effects."""
from __future__ import annotations

import dataclasses
Expand Down Expand Up @@ -74,13 +74,14 @@ def run(self: _SideEffectRunnerThread[Event]) -> None:


class Store(Generic[State, Action, Event]):
custom_serializer = None
"""Redux store for managing state and side effects."""

def __init__(
self: Store[State, Action, Event],
reducer: ReducerType[State, Action, Event],
options: CreateStoreOptions | None = None,
) -> None:
"""Create a new store."""
self.store_options = options or CreateStoreOptions()
self.reducer = reducer
self._create_task: Callable[[Coroutine], Any] = (
Expand Down Expand Up @@ -175,6 +176,7 @@ def _run_event_handlers(self: Store[State, Action, Event]) -> None:
cast(Callable[[], Any], event_handler)()

def run(self: Store[State, Action, Event]) -> None:
"""Run the store."""
with self._is_running:
while len(self._actions) > 0 or len(self._events) > 0:
if len(self._actions) > 0:
Expand All @@ -189,6 +191,7 @@ def dispatch(
with_state: Callable[[State | None], DispatchParameters[Action, Event]]
| None = None,
) -> None:
"""Dispatch actions and/or events."""
if with_state is not None:
self.dispatch(with_state(self._state))

Expand Down Expand Up @@ -217,6 +220,7 @@ def subscribe(
*,
keep_ref: bool = True,
) -> Callable[[], None]:
"""Subscribe to state changes."""
if keep_ref:
listener_ref = listener
elif inspect.ismethod(listener):
Expand All @@ -234,6 +238,7 @@ def subscribe_event(
*,
options: EventSubscriptionOptions | None = None,
) -> Callable[[], None]:
"""Subscribe to events."""
subscription_options = (
EventSubscriptionOptions() if options is None else options
)
Expand Down Expand Up @@ -271,6 +276,8 @@ def autorun(
SelectorOutput,
AutorunOriginalReturnType,
]:
"""Create a new autorun, reflecting on state changes."""

def decorator(
func: Callable[[SelectorOutput], AutorunOriginalReturnType]
| Callable[[SelectorOutput, SelectorOutput], AutorunOriginalReturnType],
Expand All @@ -285,26 +292,19 @@ def decorator(

return decorator

def set_custom_serializer(
self: Store,
serializer: Callable[[object | type], SnapshotAtom],
) -> None:
"""Set a custom serializer for the store snapshot."""
self.custom_serializer = serializer

@property
def snapshot(self: Store[State, Action, Event]) -> SnapshotAtom:
return self._serialize_value(self._state)
"""Return a snapshot of the current state of the store."""
return self.serialize_value(self._state)

def _serialize_value(self: Store, obj: object | type) -> SnapshotAtom:
if self.custom_serializer:
return self.custom_serializer(obj)
def serialize_value(self: Store, obj: object | type) -> SnapshotAtom:
"""Serialize a value to a snapshot atom."""
if is_immutable(obj):
return self._serialize_dataclass_to_dict(obj)
if isinstance(obj, (list, tuple)):
return [self._serialize_value(i) for i in obj]
return [self.serialize_value(i) for i in obj]
if callable(obj):
return self._serialize_value(obj())
return self.serialize_value(obj())
if isinstance(obj, StrEnum):
return str(obj)
if isinstance(obj, IntEnum):
Expand All @@ -320,6 +320,6 @@ def _serialize_dataclass_to_dict(
) -> dict[str, Any]:
result = {}
for field in dataclasses.fields(obj):
value = self._serialize_value(getattr(obj, field.name))
value = self.serialize_value(getattr(obj, field.name))
result[field.name] = value
return result

0 comments on commit fcc6d6e

Please sign in to comment.