From fcad764d200d6f7bbb4e276d1c3012f07b8265a4 Mon Sep 17 00:00:00 2001 From: Avasam Date: Sat, 30 Mar 2024 17:09:45 -0400 Subject: [PATCH 1/3] Extracted worksheet changes from big Merge PR --- stubs/openpyxl/openpyxl/cell/cell.pyi | 8 +++--- stubs/openpyxl/openpyxl/reader/workbook.pyi | 7 +++-- stubs/openpyxl/openpyxl/workbook/workbook.pyi | 26 +++++++++++-------- stubs/openpyxl/openpyxl/worksheet/_reader.pyi | 5 ++-- stubs/openpyxl/openpyxl/worksheet/_writer.pyi | 7 +++-- 5 files changed, 30 insertions(+), 23 deletions(-) diff --git a/stubs/openpyxl/openpyxl/cell/cell.pyi b/stubs/openpyxl/openpyxl/cell/cell.pyi index 3b1c1c7437ae..3b5643673054 100644 --- a/stubs/openpyxl/openpyxl/cell/cell.pyi +++ b/stubs/openpyxl/openpyxl/cell/cell.pyi @@ -8,8 +8,8 @@ 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 from openpyxl.styles.styleable import StyleableObject +from openpyxl.workbook.child import _WorkbookChild from openpyxl.worksheet.hyperlink import Hyperlink -from openpyxl.worksheet.worksheet import Worksheet __docformat__: Final = "restructuredtext en" TIME_TYPES: Final[tuple[type, ...]] @@ -41,7 +41,7 @@ class Cell(StyleableObject): # row and column are never meant to be None and would lead to errors def __init__( self, - worksheet: Worksheet, + worksheet: _WorkbookChild, row: int, column: int, value: str | float | datetime | None = None, @@ -86,10 +86,10 @@ class MergedCell(StyleableObject): hyperlink: Hyperlink | None row: int | None column: int | None - def __init__(self, worksheet: Worksheet, row: int | None = None, column: int | None = None) -> None: ... + def __init__(self, worksheet: _WorkbookChild, row: int | None = None, column: int | None = None) -> None: ... # Same as Cell.coordinate @property def coordinate(self) -> str: ... value: str | float | int | datetime | None -def WriteOnlyCell(ws: Worksheet | None = None, value: str | float | datetime | None = None) -> Cell: ... +def WriteOnlyCell(ws: _WorkbookChild | None = None, value: str | float | datetime | None = None) -> Cell: ... diff --git a/stubs/openpyxl/openpyxl/reader/workbook.pyi b/stubs/openpyxl/openpyxl/reader/workbook.pyi index d27a6deb9e59..4faa3c1f5e6c 100644 --- a/stubs/openpyxl/openpyxl/reader/workbook.pyi +++ b/stubs/openpyxl/openpyxl/reader/workbook.pyi @@ -1,9 +1,8 @@ -from _typeshed import Incomplete from collections.abc import Generator from zipfile import ZipFile from openpyxl.packaging.relationship import Relationship, RelationshipList -from openpyxl.packaging.workbook import PivotCache +from openpyxl.packaging.workbook import ChildSheet, PivotCache from openpyxl.pivot.cache import CacheDefinition from openpyxl.workbook import Workbook @@ -12,14 +11,14 @@ class WorkbookParser: workbook_part_name: str wb: Workbook keep_links: bool - sheets: list[Incomplete] + sheets: list[ChildSheet] def __init__(self, archive: ZipFile, workbook_part_name: str, keep_links: bool = True) -> None: ... @property def rels(self) -> RelationshipList: ... # Errors if "parse" is never called. caches: list[PivotCache] def parse(self) -> None: ... - def find_sheets(self) -> Generator[tuple[Incomplete, Relationship], None, None]: ... + def find_sheets(self) -> Generator[tuple[ChildSheet, Relationship], None, None]: ... def assign_names(self) -> None: ... @property def pivot_caches(self) -> dict[int, CacheDefinition]: ... diff --git a/stubs/openpyxl/openpyxl/workbook/workbook.pyi b/stubs/openpyxl/openpyxl/workbook/workbook.pyi index b153cc88729b..e7af8fdab638 100644 --- a/stubs/openpyxl/openpyxl/workbook/workbook.pyi +++ b/stubs/openpyxl/openpyxl/workbook/workbook.pyi @@ -49,38 +49,42 @@ class Workbook: @property def excel_base_date(self) -> datetime: ... @property - def active(self) -> _WorkbookChild | None: ... + def active(self) -> Worksheet | WriteOnlyWorksheet | Chartsheet | ReadOnlyWorksheet | None: ... @active.setter - def active(self, value: _WorkbookChild | int) -> None: ... + def active(self, value: Worksheet | Chartsheet | int) -> None: ... # Could be generic based on write_only def create_sheet( self, title: str | _Decodable | None = None, index: int | None = None ) -> Any: ... # AnyOf[WriteOnlyWorksheet, Worksheet] def move_sheet(self, sheet: Worksheet | str, offset: int = 0) -> None: ... - def remove(self, worksheet: Worksheet) -> None: ... + def remove(self, worksheet: Worksheet | WriteOnlyWorksheet | Chartsheet | ReadOnlyWorksheet) -> None: ... @deprecated("Use wb.remove(worksheet) or del wb[sheetname]") - def remove_sheet(self, worksheet: Worksheet) -> None: ... + def remove_sheet(self, worksheet: Worksheet | WriteOnlyWorksheet | Chartsheet | ReadOnlyWorksheet) -> None: ... def create_chartsheet(self, title: str | _Decodable | None = None, index: int | None = None) -> Chartsheet: ... @deprecated("Use wb[sheetname]") - def get_sheet_by_name(self, name: str) -> Worksheet: ... + def get_sheet_by_name(self, name: str) -> Worksheet | ReadOnlyWorksheet | WriteOnlyWorksheet | Chartsheet: ... def __contains__(self, key: str) -> bool: ... - def index(self, worksheet: Worksheet) -> int: ... + def index(self, worksheet: Worksheet | ReadOnlyWorksheet | WriteOnlyWorksheet) -> int: ... @deprecated("Use wb.index(worksheet)") - def get_index(self, worksheet: Worksheet) -> int: ... - def __getitem__(self, key: str) -> Worksheet: ... + def get_index(self, worksheet: Worksheet | ReadOnlyWorksheet | WriteOnlyWorksheet) -> int: ... + def __getitem__(self, key: str) -> Worksheet | ReadOnlyWorksheet | WriteOnlyWorksheet | Chartsheet: ... def __delitem__(self, key: str) -> None: ... - def __iter__(self) -> Iterator[Worksheet]: ... + def __iter__(self) -> Iterator[Worksheet | ReadOnlyWorksheet | WriteOnlyWorksheet]: ... @deprecated("Use wb.sheetnames") def get_sheet_names(self) -> list[Worksheet]: ... @property - def worksheets(self) -> list[Worksheet]: ... + def worksheets(self) -> list[Worksheet | ReadOnlyWorksheet | WriteOnlyWorksheet]: ... @property def chartsheets(self) -> list[Chartsheet]: ... @property def sheetnames(self) -> list[str]: ... @deprecated("Assign scoped named ranges directly to worksheets or global ones to the workbook. Deprecated in 3.1") def create_named_range( - self, name: str, worksheet: Worksheet | None = None, value: str | Incomplete | None = None, scope: Unused = None + self, + name: str, + worksheet: _WorkbookChild | ReadOnlyWorksheet | None = None, + value: str | Incomplete | None = None, + scope: Unused = None, ) -> None: ... def add_named_style(self, style: NamedStyle) -> None: ... @property diff --git a/stubs/openpyxl/openpyxl/worksheet/_reader.pyi b/stubs/openpyxl/openpyxl/worksheet/_reader.pyi index 8c0296d8608e..9b9b21bc015c 100644 --- a/stubs/openpyxl/openpyxl/worksheet/_reader.pyi +++ b/stubs/openpyxl/openpyxl/worksheet/_reader.pyi @@ -15,6 +15,7 @@ from .hyperlink import HyperlinkList from .pagebreak import ColBreak, RowBreak from .protection import SheetProtection from .table import TablePartList +from .worksheet import Worksheet CELL_TAG: Final[str] VALUE_TAG: Final[str] @@ -100,11 +101,11 @@ class WorkSheetParser: def parse_custom_views(self, element: Unused) -> None: ... class WorksheetReader: - ws: Incomplete + ws: Worksheet parser: WorkSheetParser tables: list[Incomplete] def __init__( - self, ws, xml_source: _FileRead, shared_strings: SupportsGetItem[int, str], data_only: bool, rich_text: bool + self, ws: Worksheet, xml_source: _FileRead, shared_strings: SupportsGetItem[int, str], data_only: bool, rich_text: bool ) -> None: ... def bind_cells(self) -> None: ... def bind_formatting(self) -> None: ... diff --git a/stubs/openpyxl/openpyxl/worksheet/_writer.pyi b/stubs/openpyxl/openpyxl/worksheet/_writer.pyi index 585c5029de5d..06059186e2c8 100644 --- a/stubs/openpyxl/openpyxl/worksheet/_writer.pyi +++ b/stubs/openpyxl/openpyxl/worksheet/_writer.pyi @@ -3,6 +3,9 @@ from collections.abc import Generator from typing import Protocol from typing_extensions import TypeAlias +from openpyxl.worksheet._write_only import WriteOnlyWorksheet +from openpyxl.worksheet.worksheet import Worksheet + # WorksheetWriter.read has an explicit BytesIO branch. Let's make sure this protocol is viable for BytesIO too. class _SupportsCloseAndWrite(Protocol): def write(self, buffer: ReadableBuffer, /) -> Unused: ... @@ -17,10 +20,10 @@ ALL_TEMP_FILES: list[str] def create_temporary_file(suffix: str = "") -> str: ... class WorksheetWriter: - ws: Incomplete + ws: Worksheet | WriteOnlyWorksheet out: _OutType xf: Generator[Incomplete | None, Incomplete, None] - def __init__(self, ws, out: _OutType | None = None) -> None: ... + def __init__(self, ws: Worksheet | WriteOnlyWorksheet, out: _OutType | None = None) -> None: ... def write_properties(self) -> None: ... def write_dimensions(self) -> None: ... def write_format(self) -> None: ... From 02c50ace3713aeb2eba3e7e9c1f13ccbe1d1428d Mon Sep 17 00:00:00 2001 From: Avasam Date: Sun, 31 Mar 2024 13:34:31 -0400 Subject: [PATCH 2/3] Reviewed all sheet and workbook related annotations --- stubs/openpyxl/openpyxl/cell/_writer.pyi | 6 ++-- stubs/openpyxl/openpyxl/cell/cell.pyi | 10 ++++-- stubs/openpyxl/openpyxl/cell/read_only.pyi | 11 ++++-- stubs/openpyxl/openpyxl/chart/chartspace.pyi | 1 + stubs/openpyxl/openpyxl/chart/reference.pyi | 10 +++--- .../openpyxl/chartsheet/chartsheet.pyi | 5 +-- .../openpyxl/openpyxl/packaging/workbook.pyi | 2 +- stubs/openpyxl/openpyxl/styles/styleable.pyi | 10 ++++-- stubs/openpyxl/openpyxl/styles/stylesheet.pyi | 2 +- stubs/openpyxl/openpyxl/workbook/_writer.pyi | 8 +++-- stubs/openpyxl/openpyxl/workbook/workbook.pyi | 35 +++++++++++-------- .../openpyxl/worksheet/_read_only.pyi | 11 ++++-- .../openpyxl/worksheet/_write_only.pyi | 7 ++-- .../openpyxl/worksheet/dimensions.pyi | 3 ++ stubs/openpyxl/openpyxl/worksheet/merge.pyi | 6 ++-- stubs/openpyxl/openpyxl/writer/excel.pyi | 3 +- 16 files changed, 86 insertions(+), 44 deletions(-) diff --git a/stubs/openpyxl/openpyxl/cell/_writer.pyi b/stubs/openpyxl/openpyxl/cell/_writer.pyi index 0502536f1c39..a546a3241df0 100644 --- a/stubs/openpyxl/openpyxl/cell/_writer.pyi +++ b/stubs/openpyxl/openpyxl/cell/_writer.pyi @@ -1,7 +1,7 @@ -from _typeshed import Incomplete +from _typeshed import Incomplete, Unused -def etree_write_cell(xf, worksheet, cell, styled: Incomplete | None = None) -> None: ... -def lxml_write_cell(xf, worksheet, cell, styled: bool = False) -> None: ... +def etree_write_cell(xf, worksheet: Unused, cell, styled: Incomplete | None = None) -> None: ... +def lxml_write_cell(xf, worksheet: Unused, cell, styled: bool = False) -> None: ... write_cell = lxml_write_cell write_cell = etree_write_cell diff --git a/stubs/openpyxl/openpyxl/cell/cell.pyi b/stubs/openpyxl/openpyxl/cell/cell.pyi index 3b5643673054..9eb5ebc07178 100644 --- a/stubs/openpyxl/openpyxl/cell/cell.pyi +++ b/stubs/openpyxl/openpyxl/cell/cell.pyi @@ -9,6 +9,7 @@ from openpyxl.compat.numbers import NUMERIC_TYPES as NUMERIC_TYPES # cell numer from openpyxl.styles.cell_style import StyleArray from openpyxl.styles.styleable import StyleableObject from openpyxl.workbook.child import _WorkbookChild +from openpyxl.worksheet._read_only import ReadOnlyWorksheet from openpyxl.worksheet.hyperlink import Hyperlink __docformat__: Final = "restructuredtext en" @@ -41,7 +42,7 @@ class Cell(StyleableObject): # row and column are never meant to be None and would lead to errors def __init__( self, - worksheet: _WorkbookChild, + worksheet: _WorkbookChild | ReadOnlyWorksheet, row: int, column: int, value: str | float | datetime | None = None, @@ -86,10 +87,13 @@ class MergedCell(StyleableObject): hyperlink: Hyperlink | None row: int | None column: int | None - def __init__(self, worksheet: _WorkbookChild, row: int | None = None, column: int | None = None) -> None: ... + def __init__( + self, worksheet: _WorkbookChild | ReadOnlyWorksheet, row: int | None = None, column: int | None = None + ) -> None: ... # Same as Cell.coordinate + # https://github.com/python/mypy/issues/6700 @property def coordinate(self) -> str: ... value: str | float | int | datetime | None -def WriteOnlyCell(ws: _WorkbookChild | None = None, value: str | float | datetime | None = None) -> Cell: ... +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 2e6082c65f9e..170624f03860 100644 --- a/stubs/openpyxl/openpyxl/cell/read_only.pyi +++ b/stubs/openpyxl/openpyxl/cell/read_only.pyi @@ -8,20 +8,26 @@ from openpyxl.styles.cell_style import StyleArray from openpyxl.styles.fills import Fill from openpyxl.styles.fonts import Font from openpyxl.styles.protection import Protection +from openpyxl.workbook.child import _WorkbookChild +from openpyxl.worksheet._read_only import ReadOnlyWorksheet class ReadOnlyCell: - parent: Incomplete + parent: _WorkbookChild | ReadOnlyWorksheet row: Incomplete column: Incomplete data_type: Incomplete - def __init__(self, sheet, row, column, value, data_type: str = "n", style_id: int = 0) -> None: ... + def __init__( + self, sheet: _WorkbookChild | ReadOnlyWorksheet, row, column, value, data_type: str = "n", style_id: int = 0 + ) -> None: ... def __eq__(self, other: object) -> bool: ... def __ne__(self, other: object) -> bool: ... # Same as Cell.coordinate + # https://github.com/python/mypy/issues/6700 # Defined twice in the implementation @property def coordinate(self) -> str: ... # Same as Cell.column_letter + # https://github.com/python/mypy/issues/6700 @property def column_letter(self) -> str: ... @property @@ -41,6 +47,7 @@ class ReadOnlyCell: @property def protection(self) -> Protection: ... # Same as Cell.is_date + # https://github.com/python/mypy/issues/6700 @property def is_date(self) -> bool: ... @property diff --git a/stubs/openpyxl/openpyxl/chart/chartspace.pyi b/stubs/openpyxl/openpyxl/chart/chartspace.pyi index 12797dfc58af..eeaa4f6d4a52 100644 --- a/stubs/openpyxl/openpyxl/chart/chartspace.pyi +++ b/stubs/openpyxl/openpyxl/chart/chartspace.pyi @@ -28,6 +28,7 @@ class ChartContainer(Serialisable): pivotFmts: Incomplete # Same as _3DBase + # https://github.com/python/mypy/issues/6700 view3D: Typed[View3D, Literal[True]] floor: Typed[Surface, Literal[True]] sideWall: Typed[Surface, Literal[True]] diff --git a/stubs/openpyxl/openpyxl/chart/reference.pyi b/stubs/openpyxl/openpyxl/chart/reference.pyi index 408dbb32d31a..264bd4a599f8 100644 --- a/stubs/openpyxl/openpyxl/chart/reference.pyi +++ b/stubs/openpyxl/openpyxl/chart/reference.pyi @@ -1,9 +1,11 @@ -from _typeshed import ConvertibleToInt, Incomplete, Unused +from _typeshed import ConvertibleToInt, Unused from collections.abc import Generator from typing import Literal, overload from openpyxl.descriptors import Strict from openpyxl.descriptors.base import MinMax, String +from openpyxl.workbook.child import _WorkbookChild +from openpyxl.worksheet._read_only import ReadOnlyWorksheet class DummyWorksheet: title: str @@ -15,12 +17,12 @@ class Reference(Strict): min_col: MinMax[int, Literal[False]] max_col: MinMax[int, Literal[False]] range_string: String[Literal[True]] - worksheet: Incomplete | None + worksheet: _WorkbookChild | ReadOnlyWorksheet | DummyWorksheet @overload def __init__( self, *, - worksheet: Unused = None, + worksheet: _WorkbookChild | ReadOnlyWorksheet | DummyWorksheet | None = None, min_col: Unused = None, min_row: Unused = None, max_col: Unused = None, @@ -30,7 +32,7 @@ class Reference(Strict): @overload def __init__( self, - worksheet: Incomplete | None, + worksheet: _WorkbookChild | ReadOnlyWorksheet, min_col: ConvertibleToInt, min_row: ConvertibleToInt, max_col: ConvertibleToInt | None = None, diff --git a/stubs/openpyxl/openpyxl/chartsheet/chartsheet.pyi b/stubs/openpyxl/openpyxl/chartsheet/chartsheet.pyi index 789acb7663d5..84d4fafede37 100644 --- a/stubs/openpyxl/openpyxl/chartsheet/chartsheet.pyi +++ b/stubs/openpyxl/openpyxl/chartsheet/chartsheet.pyi @@ -1,4 +1,4 @@ -from _typeshed import Incomplete, Unused +from _typeshed import Unused from typing import ClassVar, Literal from openpyxl import _Decodable, _VisibilityType @@ -12,6 +12,7 @@ from openpyxl.descriptors.base import Alias, Set, Typed from openpyxl.descriptors.excel import ExtensionList from openpyxl.descriptors.serialisable import Serialisable from openpyxl.workbook.child import _WorkbookChild +from openpyxl.workbook.workbook import Workbook from openpyxl.worksheet.drawing import Drawing from openpyxl.worksheet.header_footer import HeaderFooter as _HeaderFooter from openpyxl.worksheet.page import PageMargins, PrintPageSetup @@ -50,7 +51,7 @@ class Chartsheet(_WorkbookChild, Serialisable): picture: SheetBackgroundPicture | None = None, webPublishItems: WebPublishItems | None = None, extLst: Unused = None, - parent: Incomplete | None = None, + parent: Workbook | None = None, title: str | _Decodable | None = "", sheet_state: _VisibilityType = "visible", ) -> None: ... diff --git a/stubs/openpyxl/openpyxl/packaging/workbook.pyi b/stubs/openpyxl/openpyxl/packaging/workbook.pyi index 08322f8a0f17..b333a3651550 100644 --- a/stubs/openpyxl/openpyxl/packaging/workbook.pyi +++ b/stubs/openpyxl/openpyxl/packaging/workbook.pyi @@ -60,7 +60,7 @@ class WorkbookPackage(Serialisable): properties: Alias workbookProtection: Typed[WorkbookProtection, Literal[True]] bookViews: Incomplete - sheets: Incomplete + sheets: Incomplete # NestedSequence[ChildSheet] functionGroups: Typed[FunctionGroupList, Literal[True]] externalReferences: Incomplete definedNames: Typed[DefinedNameList, Literal[True]] diff --git a/stubs/openpyxl/openpyxl/styles/styleable.pyi b/stubs/openpyxl/openpyxl/styles/styleable.pyi index 50aef163e722..07744bd3ecdb 100644 --- a/stubs/openpyxl/openpyxl/styles/styleable.pyi +++ b/stubs/openpyxl/openpyxl/styles/styleable.pyi @@ -1,7 +1,9 @@ -from _typeshed import Incomplete, Unused +from _typeshed import Unused from collections.abc import Iterable from openpyxl.descriptors.serialisable import Serialisable +from openpyxl.workbook.child import _WorkbookChild +from openpyxl.worksheet._read_only import ReadOnlyWorksheet from .named_styles import NamedStyle from .proxy import StyleProxy @@ -41,8 +43,10 @@ class StyleableObject: style: NamedStyleDescriptor quotePrefix: StyleArrayDescriptor pivotButton: StyleArrayDescriptor - parent: Incomplete - def __init__(self, sheet, style_array: bytes | bytearray | Iterable[int] | None = None) -> None: ... + parent: _WorkbookChild | ReadOnlyWorksheet + def __init__( + self, sheet: _WorkbookChild | ReadOnlyWorksheet, style_array: bytes | bytearray | Iterable[int] | None = None + ) -> None: ... @property def style_id(self) -> int: ... @property diff --git a/stubs/openpyxl/openpyxl/styles/stylesheet.pyi b/stubs/openpyxl/openpyxl/styles/stylesheet.pyi index 1d4f1e8324dd..c977920767fa 100644 --- a/stubs/openpyxl/openpyxl/styles/stylesheet.pyi +++ b/stubs/openpyxl/openpyxl/styles/stylesheet.pyi @@ -56,4 +56,4 @@ class Stylesheet(Serialisable): def to_tree(self, tagname: str | None = None, idx: Unused = None, namespace: str | None = None) -> Element: ... def apply_stylesheet(archive: ZipFile, wb: _WorkbookT) -> _WorkbookT | None: ... -def write_stylesheet(wb): ... +def write_stylesheet(wb: Workbook): ... diff --git a/stubs/openpyxl/openpyxl/workbook/_writer.pyi b/stubs/openpyxl/openpyxl/workbook/_writer.pyi index 4789be9fd13a..40e639a58d32 100644 --- a/stubs/openpyxl/openpyxl/workbook/_writer.pyi +++ b/stubs/openpyxl/openpyxl/workbook/_writer.pyi @@ -1,12 +1,14 @@ from _typeshed import Incomplete -def get_active_sheet(wb): ... +from openpyxl.workbook.workbook import Workbook + +def get_active_sheet(wb: Workbook) -> int | None: ... class WorkbookWriter: - wb: Incomplete + wb: Workbook rels: Incomplete package: Incomplete - def __init__(self, wb) -> None: ... + def __init__(self, wb: Workbook) -> None: ... def write_properties(self) -> None: ... def write_worksheets(self) -> None: ... def write_refs(self) -> None: ... diff --git a/stubs/openpyxl/openpyxl/workbook/workbook.pyi b/stubs/openpyxl/openpyxl/workbook/workbook.pyi index e7af8fdab638..5687dbc7aa64 100644 --- a/stubs/openpyxl/openpyxl/workbook/workbook.pyi +++ b/stubs/openpyxl/openpyxl/workbook/workbook.pyi @@ -2,7 +2,7 @@ from _typeshed import Incomplete, Unused from collections.abc import Iterator from datetime import datetime from typing import Any, Final -from typing_extensions import deprecated +from typing_extensions import TypeAlias, deprecated from zipfile import ZipFile from openpyxl import _Decodable, _ZipFileFileProtocol @@ -14,6 +14,9 @@ from openpyxl.worksheet._read_only import ReadOnlyWorksheet from openpyxl.worksheet._write_only import WriteOnlyWorksheet from openpyxl.worksheet.worksheet import Worksheet +_WorkbookWorksheet: TypeAlias = Worksheet | WriteOnlyWorksheet | ReadOnlyWorksheet +_WorkbookSheet: TypeAlias = _WorkbookWorksheet | Chartsheet + INTEGER_TYPES: Final[tuple[type[int]]] class Workbook: @@ -32,9 +35,9 @@ class Workbook: rels: Incomplete calculation: Incomplete views: Incomplete - # Private, but useful as a reference of what "sheets" can be for other types + # Useful as a reference of what "sheets" can be for other types # ExcelReader can add ReadOnlyWorksheet in read_only mode. - _sheets: list[Worksheet | WriteOnlyWorksheet | Chartsheet | ReadOnlyWorksheet] + # _sheets: list[_WorkbookSheet] def __init__(self, write_only: bool = False, iso_dates: bool = False) -> None: ... @property def epoch(self) -> datetime: ... @@ -49,31 +52,32 @@ class Workbook: @property def excel_base_date(self) -> datetime: ... @property - def active(self) -> Worksheet | WriteOnlyWorksheet | Chartsheet | ReadOnlyWorksheet | None: ... + def active(self) -> _WorkbookSheet | None: ... @active.setter def active(self, value: Worksheet | Chartsheet | int) -> None: ... + # read_only workbook cannot call this method # Could be generic based on write_only def create_sheet( self, title: str | _Decodable | None = None, index: int | None = None ) -> Any: ... # AnyOf[WriteOnlyWorksheet, Worksheet] def move_sheet(self, sheet: Worksheet | str, offset: int = 0) -> None: ... - def remove(self, worksheet: Worksheet | WriteOnlyWorksheet | Chartsheet | ReadOnlyWorksheet) -> None: ... + def remove(self, worksheet: _WorkbookSheet) -> None: ... @deprecated("Use wb.remove(worksheet) or del wb[sheetname]") - def remove_sheet(self, worksheet: Worksheet | WriteOnlyWorksheet | Chartsheet | ReadOnlyWorksheet) -> None: ... + def remove_sheet(self, worksheet: _WorkbookSheet) -> None: ... def create_chartsheet(self, title: str | _Decodable | None = None, index: int | None = None) -> Chartsheet: ... @deprecated("Use wb[sheetname]") - def get_sheet_by_name(self, name: str) -> Worksheet | ReadOnlyWorksheet | WriteOnlyWorksheet | Chartsheet: ... + def get_sheet_by_name(self, name: str) -> _WorkbookSheet: ... def __contains__(self, key: str) -> bool: ... - def index(self, worksheet: Worksheet | ReadOnlyWorksheet | WriteOnlyWorksheet) -> int: ... + def index(self, worksheet: _WorkbookWorksheet) -> int: ... @deprecated("Use wb.index(worksheet)") - def get_index(self, worksheet: Worksheet | ReadOnlyWorksheet | WriteOnlyWorksheet) -> int: ... - def __getitem__(self, key: str) -> Worksheet | ReadOnlyWorksheet | WriteOnlyWorksheet | Chartsheet: ... + def get_index(self, worksheet: _WorkbookWorksheet) -> int: ... + def __getitem__(self, key: str) -> _WorkbookSheet: ... def __delitem__(self, key: str) -> None: ... - def __iter__(self) -> Iterator[Worksheet | ReadOnlyWorksheet | WriteOnlyWorksheet]: ... + def __iter__(self) -> Iterator[_WorkbookWorksheet]: ... @deprecated("Use wb.sheetnames") - def get_sheet_names(self) -> list[Worksheet]: ... + def get_sheet_names(self) -> list[str]: ... @property - def worksheets(self) -> list[Worksheet | ReadOnlyWorksheet | WriteOnlyWorksheet]: ... + def worksheets(self) -> list[_WorkbookWorksheet]: ... @property def chartsheets(self) -> list[Chartsheet]: ... @property @@ -94,5 +98,8 @@ class Workbook: def save(self, filename: _ZipFileFileProtocol) -> None: ... @property def style_names(self) -> list[str]: ... - def copy_worksheet(self, from_worksheet: Worksheet) -> Worksheet | WriteOnlyWorksheet: ... + # A write_only and read_only workbooks can't use this method as it requires both reading and writing. + # On an implementation level, a WorksheetCopy is created from the call to self.create_sheet, + # but WorksheetCopy only works with Worksheet. + def copy_worksheet(self, from_worksheet: Worksheet) -> Worksheet: ... def close(self) -> None: ... diff --git a/stubs/openpyxl/openpyxl/worksheet/_read_only.pyi b/stubs/openpyxl/openpyxl/worksheet/_read_only.pyi index 1dd962e07f5f..98d2c10cf272 100644 --- a/stubs/openpyxl/openpyxl/worksheet/_read_only.pyi +++ b/stubs/openpyxl/openpyxl/worksheet/_read_only.pyi @@ -1,10 +1,11 @@ -from _typeshed import Incomplete, SupportsGetItem +from _typeshed import SupportsGetItem from collections.abc import Generator from openpyxl import _VisibilityType from openpyxl.cell import _CellValue from openpyxl.cell.cell import Cell from openpyxl.utils.cell import _RangeBoundariesTuple +from openpyxl.workbook.workbook import Workbook from openpyxl.worksheet.worksheet import Worksheet def read_dimension(source) -> _RangeBoundariesTuple | None: ... @@ -13,17 +14,21 @@ class ReadOnlyWorksheet: cell = Worksheet.cell iter_rows = Worksheet.iter_rows # Same as Worksheet.values + # https://github.com/python/mypy/issues/6700 @property def values(self) -> Generator[tuple[_CellValue, ...], None, None]: ... # Same as Worksheet.rows + # https://github.com/python/mypy/issues/6700 @property def rows(self) -> Generator[tuple[Cell, ...], None, None]: ... __getitem__ = Worksheet.__getitem__ __iter__ = Worksheet.__iter__ - parent: Incomplete + parent: Workbook title: str sheet_state: _VisibilityType - def __init__(self, parent_workbook, title: str, worksheet_path, shared_strings: SupportsGetItem[int, str]) -> None: ... + def __init__( + self, parent_workbook: Workbook, title: str, worksheet_path, shared_strings: SupportsGetItem[int, str] + ) -> None: ... def calculate_dimension(self, force: bool = False): ... def reset_dimensions(self) -> None: ... @property diff --git a/stubs/openpyxl/openpyxl/worksheet/_write_only.pyi b/stubs/openpyxl/openpyxl/worksheet/_write_only.pyi index ffecf33377c6..eb1f6e6fdc09 100644 --- a/stubs/openpyxl/openpyxl/worksheet/_write_only.pyi +++ b/stubs/openpyxl/openpyxl/worksheet/_write_only.pyi @@ -3,7 +3,9 @@ from collections.abc import Iterable from openpyxl import _Decodable from openpyxl.cell.cell import Cell from openpyxl.workbook.child import _WorkbookChild +from openpyxl.workbook.workbook import Workbook from openpyxl.worksheet.table import TableList +from openpyxl.worksheet.views import SheetView from openpyxl.worksheet.worksheet import Worksheet class WriteOnlyWorksheet(_WorkbookChild): @@ -13,6 +15,7 @@ class WriteOnlyWorksheet(_WorkbookChild): add_table = Worksheet.add_table # Same properties as Worksheet + # https://github.com/python/mypy/issues/6700 @property def tables(self) -> TableList: ... @property @@ -34,8 +37,8 @@ class WriteOnlyWorksheet(_WorkbookChild): @print_area.setter def print_area(self, value: str | Iterable[str] | None) -> None: ... @property - def sheet_view(self): ... - def __init__(self, parent, title: str | _Decodable | None) -> None: ... + def sheet_view(self) -> SheetView: ... + def __init__(self, parent: Workbook | None, title: str | _Decodable | None) -> None: ... @property def closed(self) -> bool: ... def close(self) -> None: ... diff --git a/stubs/openpyxl/openpyxl/worksheet/dimensions.pyi b/stubs/openpyxl/openpyxl/worksheet/dimensions.pyi index 1bed2959cc68..644e5684a34f 100644 --- a/stubs/openpyxl/openpyxl/worksheet/dimensions.pyi +++ b/stubs/openpyxl/openpyxl/worksheet/dimensions.pyi @@ -24,6 +24,9 @@ class Dimension(Strict, StyleableObject): collapsed: Bool[Literal[False]] style: Alias # type: ignore[assignment] + # Dimensions are only meant to be used on Worksheet objects + parent: Worksheet + def __init__( self, index: ConvertibleToInt, diff --git a/stubs/openpyxl/openpyxl/worksheet/merge.pyi b/stubs/openpyxl/openpyxl/worksheet/merge.pyi index 31ca31bcf98b..bbf8c225be9e 100644 --- a/stubs/openpyxl/openpyxl/worksheet/merge.pyi +++ b/stubs/openpyxl/openpyxl/worksheet/merge.pyi @@ -2,12 +2,14 @@ from _typeshed import Incomplete, Unused from typing import ClassVar from openpyxl.descriptors.serialisable import Serialisable +from openpyxl.worksheet.worksheet import Worksheet from .cell_range import CellRange class MergeCell(CellRange): tagname: ClassVar[str] # Same as CellRange.coord + # https://github.com/python/mypy/issues/6700 @property def ref(self) -> str: ... __attrs__: ClassVar[tuple[str, ...]] @@ -26,9 +28,9 @@ class MergeCells(Serialisable): def count(self) -> int: ... class MergedCellRange(CellRange): - ws: Incomplete + ws: Worksheet start_cell: Incomplete - def __init__(self, worksheet, coord) -> None: ... + def __init__(self, worksheet: Worksheet, coord) -> None: ... def format(self) -> None: ... def __contains__(self, coord: str) -> bool: ... def __copy__(self): ... diff --git a/stubs/openpyxl/openpyxl/writer/excel.pyi b/stubs/openpyxl/openpyxl/writer/excel.pyi index 3d8ab5354747..5baba43b2859 100644 --- a/stubs/openpyxl/openpyxl/writer/excel.pyi +++ b/stubs/openpyxl/openpyxl/writer/excel.pyi @@ -4,6 +4,7 @@ from zipfile import ZipFile from openpyxl import _ZipFileFileProtocol from openpyxl.packaging.manifest import Manifest from openpyxl.workbook.workbook import Workbook +from openpyxl.worksheet.worksheet import Worksheet class ExcelWriter: workbook: Workbook @@ -11,7 +12,7 @@ class ExcelWriter: vba_modified: set[str | None] def __init__(self, workbook: Workbook, archive: ZipFile) -> None: ... def write_data(self) -> None: ... - def write_worksheet(self, ws) -> None: ... + def write_worksheet(self, ws: Worksheet) -> None: ... def save(self) -> None: ... def save_workbook(workbook: Workbook, filename: _ZipFileFileProtocol) -> Literal[True]: ... From 6ba35f5c40770edab37edb5a7a6be964c7befaba Mon Sep 17 00:00:00 2001 From: Avasam Date: Sun, 31 Mar 2024 14:07:02 -0400 Subject: [PATCH 3/3] Add stubtest_allowlist entries --- stubs/openpyxl/@tests/stubtest_allowlist.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/stubs/openpyxl/@tests/stubtest_allowlist.txt b/stubs/openpyxl/@tests/stubtest_allowlist.txt index 010e8d68760d..cf28e9a4b6fa 100644 --- a/stubs/openpyxl/@tests/stubtest_allowlist.txt +++ b/stubs/openpyxl/@tests/stubtest_allowlist.txt @@ -46,6 +46,8 @@ openpyxl\.descriptors\.(base\.)?Typed\.allow_none # - or, keyword arguments are explicitly specified openpyxl.cell.Cell.__init__ openpyxl.cell.cell.Cell.__init__ +openpyxl.cell.cell.WriteOnlyCell +openpyxl.cell.WriteOnlyCell openpyxl.cell.text.PhoneticProperties.__init__ openpyxl.cell.text.PhoneticText.__init__ openpyxl.chart.axis._BaseAxis.__init__