Updated script that can be controled by Nodejs web app
This commit is contained in:
202
lib/python3.13/site-packages/openpyxl/cell/rich_text.py
Normal file
202
lib/python3.13/site-packages/openpyxl/cell/rich_text.py
Normal file
@ -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
|
||||
|
Reference in New Issue
Block a user