Python
Install
Section titled “Install”From the release
Section titled “From the release”v0.1.3 ships abi3 wheels for Python 3.11+ on Windows, macOS and Linux (glibc), x64 and arm64, built with PyO3 and maturin, with no runtime dependencies. Install the wheel for your platform straight from the release:
# x64pip install https://github.com/Netizine/sourceorrery/releases/download/v0.1.3/sourceorrery-0.1.3-cp311-abi3-win_amd64.whl# Arm64pip install https://github.com/Netizine/sourceorrery/releases/download/v0.1.3/sourceorrery-0.1.3-cp311-abi3-win_arm64.whl# Apple siliconpip install https://github.com/Netizine/sourceorrery/releases/download/v0.1.3/sourceorrery-0.1.3-cp311-abi3-macosx_11_0_arm64.whl# Intelpip install https://github.com/Netizine/sourceorrery/releases/download/v0.1.3/sourceorrery-0.1.3-cp311-abi3-macosx_10_12_x86_64.whl# x64pip install https://github.com/Netizine/sourceorrery/releases/download/v0.1.3/sourceorrery-0.1.3-cp311-abi3-manylinux_2_28_x86_64.whl# arm64pip install https://github.com/Netizine/sourceorrery/releases/download/v0.1.3/sourceorrery-0.1.3-cp311-abi3-manylinux_2_28_aarch64.whlTo pin it, put the same URL in requirements.txt as
sourceorrery @ https://…/sourceorrery-0.1.3-cp311-abi3-win_amd64.whl;
append #sha256=<hash> with the hash from the release’s SHA256SUMS and
pip verifies the download. Any other platform builds the sdist from the same
release (sourceorrery-0.1.3.tar.gz; Rust 1.88+ required) with
pip install <its URL>.
From PyPI
Section titled “From PyPI”pip install sourceorreryEvery release is on PyPI, with the same wheels and sdist.
Get a secret
Section titled “Get a secret”from sourceorrery import SecretReader
with SecretReader("development") as reader, reader.get("database-password") as secret: connect(password=secret.value.expose_text())# the value is zeroised when the `with` block endsSecretReader(vault, *, home=None, passphrase=None, passphrase_file=None, environment=True)
opens the vault. With no arguments it behaves like the CLI: SOURCEORRERY_HOME
locates the vault; the OS credential store, then SOURCEORRERY_PASSPHRASE,
then SOURCEORRERY_PASSPHRASE_FILE unlock it. Pass environment=False to
ignore the two passphrase variables.
| Call | Returns |
|---|---|
reader.get(name) |
Secret for the newest accessible version |
reader.get(name, version) |
Secret for exactly that version |
reader.properties(name, version=None) |
SecretProperties (policy not applied) |
reader.resolve("sourceorrery://development/database-password") |
Secret |
reader.descriptor() |
dict describing the vault (no values) |
reader.close() |
releases the vault; also a context manager |
Secret has .properties (a frozen dataclass: vault, name, version,
enabled, content_type, tags, not_before, expires_on, created_on,
updated_on, recovery_level, reference) and .value, a SecretValue:
value = secret.valuevalue.expose() # bytes (a copy)value.expose_text() # strlen(value)value.close() # zeroise; expose() raises ValueError afterwardsrepr(value) # 'SecretValue([REDACTED])'pickle.dumps(value), copy.copy(value) and json.dumps(value) raise
TypeError.
Errors
Section titled “Errors”All exceptions derive from sourceorrery.SourceOrreryError and carry
.code, .message and .hint; str(err) is the message followed by the
hint.
from sourceorrery import SecretReader, SecretNotFoundError, VaultLockedError, SourceOrreryError
try: with SecretReader("development") as reader: secret = reader.get("database-password")except VaultLockedError as err: print(err.hint) # which passphrase sources were tried, how to add a protectorexcept SecretNotFoundError as err: print(err.hint) # "Store it with `sourceorrery secret set database-password --vault development` ..."except SourceOrreryError as err: print(err.code, err)Classes: VaultNotFoundError, VaultLockedError, MigrationRequiredError,
SecretNotFoundError, VersionNotFoundError, SecretDeletedError,
PolicyError with SecretDisabledError, SecretNotYetValidError
(.transient is true), SecretExpiredError, IntegrityError,
UnsupportedError, InvalidArgumentError, InvalidNameError,
ManifestError, PermissionDeniedError, StorageError. See
the SDK overview for what each hint says.
Load a project
Section titled “Load a project”from sourceorrery import Project
with Project.load("sourceorrery.toml") as project: # or Project.load() to discover it os.environ.update({s.env: s.value.expose_text() for s in project})Project.load resolves every [secrets.*] entry the way sourceorrery run
does and raises the first required secret’s error if one cannot be read.
project.env("DATABASE_PASSWORD"), project.get("database-password") and
iteration give the resolved entries.
Threads
Section titled “Threads”A SecretReader may be shared between threads; the native call releases
the GIL, so reads run in parallel.
Building from source
Section titled “Building from source”pip install maturincd bindings/python && maturin develop --releaseeval "$(bash ../../scripts/ci/fixture-vault.sh)" && python -m pytestSource: bindings/python.