String

The higher-level yuio.io module uses strings with xml-like color tags to store information about line formatting. Here, on the lower level, these strings are parsed and transformed to ColorizedStrings.

final class yuio.string.ColorizedString
final class yuio.string.ColorizedString(rhs: ColorizedString, /)
final class yuio.string.ColorizedString(*args: AnyString, /)

A string with colors.

This class is a wrapper over a list of strings, colors, and no-wrap markers. Each color applies to strings after it, right until the next color.

ColorizedString supports some basic string operations. Most notably, it supports wide-character-aware wrapping (see wrap()), and %-like formatting (see percent_format()).

Unlike str, ColorizedString is mutable through the += operator and append/extend methods.

Parameters:
  • rhs – when constructor gets a single ColorizedString, it makes a copy.

  • args – when constructor gets multiple arguments, it creates an empty string and appends arguments to it.

String combination semantics

When you append a str, it will take on color and no-wrap semantics according to the last appended color and no-wrap marker.

When you append another ColorizedString, it will not change its colors based on the last appended color, nor will it affect colors of the consequent strings. If appended ColorizedString had an unterminated no-wrap region or link region, this region will be terminated after appending.

Thus, appending a colorized string does not change current color, no-wrap or link setting:

>>> s1 = yuio.string.ColorizedString()
>>> s1 += yuio.color.Color.FORE_RED
>>> s1 += yuio.string.NO_WRAP_START
>>> s1 += "red nowrap text"
>>> s1
ColorizedString([yuio.string.NO_WRAP_START,
                 <Color fore=<RED>>,
                 'red nowrap text'])

>>> s2 = yuio.string.ColorizedString()
>>> s2 += yuio.color.Color.FORE_GREEN
>>> s2 += "green text "
>>> s2 += s1
>>> s2 += " green text continues"
>>> s2
ColorizedString([<Color fore=<GREEN>>,
                 'green text ',
                 yuio.string.NO_WRAP_START,
                 <Color fore=<RED>>,
                 'red nowrap text',
                 yuio.string.NO_WRAP_END,
                 <Color fore=<GREEN>>,
                 ' green text continues'])
property explicit_newline: str

Explicit newline indicates that a line of a wrapped text was broken because the original text contained a new line character.

See wrap() for details.

property active_color: Color

Last color appended to this string.

property active_url: str | None

Last url appended to this string.

property width: int

String width when the string is displayed in a terminal.

See line_width() for more information.

property len: int

Line length in bytes, ignoring all colors.

append_color(color: Color, /)

Append new color to this string.

This operation is lazy, the color will be appended if a non-empty string is appended after it.

Parameters:

color – color to append.

Append new link marker to this string.

This operation is lazy, the link marker will be appended if a non-empty string is appended after it.s

Parameters:

url – link url.

Start hyperlink with the given url.

Parameters:

url – link url.

End hyperlink.

append_str(s: str, /)

Append new plain string to this string.

Parameters:

s – plain string to append.

append_colorized_str(s: ColorizedString, /)

Append new colorized string to this string.

Parameters:

s – colorized string to append.

append_no_wrap(m: NoWrapMarker, /)

Append a no-wrap marker.

Parameters:

m – no-wrap marker, will be dispatched to start_no_wrap() or end_no_wrap().

start_no_wrap()

Start a no-wrap region.

String parts within no-wrap regions are not wrapped on spaces; they can be hard-wrapped if break_long_nowrap_words is True. Whitespaces and newlines in no-wrap regions are preserved regardless of preserve_spaces and preserve_newlines settings.

end_no_wrap()

End a no-wrap region.

extend(
parts: Iterable[str | ColorizedString | Color | NoWrapMarker | LinkMarker],
/,
)

Extend string from iterable of raw parts.

Parameters:

parts – raw parts that will be appended to the string.

copy() ColorizedString

Copy this string.

Returns:

copy of the string.

with_base_color(
base_color: Color,
) ColorizedString

Apply the given color “under” all parts of this string. That is, all colors in this string will be combined with this color on the left: base_color | color.

Parameters:

base_color – color that will be added under the string.

Returns:

new string with changed colors, or current string if base color is NONE.

Example:
>>> s1 = yuio.string.ColorizedString([
...     "part 1",
...     yuio.color.Color.FORE_GREEN,
...     "part 2",
... ])
>>> s2 = s1.with_base_color(
...     yuio.color.Color.FORE_RED
...     | yuio.color.Color.STYLE_BOLD
... )
>>> s2
ColorizedString([<Color fore=<RED> bold=True>,
                 'part 1',
                 <Color fore=<GREEN> bold=True>,
                 'part 2'])
as_code(color_support: ColorSupport, /) list[str]

Convert colors in this string to ANSI escape sequences.

Parameters:

color_support – desired level of color support.

Returns:

raw parts of colorized string with all colors converted to ANSI escape sequences.

wrap(
width: int,
/,
*,
preserve_spaces: bool = False,
preserve_newlines: bool = True,
break_long_words: bool = True,
break_long_nowrap_words: bool = False,
overflow: Literal[False] | str = False,
indent: AnyString | int = '',
continuation_indent: AnyString | int | None = None,
) list[ColorizedString]

Wrap a long line of text into multiple lines.

Parameters:
  • width – desired wrapping width.

  • preserve_spaces

    if set to True, all spaces are preserved. Otherwise, consecutive spaces are collapsed into a single space.

    Note that tabs always treated as a single whitespace.

  • preserve_newlines

    if set to True (default), text is additionally wrapped on newline sequences. When this happens, the newline sequence that wrapped the line will be placed into explicit_newline.

    If set to False, newline sequences are treated as whitespaces.

    Whitespace sequences

    Sequence

    preserve_newlines

    Result

    \n, \r\n, \r

    False

    Treated as a single whitespace.

    \n, \r\n, \r

    True

    Creates a new line.

    \v, \v\n, \v\r\n, \v\r

    Any

    Always creates a new line.

  • break_long_words – if set to True (default), words that don’t fit into a single line will be split into multiple lines.

  • break_long_nowrap_words – if set to True, words in no-wrap regions that don’t fit into a single line will be split into multiple lines.

  • overflow – a symbol that will be added to a line if it doesn’t fit the given width. Pass False to keep the overflowing lines without modification.

  • indent – a string that will be prepended before the first line.

  • continuation_indent – a string that will be prepended before all subsequent lines. Defaults to indent.

Returns:

a list of individual lines without newline characters at the end.

indent(
indent: AnyString | int = '  ',
continuation_indent: AnyString | int | None = None,
) ColorizedString

Indent this string.

Parameters:
  • indent – this will be prepended to the first line in the string. Defaults to two spaces.

  • continuation_indent – this will be prepended to subsequent lines in the string. Defaults to indent.

Returns:

indented string.

percent_format(
args: Any,
ctx: ReprContext,
) ColorizedString

Format colorized string as if with %-formatting (i.e. printf-style formatting).

Parameters:
  • args – arguments for formatting. Can be either a tuple of a mapping. Any other value will be converted to a tuple of one element.

  • ctxReprContext that will be passed to __colorized_str__ and __colorized_repr__ when formatting colorables.

Returns:

formatted string.

Raises:

TypeError, ValueError, KeyError if formatting fails.

Pretty printing protocol

Complex message formatting requires knowing capabilities of the target terminal. This affects which message decorations are used (Unicode or ASCII), how lines are wrapped, and so on. This data is encapsulated in an instance of ReprContext:

final class yuio.string.ReprContext(
*,
term: Term,
theme: Theme,
multiline: bool | None = None,
highlighted: bool | None = None,
max_depth: int | None = None,
width: int | None = None,
)

Context object that tracks repr settings and ensures that recursive objects are handled properly.

Warning

ReprContexts are not thread safe. As such, you shouldn’t create them for long term use.

Parameters:
  • term – terminal that will be used to print formatted messages.

  • theme – theme that will be used to format messages.

  • multiline – indicates that values rendered via rich repr protocol should be split into multiple lines. Default is False.

  • highlighted – indicates that values rendered via rich repr protocol or via built-in repr() should be highlighted according to python syntax. Default is False.

  • max_depth – maximum depth of nested containers, after which container’s contents are not rendered. Default is 5.

  • width – maximum width of the content, used when wrapping text, rendering markdown, or rendering horizontal rulers. If not given, defaults to Theme.fallback_width.

term

Current term.

theme

Current theme.

multiline: bool

Whether values rendered with repr() are split into multiple lines.

highlighted: bool

Whether values rendered with repr() are highlighted.

max_depth: int

Maximum depth of nested containers, after which container’s contents are not rendered.

width: int

Maximum width of the content, used when wrapping text or rendering markdown.

static make_dummy(is_unicode: bool = True) ReprContext

Make a dummy repr context with default settings.

get_color(paths: str, /) Color

Lookup a color by path.

to_color(
color_or_path: Color | str | None,
/,
) Color

Convert color or color path to color.

get_msg_decoration(name: str, /) str

Get message decoration by name.

repr(
value: Any,
/,
*,
multiline: bool | None = None,
highlighted: bool | None = None,
width: int | None = None,
max_depth: int | None = None,
) ColorizedString

Convert value to colorized string using repr methods.

Parameters:
  • value – value to be rendered.

  • multiline – if given, overrides settings passed to ReprContext for this call.

  • highlighted – if given, overrides settings passed to ReprContext for this call.

  • width – if given, overrides settings passed to ReprContext for this call.

  • max_depth – if given, overrides settings passed to ReprContext for this call.

Returns:

a colorized string containing representation of the value.

Raises:

this method does not raise any errors. If any inner object raises an exception, this function returns a colorized string with an error description.

str(
value: Any,
/,
*,
multiline: bool | None = None,
highlighted: bool | None = None,
width: int | None = None,
max_depth: int | None = None,
) ColorizedString

Convert value to colorized string.

Parameters:
  • value – value to be rendered.

  • multiline – if given, overrides settings passed to ReprContext for this call.

  • highlighted – if given, overrides settings passed to ReprContext for this call.

  • width – if given, overrides settings passed to ReprContext for this call.

  • max_depth – if given, overrides settings passed to ReprContext for this call.

Returns:

a colorized string containing string representation of the value.

Raises:

this method does not raise any errors. If any inner object raises an exception, this function returns a colorized string with an error description.

convert(
value: Any,
conversion: Literal['a', 'r', 's'] | None,
format_spec: str | None = None,
/,
*,
multiline: bool | None = None,
highlighted: bool | None = None,
width: int | None = None,
max_depth: int | None = None,
)

Perform string conversion, similar to string.templatelib.convert(), and format the object with respect to the given format_spec.

Parameters:
  • value – value to be converted.

  • conversion

    string conversion method:

    • 's' calls str(),

    • 'r' calls repr(),

    • 'a' calls repr() and escapes non-ascii characters.

  • format_spec – formatting spec can override multiline and highlighted, and controls width, alignment, fill chars, etc. See its syntax below.

  • multiline – if given, overrides settings passed to ReprContext for this call.

  • highlighted – if given, overrides settings passed to ReprContext for this call.

  • width – if given, overrides settings passed to ReprContext for this call.

  • max_depth – if given, overrides settings passed to ReprContext for this call.

Returns:

a colorized string containing string representation of the value.

Raises:

ValueError if conversion or format_spec are invalid.

Format specification

fillalignflagswidth[0-9]+precision'.'[0-9]+conversion type's'

fill

Any character that will be used to extend string to the desired width.

align

Controls alignment of a string when width is given: "<" for flushing string left, ">" for flushing string right, "^" for centering.

flags

One or several flags: "#" to enable highlighting, "+" to enable multiline repr.

width

If formatted string is narrower than this value, it will be extended and aligned using fill and align settings.

precision

If formatted string is wider that this value, it will be cropped to this width.

conversion type

The only supported conversion type is "s".

hl(
value: str,
/,
*,
highlighted: bool | None = None,
) ColorizedString

Highlight result of repr().

ReprContext.repr() does this automatically, but sometimes you need to highlight a string without repr()-ing it one more time.

Parameters:

value – result of repr() that needs highlighting.

Returns:

highlighted string.

with_settings(
*,
multiline: bool | None = None,
highlighted: bool | None = None,
width: int | None = None,
max_depth: int | None = None,
)

Temporarily replace settings of this context.

Parameters:
  • multiline – if given, overrides settings passed to ReprContext for this call.

  • highlighted – if given, overrides settings passed to ReprContext for this call.

  • width – if given, overrides settings passed to ReprContext for this call.

  • max_depth – if given, overrides settings passed to ReprContext for this call.

Returns:

a context manager that overrides settings.

Repr context may not always be available when a message is created, though. For example, we may know that we will be printing some data, but we don’t know whether we’ll print it to a file or to a terminal.

The solution is to defer formatting by creating a Colorable, i.e. an object that defines one of the following special methods:

__colorized_str__, __colorized_repr__

This should be a method that accepts a single positional argument, ReprContext, and returns a ColorizedString.

Tip

Prefer __rich_repr__ for simpler use cases, and only use __colorized_repr__ when you need something advanced.

Example:

class MyObject:
    def __init__(self, value):
        self.value = value

    def __colorized_str__(self, ctx: yuio.string.ReprContext):
        result = yuio.string.ColorizedString()
        result += ctx.get_color("magenta")
        result += "MyObject"
        result += ctx.get_color("normal")
        result += "("
        result += ctx.repr(self.value)
        result += ")"
        return result
__rich_repr__

This method doesn’t have any arguments. It should return an iterable of tuples describing object’s arguments:

  • yield name, value will generate a keyword argument,

  • yield name, value, default will generate a keyword argument if value is not equal to default,

  • if name is None, it will generate positional argument instead.

See the Rich library documentation for more info.

Example:

class MyObject:
    def __init__(self, value1, value2):
        self.value1 = value1
        self.value2 = value2

    def __rich_repr__(self) -> yuio.string.RichReprResult:
        yield "value1", self.value1
        yield "value2", self.value2
type yuio.string.RichReprResult = Iterable[tuple[Any] | tuple[str | None, Any] | tuple[str | None, Any, Any]]

This is an alias similar to rich.repr.Result, but stricter: it only allows tuples, not arbitrary values.

This is done to avoid bugs where you yield a single value which happens to contain a tuple, and Yuio (or Rich) renders it as a named argument.

type yuio.string.ColorizedStrProtocol

Protocol for objects that define __colorized_str__ method.

type yuio.string.ColorizedReprProtocol

Protocol for objects that define __colorized_repr__ method.

type yuio.string.RichReprProtocol

Protocol for objects that define __rich_repr__ method.

type yuio.string.Printable

Any object that supports printing.

Technically, any object supports colorized printing because we’ll fall back to __repr__ or __str__ if there are no special methods on it.

However, we don’t use typing.Any to avoid potential errors.

type yuio.string.Colorable = Printable | ColorizedStrProtocol | ColorizedReprProtocol | RichReprProtocol | LiteralString | BaseException

An object that supports colorized printing.

This can be a string, and exception, or any object that follows ColorizedStrProtocol. Additionally, you can pass any object that has __repr__, but you’ll have to wrap it into Printable to confirm your intent to print it.

type yuio.string.ToColorable = Colorable | Template

Any object that can be converted to a Colorable by formatting it via Format.

yuio.string.repr_from_rich(cls: RichReprProtocol) RichReprProtocol

A decorator that generates __repr__ from __rich_repr__.

Parameters:

cls – class that needs __repr__.

Returns:

always returns cls.

Example:
@yuio.string.repr_from_rich
class MyClass:
    def __init__(self, value):
        self.value = value

    def __rich_repr__(self) -> yuio.string.RichReprResult:
        yield "value", self.value
>>> print(repr(MyClass("plush!")))
MyClass(value='plush!')

Formatting utilities

class yuio.string.Format(msg: LiteralString, /, *args: Any)
class yuio.string.Format(msg: Template, /)

Lazy wrapper that %-formats the given message, or formats a Template.

This utility allows saving %-formatted messages and templates and performing actual formatting lazily when requested. Color tags and backticks are handled as usual.

Parameters:
  • msg – message to format.

  • args – arguments for %-formatting the message.

Example:
>>> message = Format("Hello, `%s`!", "world")
>>> print(message)
Hello, world!
final class yuio.string.Repr(
value: Any,
/,
*,
multiline: bool | None = None,
highlighted: bool | None = None,
)

Lazy wrapper that calls repr() on the given value.

Parameters:
  • value – value to repr.

  • multiline – if given, overrides settings passed to ReprContext for this call.

  • highlighted – if given, overrides settings passed to ReprContext for this call.

Example:
config = ...
yuio.io.info(
    "Loaded config:\n`%#+s`", yuio.string.Indent(yuio.string.Repr(config))
)
final class yuio.string.TypeRepr(ty: Any, /, *, highlighted: bool | None = None)

Lazy wrapper that calls annotationlib.type_repr() on the given value and highlights the result.

Parameters:
  • ty

    type to format.

    If ty is a string, annotationlib.type_repr() is not called on it, allowing you to mix types and arbitrary descriptions.

  • highlighted – if given, overrides settings passed to ReprContext for this call.

Example:
yuio.io.error("Expected `str`, got `%s`", yuio.string.TypeRepr(type(value)))
final class yuio.string.JoinStr(
collection: Iterable[Any],
/,
*,
sep: str = ', ',
sep_two: str | None = None,
sep_last: str | None = None,
fallback: AnyString = '',
color: str | Color | None = 'code',
limit: int = 0,
limit_msg: str | None = None,
)

Lazy wrapper that calls str() on elements of the given collection, then joins the results using the given separator.

Parameters:
  • collection – collection that will be printed.

  • sep – separator that’s printed between elements of the collection.

  • sep_two – separator that’s used when there are only two elements in the collection. Defaults to sep.

  • sep_last – separator that’s used between the last and prior-to-last element of the collection. Defaults to sep.

  • fallback – printed if collection is empty.

  • color – color applied to elements of the collection.

  • limit – truncate number of entries to this limit.

  • limit_msg – message that replaces truncated part. Will be formatted with a single keyword argument n – number of truncated entries. Default is "+{n} more".

Example:
values = ["foo", "bar"]
yuio.io.info("Available values: %s", yuio.string.JoinStr(values))
classmethod and_(
collection: Iterable[Any],
/,
*,
fallback: AnyString = '',
color: str | Color | None = 'code',
limit: int = 0,
) Self

Shortcut for joining arguments using word “and” as the last separator.

Example:
>>> print(yuio.string.JoinStr.and_([1, 2, 3]))
1, 2, and 3
classmethod or_(
collection: Iterable[Any],
/,
*,
fallback: AnyString = '',
color: str | Color | None = 'code',
limit: int = 0,
) Self

Shortcut for joining arguments using word “or” as the last separator.

Example:
>>> print(yuio.string.JoinStr.or_([1, 2, 3]))
1, 2, or 3
final class yuio.string.JoinRepr(
collection: Iterable[Any],
/,
*,
sep: str = ', ',
sep_two: str | None = None,
sep_last: str | None = None,
fallback: AnyString = '',
color: str | Color | None = 'code',
limit: int = 0,
limit_msg: str | None = None,
)

Lazy wrapper that calls repr() on elements of the given collection, then joins the results using the given separator.

Parameters:
  • collection – collection that will be printed.

  • sep – separator that’s printed between elements of the collection.

  • sep_two – separator that’s used when there are only two elements in the collection. Defaults to sep.

  • sep_last – separator that’s used between the last and prior-to-last element of the collection. Defaults to sep.

  • fallback – printed if collection is empty.

  • color – color applied to elements of the collection.

  • limit – truncate number of entries to this limit.

  • limit_msg – message that replaces truncated part. Will be %-formatted with a single keyword argument n – number of truncated entries. Default is "+{n} more".

Example:
values = ["foo", "bar"]
yuio.io.info("Available values: %s", yuio.string.JoinRepr(values))
classmethod and_(
collection: Iterable[Any],
/,
*,
fallback: AnyString = '',
color: str | Color | None = 'code',
limit: int = 0,
) Self

Shortcut for joining arguments using word “and” as the last separator.

Example:
>>> print(yuio.string.JoinStr.and_([1, 2, 3]))
1, 2, and 3
classmethod or_(
collection: Iterable[Any],
/,
*,
fallback: AnyString = '',
color: str | Color | None = 'code',
limit: int = 0,
) Self

Shortcut for joining arguments using word “or” as the last separator.

Example:
>>> print(yuio.string.JoinStr.or_([1, 2, 3]))
1, 2, or 3
yuio.string.And(
collection: Iterable[Any],
/,
*,
fallback: AnyString = '',
color: str | Color | None = 'code',
limit: int = 0,
) Self

Shortcut for JoinStr.and_().

yuio.string.Or(
collection: Iterable[Any],
/,
*,
fallback: AnyString = '',
color: str | Color | None = 'code',
limit: int = 0,
) Self

Shortcut for JoinStr.or_().

final class yuio.string.Stack(*args: Colorable)

Lazy wrapper that joins multiple Colorable objects with newlines, effectively stacking them one on top of another.

Parameters:

args – colorables to stack.

Example:
>>> print(
...     yuio.string.Stack(
...         yuio.string.Format("<c bold magenta>Example:</c>"),
...         yuio.string.Indent(
...             yuio.string.Hl(
...                 """
...                     {
...                         "foo": "bar"
...                     }
...                 """,
...                 syntax="json",
...             ),
...             indent="->  ",
...         ),
...     )
... )
Example:
->  {
->      "foo": "bar"
->  }

Lazy wrapper that adds a hyperlink to whatever is passed to it.

Parameters:
  • msg – link body.

  • url – link url, should be properly urlencoded.

classmethod from_path(
msg: Colorable,
/,
*,
path: str | Path,
) Self

Create a link to a local file.

Ensures that file path is absolute and properly formatted.

Parameters:
  • msg – link body.

  • path – path to a file.

final class yuio.string.Indent(
msg: Colorable,
/,
*,
indent: AnyString | int = '  ',
continuation_indent: AnyString | int | None = None,
)

Lazy wrapper that indents the message during formatting.

Parameters:
  • msg – message to indent.

  • indent – this will be prepended to the first line in the string. Defaults to two spaces.

  • continuation_indent – this will be prepended to subsequent lines in the string. Defaults to indent.

Example:
config = ...
yuio.io.info(
    "Loaded config:\n`%#+s`", yuio.string.Indent(yuio.string.Repr(config))
)
final class yuio.string.Md(
msg: LiteralString,
/,
*args,
width: int | None | yuio.Missing = yuio.MISSING,
dedent: bool = True,
allow_headings: bool = True,
)
final class yuio.string.Md(
msg: str,
/,
*,
width: int | None | yuio.Missing = yuio.MISSING,
dedent: bool = True,
allow_headings: bool = True,
)

Lazy wrapper that renders markdown during formatting.

Parameters:
  • md – text to format.

  • width – if given, overrides settings passed to ReprContext for this call.

  • dedent – whether to remove leading indent from text.

  • allow_headings – whether to render headings as actual headings or as paragraphs.

final class yuio.string.Rst(
msg: LiteralString,
/,
*args,
width: int | None | yuio.Missing = yuio.MISSING,
dedent: bool = True,
allow_headings: bool = True,
)
final class yuio.string.Rst(
msg: str,
/,
*,
width: int | None | yuio.Missing = yuio.MISSING,
dedent: bool = True,
allow_headings: bool = True,
)

Lazy wrapper that renders ReStructuredText during formatting.

Parameters:
  • rst – text to format.

  • width – if given, overrides settings passed to ReprContext for this call.

  • dedent – whether to remove leading indent from text.

  • allow_headings – whether to render headings as actual headings or as paragraphs.

final class yuio.string.Hl(code: LiteralString, /, *args, syntax: str, dedent: bool = True)
final class yuio.string.Hl(code: str, /, *, syntax: str, dedent: bool = True)

Lazy wrapper that highlights code during formatting.

Parameters:
  • md – code to highlight.

  • args – arguments for %-formatting the highlighted code.

  • syntax – name of syntax or a SyntaxHighlighter instance.

  • dedent – whether to remove leading indent from code.

final class yuio.string.Wrap(
msg: Colorable,
/,
*,
width: int | None = None,
preserve_spaces: bool = False,
preserve_newlines: bool = True,
break_long_words: bool = True,
break_long_nowrap_words: bool = False,
overflow: bool | str = False,
indent: AnyString | int = '',
continuation_indent: AnyString | int | None = None,
)

Lazy wrapper that wraps the message during formatting.

Parameters:
  • msg – message to wrap.

  • width – if given, overrides settings passed to ReprContext for this call.

  • preserve_spaces

    if set to True, all spaces are preserved. Otherwise, consecutive spaces are collapsed when newline break occurs.

    Note that tabs always treated as a single whitespace.

  • preserve_newlines

    if set to True (default), text is additionally wrapped on newline sequences. When this happens, the newline sequence that wrapped the line will be placed into explicit_newline.

    If set to False, newline sequences are treated as whitespaces.

  • break_long_words – if set to True (default), words that don’t fit into a single line will be split into multiple lines.

  • overflow – Pass True to trim overflowing lines and replace them with ellipsis.

  • break_long_nowrap_words – if set to True, words in no-wrap regions that don’t fit into a single line will be split into multiple lines.

  • indent – this will be prepended to the first line in the string. Defaults to two spaces.

  • continuation_indent – this will be prepended to subsequent lines in the string. Defaults to indent.

final class yuio.string.WithBaseColor(
msg: Colorable,
/,
*,
base_color: str | Color,
)

Lazy wrapper that applies the given color “under” the given colorable. That is, all colors in the rendered colorable will be combined with this color on the left: base_color | color.

Parameters:
  • msg – message to highlight.

  • base_color – color that will be added under the message.

class yuio.string.Hr(
msg: Colorable = '',
/,
*,
weight: int | str = 1,
overflow: bool | str = True,
**kwargs,
)

Produces horizontal ruler when converted to string.

Parameters:
  • msg – any colorable that will be placed in the middle of the ruler.

  • weight

    weight or style of the ruler:

    • 0 prints no ruler (but still prints centered text),

    • 1 prints normal ruler,

    • 2 prints bold ruler.

    Additional styles can be added through Theme.msg_decorations.

  • width – if given, overrides settings passed to ReprContext for this call.

  • overflow – pass False to disable trimming msg to terminal width.

  • kwargs

    Other keyword arguments override corresponding decorations from the theme:

    left_start:

    start of the ruler to the left of the message.

    left_middle:

    filler of the ruler to the left of the message.

    left_end:

    end of the ruler to the left of the message.

    middle:

    filler of the ruler that’s used if msg is empty.

    right_start:

    start of the ruler to the right of the message.

    right_middle:

    filler of the ruler to the right of the message.

    right_end:

    end of the ruler to the right of the message.

final class yuio.string.Plural(
n: float,
/,
one: str = '',
other: str | None = None,
*,
key: Callable[[float], str] | None = None,
**forms,
)

Lazy wrapper that pluralizes the given string by adding s to its end.

Parameters:
  • n – number to be used for pluralization.

  • one – singular form of the word, i.e. “one thing”. Will be formatted with a single keyword argument n – the given number.

  • other – plural form of the word, i.e. “other number of things”; defaults to "ones".

  • forms – additional forms of the word, only used with custom key.

  • key – can be used to provide pluralization for non-english words. This callable should take a number and return a string "one", "other", or a key of the forms dictionary.

Example:
n = 5
yuio.io.info("Loaded %s", yuio.string.Plural(n, "a sample", "{n} samples"))

With custom key:

lt_plural_key = lambda n: (
    "one"
    if n % 10 == 1 and not 11 <= n % 100 <= 19
    else "few"
    if 2 <= n % 10 <= 9 and not 11 <= n % 100 <= 19
    else "many"
    if n != int(n)
    else "other"
)

for n in [1, 2, 0.1, 10]:
    yuio.io.info(
        "Rasta %s",
        yuio.string.Plural(
            n,
            one="{n} obuolys",
            few="{n} obuoliai",
            many="{n} obuolio",
            other="{n} obuolių",
            key=lt_plural_key,
        ),
    )
class yuio.string.Ordinal(n: float, /)

Lazy wrapper that formats numbers as English ordinals (i.e. 1st, 2nd, etc.)

Parameters:

n – number to format.

Example:
for n in range(5):
    print(yuio.string.Ordinal(n + 1))

Parsing color tags

yuio.string.colorize(
line: str,
/,
*args: Any,
ctx: ReprContext,
default_color: Color | str = Color.NONE,
parse_cli_flags_in_backticks: bool = False,
) ColorizedString
yuio.string.colorize(
line: Template,
/,
*,
ctx: ReprContext,
default_color: Color | str = Color.NONE,
parse_cli_flags_in_backticks: bool = False,
) ColorizedString

Parse color tags and produce a colorized string.

Apply default_color to the entire paragraph, and process color tags and backticks within it.

Parameters:
  • line – text to colorize.

  • args – if given, string will be %-formatted after parsing. Can’t be given if line is Template.

  • ctxReprContext that will be used to look up color tags and format arguments.

  • default_color – color or color tag to apply to the entire text.

Returns:

a colorized string.

yuio.string.strip_color_tags(s: str) str

Remove all color tags from a string.

Helpers

yuio.string.line_width(s: str, /) int

Calculates string width when the string is displayed in a terminal.

This function makes effort to detect wide characters such as emojis. If does not, however, work correctly with extended grapheme clusters, and so it may fail for emojis with modifiers, or other complex characters.

Example where it fails is 👩🏽‍💻. It consists of four code points:

  • Unicode Character WOMAN (U+1F469, 👩),

  • Unicode Character EMOJI MODIFIER FITZPATRICK TYPE-4 (U+1F3FD),

  • Unicode Character ZERO WIDTH JOINER (U+200D),

  • Unicode Character PERSONAL COMPUTER (U+1F4BB, 💻).

Since line_width() can’t understand that these code points are combined into a single emoji, it treats them separately, resulting in answer 6 (2 for every code point except ZERO WIDTH JOINER):

>>> line_width("👩🏽‍💻")
6

In all fairness, detecting how much space such an emoji will take is not so straight forward, as that will depend on unicode capabilities of a specific terminal. Since a lot of terminals will not handle such emojis correctly, I’ve decided to go with this simplistic implementation.

type yuio.string.AnyString = str | Color | ColorizedString | NoWrapMarker | Iterable[AnyString]

Any string (i.e. a str, a raw colorized string, or a normal colorized string).

class yuio.string.LinkMarker(url: str | None)

Indicates start or end of a hyperlink in a colorized string.

yuio.string.NO_WRAP_START: NoWrapStart = yuio.string.NO_WRAP_START

Indicates start of a no-wrap region in a ColorizedString.

yuio.string.NO_WRAP_END: NoWrapEnd = yuio.string.NO_WRAP_END

Indicates end of a no-wrap region in a ColorizedString.

type yuio.string.NoWrapMarker
type yuio.string.NoWrapStart
type yuio.string.NoWrapEnd

Type of a no-wrap marker.