json-diff-tool / utils.py
Amanda Torres
initial commit
e197abb
raw
history blame
1.83 kB
import hashlib
import hmac
import re
import secrets
import string
from datetime import datetime, timezone
from typing import Any, Optional
EMAIL_RE = re.compile(r'^[\w.+-]+@[\w-]+\.[\w.-]+$')
def hash_password(pw: str, salt: Optional[str] = None) -> tuple[str, str]:
if salt is None:
salt = secrets.token_hex(16)
digest = hashlib.pbkdf2_hmac("sha256", pw.encode(), salt.encode(), 200_000)
return digest.hex(), salt
def verify_password(pw: str, digest: str, salt: str) -> bool:
computed, _ = hash_password(pw, salt)
return hmac.compare_digest(computed, digest)
def generate_token(n: int = 32) -> str:
return "".join(secrets.choice(string.ascii_letters + string.digits) for _ in range(n))
def slugify(text: str, max_len: int = 60) -> str:
text = text.lower().replace(" ", "-")
text = re.sub(r"[^\w-]", "", text)
return text[:max_len].strip("-")
def truncate(text: str, n: int = 120) -> str:
return text if len(text) <= n else text[:n - 3] + "..."
def utcnow() -> str:
return datetime.now(timezone.utc).isoformat()
def parse_bool(v: Any) -> bool:
if isinstance(v, bool):
return v
return str(v).strip().lower() in ("1", "true", "yes", "on")
def chunk(lst: list, size: int) -> list[list]:
return [lst[i:i + size] for i in range(0, len(lst), size)]
def deep_merge(base: dict, override: dict) -> dict:
out = dict(base)
for k, v in override.items():
if k in out and isinstance(out[k], dict) and isinstance(v, dict):
out[k] = deep_merge(out[k], v)
else:
out[k] = v
return out
def flatten(nested: list) -> list:
result = []
for item in nested:
if isinstance(item, list):
result.extend(flatten(item))
else:
result.append(item)
return result