Repository navigation
Releases: B4PT0R/modict
Releases · B4PT0R/modict
Release list
v0.4.18
Performance overhaul for TypeChecker & Coercer
Major optimization of the type checking and coercion pipeline — the primary bottleneck of the package.
Highlights
- check_type(int, 42): -61% (0.54 → 0.21 us/op)
- check_type cached nested generic: -51% (36.94 → 17.98 us/op)
- coerce cached nested generic: -45% (72.03 → 39.71 us/op)
- modict init (cached): -30% (259.65 → 182.02 us/op)
- typed assignment / no-op: -44% (10.56 → 5.88 us/op)
- bulk update / no-op values: -47% (31.59 → 16.68 us/op)
What changed
- Fast-path checks reordered by realistic type frequency (int/str/float first)
- Eliminated redundant double fast-path calls in the check_type pipeline
- Rare hint wrappers (TypeAlias, ForwardRef, Required/NotRequired) integrated into cached hint plan
- Inline element checking for common types in sequences/sets/mappings
- Coercer fast-path bypass for already-matching basic types
- New
benchmarks/typechecker_validation.pywith 37 scenarios
See CHANGELOG.md for full details.
0.4.17
Changed
- Validation sequencing was clarified: any_validator is now a pure value hook, model_validator keeps final authority over values, and structural key checks are enforced on the final post-validator state.
- Assignment validation now aligns more closely with init-time sequencing when model_validator is involved, including deferred default-key-hint normalization.
- Default value hint checking now runs before field-specific hint checking, with refined incompatibility reporting.
- Benchmark tooling now stores a machine-readable baseline in benchmarks/baseline.toml and compares current runs against it.
Tests
- Added regression coverage for any_validator mutation blocking, final-state key normalization after model_validator, and refined default-hint-vs-field-hint error cases.
0.4.16
Fixed
- A.config(...) now uses the subclass's effective config as its base, so deeper subclasses can override config through an intermediate subclass without dropping inherited settings.
Tests
- Added regression coverage for chained config overrides declared via an intermediate subclass's config() classmethod.
v0.4.15
Added
- Added
get_attr(name, default=MISSING) -> Anyto complete the runtime attrs helper API alongsideset_attr()/has_attr()/del_attr().
Changed
- Updated the public API docs and quickstart runtime metadata examples to document
get_attr().
Tests
- Added regression coverage for instance attrs, inherited class attrs, missing attrs, and payload-key collisions.
v0.4.14
Added
@modict.any_validator(mode="before"|"after")for key-aware validation/transformation on every validated assignment, with signature(self, key, value) -> value.
Changed
- README now documents
@modict.any_validator(...)alongside the other model-layer decorators.
Tests
- Added regression coverage for any-key validator collection, runtime execution, and signature validation.
v0.4.13
Added
ignore_noneconfig option to skip incomingNoneassignments for non-destructive overlay/merge workflows.
Changed
- Defaults declared as
Nonenow follow the field's effective required level whenignore_none=True: effectively optional fields stay absent, effectively required fields are materialized withNone. - Documentation now covers
ignore_nonebehavior inmodictConfigand the main README.
0.4.11
0.4.11
Changed
- Documentation and examples are now aligned with the current
required="always"semantics, themodel_validator(self)contract, and the newercheck_values/check_keysbehavior descriptions. - Internal field collection now uses explicit required levels like
"never"instead of legacy boolean flags.
Fixed
- Source distribution packaging now includes the main docs plus the
examples/andbenchmarks/trees cleanly.
0.4.10
v0.4.8
0.4.8
Changed
check_valuesandcheck_keysconfig options no longer accept"auto"— the smart early-exit behavior is now always active when the option isTrue(default). The accepted values are simplyTrue(default, with early exit when no constraints apply) andFalse(bypass entirely). Documentation and docstrings updated accordingly.
0.4.7
Changed
require_allconfig option now accepts"never"|"at_init"|"always"instead ofbool. Default changed fromFalseto"at_init": annotated fields without a default are now required at construction time but remain freely deletable afterwards.True/Falsestill accepted for backward compat.modict.field(required=...)follows the same three-level scale. The stronger constraint between field-levelrequiredand config-levelrequire_allalways wins.
Fixed
- Deletion of declared fields is now only blocked when the effective required level is
"always"—"at_init"fields can be freely removed after construction.
0.4.6
Added
QUICKSTART.md: a narrative, example-driven introduction to modict for new users
Changed
- README intro rewritten for clarity and conciseness: tighter positioning, cleaner "Why modict" paragraph, richer use-case descriptions
- Development section now includes full local setup instructions
Fixed
- Protocol compatibility hardened on older Python versions (3.10/3.11)
- Cross-version typing and JSONPath compatibility fixes
0.4.5
Added
- A dedicated
benchmarks/directory with sequential runners fortypechecker,modict core,path_utils, andcollections_utils
Changed
typecheckerandcoercernow cache compiled hint/coercion plans more aggressively, with additional fast paths for trivial scalar/runtime checksmodicthot paths (__setitem__,update(), computed invalidation, key/value pipeline guards) were tightened to avoid repeated no-op work and repeated structural scanspath_utilsnow caches parsed JSONPath strings, making repeated path-based operations dramatically cheapercollections_utilstraversal and reconstruction paths (walk,unwalk,diff_nested,set_nested) now rely on lighter internal path/container handling for better deep-op throughput
Fixed
- Runtime container helper fast paths now still respect explicit
excluded=...overrides
Tests
- Added regression coverage around performance-sensitive copy/translate/computed bookkeeping paths and the newer
typecheckerfast paths
0.4.4
Added
modict.attr(...)/Attributefor explicit runtime/class metadata that stays outside the payload instead of being collected as a fieldset_attr()/has_attr()/del_attr()instance helpers for ergonomic runtime metadata managementmodict.wrap(...)/__wrap_init__()for advanced constructor-time business context without polluting the native dict-like constructor signature- A new
examples/directory with practical end-to-end scripts covering webhook payloads, config rollouts, SDK object adaptation, redaction/export flows, and a React-like UI component tree
Changed
wrap(...)now resolves a single__wrap_init__entry point on the target class; inheritance-time parameter routing is explicit inside user overrides instead of being inferred across the MRO- The root
modictpackage now keeps a tighter convenience surface focused on the main entry points; advanced descriptor/config/runtime classes stay exposed from their dedicated submodules - The README now starts every Python snippet from explicit imports, routes readers more clearly toward submodule READMEs from the package tour, and keeps advanced payload/runtime patterns later in the narrative
Computedsemantics are documented more explicitly: class-declared computeds participate in the model contract, while dynamic instance computeds remain runtime values unless they target an already-declared field
Fixed
- Runtime attrs declared with
modict.attr(...)now bypass field collection reliably, remain available through inheritance, and can be overridden or cleared on instances without conflicting with declared field names wrap(...)behavior is now aligned between implementation, documentation, and tests for inheritance-heavy use cases
Tests
- Added regression coverage for runtime attrs, wrapped construction, explicit wrap-parameter routing in inheritance scenarios, dynamic computed typing semantics, and the narrowed root public API
0.4.3
Fixed
clear()now respectsfrozen=Trueand computed-field protection invariants- Replacing a computed field now invalidates dependant computed caches consistently, and
aftermodel validators no longer bypass assignment/key policies Config.copy()/Config.merge()now isolate mutable config payloads such asjson_encodersreset_global_typechecker()now resets the global coercer too, keeping the public helper singletons in syncPath.__radd__()now treatsstr/intas single path keys, andPathNodereports stable errors for invalid containerswalk()is now cycle-safe, anddeep_merge()no longer treatsstr/bytes/bytearrayas mergeable deep sequencesmodict.__or__()now works correctly on frozen instances without mutating the source objectconvert()/unconvert()now handle self-referential structures safely while preserving the intended in-place container semanticscoerce()now handles PEP 604 optionals likeint | None, and hostile iterables/mappings now fail withCoercionErrorinstead of leaking raw runtime exceptions
Changed
- Validator and model-validator signature errors are now detected at registration time, while runtime
TypeErrors raised inside validator bodies are preserved as-is - Documentation now explicitly reflects the accepted relative
Path(...)string forms
Tests
- Expanded regression and edge-case coverage across
core,path_utils,collections_utils,model_api, andtypechecker, including cycles, alias preservation, hostile coercion inputs, andfrom_attributesfailure modes
0.4.2
Removed
rename()from the public API; in-place key renaming was a poor fit for typed/model-like modicts and could break expected key structure
Added
translate()to return a plainmodictwith translated keys, intended for payload/header/schema projection without mutating the source object- Path ergonomics improvements:
tuple(path)iteration on keys, readablerepr(path), non-mutatingwith_root(), and relationship helpersstarts_with(),is_ancestor_of(),relative_to() unwalk(..., kind_resolver=...)andmodict.unwalk(..., kind_resolver=...)to refine inferredmapping/sequencestructure per container path
Changed
set_nested()is now strict by default: missing intermediate containers raise unlesscreate_missing=Trueis passed explicitlyset_nested(..., create_missing=True)now uses acontainer_factory(path)hook instead of implicit container inventionunwalk()now reconstructs structuraldict/listcontainers via an internal tree build/materialization pass instead of replaying every path through repeated nested writesmodict.unwalk()continues to recast the root mapping through the target class so model validation/coercion can re-establish the desired root type safelyPathno longer exposes a.keysproperty; the public sequence API is nowtuple(path)/ iteration on keysignore_typesonunwalk()is now a legacy compatibility mode; structure selection is driven by the default or customkind_resolverrepr(modict)now renders computed fields asComputed(current_value)instead of hiding their derived nature in console output
0.4.1
Added
- GitHub Actions test workflow covering Python
3.10through3.14 - Additional regression coverage for
typecheckerruntime semantics, recursion safety, and permissive interface-only checks
Changed
typecheckerdocumentation now distinguishes strictly checked constructs from intentionally permissive runtime-only checks- Contribution guide now includes the focused
typecheckertest command and CI expectations
Fixed
- Hardened
typecheckerandcoerceraroundCallable[...]variance,Protocolmember checking,TypedDictwithRequired[...]/NotRequired[...],type[T], explicitForwardRef, and modernTypeAliasType - Recursive aliases and cyclic values now fail safely during coercion instead of recursing indefinitely
- Remaining French comments/docstrings in the
typecheckerpublic surface were translated to English
v0.4.0
What's new
Removed
- Pydantic interoperability (
from_model,to_model,TypeCache) - JSON Schema export (
json_schema) and fieldconstraints invalidate_all_computed()— useinvalidate_computed()with no argumentsfilter()/filtered()— redundant with native Python; also blocked those key names
Added
Query(path, value)primitive for combined path+value deep searchfind()/found()on modict instances viaQueryor inline constraintsupdate(other=(), /, **kwargs)override routing all assignments through the validation pipeline
Fixed
popitem()now returns the last-inserted item (LIFO, matching native dict)update()no longer lets CPython bypass__setitem__validation
Changed
- README rewritten: intro compares modict to
dict,dataclass,TypedDict,Pydantic,attrs - All French inline comments translated to English
- +120 tests covering all native dict methods and modict-specific ops