Package giraph
Grapheme helper package for Python
Sub-modules
giraph.buffer
-
GraphemeBuffer
class module giraph.constants
-
Console management constants
giraph.grapheme
-
Grapheme
class module giraph.logging
-
Logging
Classes
class Grapheme (char: str = '',
mods: list[str] | None = None,
width: int = 1,
force_wide: bool = False)-
Expand source code
class Grapheme: """ Class for storing (potentially clustered) graphemes The base character is stored separately from its various modifying sequences to accommodate terminals which do not support zero-width characters, combining characters, etc. Variation-selected emoji which are considered by the terminal (incorrectly) to be narrow graphemes are flagged so that the column offset caused during display can be compensated for. """ char: str """Base character""" mods: list[str] """Modifiers""" width: int """Character width""" force_wide: bool """Force 'wide' representation""" def __init__( self, char: str = "", mods: list[str] | None = None, width: int = 1, force_wide: bool = False, ): self.char = char self.mods = mods if mods else [] self.width = width self.force_wide = force_wide def _modstr(self, s) -> str: return "0x%04X" % ord(s) if wcswidth(s) <= 0 else s def __eq__(self, __object: object) -> bool: if not isinstance(__object, Grapheme): return NotImplemented return str(self) == str(__object) def __repr__(self) -> str: return ( f"Grapheme(char={self.char!r}, " f"mods={[self._modstr(c) for c in self.mods]}, " f"width={self.width}{' <forced>' if self.force_wide else ''})" ) def __str__(self) -> str: return "".join((self.raw, " " if self.force_wide else "")) @property def raw(self) -> str: """The raw output of this grapheme, without forced-width adjustment.""" return "".join((self.char, "".join(self.mods))) @classmethod def from_str(self, input: str) -> Grapheme: """ Construct a single `Grapheme` from the given `str`. Args: input: The input to parse. Returns: A `Grapheme` instance representing the first grapheme from the input. """ # avoid circular import from ._from_str import _from_str output = _from_str(input, True) assert isinstance(output, Grapheme) return output
Class for storing (potentially clustered) graphemes
The base character is stored separately from its various modifying sequences to accommodate terminals which do not support zero-width characters, combining characters, etc. Variation-selected emoji which are considered by the terminal (incorrectly) to be narrow graphemes are flagged so that the column offset caused during display can be compensated for.
Class variables
var char : str
-
Base character
var force_wide : bool
-
Force 'wide' representation
var mods : list[str]
-
Modifiers
var width : int
-
Character width
Static methods
def from_str(input: str) ‑> Grapheme
Instance variables
prop raw : str
-
Expand source code
@property def raw(self) -> str: """The raw output of this grapheme, without forced-width adjustment.""" return "".join((self.char, "".join(self.mods)))
The raw output of this grapheme, without forced-width adjustment.
class GraphemeBuffer (*args, **kwargs)
-
Expand source code
class GraphemeBuffer(list[Grapheme | None]): """ A contiguous segment of cells for display on the console, each of which is either a `Grapheme` instance or `None`. A value of `None` should denote that the cell is occupied by the remainder of the previous `Grapheme` (i.e. the previous `Grapheme` has a `width` value greater than 1). """ def __add__(self, __object: str) -> GraphemeBuffer: # type: ignore return GraphemeBuffer( super(GraphemeBuffer, self).__add__( GraphemeBuffer.from_str(__object) ) ) def __iadd__(self, __object: str) -> GraphemeBuffer: # type: ignore return super(GraphemeBuffer, self).__iadd__( GraphemeBuffer.from_str(__object) ) def __repr__(self) -> str: return f"GraphemeBuffer({len(self)})" def __setitem__( # type: ignore self, __index: SupportsIndex, __object: str, ): return super(GraphemeBuffer, self).__setitem__( __index, GraphemeBuffer.from_str(__object)[0] ) def __str__(self): return "".join(str(g) if g else "" for g in self) def append(self, __object: Grapheme | None) -> None: val = super(GraphemeBuffer, self).append(__object) # pad wide graphemes if __object and __object.width > 1: for _ in range(__object.width - 1): super(GraphemeBuffer, self).append(None) return val def insert(self, __index: SupportsIndex, __object: Grapheme | None) -> None: if not isinstance(__index, int): return NotImplemented if __object and __object.width > 1: for _ in range(__object.width - 1): super(GraphemeBuffer, self).insert(__index, None) return super(GraphemeBuffer, self).insert(__index, __object) def pop(self, __index: SupportsIndex = -1) -> Grapheme | None: if not isinstance(__index, int): return NotImplemented val = super(GraphemeBuffer, self).pop(__index) idx = int(__index) if val and val.width > 1 and idx >= 0: for _ in range(val.width - 1): super(GraphemeBuffer, self).pop(__index) iterate = idx > 0 while not val and idx != 0: if iterate: idx -= 1 val = super(GraphemeBuffer, self).pop(idx) return val @property def grapheme_count(self) -> int: """The total number of `Grapheme` objects, excluding `None` values.""" return sum([1 if g else 0 for g in self]) @property def raw(self) -> str: """Console output as a `str` without forced-width adjustments.""" return "".join(g.raw if g else "" for g in self) def _strip(self, lstrip: bool = False) -> GraphemeBuffer: length = len(self) if length == 0: return GraphemeBuffer() idx = -1 if lstrip else 0 limit = length + idx step = 1 if lstrip else -1 grapheme: Grapheme | None = None discard = set((" ", "\n")) absidx = 0 while (grapheme is None or grapheme.char in discard) and absidx < limit: idx += step absidx = abs(idx) grapheme = self[idx] if not grapheme: logger.debug("empty after strip") return GraphemeBuffer() if not lstrip: idx -= step * grapheme.width if idx == 0: return GraphemeBuffer(self.copy()) logger.debug(f"stripped: {idx}") return GraphemeBuffer(self[idx:] if lstrip else self[:idx]) def lstrip(self) -> GraphemeBuffer: """Trim leading spaces/newlines.""" return self._strip(True) def rstrip(self) -> GraphemeBuffer: """Trim trailing spaces/newlines.""" return self._strip() def strip(self) -> GraphemeBuffer: """Trim leading and trailing spaces/newlines.""" return self._strip()._strip(True) def split(self, separator: Grapheme | str) -> list[GraphemeBuffer]: """ Split the segment into smaller segments, separated by `separator`. Args: separator: The `Grapheme` or `str` to use for tokenizing. Returns: A list of `GraphemeBuffer` instances. """ is_grapheme = isinstance(separator, Grapheme) result: list[GraphemeBuffer] = [] segment = GraphemeBuffer() for g in [g for g in self if g]: if (is_grapheme and g == separator) or ( not is_grapheme and g.char == separator ): result.append(segment) segment = GraphemeBuffer() else: segment.append(g) if len(segment): result.append(segment) return result @classmethod def from_str(cls, input: str) -> GraphemeBuffer: """ Construct a `GraphemeBuffer` from the given `str`. Args: input: The input to parse. Returns: A `GraphemeBuffer` instance representing the grapheme(s) from the input. """ # avoid circular import from ._from_str import _from_str output = _from_str(input, False) assert isinstance(output, GraphemeBuffer) return output
A contiguous segment of cells for display on the console, each of which is either a
Grapheme
instance orNone
. A value ofNone
should denote that the cell is occupied by the remainder of the previousGrapheme
(i.e. the previousGrapheme
has awidth
value greater than 1).Ancestors
- builtins.list
Static methods
def from_str(input: str) ‑> GraphemeBuffer
-
Construct a
GraphemeBuffer
from the givenstr
.Args
input
- The input to parse.
Returns
A
GraphemeBuffer
instance representing the grapheme(s) from the input.
Instance variables
prop grapheme_count : int
-
Expand source code
@property def grapheme_count(self) -> int: """The total number of `Grapheme` objects, excluding `None` values.""" return sum([1 if g else 0 for g in self])
The total number of
Grapheme
objects, excludingNone
values. prop raw : str
-
Expand source code
@property def raw(self) -> str: """Console output as a `str` without forced-width adjustments.""" return "".join(g.raw if g else "" for g in self)
Console output as a
str
without forced-width adjustments.
Methods
def append(self,
_GraphemeBuffer__object: Grapheme | None) ‑> None-
Expand source code
def append(self, __object: Grapheme | None) -> None: val = super(GraphemeBuffer, self).append(__object) # pad wide graphemes if __object and __object.width > 1: for _ in range(__object.width - 1): super(GraphemeBuffer, self).append(None) return val
Append object to the end of the list.
def insert(self,
_GraphemeBuffer__index: SupportsIndex,
_GraphemeBuffer__object: Grapheme | None) ‑> None-
Expand source code
def insert(self, __index: SupportsIndex, __object: Grapheme | None) -> None: if not isinstance(__index, int): return NotImplemented if __object and __object.width > 1: for _ in range(__object.width - 1): super(GraphemeBuffer, self).insert(__index, None) return super(GraphemeBuffer, self).insert(__index, __object)
Insert object before index.
def lstrip(self) ‑> GraphemeBuffer
-
Expand source code
def lstrip(self) -> GraphemeBuffer: """Trim leading spaces/newlines.""" return self._strip(True)
Trim leading spaces/newlines.
def pop(self) ‑> Grapheme | None
-
Expand source code
def pop(self, __index: SupportsIndex = -1) -> Grapheme | None: if not isinstance(__index, int): return NotImplemented val = super(GraphemeBuffer, self).pop(__index) idx = int(__index) if val and val.width > 1 and idx >= 0: for _ in range(val.width - 1): super(GraphemeBuffer, self).pop(__index) iterate = idx > 0 while not val and idx != 0: if iterate: idx -= 1 val = super(GraphemeBuffer, self).pop(idx) return val
Remove and return item at index (default last).
Raises IndexError if list is empty or index is out of range.
def rstrip(self) ‑> GraphemeBuffer
-
Expand source code
def rstrip(self) -> GraphemeBuffer: """Trim trailing spaces/newlines.""" return self._strip()
Trim trailing spaces/newlines.
def split(self,
separator: Grapheme | str) ‑> list[GraphemeBuffer]-
Expand source code
def split(self, separator: Grapheme | str) -> list[GraphemeBuffer]: """ Split the segment into smaller segments, separated by `separator`. Args: separator: The `Grapheme` or `str` to use for tokenizing. Returns: A list of `GraphemeBuffer` instances. """ is_grapheme = isinstance(separator, Grapheme) result: list[GraphemeBuffer] = [] segment = GraphemeBuffer() for g in [g for g in self if g]: if (is_grapheme and g == separator) or ( not is_grapheme and g.char == separator ): result.append(segment) segment = GraphemeBuffer() else: segment.append(g) if len(segment): result.append(segment) return result
Split the segment into smaller segments, separated by
separator
.Args
separator
- The
Grapheme
orstr
to use for tokenizing.
Returns
A list of
GraphemeBuffer
instances. def strip(self) ‑> GraphemeBuffer
-
Expand source code
def strip(self) -> GraphemeBuffer: """Trim leading and trailing spaces/newlines.""" return self._strip()._strip(True)
Trim leading and trailing spaces/newlines.