Skip to main content

helpers

Version: 20.1.0

wexample-helpers is a Python utility library for developers who want a consistent, typed foundation across their projects. It ships pure-function helpers covering strings, dicts, arrays, files, paths, shell commands, JSON, HTML, Jinja, ANSI, CLI, Docker, and more, alongside a @base_class decorator (built on attrs) that enforces typed field visibility through Field, PrivateField, and ProtectedField descriptors. The package stands alone or as the base layer of the broader Wexample suite.

Table of Contents

Installation

pip install wexample-helpers

Requires Python >=3.10.

Quickstart

Install from PyPI:

pip install wexample-helpers

Import and call a helper — here, converting any string to snake_case regardless of its original format:

from wexample_helpers.helper.string import string_to_snake_case

print(string_to_snake_case("MyClassName"))
# my_class_name

The same normalisation engine powers every other case converter. Pass a target format name to string_convert_case instead of calling a specific function:

from wexample_helpers.helper.string import string_convert_case

print(string_convert_case("my-class-name", "pascal"))
# MyClassName

Valid target names are snake, kebab, camel, pascal, constant, title, dot, and path.

For dict work, dict_merge recurses into nested dicts rather than overwriting them:

from wexample_helpers.helper.dict import dict_merge

result = dict_merge({"a": 1, "b": {"x": 10}}, {"b": {"y": 20}, "c": 3})
# {"a": 1, "b": {"x": 10, "y": 20}, "c": 3}

Tests

This project uses pytest for testing and pytest-cov for code coverage analysis.

Installation

First, install the required testing dependencies:

.venv/bin/python -m pip install pytest pytest-cov

Basic Usage

Run all tests with coverage:

.venv/bin/python -m pytest --cov --cov-report=html

Common Commands

# Run tests with coverage for a specific module
.venv/bin/python -m pytest --cov=your_module

# Show which lines are not covered
.venv/bin/python -m pytest --cov=your_module --cov-report=term-missing

# Generate an HTML coverage report
.venv/bin/python -m pytest --cov=your_module --cov-report=html

# Combine terminal and HTML reports
.venv/bin/python -m pytest --cov=your_module --cov-report=term-missing --cov-report=html

# Run specific test file with coverage
.venv/bin/python -m pytest tests/test_file.py --cov=your_module --cov-report=term-missing

Viewing HTML Reports

After generating an HTML report, open htmlcov/index.html in your browser to view detailed line-by-line coverage information.

Coverage Threshold

To enforce a minimum coverage percentage:

.venv/bin/python -m pytest --cov=your_module --cov-fail-under=80

This will cause the test suite to fail if coverage drops below 80%.

Architecture

wexample-helpers is a pure Python library that ships two things: a collection of stateless helper modules, and a class-building system that enforces typed field visibility at definition time. Every concrete class the library defines follows the same pattern; the helpers stand independently and carry no class-level state.

Package layout

src/wexample_helpers/
├── decorator/        # @base_class — thin attrs.define wrapper
├── classes/          # BaseClass, field system, class-level mixins
│   └── mixin/        # opt-in behaviours (logging, two-step init, serialization …)
├── common/
│   ├── debug/        # DebugDump, DebugDumpClass, DebugBreakpoint
│   └── exception/    # ExceptionFrame, TraceCollector, TraceFormatter, ExceptionHandler
├── exception/        # UndefinedException and concrete exception classes
│   └── mixin/
├── service/          # Registry, SingletonRegistry, SharedRegistry, Registrable
│   └── mixin/        # RegistryContainerMixin
├── helper/           # One module per domain — pure functions, no shared state
├── validator/        # AbstractValidator, RegexValidator, RangeValidator
├── enums/            # DebugPathStyle, FieldVisibility, ErrorTruncateRules
├── const/            # Type aliases, ANSI codes, terminal constants
├── mixin/            # Standalone mixins (WithEntrypointPathMixin)
└── testing/          # Fixture classes and pytest plugin
    └── plugin/

The @base_class decorator

src/wexample_helpers/decorator/base_class.py wraps attrs.define(kw_only=True):

def base_class(_cls=None, *, slots=False):
    def wrap(cls):
        return attrs.define(kw_only=True, slots=slots)(cls)
    ...

Every class in the library that carries fields carries this decorator. It makes construction keyword-only and hands attribute management to attrs.

BaseClass and field validation

src/wexample_helpers/classes/base_class.py is the common root for library classes. Its __init_subclass__ hook fires at class definition time and rejects any non-uppercase, non-method attribute that is not a BaseField instance:

raise TypeError(
    f"Property '{name}' in class '{cls.__name__}' must inherit from BaseField. "
    f"Use Field(), PrivateField(), or ProtectedField() instead of raw attrs.field()"
)

A typo or bare attrs.field() call is therefore a hard error before the first object is constructed.

Field system

src/wexample_helpers/classes/base_field.py defines BaseField, which wraps an attrs field with a description, optional validator, and visibility metadata. Three concrete subclasses live in their own files:

  • src/wexample_helpers/classes/field.py — Field / public_field(): no prefix constraint.
  • src/wexample_helpers/classes/private_field.py — PrivateField / private_field(): name must start with _, init=False by default.
  • src/wexample_helpers/classes/protected_field.py — ProtectedField / protected_field(): name must start with _.

Each exposes a factory function (public_field(description, ...)) that returns an attrs field. The BaseField.to_attrs_field() method sets metadata["field_type"] to the concrete class name so the BaseClass validator can read it back from attrs field descriptors.

Helper modules

src/wexample_helpers/helper contains one module per domain. Each exports free functions with no shared state. The full set at the time of writing: ansi, args, array, classes, cli, debug, dict, directory, docker, error, file, html, jinja, json, module, parallel, path, polyfill, python, shell, string, system, trace, type, user, variable, version, plus the attempt-manager helpers (see below).

src/wexample_helpers/helper/parallel.py provides parallel_map and parallel_for_each backed by ThreadPoolExecutor, intended for I/O-bound work. Single-item inputs run inline.

src/wexample_helpers/helper/shell.py provides shell_run, shell_run_async, and shell_stream_async. All three resolve the command through shlex, spawn the process in a fresh process group (start_new_session=True), and return or raise ShellCommandFailedException on non-zero exit.

Debug and trace pipeline

Calling debug_trace() in src/wexample_helpers/helper/debug.py delegates through src/wexample_helpers/helper/trace.py:

  1. trace_get_frames() calls TraceCollector.from_stack() in src/wexample_helpers/common/exception/collector.py, which walks inspect.stack() and builds a list of ExceptionFrame objects.
  2. ExceptionFrame (src/wexample_helpers/common/exception/frame.py) is a frozen dataclass that holds filename, lineno, function, code, and a DebugPathStyle controlling how the path is rendered.
  3. trace_format() passes the frame list to TraceFormatter.format() in src/wexample_helpers/common/exception/formatter.py, which filters internal frames and returns a printable string.

Exception formatting takes the same path with a different entry point: ExceptionHandler.format_exception(err) in src/wexample_helpers/common/exception/handler.py calls TraceCollector.from_traceback(), then optionally truncates frames according to the rules in ErrorTruncateRules before calling TraceFormatter.format().

Exception system

src/wexample_helpers/exception/undefined_exception.py is the base exception class. It is an attrs class (@base_class) that also inherits from Exception. Fields include message, cause, previous, suggestions, data, and an auto-generated exception_id. Subclasses override _build_message() to derive their message from their own fields; render_message() calls it lazily, so field declaration order never matters.

collect_data() merges the explicit data dict with every public field declared by the subclass, giving a complete structured payload without hand-building a data={...} dict in each subclass.

Registry system

src/wexample_helpers/service/registrable.py defines the Registrable protocol: items expose get_registry_key(), dependencies(), init_sync(), and init_async().

src/wexample_helpers/service/registry.py is the base generic registry. register(item) auto-derives the key by probing get_registry_key(), then get_snake_short_class_name(), then the class name. get(key) returns None or raises KeyError when _fail_if_missing is set.

src/wexample_helpers/service/singleton_registry.py stores classes rather than instances. init_all_sync() and init_all_async() instantiate them in topological order derived from Registrable.dependencies(). The async variant gathers init_async() calls within each independent layer.

src/wexample_helpers/service/shared_registry.py adds a class-level .shared() class method that returns a lazily created, per-subclass singleton. reset_shared() drops it, which is useful in tests.

src/wexample_helpers/service/mixin/registry_container_mixin.py provides RegistryContainerMixin, which an object can inherit to host multiple named registries internally.

Attempt managers

src/wexample_helpers/helper/abstract_attempt_manager.py defines AbstractAttemptManager, a generic retry loop. Subclasses implement _attempt(attempt) → AttemptOutcome and _handle_exhaustion(). The loop applies exponential backoff (backoff_base_seconds ** attempt) unless delay_seconds_callback overrides it.

Two concrete subclasses live in the same helper/ directory:

  • src/wexample_helpers/helper/polling_callback_manager.py — PollingCallbackManager: retries until the callback returns a non-None value; raises TimeoutError on exhaustion.
  • src/wexample_helpers/helper/retryable_callback_manager.py — RetryableCallbackManager: retries on any exception when should_retry_callback approves; re-raises the last exception on exhaustion.

Validator system

src/wexample_helpers/validator/abstract_validator.py defines AbstractValidator as an attrs class with an optional error_message. Concrete validators implement validate(value) → bool and _get_default_error_message(value) → str. Two ship with the library: RegexValidator (one or more re patterns, OR logic) and RangeValidator (inclusive numeric bounds).

Testing support

src/wexample_helpers/testing/plugin/runtest_makereport.py is a pytest hook that replaces the default failure repr with output from ExceptionHandler.format_exception(). It is registered automatically when the package is installed with pytest enabled and the plugin is activated.

testing/classes/ and testing/mixin/ contain concrete classes used by the test suite to exercise attrs inheritance, pydantic integration, multiple-inheritance MRO, and circular forward references. They carry no production logic.

Integration in the Suite

This package is part of the Wexample Suite — a collection of high-quality, modular tools designed to work seamlessly together across multiple languages and environments.

The suite includes packages for configuration management, file handling, prompts, and more. Each package can be used independently or as part of the integrated suite.

Visit the Wexample Suite documentation for the complete package ecosystem.

Dependencies

  • attrs: >=23.1.0
  • cattrs: >=23.1.0
  • jinja2: >=3.0.0

Versioning & Compatibility Policy

Wexample packages follow Semantic Versioning (SemVer):

  • MAJOR: Breaking changes
  • MINOR: New features, backward compatible
  • PATCH: Bug fixes, backward compatible

We maintain backward compatibility within major versions and provide clear migration guides for breaking changes.

License

This project is licensed under the MIT License - see the LICENSE file for details.

Free to use in both personal and commercial projects.

About us

Wexample stands as a cornerstone of the digital ecosystem — a collective of seasoned engineers, researchers, and creators driven by a relentless pursuit of technological excellence. More than a media platform, it has grown into a vibrant community where innovation meets craftsmanship, and where every line of code reflects a commitment to clarity, durability, and shared intelligence.

This packages suite embodies this spirit. Trusted by professionals and enthusiasts alike, it delivers a consistent, high-quality foundation for modern development — open, elegant, and battle-tested. Its reputation is built on years of collaboration, refinement, and rigorous attention to detail, making it a natural choice for those who demand both robustness and beauty in their tools.

Wexample cultivates a culture of mastery. Each package, each contribution carries the mark of a community that values precision, ethics, and innovation — a community proud to shape the future of digital craftsmanship.

Known Limitations & Roadmap

Current limitations and planned features are tracked in the GitHub issues.

See the project roadmap for upcoming features and improvements.

Status & Compatibility

Maturity: Production-ready

Python Support: >=3.10

OS Support: Linux, macOS, Windows

Status: Actively maintained

Migration Notes

When upgrading between major versions, refer to the migration guides in the documentation.

Breaking changes are clearly documented with upgrade paths and examples.

Metadata

Release files for wexample-helpers 20.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for wexample-helpers 20.1.0
File Size Uploaded
wexample_helpers-20.1.0.tar.gz 100.7 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for wexample-helpers 20.1.0
File Interpreter ABI Platform
wexample_helpers-20.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 218.4 kB

Release files / wexample_helpers-20.1.0.tar.gz

Download URL wexample_helpers-20.1.0.tar.gz
Size 100.7 kB
Tags Source
SHA-256 checksum
How to use checksums
3b65befecb5defed159db85801de81b3802e591f8b51f7acf53e71ff14ee7c2a
BLAKE2b-256 checksum
How to use checksums
57108c19788bdbe62d8af2091cd2f046f38d0ab15cde0f48f2da21992824a649
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via pdm/2.25.9 CPython/3.12.3 Linux/6.8.0-139-generic

Release files / wexample_helpers-20.1.0-py3-none-any.whl

Download URL wexample_helpers-20.1.0-py3-none-any.whl
Size 117.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
6f74bed42ba5dae7f97894da5ede8d0da667683f0726e8e9df221063e8f53cf8
BLAKE2b-256 checksum
How to use checksums
450572a20af2888518ffd0d0c433ace590a484f00a9e82d924c5c57bdba6000e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via pdm/2.25.9 CPython/3.12.3 Linux/6.8.0-139-generic

Release history Release notifications | RSS feed

20.3.0

2 release files

This release

20.1.0 This release

2 release files

19.1.0

2 release files

18.0.0

2 release files

17.3.1

2 release files

17.3.0

2 release files

17.2.0

2 release files

17.0.0

2 release files

16.2.0

2 release files

16.0.2

2 release files

16.0.1

2 release files

16.0.0

2 release files

15.0.0

2 release files

14.2.0

2 release files

14.0.0

2 release files

13.1.0

2 release files

13.0.2

2 release files

13.0.0

2 release files

11.0.0

2 release files

8.0.0

2 release files

6.12.0

2 release files

6.9.0

2 release files

6.8.0

2 release files

6.7.0

2 release files

6.0.20

2 release files

2.0.0

2 release files

1.1.15

2 release files

1.1.0

2 release files

1.0.0

2 release files

0.7.0

2 release files

0.0.93

2 release files

0.0.85

2 release files

0.0.84

2 release files

0.0.83

2 release files

0.0.81

2 release files

0.0.80

2 release files

0.0.76

2 release files

0.0.75

2 release files

0.0.74

2 release files

0.0.72

2 release files

0.0.71

2 release files

0.0.70

2 release files

0.0.68

2 release files

0.0.65

2 release files

0.0.64

2 release files

0.0.63

2 release files

0.0.62

2 release files

0.0.61

2 release files

0.0.60

2 release files

0.0.59

2 release files

0.0.53

2 release files

0.0.52

2 release files

0.0.34

2 release files

0.0.32

2 release files

0.0.31

1 release file

0.0.30

2 release files

0.0.22

2 release files

0.0.21

2 release files

0.0.20

2 release files

0.0.19

2 release files

0.0.18

2 release files

0.0.9

2 release files

0.0.8

2 release files

0.0.7

2 release files

0.0.6

2 release files

0.0.5

2 release files

0.0.3

2 release files

0.0.2

2 release files

0.0.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page