Transitive synchronization and shared-state fusion for Python through Nexus fusion and atomic internal synchronization
Project description
NexPy โ Transitive Synchronization and Shared-State Fusion for Python
NexPy (distributed on PyPI as nexpylib) is a reactive synchronization framework for Python that provides a universal mechanism for maintaining coherent shared state across independent objects through Nexus fusion and internal Hook synchronization.
๐ฏ Core Concept: Inter-Object Synchronization via Nexus Fusion
Unlike traditional reactive frameworks that propagate changes through dependency graphs, NexPy creates fusion domains where multiple hooks share a single Nexusโa centralized synchronization core that holds and propagates state.
What is a Nexus?
A Nexus is a shared synchronization core that represents a fusion domain. Each Hook in NexPy references a Nexus, but does not own itโinstead, multiple hooks may share the same Nexus, forming a dynamic network of coherence.
What is Nexus Fusion?
When two hooks are joined, their respective Nexuses undergo a fusion process:
- Original Nexuses are destroyed โ Both hooks' previous Nexuses cease to exist
- New unified Nexus is created โ A single Nexus is created to hold the shared value
- Both hooks join the same fusion domain โ They now share synchronized state
This joining is:
- Symmetric โ
A.join(B)is equivalent toB.join(A) - Transitive โ Joining creates equivalence chains across all connected hooks
- Non-directional โ There's no "master" or "slave"; all hooks are equal participants
Transitive Synchronization Example
import nexpy as nx
A = nx.Hook(1)
B = nx.Hook(2)
C = nx.Hook(3)
D = nx.Hook(4)
# Create first fusion domain
A.join(B) # โ creates Nexus_AB containing A and B
# Create second fusion domain
C.join(D) # โ creates Nexus_CD containing C and D
# Fuse both domains by connecting any pair
B.join(C) # โ fuses both domains โ Nexus_ABCD
# All four hooks now share the same Nexus and value
# Even though A and D were never joined directly!
print(A.value, B.value, C.value, D.value) # All have the same value
# Changing any hook updates all hooks in the fusion domain
A.value = 42
print(A.value, B.value, C.value, D.value) # 42 42 42 42
Hook Isolation
A hook can later be isolated, which:
- Removes it from its current fusion domain
- Creates a new, independent Nexus initialized with the hook's current value
- Leaves remaining hooks still joined and synchronized
import nexpy as nx
A = nx.Hook(1)
B = nx.Hook(1)
C = nx.Hook(1)
A.join(B)
B.join(C)
# All share Nexus_ABC
B.isolate()
# B now has a fresh Nexus_B
# A and C remain joined via Nexus_AC
A.value = 10
print(A.value, B.value, C.value) # 10 1 10
โ๏ธ Internal Synchronization: Intra-Object Coherence
In addition to global fusion, NexPy maintains atomic internal synchronization among related hooks within a single object through a transaction-like validation and update protocol.
Example: XDictSelect โ Multi-Hook Atomic Synchronization
XDictSelect exposes 5 synchronized hooks: dict, keys, values, key, and value.
import nexpy as nx
# Create a selection dict that maintains consistency between
# the dict, selected key, and corresponding value
select = nx.XDictSelect({"a": 1, "b": 2, "c": 3}, key="a")
# All hooks are synchronized
print(select.dict_hook.value) # {"a": 1, "b": 2, "c": 3}
print(select.key_hook.value) # "a"
print(select.value_hook.value) # 1
# Changing the key automatically updates the value
select.key = "b"
print(select.value) # 2
# Changing the value updates the dictionary
select.value = 20
print(select.dict) # {"a": 1, "b": 20, "c": 3}
# All changes maintain invariants atomically
The Internal Synchronization Protocol
When one hook changes (e.g., key), NexPy:
- Determines affected Nexuses โ Which related Nexuses must update (e.g.,
value,dict) - Readiness check (validation pre-step) โ Queries each affected Nexus via validation callbacks
- Atomic update โ If all Nexuses report readiness, applies all updates in one transaction
- Rejection โ Otherwise rejects the change to maintain global validity
This ensures the system is:
- Atomic โ All updates occur together or not at all
- Consistent โ Constraints are always satisfied
- Isolated โ Concurrent modifications are safely locked
- Durable (logical) โ Once accepted, coherence persists until the next explicit change
NexPy guarantees continuous validity both within objects (internal sync) and across objects (Nexus fusion).
๐ Quick Start
Installation
pip install nexpylib
Basic Usage
1. Simple Reactive Value
import nexpy as nx
# Create a reactive value
value = nx.XValue(42)
# Read the value
print(value.value) # 42
# Update the value
value.value = 100
print(value.value) # 100
# Add a listener that reacts to changes
def on_change():
print(f"Value changed to: {value.value}")
value.value_hook.add_listener(on_change)
value.value = 200 # Prints: "Value changed to: 200"
2. Hook Fusion Across Independent Objects
import nexpy as nx
# Create two independent reactive values
temperature_sensor = nx.XValue(20.0)
display_value = nx.XValue(0.0)
# Fuse them so they share the same state
temperature_sensor.value_hook.join(display_value.value_hook)
# Now they're synchronized
print(temperature_sensor.value, display_value.value) # 20.0 20.0
# Changing one updates the other
temperature_sensor.value = 25.5
print(display_value.value) # 25.5
3. Reactive Collections
import nexpy as nx
# Reactive list
numbers = nx.XList([1, 2, 3])
numbers.list_hook.add_listener(lambda: print(f"List changed: {numbers.list}"))
numbers.append(4) # Prints: "List changed: [1, 2, 3, 4]"
# Reactive set
tags = nx.XSet({"python", "reactive"})
tags.add("framework")
print(tags.set) # {"python", "reactive", "framework"}
# Reactive dict
config = nx.XDict({"debug": False, "version": "1.0"})
config["debug"] = True
print(config.dict) # {"debug": True, "version": "1.0"}
4. Selection Objects with Internal Synchronization
import nexpy as nx
# Create a selection from a dictionary
options = nx.XDictSelect(
{"low": 1, "medium": 5, "high": 10},
key="medium"
)
print(options.key) # "medium"
print(options.value) # 5
# Change selection
options.key = "high"
print(options.value) # 10 (automatically updated)
# Modify value (updates dict atomically)
options.value = 15
print(options.dict) # {"low": 1, "medium": 5, "high": 15}
5. Adapter Objects for Type Bridging
import nexpy as nx
# Bridge between int and Optional[int] (blocks None on the T side)
optional_adapter = nx.XOptionalAdapter[int](
hook_t_or_value=42,
hook_optional=None
)
print(optional_adapter.hook_t.value) # 42
print(optional_adapter.hook_optional.value) # 42
# Update via either hook - they stay synchronized
optional_adapter.hook_t.value = 100
print(optional_adapter.hook_optional.value) # 100
# Bridge between set and sequence with custom sorting
set_seq_adapter = nx.XSetSequenceAdapter[int](
hook_set_or_value={3, 1, 2},
hook_sequence=None,
sort_callable=lambda s: list(reversed(sorted(s))) # Reverse order
)
print(set_seq_adapter.hook_set.value) # {3, 1, 2}
print(set_seq_adapter.hook_sequence.value) # [3, 2, 1] (reverse sorted)
6. Configuring Floating-Point Tolerance
import nexpy as nx
from nexpy import default
# Configure BEFORE creating any observables
# Adjust tolerance based on your use case:
# - UI applications: 1e-6 to 1e-3 (more lenient)
# - General purpose: 1e-9 (default)
# - Scientific: 1e-12 to 1e-15 (high precision)
default.FLOAT_ACCURACY = 1e-6 # Lenient for UI work
# Now floating-point comparisons use the configured tolerance
temperature = nx.XValue(20.0)
temperature.value = 20.0000001 # No update (within tolerance)
temperature.value = 20.001 # Update triggered (exceeds tolerance)
๐ Key Features
๐ Transitive Hook Fusion
- Join any hooks to create fusion domains
- Transitive synchronization:
AโB+BโC=AโBโC - Symmetric and non-directional connections
- Isolate hooks to break fusion domains
โ๏ธ Atomic Internal Synchronization
- ACID-like guarantees for multi-hook objects
- Transaction-style validation and updates
- Automatic constraint maintenance
- Continuous validity enforcement
๐ Reactive Collections
XListโ Reactive lists with element accessXSetโ Reactive sets with membership trackingXDictโ Reactive dictionaries with key-value pairs- Full Python collection protocol support
๐ฏ Selection Objects
XDictSelectโ Select key-value pairs from dictsXSetSingleSelectโ Select single elements from setsXSetMultiSelectโ Multiple selection support- Optional selection variants (allow
Noneselection)
๐ Adapter Objects
XOptionalAdapterโ Bridge betweenTandOptional[T](blocksNone)XIntFloatAdapterโ Bridge betweenintandfloat(validates integer-valued floats)XSetSequenceAdapterโ Bridge betweenAbstractSetandSequence(validates unique elements)- Custom sorting control for set-to-sequence conversion
- Type-safe bridging between incompatible hook types
๐ Thread-Safe by Design
- All operations protected by reentrant locks
- Safe concurrent access from multiple threads
- Reentrancy protection against recursive modifications
- Independent nested submissions allowed
๐ญ Multiple Notification Philosophies
- Listeners (Synchronous) โ Direct callbacks during updates
- Publish-Subscribe (Asynchronous) โ Decoupled async notifications
- Hooks (Bidirectional Validation) โ Enforce constraints across objects
๐ฏ Custom Equality Checks
- Built-in floating-point tolerance (configurable via
default.FLOAT_ACCURACY) - Standard practice: 1e-9 tolerance to avoid spurious updates
- Cross-type comparison support (e.g.,
floatvsint) - Register custom equality callbacks for specialized types at the NexusManager level
๐ Documentation
- Usage Guide โ Join/isolate mechanics, Hook basics, Nexus fusion
- Internal Synchronization โ Atomic updates and validation protocol
- Architecture โ Design philosophy, data flow, locking
- API Reference โ Complete API documentation
- Examples โ Practical examples and runnable code
- Concepts โ Deep dive into fusion domains and synchronization
๐๏ธ Architecture Overview
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ User Objects โ
โ โโโโโโโโโโโโ โโโโโโโโโโโโ โโโโโโโโโโโโ โโโโโโโโโโโโ โ
โ โ XValue โ โ XDict โ โ XList โ โ XSet โ โ
โ โโโโโโฌโโโโโโ โโโโโโฌโโโโโโ โโโโโโฌโโโโโโ โโโโโโฌโโโโโโ โ
โโโโโโโโโผโโโโโโโโโโโโโโผโโโโโโโโโโโโโโผโโโโโโโโโโโโโโผโโโโโโโโโโโ
โ โ โ โ
โโโโโโโโโโโโโโโดโโโโโโโโโโโโโโดโโโโโโโโโโโโโโ
โ
โโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโ
โ Hook Layer โ
โ (Owned Hooks + Floating Hooks) โ
โโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโ
โ
โโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโ
โ Nexus Layer โ
โ (Fusion Domains + Shared State) โ
โโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโ
โ
โโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโ
โ NexusManager โ
โ (Coordination + Validation) โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Key Components:
- Hooks โ Connection points that reference Nexuses
- Nexus โ Shared synchronization core for fusion domains
- NexusManager โ Central coordinator for validation and updates
- X Objects โ High-level reactive data structures
๐ Use Cases
1. GUI Data Binding
import nexpy as nx
# Model
user_name = nx.XValue("Alice")
# View (simulated)
class TextWidget:
def __init__(self, hook):
self.hook = hook
hook.add_listener(self.refresh)
def refresh(self):
print(f"Display: {self.hook.value}")
widget = TextWidget(user_name.value_hook)
# Changing model updates view automatically
user_name.value = "Bob" # Display: Bob
2. Configuration Synchronization
import nexpy as nx
# Multiple configuration stores that stay in sync
app_config = nx.XDict({"theme": "dark", "lang": "en"})
cache_config = nx.XDict({})
# Fuse configuration hooks
cache_config.dict_hook.join(app_config.dict_hook)
# Both stay synchronized
app_config["theme"] = "light"
print(cache_config["theme"]) # "light"
3. State Machines with Atomic Transitions
import nexpy as nx
states = {"idle", "running", "paused", "stopped"}
current = nx.XDictSelect(
{state: state for state in states},
key="idle"
)
def validate_transition(values):
# Add custom validation logic
if values["key"] == "running" and some_condition:
return False, "Cannot transition to running"
return True, "Valid"
# Transitions are atomic and validated
try:
current.key = "running"
except ValueError as e:
print(f"Transition rejected: {e}")
๐ค Contributing
Contributions are welcome! Please see our Contributing Guide for details.
Development Setup
# Clone the repository
git clone https://github.com/babrandes/nexpylib.git
cd nexpylib
# Install in development mode
pip install -e .
# Run tests
python -m pytest tests/
๐ License
This project is licensed under the Apache License 2.0 โ see the LICENSE file for details.
๐ Links
- PyPI: https://pypi.org/project/nexpylib/
- GitHub: https://github.com/babrandes/nexpylib
- Documentation: https://github.com/babrandes/nexpylib#readme
- Issue Tracker: https://github.com/babrandes/nexpylib/issues
๐ฏ Changelog
See CHANGELOG.md for a list of changes between versions.
โญ Star History
If you find NexPy useful, please consider starring the repository on GitHub!
Built with โค๏ธ by Benedikt Axel Brandes
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 nexpylib-0.6.0.tar.gz.
File metadata
- Download URL: nexpylib-0.6.0.tar.gz
- Upload date:
- Size: 235.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fc611a6ea34fd82d1dad76561c76818148ae7d1bb0fec499527b11b34dbe8d3e
|
|
| MD5 |
0f66851e98287bac4dd9fbe0f32a3c0d
|
|
| BLAKE2b-256 |
9bbe28f1043f762785661f3e2ef1431203df6f79a8a7026032b7f7381e555361
|
File details
Details for the file nexpylib-0.6.0-py3-none-any.whl.
File metadata
- Download URL: nexpylib-0.6.0-py3-none-any.whl
- Upload date:
- Size: 187.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f7beb3c5a6964756c8eb7ec424ca0fb8d889e873fa035b7f4e472a603bcc5824
|
|
| MD5 |
2cee3eda5e587f1a489f28b04af2f5ef
|
|
| BLAKE2b-256 |
1c9aca9f34aacfdfdb464c4f387cdea98302b186bce96d032b03c71be272628b
|