"""Marshmallow schemas."""
from __future__ import annotations
from marshmallow import Schema
from marshmallow_polyfield import PolyField
from sortedcontainers import SortedDict
from nitpick import fields
from nitpick.blender import flatten_quotes
from nitpick.constants import PYTHON_SETUP_CFG, READ_THE_DOCS_URL
[docs]def flatten_marshmallow_errors(errors: dict) -> str:
"""Flatten Marshmallow errors to a string."""
formatted = []
for field, data in SortedDict(flatten_quotes(errors)).items():
if isinstance(data, (list, tuple)):
messages_per_field = [f"{field}: {', '.join(data)}"]
else:
# This should not happen; if it does, let's just convert to a string
messages_per_field = [f"{field}: {data}"]
formatted.append("\n".join(messages_per_field))
return "\n".join(formatted)
[docs]def help_message(sentence: str, help_page: str) -> str:
"""Show help with the documentation URL on validation errors."""
clean_sentence = sentence.strip(" .")
return f"{clean_sentence}. See {READ_THE_DOCS_URL}{help_page}."
[docs]class BaseNitpickSchema(Schema):
"""Base schema for all others, with default error messages."""
error_messages = {"unknown": help_message("Unknown configuration", "nitpick_section.html")} # noqa: RUF012
[docs]class NitpickStylesSectionSchema(BaseNitpickSchema):
"""Validation schema for the ``[nitpick.styles]`` section on the style file."""
error_messages = { # noqa: RUF012
"unknown": help_message("Unknown configuration", "nitpick_section.html#nitpick-styles")
}
include = PolyField(deserialization_schema_selector=fields.string_or_list_field)
[docs]class IniSchema(BaseNitpickSchema):
"""Validation schema for INI files."""
error_messages = { # noqa: RUF012
"unknown": help_message("Unknown configuration", "nitpick_section.html#comma-separated-values")
}
comma_separated_values = fields.List(fields.String(validate=fields.validate_section_dot_field))
[docs]class NitpickFilesSectionSchema(BaseNitpickSchema):
"""Validation schema for the ``[nitpick.files]`` section on the style file."""
error_messages = {"unknown": help_message("Unknown file", "nitpick_section.html#nitpick-files")} # noqa: RUF012
absent = fields.Dict(fields.NonEmptyString, fields.String())
present = fields.Dict(fields.NonEmptyString, fields.String())
# TODO: refactor: load this schema dynamically, then add this next field setup_cfg
setup_cfg = fields.Nested(IniSchema, data_key=PYTHON_SETUP_CFG)
[docs]class NitpickSectionSchema(BaseNitpickSchema):
"""Validation schema for the ``[nitpick]`` section on the style file."""
meta = fields.Nested(NitpickMetaSchema)
minimum_version = fields.NonEmptyString()
styles = fields.Nested(NitpickStylesSectionSchema)
files = fields.Nested(NitpickFilesSectionSchema)
[docs]class BaseStyleSchema(Schema):
"""Base validation schema for style files.
Dynamic fields will be added to it later.
"""
error_messages = {"unknown": help_message("Unknown file", "plugins.html")} # noqa: RUF012
nitpick = fields.Nested(NitpickSectionSchema)