Add a validator#

Validators in Cookieplone check user input at prompt time. They live in cookieplone/validators/__init__.py and return bool (True means the value is valid).

Understand the contract#

A validator is a plain function that accepts a single str value and returns bool:

def my_validator(value: str) -> bool:
    """Return True if value passes the check."""
    return bool(value)
  • Return True → the value is accepted.

  • Return False → the prompt repeats and asks the user to try again.

Add the validator function#

Open cookieplone/validators/__init__.py. Add the new function, following the existing pattern:

def semver(value: str) -> bool:
    """Validate that value is a valid SemVer string (MAJOR.MINOR.PATCH)."""
    import re
    pattern = r"^\d+\.\d+\.\d+$"
    return bool(re.match(pattern, value))

If the underlying logic is non-trivial, add a helper to cookieplone/utils/validators.py and call it from here (following the pattern of hostname, python_package_name, and others).

Wire the validator to a field name (optional)#

If the new validator applies to a field that appears in many templates by name, add it to DEFAULT_VALIDATORS in cookieplone/settings.py:

DEFAULT_VALIDATORS = {
    "plone_version": "cookieplone.validators.plone_version",
    "volto_version": "cookieplone.validators.volto_version",
    "python_package_name": "cookieplone.validators.python_package_name",
    "hostname": "cookieplone.validators.hostname",
    "language_code": "cookieplone.validators.language_code",
    "semver_field": "cookieplone.validators.semver",  # new entry
}

Any template field named semver_field then runs semver automatically without any extra configuration.

Template authors can also reference it explicitly via the validator key in cookieplone.json:

{
  "version": "2.0",
  "properties": {
    "api_version": {
      "type": "string",
      "title": "API version",
      "default": "1.0.0",
      "validator": "cookieplone.validators.semver"
    }
  }
}

Write a test#

Add a test in tests/validators/:

# tests/validators/test_semver.py
from cookieplone.validators import semver


def test_semver_valid():
    assert semver("1.2.3") is True


def test_semver_invalid_missing_patch():
    assert semver("1.2") is False


def test_semver_invalid_text():
    assert semver("latest") is False


def test_semver_empty():
    assert semver("") is False

Run the test:

uv run pytest tests/validators/test_semver.py -v

Verify the full test suite still passes#

make test

Document the validator#

Add a row for the new validator in Validators reference. Note whether it is wired into DEFAULT_VALIDATORS.