This release has been yanked by its maintainers, and will be ignored by installers, except when explicitly specified.
Consider using release 3000.7.1 instead.
Reason given by maintainers: Logs the 1Password service-account token when authentication is retried. Upgrade to 3000.7.1. See GHSA-3rmr-35mv-wrrp.
A convenient way to load your app configuration from 1Password.
This project is licensed under the terms of the MIT license.
Quick Start
import asyncio
import os
from configator import load_config
from pydantic import BaseModel
class DatabaseConfig(BaseModel):
host: str
port: int
username: str
password: str
class AppConfig(BaseModel):
api_key: str
debug: bool
timeout: int
class Config(BaseModel):
db: DatabaseConfig
app: AppConfig
debug: bool = False
async def main():
token = os.getenv("OP_SERVICE_ACCOUNT_TOKEN")
cfg: Config = await load_config(
schema=Config,
token=token,
vault="REPO whatever",
item="whatever-develop",
)
assert cfg.db.port == 5432
asyncio.run(main())
Developer Mode
For local development, you can override configuration values using a .env file by setting the CONFIGATOR_DEV_MODE environment variable:
export CONFIGATOR_DEV_MODE=1
When developer mode is enabled, values are loaded with the following priority (highest to lowest):
.envfile- Environment variables
- 1Password values (via initialization parameters)
Without developer mode, the standard priority applies (1Password values take precedence over environment variables and .env files).
⚠️ Never enable developer mode in production. A stray
.envfile would silently override vetted secrets. Configator guards against this: ifCONFIGATOR_DEV_MODEis set whileENVIRONMENT(or, as a fallback,APP_ENV) resolves to production — any value case-insensitively starting withproduct, e.g.productorproduction— instantiating a config model raises aRuntimeError. Production deployments must ensureCONFIGATOR_DEV_MODEis unset and that no.envfile ships in production images.
This feature works with the provided common configuration models (PostgresConfig, SentryConfig). For your own config schemas, you can simply extend ConfigatorSettings to get this behavior.
Installation
uv add "git+https://github.com/Utiligize/configator@v3000.0.0"
or, if you like the bleeding edge:
uv add "git+https://github.com/Utiligize/configator"
For information on how to authenticate uv with GitHub, see https://docs.astral.sh/uv/concepts/authentication/git/.
For information on how to use private repos in GitHub Actions, see https://docs.astral.sh/uv/guides/integration/github/#private-repos. If you create a fine-grained access token, it simply needs the "Content" read permission.
Writing Config Classes
Define your app's config as a class deriving from Pydantic's BaseModel. The field names will be matched against the 1Password item field titles, and the values loaded from them. The field names are treated as lower snake case, and item field names in 1Password are converted accordingly when matching. For example, a Python model with a field called sentry_key will match a 1Password item with a field title of SENTRY_KEY or sentry-key. It is therefore important to ensure that field names are unique, at least within sections.
Nested models are loaded from separate sections in the 1Password item. Fields in these nested models can have the same name as fields in other sections. Fields in the base config class are found by name, no matter their section (but the intention is for them to be added without one), so the names of these must be unique in the full model.
Supported Features
- Basic types (
str,int,float, evencomplex) are simply parsed from the string in 1Password. decimal.Decimalis also supported and should usually be preferred overfloat.- Booleans are special: since any string is truthy in Python, a
boolmust have one of 8 (case-insensitive) values:- "true", "1", "yes", and "on" are interpreted as
True. - "false", "0", "no", and "off" are interpreted as
False. - any other value for a field defined as
boolwill raise aValueError.
- "true", "1", "yes", and "on" are interpreted as
- Collections (
dict,list,set) are loaded by interpreting the string value in 1Password as JSON and passing that object to the constructor. This means that a set can be constructed from what looks like a list, for example. - Any string starting with
op://will be resolved recursively (up to a depth of 10 links). All references in the config item are resolved together, one batched request per level of nesting, so a schema with many referencing fields costs a handful of 1Password requests rather than one per field. The request count for each load is emitted as an info log line. - Every 1Password call is retried individually on transient failures (3 attempts, with no further attempt scheduled more than 10 seconds after the first), so a retry costs one request rather than a full reload. The cap bounds retrying, not a single hung request — the SDK exposes no request timeout. Rate-limit errors are never retried: they are logged and raised immediately, because the hourly read budget can be up to an hour from resetting and each retry would spend a request against a budget that is already empty.
Planned Features
- Providing access to extra fields in the config item when
model_config = ConfigDict(extra='allow')is specified in the input model. See https://docs.pydantic.dev/latest/api/config/#pydantic.config.ConfigDict.extra.
Unsupported Features
-
Typed collections are sadly not supported, because it confuses the
issubclassmatching of fields. This means that fields in your config model must be defined as e.g. plaindict, notdict[str, str]. -
OptionalandUnionfields are not supported, i.e. you cannot do either offoo: str | None = None bar: Optional[str] baz: int | float
because it confuses the hydrator, who won't know which constructor to call or will try to initialize
None. -
While
defaultvalues are supported,default_factoryis not. -
Basic Python types
bytesandbytearraymay work but are not officially supported.
Development
Setup
uv sync
Lint and Format
just lint
Run Tests
just test
Run Failed Tests
just test-failed
◼️◼️◼️
Release files for configator-op 3000.6.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| configator_op-3000.6.0.tar.gz | 27.3 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| configator_op-3000.6.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 40.2 kB
Release files / configator_op-3000.6.0.tar.gz
| Download URL | configator_op-3000.6.0.tar.gz |
|---|---|
| Size | 27.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
9d9c41f9c66e073a8bc0dbcc21345e53429c4041140abd807be60a40cec79a32
|
|
BLAKE2b-256 checksum How to use checksums |
7ef40943475b4e054f0d0e8ec18ec38dc42eabe26b3de069330283a4293cae4e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.2
|
Release files / configator_op-3000.6.0-py3-none-any.whl
| Download URL | configator_op-3000.6.0-py3-none-any.whl |
|---|---|
| Size | 13.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
0df3649278aa56e0c6645a5e15122877d6cce14111331951319fd340b9ee228b
|
|
BLAKE2b-256 checksum How to use checksums |
c946ab05c72f0757135008afbd2e979bfa7087c3c6baaa352f1798ad718f6903
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.2
|