A Python state management library inspired by NgRx
Project description
Pystorex
A lightweight Python state management library inspired by NgRx/Redux patterns and ReactiveX for Python (reactivex). Manage application state with reducers, handle side effects with effects, compose middleware, and select state slices efficiently.
Features
- Typed State: Define your root state using Pydantic or any Python object, fully generic.
- Reducers: Pure functions to update state in response to actions.
- Effects: Handle side effects by listening to action streams and optionally dispatching actions.
- Middleware: Insert custom logic (logging, thunks, error handling) into dispatch pipeline.
- Selectors: Memoized and configurable (deep compare, TTL) state accessors.
- Immutable Updates: Shallow copy at feature level or integrate with
immutables.Map. - Hot Module Management: Register/unregister feature reducers and effects at runtime.
Installation
pip install pystorex
Requires Python 3.7+
Quick Start
from pystorex import create_store, create_reducer, on, create_effect, create_selector
from pydantic import BaseModel
# 1. Define your state models
class CounterState(BaseModel):
count: int = 0
# 2. Create actions
from pystorex.actions import create_action
increment = create_action("increment")
decrement = create_action("decrement")
# 3. Create reducer
def counter_handler(state: CounterState, action):
if action.type == increment.type:
state.count += 1
elif action.type == decrement.type:
state.count -= 1
return state
counter_reducer = create_reducer(CounterState(), on(increment, counter_handler), on(decrement, counter_handler))
# 4. Create store
store = create_store(CounterState())
store.register_root({"counter": counter_reducer})
# 5. Subscribe to state changes
store.select(lambda s: s.counter.count).subscribe(lambda new: print("Count:", new))
# 6. Dispatch actions
store.dispatch(increment()) # Count: 1
store.dispatch(increment()) # Count: 2
store.dispatch(decrement()) # Count: 1
Examples
This project includes the following example scripts to demonstrate both the modular and monolithic usage patterns:
Counter Example
examples/counter_example/main.py: Entry point for the modular Counter example.examples/counter_example/counter_example_monolithic.py: Monolithic Counter example.
Detection Example
examples/detection_example/main.py: Entry point for the modular Detection example.examples/detection_example/detection_example_monolithic.py: Monolithic Detection example.
You can run them from the project root:
python examples/counter_example/main.py
python examples/counter_example/counter_example_monolithic.py
python examples/detection_example/main.py
python examples/detection_example/detection_example_monolithic.py
Core Concepts
Store
Manages application state, dispatches actions, and notifies subscribers.
store = create_store(MyRootState())
store.register_root({
"feature_key": feature_reducer,
# ... more reducers
})
store.register_effects(FeatureEffects)
Actions
Use create_action(type, prepare_fn) to define action creators.
from pystorex.actions import create_action
my_action = create_action("myAction", lambda data: {"payload": data})
Reducers
Pure functions taking (state, action) and returning new state.
from pystorex import create_reducer, on
reducer = create_reducer(
InitialState(),
on(my_action, my_handler)
)
Effects
Side-effect handlers listening to action streams via ReactiveX.
from pystorex import create_effect
from reactivex import operators as ops
class FeatureEffects:
@create_effect
def log_actions(action$):
return action$.pipe(
ops.filter(lambda a: a.type == my_action.type),
ops.map(lambda _: another_action())
)
Middleware
Insert custom dispatch logic. Example: Logger
class LoggerMiddleware:
def on_next(self, action): print("▶️", action.type)
def on_complete(self, result, action): print("✅", action)
def on_error(self, err, action): print("❌", err)
store.apply_middleware(LoggerMiddleware)
Selectors
Memoized accessors with optional deep=True or ttl.
from pystorex.selectors import create_selector
get_items = create_selector(
lambda s: s.feature.items,
result_fn=lambda items: [i.value for i in items],
deep=True, ttl=5.0
)
Advanced Topics
- Hot Module DnD:
store.register_feature/store.unregister_featureto add/remove features at runtime. - Immutable State: Integrate
immutables.Mapfor structural sharing. - DevTools: Capture action/state history for time-travel debugging.
Publishing to PyPI
- Ensure
pyproject.toml&setup.cfgare configured. - Install build tools:
pip install --upgrade build twine
- Build distributions:
python -m build
- Upload:
python -m twine upload dist/*
Contributing
- Fork the repo
- Create a feature branch
- Write tests (pytest) and update docs
- Submit a Pull Request
License
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pystorex-0.1.6.tar.gz.
File metadata
- Download URL: pystorex-0.1.6.tar.gz
- Upload date:
- Size: 20.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.11.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
86303e8dadf2439a933188f0bfeab4f8980c415a0279332d6da07b8226170b08
|
|
| MD5 |
074b192388a288d84dc44d0728354434
|
|
| BLAKE2b-256 |
ef6deb04dbb8a4f78f6da0b0e49a4fb3103d7a4fcd221219b9728c049149e58c
|
File details
Details for the file pystorex-0.1.6-py3-none-any.whl.
File metadata
- Download URL: pystorex-0.1.6-py3-none-any.whl
- Upload date:
- Size: 20.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.11.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4ab95a4b235444b3bcfdb5ca20b5ed2a24062eecc63e3f00ba6ebf35933c7805
|
|
| MD5 |
78b83a0d27673cb11024bf89f33986f4
|
|
| BLAKE2b-256 |
fc9504c13179b1b73189cd88f9bfc211456e2d2d2b867f7b1c8a9a166f48080e
|