2 from typing
import Dict
, List
, IO
, Mapping
, Optional
4 from .default_styles
import DEFAULT_STYLES
5 from .style
import Style
, StyleType
9 """A container for style information, used by :class:`~rich.console.Console`.
12 styles (Dict[str, Style], optional): A mapping of style names on to styles. Defaults to None for a theme with no styles.
13 inherit (bool, optional): Inherit default styles. Defaults to True.
16 styles
: Dict
[str, Style
]
19 self
, styles
: Optional
[Mapping
[str, StyleType
]] = None, inherit
: bool = True
21 self
.styles
= DEFAULT_STYLES
.copy() if inherit
else {}
22 if styles
is not None:
25 name
: style
if isinstance(style
, Style
) else Style
.parse(style
)
26 for name
, style
in styles
.items()
31 def config(self
) -> str:
32 """Get contents of a config file for this theme."""
33 config
= "[styles]\n" + "\n".join(
34 f
"{name} = {style}" for name
, style
in sorted(self
.styles
.items())
40 cls
, config_file
: IO
[str], source
: Optional
[str] = None, inherit
: bool = True
42 """Load a theme from a text mode file.
45 config_file (IO[str]): An open conf file.
46 source (str, optional): The filename of the open file. Defaults to None.
47 inherit (bool, optional): Inherit default styles. Defaults to True.
50 Theme: A New theme instance.
52 config
= configparser
.ConfigParser()
53 config
.read_file(config_file
, source
=source
)
54 styles
= {name: Style.parse(value) for name, value in config.items("styles")}
55 theme
= Theme(styles
, inherit
=inherit
)
60 cls
, path
: str, inherit
: bool = True, encoding
: Optional
[str] = None
62 """Read a theme from a path.
65 path (str): Path to a config file readable by Python configparser module.
66 inherit (bool, optional): Inherit default styles. Defaults to True.
67 encoding (str, optional): Encoding of the config file. Defaults to None.
70 Theme: A new theme instance.
72 with open(path
, "rt", encoding
=encoding
) as config_file
:
73 return cls
.from_file(config_file
, source
=path
, inherit
=inherit
)
76 class ThemeStackError(Exception):
77 """Base exception for errors related to the theme stack."""
84 theme (Theme): A theme instance
87 def __init__(self
, theme
: Theme
) -> None:
88 self
._entries
: List
[Dict
[str, Style
]] = [theme
.styles
]
89 self
.get
= self
._entries
[-1].get
91 def push_theme(self
, theme
: Theme
, inherit
: bool = True) -> None:
92 """Push a theme on the top of the stack.
95 theme (Theme): A Theme instance.
96 inherit (boolean, optional): Inherit styles from current top of stack.
98 styles
: Dict
[str, Style
]
100 {**self._entries[-1], **theme.styles}
if inherit
else theme
.styles
.copy()
102 self
._entries
.append(styles
)
103 self
.get
= self
._entries
[-1].get
105 def pop_theme(self
) -> None:
106 """Pop (and discard) the top-most theme."""
107 if len(self
._entries
) == 1:
108 raise ThemeStackError("Unable to pop base theme")
110 self
.get
= self
._entries
[-1].get
113 if __name__
== "__main__": # pragma: no cover