sopel.plugins.capabilities#
Capability Requests management for plugins.
New in version 8.0.
Important
This is all relatively new. Its usage and documentation is for Sopel core development and advanced developers. It is subject to rapid changes between versions without much (or any) warning.
Do not build your plugin based on what is here, you do not need to.
- class sopel.plugins.capabilities.Manager#
Manager of plugins’ capability requests.
Whenever a plugin declares a capability request (through
sopel.plugin.capability
), the bot will register the request with this manager.The bot is responsible to call the manager at the appropriate time, and the manager will store requests’ state and handle acknowledgement, by following this workflow:
the bot will register plugins’ requests with the
register()
methodthe bot will request the list of available capabilities with the
CAP LS
subcommandupon receiving the list, it’ll use the
request_available()
method to let the manager send the requiredCAP REQ
messages.when the server
ACK
a request, the bot will call theacknowledge()
method; when the serverNAK
a request, the bot will call thedeny()
methodonce all requests are handled (either directly or after calling the
resume()
method), the bot will send theCAP END
message to end capability negotiation
- acknowledge(
- bot: SopelWrapper,
- cap_req: tuple[str, ...],
Acknowledge a capability request and execute handlers.
- Parameters:
bot – bot instance to manage the capabilities for
cap_req – the capability request from
CAP ACK :<cap_req>
- Returns:
a list of results and statuses if the capability was requested
This acknowledges a capability request and executes its callbacks from plugins. It returns the result, as a list of 2-value tuples: the first value tells if the callback is done with the processing, and the second is the returned value.
If the capability request was denied before, it is now considered acknowledged instead.
If the capability wasn’t requested, the result will be
None
.
- property acknowledged: frozenset[tuple[str, ...]]#
Set of acknowledged capability requests.
Each element is a capability request as a tuple of capability names:
>>> manager.acknowledged {('cap1',), ('cap2', 'cap3')}
An acknowledged request is a registered and requested request for which the bot received a
CAP ACK
message.Only requested requests can be acknowledged.
- property denied: frozenset[tuple[str, ...]]#
Set of denied capability requests.
Each element is a capability request as a tuple of capability names:
>>> manager.denied {('cap1',), ('cap2', 'cap3')}
A denied request is a registered and requested request for which the bot received a
CAP NAK
message.Only requested requests can be denied.
- deny(
- bot: SopelWrapper,
- cap_req: tuple[str, ...],
Deny a capability request and execute handlers.
- Parameters:
bot – bot instance to manage the capabilities for
cap_req – the capability request from
CAP NAK :<cap_req>
This denies a capability request and executes its callbacks from plugins. It returns the result, as a list of 2-value tuples: the first value tells if the callback is done with the processing, and the second is the returned value.
If the capability request was acknowledged before, it is now considered denied instead.
If the capability wasn’t requested, the result will be
None
.
- get( ) Generator[tuple[str, capability], None, None] #
Retrieve the registered request handlers for a capability request.
- Parameters:
cap_req – the capability request to retrieve handlers for
- Returns:
yield 2-value tuples with (plugin name, capability)
- is_acknowledged(request: Iterable[str]) bool #
Tell if a capability request is acknowledged.
- Parameters:
request – a set of capabilities that form a capability request together; this can be any iterable
- property is_complete: bool#
Tell if the capability negotiation is complete.
When capability negotiation is complete, the bot can send
CAP END
to notify the server that negotiation is complete.The capability negotiation is complete when all capability requests have been either acknowledged or denied successfuly (directly or by calling the
resume()
method).
- is_denied(request: Iterable[str]) bool #
Tell if a capability request is denied.
- Parameters:
request – a set of capabilities that form a capability request together; this can be any iterable
- is_registered(request: Iterable[str]) bool #
Tell if a capability request is registered.
- Parameters:
request – a set of capabilities that form a capability request together; this can be any iterable
- is_requested(request: Iterable[str]) bool #
Tell if a capability request is requested.
- Parameters:
request – a set of capabilities that form a capability request together; this can be any iterable
- register(plugin_name: str, request: capability) None #
Register a capability
request
forplugin_name
.- Parameters:
request – the capability request to register for later
- Raises:
RuntimeError – when the capability request is too long for a single
CAP REQ
andCAP * ACK
Once registered, the capability request can be requested by the bot. A registered request appears in
registered
:>>> from sopel import plugin >>> request = plugin.capability('cap1') >>> manager.register('coretasks', request) >>> ('cap1',) in manager.registered True >>> manager.is_registered(('cap1',)) True
It is not, however, directly requested:
>>> manager.is_requested(('cap1',)) False
See
request_available()
to automatically request capabilities advertised by the server.Warning
Sopel cannot accept a request that is too long, because it does not know how to handle a multi-line ACK, and it would not know how to call back the appropriate
capability
handler.
- property registered: frozenset[tuple[str, ...]]#
Set of registered capability requests.
Each element is a capability request as a tuple of capability names:
>>> manager.registered {('cap1',), ('cap2', 'cap3')}
A registered request is a request wanted by a plugin. The request may or may not be requested, acknowledged, or denied.
- request_available( ) None #
Request available capabilities.
- Parameters:
bot – the bot instance used to send capability requests
available_capabilities – available capabilities
This sends
CAP REQ
commands for requests that can be made, i.e. all the requested capabilities (with or without prefix) must be available for Sopel to send the request.Requests made are stored as requested; others are ignored:
>>> manager.register('example', 'cap1') >>> manager.register('example', 'cap2') >>> manager.request_available(bot, ('cap1', 'cap3')) >>> manager.is_requested(('cap1',)) True >>> manager.is_requested(('cap2',)) False >>> manager.is_requested(('cap3',)) False
Important
The capability request
('cap1', '-cap2')
means “enable cap1 and disable cap2”, and the request will be acknowledged or denied at once. If the server doesn’t advertise any of these capabilities, the client should not send a request.As a result, Sopel will send a request to enable or disable a capability only if it is advertised first. If a request is never made, its callback will never be called, because there won’t be any related ACK/NAK message from the server.
Plugin authors should not use the request’s callback to activate or deactivate features, and instead check the bot’s capabilities every time they need to.
The only exception to that is when the plugin needs to perform an operation while negotiating the capabilities (such as SASL auth).
- property requested: frozenset[tuple[str, ...]]#
Set of requested capability requests.
Each element is a capability request as a tuple of capability names:
>>> manager.requested {('cap1',), ('cap2', 'cap3')}
A requested request is a registered request for which the bot sent a
CAP REQ
message to the server. The request may or may not be acknowledged or denied.Only registered requests can be requested.
- resume(request: Iterable[str], plugin_name: str) tuple[bool, bool] #
Resume the registered plugin capability request.
- Returns:
a 2-value tuple with (was completed, is completed)
The capability request, for that plugin, will be marked as done, and the result will be about the capability negotiation process:
was it already completed before the resume?
is it completed now?
If the capability request cannot be found for that plugin, the result value remains the same (it stays incomplete or complete)
Important
When a request’s callback returns
CONTINUE
, this method must be called later (once the plugin has finished its job) or the bot will never send theCAP END
command and hang forever.See also
Plugins can use the method
resume_capability_negotiation()
from the bot to resume and automatically sendCAP END
when necessary.