about summary refs log tree commit diff
path: root/.venv/lib/python3.12/site-packages/openpyxl/styles/named_styles.py
diff options
context:
space:
mode:
Diffstat (limited to '.venv/lib/python3.12/site-packages/openpyxl/styles/named_styles.py')
-rw-r--r--.venv/lib/python3.12/site-packages/openpyxl/styles/named_styles.py282
1 files changed, 282 insertions, 0 deletions
diff --git a/.venv/lib/python3.12/site-packages/openpyxl/styles/named_styles.py b/.venv/lib/python3.12/site-packages/openpyxl/styles/named_styles.py
new file mode 100644
index 00000000..221d333b
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/openpyxl/styles/named_styles.py
@@ -0,0 +1,282 @@
+# Copyright (c) 2010-2024 openpyxl
+
+from openpyxl.compat import safe_string
+
+from openpyxl.descriptors import (
+    Typed,
+    Integer,
+    Bool,
+    String,
+    Sequence,
+)
+from openpyxl.descriptors.excel import ExtensionList
+from openpyxl.descriptors.serialisable import Serialisable
+
+from .fills import PatternFill, Fill
+from .fonts import Font
+from .borders import Border
+from .alignment import Alignment
+from .protection import Protection
+from .numbers import (
+    NumberFormatDescriptor,
+    BUILTIN_FORMATS_MAX_SIZE,
+    BUILTIN_FORMATS_REVERSE,
+)
+from .cell_style import (
+    StyleArray,
+    CellStyle,
+)
+
+
+class NamedStyle(Serialisable):
+
+    """
+    Named and editable styles
+    """
+
+    font = Typed(expected_type=Font)
+    fill = Typed(expected_type=Fill)
+    border = Typed(expected_type=Border)
+    alignment = Typed(expected_type=Alignment)
+    number_format = NumberFormatDescriptor()
+    protection = Typed(expected_type=Protection)
+    builtinId = Integer(allow_none=True)
+    hidden = Bool(allow_none=True)
+    name = String()
+    _wb = None
+    _style = StyleArray()
+
+
+    def __init__(self,
+                 name="Normal",
+                 font=None,
+                 fill=None,
+                 border=None,
+                 alignment=None,
+                 number_format=None,
+                 protection=None,
+                 builtinId=None,
+                 hidden=False,
+                 ):
+        self.name = name
+        self.font = font or Font()
+        self.fill = fill or PatternFill()
+        self.border = border or Border()
+        self.alignment = alignment or Alignment()
+        self.number_format = number_format
+        self.protection = protection or Protection()
+        self.builtinId = builtinId
+        self.hidden = hidden
+        self._wb = None
+        self._style = StyleArray()
+
+
+    def __setattr__(self, attr, value):
+        super().__setattr__(attr, value)
+        if getattr(self, '_wb', None) and attr in (
+           'font', 'fill', 'border', 'alignment', 'number_format', 'protection',
+            ):
+            self._recalculate()
+
+
+    def __iter__(self):
+        for key in ('name', 'builtinId', 'hidden', 'xfId'):
+            value = getattr(self, key, None)
+            if value is not None:
+                yield key, safe_string(value)
+
+
+    def bind(self, wb):
+        """
+        Bind a named style to a workbook
+        """
+        self._wb = wb
+        self._recalculate()
+
+
+    def _recalculate(self):
+        self._style.fontId =  self._wb._fonts.add(self.font)
+        self._style.borderId = self._wb._borders.add(self.border)
+        self._style.fillId =  self._wb._fills.add(self.fill)
+        self._style.protectionId = self._wb._protections.add(self.protection)
+        self._style.alignmentId = self._wb._alignments.add(self.alignment)
+        fmt = self.number_format
+        if fmt in BUILTIN_FORMATS_REVERSE:
+            fmt = BUILTIN_FORMATS_REVERSE[fmt]
+        else:
+            fmt = self._wb._number_formats.add(self.number_format) + (
+                  BUILTIN_FORMATS_MAX_SIZE)
+        self._style.numFmtId = fmt
+
+
+    def as_tuple(self):
+        """Return a style array representing the current style"""
+        return self._style
+
+
+    def as_xf(self):
+        """
+        Return equivalent XfStyle
+        """
+        xf = CellStyle.from_array(self._style)
+        xf.xfId = None
+        xf.pivotButton = None
+        xf.quotePrefix = None
+        if self.alignment != Alignment():
+            xf.alignment = self.alignment
+        if self.protection != Protection():
+            xf.protection = self.protection
+        return xf
+
+
+    def as_name(self):
+        """
+        Return relevant named style
+
+        """
+        named = _NamedCellStyle(
+            name=self.name,
+            builtinId=self.builtinId,
+            hidden=self.hidden,
+            xfId=self._style.xfId
+        )
+        return named
+
+
+class NamedStyleList(list):
+    """
+    Named styles are editable and can be applied to multiple objects
+
+    As only the index is stored in referencing objects the order mus
+    be preserved.
+
+    Returns a list of NamedStyles
+    """
+
+    def __init__(self, iterable=()):
+        """
+        Allow a list of named styles to be passed in and index them.
+        """
+
+        for idx, s in enumerate(iterable, len(self)):
+            s._style.xfId = idx
+        super().__init__(iterable)
+
+
+    @property
+    def names(self):
+        return [s.name for s in self]
+
+
+    def __getitem__(self, key):
+        if isinstance(key, int):
+            return super().__getitem__(key)
+
+
+        for idx, name in enumerate(self.names):
+            if name == key:
+                return self[idx]
+
+        raise KeyError("No named style with the name{0} exists".format(key))
+
+    def append(self, style):
+        if not isinstance(style, NamedStyle):
+            raise TypeError("""Only NamedStyle instances can be added""")
+        elif style.name in self.names: # hotspot
+            raise ValueError("""Style {0} exists already""".format(style.name))
+        style._style.xfId = (len(self))
+        super().append(style)
+
+
+class _NamedCellStyle(Serialisable):
+
+    """
+    Pointer-based representation of named styles in XML
+    xfId refers to the corresponding CellStyleXfs
+
+    Not used in client code.
+    """
+
+    tagname = "cellStyle"
+
+    name = String()
+    xfId = Integer()
+    builtinId = Integer(allow_none=True)
+    iLevel = Integer(allow_none=True)
+    hidden = Bool(allow_none=True)
+    customBuiltin = Bool(allow_none=True)
+    extLst = Typed(expected_type=ExtensionList, allow_none=True)
+
+    __elements__ = ()
+
+
+    def __init__(self,
+                 name=None,
+                 xfId=None,
+                 builtinId=None,
+                 iLevel=None,
+                 hidden=None,
+                 customBuiltin=None,
+                 extLst=None,
+                ):
+        self.name = name
+        self.xfId = xfId
+        self.builtinId = builtinId
+        self.iLevel = iLevel
+        self.hidden = hidden
+        self.customBuiltin = customBuiltin
+
+
+class _NamedCellStyleList(Serialisable):
+    """
+    Container for named cell style objects
+
+    Not used in client code
+    """
+
+    tagname = "cellStyles"
+
+    count = Integer(allow_none=True)
+    cellStyle = Sequence(expected_type=_NamedCellStyle)
+
+    __attrs__ = ("count",)
+
+    def __init__(self,
+                 count=None,
+                 cellStyle=(),
+                ):
+        self.cellStyle = cellStyle
+
+
+    @property
+    def count(self):
+        return len(self.cellStyle)
+
+
+    def remove_duplicates(self):
+        """
+        Some applications contain duplicate definitions either by name or
+        referenced style.
+
+        As the references are 0-based indices, styles are sorted by
+        index.
+
+        Returns a list of style references with duplicates removed
+        """
+
+        def sort_fn(v):
+            return v.xfId
+
+        styles = []
+        names = set()
+        ids = set()
+
+        for ns in sorted(self.cellStyle, key=sort_fn):
+            if ns.xfId in ids or ns.name in names: # skip duplicates
+                continue
+            ids.add(ns.xfId)
+            names.add(ns.name)
+
+            styles.append(ns)
+
+        return styles