1313# limitations under the License.
1414from decimal import Decimal , InvalidOperation
1515
16+ _EXPONENTS = {
17+ "n" : - 3 ,
18+ "u" : - 2 ,
19+ "m" : - 1 ,
20+ "K" : 1 ,
21+ "k" : 1 ,
22+ "M" : 2 ,
23+ "G" : 3 ,
24+ "T" : 4 ,
25+ "P" : 5 ,
26+ "E" : 6 ,
27+ }
28+
1629
1730def parse_quantity (quantity ):
1831 """
@@ -35,17 +48,14 @@ def parse_quantity(quantity):
3548 if isinstance (quantity , (int , float , Decimal )):
3649 return Decimal (quantity )
3750
38- exponents = {"n" : - 3 , "u" : - 2 , "m" : - 1 , "K" : 1 , "k" : 1 , "M" : 2 ,
39- "G" : 3 , "T" : 4 , "P" : 5 , "E" : 6 }
40-
4151 quantity = str (quantity )
4252 number = quantity
4353 suffix = None
4454 if len (quantity ) >= 2 and quantity [- 1 ] == "i" :
45- if quantity [- 2 ] in exponents :
55+ if quantity [- 2 ] in _EXPONENTS :
4656 number = quantity [:- 2 ]
4757 suffix = quantity [- 2 :]
48- elif len (quantity ) >= 1 and quantity [- 1 ] in exponents :
58+ elif len (quantity ) >= 1 and quantity [- 1 ] in _EXPONENTS :
4959 number = quantity [:- 1 ]
5060 suffix = quantity [- 1 :]
5161
@@ -68,8 +78,62 @@ def parse_quantity(quantity):
6878 if suffix == "ki" :
6979 raise ValueError ("{} has unknown suffix" .format (quantity ))
7080
71- if suffix [0 ] not in exponents :
81+ if suffix [0 ] not in _EXPONENTS :
7282 raise ValueError ("{} has unknown suffix" .format (quantity ))
7383
74- exponent = Decimal (exponents [suffix [0 ]])
84+ exponent = Decimal (_EXPONENTS [suffix [0 ]])
7585 return number * (base ** exponent )
86+
87+
88+ def format_quantity (quantity_value , suffix , quantize = None ) -> str :
89+ """
90+ Takes a decimal and produces a string value in kubernetes' canonical quantity form,
91+ like "200Mi".Users can specify an additional decimal number to quantize the output.
92+
93+ Example - Relatively increase pod memory limits:
94+
95+ # retrieve my_pod
96+ current_memory: Decimal = parse_quantity(my_pod.spec.containers[0].resources.limits.memory)
97+ desired_memory = current_memory * 1.2
98+ desired_memory_str = format_quantity(desired_memory, suffix="Gi", quantize=Decimal(1))
99+ # patch pod with desired_memory_str
100+
101+ 'quantize=Decimal(1)' ensures that the result does not contain any fractional digits.
102+
103+ Supported SI suffixes:
104+ base1024: Ki | Mi | Gi | Ti | Pi | Ei
105+ base1000: n | u | m | "" | k | M | G | T | P | E
106+
107+ See https://github.com/kubernetes/apimachinery/blob/master/pkg/api/resource/quantity.go
108+
109+ Input:
110+ quantity: Decimal. Quantity as a number which is supposed to converted to a string
111+ with SI suffix.
112+ suffix: string. The desired suffix/unit-of-measure of the output string
113+ quantize: Decimal. Can be used to round/quantize the value before the string
114+ is returned. Defaults to None.
115+
116+ Returns:
117+ string. Canonical Kubernetes quantity string containing the SI suffix.
118+
119+ Raises:
120+ ValueError if the SI suffix is not supported.
121+ """
122+
123+ if suffix .endswith ("i" ):
124+ base = 1024
125+ elif len (suffix ) == 1 :
126+ base = 1000
127+ else :
128+ raise ValueError (f"{ quantity_value } has unknown suffix" )
129+
130+ if suffix == "ki" :
131+ raise ValueError (f"{ quantity_value } has unknown suffix" )
132+
133+ if suffix [0 ] not in _EXPONENTS :
134+ raise ValueError (f"{ quantity_value } has unknown suffix" )
135+
136+ different_scale = quantity_value / Decimal (base ** _EXPONENTS [suffix [0 ]])
137+ if quantize :
138+ different_scale = different_scale .quantize (quantize )
139+ return str (different_scale ) + suffix
0 commit comments