dazzle-lib 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
dazzle_lib/__init__.py ADDED
@@ -0,0 +1,51 @@
1
+ """dazzle-lib -- the DazzleLib stack's bedrock.
2
+
3
+ Shared Protocols, TypedDict payload schemas, and the exception root that every
4
+ ``dazzle-*`` library builds on. Types only: this package is stdlib-only forever
5
+ and, by charter, contains no I/O, no path handling, no platform probing, and no
6
+ "utils". See the architecture contract:
7
+ https://github.com/DazzleLib/.github/blob/main/docs/STACK-MAP.md
8
+ """
9
+
10
+ from ._version import PIP_VERSION, __app_name__, __version__
11
+ from .exceptions import (
12
+ DazzleError,
13
+ FileOperationError,
14
+ LinkError,
15
+ PathIdentityError,
16
+ PreserveError,
17
+ )
18
+ from .mixins import DazzleDataMixin
19
+ from .payloads import (
20
+ FileMetadataDict,
21
+ HashResultDict,
22
+ LinkTargetDict,
23
+ TimestampsDict,
24
+ UnixMetadataDict,
25
+ WindowsMetadataDict,
26
+ )
27
+ from .protocols import Serializable, Viewable
28
+
29
+ __all__ = [
30
+ "__version__",
31
+ "__app_name__",
32
+ "PIP_VERSION",
33
+ # protocols
34
+ "Viewable",
35
+ "Serializable",
36
+ # payload schemas
37
+ "TimestampsDict",
38
+ "WindowsMetadataDict",
39
+ "UnixMetadataDict",
40
+ "FileMetadataDict",
41
+ "LinkTargetDict",
42
+ "HashResultDict",
43
+ # exceptions
44
+ "DazzleError",
45
+ "PathIdentityError",
46
+ "FileOperationError",
47
+ "LinkError",
48
+ "PreserveError",
49
+ # mixin
50
+ "DazzleDataMixin",
51
+ ]
dazzle_lib/__main__.py ADDED
@@ -0,0 +1,11 @@
1
+ """``python -m dazzle_lib`` -- print version and charter (a library, not a tool)."""
2
+
3
+ from ._version import DISPLAY_VERSION, __app_name__
4
+
5
+ if __name__ == "__main__":
6
+ print(f"{__app_name__} {DISPLAY_VERSION}")
7
+ print(
8
+ "The DazzleLib stack's bedrock: Protocols, TypedDict payload schemas, "
9
+ "and the exception root.\nTypes only -- by charter this package "
10
+ "contains no behavior. https://github.com/DazzleLib/dazzle-lib"
11
+ )
dazzle_lib/_version.py ADDED
@@ -0,0 +1,92 @@
1
+ """
2
+ Version information for dazzle-lib.
3
+
4
+ This file is the canonical source for version numbers.
5
+ The __version__ string is automatically updated by git hooks
6
+ with build metadata (branch, build number, date, commit hash).
7
+
8
+ Format: MAJOR.MINOR.PATCH[-PHASE]_BRANCH_BUILD-YYYYMMDD-COMMITHASH
9
+ Example: 0.1.0_main_1-20260101-a1b2c3d4
10
+
11
+ Version levels:
12
+ PROJECT_PHASE: Global project maturity (prealpha -> alpha -> beta -> stable).
13
+ Changes rarely, when the overall project hits a threshold.
14
+ PHASE: Per-MINOR feature set maturity (alpha -> beta -> "" for stable).
15
+ Drops when a MINOR's feature set is complete.
16
+ """
17
+
18
+ # Version components - edit these for version bumps
19
+ MAJOR = 0
20
+ MINOR = 1
21
+ PATCH = 0
22
+ PHASE = "" # Per-MINOR feature set: "" (stable), "alpha", "beta", "rc1", etc.
23
+
24
+ # Project-level phase (independent of version phase)
25
+ PROJECT_PHASE = "" # "prealpha", "alpha", "beta", "stable", or ""
26
+
27
+ # Auto-updated by git hooks - do not edit manually
28
+ __version__ = "0.1.0_main_5-20260611-b3174573"
29
+ __app_name__ = "dazzle-lib"
30
+
31
+
32
+ def get_version():
33
+ """Return the full version string including branch and build info."""
34
+ return __version__
35
+
36
+
37
+ def get_base_version():
38
+ """Return the semantic version string (MAJOR.MINOR.PATCH[-PHASE])."""
39
+ if "_" in __version__:
40
+ return __version__.split("_")[0]
41
+ base = f"{MAJOR}.{MINOR}.{PATCH}"
42
+ if PHASE:
43
+ base = f"{base}-{PHASE}"
44
+ return base
45
+
46
+
47
+ def get_display_version():
48
+ """Return a human-friendly version string with project phase.
49
+
50
+ Example: 'PREALPHA 0.1.0-alpha' or 'BETA 0.5.1' or '1.0.0'
51
+ """
52
+ base = get_base_version()
53
+ if PROJECT_PHASE and PROJECT_PHASE != "stable":
54
+ return f"{PROJECT_PHASE.upper()} {base}"
55
+ return base
56
+
57
+
58
+ def get_pip_version():
59
+ """
60
+ Return PEP 440 compliant version for pip/setuptools.
61
+
62
+ Converts our version format to PEP 440:
63
+ - Main branch: 0.1.0_main_3-20260404-hash -> 0.1.0
64
+ - Dev branch: 0.1.0_dev_3-20260404-hash -> 0.1.0.dev3
65
+ - Alpha: 0.1.0-alpha_main_3 -> 0.1.0a0
66
+ """
67
+ base = f"{MAJOR}.{MINOR}.{PATCH}"
68
+
69
+ # Map phase to PEP 440 pre-release segment
70
+ phase_map = {"alpha": "a0", "beta": "b0"}
71
+ if PHASE:
72
+ base += phase_map.get(PHASE, PHASE)
73
+
74
+ if "_" not in __version__:
75
+ return base
76
+
77
+ parts = __version__.split("_")
78
+ branch = parts[1] if len(parts) > 1 else "unknown"
79
+
80
+ if branch == "main":
81
+ return base
82
+ else:
83
+ build_info = "_".join(parts[2:]) if len(parts) > 2 else ""
84
+ build_num = build_info.split("-")[0] if "-" in build_info else "0"
85
+ return f"{base}.dev{build_num}"
86
+
87
+
88
+ # For convenience in imports
89
+ VERSION = get_version()
90
+ BASE_VERSION = get_base_version()
91
+ PIP_VERSION = get_pip_version()
92
+ DISPLAY_VERSION = get_display_version()
@@ -0,0 +1,43 @@
1
+ """The DazzleLib exception bedrock.
2
+
3
+ One catchable root (:class:`DazzleError`) for the whole stack, plus one base
4
+ per layer domain. Each stack library derives ITS OWN exceptions from the
5
+ matching domain base (e.g. dazzle-preservelib's ``ManifestVersionError`` would
6
+ subclass :class:`PreserveError`), so consumers can choose their catch
7
+ granularity: a specific error, a domain, or the whole stack.
8
+
9
+ Charter reminder: these are plain exception types. No behavior beyond
10
+ ``__init__``-style state, no I/O.
11
+ """
12
+
13
+ __all__ = [
14
+ "DazzleError",
15
+ "PathIdentityError",
16
+ "FileOperationError",
17
+ "LinkError",
18
+ "PreserveError",
19
+ ]
20
+
21
+
22
+ class DazzleError(Exception):
23
+ """Root of every exception raised by a DazzleLib stack library."""
24
+
25
+
26
+ class PathIdentityError(DazzleError):
27
+ """Domain base for path-identity failures (dazzle-unctools, L0):
28
+ UNC/drive mapping, origin classification, identity probing."""
29
+
30
+
31
+ class FileOperationError(DazzleError):
32
+ """Domain base for filesystem-primitive failures (dazzle-filekit, L1):
33
+ copy/move, metadata collect/apply, hashing, link creation."""
34
+
35
+
36
+ class LinkError(DazzleError):
37
+ """Domain base for link-serialization failures (dazzle-linklib, L2):
38
+ .dazzlelink parsing, export/import, rebase."""
39
+
40
+
41
+ class PreserveError(DazzleError):
42
+ """Domain base for orchestration failures (dazzle-preservelib, L3):
43
+ manifests, transactional copy/move/restore/verify, conflict policy."""
dazzle_lib/mixins.py ADDED
@@ -0,0 +1,42 @@
1
+ """The one permitted mixin: derive presentation from ``to_dict``.
2
+
3
+ :class:`DazzleDataMixin` is convenience, not contract -- objects may satisfy
4
+ the protocols without it. It exists so simple data objects don't each rewrite
5
+ ``to_json``/``__str__``/``summary`` plumbing. Anything fancier belongs in the
6
+ object itself, not here (charter: this module stays this small).
7
+ """
8
+
9
+ import json
10
+ from typing import Any, Dict
11
+
12
+ __all__ = ["DazzleDataMixin"]
13
+
14
+
15
+ class DazzleDataMixin:
16
+ """Derives ``to_json``, ``summary`` and ``__str__`` from ``to_dict``.
17
+
18
+ The host class supplies ``to_dict()`` (and thereby decides what is
19
+ JSON-safe); the mixin only formats. Combined with a ``from_dict``
20
+ classmethod and a ``SCHEMA_VERSION`` attribute, a host class satisfies
21
+ both :class:`~dazzle_lib.protocols.Serializable` and
22
+ :class:`~dazzle_lib.protocols.Viewable`.
23
+ """
24
+
25
+ def to_dict(self) -> Dict[str, Any]: # pragma: no cover - host overrides
26
+ raise NotImplementedError(
27
+ f"{type(self).__name__} must implement to_dict() to use DazzleDataMixin"
28
+ )
29
+
30
+ def to_json(self, *, indent: int = 2, sort_keys: bool = False) -> str:
31
+ """JSON form of :meth:`to_dict` (``default=str`` catches stragglers)."""
32
+ return json.dumps(
33
+ self.to_dict(), indent=indent, sort_keys=sort_keys, default=str
34
+ )
35
+
36
+ def summary(self) -> str:
37
+ """One-line description: class name plus top-level keys."""
38
+ keys = ", ".join(list(self.to_dict().keys())[:6])
39
+ return f"{type(self).__name__}({keys})"
40
+
41
+ def __str__(self) -> str:
42
+ return self.to_json()
dazzle_lib/payloads.py ADDED
@@ -0,0 +1,127 @@
1
+ """TypedDict payload schemas shared across the DazzleLib stack.
2
+
3
+ These are THE cross-layer payload shapes (STACK-MAP D10): when one stack
4
+ library hands file metadata, timestamps, link descriptions, or hash results to
5
+ another, the value conforms to a shape defined here. Rich objects in upper
6
+ layers serialize themselves INTO these shapes; primitive functions in lower
7
+ layers take and return them directly.
8
+
9
+ The shapes are not invented -- they mirror what ``dazzle-filekit`` actually
10
+ produces today (``collect_file_metadata`` / ``collect_timestamp_info`` /
11
+ ``calculate_file_hash``), so adopting them is a typing change, not a behavior
12
+ change. Admission policy (rule of two): a shape lives here only once two or
13
+ more stack libraries need it.
14
+
15
+ Charter reminder: this module is types-only. No I/O, no behavior.
16
+ """
17
+
18
+ from typing import Dict, Optional, TypedDict
19
+
20
+ __all__ = [
21
+ "TimestampsDict",
22
+ "WindowsMetadataDict",
23
+ "UnixMetadataDict",
24
+ "FileMetadataDict",
25
+ "LinkTargetDict",
26
+ "HashResultDict",
27
+ ]
28
+
29
+
30
+ class TimestampsDict(TypedDict, total=False):
31
+ """File timestamps, epoch floats plus ISO-8601 projections.
32
+
33
+ Mirrors ``dazzle_filekit.metadata.collect_timestamp_info``. Note that
34
+ ``created`` carries ``st_ctime``, which is creation time on Windows but
35
+ inode-change time on Unix -- consumers must not assume birth-time
36
+ semantics cross-platform.
37
+ """
38
+
39
+ created: float
40
+ modified: float
41
+ accessed: float
42
+ created_iso: str
43
+ modified_iso: str
44
+ accessed_iso: str
45
+
46
+
47
+ class WindowsMetadataDict(TypedDict, total=False):
48
+ """Windows-specific metadata (mirrors filekit's ``_collect_windows_metadata``).
49
+
50
+ With pywin32 available the rich fields are present (``attributes``,
51
+ owner/group + SIDs, ``security_descriptor_sddl``); without it the
52
+ ``attrib``-fallback path fills only the boolean flags and
53
+ ``attrib_output``. ``security_descriptor_sddl`` may be present-but-None
54
+ when the descriptor could not be stringified.
55
+ """
56
+
57
+ attributes: int
58
+ is_hidden: bool
59
+ is_system: bool
60
+ is_readonly: bool
61
+ is_archive: bool
62
+ owner: str
63
+ group: str
64
+ owner_sid: str
65
+ group_sid: str
66
+ security_descriptor_sddl: Optional[str]
67
+ attrib_output: str
68
+
69
+
70
+ class UnixMetadataDict(TypedDict, total=False):
71
+ """Unix-specific metadata (mirrors filekit's unix branch)."""
72
+
73
+ uid: int
74
+ gid: int
75
+
76
+
77
+ class _FileMetadataRequired(TypedDict):
78
+ mode: int
79
+ size: int
80
+ timestamps: TimestampsDict
81
+
82
+
83
+ class FileMetadataDict(_FileMetadataRequired, total=False):
84
+ """A file's preservable metadata snapshot.
85
+
86
+ Mirrors ``dazzle_filekit.metadata.collect_file_metadata``: ``mode``,
87
+ ``size``, and ``timestamps`` are always present; exactly one of
88
+ ``windows`` / ``unix`` appears depending on platform; ``xattrs`` (name ->
89
+ base64-encoded value) appears on Unix when extended attributes exist.
90
+ """
91
+
92
+ windows: WindowsMetadataDict
93
+ unix: UnixMetadataDict
94
+ xattrs: Dict[str, str]
95
+
96
+
97
+ class LinkTargetDict(TypedDict, total=False):
98
+ """An intrinsic description of a filesystem link, as data.
99
+
100
+ The cross-layer shape for "what is this link": produced by link analysis
101
+ (dazzle-filekit's ``analyze_link``), embedded in serialized link files
102
+ (dazzle-linklib), and consumed by orchestration policy (dazzle-preservelib).
103
+ Intrinsic properties only -- anything relative to a specific operation
104
+ (e.g. "does this link point inside the move destination") is computed at
105
+ the orchestration layer and does NOT belong here.
106
+
107
+ ``kind`` is one of ``"symlink"``, ``"junction"``, ``"hardlink"``.
108
+ ``raw_target`` is the stored target text exactly as written; ``resolved_target``
109
+ is its absolute resolution (when resolvable). ``target_is_directory`` is
110
+ best-effort (False when the target is missing).
111
+ """
112
+
113
+ kind: str
114
+ raw_target: str
115
+ resolved_target: str
116
+ is_broken: bool
117
+ is_circular: bool
118
+ target_is_directory: bool
119
+
120
+
121
+ HashResultDict = Dict[str, str]
122
+ """Hash results keyed by algorithm name, hex digests as values.
123
+
124
+ Mirrors ``dazzle_filekit.verification.calculate_file_hash`` (e.g.
125
+ ``{"sha256": "ab12...", "md5": "cd34..."}``). A plain ``Dict`` alias rather
126
+ than a TypedDict because the key set is open (any hashlib algorithm).
127
+ """
@@ -0,0 +1,60 @@
1
+ """Structural protocols every DazzleLib stack object is expected to satisfy.
2
+
3
+ These are :class:`typing.Protocol` definitions -- STRUCTURAL contracts, not base
4
+ classes. Nothing in the stack is required to subclass anything here; an object
5
+ satisfies a protocol simply by implementing its methods (and can be checked at
6
+ runtime with ``isinstance`` because both are ``@runtime_checkable``).
7
+
8
+ The design stance (STACK-MAP D10): "the dict is the interface; objects know how
9
+ to become dicts." Rich objects in upper layers (manifest, link-data, results)
10
+ serialize themselves INTO the plain TypedDict payload shapes defined in
11
+ :mod:`dazzle_lib.payloads`; lower-layer functions take and return those dicts.
12
+
13
+ Charter reminder: this module is types-only. No I/O, no behavior.
14
+ """
15
+
16
+ from typing import Any, Dict, Protocol, runtime_checkable
17
+
18
+ __all__ = ["Viewable", "Serializable"]
19
+
20
+
21
+ @runtime_checkable
22
+ class Viewable(Protocol):
23
+ """An object that can present itself to a human.
24
+
25
+ Expectations:
26
+
27
+ - ``summary()`` returns a SHORT one-line description suitable for list
28
+ views, log lines, and progress output.
29
+ - ``__str__`` may be longer (multi-line is fine) but must never raise.
30
+ """
31
+
32
+ def summary(self) -> str:
33
+ """One-line human-readable description of this object."""
34
+ ...
35
+
36
+
37
+ @runtime_checkable
38
+ class Serializable(Protocol):
39
+ """An object that can round-trip through a plain, JSON-safe dict.
40
+
41
+ Expectations:
42
+
43
+ - ``to_dict()`` returns a dict containing only JSON-safe values
44
+ (str/int/float/bool/None/list/dict). Where a shared payload shape
45
+ exists in :mod:`dazzle_lib.payloads`, the dict conforms to it.
46
+ - ``from_dict(data)`` is a classmethod constructing an equivalent object.
47
+ - ``SCHEMA_VERSION`` identifies the dict layout so readers can migrate
48
+ old serialized forms. Bump it on any breaking shape change.
49
+ """
50
+
51
+ SCHEMA_VERSION: int
52
+
53
+ def to_dict(self) -> Dict[str, Any]:
54
+ """Return a JSON-safe dict representation of this object."""
55
+ ...
56
+
57
+ @classmethod
58
+ def from_dict(cls, data: Dict[str, Any]) -> "Serializable":
59
+ """Construct an instance from a dict produced by :meth:`to_dict`."""
60
+ ...
@@ -0,0 +1,118 @@
1
+ Metadata-Version: 2.4
2
+ Name: dazzle-lib
3
+ Version: 0.1.0
4
+ Summary: The DazzleLib bedrock: shared Protocols, TypedDict payload schemas, and exception root for the dazzle-* library stack. Stdlib-only by charter.
5
+ Author-email: djdarcy <djdarcy@users.noreply.github.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/DazzleLib/dazzle-lib
8
+ Project-URL: Repository, https://github.com/DazzleLib/dazzle-lib
9
+ Project-URL: Issues, https://github.com/DazzleLib/dazzle-lib/issues
10
+ Keywords: dazzlelib,protocols,typeddict,serialization,bedrock,stack
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Operating System :: OS Independent
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.9
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Topic :: Software Development :: Libraries
22
+ Classifier: Typing :: Typed
23
+ Requires-Python: >=3.9
24
+ Description-Content-Type: text/markdown
25
+ License-File: LICENSE
26
+ Provides-Extra: dev
27
+ Requires-Dist: pytest>=7.0.0; extra == "dev"
28
+ Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
29
+ Dynamic: license-file
30
+
31
+ # dazzle-lib
32
+
33
+ **The DazzleLib stack's bedrock: shared Protocols, TypedDict payload schemas, and the exception root.**
34
+
35
+ [![PyPI](https://img.shields.io/pypi/v/dazzle-lib)](https://pypi.org/project/dazzle-lib/)
36
+ [![Python](https://img.shields.io/badge/python-3.9%2B-blue)](https://pypi.org/project/dazzle-lib/)
37
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
38
+ [![Platforms](https://img.shields.io/badge/platforms-all-brightgreen)](docs/platform-support.md)
39
+
40
+ Every `dazzle-*` library ([the stack](https://github.com/DazzleLib/.github/blob/main/docs/STACK-MAP.md)) builds on this package: it defines what stack objects can be expected to do (view themselves, serialize themselves) and what shapes cross-layer payloads have. **Types only** -- by charter this package contains no I/O, no path handling, no platform probing, and no behavior, forever.
41
+
42
+ ```bash
43
+ pip install dazzle-lib
44
+ ```
45
+
46
+ ## What's inside (all of it)
47
+
48
+ | Module | Contents |
49
+ |---|---|
50
+ | `dazzle_lib.protocols` | `Viewable` (`summary()`/`__str__`), `Serializable` (`to_dict`/`from_dict`/`to_json`, `SCHEMA_VERSION`) -- structural `Protocol`s, `runtime_checkable`, nothing is forced to subclass |
51
+ | `dazzle_lib.payloads` | The cross-layer TypedDict schemas: `FileMetadataDict`, `TimestampsDict`, `WindowsMetadataDict`, `UnixMetadataDict`, `LinkTargetDict`, `HashResultDict` -- mirroring what `dazzle-filekit` actually produces |
52
+ | `dazzle_lib.exceptions` | `DazzleError` root + per-domain bases (`PathIdentityError`, `FileOperationError`, `LinkError`, `PreserveError`) |
53
+ | `dazzle_lib.mixins` | `DazzleDataMixin` -- derives `to_json`/`summary`/`__str__` from your `to_dict` |
54
+
55
+ ## The idea: the dict is the interface
56
+
57
+ Rich objects in upper layers know how to become plain dicts; lower-layer functions take and return those dicts. The TypedDicts here are the agreed shapes, so a manifest object in `dazzle-preservelib` and a metadata collector in `dazzle-filekit` speak the same payload without sharing a class hierarchy:
58
+
59
+ ```python
60
+ from dataclasses import dataclass
61
+ from dazzle_lib import DazzleDataMixin, Serializable, FileMetadataDict
62
+
63
+ @dataclass
64
+ class TransferResult(DazzleDataMixin):
65
+ SCHEMA_VERSION = 1
66
+ path: str
67
+ metadata: FileMetadataDict
68
+
69
+ def to_dict(self):
70
+ return {"schema_version": self.SCHEMA_VERSION,
71
+ "path": self.path, "metadata": dict(self.metadata)}
72
+
73
+ @classmethod
74
+ def from_dict(cls, data):
75
+ return cls(path=data["path"], metadata=data["metadata"])
76
+
77
+ result = TransferResult("a.txt", {"mode": 0o644, "size": 10, "timestamps": {}})
78
+ assert isinstance(result, Serializable) # structural -- no subclassing needed
79
+ print(result.summary()) # one-liner for logs
80
+ ```
81
+
82
+ And one catchable root for the whole stack:
83
+
84
+ ```python
85
+ from dazzle_lib import DazzleError
86
+ try:
87
+ ... # any dazzle-* library call
88
+ except DazzleError as e:
89
+ ... # caught, whichever layer raised it
90
+ ```
91
+
92
+ ## The charter (enforced by tests)
93
+
94
+ This package is **stdlib-only forever** and contains **no behavior**. `tests/test_charter.py` fails on any banned import (`os`, `shutil`, `pathlib`, `subprocess`, ...) anywhere in the package -- a PR that needs to weaken that test is adding something that belongs in a higher layer. Admission follows the **rule of two**: a Protocol or TypedDict enters the bedrock only when two or more stack libraries need it.
95
+
96
+ ## The stack
97
+
98
+ | Layer | Library | Role |
99
+ |---|---|---|
100
+ | B | **dazzle-lib** (this) | bedrock contracts |
101
+ | L0 | [dazzle-unctools](https://github.com/DazzleLib/UNCtools) | path identity (UNC/drive/origin) |
102
+ | L1 | [dazzle-filekit](https://github.com/DazzleLib/dazzle-filekit) | filesystem primitives |
103
+ | L2 | dazzle-linklib *(planned)* | link serialization |
104
+ | L3 | dazzle-preservelib *(planned)* | operation orchestration |
105
+ | ⊥ | [dazzle-treelib](https://github.com/DazzleLib/dazzle-tree-lib) | traversal engine |
106
+
107
+ Full architecture contract: [STACK-MAP.md](https://github.com/DazzleLib/.github/blob/main/docs/STACK-MAP.md). API stability policy: [docs/api-stability.md](docs/api-stability.md).
108
+
109
+ ## Development
110
+
111
+ ```bash
112
+ pip install -e ".[dev]"
113
+ python -m pytest tests/ -v
114
+ ```
115
+
116
+ ## License
117
+
118
+ MIT -- the bedrock sits beneath MIT and GPL stack members alike, so it carries the permissive license.
@@ -0,0 +1,12 @@
1
+ dazzle_lib/__init__.py,sha256=uxV2FjmpcWyjTVmeaVERrXhdRMUnECU7fJcafgPEW_c,1270
2
+ dazzle_lib/__main__.py,sha256=rQt-ikb4ZbOP_81eR13beNDGtGEwT8lHvaJVNv2oihs,456
3
+ dazzle_lib/_version.py,sha256=Sr_O8_AIZZH5bnUUI46Ez4i4BxV5Um9IXOCzUABWObA,2772
4
+ dazzle_lib/exceptions.py,sha256=0UPGcyO6TTmB5iBhbeM3oXIsLTeoSiUOLiXBpzQE0lc,1429
5
+ dazzle_lib/mixins.py,sha256=fvaUx9Q8y72Eck9QWJKxDF_tf8pxmhDVPSYop6HePJ4,1613
6
+ dazzle_lib/payloads.py,sha256=ktr15Vj4hgmI9UzLdgCr_xHN8nCgXy_KY5a9sjor-x8,4258
7
+ dazzle_lib/protocols.py,sha256=vmH8fco_bz_VSeGoUAgny3KMf04VqhU5IAe50MxcAZA,2195
8
+ dazzle_lib-0.1.0.dist-info/licenses/LICENSE,sha256=DlZy6_97dpafvd_ObU8YNvyk5Gzk_qX070j7pKyDJBY,1069
9
+ dazzle_lib-0.1.0.dist-info/METADATA,sha256=n4Ybhg5AQrl6MBBl_udbGpFtiGjQo3RCgdrZDdSwyDg,5611
10
+ dazzle_lib-0.1.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
11
+ dazzle_lib-0.1.0.dist-info/top_level.txt,sha256=Ng-Ykc6wxyQQ9gb3Oxgzrb1SdTbWF8HaqI485_tM_JM,11
12
+ dazzle_lib-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (82.0.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Dustin Darcy
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1 @@
1
+ dazzle_lib