Skip to content

Commit 0cea0bc

Browse files
authored
openpyxl: Add _WorkbookChild / ReadOnlyWorksheet / Workbook annotations (#11677)
1 parent ccc47c0 commit 0cea0bc

20 files changed

+106
-55
lines changed

stubs/openpyxl/@tests/stubtest_allowlist.txt

+2
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ openpyxl\.descriptors\.(base\.)?Typed\.allow_none
4646
# - or, keyword arguments are explicitly specified
4747
openpyxl.cell.Cell.__init__
4848
openpyxl.cell.cell.Cell.__init__
49+
openpyxl.cell.cell.WriteOnlyCell
50+
openpyxl.cell.WriteOnlyCell
4951
openpyxl.cell.text.PhoneticProperties.__init__
5052
openpyxl.cell.text.PhoneticText.__init__
5153
openpyxl.chart.axis._BaseAxis.__init__
+3-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
from _typeshed import Incomplete
1+
from _typeshed import Incomplete, Unused
22

3-
def etree_write_cell(xf, worksheet, cell, styled: Incomplete | None = None) -> None: ...
4-
def lxml_write_cell(xf, worksheet, cell, styled: bool = False) -> None: ...
3+
def etree_write_cell(xf, worksheet: Unused, cell, styled: Incomplete | None = None) -> None: ...
4+
def lxml_write_cell(xf, worksheet: Unused, cell, styled: bool = False) -> None: ...
55

66
write_cell = lxml_write_cell
77
write_cell = etree_write_cell

stubs/openpyxl/openpyxl/cell/cell.pyi

+8-4
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,9 @@ from openpyxl.comments.comments import Comment
88
from openpyxl.compat.numbers import NUMERIC_TYPES as NUMERIC_TYPES # cell numeric types
99
from openpyxl.styles.cell_style import StyleArray
1010
from openpyxl.styles.styleable import StyleableObject
11+
from openpyxl.workbook.child import _WorkbookChild
12+
from openpyxl.worksheet._read_only import ReadOnlyWorksheet
1113
from openpyxl.worksheet.hyperlink import Hyperlink
12-
from openpyxl.worksheet.worksheet import Worksheet
1314

1415
__docformat__: Final = "restructuredtext en"
1516
TIME_TYPES: Final[tuple[type, ...]]
@@ -41,7 +42,7 @@ class Cell(StyleableObject):
4142
# row and column are never meant to be None and would lead to errors
4243
def __init__(
4344
self,
44-
worksheet: Worksheet,
45+
worksheet: _WorkbookChild | ReadOnlyWorksheet,
4546
row: int,
4647
column: int,
4748
value: str | float | datetime | None = None,
@@ -86,10 +87,13 @@ class MergedCell(StyleableObject):
8687
hyperlink: Hyperlink | None
8788
row: int | None
8889
column: int | None
89-
def __init__(self, worksheet: Worksheet, row: int | None = None, column: int | None = None) -> None: ...
90+
def __init__(
91+
self, worksheet: _WorkbookChild | ReadOnlyWorksheet, row: int | None = None, column: int | None = None
92+
) -> None: ...
9093
# Same as Cell.coordinate
94+
# https://github.com/python/mypy/issues/6700
9195
@property
9296
def coordinate(self) -> str: ...
9397
value: str | float | int | datetime | None
9498

95-
def WriteOnlyCell(ws: Worksheet | None = None, value: str | float | datetime | None = None) -> Cell: ...
99+
def WriteOnlyCell(ws: _WorkbookChild | ReadOnlyWorksheet, value: str | float | datetime | None = None) -> Cell: ...

stubs/openpyxl/openpyxl/cell/read_only.pyi

+9-2
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,26 @@ from openpyxl.styles.cell_style import StyleArray
88
from openpyxl.styles.fills import Fill
99
from openpyxl.styles.fonts import Font
1010
from openpyxl.styles.protection import Protection
11+
from openpyxl.workbook.child import _WorkbookChild
12+
from openpyxl.worksheet._read_only import ReadOnlyWorksheet
1113

1214
class ReadOnlyCell:
13-
parent: Incomplete
15+
parent: _WorkbookChild | ReadOnlyWorksheet
1416
row: Incomplete
1517
column: Incomplete
1618
data_type: Incomplete
17-
def __init__(self, sheet, row, column, value, data_type: str = "n", style_id: int = 0) -> None: ...
19+
def __init__(
20+
self, sheet: _WorkbookChild | ReadOnlyWorksheet, row, column, value, data_type: str = "n", style_id: int = 0
21+
) -> None: ...
1822
def __eq__(self, other: object) -> bool: ...
1923
def __ne__(self, other: object) -> bool: ...
2024
# Same as Cell.coordinate
25+
# https://github.com/python/mypy/issues/6700
2126
# Defined twice in the implementation
2227
@property
2328
def coordinate(self) -> str: ...
2429
# Same as Cell.column_letter
30+
# https://github.com/python/mypy/issues/6700
2531
@property
2632
def column_letter(self) -> str: ...
2733
@property
@@ -41,6 +47,7 @@ class ReadOnlyCell:
4147
@property
4248
def protection(self) -> Protection: ...
4349
# Same as Cell.is_date
50+
# https://github.com/python/mypy/issues/6700
4451
@property
4552
def is_date(self) -> bool: ...
4653
@property

stubs/openpyxl/openpyxl/chart/chartspace.pyi

+1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ class ChartContainer(Serialisable):
2828
pivotFmts: Incomplete
2929

3030
# Same as _3DBase
31+
# https://github.com/python/mypy/issues/6700
3132
view3D: Typed[View3D, Literal[True]]
3233
floor: Typed[Surface, Literal[True]]
3334
sideWall: Typed[Surface, Literal[True]]

stubs/openpyxl/openpyxl/chart/reference.pyi

+6-4
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1-
from _typeshed import ConvertibleToInt, Incomplete, Unused
1+
from _typeshed import ConvertibleToInt, Unused
22
from collections.abc import Generator
33
from typing import Literal, overload
44

55
from openpyxl.descriptors import Strict
66
from openpyxl.descriptors.base import MinMax, String
7+
from openpyxl.workbook.child import _WorkbookChild
8+
from openpyxl.worksheet._read_only import ReadOnlyWorksheet
79

810
class DummyWorksheet:
911
title: str
@@ -15,12 +17,12 @@ class Reference(Strict):
1517
min_col: MinMax[int, Literal[False]]
1618
max_col: MinMax[int, Literal[False]]
1719
range_string: String[Literal[True]]
18-
worksheet: Incomplete | None
20+
worksheet: _WorkbookChild | ReadOnlyWorksheet | DummyWorksheet
1921
@overload
2022
def __init__(
2123
self,
2224
*,
23-
worksheet: Unused = None,
25+
worksheet: _WorkbookChild | ReadOnlyWorksheet | DummyWorksheet | None = None,
2426
min_col: Unused = None,
2527
min_row: Unused = None,
2628
max_col: Unused = None,
@@ -30,7 +32,7 @@ class Reference(Strict):
3032
@overload
3133
def __init__(
3234
self,
33-
worksheet: Incomplete | None,
35+
worksheet: _WorkbookChild | ReadOnlyWorksheet,
3436
min_col: ConvertibleToInt,
3537
min_row: ConvertibleToInt,
3638
max_col: ConvertibleToInt | None = None,

stubs/openpyxl/openpyxl/chartsheet/chartsheet.pyi

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from _typeshed import Incomplete, Unused
1+
from _typeshed import Unused
22
from typing import ClassVar, Literal
33

44
from openpyxl import _Decodable, _VisibilityType
@@ -12,6 +12,7 @@ from openpyxl.descriptors.base import Alias, Set, Typed
1212
from openpyxl.descriptors.excel import ExtensionList
1313
from openpyxl.descriptors.serialisable import Serialisable
1414
from openpyxl.workbook.child import _WorkbookChild
15+
from openpyxl.workbook.workbook import Workbook
1516
from openpyxl.worksheet.drawing import Drawing
1617
from openpyxl.worksheet.header_footer import HeaderFooter as _HeaderFooter
1718
from openpyxl.worksheet.page import PageMargins, PrintPageSetup
@@ -50,7 +51,7 @@ class Chartsheet(_WorkbookChild, Serialisable):
5051
picture: SheetBackgroundPicture | None = None,
5152
webPublishItems: WebPublishItems | None = None,
5253
extLst: Unused = None,
53-
parent: Incomplete | None = None,
54+
parent: Workbook | None = None,
5455
title: str | _Decodable | None = "",
5556
sheet_state: _VisibilityType = "visible",
5657
) -> None: ...

stubs/openpyxl/openpyxl/packaging/workbook.pyi

+1-1
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ class WorkbookPackage(Serialisable):
6060
properties: Alias
6161
workbookProtection: Typed[WorkbookProtection, Literal[True]]
6262
bookViews: Incomplete
63-
sheets: Incomplete
63+
sheets: Incomplete # NestedSequence[ChildSheet]
6464
functionGroups: Typed[FunctionGroupList, Literal[True]]
6565
externalReferences: Incomplete
6666
definedNames: Typed[DefinedNameList, Literal[True]]
+3-4
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1-
from _typeshed import Incomplete
21
from collections.abc import Generator
32
from zipfile import ZipFile
43

54
from openpyxl.packaging.relationship import Relationship, RelationshipList
6-
from openpyxl.packaging.workbook import PivotCache
5+
from openpyxl.packaging.workbook import ChildSheet, PivotCache
76
from openpyxl.pivot.cache import CacheDefinition
87
from openpyxl.workbook import Workbook
98

@@ -12,14 +11,14 @@ class WorkbookParser:
1211
workbook_part_name: str
1312
wb: Workbook
1413
keep_links: bool
15-
sheets: list[Incomplete]
14+
sheets: list[ChildSheet]
1615
def __init__(self, archive: ZipFile, workbook_part_name: str, keep_links: bool = True) -> None: ...
1716
@property
1817
def rels(self) -> RelationshipList: ...
1918
# Errors if "parse" is never called.
2019
caches: list[PivotCache]
2120
def parse(self) -> None: ...
22-
def find_sheets(self) -> Generator[tuple[Incomplete, Relationship], None, None]: ...
21+
def find_sheets(self) -> Generator[tuple[ChildSheet, Relationship], None, None]: ...
2322
def assign_names(self) -> None: ...
2423
@property
2524
def pivot_caches(self) -> dict[int, CacheDefinition]: ...

stubs/openpyxl/openpyxl/styles/styleable.pyi

+7-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1-
from _typeshed import Incomplete, Unused
1+
from _typeshed import Unused
22
from collections.abc import Iterable
33

44
from openpyxl.descriptors.serialisable import Serialisable
5+
from openpyxl.workbook.child import _WorkbookChild
6+
from openpyxl.worksheet._read_only import ReadOnlyWorksheet
57

68
from .named_styles import NamedStyle
79
from .proxy import StyleProxy
@@ -41,8 +43,10 @@ class StyleableObject:
4143
style: NamedStyleDescriptor
4244
quotePrefix: StyleArrayDescriptor
4345
pivotButton: StyleArrayDescriptor
44-
parent: Incomplete
45-
def __init__(self, sheet, style_array: bytes | bytearray | Iterable[int] | None = None) -> None: ...
46+
parent: _WorkbookChild | ReadOnlyWorksheet
47+
def __init__(
48+
self, sheet: _WorkbookChild | ReadOnlyWorksheet, style_array: bytes | bytearray | Iterable[int] | None = None
49+
) -> None: ...
4650
@property
4751
def style_id(self) -> int: ...
4852
@property

stubs/openpyxl/openpyxl/styles/stylesheet.pyi

+1-1
Original file line numberDiff line numberDiff line change
@@ -56,4 +56,4 @@ class Stylesheet(Serialisable):
5656
def to_tree(self, tagname: str | None = None, idx: Unused = None, namespace: str | None = None) -> Element: ...
5757

5858
def apply_stylesheet(archive: ZipFile, wb: _WorkbookT) -> _WorkbookT | None: ...
59-
def write_stylesheet(wb): ...
59+
def write_stylesheet(wb: Workbook): ...

stubs/openpyxl/openpyxl/workbook/_writer.pyi

+5-3
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
from _typeshed import Incomplete
22

3-
def get_active_sheet(wb): ...
3+
from openpyxl.workbook.workbook import Workbook
4+
5+
def get_active_sheet(wb: Workbook) -> int | None: ...
46

57
class WorkbookWriter:
6-
wb: Incomplete
8+
wb: Workbook
79
rels: Incomplete
810
package: Incomplete
9-
def __init__(self, wb) -> None: ...
11+
def __init__(self, wb: Workbook) -> None: ...
1012
def write_properties(self) -> None: ...
1113
def write_worksheets(self) -> None: ...
1214
def write_refs(self) -> None: ...

stubs/openpyxl/openpyxl/workbook/workbook.pyi

+27-16
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ from _typeshed import Incomplete, Unused
22
from collections.abc import Iterator
33
from datetime import datetime
44
from typing import Any, Final
5-
from typing_extensions import deprecated
5+
from typing_extensions import TypeAlias, deprecated
66
from zipfile import ZipFile
77

88
from openpyxl import _Decodable, _ZipFileFileProtocol
@@ -14,6 +14,9 @@ from openpyxl.worksheet._read_only import ReadOnlyWorksheet
1414
from openpyxl.worksheet._write_only import WriteOnlyWorksheet
1515
from openpyxl.worksheet.worksheet import Worksheet
1616

17+
_WorkbookWorksheet: TypeAlias = Worksheet | WriteOnlyWorksheet | ReadOnlyWorksheet
18+
_WorkbookSheet: TypeAlias = _WorkbookWorksheet | Chartsheet
19+
1720
INTEGER_TYPES: Final[tuple[type[int]]]
1821

1922
class Workbook:
@@ -32,9 +35,9 @@ class Workbook:
3235
rels: Incomplete
3336
calculation: Incomplete
3437
views: Incomplete
35-
# Private, but useful as a reference of what "sheets" can be for other types
38+
# Useful as a reference of what "sheets" can be for other types
3639
# ExcelReader can add ReadOnlyWorksheet in read_only mode.
37-
_sheets: list[Worksheet | WriteOnlyWorksheet | Chartsheet | ReadOnlyWorksheet]
40+
# _sheets: list[_WorkbookSheet]
3841
def __init__(self, write_only: bool = False, iso_dates: bool = False) -> None: ...
3942
@property
4043
def epoch(self) -> datetime: ...
@@ -49,38 +52,43 @@ class Workbook:
4952
@property
5053
def excel_base_date(self) -> datetime: ...
5154
@property
52-
def active(self) -> _WorkbookChild | None: ...
55+
def active(self) -> _WorkbookSheet | None: ...
5356
@active.setter
54-
def active(self, value: _WorkbookChild | int) -> None: ...
57+
def active(self, value: Worksheet | Chartsheet | int) -> None: ...
58+
# read_only workbook cannot call this method
5559
# Could be generic based on write_only
5660
def create_sheet(
5761
self, title: str | _Decodable | None = None, index: int | None = None
5862
) -> Any: ... # AnyOf[WriteOnlyWorksheet, Worksheet]
5963
def move_sheet(self, sheet: Worksheet | str, offset: int = 0) -> None: ...
60-
def remove(self, worksheet: Worksheet) -> None: ...
64+
def remove(self, worksheet: _WorkbookSheet) -> None: ...
6165
@deprecated("Use wb.remove(worksheet) or del wb[sheetname]")
62-
def remove_sheet(self, worksheet: Worksheet) -> None: ...
66+
def remove_sheet(self, worksheet: _WorkbookSheet) -> None: ...
6367
def create_chartsheet(self, title: str | _Decodable | None = None, index: int | None = None) -> Chartsheet: ...
6468
@deprecated("Use wb[sheetname]")
65-
def get_sheet_by_name(self, name: str) -> Worksheet: ...
69+
def get_sheet_by_name(self, name: str) -> _WorkbookSheet: ...
6670
def __contains__(self, key: str) -> bool: ...
67-
def index(self, worksheet: Worksheet) -> int: ...
71+
def index(self, worksheet: _WorkbookWorksheet) -> int: ...
6872
@deprecated("Use wb.index(worksheet)")
69-
def get_index(self, worksheet: Worksheet) -> int: ...
70-
def __getitem__(self, key: str) -> Worksheet: ...
73+
def get_index(self, worksheet: _WorkbookWorksheet) -> int: ...
74+
def __getitem__(self, key: str) -> _WorkbookSheet: ...
7175
def __delitem__(self, key: str) -> None: ...
72-
def __iter__(self) -> Iterator[Worksheet]: ...
76+
def __iter__(self) -> Iterator[_WorkbookWorksheet]: ...
7377
@deprecated("Use wb.sheetnames")
74-
def get_sheet_names(self) -> list[Worksheet]: ...
78+
def get_sheet_names(self) -> list[str]: ...
7579
@property
76-
def worksheets(self) -> list[Worksheet]: ...
80+
def worksheets(self) -> list[_WorkbookWorksheet]: ...
7781
@property
7882
def chartsheets(self) -> list[Chartsheet]: ...
7983
@property
8084
def sheetnames(self) -> list[str]: ...
8185
@deprecated("Assign scoped named ranges directly to worksheets or global ones to the workbook. Deprecated in 3.1")
8286
def create_named_range(
83-
self, name: str, worksheet: Worksheet | None = None, value: str | Incomplete | None = None, scope: Unused = None
87+
self,
88+
name: str,
89+
worksheet: _WorkbookChild | ReadOnlyWorksheet | None = None,
90+
value: str | Incomplete | None = None,
91+
scope: Unused = None,
8492
) -> None: ...
8593
def add_named_style(self, style: NamedStyle) -> None: ...
8694
@property
@@ -90,5 +98,8 @@ class Workbook:
9098
def save(self, filename: _ZipFileFileProtocol) -> None: ...
9199
@property
92100
def style_names(self) -> list[str]: ...
93-
def copy_worksheet(self, from_worksheet: Worksheet) -> Worksheet | WriteOnlyWorksheet: ...
101+
# A write_only and read_only workbooks can't use this method as it requires both reading and writing.
102+
# On an implementation level, a WorksheetCopy is created from the call to self.create_sheet,
103+
# but WorksheetCopy only works with Worksheet.
104+
def copy_worksheet(self, from_worksheet: Worksheet) -> Worksheet: ...
94105
def close(self) -> None: ...

stubs/openpyxl/openpyxl/worksheet/_read_only.pyi

+8-3
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
from _typeshed import Incomplete, SupportsGetItem
1+
from _typeshed import SupportsGetItem
22
from collections.abc import Generator
33

44
from openpyxl import _VisibilityType
55
from openpyxl.cell import _CellValue
66
from openpyxl.cell.cell import Cell
77
from openpyxl.utils.cell import _RangeBoundariesTuple
8+
from openpyxl.workbook.workbook import Workbook
89
from openpyxl.worksheet.worksheet import Worksheet
910

1011
def read_dimension(source) -> _RangeBoundariesTuple | None: ...
@@ -13,17 +14,21 @@ class ReadOnlyWorksheet:
1314
cell = Worksheet.cell
1415
iter_rows = Worksheet.iter_rows
1516
# Same as Worksheet.values
17+
# https://github.com/python/mypy/issues/6700
1618
@property
1719
def values(self) -> Generator[tuple[_CellValue, ...], None, None]: ...
1820
# Same as Worksheet.rows
21+
# https://github.com/python/mypy/issues/6700
1922
@property
2023
def rows(self) -> Generator[tuple[Cell, ...], None, None]: ...
2124
__getitem__ = Worksheet.__getitem__
2225
__iter__ = Worksheet.__iter__
23-
parent: Incomplete
26+
parent: Workbook
2427
title: str
2528
sheet_state: _VisibilityType
26-
def __init__(self, parent_workbook, title: str, worksheet_path, shared_strings: SupportsGetItem[int, str]) -> None: ...
29+
def __init__(
30+
self, parent_workbook: Workbook, title: str, worksheet_path, shared_strings: SupportsGetItem[int, str]
31+
) -> None: ...
2732
def calculate_dimension(self, force: bool = False): ...
2833
def reset_dimensions(self) -> None: ...
2934
@property

0 commit comments

Comments
 (0)