A python implementation of Operational Transformation.
Project description
Python-OTType
A python library for Operational Transformation (OT). Basic idea follows the spec at https://github.com/ottypes/docs.
Supported Python versions : CPython 3.9 - 3.12, PyPy 3.9 - 3.10
Installation
pip install python-ottype
Basic usage:
import ottype
assert ottype.apply('asdf', [3, '123', {'d':'f'}]) == 'asd123'
OT Operations
Skip
Object type : int
Skip n
characters from the current position is represented as n
assert apply('asdf', [3]) == 'asdf'
Insert
Object type : str
Insert a string s
at the current position is represented as s
assert apply('asdf', ['qwer']) == 'qwerasdf'
assert apply('asdf', [2, 'qwer']) == 'asqwerdf'
Delete
Object type : dict
Delete a string s
at the current position is represented as {'d': s}
assert apply('asdf', [{'d': 'as'}]) == 'df'
assert apply('asdf', [1, {'d': 'sd'}]) == 'af'
Supported Functions
OT = int | str | dict[str, str]
check(ots: Sequence[OT], *, check_unoptimized: bool = True) -> bool
Check the sequence if it only contains valid OTs. If check_unoptimized
is True
, only normalized sequence of OTs is accepted.
assert check(['a', 4, 'b'])
assert not check(['a', 'b']) # is not normalized
assert not check([3]) # is not normalized
apply(doc: str, ots: Sequence[OT], *, check_unoptimized: bool = True) -> str
Apply a sequence of OTs to a string.
assert apply('abcde', [2, 'qq', {'d': 'c'}, 1, 'w']) == 'abqqdwe'
inverse_apply(doc: str, ots: Sequence[OT], *, check_unoptimized: bool = True) -> str
Inversely apply a sequence of OTs to a string.
assert inverse_apply(apply(doc, ots), ots) == doc
normalize(ots: Sequence[OT]) -> Sequence[OT]
Normalize a sequence of OTs : merge consecutive OTs and trim the last skip operation.
assert normalize([1, 2, 'as', 'df', {'d': 'qw'}, {'d': 'er'}, 3]) \
== [3, 'asdf', {'d': 'qwer'}]
transform(ots1: Sequence[OT], ots2: Sequence[OT]) -> Sequence[OT]
Transform a sequence of OTs with the property:
assert apply(apply(doc, ots1), transform(ots2, ots1, 'left')) \
== apply(apply(doc, ots2), transform(ots1, ots2, 'right'))
compose(ots1: Sequence[OT], ots2: Sequence[OT]) -> Sequence[OT]
Compose two sequences of OTs with the property:
assert apply(apply(doc, ots1), ots2) == apply(doc, compose(ots1, ots2))
Benchmark (at CPython 3.12.1)
Benchmark : apply
operation
len(doc) | len(ots) | python (Kops/s) | cython (Kops/s) |
---|---|---|---|
100 | 5 | 289.58 ( 1.00x) | 663.47 ( 2.29x) |
100 | 10 | 206.50 ( 1.00x) | 513.00 ( 2.48x) |
100 | 20 | 114.52 ( 1.00x) | 298.82 ( 2.61x) |
100 | 50 | 48.37 ( 1.00x) | 127.90 ( 2.64x) |
100 | 100 | 26.96 ( 1.00x) | 71.84 ( 2.66x) |
1000 | 5 | 412.41 ( 1.00x) | 974.43 ( 2.36x) |
1000 | 10 | 220.19 ( 1.00x) | 493.53 ( 2.24x) |
1000 | 20 | 128.66 ( 1.00x) | 317.18 ( 2.47x) |
1000 | 50 | 37.56 ( 1.00x) | 98.56 ( 2.62x) |
1000 | 100 | 23.43 ( 1.00x) | 64.25 ( 2.74x) |
10000 | 5 | 203.14 ( 1.00x) | 322.31 ( 1.59x) |
10000 | 10 | 142.25 ( 1.00x) | 279.79 ( 1.97x) |
10000 | 20 | 95.63 ( 1.00x) | 202.97 ( 2.12x) |
10000 | 50 | 48.58 ( 1.00x) | 122.09 ( 2.51x) |
10000 | 100 | 21.17 ( 1.00x) | 57.59 ( 2.72x) |
Benchmark : inverse_apply
operation
len(doc) | len(ots) | python (Kops/s) | cython (Kops/s) |
---|---|---|---|
100 | 5 | 194.12 ( 1.00x) | 408.56 ( 2.10x) |
100 | 10 | 113.27 ( 1.00x) | 269.10 ( 2.38x) |
100 | 20 | 60.99 ( 1.00x) | 150.49 ( 2.47x) |
100 | 50 | 26.35 ( 1.00x) | 64.27 ( 2.44x) |
100 | 100 | 16.62 ( 1.00x) | 42.87 ( 2.58x) |
1000 | 5 | 309.57 ( 1.00x) | 565.47 ( 1.83x) |
1000 | 10 | 153.62 ( 1.00x) | 351.55 ( 2.29x) |
1000 | 20 | 69.48 ( 1.00x) | 162.52 ( 2.34x) |
1000 | 50 | 37.12 ( 1.00x) | 91.88 ( 2.48x) |
1000 | 100 | 17.06 ( 1.00x) | 42.51 ( 2.49x) |
10000 | 5 | 145.11 ( 1.00x) | 257.81 ( 1.78x) |
10000 | 10 | 96.66 ( 1.00x) | 198.97 ( 2.06x) |
10000 | 20 | 65.18 ( 1.00x) | 140.90 ( 2.16x) |
10000 | 50 | 27.40 ( 1.00x) | 67.74 ( 2.47x) |
10000 | 100 | 13.53 ( 1.00x) | 32.23 ( 2.38x) |
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 Distributions
Hashes for python_ottype-24.6.0-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 54112bac3ef09518591c1eb6abb7df23d51977809917ce8635561c0b6ca99fca |
|
MD5 | 37195f524e056338041f2675a04e363b |
|
BLAKE2b-256 | 884456e1fa6652e6195aee8778c955012a4c3c0e2266e8eb40118367c2d27ae6 |
Hashes for python_ottype-24.6.0-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 5c16b863cdc6ddbe246f96bcf405579e39454920a8a69f59b0db54e9e0a73b61 |
|
MD5 | 6e8900581eaf6d01562b3d86fa8659f4 |
|
BLAKE2b-256 | 93d0e690fa9290063776c37006bdd431def35f1cd10a9e4c083c752bd0a534f3 |
Hashes for python_ottype-24.6.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 54f394b2e27c7add1d23a7a1a719d210af46b6731724fa1b0a2db2f00009fc82 |
|
MD5 | 6d5e7477ef2120ad4041503ced577d1d |
|
BLAKE2b-256 | 1d298028fc9d4590bf544f9a6a1e824df2f94b4d774b80aaa719dee861e752f1 |
Hashes for python_ottype-24.6.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | ad1f4b5f06d5f6b887aaf5734b89eaffbad50bef81ff9e8a5acc35346df27b5f |
|
MD5 | 41200e4ee35692ceabfd5e0fb944a3d5 |
|
BLAKE2b-256 | 83d29d591b6236a3527f764cd0e775734712c4970767a8e40329f928e6ea899a |
Hashes for python_ottype-24.6.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | f351bab11ce2cef7e566a0d5c3791840925eddeb2444377a7dfcd2ccad2d4b40 |
|
MD5 | b5a575f2b5d4c279d5698b24716cf636 |
|
BLAKE2b-256 | 0822e4cdcb2f99abd2551ad281d78fc6b83ea4581a00591ed95b01474da13e67 |
Hashes for python_ottype-24.6.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 610b54586153c07c7d56d4c670198939ae94de82e99f93397688f74a3eb8b782 |
|
MD5 | 7f56f500556509c5520eb6e7fee752ec |
|
BLAKE2b-256 | 627e88c758477db7ad91932bd0b104ce8dbba96daf4382a02f5f898b26f8fca2 |