Skip to content

Optional-peer integration pattern for unctools and preservelib #8

@djdarcy

Description

@djdarcy

Summary

Define and document the "optional peer" integration pattern that
dazzle_filekit.data (sub-issue #N+1) uses to compose with unctools
and preservelib without making them hard dependencies.

This is the architectural contract that keeps the primitives layer
(v0.2.x filekit) decoupled from the workflow layer (v0.3.x) even though
they share a package namespace.

The pattern

# Inside dazzle_filekit/data/__init__.py or a helper module

# --- Detection -----------------------------------------------------

try:
    import unctools
    HAS_UNCTOOLS = True
except ImportError:
    HAS_UNCTOOLS = False

try:
    from preservelib import manifest as _pl_manifest
    HAS_PRESERVELIB = True
except ImportError:
    HAS_PRESERVELIB = False


# --- Guards --------------------------------------------------------

def _require_preservelib(feature: str):
    if not HAS_PRESERVELIB:
        raise RuntimeError(
            f"{feature} requires preservelib. Install it with:\n"
            f"    pip install 'dazzle-filekit[preservelib]'\n"
            f"or install preservelib directly alongside filekit."
        )


# --- Use at the call site ------------------------------------------

def copy(src, dst, *, manifest=False, ...):
    if manifest:
        _require_preservelib("manifest=True")
        # ... use _pl_manifest ...
    else:
        # fall back to filekit's atomic_write_json with a minimal schema
        ...

Invariants

  1. import dazzle_filekit must never fail because unctools or
    preservelib are missing.
    The top-level package imports only its
    own submodules.
  2. import dazzle_filekit.data must never fail because peers are
    missing.
    The data submodule sets HAS_UNCTOOLS / HAS_PRESERVELIB
    at import time but doesn't fail.
  3. Feature-gated calls raise a clear RuntimeError with an install
    hint
    , never a confusing ImportError or AttributeError from
    deep in the composition chain.
  4. Default behavior degrades to filekit-only primitives when peers
    are missing. For example, manifest=False is the default so the
    common case works without preservelib.
  5. No monkey-patching. If a user installs preservelib after
    importing filekit, they need to reimport filekit to pick up the
    new features. (Document this.)

pyproject.toml extras

[project.optional-dependencies]
unctools = ["unctools>=0.1.0"]
preservelib = ["preservelib>=0.5.0"]
full = ["unctools>=0.1.0", "preservelib>=0.5.0"]
dev = [
    "pytest>=7.0.0",
    "pytest-cov>=3.0.0",
    "flake8>=3.8.0",
    "black>=20.8b1",
]

Install variants:

  • pip install dazzle-filekit -- primitives only
  • pip install 'dazzle-filekit[unctools]' -- primitives + UNC translation
  • pip install 'dazzle-filekit[preservelib]' -- primitives + manifest support
  • pip install 'dazzle-filekit[full]' -- the whole seamless experience

Acceptance criteria

  • HAS_UNCTOOLS / HAS_PRESERVELIB module-level flags exist in
    dazzle_filekit.data
  • _require_unctools() / _require_preservelib() helpers raise
    clear errors with install hints
  • pyproject.toml has unctools, preservelib, and full extras
  • docs/optional-peers.md documents the pattern for downstream
    tool authors
  • Tests verify the graceful-degradation path (by monkeypatching
    HAS_UNCTOOLS = False in a test fixture)

Dependencies

  • Blocks: #N+1 (data submodule), #N+2 (DataRef), and all other
    Layer 1 work that composes the peers

Non-goals

  • Actually refactoring unctools or preservelib to make them more
    filekit-friendly -- those are separate tracks in their own repos

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestlayer-1High-level workflow API on top of primitivesv0.3.0Targeted for v0.3.0 release

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions