Skip to content

openpyxl: type to_tree methods #10967

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

Merged
merged 11 commits into from
Dec 1, 2023
1 change: 1 addition & 0 deletions stubs/openpyxl/@tests/stubtest_allowlist.txt
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ openpyxl.drawing.text.PresetTextShape.__init__
openpyxl.drawing.text.TextField.__init__
openpyxl.drawing.text.TextNormalAutofit.__init__
openpyxl.formatting.rule.DataBar.__init__
openpyxl.packaging.core.QualifiedDateTime.to_tree
openpyxl.packaging.relationship.get_rel
openpyxl.packaging.relationship.Relationship.__init__
openpyxl.packaging.workbook.ChildSheet.__init__
Expand Down
4 changes: 3 additions & 1 deletion stubs/openpyxl/openpyxl/chart/_chart.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ from openpyxl.chart.shapes import GraphicalProperties
from openpyxl.chart.title import TitleDescriptor
from openpyxl.descriptors.base import Alias, Bool, Integer, MinMax, Set, Typed
from openpyxl.descriptors.serialisable import Serialisable
from openpyxl.xml.functions import Element

_ChartBaseDisplayBlanks: TypeAlias = Literal["span", "gap", "zero"]

Expand Down Expand Up @@ -41,7 +42,8 @@ class ChartBase(Serialisable):
def __init__(self, axId=(), **kw: Unused) -> None: ...
def __hash__(self) -> int: ...
def __iadd__(self, other): ...
def to_tree(self, namespace: str | None = None, tagname: str | None = None, idx: Incomplete | None = None): ... # type: ignore[override]
# namespace is in the wrong order to respect the override. This is an issue in openpyxl itself
def to_tree(self, namespace: Unused = None, tagname: str | None = None, idx: Unused = None) -> Element: ... # type: ignore[override]
def set_categories(self, labels) -> None: ...
def add_data(self, data, from_rows: bool = False, titles_from_data: bool = False) -> None: ...
def append(self, value) -> None: ...
Expand Down
3 changes: 2 additions & 1 deletion stubs/openpyxl/openpyxl/chart/chartspace.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ from openpyxl.descriptors.excel import ExtensionList
from openpyxl.descriptors.nested import NestedBool, NestedMinMax, NestedNoneSet, NestedString, _NestedNoneSetParam
from openpyxl.descriptors.serialisable import Serialisable
from openpyxl.drawing.colors import ColorMapping
from openpyxl.xml.functions import Element

from ..xml._functions_overloads import _HasTagAndGet

Expand Down Expand Up @@ -140,4 +141,4 @@ class ChartSpace(Serialisable):
userShapes: Incomplete | None = None,
extLst: Unused = None,
) -> None: ...
def to_tree(self, tagname: Incomplete | None = None, idx: Incomplete | None = None, namespace: str | None = None): ...
def to_tree(self, tagname: Unused = None, idx: Unused = None, namespace: Unused = None) -> Element: ...
3 changes: 2 additions & 1 deletion stubs/openpyxl/openpyxl/chart/plotarea.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ 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, _ChildSerialisableTreeElement
from openpyxl.xml.functions import Element

from ..xml._functions_overloads import _HasTagAndGet

Expand Down Expand Up @@ -71,6 +72,6 @@ class PlotArea(Serialisable):
_axes=(),
extLst: Unused = None,
) -> None: ...
def to_tree(self, tagname: str | None = None, idx: Incomplete | None = None, namespace: str | None = None): ...
def to_tree(self, tagname: str | None = None, idx: Unused = None, namespace: Unused = None) -> Element: ...
@classmethod
def from_tree(cls, node: _ChildSerialisableTreeElement) -> Self: ...
3 changes: 2 additions & 1 deletion stubs/openpyxl/openpyxl/chart/series.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ from openpyxl.descriptors.base import Alias, Typed, _ConvertibleToBool
from openpyxl.descriptors.excel import ExtensionList
from openpyxl.descriptors.nested import NestedBool, NestedInteger, NestedNoneSet, NestedText, _NestedNoneSetParam
from openpyxl.descriptors.serialisable import Serialisable
from openpyxl.xml.functions import Element

from ..xml._functions_overloads import _HasTagAndGet

Expand Down Expand Up @@ -82,7 +83,7 @@ class Series(Serialisable):
explosion: _HasTagAndGet[ConvertibleToInt | None] | ConvertibleToInt | None = None,
extLst: Unused = None,
) -> None: ...
def to_tree(self, tagname: str | None = None, idx: Incomplete | None = None): ... # type: ignore[override]
def to_tree(self, tagname: str | None = None, idx: _HasTagAndGet[ConvertibleToInt] | ConvertibleToInt | None = None) -> Element: ... # type: ignore[override]

class XYSeries(Series):
# Same as parent
Expand Down
5 changes: 3 additions & 2 deletions stubs/openpyxl/openpyxl/chart/text.pyi
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
from _typeshed import Incomplete
from _typeshed import Incomplete, Unused
from typing import ClassVar
from typing_extensions import Literal

from openpyxl.chart.data_source import StrRef
from openpyxl.descriptors.base import Alias, Typed
from openpyxl.descriptors.serialisable import Serialisable
from openpyxl.drawing.text import ListStyle, RichTextProperties
from openpyxl.xml.functions import Element

class RichText(Serialisable):
tagname: ClassVar[str]
Expand All @@ -25,4 +26,4 @@ class Text(Serialisable):
rich: Typed[RichText, Literal[True]]
__elements__: ClassVar[tuple[str, ...]]
def __init__(self, strRef: StrRef | None = None, rich: RichText | None = None) -> None: ...
def to_tree(self, tagname: str | None = None, idx: Incomplete | None = None, namespace: str | None = None): ...
def to_tree(self, tagname: str | None = None, idx: Unused = None, namespace: str | None = None) -> Element: ...
3 changes: 2 additions & 1 deletion stubs/openpyxl/openpyxl/chartsheet/chartsheet.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ from openpyxl.workbook.child import _WorkbookChild
from openpyxl.worksheet.drawing import Drawing
from openpyxl.worksheet.header_footer import HeaderFooter as _HeaderFooter
from openpyxl.worksheet.page import PageMargins, PrintPageSetup
from openpyxl.xml.functions import Element

class Chartsheet(_WorkbookChild, Serialisable):
tagname: ClassVar[str]
Expand Down Expand Up @@ -55,4 +56,4 @@ class Chartsheet(_WorkbookChild, Serialisable):
sheet_state: _VisibilityType = "visible",
) -> None: ...
def add_chart(self, chart) -> None: ...
def to_tree(self): ...
def to_tree(self) -> Element: ... # type:ignore[override]
3 changes: 2 additions & 1 deletion stubs/openpyxl/openpyxl/comments/comment_sheet.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ from openpyxl.descriptors.base import Bool, Integer, Set, String, Typed, _Conver
from openpyxl.descriptors.excel import ExtensionList
from openpyxl.descriptors.serialisable import Serialisable
from openpyxl.worksheet.ole import ObjectAnchor
from openpyxl.xml.functions import Element

_PropertiesTextHAlign: TypeAlias = Literal["left", "center", "right", "justify", "distributed"]
_PropertiesTextVAlign: TypeAlias = Literal["top", "center", "bottom", "justify", "distributed"]
Expand Down Expand Up @@ -112,7 +113,7 @@ class CommentSheet(Serialisable):
mime_type: str
__elements__: ClassVar[tuple[str, ...]]
def __init__(self, authors: AuthorList, commentList: Incomplete | None = None, extLst: Unused = None) -> None: ...
def to_tree(self): ...
def to_tree(self) -> Element: ... # type: ignore[override]
@property
def comments(self) -> Generator[tuple[str, Comment], None, None]: ...
@classmethod
Expand Down
2 changes: 1 addition & 1 deletion stubs/openpyxl/openpyxl/compat/strings.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ from typing_extensions import Final

VER: Final[sys._version_info]

def safe_string(value): ...
def safe_string(value: object) -> str: ...
3 changes: 2 additions & 1 deletion stubs/openpyxl/openpyxl/descriptors/namespace.pyi
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
def namespaced(obj, tagname, namespace: str | None = None): ...
# 'None' shouldn't be a valid tagname and namespaced should always return str
def namespaced(obj: object, tagname: str, namespace: str | None = None) -> str: ...
19 changes: 15 additions & 4 deletions stubs/openpyxl/openpyxl/descriptors/nested.pyi
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from _typeshed import ConvertibleToFloat, ConvertibleToInt, Incomplete, Unused
from _typeshed import ConvertibleToFloat, ConvertibleToInt, Unused
from collections.abc import Iterable
from typing import Any, ClassVar, NoReturn, overload
from typing_extensions import Literal, TypeAlias
Expand Down Expand Up @@ -36,7 +36,10 @@ class Nested(Descriptor[_T]):
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: _HasGet[_T]) -> _T: ...
def to_tree(self, tagname: str | None = None, value: Incomplete | None = None, namespace: str | None = None) -> Element: ...
@overload
def to_tree(self, tagname: Unused = None, value: None = None, namespace: Unused = None) -> None: ... # type: ignore[overload-overlap]
@overload
def to_tree(self, tagname: str, value: object, namespace: str | None = None) -> Element: ...

class NestedValue(Nested[_T], Convertible[_T, _N]): # type: ignore[misc]
@overload
Expand Down Expand Up @@ -151,7 +154,10 @@ class NestedText(NestedValue[_T, _N]):
@overload
def __set__(self: NestedText[_T, Literal[True]], instance: Serialisable | Strict, value: _T | int | Any | None) -> None: ...
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: ...
@overload
def to_tree(self, tagname: Unused = None, value: None = None, namespace: Unused = None) -> None: ... # type: ignore[overload-overlap]
@overload
def to_tree(self, tagname: str, value: object, namespace: str | None = None) -> Element: ...

class NestedFloat(NestedValue[float, _N], Float[_N]): # type: ignore[misc]
@overload
Expand Down Expand Up @@ -264,4 +270,9 @@ class EmptyTag(Nested[bool], Bool[_N]): # type: ignore[misc]
def __get__(self: EmptyTag[Literal[False]], instance: Serialisable | Strict, cls: type | None = None) -> bool: ...
def __set__(self, instance: Serialisable | Strict, value: _HasTagAndGet[_ConvertibleToBool] | _ConvertibleToBool) -> None: ...
def from_tree(self, node: Unused) -> Literal[True]: ...
def to_tree(self, tagname: str | None = None, value: Incomplete | None = None, namespace: str | None = None) -> Element: ...
@overload
def to_tree( # type: ignore[overload-overlap]
self, tagname: Unused = None, value: None = None, namespace: Unused = None
) -> None: ...
@overload
def to_tree(self, tagname: str, value: object, namespace: str | None = None) -> Element: ...
24 changes: 19 additions & 5 deletions stubs/openpyxl/openpyxl/descriptors/sequence.pyi
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
from _typeshed import Incomplete, Unused
from collections.abc import Generator, Iterable
from collections.abc import Generator, Iterable, Sized
from typing import Any, Protocol, TypeVar
from typing_extensions import Self

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

from .base import Alias, Descriptor

Expand All @@ -15,35 +16,48 @@ class _SupportsFromTree(Protocol):
@classmethod
def from_tree(cls, node: _SerialisableTreeElement) -> Any: ...

class _SupportsToTree(Protocol):
def to_tree(self) -> Element: ...

class Sequence(Descriptor[Incomplete]):
expected_type: type[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]: ...
def to_tree(
self, tagname: str | None, obj: Iterable[object], namespace: str | None = None
) -> Generator[Element, 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]: ...
def to_tree(
self, tagname: str, obj: Iterable[object], namespace: str | None = None # type: ignore[override]
) -> Generator[Element, None, None]: ...
def from_tree(self, node: _HasGet[_T]) -> _T: ...

class _NestedSequenceToTreeObj(Sized, Iterable[_SupportsToTree], Protocol): ...

class NestedSequence(Sequence):
count: bool
expected_type: type[_SupportsFromTree]
def to_tree(self, tagname, obj, namespace: str | None = None): ...
def to_tree( # type: ignore[override]
self, tagname: str, obj: _NestedSequenceToTreeObj, namespace: str | None = None
) -> Element: ...
# 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: ...
def to_tree(self, tagname, obj, namespace: str | None = None) -> Generator[Incomplete, None, None]: ...
def to_tree(
self, tagname: Unused, obj: Iterable[_SupportsToTree], namespace: str | None = None # type: ignore[override]
) -> Generator[Element, None, None]: ...

class MultiSequencePart(Alias):
expected_type: type[Incomplete]
Expand Down
14 changes: 11 additions & 3 deletions stubs/openpyxl/openpyxl/descriptors/serialisable.pyi
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
from _typeshed import Incomplete, SupportsIter
from _typeshed import ConvertibleToInt, Incomplete, SupportsIter
from collections.abc import Iterator
from typing import Any, ClassVar, Protocol
from typing_extensions import Final, Self

from openpyxl.descriptors import MetaSerialisable
from openpyxl.xml.functions import Element

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

# For any override directly re-using Serialisable.from_tree
class _ChildSerialisableTreeElement(_HasAttrib, _HasText, SupportsIter[Incomplete], Protocol): ...
Expand Down Expand Up @@ -34,7 +35,14 @@ class Serialisable(metaclass=MetaSerialisable):
# Use _ChildSerialisableTreeElement instead for child classes that reuse Serialisable.from_tree directly.
@classmethod
def from_tree(cls, node: _SerialisableTreeElement) -> Self | None: ...
def to_tree(self, tagname: str | None = None, idx: Incomplete | None = None, namespace: str | None = None): ...
# Note: To respect the Liskov substitution principle, idx is a type union of all child class requirements.
# Use Unused instead for child classes that reuse Serialisable.to_tree directly.
def to_tree(
self,
tagname: str | None = None,
idx: _HasTagAndGet[ConvertibleToInt] | ConvertibleToInt | None = None,
namespace: str | None = None,
) -> Element: ...
def __iter__(self) -> Iterator[tuple[str, str]]: ...
def __eq__(self, other: object) -> bool: ...
def __ne__(self, other: object) -> bool: ...
Expand Down
12 changes: 9 additions & 3 deletions stubs/openpyxl/openpyxl/packaging/core.pyi
Original file line number Diff line number Diff line change
@@ -1,19 +1,25 @@
from _typeshed import Incomplete
from typing import ClassVar
from datetime import datetime
from typing import ClassVar, overload
from typing_extensions import Literal

from openpyxl.descriptors import DateTime
from openpyxl.descriptors.base import Alias
from openpyxl.descriptors.nested import NestedText
from openpyxl.descriptors.serialisable import Serialisable
from openpyxl.xml.functions import Element

# Does not reimplement the relevant methods, so runtime also has incompatible supertypes
class NestedDateTime(DateTime[Incomplete], NestedText[Incomplete, Incomplete]): # type: ignore[misc]
expected_type: type[Incomplete]
def to_tree(self, tagname: str | None = None, value: Incomplete | None = None, namespace: str | None = None): ...
@overload # type: ignore[override]
def to_tree(self, tagname: str | None = None, value: None = None, namespace: str | None = None) -> None: ...
@overload
def to_tree(self, tagname: str, value: datetime, namespace: str | None = None) -> Element: ...

class QualifiedDateTime(NestedDateTime):
def to_tree(self, tagname: str | None = None, value: Incomplete | None = None, namespace: str | None = None): ...
# value cannot be None or it'll raise
def to_tree(self, tagname: str, value: datetime, namespace: str | None = None) -> Element: ... # type: ignore[override]

class DocumentProperties(Serialisable):
tagname: ClassVar[str]
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 @@ -8,6 +8,7 @@ from openpyxl.descriptors import Sequence, Strict
from openpyxl.descriptors.base import Bool, DateTime, Float, Integer, String, _ConvertibleToBool
from openpyxl.descriptors.nested import NestedText
from openpyxl.descriptors.serialisable import _ChildSerialisableTreeElement
from openpyxl.xml.functions import Element

_T = TypeVar("_T")

Expand Down Expand Up @@ -51,7 +52,7 @@ class CustomPropertyList(Strict, Generic[_T]):
@classmethod
def from_tree(cls, tree: _ChildSerialisableTreeElement) -> Self: ...
def append(self, prop) -> None: ...
def to_tree(self): ...
def to_tree(self) -> Element: ...
def __len__(self) -> int: ...
@property
def names(self) -> list[str]: ...
Expand Down
3 changes: 2 additions & 1 deletion stubs/openpyxl/openpyxl/packaging/extended.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ from typing_extensions import Literal
from openpyxl.descriptors.base import Typed
from openpyxl.descriptors.nested import NestedText
from openpyxl.descriptors.serialisable import Serialisable
from openpyxl.xml.functions import Element

def get_version(): ...

Expand Down Expand Up @@ -80,4 +81,4 @@ class ExtendedProperties(Serialisable):
AppVersion: object = None,
DocSecurity: ConvertibleToInt | None = None,
) -> None: ...
def to_tree(self): ...
def to_tree(self) -> Element: ... # type: ignore[override]
3 changes: 2 additions & 1 deletion stubs/openpyxl/openpyxl/packaging/manifest.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ from typing_extensions import Final, Literal

from openpyxl.descriptors.base import String
from openpyxl.descriptors.serialisable import Serialisable
from openpyxl.xml.functions import Element

mimetypes: Incomplete

Expand Down Expand Up @@ -34,7 +35,7 @@ class Manifest(Serialisable):
def filenames(self) -> list[str]: ...
@property
def extensions(self) -> list[tuple[str, str]]: ...
def to_tree(self): ...
def to_tree(self) -> Element: ... # type: ignore[override]
def __contains__(self, content_type: str) -> bool: ...
def find(self, content_type): ...
def findall(self, content_type) -> Generator[Incomplete, None, None]: ...
Expand Down
3 changes: 2 additions & 1 deletion stubs/openpyxl/openpyxl/packaging/relationship.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ from openpyxl.descriptors.serialisable import Serialisable
from openpyxl.pivot.cache import CacheDefinition
from openpyxl.pivot.record import RecordList
from openpyxl.pivot.table import TableDefinition
from openpyxl.xml.functions import Element

_SerialisableT = TypeVar("_SerialisableT", bound=Serialisable)
_SerialisableRelTypeT = TypeVar("_SerialisableRelTypeT", bound=CacheDefinition | RecordList | TableDefinition)
Expand Down Expand Up @@ -41,7 +42,7 @@ class RelationshipList(Serialisable):
def __bool__(self) -> bool: ...
def find(self, content_type) -> Generator[Incomplete, None, None]: ...
def __getitem__(self, key): ...
def to_tree(self): ...
def to_tree(self) -> Element: ... # type: ignore[override]

def get_rels_path(path): ...
def get_dependents(archive: ZipFile, filename: str) -> RelationshipList: ...
Expand Down
3 changes: 2 additions & 1 deletion stubs/openpyxl/openpyxl/packaging/workbook.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ from openpyxl.workbook.properties import CalcProperties, FileVersion, WorkbookPr
from openpyxl.workbook.protection import FileSharing, WorkbookProtection
from openpyxl.workbook.smart_tags import SmartTagList, SmartTagProperties
from openpyxl.workbook.web import WebPublishing, WebPublishObjectList
from openpyxl.xml.functions import Element

_WorkbookPackageConformance: TypeAlias = Literal["strict", "transitional"]

Expand Down Expand Up @@ -99,6 +100,6 @@ class WorkbookPackage(Serialisable):
extLst: Unused = None,
Ignorable: Unused = None,
) -> None: ...
def to_tree(self): ...
def to_tree(self) -> Element: ... # type: ignore[override]
@property
def active(self) -> int: ...
3 changes: 2 additions & 1 deletion stubs/openpyxl/openpyxl/pivot/cache.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ from openpyxl.descriptors.nested import NestedInteger
from openpyxl.descriptors.serialisable import Serialisable
from openpyxl.pivot.fields import Error, Missing, Number, Text, TupleList
from openpyxl.pivot.table import PivotArea
from openpyxl.xml.functions import Element

from ..xml._functions_overloads import _HasTagAndGet

Expand Down Expand Up @@ -710,6 +711,6 @@ class CacheDefinition(Serialisable):
extLst: ExtensionList | None = None,
id: Incomplete | None = None,
) -> None: ...
def to_tree(self): ...
def to_tree(self) -> Element: ... # type: ignore[override]
@property
def path(self) -> str: ...
Loading