Coverage for /run/media/veganeco/water/status600.com/pypi/reptilian_climates/modules_series_2/ships/fields/gardens_pip/rich/panel.py: 18%

1 from typing import TYPE_CHECKING, Optional

2

3 from .align import AlignMethod

4 from .box import ROUNDED, Box

5 from .cells import cell_len

6 from .jupyter import JupyterMixin

7 from .measure import Measurement, measure_renderables

8 from .padding import Padding, PaddingDimensions

9 from .segment import Segment

10 from .style import Style, StyleType

11 from .text import Text, TextType

12

13 if TYPE_CHECKING:

14 from .console import Console, ConsoleOptions, RenderableType, RenderResult

15

16

17 class Panel(JupyterMixin):

18 """A console renderable that draws a border around its contents.

19

20 Example:

21 >>> console.print(Panel("Hello, World!"))

22

23 Args:

24 renderable (RenderableType): A console renderable object.

25 box (Box, optional): A Box instance that defines the look of the border (see :ref:`appendix_box`.

26 Defaults to box.ROUNDED.

27 safe_box (bool, optional): Disable box characters that don't display on windows legacy terminal with *raster* fonts. Defaults to True.

28 expand (bool, optional): If True the panel will stretch to fill the console

29 width, otherwise it will be sized to fit the contents. Defaults to True.

30 style (str, optional): The style of the panel (border and contents). Defaults to "none".

31 border_style (str, optional): The style of the border. Defaults to "none".

32 width (Optional[int], optional): Optional width of panel. Defaults to None to auto-detect.

33 height (Optional[int], optional): Optional height of panel. Defaults to None to auto-detect.

34 padding (Optional[PaddingDimensions]): Optional padding around renderable. Defaults to 0.

35 highlight (bool, optional): Enable automatic highlighting of panel title (if str). Defaults to False.

36 """

37

38 def __init__(

39 self,

40 renderable: "RenderableType",

41 box: Box = ROUNDED,

42 *,

43 title: Optional[TextType] = None,

44 title_align: AlignMethod = "center",

45 subtitle: Optional[TextType] = None,

46 subtitle_align: AlignMethod = "center",

47 safe_box: Optional[bool] = None,

48 expand: bool = True,

49 style: StyleType = "none",

50 border_style: StyleType = "none",

51 width: Optional[int] = None,

52 height: Optional[int] = None,

53 padding: PaddingDimensions = (0, 1),

54 highlight: bool = False,

55 ) -> None:

56 self.renderable = renderable

57 self.box = box

58 self.title = title

59 self.title_align: AlignMethod = title_align

60 self.subtitle = subtitle

61 self.subtitle_align = subtitle_align

62 self.safe_box = safe_box

63 self.expand = expand

64 self.style = style

65 self.border_style = border_style

66 self.width = width

67 self.height = height

68 self.padding = padding

69 self.highlight = highlight

70

71 @classmethod

72 def fit(

73 cls,

74 renderable: "RenderableType",

75 box: Box = ROUNDED,

76 *,

77 title: Optional[TextType] = None,

78 title_align: AlignMethod = "center",

79 subtitle: Optional[TextType] = None,

80 subtitle_align: AlignMethod = "center",

81 safe_box: Optional[bool] = None,

82 style: StyleType = "none",

83 border_style: StyleType = "none",

84 width: Optional[int] = None,

85 height: Optional[int] = None,

86 padding: PaddingDimensions = (0, 1),

87 highlight: bool = False,

88 ) -> "Panel":

89 """An alternative constructor that sets expand=False."""

90 return cls(

91 renderable,

92 box,

93 title=title,

94 title_align=title_align,

95 subtitle=subtitle,

96 subtitle_align=subtitle_align,

97 safe_box=safe_box,

98 style=style,

99 border_style=border_style,

100 width=width,

101 height=height,

102 padding=padding,

103 highlight=highlight,

104 expand=False,

105 )

106

107 @property

108 def _title(self) -> Optional[Text]:

109 if self.title:

110 title_text = (

111 Text.from_markup(self.title)

112 if isinstance(self.title, str)

113 else self.title.copy()

114 )

115 title_text.end = ""

116 title_text.plain = title_text.plain.replace("\n", " ")

117 title_text.no_wrap = True

118 title_text.expand_tabs()

119 title_text.pad(1)

120 return title_text

121 return None

122

123 @property

124 def _subtitle(self) -> Optional[Text]:

125 if self.subtitle:

126 subtitle_text = (

127 Text.from_markup(self.subtitle)

128 if isinstance(self.subtitle, str)

129 else self.subtitle.copy()

130 )

131 subtitle_text.end = ""

132 subtitle_text.plain = subtitle_text.plain.replace("\n", " ")

133 subtitle_text.no_wrap = True

134 subtitle_text.expand_tabs()

135 subtitle_text.pad(1)

136 return subtitle_text

137 return None

138

139 def __rich_console__(

140 self, console: "Console", options: "ConsoleOptions"

141 ) -> "RenderResult":

142 _padding = Padding.unpack(self.padding)

143 renderable = (

144 Padding(self.renderable, _padding) if any(_padding) else self.renderable

145 )

146 style = console.get_style(self.style)

147 border_style = style + console.get_style(self.border_style)

148 width = (

149 options.max_width

150 if self.width is None

151 else min(options.max_width, self.width)

152 )

153

154 safe_box: bool = console.safe_box if self.safe_box is None else self.safe_box

155 box = self.box.substitute(options, safe=safe_box)

156

157 def align_text(

158 text: Text, width: int, align: str, character: str, style: Style

159 ) -> Text:

160 """Gets new aligned text.

161

162 Args:

163 text (Text): Title or subtitle text.

164 width (int): Desired width.

165 align (str): Alignment.

166 character (str): Character for alignment.

167 style (Style): Border style

168

169 Returns:

170 Text: New text instance

171 """

172 text = text.copy()

173 text.truncate(width)

174 excess_space = width - cell_len(text.plain)

175 if excess_space:

176 if align == "left":

177 return Text.assemble(

178 text,

179 (character * excess_space, style),

180 no_wrap=True,

181 end="",

182 )

183 elif align == "center":

184 left = excess_space // 2

185 return Text.assemble(

186 (character * left, style),

187 text,

188 (character * (excess_space - left), style),

189 no_wrap=True,

190 end="",

191 )

192 else:

193 return Text.assemble(

194 (character * excess_space, style),

195 text,

196 no_wrap=True,

197 end="",

198 )

199 return text

200

201 title_text = self._title

202 if title_text is not None:

203 title_text.stylize_before(border_style)

204

205 child_width = (

206 width - 2

207 if self.expand

208 else console.measure(

209 renderable, options=options.update_width(width - 2)

210 ).maximum

211 )

212 child_height = self.height or options.height or None

213 if child_height:

214 child_height -= 2

215 if title_text is not None:

216 child_width = min(

217 options.max_width - 2, max(child_width, title_text.cell_len + 2)

218 )

219

220 width = child_width + 2

221 child_options = options.update(

222 width=child_width, height=child_height, highlight=self.highlight

223 )

224 lines = console.render_lines(renderable, child_options, style=style)

225

226 line_start = Segment(box.mid_left, border_style)

227 line_end = Segment(f"{box.mid_right}", border_style)

228 new_line = Segment.line()

229 if title_text is None or width <= 4:

230 yield Segment(box.get_top([width - 2]), border_style)

231 else:

232 title_text = align_text(

233 title_text,

234 width - 4,

235 self.title_align,

236 box.top,

237 border_style,

238 )

239 yield Segment(box.top_left + box.top, border_style)

240 yield from console.render(title_text, child_options.update_width(width - 4))

241 yield Segment(box.top + box.top_right, border_style)

242

243 yield new_line

244 for line in lines:

245 yield line_start

246 yield from line

247 yield line_end

248 yield new_line

249

250 subtitle_text = self._subtitle

251 if subtitle_text is not None:

252 subtitle_text.stylize_before(border_style)

253

254 if subtitle_text is None or width <= 4:

255 yield Segment(box.get_bottom([width - 2]), border_style)

256 else:

257 subtitle_text = align_text(

258 subtitle_text,

259 width - 4,

260 self.subtitle_align,

261 box.bottom,

262 border_style,

263 )

264 yield Segment(box.bottom_left + box.bottom, border_style)

265 yield from console.render(

266 subtitle_text, child_options.update_width(width - 4)

267 )

268 yield Segment(box.bottom + box.bottom_right, border_style)

269

270 yield new_line

271

272 def __rich_measure__(

273 self, console: "Console", options: "ConsoleOptions"

274 ) -> "Measurement":

275 _title = self._title

276 _, right, _, left = Padding.unpack(self.padding)

277 padding = left + right

278 renderables = [self.renderable, _title] if _title else [self.renderable]

279

280 if self.width is None:

281 width = (

282 measure_renderables(

283 console,

284 options.update_width(options.max_width - padding - 2),

285 renderables,

286 ).maximum

287 + padding

288 + 2

289 )

290 else:

291 width = self.width

292 return Measurement(width, width)

293

294

295 if __name__ == "__main__": # pragma: no cover

296 from .console import Console

297

298 c = Console()

299

300 from .box import DOUBLE, ROUNDED

301 from .padding import Padding

302

303 p = Panel(

304 "Hello, World!",

305 title="rich.Panel",

306 style="white on blue",

307 box=DOUBLE,

308 padding=1,

309 )

310

311 c.print()

312 c.print(p)