🔢 Conversions & formatting¶
Forgiving converters and human-friendly formatters for the messy, real-world data you get from users, files and APIs.
Numbers out of strings¶
to_int and to_float never raise on bad input — they return a default
(itself 0 by default). Opt into regexp extraction to pull the first number out
of surrounding text:
from python_utils import converters
converters.to_int('abc') # 0
converters.to_int('spam15eggs', regexp=True) # 15
converters.to_int('nope', default=-1) # -1
converters.to_float('pi is 3.14', regexp=True) # 3.14
regexp=True uses a sensible built-in pattern; pass your own str or compiled
re.Pattern for full control (the last capture group is used).
Text and bytes¶
to_str and to_unicode normalise between str and bytes with configurable
encoding and error handling:
from python_utils import converters
converters.to_unicode(b'a') # 'a'
converters.to_str('a') # b'a'
scale_1024 — human-readable sizes¶
Scale a number by powers of 1024 and get back both the scaled value and the
power, ready to index into a list of prefixes (['', 'Ki', 'Mi', ...]):
from python_utils import converters
converters.scale_1024(1, 3) # (1.0, 0) -> 1 B
converters.scale_1024(2048, 3) # (2.0, 1) -> 2 KiB
remap — move a value between ranges¶
Linearly remap a value from one range to another. Pass a decimal.Decimal
anywhere and the whole computation is done in Decimal to avoid floating-point
error; otherwise it follows Python’s usual int/float promotion:
import decimal
from python_utils import converters
converters.remap(500, 0, 1000, 0, 100) # 50
converters.remap(46.0, 0.0, 100.0, -80.0, 10.0) # -38.6 (46% volume -> dB)
converters.remap(decimal.Decimal('250.0'), 0.0, 1000.0, 0.0, 100.0)
# Decimal('25.0')
camel_to_underscore & apply_recursive¶
Convert CamelCase to snake_case, and apply any string transform to every key of a (possibly nested) mapping:
from python_utils import formatters
formatters.camel_to_underscore('SpamEggsAndBacon') # 'spam_eggs_and_bacon'
formatters.apply_recursive(
formatters.camel_to_underscore,
{'SpamEggs': {'FooBar': 1}},
) # {'spam_eggs': {'foo_bar': 1}}
timesince & format_time¶
timesince gives a Django-style “time ago” string; format_time renders
timedeltas, datetimes, dates and raw seconds uniformly:
import datetime
from python_utils import formatters, time
now = datetime.datetime.now()
formatters.timesince(now - datetime.timedelta(seconds=61)) # '1 minute and 1 second ago'
time.format_time(1) # '0:00:01'
time.format_time(datetime.timedelta(seconds=3661)) # '1:01:01'
time.format_time(datetime.datetime(2000, 1, 2, 3, 4, 5)) # '2000-01-02 03:04:05'
time.format_time(None) # '--:--:--'
See the API reference for every parameter.