Skip to content

Commit 0e3a330

Browse files
authored
Support negative values (#12)
1 parent adc81c1 commit 0e3a330

File tree

2 files changed

+90
-17
lines changed

2 files changed

+90
-17
lines changed

binary/core.py

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from decimal import Decimal
2-
from typing import NamedTuple, Optional, Tuple, Union
2+
from typing import TYPE_CHECKING, NamedTuple, Optional, Tuple, Union
3+
import typing
34

45
BYTE = 1
56

@@ -169,41 +170,43 @@ def convert_units(
169170
except KeyError:
170171
raise ValueError(f'{to} is not a valid unit.')
171172

173+
babs = typing.cast(Union[float, Decimal], abs(b))
174+
172175
if unit in BINARY_PREFIXES and not si:
173-
if b < KIBIBYTE:
176+
if babs < KIBIBYTE:
174177
return b, 'B'
175-
elif b < MEBIBYTE:
178+
elif babs < MEBIBYTE:
176179
return b / KIBIBYTE, 'KiB'
177-
elif b < GIBIBYTE:
180+
elif babs < GIBIBYTE:
178181
return b / MEBIBYTE, 'MiB'
179-
elif b < TEBIBYTE:
182+
elif babs < TEBIBYTE:
180183
return b / GIBIBYTE, 'GiB'
181-
elif b < PEBIBYTE:
184+
elif babs < PEBIBYTE:
182185
return b / TEBIBYTE, 'TiB'
183-
elif b < EXBIBYTE:
186+
elif babs < EXBIBYTE:
184187
return b / PEBIBYTE, 'PiB'
185-
elif b < ZEBIBYTE:
188+
elif babs < ZEBIBYTE:
186189
return b / EXBIBYTE, 'EiB'
187-
elif b < YOBIBYTE:
190+
elif babs < YOBIBYTE:
188191
return b / ZEBIBYTE, 'ZiB'
189192
else:
190193
return b / YOBIBYTE, 'YiB'
191194
else:
192-
if b < KILOBYTE:
195+
if babs < KILOBYTE:
193196
return b, 'B'
194-
elif b < MEGABYTE:
197+
elif babs < MEGABYTE:
195198
return b / KILOBYTE, 'KB'
196-
elif b < GIGABYTE:
199+
elif babs < GIGABYTE:
197200
return b / MEGABYTE, 'MB'
198-
elif b < TERABYTE:
201+
elif babs < TERABYTE:
199202
return b / GIGABYTE, 'GB'
200-
elif b < PETABYTE:
203+
elif babs < PETABYTE:
201204
return b / TERABYTE, 'TB'
202-
elif b < EXABYTE:
205+
elif babs < EXABYTE:
203206
return b / PETABYTE, 'PB'
204-
elif b < ZETTABYTE:
207+
elif babs < ZETTABYTE:
205208
return b / EXABYTE, 'EB'
206-
elif b < YOTTABYTE:
209+
elif babs < YOTTABYTE:
207210
return b / ZETTABYTE, 'ZB'
208211
else:
209212
return b / YOTTABYTE, 'YB'

tests/test_core.py

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,108 +121,144 @@ class TestConvert:
121121
def test_byte(self) -> None:
122122
assert convert_units(1, bunits.YB, bunits.B) == (bunits.YB // 1, 'B')
123123
assert convert_units(1, dunits.YB, dunits.B) == (dunits.YB // 1, 'B')
124+
assert convert_units(-1, bunits.YB, bunits.B) == (-bunits.YB // 1, 'B')
125+
assert convert_units(-1, dunits.YB, dunits.B) == (-dunits.YB // 1, 'B')
124126

125127
def test_kibibyte(self) -> None:
126128
assert convert_units(1, bunits.YB, bunits.KB) == (bunits.YB / 1024 ** 1, 'KiB')
129+
assert convert_units(-1, bunits.YB, bunits.KB) == (-bunits.YB / 1024 ** 1, 'KiB')
127130

128131
def test_mebibyte(self) -> None:
129132
assert convert_units(1, bunits.YB, bunits.MB) == (bunits.YB / 1024 ** 2, 'MiB')
133+
assert convert_units(-1, bunits.YB, bunits.MB) == (-bunits.YB / 1024 ** 2, 'MiB')
130134

131135
def test_gibibyte(self) -> None:
132136
assert convert_units(1, bunits.YB, bunits.GB) == (bunits.YB / 1024 ** 3, 'GiB')
137+
assert convert_units(-1, bunits.YB, bunits.GB) == (-bunits.YB / 1024 ** 3, 'GiB')
133138

134139
def test_tebibyte(self) -> None:
135140
assert convert_units(1, bunits.YB, bunits.TB) == (bunits.YB / 1024 ** 4, 'TiB')
141+
assert convert_units(-1, bunits.YB, bunits.TB) == (-bunits.YB / 1024 ** 4, 'TiB')
136142

137143
def test_pebibyte(self) -> None:
138144
assert convert_units(1, bunits.YB, bunits.PB) == (bunits.YB / 1024 ** 5, 'PiB')
145+
assert convert_units(-1, bunits.YB, bunits.PB) == (-bunits.YB / 1024 ** 5, 'PiB')
139146

140147
def test_exbibyte(self) -> None:
141148
assert convert_units(1, bunits.YB, bunits.EB) == (bunits.YB / 1024 ** 6, 'EiB')
149+
assert convert_units(-1, bunits.YB, bunits.EB) == (-bunits.YB / 1024 ** 6, 'EiB')
142150

143151
def test_zebibyte(self) -> None:
144152
assert convert_units(1, bunits.YB, bunits.ZB) == (bunits.YB / 1024 ** 7, 'ZiB')
153+
assert convert_units(-1, bunits.YB, bunits.ZB) == (-bunits.YB / 1024 ** 7, 'ZiB')
145154

146155
def test_yobibyte(self) -> None:
147156
assert convert_units(1, bunits.YB, bunits.YB) == (bunits.YB / 1024 ** 8, 'YiB')
157+
assert convert_units(-1, bunits.YB, bunits.YB) == (-bunits.YB / 1024 ** 8, 'YiB')
148158

149159
def test_kilobyte(self) -> None:
150160
assert convert_units(1, dunits.YB, dunits.KB) == (dunits.YB / 1000 ** 1, 'KB')
161+
assert convert_units(-1, dunits.YB, dunits.KB) == (-dunits.YB / 1000 ** 1, 'KB')
151162

152163
def test_megabyte(self) -> None:
153164
assert convert_units(1, dunits.YB, dunits.MB) == (dunits.YB / 1000 ** 2, 'MB')
165+
assert convert_units(-1, dunits.YB, dunits.MB) == (-dunits.YB / 1000 ** 2, 'MB')
154166

155167
def test_gigabyte(self) -> None:
156168
assert convert_units(1, dunits.YB, dunits.GB) == (dunits.YB / 1000 ** 3, 'GB')
169+
assert convert_units(-1, dunits.YB, dunits.GB) == (-dunits.YB / 1000 ** 3, 'GB')
157170

158171
def test_terabyte(self) -> None:
159172
assert convert_units(1, dunits.YB, dunits.TB) == (dunits.YB / 1000 ** 4, 'TB')
173+
assert convert_units(-1, dunits.YB, dunits.TB) == (-dunits.YB / 1000 ** 4, 'TB')
160174

161175
def test_petabyte(self) -> None:
162176
assert convert_units(1, dunits.YB, dunits.PB) == (dunits.YB / 1000 ** 5, 'PB')
177+
assert convert_units(-1, dunits.YB, dunits.PB) == (-dunits.YB / 1000 ** 5, 'PB')
163178

164179
def test_exabyte(self) -> None:
165180
assert convert_units(1, dunits.YB, dunits.EB) == (dunits.YB / 1000 ** 6, 'EB')
181+
assert convert_units(-1, dunits.YB, dunits.EB) == (-dunits.YB / 1000 ** 6, 'EB')
166182

167183
def test_zettabyte(self) -> None:
168184
assert convert_units(1, dunits.YB, dunits.ZB) == (dunits.YB / 1000 ** 7, 'ZB')
185+
assert convert_units(-1, dunits.YB, dunits.ZB) == (-dunits.YB / 1000 ** 7, 'ZB')
169186

170187
def test_yottabyte(self) -> None:
171188
assert convert_units(1, dunits.YB, dunits.YB) == (dunits.YB / 1000 ** 8, 'YB')
189+
assert convert_units(-1, dunits.YB, dunits.YB) == (-dunits.YB / 1000 ** 8, 'YB')
172190

173191

174192
class TestConvertFloatExact:
175193
def test_byte(self) -> None:
176194
assert convert_units(3.14, bunits.YB, bunits.B, exact=True) == (Decimal('3796027073589935608577392'), 'B')
177195
assert convert_units(3.14, dunits.YB, dunits.B, exact=True) == (Decimal('3140000000000000000000000'), 'B')
196+
assert convert_units(-3.14, bunits.YB, bunits.B, exact=True) == (Decimal('-3796027073589935608577392'), 'B')
197+
assert convert_units(-3.14, dunits.YB, dunits.B, exact=True) == (Decimal('-3140000000000000000000000'), 'B')
178198

179199
def test_kibibyte(self) -> None:
180200
assert convert_units(3.14, bunits.YB, bunits.KB, exact=True) == (Decimal('3707057689052671492751.36'), 'KiB')
201+
assert convert_units(-3.14, bunits.YB, bunits.KB, exact=True) == (Decimal('-3707057689052671492751.36'), 'KiB')
181202

182203
def test_mebibyte(self) -> None:
183204
assert convert_units(3.14, bunits.YB, bunits.MB, exact=True) == (Decimal('3620173524465499504.64'), 'MiB')
205+
assert convert_units(-3.14, bunits.YB, bunits.MB, exact=True) == (Decimal('-3620173524465499504.64'), 'MiB')
184206

185207
def test_gibibyte(self) -> None:
186208
assert convert_units(3.14, bunits.YB, bunits.GB, exact=True) == (Decimal('3535325707485839.36'), 'GiB')
209+
assert convert_units(-3.14, bunits.YB, bunits.GB, exact=True) == (Decimal('-3535325707485839.36'), 'GiB')
187210

188211
def test_tebibyte(self) -> None:
189212
assert convert_units(3.14, bunits.YB, bunits.TB, exact=True) == (Decimal('3452466511216.64'), 'TiB')
213+
assert convert_units(-3.14, bunits.YB, bunits.TB, exact=True) == (Decimal('-3452466511216.64'), 'TiB')
190214

191215
def test_pebibyte(self) -> None:
192216
assert convert_units(3.14, bunits.YB, bunits.PB, exact=True) == (Decimal('3371549327.36'), 'PiB')
217+
assert convert_units(-3.14, bunits.YB, bunits.PB, exact=True) == (Decimal('-3371549327.36'), 'PiB')
193218

194219
def test_exbibyte(self) -> None:
195220
assert convert_units(3.14, bunits.YB, bunits.EB, exact=True) == (Decimal('3292528.64'), 'EiB')
221+
assert convert_units(-3.14, bunits.YB, bunits.EB, exact=True) == (Decimal('-3292528.64'), 'EiB')
196222

197223
def test_zebibyte(self) -> None:
198224
assert convert_units(3.14, bunits.YB, bunits.ZB, exact=True) == (Decimal('3215.36'), 'ZiB')
225+
assert convert_units(-3.14, bunits.YB, bunits.ZB, exact=True) == (Decimal('-3215.36'), 'ZiB')
199226

200227
def test_yobibyte(self) -> None:
201228
assert convert_units(3.14, bunits.YB, bunits.YB, exact=True) == (Decimal('3.14'), 'YiB')
229+
assert convert_units(-3.14, bunits.YB, bunits.YB, exact=True) == (Decimal('-3.14'), 'YiB')
202230

203231
def test_kilobyte(self) -> None:
204232
assert convert_units(3.14, dunits.YB, dunits.KB, exact=True) == (Decimal('3140000000000000000000.00'), 'KB')
233+
assert convert_units(-3.14, dunits.YB, dunits.KB, exact=True) == (Decimal('-3140000000000000000000.00'), 'KB')
205234

206235
def test_megabyte(self) -> None:
207236
assert convert_units(3.14, dunits.YB, dunits.MB, exact=True) == (Decimal('3140000000000000000.00'), 'MB')
237+
assert convert_units(-3.14, dunits.YB, dunits.MB, exact=True) == (Decimal('-3140000000000000000.00'), 'MB')
208238

209239
def test_gigabyte(self) -> None:
210240
assert convert_units(3.14, dunits.YB, dunits.GB, exact=True) == (Decimal('3140000000000000.00'), 'GB')
241+
assert convert_units(-3.14, dunits.YB, dunits.GB, exact=True) == (Decimal('-3140000000000000.00'), 'GB')
211242

212243
def test_terabyte(self) -> None:
213244
assert convert_units(3.14, dunits.YB, dunits.TB, exact=True) == (Decimal('3140000000000.00'), 'TB')
245+
assert convert_units(-3.14, dunits.YB, dunits.TB, exact=True) == (Decimal('-3140000000000.00'), 'TB')
214246

215247
def test_petabyte(self) -> None:
216248
assert convert_units(3.14, dunits.YB, dunits.PB, exact=True) == (Decimal('3140000000.00'), 'PB')
249+
assert convert_units(-3.14, dunits.YB, dunits.PB, exact=True) == (Decimal('-3140000000.00'), 'PB')
217250

218251
def test_exabyte(self) -> None:
219252
assert convert_units(3.14, dunits.YB, dunits.EB, exact=True) == (Decimal('3140000.00'), 'EB')
253+
assert convert_units(-3.14, dunits.YB, dunits.EB, exact=True) == (Decimal('-3140000.00'), 'EB')
220254

221255
def test_zettabyte(self) -> None:
222256
assert convert_units(3.14, dunits.YB, dunits.ZB, exact=True) == (Decimal('3140.00'), 'ZB')
257+
assert convert_units(-3.14, dunits.YB, dunits.ZB, exact=True) == (Decimal('-3140.00'), 'ZB')
223258

224259
def test_yottabyte(self) -> None:
225260
assert convert_units(3.14, dunits.YB, dunits.YB, exact=True) == (Decimal('3.14'), 'YB')
261+
assert convert_units(-3.14, dunits.YB, dunits.YB, exact=True) == (Decimal('-3.14'), 'YB')
226262

227263

228264
class TestConvertUnknownTo:
@@ -231,68 +267,102 @@ def test_byte(self) -> None:
231267
assert convert_units(bunits.KB - 1) == (bunits.KB - 1, 'B')
232268
assert convert_units(dunits.B, si=True) == (dunits.B, 'B')
233269
assert convert_units(dunits.KB - 1, si=True) == (dunits.KB - 1, 'B')
270+
assert convert_units(-bunits.B) == (-bunits.B, 'B')
271+
assert convert_units(-bunits.KB + 1) == (-bunits.KB + 1, 'B')
272+
assert convert_units(-dunits.B, si=True) == (-dunits.B, 'B')
273+
assert convert_units(-dunits.KB + 1, si=True) == (-dunits.KB + 1, 'B')
234274

235275
def test_kibibyte(self) -> None:
236276
assert convert_units(bunits.KB) == (bunits.KB / bunits.KB, 'KiB')
237277
assert convert_units(bunits.MB - 1) == ((bunits.MB - 1) / bunits.KB, 'KiB')
278+
assert convert_units(-bunits.KB) == (-bunits.KB / bunits.KB, 'KiB')
279+
assert convert_units(-bunits.MB + 1) == ((-bunits.MB + 1) / bunits.KB, 'KiB')
238280

239281
def test_mebibyte(self) -> None:
240282
assert convert_units(bunits.MB) == (bunits.MB / bunits.MB, 'MiB')
241283
assert convert_units(bunits.GB - 1) == ((bunits.GB - 1) / bunits.MB, 'MiB')
284+
assert convert_units(-bunits.MB) == (-bunits.MB / bunits.MB, 'MiB')
285+
assert convert_units(-bunits.GB + 1) == ((-bunits.GB + 1) / bunits.MB, 'MiB')
242286

243287
def test_gibibyte(self) -> None:
244288
assert convert_units(bunits.GB) == (bunits.GB / bunits.GB, 'GiB')
245289
assert convert_units(bunits.TB - 1) == ((bunits.TB - 1) / bunits.GB, 'GiB')
290+
assert convert_units(-bunits.GB) == (-bunits.GB / bunits.GB, 'GiB')
291+
assert convert_units(-bunits.TB + 1) == ((-bunits.TB + 1) / bunits.GB, 'GiB')
246292

247293
def test_tebibyte(self) -> None:
248294
assert convert_units(bunits.TB) == (bunits.TB / bunits.TB, 'TiB')
249295
assert convert_units(bunits.PB - 1) == ((bunits.PB - 1) / bunits.TB, 'TiB')
296+
assert convert_units(-bunits.TB) == (-bunits.TB / bunits.TB, 'TiB')
297+
assert convert_units(-bunits.PB + 1) == ((-bunits.PB + 1) / bunits.TB, 'TiB')
250298

251299
def test_pebibyte(self) -> None:
252300
assert convert_units(bunits.PB) == (bunits.PB / bunits.PB, 'PiB')
253301
assert convert_units(bunits.EB - 1) == ((bunits.EB - 1) / bunits.PB, 'PiB')
302+
assert convert_units(-bunits.PB) == (-bunits.PB / bunits.PB, 'PiB')
303+
assert convert_units(-bunits.EB + 1) == ((-bunits.EB + 1) / bunits.PB, 'PiB')
254304

255305
def test_exbibyte(self) -> None:
256306
assert convert_units(bunits.EB) == (bunits.EB / bunits.EB, 'EiB')
257307
assert convert_units(bunits.ZB - 1) == ((bunits.ZB - 1) / bunits.EB, 'EiB')
308+
assert convert_units(-bunits.EB) == (-bunits.EB / bunits.EB, 'EiB')
309+
assert convert_units(-bunits.ZB + 1) == ((-bunits.ZB + 1) / bunits.EB, 'EiB')
258310

259311
def test_zebibyte(self) -> None:
260312
assert convert_units(bunits.ZB) == (bunits.ZB / bunits.ZB, 'ZiB')
261313
assert convert_units(bunits.YB - 1) == ((bunits.YB - 1) / bunits.ZB, 'ZiB')
314+
assert convert_units(-bunits.ZB) == (-bunits.ZB / bunits.ZB, 'ZiB')
315+
assert convert_units(-bunits.YB + 1) == ((-bunits.YB + 1) / bunits.ZB, 'ZiB')
262316

263317
def test_yobibyte(self) -> None:
264318
assert convert_units(bunits.YB) == (bunits.YB / bunits.YB, 'YiB')
319+
assert convert_units(-bunits.YB) == (-bunits.YB / bunits.YB, 'YiB')
265320

266321
def test_kilobyte(self) -> None:
267322
assert convert_units(dunits.KB, si=True) == (dunits.KB / dunits.KB, 'KB')
268323
assert convert_units(dunits.MB - 1, si=True) == ((dunits.MB - 1) / dunits.KB, 'KB')
324+
assert convert_units(-dunits.KB, si=True) == (-dunits.KB / dunits.KB, 'KB')
325+
assert convert_units(-dunits.MB + 1, si=True) == ((-dunits.MB + 1) / dunits.KB, 'KB')
269326

270327
def test_megabyte(self) -> None:
271328
assert convert_units(dunits.MB, si=True) == (dunits.MB / dunits.MB, 'MB')
272329
assert convert_units(dunits.GB - 1, si=True) == ((dunits.GB - 1) / dunits.MB, 'MB')
330+
assert convert_units(-dunits.MB, si=True) == (-dunits.MB / dunits.MB, 'MB')
331+
assert convert_units(-dunits.GB + 1, si=True) == ((-dunits.GB + 1) / dunits.MB, 'MB')
273332

274333
def test_gigabyte(self) -> None:
275334
assert convert_units(dunits.GB, si=True) == (dunits.GB / dunits.GB, 'GB')
276335
assert convert_units(dunits.TB - 1, si=True) == ((dunits.TB - 1) / dunits.GB, 'GB')
336+
assert convert_units(-dunits.GB, si=True) == (-dunits.GB / dunits.GB, 'GB')
337+
assert convert_units(-dunits.TB + 1, si=True) == ((-dunits.TB + 1) / dunits.GB, 'GB')
277338

278339
def test_terabyte(self) -> None:
279340
assert convert_units(dunits.TB, si=True) == (dunits.TB / dunits.TB, 'TB')
280341
assert convert_units(dunits.PB - 1, si=True) == ((dunits.PB - 1) / dunits.TB, 'TB')
342+
assert convert_units(-dunits.TB, si=True) == (-dunits.TB / dunits.TB, 'TB')
343+
assert convert_units(-dunits.PB + 1, si=True) == ((-dunits.PB + 1) / dunits.TB, 'TB')
281344

282345
def test_petabyte(self) -> None:
283346
assert convert_units(dunits.PB, si=True) == (dunits.PB / dunits.PB, 'PB')
284347
assert convert_units(dunits.EB - 1, si=True) == ((dunits.EB - 1) / dunits.PB, 'PB')
348+
assert convert_units(-dunits.PB, si=True) == (-dunits.PB / dunits.PB, 'PB')
349+
assert convert_units(-dunits.EB + 1, si=True) == ((-dunits.EB + 1) / dunits.PB, 'PB')
285350

286351
def test_exabyte(self) -> None:
287352
assert convert_units(dunits.EB, si=True) == (dunits.EB / dunits.EB, 'EB')
288353
assert convert_units(dunits.ZB - 1, si=True) == ((dunits.ZB - 1) / dunits.EB, 'EB')
354+
assert convert_units(-dunits.EB, si=True) == (-dunits.EB / dunits.EB, 'EB')
355+
assert convert_units(-dunits.ZB + 1, si=True) == ((-dunits.ZB + 1) / dunits.EB, 'EB')
289356

290357
def test_zettabyte(self) -> None:
291358
assert convert_units(dunits.ZB, si=True) == (dunits.ZB / dunits.ZB, 'ZB')
292359
assert convert_units(dunits.YB - 1, si=True) == ((dunits.YB - 1) / dunits.ZB, 'ZB')
360+
assert convert_units(-dunits.ZB, si=True) == (-dunits.ZB / dunits.ZB, 'ZB')
361+
assert convert_units(-dunits.YB + 1, si=True) == ((-dunits.YB + 1) / dunits.ZB, 'ZB')
293362

294363
def test_yottabyte(self) -> None:
295364
assert convert_units(dunits.YB, si=True) == (dunits.YB / dunits.YB, 'YB')
365+
assert convert_units(-dunits.YB, si=True) == (-dunits.YB / dunits.YB, 'YB')
296366

297367

298368
class TestUnknownUnits:

0 commit comments

Comments
 (0)