Warning
tomlantic is at 0.2.1 and currently, only i use it myself. it isn't battle tested,
so issues may arise.
if you're willing to run into potential bugs and issues, feel free to use it!
marrying pydantic models and tomlkit documents for data validated, style-preserving toml files
uses generics to automagically preserve model types, so you don't lose out on model type information :D
there are three notable methods to use tomlantic with your project:
-
install from pypi
pip install tomlantic
-
install from source
pip install git+https://github.com/markjoshwel/tomlantic
-
directly include tomlantic.py in your project
wget https://raw.githubusercontent.com/markjoshwel/tomlantic/main/tomlantic/tomlantic.py
tomlantic is a single file module and is free and unencumbered software released into the public domain. so, use it however you please!
see the licence section for more information.
import pydantic
import tomlkit
from tomlantic import ModelBoundTOML
class Project(pydantic.BaseModel):
model_config = pydantic.ConfigDict(validate_assignment=True)
name: str
description: str
typechecked: bool
class File(pydantic.BaseModel):
model_config = pydantic.ConfigDict(validate_assignment=True)
project: Project
toml_doc = tomlkit.parse(
"[project]\n"
'name = "tomlantic"\n'
'description = "marrying pydantic models and tomlkit documents"\n'
"typechecked = false\n"
)
# where tomlantic comes in handy
toml = ModelBoundTOML(File, toml_doc)
# access the model with .model and change the model freely
model: File = toml.model
model.project.typechecked = True
# dump the model back to a toml document
new_toml_doc = toml.model_dump_toml()
assert new_toml_doc["project"]["typechecked"] == True # type: ignore
print(new_toml_doc.as_string())
tomlantic also comes with a neat set of validators to use with handling pydantic model fields and/or the toml document itself:
- tomlantic.validate_to_specific_type
- tomlantic.validate_to_multiple_types
- tomlantic.validate_homogeneous_collection
- tomlantic.validate_heterogeneous_collection
- tomlantic.ModelBoundTOML
- tomlantic.Difference
- tomlantic.get_toml_field
- tomlantic.set_toml_field
- tomlantic.TomlanticException
- tomlantic.TOMLBaseSingleError
- tomlantic.TOMLAttributeError
- tomlantic.TOMLFrozenError
- tomlantic.TOMLMissingError
- tomlantic.TOMLValueError
- tomlantic.TOMLValidationError
- tomlantic.validate_to_specific_type
- tomlantic.validate_to_multiple_types
- tomlantic.validate_homogeneous_collection
- tomlantic.validate_heterogeneous_collection
tomlantic's magical glue class for pydantic models and tomlkit documents
will handle pydantic.ValidationErrors into more toml-friendly error messages.
set handle_errors
to False
to raise the original
pydantic.ValidationError
-
attributes:
- model:
pydantic.BaseModel
- model:
-
initialisation arguments:
- model:
pydantic.BaseModel
- toml:
tomlkit.TOMLDocument
- human_errors:
bool
=False
- model:
-
raises:
tomlantic.TOMLValidationError
if the document does not validate with the modelpydantic.ValidationError
if the document does not validate with the model andhandle_errors
isFalse
-
methods:
-
usage:
# instantiate the class toml = ModelBoundTOML(YourModel, tomlkit.parse(...)) # access your model with .model toml.model.message = "blowy red vixens fight for a quick jump" # dump the model back to a toml document toml_document = toml.model_dump_toml() # or to a toml string toml_string = toml.model_dump_toml().as_string()
method that dumps the model as a style-preserved tomlkit.TOMLDocument
-
signature:
def model_dump_toml(self) -> TOMLDocument:
-
returns
tomlkit.TOMLDocument
safely retrieve a field by it's location. not recommended for general use due to a lack of type information, but useful when accessing fields programatically
-
signature:
def get_field( self, location: Union[str, Tuple[str, ...]], default: Any = None, ) -> Any: ...
-
arguments:
- location:
Union[str, Tuple[str, ...]]
- default:
Any
=None
- location:
-
returns the field if it exists, otherwise
default
sets a field by it's location. not recommended for general use due to a lack of type safety, but useful when setting fields programatically
will handle pydantic.ValidationError
into more toml-friendly error messages.
set handle_errors
to False
to raise the original pydantic.ValidationError
-
signature:
def set_field( self, location: Union[str, Tuple[str, ...]], value: Any, handle_errors: bool = True, ) -> None: ...
-
arguments:
- location:
Union[str, Tuple[str, ...]]
- value:
Any
- handle_errors:
bool
= True
- location:
-
raises:
AttributeError
if the field does not existtomlantic.TOMLValidationError
if the document does not validate with the modelpydantic.ValidationError
if the document does not validate with the model andhandle_errors
isFalse
returns a tomlantic.Difference object of the incoming and outgoing fields that were changed between the model and the comparison_document
-
signature:
def difference_between_document( self, incoming_document: TOMLDocument ) -> Difference: ...
-
arguments:
- incoming_document:
tomlkit.TOMLDocument
- incoming_document:
-
returns
tomlantic.Difference
override fields with those from a new document
by default, this method selectively overrides fields. so fields that have been changed in the model will NOT be overriden by the incoming document
pass False
to the selective
argument to override ALL fields in the model with
the fields of the incoming document
no changes are applied until the incoming document passes all model validations
-
signature:
def load_from_document( self, incoming_document: TOMLDocument, selective: bool = True, ) -> None:
-
arguments:
- incoming_document:
tomlkit.TOMLDocument
- selective:
bool
=False
- incoming_document:
a named tuple for the differences between an outgoing tomlantic.ModelBoundTOML and a tomlkit.TOMLDocument
-
signature:
class Difference(NamedTuple): ...
-
attributes:
- incoming_changed_fields:
Tuple[str, ...]
- outgoing_changed_fields:
Tuple[str, ...]
- incoming_changed_fields:
safely retrieve a field by it's location. not recommended for general use due to a lack of type information, but useful when accessing fields programatically
-
signature:
def get_toml_field( document: TOMLDocument, location: Union[str, Tuple[str, ...]], default: Any = None, ) -> Any:
-
arguments:
- document:
TOMLDocument
- location:
Union[str, Tuple[str, ...]]
- default:
Any
=None
- document:
-
returns the field if it exists, otherwise
default
safely retrieve a toml documents field by it's location. not recommended for general use due to a lack of type information, but useful when accessing fields programatically
raises KeyError
if the field does not exist, or a LookupError
if attempting to
set a field in a non-table
if handling for errors, handle KeyError
before LookupError
as LookupError
is
the base class for KeyError
-
signature:
def set_toml_field( document: TOMLDocument, location: Union[str, Tuple[str, ...]], value: Any, ) -> None:
-
arguments:
- document:
TOMLDocument
- location:
Union[str, Tuple[str, ...]]
- value:
Any
- document:
base exception class for all tomlantic errors
-
signature:
class TomlanticException(Exception): ...
the hierarchy of exceptions that inherit this class are:
TomlanticException
├── TOMLValidationError
└── TOMLBaseSingleError
├── TOMLAttributeError
├── TOMLFrozenError
├── TOMLMissingError
├── TOMLValueError
└── TOMLValidationError
base exception class for single errors, e.g. TOMLMissingError, TOMLValueError
inherits TomlanticException
base exception class for all tomlantic errors
-
signature:
class TOMLBaseSingleError(TomlanticException): ...
-
attributes:
-
loc:
Tuple[str, ...]
the location of the error in the toml document
example:('settings', 'name') = settings.name
-
msg:
str
the error 'message' (if any) -
pydantic_error:
pydantic_core.ErrorDetails
the original pydantic error, this is what you see in the list of errors when you handle apydantic.ValidationError
-
error raised when an field does not exist, or is an extra field not in the model and the model has forbidden extra fields
inherits TOMLBaseSingleError, go there for attributes
-
signature:
class TOMLAttributeError(TOMLBaseSingleError): ...
error raised when assigning a value to a frozen field or value
inherits TOMLBaseSingleError, go there for attributes
-
signature:
class TOMLFrozenError(TOMLBaseSingleError): ...
raised when a toml document does not contain all the required fields/tables of a model
inherits TOMLBaseSingleError, go there for attributes
-
signature:
class TOMLMissingError(TOMLBaseSingleError): ...
raised when an item in a toml document is invalid for its respective model field
inherits TOMLBaseSingleError, go there for attributes
-
signature:
class TOMLValueError(TOMLBaseSingleError): ...
a toml-friendly version of pydantic.ValidationError, raised when instantiating tomlantic.ModelBoundTOML
inherits TomlanticException
-
signature:
class TOMLValidationError(TomlanticException): ...
-
attributes:
- errors:
Tuple[TOMLBaseSingleError, ...]
all validation errors raised when validating the toml document with the model
- errors:
validate a value's type to be a specific type
-
signature:
def validate_to_specific_type(v: Any, t: Type[T]) -> T: ...
-
usage:
validate_to_specific_type("hello", str) # returns "hello" validate_to_specific_type(42, str) # raises ValueError
validate a value's type to be in a tuple of specific types
-
signature:
def validate_to_multiple_types(v: Any, t: Tuple[Type[Ts], ...]) -> Ts:
-
usage:
validate_to_multiple_types("hello", (str, int)) # returns "hello" validate_to_multiple_types(42, (str, int)) # returns 42 validate_to_multiple_types(42.0, (str, int)) # raises ValueError
validate values of a collection to a specific type
-
signature:
def validate_homogeneous_collection(v: Any, t: Type[T]) -> Collection[T]:
-
usage:
validate_homogeneous_collection([1, 2, 3], int) # returns [1, 2, 3] validate_homogeneous_collection([1, 2, "3"], int) # raises ValueError
validate values of a collection to a specific type or a tuple of types
-
signature:
def validate_heterogeneous_collection(v: Collection[Any], t: Tuple[Type[Ts], ...]) -> Collection[Ts]: ...
-
usage:
validate_heterogeneous_collection([1, 2, "3"], (int, str)) # returns [1, 2, "3"] validate_heterogeneous_collection([1, 2, "3"], (int, float)) # raises ValueError
tomlantic is free and unencumbered software released into the public domain. for more information, please refer to UNLICENCE, https://unlicense.org, or the python module docstring.
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to <http://unlicense.org/>