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.
ColorizedStringsupports some basic string operations. Most notably, it supports wide-character-aware wrapping (seewrap()), and%-like formatting (seepercent_format()).Unlike
str,ColorizedStringis mutable through the+=operator andappend/extendmethods.- 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 appendedColorizedStringhad 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 width: int¶
String width when the string is displayed in a terminal.
See
line_width()for more information.
- 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_link(url: str | None, /)¶
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.
- end_link()¶
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()orend_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,
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,
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 intoexplicit_newline.If set to
False, newline sequences are treated as whitespaces.Whitespace sequences¶ Sequence
preserve_newlines
Result
\n,\r\n,\rFalseTreated as a single whitespace.
\n,\r\n,\rTrueCreates a new line.
\v,\v\n,\v\r\n,\v\rAny
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
Falseto 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( ) 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,
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.
ctx –
ReprContextthat will be passed to__colorized_str__and__colorized_repr__when formatting colorables.
- Returns:
formatted string.
- Raises:
TypeError,ValueError,KeyErrorif 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 isFalse.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.
- max_depth: int¶
Maximum depth of nested containers, after which container’s contents are not rendered.
- static make_dummy(is_unicode: bool = True) ReprContext¶
Make a dummy repr context with default settings.
- repr(
- value: Any,
- /,
- *,
- multiline: bool | None = None,
- highlighted: bool | None = None,
- width: int | None = None,
- max_depth: int | None = None,
Convert value to colorized string using repr methods.
- Parameters:
value – value to be rendered.
multiline – if given, overrides settings passed to
ReprContextfor this call.highlighted – if given, overrides settings passed to
ReprContextfor this call.width – if given, overrides settings passed to
ReprContextfor this call.max_depth – if given, overrides settings passed to
ReprContextfor 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,
Convert value to colorized string.
- Parameters:
value – value to be rendered.
multiline – if given, overrides settings passed to
ReprContextfor this call.highlighted – if given, overrides settings passed to
ReprContextfor this call.width – if given, overrides settings passed to
ReprContextfor this call.max_depth – if given, overrides settings passed to
ReprContextfor 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:
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
ReprContextfor this call.highlighted – if given, overrides settings passed to
ReprContextfor this call.width – if given, overrides settings passed to
ReprContextfor this call.max_depth – if given, overrides settings passed to
ReprContextfor this call.
- Returns:
a colorized string containing string representation of the value.
- Raises:
ValueErrorif conversion or format_spec are invalid.
Format specification
fill align flags width [0-9]+ precision '.' [0-9]+ conversion type 's' fillAny character that will be used to extend string to the desired width.
alignControls alignment of a string when width is given:
"<"for flushing string left,">"for flushing string right,"^"for centering.
flagsOne or several flags:
"#"to enable highlighting,"+"to enable multiline repr.
widthIf formatted string is narrower than this value, it will be extended and aligned using fill and align settings.
precisionIf formatted string is wider that this value, it will be cropped to this width.
conversion typeThe only supported conversion type is
"s".
- hl( ) ColorizedString¶
Highlight result of
repr().ReprContext.repr()does this automatically, but sometimes you need to highlight a string withoutrepr()-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
ReprContextfor this call.highlighted – if given, overrides settings passed to
ReprContextfor this call.width – if given, overrides settings passed to
ReprContextfor this call.max_depth – if given, overrides settings passed to
ReprContextfor 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 aColorizedString.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, valuewill generate a keyword argument,yield name, value, defaultwill 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.Anyto 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 intoPrintableto confirm your intent to print it.
- type yuio.string.ToColorable = Colorable | Template¶
Any object that can be converted to a
Colorableby formatting it viaFormat.
- 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 aTemplate.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( )¶
Lazy wrapper that calls
repr()on the given value.- Parameters:
value – value to repr.
multiline – if given, overrides settings passed to
ReprContextfor this call.highlighted – if given, overrides settings passed to
ReprContextfor 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
ReprContextfor 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
formattedwith 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))
- 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))
- yuio.string.And(
- collection: Iterable[Any],
- /,
- *,
- fallback: AnyString = '',
- color: str | Color | None = 'code',
- limit: int = 0,
Shortcut for
JoinStr.and_().
- yuio.string.Or(
- collection: Iterable[Any],
- /,
- *,
- fallback: AnyString = '',
- color: str | Color | None = 'code',
- limit: int = 0,
Shortcut for
JoinStr.or_().
- final class yuio.string.Stack(*args: Colorable)¶
Lazy wrapper that joins multiple
Colorableobjects 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" -> }
- final class yuio.string.Link(msg: Colorable, /, *, url: str)¶
Lazy wrapper that adds a hyperlink to whatever is passed to it.
- Parameters:
msg – link body.
url – link url, should be properly urlencoded.
- final class yuio.string.Indent(
- msg: Colorable,
- /,
- *,
- indent: AnyString | int = ' ',
- continuation_indent: AnyString | int | None = None,
Lazy wrapper that indents the message during formatting.
See also
- 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
ReprContextfor 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
ReprContextfor 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
SyntaxHighlighterinstance.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.
See also
- Parameters:
msg – message to wrap.
width – if given, overrides settings passed to
ReprContextfor 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 intoexplicit_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
Trueto 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( )¶
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.See also
- Parameters:
msg – message to highlight.
base_color – color that will be added under the message.
- class yuio.string.Hr( )¶
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:
0prints no ruler (but still prints centered text),1prints normal ruler,2prints bold ruler.
Additional styles can be added through
Theme.msg_decorations.width – if given, overrides settings passed to
ReprContextfor this call.overflow – pass
Falseto 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
sto its end.- Parameters:
n – number to be used for pluralization.
one – singular form of the word, i.e. “one thing”. Will be
formattedwith 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, ), )
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.