Metadata-Version: 2.5
Name: accordsync-core
Version: 0.3.2
Summary: Accord's merge core: hybrid logical clocks, operations, lww, counter, set and conflict.
Project-URL: Homepage, https://accord.benhattab.pro
Project-URL: Source, https://github.com/crossben/accordsync-python
License-Expression: Apache-2.0
License-File: LICENSE
Keywords: crdt,local-first,offline-first,sync
Requires-Python: >=3.11
Description-Content-Type: text/markdown

# accordsync-core

**Accord's merge core for Python: hybrid logical clocks, operations and the four merge strategies.**

Pure Python, no I/O, no dependencies. Most programs use the client
[`accordsync`](https://pypi.org/project/accordsync/) or the server
[`accordsync-server`](https://pypi.org/project/accordsync-server/), which depend on it. Python 3.11+.

```sh
pip install accordsync-core
```

| Strategy | Merges by |
| --- | --- |
| `lww()` | Highest hybrid logical clock wins. |
| `counter()` | Sum of every increment; none is ever lost. |
| `set_()` | Add-wins set: a remove only removes what its writer had seen. |
| `conflict()` | Concurrent values are all kept and the field is flagged; a resolution supersedes exactly the values its writer saw. |

`set_()` has a trailing underscore so it does not shadow Python's `set`.

```python
import time

from accordsync_core import LocalWriter, conflict, counter, define_schema

schema = define_schema({"dossier": {"visits": counter(), "status": conflict()}})


def now() -> int:
    return time.time_ns() // 1_000_000


a = LocalWriter(schema, "phone-a", now)
b = LocalWriter(schema, "phone-b", now)

# Each device writes offline...
from_a = [a.inc("dossier:1", "visits", 1), a.assign("dossier:1", "status", "approved")]
from_b = [b.inc("dossier:1", "visits", 2), b.assign("dossier:1", "status", "rejected")]

# ...then they exchange ops, in any order, as often as the network repeats them.
for op in from_b + from_b:
    a.receive(op)
for op in reversed(from_a):
    b.receive(op)

assert a.replica.snapshot() == b.replica.snapshot()
print(a.replica.read("dossier:1"))
# {'visits': 3, 'status': {'conflicted': [{'value': 'approved', 'opId': 'phone-a:2'},
#                                         {'value': 'rejected', 'opId': 'phone-b:2'}]}}
```

It merges byte for byte like [`@accordsync/core`](https://www.npmjs.com/package/@accordsync/core):
the test suite runs the shared golden vectors in every delivery order, and random scenarios
generated by the TypeScript core must produce identical snapshots here.

Docs: [accord.benhattab.pro/docs/schema](https://accord.benhattab.pro/docs/schema/) ·
Source: [crossben/accordsync-python](https://github.com/crossben/accordsync-python) · Licence: Apache-2.0
