Skip to content

Style Utils

Style utilities function.

_PROPERTY_MAPPING module-attribute

_PROPERTY_MAPPING = _generate_property_mapping()

_check_background_support

_check_background_support(family: str) -> None

Check if the given style family supports background properties.

Parameters:

Name Type Description Default
family str

The style family to check.

required

Raises:

Type Description
TypeError

If the family does not support background properties.

Source code in odfdo/style_utils.py
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
def _check_background_support(family: str) -> None:
    """Check if the given style family supports background properties.

    Args:
        family: The style family to check.

    Raises:
        TypeError: If the family does not support background properties.
    """
    if family not in {
        "text",
        "paragraph",
        "page-layout",
        "section",
        "table",
        "table-row",
        "table-cell",
        "graphic",
    }:
        raise TypeError(f"No background support for family {family!r}")

_check_opacity

_check_opacity(opacity: str | int | None) -> None

Validate an opacity value.

Parameters:

Name Type Description Default
opacity str | int | None

The opacity value (0-100).

required

Raises:

Type Description
ValueError

If the opacity value is outside the valid range (0-100).

Source code in odfdo/style_utils.py
205
206
207
208
209
210
211
212
213
214
215
216
217
218
def _check_opacity(opacity: str | int | None) -> None:
    """Validate an opacity value.

    Args:
        opacity: The opacity value (0-100).

    Raises:
        ValueError: If the opacity value is outside the valid range (0-100).
    """
    if not opacity:
        return
    value = int(opacity)
    if value < 0 or value > 100:
        raise ValueError(f"Incorrect opacity {opacity!r}")

_check_position

_check_position(position: str | None) -> None

Validate a background position string.

Parameters:

Name Type Description Default
position str | None

The background position string.

required

Raises:

Type Description
ValueError

If the position string is not well-formatted or contains unknown keywords.

Source code in odfdo/style_utils.py
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
def _check_position(position: str | None) -> None:
    """Validate a background position string.

    Args:
        position: The background position string.

    Raises:
        ValueError: If the position string is not well-formatted or contains
            unknown keywords.
    """
    if not position:
        return
    parts = position.split()
    if not parts:
        raise ValueError("Wrong formatted background position attribute")
    for word in parts:
        if word not in {"left", "center", "right", "top", "bottom"}:
            raise ValueError(f"Unknown background position {position!r}")

_check_repeat

_check_repeat(repeat: str | None) -> None

Validate a background repeat string.

Parameters:

Name Type Description Default
repeat str | None

The background repeat string.

required

Raises:

Type Description
ValueError

If the repeat string is not well-formatted or contains unknown keywords.

Source code in odfdo/style_utils.py
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
def _check_repeat(repeat: str | None) -> None:
    """Validate a background repeat string.

    Args:
        repeat: The background repeat string.

    Raises:
        ValueError: If the repeat string is not well-formatted or contains
            unknown keywords.
    """
    if not repeat:
        return
    parts = repeat.split()
    if not parts:
        raise ValueError("Incorrect background repeat attribute")
    for word in parts:
        if word not in {"no-repeat", "repeat", "stretch"}:
            raise ValueError(f"Unknown background repeat {repeat!r}")

_erase_background

_erase_background(element: Element) -> None

Erase background properties (color and image) from the given element.

Parameters:

Name Type Description Default
element Element

The element from which to erase background properties.

required
Source code in odfdo/style_utils.py
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
def _erase_background(element: Element) -> None:
    """Erase background properties (color and image) from the given element.

    Args:
        element: The element from which to erase background properties.
    """
    family = element.family  # type: ignore[attr-defined]
    properties = element.get_element(f"style:{family}-properties")
    if properties is None:
        return
    with contextlib.suppress(KeyError):
        properties.del_attribute("fo:background-color")
    bg_image = properties.get_element("style:background-image")
    if bg_image is not None:
        properties.delete(bg_image)

_expand_properties_dict

_expand_properties_dict(properties: PropDict) -> PropDict

Expand a dictionary of properties by mapping keys to their full ODF attribute names.

Parameters:

Name Type Description Default
properties PropDict

A dictionary of properties with potentially simplified keys.

required

Returns:

Type Description
PropDict

dict[str, str | dict]: A new dictionary with keys mapped to full ODF attribute names.

Source code in odfdo/style_utils.py
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
def _expand_properties_dict(properties: PropDict) -> PropDict:
    """Expand a dictionary of properties by mapping keys to their full ODF attribute names.

    Args:
        properties: A dictionary of properties with potentially simplified keys.

    Returns:
        dict[str, str | dict]: A new dictionary with keys mapped to full ODF attribute names.
    """
    expanded = {}
    for key in sorted(properties.keys()):
        prop_key = _map_key(key)
        if prop_key and key != prop_key:
            expanded[prop_key] = properties[key]
            continue
        if key not in expanded:
            expanded[key] = properties[key]
    return expanded

_expand_properties_list

_expand_properties_list(properties: list[str]) -> list[str]

Expand a list of property keys by mapping them to their full ODF attribute names.

Parameters:

Name Type Description Default
properties list[str]

A list of property keys with potentially simplified names.

required

Returns:

Type Description
list[str]

list[str]: A new list with keys mapped to full ODF attribute names.

Source code in odfdo/style_utils.py
131
132
133
134
135
136
137
138
139
140
def _expand_properties_list(properties: list[str]) -> list[str]:
    """Expand a list of property keys by mapping them to their full ODF attribute names.

    Args:
        properties: A list of property keys with potentially simplified names.

    Returns:
        list[str]: A new list with keys mapped to full ODF attribute names.
    """
    return list(filter(None, (_map_key(key) for key in properties)))

_generate_property_mapping

_generate_property_mapping() -> dict[str, str]
Source code in odfdo/style_utils.py
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
def _generate_property_mapping() -> dict[str, str]:
    # add <style:paragraph-properties> <style:text-properties>
    all_attributes = (
        STYLE_ATTRIBUTES["paragraph"]
        | STYLE_ATTRIBUTES["text"]
        | STYLE_ATTRIBUTES["page-layout"]
        | STYLE_ATTRIBUTES["ruby"]
        | STYLE_ATTRIBUTES["section"]
        | STYLE_ATTRIBUTES["table"]
        | STYLE_ATTRIBUTES["table-column"]
        | STYLE_ATTRIBUTES["table-row"]
        | STYLE_ATTRIBUTES["table-cell"]
        | STYLE_ATTRIBUTES["graphic"]
    )
    map_1 = {
        a[6:].replace("-", "_"): a for a in all_attributes if a.startswith("style:")
    }
    map_2 = {
        a[5:].replace("-", "_"): a for a in all_attributes if a.startswith("text:")
    }
    map_3 = {
        a.replace("-", "_").replace(":", "_"): a
        for a in all_attributes
        if a.startswith("dr3d:")
    }
    map_4 = {
        a.replace("-", "_").replace(":", "_"): a
        for a in all_attributes
        if a.startswith("draw:")
    }
    map_5 = {
        a.replace("-", "_").replace(":", "_"): a
        for a in all_attributes
        if a.startswith("svg:")
    }
    map_6 = {
        a.replace("-", "_").replace(":", "_"): a
        for a in all_attributes
        if a.startswith("table:")
    }
    return _merge_dicts(
        _BASE_PROPERTY_MAPPING, map_1, map_2, map_3, map_4, map_5, map_6
    )

_map_key

_map_key(key: str) -> str | None
Source code in odfdo/style_utils.py
100
101
102
103
104
105
106
107
108
def _map_key(key: str) -> str | None:
    if key in ODF_PROPERTIES:
        return key
    key = _PROPERTY_MAPPING.get(key, key).replace("_", "-")
    if ":" not in key:
        key = f"fo:{key}"
    if key in ODF_PROPERTIES:
        return key
    return None

_merge_dicts

_merge_dicts(
    dic_base: dict, *args: dict, **kwargs: Any
) -> dict

Merge two or more dictionaries into a new dictionary object.

Parameters:

Name Type Description Default
dic_base dict

The base dictionary.

required
*args dict

Additional dictionaries to merge.

()
**kwargs Any

Keyword arguments to merge.

{}

Returns:

Name Type Description
dict dict

A new dictionary containing the merged content.

Source code in odfdo/style_utils.py
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
def _merge_dicts(dic_base: dict, *args: dict, **kwargs: Any) -> dict:
    """Merge two or more dictionaries into a new dictionary object.

    Args:
        dic_base: The base dictionary.
        *args: Additional dictionaries to merge.
        **kwargs: Keyword arguments to merge.

    Returns:
        dict: A new dictionary containing the merged content.
    """
    new_dict = deepcopy(dic_base)
    for dic in args:
        new_dict.update(dic)
    new_dict.update(kwargs)
    return new_dict

_set_background

_set_background(
    element: Element,
    color: str | None,
    url: str | None,
    position: str | None,
    repeat: str | None,
    opacity: str | int | None,
    filter: str | None,
) -> None

Set the background properties (color or image) for an element.

This function handles setting either a background color or a background image, depending on the provided arguments. It validates background-related properties and ensures that conflicting properties (e.g., both color and image) are handled correctly.

Parameters:

Name Type Description Default
element Element

The element to set the background for.

required
color str | None

The background color string.

required
url str | None

The URL of the background image.

required
position str | None

The position of the background image.

required
repeat str | None

How the background image is repeated.

required
opacity str | int | None

The opacity of the background (0-100).

required
filter str | None

A filter to apply to the background image.

required

Raises:

Type Description
TypeError

If a background image is specified for a text style.

Source code in odfdo/style_utils.py
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
def _set_background(
    element: Element,
    color: str | None,
    url: str | None,
    position: str | None,
    repeat: str | None,
    opacity: str | int | None,
    filter: str | None,  # noqa: A002
) -> None:
    """Set the background properties (color or image) for an element.

    This function handles setting either a background color or a background image,
    depending on the provided arguments. It validates background-related properties
    and ensures that conflicting properties (e.g., both color and image) are
    handled correctly.

    Args:
        element: The element to set the background for.
        color: The background color string.
        url: The URL of the background image.
        position: The position of the background image.
        repeat: How the background image is repeated.
        opacity: The opacity of the background (0-100).
        filter: A filter to apply to the background image.

    Raises:
        TypeError: If a background image is specified for a text style.
    """
    family = element.family  # type: ignore[attr-defined]
    _check_background_support(family)
    if url is not None and family == "text":
        raise TypeError("No background image for text styles")
    if color:
        return _set_background_color(element, color)
    if url:
        return _set_background_image(element, url, position, repeat, opacity, filter)
    return _erase_background(element)

_set_background_color

_set_background_color(element: Element, color: str) -> None

Set the background color for the given element.

If a background image exists, it will be removed.

Parameters:

Name Type Description Default
element Element

The element to set the background color for.

required
color str

The color string (e.g., “#RRGGBB” or “red”).

required
Source code in odfdo/style_utils.py
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
def _set_background_color(element: Element, color: str) -> None:
    """Set the background color for the given element.

    If a background image exists, it will be removed.

    Args:
        element: The element to set the background color for.
        color: The color string (e.g., "#RRGGBB" or "red").
    """
    family = element.family  # type: ignore[attr-defined]
    properties = element.get_element(f"style:{family}-properties")
    if properties is None:
        properties = Element.from_tag(f"style:{family}-properties")
        element.append(properties)
    properties.set_attribute("fo:background-color", color)
    bg_image = properties.get_element("style:background-image")
    if bg_image is not None:
        properties.delete(bg_image)

_set_background_image

_set_background_image(
    element: Element,
    url: str | None,
    position: str | None,
    repeat: str | None,
    opacity: str | int | None,
    filter: str | None,
) -> None

Set the background image for the given element.

If a background color exists, it will be removed.

Parameters:

Name Type Description Default
element Element

The element to set the background image for.

required
url str | None

The URL of the image.

required
position str | None

The position of the background image.

required
repeat str | None

How the background image is repeated.

required
opacity str | int | None

The opacity of the background image (0-100).

required
filter str | None

A filter to apply to the image.

required
Source code in odfdo/style_utils.py
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
def _set_background_image(
    element: Element,
    url: str | None,
    position: str | None,
    repeat: str | None,
    opacity: str | int | None,
    filter: str | None,  # noqa: A002
) -> None:
    """Set the background image for the given element.

    If a background color exists, it will be removed.

    Args:
        element: The element to set the background image for.
        url: The URL of the image.
        position: The position of the background image.
        repeat: How the background image is repeated.
        opacity: The opacity of the background image (0-100).
        filter: A filter to apply to the image.
    """
    _check_position(position)
    _check_repeat(repeat)
    _check_opacity(opacity)
    family = element.family  # type: ignore[attr-defined]
    properties = element.get_element(f"style:{family}-properties")
    if properties is None:
        properties = Element.from_tag(f"style:{family}-properties")
        element.append(properties)
    # properties.set_attribute("fo:background-color", "transparent")
    with contextlib.suppress(KeyError):
        properties.del_attribute("fo:background-color")
    bg_image = properties.get_element("style:background-image")
    if bg_image is None:
        bg_image = Element.from_tag("style:background-image")
        properties.append(bg_image)
    bg_image.url = url  # type:ignore
    if position:
        bg_image.position = position  # type:ignore
    if repeat:
        bg_image.repeat = repeat  # type:ignore
    if opacity:
        bg_image.opacity = str(opacity)  # type:ignore
    if filter:
        bg_image.filter = filter  # type:ignore