diff options
Diffstat (limited to '.venv/lib/python3.12/site-packages/openpyxl/cell/rich_text.py')
-rw-r--r-- | .venv/lib/python3.12/site-packages/openpyxl/cell/rich_text.py | 202 |
1 files changed, 202 insertions, 0 deletions
diff --git a/.venv/lib/python3.12/site-packages/openpyxl/cell/rich_text.py b/.venv/lib/python3.12/site-packages/openpyxl/cell/rich_text.py new file mode 100644 index 00000000..373e263e --- /dev/null +++ b/.venv/lib/python3.12/site-packages/openpyxl/cell/rich_text.py @@ -0,0 +1,202 @@ +# Copyright (c) 2010-2024 openpyxl + +""" +RichText definition +""" +from copy import copy +from openpyxl.compat import NUMERIC_TYPES +from openpyxl.cell.text import InlineFont, Text +from openpyxl.descriptors import ( + Strict, + String, + Typed +) + +from openpyxl.xml.functions import Element, whitespace + +class TextBlock(Strict): + """ Represents text string in a specific format + + This class is used as part of constructing a rich text strings. + """ + font = Typed(expected_type=InlineFont) + text = String() + + def __init__(self, font, text): + self.font = font + self.text = text + + + def __eq__(self, other): + return self.text == other.text and self.font == other.font + + + def __str__(self): + """Just retun the text""" + return self.text + + + def __repr__(self): + font = self.font != InlineFont() and self.font or "default" + return f"{self.__class__.__name__} text={self.text}, font={font}" + + + def to_tree(self): + el = Element("r") + el.append(self.font.to_tree(tagname="rPr")) + t = Element("t") + t.text = self.text + whitespace(t) + el.append(t) + return el + +# +# Rich Text class. +# This class behaves just like a list whose members are either simple strings, or TextBlock() instances. +# In addition, it can be initialized in several ways: +# t = CellRFichText([...]) # initialize with a list. +# t = CellRFichText((...)) # initialize with a tuple. +# t = CellRichText(node) # where node is an Element() from either lxml or xml.etree (has a 'tag' element) +class CellRichText(list): + """Represents a rich text string. + + Initialize with a list made of pure strings or :class:`TextBlock` elements + Can index object to access or modify individual rich text elements + it also supports the + and += operators between rich text strings + There are no user methods for this class + + operations which modify the string will generally call an optimization pass afterwards, + that merges text blocks with identical formats, consecutive pure text strings, + and remove empty strings and empty text blocks + """ + + def __init__(self, *args): + if len(args) == 1: + args = args[0] + if isinstance(args, (list, tuple)): + CellRichText._check_rich_text(args) + else: + CellRichText._check_element(args) + args = [args] + else: + CellRichText._check_rich_text(args) + super().__init__(args) + + + @classmethod + def _check_element(cls, value): + if not isinstance(value, (str, TextBlock, NUMERIC_TYPES)): + raise TypeError(f"Illegal CellRichText element {value}") + + + @classmethod + def _check_rich_text(cls, rich_text): + for t in rich_text: + CellRichText._check_element(t) + + @classmethod + def from_tree(cls, node): + text = Text.from_tree(node) + if text.t: + return (text.t.replace('x005F_', ''),) + s = [] + for r in text.r: + t = "" + if r.t: + t = r.t.replace('x005F_', '') + if r.rPr: + s.append(TextBlock(r.rPr, t)) + else: + s.append(t) + return cls(s) + + # Merge TextBlocks with identical formatting + # remove empty elements + def _opt(self): + last_t = None + l = CellRichText(tuple()) + for t in self: + if isinstance(t, str): + if not t: + continue + elif not t.text: + continue + if type(last_t) == type(t): + if isinstance(t, str): + last_t += t + continue + elif last_t.font == t.font: + last_t.text += t.text + continue + if last_t: + l.append(last_t) + last_t = t + if last_t: + # Add remaining TextBlock at end of rich text + l.append(last_t) + super().__setitem__(slice(None), l) + return self + + + def __iadd__(self, arg): + # copy used here to create new TextBlock() so we don't modify the right hand side in _opt() + CellRichText._check_rich_text(arg) + super().__iadd__([copy(e) for e in list(arg)]) + return self._opt() + + + def __add__(self, arg): + return CellRichText([copy(e) for e in list(self) + list(arg)])._opt() + + + def __setitem__(self, indx, val): + CellRichText._check_element(val) + super().__setitem__(indx, val) + self._opt() + + + def append(self, arg): + CellRichText._check_element(arg) + super().append(arg) + + + def extend(self, arg): + CellRichText._check_rich_text(arg) + super().extend(arg) + + + def __repr__(self): + return "CellRichText([{}])".format(', '.join((repr(s) for s in self))) + + + def __str__(self): + return ''.join([str(s) for s in self]) + + + def as_list(self): + """ + Returns a list of the strings contained. + The main reason for this is to make editing easier. + """ + return [str(s) for s in self] + + + def to_tree(self): + """ + Return the full XML representation + """ + container = Element("is") + for obj in self: + if isinstance(obj, TextBlock): + container.append(obj.to_tree()) + + else: + el = Element("r") + t = Element("t") + t.text = obj + whitespace(t) + el.append(t) + container.append(el) + + return container + |