helpers
Version: 20.2.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
- Quickstart
- Tests
- Architecture
- Integration in the Suite
- Dependencies
- Versioning & Compatibility Policy
- License
- About us
- Known Limitations & Roadmap
- Status & Compatibility
- Useful Links
- Migration Notes
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=Falseby 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:
trace_get_frames()callsTraceCollector.from_stack()in src/wexample_helpers/common/exception/collector.py, which walksinspect.stack()and builds a list ofExceptionFrameobjects.ExceptionFrame(src/wexample_helpers/common/exception/frame.py) is a frozen dataclass that holdsfilename,lineno,function,code, and aDebugPathStylecontrolling how the path is rendered.trace_format()passes the frame list toTraceFormatter.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-Nonevalue; raisesTimeoutErroron exhaustion. - src/wexample_helpers/helper/retryable_callback_manager.py —
RetryableCallbackManager: retries on any exception whenshould_retry_callbackapproves; 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.
Related Packages
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
Useful Links
- Homepage: https://github.com/wexample/python-helpers
- Documentation: docs.wexample.com
- Issue Tracker: https://github.com/wexample/python-helpers/issues
- Discussions: https://github.com/wexample/python-helpers/discussions
- PyPI: pypi.org/project/wexample-helpers
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.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| wexample_helpers-20.2.0.tar.gz | 101.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| wexample_helpers-20.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 219.6 kB
Release files / wexample_helpers-20.2.0.tar.gz
| Download URL | wexample_helpers-20.2.0.tar.gz |
|---|---|
| Size | 101.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
274b2db17af891de1cd2e8f9dd09db62f0733df92b9a469544d40bb83bfee1b8
|
|
BLAKE2b-256 checksum How to use checksums |
f5d35dea0af426001ec68f642af8bfa55c3784aed60690b003b7d62d4ca42aae
|
| 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.2.0-py3-none-any.whl
| Download URL | wexample_helpers-20.2.0-py3-none-any.whl |
|---|---|
| Size | 118.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
e4bbf11aaa06d5dda0d244dd56045fda137e999077fdd73efe134cffa5228d21
|
|
BLAKE2b-256 checksum How to use checksums |
db062e49de5eb3b6ea05815c8f4cc48344dd4b3b4a1658f01180434231ca9e70
|
| 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
|