Skip to main content

vcti-properties

Sparse, scoped, multi-level property store with pluggable key mapping.

Overview

vcti-properties stores sparse named properties attached to entities or collections, with optional layered resolution — a per-entity value that falls back to a shared default. It spans the whole range from fixed metadata (units, components, a creator — authoritative, rarely overridden) to overridable properties (a plot's color, opacity, visibility — set as chart-wide defaults and overridden per series). Both are just values addressed by a structured key.

Rather than a tangle of nested dictionaries, every property lives in one sparse store keyed by a flat string, and three concerns are kept cleanly separated:

  • Authority — application-defined (system) properties vs. user-supplied ones, held in separate namespaces so they never collide. System names are drawn from a controlled vocabulary; user names are free-form.
  • Locus — what a property is bound to: a specific entity (one column, element, node), or the whole collection.
  • Resolution — a per-entity lookup can fall back to a shared default, so one value stands in for every entity that has not set its own.

Nothing here is dataset-specific: any set of entities — form fields, scene objects, config sections — each carrying its own properties over shared defaults, with system settings kept apart from user settings, fits the same shape. The levels you declare encode the (authority, locus, name) parts into one flat string key, so the store stays sparse (unset combinations cost nothing) and lookups stay O(1). Pure standard library, zero runtime dependencies.

Why not nested dicts or ChainMap?

Nested dictionaries — one level per authority, per entity, per name — mean a lot of structure for little data, plus hand-rolled lookup repeated at every call site. ChainMap gives you fallthrough for free, but you would need one dict per (authority × locus) combination and must reassemble the chain per entity — the layer count explodes with the number of entities. This package keeps the unbounded axis (locus) in a flat key over one sparse dict, and reserves layered fallthrough for the small, bounded axis where it belongs (see Design & Concepts).

Installation

pip install vcti-properties

In pyproject.toml dependencies

dependencies = [
    "vcti-properties>=1.0.0",
]

Quick Start

A store is defined by an ordered list of levels passed straight to PropertyStore (it builds the key encoder for you). Each level is one part of the key; the last level is the property name, and the value is stored separately against the assembled key.

Here's a chart whose series are styled with chart-wide defaults that any series can override — exactly the overridable kind of value that is a property (unlike fixed metadata such as units or a creator):

from enum import StrEnum

from vcti.properties import PropertyStore, Level

class Style(StrEnum):                     # the plot properties we recognise
    COLOR = "color"
    OPACITY = "opacity"
    VISIBLE = "visible"

chart = PropertyStore(
    Level("series", sentinel="@"),        # a specific series, or chart-wide (@)
    Level("style", vocabulary=Style),     # the property name
)

# Chart-wide defaults — apply to every series unless overridden:
chart.set(style=Style.COLOR, value="steelblue")     # -> "@.color"
chart.set(style=Style.OPACITY, value=1.0)
chart.set(style=Style.VISIBLE, value=True)

# Per-series overrides:
chart.set(series="revenue", style=Style.COLOR, value="crimson")
chart.set(series="forecast", style=Style.OPACITY, value=0.4)

# resolve() = the series' own value, else the chart-wide default:
chart.resolve(series="revenue",  style=Style.COLOR)    # "crimson"    (overridden)
chart.resolve(series="forecast", style=Style.COLOR)    # "steelblue"  (chart-wide default)
chart.resolve(series="forecast", style=Style.OPACITY)  # 0.4          (overridden)
chart.get(series="forecast", style=Style.COLOR)        # None         (exact read, no fallback)

Add a system/user scope as one more level when the application's own defaults must stay separate from a user's edits — system.* and user.* are distinct namespaces that never collide (each resolves within itself):

from vcti.properties import PropertyStore, KeyScope, Level

chart = PropertyStore(
    Level("scope", vocabulary=KeyScope),   # application theme (system) vs. user edits (user)
    Level("series", sentinel="@"),
    Level("name"),
)

chart.set(scope=KeyScope.SYSTEM, name="color", value="steelblue")                 # "system.@.color"
chart.set(scope=KeyScope.USER, series="revenue", name="color", value="crimson")   # "user.revenue.color"

With no levels, the store uses dot-joined paths (DefaultKeyMapper):

from vcti.properties import PropertyStore

store = PropertyStore()                                   # or PropertyStore(separator="/")
store.set("user", "profile", value={"name": "Alice"})     # key "user.profile"
store.get("user", "profile")                              # {"name": "Alice"}

Key mappers

Passing levels to PropertyStore builds a KeyMapper — the codec that encodes the (authority, locus, name) parts into a flat key and back. It's pluggable, so one store serves every layout:

Mapper What it does
DefaultKeyMapper Unstructured positional parts joined by a separator (a.b.c) — the default when no levels are given
LeveledKeyMapper Structured named levels — built from the Levels you pass to PropertyStore

Scenario-specific layouts (a system/user scoped key, a single-level config key) are configurations of levels, not separate classes. For a bespoke scheme, pass key_mapper= any object implementing parts_to_key(...) and key_to_parts(key). See Extending.


Dependencies

None. Standard library only.

Metadata

Release files for vcti-properties 1.0.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 vcti-properties 1.0.0
File Size Uploaded
vcti_properties-1.0.0.tar.gz 16.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for vcti-properties 1.0.0
File Interpreter ABI Platform
vcti_properties-1.0.0-py3-none-any.whl Python 3 none any Details

Total release size: 28.2 kB

Release files / vcti_properties-1.0.0.tar.gz

Download URL vcti_properties-1.0.0.tar.gz
Size 16.2 kB
Tags Source
SHA-256 checksum
How to use checksums
c4bc2f5bcd7fc7fa101605ba0964d30c8495dd86fe2611f7a254cf3cfbfcd613
BLAKE2b-256 checksum
How to use checksums
a5b8eed6a526a9fe0da85f3b1a9f5023fd02cf674a6cbe749db50e3c4cb27593
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 4, 2026.

Transparency log

Release files / vcti_properties-1.0.0-py3-none-any.whl

Download URL vcti_properties-1.0.0-py3-none-any.whl
Size 12.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
a60f394c56896a78bb5bf78d55069f8cc0b30752adcc3b4c4069bf4c3e45a0ab
BLAKE2b-256 checksum
How to use checksums
46bcc153849464cfb570ef79cf194bd045619e58ef694a19a370f41ace6faa1f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 4, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

1.0.0 This release

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