Skip to main content

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.13, PyPy 3.10 - 3.11

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))

diff(doc1: str, doc2: str) -> Sequence[OT]

Generate a sequence of OTs required to change doc1 to doc2:

assert apply(doc1, diff(doc1, doc2)) == doc2

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

python_ottype-25.7.0.tar.gz (12.2 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

python_ottype-25.7.0-pp311-pypy311_pp73-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl (185.9 kB view details)

Uploaded PyPymanylinux: glibc 2.17+ x86-64manylinux: glibc 2.5+ x86-64

python_ottype-25.7.0-pp310-pypy310_pp73-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl (184.1 kB view details)

Uploaded PyPymanylinux: glibc 2.17+ x86-64manylinux: glibc 2.5+ x86-64

python_ottype-25.7.0-cp313-cp313-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl (534.4 kB view details)

Uploaded CPython 3.13manylinux: glibc 2.17+ x86-64manylinux: glibc 2.5+ x86-64

python_ottype-25.7.0-cp312-cp312-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl (542.0 kB view details)

Uploaded CPython 3.12manylinux: glibc 2.17+ x86-64manylinux: glibc 2.5+ x86-64

python_ottype-25.7.0-cp311-cp311-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl (555.0 kB view details)

Uploaded CPython 3.11manylinux: glibc 2.17+ x86-64manylinux: glibc 2.5+ x86-64

python_ottype-25.7.0-cp310-cp310-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl (527.4 kB view details)

Uploaded CPython 3.10manylinux: glibc 2.17+ x86-64manylinux: glibc 2.5+ x86-64

python_ottype-25.7.0-cp39-cp39-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl (528.0 kB view details)

Uploaded CPython 3.9manylinux: glibc 2.17+ x86-64manylinux: glibc 2.5+ x86-64

File details

Details for the file python_ottype-25.7.0.tar.gz.

File metadata

  • Download URL: python_ottype-25.7.0.tar.gz
  • Upload date:
  • Size: 12.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.12.1

File hashes

Hashes for python_ottype-25.7.0.tar.gz
Algorithm Hash digest
SHA256 3a3dac2accd7cae8c9a5216d59fdf50d8e94113cffc7c0791f0f4245c6c21f15
MD5 153fe1a55002e2544f45d819c62e304c
BLAKE2b-256 81ebe24d6e8d810a87dd8a13891847f122db6dda3c80791e8794af38d6828df3

See more details on using hashes here.

File details

Details for the file python_ottype-25.7.0-pp311-pypy311_pp73-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl.

File metadata

File hashes

Hashes for python_ottype-25.7.0-pp311-pypy311_pp73-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl
Algorithm Hash digest
SHA256 292959aa9e49de780b20b169ec536e3d54d981b69527d6753b28dbe5c0fdc63a
MD5 918a68d9095a3870d8bbd20b7ab49f65
BLAKE2b-256 59c83313a21f5adc6bb1cce75c78a16cd1493210d163b651bb026ec00b53697f

See more details on using hashes here.

File details

Details for the file python_ottype-25.7.0-pp310-pypy310_pp73-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl.

File metadata

File hashes

Hashes for python_ottype-25.7.0-pp310-pypy310_pp73-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl
Algorithm Hash digest
SHA256 2b80fc3343139d04b9e40d6820010abf9d2fbe23b0973214b1ea812595558745
MD5 9192534b5cb5c681a450120e623181a3
BLAKE2b-256 d03215923079296911107a235d616742b95271682656732e9eb991d4f6ebfa15

See more details on using hashes here.

File details

Details for the file python_ottype-25.7.0-cp313-cp313-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl.

File metadata

File hashes

Hashes for python_ottype-25.7.0-cp313-cp313-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl
Algorithm Hash digest
SHA256 8532f0f3f54cf12aaa0b1888bc604fa82fe941c352b6a02e4da6af0e93020d0d
MD5 839dc64bc3aadd5f00ffe00c44eb4a64
BLAKE2b-256 a9a654950696e769b30d4d52c7f750145dab2b6f1bfb2b48ab259efefa8ada44

See more details on using hashes here.

File details

Details for the file python_ottype-25.7.0-cp312-cp312-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl.

File metadata

File hashes

Hashes for python_ottype-25.7.0-cp312-cp312-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl
Algorithm Hash digest
SHA256 f9da7865139104444b9ddbb4c4368a925ae35256e10d0c02c6538620443678e5
MD5 f16d9386c7be6ae3323a0db5575af2a1
BLAKE2b-256 e6dc1a4717b3262f7a07fd27f48eabd4ee63ad5c1fc9dda1a28f0e9922c2804b

See more details on using hashes here.

File details

Details for the file python_ottype-25.7.0-cp311-cp311-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl.

File metadata

File hashes

Hashes for python_ottype-25.7.0-cp311-cp311-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl
Algorithm Hash digest
SHA256 26300c10f849bf7a00ec24fd416c7289cb0bce15110cf7b69f2f32be6e6fe5c8
MD5 e7e7452b9756e382f5786b87f023e64c
BLAKE2b-256 b549e677c1c5eabd9118f6565fb45f62eb19e9bafe2baf67cc8adfe70c9161d4

See more details on using hashes here.

File details

Details for the file python_ottype-25.7.0-cp310-cp310-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl.

File metadata

File hashes

Hashes for python_ottype-25.7.0-cp310-cp310-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl
Algorithm Hash digest
SHA256 59a79ec503e964854f978c36029a494e3c7f390551b239f8f4dc14d1804c159c
MD5 5402baba5ee4ac947dc1c7b866c446f5
BLAKE2b-256 818ca7b766df7346fe01dedf082377d3e05521398d39f74e82992223526e6130

See more details on using hashes here.

File details

Details for the file python_ottype-25.7.0-cp39-cp39-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl.

File metadata

File hashes

Hashes for python_ottype-25.7.0-cp39-cp39-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl
Algorithm Hash digest
SHA256 1990264b14ee36ea255e404d0c5ed33f2d4db767dbbbf5c7d6bca440929c855d
MD5 d44be59674099154d27814b93bca96d0
BLAKE2b-256 56e0eaf7d773623a2a31b3703fbbe368d0e656ae584351cba4c40eb4d21b7fec

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page