Skip to main content

UniCoreFW is a lodash/underscore-style utility toolkit for Python with both functional and chainable APIs

Project description

UniCoreFW logo

Publish to PyPi Unit Tests License Python Version

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()
  • Module-spanning API
    • Functions from array, object, string, function, utils, types, security, template, and crypto are attached dynamically as static methods and as chain methods.
  • 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 cryptography is installed.

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 like UniCoreFW.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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

unicorefw-1.1.5.tar.gz (184.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

unicorefw-1.1.5-py3-none-any.whl (123.4 kB view details)

Uploaded Python 3

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

Hashes for unicorefw-1.1.5.tar.gz
Algorithm Hash digest
SHA256 8c7a645b04c09a023a6ea134b50fa5e38c69cd1cc40c9f045b930c73d78c5f44
MD5 a67cc49697dcf468ff302fac3343a545
BLAKE2b-256 8efa88301bf6c97d092f05a8ad118437e6057343f17c089a3f20b0d69ac1ddc8

See more details on using hashes here.

Provenance

The following attestation bundles were made for unicorefw-1.1.5.tar.gz:

Publisher: release.yml on unicorefw-org/unicorefw-py

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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

Hashes for unicorefw-1.1.5-py3-none-any.whl
Algorithm Hash digest
SHA256 068806dc1edec58acb93edfcefae0d63f03297b5f56ac2a1700b0d065b94fd3b
MD5 aa2111c26d269f301066f0ccc850229c
BLAKE2b-256 75900830e31a2ad61af56b39e8aef8bd2903f072ab68494ddd778e0480035900

See more details on using hashes here.

Provenance

The following attestation bundles were made for unicorefw-1.1.5-py3-none-any.whl:

Publisher: release.yml on unicorefw-org/unicorefw-py

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page