]>
jfr.im git - dlqueue.git/blob - venv/lib/python3.11/site-packages/pip/_vendor/rich/_ratio.py
2 from fractions
import Fraction
4 from typing
import cast
, List
, Optional
, Sequence
6 if sys
.version_info
>= (3, 8):
7 from typing
import Protocol
9 from pip
._vendor
.typing_extensions
import Protocol
# pragma: no cover
13 """Any object that defines an edge (such as Layout)."""
15 size
: Optional
[int] = None
20 def ratio_resolve(total
: int, edges
: Sequence
[Edge
]) -> List
[int]:
21 """Divide total space to satisfy size, ratio, and minimum_size, constraints.
23 The returned list of integers should add up to total in most cases, unless it is
24 impossible to satisfy all the constraints. For instance, if there are two edges
25 with a minimum size of 20 each and `total` is 30 then the returned list will be
26 greater than total. In practice, this would mean that a Layout object would
27 clip the rows that would overflow the screen height.
30 total (int): Total number of characters.
31 edges (List[Edge]): Edges within total space.
34 List[int]: Number of characters for each edge.
36 # Size of edge or None for yet to be determined
37 sizes
= [(edge
.size
or None) for edge
in edges
]
41 # While any edges haven't been calculated
43 # Get flexible edges and index to map these back on to sizes list
46 for index
, (size
, edge
) in enumerate(zip(sizes
, edges
))
49 # Remaining space in total
50 remaining
= total
- sum(size
or 0 for size
in sizes
)
52 # No room for flexible edges
54 ((edge
.minimum_size
or 1) if size
is None else size
)
55 for size
, edge
in zip(sizes
, edges
)
57 # Calculate number of characters in a ratio portion
59 remaining
, sum((edge
.ratio
or 1) for _
, edge
in flexible_edges
)
62 # If any edges will be less than their minimum, replace size with the minimum
63 for index
, edge
in flexible_edges
:
64 if portion
* edge
.ratio
<= edge
.minimum_size
:
65 sizes
[index
] = edge
.minimum_size
66 # New fixed size will invalidate calculations, so we need to repeat the process
69 # Distribute flexible space and compensate for rounding error
70 # Since edge sizes can only be integers we need to add the remainder
71 # to the following line
72 remainder
= _Fraction(0)
73 for index
, edge
in flexible_edges
:
74 size
, remainder
= divmod(portion
* edge
.ratio
+ remainder
, 1)
77 # Sizes now contains integers only
78 return cast(List
[int], sizes
)
82 total
: int, ratios
: List
[int], maximums
: List
[int], values
: List
[int]
84 """Divide an integer total in to parts based on ratios.
87 total (int): The total to divide.
88 ratios (List[int]): A list of integer ratios.
89 maximums (List[int]): List of maximums values for each slot.
90 values (List[int]): List of values
93 List[int]: A list of integers guaranteed to sum to total.
95 ratios
= [ratio
if _max
else 0 for ratio
, _max
in zip(ratios
, maximums
)]
96 total_ratio
= sum(ratios
)
99 total_remaining
= total
100 result
: List
[int] = []
101 append
= result
.append
102 for ratio
, maximum
, value
in zip(ratios
, maximums
, values
):
103 if ratio
and total_ratio
> 0:
104 distributed
= min(maximum
, round(ratio
* total_remaining
/ total_ratio
))
105 append(value
- distributed
)
106 total_remaining
-= distributed
113 def ratio_distribute(
114 total
: int, ratios
: List
[int], minimums
: Optional
[List
[int]] = None
116 """Distribute an integer total in to parts based on ratios.
119 total (int): The total to divide.
120 ratios (List[int]): A list of integer ratios.
121 minimums (List[int]): List of minimum values for each slot.
124 List[int]: A list of integers guaranteed to sum to total.
127 ratios
= [ratio
if _min
else 0 for ratio
, _min
in zip(ratios
, minimums
)]
128 total_ratio
= sum(ratios
)
129 assert total_ratio
> 0, "Sum of ratios must be > 0"
131 total_remaining
= total
132 distributed_total
: List
[int] = []
133 append
= distributed_total
.append
135 _minimums
= [0] * len(ratios
)
138 for ratio
, minimum
in zip(ratios
, _minimums
):
140 distributed
= max(minimum
, ceil(ratio
* total_remaining
/ total_ratio
))
142 distributed
= total_remaining
145 total_remaining
-= distributed
146 return distributed_total
149 if __name__
== "__main__":
150 from dataclasses
import dataclass
155 size
: Optional
[int] = None
157 minimum_size
: int = 1
159 resolved
= ratio_resolve(110, [E(None, 1, 1), E(None, 1, 1), E(None, 1, 1)])