UniCoreFW is a lodash/underscore-style utility toolkit for Python with both functional and chainable APIs
Project description
UniCoreFW
Universal Core Utility Library (Python)
UniCoreFW is a compact, batteries-included utility library that provides chainable and static helper functions across arrays (lists), objects (dicts / nested structures), functions, strings, security utilities, templates, and optional cryptography helpers.
Current version:
1.1.5
Key Capabilities
- Two usage styles
- Static:
UniCoreFW.map([...], fn)/_.map([...], fn) - Chainable:
_(...).map(...).filter(...).value()
- Static:
- Module-spanning API
- Functions from
array,object,string,function,utils,types,security,template, andcryptoare attached dynamically as static methods and as chain methods.
- Functions from
- Security utilities
- Input validation helpers, string sanitization, rate limiting, and audit logging.
- Template engine
<%= var %>interpolation and simple<% if cond %> ... <% endif %>with defensive checks.
- Optional cryptography utilities
- Fernet symmetric encryption if
cryptographyis installed.
- Fernet symmetric encryption if
Installation
From PyPI
pip install unicorefw
Optional dependency (Crypto module)
The unicorefw.crypto module requires cryptography:
pip install cryptography
Project Layout
project_root_dir/
├── unicorefw/
│ ├── __init__.py
│ ├── core.py
│ ├── array.py
│ ├── object.py
│ ├── string.py
│ ├── function.py
│ ├── utils.py
│ ├── types.py
│ ├── security.py
│ ├── template.py
│ ├── crypto.py
│ ├── supporter.py
│ └── db.py # present (import directly as unicorefw.db)
├── examples/
│ ├── sets/
│ ├── functions.py
│ ├── task_manager.py
│ └── underscore.py
└── README.md
Quick Start
from unicorefw import _, UniCoreFW
# Chainable usage
result = (
_([1, 2, 3, 4, 5])
.map(lambda x: x * 2)
.filter(lambda x: x > 5)
.value()
)
print(result) # [6, 8, 10]
# Static usage (either UniCoreFW.* or _.*)
print(UniCoreFW.chunk([1, 2, 3, 4, 5, 6], 2)) # [[1, 2], [3, 4], [5, 6]]
print(_.chunk([1, 2, 3, 4, 5, 6], 2)) # [[1, 2], [3, 4], [5, 6]]
How the API Works
UniCoreFW exposes two main entry points:
UniCoreFW: the primary class providing static methods likeUniCoreFW.method_name(...)._: a convenience factory that returns a UniCoreFWWrapper for chaining:_(collection).map(...).filter(...).value()- Additionally,
_.method_name(...)is available as a static shortcut.
Chaining works by applying functions across UniCoreFW’s modules in a defined order; if a function name exists in a module, it becomes both:
- a chain method on
UniCoreFWWrapper, and - a static method on
UniCoreFW(without overriding earlier modules’ functions when names collide).
Core Modules (What They Provide)
Arrays (unicorefw.array)
List/array utilities: map/reduce/filter/find, chunking, flattening, set-like ops, ordering, etc.
mapped = _.map([1, 2, 3], lambda x: x * 2) # [2, 4, 6]
flattened = _.flatten([1, [2, [3, 4]]]) # [1, 2, 3, 4]
chunked = _.chunk([1, 2, 3, 4, 5, 6], 2) # [[1,2],[3,4],[5,6]]
median = _.find_median_sorted_arrays([1, 3, 5], [2, 4, 6]) # 3.5
Objects (unicorefw.object)
Dictionary and nested-structure helpers (including safe path operations), mapping, selection, and iteration.
extended = _.extend({"a": 1}, {"b": 2}, {"c": 3}) # {"a":1,"b":2,"c":3}
print(_.has({"a": {"b": [10]}}, "a.b.0")) # True
Strings (unicorefw.string)
String transformation and inspection utilities (case transforms, regex helpers, whitespace normalization, etc.).
from unicorefw import humanize, pascal_case, normalize_whitespace
print(humanize("hello_world_example")) # "Hello world example"
print(pascal_case("hello world")) # "HelloWorld"
print(normalize_whitespace(" a b\nc\t")) # "a b c"
Functions (unicorefw.function)
Function helpers such as debounce, once, composition/flow utilities, partial/curry variants, etc.
from unicorefw import once, debounce
only_once = once(lambda: "called")
print(only_once()) # "called"
print(only_once()) # None
Utilities (unicorefw.utils)
General helpers: unique_id, now, memoize, compress/decompress, etc.
print(_.unique_id("req-")) # e.g. "req-1"
print(_.compress("aaabbc")) # "3a2b1c"
print(_.decompress("3a2b1c")) # "aaabbc"
Types (unicorefw.types)
Type predicates and helpers like is_string, is_number, is_empty, deep equality, etc.
from unicorefw import is_string, is_empty
print(is_string("x")) # True
print(is_empty({})) # True
Security (unicorefw.security)
Input validation, sanitization, rate limiting, and audit logging primitives.
from unicorefw.security import RateLimiter, AuditLogger, validate_type, sanitize_string
validate_type("test", str, "param")
safe = sanitize_string(" abc ", max_length=10, allowed_chars="a-zA-Z0-9")
print(safe) # "abc"
with RateLimiter(max_calls=100, time_window=60):
pass
with AuditLogger(log_file="security.jsonl") as logger:
logger.log("LOGIN", {"user_id": "42", "result": "success"})
Audit files are UTF-8 JSON Lines, owner-only on POSIX, and refuse symbolic-link
destinations where the operating system supports O_NOFOLLOW. Do not put
credentials, tokens, or other secrets in audit details.
Templates (unicorefw.template)
A small text-template processor plus an HTML text-node renderer:
from unicorefw.template import html_template, template
print(template("Hello, <%= name %>!", {"name": "Alice"})) # "Hello, Alice!"
print(html_template("<p><%= value %></p>", {"value": "<b>Alice</b>"}))
# <p><b>Alice</b></p>
template() produces plain text and does not HTML-escape values. html_template()
accepts untrusted values only in HTML text nodes; it rejects expressions inside
attributes, tags, scripts, and styles. Template source must always be trusted.
Caller-controlled expansion uses fixed budgets:
from unicorefw.security import ResourceLimitError
from unicorefw.template import TemplateLimits, html_template
from unicorefw.utils import decompress
limits = TemplateLimits(
max_tokens=200,
max_nesting_depth=8,
max_output_length=100_000,
)
rendered = html_template("<p><%= value %></p>", context, limits=limits)
try:
text = decompress(
encoded_text,
max_output_length=250_000,
max_compression_ratio=20,
)
except ResourceLimitError:
reject_input()
ResourceLimitError reports an exhausted runtime budget. Invalid settings raise
InputValidationError, including values above the library hard ceilings.
Other process-local helpers are bounded by default:
from unicorefw.function import debounce
from unicorefw.object import set_
from unicorefw.regex_policy import RegexLimits
from unicorefw.string import regex_test
from unicorefw.supporter import PathLimits
from unicorefw.utils import memoize
cached_lookup = memoize(
lookup,
max_entries=256,
max_weight_bytes=16 * 1024 * 1024,
ttl_seconds=300,
)
search_changed = debounce(run_search, 250, max_pending_timers=8)
set_(record, "items[9].name", "safe", limits=PathLimits(max_list_length=100))
matched = regex_test(
user_text,
r"[A-Za-z0-9_-]+",
limits=RegexLimits(max_input_length=2_000),
)
The standard-library regex engine has no portable timeout. Caller-supplied
patterns therefore use a conservative default policy that rejects
backreferences, special groups, and nested or adjacent repetition. Use
unsafe_raw_regex() only for reviewed, developer-controlled patterns; input
length remains capped when the trusted wrapper is used.
Crypto (unicorefw.crypto) (optional)
Fernet symmetric encryption utilities (requires cryptography):
from unicorefw.crypto import generate_key, encrypt_string, decrypt_string
key = generate_key()
token = encrypt_string("secret", key)
print(decrypt_string(token, key)) # "secret"
Database utilities (unicorefw.db) (module present; import directly)
The repository includes a unicorefw.db module for database helpers (multi-engine, pooling, migrations, import/export). Import it explicitly:
from unicorefw.db import CacheManager, Database
db = Database(engine="sqlite", database=":memory:")
cache = CacheManager(db, max_entries=256, max_weight_bytes=16 * 1024 * 1024)
CacheManager uses monotonic TTL expiry, LRU entry and estimated-weight limits,
and isolated copies of cached query results. Call cache.clear() after writes
that may invalidate a cached query; cache invalidation is not automatic.
Build dynamic queries from validated identifiers and bound values. Complex SQL requires an explicit trust marker:
from unicorefw.db import QueryBuilder, unsafe_raw_sql
rows = (
QueryBuilder(db)
.select("id", "name")
.from_table("users")
.where("active = ?", True)
.order_by("id", "DESC")
.limit(100)
.execute()
)
# Only reviewed, developer-controlled SQL belongs in this wrapper.
trusted_report = unsafe_raw_sql(
"SELECT department, COUNT(*) AS total FROM users GROUP BY department"
)
Exporter source strings represent table names. Pass a reviewed query through
unsafe_raw_sql(). CSV and Excel exports neutralize formula-looking text by
default; spreadsheet_safe=False opts out and preserves exact strings. HTML
export escapes headers and cells. Custom CSS requires unsafe_raw_css().
Importers cap bytes, rows, and columns. Excel import also caps ZIP expansion and member count. JSON defaults to 64 MiB, 100,000 rows, and 1,000 columns:
from unicorefw.db import DataImporter
inserted = DataImporter(db).from_json(
"users.json",
"users",
max_bytes=8 * 1024 * 1024,
max_rows=25_000,
max_columns=100,
)
CSV import counts bytes while reading and rolls its transaction back when a row limit expires. Configure limits from trusted application policy, not request parameters.
SQLite backup and restore use atomic owner-only files on POSIX. Restore builds an isolated in-memory database before it changes the target.
from unicorefw.db import BackupRestore, Database
source = Database(engine="sqlite", database="app.db")
backup_path = BackupRestore(source).backup(
"app-backup.sql", format="sql", compress=True
)
source.close()
# The safe default requires an empty target database.
target = Database(engine="sqlite", database="restored.db")
BackupRestore(target).restore(backup_path, format="sql")
target.close()
Replacing a populated target requires both flags:
target = Database(engine="sqlite", database="existing.db")
BackupRestore(target).restore(
backup_path,
format="sql",
clear_existing=True,
allow_destructive=True,
)
target.close()
Treat SQL backups as trusted executable schema artifacts. Restore denies SQLite file attachment and writable-schema pragmas, but restored triggers and views can still contain executable database logic. The default restore limits are 512 MiB after decompression and a 200:1 gzip expansion ratio. PostgreSQL, MySQL, MongoDB, and Redis backups require their native backup tools.
Changelog Notes
Older changelog entries may not include newer internal changes. Prefer GitHub releases/tags for authoritative history.
License
BSD 3-Clause License. See LICENSE.
Contributing
PRs are welcome. Please include tests where appropriate and keep changes consistent with the library’s defensive, security-oriented design.
Run the branch-coverage gate before submitting changes:
python -m pytest tests --cov=unicorefw --cov-branch \
--cov-report=term-missing --cov-report=xml --cov-report=json \
--cov-fail-under=76
CI rejects regressions below the current 76% ratchet. The project target is 100% statement and branch coverage; maintainers raise the ratchet after each coverage slice.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file unicorefw-1.1.5.tar.gz.
File metadata
- Download URL: unicorefw-1.1.5.tar.gz
- Upload date:
- Size: 184.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8c7a645b04c09a023a6ea134b50fa5e38c69cd1cc40c9f045b930c73d78c5f44
|
|
| MD5 |
a67cc49697dcf468ff302fac3343a545
|
|
| BLAKE2b-256 |
8efa88301bf6c97d092f05a8ad118437e6057343f17c089a3f20b0d69ac1ddc8
|
Provenance
The following attestation bundles were made for unicorefw-1.1.5.tar.gz:
Publisher:
release.yml on unicorefw-org/unicorefw-py
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
unicorefw-1.1.5.tar.gz -
Subject digest:
8c7a645b04c09a023a6ea134b50fa5e38c69cd1cc40c9f045b930c73d78c5f44 - Sigstore transparency entry: 2216117935
- Sigstore integration time:
-
Permalink:
unicorefw-org/unicorefw-py@c783123ffbc4ac3158be2443da1ef34a402f4fd2 -
Branch / Tag:
refs/tags/v1.1.5 - Owner: https://github.com/unicorefw-org
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@c783123ffbc4ac3158be2443da1ef34a402f4fd2 -
Trigger Event:
push
-
Statement type:
File details
Details for the file unicorefw-1.1.5-py3-none-any.whl.
File metadata
- Download URL: unicorefw-1.1.5-py3-none-any.whl
- Upload date:
- Size: 123.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
068806dc1edec58acb93edfcefae0d63f03297b5f56ac2a1700b0d065b94fd3b
|
|
| MD5 |
aa2111c26d269f301066f0ccc850229c
|
|
| BLAKE2b-256 |
75900830e31a2ad61af56b39e8aef8bd2903f072ab68494ddd778e0480035900
|
Provenance
The following attestation bundles were made for unicorefw-1.1.5-py3-none-any.whl:
Publisher:
release.yml on unicorefw-org/unicorefw-py
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
unicorefw-1.1.5-py3-none-any.whl -
Subject digest:
068806dc1edec58acb93edfcefae0d63f03297b5f56ac2a1700b0d065b94fd3b - Sigstore transparency entry: 2216117955
- Sigstore integration time:
-
Permalink:
unicorefw-org/unicorefw-py@c783123ffbc4ac3158be2443da1ef34a402f4fd2 -
Branch / Tag:
refs/tags/v1.1.5 - Owner: https://github.com/unicorefw-org
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@c783123ffbc4ac3158be2443da1ef34a402f4fd2 -
Trigger Event:
push
-
Statement type: