or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

tessl/pypi-pycrdt

Python bindings for Yrs CRDT library providing collaborative data structures for real-time synchronization.

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
pypipkg:pypi/pycrdt@0.12.x

To install, run

npx @tessl/cli install tessl/pypi-pycrdt@0.12.0

0

# pycrdt

1

2

## Overview

3

4

pycrdt is a Python library that provides bindings for Yrs, a high-performance Conflict-free Replicated Data Type (CRDT) library written in Rust. It enables developers to build collaborative applications with automatic conflict resolution, supporting various data structures like arrays, maps, text, and XML documents. The library is designed for real-time collaborative editing, distributed systems, and offline-first applications that require eventual consistency across multiple clients.

5

6

Key features:

7

- **Collaborative data structures**: Text, Array, Map, and XML with automatic conflict resolution

8

- **Real-time synchronization**: Built-in support for document synchronization across clients

9

- **Type safety**: TypedDoc, TypedArray, and TypedMap for runtime type checking

10

- **Event system**: Comprehensive observation and event handling for all data types

11

- **Position tracking**: StickyIndex for maintaining positions during concurrent edits

12

- **Undo/redo**: Full undo manager with origin filtering and scope control

13

- **Async support**: Full async/await support through anyio integration

14

15

## Package Information

16

17

- **Package Name**: pycrdt

18

- **Language**: Python

19

- **Package Manager**: pip

20

- **Installation**: `pip install pycrdt`

21

- **Minimum Python Version**: 3.9+

22

- **Build System**: maturin (Python/Rust hybrid)

23

24

## Core Imports

25

26

```python

27

import pycrdt

28

29

# Import main document and transaction types

30

from pycrdt import Doc, TypedDoc

31

from pycrdt import Transaction, NewTransaction, ReadTransaction

32

33

# Import collaborative data types

34

from pycrdt import Text, Array, Map

35

from pycrdt import TypedArray, TypedMap

36

from pycrdt import XmlFragment, XmlElement, XmlText

37

38

# Import event types

39

from pycrdt import TextEvent, ArrayEvent, MapEvent, XmlEvent

40

from pycrdt import TransactionEvent, SubdocsEvent

41

42

# Import synchronization components

43

from pycrdt import Provider, Channel, Awareness

44

from pycrdt import Decoder, Encoder

45

from pycrdt import YMessageType, YSyncMessageType

46

from pycrdt import create_sync_message, handle_sync_message

47

from pycrdt import create_awareness_message, create_update_message

48

from pycrdt import read_message, write_message, write_var_uint

49

50

# Import utility types

51

from pycrdt import StickyIndex, Assoc, UndoManager

52

from pycrdt import Subscription, StackItem

53

54

# Import update functions

55

from pycrdt import get_state, get_update, merge_updates

56

57

# Import awareness utility

58

from pycrdt import is_awareness_disconnect_message

59

60

# Get package version

61

import pycrdt

62

print(pycrdt.__version__) # Package version string

63

```

64

65

## Basic Usage

66

67

```python

68

import pycrdt

69

from pycrdt import Doc, Text, Array, Map

70

71

# Create a new collaborative document

72

doc = Doc()

73

74

# Create shared data structures

75

text = doc.get("shared_text", type=Text)

76

array = doc.get("shared_array", type=Array)

77

map_data = doc.get("shared_map", type=Map)

78

79

# Work with text

80

text.insert(0, "Hello, ")

81

text.insert(6, "world!")

82

print(str(text)) # "Hello, world!"

83

84

# Work with arrays

85

array.append("item1")

86

array.extend(["item2", "item3"])

87

print(len(array)) # 3

88

89

# Work with maps

90

map_data["key1"] = "value1"

91

map_data["key2"] = 42

92

print(map_data["key1"]) # "value1"

93

94

# Observe changes

95

def on_text_change(event):

96

print(f"Text changed: {event.delta}")

97

98

subscription = text.observe(on_text_change)

99

100

# Make changes in a transaction

101

with doc.transaction() as txn:

102

text += " How are you?"

103

array.append("item4")

104

map_data["timestamp"] = "2024-01-01"

105

```

106

107

## Architecture

108

109

pycrdt follows a layered architecture:

110

111

1. **Document Layer**: `Doc` serves as the container for all shared data types

112

2. **Transaction Layer**: All mutations happen within `Transaction` contexts for atomicity

113

3. **Data Type Layer**: `Text`, `Array`, `Map`, and XML types provide collaborative editing

114

4. **Event Layer**: Comprehensive event system for observing changes

115

5. **Synchronization Layer**: `Provider` and `Channel` handle network communication

116

6. **Awareness Layer**: Client presence and metadata management

117

118

## Capabilities

119

120

### Document Management

121

Comprehensive document lifecycle management with transactions and type safety.

122

123

```python { .api }

124

class Doc:

125

def __init__(self, init: dict = {}, *, client_id: int | None = None) -> None

126

def transaction(self, origin: Any = None) -> Transaction

127

def get(self, key: str, *, type: type[T]) -> T

128

def observe(self, callback: Callable[[TransactionEvent], None]) -> Subscription

129

```

130

131

**See [Document Management](./document-management.md) for complete API details.**

132

133

### Text Operations

134

Collaborative text editing with rich formatting and position tracking.

135

136

```python { .api }

137

class Text:

138

def insert(self, index: int, value: str, attrs: dict[str, Any] | None = None) -> None

139

def format(self, start: int, stop: int, attrs: dict[str, Any]) -> None

140

def diff(self) -> list[tuple[Any, dict[str, Any] | None]]

141

def observe(self, callback: Callable[[TextEvent], None]) -> Subscription

142

```

143

144

**See [Text Operations](./text-operations.md) for complete API details.**

145

146

### Array Operations

147

Collaborative arrays with list-like interface and change tracking.

148

149

```python { .api }

150

class Array[T]:

151

def append(self, value: T) -> None

152

def extend(self, value: list[T]) -> None

153

def insert(self, index: int, object: T) -> None

154

def move(self, source_index: int, destination_index: int) -> None

155

def observe(self, callback: Callable[[ArrayEvent], None]) -> Subscription

156

```

157

158

**See [Array Operations](./array-operations.md) for complete API details.**

159

160

### Map Operations

161

Collaborative dictionaries with key-value storage and event tracking.

162

163

```python { .api }

164

class Map[T]:

165

def get(self, key: str, default_value: T_DefaultValue = None) -> T | T_DefaultValue | None

166

def pop(self, key: str, default_value: T_DefaultValue = None) -> T | T_DefaultValue

167

def update(self, value: dict[str, T]) -> None

168

def observe(self, callback: Callable[[MapEvent], None]) -> Subscription

169

```

170

171

**See [Map Operations](./map-operations.md) for complete API details.**

172

173

### XML Support

174

Structured XML document editing with elements, attributes, and text nodes.

175

176

```python { .api }

177

class XmlElement:

178

def __init__(self, tag: str | None = None, attributes: dict[str, str] | None = None) -> None

179

@property

180

def tag(self) -> str | None

181

@property

182

def attributes(self) -> XmlAttributesView

183

@property

184

def children(self) -> XmlChildrenView

185

```

186

187

**See [XML Support](./xml-support.md) for complete API details.**

188

189

### Synchronization

190

Network synchronization with providers, channels, and message handling.

191

192

```python { .api }

193

class Provider:

194

def __init__(self, doc: Doc, channel: Channel, log: Logger | None = None) -> None

195

async def start(self) -> None

196

async def stop(self) -> None

197

198

def create_sync_message(ydoc: Doc) -> bytes

199

def handle_sync_message(message: bytes, ydoc: Doc) -> bytes | None

200

```

201

202

**See [Synchronization](./synchronization.md) for complete API details.**

203

204

### Awareness Protocol

205

Client presence management and metadata sharing in collaborative sessions.

206

207

```python { .api }

208

class Awareness:

209

def __init__(self, ydoc: Doc, *, outdated_timeout: int = 30000) -> None

210

def get_local_state(self) -> dict[str, Any] | None

211

def set_local_state(self, state: dict[str, Any] | None) -> None

212

def encode_awareness_update(self, client_ids: list[int]) -> bytes

213

```

214

215

**See [Awareness](./awareness.md) for complete API details.**

216

217

### Position Management & Undo

218

Persistent position tracking and comprehensive undo/redo operations.

219

220

```python { .api }

221

class StickyIndex:

222

def get_index(self, transaction: Transaction | None = None) -> int

223

@classmethod

224

def new(cls, sequence: Sequence, index: int, assoc: Assoc) -> Self

225

226

class UndoManager:

227

def can_undo(self) -> bool

228

def undo(self) -> bool

229

def can_redo(self) -> bool

230

def redo(self) -> bool

231

```

232

233

**See [Position Management & Undo](./position-undo.md) for complete API details.**

234

235

## Common Patterns

236

237

### Context Manager Pattern

238

All transactions use context managers for automatic cleanup:

239

240

```python

241

with doc.transaction() as txn:

242

# All mutations here are batched

243

text.insert(0, "New content")

244

array.append("new item")

245

```

246

247

### Observer Pattern

248

All shared types support event observation:

249

250

```python

251

def on_change(event):

252

print(f"Change detected: {event}")

253

254

subscription = shared_type.observe(on_change)

255

# Remember to clean up

256

shared_type.unobserve(subscription)

257

```

258

259

### Type Safety Pattern

260

Use typed variants for runtime type checking:

261

262

```python

263

class MyDoc(TypedDoc):

264

text_field: Text

265

array_field: Array[str]

266

map_field: Map[int]

267

268

doc = MyDoc()

269

doc.text_field.insert(0, "Hello") # Type-safe access

270

```

271

272

## Error Handling

273

274

pycrdt operations can raise the following exceptions:

275

276

- **ValueError**: Invalid parameters or operations

277

- **TypeError**: Type mismatches in typed variants

278

- **RuntimeError**: Document or transaction state errors

279

280

```python

281

try:

282

with doc.transaction() as txn:

283

text.insert(-1, "Invalid index") # May raise ValueError

284

except ValueError as e:

285

print(f"Operation failed: {e}")

286

```