Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

openpyxl: Typed from_tree methods #10602

Merged
merged 1 commit into from
Sep 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions stubs/openpyxl/openpyxl/chart/axis.pyi
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from _typeshed import Incomplete, Unused
from typing import ClassVar, overload
from typing_extensions import Literal, TypeAlias
from typing_extensions import Literal, Self, TypeAlias

from openpyxl.chart.layout import Layout
from openpyxl.chart.shapes import GraphicalProperties
Expand All @@ -19,7 +19,7 @@ from openpyxl.descriptors.nested import (
)
from openpyxl.descriptors.serialisable import Serialisable

from ..xml._functions_overloads import _HasTagAndGet
from ..xml._functions_overloads import _HasTagAndGet, _SupportsFindAndIterAndAttribAndText

_ScalingOrientation: TypeAlias = Literal["maxMin", "minMax"]
_BaseAxisAxPos: TypeAlias = Literal["b", "l", "r", "t"]
Expand Down Expand Up @@ -198,7 +198,7 @@ class NumericAxis(_BaseAxis):
**kw,
) -> None: ...
@classmethod
def from_tree(cls, node): ...
def from_tree(cls, node: _SupportsFindAndIterAndAttribAndText) -> Self: ...

class TextAxis(_BaseAxis):
tagname: ClassVar[str]
Expand Down
6 changes: 3 additions & 3 deletions stubs/openpyxl/openpyxl/chart/plotarea.pyi
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
from _typeshed import Incomplete, Unused
from typing import ClassVar
from typing_extensions import Literal
from typing_extensions import Literal, Self

from openpyxl.chart.layout import Layout
from openpyxl.chart.shapes import GraphicalProperties
from openpyxl.chart.text import RichText
from openpyxl.descriptors.base import Alias, Typed, _ConvertibleToBool
from openpyxl.descriptors.excel import ExtensionList
from openpyxl.descriptors.nested import NestedBool
from openpyxl.descriptors.serialisable import Serialisable
from openpyxl.descriptors.serialisable import Serialisable, _ChildSerialisableTreeElement

from ..xml._functions_overloads import _HasTagAndGet

Expand Down Expand Up @@ -73,4 +73,4 @@ class PlotArea(Serialisable):
) -> None: ...
def to_tree(self, tagname: str | None = None, idx: Incomplete | None = None, namespace: str | None = None): ...
@classmethod
def from_tree(cls, node): ...
def from_tree(cls, node: _ChildSerialisableTreeElement) -> Self: ...
8 changes: 4 additions & 4 deletions stubs/openpyxl/openpyxl/descriptors/nested.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ from openpyxl.descriptors.serialisable import Serialisable
from openpyxl.drawing.fill import Blip
from openpyxl.xml.functions import Element

from ..xml._functions_overloads import _HasTagAndGet, _HasTagAndText
from ..xml._functions_overloads import _HasGet, _HasTagAndGet, _HasText
from .base import _M, _N, _T, _ConvertibleToBool, _ConvertibleToFloat, _ConvertibleToInt, _ExpectedTypeParam

_NestedNoneSetParam: TypeAlias = _HasTagAndGet[_T | Literal["none"] | None] | _T | Literal["none"] | None
Expand All @@ -35,7 +35,7 @@ class Nested(Descriptor[_T]):
) -> None: ...
def __get__(self, instance: Serialisable | Strict, cls: type | None) -> _T: ...
def __set__(self, instance: Serialisable | Strict, value: _HasTagAndGet[_T] | _T) -> None: ...
def from_tree(self, node: _HasTagAndGet[_T]) -> _T: ...
def from_tree(self, node: _HasGet[_T]) -> _T: ...
def to_tree(self, tagname: str | None = None, value: Incomplete | None = None, namespace: str | None = None) -> Element: ...

class NestedValue(Nested[_T], Convertible[_T, _N]): # type: ignore[misc]
Expand Down Expand Up @@ -150,7 +150,7 @@ class NestedText(NestedValue[_T, _N]):
# Anything else
@overload
def __set__(self: NestedText[_T, Literal[True]], instance: Serialisable | Strict, value: _T | int | Any | None) -> None: ...
def from_tree(self, node: _HasTagAndText) -> str: ... # type: ignore[override]
def from_tree(self, node: _HasText) -> str: ... # type: ignore[override]
def to_tree(self, tagname: str | None = None, value: Incomplete | None = None, namespace: str | None = None) -> Element: ...

class NestedFloat(NestedValue[float, _N], Float[_N]): # type: ignore[misc]
Expand Down Expand Up @@ -179,7 +179,7 @@ class NestedBool(NestedValue[bool, _N], Bool[_N]): # type: ignore[misc]
def __set__( # type:ignore[override] # Different restrictions
self, instance: Serialisable | Strict, value: _HasTagAndGet[_ConvertibleToBool] | _ConvertibleToBool
) -> None: ...
def from_tree(self, node) -> bool: ... # type: ignore[override] # Actual overriden return type
def from_tree(self, node: _HasGet[bool]) -> bool: ... # type: ignore[override] # Actual overriden return type

class NestedNoneSet(Nested[_T | None], NoneSet[_T]): # type: ignore[misc]
def __init__(self, name: str | None = None, *, values: Iterable[_T | None]) -> None: ...
Expand Down
21 changes: 16 additions & 5 deletions stubs/openpyxl/openpyxl/descriptors/sequence.pyi
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
from _typeshed import Incomplete, Unused
from collections.abc import Generator
from typing_extensions import Self
from collections.abc import Generator, Iterable
from typing import Any, Protocol
from typing_extensions import Self, TypeVar

from openpyxl.descriptors import Strict
from openpyxl.descriptors.serialisable import Serialisable
from openpyxl.descriptors.serialisable import Serialisable, _SerialisableTreeElement
from openpyxl.xml._functions_overloads import _HasGet

from .base import Alias, Descriptor

_T = TypeVar("_T")

class _SupportsFromTree(Protocol):
@classmethod
def from_tree(cls, node: _SerialisableTreeElement) -> Any: ...

class Sequence(Descriptor[Incomplete]):
expected_type: type[Incomplete]
seq_types: tuple[type, ...]
Expand All @@ -23,12 +31,15 @@ class UniqueSequence(Sequence):
class ValueSequence(Sequence):
attribute: str
def to_tree(self, tagname, obj, namespace: str | None = None) -> Generator[Incomplete, None, None]: ...
def from_tree(self, node): ...
def from_tree(self, node: _HasGet[_T]) -> _T: ...

class NestedSequence(Sequence):
count: bool
expected_type: type[_SupportsFromTree]
def to_tree(self, tagname, obj, namespace: str | None = None): ...
def from_tree(self, node): ...
# returned list generic type should be same as the return type of expected_type.from_tree(node)
# Which can really be anything given the wildly different, and sometimes generic, from_tree return types
def from_tree(self, node: Iterable[_SerialisableTreeElement]) -> list[Any]: ...

class MultiSequence(Sequence):
def __set__(self, instance: Serialisable | Strict, seq) -> None: ...
Expand Down
13 changes: 6 additions & 7 deletions stubs/openpyxl/openpyxl/descriptors/serialisable.pyi
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
from _typeshed import Incomplete, SupportsIter
from typing import Any, ClassVar, NoReturn, Protocol
from typing_extensions import Final
from typing_extensions import Final, Self

from openpyxl.descriptors import MetaSerialisable

from ..xml._functions_overloads import _HasAttrib, _HasTagAndGet, _HasText
from ..xml._functions_overloads import _HasAttrib, _HasGet, _HasText, _SupportsFindChartLines

# 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: ...
class _SerialisableTreeElement(_HasGet[object], _SupportsFindChartLines, _ChildSerialisableTreeElement, Protocol): ...

KEYWORDS: Final[frozenset[str]]
seq_types: Final[tuple[type[list[Any]], type[tuple[Any, ...]]]]
Expand All @@ -26,12 +24,13 @@ 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
# Note: To respect the Liskov substitution principle, the protocol for node includes all child class requirements.
# Same with the return type to avoid override issues.
# 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: _SerialisableTreeElement): ...
def from_tree(cls, node: _SerialisableTreeElement) -> Self | None: ...
def to_tree(self, tagname: str | None = None, idx: Incomplete | None = None, namespace: str | None = None): ...
def __iter__(self): ...
def __eq__(self, other): ...
Expand Down
3 changes: 2 additions & 1 deletion stubs/openpyxl/openpyxl/packaging/custom.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ from openpyxl.descriptors.base import (
_ConvertibleToInt,
)
from openpyxl.descriptors.nested import NestedText
from openpyxl.descriptors.serialisable import _ChildSerialisableTreeElement

_T = TypeVar("_T")

Expand Down Expand Up @@ -57,7 +58,7 @@ class CustomPropertyList(Strict):
props: Sequence
def __init__(self) -> None: ...
@classmethod
def from_tree(cls, tree) -> Self: ...
def from_tree(cls, tree: _ChildSerialisableTreeElement) -> Self: ...
def append(self, prop) -> None: ...
def to_tree(self): ...
def __len__(self) -> int: ...
Expand Down
5 changes: 4 additions & 1 deletion stubs/openpyxl/openpyxl/styles/fills.pyi
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
from _typeshed import Incomplete
from collections.abc import Iterable, Sequence as ABCSequence
from typing import ClassVar
from typing_extensions import Final, Literal, TypeAlias

from openpyxl.descriptors import Sequence
from openpyxl.descriptors.base import Alias, Float, MinMax, NoneSet, Set, _ConvertibleToFloat
from openpyxl.descriptors.serialisable import Serialisable

from ..xml._functions_overloads import _SupportsIterAndAttribAndTextAndTag

FILL_NONE: Final = "none"
FILL_SOLID: Final = "solid"
FILL_PATTERN_DARKDOWN: Final = "darkDown"
Expand Down Expand Up @@ -53,7 +56,7 @@ fills: tuple[_FillsType, ...]
class Fill(Serialisable):
tagname: ClassVar[str]
@classmethod
def from_tree(cls, el): ...
def from_tree(cls, el: Iterable[ABCSequence[_SupportsIterAndAttribAndTextAndTag]]) -> PatternFill | GradientFill | None: ...

class PatternFill(Fill):
tagname: ClassVar[str]
Expand Down
6 changes: 3 additions & 3 deletions stubs/openpyxl/openpyxl/styles/fonts.pyi
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from _typeshed import Incomplete
from typing import ClassVar
from typing_extensions import Final, Literal, TypeAlias
from typing_extensions import Final, Literal, Self, TypeAlias

from openpyxl.descriptors.base import Alias, _ConvertibleToBool, _ConvertibleToFloat, _ConvertibleToInt
from openpyxl.descriptors.nested import (
Expand All @@ -14,7 +14,7 @@ from openpyxl.descriptors.nested import (
)
from openpyxl.descriptors.serialisable import Serialisable

from ..xml._functions_overloads import _HasTagAndGet
from ..xml._functions_overloads import _HasTagAndGet, _SupportsFindAndIterAndAttribAndText

_FontU: TypeAlias = Literal["single", "double", "singleAccounting", "doubleAccounting"]
_FontVertAlign: TypeAlias = Literal["superscript", "subscript", "baseline"]
Expand Down Expand Up @@ -71,6 +71,6 @@ class Font(Serialisable):
extend: _HasTagAndGet[_ConvertibleToBool | None] | _ConvertibleToBool | None = None,
) -> None: ...
@classmethod
def from_tree(cls, node): ...
def from_tree(cls, node: _SupportsFindAndIterAndAttribAndText) -> Self: ...

DEFAULT_FONT: Final[Font]
6 changes: 3 additions & 3 deletions stubs/openpyxl/openpyxl/styles/stylesheet.pyi
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
from _typeshed import Incomplete, Unused
from typing import ClassVar
from typing_extensions import Literal
from typing_extensions import Literal, Self

from openpyxl.descriptors.base import Typed
from openpyxl.descriptors.excel import ExtensionList
from openpyxl.descriptors.serialisable import Serialisable
from openpyxl.descriptors.serialisable import Serialisable, _ChildSerialisableTreeElement
from openpyxl.styles.cell_style import CellStyleList
from openpyxl.styles.colors import ColorList
from openpyxl.styles.named_styles import _NamedCellStyleList
Expand Down Expand Up @@ -45,7 +45,7 @@ class Stylesheet(Serialisable):
extLst: Unused = None,
) -> None: ...
@classmethod
def from_tree(cls, node): ...
def from_tree(cls, node: _ChildSerialisableTreeElement) -> Self: ...
@property
def custom_formats(self): ...
def to_tree(self, tagname: str | None = None, idx: Incomplete | None = None, namespace: str | None = None): ...
Expand Down
6 changes: 4 additions & 2 deletions stubs/openpyxl/openpyxl/workbook/protection.pyi
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
from _typeshed import Incomplete
from typing import ClassVar
from typing_extensions import Literal
from typing_extensions import Literal, Self

from openpyxl.descriptors.base import Alias, Bool, Integer, String, _ConvertibleToBool, _ConvertibleToInt
from openpyxl.descriptors.serialisable import Serialisable

from ..xml._functions_overloads import _SupportsIterAndAttribAndTextAndGet

class WorkbookProtection(Serialisable):
tagname: ClassVar[str]
workbook_password: Alias
Expand Down Expand Up @@ -55,7 +57,7 @@ class WorkbookProtection(Serialisable):
@revisionsPassword.setter
def revisionsPassword(self, value) -> None: ...
@classmethod
def from_tree(cls, node): ...
def from_tree(cls, node: _SupportsIterAndAttribAndTextAndGet) -> Self: ...

DocumentSecurity = WorkbookProtection

Expand Down
6 changes: 4 additions & 2 deletions stubs/openpyxl/openpyxl/worksheet/header_footer.pyi
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
from re import Pattern
from typing import ClassVar
from typing_extensions import Final, Literal
from typing_extensions import Final, Literal, Self

from openpyxl.descriptors import Strict
from openpyxl.descriptors.base import Alias, Bool, Integer, MatchPattern, String, Typed, _ConvertibleToBool, _ConvertibleToInt
from openpyxl.descriptors.serialisable import Serialisable

from ..xml._functions_overloads import _HasText

FONT_PATTERN: Final = '&"(?P<font>.+)"'
COLOR_PATTERN: Final = "&K(?P<color>[A-F0-9]{6})"
SIZE_REGEX: Final = r"&(?P<size>\d+\s?)"
Expand Down Expand Up @@ -38,7 +40,7 @@ class HeaderFooterItem(Strict):
def __bool__(self) -> bool: ...
def to_tree(self, tagname): ...
@classmethod
def from_tree(cls, node): ...
def from_tree(cls, node: _HasText) -> Self: ...

class HeaderFooter(Serialisable):
tagname: ClassVar[str]
Expand Down
6 changes: 3 additions & 3 deletions stubs/openpyxl/openpyxl/worksheet/page.pyi
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
from _typeshed import Incomplete
from typing import ClassVar
from typing_extensions import Literal, TypeAlias
from typing_extensions import Literal, Self, TypeAlias

from openpyxl.descriptors.base import Bool, Float, Integer, NoneSet, _ConvertibleToBool, _ConvertibleToFloat, _ConvertibleToInt
from openpyxl.descriptors.serialisable import Serialisable
from openpyxl.descriptors.serialisable import Serialisable, _ChildSerialisableTreeElement

_PrintPageSetupOrientation: TypeAlias = Literal["default", "portrait", "landscape"]
_PrintPageSetupPageOrder: TypeAlias = Literal["downThenOver", "overThenDown"]
Expand Down Expand Up @@ -66,7 +66,7 @@ class PrintPageSetup(Serialisable):
@autoPageBreaks.setter
def autoPageBreaks(self, value) -> None: ...
@classmethod
def from_tree(cls, node): ...
def from_tree(cls, node: _ChildSerialisableTreeElement) -> Self: ...

class PrintOptions(Serialisable):
tagname: ClassVar[str]
Expand Down
6 changes: 3 additions & 3 deletions stubs/openpyxl/openpyxl/worksheet/table.pyi
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
from _typeshed import Incomplete, Unused
from typing import ClassVar, overload
from typing_extensions import Final, Literal, TypeAlias
from typing_extensions import Final, Literal, Self, TypeAlias

from openpyxl.descriptors import Strict, String
from openpyxl.descriptors.base import Alias, Bool, Integer, NoneSet, Typed, _ConvertibleToBool, _ConvertibleToInt
from openpyxl.descriptors.excel import ExtensionList
from openpyxl.descriptors.serialisable import Serialisable
from openpyxl.descriptors.serialisable import Serialisable, _ChildSerialisableTreeElement
from openpyxl.worksheet.filters import AutoFilter, SortState

_TableColumnTotalsRowFunction: TypeAlias = Literal[
Expand Down Expand Up @@ -129,7 +129,7 @@ class TableColumn(Serialisable):
) -> None: ...
def __iter__(self): ...
@classmethod
def from_tree(cls, node): ...
def from_tree(cls, node: _ChildSerialisableTreeElement) -> Self: ...

class TableNameDescriptor(String[Incomplete]):
def __set__(self, instance: Serialisable | Strict, value) -> None: ...
Expand Down
22 changes: 18 additions & 4 deletions stubs/openpyxl/openpyxl/xml/_functions_overloads.pyi
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
# This file does not exist at runtime. It is a helper file to overload imported functions in openpyxl.xml.functions

import sys
from _typeshed import Incomplete, ReadableBuffer
from _typeshed import Incomplete, ReadableBuffer, SupportsIter
from collections.abc import Iterable, Iterator, Mapping, Sequence
from typing import Any, Protocol, TypeVar, overload
from typing_extensions import TypeAlias
from xml.etree.ElementTree import Element, ElementTree, QName, XMLParser, _FileRead

from openpyxl.chart.axis import ChartLines

_T = TypeVar("_T")
_T_co = TypeVar("_T_co", covariant=True)

Expand All @@ -17,18 +19,30 @@ _T_co = TypeVar("_T_co", covariant=True)
class _HasTag(Protocol):
tag: Any # AnyOf[str, None, Callable[..., AnyOf[str, None]]]

class _HasGet(Protocol[_T_co]):
def get(self, __value: str) -> _T_co | None: ...

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 _HasTagAndGet(_HasTag, _HasGet[_T_co], Protocol[_T_co]): ...
class _HasTagAndText(_HasTag, _HasText, Protocol): ... # noqa: Y046
class _HasTagAndTextAndAttrib(_HasTag, _HasText, _HasAttrib, Protocol): ... # noqa: Y046

class _SupportsFindChartLines(Protocol):
def find(self, __path: str) -> ChartLines | None: ...

class _SupportsFindAndIterAndAttribAndText( # noqa: Y046
_SupportsFindChartLines, SupportsIter[Incomplete], _HasAttrib, _HasText, Protocol
): ...
class _SupportsIterAndAttribAndTextAndTag(SupportsIter[Incomplete], _HasAttrib, _HasText, _HasTag, Protocol): ... # noqa: Y046
class _SupportsIterAndAttribAndTextAndGet( # noqa: Y046
SupportsIter[Incomplete], _HasAttrib, _HasText, _HasGet[Incomplete], Protocol
): ...

class _ParentElement(Protocol[_T]):
def makeelement(self, __tag: str, __attrib: dict[str, str]) -> _T: ...
def append(self, __element: _T) -> object: ...
Expand Down