correspond.ops#
The operations: small protocols an adapter implements a subset of, and the verbs that call them.
An adapter is any object with a name, capabilities and parse_ref(id), plus the
methods of whichever protocols it can honour:
Reader |
|
Listener |
|
Writer |
|
Editor |
|
Reactor |
|
Uploader |
|
Verifier |
|
AudienceReader |
|
Labeler |
|
Unlabeler |
|
Closer |
|
Reopener |
|
The verbs here (read(), listen(), send(), …) take a reference string,
find the adapter in the registry, and raise NotSupported
naming the operation when the adapter lacks it; never a silent no-op. Writes check the
draft against the channel’s capabilities first, and turn a
ChannelError into a SendResult with ok=False, so a
failed notification never crashes its caller. dry_run=True sends nothing and changes
nothing; the only call it makes is the audience lookup.
audience() is the exception to refusing: it never raises, because an audience
nobody can compute is public.
send() takes an idempotency_key: the same key again posts nothing a second time,
even after a send that went out and then reported a failure (correspond.idempotency).
Before every write (send(), edit(), react(), upload()), and in its
dry run, the before_send check runs with the conversation’s audience
(correspond.outbound). Its verdict and the audience in words go into the plan, and a
check that refuses, holds for approval, cannot be loaded or fails stops the write with that
error_kind. Calling an adapter’s own methods skips the check: write through these verbs.
Module Attributes
Operation name → the protocol an adapter implements to have it. |
Functions
|
Who can read a conversation, asked of its channel now. |
|
What a channel can do, graded, with its limits. |
|
Close a conversation (an issue or a discussion), with an optional |
|
Replace the text of a message correspond's account wrote; the |
|
The adapter registered under |
|
The operations an adapter implements, in |
|
Add |
|
Events since the cursor stored for |
|
A reference normalised by its channel's adapter (kind and parent filled in, the id validated). |
|
Add a reaction to a message (the channel's capabilities list the reactions it accepts); the |
|
The messages of a conversation, oldest first ( |
|
Reopen a closed conversation; the |
|
Send |
|
Remove |
|
Send a file to a conversation. |
|
Grade an inbound delivery on |
|
Where |
|
Have |
|
Stop webhook delivery for |
|
Messages sent or edited at or after |
|
Yield |
Classes
|
Who can read a conversation, now and plausibly later, asked of the platform at the time of the call. |
|
What every adapter has: a name, its capabilities, and the grammar of its conversation ids. |
|
Settle a conversation (close an issue or a discussion), optionally saying why. |
|
Replace the text of a message correspond's account wrote. |
|
Add labels to a conversation, apart from its opening send. |
|
Events since |
|
Add a reaction to a message. |
|
Messages of a conversation, oldest first; |
|
Unsettle a closed conversation. |
|
Remove labels from a conversation. |
|
Send a file to a conversation. |
|
Grade an inbound delivery (a webhook, a posted report) from its headers and raw body. |
|
Move where a channel's platform delivers its updates. |
|
Where a channel's platform delivers its updates now: polling, or a webhook it POSTs to. |
|
Send a draft to a conversation. |
- class correspond.ops.AudienceReader(*args, **kwargs)[source]#
Bases:
ProtocolWho can read a conversation, now and plausibly later, asked of the platform at the time of the call.
- class correspond.ops.Channel(*args, **kwargs)[source]#
Bases:
ProtocolWhat every adapter has: a name, its capabilities, and the grammar of its conversation ids.
- class correspond.ops.Closer(*args, **kwargs)[source]#
Bases:
ProtocolSettle a conversation (close an issue or a discussion), optionally saying why.
- class correspond.ops.Editor(*args, **kwargs)[source]#
Bases:
ProtocolReplace the text of a message correspond’s account wrote.
- class correspond.ops.Labeler(*args, **kwargs)[source]#
Bases:
ProtocolAdd labels to a conversation, apart from its opening send.
- class correspond.ops.Listener(*args, **kwargs)[source]#
Bases:
ProtocolEvents since
cursor, oldest first, each carrying the cursor to resume after it.
- correspond.ops.PROTOCOLS: dict[str, type] = {'audience': <class 'correspond.ops.AudienceReader'>, 'close': <class 'correspond.ops.Closer'>, 'edit': <class 'correspond.ops.Editor'>, 'label': <class 'correspond.ops.Labeler'>, 'listen': <class 'correspond.ops.Listener'>, 'react': <class 'correspond.ops.Reactor'>, 'read': <class 'correspond.ops.Reader'>, 'reopen': <class 'correspond.ops.Reopener'>, 'send': <class 'correspond.ops.Writer'>, 'unlabel': <class 'correspond.ops.Unlabeler'>, 'upload': <class 'correspond.ops.Uploader'>, 'verify': <class 'correspond.ops.Verifier'>}#
Operation name → the protocol an adapter implements to have it.
- class correspond.ops.Reader(*args, **kwargs)[source]#
Bases:
ProtocolMessages of a conversation, oldest first;
limitkeeps the most recent.
- class correspond.ops.Reopener(*args, **kwargs)[source]#
Bases:
ProtocolUnsettle a closed conversation.
- class correspond.ops.Unlabeler(*args, **kwargs)[source]#
Bases:
ProtocolRemove labels from a conversation.
- class correspond.ops.Uploader(*args, **kwargs)[source]#
Bases:
ProtocolSend a file to a conversation.
- class correspond.ops.Verifier(*args, **kwargs)[source]#
Bases:
ProtocolGrade an inbound delivery (a webhook, a posted report) from its headers and raw body.
- class correspond.ops.WebhookManager(*args, **kwargs)[source]#
Bases:
ProtocolMove where a channel’s platform delivers its updates.
Not an operation in
OPERATIONS, but a write all the same: whoever the webhook points at reads every update the account receives, so it runs thebefore_sendcheck (operation="set_webhook", the URL as the draft’s text).
- class correspond.ops.WebhookReader(*args, **kwargs)[source]#
Bases:
ProtocolWhere a channel’s platform delivers its updates now: polling, or a webhook it POSTs to.
- class correspond.ops.Writer(*args, **kwargs)[source]#
Bases:
ProtocolSend a draft to a conversation.
- correspond.ops.audience(ref, draft=None, *, registry=None)[source]#
Who can read a conversation, asked of its channel now. Never raises: unknown resolves to public.
A malformed reference, an unknown or planned channel, an adapter without an audience reader, and any error while computing all give
scope="public",complete=False,defaulted=True, with the reason inevidence. Nothing is cached: call it again right before sending.- Return type:
- correspond.ops.capabilities(channel, *, registry=None)[source]#
What a channel can do, graded, with its limits.
- Return type:
- correspond.ops.close(ref, *, reason=None, dry_run=False, registry=None, before_send=None)[source]#
Close a conversation (an issue or a discussion), with an optional
reasonin the channel’s vocabulary; thebefore_sendcheck sees the reason (orclose) as the draft’s text.- Return type:
- correspond.ops.delete_webhook(channel, *, drop_pending_updates=False, dry_run=False, registry=None, before_send=None)[source]#
Stop webhook delivery for
channel, so it can be polled again; thebefore_sendcheck runs (operation="delete_webhook").- Return type:
- correspond.ops.edit(ref, message_id, text, *, dry_run=False, registry=None, before_send=None)[source]#
Replace the text of a message correspond’s account wrote; the
before_sendcheck runs first, as forsend().- Return type:
- correspond.ops.get_channel(name, *, registry=None)[source]#
The adapter registered under
name;UnknownChannelsays what to do if there is none.- Return type:
- correspond.ops.implemented(adapter)[source]#
The operations an adapter implements, in
OPERATIONSorder.
- correspond.ops.label(ref, labels, *, dry_run=False, registry=None, before_send=None)[source]#
Add
labelsto a conversation; thebefore_sendcheck sees them, comma-joined, as the draft’s text.- Return type:
- correspond.ops.listen(ref, *, cursors=None, limit=None, commit=True, registry=None)[source]#
Events since the cursor stored for
ref; each cursor is stored once the consumer moves past its event.cursorsdefaults to files under the data root. Events can repeat after a crash or an earlybreak: deduplicate ondelivery_id.
- correspond.ops.parse_ref(ref, *, registry=None)[source]#
A reference normalised by its channel’s adapter (kind and parent filled in, the id validated).
- Return type:
- correspond.ops.react(ref, message_id, reaction, *, dry_run=False, registry=None, before_send=None)[source]#
Add a reaction to a message (the channel’s capabilities list the reactions it accepts); the
before_sendcheck sees the reaction as the draft’s text.- Return type:
- correspond.ops.read(ref, *, since=None, limit=None, registry=None)[source]#
The messages of a conversation, oldest first (
limitkeeps the most recent ones).
- correspond.ops.reopen(ref, *, dry_run=False, registry=None, before_send=None)[source]#
Reopen a closed conversation; the
before_sendcheck seesreopenas the draft’s text.- Return type:
- correspond.ops.send(ref, text, *, title=None, reply_to=None, priority=None, cc=(), bcc=(), native=None, notify=(), attachments=(), dry_run=False, registry=None, before_send=None, idempotency_key=None, sends=None)[source]#
Send
text(or aDraft) to a conversation;dry_runshows the plan and sends nothing.attachments(Draft.attachments) are files that go with the text, on channels that gradeupload, each within itsmax_upload_bytes.ccandbcccopy further recipients, on channels that gradecc(email).nativecarries channel-specific fields (Draft.native), checked against the channel’scapabilities.draft_fields: an unknown key is a validation failure, never silently dropped.notifynames who must be notified (Draft.notify); the channel’s writer guarantees it (a mention added, an address copied) or the send fails withNotSupported("notify").before_send(ref, draft, audience)runs first, on the dry run too; whenNone, the config’sbefore_sendreference, elsecorrespond.outbound.notice().idempotency_keymakes sending the same message again safe: a key that already sent answers that send’s result and posts nothing, and one whose earlier attempt may have gone out is confirmed by reading the conversation back, or refused asunconfirmed(correspond.idempotency).sendsis where keys are kept: by default files under the data root (correspond.stores.send_store()). A mapping with aclaim(key, record) -> bool(as that store has) is exclusive across processes; a plain one is checked, then set, which covers one process.- Return type:
- correspond.ops.set_webhook(channel, url, *, dry_run=False, registry=None, before_send=None)[source]#
Have
channel’s platform POST its updates tourl: listening by polling stops untildelete_webhook().Whoever
urlbelongs to reads every update the account receives from then on, so thebefore_sendcheck runs (operation="set_webhook", the URL as the draft’s text), on the dry run too.- Return type:
- correspond.ops.unlabel(ref, labels, *, dry_run=False, registry=None, before_send=None)[source]#
Remove
labelsfrom a conversation; thebefore_sendcheck sees them, comma-joined, as the draft’s text.- Return type:
- correspond.ops.upload(ref, name, data, *, media_type='application/octet-stream', dry_run=False, source=None, native=None, registry=None, before_send=None, idempotency_key=None, sends=None)[source]#
Send a file to a conversation.
nativecarries the channel’s own options, the keys itscapabilities.draft_fieldslist (Telegram:{"as_document": true}sends an image as a file, not a photo).idempotency_keykeeps a retry from posting the file twice, as forsend(); an upload is not read back, so one whose earlier attempt may have gone out is refused asunconfirmed.The
before_sendcheck sees the file name as the draft’s text (operation="upload") and the file’s metadata indraft.native["upload"]:name,media_type,bytes,sha256and, when the caller read it from disk,source(its path), so a check can hold a large, unknown or out-of-place file. It never sees the contents: a check that must vet them should hold or refuse.- Return type:
- correspond.ops.verify(channel, headers, body, *, registry=None)[source]#
Grade an inbound delivery on
channelfrom its headers and raw body.- Return type:
- correspond.ops.webhook_info(channel, *, registry=None)[source]#
Where
channel’s platform delivers its updates now (an emptyurl: polling).- Return type: