about summary refs log tree commit diff
path: root/.venv/lib/python3.12/site-packages/openpyxl/cell/cell.py
diff options
context:
space:
mode:
Diffstat (limited to '.venv/lib/python3.12/site-packages/openpyxl/cell/cell.py')
-rw-r--r--.venv/lib/python3.12/site-packages/openpyxl/cell/cell.py332
1 files changed, 332 insertions, 0 deletions
diff --git a/.venv/lib/python3.12/site-packages/openpyxl/cell/cell.py b/.venv/lib/python3.12/site-packages/openpyxl/cell/cell.py
new file mode 100644
index 00000000..d29be280
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/openpyxl/cell/cell.py
@@ -0,0 +1,332 @@
+# Copyright (c) 2010-2024 openpyxl
+
+"""Manage individual cells in a spreadsheet.
+
+The Cell class is required to know its value and type, display options,
+and any other features of an Excel cell.  Utilities for referencing
+cells using Excel's 'A1' column/row nomenclature are also provided.
+
+"""
+
+__docformat__ = "restructuredtext en"
+
+# Python stdlib imports
+from copy import copy
+import datetime
+import re
+
+
+from openpyxl.compat import (
+    NUMERIC_TYPES,
+)
+
+from openpyxl.utils.exceptions import IllegalCharacterError
+
+from openpyxl.utils import get_column_letter
+from openpyxl.styles import numbers, is_date_format
+from openpyxl.styles.styleable import StyleableObject
+from openpyxl.worksheet.hyperlink import Hyperlink
+from openpyxl.worksheet.formula import DataTableFormula, ArrayFormula
+from openpyxl.cell.rich_text import CellRichText
+
+# constants
+
+TIME_TYPES = (datetime.datetime, datetime.date, datetime.time, datetime.timedelta)
+TIME_FORMATS = {
+    datetime.datetime:numbers.FORMAT_DATE_DATETIME,
+    datetime.date:numbers.FORMAT_DATE_YYYYMMDD2,
+    datetime.time:numbers.FORMAT_DATE_TIME6,
+    datetime.timedelta:numbers.FORMAT_DATE_TIMEDELTA,
+                }
+
+STRING_TYPES = (str, bytes, CellRichText)
+KNOWN_TYPES = NUMERIC_TYPES + TIME_TYPES + STRING_TYPES + (bool, type(None))
+
+ILLEGAL_CHARACTERS_RE = re.compile(r'[\000-\010]|[\013-\014]|[\016-\037]')
+ERROR_CODES = ('#NULL!', '#DIV/0!', '#VALUE!', '#REF!', '#NAME?', '#NUM!',
+               '#N/A')
+
+TYPE_STRING = 's'
+TYPE_FORMULA = 'f'
+TYPE_NUMERIC = 'n'
+TYPE_BOOL = 'b'
+TYPE_NULL = 'n'
+TYPE_INLINE = 'inlineStr'
+TYPE_ERROR = 'e'
+TYPE_FORMULA_CACHE_STRING = 'str'
+
+VALID_TYPES = (TYPE_STRING, TYPE_FORMULA, TYPE_NUMERIC, TYPE_BOOL,
+               TYPE_NULL, TYPE_INLINE, TYPE_ERROR, TYPE_FORMULA_CACHE_STRING)
+
+
+_TYPES = {int:'n', float:'n', str:'s', bool:'b'}
+
+
+def get_type(t, value):
+    if isinstance(value, NUMERIC_TYPES):
+        dt = 'n'
+    elif isinstance(value, STRING_TYPES):
+        dt = 's'
+    elif isinstance(value, TIME_TYPES):
+        dt = 'd'
+    elif isinstance(value, (DataTableFormula, ArrayFormula)):
+        dt = 'f'
+    else:
+        return
+    _TYPES[t] = dt
+    return dt
+
+
+def get_time_format(t):
+    value = TIME_FORMATS.get(t)
+    if value:
+        return value
+    for base in t.mro()[1:]:
+        value = TIME_FORMATS.get(base)
+        if value:
+            TIME_FORMATS[t] = value
+            return value
+    raise ValueError("Could not get time format for {0!r}".format(value))
+
+
+class Cell(StyleableObject):
+    """Describes cell associated properties.
+
+    Properties of interest include style, type, value, and address.
+
+    """
+    __slots__ = (
+        'row',
+        'column',
+        '_value',
+        'data_type',
+        'parent',
+        '_hyperlink',
+        '_comment',
+                 )
+
+    def __init__(self, worksheet, row=None, column=None, value=None, style_array=None):
+        super().__init__(worksheet, style_array)
+        self.row = row
+        """Row number of this cell (1-based)"""
+        self.column = column
+        """Column number of this cell (1-based)"""
+        # _value is the stored value, while value is the displayed value
+        self._value = None
+        self._hyperlink = None
+        self.data_type = 'n'
+        if value is not None:
+            self.value = value
+        self._comment = None
+
+
+    @property
+    def coordinate(self):
+        """This cell's coordinate (ex. 'A5')"""
+        col = get_column_letter(self.column)
+        return f"{col}{self.row}"
+
+
+    @property
+    def col_idx(self):
+        """The numerical index of the column"""
+        return self.column
+
+
+    @property
+    def column_letter(self):
+        return get_column_letter(self.column)
+
+
+    @property
+    def encoding(self):
+        return self.parent.encoding
+
+    @property
+    def base_date(self):
+        return self.parent.parent.epoch
+
+
+    def __repr__(self):
+        return "<Cell {0!r}.{1}>".format(self.parent.title, self.coordinate)
+
+    def check_string(self, value):
+        """Check string coding, length, and line break character"""
+        if value is None:
+            return
+        # convert to str string
+        if not isinstance(value, str):
+            value = str(value, self.encoding)
+        value = str(value)
+        # string must never be longer than 32,767 characters
+        # truncate if necessary
+        value = value[:32767]
+        if next(ILLEGAL_CHARACTERS_RE.finditer(value), None):
+            raise IllegalCharacterError(f"{value} cannot be used in worksheets.")
+        return value
+
+    def check_error(self, value):
+        """Tries to convert Error" else N/A"""
+        try:
+            return str(value)
+        except UnicodeDecodeError:
+            return u'#N/A'
+
+
+    def _bind_value(self, value):
+        """Given a value, infer the correct data type"""
+
+        self.data_type = "n"
+        t = type(value)
+        try:
+            dt = _TYPES[t]
+        except KeyError:
+            dt = get_type(t, value)
+
+        if dt is None and value is not None:
+            raise ValueError("Cannot convert {0!r} to Excel".format(value))
+
+        if dt:
+            self.data_type = dt
+
+        if dt == 'd':
+            if not is_date_format(self.number_format):
+                self.number_format = get_time_format(t)
+
+        elif dt == "s" and not isinstance(value, CellRichText):
+            value = self.check_string(value)
+            if len(value) > 1 and value.startswith("="):
+                self.data_type = 'f'
+            elif value in ERROR_CODES:
+                self.data_type = 'e'
+
+        self._value = value
+
+
+    @property
+    def value(self):
+        """Get or set the value held in the cell.
+
+        :type: depends on the value (string, float, int or
+            :class:`datetime.datetime`)
+        """
+        return self._value
+
+    @value.setter
+    def value(self, value):
+        """Set the value and infer type and display options."""
+        self._bind_value(value)
+
+    @property
+    def internal_value(self):
+        """Always returns the value for excel."""
+        return self._value
+
+    @property
+    def hyperlink(self):
+        """Return the hyperlink target or an empty string"""
+        return self._hyperlink
+
+
+    @hyperlink.setter
+    def hyperlink(self, val):
+        """Set value and display for hyperlinks in a cell.
+        Automatically sets the `value` of the cell with link text,
+        but you can modify it afterwards by setting the `value`
+        property, and the hyperlink will remain.
+        Hyperlink is removed if set to ``None``."""
+        if val is None:
+            self._hyperlink = None
+        else:
+            if not isinstance(val, Hyperlink):
+                val = Hyperlink(ref="", target=val)
+            val.ref = self.coordinate
+            self._hyperlink = val
+            if self._value is None:
+                self.value = val.target or val.location
+
+
+    @property
+    def is_date(self):
+        """True if the value is formatted as a date
+
+        :type: bool
+        """
+        return self.data_type == 'd' or (
+            self.data_type == 'n' and is_date_format(self.number_format)
+            )
+
+
+    def offset(self, row=0, column=0):
+        """Returns a cell location relative to this cell.
+
+        :param row: number of rows to offset
+        :type row: int
+
+        :param column: number of columns to offset
+        :type column: int
+
+        :rtype: :class:`openpyxl.cell.Cell`
+        """
+        offset_column = self.col_idx + column
+        offset_row = self.row + row
+        return self.parent.cell(column=offset_column, row=offset_row)
+
+
+    @property
+    def comment(self):
+        """ Returns the comment associated with this cell
+
+            :type: :class:`openpyxl.comments.Comment`
+        """
+        return self._comment
+
+
+    @comment.setter
+    def comment(self, value):
+        """
+        Assign a comment to a cell
+        """
+
+        if value is not None:
+            if value.parent:
+                value = copy(value)
+            value.bind(self)
+        elif value is None and self._comment:
+            self._comment.unbind()
+        self._comment = value
+
+
+class MergedCell(StyleableObject):
+
+    """
+    Describes the properties of a cell in a merged cell and helps to
+    display the borders of the merged cell.
+
+    The value of a MergedCell is always None.
+    """
+
+    __slots__ = ('row', 'column')
+
+    _value = None
+    data_type = "n"
+    comment = None
+    hyperlink = None
+
+
+    def __init__(self, worksheet, row=None, column=None):
+        super().__init__(worksheet)
+        self.row = row
+        self.column = column
+
+
+    def __repr__(self):
+        return "<MergedCell {0!r}.{1}>".format(self.parent.title, self.coordinate)
+
+    coordinate = Cell.coordinate
+    _comment = comment
+    value = _value
+
+
+def WriteOnlyCell(ws=None, value=None):
+    return Cell(worksheet=ws, column=1, row=1, value=value)