diff --git a/src/mwparserfromhell/nodes/tag.py b/src/mwparserfromhell/nodes/tag.py index 027b09c..bf4ad40 100644 --- a/src/mwparserfromhell/nodes/tag.py +++ b/src/mwparserfromhell/nodes/tag.py @@ -19,11 +19,16 @@ # SOFTWARE. +from typing import TYPE_CHECKING, Any, Callable, Optional, List, Generator + from ._base import Node from .extras import Attribute from ..definitions import is_visible from ..utils import parse_anything +if TYPE_CHECKING: + from ..wikicode import Wikicode + __all__ = ["Tag"] @@ -32,19 +37,22 @@ class Tag(Node): def __init__( self, - tag, - contents=None, - attrs=None, - wiki_markup=None, - self_closing=False, - invalid=False, - implicit=False, - padding="", - closing_tag=None, - wiki_style_separator=None, - closing_wiki_markup=None, + tag: Any, + contents: Any = None, + attrs: Optional[List[Attribute]] = None, + wiki_markup: Optional[str] = None, + self_closing: bool = False, + invalid: bool = False, + implicit: bool = False, + padding: str = "", + closing_tag: Optional["Wikicode"] = None, + wiki_style_separator: Optional[str] = None, + closing_wiki_markup: Optional[str] = None, ): super().__init__() + self._attrs: List[Attribute] + self._closing_wiki_markup: Optional[str] + self.tag = tag self.contents = contents self._attrs = attrs if attrs else [] @@ -60,7 +68,7 @@ class Tag(Node): if closing_wiki_markup is not None: self.closing_wiki_markup = closing_wiki_markup - def __str__(self): + def __str__(self) -> str: if self.wiki_markup: if self.attributes: attrs = "".join([str(attr) for attr in self.attributes]) @@ -90,7 +98,7 @@ class Tag(Node): result += "" return result - def __children__(self): + def __children__(self) -> Generator["Wikicode"]: if not self.wiki_markup: yield self.tag for attr in self.attributes: @@ -102,12 +110,17 @@ class Tag(Node): if not self.wiki_markup and self.closing_tag: yield self.closing_tag - def __strip__(self, **kwargs): - if self.contents and is_visible(self.tag): + def __strip__(self, **kwargs: Any) -> Optional[str]: + if self.contents and is_visible(str(self.tag)): return self.contents.strip_code(**kwargs) return None - def __showtree__(self, write, get, mark): + def __showtree__( + self, + write: Callable[[str], None], + get: Callable[["Wikicode"], None], + mark: Callable[[], None], + ) -> None: write("") @property - def tag(self): + def tag(self) -> "Wikicode": """The tag itself, as a :class:`.Wikicode` object.""" return self._tag + @tag.setter + def tag(self, value: Any) -> None: + self._tag = self._closing_tag = parse_anything(value) + @property - def contents(self): + def contents(self) -> "Wikicode": """The contents of the tag, as a :class:`.Wikicode` object.""" return self._contents + @contents.setter + def contents(self, value: Any) -> None: + self._contents = parse_anything(value) + @property - def attributes(self): + def attributes(self) -> List[Attribute]: """The list of attributes affecting the tag. Each attribute is an instance of :class:`.Attribute`. @@ -145,7 +166,7 @@ class Tag(Node): return self._attrs @property - def wiki_markup(self): + def wiki_markup(self) -> Optional[str]: """The wikified version of a tag to show instead of HTML. If set to a value, this will be displayed instead of the brackets. @@ -154,13 +175,23 @@ class Tag(Node): """ return self._wiki_markup + @wiki_markup.setter + def wiki_markup(self, value: Optional[str]) -> None: + self._wiki_markup = str(value) if value else None + if not value or not self.closing_wiki_markup: + self._closing_wiki_markup = self._wiki_markup + @property - def self_closing(self): + def self_closing(self) -> bool: """Whether the tag is self-closing with no content (like ``
``).""" return self._self_closing + @self_closing.setter + def self_closing(self, value: bool) -> None: + self._self_closing = bool(value) + @property - def invalid(self): + def invalid(self) -> bool: """Whether the tag starts with a backslash after the opening bracket. This makes the tag look like a lone close tag. It is technically @@ -170,8 +201,12 @@ class Tag(Node): """ return self._invalid + @invalid.setter + def invalid(self, value: bool) -> None: + self._invalid = bool(value) + @property - def implicit(self): + def implicit(self) -> bool: """Whether the tag is implicitly self-closing, with no ending slash. This is only possible for specific "single" tags like ``
`` and @@ -180,13 +215,27 @@ class Tag(Node): """ return self._implicit + @implicit.setter + def implicit(self, value: bool) -> None: + self._implicit = bool(value) + @property - def padding(self): + def padding(self) -> str: """Spacing to insert before the first closing ``>``.""" return self._padding + @padding.setter + def padding(self, value: str) -> None: + if not value: + self._padding = "" + else: + value = str(value) + if not value.isspace(): + raise ValueError("padding must be entirely whitespace") + self._padding = value + @property - def closing_tag(self): + def closing_tag(self) -> "Wikicode": """The closing tag, as a :class:`.Wikicode` object. This will usually equal :attr:`tag`, unless there is additional @@ -194,76 +243,40 @@ class Tag(Node): """ return self._closing_tag + @closing_tag.setter + def closing_tag(self, value: Any) -> None: + self._closing_tag = parse_anything(value) + @property - def wiki_style_separator(self): + def wiki_style_separator(self) -> Optional[str]: """The separator between the padding and content in a wiki markup tag. Essentially the wiki equivalent of the TagCloseOpen. """ return self._wiki_style_separator + @wiki_style_separator.setter + def wiki_style_separator(self, value: Optional[str]) -> None: + self._wiki_style_separator = str(value) if value else None + @property - def closing_wiki_markup(self): + def closing_wiki_markup(self) -> Optional[str]: """The wikified version of the closing tag to show instead of HTML. If set to a value, this will be displayed instead of the close tag - brackets. If tag is :attr:`self_closing` is ``True`` then this is not - displayed. If :attr:`wiki_markup` is set and this has not been set, this - is set to the value of :attr:`wiki_markup`. If this has been set and + brackets. If the tag is :attr:`self_closing`, this is not displayed. + If :attr:`wiki_markup` is set and this has not been set, this is set + to the value of :attr:`wiki_markup`. If this has been set and :attr:`wiki_markup` is set to a ``False`` value, this is set to ``None``. """ return self._closing_wiki_markup - @tag.setter - def tag(self, value): - self._tag = self._closing_tag = parse_anything(value) - - @contents.setter - def contents(self, value): - self._contents = parse_anything(value) - - @wiki_markup.setter - def wiki_markup(self, value): - self._wiki_markup = str(value) if value else None - if not value or not self.closing_wiki_markup: - self._closing_wiki_markup = self._wiki_markup - - @self_closing.setter - def self_closing(self, value): - self._self_closing = bool(value) - - @invalid.setter - def invalid(self, value): - self._invalid = bool(value) - - @implicit.setter - def implicit(self, value): - self._implicit = bool(value) - - @padding.setter - def padding(self, value): - if not value: - self._padding = "" - else: - value = str(value) - if not value.isspace(): - raise ValueError("padding must be entirely whitespace") - self._padding = value - - @closing_tag.setter - def closing_tag(self, value): - self._closing_tag = parse_anything(value) - - @wiki_style_separator.setter - def wiki_style_separator(self, value): - self._wiki_style_separator = str(value) if value else None - @closing_wiki_markup.setter - def closing_wiki_markup(self, value): + def closing_wiki_markup(self, value: Optional[str]) -> None: self._closing_wiki_markup = str(value) if value else None - def has(self, name): + def has(self, name: str) -> bool: """Return whether any attribute in the tag has the given *name*. Note that a tag may have multiple attributes with the same name, but @@ -274,7 +287,7 @@ class Tag(Node): return True return False - def get(self, name): + def get(self, name: str) -> Attribute: """Get the attribute with the given *name*. The returned object is a :class:`.Attribute` instance. Raises @@ -289,13 +302,13 @@ class Tag(Node): def add( self, - name, - value=None, - quotes='"', - pad_first=" ", - pad_before_eq="", - pad_after_eq="", - ): + name: Any, + value: Any = None, + quotes: Optional[str] = '"', + pad_first: str = " ", + pad_before_eq: str = "", + pad_after_eq: str = "", + ) -> Attribute: """Add an attribute with the given *name* and *value*. *name* and *value* can be anything parsable by @@ -318,7 +331,7 @@ class Tag(Node): self.attributes.append(attr) return attr - def remove(self, name): + def remove(self, name: str) -> None: """Remove all attributes with the given *name*. Raises :exc:`ValueError` if none were found.