Styling - momapy

Skip to content

# Styling

## `` momapy.styling

Classes and functions for styling layout elements using style sheets

Classes:

Name | Description
--- | ---
`ChildSelector` | Class for child selectors
`ClassSelector` | Class for class selectors
`DescendantSelector` | Class for descendant selectors
`IdSelector` | Class for id selectors
`OrSelector` | Class for or selectors
`Selector` | Abstract class for selectors
`StyleCollection` | Class for style collections
`StyleSheet` | Class for style sheets
`TypeSelector` | Class for type selectors

Functions:

Name | Description
--- | ---
`apply_style_collection` | Apply a style collection to a layout element
`apply_style_sheet` | Apply a style sheet to a layout element or (layout of) a map
`combine_style_sheets` | Merge a collection of style sheets into a unique style sheet and return it

### `` ChildSelector `dataclass`

    ChildSelector(
        parent_selector: Selector, child_selector: Selector
    )

Bases: `Selector`

Class for child selectors

Parameters:

Name | Type | Description | Default
--- | --- | --- | ---
`parent_selector` | `Selector` | The parent selector | required
`child_selector` | `Selector` | The child selector | required

Methods:

Name | Description
--- | ---
`select` | Return `true` if the given layout element satisfies the selector, and `false` otherwise

#### `` select

    select(
        obj: LayoutElement | LayoutElementBuilder,
        ancestors: Collection[
            LayoutElement | LayoutElementBuilder
        ],
    )

Return `true` if the given layout element satisfies the selector, and `false` otherwise

Source code in `src/momapy/styling.py`

    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    def select(
        self,
        obj: momapy.core.LayoutElement | momapy.core.LayoutElementBuilder,
        ancestors: collections.abc.Collection[
            momapy.core.LayoutElement | momapy.core.LayoutElementBuilder
        ],
    ):
        """Return `true` if the given layout element satisfies the selector, and `false` otherwise"""
        if not ancestors:
            return False
        return self.child_selector.select(
            obj, ancestors
        ) and self.parent_selector.select(ancestors[-1], ancestors[:-1])

### `` ClassSelector `dataclass`

    ClassSelector(class_name: str)

Bases: `Selector`

Class for class selectors

Parameters:

Name | Type | Description | Default
--- | --- | --- | ---
`class_name` | `str` | The name of the class | required

Methods:

Name | Description
--- | ---
`select` | Return `true` if the given layout element satisfies the selector, and `false` otherwise

#### `` select

    select(
        obj: LayoutElement | LayoutElementBuilder,
        ancestors: Collection[
            LayoutElement | LayoutElementBuilder
        ],
    )

Return `true` if the given layout element satisfies the selector, and `false` otherwise

Source code in `src/momapy/styling.py`

    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    def select(
        self,
        obj: momapy.core.LayoutElement | momapy.core.LayoutElementBuilder,
        ancestors: collections.abc.Collection[
            momapy.core.LayoutElement | momapy.core.LayoutElementBuilder
        ],
    ):
        """Return `true` if the given layout element satisfies the selector, and `false` otherwise"""
        for cls in type(obj).__mro__:
            cls_name = cls.__name__
            # print(cls_name, f"{self.class_name}Builder")
            if (
                cls_name == self.class_name
                or cls_name == f"{self.class_name}Builder"
            ):
                return True
        return False

### `` DescendantSelector `dataclass`

    DescendantSelector(
        ancestor_selector: Selector,
        descendant_selector: Selector,
    )

Bases: `Selector`

Class for descendant selectors

Parameters:

Name | Type | Description | Default
--- | --- | --- | ---
`ancestor_selector` | `Selector` | The ancestor selector | required
`descendant_selector` | `Selector` | The descendant selector | required

Methods:

Name | Description
--- | ---
`select` | Return `true` if the given layout element satisfies the selector, and `false` otherwise

#### `` select

    select(
        obj: LayoutElement | LayoutElementBuilder,
        ancestors: Collection[
            LayoutElement | LayoutElementBuilder
        ],
    )

Return `true` if the given layout element satisfies the selector, and `false` otherwise

Source code in `src/momapy/styling.py`

    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    def select(
        self,
        obj: momapy.core.LayoutElement | momapy.core.LayoutElementBuilder,
        ancestors: collections.abc.Collection[
            momapy.core.LayoutElement | momapy.core.LayoutElementBuilder
        ],
    ):
        """Return `true` if the given layout element satisfies the selector, and `false` otherwise"""
        if not ancestors:
            return False
        return self.descendant_selector.select(obj, ancestors) and any(
            [
                self.ancestor_selector.select(ancestor, ancestors[:i])
                for i, ancestor in enumerate(ancestors)
            ]
        )

### `` IdSelector `dataclass`

    IdSelector(id_: str)

Bases: `Selector`

Class for id selectors

Parameters:

Name | Type | Description | Default
--- | --- | --- | ---
`id_` | `str` | The id | required

Methods:

Name | Description
--- | ---
`select` | Return `true` if the given layout element satisfies the selector, and `false` otherwise

#### `` select

    select(
        obj: LayoutElement | LayoutElementBuilder,
        ancestors: Collection[
            LayoutElement | LayoutElementBuilder
        ],
    )

Return `true` if the given layout element satisfies the selector, and `false` otherwise

Source code in `src/momapy/styling.py`

    225
    226
    227
    228
    229
    230
    231
    232
    233
    def select(
        self,
        obj: momapy.core.LayoutElement | momapy.core.LayoutElementBuilder,
        ancestors: collections.abc.Collection[
            momapy.core.LayoutElement | momapy.core.LayoutElementBuilder
        ],
    ):
        """Return `true` if the given layout element satisfies the selector, and `false` otherwise"""
        return hasattr(obj, "id_") and obj.id_ == self.id_

### `` OrSelector `dataclass`

    OrSelector(selectors: tuple[Selector])

Bases: `Selector`

Class for or selectors

Parameters:

Name | Type | Description | Default
--- | --- | --- | ---
`selectors` | `tuple[Selector]` | The tuple of disjunct selectors | required

Methods:

Name | Description
--- | ---
`select` | Return `true` if the given layout element satisfies the selector, and `false` otherwise

#### `` select

    select(
        obj: LayoutElement | LayoutElementBuilder,
        ancestors: Collection[
            LayoutElement | LayoutElementBuilder
        ],
    )

Return `true` if the given layout element satisfies the selector, and `false` otherwise

Source code in `src/momapy/styling.py`

    299
    300
    301
    302
    303
    304
    305
    306
    307
    308
    309
    def select(
        self,
        obj: momapy.core.LayoutElement | momapy.core.LayoutElementBuilder,
        ancestors: collections.abc.Collection[
            momapy.core.LayoutElement | momapy.core.LayoutElementBuilder
        ],
    ):
        """Return `true` if the given layout element satisfies the selector, and `false` otherwise"""
        return any(
            [selector.select(obj, ancestors) for selector in self.selectors]
        )

### `` Selector `dataclass`

    Selector()

Bases: `object`

Abstract class for selectors

Methods:

Name | Description
--- | ---
`select` | Return `true` if the given layout element satisfies the selector, and `false` otherwise

#### `` select `abstractmethod`

    select(
        obj: LayoutElement | LayoutElementBuilder,
        ancestors: Collection[
            LayoutElement | LayoutElementBuilder
        ],
    ) -> bool

Return `true` if the given layout element satisfies the selector, and `false` otherwise

Source code in `src/momapy/styling.py`

    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    @abc.abstractmethod
    def select(
        self,
        obj: momapy.core.LayoutElement | momapy.core.LayoutElementBuilder,
        ancestors: collections.abc.Collection[
            momapy.core.LayoutElement | momapy.core.LayoutElementBuilder
        ],
    ) -> bool:
        """Return `true` if the given layout element satisfies the selector, and `false` otherwise"""
        pass

### `` StyleCollection

Bases: `dict`

Class for style collections

### `` StyleSheet

Bases: `dict`

Class for style sheets

Methods:

Name | Description
--- | ---
`from_file` | Read and return a style sheet from a file
`from_files` | Read and return a style sheet from a collection of files
`from_string` | Read and return a style sheet from a string

#### `` from_file `classmethod`

    from_file(file_path: str) -> StyleSheet

Read and return a style sheet from a file

Source code in `src/momapy/styling.py`

    36
    37
    38
    39
    40
    @classmethod
    def from_file(cls, file_path: str) -> "StyleSheet":
        """Read and return a style sheet from a file"""
        style_sheet = _css_document.parse_file(file_path, parse_all=True)[0]
        return style_sheet

#### `` from_files `classmethod`

    from_files(file_paths: Collection[str]) -> StyleSheet

Read and return a style sheet from a collection of files

Source code in `src/momapy/styling.py`

    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    @classmethod
    def from_files(
        cls, file_paths: collections.abc.Collection[str]
    ) -> "StyleSheet":
        """Read and return a style sheet from a collection of files"""
        style_sheets = []
        for file_path in file_paths:
            style_sheet = StyleSheet.from_file(file_path)
            style_sheets.append(style_sheet)
        style_sheet = combine_style_sheets(style_sheets)
        return style_sheet

#### `` from_string `classmethod`

    from_string(s: str) -> StyleSheet

Read and return a style sheet from a string

Source code in `src/momapy/styling.py`

    42
    43
    44
    45
    46
    @classmethod
    def from_string(cls, s: str) -> "StyleSheet":
        """Read and return a style sheet from a string"""
        style_sheet = _css_document.parse_string(s, parse_all=True)[0]
        return style_sheet

### `` TypeSelector `dataclass`

    TypeSelector(class_name: str)

Bases: `Selector`

Class for type selectors

Parameters:

Name | Type | Description | Default
--- | --- | --- | ---
`class_name` | `str` | The name of the class | required

Methods:

Name | Description
--- | ---
`select` | Return `true` if the given layout element satisfies the selector, and `false` otherwise

#### `` select

    select(
        obj: LayoutElement | LayoutElementBuilder,
        ancestors: Collection[
            LayoutElement | LayoutElementBuilder
        ],
    )

Return `true` if the given layout element satisfies the selector, and `false` otherwise

Source code in `src/momapy/styling.py`

    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    def select(
        self,
        obj: momapy.core.LayoutElement | momapy.core.LayoutElementBuilder,
        ancestors: collections.abc.Collection[
            momapy.core.LayoutElement | momapy.core.LayoutElementBuilder
        ],
    ):
        """Return `true` if the given layout element satisfies the selector, and `false` otherwise"""
        obj_cls_name = type(obj).__name__
        return (
            obj_cls_name == self.class_name
            or obj_cls_name == f"{self.class_name}Builder"
        )

### `` apply_style_collection

    apply_style_collection(
        layout_element: LayoutElement | LayoutElementBuilder,
        style_collection: StyleCollection,
        strict: bool = True,
    ) -> LayoutElement | LayoutElementBuilder

Apply a style collection to a layout element

Source code in `src/momapy/styling.py`

    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
    def apply_style_collection(
        layout_element: (
            momapy.core.LayoutElement | momapy.core.LayoutElementBuilder
        ),
        style_collection: StyleCollection,
        strict: bool = True,
    ) -> momapy.core.LayoutElement | momapy.core.LayoutElementBuilder:
        """Apply a style collection to a layout element"""
        if not isinstance(layout_element, momapy.builder.Builder):
            layout_element = momapy.builder.builder_from_object(layout_element)
            is_builder = False
        else:
            is_builder = True
        for attribute, value in style_collection.items():
            if hasattr(layout_element, attribute):
                setattr(layout_element, attribute, value)
            else:
                if strict:
                    raise AttributeError(
                        f"{type(layout_element)} object has no "
                        f"attribute '{attribute}'"
                    )
        if is_builder:
            return layout_element
        return momapy.builder.object_from_builder(layout_element)

### `` apply_style_sheet

    apply_style_sheet(
        map_or_layout_element: Map
        | LayoutElement
        | MapBuilder
        | LayoutElementBuilder,
        style_sheet: StyleSheet,
        strict: bool = True,
        ancestors: Collection[
            LayoutElement | LayoutElementBuilder
        ] = None,
    ) -> (
        Map | LayoutElement | LayoutElementBuilder | MapBuilder
    )

Apply a style sheet to a layout element or (layout of) a map

Source code in `src/momapy/styling.py`

    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    def apply_style_sheet(
        map_or_layout_element: (
            momapy.core.Map
            | momapy.core.LayoutElement
            | momapy.core.MapBuilder
            | momapy.core.LayoutElementBuilder
        ),
        style_sheet: StyleSheet,
        strict: bool = True,
        ancestors: collections.abc.Collection[
            momapy.core.LayoutElement | momapy.core.LayoutElementBuilder
        ] = None,
    ) -> (
        momapy.core.Map
        | momapy.core.LayoutElement
        | momapy.core.LayoutElementBuilder
        | momapy.core.MapBuilder
    ):
        """Apply a style sheet to a layout element or (layout of) a map"""
        if not isinstance(map_or_layout_element, momapy.builder.Builder):
            map_or_layout_element = momapy.builder.builder_from_object(
                map_or_layout_element
            )
            is_builder = False
        else:
            is_builder = True
        if isinstance(map_or_layout_element, momapy.core.MapBuilder):
            layout_element = map_or_layout_element.layout
        else:
            layout_element = map_or_layout_element
        if style_sheet is not None:
            if ancestors is None:
                ancestors = []
            for selector, style_collection in style_sheet.items():
                if selector.select(layout_element, ancestors):
                    apply_style_collection(
                        layout_element=layout_element,
                        style_collection=style_collection,
                        strict=strict,
                    )
            ancestors = ancestors + [layout_element]
            for child in layout_element.children():
                apply_style_sheet(
                    map_or_layout_element=child,
                    style_sheet=style_sheet,
                    strict=strict,
                    ancestors=ancestors,
                )
        if is_builder:
            return map_or_layout_element
        return momapy.builder.object_from_builder(map_or_layout_element)

### `` combine_style_sheets

    combine_style_sheets(
        style_sheets: Collection[StyleSheet],
    ) -> StyleSheet

Merge a collection of style sheets into a unique style sheet and return it

Source code in `src/momapy/styling.py`

    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    def combine_style_sheets(
        style_sheets: collections.abc.Collection[StyleSheet],
    ) -> StyleSheet:
        """Merge a collection of style sheets into a unique style sheet and return it"""
        if not style_sheets:
            return None
        output_style_sheet = style_sheets[0]
        for style_sheet in style_sheets[1:]:
            output_style_sheet |= style_sheet
        return output_style_sheet