Source code for fastpyxl.drawing.line

# Copyright (c) 2010-2024 fastpyxl

from fastpyxl.xml.constants import DRAWING_NS
from fastpyxl.typed_serialisable.base import Serialisable
from fastpyxl.typed_serialisable.errors import FieldValidationError
from fastpyxl.typed_serialisable.fields import AliasField, Field

from .colors import ColorChoice
from .fill import GradientFillProperties, PatternFillProperties
from fastpyxl.descriptors.excel import ExtensionList as OfficeArtExtensionList

"""
Line elements from drawing main schema
"""


[docs] class LineEndProperties(Serialisable): tagname = "end" namespace = DRAWING_NS type: str | None = Field.attribute( expected_type=str, allow_none=True, converter=lambda v: _enum_converter(v, ("none", "triangle", "stealth", "diamond", "oval", "arrow"), "type"), default=None, ) w: str | None = Field.attribute( expected_type=str, allow_none=True, converter=lambda v: _enum_converter(v, ("sm", "med", "lg"), "w"), default=None, ) len: str | None = Field.attribute( expected_type=str, allow_none=True, converter=lambda v: _enum_converter(v, ("sm", "med", "lg"), "len"), default=None, ) def __init__(self, type=None, w=None, len=None, ): self.type = type self.w = w self.len = len
[docs] class DashStop(Serialisable): tagname = "ds" namespace = DRAWING_NS d: int | None = Field.attribute(expected_type=int, allow_none=True, default=None) length = AliasField('d', default=None) sp: int | None = Field.attribute(expected_type=int, allow_none=True, default=None) space = AliasField('sp', default=None) def __init__(self, d=0, sp=0, ): self.d = d self.sp = sp
[docs] class DashStopList(Serialisable): tagname = "custDash" namespace = DRAWING_NS ds: list[DashStop] | None = Field.sequence(expected_type=DashStop, allow_none=True, default=list) def __init__(self, ds=None, ): self.ds = ds
class _NoFill(Serialisable): tagname = "noFill" namespace = DRAWING_NS class _Round(Serialisable): tagname = "round" namespace = DRAWING_NS class _Bevel(Serialisable): tagname = "bevel" namespace = DRAWING_NS class _Miter(Serialisable): tagname = "miter" namespace = DRAWING_NS lim: int | None = Field.attribute(expected_type=int, allow_none=True, default=None) def __init__(self, lim=None): self.lim = lim def _line_no_fill_coerce(value): if value is True: return _NoFill() if value in (False, None): return None return value def _solid_fill_coerce(value): if value is None: return None if isinstance(value, ColorChoice): return value if isinstance(value, str): return ColorChoice(srgbClr=value) return value def _enum_converter(value, allowed_values, field_name: str): if value is None: return None if value not in allowed_values: raise FieldValidationError(f"{field_name} rejected value {value!r}") return value
[docs] class LineProperties(Serialisable): tagname = "ln" namespace = DRAWING_NS w: int | None = Field.attribute( expected_type=int, allow_none=True, converter=lambda v: _range_converter(v, 0, 20116800, "w"), default=None, ) # EMU width = AliasField('w', default=None) cap: str | None = Field.attribute( expected_type=str, allow_none=True, converter=lambda v: _enum_converter(v, ("rnd", "sq", "flat"), "cap"), default=None, ) cmpd: str | None = Field.attribute( expected_type=str, allow_none=True, converter=lambda v: _enum_converter(v, ("sng", "dbl", "thickThin", "thinThick", "tri"), "cmpd"), default=None, ) algn: str | None = Field.attribute( expected_type=str, allow_none=True, converter=lambda v: _enum_converter(v, ("ctr", "in"), "algn"), default=None, ) noFill: _NoFill | None = Field.element( expected_type=_NoFill, allow_none=True, converter=_line_no_fill_coerce, default=None, ) solidFill: ColorChoice | None = Field.element( expected_type=ColorChoice, allow_none=True, converter=_solid_fill_coerce, default=None ) gradFill: GradientFillProperties | None = Field.element(expected_type=GradientFillProperties, allow_none=True, default=None) pattFill: PatternFillProperties | None = Field.element(expected_type=PatternFillProperties, allow_none=True, default=None) prstDash: str | None = Field.nested_value( expected_type=str, allow_none=True, converter=lambda v: _enum_converter( v, ("solid", "dot", "dash", "lgDash", "dashDot", "lgDashDot", "lgDashDotDot", "sysDash", "sysDot", "sysDashDot", "sysDashDotDot"), "prstDash", ), default=None, ) dashStyle = AliasField('prstDash', default=None) custDash: DashStopList | None = Field.element(expected_type=DashStopList, allow_none=True, default=None) round: _Round | None = Field.element(expected_type=_Round, allow_none=True, default=None) bevel: _Bevel | None = Field.element(expected_type=_Bevel, allow_none=True, default=None) miter: _Miter | None = Field.element(expected_type=_Miter, allow_none=True, default=None) headEnd: LineEndProperties | None = Field.element(expected_type=LineEndProperties, allow_none=True, default=None) tailEnd: LineEndProperties | None = Field.element(expected_type=LineEndProperties, allow_none=True, default=None) extLst: OfficeArtExtensionList | None = Field.element(expected_type=OfficeArtExtensionList, allow_none=True, default=None) xml_order = ('noFill', 'solidFill', 'gradFill', 'pattFill', 'prstDash', 'custDash', 'round', 'bevel', 'miter', 'headEnd', 'tailEnd') def __init__(self, w=None, cap=None, cmpd=None, algn=None, noFill=None, solidFill=None, gradFill=None, pattFill=None, prstDash=None, custDash=None, round=None, bevel=None, miter=None, headEnd=None, tailEnd=None, extLst=None, ): self.w = w self.cap = cap self.cmpd = cmpd self.algn = algn self.noFill = _NoFill() if noFill else None self.solidFill = solidFill self.gradFill = gradFill self.pattFill = pattFill if prstDash is None: prstDash = "solid" self.prstDash = prstDash self.custDash = DashStopList(ds=[custDash]) if isinstance(custDash, DashStop) else custDash self.round = _Round() if round else None self.bevel = _Bevel() if bevel else None self.miter = _Miter(lim=miter) if isinstance(miter, int) else miter self.headEnd = headEnd self.tailEnd = tailEnd self.extLst = extLst
def _range_converter(value, minimum: int, maximum: int, field_name: str): if value is None: return None try: numeric = int(value) except (TypeError, ValueError) as exc: raise FieldValidationError(f"{field_name} rejected value {value!r}") from exc if not minimum <= numeric <= maximum: raise FieldValidationError(f"{field_name} rejected value {value!r}") return numeric