Technical Info

Currently, suitkaise is version 0.4.14.

suitkaise supports Python 3.11 and above.

It has no dependencies outside of the Python standard library.

README

Suitkaise

Write Python at hacker-level speeds.

(pronounced exactly like the word suitcase)

All files in this repository are licensed under the Apache License 2.0, including source code, examples, documentation, tests, site content code, and everything else.

Installation

pip install suitkaise

Info

Explicitly supported Python versions: 3.11 and above

Currently, suitkaise is version 0.4.14.

suitkaise contains the following modules:

Documentation

All documentation is available for download.

CLI (downloads to project root, cwd must be within project root):

suitkaise docs

Python:

from suitkaise import docs

# download to project root
docs.download()

# download to a specific path within your project
docs.download("path/within/project")

To place docs outside your project root, use the Permission context manager.

from suitkaise import docs

with docs.Permission():
    docs.download("/Users/joe/Documents")

You can also view more at suitkaise.info.

Quick Start

Parallel processing with shared state

from suitkaise.processing import Share, Pool, Skprocess
import logging

share = Share()
share.counter = 0
share.results = []
share.log = logging.getLogger("worker")

class Worker(Skprocess):
    def __init__(self, share, item):
        self.share = share
        self.item = item

    def __run__(self):
        result = self.item * 2
        self.share.results.append(result)
        self.share.counter += 1
        self.share.log.info(f"done: {result}")

pool = Pool(workers=4)
pool.star().map(Worker, [(share, x) for x in range(20)])

print(share.counter)         # 20
print(len(share.results))    # 20
print(share.log.handlers)    # still works

Serialize anything

from suitkaise import cucumber

data = cucumber.serialize(any_object)
restored = cucumber.deserialize(data)

Time anything

from suitkaise.timing import timethis

@timethis()
def my_function():
    do_work()

my_function()
print(my_function.timer.mean)

Add retry, timeout, background execution to any function

from suitkaise import sk

@sk
def fetch(url):
    return requests.get(url).json()

data = fetch.retry(3).timeout(5.0)("https://api.example.com")

Cross-platform paths

from suitkaise.paths import Skpath

path = Skpath("data/file.txt")
print(path.rp)  # "data/file.txt" — same on every machine, every OS

Circuit breakers

from suitkaise import Circuit

circuit = Circuit(num_shorts_to_trip=5, sleep_time_after_trip=1.0)

for request in requests:
    try:
        process(request)
    except ServiceError:
        circuit.short()

For more, see the full documentation at suitkaise.info or download the docs with suitkaise docs in your terminal after installation.

License

Apache License 2.0

Copyright 2025-2026 Casey Eddings

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.

You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

Full license text
                             Apache License
                       Version 2.0, January 2004
                    http://www.apache.org/licenses/

TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

1. Definitions.

   "License" shall mean the terms and conditions for use, reproduction,
   and distribution as defined by Sections 1 through 9 of this document.

   "Licensor" shall mean the copyright owner or entity authorized by
   the copyright owner that is granting the License.

   "Legal Entity" shall mean the union of the acting entity and all
   other entities that control, are controlled by, or are under common
   control with that entity.

   "You" (or "Your") shall mean an individual or Legal Entity
   exercising permissions granted by this License.

   "Source" form shall mean the preferred form for making modifications.

   "Object" form shall mean any form resulting from mechanical
   transformation or translation of a Source form.

   "Work" shall mean the work of authorship, whether in Source or
   Object form, made available under the License.

   "Derivative Works" shall mean any work that is based on (or derived
   from) the Work.

   "Contribution" shall mean any work of authorship intentionally
   submitted to the Licensor for inclusion in the Work.

   "Contributor" shall mean Licensor and any individual or Legal Entity
   on behalf of whom a Contribution has been received by Licensor and
   subsequently incorporated within the Work.

2. Grant of Copyright License.

3. Grant of Patent License.

4. Redistribution.

5. Submission of Contributions.

6. Trademarks.

7. Disclaimer of Warranty. THE WORK IS PROVIDED ON AN "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND.

8. Limitation of Liability.

9. Accepting Warranty or Additional Liability.

END OF TERMS AND CONDITIONS

Copyright 2025-2026 Casey Eddings

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Changelog

All notable changes to this project will be documented in this file.

The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.

Changelog is maintained from version 0.3.0 forward.

[0.4.14] - 2026-02-23

Fixed

  • Share counter-registry manager locks now use bounded acquisition with recovery/retry, preventing worker hangs on stale manager lock proxies under multiprocessing spawn workloads.
  • Skprocess IPC proxy cleanup is now best-effort during object teardown to reduce intermittent Bad file descriptor warnings from multiprocessing connection finalizers.
  • Restored one-time post-install welcome display through the package import path (still gated by interactive terminal + version marker behavior).
[0.4.13] - 2026-02-23

Fixed

  • Share manager counter retry now recovers stale manager lock handles that surface as TypeError: 'NoneType' object cannot be interpreted as an integer in worker write paths.
  • Restored correct cucumber handler detection in Share so handler-backed objects (like sqlite3.Connection) resolve to reconnectors instead of being incorrectly proxied.
  • Normalized supported-type name matching in processing tests to avoid false failures from case-only differences (e.g., User-defined vs user-defined).
  • Share.__serialize__ now caches live coordinator-state bytes so repeated Pool payload serialization does not repickle manager proxies on every item (spawn-stability regression guard).
  • Added atomic operator-intent support for common read-modify-reassign forms on shared mutable objects (share.lst = share.lst + [...], share.s = share.s | {...}, share.d = share.d | {...}) to preserve regular-Python ergonomics under concurrency.
  • Share.__deserialize__ now caches live coordinator-bound Share instances per worker process, preventing repeated manager-proxy reconstruction for every mapped task item.
[0.4.12] - 2026-02-23

Fixed

  • Share primitive assignments now behave consistently in multiprocessing for plain Python types (int, float, bool, str, bytes, tuple, frozenset, complex), including atomic augmented operations (+=, -=, *=, etc.).
  • Added primitive read-your-own-write behavior so immediate reads after augmented assignment reflect the worker's just-applied value.
  • Prevented stale Share snapshot restores in client mode from overwriting active coordinator state.
  • Prevented logging.Logger proxy deadlocks in shared objects by treating logger handlers as non-proxied.
  • Fixed cucumber deserializer cleanup guard for reconstruction path underflow (pop from empty list).
  • CLI welcome message no longer triggers from package import path; it now runs from CLI startup and is still shown once per installed version.
[0.4.7b0] - 2026-02-11

Fixed

  • Regression fix (Share + Pool ETL workloads): hardened manager-proxy lifecycle recovery for Share write paths that could fail with OSError: handle is closed in long-running Pool.star().map(...) workers.
[0.4.7b0] - Additional fixes

Fixed

  • Regression fix (Pool + TimeThis): Sktimer is now fork-safe in subprocess workers.
  • Regression fix (Share + BreakingCircuit): Circuit and BreakingCircuit now serialize without carrying live threading.RLock internals.
[0.4.5b0] - 2026-02-11

Fixed

  • Memory leak: _Coordinator.stop() skipped SharedMemory cleanup when called on an already-stopped coordinator.
  • Memory leak: Share._META_CACHE used a plain dict, preventing garbage collection. Changed to weakref.WeakKeyDictionary.
  • Memory leak: Sktimer._sessions grew unboundedly as threads were created and destroyed.
  • Memory leak: Pool worker multiprocessing.Queue resources were not cleaned up after worker timeout/termination.
  • Memory leak: _AtomicCounterRegistry.remove_object() only unlinked SharedMemory segments for the owning process.
  • Memory leak: _Coordinator.destroy() / __del__ split for restartable vs. permanent shutdown.
  • Thread-safety: cucumber.serialize() and cucumber.deserialize() replaced module-level singletons with per-thread instances via threading.local().
[0.4.4b0] - 2026-02-10

Fixed

  • Python 3.12/3.13 compatibility: TemporaryFileHandler no longer crashes on _TemporaryFileCloser objects.
  • Share proxy false "stopped" warnings in child processes.
  • Share proxy broke user class methods due to falsy empty-list check.
  • Shared memory leaks at shutdown.
  • Sktimer.percentile(), get_time(), get_statistics() returned None through Share proxy.
  • TimeThis recorded partial measurements when exceptions were raised.
  • NamedTuples were serialized as plain tuples, losing field names.
  • @sk modifier methods bypassed outer decorators like @timethis.
  • Skpath comparison operators (<, >, <=, >=) now work correctly.
  • Share proxy returned None for method calls on plain user classes (no @sk).
  • @sk class .asynced() non-blocking methods are now uniformly awaitable.
  • cucumber deserializer guard for missing placeholder in registry.

Added

  • Builtin mutable type proxy support: list, set, dict assigned to Share are now proxied.
  • Dunder protocol methods on _ObjectProxy: __len__, __iter__, __contains__, __bool__, __getitem__, __setitem__, __delitem__, __str__.
  • Sktimer blocks timing methods when used through Share. Use add_time(elapsed) instead.
  • Circuit is now disallowed in Share. Use BreakingCircuit instead.
  • BreakingCircuit short() and trip() skip sleep when called through Share.

Changed

  • Test coverage increased from 80% to 82%.
  • CI matrix expanded to 9 jobs: 3 OSes × 3 Python versions (3.11, 3.12, 3.13).
[0.4.0b0] - 2026-02-07

Added

Processing:

  • Pool.unordered_map() — returns a list in completion order.
  • Skprocess.run() now supports .timeout(), .background(), and .asynced() modifiers.
  • processing.Pipe for inter-process communication.
  • @autoreconnect decorator to automatically reconnect resources after deserialization.

Cucumber:

  • Expanded blocking call detection for common sync libraries.
  • Best-effort socket auto-reconnect.
  • Base Reconnector class with consistent .reconnect() API.
  • Database-specific reconnector classes for Postgres, MySQL, MongoDB, Redis, and more.
  • cucumber.reconnect_all(obj, **kwargs) for recursive reconnection.
  • Full auth/credential support in database reconnectors.

Changed

  • License updated to Apache License 2.0.
  • Processing module updated to correctly work on Windows.
  • Streamlined all public API; tested all examples in API docstrings.
[0.3.0] - 2026-01-16 — 2026-01-27

Added

  • Initial release contents for all modules: cucumber, circuits, processing, paths, sk, timing.
  • Initial type stub files (.pyi) for IDE autocompletion.
  • py.typed marker for PEP 561 compliance.
  • suitkaise CLI entrypoint with version, info, modules, and docs commands.
  • CI workflow for running the full test suite with coverage reporting.

Performance

  • FileIO serialization: >2000µs → 45µs (44x faster)
  • BufferedReader serialization: >2000µs → 85µs (23x faster)
  • BufferedWriter serialization: >2000µs → 50µs (40x faster)
  • FrameType serialization: >2500µs → 12µs (208x faster)
CLI Commands

Run suitkaise from the terminal after installation. If no command is provided, the help menu is printed.

suitkaise --version

Print the current version of suitkaise.

$ suitkaise --version
0.4.14

suitkaise info

Print version, module list, and supported Python versions.

$ suitkaise info

  suitkaise 0.4.14

  Website:         https://suitkaise.info
  Download docs:   suitkaise docs

suitkaise modules

List all available modules, one per line.

$ suitkaise modules
timing
paths
circuits
cucumber
processing
sk

suitkaise docs

Download the full suitkaise documentation to your project root. Your current working directory must be inside the project root.

$ suitkaise docs

You can also download docs from Python:

from suitkaise import docs

docs.download()

# or to a specific path within your project
docs.download("path/within/project")

To place docs outside your project root, use the Permission context manager:

from suitkaise import docs

with docs.Permission():
    docs.download("/Users/joe/Documents")
Modules
cucumber

Serialization engine that eliminates PicklingErrors by handling types that pickle, cloudpickle, and dill cannot — threads, queues, sockets, generators, database connections, and more. Provides live resource reconnection and supports classes defined in __main__ for multiprocessing.

from suitkaise.cucumber import (
    serialize,
    deserialize,
    serialize_ir,
    reconnect_all,
    ir_to_jsonable,
    ir_to_json,
    to_jsonable,
    to_json,
    SerializationError,
    DeserializationError,
)

Or from the top level:

from suitkaise import serialize, deserialize, reconnect_all
circuits

Circuit breaker module for managing failures with exponential backoff, jitter, and thread-safe coordination. Circuit auto-resets after sleeping. BreakingCircuit stays broken until manually reset. Works with Share for cross-process failure coordination.

from suitkaise.circuits import (
    Circuit,
    BreakingCircuit,
)
processing

Parallel processing module with class-based processes (Skprocess), easy shared state (Share), and automatic serialization using cucumber. Supports lifecycle hooks, automatic retries, timeouts, and inter-process communication via Pipe.

from suitkaise.processing import (
    Skprocess,
    Pool,
    Share,
    Pipe,
    autoreconnect,
    ProcessTimers,
    ProcessError,
    PreRunError,
    RunError,
    PostRunError,
    OnFinishError,
    ResultError,
    ErrorHandlerError,
    ProcessTimeoutError,
    ResultTimeoutError,
)
paths

Cross-platform path handling with project-relative paths. Automatically detects project root, normalizes separators, and provides @autopath for automatic type conversion. Drop-in upgrade from pathlib.Path.

from suitkaise.paths import (
    Skpath,
    AnyPath,
    autopath,
    CustomRoot,
    set_custom_root,
    get_custom_root,
    clear_custom_root,
    get_project_root,
    get_caller_path,
    get_current_dir,
    get_cwd,
    get_module_path,
    get_id,
    get_project_paths,
    get_project_structure,
    get_formatted_project_tree,
    is_valid_filename,
    streamline_path,
    PathDetectionError,
    NotAFileError,
)
sk

Modifier system that adds retry, timeout, background execution, rate limiting, and async support to any function or class. Modifiers are applied at the call site, not the definition.

from suitkaise.sk import (
    sk,
    blocking,
    SkModifierError,
    FunctionTimeoutError,
)
timing

Performance timing with deep statistics (mean, median, stdev, percentiles) and thread-safe measurement. Use @timethis, TimeThis, or Sktimer directly. Works with Share for cross-process aggregation.

from suitkaise.timing import (
    time,
    sleep,
    elapsed,
    Sktimer,
    TimeThis,
    timethis,
    clear_global_timers,
)