Manage your configuration data by stacking grouped edits.
Reason this release was yanked:
buggy JetStreamStore
Project description
tgzr.contextual_settigs
Manage settings values in layers of operations.
Install
pip install tgzr.contextual_settigs
If you want to use the demo GUI:
pip install tgzr.contextual_settigs[demo]
See Running the Demo
Usage
There will be more store types in the future (FileStore, RESTStore, SqlStore, ...) But there's only MemoryStore for now.
Also, you'll be able to provide your own store implementations.
MemoryStore
The MemoryStore stores the config in memory. You need to populate it yourself.
from tgzr.contextual_settigs.stores.memory_store import MemoryStore
# Create the store
store = MemoryStore()
# Populate values to some contexts
store.set("BASE", "app.name", "my_app")
store.set("BASE", "app.title", "My App")
store.set("BASE", "app.version", "1.0")
store.set("BASE", "team", ["Alice", "Bob"])
store.set("DEV", "app.title", "My App (Dev)")
store.set("DEV", "app.version", "1.0+dev1")
store.append("DEV", "team", "Carol")
store.set("RC", "app.title", "My App (Release Candidat)")
store.set("RC", "app.version", "2.0rc1")
store.remove("RC", "team", "Bob")
store.append("RC", "team", "Dee")
Resolving Config
As Nested Dicts
Once the store is populated, you can retrieve the config for a given context:
base = store.get_context_dict(["BASE"])
assert base["app"]["name"] == "my_app"
assert base["app"]["title"] == "My App"
assert base["team"] == ["Alice", "Bob"]
dev = store.get_context_dict(["DEV"])
try:
base["app"]["name"]
except KeyError as err:
assert str(err) == "name"
assert dev["app"]["title"] == "My App (Dev)"
assert dev["team"] == ["Carol"]
Or for a list of stacked contexts:
conf_dev = store.get_context_dict(["BASE", "DEV"])
assert conf_dev["app"]["name"] == "my_app"
assert conf_dev["app"]["title"] == "My App (Dev)"
assert conf_dev["team"] == ["Alice", "Bob", "Carol"]
conf_rc = store.get_context_dict(["BASE", "RC"])
assert conf_rc["app"]["name"] == "my_app"
assert conf_rc["app"]["title"] == "My App (Release Candidat)"
assert conf_rc["team"] == ["Alice", "Dee"]
With History
if you want to inspect how the value was built, you can set the
with_history arg to True.
The returned dict will contain a __history__ key containing a dict
with the same keys as previously, but each value for these key is a list
of dict depicting the operation affecting the value:
config = store.get_context_dict(["BASE", "DEV"], with_history=True)
assert config["app"]["name"] == "my_app"
assert config["app"]["title"] == "My App (Dev)"
assert config["team"] == ["Alice", "Bob", "Carol"]
assert config["__history__"]["app"].get("name") is None
assert config["__history__"]["app"]["title"][0]["context_name"] == "DEV"
assert config["__history__"]["app"]["title"][0]["op_name"] == "Set"
The history list contain dicts with these keys:
context_name: the name of the context affecting the valueop_name: the name of the operation affecting the valueop: a string representation of the operation affecting the value
As Flat Dict
If you prefer to access your value without nested dict, you can use
get_context_flat() (with or without history):
config = store.get_context_flat(["BASE", "DEV"])
assert config["app.name"] == "my_app"
assert config["app.title"] == "My App (Dev)"
assert config["team"] == ["Alice", "Bob", "Carol"]
assert config["__history__"].get("app.name") is None
assert config["__history__"]["app.title"][0]["context_name"] == "DEV"
assert config["__history__"]["app.title"][0]["op_name"] == "Set"
As Pydantic Models
You can get a config as an instance of a pydantic.BaseModel.
This is usefull to coerce / validate the schema of the generated config, and
also provide you with ✨code completion✨:
import pydantic
class AppSettings(pydantic.BaseModel):
name: str | None = None
title: str | None = None
version: str | None = None
class Config(pydantic.BaseModel):
app: AppSettings = AppSettings()
team: list[str] = []
config = store.get_context(["BASE", "DEV"], Config)
assert config.app.name == "my_app"
assert config.app.title == "My App (Dev)"
assert config.team == ["Alice", "Bob", "Carol"]
Note:
You cannot request the history when getting the context as a pydandic model.
Context name expansion
Environment Variables
You can use environment variable in the context names:
import os
os.environ['STAGE'] = 'PROD'
config_1 = store.get_context_dict(['defaults', '$STAGE'])
config_2 = store.get_context_dict(['defaults', 'PROD'])
assert config_1 == config_2
You can even nest environment variables:
import os
os.environ['FirstName'] = 'Guido'
os.environ['LastName'] = 'van Rossum'
os.environ['FullName'] = '$FirstName $LastName'
config_1 = store.get_context_dict(['$FullName'])
config_2 = store.get_context_dict(['Guido van Rossum'])
assert config_1 == config_2
Expand Path
When you manage context for a hierarchy of things, you often need to specify a context per level of that hierarchy. For example, with a hierarchy like:
'$project_name/teams/$team_name'
You'll probably want to use context names like:
['@project_name', '$project_name/teams', '$project_name/teams/$team_name']
to cumulate all the value set at each level of the hierarchy.
To generate this list, you can use the Expand Path notation.
When a context name is enclosed with square brackets, the name will be
treated as the path you want to expand:
config_1 = store.get_context_dict(['Base', '[$PROJ/Teams/$Team]', 'Last'])
config_2 = store.get_context_dict(
['Base', '$PROJ', '$PROJ/Teams', '$PROJ/Teams/$Team', 'Last']
)
assert config_1 == config_2
(Of course, environement variable will be reduced too)
Running the Demo
To run the Demo GUI, you must install with the demo extra:
pip install tgzr.contextual_settigs[demo]
And then, you can launch the demo with:
uv run tgzr_contextual_settings_demo
or, if you want to pass arguments to faspapi:
uv run -p 3.13 --extra demo fastapi dev ./src/tgzr/contextual_settigs/demo/app.py
This will open a browser window with the Demo GUI.
With docker
If you fancy it, you can build a docker image and run it.
From the root of the repository:
docker build -t tgzr-contextual_settigs-demo .
docker run -d --name contextual_settigs_demo -p 8083:8080 tgzr-contextual_settigs-demo
Implementation Checklist
- MemoryStore
- Basic set of operators
- Get context as dict
- Get context as flat dict
- Get context as pydantic model
- Support env var in context names
- Support path expansion in context names
- Get context with history
- Rename *store -> *Conf ?
- Support context info (color, type, ...)
- [~] web UI
- Update context with dict
- Update context with flat dict
- Update context with pydantic model
- [~] Base models for collection of items
- Validate context with pydantic model, report all error (for gui/inspection)
- Refactor tests wiht pytest
- test store.get_context* with path
- Rest Service
- desktop UI
- Fancy operators
- FileStore
- SqlStore
- RestStore
- Support string templating in context name
- Support env var in values
- Support string templating in values
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file tgzr_contextual_settings-0.0.5.tar.gz.
File metadata
- Download URL: tgzr_contextual_settings-0.0.5.tar.gz
- Upload date:
- Size: 660.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.7.19
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3280d42ec38f70d8257d53e2649b4e4792ef47f7866851a2a575786effcd0973
|
|
| MD5 |
f8a6edcd45729ccc75e2e0cf7a23c2eb
|
|
| BLAKE2b-256 |
d9c7f22fdd54d7123a359a95e8d1f19e8894c290cfaf8e44b8a661e1b9430818
|
File details
Details for the file tgzr_contextual_settings-0.0.5-py3-none-any.whl.
File metadata
- Download URL: tgzr_contextual_settings-0.0.5-py3-none-any.whl
- Upload date:
- Size: 673.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.7.19
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
65b436ae19a0000eadd6a52ee57d7511dd04a76e03abaa309a8e2cfbe5f824ea
|
|
| MD5 |
2585ccdf9ff7b7df4e9cce35919c6094
|
|
| BLAKE2b-256 |
95ef37d33ad686820b791b6aa88df942494b5f6e3a1a4b73260ca8f6f03815a8
|