Usage
Piny loads your YAML configuration file. It optionally validates data loaded from config file. Piny main logic is in a loader class. You can pass arguments in the loader class to change the way YAML file is parsed and validated.
Loaders
YamlLoader
loader class is dedicated for use in Python applications.
Based on PyYAML, it parses YAML files, (arguably) the most beautiful
file format for configuration files!
Basic loader usage is the following.
Set your environment variables
Mark up your YAML configuration file with these env names:
db:
login: user
password: ${DB_PASSWORD}
mail:
login: user
password: ${MAIL_PASSWORD:-my_default_password}
sentry:
dsn: ${VAR_NOT_SET}
In your app load config with Piny:
from piny import YamlLoader
config = YamlLoader(path="config.yaml").load()
print(config)
# {'db': {'login': 'user', 'password': 'my_db_password'},
# 'mail': {'login': 'user', 'password': 'my_default_password'},
# 'sentry': {'dsn': None}}
YamlStreamLoader
class primary use is Piny CLI tool (see Command line utility).
But it also can be used interchargably with YamlLoader
whenever IO streams
are used instead of file paths.
- class piny.loaders.YamlLoader(path: str, *, matcher: ~typing.Type[~piny.matchers.Matcher] = <class 'piny.matchers.MatcherWithDefaults'>, validator: ~typing.Type[~piny.validators.Validator] | None = None, schema: ~typing.Any = None, **schema_params)[source]
Bases:
object
YAML configuration file loader
- class piny.loaders.YamlStreamLoader(stream: str | ~typing.IO[str], *, matcher: ~typing.Type[~piny.matchers.Matcher] = <class 'piny.matchers.MatcherWithDefaults'>, validator: ~typing.Type[~piny.validators.Validator] | None = None, schema: ~typing.Any = None, **schema_params)[source]
Bases:
YamlLoader
YAML configuration loader for IO streams, e.g. file objects or stdin
Matchers
In the Loaders section we used Bash-style environment variables with defaults. You may want to discourage such envs in your project. This is where matchers come in handy. They apply a regular expression when parsing your YAML file that matches environment variables we want to interpolate.
By default MatcherWithDefaults
is used. StrictMatcher
is another
matcher class used for plain vanilla envs with no default values support.
Both strict and default matchers return None
value if environment variable
matched is not set in the system.
Basic usage example is the following:
from piny import YamlLoader, StrictMatcher
config = YamlLoader(path="config.yaml", matcher=StrictMatcher).load()
- class piny.matchers.Matcher(stream)[source]
Bases:
SafeLoader
Base class for matchers
Use this class only to derive new child classes
- matcher: Pattern[str] = re.compile('')
Validators
Piny supports optional data validation using third-party libraries: Marshmallow, Pydantic, Trafaret.
In order to use data validation pass validator
and schema
arguments
in the Loaders class. You may also initialize loader class
with optional named arguments that will be passed to the validator’s schema.
Additional loading arguments may be passed in load
method invocation.
- class piny.validators.MarshmallowValidator(schema: Any, **params)[source]
Bases:
Validator
Validator class for Marshmallow library
- class piny.validators.PydanticV2Validator(schema: Any, **params)[source]
Bases:
Validator
Validator class for Pydantic Version 2
- class piny.validators.PydanticValidator(schema: Any, **params)[source]
Bases:
Validator
Validator class for Pydantic Version 1
- class piny.validators.TrafaretValidator(schema: Any, **params)[source]
Bases:
Validator
Validator class for Trafaret library
- class piny.validators.Validator(schema: Any, **params)[source]
Bases:
ABC
Abstract base class for optional validator classes
Use only to derive new child classes, implement all abstract methods
Marshmallow validation example
import marshmallow as ma
from piny import MarshmallowValidator, StrictMatcher, YamlLoader
class DBSchema(ma.Schema):
login = ma.fields.String(required=True)
password = ma.fields.String()
class ConfigSchema(ma.Schema):
db = ma.fields.Nested(DBSchema)
config = YamlLoader(
path="database.yaml",
matcher=StrictMatcher,
validator=MarshmallowValidator,
schema=ConfigSchema,
).load(many=False)
Pydantic validation example
from pydantic import BaseModel
from piny import PydanticV2Validator, StrictMatcher, YamlLoader
# Watch out!
# Pydantic V2 deprecated some model's methods:
# https://docs.pydantic.dev/2.0/migration/
#
# For Pydantic v2 use `PydanticV2Validator`
# For Pydantic v1 use `PydanticValidator`
class DBModel(BaseModel):
login: str
password: str
class ConfigModel(BaseModel):
db: DBModel
config = YamlLoader(
path="database.yaml",
matcher=StrictMatcher,
validator=PydanticV2Validator,
schema=ConfigModel,
).load()
Trafaret validation example
import trafaret
from piny import TrafaretValidator, StrictMatcher, YamlLoader
DBSchema = trafaret.Dict(login=trafaret.String, password=trafaret.String)
ConfigSchema = trafaret.Dict(db=DBSchema)
config = YamlLoader(
path="database.yaml",
matcher=StrictMatcher,
validator=TrafaretValidator,
schema=ConfigSchema,
).load()
Exceptions
LoadingError
is thrown when something goes wrong with reading or
parsing a YAML file. ValidationError
is a wrapper for exceptions
raised by the libraries for optional data validation. Original exception
can be accessed by origin
attribute. It comes in handy when you need
more than just an original exception message (e.g. a dictionary of validation
errors).
Both exceptions inherit from the ConfigError
.
- exception piny.errors.ConfigError(origin: Exception | None = None, **context: Any)[source]
Bases:
PinyErrorMixin
,Exception
Base class for Piny exceptions
- exception piny.errors.LoadingError(origin: Exception | None = None, **context: Any)[source]
Bases:
ConfigError
Exception for reading or parsing configuration file errors
- msg_template: str = 'Loading YAML file failed: {reason}'
- class piny.errors.PinyErrorMixin(origin: Exception | None = None, **context: Any)[source]
Bases:
object
Mixin class to wrap and format original exception
- msg_template: str
- exception piny.errors.ValidationError(origin: Exception | None = None, **context: Any)[source]
Bases:
ConfigError
Exception for data validation errors
- msg_template: str = 'Validation failed: {reason}'
Command line utility
Piny comes with CLI tool that substitutes the values of environment variables
in input file or stdin
and write result to an output file or stdout
.
Piny CLI utility is somewhat similar to GNU/gettext
envsubst but works
with files too.
piny
Substitute environment variables with their values.
Read INPUT, find environment variables in it, substitute them with their values and write to OUTPUT.
INPUT and OUTPUT can be files or standard input and output respectively. With no INPUT, or when INPUT is -, read standard input. With no OUTPUT, or when OUTPUT is -, write to standard output.
Examples:
piny [OPTIONS] [INPUT] [OUTPUT]
Options
- --strict, --no-strict
Enable or disable strict matcher
Arguments
- INPUT
Optional argument
- OUTPUT
Optional argument