Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/rich/measure.py: 31%

54 statements  

« prev     ^ index     » next       coverage.py v7.2.7, created at 2023-06-07 06:35 +0000

1from operator import itemgetter 

2from typing import TYPE_CHECKING, Callable, NamedTuple, Optional, Sequence 

3 

4from . import errors 

5from .protocol import is_renderable, rich_cast 

6 

7if TYPE_CHECKING: 

8 from .console import Console, ConsoleOptions, RenderableType 

9 

10 

11class Measurement(NamedTuple): 

12 """Stores the minimum and maximum widths (in characters) required to render an object.""" 

13 

14 minimum: int 

15 """Minimum number of cells required to render.""" 

16 maximum: int 

17 """Maximum number of cells required to render.""" 

18 

19 @property 

20 def span(self) -> int: 

21 """Get difference between maximum and minimum.""" 

22 return self.maximum - self.minimum 

23 

24 def normalize(self) -> "Measurement": 

25 """Get measurement that ensures that minimum <= maximum and minimum >= 0 

26 

27 Returns: 

28 Measurement: A normalized measurement. 

29 """ 

30 minimum, maximum = self 

31 minimum = min(max(0, minimum), maximum) 

32 return Measurement(max(0, minimum), max(0, max(minimum, maximum))) 

33 

34 def with_maximum(self, width: int) -> "Measurement": 

35 """Get a RenderableWith where the widths are <= width. 

36 

37 Args: 

38 width (int): Maximum desired width. 

39 

40 Returns: 

41 Measurement: New Measurement object. 

42 """ 

43 minimum, maximum = self 

44 return Measurement(min(minimum, width), min(maximum, width)) 

45 

46 def with_minimum(self, width: int) -> "Measurement": 

47 """Get a RenderableWith where the widths are >= width. 

48 

49 Args: 

50 width (int): Minimum desired width. 

51 

52 Returns: 

53 Measurement: New Measurement object. 

54 """ 

55 minimum, maximum = self 

56 width = max(0, width) 

57 return Measurement(max(minimum, width), max(maximum, width)) 

58 

59 def clamp( 

60 self, min_width: Optional[int] = None, max_width: Optional[int] = None 

61 ) -> "Measurement": 

62 """Clamp a measurement within the specified range. 

63 

64 Args: 

65 min_width (int): Minimum desired width, or ``None`` for no minimum. Defaults to None. 

66 max_width (int): Maximum desired width, or ``None`` for no maximum. Defaults to None. 

67 

68 Returns: 

69 Measurement: New Measurement object. 

70 """ 

71 measurement = self 

72 if min_width is not None: 

73 measurement = measurement.with_minimum(min_width) 

74 if max_width is not None: 

75 measurement = measurement.with_maximum(max_width) 

76 return measurement 

77 

78 @classmethod 

79 def get( 

80 cls, console: "Console", options: "ConsoleOptions", renderable: "RenderableType" 

81 ) -> "Measurement": 

82 """Get a measurement for a renderable. 

83 

84 Args: 

85 console (~rich.console.Console): Console instance. 

86 options (~rich.console.ConsoleOptions): Console options. 

87 renderable (RenderableType): An object that may be rendered with Rich. 

88 

89 Raises: 

90 errors.NotRenderableError: If the object is not renderable. 

91 

92 Returns: 

93 Measurement: Measurement object containing range of character widths required to render the object. 

94 """ 

95 _max_width = options.max_width 

96 if _max_width < 1: 

97 return Measurement(0, 0) 

98 if isinstance(renderable, str): 

99 renderable = console.render_str( 

100 renderable, markup=options.markup, highlight=False 

101 ) 

102 renderable = rich_cast(renderable) 

103 if is_renderable(renderable): 

104 get_console_width: Optional[ 

105 Callable[["Console", "ConsoleOptions"], "Measurement"] 

106 ] = getattr(renderable, "__rich_measure__", None) 

107 if get_console_width is not None: 

108 render_width = ( 

109 get_console_width(console, options) 

110 .normalize() 

111 .with_maximum(_max_width) 

112 ) 

113 if render_width.maximum < 1: 

114 return Measurement(0, 0) 

115 return render_width.normalize() 

116 else: 

117 return Measurement(0, _max_width) 

118 else: 

119 raise errors.NotRenderableError( 

120 f"Unable to get render width for {renderable!r}; " 

121 "a str, Segment, or object with __rich_console__ method is required" 

122 ) 

123 

124 

125def measure_renderables( 

126 console: "Console", 

127 options: "ConsoleOptions", 

128 renderables: Sequence["RenderableType"], 

129) -> "Measurement": 

130 """Get a measurement that would fit a number of renderables. 

131 

132 Args: 

133 console (~rich.console.Console): Console instance. 

134 options (~rich.console.ConsoleOptions): Console options. 

135 renderables (Iterable[RenderableType]): One or more renderable objects. 

136 

137 Returns: 

138 Measurement: Measurement object containing range of character widths required to 

139 contain all given renderables. 

140 """ 

141 if not renderables: 

142 return Measurement(0, 0) 

143 get_measurement = Measurement.get 

144 measurements = [ 

145 get_measurement(console, options, renderable) for renderable in renderables 

146 ] 

147 measured_width = Measurement( 

148 max(measurements, key=itemgetter(0)).minimum, 

149 max(measurements, key=itemgetter(1)).maximum, 

150 ) 

151 return measured_width