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
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
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",
    }:
        msg = f"No background support for family {family!r}"
        raise TypeError(msg)

_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
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
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:
        msg = f"Incorrect opacity {opacity!r}"
        raise ValueError(msg)

_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
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
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:
        msg = "Wrong formatted background position attribute"
        raise ValueError(msg)
    for word in parts:
        if word not in {"left", "center", "right", "top", "bottom"}:
            msg = f"Unknown background position {position!r}"
            raise ValueError(msg)

_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
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
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:
        msg = "Incorrect background repeat attribute"
        raise ValueError(msg)
    for word in parts:
        if word not in {"no-repeat", "repeat", "stretch"}:
            msg = f"Unknown background repeat {repeat!r}"
            raise ValueError(msg)

_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
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
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
    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: Mapping[str, Any],
) -> PropDict

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

Parameters:

Name Type Description Default
properties Mapping[str, Any]

A dictionary of properties with potentially simplified keys.

required

Returns:

Type Description
PropDict

A new dictionary with keys mapped to full ODF attribute names.

Source code in odfdo/style_utils.py
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
def _expand_properties_dict(properties: Mapping[str, Any]) -> 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:
        A new dictionary with keys mapped to full ODF attribute names.

    """
    expanded: PropDict = {}
    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
141
142
143
144
145
146
147
148
149
150
151
152
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
 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
 95
 96
 97
 98
 99
100
101
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
107
108
109
110
111
112
113
114
115
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: Mapping[str, Any],
    *args: Mapping[str, Any],
    **kwargs: Any,
) -> dict[str, Any]

Merge two or more dictionaries into a new dictionary object.

Parameters:

Name Type Description Default
dic_base Mapping[str, Any]

The base dictionary.

required
*args Mapping[str, Any]

Additional dictionaries to merge.

()
**kwargs Any

Keyword arguments to merge.

{}

Returns:

Type Description
dict[str, Any]

A new dictionary containing the merged content.

Source code in odfdo/style_utils.py
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
def _merge_dicts(
    dic_base: Mapping[str, Any], *args: Mapping[str, Any], **kwargs: Any
) -> dict[str, Any]:
    """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:
        A new dictionary containing the merged content.

    """
    new_dict = 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
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
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
    _check_background_support(family)
    if url is not None and family == "text":
        msg = "No background image for text styles"
        raise TypeError(msg)
    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
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
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
    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
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
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
    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
    if position:
        bg_image.position = position
    if repeat:
        bg_image.repeat = repeat
    if opacity:
        bg_image.opacity = str(opacity)
    if filter:
        bg_image.filter = filter