Module slack_sdk.models.blocks.basic_components
Expand source code
import copy
import logging
import warnings
from typing import List, Optional, Set, Union, Sequence, Dict, Any
from slack_sdk.models import show_unknown_key_warning
from slack_sdk.models.basic_objects import (
JsonObject,
JsonValidator,
)
from slack_sdk.models.messages import Link
ButtonStyles = {"danger", "primary"}
DynamicSelectElementTypes = {"channels", "conversations", "users"}
class TextObject(JsonObject):
"""The interface for text objects (types: plain_text, mrkdwn)"""
attributes = {"text", "type", "emoji"}
logger = logging.getLogger(__name__)
def _subtype_warning(self): # skipcq: PYL-R0201
warnings.warn(
"subtype is deprecated since slackclient 2.6.0, use type instead",
DeprecationWarning,
)
@property
def subtype(self) -> Optional[str]:
return self.type
@classmethod
def parse(
cls,
text: Union[str, Dict[str, Any], "TextObject"],
default_type: str = "mrkdwn",
) -> Optional["TextObject"]:
if not text: # skipcq: PYL-R1705
return None
elif isinstance(text, str):
if default_type == PlainTextObject.type: # skipcq: PYL-R1705
return PlainTextObject.from_str(text)
else:
return MarkdownTextObject.from_str(text)
elif isinstance(text, dict):
d = copy.copy(text)
t = d.pop("type")
if t == PlainTextObject.type: # skipcq: PYL-R1705
return PlainTextObject(**d)
else:
return MarkdownTextObject(**d)
elif isinstance(text, TextObject):
return text
else:
cls.logger.warning(f"Unknown type ({type(text)}) detected when parsing a TextObject")
return None
def __init__(
self,
text: str,
type: Optional[str] = None, # skipcq: PYL-W0622
subtype: Optional[str] = None,
emoji: Optional[bool] = None,
**kwargs,
):
"""Super class for new text "objects" used in Block kit"""
if subtype:
self._subtype_warning()
self.text = text
self.type = type if type else subtype
self.emoji = emoji
class PlainTextObject(TextObject):
"""plain_text typed text object"""
type = "plain_text"
@property
def attributes(self) -> Set[str]:
return super().attributes.union({"emoji"})
def __init__(self, *, text: str, emoji: Optional[bool] = None):
"""A plain text object, meaning markdown characters will not be parsed as
formatting information.
https://api.slack.com/reference/block-kit/composition-objects#text
Args:
text (required): The text for the block. This field accepts any of the standard text formatting markup
when type is mrkdwn.
emoji: Indicates whether emojis in a text field should be escaped into the colon emoji format.
This field is only usable when type is plain_text.
"""
super().__init__(text=text, type=self.type)
self.emoji = emoji
@staticmethod
def from_str(text: str) -> "PlainTextObject":
return PlainTextObject(text=text, emoji=True)
@staticmethod
def direct_from_string(text: str) -> Dict[str, Any]:
"""Transforms a string into the required object shape to act as a PlainTextObject"""
return PlainTextObject.from_str(text).to_dict()
class MarkdownTextObject(TextObject):
"""mrkdwn typed text object"""
type = "mrkdwn"
@property
def attributes(self) -> Set[str]:
return super().attributes.union({"verbatim"})
def __init__(self, *, text: str, verbatim: Optional[bool] = None):
"""A Markdown text object, meaning markdown characters will be parsed as
formatting information.
https://api.slack.com/reference/block-kit/composition-objects#text
Args:
text (required): The text for the block. This field accepts any of the standard text formatting markup
when type is mrkdwn.
verbatim: When set to false (as is default) URLs will be auto-converted into links,
conversation names will be link-ified, and certain mentions will be automatically parsed.
Using a value of true will skip any preprocessing of this nature,
although you can still include manual parsing strings. This field is only usable when type is mrkdwn.
"""
super().__init__(text=text, type=self.type)
self.verbatim = verbatim
@staticmethod
def from_str(text: str) -> "MarkdownTextObject":
"""Transforms a string into the required object shape to act as a MarkdownTextObject"""
return MarkdownTextObject(text=text)
@staticmethod
def direct_from_string(text: str) -> Dict[str, Any]:
"""Transforms a string into the required object shape to act as a MarkdownTextObject"""
return MarkdownTextObject.from_str(text).to_dict()
@staticmethod
def from_link(link: Link, title: str = "") -> "MarkdownTextObject":
"""
Transform a Link object directly into the required object shape
to act as a MarkdownTextObject
"""
if title:
title = f": {title}"
return MarkdownTextObject(text=f"{link}{title}")
@staticmethod
def direct_from_link(link: Link, title: str = "") -> Dict[str, Any]:
"""
Transform a Link object directly into the required object shape
to act as a MarkdownTextObject
"""
return MarkdownTextObject.from_link(link, title).to_dict()
class Option(JsonObject):
"""Option object used in dialogs, legacy message actions (interactivity in attachments),
and blocks. JSON must be retrieved with an explicit option_type - the Slack API has
different required formats in different situations
"""
attributes = {} # no attributes because to_dict has unique implementations
logger = logging.getLogger(__name__)
label_max_length = 75
value_max_length = 75
def __init__(
self,
*,
value: str,
label: Optional[str] = None,
text: Optional[Union[str, Dict[str, Any], TextObject]] = None, # Block Kit
description: Optional[Union[str, Dict[str, Any], TextObject]] = None,
url: Optional[str] = None,
**others: Dict[str, Any],
):
"""
An object that represents a single selectable item in a block element (
SelectElement, OverflowMenuElement) or dialog element
(StaticDialogSelectElement)
Blocks:
https://api.slack.com/reference/block-kit/composition-objects#option
Dialogs:
https://api.slack.com/dialogs#select_elements
Legacy interactive attachments:
https://api.slack.com/legacy/interactive-message-field-guide#option_fields
Args:
label: A short, user-facing string to label this option to users.
Cannot exceed 75 characters.
value: A short string that identifies this particular option to your
application. It will be part of the payload when this option is selected
. Cannot exceed 75 characters.
description: A user-facing string that provides more details about
this option. Only supported in legacy message actions, not in blocks or
dialogs.
"""
if text:
# For better compatibility with Block Kit ("mrkdwn" does not work for it),
# we've changed the default text object type to plain_text since version 3.10.0
self._text: Optional[TextObject] = TextObject.parse(
text=text, # "text" here can be either a str or a TextObject
default_type=PlainTextObject.type,
)
self._label: Optional[str] = None
else:
self._text: Optional[TextObject] = None
self._label: Optional[str] = label
# for backward-compatibility with version 2.0-2.5, the following fields return str values
self.text: Optional[str] = self._text.text if self._text else None
self.label: Optional[str] = self._label
self.value: str = value
# for backward-compatibility with version 2.0-2.5, the following fields return str values
if isinstance(description, str):
self.description = description
self._block_description = PlainTextObject.from_str(description)
elif isinstance(description, dict):
self.description = description["text"]
self._block_description = TextObject.parse(description)
elif isinstance(description, TextObject):
self.description = description.text
self._block_description = description
else:
self.description = None
self._block_description = None
# A URL to load in the user's browser when the option is clicked.
# The url attribute is only available in overflow menus.
# Maximum length for this field is 3000 characters.
# If you're using url, you'll still receive an interaction payload
# and will need to send an acknowledgement response.
self.url: Optional[str] = url
show_unknown_key_warning(self, others)
@JsonValidator(f"label attribute cannot exceed {label_max_length} characters")
def _validate_label_length(self) -> bool:
return self._label is None or len(self._label) <= self.label_max_length
@JsonValidator(f"text attribute cannot exceed {label_max_length} characters")
def _validate_text_length(self) -> bool:
return self._text is None or self._text.text is None or len(self._text.text) <= self.label_max_length
@JsonValidator(f"value attribute cannot exceed {value_max_length} characters")
def _validate_value_length(self) -> bool:
return len(self.value) <= self.value_max_length
@classmethod
def parse_all(cls, options: Optional[Sequence[Union[Dict[str, Any], "Option"]]]) -> Optional[List["Option"]]:
if options is None:
return None
option_objects: List[Option] = []
for o in options:
if isinstance(o, dict):
d = copy.copy(o)
option_objects.append(Option(**d))
elif isinstance(o, Option):
option_objects.append(o)
else:
cls.logger.warning(f"Unknown option object detected and skipped ({o})")
return option_objects
def to_dict(self, option_type: str = "block") -> Dict[str, Any]: # skipcq: PYL-W0221
"""
Different parent classes must call this with a valid value from OptionTypes -
either "dialog", "action", or "block", so that JSON is returned in the
correct shape.
"""
self.validate_json()
if option_type == "dialog": # skipcq: PYL-R1705
return {"label": self.label, "value": self.value}
elif option_type == "action" or option_type == "attachment":
# "action" can be confusing but it means a legacy message action in attachments
# we don't remove the type name for backward compatibility though
json = {"text": self.label, "value": self.value}
if self.description is not None:
json["description"] = self.description
return json
else: # if option_type == "block"; this should be the most common case
text: TextObject = self._text or PlainTextObject.from_str(self.label)
json: Dict[str, Any] = {
"text": text.to_dict(),
"value": self.value,
}
if self._block_description:
json["description"] = self._block_description.to_dict()
if self.url:
json["url"] = self.url
return json
@staticmethod
def from_single_value(value_and_label: str):
"""Creates a simple Option instance with the same value and label"""
return Option(value=value_and_label, label=value_and_label)
class OptionGroup(JsonObject):
"""
JSON must be retrieved with an explicit option_type - the Slack API has
different required formats in different situations
"""
attributes = {} # no attributes because to_dict has unique implementations
label_max_length = 75
options_max_length = 100
logger = logging.getLogger(__name__)
def __init__(
self,
*,
label: Optional[Union[str, Dict[str, Any], TextObject]] = None,
options: Sequence[Union[Dict[str, Any], Option]],
**others: Dict[str, Any],
):
"""
Create a group of Option objects - pass in a label (that will be part of the
UI) and a list of Option objects.
Blocks:
https://api.slack.com/reference/block-kit/composition-objects#option-group
Dialogs:
https://api.slack.com/dialogs#select_elements
Legacy interactive attachments:
https://api.slack.com/legacy/interactive-message-field-guide#option_groups_to_place_within_message_menu_actions
Args:
label: Text to display at the top of this group of options.
options: A list of no more than 100 Option objects.
""" # noqa prevent flake8 blowing up on the long URL
# default_type=PlainTextObject.type is for backward-compatibility
self._label: Optional[TextObject] = TextObject.parse(label, default_type=PlainTextObject.type)
self.label: Optional[str] = self._label.text if self._label else None
self.options = Option.parse_all(options) # compatible with version 2.5
show_unknown_key_warning(self, others)
@JsonValidator(f"label attribute cannot exceed {label_max_length} characters")
def _validate_label_length(self):
return self.label is None or len(self.label) <= self.label_max_length
@JsonValidator(f"options attribute cannot exceed {options_max_length} elements")
def _validate_options_length(self):
return self.options is None or len(self.options) <= self.options_max_length
@classmethod
def parse_all(
cls, option_groups: Optional[Sequence[Union[Dict[str, Any], "OptionGroup"]]]
) -> Optional[List["OptionGroup"]]:
if option_groups is None:
return None
option_group_objects = []
for o in option_groups:
if isinstance(o, dict):
d = copy.copy(o)
option_group_objects.append(OptionGroup(**d))
elif isinstance(o, OptionGroup):
option_group_objects.append(o)
else:
cls.logger.warning(f"Unknown option group object detected and skipped ({o})")
return option_group_objects
def to_dict(self, option_type: str = "block") -> Dict[str, Any]: # skipcq: PYL-W0221
self.validate_json()
dict_options = [o.to_dict(option_type) for o in self.options]
if option_type == "dialog": # skipcq: PYL-R1705
return {
"label": self.label,
"options": dict_options,
}
elif option_type == "action":
return {
"text": self.label,
"options": dict_options,
}
else: # if option_type == "block"; this should be the most common case
dict_label: Dict[str, Any] = self._label.to_dict()
return {
"label": dict_label,
"options": dict_options,
}
class ConfirmObject(JsonObject):
attributes = {} # no attributes because to_dict has unique implementations
title_max_length = 100
text_max_length = 300
confirm_max_length = 30
deny_max_length = 30
@classmethod
def parse(cls, confirm: Union["ConfirmObject", Dict[str, Any]]):
if confirm:
if isinstance(confirm, ConfirmObject): # skipcq: PYL-R1705
return confirm
elif isinstance(confirm, dict):
return ConfirmObject(**confirm)
else:
# Not yet implemented: show some warning here
return None
return None
def __init__(
self,
*,
title: Union[str, Dict[str, Any], PlainTextObject],
text: Union[str, Dict[str, Any], TextObject],
confirm: Union[str, Dict[str, Any], PlainTextObject] = "Yes",
deny: Union[str, Dict[str, Any], PlainTextObject] = "No",
style: Optional[str] = None,
):
"""
An object that defines a dialog that provides a confirmation step to any
interactive element. This dialog will ask the user to confirm their action by
offering a confirm and deny button.
https://api.slack.com/reference/block-kit/composition-objects#confirm
"""
self._title = TextObject.parse(title, default_type=PlainTextObject.type)
self._text = TextObject.parse(text, default_type=MarkdownTextObject.type)
self._confirm = TextObject.parse(confirm, default_type=PlainTextObject.type)
self._deny = TextObject.parse(deny, default_type=PlainTextObject.type)
self._style = style
# for backward-compatibility with version 2.0-2.5, the following fields return str values
self.title = self._title.text if self._title else None
self.text = self._text.text if self._text else None
self.confirm = self._confirm.text if self._confirm else None
self.deny = self._deny.text if self._deny else None
self.style = self._style
@JsonValidator(f"title attribute cannot exceed {title_max_length} characters")
def title_length(self) -> bool:
return self._title is None or len(self._title.text) <= self.title_max_length
@JsonValidator(f"text attribute cannot exceed {text_max_length} characters")
def text_length(self) -> bool:
return self._text is None or len(self._text.text) <= self.text_max_length
@JsonValidator(f"confirm attribute cannot exceed {confirm_max_length} characters")
def confirm_length(self) -> bool:
return self._confirm is None or len(self._confirm.text) <= self.confirm_max_length
@JsonValidator(f"deny attribute cannot exceed {deny_max_length} characters")
def deny_length(self) -> bool:
return self._deny is None or len(self._deny.text) <= self.deny_max_length
@JsonValidator('style for confirm must be either "primary" or "danger"')
def _validate_confirm_style(self) -> bool:
return self._style is None or self._style in ["primary", "danger"]
def to_dict(self, option_type: str = "block") -> Dict[str, Any]: # skipcq: PYL-W0221
if option_type == "action": # skipcq: PYL-R1705
# deliberately skipping JSON validators here - can't find documentation
# on actual limits here
json = {
"ok_text": self._confirm.text if self._confirm and self._confirm.text != "Yes" else "Okay",
"dismiss_text": self._deny.text if self._deny and self._deny.text != "No" else "Cancel",
}
if self._title:
json["title"] = self._title.text
if self._text:
json["text"] = self._text.text
return json
else:
self.validate_json()
json = {}
if self._title:
json["title"] = self._title.to_dict()
if self._text:
json["text"] = self._text.to_dict()
if self._confirm:
json["confirm"] = self._confirm.to_dict()
if self._deny:
json["deny"] = self._deny.to_dict()
if self._style:
json["style"] = self._style
return json
class DispatchActionConfig(JsonObject):
attributes = {"trigger_actions_on"}
@classmethod
def parse(cls, config: Union["DispatchActionConfig", Dict[str, Any]]):
if config:
if isinstance(config, DispatchActionConfig): # skipcq: PYL-R1705
return config
elif isinstance(config, dict):
return DispatchActionConfig(**config)
else:
# Not yet implemented: show some warning here
return None
return None
def __init__(
self,
*,
trigger_actions_on: Optional[List[Any]] = None,
):
"""
Determines when a plain-text input element will return a block_actions interaction payload.
https://api.slack.com/reference/block-kit/composition-objects#dispatch_action_config
"""
self._trigger_actions_on = trigger_actions_on or []
def to_dict(self) -> Dict[str, Any]: # skipcq: PYL-W0221
self.validate_json()
json = {}
if self._trigger_actions_on:
json["trigger_actions_on"] = self._trigger_actions_on
return json
class WorkflowTrigger(JsonObject):
attributes = {"trigger"}
def __init__(self, *, url: str, customizable_input_parameters: Optional[List[Dict[str, str]]] = None):
self._url = url
self._customizable_input_parameters = customizable_input_parameters
def to_dict(self) -> Dict[str, Any]: # skipcq: PYL-W0221
self.validate_json()
json = {"url": self._url}
if self._customizable_input_parameters is not None:
json.update({"customizable_input_parameters": self._customizable_input_parameters})
return json
class Workflow(JsonObject):
attributes = {"trigger"}
def __init__(
self,
*,
trigger: Union[WorkflowTrigger, dict],
):
self._trigger = trigger
def to_dict(self) -> Dict[str, Any]: # skipcq: PYL-W0221
self.validate_json()
json = {}
if isinstance(self._trigger, WorkflowTrigger):
json["trigger"] = self._trigger.to_dict()
else:
json["trigger"] = self._trigger
return json
class SlackFile(JsonObject):
attributes = {"id", "url"}
def __init__(
self,
*,
id: Optional[str] = None,
url: Optional[str] = None,
):
"""An object containing Slack file information to be used in an image block or image element.
https://api.slack.com/reference/block-kit/composition-objects#slack_file
Args:
id: Slack ID of the file.
url: This URL can be the url_private or the permalink of the Slack file.
"""
self._id = id
self._url = url
def to_dict(self) -> Dict[str, Any]: # skipcq: PYL-W0221
self.validate_json()
json = {}
if self._id is not None:
json["id"] = self._id
if self._url is not None:
json["url"] = self._url
return json
Classes
class ConfirmObject (*, title: Union[str, Dict[str, Any], PlainTextObject], text: Union[str, Dict[str, Any], TextObject], confirm: Union[str, Dict[str, Any], PlainTextObject] = 'Yes', deny: Union[str, Dict[str, Any], PlainTextObject] = 'No', style: Optional[str] = None)
-
The base class for JSON serializable class objects
An object that defines a dialog that provides a confirmation step to any interactive element. This dialog will ask the user to confirm their action by offering a confirm and deny button. https://api.slack.com/reference/block-kit/composition-objects#confirm
Expand source code
class ConfirmObject(JsonObject): attributes = {} # no attributes because to_dict has unique implementations title_max_length = 100 text_max_length = 300 confirm_max_length = 30 deny_max_length = 30 @classmethod def parse(cls, confirm: Union["ConfirmObject", Dict[str, Any]]): if confirm: if isinstance(confirm, ConfirmObject): # skipcq: PYL-R1705 return confirm elif isinstance(confirm, dict): return ConfirmObject(**confirm) else: # Not yet implemented: show some warning here return None return None def __init__( self, *, title: Union[str, Dict[str, Any], PlainTextObject], text: Union[str, Dict[str, Any], TextObject], confirm: Union[str, Dict[str, Any], PlainTextObject] = "Yes", deny: Union[str, Dict[str, Any], PlainTextObject] = "No", style: Optional[str] = None, ): """ An object that defines a dialog that provides a confirmation step to any interactive element. This dialog will ask the user to confirm their action by offering a confirm and deny button. https://api.slack.com/reference/block-kit/composition-objects#confirm """ self._title = TextObject.parse(title, default_type=PlainTextObject.type) self._text = TextObject.parse(text, default_type=MarkdownTextObject.type) self._confirm = TextObject.parse(confirm, default_type=PlainTextObject.type) self._deny = TextObject.parse(deny, default_type=PlainTextObject.type) self._style = style # for backward-compatibility with version 2.0-2.5, the following fields return str values self.title = self._title.text if self._title else None self.text = self._text.text if self._text else None self.confirm = self._confirm.text if self._confirm else None self.deny = self._deny.text if self._deny else None self.style = self._style @JsonValidator(f"title attribute cannot exceed {title_max_length} characters") def title_length(self) -> bool: return self._title is None or len(self._title.text) <= self.title_max_length @JsonValidator(f"text attribute cannot exceed {text_max_length} characters") def text_length(self) -> bool: return self._text is None or len(self._text.text) <= self.text_max_length @JsonValidator(f"confirm attribute cannot exceed {confirm_max_length} characters") def confirm_length(self) -> bool: return self._confirm is None or len(self._confirm.text) <= self.confirm_max_length @JsonValidator(f"deny attribute cannot exceed {deny_max_length} characters") def deny_length(self) -> bool: return self._deny is None or len(self._deny.text) <= self.deny_max_length @JsonValidator('style for confirm must be either "primary" or "danger"') def _validate_confirm_style(self) -> bool: return self._style is None or self._style in ["primary", "danger"] def to_dict(self, option_type: str = "block") -> Dict[str, Any]: # skipcq: PYL-W0221 if option_type == "action": # skipcq: PYL-R1705 # deliberately skipping JSON validators here - can't find documentation # on actual limits here json = { "ok_text": self._confirm.text if self._confirm and self._confirm.text != "Yes" else "Okay", "dismiss_text": self._deny.text if self._deny and self._deny.text != "No" else "Cancel", } if self._title: json["title"] = self._title.text if self._text: json["text"] = self._text.text return json else: self.validate_json() json = {} if self._title: json["title"] = self._title.to_dict() if self._text: json["text"] = self._text.to_dict() if self._confirm: json["confirm"] = self._confirm.to_dict() if self._deny: json["deny"] = self._deny.to_dict() if self._style: json["style"] = self._style return json
Ancestors
Class variables
var confirm_max_length
var deny_max_length
var text_max_length
var title_max_length
Static methods
def parse(confirm: Union[ForwardRef('ConfirmObject'), Dict[str, Any]])
-
Expand source code
@classmethod def parse(cls, confirm: Union["ConfirmObject", Dict[str, Any]]): if confirm: if isinstance(confirm, ConfirmObject): # skipcq: PYL-R1705 return confirm elif isinstance(confirm, dict): return ConfirmObject(**confirm) else: # Not yet implemented: show some warning here return None return None
Methods
def confirm_length(self) ‑> bool
-
Expand source code
@JsonValidator(f"confirm attribute cannot exceed {confirm_max_length} characters") def confirm_length(self) -> bool: return self._confirm is None or len(self._confirm.text) <= self.confirm_max_length
def deny_length(self) ‑> bool
-
Expand source code
@JsonValidator(f"deny attribute cannot exceed {deny_max_length} characters") def deny_length(self) -> bool: return self._deny is None or len(self._deny.text) <= self.deny_max_length
def text_length(self) ‑> bool
-
Expand source code
@JsonValidator(f"text attribute cannot exceed {text_max_length} characters") def text_length(self) -> bool: return self._text is None or len(self._text.text) <= self.text_max_length
def title_length(self) ‑> bool
-
Expand source code
@JsonValidator(f"title attribute cannot exceed {title_max_length} characters") def title_length(self) -> bool: return self._title is None or len(self._title.text) <= self.title_max_length
Inherited members
class DispatchActionConfig (*, trigger_actions_on: Optional[List[Any]] = None)
-
The base class for JSON serializable class objects
Determines when a plain-text input element will return a block_actions interaction payload. https://api.slack.com/reference/block-kit/composition-objects#dispatch_action_config
Expand source code
class DispatchActionConfig(JsonObject): attributes = {"trigger_actions_on"} @classmethod def parse(cls, config: Union["DispatchActionConfig", Dict[str, Any]]): if config: if isinstance(config, DispatchActionConfig): # skipcq: PYL-R1705 return config elif isinstance(config, dict): return DispatchActionConfig(**config) else: # Not yet implemented: show some warning here return None return None def __init__( self, *, trigger_actions_on: Optional[List[Any]] = None, ): """ Determines when a plain-text input element will return a block_actions interaction payload. https://api.slack.com/reference/block-kit/composition-objects#dispatch_action_config """ self._trigger_actions_on = trigger_actions_on or [] def to_dict(self) -> Dict[str, Any]: # skipcq: PYL-W0221 self.validate_json() json = {} if self._trigger_actions_on: json["trigger_actions_on"] = self._trigger_actions_on return json
Ancestors
Static methods
def parse(config: Union[ForwardRef('DispatchActionConfig'), Dict[str, Any]])
-
Expand source code
@classmethod def parse(cls, config: Union["DispatchActionConfig", Dict[str, Any]]): if config: if isinstance(config, DispatchActionConfig): # skipcq: PYL-R1705 return config elif isinstance(config, dict): return DispatchActionConfig(**config) else: # Not yet implemented: show some warning here return None return None
Inherited members
class MarkdownTextObject (*, text: str, verbatim: Optional[bool] = None)
-
mrkdwn typed text object
A Markdown text object, meaning markdown characters will be parsed as formatting information. https://api.slack.com/reference/block-kit/composition-objects#text
Args
text
:required
- The text for the block. This field accepts any of the standard text formatting markup when type is mrkdwn.
verbatim
- When set to false (as is default) URLs will be auto-converted into links, conversation names will be link-ified, and certain mentions will be automatically parsed. Using a value of true will skip any preprocessing of this nature, although you can still include manual parsing strings. This field is only usable when type is mrkdwn.
Expand source code
class MarkdownTextObject(TextObject): """mrkdwn typed text object""" type = "mrkdwn" @property def attributes(self) -> Set[str]: return super().attributes.union({"verbatim"}) def __init__(self, *, text: str, verbatim: Optional[bool] = None): """A Markdown text object, meaning markdown characters will be parsed as formatting information. https://api.slack.com/reference/block-kit/composition-objects#text Args: text (required): The text for the block. This field accepts any of the standard text formatting markup when type is mrkdwn. verbatim: When set to false (as is default) URLs will be auto-converted into links, conversation names will be link-ified, and certain mentions will be automatically parsed. Using a value of true will skip any preprocessing of this nature, although you can still include manual parsing strings. This field is only usable when type is mrkdwn. """ super().__init__(text=text, type=self.type) self.verbatim = verbatim @staticmethod def from_str(text: str) -> "MarkdownTextObject": """Transforms a string into the required object shape to act as a MarkdownTextObject""" return MarkdownTextObject(text=text) @staticmethod def direct_from_string(text: str) -> Dict[str, Any]: """Transforms a string into the required object shape to act as a MarkdownTextObject""" return MarkdownTextObject.from_str(text).to_dict() @staticmethod def from_link(link: Link, title: str = "") -> "MarkdownTextObject": """ Transform a Link object directly into the required object shape to act as a MarkdownTextObject """ if title: title = f": {title}" return MarkdownTextObject(text=f"{link}{title}") @staticmethod def direct_from_link(link: Link, title: str = "") -> Dict[str, Any]: """ Transform a Link object directly into the required object shape to act as a MarkdownTextObject """ return MarkdownTextObject.from_link(link, title).to_dict()
Ancestors
Class variables
var type
Static methods
def direct_from_link(link: Link, title: str = '') ‑> Dict[str, Any]
-
Transform a Link object directly into the required object shape to act as a MarkdownTextObject
Expand source code
@staticmethod def direct_from_link(link: Link, title: str = "") -> Dict[str, Any]: """ Transform a Link object directly into the required object shape to act as a MarkdownTextObject """ return MarkdownTextObject.from_link(link, title).to_dict()
def direct_from_string(text: str) ‑> Dict[str, Any]
-
Transforms a string into the required object shape to act as a MarkdownTextObject
Expand source code
@staticmethod def direct_from_string(text: str) -> Dict[str, Any]: """Transforms a string into the required object shape to act as a MarkdownTextObject""" return MarkdownTextObject.from_str(text).to_dict()
def from_link(link: Link, title: str = '') ‑> MarkdownTextObject
-
Transform a Link object directly into the required object shape to act as a MarkdownTextObject
Expand source code
@staticmethod def from_link(link: Link, title: str = "") -> "MarkdownTextObject": """ Transform a Link object directly into the required object shape to act as a MarkdownTextObject """ if title: title = f": {title}" return MarkdownTextObject(text=f"{link}{title}")
def from_str(text: str) ‑> MarkdownTextObject
-
Transforms a string into the required object shape to act as a MarkdownTextObject
Expand source code
@staticmethod def from_str(text: str) -> "MarkdownTextObject": """Transforms a string into the required object shape to act as a MarkdownTextObject""" return MarkdownTextObject(text=text)
Instance variables
var attributes : Set[str]
-
set() -> new empty set object set(iterable) -> new set object
Build an unordered collection of unique elements.
Expand source code
@property def attributes(self) -> Set[str]: return super().attributes.union({"verbatim"})
Inherited members
class Option (*, value: str, label: Optional[str] = None, text: Union[str, Dict[str, Any], TextObject, ForwardRef(None)] = None, description: Union[str, Dict[str, Any], TextObject, ForwardRef(None)] = None, url: Optional[str] = None, **others: Dict[str, Any])
-
Option object used in dialogs, legacy message actions (interactivity in attachments), and blocks. JSON must be retrieved with an explicit option_type - the Slack API has different required formats in different situations
An object that represents a single selectable item in a block element ( SelectElement, OverflowMenuElement) or dialog element (StaticDialogSelectElement)
Blocks: https://api.slack.com/reference/block-kit/composition-objects#option
Dialogs: https://api.slack.com/dialogs#select_elements
Legacy interactive attachments: https://api.slack.com/legacy/interactive-message-field-guide#option_fields
Args
label
- A short, user-facing string to label this option to users. Cannot exceed 75 characters.
value
- A short string that identifies this particular option to your application. It will be part of the payload when this option is selected . Cannot exceed 75 characters.
description
- A user-facing string that provides more details about this option. Only supported in legacy message actions, not in blocks or dialogs.
Expand source code
class Option(JsonObject): """Option object used in dialogs, legacy message actions (interactivity in attachments), and blocks. JSON must be retrieved with an explicit option_type - the Slack API has different required formats in different situations """ attributes = {} # no attributes because to_dict has unique implementations logger = logging.getLogger(__name__) label_max_length = 75 value_max_length = 75 def __init__( self, *, value: str, label: Optional[str] = None, text: Optional[Union[str, Dict[str, Any], TextObject]] = None, # Block Kit description: Optional[Union[str, Dict[str, Any], TextObject]] = None, url: Optional[str] = None, **others: Dict[str, Any], ): """ An object that represents a single selectable item in a block element ( SelectElement, OverflowMenuElement) or dialog element (StaticDialogSelectElement) Blocks: https://api.slack.com/reference/block-kit/composition-objects#option Dialogs: https://api.slack.com/dialogs#select_elements Legacy interactive attachments: https://api.slack.com/legacy/interactive-message-field-guide#option_fields Args: label: A short, user-facing string to label this option to users. Cannot exceed 75 characters. value: A short string that identifies this particular option to your application. It will be part of the payload when this option is selected . Cannot exceed 75 characters. description: A user-facing string that provides more details about this option. Only supported in legacy message actions, not in blocks or dialogs. """ if text: # For better compatibility with Block Kit ("mrkdwn" does not work for it), # we've changed the default text object type to plain_text since version 3.10.0 self._text: Optional[TextObject] = TextObject.parse( text=text, # "text" here can be either a str or a TextObject default_type=PlainTextObject.type, ) self._label: Optional[str] = None else: self._text: Optional[TextObject] = None self._label: Optional[str] = label # for backward-compatibility with version 2.0-2.5, the following fields return str values self.text: Optional[str] = self._text.text if self._text else None self.label: Optional[str] = self._label self.value: str = value # for backward-compatibility with version 2.0-2.5, the following fields return str values if isinstance(description, str): self.description = description self._block_description = PlainTextObject.from_str(description) elif isinstance(description, dict): self.description = description["text"] self._block_description = TextObject.parse(description) elif isinstance(description, TextObject): self.description = description.text self._block_description = description else: self.description = None self._block_description = None # A URL to load in the user's browser when the option is clicked. # The url attribute is only available in overflow menus. # Maximum length for this field is 3000 characters. # If you're using url, you'll still receive an interaction payload # and will need to send an acknowledgement response. self.url: Optional[str] = url show_unknown_key_warning(self, others) @JsonValidator(f"label attribute cannot exceed {label_max_length} characters") def _validate_label_length(self) -> bool: return self._label is None or len(self._label) <= self.label_max_length @JsonValidator(f"text attribute cannot exceed {label_max_length} characters") def _validate_text_length(self) -> bool: return self._text is None or self._text.text is None or len(self._text.text) <= self.label_max_length @JsonValidator(f"value attribute cannot exceed {value_max_length} characters") def _validate_value_length(self) -> bool: return len(self.value) <= self.value_max_length @classmethod def parse_all(cls, options: Optional[Sequence[Union[Dict[str, Any], "Option"]]]) -> Optional[List["Option"]]: if options is None: return None option_objects: List[Option] = [] for o in options: if isinstance(o, dict): d = copy.copy(o) option_objects.append(Option(**d)) elif isinstance(o, Option): option_objects.append(o) else: cls.logger.warning(f"Unknown option object detected and skipped ({o})") return option_objects def to_dict(self, option_type: str = "block") -> Dict[str, Any]: # skipcq: PYL-W0221 """ Different parent classes must call this with a valid value from OptionTypes - either "dialog", "action", or "block", so that JSON is returned in the correct shape. """ self.validate_json() if option_type == "dialog": # skipcq: PYL-R1705 return {"label": self.label, "value": self.value} elif option_type == "action" or option_type == "attachment": # "action" can be confusing but it means a legacy message action in attachments # we don't remove the type name for backward compatibility though json = {"text": self.label, "value": self.value} if self.description is not None: json["description"] = self.description return json else: # if option_type == "block"; this should be the most common case text: TextObject = self._text or PlainTextObject.from_str(self.label) json: Dict[str, Any] = { "text": text.to_dict(), "value": self.value, } if self._block_description: json["description"] = self._block_description.to_dict() if self.url: json["url"] = self.url return json @staticmethod def from_single_value(value_and_label: str): """Creates a simple Option instance with the same value and label""" return Option(value=value_and_label, label=value_and_label)
Ancestors
Class variables
var label_max_length
var logger
var value_max_length
Static methods
def from_single_value(value_and_label: str)
-
Creates a simple Option instance with the same value and label
Expand source code
@staticmethod def from_single_value(value_and_label: str): """Creates a simple Option instance with the same value and label""" return Option(value=value_and_label, label=value_and_label)
def parse_all(options: Optional[Sequence[Union[Dict[str, Any], ForwardRef('Option')]]]) ‑> Optional[List[Option]]
-
Expand source code
@classmethod def parse_all(cls, options: Optional[Sequence[Union[Dict[str, Any], "Option"]]]) -> Optional[List["Option"]]: if options is None: return None option_objects: List[Option] = [] for o in options: if isinstance(o, dict): d = copy.copy(o) option_objects.append(Option(**d)) elif isinstance(o, Option): option_objects.append(o) else: cls.logger.warning(f"Unknown option object detected and skipped ({o})") return option_objects
Methods
def to_dict(self, option_type: str = 'block') ‑> Dict[str, Any]
-
Different parent classes must call this with a valid value from OptionTypes - either "dialog", "action", or "block", so that JSON is returned in the correct shape.
Expand source code
def to_dict(self, option_type: str = "block") -> Dict[str, Any]: # skipcq: PYL-W0221 """ Different parent classes must call this with a valid value from OptionTypes - either "dialog", "action", or "block", so that JSON is returned in the correct shape. """ self.validate_json() if option_type == "dialog": # skipcq: PYL-R1705 return {"label": self.label, "value": self.value} elif option_type == "action" or option_type == "attachment": # "action" can be confusing but it means a legacy message action in attachments # we don't remove the type name for backward compatibility though json = {"text": self.label, "value": self.value} if self.description is not None: json["description"] = self.description return json else: # if option_type == "block"; this should be the most common case text: TextObject = self._text or PlainTextObject.from_str(self.label) json: Dict[str, Any] = { "text": text.to_dict(), "value": self.value, } if self._block_description: json["description"] = self._block_description.to_dict() if self.url: json["url"] = self.url return json
Inherited members
class OptionGroup (*, label: Union[str, Dict[str, Any], TextObject, ForwardRef(None)] = None, options: Sequence[Union[Dict[str, Any], Option]], **others: Dict[str, Any])
-
JSON must be retrieved with an explicit option_type - the Slack API has different required formats in different situations
Create a group of Option objects - pass in a label (that will be part of the UI) and a list of Option objects.
Blocks: https://api.slack.com/reference/block-kit/composition-objects#option-group
Dialogs: https://api.slack.com/dialogs#select_elements
Legacy interactive attachments: https://api.slack.com/legacy/interactive-message-field-guide#option_groups_to_place_within_message_menu_actions
Args
label
- Text to display at the top of this group of options.
options
- A list of no more than 100 Option objects.
Expand source code
class OptionGroup(JsonObject): """ JSON must be retrieved with an explicit option_type - the Slack API has different required formats in different situations """ attributes = {} # no attributes because to_dict has unique implementations label_max_length = 75 options_max_length = 100 logger = logging.getLogger(__name__) def __init__( self, *, label: Optional[Union[str, Dict[str, Any], TextObject]] = None, options: Sequence[Union[Dict[str, Any], Option]], **others: Dict[str, Any], ): """ Create a group of Option objects - pass in a label (that will be part of the UI) and a list of Option objects. Blocks: https://api.slack.com/reference/block-kit/composition-objects#option-group Dialogs: https://api.slack.com/dialogs#select_elements Legacy interactive attachments: https://api.slack.com/legacy/interactive-message-field-guide#option_groups_to_place_within_message_menu_actions Args: label: Text to display at the top of this group of options. options: A list of no more than 100 Option objects. """ # noqa prevent flake8 blowing up on the long URL # default_type=PlainTextObject.type is for backward-compatibility self._label: Optional[TextObject] = TextObject.parse(label, default_type=PlainTextObject.type) self.label: Optional[str] = self._label.text if self._label else None self.options = Option.parse_all(options) # compatible with version 2.5 show_unknown_key_warning(self, others) @JsonValidator(f"label attribute cannot exceed {label_max_length} characters") def _validate_label_length(self): return self.label is None or len(self.label) <= self.label_max_length @JsonValidator(f"options attribute cannot exceed {options_max_length} elements") def _validate_options_length(self): return self.options is None or len(self.options) <= self.options_max_length @classmethod def parse_all( cls, option_groups: Optional[Sequence[Union[Dict[str, Any], "OptionGroup"]]] ) -> Optional[List["OptionGroup"]]: if option_groups is None: return None option_group_objects = [] for o in option_groups: if isinstance(o, dict): d = copy.copy(o) option_group_objects.append(OptionGroup(**d)) elif isinstance(o, OptionGroup): option_group_objects.append(o) else: cls.logger.warning(f"Unknown option group object detected and skipped ({o})") return option_group_objects def to_dict(self, option_type: str = "block") -> Dict[str, Any]: # skipcq: PYL-W0221 self.validate_json() dict_options = [o.to_dict(option_type) for o in self.options] if option_type == "dialog": # skipcq: PYL-R1705 return { "label": self.label, "options": dict_options, } elif option_type == "action": return { "text": self.label, "options": dict_options, } else: # if option_type == "block"; this should be the most common case dict_label: Dict[str, Any] = self._label.to_dict() return { "label": dict_label, "options": dict_options, }
Ancestors
Class variables
var label_max_length
var logger
var options_max_length
Static methods
def parse_all(option_groups: Optional[Sequence[Union[Dict[str, Any], ForwardRef('OptionGroup')]]]) ‑> Optional[List[OptionGroup]]
-
Expand source code
@classmethod def parse_all( cls, option_groups: Optional[Sequence[Union[Dict[str, Any], "OptionGroup"]]] ) -> Optional[List["OptionGroup"]]: if option_groups is None: return None option_group_objects = [] for o in option_groups: if isinstance(o, dict): d = copy.copy(o) option_group_objects.append(OptionGroup(**d)) elif isinstance(o, OptionGroup): option_group_objects.append(o) else: cls.logger.warning(f"Unknown option group object detected and skipped ({o})") return option_group_objects
Inherited members
class PlainTextObject (*, text: str, emoji: Optional[bool] = None)
-
plain_text typed text object
A plain text object, meaning markdown characters will not be parsed as formatting information. https://api.slack.com/reference/block-kit/composition-objects#text
Args
text
:required
- The text for the block. This field accepts any of the standard text formatting markup when type is mrkdwn.
emoji
- Indicates whether emojis in a text field should be escaped into the colon emoji format. This field is only usable when type is plain_text.
Expand source code
class PlainTextObject(TextObject): """plain_text typed text object""" type = "plain_text" @property def attributes(self) -> Set[str]: return super().attributes.union({"emoji"}) def __init__(self, *, text: str, emoji: Optional[bool] = None): """A plain text object, meaning markdown characters will not be parsed as formatting information. https://api.slack.com/reference/block-kit/composition-objects#text Args: text (required): The text for the block. This field accepts any of the standard text formatting markup when type is mrkdwn. emoji: Indicates whether emojis in a text field should be escaped into the colon emoji format. This field is only usable when type is plain_text. """ super().__init__(text=text, type=self.type) self.emoji = emoji @staticmethod def from_str(text: str) -> "PlainTextObject": return PlainTextObject(text=text, emoji=True) @staticmethod def direct_from_string(text: str) -> Dict[str, Any]: """Transforms a string into the required object shape to act as a PlainTextObject""" return PlainTextObject.from_str(text).to_dict()
Ancestors
Class variables
var type
Static methods
def direct_from_string(text: str) ‑> Dict[str, Any]
-
Transforms a string into the required object shape to act as a PlainTextObject
Expand source code
@staticmethod def direct_from_string(text: str) -> Dict[str, Any]: """Transforms a string into the required object shape to act as a PlainTextObject""" return PlainTextObject.from_str(text).to_dict()
def from_str(text: str) ‑> PlainTextObject
-
Expand source code
@staticmethod def from_str(text: str) -> "PlainTextObject": return PlainTextObject(text=text, emoji=True)
Instance variables
var attributes : Set[str]
-
set() -> new empty set object set(iterable) -> new set object
Build an unordered collection of unique elements.
Expand source code
@property def attributes(self) -> Set[str]: return super().attributes.union({"emoji"})
Inherited members
class SlackFile (*, id: Optional[str] = None, url: Optional[str] = None)
-
The base class for JSON serializable class objects
An object containing Slack file information to be used in an image block or image element. https://api.slack.com/reference/block-kit/composition-objects#slack_file
Args
id
- Slack ID of the file.
url
- This URL can be the url_private or the permalink of the Slack file.
Expand source code
class SlackFile(JsonObject): attributes = {"id", "url"} def __init__( self, *, id: Optional[str] = None, url: Optional[str] = None, ): """An object containing Slack file information to be used in an image block or image element. https://api.slack.com/reference/block-kit/composition-objects#slack_file Args: id: Slack ID of the file. url: This URL can be the url_private or the permalink of the Slack file. """ self._id = id self._url = url def to_dict(self) -> Dict[str, Any]: # skipcq: PYL-W0221 self.validate_json() json = {} if self._id is not None: json["id"] = self._id if self._url is not None: json["url"] = self._url return json
Ancestors
Inherited members
class TextObject (text: str, type: Optional[str] = None, subtype: Optional[str] = None, emoji: Optional[bool] = None, **kwargs)
-
The interface for text objects (types: plain_text, mrkdwn)
Super class for new text "objects" used in Block kit
Expand source code
class TextObject(JsonObject): """The interface for text objects (types: plain_text, mrkdwn)""" attributes = {"text", "type", "emoji"} logger = logging.getLogger(__name__) def _subtype_warning(self): # skipcq: PYL-R0201 warnings.warn( "subtype is deprecated since slackclient 2.6.0, use type instead", DeprecationWarning, ) @property def subtype(self) -> Optional[str]: return self.type @classmethod def parse( cls, text: Union[str, Dict[str, Any], "TextObject"], default_type: str = "mrkdwn", ) -> Optional["TextObject"]: if not text: # skipcq: PYL-R1705 return None elif isinstance(text, str): if default_type == PlainTextObject.type: # skipcq: PYL-R1705 return PlainTextObject.from_str(text) else: return MarkdownTextObject.from_str(text) elif isinstance(text, dict): d = copy.copy(text) t = d.pop("type") if t == PlainTextObject.type: # skipcq: PYL-R1705 return PlainTextObject(**d) else: return MarkdownTextObject(**d) elif isinstance(text, TextObject): return text else: cls.logger.warning(f"Unknown type ({type(text)}) detected when parsing a TextObject") return None def __init__( self, text: str, type: Optional[str] = None, # skipcq: PYL-W0622 subtype: Optional[str] = None, emoji: Optional[bool] = None, **kwargs, ): """Super class for new text "objects" used in Block kit""" if subtype: self._subtype_warning() self.text = text self.type = type if type else subtype self.emoji = emoji
Ancestors
Subclasses
Class variables
var logger
Static methods
def parse(text: Union[str, Dict[str, Any], ForwardRef('TextObject')], default_type: str = 'mrkdwn') ‑> Optional[TextObject]
-
Expand source code
@classmethod def parse( cls, text: Union[str, Dict[str, Any], "TextObject"], default_type: str = "mrkdwn", ) -> Optional["TextObject"]: if not text: # skipcq: PYL-R1705 return None elif isinstance(text, str): if default_type == PlainTextObject.type: # skipcq: PYL-R1705 return PlainTextObject.from_str(text) else: return MarkdownTextObject.from_str(text) elif isinstance(text, dict): d = copy.copy(text) t = d.pop("type") if t == PlainTextObject.type: # skipcq: PYL-R1705 return PlainTextObject(**d) else: return MarkdownTextObject(**d) elif isinstance(text, TextObject): return text else: cls.logger.warning(f"Unknown type ({type(text)}) detected when parsing a TextObject") return None
Instance variables
var subtype : Optional[str]
-
Expand source code
@property def subtype(self) -> Optional[str]: return self.type
Inherited members
class Workflow (*, trigger: Union[WorkflowTrigger, dict])
-
The base class for JSON serializable class objects
Expand source code
class Workflow(JsonObject): attributes = {"trigger"} def __init__( self, *, trigger: Union[WorkflowTrigger, dict], ): self._trigger = trigger def to_dict(self) -> Dict[str, Any]: # skipcq: PYL-W0221 self.validate_json() json = {} if isinstance(self._trigger, WorkflowTrigger): json["trigger"] = self._trigger.to_dict() else: json["trigger"] = self._trigger return json
Ancestors
Inherited members
class WorkflowTrigger (*, url: str, customizable_input_parameters: Optional[List[Dict[str, str]]] = None)
-
The base class for JSON serializable class objects
Expand source code
class WorkflowTrigger(JsonObject): attributes = {"trigger"} def __init__(self, *, url: str, customizable_input_parameters: Optional[List[Dict[str, str]]] = None): self._url = url self._customizable_input_parameters = customizable_input_parameters def to_dict(self) -> Dict[str, Any]: # skipcq: PYL-W0221 self.validate_json() json = {"url": self._url} if self._customizable_input_parameters is not None: json.update({"customizable_input_parameters": self._customizable_input_parameters}) return json
Ancestors
Inherited members