Handle ruff complaints in string module

This commit is contained in:
Dominik Jain 2023-10-03 20:59:06 +02:00
parent de70147752
commit ce26e25923
2 changed files with 128 additions and 110 deletions

View File

@ -125,6 +125,8 @@ ignore = [
"B011", # assert false. we don't use python -O "B011", # assert false. we don't use python -O
"B028", # we don't need explicit stacklevel for warnings "B028", # we don't need explicit stacklevel for warnings
"D100", "D101", "D102", "D104", "D105", "D107", "D203", "D213", "D401", "D402", "D106", "D205", # docstring stuff "D100", "D101", "D102", "D104", "D105", "D107", "D203", "D213", "D401", "D402", "D106", "D205", # docstring stuff
"G004", # logging (no f-strings)
"RUF012", # disallows mutable class variables unless annotated
"DTZ005", # we don't need that "DTZ005", # we don't need that
"RET505", # sacrifices visual discernability of control flow paths for brevity (regarding return statements) "RET505", # sacrifices visual discernability of control flow paths for brevity (regarding return statements)
# remaining rules from https://github.com/psf/black/blob/main/.flake8 (except W503) # remaining rules from https://github.com/psf/black/blob/main/.flake8 (except W503)

View File

@ -1,6 +1,4 @@
""" """Copy of sensai.util.string from sensAI commit d7b4afcc89b4d2e922a816cb07dffde27f297354."""
This is a copy of sensai.util.string from sensAI commit d7b4afcc89b4d2e922a816cb07dffde27f297354
"""
import functools import functools
@ -9,7 +7,10 @@ import re
import sys import sys
import types import types
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
from typing import Union, List, Dict, Any, Sequence, Iterable, Optional, Mapping, Callable from collections.abc import Callable, Iterable, Mapping, Sequence
from typing import (
Any,
)
reCommaWhitespacePotentiallyBreaks = re.compile(r",\s+") reCommaWhitespacePotentiallyBreaks = re.compile(r",\s+")
@ -17,18 +18,16 @@ log = logging.getLogger(__name__)
class StringConverter(ABC): class StringConverter(ABC):
""" """Abstraction for a string conversion mechanism."""
Abstraction for a string conversion mechanism
"""
@abstractmethod @abstractmethod
def to_string(self, x) -> str: def to_string(self, x) -> str:
pass pass
def dict_string(d: Mapping, brackets: Optional[str] = None, converter: StringConverter = None): def dict_string(d: Mapping, brackets: str | None = None, converter: StringConverter = None):
""" """Converts a dictionary to a string of the form "<key>=<value>, <key>=<value>, ...", optionally enclosed
Converts a dictionary to a string of the form "<key>=<value>, <key>=<value>, ...", optionally enclosed by brackets.
by brackets
:param d: the dictionary :param d: the dictionary
:param brackets: a two-character string containing the opening and closing bracket to use, e.g. ``"{}"``; :param brackets: a two-character string containing the opening and closing bracket to use, e.g. ``"{}"``;
@ -36,16 +35,20 @@ def dict_string(d: Mapping, brackets: Optional[str] = None, converter: StringCon
:param converter: the string converter to use for values :param converter: the string converter to use for values
:return: the string representation :return: the string representation
""" """
s = ', '.join([f'{k}={to_string(v, converter=converter, context=k)}' for k, v in d.items()]) s = ", ".join([f"{k}={to_string(v, converter=converter, context=k)}" for k, v in d.items()])
if brackets is not None: if brackets is not None:
return brackets[:1] + s + brackets[-1:] return brackets[:1] + s + brackets[-1:]
else: else:
return s return s
def list_string(l: Iterable[Any], brackets="[]", quote: Optional[str] = None, converter: StringConverter = None): def list_string(
""" l: Iterable[Any],
Converts a list or any other iterable to a string of the form "[<value>, <value>, ...]", optionally enclosed brackets="[]",
quote: str | None = None,
converter: StringConverter = None,
):
"""Converts a list or any other iterable to a string of the form "[<value>, <value>, ...]", optionally enclosed
by different brackets or with the values quoted. by different brackets or with the values quoted.
:param l: the list :param l: the list
@ -55,22 +58,28 @@ def list_string(l: Iterable[Any], brackets="[]", quote: Optional[str] = None, co
:param converter: the string converter to use for values :param converter: the string converter to use for values
:return: the string representation :return: the string representation
""" """
def item(x): def item(x):
x = to_string(x, converter=converter, context="list") x = to_string(x, converter=converter, context="list")
if quote is not None: if quote is not None:
return quote + x + quote return quote + x + quote
else: else:
return x return x
s = ", ".join((item(x) for x in l))
s = ", ".join(item(x) for x in l)
if brackets is not None: if brackets is not None:
return brackets[:1] + s + brackets[-1:] return brackets[:1] + s + brackets[-1:]
else: else:
return s return s
def to_string(x, converter: StringConverter = None, apply_converter_to_non_complex_objects=True, context=None): def to_string(
""" x,
Converts the given object to a string, with proper handling of lists, tuples and dictionaries, optionally using a converter. converter: StringConverter = None,
apply_converter_to_non_complex_objects=True,
context=None,
):
"""Converts the given object to a string, with proper handling of lists, tuples and dictionaries, optionally using a converter.
The conversion also removes unwanted line breaks (as present, in particular, in sklearn's string representations). The conversion also removes unwanted line breaks (as present, in particular, in sklearn's string representations).
:param x: the object to convert :param x: the object to convert
@ -83,13 +92,13 @@ def to_string(x, converter: StringConverter = None, apply_converter_to_non_compl
:return: the string representation :return: the string representation
""" """
try: try:
if type(x) == list: if isinstance(x, list):
return list_string(x, converter=converter) return list_string(x, converter=converter)
elif type(x) == tuple: elif isinstance(x, tuple):
return list_string(x, brackets="()", converter=converter) return list_string(x, brackets="()", converter=converter)
elif type(x) == dict: elif isinstance(x, dict):
return dict_string(x, brackets="{}", converter=converter) return dict_string(x, brackets="{}", converter=converter)
elif type(x) == types.MethodType: elif isinstance(x, types.MethodType):
# could be bound method of a ToStringMixin instance (which would print the repr of the instance, which can potentially cause # could be bound method of a ToStringMixin instance (which would print the repr of the instance, which can potentially cause
# an infinite recursion) # an infinite recursion)
return f"Method[{x.__name__}]" return f"Method[{x.__name__}]"
@ -100,16 +109,19 @@ def to_string(x, converter: StringConverter = None, apply_converter_to_non_compl
s = str(x) s = str(x)
# remove any unwanted line breaks and indentation after commas (as generated, for example, by sklearn objects) # remove any unwanted line breaks and indentation after commas (as generated, for example, by sklearn objects)
s = reCommaWhitespacePotentiallyBreaks.sub(", ", s) return reCommaWhitespacePotentiallyBreaks.sub(", ", s)
return s except RecursionError:
except RecursionError as e:
log.error(f"Recursion in string conversion detected; context={context}") log.error(f"Recursion in string conversion detected; context={context}")
raise raise
def object_repr(obj, member_names_or_dict: Union[List[str], Dict[str, Any]]): def object_repr(obj, member_names_or_dict: list[str] | dict[str, Any]):
if type(member_names_or_dict) == dict: """Creates a string representation for the given object based on the given members.
The string takes the form "ClassName[attr1=value1, attr2=value2, ...]"
"""
if isinstance(member_names_or_dict, dict):
members_dict = member_names_or_dict members_dict = member_names_or_dict
else: else:
members_dict = {m: to_string(getattr(obj, m)) for m in member_names_or_dict} members_dict = {m: to_string(getattr(obj, m)) for m in member_names_or_dict}
@ -117,9 +129,7 @@ def object_repr(obj, member_names_or_dict: Union[List[str], Dict[str, Any]]):
def or_regex_group(allowed_names: Sequence[str]): def or_regex_group(allowed_names: Sequence[str]):
""" """:param allowed_names: strings to include as literals in the regex
:param allowed_names: strings to include as literals in the regex
:return: a regular expression string of the form (<name1>| ...|<nameN>), which any of the given names :return: a regular expression string of the form (<name1>| ...|<nameN>), which any of the given names
""" """
allowed_names = [re.escape(name) for name in allowed_names] allowed_names = [re.escape(name) for name in allowed_names]
@ -127,6 +137,12 @@ def or_regex_group(allowed_names: Sequence[str]):
def function_name(x: Callable) -> str: def function_name(x: Callable) -> str:
"""Attempts to retrieve the name of the given function/callable object, taking the possibility
of the function being defined via functools.partial into account.
:param x: a callable object
:return: name of the function or str(x) as a fallback
"""
if isinstance(x, functools.partial): if isinstance(x, functools.partial):
return function_name(x.func) return function_name(x.func)
elif hasattr(x, "__name__"): elif hasattr(x, "__name__"):
@ -136,8 +152,7 @@ def function_name(x: Callable) -> str:
class ToStringMixin: class ToStringMixin:
""" """Provides implementations for ``__str__`` and ``__repr__`` which are based on the format ``"<class name>[<object info>]"`` and
Provides implementations for ``__str__`` and ``__repr__`` which are based on the format ``"<class name>[<object info>]"`` and
``"<class name>[id=<object id>, <object info>]"`` respectively, where ``<object info>`` is usually a list of entries of the ``"<class name>[id=<object id>, <object info>]"`` respectively, where ``<object info>`` is usually a list of entries of the
form ``"<name>=<value>, ..."``. form ``"<name>=<value>, ..."``.
@ -174,23 +189,23 @@ class ToStringMixin:
.. automethod:: _tostring_additional_entries .. automethod:: _tostring_additional_entries
.. automethod:: _tostring_exclude_private .. automethod:: _tostring_exclude_private
""" """
_TOSTRING_INCLUDE_ALL = "__all__" _TOSTRING_INCLUDE_ALL = "__all__"
def _tostring_class_name(self): def _tostring_class_name(self):
""" """:return: the string use for <class name> in the string representation ``"<class name>[<object info]"``"""
:return: the string use for <class name> in the string representation ``"<class name>[<object info]"``
"""
return type(self).__qualname__ return type(self).__qualname__
def _tostring_properties(self, def _tostring_properties(
exclude: Optional[Union[str, Iterable[str]]] = None, self,
include: Optional[Union[str, Iterable[str]]] = None, exclude: str | Iterable[str] | None = None,
exclude_exceptions: Optional[List[str]] = None, include: str | Iterable[str] | None = None,
include_forced: Optional[List[str]] = None, exclude_exceptions: list[str] | None = None,
additional_entries: Dict[str, Any] = None, include_forced: list[str] | None = None,
converter: StringConverter = None) -> str: additional_entries: dict[str, Any] | None = None,
""" converter: StringConverter = None,
Creates a string of the class attributes, with optional exclusions/inclusions/additions. ) -> str:
"""Creates a string of the class attributes, with optional exclusions/inclusions/additions.
Exclusions take precedence over inclusions. Exclusions take precedence over inclusions.
:param exclude: attributes to be excluded :param exclude: attributes to be excluded
@ -201,10 +216,11 @@ class ToStringMixin:
:param converter: the string converter to use; if None, use default (which avoids infinite recursions) :param converter: the string converter to use; if None, use default (which avoids infinite recursions)
:return: a string containing entry/property names and values :return: a string containing entry/property names and values
""" """
def mklist(x): def mklist(x):
if x is None: if x is None:
return [] return []
if type(x) == str: if isinstance(x, str):
return [x] return [x]
return x return x
@ -219,17 +235,21 @@ class ToStringMixin:
if k in exclude: if k in exclude:
return True return True
if self._tostring_exclude_private(): if self._tostring_exclude_private():
is_private = k.startswith("_") return k.startswith("_")
return is_private
else: else:
return False return False
# determine relevant attribute dictionary # determine relevant attribute dictionary
if len(include) == 1 and include[0] == self._TOSTRING_INCLUDE_ALL: # exclude semantics (include everything by default) if (
len(include) == 1 and include[0] == self._TOSTRING_INCLUDE_ALL
): # exclude semantics (include everything by default)
attribute_dict = self.__dict__ attribute_dict = self.__dict__
else: # include semantics (include only inclusions) else: # include semantics (include only inclusions)
attribute_dict = {k: getattr(self, k) for k in set(include + include_forced) attribute_dict = {
if hasattr(self, k) and k != self._TOSTRING_INCLUDE_ALL} k: getattr(self, k)
for k in set(include + include_forced)
if hasattr(self, k) and k != self._TOSTRING_INCLUDE_ALL
}
# apply exclusions and remove underscores from attribute names # apply exclusions and remove underscores from attribute names
d = {k.strip("_"): v for k, v in attribute_dict.items() if not is_excluded(k)} d = {k.strip("_"): v for k, v in attribute_dict.items() if not is_excluded(k)}
@ -242,8 +262,7 @@ class ToStringMixin:
return dict_string(d, converter=converter) return dict_string(d, converter=converter)
def _tostring_object_info(self) -> str: def _tostring_object_info(self) -> str:
""" """Override this method to use a fully custom definition of the ``<object info>`` part in the full string
Override this method to use a fully custom definition of the ``<object info>`` part in the full string
representation ``"<class name>[<object info>]"`` to be generated. representation ``"<class name>[<object info>]"`` to be generated.
As soon as this method is overridden, any property-based exclusions, inclusions, etc. will have no effect As soon as this method is overridden, any property-based exclusions, inclusions, etc. will have no effect
(unless the implementation is specifically designed to make use of them - as is the default (unless the implementation is specifically designed to make use of them - as is the default
@ -253,13 +272,16 @@ class ToStringMixin:
:return: a string containing the string to use for ``<object info>`` :return: a string containing the string to use for ``<object info>``
""" """
return self._tostring_properties(exclude=self._tostring_excludes(), include=self._tostring_includes(), return self._tostring_properties(
exclude_exceptions=self._tostring_exclude_exceptions(), include_forced=self._tostring_includes_forced(), exclude=self._tostring_excludes(),
additional_entries=self._tostring_additional_entries()) include=self._tostring_includes(),
exclude_exceptions=self._tostring_exclude_exceptions(),
include_forced=self._tostring_includes_forced(),
additional_entries=self._tostring_additional_entries(),
)
def _tostring_excludes(self) -> List[str]: def _tostring_excludes(self) -> list[str]:
""" """Makes the string representation exclude the returned attributes.
Makes the string representation exclude the returned attributes.
This method can be conveniently overridden by subclasses which can call super and extend the list returned. This method can be conveniently overridden by subclasses which can call super and extend the list returned.
This method will only have no effect if :meth:`_toStringObjectInfo` is overridden to not use its result. This method will only have no effect if :meth:`_toStringObjectInfo` is overridden to not use its result.
@ -268,9 +290,8 @@ class ToStringMixin:
""" """
return [] return []
def _tostring_includes(self) -> List[str]: def _tostring_includes(self) -> list[str]:
""" """Makes the string representation include only the returned attributes (i.e. introduces inclusion semantics);
Makes the string representation include only the returned attributes (i.e. introduces inclusion semantics);
By default, the list contains only a marker element, which is interpreted as "all attributes included". By default, the list contains only a marker element, which is interpreted as "all attributes included".
This method can be conveniently overridden by sub-classes which can call super and extend the list returned. This method can be conveniently overridden by sub-classes which can call super and extend the list returned.
@ -287,9 +308,8 @@ class ToStringMixin:
return [self._TOSTRING_INCLUDE_ALL] return [self._TOSTRING_INCLUDE_ALL]
# noinspection PyMethodMayBeStatic # noinspection PyMethodMayBeStatic
def _tostring_includes_forced(self) -> List[str]: def _tostring_includes_forced(self) -> list[str]:
""" """Defines a list of attribute names that are required to be present in the string representation, regardless of the
Defines a list of attribute names that are required to be present in the string representation, regardless of the
instance using include semantics or exclude semantics, thus facilitating added inclusions in sub-classes. instance using include semantics or exclude semantics, thus facilitating added inclusions in sub-classes.
This method will have no effect if :meth:`_toStringObjectInfo` is overridden to not use its result. This method will have no effect if :meth:`_toStringObjectInfo` is overridden to not use its result.
@ -298,22 +318,18 @@ class ToStringMixin:
""" """
return [] return []
def _tostring_additional_entries(self) -> Dict[str, Any]: def _tostring_additional_entries(self) -> dict[str, Any]:
""" """:return: a dictionary of entries to be included in the ``<object info>`` part of the string representation"""
:return: a dictionary of entries to be included in the ``<object info>`` part of the string representation
"""
return {} return {}
def _tostring_exclude_private(self) -> bool: def _tostring_exclude_private(self) -> bool:
""" """:return: whether to exclude properties that are private (start with an underscore); explicitly included attributes
:return: whether to exclude properties that are private (start with an underscore); explicitly included attributes will still be considered - as will properties exempt from the rule via :meth:`toStringExcludeException`.
will still be considered - as will properties exempt from the rule via :meth:`toStringExcludeException`.
""" """
return False return False
def _tostring_exclude_exceptions(self) -> List[str]: def _tostring_exclude_exceptions(self) -> list[str]:
""" """Defines attribute names which should not be excluded even though other rules (particularly the exclusion of private members
Defines attribute names which should not be excluded even though other rules (particularly the exclusion of private members
via :meth:`_toStringExcludePrivate`) would otherwise exclude them. via :meth:`_toStringExcludePrivate`) would otherwise exclude them.
:return: a list of attribute names :return: a list of attribute names
@ -331,8 +347,7 @@ class ToStringMixin:
return f"{self._tostring_class_name()}[{info}]" return f"{self._tostring_class_name()}[{info}]"
def pprint(self, file=sys.stdout): def pprint(self, file=sys.stdout):
""" """Prints a prettily formatted string representation of the object (with line breaks and indentations)
Prints a prettily formatted string representation of the object (with line breaks and indentations)
to ``stdout`` or the given file. to ``stdout`` or the given file.
:param file: the file to print to :param file: the file to print to
@ -340,25 +355,21 @@ class ToStringMixin:
print(self.pprints(), file=file) print(self.pprints(), file=file)
def pprints(self) -> str: def pprints(self) -> str:
""" """:return: a prettily formatted string representation with line breaks and indentations"""
:return: a prettily formatted string representation with line breaks and indentations
"""
return pretty_string_repr(self) return pretty_string_repr(self)
class _StringConverterAvoidToStringMixinRecursion(StringConverter): class _StringConverterAvoidToStringMixinRecursion(StringConverter):
""" """Avoids recursions when converting objects implementing :class:`ToStringMixin` which may contain themselves to strings.
Avoids recursions when converting objects implementing :class:`ToStringMixin` which may contain themselves to strings.
Use of this object prevents infinite recursions caused by a :class:`ToStringMixin` instance recursively containing itself in Use of this object prevents infinite recursions caused by a :class:`ToStringMixin` instance recursively containing itself in
either a property of another :class:`ToStringMixin`, a list or a tuple. either a property of another :class:`ToStringMixin`, a list or a tuple.
It handles all :class:`ToStringMixin` instances recursively encountered. It handles all :class:`ToStringMixin` instances recursively encountered.
A previously handled instance is converted to a string of the form "<class name>[<<]". A previously handled instance is converted to a string of the form "<class name>[<<]".
""" """
def __init__(self, *handled_objects: "ToStringMixin"): def __init__(self, *handled_objects: "ToStringMixin"):
""" """:param handled_objects: objects which are initially assumed to have been handled already"""
:param handled_objects: objects which are initially assumed to have been handled already self._handled_to_string_mixin_ids = {id(o) for o in handled_objects}
"""
self._handled_to_string_mixin_ids = set([id(o) for o in handled_objects])
def to_string(self, x) -> str: def to_string(self, x) -> str:
if isinstance(x, ToStringMixin): if isinstance(x, ToStringMixin):
@ -368,11 +379,15 @@ class ToStringMixin:
self._handled_to_string_mixin_ids.add(oid) self._handled_to_string_mixin_ids.add(oid)
return str(self._ToStringMixinProxy(x, self)) return str(self._ToStringMixinProxy(x, self))
else: else:
return to_string(x, converter=self, apply_converter_to_non_complex_objects=False, context=x.__class__) return to_string(
x,
converter=self,
apply_converter_to_non_complex_objects=False,
context=x.__class__,
)
class _ToStringMixinProxy: class _ToStringMixinProxy:
""" """A proxy object which wraps a ToStringMixin to ensure that the converter is applied when creating the properties string.
A proxy object which wraps a ToStringMixin to ensure that the converter is applied when creating the properties string.
The proxy is to achieve that all ToStringMixin methods that aren't explicitly overwritten are bound to this proxy The proxy is to achieve that all ToStringMixin methods that aren't explicitly overwritten are bound to this proxy
(rather than the original object), such that the transitive call to _toStringProperties will call the new (rather than the original object), such that the transitive call to _toStringProperties will call the new
implementation. implementation.
@ -392,9 +407,15 @@ class ToStringMixin:
return self.x._tostring_class_name() return self.x._tostring_class_name()
def __getattr__(self, attr: str): def __getattr__(self, attr: str):
if attr.startswith("_tostring"): # ToStringMixin method which we may bind to use this proxy to ensure correct transitive call if attr.startswith(
"_tostring",
): # ToStringMixin method which we may bind to use this proxy to ensure correct transitive call
method = getattr(self.x.__class__, attr) method = getattr(self.x.__class__, attr)
obj = self if attr in self.TOSTRING_METHODS_TRANSITIVELY_CALLING_TOSTRINGPROPERTIES else self.x obj = (
self
if attr in self.TOSTRING_METHODS_TRANSITIVELY_CALLING_TOSTRINGPROPERTIES
else self.x
)
return lambda *args, **kwargs: method(obj, *args, **kwargs) return lambda *args, **kwargs: method(obj, *args, **kwargs)
else: else:
return getattr(self.x, attr) return getattr(self.x, attr)
@ -404,8 +425,7 @@ class ToStringMixin:
def pretty_string_repr(s: Any, initial_indentation_level=0, indentation_string=" "): def pretty_string_repr(s: Any, initial_indentation_level=0, indentation_string=" "):
""" """Creates a pretty string representation (using indentations) from the given object/string representation (as generated, for example, via
Creates a pretty string representation (using indentations) from the given object/string representation (as generated, for example, via
ToStringMixin). An indentation level is added for every opening bracket. ToStringMixin). An indentation level is added for every opening bracket.
:param s: an object or object string representation :param s: an object or object string representation
@ -413,7 +433,7 @@ def pretty_string_repr(s: Any, initial_indentation_level=0, indentation_string="
:param indentation_string: the string which corresponds to a single indentation level :param indentation_string: the string which corresponds to a single indentation level
:return: a reformatted version of the input string with added indentations and line breaks :return: a reformatted version of the input string with added indentations and line breaks
""" """
if type(s) != str: if not isinstance(s, str):
s = str(s) s = str(s)
indent = initial_indentation_level indent = initial_indentation_level
result = indentation_string * indent result = indentation_string * indent
@ -425,7 +445,7 @@ def pretty_string_repr(s: Any, initial_indentation_level=0, indentation_string="
def take(cnt=1): def take(cnt=1):
nonlocal result, i nonlocal result, i
result += s[i:i+cnt] result += s[i : i + cnt]
i += cnt i += cnt
def find_matching(j): def find_matching(j):
@ -455,9 +475,11 @@ def pretty_string_repr(s: Any, initial_indentation_level=0, indentation_string="
if i_match is not None: if i_match is not None:
k = i_match + 1 k = i_match + 1
full_match = s[i:k] full_match = s[i:k]
take_full_match_without_break = is_quote or not("=" in full_match and "," in full_match) take_full_match_without_break = is_quote or not (
"=" in full_match and "," in full_match
)
if take_full_match_without_break: if take_full_match_without_break:
take(k-i) take(k - i)
if not take_full_match_without_break: if not take_full_match_without_break:
take(1) take(1)
indent += 1 indent += 1
@ -465,7 +487,7 @@ def pretty_string_repr(s: Any, initial_indentation_level=0, indentation_string="
elif s[i] in "])": elif s[i] in "])":
take(1) take(1)
indent -= 1 indent -= 1
elif s[i:i+2] == ", ": elif s[i : i + 2] == ", ":
take(2) take(2)
nl() nl()
else: else:
@ -475,12 +497,10 @@ def pretty_string_repr(s: Any, initial_indentation_level=0, indentation_string="
class TagBuilder: class TagBuilder:
""" """Assists in building strings made up of components that are joined via a glue string."""
Assists in building strings made up of components that are joined via a glue string
"""
def __init__(self, *initial_components: str, glue="_"): def __init__(self, *initial_components: str, glue="_"):
""" """:param initial_components: initial components to always include at the beginning
:param initial_components: initial components to always include at the beginning
:param glue: the glue string which joins components :param glue: the glue string which joins components
""" """
self.glue = glue self.glue = glue
@ -490,8 +510,7 @@ class TagBuilder:
self.components.append(component) self.components.append(component)
def with_conditional(self, cond: bool, component: str): def with_conditional(self, cond: bool, component: str):
""" """Conditionally adds the given component.
Conditionally adds the given component
:param cond: the condition :param cond: the condition
:param component: the component to add if the condition holds :param component: the component to add if the condition holds
@ -502,8 +521,7 @@ class TagBuilder:
return self return self
def with_alternative(self, cond: bool, true_component: str, false_component: str): def with_alternative(self, cond: bool, true_component: str, false_component: str):
""" """Adds a component depending on a condition.
Adds a component depending on a condition
:param cond: the condition :param cond: the condition
:param true_component: the component to add if the condition holds :param true_component: the component to add if the condition holds
@ -514,7 +532,5 @@ class TagBuilder:
return self return self
def build(self): def build(self):
""" """:return: the string (with all components joined)"""
:return: the string (with all components joined)
"""
return self.glue.join(self.components) return self.glue.join(self.components)