lace

Normal Python application surface for Lace.

  1"""Normal Python application surface for Lace."""
  2
  3from .compaction import CompactionReport
  4from .connected import ConnectedPeer, PeerProofAssurance, SessionOperand
  5from .errors import (
  6    InterlaceError,
  7    LaceError,
  8    LaceIntegrationError,
  9    LaceLimitExceededError,
 10    LacePeerProtocolError,
 11    LacePolicyError,
 12    LaceStoreError,
 13    LaceTimeoutError,
 14    LaceTransportError,
 15)
 16from .events import (
 17    Closed,
 18    FixedPoint,
 19    InterlaceEvent,
 20    RecordEvent,
 21    RecordSaved,
 22    RecordSent,
 23)
 24from .lace import Cancellation, Lace, LaceHandle, LocalPeer
 25from .operations import (
 26    BoundedInterlaceOutcome,
 27    Complete,
 28    Failed,
 29    ForEachStream,
 30    GetOutcome,
 31    ListOutcome,
 32    OpenBoundaryOutcome,
 33    OpenInterlace,
 34    StoppedByLimit,
 35    StoreOutcome,
 36    StoreRecordResult,
 37    bounded_interlace,
 38    open_interlace,
 39    read_record_stream,
 40)
 41from ._porcelain import StoreStream, for_each, get, list_records, store, store_stream
 42from .policy import FieldExclusion, PreparedPolicy, all_records, compile, compose_policies
 43from .record import MAX_RECORD_BYTES, Record, parse_by
 44from . import compaction as _compaction
 45
 46__all__ = [
 47    "BoundedInterlaceOutcome",
 48    "Cancellation",
 49    "Closed",
 50    "CompactionReport",
 51    "Complete",
 52    "ConnectedPeer",
 53    "Failed",
 54    "FixedPoint",
 55    "FieldExclusion",
 56    "ForEachStream",
 57    "GetOutcome",
 58    "InterlaceError",
 59    "InterlaceEvent",
 60    "Lace",
 61    "LaceError",
 62    "LaceHandle",
 63    "LaceIntegrationError",
 64    "LaceLimitExceededError",
 65    "LacePeerProtocolError",
 66    "LacePolicyError",
 67    "LaceStoreError",
 68    "LaceTimeoutError",
 69    "LaceTransportError",
 70    "ListOutcome",
 71    "LocalPeer",
 72    "MAX_RECORD_BYTES",
 73    "OpenBoundaryOutcome",
 74    "OpenInterlace",
 75    "PeerProofAssurance",
 76    "PreparedPolicy",
 77    "Record",
 78    "RecordEvent",
 79    "RecordSaved",
 80    "RecordSent",
 81    "SessionOperand",
 82    "StoppedByLimit",
 83    "StoreOutcome",
 84    "StoreRecordResult",
 85    "StoreStream",
 86    "all_records",
 87    "bounded_interlace",
 88    "compile",
 89    "compose_policies",
 90    "for_each",
 91    "get",
 92    "list_records",
 93    "open_interlace",
 94    "parse_by",
 95    "read_record_stream",
 96    "store",
 97    "store_stream",
 98]
 99
100# Native roots are absent on WASM targets.
101if hasattr(_compaction, "compact_filesystem"):
102    from .compaction import compact_filesystem as compact_filesystem
103
104    __all__ += ["compact_filesystem"]
105
106# Present only with the extension's `lmdb` feature.
107if hasattr(_compaction, "compact_lmdb"):
108    from .compaction import compact_lmdb as compact_lmdb
109
110    __all__ += ["compact_lmdb"]
@dataclass(frozen=True)
class BoundedInterlaceOutcome:
163@dataclass(frozen=True)
164class BoundedInterlaceOutcome:
165    terminal: Terminal
166    observations: list[InterlaceEvent]
167    peer_by: str | None
168    outgoing_encoding: str | None
169    incoming_encoding: str | None
BoundedInterlaceOutcome( terminal: Complete | StoppedByLimit | Failed, observations: list[InterlaceEvent], peer_by: str | None, outgoing_encoding: str | None, incoming_encoding: str | None)
observations: list[InterlaceEvent]
peer_by: str | None
outgoing_encoding: str | None
incoming_encoding: str | None
class Cancellation:
186class Cancellation:
187    """Thread-safe caller cancellation for bounded operations.
188
189    ``set()`` may be called from any thread. The operation retires its machine
190    and transport, settles started store work through position publication,
191    then raises ``concurrent.futures.CancelledError``. ``set()`` wakes blocked
192    waits directly; nothing polls it.
193    """
194
195    def __init__(self) -> None:
196        self._lock = threading.Lock()
197        self._set = False
198        self._wakes = _WakeHub()
199
200    def set(self) -> None:
201        with self._lock:
202            if self._set:
203                return
204            self._set = True
205        self._wakes.signal()
206
207    def is_set(self) -> bool:
208        with self._lock:
209            return self._set
210
211    def _subscribe(
212        self, condition: threading.Condition | None = None
213    ) -> _WakeSubscription:
214        """A wake already signalled when cancellation was set before subscribing."""
215        subscription = self._wakes.subscribe(condition)
216        if self.is_set():
217            subscription.signal(raise_errors=False)
218        return subscription

Thread-safe caller cancellation for bounded operations.

set() may be called from any thread. The operation retires its machine and transport, settles started store work through position publication, then raises concurrent.futures.CancelledError. set() wakes blocked waits directly; nothing polls it.

def set(self) -> None:
200    def set(self) -> None:
201        with self._lock:
202            if self._set:
203                return
204            self._set = True
205        self._wakes.signal()
def is_set(self) -> bool:
207    def is_set(self) -> bool:
208        with self._lock:
209            return self._set
@dataclass(frozen=True)
class Closed(lace.InterlaceEvent):
46@dataclass(frozen=True)
47class Closed(InterlaceEvent):
48    reason: CloseReason
Closed(reason: Literal['peer-closed', 'cancelled'])
reason: Literal['peer-closed', 'cancelled']
@dataclass(frozen=True)
class CompactionReport:
15@dataclass(frozen=True)
16class CompactionReport:
17    """What one completed compaction removed and released.
18
19    ``boundary`` is the high-water the retention sweep evaluated.
20    ``bytes_released`` counts arena bytes between the new and previous
21    committed end; ``release`` is ``"unsupported"`` when the filesystem cannot
22    release them, after the root is already consistent.
23    """
24
25    boundary: int
26    retained: int
27    removed: int
28    bytes_released: int
29    release: Literal["ok", "unsupported"]

What one completed compaction removed and released.

boundary is the high-water the retention sweep evaluated. bytes_released counts arena bytes between the new and previous committed end; release is "unsupported" when the filesystem cannot release them, after the root is already consistent.

CompactionReport( boundary: int, retained: int, removed: int, bytes_released: int, release: Literal['ok', 'unsupported'])
boundary: int
retained: int
removed: int
bytes_released: int
release: Literal['ok', 'unsupported']
@dataclass(frozen=True)
class Complete:
115@dataclass(frozen=True)
116class Complete:
117    kind: Literal["complete"] = "complete"
Complete(kind: Literal['complete'] = 'complete')
kind: Literal['complete'] = 'complete'
class ConnectedPeer:
158class ConnectedPeer:
159    """One host-owned connected participant over established ILTP byte IO."""
160
161    def __init__(self) -> None:
162        raise TypeError("ConnectedPeer instances are created by transport factories")
163
164    @classmethod
165    def from_duplex(
166        cls,
167        io: RawIo,
168        *,
169        role: CarrierRole,
170        by_secret: str | None = None,
171        peer_proof: PeerProofAssurance | ProofAssurance = PeerProofAssurance.DISABLED,
172        channel_binding: bytes | bytearray | memoryview | None = None,
173        expected_peer_by: str | None = None,
174        stream_encodings: Sequence[str] | None = None,
175        port: str | None = None,
176    ) -> "ConnectedPeer":
177        """Adopt one duplex POSIX IO owner as a connected peer."""
178        return cls._from_owners(
179            io,
180            io,
181            role=role,
182            by_secret=by_secret,
183            peer_proof=peer_proof,
184            channel_binding=channel_binding,
185            expected_peer_by=expected_peer_by,
186            stream_encodings=stream_encodings,
187            port=port,
188            duplex=True,
189        )
190
191    @classmethod
192    def from_split(
193        cls,
194        reader: RawIo,
195        writer: RawIo,
196        *,
197        role: CarrierRole,
198        by_secret: str | None = None,
199        peer_proof: PeerProofAssurance | ProofAssurance = PeerProofAssurance.DISABLED,
200        channel_binding: bytes | bytearray | memoryview | None = None,
201        expected_peer_by: str | None = None,
202        stream_encodings: Sequence[str] | None = None,
203        port: str | None = None,
204    ) -> "ConnectedPeer":
205        """Adopt independent POSIX reader/writer owners as one connected peer."""
206        return cls._from_owners(
207            reader,
208            writer,
209            role=role,
210            by_secret=by_secret,
211            peer_proof=peer_proof,
212            channel_binding=channel_binding,
213            expected_peer_by=expected_peer_by,
214            stream_encodings=stream_encodings,
215            port=port,
216            duplex=False,
217        )
218
219    @classmethod
220    def _from_owners(
221        cls,
222        reader: RawIo,
223        writer: RawIo,
224        *,
225        role: CarrierRole,
226        by_secret: str | None,
227        peer_proof: PeerProofAssurance | ProofAssurance,
228        channel_binding: bytes | bytearray | memoryview | None,
229        expected_peer_by: str | None,
230        stream_encodings: Sequence[str] | None,
231        port: str | None,
232        duplex: bool,
233    ) -> "ConnectedPeer":
234        from ._raw_split_transport import _RawTransport
235
236        try:
237            assurance, binding, encodings = cls._validate_inputs(
238                role, by_secret, peer_proof, channel_binding, expected_peer_by,
239                stream_encodings, port,
240            )
241            transport = _RawTransport(reader, writer, role=role, duplex=duplex)
242        except BaseException as error:
243            owners = (reader,) if reader is writer else (writer, reader)
244            _raise_after_cleanup(error, *(lambda owner=owner: owner.close() for owner in owners))
245        # The complete transport now owns cleanup, including failed peer setup.
246        return cls._from_transport(
247            transport, by_secret=by_secret, peer_proof=assurance,
248            channel_binding=binding, expected_peer_by=expected_peer_by,
249            stream_encodings=encodings, port=port,
250        )
251
252    @classmethod
253    def _from_transport(
254        cls,
255        transport: _ConnectedTransport,
256        *,
257        by_secret: str | None,
258        peer_proof: PeerProofAssurance,
259        channel_binding: bytes | None = None,
260        expected_peer_by: str | None = None,
261        stream_encodings: list[str] | None = None,
262        port: str | None = None,
263    ) -> "ConnectedPeer":
264        """Adopt a transport with already validated and snapshotted options."""
265        try:
266            peer = cls.__new__(cls)
267            peer._initialize(
268                transport, by_secret=by_secret, peer_proof=peer_proof,
269                channel_binding=channel_binding, expected_peer_by=expected_peer_by,
270                stream_encodings=stream_encodings, port=port,
271            )
272        except BaseException as error:
273            _raise_after_cleanup(error, transport.close)
274        return peer
275
276    @staticmethod
277    def _validate_inputs(
278        role: CarrierRole,
279        by_secret: str | None,
280        peer_proof: PeerProofAssurance | ProofAssurance,
281        channel_binding: bytes | bytearray | memoryview | None,
282        expected_peer_by: str | None,
283        stream_encodings: Sequence[str] | None,
284        port: str | None,
285    ) -> tuple[PeerProofAssurance, bytes | None, list[str] | None]:
286        if role not in {"listener", "connector"}:
287            raise ValueError("transport carrier_role must be listener or connector")
288        if by_secret is not None:
289            _native.Record.by_from_secret(by_secret)
290        if not isinstance(peer_proof, str):
291            raise TypeError("peer_proof must be a PeerProofAssurance or string")
292        assurance = PeerProofAssurance(peer_proof)
293        binding = None
294        if assurance is PeerProofAssurance.CHANNEL_BOUND:
295            if by_secret is None:
296                raise ValueError("channel-bound proof requires by_secret")
297            if channel_binding is None:
298                raise ValueError("channel-bound proof requires channel_binding")
299            if not isinstance(channel_binding, (bytes, bytearray, memoryview)):
300                raise TypeError("channel_binding must be bytes, bytearray, or memoryview")
301            binding = bytes(channel_binding)
302            if len(binding) != 32:
303                raise ValueError("channel_binding must contain exactly 32 bytes")
304        elif channel_binding is not None:
305            raise ValueError("channel_binding requires channel-bound proof")
306        if expected_peer_by is not None:
307            _native.validate_by(expected_peer_by)
308            if assurance is PeerProofAssurance.DISABLED:
309                raise ValueError("expected_peer_by requires enabled peer_proof")
310        encodings = None
311        if stream_encodings is not None:
312            if isinstance(stream_encodings, (str, bytes)) or not isinstance(
313                stream_encodings, Sequence
314            ):
315                raise TypeError("stream_encodings must be a sequence of token strings")
316            encodings = list(stream_encodings)
317            if not all(isinstance(token, str) for token in encodings):
318                raise TypeError("stream_encodings must be a sequence of token strings")
319            _native.validate_stream_encodings(encodings)
320        if port is not None:
321            if not isinstance(port, str):
322                raise TypeError("port must be a string")
323            _native.validate_port(port)
324        return assurance, binding, encodings
325
326    def _initialize(
327        self,
328        transport: _ConnectedTransport,
329        *,
330        by_secret: str | None,
331        peer_proof: PeerProofAssurance,
332        channel_binding: bytes | None,
333        expected_peer_by: str | None,
334        stream_encodings: list[str] | None,
335        port: str | None,
336    ) -> None:
337        nonce_seed = os.urandom(32)
338        if not any(nonce_seed):
339            raise LaceIntegrationError(
340                "OS randomness returned an all-zero carrier nonce seed"
341            )
342        self._input: _ConnectedInput | None = _ConnectedInput(
343            transport, transport.carrier_role, by_secret,
344            peer_proof, channel_binding, nonce_seed, expected_peer_by,
345            stream_encodings, port,
346        )
347        self._close_error: BaseException | None = None
348
349    def _claim(self) -> _ConnectedInput:
350        if self._input is None:
351            raise RuntimeError("connected peer is closed or already owned by an interlace")
352        owned, self._input = self._input, None
353        return owned
354
355    def close(self) -> None:
356        if self._input is not None:
357            owned, self._input = self._input, None
358            try:
359                owned.close()
360            except BaseException as error:
361                self._close_error = error
362        if self._close_error is not None:
363            raise self._close_error
364
365    def __enter__(self) -> "ConnectedPeer":
366        return self
367
368    def __exit__(
369        self,
370        exc_type: type[BaseException] | None,
371        exc: BaseException | None,
372        tb: TracebackType | None,
373    ) -> None:
374        try:
375            self.close()
376        except BaseException as cleanup_error:
377            failure = _combine_failures(exc, cleanup_error)
378            assert failure is not None
379            raise failure

One host-owned connected participant over established ILTP byte IO.

@classmethod
def from_duplex( cls, io: lace.connected.RawIo, *, role: Literal['listener', 'connector'], by_secret: str | None = None, peer_proof: Union[PeerProofAssurance, Literal['disabled', 'confidential-channel', 'channel-bound']] = <PeerProofAssurance.DISABLED: 'disabled'>, channel_binding: bytes | bytearray | memoryview | None = None, expected_peer_by: str | None = None, stream_encodings: Sequence[str] | None = None, port: str | None = None) -> ConnectedPeer:
164    @classmethod
165    def from_duplex(
166        cls,
167        io: RawIo,
168        *,
169        role: CarrierRole,
170        by_secret: str | None = None,
171        peer_proof: PeerProofAssurance | ProofAssurance = PeerProofAssurance.DISABLED,
172        channel_binding: bytes | bytearray | memoryview | None = None,
173        expected_peer_by: str | None = None,
174        stream_encodings: Sequence[str] | None = None,
175        port: str | None = None,
176    ) -> "ConnectedPeer":
177        """Adopt one duplex POSIX IO owner as a connected peer."""
178        return cls._from_owners(
179            io,
180            io,
181            role=role,
182            by_secret=by_secret,
183            peer_proof=peer_proof,
184            channel_binding=channel_binding,
185            expected_peer_by=expected_peer_by,
186            stream_encodings=stream_encodings,
187            port=port,
188            duplex=True,
189        )

Adopt one duplex POSIX IO owner as a connected peer.

@classmethod
def from_split( cls, reader: lace.connected.RawIo, writer: lace.connected.RawIo, *, role: Literal['listener', 'connector'], by_secret: str | None = None, peer_proof: Union[PeerProofAssurance, Literal['disabled', 'confidential-channel', 'channel-bound']] = <PeerProofAssurance.DISABLED: 'disabled'>, channel_binding: bytes | bytearray | memoryview | None = None, expected_peer_by: str | None = None, stream_encodings: Sequence[str] | None = None, port: str | None = None) -> ConnectedPeer:
191    @classmethod
192    def from_split(
193        cls,
194        reader: RawIo,
195        writer: RawIo,
196        *,
197        role: CarrierRole,
198        by_secret: str | None = None,
199        peer_proof: PeerProofAssurance | ProofAssurance = PeerProofAssurance.DISABLED,
200        channel_binding: bytes | bytearray | memoryview | None = None,
201        expected_peer_by: str | None = None,
202        stream_encodings: Sequence[str] | None = None,
203        port: str | None = None,
204    ) -> "ConnectedPeer":
205        """Adopt independent POSIX reader/writer owners as one connected peer."""
206        return cls._from_owners(
207            reader,
208            writer,
209            role=role,
210            by_secret=by_secret,
211            peer_proof=peer_proof,
212            channel_binding=channel_binding,
213            expected_peer_by=expected_peer_by,
214            stream_encodings=stream_encodings,
215            port=port,
216            duplex=False,
217        )

Adopt independent POSIX reader/writer owners as one connected peer.

def close(self) -> None:
355    def close(self) -> None:
356        if self._input is not None:
357            owned, self._input = self._input, None
358            try:
359                owned.close()
360            except BaseException as error:
361                self._close_error = error
362        if self._close_error is not None:
363            raise self._close_error
@dataclass(frozen=True)
class Failed:
125@dataclass(frozen=True)
126class Failed:
127    error: InterlaceError
128    kind: Literal["failed"] = "failed"
Failed( error: InterlaceError, kind: Literal['failed'] = 'failed')
kind: Literal['failed'] = 'failed'
@dataclass(frozen=True)
class FixedPoint(lace.InterlaceEvent):
41@dataclass(frozen=True)
42class FixedPoint(InterlaceEvent):
43    pass
@dataclass(frozen=True)
class FieldExclusion:
52@dataclass(frozen=True)
53class FieldExclusion:
54    """Records carrying a matching ``Field`` occurrence; ``None`` matches anything."""
55    name: str | None = None
56    index: str | None = None
57    value: str | None = None

Records carrying a matching Field occurrence; None matches anything.

FieldExclusion( name: str | None = None, index: str | None = None, value: str | None = None)
name: str | None = None
index: str | None = None
value: str | None = None
class ForEachStream:
528class ForEachStream:
529    """Observer stream: records saved to the private observer, plus boundaries."""
530
531    def __init__(self, opened: OpenInterlace) -> None:
532        self._opened = opened
533
534    def close(self) -> None:
535        self._opened.close()
536
537    def next_event(self, *, timeout: float | None = None) -> InterlaceEvent | None:
538        timeout = _validate_timeout(timeout)
539        deadline = None if timeout is None else time.monotonic() + timeout
540        while True:
541            remaining = None if deadline is None else max(0.0, deadline - time.monotonic())
542            event = self._opened.next_event(timeout=remaining)
543            if (
544                event is None
545                or isinstance(event, (FixedPoint, Closed))
546                or (isinstance(event, RecordSaved) and event.position == "first")
547            ):
548                return event
549
550    def __enter__(self) -> "ForEachStream":
551        return self
552
553    def __exit__(
554        self,
555        exc_type: type[BaseException] | None,
556        exc: BaseException | None,
557        tb: TracebackType | None,
558    ) -> None:
559        self._opened.__exit__(exc_type, exc, tb)
560
561    def __iter__(self) -> Iterator[InterlaceEvent]:
562        return self
563
564    def __next__(self) -> InterlaceEvent:
565        observation = self.next_event()
566        if observation is None:
567            raise StopIteration
568        return observation

Observer stream: records saved to the private observer, plus boundaries.

ForEachStream(opened: OpenInterlace)
531    def __init__(self, opened: OpenInterlace) -> None:
532        self._opened = opened
def close(self) -> None:
534    def close(self) -> None:
535        self._opened.close()
def next_event( self, *, timeout: float | None = None) -> InterlaceEvent | None:
537    def next_event(self, *, timeout: float | None = None) -> InterlaceEvent | None:
538        timeout = _validate_timeout(timeout)
539        deadline = None if timeout is None else time.monotonic() + timeout
540        while True:
541            remaining = None if deadline is None else max(0.0, deadline - time.monotonic())
542            event = self._opened.next_event(timeout=remaining)
543            if (
544                event is None
545                or isinstance(event, (FixedPoint, Closed))
546                or (isinstance(event, RecordSaved) and event.position == "first")
547            ):
548                return event
@dataclass(frozen=True)
class GetOutcome:
156@dataclass(frozen=True)
157class GetOutcome:
158    terminal: Terminal
159    observations: list[InterlaceEvent]
160    record: Record | None
GetOutcome( terminal: Complete | StoppedByLimit | Failed, observations: list[InterlaceEvent], record: Record | None)
observations: list[InterlaceEvent]
record: Record | None
class InterlaceError(lace.LaceError):
36class InterlaceError(LaceError):
37    category: ClassVar[ErrorCategory] = "integration"
38
39    def __init__(
40        self,
41        message: str,
42        *,
43        position: ParticipantPosition | None = None,
44        record_hash: str | None = None,
45        phase: TimeoutPhase | None = None,
46    ) -> None:
47        super().__init__(message)
48        self.message = message
49        self.position = position
50        self.record_hash = record_hash
51        self.phase = phase

Base class for Lace binding errors.

InterlaceError( message: str, *, position: Optional[Literal['first', 'second']] = None, record_hash: str | None = None, phase: Optional[Literal['prefacing', 'side0-proof', 'side1-proof', 'side0-operand', 'side1-operand', 'advertising', 'requesting', 'answering', 'fencing']] = None)
39    def __init__(
40        self,
41        message: str,
42        *,
43        position: ParticipantPosition | None = None,
44        record_hash: str | None = None,
45        phase: TimeoutPhase | None = None,
46    ) -> None:
47        super().__init__(message)
48        self.message = message
49        self.position = position
50        self.record_hash = record_hash
51        self.phase = phase
category: ClassVar[Literal['peer-protocol', 'limit-exceeded', 'timeout', 'policy', 'store', 'transport', 'integration']] = 'integration'
message
position
record_hash
phase
@dataclass(frozen=True)
class InterlaceEvent:
18@dataclass(frozen=True)
19class InterlaceEvent:
20    pass
class Lace:
245class Lace:
246    """Non-clonable Python owner of one adopted store and its publication state."""
247
248    def __init__(
249        self,
250        store: _StoreOwner,
251        *,
252        position_may_advance_externally: bool,
253        operand_cache: int = DEFAULT_OPERAND_CACHE_ENTRIES,
254        _adoption_token: object | None = None,
255    ):
256        if _adoption_token is not _ADOPTION_TOKEN:
257            raise TypeError(
258                "construct Lace with a built-in store constructor, or use lace.advanced.with_store"
259            )
260        if type(position_may_advance_externally) is not bool:
261            raise TypeError("position_may_advance_externally must be a bool")
262        self._store = store
263        self._position_may_advance_externally = position_may_advance_externally
264        try:
265            if isinstance(operand_cache, bool) or not isinstance(operand_cache, int):
266                raise TypeError("operand_cache must be an int")
267            if operand_cache < 0:
268                raise ValueError("operand_cache must not be negative")
269            # Peer operands held by hash, shared by this Lace's connected operations.
270            self._operand_cache = _native.OperandCache(operand_cache)
271            try:
272                initial_position = store.current_position()
273            except Exception as error:
274                if isinstance(error, LaceError):
275                    raise
276                raise LaceStoreError(str(error)) from error
277            self._closed = False
278            self._close_complete = False
279            self._close_error: BaseException | None = None
280            # Registration order is close order.
281            self._open_interlaces: dict[OpenInterlace, None] = {}
282            self._mutation_lock = threading.Lock()
283            self._position_lock = threading.Lock()
284            self._latest_store_position = initial_position
285            self._position_subscriptions: set[_StorePositionSubscription] = set()
286            self._work_condition = threading.Condition()
287            self._wakes = _WakeHub()
288            self._active_store_work: set[PendingWork] = set()
289            self._unacknowledged_work_errors: list[BaseException] = []
290            self._terminal_failure: BaseException | None = None
291            self._next_poll_at = time.monotonic() + _REMOTE_POSITION_POLL_INTERVAL_SECONDS
292            self._poll_in_flight = False
293        except BaseException as error:
294            _raise_after_cleanup(error, self._store_close)
295
296    @classmethod
297    def _adopt(
298        cls,
299        store: _StoreOwner,
300        *,
301        position_may_advance_externally: bool,
302        operand_cache: int = DEFAULT_OPERAND_CACHE_ENTRIES,
303    ) -> "Lace":
304        return cls(
305            store,
306            position_may_advance_externally=position_may_advance_externally,
307            operand_cache=operand_cache,
308            _adoption_token=_ADOPTION_TOKEN,
309        )
310
311    @classmethod
312    def memory(
313        cls,
314        records: Record | Iterable[Record] | None = None,
315        *,
316        operand_cache: int = DEFAULT_OPERAND_CACHE_ENTRIES,
317    ) -> "Lace":
318        return cls._with_initial_records(
319            cls._adopt(
320                _indexed_memory_owner(),
321                position_may_advance_externally=False,
322                operand_cache=operand_cache,
323            ),
324            records,
325        )
326
327    if hasattr(_native.NativeStore, "filesystem"):
328        @classmethod
329        def filesystem(
330            cls,
331            path: str | os.PathLike[str],
332            records: Record | Iterable[Record] | None = None,
333            *,
334            operand_cache: int = DEFAULT_OPERAND_CACHE_ENTRIES,
335        ) -> "Lace":
336            return cls._with_initial_records(
337                cls._adopt(
338                    _blocking_native_owner(_native.NativeStore.filesystem, path),
339                    position_may_advance_externally=False,
340                    operand_cache=operand_cache,
341                ),
342                records,
343            )
344
345    if hasattr(_native.NativeStore, "lmdb"):
346        @classmethod
347        def lmdb(
348            cls,
349            path: str | os.PathLike[str],
350            *,
351            operand_cache: int = DEFAULT_OPERAND_CACHE_ENTRIES,
352        ) -> "Lace":
353            return cls._adopt(
354                _blocking_native_owner(_native.NativeStore.lmdb, path),
355                position_may_advance_externally=True,
356                operand_cache=operand_cache,
357            )
358
359    @staticmethod
360    def _with_initial_records(
361        lace: "Lace", records: Record | Iterable[Record] | None
362    ) -> "Lace":
363        if records is None:
364            return lace
365        try:
366            from .operations import Failed, StoppedByLimit
367            from ._porcelain import store
368
369            outcome = store(lace, records)
370            if isinstance(outcome.terminal, Failed):
371                raise outcome.terminal.error
372            if isinstance(outcome.terminal, StoppedByLimit):
373                raise LaceLimitExceededError("initial record admission stopped by a limit")
374            return lace
375        except BaseException as error:
376            _raise_after_cleanup(error, lace.close)
377
378    def handle(self) -> LaceHandle:
379        self._raise_if_unavailable()
380        return LaceHandle(self)
381
382    def __reduce_ex__(self, protocol: SupportsIndex) -> NoReturn:
383        # copy, deepcopy and pickle all reduce through this.
384        raise TypeError("Lace is non-clonable; clone Lace.handle() instead")
385
386    def _register_open_interlace(self, interlace: OpenInterlace) -> None:
387        with self._work_condition:
388            self._raise_if_unavailable_locked()
389            self._open_interlaces[interlace] = None
390
391    def _unregister_open_interlace(self, interlace: OpenInterlace) -> None:
392        with self._work_condition:
393            self._open_interlaces.pop(interlace, None)
394
395    def _subscribe_wakes(
396        self, condition: threading.Condition | None = None
397    ) -> _WakeSubscription:
398        with self._work_condition:
399            self._raise_if_unavailable_locked()
400            return self._wakes.subscribe(condition)
401
402    def _subscribe_store_position(
403        self, condition: threading.Condition
404    ) -> _StorePositionSubscription:
405        subscription = _StorePositionSubscription(self, condition)
406        self._wakes.attach(subscription)
407        with self._work_condition:
408            try:
409                self._raise_if_unavailable_locked()
410            except BaseException:
411                subscription.close()
412                raise
413            with self._position_lock:
414                self._position_subscriptions.add(subscription)
415        return subscription
416
417    def _unsubscribe_store_position(
418        self, subscription: _StorePositionSubscription
419    ) -> None:
420        with self._position_lock:
421            self._position_subscriptions.discard(subscription)
422
423    def _raise_if_unavailable_locked(self) -> None:
424        if self._terminal_failure is not None:
425            raise self._terminal_failure
426        if self._closed:
427            raise RuntimeError("Lace is closed")
428
429    def _raise_if_unavailable(self) -> None:
430        with self._work_condition:
431            self._raise_if_unavailable_locked()
432
433    def _poison(self, error: BaseException) -> BaseException:
434        with self._work_condition:
435            if self._terminal_failure is None:
436                for execution in self._active_store_work:
437                    execution.prevent_start(error)
438                self._terminal_failure = error
439            self._poll_in_flight = False
440            retained = self._terminal_failure
441            self._work_condition.notify_all()
442        self._wakes.signal()
443        return retained
444
445    def _latest_position(self) -> int:
446        with self._work_condition:
447            if self._terminal_failure is not None:
448                raise self._terminal_failure
449        with self._position_lock:
450            return self._latest_store_position
451
452    def _publish_store_position(self, position: int) -> None:
453        """Retain and signal one confirmed position while the mutation gate is held."""
454        with self._work_condition:
455            if self._terminal_failure is not None:
456                raise self._terminal_failure
457            with self._position_lock:
458                if position < self._latest_store_position:
459                    failure = LaceIntegrationError(
460                        f"store position regressed from {self._latest_store_position} to {position}"
461                    )
462                    subscriptions: tuple[_StorePositionSubscription, ...] = ()
463                elif position == self._latest_store_position:
464                    return
465                else:
466                    failure = None
467                    self._latest_store_position = position
468                    subscriptions = tuple(self._position_subscriptions)
469
470        signal_error: BaseException | None = None
471        for subscription in subscriptions:
472            try:
473                subscription.signal()
474            except BaseException as error:
475                signal_error = _combine_failures(signal_error, error)
476        if signal_error is not None:
477            failure = LaceIntegrationError(
478                f"failed to publish confirmed store position: {signal_error}"
479            )
480            failure.__cause__ = signal_error
481        if failure is None:
482            return
483        retained = self._poison(failure)
484        raise retained
485
486    def _begin_store_work(self, execution: PendingWork) -> None:
487        with self._work_condition:
488            self._raise_if_unavailable_locked()
489            self._active_store_work.add(execution)
490
491    def _finish_store_work(self, execution: PendingWork) -> None:
492        with self._work_condition:
493            self._active_store_work.discard(execution)
494            self._work_condition.notify_all()
495
496    def _retain_store_work_error(self, error: BaseException) -> None:
497        with self._work_condition:
498            self._unacknowledged_work_errors.append(error)
499            self._work_condition.notify_all()
500
501    def _external_position_poll_deadline(self, now: float) -> float | None:
502        with self._work_condition:
503            self._raise_if_unavailable_locked()
504            if not self._position_may_advance_externally:
505                return None
506            if self._poll_in_flight and self._next_poll_at <= now:
507                return now + _REMOTE_POSITION_POLL_INTERVAL_SECONDS
508            return self._next_poll_at
509
510    def _start_due_external_position_refresh(self, now: float) -> bool:
511        from ._store_execution import PendingWork
512
513        with self._work_condition:
514            self._raise_if_unavailable_locked()
515            if (
516                not self._position_may_advance_externally
517                or self._poll_in_flight
518                or now < self._next_poll_at
519            ):
520                return False
521            execution = PendingWork.refresh(self)
522            self._poll_in_flight = True
523            self._next_poll_at = now + _REMOTE_POSITION_POLL_INTERVAL_SECONDS
524            self._active_store_work.add(execution)
525        try:
526            execution.start_thread()
527        except BaseException as error:
528            failure = LaceIntegrationError(
529                f"failed to start external store-position probe: {error}"
530            )
531            failure.__cause__ = error
532            with self._work_condition:
533                # An interrupted start may already have handed the probe to
534                # its worker. Keep that owner until publication/settlement.
535                if execution.channel.claim():
536                    self._active_store_work.discard(execution)
537                self._poll_in_flight = False
538                self._next_poll_at = (
539                    time.monotonic() + _REMOTE_POSITION_POLL_INTERVAL_SECONDS
540                )
541                if self._terminal_failure is None:
542                    for pending in self._active_store_work:
543                        pending.prevent_start(failure)
544                    self._terminal_failure = failure
545                retained = self._terminal_failure
546                self._work_condition.notify_all()
547            self._wakes.signal()
548            if not isinstance(error, Exception):
549                raise
550            raise retained
551        return True
552
553    def _finish_external_position_refresh(
554        self,
555        execution: PendingWork,
556        failure: BaseException | None,
557    ) -> None:
558        with self._work_condition:
559            self._active_store_work.discard(execution)
560            self._poll_in_flight = False
561            self._next_poll_at = (
562                time.monotonic() + _REMOTE_POSITION_POLL_INTERVAL_SECONDS
563            )
564            if failure is not None and self._terminal_failure is None:
565                for pending in self._active_store_work:
566                    pending.prevent_start(failure)
567                self._terminal_failure = failure
568            self._work_condition.notify_all()
569        self._wakes.signal()
570
571    def _settle_external_position_poll(self) -> None:
572        """Finish the one Lace-owned probe before an operation releases this Lace."""
573        subscription = self._wakes.subscribe()
574        failure: BaseException | None = self._terminal_failure
575        try:
576            while True:
577                try:
578                    # Publish retired predecessors before waiting on a queued
579                    # probe; never consume another live operation's response.
580                    self._drain_store_work(wait=False)
581                    self._finish_ready_position_refreshes()
582                    with self._work_condition:
583                        refresh_pending = any(
584                            execution.is_refresh for execution in self._active_store_work
585                        )
586                        failure = _combine_failures(failure, self._terminal_failure)
587                    if not refresh_pending:
588                        break
589                    subscription.wait()
590                except BaseException as error:
591                    failure = _combine_failures(failure, error)
592        finally:
593            try:
594                subscription.close()
595            except BaseException as error:
596                failure = _combine_failures(failure, error)
597        if failure is not None:
598            raise failure
599
600    def _has_ready_store_work(self) -> bool:
601        with self._work_condition:
602            return any(
603                (execution.is_refresh or execution.retired) and execution.ready()
604                for execution in self._active_store_work
605            )
606
607    def _finish_ready_position_refreshes(self) -> bool:
608        """Publish ready Lace-local refreshes without taking another operation's work."""
609        with self._work_condition:
610            refreshes = tuple(
611                execution
612                for execution in self._active_store_work
613                if execution.is_refresh
614            )
615        progressed = False
616        for refresh in refreshes:
617            if refresh.finished or not refresh.ready():
618                continue
619            refresh.finish(self, wait=False)
620            progressed = refresh.finished or progressed
621        return progressed
622
623    def _drain_store_work(
624        self,
625        *,
626        wait: bool,
627        excluding: set[PendingWork] | None = None,
628        report_errors: bool = False,
629    ) -> None:
630        excluded = excluding or set()
631        while True:
632            with self._work_condition:
633                executions = tuple(
634                    execution
635                    for execution in self._active_store_work
636                    if execution not in excluded
637                )
638            if not executions:
639                break
640            progressed = False
641            for execution in executions:
642                if not wait and (not execution.retired or not execution.ready()):
643                    continue
644                execution.finish(self, wait=wait)
645                progressed = True
646                execution.retain_late_failure(self)
647            if not wait:
648                break
649            if not progressed:
650                raise RuntimeError("active StoreWork could not be drained")
651        if report_errors and self._unacknowledged_work_errors:
652            failure: BaseException | None = None
653            for error in self._unacknowledged_work_errors:
654                failure = _combine_failures(failure, error)
655            self._unacknowledged_work_errors.clear()
656            if failure is not None:
657                raise failure
658
659    def _wait_for_store_work(self) -> None:
660        subscription = self._wakes.subscribe()
661        failure: BaseException | None = None
662        try:
663            while True:
664                try:
665                    with self._work_condition:
666                        executions = tuple(self._active_store_work)
667                    if not executions:
668                        break
669                    progressed = False
670                    for execution in executions:
671                        if not execution.ready():
672                            continue
673                        try:
674                            error = execution.finish(self, wait=False)
675                            if execution.executed:
676                                failure = _combine_failures(failure, error)
677                        finally:
678                            if execution.finished:
679                                execution.retain_late_failure(self)
680                        progressed = True
681                    if not progressed:
682                        subscription.wait()
683                except BaseException as error:
684                    failure = _combine_failures(failure, error)
685            for retained_error in self._unacknowledged_work_errors:
686                failure = _combine_failures(failure, retained_error)
687            self._unacknowledged_work_errors.clear()
688        finally:
689            try:
690                subscription.close()
691            except BaseException as error:
692                failure = _combine_failures(failure, error)
693        if failure is not None:
694            raise failure
695
696    def _store_close(self) -> None:
697        try:
698            self._store.close()
699        except LaceError:
700            raise
701        except BaseException as error:
702            raise LaceStoreError(str(error)) from error
703
704    def close(self) -> None:
705        # Every claimed operation is released here, whatever interrupts close.
706        claimed: list[OpenInterlace] = []
707        try:
708            self._close_claimed(claimed)
709        finally:
710            for interlace in claimed:
711                interlace._release()
712
713    def _close_claimed(self, claimed: list[OpenInterlace]) -> None:
714        with self._work_condition:
715            if self._closed:
716                while not self._close_complete:
717                    try:
718                        self._work_condition.wait()
719                    except BaseException as error:
720                        self._close_error = _combine_failures(self._close_error, error)
721                if self._close_error is not None:
722                    raise self._close_error
723                return
724            # Claim every live operation before the participant lifecycle
725            # changes; one that another caller is using makes close fail busy.
726            for interlace in list(self._open_interlaces):
727                interlace._claim()
728                claimed.append(interlace)
729            # Stop queued calls before the close cut; already-executing calls
730            # still own their mandatory refresh and publication interval.
731            for execution in self._active_store_work:
732                execution.prevent_start(RuntimeError("Lace is closed"))
733            # This is the close linearization point. New work and operation
734            # registration fail, while counted work retains the store.
735            self._closed = True
736        failure: BaseException | None = self._terminal_failure
737        try:
738            for interlace in claimed:
739                try:
740                    interlace._finish()
741                except BaseException as error:
742                    failure = _combine_failures(failure, error)
743            with self._work_condition:
744                self._open_interlaces.clear()
745            try:
746                self._wait_for_store_work()
747            except BaseException as error:
748                failure = _combine_failures(failure, error)
749            failure = _combine_failures(failure, self._terminal_failure)
750            try:
751                self._store_close()
752            except BaseException as error:
753                failure = _combine_failures(failure, error)
754            failure = _combine_failures(failure, self._terminal_failure)
755        finally:
756            with self._work_condition:
757                self._close_error = _combine_failures(failure, self._close_error)
758                self._close_complete = True
759                self._work_condition.notify_all()
760        if self._close_error is not None:
761            raise self._close_error
762
763    def __enter__(self) -> "Lace":
764        return self
765
766    def __exit__(
767        self,
768        exc_type: type[BaseException] | None,
769        exc: BaseException | None,
770        tb: TracebackType | None,
771    ) -> None:
772        try:
773            self.close()
774        except BaseException as cleanup_error:
775            if exc is None:
776                raise
777            _combine_failures(exc, cleanup_error)
778            raise exc

Non-clonable Python owner of one adopted store and its publication state.

Lace( store: lace._store._StoreOwner, *, position_may_advance_externally: bool, operand_cache: int = 32, _adoption_token: object | None = None)
248    def __init__(
249        self,
250        store: _StoreOwner,
251        *,
252        position_may_advance_externally: bool,
253        operand_cache: int = DEFAULT_OPERAND_CACHE_ENTRIES,
254        _adoption_token: object | None = None,
255    ):
256        if _adoption_token is not _ADOPTION_TOKEN:
257            raise TypeError(
258                "construct Lace with a built-in store constructor, or use lace.advanced.with_store"
259            )
260        if type(position_may_advance_externally) is not bool:
261            raise TypeError("position_may_advance_externally must be a bool")
262        self._store = store
263        self._position_may_advance_externally = position_may_advance_externally
264        try:
265            if isinstance(operand_cache, bool) or not isinstance(operand_cache, int):
266                raise TypeError("operand_cache must be an int")
267            if operand_cache < 0:
268                raise ValueError("operand_cache must not be negative")
269            # Peer operands held by hash, shared by this Lace's connected operations.
270            self._operand_cache = _native.OperandCache(operand_cache)
271            try:
272                initial_position = store.current_position()
273            except Exception as error:
274                if isinstance(error, LaceError):
275                    raise
276                raise LaceStoreError(str(error)) from error
277            self._closed = False
278            self._close_complete = False
279            self._close_error: BaseException | None = None
280            # Registration order is close order.
281            self._open_interlaces: dict[OpenInterlace, None] = {}
282            self._mutation_lock = threading.Lock()
283            self._position_lock = threading.Lock()
284            self._latest_store_position = initial_position
285            self._position_subscriptions: set[_StorePositionSubscription] = set()
286            self._work_condition = threading.Condition()
287            self._wakes = _WakeHub()
288            self._active_store_work: set[PendingWork] = set()
289            self._unacknowledged_work_errors: list[BaseException] = []
290            self._terminal_failure: BaseException | None = None
291            self._next_poll_at = time.monotonic() + _REMOTE_POSITION_POLL_INTERVAL_SECONDS
292            self._poll_in_flight = False
293        except BaseException as error:
294            _raise_after_cleanup(error, self._store_close)
@classmethod
def memory( cls, records: Record | Iterable[Record] | None = None, *, operand_cache: int = 32) -> Lace:
311    @classmethod
312    def memory(
313        cls,
314        records: Record | Iterable[Record] | None = None,
315        *,
316        operand_cache: int = DEFAULT_OPERAND_CACHE_ENTRIES,
317    ) -> "Lace":
318        return cls._with_initial_records(
319            cls._adopt(
320                _indexed_memory_owner(),
321                position_may_advance_externally=False,
322                operand_cache=operand_cache,
323            ),
324            records,
325        )
def handle(self) -> LaceHandle:
378    def handle(self) -> LaceHandle:
379        self._raise_if_unavailable()
380        return LaceHandle(self)
def close(self) -> None:
704    def close(self) -> None:
705        # Every claimed operation is released here, whatever interrupts close.
706        claimed: list[OpenInterlace] = []
707        try:
708            self._close_claimed(claimed)
709        finally:
710            for interlace in claimed:
711                interlace._release()
@classmethod
def filesystem( cls, path: str | os.PathLike[str], records: Record | Iterable[Record] | None = None, *, operand_cache: int = 32) -> Lace:
328        @classmethod
329        def filesystem(
330            cls,
331            path: str | os.PathLike[str],
332            records: Record | Iterable[Record] | None = None,
333            *,
334            operand_cache: int = DEFAULT_OPERAND_CACHE_ENTRIES,
335        ) -> "Lace":
336            return cls._with_initial_records(
337                cls._adopt(
338                    _blocking_native_owner(_native.NativeStore.filesystem, path),
339                    position_may_advance_externally=False,
340                    operand_cache=operand_cache,
341                ),
342                records,
343            )
class LaceError(builtins.RuntimeError):
32class LaceError(RuntimeError):
33    """Base class for Lace binding errors."""

Base class for Lace binding errors.

class LaceHandle:
34class LaceHandle:
35    """Clonable opaque capability to one store-backed Lace owner."""
36
37    def __init__(self, lace: "Lace"):
38        self._lace = lace
39
40    def handle(self) -> "LaceHandle":
41        return self._lace.handle()

Clonable opaque capability to one store-backed Lace owner.

LaceHandle(lace: Lace)
37    def __init__(self, lace: "Lace"):
38        self._lace = lace
def handle(self) -> LaceHandle:
40    def handle(self) -> "LaceHandle":
41        return self._lace.handle()
class LaceIntegrationError(lace.InterlaceError):
88class LaceIntegrationError(InterlaceError):
89    category: ClassVar[ErrorCategory] = "integration"

Base class for Lace binding errors.

category: ClassVar[Literal['peer-protocol', 'limit-exceeded', 'timeout', 'policy', 'store', 'transport', 'integration']] = 'integration'
class LaceLimitExceededError(lace.InterlaceError):
58class LaceLimitExceededError(InterlaceError):
59    category: ClassVar[ErrorCategory] = "limit-exceeded"

Base class for Lace binding errors.

category: ClassVar[Literal['peer-protocol', 'limit-exceeded', 'timeout', 'policy', 'store', 'transport', 'integration']] = 'limit-exceeded'
class LacePeerProtocolError(lace.InterlaceError):
54class LacePeerProtocolError(InterlaceError):
55    category: ClassVar[ErrorCategory] = "peer-protocol"

Base class for Lace binding errors.

category: ClassVar[Literal['peer-protocol', 'limit-exceeded', 'timeout', 'policy', 'store', 'transport', 'integration']] = 'peer-protocol'
class LacePolicyError(lace.InterlaceError):
76class LacePolicyError(InterlaceError):
77    category: ClassVar[ErrorCategory] = "policy"

Base class for Lace binding errors.

category: ClassVar[Literal['peer-protocol', 'limit-exceeded', 'timeout', 'policy', 'store', 'transport', 'integration']] = 'policy'
class LaceStoreError(lace.InterlaceError):
80class LaceStoreError(InterlaceError):
81    category: ClassVar[ErrorCategory] = "store"

Base class for Lace binding errors.

category: ClassVar[Literal['peer-protocol', 'limit-exceeded', 'timeout', 'policy', 'store', 'transport', 'integration']] = 'store'
class LaceTimeoutError(lace.InterlaceError):
62class LaceTimeoutError(InterlaceError):
63    category: ClassVar[ErrorCategory] = "timeout"
64
65    def __init__(
66        self,
67        message: str,
68        *,
69        phase: TimeoutPhase,
70        position: ParticipantPosition | None = None,
71        record_hash: str | None = None,
72    ) -> None:
73        super().__init__(message, position=position, record_hash=record_hash, phase=phase)

Base class for Lace binding errors.

LaceTimeoutError( message: str, *, phase: Literal['prefacing', 'side0-proof', 'side1-proof', 'side0-operand', 'side1-operand', 'advertising', 'requesting', 'answering', 'fencing'], position: Optional[Literal['first', 'second']] = None, record_hash: str | None = None)
65    def __init__(
66        self,
67        message: str,
68        *,
69        phase: TimeoutPhase,
70        position: ParticipantPosition | None = None,
71        record_hash: str | None = None,
72    ) -> None:
73        super().__init__(message, position=position, record_hash=record_hash, phase=phase)
category: ClassVar[Literal['peer-protocol', 'limit-exceeded', 'timeout', 'policy', 'store', 'transport', 'integration']] = 'timeout'
class LaceTransportError(lace.InterlaceError):
84class LaceTransportError(InterlaceError):
85    category: ClassVar[ErrorCategory] = "transport"

Base class for Lace binding errors.

category: ClassVar[Literal['peer-protocol', 'limit-exceeded', 'timeout', 'policy', 'store', 'transport', 'integration']] = 'transport'
@dataclass(frozen=True)
class ListOutcome:
134@dataclass(frozen=True)
135class ListOutcome:
136    terminal: Terminal
137    observations: list[InterlaceEvent]
138    records: list[Record]
ListOutcome( terminal: Complete | StoppedByLimit | Failed, observations: list[InterlaceEvent], records: list[Record])
observations: list[InterlaceEvent]
records: list[Record]
class LocalPeer:
44class LocalPeer:
45    """Reusable local participant that supplies its own prepared operand.
46
47    In an interlace, a bare ``Lace``/``LaceHandle`` position receives the
48    operation's policy and a ``LocalPeer`` position receives this operand. At
49    most one position may be a ``LocalPeer``, and it cannot join a connected peer.
50    """
51
52    def __init__(self, lace: "Lace | LaceHandle", policy: PolicyInput):
53        if isinstance(lace, LaceHandle):
54            lace = lace._lace
55        elif not isinstance(lace, Lace):
56            raise TypeError("LocalPeer requires a Lace or LaceHandle")
57        self._lace: Lace = lace
58        self._policy: PreparedPolicy = _prepare_policy(policy)

Reusable local participant that supplies its own prepared operand.

In an interlace, a bare Lace/LaceHandle position receives the operation's policy and a LocalPeer position receives this operand. At most one position may be a LocalPeer, and it cannot join a connected peer.

LocalPeer( lace: Lace | LaceHandle, policy: str | PreparedPolicy)
52    def __init__(self, lace: "Lace | LaceHandle", policy: PolicyInput):
53        if isinstance(lace, LaceHandle):
54            lace = lace._lace
55        elif not isinstance(lace, Lace):
56            raise TypeError("LocalPeer requires a Lace or LaceHandle")
57        self._lace: Lace = lace
58        self._policy: PreparedPolicy = _prepare_policy(policy)
MAX_RECORD_BYTES = 33620814
@dataclass(frozen=True)
class OpenBoundaryOutcome:
172@dataclass(frozen=True)
173class OpenBoundaryOutcome:
174    boundary: FixedPoint | Closed
175    observations: list[InterlaceEvent]
OpenBoundaryOutcome( boundary: FixedPoint | Closed, observations: list[InterlaceEvent])
boundary: FixedPoint | Closed
observations: list[InterlaceEvent]
class OpenInterlace:
319class OpenInterlace:
320    """One open interlace owning one route driver.
321
322    Event reading, policy replacement and close exclude each other: a call made
323    while another owns the interlace fails as busy instead of waiting.
324    """
325
326    @classmethod
327    def _open(
328        cls,
329        first: _AcceptedParticipant,
330        second: _AcceptedParticipant,
331        first_policy: PreparedPolicy,
332        second_policy: PreparedPolicy,
333        limits: dict[str, int] | None = None,
334        *,
335        private: Lace | None = None,
336    ) -> "OpenInterlace":
337        """Open one route with operands by participant position.
338
339        `private` is a porcelain operation's own first participant, closed with
340        the operation.
341        """
342        driver = _create_driver(first, second, first_policy, second_policy, limits, None)
343        return cls._own(driver, private=private)
344
345    @classmethod
346    def _own(cls, driver: Driver, *, private: Lace | None = None) -> "OpenInterlace":
347        try:
348            return cls(driver, private=private)
349        except BaseException as error:
350            _raise_after_cleanup(error, driver.close)
351
352    def __init__(self, driver: Driver, *, private: Lace | None = None) -> None:
353        self._busy = threading.Lock()
354        self._driver = driver
355        self._laces = driver.laces
356        # A porcelain operation's private Lace, closed with the operation.
357        self._private_lace = private
358        self._closed = False
359        self._closed_delivered = False
360        self._failure: BaseException | None = None
361        self._close_error: BaseException | None = None
362        self._failure_delivered = False
363        registered: list[Lace] = []
364        try:
365            for lace in self._laces:
366                lace._register_open_interlace(self)
367                registered.append(lace)
368        except BaseException as error:
369            _raise_after_cleanup(
370                error,
371                *(partial(lace._unregister_open_interlace, self) for lace in registered),
372            )
373
374    def _claim(self) -> None:
375        if not self._busy.acquire(blocking=False):
376            raise RuntimeError("interlace is busy")
377
378    def _release(self) -> None:
379        self._busy.release()
380
381    def close(self) -> None:
382        self._claim()
383        try:
384            self._finish()
385        finally:
386            self._release()
387
388    def _finish(self) -> None:
389        if self._closed:
390            if self._close_error is not None:
391                raise self._close_error
392            return
393        self._closed = True
394        failure = self._failure
395        cleanup: list[Callable[[], None]] = [
396            self._driver.close,
397            *(partial(lace._unregister_open_interlace, self) for lace in self._laces),
398        ]
399        if self._private_lace is not None:
400            cleanup.append(self._private_lace.close)
401        for close in cleanup:
402            try:
403                close()
404            except BaseException as error:
405                failure = _combine_failures(failure, error)
406        self._close_error = failure
407        if failure is not None:
408            self._failure = failure
409            raise failure
410
411    def __enter__(self) -> "OpenInterlace":
412        return self
413
414    def __exit__(
415        self,
416        exc_type: type[BaseException] | None,
417        exc: BaseException | None,
418        tb: TracebackType | None,
419    ) -> None:
420        try:
421            self.close()
422        except BaseException as cleanup_error:
423            failure = _combine_failures(exc, cleanup_error)
424            assert failure is not None
425            raise failure
426
427    def __iter__(self) -> Iterator[InterlaceEvent]:
428        return self
429
430    def __next__(self) -> InterlaceEvent:
431        event = self.next_event()
432        if event is None:
433            raise StopIteration
434        return event
435
436    @property
437    def peer_port(self) -> str | None:
438        """The port the connected peer's latest preface sent, for diagnostics;
439        `None` when it sent none or the interlace is direct."""
440        return self._driver.peer_port
441
442    @property
443    def peer_by(self) -> str | None:
444        """The By the live peer proved in the latest session under
445        confidential-channel or channel-bound assurance, for diagnostics;
446        `None` before that proof validates, without one, or when the interlace
447        is direct."""
448        return self._driver.peer_by
449
450    @property
451    def outgoing_encoding(self) -> str | None:
452        """The 065 token of the local-to-peer stream encoding the latest
453        preface pair selected, for diagnostics; `None` before the first peer
454        preface or when the interlace is direct."""
455        return self._driver.outgoing_encoding
456
457    @property
458    def incoming_encoding(self) -> str | None:
459        """The 065 token of the peer-to-local stream encoding, as
460        `outgoing_encoding`."""
461        return self._driver.incoming_encoding
462
463    def replace_policy(self, next_policy: PolicyInput) -> None:
464        """Stage `next_policy`. An interlace opened with a selector takes each
465        session's policy from it and raises LacePolicyError."""
466        self._claim()
467        try:
468            if self._failure is not None:
469                raise self._failure
470            if self._closed:
471                raise LacePolicyError("interlace is not open")
472            self._driver.replace(_prepare_policy(next_policy))
473        finally:
474            self._release()
475
476    def next_event(self, *, timeout: float | None = None) -> InterlaceEvent | None:
477        """One-event reading; `RecordSaved` carries the admitted record."""
478        timeout = _validate_timeout(timeout)
479        self._claim()
480        try:
481            return self._next_claimed(timeout)
482        finally:
483            self._release()
484
485    def _next_claimed(self, timeout: float | None) -> InterlaceEvent | None:
486        if self._failure is not None:
487            if self._failure_delivered:
488                return None
489            self._failure_delivered = True
490            raise self._failure
491        if self._closed:
492            if self._closed_delivered:
493                return None
494            self._closed_delivered = True
495            return Closed("cancelled")
496        try:
497            poll = self._driver.next_raw(timeout)
498            if poll is None:
499                return None
500            event = event_from_poll(poll, open_stream=True)
501            if isinstance(event, Closed):
502                self._finish()
503                self._closed_delivered = True
504            return event
505        except BaseException as error:
506            self._failure_delivered = True
507            if self._closed:
508                # Closing after `Closed` failed; `_finish` retained that failure.
509                raise
510            failure = error if not isinstance(error, Exception) else _as_interlace_error(error)
511            self._failure = failure
512            self._finish()
513            raise failure
514
515    def run_until_fixed_point(self) -> OpenBoundaryOutcome:
516        observations: list[InterlaceEvent] = []
517        while True:
518            observation = self.next_event()
519            if observation is None:
520                raise LaceIntegrationError(
521                    "interlace event stream exhausted before a boundary"
522                )
523            observations.append(observation)
524            if isinstance(observation, (FixedPoint, Closed)):
525                return OpenBoundaryOutcome(observation, observations)

One open interlace owning one route driver.

Event reading, policy replacement and close exclude each other: a call made while another owns the interlace fails as busy instead of waiting.

OpenInterlace( driver: lace._driver.Driver, *, private: Lace | None = None)
352    def __init__(self, driver: Driver, *, private: Lace | None = None) -> None:
353        self._busy = threading.Lock()
354        self._driver = driver
355        self._laces = driver.laces
356        # A porcelain operation's private Lace, closed with the operation.
357        self._private_lace = private
358        self._closed = False
359        self._closed_delivered = False
360        self._failure: BaseException | None = None
361        self._close_error: BaseException | None = None
362        self._failure_delivered = False
363        registered: list[Lace] = []
364        try:
365            for lace in self._laces:
366                lace._register_open_interlace(self)
367                registered.append(lace)
368        except BaseException as error:
369            _raise_after_cleanup(
370                error,
371                *(partial(lace._unregister_open_interlace, self) for lace in registered),
372            )
def close(self) -> None:
381    def close(self) -> None:
382        self._claim()
383        try:
384            self._finish()
385        finally:
386            self._release()
peer_port: str | None
436    @property
437    def peer_port(self) -> str | None:
438        """The port the connected peer's latest preface sent, for diagnostics;
439        `None` when it sent none or the interlace is direct."""
440        return self._driver.peer_port

The port the connected peer's latest preface sent, for diagnostics; None when it sent none or the interlace is direct.

peer_by: str | None
442    @property
443    def peer_by(self) -> str | None:
444        """The By the live peer proved in the latest session under
445        confidential-channel or channel-bound assurance, for diagnostics;
446        `None` before that proof validates, without one, or when the interlace
447        is direct."""
448        return self._driver.peer_by

The By the live peer proved in the latest session under confidential-channel or channel-bound assurance, for diagnostics; None before that proof validates, without one, or when the interlace is direct.

outgoing_encoding: str | None
450    @property
451    def outgoing_encoding(self) -> str | None:
452        """The 065 token of the local-to-peer stream encoding the latest
453        preface pair selected, for diagnostics; `None` before the first peer
454        preface or when the interlace is direct."""
455        return self._driver.outgoing_encoding

The 065 token of the local-to-peer stream encoding the latest preface pair selected, for diagnostics; None before the first peer preface or when the interlace is direct.

incoming_encoding: str | None
457    @property
458    def incoming_encoding(self) -> str | None:
459        """The 065 token of the peer-to-local stream encoding, as
460        `outgoing_encoding`."""
461        return self._driver.incoming_encoding

The 065 token of the peer-to-local stream encoding, as outgoing_encoding.

def replace_policy(self, next_policy: str | PreparedPolicy) -> None:
463    def replace_policy(self, next_policy: PolicyInput) -> None:
464        """Stage `next_policy`. An interlace opened with a selector takes each
465        session's policy from it and raises LacePolicyError."""
466        self._claim()
467        try:
468            if self._failure is not None:
469                raise self._failure
470            if self._closed:
471                raise LacePolicyError("interlace is not open")
472            self._driver.replace(_prepare_policy(next_policy))
473        finally:
474            self._release()

Stage next_policy. An interlace opened with a selector takes each session's policy from it and raises LacePolicyError.

def next_event( self, *, timeout: float | None = None) -> InterlaceEvent | None:
476    def next_event(self, *, timeout: float | None = None) -> InterlaceEvent | None:
477        """One-event reading; `RecordSaved` carries the admitted record."""
478        timeout = _validate_timeout(timeout)
479        self._claim()
480        try:
481            return self._next_claimed(timeout)
482        finally:
483            self._release()

One-event reading; RecordSaved carries the admitted record.

def run_until_fixed_point(self) -> OpenBoundaryOutcome:
515    def run_until_fixed_point(self) -> OpenBoundaryOutcome:
516        observations: list[InterlaceEvent] = []
517        while True:
518            observation = self.next_event()
519            if observation is None:
520                raise LaceIntegrationError(
521                    "interlace event stream exhausted before a boundary"
522                )
523            observations.append(observation)
524            if isinstance(observation, (FixedPoint, Closed)):
525                return OpenBoundaryOutcome(observation, observations)
class PeerProofAssurance(builtins.str, enum.Enum):
27class PeerProofAssurance(str, Enum):
28    """Host assertion about established IO, not transport protection.
29
30    CONFIDENTIAL_CHANNEL asserts confidentiality, integrity, and endpoint
31    confinement for the complete channel, including proxies and backend hops.
32    CHANNEL_BOUND additionally binds both live proofs to the supplied channel.
33    """
34
35    DISABLED = "disabled"
36    CONFIDENTIAL_CHANNEL = "confidential-channel"
37    CHANNEL_BOUND = "channel-bound"

Host assertion about established IO, not transport protection.

CONFIDENTIAL_CHANNEL asserts confidentiality, integrity, and endpoint confinement for the complete channel, including proxies and backend hops. CHANNEL_BOUND additionally binds both live proofs to the supplied channel.

DISABLED = <PeerProofAssurance.DISABLED: 'disabled'>
CONFIDENTIAL_CHANNEL = <PeerProofAssurance.CONFIDENTIAL_CHANNEL: 'confidential-channel'>
CHANNEL_BOUND = <PeerProofAssurance.CHANNEL_BOUND: 'channel-bound'>
@dataclass(frozen=True, init=False)
class PreparedPolicy:
12@dataclass(frozen=True, init=False)
13class PreparedPolicy:
14    """An independently owned, validated canonical exchange operand."""
15    _native: _lace_py._PreparedPolicy
16
17    def __new__(cls) -> PreparedPolicy:
18        raise TypeError("use compile or PreparedPolicy.from_canonical_text")
19
20    @classmethod
21    def _from_native(cls, value: _lace_py._PreparedPolicy) -> PreparedPolicy:
22        result = object.__new__(cls)
23        object.__setattr__(result, "_native", value)
24        return result
25
26    @classmethod
27    def from_canonical_text(cls, text: str) -> PreparedPolicy:
28        if not isinstance(text, str):
29            raise TypeError("canonical policy text must be a string")
30        return cls._from_native(_native._PreparedPolicy.from_canonical_text(text))
31
32    @property
33    def canonical_text(self) -> str:
34        return self._native.canonical_text
35
36    @property
37    def operand_hash(self) -> str:
38        return self._native.operand_hash

An independently owned, validated canonical exchange operand.

@classmethod
def from_canonical_text(cls, text: str) -> PreparedPolicy:
26    @classmethod
27    def from_canonical_text(cls, text: str) -> PreparedPolicy:
28        if not isinstance(text, str):
29            raise TypeError("canonical policy text must be a string")
30        return cls._from_native(_native._PreparedPolicy.from_canonical_text(text))
canonical_text: str
32    @property
33    def canonical_text(self) -> str:
34        return self._native.canonical_text
operand_hash: str
36    @property
37    def operand_hash(self) -> str:
38        return self._native.operand_hash
class Record:
def from_bytes(bytes):
def create(*, fields=None, data=None, by_secret=None):
def generate_by_secret():
def by_from_secret(secret):
def fields(self, /, name):
def field_occurrences(self, /):
def contiguous_bytes(self, /):

The complete canonical bytes, when the record holds them contiguously.

def contiguous_data(self, /):

The Blob data, when the record holds it contiguously.

def read_at(self, /, offset, size):

At most size canonical bytes from offset; fewer only at the end.

def to_bytes(self, /, limit):

The complete canonical bytes, if at most limit bytes long.

def data_to_bytes(self, /, limit):

The Blob data, if at most limit bytes long.

kind
plex_hash
data_offset

Offset of the Blob data within the canonical bytes.

canonical_len

The complete canonical length in bytes.

blob_hash
hash
data_length
by
mark
@dataclass(frozen=True)
class RecordEvent(lace.InterlaceEvent):
23@dataclass(frozen=True)
24class RecordEvent(InterlaceEvent):
25    hash: str
26    position: ParticipantPosition
RecordEvent(hash: str, position: Literal['first', 'second'])
hash: str
position: Literal['first', 'second']
@dataclass(frozen=True)
class RecordSaved(lace.RecordEvent):
34@dataclass(frozen=True)
35class RecordSaved(RecordEvent):
36    """`record` is the admitted owned record on open streams, `None` in bounded outcomes."""
37
38    record: Record | None = None

record is the admitted owned record on open streams, None in bounded outcomes.

RecordSaved( hash: str, position: Literal['first', 'second'], record: Record | None = None)
record: Record | None = None
@dataclass(frozen=True)
class RecordSent(lace.RecordEvent):
29@dataclass(frozen=True)
30class RecordSent(RecordEvent):
31    pass
RecordSent(hash: str, position: Literal['first', 'second'])
@dataclass(frozen=True)
class SessionOperand:
40@dataclass(frozen=True)
41class SessionOperand:
42    """One logical session's operand, returned by an `open_interlace` selector.
43
44    `policy` is prepared when the selector returns it; `expected_peer_by`
45    rejects every peer proof but that By's, as at connected construction.
46    """
47
48    policy: PolicyInput
49    expected_peer_by: str | None = None
50
51    def __init__(self, policy: PolicyInput, *, expected_peer_by: str | None = None) -> None:
52        if not isinstance(policy, (str, PreparedPolicy)):
53            raise TypeError("policy must be source text or PreparedPolicy")
54        if expected_peer_by is not None:
55            _native.validate_by(expected_peer_by)
56        object.__setattr__(self, "policy", policy)
57        object.__setattr__(self, "expected_peer_by", expected_peer_by)

One logical session's operand, returned by an open_interlace selector.

policy is prepared when the selector returns it; expected_peer_by rejects every peer proof but that By's, as at connected construction.

SessionOperand( policy: str | PreparedPolicy, *, expected_peer_by: str | None = None)
51    def __init__(self, policy: PolicyInput, *, expected_peer_by: str | None = None) -> None:
52        if not isinstance(policy, (str, PreparedPolicy)):
53            raise TypeError("policy must be source text or PreparedPolicy")
54        if expected_peer_by is not None:
55            _native.validate_by(expected_peer_by)
56        object.__setattr__(self, "policy", policy)
57        object.__setattr__(self, "expected_peer_by", expected_peer_by)
policy: str | PreparedPolicy
expected_peer_by: str | None = None
@dataclass(frozen=True)
class StoppedByLimit:
120@dataclass(frozen=True)
121class StoppedByLimit:
122    kind: Literal["stopped-by-limit"] = "stopped-by-limit"
StoppedByLimit(kind: Literal['stopped-by-limit'] = 'stopped-by-limit')
kind: Literal['stopped-by-limit'] = 'stopped-by-limit'
@dataclass(frozen=True)
class StoreOutcome:
149@dataclass(frozen=True)
150class StoreOutcome:
151    terminal: Terminal
152    observations: list[InterlaceEvent]
153    records: list[StoreRecordResult]
StoreOutcome( terminal: Complete | StoppedByLimit | Failed, observations: list[InterlaceEvent], records: list[StoreRecordResult])
observations: list[InterlaceEvent]
records: list[StoreRecordResult]
@dataclass(frozen=True)
class StoreRecordResult:
141@dataclass(frozen=True)
142class StoreRecordResult:
143    hash: str
144    kind: Literal["saved", "skipped", "unsettled"]
145    provider_sent: bool
146    target_saved: bool
StoreRecordResult( hash: str, kind: Literal['saved', 'skipped', 'unsettled'], provider_sent: bool, target_saved: bool)
hash: str
kind: Literal['saved', 'skipped', 'unsettled']
provider_sent: bool
target_saved: bool
class StoreStream:
188class StoreStream:
189    """The open counterpart of `store`: offers records one at a time.
190
191    An offer made while another runs fails as busy. An error, including an
192    interrupted offer, ends the stream: later offers raise it, and records
193    saved before it stay saved.
194    """
195
196    def __init__(self, opened: OpenInterlace, provider: Lace) -> None:
197        self._opened = opened
198        self._provider = provider
199        self._busy = threading.Lock()
200        self._failure: BaseException | None = None
201        self._closed = False
202
203    def offer(self, record: Record) -> Literal["saved", "skipped"]:
204        """Store `record` into the provider and drive to the next fixed point:
205        "saved" when the provider sent it, "skipped" when it did not or the
206        provider already held it."""
207        if not isinstance(record, Record):
208            raise TypeError("offer accepts a Record; use Record.from_bytes(...) to validate imported bytes first")
209        if not self._busy.acquire(blocking=False):
210            raise RuntimeError("store stream is busy")
211        try:
212            if self._failure is not None:
213                raise self._failure
214            if self._closed:
215                raise RuntimeError("store stream is closed")
216            try:
217                return self._offer(record)
218            except BaseException as error:
219                self._failure = error
220                raise
221        finally:
222            self._busy.release()
223
224    def _offer(self, record: Record) -> Literal["saved", "skipped"]:
225        # The provider admits the record through ordinary interlace; its
226        # published position wakes the open interlace.
227        outcome = store(self._provider, record)
228        if isinstance(outcome.terminal, Failed):
229            raise outcome.terminal.error
230        if not isinstance(outcome.terminal, Complete):
231            raise LaceLimitExceededError("storing the offer into the provider stopped by a limit")
232        if outcome.records[0].kind == "skipped":
233            return "skipped"
234        return "saved" if self._fixed_point(record.hash) else "skipped"
235
236    def _fixed_point(self, record_hash: str | None) -> bool:
237        """Drive to the next fixed point; whether the provider sent `record_hash`."""
238        sent = False
239        while True:
240            event = self._opened.next_event()
241            if event is None:
242                raise LaceIntegrationError("store stream ended before its fixed point")
243            if isinstance(event, FixedPoint):
244                return sent
245            if isinstance(event, Closed):
246                raise LacePeerProtocolError(
247                    f"store stream closed before an offer's fixed point: {event.reason}"
248                )
249            if isinstance(event, RecordSent) and event.position == "first":
250                sent = sent or event.hash == record_hash
251
252    def close(self) -> None:
253        """Cancel the interlace and close the provider; raise the failure that
254        ended the stream with any cleanup failure."""
255        if not self._busy.acquire(blocking=False):
256            raise RuntimeError("store stream is busy")
257        try:
258            failure = self._failure
259            if not self._closed:
260                self._closed = True
261                try:
262                    self._opened.close()
263                except BaseException as error:
264                    if error is not failure:
265                        failure = _combine_failures(failure, error)
266                self._failure = failure
267            if failure is not None:
268                raise failure
269        finally:
270            self._busy.release()
271
272    def __enter__(self) -> "StoreStream":
273        return self
274
275    def __exit__(
276        self,
277        exc_type: type[BaseException] | None,
278        exc: BaseException | None,
279        tb: TracebackType | None,
280    ) -> None:
281        try:
282            self.close()
283        except BaseException as cleanup_error:
284            if exc is None or cleanup_error is exc:
285                raise
286            failure = _combine_failures(exc, cleanup_error)
287            assert failure is not None
288            raise failure

The open counterpart of store: offers records one at a time.

An offer made while another runs fails as busy. An error, including an interrupted offer, ends the stream: later offers raise it, and records saved before it stay saved.

StoreStream(opened: OpenInterlace, provider: Lace)
196    def __init__(self, opened: OpenInterlace, provider: Lace) -> None:
197        self._opened = opened
198        self._provider = provider
199        self._busy = threading.Lock()
200        self._failure: BaseException | None = None
201        self._closed = False
def offer(self, record: Record) -> Literal['saved', 'skipped']:
203    def offer(self, record: Record) -> Literal["saved", "skipped"]:
204        """Store `record` into the provider and drive to the next fixed point:
205        "saved" when the provider sent it, "skipped" when it did not or the
206        provider already held it."""
207        if not isinstance(record, Record):
208            raise TypeError("offer accepts a Record; use Record.from_bytes(...) to validate imported bytes first")
209        if not self._busy.acquire(blocking=False):
210            raise RuntimeError("store stream is busy")
211        try:
212            if self._failure is not None:
213                raise self._failure
214            if self._closed:
215                raise RuntimeError("store stream is closed")
216            try:
217                return self._offer(record)
218            except BaseException as error:
219                self._failure = error
220                raise
221        finally:
222            self._busy.release()

Store record into the provider and drive to the next fixed point: "saved" when the provider sent it, "skipped" when it did not or the provider already held it.

def close(self) -> None:
252    def close(self) -> None:
253        """Cancel the interlace and close the provider; raise the failure that
254        ended the stream with any cleanup failure."""
255        if not self._busy.acquire(blocking=False):
256            raise RuntimeError("store stream is busy")
257        try:
258            failure = self._failure
259            if not self._closed:
260                self._closed = True
261                try:
262                    self._opened.close()
263                except BaseException as error:
264                    if error is not failure:
265                        failure = _combine_failures(failure, error)
266                self._failure = failure
267            if failure is not None:
268                raise failure
269        finally:
270            self._busy.release()

Cancel the interlace and close the provider; raise the failure that ended the stream with any cleanup failure.

def all_records() -> PreparedPolicy:
103def all_records() -> PreparedPolicy:
104    """The policy that selects, exposes, and requests every record."""
105    return PreparedPolicy._from_native(_native.all_records())

The policy that selects, exposes, and requests every record.

def bounded_interlace( first: Lace | LaceHandle | LocalPeer | ConnectedPeer, second: Lace | LaceHandle | LocalPeer | ConnectedPeer, policy: str | PreparedPolicy, *, limits: dict[str, int] | None = None, cancellation: Cancellation | None = None) -> BoundedInterlaceOutcome:
628def bounded_interlace(
629    first: Participant,
630    second: Participant,
631    policy: PolicyInput,
632    *,
633    limits: dict[str, int] | None = None,
634    cancellation: Cancellation | None = None,
635) -> BoundedInterlaceOutcome:
636    with _accept_connected_inputs(first, second) as (owned_first, owned_second):
637        cancellation = _cancellation_argument(cancellation)
638        prepared = _prepare_policy(policy)
639        raw = _bounded_any_raw(
640            owned_first, owned_second, prepared, prepared,
641            limits=limits, cancellation=cancellation,
642        )
643        return BoundedInterlaceOutcome(
644            _terminal(raw), raw.events, raw.peer_by,
645            raw.outgoing_encoding, raw.incoming_encoding,
646        )
def compile( source: str, *, max_source_bytes: int = 1048576) -> PreparedPolicy:
41def compile(source: str, *, max_source_bytes: int = 1 << 20) -> PreparedPolicy:
42    """Compile one complete Interlang contribution into an exchange operand."""
43    if not isinstance(source, str):
44        raise TypeError("policy source must be a string")
45    if isinstance(max_source_bytes, bool) or not isinstance(max_source_bytes, int):
46        raise TypeError("max_source_bytes must be a nonnegative integer")
47    if max_source_bytes < 0:
48        raise ValueError("max_source_bytes must be a nonnegative integer")
49    return PreparedPolicy._from_native(_native.compile_policy(source, max_source_bytes))

Compile one complete Interlang contribution into an exchange operand.

def compose_policies( policies: Sequence[PreparedPolicy], *, guests: Sequence[PreparedPolicy] = (), exclusions: Sequence[FieldExclusion] = ()) -> PreparedPolicy:
60def compose_policies(
61    policies: Sequence[PreparedPolicy],
62    *,
63    guests: Sequence[PreparedPolicy] = (),
64    exclusions: Sequence[FieldExclusion] = (),
65) -> PreparedPolicy:
66    """Intersect contributed selection/exposure facets and union vetoes.
67
68    Each input retains private helpers. Absent facets add no local constraint;
69    empty ``policies`` is an error. Guest rules see only records the authoring
70    ``policies`` expose. Records matching an exclusion are neither selected,
71    requested nor exposed. All complete sequences are composed in one Rust call.
72    """
73    return PreparedPolicy._from_native(_native.compose_policies(
74        _prepared_sequence(policies, "policies"), _prepared_sequence(guests, "guests"),
75        _exclusion_sequence(exclusions)))

Intersect contributed selection/exposure facets and union vetoes.

Each input retains private helpers. Absent facets add no local constraint; empty policies is an error. Guest rules see only records the authoring policies expose. Records matching an exclusion are neither selected, requested nor exposed. All complete sequences are composed in one Rust call.

def for_each( lace: Lace | LaceHandle | LocalPeer | ConnectedPeer, policy: str | PreparedPolicy, *, limits: dict[str, int] | None = None) -> ForEachStream:
144def for_each(
145    lace: Participant,
146    policy: PolicyInput,
147    *,
148    limits: dict[str, int] | None = None,
149) -> ForEachStream:
150    with _accept_connected_inputs(lace) as (target,):
151        operands = _private_operands(_prepare_policy(policy), _native.tx_disabled())
152        observer = _private_lace()
153        try:
154            return ForEachStream(
155                OpenInterlace._open(observer, target, *operands, limits, private=observer)
156            )
157        except BaseException as error:
158            _raise_after_cleanup(error, observer.close)
def get( lace: Lace | LaceHandle | LocalPeer | ConnectedPeer, policy: str | PreparedPolicy, *, limits: dict[str, int] | None = None, cancellation: Cancellation | None = None) -> GetOutcome:
126def get(
127    lace: Participant,
128    policy: PolicyInput,
129    *,
130    limits: dict[str, int] | None = None,
131    cancellation: Cancellation | None = None,
132) -> GetOutcome:
133    with _accept_connected_inputs(lace) as (target,):
134        result = _capture_records(
135            target, policy, limits=limits,
136            cancellation=_cancellation_argument(cancellation), first_only=True,
137        )
138        return GetOutcome(
139            result.terminal, result.observations,
140            result.records[0] if result.records else None,
141        )
def list_records( lace: Lace | LaceHandle | LocalPeer | ConnectedPeer, policy: str | PreparedPolicy, *, limits: dict[str, int] | None = None, cancellation: Cancellation | None = None) -> ListOutcome:
112def list_records(
113    lace: Participant,
114    policy: PolicyInput,
115    *,
116    limits: dict[str, int] | None = None,
117    cancellation: Cancellation | None = None,
118) -> ListOutcome:
119    with _accept_connected_inputs(lace) as (target,):
120        return _capture_records(
121            target, policy, limits=limits,
122            cancellation=_cancellation_argument(cancellation), first_only=False,
123        )
def open_interlace( first: Lace | LaceHandle | LocalPeer | ConnectedPeer, second: Lace | LaceHandle | LocalPeer | ConnectedPeer, policy: str | PreparedPolicy | None = None, *, selector: Optional[Callable[[str | None], SessionOperand | None]] = None, limits: dict[str, int] | None = None) -> OpenInterlace:
649def open_interlace(
650    first: Participant,
651    second: Participant,
652    policy: PolicyInput | None = None,
653    *,
654    selector: Selector | None = None,
655    limits: dict[str, int] | None = None,
656) -> OpenInterlace:
657    """Open an interlace under `policy`, or under `selector` between one local
658    Lace and one ConnectedPeer.
659
660    The selector is called once per logical session with the peer preface's
661    port, or `None` when it sent none, and returns that session's
662    `SessionOperand` or `None` to refuse the port, which fails the operation
663    as LacePeerProtocolError("port refused").
664    """
665    with _accept_connected_inputs(first, second) as (owned_first, owned_second):
666        if (policy is None) == (selector is None):
667            raise TypeError("open_interlace takes exactly one of policy or selector")
668        if selector is not None:
669            if not callable(selector):
670                raise TypeError("selector must be callable")
671            return OpenInterlace._own(
672                _create_selected_driver(owned_first, owned_second, selector, limits)
673            )
674        assert policy is not None
675        prepared = _prepare_policy(policy)
676        return OpenInterlace._open(owned_first, owned_second, prepared, prepared, limits)

Open an interlace under policy, or under selector between one local Lace and one ConnectedPeer.

The selector is called once per logical session with the peer preface's port, or None when it sent none, and returns that session's SessionOperand or None to refuse the port, which fails the operation as LacePeerProtocolError("port refused").

def parse_by(text: str) -> str:
 8def parse_by(text: str) -> str:
 9    """Parse one canonical public Lace By value and return its canonical text."""
10    try:
11        return _native.validate_by(text)
12    except Exception as error:
13        raise ValueError(str(error)) from error

Parse one canonical public Lace By value and return its canonical text.

def read_record_stream( lace: Lace | LaceHandle, reader: <class 'BinaryIO'>, *, max_bytes: int) -> Iterator[Record]:
68def read_record_stream(
69    lace: Lace | LaceHandle, reader: BinaryIO, *, max_bytes: int
70) -> Iterator[Record]:
71    """The records of one Lace-010 record stream read from a binary reader.
72
73    Records arrive in stream order, each received into memory once its bytes
74    are validated; nothing is admitted. A record whose canonical length exceeds
75    what remains of `max_bytes` fails at its start with LaceLimitExceededError,
76    before its bytes are held. An invalid record, bytes after a record that do
77    not form one, or a stream ending inside a record raise
78    LacePeerProtocolError, and a failed read LaceTransportError. A failure ends
79    the iterator and discards the partial record.
80    """
81    owner = lace if isinstance(lace, Lace) else lace._lace if isinstance(lace, LaceHandle) else None
82    if owner is None:
83        raise TypeError("read_record_stream requires a Lace or LaceHandle")
84    owner._raise_if_unavailable()
85    if isinstance(max_bytes, bool) or not isinstance(max_bytes, int) or not 0 <= max_bytes < 1 << 64:
86        raise ValueError("max_bytes must be a u64 integer")
87    return _record_stream(_native.RecordStreamDecoder(max_bytes), reader)

The records of one Lace-010 record stream read from a binary reader.

Records arrive in stream order, each received into memory once its bytes are validated; nothing is admitted. A record whose canonical length exceeds what remains of max_bytes fails at its start with LaceLimitExceededError, before its bytes are held. An invalid record, bytes after a record that do not form one, or a stream ending inside a record raise LacePeerProtocolError, and a failed read LaceTransportError. A failure ends the iterator and discards the partial record.

def store( lace: Lace | LaceHandle | LocalPeer | ConnectedPeer, record: Record | Iterable[Record], *, limits: dict[str, int] | None = None, cancellation: Cancellation | None = None) -> StoreOutcome:
35def store(
36    lace: Participant,
37    record: Record | Iterable[Record],
38    *,
39    limits: dict[str, int] | None = None,
40    cancellation: Cancellation | None = None,
41) -> StoreOutcome:
42    with _accept_connected_inputs(lace) as (target,):
43        cancellation = _cancellation_argument(cancellation)
44        target_lace = _store_lace(target)
45        if target_lace is None and not isinstance(target, (LocalPeer, _ConnectedInput)):
46            raise TypeError("store target must be a Lace, LaceHandle, LocalPeer, or connected peer")
47        normalized_limits = _interlace_limits(limits)
48        records_input = _normalize_records(record)
49        if not records_input:
50            return StoreOutcome(Complete(), [], [])
51        operands = _private_operands(all_records(), _native.rx_disabled())
52        source = _private_lace(records_input)
53        try:
54            raw = _bounded_any_raw(
55                source, target, *operands,
56                limits=normalized_limits, cancellation=cancellation,
57            )
58        except BaseException as error:
59            _raise_after_cleanup(error, source.close)
60        raw.settle(source.close)
61        unique = dict.fromkeys(input_record.hash for input_record in records_input)
62        sent = {
63            event.hash for event in raw.events
64            if isinstance(event, RecordSent) and event.position == "first"
65        }
66        terminal = _terminal(raw)
67        settled = isinstance(terminal, Complete)
68        results = [
69            StoreRecordResult(
70                hash_text,
71                "saved" if settled and hash_text in sent else "skipped" if settled else "unsettled",
72                hash_text in sent, settled and hash_text in sent,
73            )
74            for hash_text in unique
75        ]
76        return StoreOutcome(terminal, raw.events, results)
def store_stream( lace: Lace | LaceHandle | LocalPeer | ConnectedPeer, *, limits: dict[str, int] | None = None) -> StoreStream:
161def store_stream(
162    lace: Participant,
163    *,
164    limits: dict[str, int] | None = None,
165) -> "StoreStream":
166    """Open `store`'s interlace against `lace` with an empty private provider
167    and drive it to its first fixed point; then `offer` each record."""
168    with _accept_connected_inputs(lace) as (target,):
169        if _store_lace(target) is None and not isinstance(target, (LocalPeer, _ConnectedInput)):
170            raise TypeError("store_stream target must be a Lace, LaceHandle, LocalPeer, or connected peer")
171        operands = _private_operands(all_records(), _native.rx_disabled())
172        provider = _private_lace()
173        try:
174            opened = OpenInterlace._open(provider, target, *operands, limits, private=provider)
175        except BaseException as error:
176            _raise_after_cleanup(error, provider.close)
177        stream = StoreStream(opened, provider)
178        try:
179            stream._fixed_point(None)
180        except BaseException as error:
181            # Close raises this failure with any cleanup failure.
182            stream._failure = error
183            stream.close()
184            raise
185        return stream

Open store's interlace against lace with an empty private provider and drive it to its first fixed point; then offer each record.

def compact_filesystem( root: str | os.PathLike[str], policies: Sequence[str | PreparedPolicy]) -> CompactionReport:
39    def compact_filesystem(
40        root: str | os.PathLike[str], policies: Sequence[PolicyInput]
41    ) -> CompactionReport:
42        """Remove every record of the filesystem root that no policy selects.
43
44        The root must have no open Lace and no live record in any process.
45        A root holding an interrupted compaction resumes it without evaluating
46        ``policies``. ``KeyboardInterrupt`` stops the work at its next store
47        operation or move batch and leaves a root only compaction reopens.
48        """
49        natives = _native_policies(policies)
50        return CompactionReport(*_native.compact_filesystem(str(Path(root)), natives))

Remove every record of the filesystem root that no policy selects.

The root must have no open Lace and no live record in any process. A root holding an interrupted compaction resumes it without evaluating policies. KeyboardInterrupt stops the work at its next store operation or move batch and leaves a root only compaction reopens.