API Reference¶
Bot¶
- class osmium_chat.bot.Bot(prefix, client_id, *, logger=None)[source]¶
Bases:
objectThe main entry point for an Osmium bot.
Holds connection state, the registered event listeners, and the authenticated
Useronce connected.Commands and event listeners are defined by subclassing
Commandsand registering the subclass withadd_commands().Events
The built-in events (used with
listen()) are:connect— fired with no arguments once the bot has authorized.message— fired with aMessagefor every inbound message, regardless of where it came from.guild_message— fired with aMessagewhen the message was sent in a community (guild) channel.dm_message— fired with aMessagewhen the message was a direct message to the bot.command_error— fired with(ctx, error)when a command lookup or invocation fails.
from osmium_chat import Bot, Context, Message, commands class MyCommands(commands.Commands): @commands.listen("message") async def on_message(self, message: Message) -> None: ... @commands.command("ping") async def ping(self, ctx: Context) -> None: await ctx.channel.send("pong") bot = Bot(prefix="!", client_id=12345) bot.add_commands(MyCommands) bot.run(token="...")
- prefix¶
- async dispatch(event, *args, **kwargs)[source]¶
Invoke every listener registered for
event.Handler errors are logged and swallowed so one faulty listener can’t take down the connection or block the others.
- async lookup_invite(code)[source]¶
Fetch an invite by code and return its full metadata.
- Parameters:
code (str) – The invite code to resolve.
- Returns:
The
InvitePreviewfor the invite.- Raises:
RequestError – If the gateway cannot find the invite.
- Return type:
- add_commands(cls, *args, **kwargs)[source]¶
Instantiate a
Commandssubclass and register all its decorated commands and listeners.The bot calls
cls(self, *args, **kwargs), so any extra arguments are forwarded directly to the subclass__init__afterbot. This lets command collections accept configuration at registration time without needing globals or post-init setters:class Greeter(commands.Commands): def __init__(self, bot: Bot, greeting: str) -> None: super().__init__(bot) self.greeting = greeting @commands.command("hi") async def hi(self, ctx: Context) -> None: await ctx.channel.send(self.greeting) bot.add_commands(Greeter, greeting="Howdy!")
- remove_commands(cls)[source]¶
Remove all commands and listeners that were registered from cls.
- Parameters:
cls (type[Commands]) – The same
Commandssubclass that was passed toadd_commands().- Return type:
None
- async process_commands(update)[source]¶
Turn an inbound message into a command invocation.
Builds the
Context, fires themessageevent, and — if the message starts with the prefix and names a known command — parses its arguments and invokes it. Command failures are surfaced through thecommand_errorevent.- Parameters:
update (UpdateMessageCreated) – The decoded
message_createdpayload from the gateway.- Return type:
None
- async use_invite(invite_code)[source]¶
Redeem an invite code on behalf of the bot.
- Parameters:
invite_code (str) – The invite code to redeem.
- Return type:
None
Client¶
- class osmium_chat.client.Client(client_id, bot, *, logger=None)[source]¶
Bases:
objectLow-level WebSocket transport between a
Botand the Osmium gateway.Handles connecting, the initialize/authorize handshake, sending protobuf messages, and reading the inbound message stream.
- async send_pb(message)[source]¶
Wrap, serialize, and send a protobuf message over the connection.
This is fire-and-forget: it sends with request id
0and does not wait for a reply. Userequest()when you need the server’s response.- Parameters:
message (Any) – The protobuf message to send.
- Return type:
None
- async request(payload, *, timeout=60.0)[source]¶
Send a request and wait for the gateway’s matching
RpcResult.Tags the outbound frame with a unique request id, registers a future for it, and resolves once the server replies with a result carrying the same id. This requires the read loop (
_handle_ws()) to be running, which it is for the whole lifetime of a connected bot.- Parameters:
- Returns:
The
PB_RpcResultfor this request.- Raises:
RequestError – If the gateway answers with an error.
TimeoutError – If no response arrives within
timeout.
- Return type:
RpcResult
- async upload_file(data, filename, mimetype='application/octet-stream', send_as_file=False)[source]¶
Upload
datato the Osmium media service in chunks.Splits
datainto parts of up to_UPLOAD_CHUNK_SIZEbytes, sends each part sequentially, and returns the server-side ref together with a ready-to-usePB_MediaReffor attaching to aPB_SendMessage.- Parameters:
- Returns:
A
(PB_UploadedFileRef, PB_MediaRef)pair.- Raises:
RequestError – If the gateway rejects any part.
- Return type:
tuple[UploadedFileRef, MediaRef]
- async upload_emoji_image(data, name, mimetype, community_id)[source]¶
Upload emoji image bytes and return a ref ready for
PB_AddStickerToPack.Splits
datainto chunks, uploads them, and wraps the result in aPB_MediaRefUploadedFilecarrying custom-emoji metadata pointing atcommunity_id’s sticker pack.- Parameters:
- Returns:
A
PB_MediaRefUploadedFileready to pass as thestickerargument ofPB_AddStickerToPack.- Raises:
RequestError – If the gateway rejects any part.
- Return type:
MediaRefUploadedFile
- async connect(token)[source]¶
Open the connection, run the handshake, and process messages.
Performs the initialize/authorize exchange, dispatches the bot’s
connectevent once authorized, then blocks reading messages until the connection closes.- Parameters:
token (str) – The authorization token for the bot.
- Raises:
ConnectionError – If the connection closes before authorization.
- Return type:
None
Commands¶
Command parsing and argument conversion.
Commands are defined by subclassing Commands and decorating methods
with command(), guild_command(), or dm_command(). Event
listeners are decorated with listen(). Register the subclass with
add_commands().
Basic types
The built-in converters handle the most common cases:
str— raw token, unchanged.int/float— numeric conversion.bool— acceptstrue/false,yes/no,on/off,y/n,1/0,enable/disable(case-insensitive).UnicodeEmoji— wraps the raw token.
Any other annotation is called with the raw token (annotation(token)), so a
type whose constructor accepts a single string just works. Custom types can be
registered by inserting into CONVERTERS.
Mention types
These types are resolved from message entities and community data:
User— from auser_mentionentity,@username/@<id>text, or a bare username/id.Role— from&<name-or-id>text or a bare name/id.Channel— from#<name-or-id>text or a bare name/id.Category— from#<name-or-id>text or a bare name/id (resolved against categories).CustomEmoji— from acustom_emojientity or:name:text.
Multi-type (union) parameters
Annotating a parameter as A | B (or Union[A, B]) tells the parser to
try each candidate type in declaration order, accepting the first one that
succeeds:
class Targeting(commands.Commands):
@commands.command("target")
async def target(self, ctx: Context, who: User | Channel) -> None:
...
# !target @alice → who is a User
# !target #general → who is a Channel
When a message entity at the argument’s position unambiguously identifies a
type (e.g. a custom_emoji entity for CustomEmoji),
the parser skips the fallback candidates and raises
BadArgument immediately if conversion fails.
Optional[T] / T | None is treated as the type T with an implicit
None default — the None arm is never tried as a conversion candidate.
Quoting
Arguments are split on whitespace. To pass a value containing spaces as a single argument, wrap it in single or double quotes. A backslash escapes the next character inside quotes:
# !echo "hello world" → word == "hello world"
Consume-rest and variadic parameters
A keyword-only parameter (declared after a bare *) consumes the entire
remaining message as one unsplit string:
class SayCommands(commands.Commands):
@commands.command("say")
async def say(self, ctx: Context, *, words: str) -> None:
await ctx.channel.send(words)
# !say hello there world → words == "hello there world"
A variadic *args parameter collects every remaining token:
class MathCommands(commands.Commands):
@commands.command("sum")
async def sum_(self, ctx: Context, *numbers: int) -> None:
await ctx.channel.send(str(sum(numbers)))
# !sum 1 2 3 → numbers == (1, 2, 3)
- class osmium_chat.commands.Command(callback, *, name=None, aliases=(), restriction=CommandRestriction.NONE)[source]¶
Bases:
objectA registered command: a name, optional aliases, and a parsed callback.
The callback’s signature drives argument parsing. The first parameter always receives the
Context; each parameter after it becomes a command argument, read from the message text following the command name and converted according to the rules below.Automatic type conversion
Each argument is converted to its annotated type before the callback runs. The built-in converters are:
str(or an un-annotated parameter) — the raw token, unchanged.int— parsed withint.float— parsed withfloat.bool— acceptstrue/false,yes/no,y/n,on/off,1/0,enable/disable(case-insensitive).UnicodeEmoji— wraps the raw token as aUnicodeEmoji.
Mention types (resolved via message entities and community lookups)
User— decoded from auser_mentionentity; the text at that span must be the user’s numeric id (with or without a leading@).Role— decoded from&<name-or-id>text.Channel— decoded from#<name-or-id>text.Category— decoded from#<name-or-id>text (resolved in categories).CustomEmoji— decoded from acustom_emojientity (byemoji_id) or from:name:text as a fallback.
Any other annotation is called with the raw token (
annotation(token)), so a type whose constructor takes a single string just works. Conversion failures raiseBadArgument. New types can be registered by adding toCONVERTERS.Optional arguments
A parameter with a default value is optional; if the invoker omits it, the default is used. Otherwise a missing argument raises
MissingRequiredArgument. An annotation ofT | None(i.e.Optional[T]) is converted asT.Quoting (
"...")Arguments are split on whitespace, so each parameter normally receives a single word. To pass a value that contains spaces as one argument, wrap it in single or double quotes; the surrounding quotes are stripped and a backslash escapes the next character inside them:
@bot.command("echo") async def echo(ctx: Context, word: str) -> None: await ctx.channel.send(word) # !echo "hello world" -> word == "hello world"
Consume-rest (
*) and variadic (*args)A keyword-only parameter — one declared after a bare
*— consumes the entire remaining message as a single, unsplit string (quotes are kept verbatim here). This is the idiomatic way to accept free-form text:@bot.command("say") async def say(ctx: Context, *, words: str) -> None: await ctx.channel.send(words) # !say hello there world -> words == "hello there world"
A variadic
*argsparameter instead collects every remaining token, converting each one to the annotated element type:@bot.command("sum") async def sum_(ctx: Context, *numbers: int) -> None: await ctx.channel.send(str(sum(numbers))) # !sum 1 2 3 -> numbers == (1, 2, 3)
Any leftover text after all parameters are filled raises
TooManyArguments.- Parameters:
- callback¶
- name¶
- aliases¶
- restriction¶
- params¶
- async parse_arguments(ctx, view, entity_by_pos, prefix_utf16)[source]¶
Convert the argument string into call arguments for the callback.
Returns the positional
argsand keyword-onlykwargsto pass to the callback alongside the context.- Parameters:
ctx (Context) – The invocation context, used to resolve mention-type arguments.
view (StringView) – A view over the message text following the command name.
entity_by_pos (dict[int, Any]) – Mapping of UTF-16 start position → message entity, built from the message’s entity list.
prefix_utf16 (int) – The UTF-16 length of the command prefix, used to translate view-relative positions back to full-content positions.
- Raises:
MissingRequiredArgument – If a required argument is absent.
BadArgument – If an argument fails type conversion.
TooManyArguments – If unconsumed tokens remain at the end.
- Return type:
- async invoke(ctx, view)[source]¶
Parse arguments from
viewand run the command callback.- Parameters:
ctx (Context) – The invocation context, passed as the first argument.
view (StringView) – A view over the message text following the command name.
- Return type:
None
- class osmium_chat.commands.CommandRestriction(*values)[source]¶
Bases:
EnumWhere a command is allowed to be invoked.
- NONE = 'none'¶
- DM_ONLY = 'dm_only'¶
- COMMUNITY_ONLY = 'community_only'¶
- class osmium_chat.commands.Commands(bot)[source]¶
Bases:
objectBase class for a collection of related bot commands and listeners.
Subclass this, decorate methods with
command(),guild_command(), ordm_command(), and add event listeners withlisten(). Then register the subclass (uninitialised) withadd_commands().The default
__init__accepts onlybot. Override it to receive additional arguments — they are forwarded from theadd_commands()call:from osmium_chat import Bot, Context, Message, commands class MyCommands(commands.Commands): # No extra args — use the inherited __init__. @commands.listen("connect") async def on_connect(self) -> None: print("connected!") @commands.listen("message") async def on_message(self, message: Message) -> None: print(message.content) @commands.command("ping") async def ping(self, ctx: Context) -> None: await ctx.channel.send("pong") @commands.guild_command("info") async def info(self, ctx: Context) -> None: await ctx.reply(f"Community: {ctx.community.name}") @commands.dm_command("help") async def help(self, ctx: Context) -> None: await ctx.channel.send("Commands: ping, info, help") class GreetCommands(commands.Commands): # Extra constructor argument supplied via add_commands. def __init__(self, bot: Bot, greeting: str = "Hello") -> None: super().__init__(bot) self.greeting = greeting @commands.command("greet") async def greet(self, ctx: Context) -> None: await ctx.channel.send(self.greeting) bot = Bot(prefix="!", client_id=12345) bot.add_commands(MyCommands) bot.add_commands(GreetCommands, greeting="Howdy") bot.run(token="...")
- Parameters:
bot (Bot)
- class osmium_chat.commands.Parameter(name, annotation, kind, default)[source]¶
Bases:
objectA single command argument, resolved from the callback’s signature.
- name¶
- annotation¶
- kind¶
- default¶
- optional¶
- convert(value)[source]¶
Convert a raw token to this parameter’s annotated type.
Tries each candidate type in declaration order, returning the first successful result.
- Parameters:
value (str) – The raw token from the message.
- Raises:
BadArgument – If no candidate type can convert the token.
- Return type:
- async resolve(ctx, value, *, entity=None)[source]¶
Convert a raw token, using the invocation context for mention types.
Tries each candidate type in declaration order, returning the first successful result. Falls back to
convert()for types that don’t need context.- Parameters:
- Raises:
BadArgument – If no candidate type can convert the token.
- Return type:
- class osmium_chat.commands.StringView(text)[source]¶
Bases:
objectA cursor over a command’s argument string.
Hands out whitespace-delimited words one at a time (respecting single and double quotes so multi-word arguments can be passed), or the entire remaining string for “consume rest” parameters.
- Parameters:
text (str)
- text¶
- index¶
- word_start¶
- rest()[source]¶
Consume and return the remaining string, stripped of surrounding space.
- Return type:
- get_word()[source]¶
Consume and return the next word, or
Noneif none remain.A word is a run of non-whitespace characters, unless it is wrapped in matching quotes, in which case everything up to the closing quote is returned as a single word (with backslash escaping inside the quotes).
word_startis updated to the position intextwhere the returned word began, so callers can correlate it with message entities.- Return type:
str | None
- osmium_chat.commands.command(name=None, *, aliases=(), restriction=None)[source]¶
Mark a
Commandsmethod as a bot command.- Parameters:
name (str | None) – The command name; defaults to the method name.
aliases (tuple[str, ...]) – Additional names the command responds to.
restriction (CommandRestriction) – Where the command may be invoked.
- Return type:
Callable[[Callable[[…], Awaitable[None]]], Callable[[…], Awaitable[None]]]
- osmium_chat.commands.dm_command(name=None, *, aliases=())[source]¶
Shorthand for
@command(..., restriction=CommandRestriction.DM_ONLY).
- osmium_chat.commands.guild_command(name=None, *, aliases=())[source]¶
Shorthand for
@command(..., restriction=CommandRestriction.COMMUNITY_ONLY).
Context¶
- class osmium_chat.context.Context(*, bot, message, author, channel, community=None, prefix, command=None, invoked_with=None, args=None)[source]¶
Bases:
objectThe invocation context handed to a command callback.
Bundles everything a command needs: who sent the message (
author), where it came from (channel), the underlyingmessage, and the resolved command metadata. Reply withawait ctx.channel.send(...)or thesend()shortcut.- Parameters:
- bot¶
- message¶
- channel¶
- community¶
- prefix¶
- command¶
- invoked_with¶
Channels¶
- class osmium_chat.channel.ChannelType(*values)[source]¶
Bases:
IntEnumThe kind of a community channel.
Mirrors
PB_ChannelTypeso callers can use a readable name (ChannelType.TEXT) instead of a raw integer when creating channels.- TEXT = 0¶
- VOICE = 1¶
- CATEGORY = 2¶
- class osmium_chat.channel.Channel(chat_ref, client, *, id=None, name=None, type=None, community_id=None, position=None, parent_id=None, community=None)[source]¶
Bases:
objectA conversation a message can be sent to.
Wraps the
PB_ChatRefthat identifies a destination (a user DM, community channel, group, or self) together with the client used to deliver outbound messages, so callers can simplyawait channel.send(...).When the channel was resolved from a community (see
from_pb()) the descriptive fields —id,name,type,community_id,position, andparent_id— are populated; for an ad-hoc DM or group ref they areNone. Only community channels can be edited or deleted, since those operations need aPB_ChannelRef.- Parameters:
- id¶
- name¶
- type¶
- community_id¶
- position¶
- parent_id¶
- classmethod from_pb(channel, client)[source]¶
Build a channel from a community’s
PB_Channel.Constructs the addressing ref from the channel’s community and id and copies across the descriptive metadata, so the returned channel can be both sent to and edited/deleted.
- async send(content, *, reply_to=None)[source]¶
Send a message to this channel and return the created message.
Waits for the gateway to acknowledge the send so the returned
Messagecarries the server-assigned id, ready toedit()ordelete().
- async send_file(data, filename, *, mimetype='application/octet-stream', reply_to=None)[source]¶
Upload
dataand send it as a file attachment to this channel.- Parameters:
- Returns:
The newly created message carrying the file attachment.
- Raises:
RequestError – If the gateway rejects the upload or send.
- Return type:
- async edit(*, name=None, position=None, parent_id=None, explicit=None)[source]¶
Edit this community channel’s attributes.
Only the arguments you pass are changed; anything left as
Noneis kept as-is by the server. Waits for the gateway to confirm the edit and updates the local metadata to match.- Parameters:
- Returns:
This channel, with its local metadata updated.
- Raises:
TypeError – If this channel is not a community channel.
RequestError – If the gateway rejects the edit.
- Return type:
- async delete()[source]¶
Delete this community channel.
- Raises:
TypeError – If this channel is not a community channel.
- Return type:
None
- async create_invite(*, expires_at=None, max_uses=None)[source]¶
Create an invite link for this channel and return the full preview.
Creates the invite then immediately fetches its metadata so the returned
InvitePreviewcarries creator and target info.- Parameters:
- Returns:
The newly created invite with full metadata.
- Raises:
RequestError – If the gateway rejects the request.
- Return type:
- async get_invites()[source]¶
Fetch all active invite links for this channel.
- Returns:
The channel’s active invites with full metadata.
- Raises:
RequestError – If the gateway rejects the request.
- Return type:
Categories¶
Category channels that group other channels together.
- class osmium_chat.category.Category(*args, **kwargs)[source]¶
Bases:
ChannelA category channel that groups other channels under it.
Subclasses
Channel— it can be sent to, edited, and deleted via the inherited methods. The extrachannelsattribute holds the channels nested under this category.
Messages¶
- class osmium_chat.message.Message(message, client, *, author=None, channel=None, community=None)[source]¶
Bases:
objectA chat message, parsed from its protobuf representation.
Holds where the message came from (
chat_ref) so replies, edits, and deletes can be routed back to the same conversation, alongside its text content, the resolvedauthor, and other metadata.- Parameters:
- async edit(content)[source]¶
Edit this message’s text content.
Waits for the gateway to confirm the edit and updates
contentandcontent_rawto match.- Parameters:
content (str | Content) – The new message text, either a plain string or a
Contentobject.- Returns:
This message, with its content updated.
- Raises:
ValueError – If the message has no chat ref to route the edit to.
RequestError – If the gateway rejects the edit.
- Return type:
- async delete()[source]¶
Delete this message.
- Raises:
ValueError – If the message has no chat ref to route the delete to.
- Return type:
None
- async add_reaction(emoji)[source]¶
Add a reaction to this message.
Accepts a
CustomEmoji, aUnicodeEmoji, or a plain Unicode emoji string (e.g."🎉"). A user may only add one reaction of each emoji type to a message.- Parameters:
emoji (CustomEmoji | UnicodeEmoji | str) – The emoji to react with.
- Raises:
ValueError – If the message has no chat ref.
RequestError – If the gateway rejects the request.
- Return type:
None
- async remove_reaction(emoji)[source]¶
Remove a previously added reaction from this message.
Accepts a
CustomEmoji, aUnicodeEmoji, or a plain Unicode emoji string (e.g."🎉").- Parameters:
emoji (CustomEmoji | UnicodeEmoji | str) – The emoji reaction to remove.
- Raises:
ValueError – If the message has no chat ref.
RequestError – If the gateway rejects the request.
- Return type:
None
- async reply_file(data, filename, *, mimetype='application/octet-stream')[source]¶
Upload
dataand send it as a file reply to this message.- Parameters:
- Returns:
The newly created reply message carrying the file attachment.
- Raises:
ValueError – If the message has no chat ref to reply into.
RequestError – If the gateway rejects the upload or send.
- Return type:
- async reply(content)[source]¶
Send a message to this message’s conversation, threaded as a reply.
Waits for the gateway to acknowledge the send so the returned message carries the server-assigned id.
- Parameters:
content (str | Content) – The reply text, either a plain string or a
Contentobject.- Returns:
The newly created reply message.
- Raises:
ValueError – If the message has no chat ref to reply into.
RequestError – If the gateway rejects the send.
- Return type:
Reactions¶
Message reaction model.
A Reaction groups every user who reacted to a message with the same
emoji into one object. The emoji is either a
UnicodeEmoji (standard Unicode) or a
CustomEmoji stub (community emoji).
Reading reactions
Reactions arrive in reactions after a
message is parsed from the gateway:
for reaction in message.reactions:
print(reaction.emoji, reaction.count, reaction.users)
Adding and removing reactions
Use add_reaction() and
remove_reaction() to react to a message.
Both accept a plain Unicode string, a UnicodeEmoji,
or a CustomEmoji:
await message.add_reaction("👍")
await message.add_reaction(UnicodeEmoji("🎉"))
await message.add_reaction(custom_emoji)
await message.remove_reaction("👍")
Note
The users list is a gateway-provided preview and may be
truncated for reactions with many participants. count is
always the authoritative total.
- class osmium_chat.reaction.Reaction(emoji, count, users)[source]¶
Bases:
objectA single reaction type on a message.
Groups all users who reacted with the same emoji under one
Reaction. Theemojiis either aUnicodeEmoji(for standard Unicode emoji) or aCustomEmojistub carrying only the server id (for community custom emoji received from the gateway).usersholds the preview list of user ids the gateway provided — it may be truncated for reactions with many participants.- Parameters:
emoji (CustomEmoji | UnicodeEmoji) – The emoji this reaction represents.
count (int) – Total number of users who added this reaction.
users (list[int]) – Preview list of user ids who added this reaction.
- emoji: CustomEmoji | UnicodeEmoji¶
Formatting¶
Rich text formatting for outbound messages.
Formatting nodes — Bold, Italic, Underline,
Strikethrough, Code, CodeBlock, Spoiler,
TextUrl, and CustomEmoji — can
be nested freely and embedded inside a Content using either the
constructor or f-string interpolation:
from osmium_chat.content import Bold, Content, Italic, UnicodeEmoji
# constructor form
msg = Content("Hello, ", Bold("world"), "!")
# f-string form — identical result
msg = Content(f"Hello, {Bold('world')}!")
# nesting
msg = Content(f"{Bold(Italic('important'))}")
# unicode emoji (rendered as plain text)
msg = Content("Congrats! ", UnicodeEmoji("🎉"))
Each node tree is serialized to a flat text string plus a matching list of
PB_MessageEntity offset/length spans — the wire
format the Osmium gateway expects.
- class osmium_chat.content.Bold(*parts)[source]¶
Bases:
_FormattingNodeRenders its contents in bold.
- Parameters:
parts (str | _FormattingNode)
- class osmium_chat.content.Code(*parts)[source]¶
Bases:
_FormattingNodeRenders its contents as inline
code.- Parameters:
parts (str | _FormattingNode)
- class osmium_chat.content.CodeBlock(*parts, language='')[source]¶
Bases:
_FormattingNodeRenders its contents as a fenced code block with optional syntax highlighting.
CodeBlock("print('hello')", language="python")
- class osmium_chat.content.Content(*parts)[source]¶
Bases:
objectA complete message payload: plain text plus formatting entity spans.
Construct by passing any mix of
strand formatting nodes:content = Content("Price: ", Bold("$9.99"), " — limited time!")
Or use f-string embedding:
content = Content(f"Price: {Bold('$9.99')} — limited time!")
The
textproperty returns the plain-text string;entitiesreturns the matchingPB_MessageEntitylist ready for the wire.- Parameters:
parts (str | _FormattingNode | UnicodeEmoji)
- class osmium_chat.content.Italic(*parts)[source]¶
Bases:
_FormattingNodeRenders its contents in italic.
- Parameters:
parts (str | _FormattingNode)
- class osmium_chat.content.Spoiler(*parts)[source]¶
Bases:
_FormattingNodeHides its contents behind a spoiler that must be clicked to reveal.
- Parameters:
parts (str | _FormattingNode)
- class osmium_chat.content.Strikethrough(*parts)[source]¶
Bases:
_FormattingNodeRenders its contents with a ~~strikethrough~~.
- Parameters:
parts (str | _FormattingNode)
- class osmium_chat.content.TextUrl(*parts, url)[source]¶
Bases:
_FormattingNodeRenders its contents as a hyperlink.
TextUrl("osmium.chat", url="https://osmium.chat")
- class osmium_chat.content.Underline(*parts)[source]¶
Bases:
_FormattingNodeRenders its contents with an underline.
- Parameters:
parts (str | _FormattingNode)
- class osmium_chat.content.UnicodeEmoji(emoji)[source]¶
Bases:
objectA standard Unicode emoji for use in
Content.When passed to
Content, it is treated as plain text — the emoji character is embedded in the message string without any formatting entity.Content("Congrats! ", UnicodeEmoji("🎉"))
- Parameters:
emoji (str) – The Unicode emoji character(s).
Communities¶
- class osmium_chat.community.Community(community, client, *, channels=None, categories=None, roles=None)[source]¶
Bases:
objectAn Osmium community (a server), parsed from its protobuf representation.
A community owns a list of
channelsandroles. Those lists are populated when the community is built from data that includes them (seefrom_pb()); since the gateway delivers channels and roles as separate updates,fetch_channels()andfetch_roles()ask the server to (re)send them. Useedit(),create_channel(), andcreate_role()to manage the community.- Parameters:
- permissions: CommunityPermission¶
- custom_emojis: list[CustomEmoji]¶
- classmethod from_id(community_id, client)[source]¶
Build a minimal community stub from a bare id.
Only
idis meaningful; all other descriptive fields are their zero/default values until you callfetch_channels(),fetch_roles(), or similar methods that hit the gateway.
- classmethod from_pb(community, client, *, channels=None, roles=None)[source]¶
Build a community, wrapping any raw channel/role protobufs supplied.
- Parameters:
- Return type:
- async edit(*, name=None, username=None)[source]¶
Edit this community’s attributes.
Only the arguments you pass are changed; anything left as
Noneis kept as-is. The local attributes are updated to match.- Parameters:
- Returns:
This community, with its local attributes updated.
- Raises:
RequestError – If the gateway rejects the edit.
- Return type:
- async create_channel(name, *, type=ChannelType.TEXT, parent_id=None)[source]¶
Create a new channel in this community and return it.
The gateway’s create RPC doesn’t echo the new channel, so this snapshots the existing channel ids, creates the channel, refetches, and returns the newly appeared one (with its server-assigned id).
channelsis refreshed as a side effect.- Parameters:
name (str) – The name of the new channel.
type (ChannelType) – The
ChannelTypeto create.parent_id (int | None) – The id of the category channel to nest it under, if any.
- Returns:
The newly created channel.
- Raises:
RequestError – If the gateway rejects the request.
OsmiumChatError – If the channel was created but cannot be located in the refetched channel list.
- Return type:
- async create_category(name)[source]¶
Create a new category channel in this community and return it.
Snapshots existing channel ids, creates the category, refetches, and returns the newly appeared
Categorywith an emptychannelslist (child channels can be assigned by creating channels with the category’s id asparent_id).channelsis refreshed as a side effect.- Parameters:
name (str) – The name of the new category.
- Returns:
The newly created category.
- Raises:
RequestError – If the gateway rejects the request.
OsmiumChatError – If the category was created but cannot be located in the refetched channel list.
- Return type:
- async create_role(name, *, permissions=<CommunityPermission.NO_PERMISSION: 0>, priority=0, color=0, separated=False, public=False)[source]¶
Create a new role in this community and return it.
The gateway’s create RPC doesn’t echo the new role, so this snapshots the existing role ids, creates the role, refetches, and returns the newly appeared one (with its server-assigned id).
rolesis refreshed as a side effect.- Parameters:
name (str) – The name of the new role.
permissions (CommunityPermission | int) – The permission bitfield to grant.
priority (int) – The role priority (higher sorts above lower).
color (int) – The role’s display color.
separated (bool) – Whether members with this role are shown separately.
public (bool) – Whether the role is publicly visible.
- Returns:
The newly created role.
- Raises:
RequestError – If the gateway rejects the request.
OsmiumChatError – If the role was created but cannot be located in the refetched role list.
- Return type:
- async fetch_channels()[source]¶
Fetch this community’s channels from the gateway.
The result is also cached on
channels, replacing whatever was there before.
- async fetch_roles()[source]¶
Fetch this community’s roles from the gateway.
The result is also cached on
roles, replacing whatever was there before.
- async fetch_custom_emojis()[source]¶
Fetch this community’s custom emojis from the gateway.
Requests the community’s emoji sticker pack, then fetches full file metadata via a second request to resolve emoji names. The result is cached on
custom_emojis, replacing whatever was there before.- Returns:
The community’s custom emojis.
- Raises:
RequestError – If the gateway rejects either request.
- Return type:
- async create_custom_emoji(image, name, *, mimetype='image/png')[source]¶
Upload an image and add it as a custom emoji for this community.
Snapshots the existing emoji ids, uploads
image, adds it to the community’s emoji sticker pack, re-fetches, and returns the newly createdCustomEmojiwith its server-assigned id.- Parameters:
- Returns:
The newly created custom emoji.
- Raises:
RequestError – If the gateway rejects the upload or pack add.
OsmiumChatError – If the emoji was created but cannot be located in the re-fetched emoji list.
- Return type:
Custom Emoji¶
Custom community emoji.
A CustomEmoji represents a community-specific emoji uploaded to an
Osmium sticker pack. It can be embedded directly in a
Content message, used as a reaction, or accepted
as a command argument.
Fetching
Custom emojis for a community are retrieved with
fetch_custom_emojis():
emojis = await ctx.community.fetch_custom_emojis()
emoji = next(e for e in emojis if e.name == "wave")
Embedding in messages
Pass a CustomEmoji directly to Content
— it renders as the emoji name in plain text client-side and produces a
custom_emoji entity span on the wire:
await ctx.channel.send(Content("Hello! ", emoji))
As a command argument
Annotating a command parameter as CustomEmoji makes the parser accept
either a :name: mention or a custom_emoji message entity at the
argument’s position:
@bot.command("react")
async def react(ctx: Context, emoji: CustomEmoji) -> None:
await ctx.message.add_reaction(emoji)
Creating and deleting
Upload a new emoji with
create_custom_emoji(), and remove one
with CustomEmoji.delete():
emoji = await ctx.community.create_custom_emoji(image_bytes, "wave")
await emoji.delete()
- class osmium_chat.emoji.CustomEmoji(emoji_id, name, community_id, pack_id, client)[source]¶
Bases:
_FormattingNodeA custom emoji belonging to a community’s emoji pack.
Can be embedded directly in a
Contentmessage — it renders as the emoji name in plain text and produces acustom_emojientity span on the wire:content = Content("Look at this! ", emoji)
Use
delete()to remove it from its community, andrename()to update its local display name.- Parameters:
emoji_id (int) – The server-assigned snowflake id of this emoji.
name (str) – The emoji’s short name (without colons).
community_id (int) – The id of the community this emoji belongs to.
pack_id (int) – The id of the sticker pack that holds this emoji.
client (Client) – The client used to manage the emoji.
- async delete()[source]¶
Remove this emoji from its community’s emoji pack.
- Raises:
RequestError – If the gateway rejects the request.
- Return type:
None
- rename(name)[source]¶
Update this emoji’s local display name.
The Osmium gateway does not expose a rename endpoint, so this only updates the local
nameand the placeholder text used when the emoji is embedded in aContent. The server-side name (set at upload time) is unchanged.
Invites¶
Invite links for joining communities and channels.
- class osmium_chat.invite.Invite(invite, client)[source]¶
Bases:
objectA channel invite handle that can be revoked.
Holds the invite
codereturned by the gateway. Calldelete()to revoke it. For the full hydrated metadata useInvitePreviewinstead.- Parameters:
invite (CreatedInvite)
client (Client)
- class osmium_chat.invite.InvitePreview(preview, client)[source]¶
Bases:
objectA hydrated invite including creator and target metadata.
Returned by
create_invite()andget_invites(). Calldelete()to revoke it.- Parameters:
preview (InvitePreview)
client (Client)
- target_type: InviteType¶
Members¶
Community member: a user viewed through the lens of a specific community.
- class osmium_chat.member.Member(member, user, client, *, community)[source]¶
Bases:
UserA user as a member of a specific community.
Extends
Userwith community-specific data: anickname, a list ofrole_ids, and helpers to manage roles.Note
When a
Memberis built from an incoming message event the gateway does not include full member metadata, sonicknamestarts asNoneandrole_idsstarts empty. Callfetch_members()(once available) if you need the current roles.- property roles: list[Role]¶
The member’s roles, resolved from the community’s cached role list.
Call
fetch_roles()first if you need up-to-date role data.
- async add_role(role)[source]¶
Add a role to this member.
No-ops if the member already has the role. Updates
role_idson success.- Parameters:
role (Role) – The role to add.
- Raises:
RequestError – If the gateway rejects the request.
- Return type:
None
- async remove_role(role)[source]¶
Remove a role from this member.
No-ops if the member does not have the role. Updates
role_idson success.- Parameters:
role (Role) – The role to remove.
- Raises:
RequestError – If the gateway rejects the request.
- Return type:
None
Roles¶
Community roles controlling member permissions and display.
- class osmium_chat.role.Role(role, client)[source]¶
Bases:
objectA role within a community, parsed from its protobuf representation.
Roles bundle a set of
CommunityPermissiongrants, a displaycolor, and aprioritythat orders them. Theedit()anddelete()helpers let you manage a role in place.- Parameters:
role (CommunityRole)
client (Client)
- permissions: CommunityPermission¶
- async edit(*, name=None, permissions=None, priority=None, color=None, separated=None, public=None)[source]¶
Edit this role’s attributes.
The edit endpoint replaces the whole role, so any argument left as
Nonekeeps the role’s current value. The local attributes are updated to match, and the call waits for the gateway to confirm the edit.- Parameters:
name (str | None) – A new name for the role.
permissions (CommunityPermission | int | None) – A new permission bitfield.
priority (int | None) – A new priority (higher sorts above lower).
color (int | None) – A new display color.
separated (bool | None) – Whether members with this role are shown separately.
public (bool | None) – Whether the role is publicly visible.
- Returns:
This role, with its local attributes updated.
- Raises:
RequestError – If the gateway rejects the edit.
- Return type:
Permissions¶
- class osmium_chat.permissions.CommunityPermission(*values)[source]¶
Bases:
IntFlagA bitfield of the permissions a role can grant within a community.
Mirrors
PB_CommunityPermission. Being anenum.IntFlag, members combine with|and can be tested within, so a role’s permissions integer reads naturally:perms = CommunityPermission.VIEW_CHANNEL | CommunityPermission.SEND_MESSAGES await community.create_role("member", permissions=perms) if CommunityPermission.ADMINISTRATOR in CommunityPermission(role.permissions): ...
- NO_PERMISSION = 0¶
- ADMINISTRATOR = 1¶
- VIEW_CHANNEL = 2¶
- SEND_MESSAGES = 4¶
- CONNECT_VOICE = 8¶
- MODIFY_CHANNEL = 16¶
- SEND_MEDIA = 32¶
- DELETE_MESSAGES = 64¶
- PIN_MESSAGES = 128¶
- SPEAK_VOICE = 256¶
- MODIFY_COMMUNITY = 512¶
- MODIFY_ROLES = 1024¶
- REMOVE_MEMBERS = 2048¶
- ADD_REACTIONS = 4096¶
- MODIFY_LINKED_STICKERS = 8192¶
Utilities¶
- osmium_chat.utils.locate_created(before_ids, after, name)[source]¶
Pick the entity just created out of a freshly fetched list.
Several Osmium create RPCs don’t echo the new entity back, so the caller snapshots the ids that existed beforehand, performs the create, refetches, and uses this to find what appeared. Among the ids that are new we prefer a name match and take the highest id (the most recently created); if nothing is new we fall back to the newest name match across the whole list.
- Parameters:
- Returns:
The created entity, or
Noneif it could not be located.- Return type:
_T | None
Errors¶
Exceptions raised while parsing and invoking commands.
- exception osmium_chat.errors.OsmiumChatError[source]¶
Bases:
ExceptionBase class for every exception raised by
osmium_chat.
- exception osmium_chat.errors.RequestError(code, message)[source]¶
Bases:
OsmiumChatErrorThe gateway returned an error in response to a request.
Raised from
request()when the matchingRpcResultcarries an error instead of a result payload.
- exception osmium_chat.errors.CommandError[source]¶
Bases:
OsmiumChatErrorBase class for errors that occur while handling a command.
- exception osmium_chat.errors.CommandNotFound(name)[source]¶
Bases:
CommandErrorNo command was registered under the invoked name or alias.
- Parameters:
name (str)
- Return type:
None
- exception osmium_chat.errors.CommandRestrictionError(name, restriction)[source]¶
Bases:
CommandErrorA command was invoked in a context it does not allow.
- Parameters:
name (str)
restriction (Any)
- Return type:
None
- exception osmium_chat.errors.ArgumentError[source]¶
Bases:
CommandErrorBase class for problems converting or supplying command arguments.
- exception osmium_chat.errors.MissingRequiredArgument(name)[source]¶
Bases:
ArgumentErrorA required argument was not supplied by the invoker.
- Parameters:
name (str)
- Return type:
None
- exception osmium_chat.errors.BadArgument(name, value, expected)[source]¶
Bases:
ArgumentErrorAn argument could not be converted to the parameter’s annotated type.
- exception osmium_chat.errors.TooManyArguments(extra)[source]¶
Bases:
ArgumentErrorThe invoker supplied more arguments than the command accepts.
- Parameters:
extra (str)
- Return type:
None
Users¶
- class osmium_chat.user.user.User(user, client)[source]¶
Bases:
objectAn Osmium user, parsed from its protobuf representation.
- Parameters:
user (User)
client (Client)
- status: UserStatus | None¶
- async fetch_profile()[source]¶
Fetch this user’s extended profile and cache it on
profile.Calls
users.getProfileand wraps the result in aProfile, which carries the user’s bio, premium status, and image banner.- Returns:
The fetched
Profile.- Raises:
RequestError – If the gateway rejects the request.
- Return type:
Profile
- class osmium_chat.user.status.UserStatusStatus(*values)[source]¶
Bases:
IntEnumA user’s availability state.
- ONLINE = 0¶
- IDLE = 1¶
- class osmium_chat.user.status.UserStatus(status)[source]¶
Bases:
objectA user’s presence: online flag, status state, and activities.
- Parameters:
status (UserStatus)
- status: UserStatusStatus | None¶
- activities: list[UserStatusActivity]¶
Media¶
- class osmium_chat.photo.Photo(photo, client)[source]¶
Bases:
objectA chat photo: its file id and an inline preview blob.
- Parameters:
photo (ChatPhoto)
client (Client)
- download()[source]¶
Fetch the full photo contents as
bytes.The return value can be awaited directly or used as an async context manager; both yield the complete photo bytes:
data = await photo.download() async with photo.download() as data: ...
- Returns:
An awaitable / async context manager resolving to the bytes.
- Raises:
RequestError – If the gateway rejects any part request.
- Return type:
_PhotoDownload
- class osmium_chat.file.File(file, client)[source]¶
Bases:
objectA file attachment on a received message.
Wraps the
PB_Filemetadata the server sends alongside a message. Calldownload()to fetch the raw bytes.- Parameters:
file (File)
client (Client)
- async download()[source]¶
Fetch and return the full file contents as
bytes.Requests the file in
_DOWNLOAD_CHUNK_SIZE-byte windows and reassembles them in order.- Returns:
The complete file bytes.
- Raises:
RequestError – If the gateway rejects any part request.
- Return type:
- async save(path=None)[source]¶
Download the file and write it to disk.
- Parameters:
path (str | Path | None) – Destination path. Pass a directory to write
<dir>/<filename>using the server-provided name, or a full file path to control the exact location. Defaults to the current working directory with the server-provided name (orfile_<id>when the server did not supply one).- Returns:
The
Paththe file was written to.- Raises:
RequestError – If the gateway rejects any part request.
- Return type: