asyncron/asyncron/fields/toml.py

84 lines
2.4 KiB
Python

from django.db import models
from django.forms import fields
from asyncron.widgets import Codearea
import tomlkit
from tomlkit.exceptions import ParseError
from tomlkit.toml_document import TOMLDocument
class InvalidTOMLInput(str):
pass
class TOMLFormField( fields.JSONField ):
default_error_messages = {
"invalid": "Enter a valid TOML.",
}
widget = Codearea( language = "ini" )
def to_python(self, value):
if self.disabled: return value
if isinstance(value, (list, dict, int, float)): return value
try:
converted = tomlkit.loads( value )
except ParseError:
raise ValidationError(
self.error_messages["invalid"],
code="invalid",
params={"value": value},
)
return converted
def bound_data(self, data, initial):
if self.disabled: return initial
if data is None: return None
try:
return tomlkit.loads( data )
except ParseError:
return InvalidTOMLInput(data)
def prepare_value(self, value):
if isinstance(value, InvalidTOMLInput): return value
return value.as_string()
class TOMLField( models.JSONField ):
empty_strings_allowed = True
description = "A TOML Field"
def from_db_value(self, *args, **kwargs):
value_as_dict = super().from_db_value(*args, **kwargs)
#This is a cop-out, but I don't have time to do this properly even though it's very interesting.
#But duplicating the date on fields that are meant to be human readable, isn't a serious problem.
#
# Links to related parts of tomlkit in case I decide to improve on this later:
# - as_string function which decies which renderer to choose
# - https://github.com/python-poetry/tomlkit/blob/6042e0ce80c8c49f325a6e60b6ee3e153669b144/tomlkit/container.py#L485
#
# - The simple renderer which has the item.as_string bit that we have to optimize out.
# - https://github.com/python-poetry/tomlkit/blob/6042e0ce80c8c49f325a6e60b6ee3e153669b144/tomlkit/container.py#L633
#
try: value_as_toml = tomlkit.loads( value_as_dict.pop('_toml', '') )
except: value_as_toml = tomlkit.document()
value_as_toml.update( value_as_dict )
return value_as_toml
def get_prep_value(self, *args, **kwargs):
result = super().get_prep_value( *args, **kwargs )
if not isinstance( result, TOMLDocument ): return result
as_dict = result.unwrap()
as_dict['_toml'] = result.as_string()
return as_dict
def formfield( self, *args, **kwargs ):
kwargs['form_class'] = TOMLFormField
return super().formfield(*args, **kwargs)