From df05ff2f52a1c0aaff1196661c251875da0c9eb2 Mon Sep 17 00:00:00 2001 From: Avasam Date: Sun, 15 Oct 2023 11:49:57 -0400 Subject: [PATCH] Typed openpyxl colors descriptors (#10882) --- stubs/openpyxl/@tests/stubtest_allowlist.txt | 2 + stubs/openpyxl/openpyxl/chart/shapes.pyi | 5 +- stubs/openpyxl/openpyxl/drawing/colors.pyi | 5 +- stubs/openpyxl/openpyxl/drawing/line.pyi | 5 +- stubs/openpyxl/openpyxl/drawing/text.pyi | 7 ++- stubs/openpyxl/openpyxl/formatting/rule.pyi | 18 +++++- stubs/openpyxl/openpyxl/styles/borders.pyi | 5 +- stubs/openpyxl/openpyxl/styles/colors.pyi | 61 +++++++++++++++---- stubs/openpyxl/openpyxl/styles/fills.pyi | 17 +++--- stubs/openpyxl/openpyxl/styles/fonts.pyi | 6 +- .../openpyxl/worksheet/properties.pyi | 6 +- 11 files changed, 96 insertions(+), 41 deletions(-) diff --git a/stubs/openpyxl/@tests/stubtest_allowlist.txt b/stubs/openpyxl/@tests/stubtest_allowlist.txt index f40d00628..5bb3c6b68 100644 --- a/stubs/openpyxl/@tests/stubtest_allowlist.txt +++ b/stubs/openpyxl/@tests/stubtest_allowlist.txt @@ -109,6 +109,7 @@ openpyxl.drawing.text.GeomGuide.__init__ openpyxl.drawing.text.PresetTextShape.__init__ openpyxl.drawing.text.TextField.__init__ openpyxl.drawing.text.TextNormalAutofit.__init__ +openpyxl.formatting.rule.DataBar.__init__ openpyxl.packaging.relationship.Relationship.__init__ openpyxl.packaging.workbook.ChildSheet.__init__ openpyxl.packaging.workbook.PivotCache.__init__ @@ -154,6 +155,7 @@ openpyxl.pivot.table.PivotFilter.__init__ openpyxl.pivot.table.PivotFilters.__init__ openpyxl.pivot.table.RowColField.__init__ openpyxl.pivot.table.TableDefinition.__init__ +openpyxl.styles.colors.RgbColor.__init__ openpyxl.styles.named_styles._NamedCellStyle.__init__ openpyxl.styles.numbers.NumberFormat.__init__ openpyxl.styles.table.TableStyle.__init__ diff --git a/stubs/openpyxl/openpyxl/chart/shapes.pyi b/stubs/openpyxl/openpyxl/chart/shapes.pyi index 94da38a6b..ab7de9d1a 100644 --- a/stubs/openpyxl/openpyxl/chart/shapes.pyi +++ b/stubs/openpyxl/openpyxl/chart/shapes.pyi @@ -5,6 +5,7 @@ from typing_extensions import Literal, TypeAlias from openpyxl.descriptors.base import Alias, NoneSet, Typed, _ConvertibleToBool from openpyxl.descriptors.nested import EmptyTag from openpyxl.descriptors.serialisable import Serialisable +from openpyxl.drawing.colors import ColorChoice, ColorChoiceDescriptor from openpyxl.drawing.fill import GradientFillProperties, PatternFillProperties from openpyxl.drawing.geometry import CustomGeometry2D, PresetGeometry2D, Scene3D, Shape3D, Transform2D from openpyxl.drawing.line import LineProperties @@ -23,7 +24,7 @@ class GraphicalProperties(Serialisable): custGeom: Typed[CustomGeometry2D, Literal[True]] prstGeom: Typed[PresetGeometry2D, Literal[True]] noFill: EmptyTag[Literal[False]] - solidFill: Incomplete + solidFill: ColorChoiceDescriptor gradFill: Typed[GradientFillProperties, Literal[True]] pattFill: Typed[PatternFillProperties, Literal[True]] ln: Typed[LineProperties, Literal[True]] @@ -38,7 +39,7 @@ class GraphicalProperties(Serialisable): bwMode: _GraphicalPropertiesBwMode | Literal["none"] | None = None, xfrm: Transform2D | None = None, noFill: _HasTagAndGet[_ConvertibleToBool] | _ConvertibleToBool = None, - solidFill: Incomplete | None = None, + solidFill: str | ColorChoice | None = None, gradFill: GradientFillProperties | None = None, pattFill: PatternFillProperties | None = None, ln: Incomplete | None = None, diff --git a/stubs/openpyxl/openpyxl/drawing/colors.pyi b/stubs/openpyxl/openpyxl/drawing/colors.pyi index 889d7de2a..24cce5f4d 100644 --- a/stubs/openpyxl/openpyxl/drawing/colors.pyi +++ b/stubs/openpyxl/openpyxl/drawing/colors.pyi @@ -503,7 +503,8 @@ class ColorMapping(Serialisable): extLst: ExtensionList | None = None, ) -> None: ... -class ColorChoiceDescriptor(Typed[ColorChoice, Incomplete]): +class ColorChoiceDescriptor(Typed[ColorChoice, Literal[True]]): expected_type: type[ColorChoice] allow_none: Literal[True] - def __set__(self, instance: Serialisable | Strict, value) -> None: ... + def __init__(self, name: str | None = None) -> None: ... + def __set__(self, instance: Serialisable | Strict, value: str | ColorChoice | None) -> None: ... diff --git a/stubs/openpyxl/openpyxl/drawing/line.pyi b/stubs/openpyxl/openpyxl/drawing/line.pyi index 8a7aba534..70ff2585a 100644 --- a/stubs/openpyxl/openpyxl/drawing/line.pyi +++ b/stubs/openpyxl/openpyxl/drawing/line.pyi @@ -15,6 +15,7 @@ from openpyxl.descriptors.base import ( from openpyxl.descriptors.excel import ExtensionList from openpyxl.descriptors.nested import EmptyTag, NestedInteger, NestedNoneSet, _NestedNoneSetParam from openpyxl.descriptors.serialisable import Serialisable +from openpyxl.drawing.colors import ColorChoice, ColorChoiceDescriptor from openpyxl.drawing.fill import GradientFillProperties, PatternFillProperties from ..xml._functions_overloads import _HasTagAndGet @@ -63,7 +64,7 @@ class LineProperties(Serialisable): cmpd: NoneSet[_LinePropertiesCmpd] algn: NoneSet[_LinePropertiesAlgn] noFill: EmptyTag[Literal[False]] - solidFill: Incomplete + solidFill: ColorChoiceDescriptor gradFill: Typed[GradientFillProperties, Literal[True]] pattFill: Typed[PatternFillProperties, Literal[True]] prstDash: NestedNoneSet[_LinePropertiesPrstDash] @@ -83,7 +84,7 @@ class LineProperties(Serialisable): cmpd: _LinePropertiesCmpd | Literal["none"] | None = None, algn: _LinePropertiesAlgn | Literal["none"] | None = None, noFill: _HasTagAndGet[_ConvertibleToBool] | _ConvertibleToBool = None, - solidFill: Incomplete | None = None, + solidFill: str | ColorChoice | None = None, gradFill: GradientFillProperties | None = None, pattFill: PatternFillProperties | None = None, prstDash: _NestedNoneSetParam[_LinePropertiesPrstDash] = None, diff --git a/stubs/openpyxl/openpyxl/drawing/text.pyi b/stubs/openpyxl/openpyxl/drawing/text.pyi index 672b0d26f..e18fa6dab 100644 --- a/stubs/openpyxl/openpyxl/drawing/text.pyi +++ b/stubs/openpyxl/openpyxl/drawing/text.pyi @@ -18,6 +18,7 @@ from openpyxl.descriptors.base import ( from openpyxl.descriptors.excel import Coordinate, ExtensionList from openpyxl.descriptors.nested import EmptyTag, NestedBool, NestedInteger, NestedText, NestedValue from openpyxl.descriptors.serialisable import Serialisable +from openpyxl.drawing.colors import ColorChoice, ColorChoiceDescriptor from openpyxl.drawing.effect import Color, EffectContainer, EffectList from openpyxl.drawing.fill import Blip, BlipFillProperties, GradientFillProperties, PatternFillProperties from openpyxl.drawing.geometry import Scene3D @@ -223,7 +224,7 @@ class CharacterProperties(Serialisable): rtl: NestedBool[Literal[True]] extLst: Typed[ExtensionList, Literal[True]] noFill: EmptyTag[Literal[False]] - solidFill: Incomplete + solidFill: ColorChoiceDescriptor gradFill: Typed[GradientFillProperties, Literal[True]] blipFill: Typed[BlipFillProperties, Literal[True]] pattFill: Typed[PatternFillProperties, Literal[True]] @@ -265,9 +266,9 @@ class CharacterProperties(Serialisable): hlinkClick: Hyperlink | None = None, hlinkMouseOver: Hyperlink | None = None, rtl: _HasTagAndGet[_ConvertibleToBool | None] | _ConvertibleToBool | None = None, - extLst: ExtensionList | None = None, + extLst: Unused = None, noFill: _HasTagAndGet[_ConvertibleToBool] | _ConvertibleToBool = None, - solidFill: Incomplete | None = None, + solidFill: str | ColorChoice | None = None, gradFill: GradientFillProperties | None = None, blipFill: BlipFillProperties | None = None, pattFill: PatternFillProperties | None = None, diff --git a/stubs/openpyxl/openpyxl/formatting/rule.pyi b/stubs/openpyxl/openpyxl/formatting/rule.pyi index b9e99931d..2ccd4f9f0 100644 --- a/stubs/openpyxl/openpyxl/formatting/rule.pyi +++ b/stubs/openpyxl/openpyxl/formatting/rule.pyi @@ -1,11 +1,12 @@ from _typeshed import Incomplete, Unused -from typing import ClassVar +from typing import ClassVar, overload from typing_extensions import Literal, TypeAlias from openpyxl.descriptors import Float, Strict from openpyxl.descriptors.base import Bool, Integer, NoneSet, Set, String, Typed, _ConvertibleToBool, _ConvertibleToInt from openpyxl.descriptors.excel import ExtensionList from openpyxl.descriptors.serialisable import Serialisable +from openpyxl.styles.colors import Color, ColorDescriptor from openpyxl.styles.differential import DifferentialStyle _IconSetIconSet: TypeAlias = Literal[ @@ -106,16 +107,27 @@ class DataBar(RuleType): minLength: Integer[Literal[True]] maxLength: Integer[Literal[True]] showValue: Bool[Literal[True]] - color: Incomplete + color: ColorDescriptor[Literal[False]] __elements__: ClassVar[tuple[str, ...]] cfvo: Incomplete + @overload def __init__( self, minLength: _ConvertibleToInt | None = None, maxLength: _ConvertibleToInt | None = None, showValue: _ConvertibleToBool | None = None, cfvo: Incomplete | None = None, - color: Incomplete | None = None, + *, + color: str | Color, + ) -> None: ... + @overload + def __init__( + self, + minLength: _ConvertibleToInt | None, + maxLength: _ConvertibleToInt | None, + showValue: _ConvertibleToBool | None, + cfvo: Incomplete | None, + color: str | Color, ) -> None: ... class ColorScale(RuleType): diff --git a/stubs/openpyxl/openpyxl/styles/borders.pyi b/stubs/openpyxl/openpyxl/styles/borders.pyi index 3a9607925..d0c46d0b2 100644 --- a/stubs/openpyxl/openpyxl/styles/borders.pyi +++ b/stubs/openpyxl/openpyxl/styles/borders.pyi @@ -4,6 +4,7 @@ from typing_extensions import Final, Literal, TypeAlias from openpyxl.descriptors.base import Alias, Bool, NoneSet, Typed, _ConvertibleToBool from openpyxl.descriptors.serialisable import Serialisable +from openpyxl.styles.colors import Color, ColorDescriptor _SideStyle: TypeAlias = Literal[ "dashDot", @@ -38,13 +39,13 @@ BORDER_THIN: Final = "thin" class Side(Serialisable): __fields__: ClassVar[tuple[str, ...]] - color: Incomplete + color: ColorDescriptor[Literal[True]] style: NoneSet[_SideStyle] border_style: Alias def __init__( self, style: _SideStyle | Literal["none"] | None = None, - color: Incomplete | None = None, + color: str | Color | None = None, border_style: Incomplete | None = None, ) -> None: ... diff --git a/stubs/openpyxl/openpyxl/styles/colors.pyi b/stubs/openpyxl/openpyxl/styles/colors.pyi index a28e194a6..5358b374c 100644 --- a/stubs/openpyxl/openpyxl/styles/colors.pyi +++ b/stubs/openpyxl/openpyxl/styles/colors.pyi @@ -1,25 +1,44 @@ from _typeshed import Incomplete, Unused +from collections.abc import Generator from re import Pattern -from typing import ClassVar -from typing_extensions import Final, Literal +from typing import ClassVar, TypeVar, overload +from typing_extensions import Final, Literal, Self from openpyxl.descriptors import Strict, Typed -from openpyxl.descriptors.base import Bool, Integer, MinMax, String, _ConvertibleToBool, _ConvertibleToFloat, _ConvertibleToInt +from openpyxl.descriptors.base import ( + _N, + Bool, + Integer, + MinMax, + String, + _ConvertibleToBool, + _ConvertibleToFloat, + _ConvertibleToInt, +) from openpyxl.descriptors.serialisable import Serialisable +_S = TypeVar("_S", bound=Serialisable) + COLOR_INDEX: Final[tuple[str, ...]] BLACK: Final = "00000000" WHITE: Final = "00FFFFFF" BLUE: Final = "00FFFFFF" aRGB_REGEX: Final[Pattern[str]] -class RGB(Typed[str, Incomplete]): +class RGB(Typed[str, _N]): expected_type: type[str] - def __set__(self, instance: Serialisable | Strict, value) -> None: ... + @overload + def __init__(self: RGB[Literal[True]], name: str | None = None, *, allow_none: Literal[True]) -> None: ... + @overload + def __init__(self: RGB[Literal[False]], name: str | None = None, *, allow_none: Literal[False] = False) -> None: ... + @overload + def __set__(self: RGB[Literal[True]], instance: Serialisable | Strict, value: str | None) -> None: ... + @overload + def __set__(self: RGB[Literal[False]], instance: Serialisable | Strict, value: str) -> None: ... class Color(Serialisable): tagname: ClassVar[str] - rgb: Incomplete + rgb: RGB[Literal[False]] indexed: Integer[Literal[False]] auto: Bool[Literal[False]] theme: Integer[Literal[False]] @@ -39,26 +58,42 @@ class Color(Serialisable): def value(self) -> str | int | bool: ... @value.setter def value(self, value: str | _ConvertibleToInt | _ConvertibleToBool) -> None: ... - def __iter__(self): ... + def __iter__(self) -> Generator[tuple[str, str], None, None]: ... @property def index(self) -> str | int | bool: ... - def __add__(self, other): ... + @overload + def __add__(self, other: Color) -> Self: ... + @overload + def __add__(self, other: _S) -> _S: ... -class ColorDescriptor(Typed[Color, Incomplete]): +class ColorDescriptor(Typed[Color, _N]): expected_type: type[Color] - def __set__(self, instance: Serialisable | Strict, value) -> None: ... + @overload + def __init__(self: ColorDescriptor[Literal[True]], name: str | None = None, *, allow_none: Literal[True]) -> None: ... + @overload + def __init__( + self: ColorDescriptor[Literal[False]], name: str | None = None, *, allow_none: Literal[False] = False + ) -> None: ... + @overload + def __set__(self: ColorDescriptor[_N], instance: Serialisable | Strict, value: str) -> None: ... + @overload + def __set__(self: ColorDescriptor[Literal[True]], instance: Serialisable | Strict, value: Color | None) -> None: ... + @overload + def __set__(self: ColorDescriptor[Literal[False]], instance: Serialisable | Strict, value: Color) -> None: ... class RgbColor(Serialisable): tagname: ClassVar[str] - rgb: Incomplete - def __init__(self, rgb: Incomplete | None = None) -> None: ... + rgb: RGB[Literal[False]] + def __init__(self, rgb: str) -> None: ... class ColorList(Serialisable): tagname: ClassVar[str] indexedColors: Incomplete mruColors: Incomplete __elements__: ClassVar[tuple[str, ...]] - def __init__(self, indexedColors=(), mruColors=()) -> None: ... + def __init__( + self, indexedColors: list[RgbColor] | tuple[RgbColor, ...] = (), mruColors: list[Color] | tuple[Color, ...] = () + ) -> None: ... def __bool__(self) -> bool: ... @property def index(self) -> list[str]: ... diff --git a/stubs/openpyxl/openpyxl/styles/fills.pyi b/stubs/openpyxl/openpyxl/styles/fills.pyi index f8bf1b486..3a0b7324d 100644 --- a/stubs/openpyxl/openpyxl/styles/fills.pyi +++ b/stubs/openpyxl/openpyxl/styles/fills.pyi @@ -6,6 +6,7 @@ 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 openpyxl.styles.colors import Color, ColorDescriptor from ..xml._functions_overloads import _SupportsIterAndAttribAndTextAndTag @@ -63,18 +64,18 @@ class PatternFill(Fill): __elements__: ClassVar[tuple[str, ...]] patternType: NoneSet[_FillsType] fill_type: Alias - fgColor: Incomplete + fgColor: ColorDescriptor[Literal[False]] start_color: Alias - bgColor: Incomplete + bgColor: ColorDescriptor[Literal[False]] end_color: Alias def __init__( self, - patternType: Incomplete | None = None, - fgColor=..., - bgColor=..., - fill_type: Incomplete | None = None, - start_color: Incomplete | None = None, - end_color: Incomplete | None = None, + patternType: _FillsType | Literal["none"] | None = None, + fgColor: str | Color = ..., + bgColor: str | Color = ..., + fill_type: _FillsType | Literal["none"] | None = None, + start_color: str | Color | None = None, + end_color: str | Color | None = None, ) -> None: ... def to_tree(self, tagname: str | None = None, idx: Incomplete | None = None): ... # type: ignore[override] diff --git a/stubs/openpyxl/openpyxl/styles/fonts.pyi b/stubs/openpyxl/openpyxl/styles/fonts.pyi index d8ab9e06d..1972fa612 100644 --- a/stubs/openpyxl/openpyxl/styles/fonts.pyi +++ b/stubs/openpyxl/openpyxl/styles/fonts.pyi @@ -1,4 +1,3 @@ -from _typeshed import Incomplete from typing import ClassVar from typing_extensions import Final, Literal, Self, TypeAlias @@ -13,6 +12,7 @@ from openpyxl.descriptors.nested import ( _NestedNoneSetParam, ) from openpyxl.descriptors.serialisable import Serialisable +from openpyxl.styles.colors import Color, ColorDescriptor from ..xml._functions_overloads import _HasTagAndGet, _SupportsFindAndIterAndAttribAndText @@ -43,7 +43,7 @@ class Font(Serialisable): u: NestedNoneSet[_FontU] underline: Alias vertAlign: NestedNoneSet[_FontVertAlign] - color: Incomplete + color: ColorDescriptor[Literal[True]] scheme: NestedNoneSet[_FontScheme] tagname: ClassVar[str] __elements__: ClassVar[tuple[str, ...]] @@ -56,7 +56,7 @@ class Font(Serialisable): charset: _HasTagAndGet[_ConvertibleToInt | None] | _ConvertibleToInt | None = None, u: _NestedNoneSetParam[_FontU] = None, strike: _HasTagAndGet[_ConvertibleToBool | None] | _ConvertibleToBool | None = None, - color: Incomplete | None = None, + color: str | Color | None = None, scheme: _NestedNoneSetParam[_FontScheme] = None, family: _HasTagAndGet[_ConvertibleToFloat | None] | _ConvertibleToFloat | None = None, size: _HasTagAndGet[_ConvertibleToFloat] | _ConvertibleToFloat | None = None, diff --git a/stubs/openpyxl/openpyxl/worksheet/properties.pyi b/stubs/openpyxl/openpyxl/worksheet/properties.pyi index dcc4fdef2..3a2195906 100644 --- a/stubs/openpyxl/openpyxl/worksheet/properties.pyi +++ b/stubs/openpyxl/openpyxl/worksheet/properties.pyi @@ -1,9 +1,9 @@ -from _typeshed import Incomplete from typing import ClassVar from typing_extensions import Literal from openpyxl.descriptors.base import Bool, String, Typed, _ConvertibleToBool from openpyxl.descriptors.serialisable import Serialisable +from openpyxl.styles.colors import Color, ColorDescriptor class Outline(Serialisable): tagname: ClassVar[str] @@ -36,7 +36,7 @@ class WorksheetProperties(Serialisable): syncVertical: Bool[Literal[True]] transitionEvaluation: Bool[Literal[True]] transitionEntry: Bool[Literal[True]] - tabColor: Incomplete + tabColor: ColorDescriptor[Literal[True]] outlinePr: Typed[Outline, Literal[True]] pageSetUpPr: Typed[PageSetupProperties, Literal[True]] __elements__: ClassVar[tuple[str, ...]] @@ -51,7 +51,7 @@ class WorksheetProperties(Serialisable): syncVertical: _ConvertibleToBool | None = None, transitionEvaluation: _ConvertibleToBool | None = None, transitionEntry: _ConvertibleToBool | None = None, - tabColor: Incomplete | None = None, + tabColor: str | Color | None = None, outlinePr: Outline | None = None, pageSetUpPr: PageSetupProperties | None = None, ) -> None: ...