diff --git a/stubs/openpyxl/@tests/stubtest_allowlist.txt b/stubs/openpyxl/@tests/stubtest_allowlist.txt index dd6ff8ec8..f40d00628 100644 --- a/stubs/openpyxl/@tests/stubtest_allowlist.txt +++ b/stubs/openpyxl/@tests/stubtest_allowlist.txt @@ -1,3 +1,14 @@ +# Loop variables leaked in global scope +openpyxl.utils.cell.col +openpyxl.utils.cell.i + +# Unintended re-export from star-import +openpyxl.chart.marker.DRAWING_NS +openpyxl.chart.marker.PRESET_COLORS +openpyxl.chart.shapes.DRAWING_NS +openpyxl.chart.shapes.PRESET_COLORS +openpyxl.descriptors.DEBUG + # The actual runtime definition depends on what else is installed # (lxml, defusedxml, et_xmlfile) openpyxl.xml._functions_overloads diff --git a/stubs/openpyxl/METADATA.toml b/stubs/openpyxl/METADATA.toml index af3b0230e..cb4138c9f 100644 --- a/stubs/openpyxl/METADATA.toml +++ b/stubs/openpyxl/METADATA.toml @@ -1,6 +1,2 @@ version = "3.1.*" upstream_repository = "https://foss.heptapod.net/openpyxl/openpyxl" -partial_stub = true - -[tool.stubtest] -ignore_missing_stub = true diff --git a/stubs/openpyxl/openpyxl/__init__.pyi b/stubs/openpyxl/openpyxl/__init__.pyi index c252e6d9c..e72969903 100644 --- a/stubs/openpyxl/openpyxl/__init__.pyi +++ b/stubs/openpyxl/openpyxl/__init__.pyi @@ -12,4 +12,5 @@ from ._constants import ( __version__ as __version__, ) +DEBUG: bool open = load_workbook diff --git a/stubs/openpyxl/openpyxl/cell/rich_text.pyi b/stubs/openpyxl/openpyxl/cell/rich_text.pyi index 0100282c0..0732bccea 100644 --- a/stubs/openpyxl/openpyxl/cell/rich_text.pyi +++ b/stubs/openpyxl/openpyxl/cell/rich_text.pyi @@ -4,6 +4,7 @@ from typing_extensions import Literal, Self from openpyxl.cell.text import InlineFont from openpyxl.descriptors import Strict, String, Typed +from openpyxl.descriptors.serialisable import _ChildSerialisableTreeElement class TextBlock(Strict): font: Typed[InlineFont, Literal[False]] @@ -18,7 +19,7 @@ class CellRichText(list[str | TextBlock]): @overload def __init__(self, *args: str | TextBlock) -> None: ... @classmethod - def from_tree(cls, node) -> Self: ... + def from_tree(cls, node: _ChildSerialisableTreeElement) -> Self: ... def __add__(self, arg: Iterable[str | TextBlock]) -> CellRichText: ... # type: ignore[override] def append(self, arg: str | TextBlock) -> None: ... def extend(self, arg: Iterable[str | TextBlock]) -> None: ... diff --git a/stubs/openpyxl/openpyxl/chart/chartspace.pyi b/stubs/openpyxl/openpyxl/chart/chartspace.pyi index 1d8505dce..a95939182 100644 --- a/stubs/openpyxl/openpyxl/chart/chartspace.pyi +++ b/stubs/openpyxl/openpyxl/chart/chartspace.pyi @@ -91,7 +91,7 @@ class ChartSpace(Serialisable): protection: Typed[Protection, Literal[True]] chart: Typed[ChartContainer, Literal[False]] spPr: Typed[GraphicalProperties, Literal[True]] - graphicalProperties: Alias + graphical_properties: Alias txPr: Typed[RichText, Literal[True]] textProperties: Alias externalData: Typed[ExternalData, Literal[True]] diff --git a/stubs/openpyxl/openpyxl/descriptors/excel.pyi b/stubs/openpyxl/openpyxl/descriptors/excel.pyi index 7bf24ad9d..fc4dcdaf3 100644 --- a/stubs/openpyxl/openpyxl/descriptors/excel.pyi +++ b/stubs/openpyxl/openpyxl/descriptors/excel.pyi @@ -1,13 +1,11 @@ from _typeshed import Incomplete -from typing import ClassVar, TypeVar +from typing import ClassVar from typing_extensions import Literal from . import Integer, MatchPattern, MinMax, Strict, String +from .base import _M, _N from .serialisable import Serialisable -_N = TypeVar("_N", bound=bool) -_M = TypeVar("_M", int, float) - class HexBinary(MatchPattern[str, Incomplete]): pattern: str diff --git a/stubs/openpyxl/openpyxl/descriptors/sequence.pyi b/stubs/openpyxl/openpyxl/descriptors/sequence.pyi index 333a592a2..ff2176f25 100644 --- a/stubs/openpyxl/openpyxl/descriptors/sequence.pyi +++ b/stubs/openpyxl/openpyxl/descriptors/sequence.pyi @@ -9,12 +9,17 @@ from .base import Alias, Descriptor class Sequence(Descriptor[Incomplete]): expected_type: type[Incomplete] - seq_types: Incomplete + seq_types: tuple[type, ...] idx_base: int unique: bool + container: type def __set__(self, instance: Serialisable | Strict, seq) -> None: ... def to_tree(self, tagname, obj, namespace: str | None = None) -> Generator[Incomplete, None, None]: ... +class UniqueSequence(Sequence): + seq_types: tuple[type, ...] + container: type + class ValueSequence(Sequence): attribute: str def to_tree(self, tagname, obj, namespace: str | None = None) -> Generator[Incomplete, None, None]: ... diff --git a/stubs/openpyxl/openpyxl/descriptors/serialisable.pyi b/stubs/openpyxl/openpyxl/descriptors/serialisable.pyi index d2ecf72e0..3afff355f 100644 --- a/stubs/openpyxl/openpyxl/descriptors/serialisable.pyi +++ b/stubs/openpyxl/openpyxl/descriptors/serialisable.pyi @@ -1,10 +1,16 @@ -from _typeshed import Incomplete -from typing import Any, ClassVar, NoReturn +from _typeshed import Incomplete, SupportsIter +from typing import Any, ClassVar, NoReturn, Protocol from typing_extensions import Final from openpyxl.descriptors import MetaSerialisable -from ..xml._functions_overloads import _HasTagAndTextAndAttrib +from ..xml._functions_overloads import _HasAttrib, _HasTagAndGet, _HasText + +# For any override directly re-using Serialisable.from_tree +class _ChildSerialisableTreeElement(_HasAttrib, _HasText, SupportsIter[Incomplete], Protocol): ... + +class _SerialisableTreeElement(_HasTagAndGet[Incomplete], _ChildSerialisableTreeElement, Protocol): + def find(self, __path: str) -> Incomplete | None: ... KEYWORDS: Final[frozenset[str]] seq_types: Final[tuple[type[list[Any]], type[tuple[Any, ...]]]] @@ -20,8 +26,12 @@ class Serialisable(metaclass=MetaSerialisable): @property def tagname(self) -> str | NoReturn: ... namespace: ClassVar[str | None] + # Note: To respect the Liskov substitution principle, the protocol for node includes all child class requirements + # See comment in xml/functions.pyi as to why use a protocol instead of Element + # Child classes should be more precise than _SerialisableTreeElement ! + # Use _ChildSerialisableTreeElement instead for child classes that reuse Serialisable.from_tree directly. @classmethod - def from_tree(cls, node: _HasTagAndTextAndAttrib): ... + def from_tree(cls, node: _SerialisableTreeElement): ... def to_tree(self, tagname: str | None = None, idx: Incomplete | None = None, namespace: str | None = None): ... def __iter__(self): ... def __eq__(self, other): ... diff --git a/stubs/openpyxl/openpyxl/pivot/table.pyi b/stubs/openpyxl/openpyxl/pivot/table.pyi index 59af9e6eb..6f27a7a32 100644 --- a/stubs/openpyxl/openpyxl/pivot/table.pyi +++ b/stubs/openpyxl/openpyxl/pivot/table.pyi @@ -953,3 +953,6 @@ class TableDefinition(Serialisable): def to_tree(self): ... @property def path(self): ... + def formatted_fields(self) -> dict[Incomplete, list[Incomplete]]: ... + @property + def summary(self) -> str: ... diff --git a/stubs/openpyxl/openpyxl/reader/excel.pyi b/stubs/openpyxl/openpyxl/reader/excel.pyi index 4747182a4..7464059aa 100644 --- a/stubs/openpyxl/openpyxl/reader/excel.pyi +++ b/stubs/openpyxl/openpyxl/reader/excel.pyi @@ -37,6 +37,7 @@ class ExcelReader: def read_strings(self) -> None: ... def read_workbook(self) -> None: ... def read_properties(self) -> None: ... + def read_custom(self) -> None: ... def read_theme(self) -> None: ... def read_chartsheet(self, sheet: Chartsheet, rel: Relationship) -> None: ... def read_worksheets(self) -> None: ... diff --git a/stubs/openpyxl/openpyxl/reader/strings.pyi b/stubs/openpyxl/openpyxl/reader/strings.pyi index 932a8b6f3..3d6b247de 100644 --- a/stubs/openpyxl/openpyxl/reader/strings.pyi +++ b/stubs/openpyxl/openpyxl/reader/strings.pyi @@ -1 +1,6 @@ -def read_string_table(xml_source): ... +from xml.etree.ElementTree import _FileRead + +from openpyxl.cell.rich_text import CellRichText + +def read_string_table(xml_source: _FileRead) -> list[str]: ... +def read_rich_text(xml_source: _FileRead) -> list[CellRichText | str]: ... diff --git a/stubs/openpyxl/openpyxl/utils/formulas.pyi b/stubs/openpyxl/openpyxl/utils/formulas.pyi index 6d16169b1..af0607318 100644 --- a/stubs/openpyxl/openpyxl/utils/formulas.pyi +++ b/stubs/openpyxl/openpyxl/utils/formulas.pyi @@ -1,3 +1,5 @@ from typing_extensions import Final FORMULAE: Final[frozenset[str]] + +def validate(formula: str) -> None: ... diff --git a/stubs/openpyxl/openpyxl/worksheet/_reader.pyi b/stubs/openpyxl/openpyxl/worksheet/_reader.pyi index 840801abb..4d3cf8f0c 100644 --- a/stubs/openpyxl/openpyxl/worksheet/_reader.pyi +++ b/stubs/openpyxl/openpyxl/worksheet/_reader.pyi @@ -3,6 +3,9 @@ from _typeshed import Incomplete from collections.abc import Container, Generator from typing_extensions import Final +from openpyxl.cell.rich_text import CellRichText +from openpyxl.descriptors.serialisable import _ChildSerialisableTreeElement + from .hyperlink import HyperlinkList from .pagebreak import ColBreak, RowBreak from .protection import SheetProtection @@ -37,6 +40,8 @@ DATA_TAG: Final[str] DIMENSION_TAG: Final[str] CUSTOM_VIEWS_TAG: Final[str] +def parse_richtext_string(element: _ChildSerialisableTreeElement) -> CellRichText | str: ... + class WorkSheetParser: min_row: Incomplete | None min_col: Incomplete | None diff --git a/stubs/openpyxl/openpyxl/worksheet/cell_range.pyi b/stubs/openpyxl/openpyxl/worksheet/cell_range.pyi index 1c6e0f61d..68e7bfbd9 100644 --- a/stubs/openpyxl/openpyxl/worksheet/cell_range.pyi +++ b/stubs/openpyxl/openpyxl/worksheet/cell_range.pyi @@ -79,6 +79,7 @@ class MultiCellRange(Strict): ranges: Incomplete def __init__(self, ranges=...) -> None: ... def __contains__(self, coord): ... + def sorted(self) -> list[CellRange]: ... def add(self, coord) -> None: ... def __iadd__(self, coord): ... def __eq__(self, other): ... diff --git a/stubs/openpyxl/openpyxl/worksheet/filters.pyi b/stubs/openpyxl/openpyxl/worksheet/filters.pyi index a53c503f1..96489745c 100644 --- a/stubs/openpyxl/openpyxl/worksheet/filters.pyi +++ b/stubs/openpyxl/openpyxl/worksheet/filters.pyi @@ -1,11 +1,14 @@ from _typeshed import Incomplete, Unused from datetime import datetime +from re import Pattern from typing import ClassVar, overload from typing_extensions import Literal, TypeAlias +from openpyxl.descriptors import Strict from openpyxl.descriptors.base import ( Alias, Bool, + Convertible, DateTime, Float, Integer, @@ -21,6 +24,8 @@ from openpyxl.descriptors.base import ( from openpyxl.descriptors.excel import ExtensionList from openpyxl.descriptors.serialisable import Serialisable +from ..descriptors.base import _N + _SortConditionSortBy: TypeAlias = Literal["value", "cellColor", "fontColor", "icon"] _IconSet: TypeAlias = Literal[ "3Arrows", @@ -167,6 +172,18 @@ class DynamicFilter(Serialisable): maxValIso: datetime | str | None = None, ) -> None: ... +class CustomFilterValueDescriptor(Convertible[float | str, _N]): + pattern: Pattern[str] + expected_type: type[float | str] + @overload # type:ignore[override] # Different restrictions + def __set__( + self: CustomFilterValueDescriptor[Literal[True]], instance: Serialisable | Strict, value: str | _ConvertibleToFloat | None + ) -> None: ... + @overload + def __set__( + self: CustomFilterValueDescriptor[Literal[False]], instance: Serialisable | Strict, value: str | _ConvertibleToFloat + ) -> None: ... + class CustomFilter(Serialisable): tagname: ClassVar[str] operator: NoneSet[_CustomFilterOperator] diff --git a/stubs/openpyxl/openpyxl/xml/_functions_overloads.pyi b/stubs/openpyxl/openpyxl/xml/_functions_overloads.pyi index be1fb7a04..06437d35f 100644 --- a/stubs/openpyxl/openpyxl/xml/_functions_overloads.pyi +++ b/stubs/openpyxl/openpyxl/xml/_functions_overloads.pyi @@ -20,13 +20,14 @@ class _HasTag(Protocol): class _HasText(Protocol): text: str +class _HasAttrib(Protocol): + attrib: Iterable[Any] # AnyOf[dict[str, str], Iterable[tuple[str, str]]] + class _HasTagAndGet(_HasTag, Protocol[_T_co]): def get(self, __value: str) -> _T_co | None: ... class _HasTagAndText(_HasTag, _HasText, Protocol): ... # noqa: Y046 - -class _HasTagAndTextAndAttrib(_HasTag, _HasText, Protocol): # noqa: Y046 - attrib: Iterable[Any] # AnyOf[dict[str, str], Iterable[tuple[str, str]]] +class _HasTagAndTextAndAttrib(_HasTag, _HasText, _HasAttrib, Protocol): ... # noqa: Y046 class _ParentElement(Protocol[_T]): def makeelement(self, __tag: str, __attrib: dict[str, str]) -> _T: ...