Build a process/service runtime stamp from a format template and pluggable value sources
Project description
runstamp
Build a process/service runtime stamp from a str.format template and a handful of pluggable value sources.
Installation
pip install runstamp
Requires Python 3.11+.
Why runstamp?
Almost every long-running service wants a single string identifying the running instance — something to stamp into logs, metrics labels, and tracing spans:
service:acme/billing/api, build:1.42.7, host:node-07, user:svc-billing, run:2026-04-22T09:14:01+00:00
The pieces come from different places: some from the surrounding application, some from environment variables, some from a build-info module, some from socket.gethostname(). There is no stdlib way to assemble them — every project ends up hand-rolling the string with hidden indirections to each value.
runstamp describes that string as a format template plus one Source per placeholder. Sources are plain Python objects, the resolver is async — just a function, a dataclass, and a Protocol.
Quick Start
# my_app/build_info.py — committed as a stub, overwritten by CI before packaging.
# Recommended CI step (e.g. in your build job):
# echo "build_id = \"$CI_BUILD_VERSION\"" > my_app/build_info.py
# Locally the stub is used as-is, so `build` resolves to "dev" via the source's default.
build_id = "dev"
import asyncio
import socket
from datetime import datetime, timezone
from runstamp import (
build_runstamp,
RunstampConfig,
KwargsSource,
ImportSource,
CallableSource,
)
config = RunstampConfig(
template="service:{project}, build:{build}, host:{host}, run:{started_at}",
sources={
"project": KwargsSource("ctx", attr="project_name"),
"build": ImportSource("my_app.build_info", attr="build_id", default="dev"),
"host": CallableSource(socket.gethostname),
"started_at": CallableSource(
lambda: datetime.now(timezone.utc).isoformat()
),
},
)
app_ctx = type("Ctx", (), {"project_name": "billing"})()
stamp = asyncio.run(build_runstamp(config, ctx=app_ctx))
# In CI (after build_info.py was rewritten with the release version):
# 'service:billing, build:1.42.7, host:node-07, run:2026-04-22T09:14:01+00:00'
# Locally (build_info.py contains build_id = "dev"):
# 'service:billing, build:dev, host:my-laptop, run:2026-04-22T09:14:01+00:00'
Overview
Core: build_runstamp | RunstampConfig | Source
Built-in sources: ConstantSource | EnvVarSource | KwargsSource | ImportSource | CallableSource
Defaults: default_sources | DEFAULT_TEMPLATE
Core
build_runstamp
async def build_runstamp(config: RunstampConfig, /, **context: Any) -> str
Renders config.template by calling resolve(**context) on each source. Every {name} in the template must have a matching entry in config.sources; otherwise KeyError is raised before any source runs. Extra unused sources are ignored — convenient when one source mapping is shared across several templates.
RunstampConfig
Frozen dataclass pairing a template with its source mapping.
from runstamp import RunstampConfig, EnvVarSource
config = RunstampConfig(
template="{region}-{stage}",
sources={
"region": EnvVarSource("AWS_REGION"),
"stage": EnvVarSource("STAGE", default="dev"),
},
)
Source
Protocol describing the single method every source implements:
class Source(Protocol):
async def resolve(self, **context: Any) -> Any: ...
Write your own source whenever a built-in doesn't fit — for example, a source that fetches from a config server:
from dataclasses import dataclass
@dataclass(frozen=True, slots=True)
class ConfigServerSource:
key: str
async def resolve(self, **context):
return await my_config_client.get(self.key)
resolve is async so I/O-bound sources are natural; synchronous work is fine too — just async def and return.
Built-in sources
Every built-in source accepts an optional default=... keyword. When set, any expected failure (missing env var, missing attribute, failed import, callable raising) returns the default instead of propagating. When not set, the failure raises.
ConstantSource
ConstantSource("prod")
Always returns the given value.
EnvVarSource
EnvVarSource("SHARD_ID")
EnvVarSource("REGION", default="us-east-1")
Reads an environment variable. Raises KeyError if missing and default was not supplied.
KwargsSource
KwargsSource("ctx") # -> context["ctx"]
KwargsSource("ctx", attr="project") # -> context["ctx"].project
KwargsSource("ctx", attr="project.name") # -> context["ctx"].project.name
KwargsSource("ctx", attr="missing", default=None)
Pulls a key from the context kwargs passed to build_runstamp, with optional dotted attribute access.
ImportSource
ImportSource("socket") # -> the module
ImportSource("my_app.build_info", attr="build_id") # -> attribute value
ImportSource("socket", attr="gethostname", call=True) # -> gethostname()
ImportSource("missing.mod", attr="x", default=None) # -> None on ImportError/AttributeError
Imports a module and optionally drills into a dotted attribute path. Set call=True to call the final attribute; if it returns a coroutine it is awaited.
CallableSource
CallableSource(socket.gethostname)
CallableSource(lambda: datetime.now(timezone.utc).isoformat())
CallableSource(fetch_current_tenant) # async function also fine
Calls any zero-argument callable. Coroutines are awaited. Pass default=... to swallow a specific failure.
Defaults
default_sources
from runstamp import default_sources, RunstampConfig, DEFAULT_TEMPLATE
config = RunstampConfig(DEFAULT_TEMPLATE, default_sources())
Returns a ready-made mapping:
| Placeholder | Source |
|---|---|
company |
KwargsSource("context", attr="company") |
group |
KwargsSource("context", attr="project_group") |
project |
KwargsSource("context", attr="project_name") |
build |
ImportSource("build_info", attr="build_id", default=None) |
environment |
EnvVarSource("ENVIRONMENT", default=None) |
shard_id |
EnvVarSource("SHARD_ID", default=None) |
started_at |
CallableSource(lambda: datetime.now(UTC).astimezone().isoformat()) |
host |
CallableSource(socket.gethostname) |
user |
CallableSource(getpass.getuser) |
Mix and match — override just the keys you need:
sources = {**default_sources(), "project": KwargsSource("app", attr="name")}
DEFAULT_TEMPLATE
service:{company}/{group}/{project}, built:{build}, host:{host}, user:{user}, run:{started_at}
License
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 runstamp-1.0.0.tar.gz.
File metadata
- Download URL: runstamp-1.0.0.tar.gz
- Upload date:
- Size: 11.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
deec6ccada10744d21898b8993f7558c4b45e84928f534878e145dc8b20a4bf9
|
|
| MD5 |
8eab0213beb987ac0cc3e6fe12fedb60
|
|
| BLAKE2b-256 |
c08d8ed8459e8a296a6f3068bd3802648d71b0a2823cee15143504bb1eb2c2cc
|
Provenance
The following attestation bundles were made for runstamp-1.0.0.tar.gz:
Publisher:
publish-pypi.yml on miriada-io/runstamp
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
runstamp-1.0.0.tar.gz -
Subject digest:
deec6ccada10744d21898b8993f7558c4b45e84928f534878e145dc8b20a4bf9 - Sigstore transparency entry: 1553147477
- Sigstore integration time:
-
Permalink:
miriada-io/runstamp@dd7d3233c34da1e72590f179791faae1236c47fc -
Branch / Tag:
refs/tags/v1.0.0 - Owner: https://github.com/miriada-io
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@dd7d3233c34da1e72590f179791faae1236c47fc -
Trigger Event:
release
-
Statement type:
File details
Details for the file runstamp-1.0.0-py3-none-any.whl.
File metadata
- Download URL: runstamp-1.0.0-py3-none-any.whl
- Upload date:
- Size: 8.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
113c33f2169fd766b97087d001cb706b6c4baebf26accb0ade2afe86a8309993
|
|
| MD5 |
dbd95ac8f3e329fd17f47224602b629d
|
|
| BLAKE2b-256 |
81347c9c79704f75a6ae1893bfb6b18e61737b63fe2fdd4b71d339f638d53c73
|
Provenance
The following attestation bundles were made for runstamp-1.0.0-py3-none-any.whl:
Publisher:
publish-pypi.yml on miriada-io/runstamp
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
runstamp-1.0.0-py3-none-any.whl -
Subject digest:
113c33f2169fd766b97087d001cb706b6c4baebf26accb0ade2afe86a8309993 - Sigstore transparency entry: 1553147481
- Sigstore integration time:
-
Permalink:
miriada-io/runstamp@dd7d3233c34da1e72590f179791faae1236c47fc -
Branch / Tag:
refs/tags/v1.0.0 - Owner: https://github.com/miriada-io
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@dd7d3233c34da1e72590f179791faae1236c47fc -
Trigger Event:
release
-
Statement type: