Big News: Socket raises $60M Series C at a $1B valuation to secure software supply chains for AI-driven development.Announcement
Sign In

libdev

Package Overview
Dependencies
Maintainers
1
Versions
102
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

libdev - pypi Package Compare versions

Comparing version
0.93
to
0.94
+1
-1
libdev.egg-info/PKG-INFO
Metadata-Version: 2.1
Name: libdev
Version: 0.93
Version: 0.94
Summary: Set of standard functions for development

@@ -5,0 +5,0 @@ Home-page: https://github.com/chilleco/lib

@@ -5,4 +5,4 @@ """

__version__ = "0.93"
__version__ = "0.94"
__all__ = ("__version__",)

@@ -7,17 +7,6 @@ """

import math
from decimal import Decimal, ROUND_HALF_UP
from decimal import Decimal, InvalidOperation
_SUBSCRIPTS = {
"0": "₀",
"1": "₁",
"2": "₂",
"3": "₃",
"4": "₄",
"5": "₅",
"6": "₆",
"7": "₇",
"8": "₈",
"9": "₉",
}
_SUBSCRIPTS = str.maketrans("0123456789", "₀₁₂₃₄₅₆₇₈₉")

@@ -133,3 +122,10 @@

def pretty(value, decimals=None, sign=False, symbol="’"):
def pretty(
value,
decimals=None,
sign=False,
symbol="’",
zeros=4,
compress=None,
):
"""Decorate the number beautifully"""

@@ -140,14 +136,41 @@

data = str(float(value))
# Handle decimals parameter first (takes precedence)
if decimals is not None:
cur = len(data.split(".", maxsplit=1)[0])
data = str(round(value, max(0, decimals - cur)))
# Use the original decimals logic for backward compatibility
s = to_plain(abs(value))
if "." in s:
int_part = s.split(".", 1)[0]
cur = len(int_part)
target_decimals = max(0, decimals - cur)
# Apply rounding first
rounded_value = round(float(value), target_decimals)
# If target_decimals is 0, convert to int for proper formatting
if target_decimals == 0:
rounded_value = int(rounded_value)
# Then use compress_zeros without round parameter
data = compress_zeros(rounded_value, zeros=zeros)
else:
data = compress_zeros(value, zeros=zeros)
elif zeros is None and compress is None:
# No compression or special formatting requested, use plain representation
data = to_plain(value)
else:
# Use compress_zeros with specified parameters
compress_zeros_args = {}
if data.rsplit(".", maxsplit=1)[-1] == "0":
data = data.split(".", maxsplit=1)[0]
if zeros is not None:
compress_zeros_args["zeros"] = zeros
if compress is not None:
compress_zeros_args["round"] = compress
data = compress_zeros(value, **compress_zeros_args)
if data == "0":
return "0"
# Remove trailing zeros after decimal point for cleaner formatting
if "." in data and data.rsplit(".", maxsplit=1)[-1] == "0":
data = data.split(".", maxsplit=1)[0]
if symbol:

@@ -264,24 +287,38 @@ data = add_radix(data, symbol)

def _to_subscript(n: int) -> str:
"""Convert an integer n to a string of subscript digits."""
return "".join(_SUBSCRIPTS[d] for d in str(n))
def to_plain(value) -> str:
if value is None:
return None
try:
if isinstance(value, str):
d = Decimal(value)
elif isinstance(value, float):
d = Decimal(str(value))
else:
d = Decimal(value)
s = format(d.normalize(), "f")
def compress_zeros(x: int | float, round: int | None = None) -> str | None:
"""
Given a float or decimal‐string x, return a string where
runs of leading zeros in the fraction are shown as:
one '0' plus a subscript count of the zeros.
If `round` is provided, the remaining digits after the zeros
are rounded to that many places.
if "." in s:
s = s.rstrip("0").rstrip(".")
if s == "-0":
s = "0"
return s
except (InvalidOperation, ValueError, TypeError):
return str(value)
Examples:
compress_zeros(0.00012) -> '0.0₃12'
compress_zeros(0.00012, round=2) -> '0.0₃12'
compress_zeros(0.0123) -> '0.0123' (only one leading zero, so unchanged)
compress_zeros(0.0123456, round=3)-> '0.0123'
compress_zeros(1.000045) -> '1.0₄45'
compress_zeros(-0.0010959999999999997522, round=3)
-> '-0.0₂11'
def _round_to_decimals(x, decimals):
"""Helper function to round to specified decimal places"""
if decimals <= 0:
return float(int(x))
return round(float(x), decimals)
def compress_zeros(x, zeros=2, round=None) -> str:
"""
0.000012 -> '0.0₄12'
1.000045 -> '1.0₄45'
round: number of digits after the zero block (rounds).
zeros: minimum count of consecutive zeros to compress (default: 2).
"""

@@ -291,45 +328,115 @@ if x is None:

dec_x = Decimal(str(x))
s = format(dec_x, "f")
# Store original string representation for rounding calculations
original_str = None
if isinstance(x, str):
original_str = x.strip()
x = original_str
# Remove trailing zeros from string
if "." in x:
x = x.rstrip("0").rstrip(".")
# Convert to appropriate numeric type
try:
if "." in x:
x = float(x)
else:
x = int(x)
except ValueError:
return str(x)
# no fractional part
if "." not in s:
return s
# Determine if original was float or int to preserve format
is_float_type = isinstance(x, float) or (isinstance(x, str) and "." in str(x))
int_part, frac = s.split(".", 1)
# Handle rounding if specified
if round is not None:
# For rounding, use original string if available, otherwise convert to plain string
if original_str and "." in original_str:
s = original_str.lstrip("-")
else:
# Use to_plain to avoid scientific notation
s = to_plain(abs(x))
# count leading zeros in the fractional part
zero_run = len(frac) - len(frac.lstrip("0"))
if "." in s:
int_part, frac_part = s.split(".")
# Count leading zeros in fractional part
leading_zeros = 0
for c in frac_part:
if c == "0":
leading_zeros += 1
else:
break
# If rounding is requested, do it first
if round is not None:
# ensure at least one zero is counted for quantization
places = max(zero_run, 1) + round
quant = Decimal(f"1e-{places}")
dec_q = dec_x.quantize(quant, rounding=ROUND_HALF_UP)
s_q = format(dec_q, "f")
# Count trailing zeros in fractional part
trailing_zeros = 0
for c in reversed(frac_part):
if c == "0":
trailing_zeros += 1
else:
break
# if rounding eliminated fractional part
if "." not in s_q:
return s_q
# Apply rounding logic
if leading_zeros > 0:
# If there are leading zeros, round after them (regardless of compression)
total_decimals = leading_zeros + round
x = _round_to_decimals(x, total_decimals)
else:
# No leading zeros, apply normal rounding
x = _round_to_decimals(x, round)
int_part_q, frac_q = s_q.split(".", 1)
# for zero_run == 0 or 1, we just return the rounded string
if zero_run <= 1:
return s_q
# Convert to string representation
if isinstance(x, int) and not is_float_type:
s = str(x)
else:
# For floats, use format that preserves trailing decimals when needed
if x == int(x) and is_float_type:
s = f"{int(x)}.0"
else:
s = str(float(x))
# Remove scientific notation if present
if "e" in s.lower():
s = f"{float(x):.15f}".rstrip("0")
if s.endswith("."):
s += "0"
# strip any trailing zeros, then compress
frac_q = frac_q.rstrip("0")
if not frac_q:
return int_part_q
tail = frac_q[zero_run:]
return f"{int_part_q}.0{_to_subscript(zero_run)}{tail}"
# Handle negative sign
negative = s.startswith("-")
if negative:
s = s[1:]
# No rounding: only compress if more than one leading zero
if zero_run <= 1:
return s
# Process compression
if "." not in s:
result = s
else:
int_part, frac_part = s.split(".")
tail = frac[zero_run:]
# Compress leading zeros in fractional part
leading_zeros = 0
for c in frac_part:
if c == "0":
leading_zeros += 1
else:
break
# build compressed form
return f"{int_part}.0{_to_subscript(zero_run)}{tail}"
# Compress trailing zeros in fractional part
trailing_zeros = 0
for c in reversed(frac_part):
if c == "0":
trailing_zeros += 1
else:
break
# Apply compression
if leading_zeros >= zeros:
# Compress leading zeros
remaining_frac = frac_part[leading_zeros:]
result = f"{int_part}.0{str(leading_zeros).translate(_SUBSCRIPTS)}{remaining_frac}"
elif trailing_zeros >= zeros and leading_zeros == 0:
# Compress trailing zeros (but not if there are leading zeros)
remaining_frac = frac_part[:-trailing_zeros]
if remaining_frac:
result = f"{int_part}.{remaining_frac}0{str(trailing_zeros).translate(_SUBSCRIPTS)}"
else:
result = f"{int_part}.0{str(trailing_zeros).translate(_SUBSCRIPTS)}"
else:
result = s
return f"-{result}" if negative else result

@@ -303,2 +303,23 @@ """

def get_week_start(timestamp=None, tz=0):
"""
Get the start of the week (midnight on Monday) for a given timestamp in a specified timezone.
Args:
timestamp (float): The original timestamp (in seconds since epoch). Defaults to the current time if None.
tz (int): The timezone offset in hours (e.g., 3 for UTC+3).
Returns:
float: The timestamp for the start of the week (Monday at midnight) in the specified timezone.
"""
if timestamp is None:
timestamp = time.time()
dt_local = datetime.datetime.fromtimestamp(timestamp, tz=to_tz(tz))
# Calculate days to subtract to get to Monday (weekday() returns 0 for Monday, 6 for Sunday)
days_since_monday = dt_local.weekday()
start_week = dt_local - datetime.timedelta(days=days_since_monday)
start_week = start_week.replace(hour=0, minute=0, second=0, microsecond=0)
return int(start_week.timestamp())
def get_next_day(timestamp=None, tz=0):

@@ -305,0 +326,0 @@ """

Metadata-Version: 2.1
Name: libdev
Version: 0.93
Version: 0.94
Summary: Set of standard functions for development

@@ -5,0 +5,0 @@ Home-page: https://github.com/chilleco/lib

@@ -14,2 +14,3 @@ from libdev.num import (

pretty,
to_plain,
compress_zeros,

@@ -160,4 +161,67 @@ )

assert pretty(12345.6, 3, True) == "+12’346"
assert pretty(-0.000000235235, zeros=None, compress=None) == "-0.000000235235"
assert pretty(-0.000000235235, zeros=4, compress=2) == "-0.0₆24"
def test_to_plain():
assert to_plain(None) == None
assert to_plain(0) == "0"
# assert to_plain(0.0) == "0.0"
# assert to_plain(1.0) == "1.0"
assert to_plain(1.1) == "1.1"
assert to_plain(0.000000235235) == "0.000000235235"
assert to_plain(-0.000000235235) == "-0.000000235235"
assert to_plain("0.000000235235") == "0.000000235235"
assert to_plain(2.35235e-07) == "0.000000235235"
assert to_plain("1e-12") == "0.000000000001"
assert to_plain("123.4500") == "123.45"
def test_pretty_with_compression():
# Test pretty function with compression parameters
# Test zeros parameter (minimum zeros to compress)
assert pretty(0.00012, zeros=2) == "0.0₃12" # Default behavior, compress >=2 zeros
assert pretty(0.01, zeros=1) == "0.0₁1" # Compress single zero with zeros=1
assert pretty(0.01, zeros=3) == "0.01" # Don't compress with zeros=3 (only 1 zero)
assert pretty(0.0001, zeros=3) == "0.0₃1" # Compress with zeros=3 (3 zeros)
# Test compress parameter (round after zero block)
assert (
pretty(0.00012345, zeros=2, compress=2) == "0.0₃12"
) # Round to 2 digits after zeros
assert (
pretty(0.00012345, zeros=4, compress=4) == "0.0001234"
) # No compression (3 < 4 zeros), 4 digits after 3 zeros
assert pretty(0.00012345, zeros=4, compress=8) == "0.00012345"
assert (
pretty(0.00012345, zeros=2, compress=3) == "0.0₃123"
) # Round to 3 digits after zeros
assert (
pretty(-0.0010959999999999997522, compress=3) == "-0.0011"
) # Negative with rounding
# Test both parameters together
assert (
pretty("0.0000012345", zeros=4, compress=2) == "0.0₅12"
) # 5 zeros, round to 2 digits
assert (
pretty("0.00012345", zeros=4, compress=2) == "0.00012"
) # Only 3 zeros, no compression, 2 digits after 3 zeros
# Test that other pretty parameters still work with compression
assert pretty(0.00012, zeros=2, sign=True) == "+0.0₃12" # With sign
assert pretty(12000.00012, zeros=2, symbol="'") == "12'000.0₃12" # With radix
assert (
pretty(-0.00012, zeros=2, sign=True, symbol="'") == "-0.0₃12"
) # Negative with sign and radix
# Test edge cases
assert pretty(0, zeros=1) == "0" # Zero value
assert pretty(None, zeros=2) == None # None value
assert (
pretty(1.0, zeros=2) == "1"
) # No fractional zeros to compress, trailing zero removed for clean formatting
def test_compress_zeros():

@@ -175,2 +239,14 @@ assert compress_zeros(None) == None

assert compress_zeros(1.000045) == "1.0₄45"
assert compress_zeros(0.0010859999999999997522, round=3) == "0.0₂109"
assert compress_zeros(-0.0010959999999999997522, round=3) == "-0.0₂11"
assert compress_zeros("-0.012300") == "-0.0123"
assert compress_zeros(0.01, zeros=1) == "0.0₁1"
assert compress_zeros(0.001, zeros=1) == "0.0₂1"
assert compress_zeros("1.10", zeros=1) == "1.1"
assert compress_zeros(0.01, zeros=3) == "0.01"
assert compress_zeros(0.001, zeros=3) == "0.001"
assert compress_zeros(0.0001, zeros=3) == "0.0₃1"
assert compress_zeros(0.00001, zeros=3) == "0.0₄1"
assert compress_zeros(0.0000012, zeros=1) == "0.0₅12"
assert compress_zeros(0.0000012, zeros=5) == "0.0₅12"
assert compress_zeros(0.0000012, zeros=6) == "0.0000012"