From 4c008d0ca05865fac5efa825e0f5bab46bb2bc09 Mon Sep 17 00:00:00 2001
From: Avasam <samuel.06@hotmail.com>
Date: Sat, 3 May 2025 12:54:29 -0400
Subject: [PATCH] Openpyxl: type cell values

---
 stubs/openpyxl/openpyxl/cell/__init__.pyi     |  6 ++-
 stubs/openpyxl/openpyxl/cell/cell.pyi         | 13 +++---
 stubs/openpyxl/openpyxl/cell/read_only.pyi    |  6 +--
 .../openpyxl/chart/series_factory.pyi         |  8 ++--
 .../openpyxl/worksheet/_read_only.pyi         |  4 +-
 .../openpyxl/openpyxl/worksheet/worksheet.pyi | 45 +++++++++----------
 6 files changed, 40 insertions(+), 42 deletions(-)

diff --git a/stubs/openpyxl/openpyxl/cell/__init__.pyi b/stubs/openpyxl/openpyxl/cell/__init__.pyi
index 54641897e49a..5501a28fd6eb 100644
--- a/stubs/openpyxl/openpyxl/cell/__init__.pyi
+++ b/stubs/openpyxl/openpyxl/cell/__init__.pyi
@@ -10,7 +10,7 @@ from .cell import Cell as Cell, MergedCell as MergedCell, WriteOnlyCell as Write
 from .read_only import ReadOnlyCell as ReadOnlyCell
 
 _TimeTypes: TypeAlias = datetime | date | time | timedelta
-_CellValue: TypeAlias = (  # noqa: Y047 # Used in other modules
+_CellGetValue: TypeAlias = (  # noqa: Y047 # Used in other modules
     # if numpy is installed also numpy bool and number types
     bool
     | float
@@ -20,7 +20,9 @@ _CellValue: TypeAlias = (  # noqa: Y047 # Used in other modules
     | _TimeTypes
     | DataTableFormula
     | ArrayFormula
+    | None
 )
-_AnyCellValue: TypeAlias = Any  # Any of _CellValue # noqa: Y047 # Used in other modules
+_AnyCellValue: TypeAlias = Any  # AnyOf _CellGetValue # noqa: Y047 # Used in other modules
+_CellSetValue: TypeAlias = _CellGetValue | bytes  # noqa: Y047 # Used in other modules
 
 _CellOrMergedCell: TypeAlias = Cell | MergedCell  # noqa: Y047 # Used in other modules
diff --git a/stubs/openpyxl/openpyxl/cell/cell.pyi b/stubs/openpyxl/openpyxl/cell/cell.pyi
index dea71e03d8a8..fb5cbb54545c 100644
--- a/stubs/openpyxl/openpyxl/cell/cell.pyi
+++ b/stubs/openpyxl/openpyxl/cell/cell.pyi
@@ -3,7 +3,7 @@ from datetime import datetime
 from re import Pattern
 from typing import Final, Literal, overload
 
-from openpyxl.cell import _CellOrMergedCell, _CellValue, _TimeTypes
+from openpyxl.cell import _CellGetValue, _CellOrMergedCell, _CellSetValue, _TimeTypes
 from openpyxl.comments.comments import Comment
 from openpyxl.compat.numbers import NUMERIC_TYPES as NUMERIC_TYPES  # cell numeric types
 from openpyxl.styles.cell_style import StyleArray
@@ -45,7 +45,7 @@ class Cell(StyleableObject):
         worksheet: _WorkbookChild | ReadOnlyWorksheet,
         row: int,
         column: int,
-        value: str | float | datetime | None = None,
+        value: _CellSetValue = None,
         style_array: StyleArray | None = None,
     ) -> None: ...
     @property
@@ -64,11 +64,11 @@ class Cell(StyleableObject):
     def check_string(self, value: str | ReadableBuffer) -> str: ...
     def check_error(self, value: object) -> str: ...
     @property
-    def value(self) -> _CellValue | None: ...
+    def value(self) -> _CellGetValue: ...
     @value.setter
-    def value(self, value: _CellValue | bytes | None) -> None: ...
+    def value(self, value: _CellSetValue) -> None: ...
     @property
-    def internal_value(self) -> _CellValue | None: ...
+    def internal_value(self) -> _CellGetValue: ...
     @property
     def hyperlink(self) -> Hyperlink | None: ...
     @hyperlink.setter
@@ -94,6 +94,7 @@ class MergedCell(StyleableObject):
     # https://github.com/python/mypy/issues/6700
     @property
     def coordinate(self) -> str: ...
-    value: str | float | int | datetime | None
+    # The value of a MergedCell is always None.
+    value: None
 
 def WriteOnlyCell(ws: _WorkbookChild | ReadOnlyWorksheet, value: str | float | datetime | None = None) -> Cell: ...
diff --git a/stubs/openpyxl/openpyxl/cell/read_only.pyi b/stubs/openpyxl/openpyxl/cell/read_only.pyi
index 170624f03860..b8dd7cf3226e 100644
--- a/stubs/openpyxl/openpyxl/cell/read_only.pyi
+++ b/stubs/openpyxl/openpyxl/cell/read_only.pyi
@@ -1,7 +1,7 @@
 from _typeshed import Incomplete
 from typing import Final
 
-from openpyxl.cell import _CellValue
+from openpyxl.cell import _CellGetValue
 from openpyxl.styles.alignment import Alignment
 from openpyxl.styles.borders import Border
 from openpyxl.styles.cell_style import StyleArray
@@ -51,9 +51,9 @@ class ReadOnlyCell:
     @property
     def is_date(self) -> bool: ...
     @property
-    def internal_value(self) -> _CellValue | None: ...
+    def internal_value(self) -> _CellGetValue: ...
     @property
-    def value(self) -> _CellValue | None: ...
+    def value(self) -> _CellGetValue: ...
     @value.setter
     def value(self, value: None) -> None: ...
 
diff --git a/stubs/openpyxl/openpyxl/chart/series_factory.pyi b/stubs/openpyxl/openpyxl/chart/series_factory.pyi
index 93bc957ff400..9faddc33a413 100644
--- a/stubs/openpyxl/openpyxl/chart/series_factory.pyi
+++ b/stubs/openpyxl/openpyxl/chart/series_factory.pyi
@@ -1,9 +1,9 @@
-from _typeshed import Incomplete
+from .reference import Reference
 
 def SeriesFactory(
-    values,
-    xvalues: Incomplete | None = None,
-    zvalues: Incomplete | None = None,
+    values: Reference | str,
+    xvalues: Reference | str | None = None,
+    zvalues: Reference | str | None = None,
     title: object = None,
     title_from_data: bool = False,
 ): ...
diff --git a/stubs/openpyxl/openpyxl/worksheet/_read_only.pyi b/stubs/openpyxl/openpyxl/worksheet/_read_only.pyi
index 0579afc366a4..fbd34ec813a3 100644
--- a/stubs/openpyxl/openpyxl/worksheet/_read_only.pyi
+++ b/stubs/openpyxl/openpyxl/worksheet/_read_only.pyi
@@ -2,7 +2,7 @@ from _typeshed import SupportsGetItem
 from collections.abc import Generator
 
 from openpyxl import _VisibilityType
-from openpyxl.cell import _CellOrMergedCell, _CellValue
+from openpyxl.cell import _CellGetValue, _CellOrMergedCell
 from openpyxl.utils.cell import _RangeBoundariesTuple
 from openpyxl.workbook.workbook import Workbook
 from openpyxl.worksheet.worksheet import Worksheet
@@ -15,7 +15,7 @@ class ReadOnlyWorksheet:
     # Same as Worksheet.values
     # https://github.com/python/mypy/issues/6700
     @property
-    def values(self) -> Generator[tuple[_CellValue, ...], None, None]: ...
+    def values(self) -> Generator[tuple[_CellGetValue, ...], None, None]: ...
     # Same as Worksheet.rows
     # https://github.com/python/mypy/issues/6700
     @property
diff --git a/stubs/openpyxl/openpyxl/worksheet/worksheet.pyi b/stubs/openpyxl/openpyxl/worksheet/worksheet.pyi
index 6b40a85a7be6..87819280da3a 100644
--- a/stubs/openpyxl/openpyxl/worksheet/worksheet.pyi
+++ b/stubs/openpyxl/openpyxl/worksheet/worksheet.pyi
@@ -1,12 +1,11 @@
 from _typeshed import ConvertibleToInt, Incomplete
 from collections.abc import Generator, Iterable, Iterator
-from datetime import datetime
 from types import GeneratorType
 from typing import Any, Final, Literal, NoReturn, overload
 from typing_extensions import deprecated
 
 from openpyxl import _Decodable, _VisibilityType
-from openpyxl.cell import _CellOrMergedCell, _CellValue
+from openpyxl.cell import _AnyCellValue, _CellGetValue, _CellOrMergedCell, _CellSetValue
 from openpyxl.cell.cell import Cell
 from openpyxl.chart._chart import ChartBase
 from openpyxl.drawing.image import Image
@@ -87,7 +86,11 @@ class Worksheet(_WorkbookChild):
     def freeze_panes(self) -> str | None: ...
     @freeze_panes.setter
     def freeze_panes(self, topLeftCell: str | Cell | None = None) -> None: ...
-    def cell(self, row: int, column: int, value: _CellValue | None = None) -> _CellOrMergedCell: ...
+    # A MergedCell value should be kept to None
+    @overload
+    def cell(self, row: int, column: int, value: None = None) -> _CellOrMergedCell: ...
+    @overload
+    def cell(self, row: int, column: int, value: _CellSetValue = None) -> Cell: ...
     # An int is necessarily a row selection
     @overload
     def __getitem__(self, key: int) -> tuple[_CellOrMergedCell, ...]: ...
@@ -99,7 +102,7 @@ class Worksheet(_WorkbookChild):
     def __getitem__(
         self, key: str
     ) -> Any: ...  # AnyOf[_CellOrMergedCell, tuple[_CellOrMergedCell, ...], tuple[tuple[_CellOrMergedCell, ...], ...]]
-    def __setitem__(self, key: str, value: _CellValue) -> None: ...
+    def __setitem__(self, key: str, value: _CellSetValue) -> None: ...
     def __iter__(self) -> Iterator[tuple[_CellOrMergedCell, ...]]: ...
     def __delitem__(self, key: str) -> None: ...
     @property
@@ -116,7 +119,7 @@ class Worksheet(_WorkbookChild):
     @overload
     def iter_rows(
         self, min_row: int | None, max_row: int | None, min_col: int | None, max_col: int | None, values_only: Literal[True]
-    ) -> Generator[tuple[str | float | datetime | None, ...], None, None]: ...
+    ) -> Generator[tuple[_CellGetValue, ...], None, None]: ...
     @overload
     def iter_rows(
         self,
@@ -126,7 +129,7 @@ class Worksheet(_WorkbookChild):
         max_col: int | None = None,
         *,
         values_only: Literal[True],
-    ) -> Generator[tuple[str | float | datetime | None, ...], None, None]: ...
+    ) -> Generator[tuple[_CellGetValue, ...], None, None]: ...
     @overload
     def iter_rows(
         self,
@@ -139,9 +142,7 @@ class Worksheet(_WorkbookChild):
     @overload
     def iter_rows(
         self, min_row: int | None, max_row: int | None, min_col: int | None, max_col: int | None, values_only: bool
-    ) -> (
-        Generator[tuple[_CellOrMergedCell, ...], None, None] | Generator[tuple[str | float | datetime | None, ...], None, None]
-    ): ...
+    ) -> Generator[tuple[_CellOrMergedCell, ...], None, None] | Generator[tuple[_CellGetValue, ...], None, None]: ...
     @overload
     def iter_rows(
         self,
@@ -151,17 +152,15 @@ class Worksheet(_WorkbookChild):
         max_col: int | None = None,
         *,
         values_only: bool,
-    ) -> (
-        Generator[tuple[_CellOrMergedCell, ...], None, None] | Generator[tuple[str | float | datetime | None, ...], None, None]
-    ): ...
+    ) -> Generator[tuple[_CellOrMergedCell, ...], None, None] | Generator[tuple[_CellGetValue, ...], None, None]: ...
     @property
     def rows(self) -> Generator[tuple[_CellOrMergedCell, ...], None, None]: ...
     @property
-    def values(self) -> Generator[tuple[_CellValue | None, ...]]: ...
+    def values(self) -> Generator[tuple[_CellGetValue, ...]]: ...
     @overload
     def iter_cols(
         self, min_col: int | None, max_col: int | None, min_row: int | None, max_row: int | None, values_only: Literal[True]
-    ) -> Generator[tuple[str | float | datetime | None, ...], None, None]: ...
+    ) -> Generator[tuple[_CellGetValue, ...], None, None]: ...
     @overload
     def iter_cols(
         self,
@@ -171,7 +170,7 @@ class Worksheet(_WorkbookChild):
         max_row: int | None = None,
         *,
         values_only: Literal[True],
-    ) -> Generator[tuple[str | float | datetime | None, ...], None, None]: ...
+    ) -> Generator[tuple[_CellGetValue, ...], None, None]: ...
     @overload
     def iter_cols(
         self,
@@ -184,9 +183,7 @@ class Worksheet(_WorkbookChild):
     @overload
     def iter_cols(
         self, min_col: int | None, max_col: int | None, min_row: int | None, max_row: int | None, values_only: bool
-    ) -> (
-        Generator[tuple[_CellOrMergedCell, ...], None, None] | Generator[tuple[str | float | datetime | None, ...], None, None]
-    ): ...
+    ) -> Generator[tuple[_CellOrMergedCell, ...], None, None] | Generator[tuple[_CellGetValue, ...], None, None]: ...
     @overload
     def iter_cols(
         self,
@@ -196,9 +193,7 @@ class Worksheet(_WorkbookChild):
         max_row: int | None = None,
         *,
         values_only: bool,
-    ) -> (
-        Generator[tuple[_CellOrMergedCell, ...], None, None] | Generator[tuple[str | float | datetime | None, ...], None, None]
-    ): ...
+    ) -> Generator[tuple[_CellOrMergedCell, ...], None, None] | Generator[tuple[_CellGetValue, ...], None, None]: ...
     @property
     def columns(self) -> Generator[tuple[_CellOrMergedCell, ...], None, None]: ...
     @property
@@ -252,11 +247,11 @@ class Worksheet(_WorkbookChild):
     def append(
         self,
         iterable: (
-            list[Any]  # lists are invariant, but any subtype or union will do
-            | tuple[_CellOrMergedCell | str | float | datetime | None, ...]
+            list[_AnyCellValue]
+            | tuple[_CellOrMergedCell | _CellGetValue, ...]
             | range
-            | GeneratorType[_CellOrMergedCell | str | float | datetime | None, object, object]
-            | dict[int | str, str | float | datetime | None]
+            | GeneratorType[_CellOrMergedCell | _CellGetValue, object, object]
+            | dict[int | str, _AnyCellValue]
         ),
     ) -> None: ...
     def insert_rows(self, idx: int, amount: int = 1) -> None: ...