Skip to content

Commit e8a69ea

Browse files
committed
2. add base_encode, base_decode, gen_id, timeti to utils
1 parent 51d234c commit e8a69ea

File tree

2 files changed

+127
-1
lines changed

2 files changed

+127
-1
lines changed

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
### 1.2.1 (2025-03-03)
22
1. add `utils.get_size` to get size of objects recursively.
3-
2.
3+
2. add `base_encode, base_decode, gen_id, timeti` to `utils`
44

55

66
### 1.2.0 (2025-02-16)

morebuiltins/utils.py

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,11 @@
1212
import subprocess
1313
import sys
1414
import tempfile
15+
import timeit
1516
import traceback
1617
import types
1718
from collections import UserDict
19+
from datetime import datetime
1820
from enum import IntEnum
1921
from functools import wraps
2022
from itertools import groupby, islice
@@ -72,6 +74,10 @@
7274
"get_hash_int",
7375
"iter_weights",
7476
"get_size",
77+
"base_encode",
78+
"base_decode",
79+
"gen_id",
80+
"timeti",
7581
]
7682

7783

@@ -1766,6 +1772,126 @@ def get_size(obj, seen=None, iterate_unsafe=False) -> int:
17661772
return size
17671773

17681774

1775+
def base_encode(
1776+
num: int,
1777+
alphabet: str = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ",
1778+
) -> str:
1779+
"""Encode a number to a base-N string.
1780+
1781+
Args:
1782+
num (int): The number to encode.
1783+
alphabet (str, optional): Defaults to "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".
1784+
1785+
Returns:
1786+
str: The encoded string.
1787+
1788+
Examples:
1789+
>>> base_encode(0)
1790+
'0'
1791+
>>> base_encode(1)
1792+
'1'
1793+
>>> base_encode(10000000000000)
1794+
'2Q3rKTOE'
1795+
>>> base_encode(10000000000000, "0123456789")
1796+
'10000000000000'
1797+
"""
1798+
length = len(alphabet)
1799+
result = ""
1800+
while num:
1801+
num, i = divmod(num, length)
1802+
result = f"{alphabet[i]}{result}"
1803+
return result or alphabet[0]
1804+
1805+
1806+
def base_decode(
1807+
string: str,
1808+
alphabet: str = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ",
1809+
) -> int:
1810+
"""Decode a base-N string to a number.
1811+
1812+
Args:
1813+
string (str): The string to decode.
1814+
alphabet (str, optional): Defaults to "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".
1815+
1816+
Returns:
1817+
int: The decoded number.
1818+
1819+
Examples:
1820+
>>> base_decode("0")
1821+
0
1822+
>>> base_decode("1")
1823+
1
1824+
>>> base_decode("2Q3rKTOE")
1825+
10000000000000
1826+
>>> base_decode("10000000000000", "0123456789")
1827+
10000000000000
1828+
"""
1829+
length = len(alphabet)
1830+
result = 0
1831+
for char in string:
1832+
result = result * length + alphabet.index(char)
1833+
return result
1834+
1835+
1836+
def gen_id(rand_len=4) -> str:
1837+
"""Generate a unique ID based on the current time and random bytes
1838+
1839+
Args:
1840+
rand_len (int, optional): Defaults to 4.
1841+
1842+
Returns:
1843+
str: The generated ID.
1844+
1845+
Examples:
1846+
>>> a, b = gen_id(), gen_id()
1847+
>>> a != b
1848+
True
1849+
>>> import time
1850+
>>> ids = [time.sleep(0.000001) or gen_id() for _ in range(1000)]
1851+
>>> len(set(ids))
1852+
1000
1853+
>>> ids = [gen_id() for _ in range(10000)]
1854+
>>> len(set(ids)) < 10000
1855+
True
1856+
"""
1857+
now = datetime.now()
1858+
s1 = now.strftime("%y%m%d_%H%M%S")
1859+
s2 = base_encode(now.microsecond)
1860+
s2 = f"{s2:>04}{os.urandom(rand_len // 2).hex()}"
1861+
return f"{s1}_{s2}"
1862+
1863+
1864+
def timeti(
1865+
stmt: Union[str, Callable] = "pass",
1866+
setup="pass",
1867+
timer=timeit.default_timer,
1868+
number=1000000,
1869+
globals=None,
1870+
) -> int:
1871+
"""Return the number of iterations per second for a given statement.
1872+
1873+
Args:
1874+
stmt (str, optional): Defaults to "pass".
1875+
setup (str, optional): Defaults to "pass".
1876+
timer (optional): Defaults to timeit.default_timer.
1877+
number (int, optional): Defaults to 1000000.
1878+
globals (dict, optional): Defaults to None.
1879+
1880+
Returns:
1881+
int: The number of iterations per second.
1882+
1883+
Examples:
1884+
>>> timeti("1 / 1") > 1000000
1885+
True
1886+
>>> timeti(lambda : 1 + 1, number=100000) > 100000
1887+
True
1888+
"""
1889+
result = timeit.timeit(
1890+
stmt=stmt, setup=setup, timer=timer, number=number, globals=globals
1891+
)
1892+
return int(1 / (result / number))
1893+
1894+
17691895
if __name__ == "__main__":
17701896
__name__ = "morebuiltins.utils"
17711897
import doctest

0 commit comments

Comments
 (0)