|
| 1 | +""" |
| 2 | +# PyHTML / Render Options |
| 3 | +
|
| 4 | +Definition for the `Options` object, used to control rendering. |
| 5 | +""" |
| 6 | + |
| 7 | +from dataclasses import asdict, dataclass |
| 8 | +from typing import Optional |
| 9 | + |
| 10 | +# While it could be cleaner (and far less-repetitive) to use a TypedDict and |
| 11 | +# declare the partial options class as per |
| 12 | +# https://discuss.python.org/t/introduce-partial-for-typeddict/45176/4 |
| 13 | +# I elected not to do this, as by using a dataclass, the type is much more |
| 14 | +# explicit, meaning that users won't encounter very confusing type-checker |
| 15 | +# errors if they inadvertently pass a non-Options-shaped `dict` to a tag |
| 16 | +# constructor. |
| 17 | +# By using a `dataclass`, it is also much easier to perform `isinstance` |
| 18 | +# checking on the object, which simplifies the implementation significantly. |
| 19 | +# The only down-side is the duplicated definitions and copy-pasted |
| 20 | +# documentation. |
| 21 | + |
| 22 | + |
| 23 | +@dataclass(kw_only=True, frozen=True) |
| 24 | +class FullOptions: |
| 25 | + indent: str |
| 26 | + """String to add to indentation for non-inline child elements""" |
| 27 | + spacing: str |
| 28 | + """String to use for spacing between child elements""" |
| 29 | + |
| 30 | + def union(self, other: "Options | FullOptions") -> "FullOptions": |
| 31 | + """ |
| 32 | + Union this set of options with the other options, returning a new |
| 33 | + `Options` object as the result. |
| 34 | +
|
| 35 | + Any non-`None` options in `other` will overwrite the original values. |
| 36 | + """ |
| 37 | + values = asdict(self) |
| 38 | + for field in values: |
| 39 | + if (other_value := getattr(other, field)) is not None: |
| 40 | + values[field] = other_value |
| 41 | + |
| 42 | + return FullOptions(**values) |
| 43 | + |
| 44 | + |
| 45 | +@dataclass(kw_only=True, frozen=True) |
| 46 | +class Options: |
| 47 | + """ |
| 48 | + PyHTML rendering options. |
| 49 | +
|
| 50 | + * `indent` (`str`): string to add to indentation for non-inline child |
| 51 | + elements. For example, to indent using a tab, you could use `'\\t'`. |
| 52 | + Defaults to 2 spaces `' '`. |
| 53 | + * `spacing` (`str`): string to use for spacing between child elements. When |
| 54 | + this is set to `'\\n'`, each child element will be placed on its own |
| 55 | + line, and indentation will be applied. Otherwise, each child element will |
| 56 | + be separated using the given value. |
| 57 | + """ |
| 58 | + |
| 59 | + indent: Optional[str] = None |
| 60 | + """String to add to indentation for non-inline child elements""" |
| 61 | + spacing: Optional[str] = None |
| 62 | + """String to use for spacing between child elements""" |
| 63 | + |
| 64 | + @staticmethod |
| 65 | + def default() -> FullOptions: |
| 66 | + """ |
| 67 | + Returns PyHTML's default rendering options. |
| 68 | + """ |
| 69 | + return FullOptions( |
| 70 | + indent=" ", |
| 71 | + spacing="\n", |
| 72 | + ) |
0 commit comments