From cfb8083116b9d854da9ad19e4d802615f640da5f Mon Sep 17 00:00:00 2001 From: Krittick Date: Thu, 17 Mar 2022 19:36:59 -0700 Subject: [PATCH 01/19] add EmbedField object to allow for easier embed class instance creation --- discord/embeds.py | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/discord/embeds.py b/discord/embeds.py index da72932373..8a85b505b5 100644 --- a/discord/embeds.py +++ b/discord/embeds.py @@ -33,6 +33,7 @@ Final, List, Mapping, + Optional, Protocol, Type, TypeVar, @@ -114,6 +115,32 @@ class _EmbedAuthorProxy(Protocol): proxy_icon_url: MaybeEmpty[str] +class EmbedField: + """Represents a field on the :class:`Embed` object. + + Attributes + ---------- + name: :class:`str` + The name of the field. + value: :class:`str` + The value of the field. + inline: :class:`bool` + Whether the field should be displayed inline. + """ + + def __init__(self, name: str, value: str, inline: Optional[bool] = False): + self.name = name + self.value = value + self.inline = inline + + def to_dict(self) -> Dict[str, Union[str, bool]]: + return { + "name": self.name, + "value": self.value, + "inline": self.inline, + } + + class Embed: """Represents a Discord embed. @@ -195,6 +222,7 @@ def __init__( url: MaybeEmpty[Any] = EmptyEmbed, description: MaybeEmpty[Any] = EmptyEmbed, timestamp: datetime.datetime = None, + fields: List[EmbedField] = None, ): self.colour = colour if colour is not EmptyEmbed else color @@ -215,6 +243,10 @@ def __init__( if timestamp: self.timestamp = timestamp + if fields: + for field in fields: + self.add_field(name=field.name, value=field.value, inline=field.inline) + @classmethod def from_dict(cls: Type[E], data: Mapping[str, Any]) -> E: """Converts a :class:`dict` to a :class:`Embed` provided it is in the @@ -615,6 +647,19 @@ def fields(self) -> List[_EmbedFieldProxy]: """ return [EmbedProxy(d) for d in getattr(self, "_fields", [])] # type: ignore + @fields.setter + def fields(self, value: List[EmbedField]) -> None: + """Sets the fields for the embed. This overwrites any existing fields. + + Parameters + ---------- + value: List[:class:`EmbedField`] + The list of :class:`EmbedField` objects to include in the embed. + """ + self.clear_fields() + for field in value: + self.add_field(name=field.name, value=field.value, inline=field.inline) + def add_field(self: E, *, name: Any, value: Any, inline: bool = True) -> E: """Adds a field to the embed object. From 772d0e6f22c3c473a11ad12bac143b6e0e8cbab3 Mon Sep 17 00:00:00 2001 From: Krittick Date: Sat, 19 Mar 2022 19:30:56 -0700 Subject: [PATCH 02/19] add TypeError if `fields` setter is passed a list containing anything other than `EmbedField` objects --- discord/embeds.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/discord/embeds.py b/discord/embeds.py index 8a85b505b5..87cd5877ad 100644 --- a/discord/embeds.py +++ b/discord/embeds.py @@ -656,6 +656,9 @@ def fields(self, value: List[EmbedField]) -> None: value: List[:class:`EmbedField`] The list of :class:`EmbedField` objects to include in the embed. """ + if not all(isinstance(x, EmbedField) for x in value): + raise TypeError("Expected a list of EmbedField objects.") + self.clear_fields() for field in value: self.add_field(name=field.name, value=field.value, inline=field.inline) From 53ba029a45614d4ef23d85ae6a68b85af76ef65d Mon Sep 17 00:00:00 2001 From: Krittick Date: Sat, 19 Mar 2022 19:42:18 -0700 Subject: [PATCH 03/19] initial pass at removing proxy object reliance from embed fields --- discord/embeds.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/discord/embeds.py b/discord/embeds.py index 87cd5877ad..0ce2d607ee 100644 --- a/discord/embeds.py +++ b/discord/embeds.py @@ -638,14 +638,17 @@ def remove_author(self: E) -> E: return self @property - def fields(self) -> List[_EmbedFieldProxy]: - """List[Union[``EmbedProxy``, :attr:`Empty`]]: Returns a :class:`list` of ``EmbedProxy`` denoting the field contents. + def fields(self) -> Optional[List[Dict[str, Union[bool, str]]]]: + """Returns a :class:`list` of :class:`EmbedField` objects denoting the field contents. See :meth:`add_field` for possible values you can access. - If the attribute has no value then :attr:`Empty` is returned. + If the attribute has no value then ``None`` is returned. """ - return [EmbedProxy(d) for d in getattr(self, "_fields", [])] # type: ignore + if self._fields: + return self._fields + else: + return None @fields.setter def fields(self, value: List[EmbedField]) -> None: From ab18423276a8acdc01949097653262e41d938555 Mon Sep 17 00:00:00 2001 From: Krittick Date: Sat, 9 Apr 2022 15:05:32 -0700 Subject: [PATCH 04/19] add self._fields to Embed.__init__ (prevents AttributeError) fix typing for fields parameter in Embed.__init__ fix typing for Embed.fields property change Embed.add_field, Embed.insert_field_at to use an EmbedField object when appending to Embed._fields change Embed.set_field_at to set EmbedField properties instead of dictionary values --- discord/embeds.py | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/discord/embeds.py b/discord/embeds.py index 0ce2d607ee..fcea5f423f 100644 --- a/discord/embeds.py +++ b/discord/embeds.py @@ -222,7 +222,7 @@ def __init__( url: MaybeEmpty[Any] = EmptyEmbed, description: MaybeEmpty[Any] = EmptyEmbed, timestamp: datetime.datetime = None, - fields: List[EmbedField] = None, + fields: Optional[List[EmbedField]] = None, ): self.colour = colour if colour is not EmptyEmbed else color @@ -242,7 +242,7 @@ def __init__( if timestamp: self.timestamp = timestamp - + self._fields: List[EmbedField] = fields or [] if fields: for field in fields: self.add_field(name=field.name, value=field.value, inline=field.inline) @@ -638,7 +638,7 @@ def remove_author(self: E) -> E: return self @property - def fields(self) -> Optional[List[Dict[str, Union[bool, str]]]]: + def fields(self) -> Optional[List[EmbedField]]: """Returns a :class:`list` of :class:`EmbedField` objects denoting the field contents. See :meth:`add_field` for possible values you can access. @@ -682,11 +682,7 @@ def add_field(self: E, *, name: Any, value: Any, inline: bool = True) -> E: Whether the field should be displayed inline. """ - field = { - "inline": inline, - "name": str(name), - "value": str(value), - } + field = EmbedField(name=str(name), value=str(value), inline=inline) try: self._fields.append(field) @@ -715,11 +711,7 @@ def insert_field_at(self: E, index: int, *, name: Any, value: Any, inline: bool Whether the field should be displayed inline. """ - field = { - "inline": inline, - "name": str(name), - "value": str(value), - } + field = EmbedField(name=str(name), value=str(value), inline=inline) try: self._fields.insert(index, field) @@ -786,9 +778,9 @@ def set_field_at(self: E, index: int, *, name: Any, value: Any, inline: bool = T except (TypeError, IndexError, AttributeError): raise IndexError("field index out of range") - field["name"] = str(name) - field["value"] = str(value) - field["inline"] = inline + field.name = str(name) + field.value = str(value) + field.inline = inline return self def to_dict(self) -> EmbedData: From a1d8b19465eb2f4dce1cca3469d2cb4523619815 Mon Sep 17 00:00:00 2001 From: Krittick Date: Sat, 9 Apr 2022 15:09:54 -0700 Subject: [PATCH 05/19] add EmbedField to __all__ --- discord/embeds.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/discord/embeds.py b/discord/embeds.py index fcea5f423f..4b6624ee2c 100644 --- a/discord/embeds.py +++ b/discord/embeds.py @@ -43,7 +43,10 @@ from . import utils from .colour import Colour -__all__ = ("Embed",) +__all__ = ( + "Embed", + "EmbedField", +) class _EmptyEmbed: From 70a794227a220582882a7183eb0fa796826d14b6 Mon Sep 17 00:00:00 2001 From: Krittick Date: Sat, 9 Apr 2022 15:17:08 -0700 Subject: [PATCH 06/19] fix init loop --- discord/embeds.py | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/discord/embeds.py b/discord/embeds.py index 4b6624ee2c..ecde036232 100644 --- a/discord/embeds.py +++ b/discord/embeds.py @@ -246,8 +246,8 @@ def __init__( if timestamp: self.timestamp = timestamp self._fields: List[EmbedField] = fields or [] - if fields: - for field in fields: + if self._fields: + for field in self._fields: self.add_field(name=field.name, value=field.value, inline=field.inline) @classmethod @@ -669,7 +669,7 @@ def fields(self, value: List[EmbedField]) -> None: for field in value: self.add_field(name=field.name, value=field.value, inline=field.inline) - def add_field(self: E, *, name: Any, value: Any, inline: bool = True) -> E: + def add_field(self: E, *, name: str, value: str, inline: bool = True) -> E: """Adds a field to the embed object. This function returns the class instance to allow for fluent-style @@ -687,10 +687,7 @@ def add_field(self: E, *, name: Any, value: Any, inline: bool = True) -> E: field = EmbedField(name=str(name), value=str(value), inline=inline) - try: - self._fields.append(field) - except AttributeError: - self._fields = [field] + self._fields.append(field) return self @@ -716,10 +713,7 @@ def insert_field_at(self: E, index: int, *, name: Any, value: Any, inline: bool field = EmbedField(name=str(name), value=str(value), inline=inline) - try: - self._fields.insert(index, field) - except AttributeError: - self._fields = [field] + self._fields.insert(index, field) return self @@ -748,7 +742,7 @@ def remove_field(self, index: int) -> None: """ try: del self._fields[index] - except (AttributeError, IndexError): + except IndexError: pass def set_field_at(self: E, index: int, *, name: Any, value: Any, inline: bool = True) -> E: @@ -778,7 +772,7 @@ def set_field_at(self: E, index: int, *, name: Any, value: Any, inline: bool = T try: field = self._fields[index] - except (TypeError, IndexError, AttributeError): + except (TypeError, IndexError): raise IndexError("field index out of range") field.name = str(name) From b508b46c2d5a7800bdf234bb519a1be097f675e0 Mon Sep 17 00:00:00 2001 From: Krittick Date: Sat, 9 Apr 2022 15:21:16 -0700 Subject: [PATCH 07/19] fix init loop --- discord/embeds.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/discord/embeds.py b/discord/embeds.py index ecde036232..92031b1f39 100644 --- a/discord/embeds.py +++ b/discord/embeds.py @@ -246,9 +246,6 @@ def __init__( if timestamp: self.timestamp = timestamp self._fields: List[EmbedField] = fields or [] - if self._fields: - for field in self._fields: - self.add_field(name=field.name, value=field.value, inline=field.inline) @classmethod def from_dict(cls: Type[E], data: Mapping[str, Any]) -> E: From aadebba5326670645d18a4c2198c7db2e15a6c6a Mon Sep 17 00:00:00 2001 From: Krittick Date: Sat, 9 Apr 2022 15:57:51 -0700 Subject: [PATCH 08/19] fix to_dict for _fields attr --- discord/embeds.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/discord/embeds.py b/discord/embeds.py index 92031b1f39..db3074250b 100644 --- a/discord/embeds.py +++ b/discord/embeds.py @@ -319,7 +319,7 @@ def copy(self: E) -> E: def __len__(self) -> int: total = len(self.title) + len(self.description) for field in getattr(self, "_fields", []): - total += len(field["name"]) + len(field["value"]) + total += len(field.name) + len(field.value) try: footer_text = self._footer["text"] @@ -781,7 +781,14 @@ def to_dict(self) -> EmbedData: """Converts this embed object into a dict.""" # add in the raw data into the dict - result = {key[1:]: getattr(self, key) for key in self.__slots__ if key[0] == "_" and hasattr(self, key)} + result = { + key[1:]: getattr(self, key) + for key in self.__slots__ + if key[0] == "_" and key != "_fields" and hasattr(self, key) + } + + # add in the fields + result["fields"] = [field.to_dict() for field in self._fields] # deal with basic convenience wrappers From b4081a6491e769f9fd3516b347266a8047764b20 Mon Sep 17 00:00:00 2001 From: Krittick Date: Sat, 9 Apr 2022 16:03:31 -0700 Subject: [PATCH 09/19] remove now-unused _EmbedFieldProxy class --- discord/embeds.py | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/discord/embeds.py b/discord/embeds.py index db3074250b..abfafef6c2 100644 --- a/discord/embeds.py +++ b/discord/embeds.py @@ -91,11 +91,6 @@ class _EmbedFooterProxy(Protocol): text: MaybeEmpty[str] icon_url: MaybeEmpty[str] - class _EmbedFieldProxy(Protocol): - name: MaybeEmpty[str] - value: MaybeEmpty[str] - inline: bool - class _EmbedMediaProxy(Protocol): url: MaybeEmpty[str] proxy_url: MaybeEmpty[str] @@ -784,7 +779,7 @@ def to_dict(self) -> EmbedData: result = { key[1:]: getattr(self, key) for key in self.__slots__ - if key[0] == "_" and key != "_fields" and hasattr(self, key) + if key != "_fields" and key[0] == "_" and hasattr(self, key) } # add in the fields @@ -811,7 +806,7 @@ def to_dict(self) -> EmbedData: else: result["timestamp"] = timestamp.replace(tzinfo=datetime.timezone.utc).isoformat() - # add in the non raw attribute ones + # add in the non-raw attribute ones if self.type: result["type"] = self.type From 571a650de55f1ce3b41cff2c969a5ce8f329aafe Mon Sep 17 00:00:00 2001 From: Krittick Date: Sat, 9 Apr 2022 16:22:49 -0700 Subject: [PATCH 10/19] add from_dict classmethod to EmbedField for better handling with Embed.from_dict --- discord/embeds.py | 33 ++++++++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/discord/embeds.py b/discord/embeds.py index abfafef6c2..2de4cd18c8 100644 --- a/discord/embeds.py +++ b/discord/embeds.py @@ -131,6 +131,24 @@ def __init__(self, name: str, value: str, inline: Optional[bool] = False): self.value = value self.inline = inline + @classmethod + def from_dict(cls: Type[E], data: Mapping[str, Any]) -> E: + """Converts a :class:`dict` to a :class:`EmbedField` provided it is in the + format that Discord expects it to be in. + + You can find out about this format in the `official Discord documentation`__. + + .. _DiscordDocs: https://discord.com/developers/docs/resources/channel#embed-object-embed-field-structure + + __ DiscordDocs_ + + Parameters + ----------- + data: :class:`dict` + The dictionary to convert into an EmbedField object. + """ + return cls(name=data["name"], value=data["value"], inline=data.get("inline", False)) + def to_dict(self) -> Dict[str, Union[str, bool]]: return { "name": self.name, @@ -298,12 +316,17 @@ def from_dict(cls: Type[E], data: Mapping[str, Any]) -> E: "image", "footer", ): - try: - value = data[attr] - except KeyError: - continue + if attr == "fields": + value = data.get(attr, []) + if value: + self._fields = [EmbedField.from_dict(d) for d in value] else: - setattr(self, f"_{attr}", value) + try: + value = data[attr] + except KeyError: + continue + else: + setattr(self, f"_{attr}", value) return self From 50d3e352bf975a0957460838893b724b08578ca5 Mon Sep 17 00:00:00 2001 From: Krittick Date: Sat, 9 Apr 2022 16:28:27 -0700 Subject: [PATCH 11/19] update EmbedField.from_dict to more closely match the behavior of Embed.from_dict --- discord/embeds.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/discord/embeds.py b/discord/embeds.py index 2de4cd18c8..151e1bd259 100644 --- a/discord/embeds.py +++ b/discord/embeds.py @@ -147,7 +147,13 @@ def from_dict(cls: Type[E], data: Mapping[str, Any]) -> E: data: :class:`dict` The dictionary to convert into an EmbedField object. """ - return cls(name=data["name"], value=data["value"], inline=data.get("inline", False)) + self: E = cls.__new__(cls) + + self.name = data["name"] + self.value = data["value"] + self.inline = data.get("inline", False) + + return self def to_dict(self) -> Dict[str, Union[str, bool]]: return { @@ -180,7 +186,7 @@ class Embed: :attr:`Embed.Empty`. For ease of use, all parameters that expect a :class:`str` are implicitly - casted to :class:`str` for you. + cast to :class:`str` for you. Attributes ----------- From c1c0d188a51d71d220c5a4b737bea26a35af6557 Mon Sep 17 00:00:00 2001 From: Krittick Date: Sat, 9 Apr 2022 16:36:25 -0700 Subject: [PATCH 12/19] add Embed.append_field option to allow directly adding EmbedField objects without breaking Embed.add_field (similar to Select.append_option) --- discord/embeds.py | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/discord/embeds.py b/discord/embeds.py index 151e1bd259..993728d41b 100644 --- a/discord/embeds.py +++ b/discord/embeds.py @@ -690,6 +690,19 @@ def fields(self, value: List[EmbedField]) -> None: for field in value: self.add_field(name=field.name, value=field.value, inline=field.inline) + def append_field(self, field: EmbedField) -> None: + """Appends an :class:`EmbedField` object to the embed. + + Parameters + ---------- + field: :class:`EmbedField` + The field to add. + """ + if not isinstance(field, EmbedField): + raise TypeError("Expected an EmbedField object.") + + self._fields.append(field) + def add_field(self: E, *, name: str, value: str, inline: bool = True) -> E: """Adds a field to the embed object. @@ -705,10 +718,7 @@ def add_field(self: E, *, name: str, value: str, inline: bool = True) -> E: inline: :class:`bool` Whether the field should be displayed inline. """ - - field = EmbedField(name=str(name), value=str(value), inline=inline) - - self._fields.append(field) + self._fields.append(EmbedField(name=str(name), value=str(value), inline=inline)) return self From 068c86d064d1d9010a5f8d9e05229d248862a147 Mon Sep 17 00:00:00 2001 From: Krittick Date: Sat, 9 Apr 2022 16:37:20 -0700 Subject: [PATCH 13/19] add EmbedField to docs --- docs/api.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/api.rst b/docs/api.rst index adbfcd1026..d1a7d4b067 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -4673,6 +4673,14 @@ Embed .. autoclass:: Embed :members: +EmbedField +~~~~~~~~~~ + +.. attributetable:: EmbedField + +.. autoclass:: EmbedField + :members: + AllowedMentions ~~~~~~~~~~~~~~~~~ From dacdfe0dbae9dad8a9a75d47780894d5f53c206e Mon Sep 17 00:00:00 2001 From: Krittick Date: Sat, 9 Apr 2022 16:42:07 -0700 Subject: [PATCH 14/19] doc fix --- discord/embeds.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/discord/embeds.py b/discord/embeds.py index 993728d41b..02efafd9b1 100644 --- a/discord/embeds.py +++ b/discord/embeds.py @@ -138,9 +138,9 @@ def from_dict(cls: Type[E], data: Mapping[str, Any]) -> E: You can find out about this format in the `official Discord documentation`__. - .. _DiscordDocs: https://discord.com/developers/docs/resources/channel#embed-object-embed-field-structure + .. _DiscordDocsEF: https://discord.com/developers/docs/resources/channel#embed-object-embed-field-structure - __ DiscordDocs_ + __ DiscordDocsEF_ Parameters ----------- From fb9a7018aa0035c9be447c95f73e57bfd20fe4ac Mon Sep 17 00:00:00 2001 From: Krittick Date: Sat, 9 Apr 2022 16:46:40 -0700 Subject: [PATCH 15/19] add docstring for EmbedField.to_dict --- discord/embeds.py | 1 + 1 file changed, 1 insertion(+) diff --git a/discord/embeds.py b/discord/embeds.py index 02efafd9b1..477f827ac5 100644 --- a/discord/embeds.py +++ b/discord/embeds.py @@ -156,6 +156,7 @@ def from_dict(cls: Type[E], data: Mapping[str, Any]) -> E: return self def to_dict(self) -> Dict[str, Union[str, bool]]: + """Converts this EmbedField object into a dict.""" return { "name": self.name, "value": self.value, From 0c097cf3b175cf75f4360b1faf19154def4ed779 Mon Sep 17 00:00:00 2001 From: Krittick Date: Tue, 12 Apr 2022 01:10:30 -0700 Subject: [PATCH 16/19] fix for embeds with no initial fields --- discord/embeds.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/discord/embeds.py b/discord/embeds.py index 477f827ac5..d03dcda41c 100644 --- a/discord/embeds.py +++ b/discord/embeds.py @@ -823,7 +823,7 @@ def to_dict(self) -> EmbedData: } # add in the fields - result["fields"] = [field.to_dict() for field in self._fields] + result["fields"] = [field.to_dict() for field in self._fields if self._fields] # deal with basic convenience wrappers From 870d82bf8d8faa3dd97de096f2aee0f76ccc9c27 Mon Sep 17 00:00:00 2001 From: Krittick Date: Tue, 12 Apr 2022 01:11:07 -0700 Subject: [PATCH 17/19] revert --- discord/embeds.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/discord/embeds.py b/discord/embeds.py index d03dcda41c..477f827ac5 100644 --- a/discord/embeds.py +++ b/discord/embeds.py @@ -823,7 +823,7 @@ def to_dict(self) -> EmbedData: } # add in the fields - result["fields"] = [field.to_dict() for field in self._fields if self._fields] + result["fields"] = [field.to_dict() for field in self._fields] # deal with basic convenience wrappers From 1e536370978d4094367e1271a5e22d2988a4ba1c Mon Sep 17 00:00:00 2001 From: Krittick Date: Tue, 12 Apr 2022 01:27:57 -0700 Subject: [PATCH 18/19] fix for copying embeds with no fields --- discord/embeds.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/discord/embeds.py b/discord/embeds.py index 477f827ac5..a066edc36a 100644 --- a/discord/embeds.py +++ b/discord/embeds.py @@ -325,8 +325,7 @@ def from_dict(cls: Type[E], data: Mapping[str, Any]) -> E: ): if attr == "fields": value = data.get(attr, []) - if value: - self._fields = [EmbedField.from_dict(d) for d in value] + self._fields = [EmbedField.from_dict(d) for d in value] if value else [] else: try: value = data[attr] From 6c113fd5a3d15cede29c9df5ef86ccd5d6e9e271 Mon Sep 17 00:00:00 2001 From: Krittick Date: Sun, 17 Apr 2022 14:56:29 -0700 Subject: [PATCH 19/19] add versionadded to docstrings --- discord/embeds.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/discord/embeds.py b/discord/embeds.py index a066edc36a..c41a7b51c2 100644 --- a/discord/embeds.py +++ b/discord/embeds.py @@ -116,6 +116,8 @@ class _EmbedAuthorProxy(Protocol): class EmbedField: """Represents a field on the :class:`Embed` object. + .. versionadded:: 2.0 + Attributes ---------- name: :class:`str` @@ -693,6 +695,8 @@ def fields(self, value: List[EmbedField]) -> None: def append_field(self, field: EmbedField) -> None: """Appends an :class:`EmbedField` object to the embed. + .. versionadded:: 2.0 + Parameters ---------- field: :class:`EmbedField`