diff --git a/src/baseframe/forms/auto.py b/src/baseframe/forms/auto.py index 8bceef8c..5fe7f6ce 100644 --- a/src/baseframe/forms/auto.py +++ b/src/baseframe/forms/auto.py @@ -51,7 +51,7 @@ def render_form( with_chrome: bool = True, action: t.Optional[str] = None, autosave: bool = False, - draft_revision: t.Optional[int] = None, + draft_revision: t.Optional[t.Any] = None, template: str = '', ) -> Response: """Render a form.""" diff --git a/src/baseframe/forms/fields.py b/src/baseframe/forms/fields.py index ce8b0a02..bbd7f981 100644 --- a/src/baseframe/forms/fields.py +++ b/src/baseframe/forms/fields.py @@ -20,6 +20,7 @@ from werkzeug.datastructures import MultiDict from wtforms import Form as WTForm from wtforms.fields import ( + DateTimeField as DateTimeFieldBase, Field, FieldList, FileField, @@ -27,6 +28,7 @@ SelectField as SelectFieldBase, SelectMultipleField, SubmitField, + TextAreaField as TextAreaFieldBase, ) from wtforms.utils import unset_value from wtforms.widgets import Select as OriginalSelectWidget @@ -122,6 +124,12 @@ def process( def populate_obj(self, *_args: t.Any, **_kwargs: t.Any) -> None: """Override populate_obj to not attempt setting nonce on the object.""" + def get_default(self) -> str: + """Get default value.""" + if callable(default := self.default): + return default() + return default + class RecaptchaField(RecaptchaFieldBase): """RecaptchaField with an improved validator.""" @@ -270,7 +278,7 @@ def process_formdata(self, valuelist: t.List[str]) -> None: self.data = bleach.linkify(self.data or '', callbacks=[]) -class DateTimeField(wtforms.fields.DateTimeField): +class DateTimeField(DateTimeFieldBase): """ A text field which stores a `datetime.datetime` matching a format. @@ -365,14 +373,14 @@ def process_formdata(self, valuelist: t.List[str]) -> None: if valuelist: # We received a timestamp from the browser. Parse and save it data: t.Optional[datetime] = None - # Valuelist will contain `date` and `time` as two separate values + # `valuelist` will contain `date` and `time` as two separate values # if the widget is rendered as two parts. If so, parse each at a time # and use it as a default to replace values from the next value. If the # front-end renders a single widget, the entire content will be parsed once. for value in valuelist: if value.strip(): try: - # dateutil cannot handle ISO and European-style dates at the + # `dateutil` cannot handle ISO and European-style dates at the # same time, so `dayfirst` MUST be False. Setting it to True # will interpret YYYY-DD-MM instead of YYYY-MM-DD. Bug report: # https://github.com/dateutil/dateutil/issues/402 @@ -381,7 +389,7 @@ def process_formdata(self, valuelist: t.List[str]) -> None: ) except (ValueError, OverflowError, TypeError): # TypeError is not a documented error for `parser.parse`, but - # the DateTimeField implementation in wtforms_dateutil says + # the DateTimeField implementation in `wtforms_dateutil` says # it can happen due to a known bug raise ValidationError(self.message) from None if data is not None: @@ -404,7 +412,7 @@ def process_formdata(self, valuelist: t.List[str]) -> None: self.data = None -class TextListField(wtforms.fields.TextAreaField): +class TextListField(TextAreaFieldBase): """A list field that renders as a textarea with one line per list item.""" def _value(self) -> str: diff --git a/src/baseframe/forms/widgets.py b/src/baseframe/forms/widgets.py index 23b8f1c3..7f8474c8 100644 --- a/src/baseframe/forms/widgets.py +++ b/src/baseframe/forms/widgets.py @@ -8,7 +8,7 @@ from flask import current_app, render_template from furl import furl from markupsafe import Markup, escape -from wtforms import Field as WTField +from wtforms import Field as WTField, SelectFieldBase from wtforms.widgets import RadioInput, Select, html_params from ..extensions import _ @@ -31,7 +31,7 @@ class SelectWidget(Select): """Add support of choices with ``optgroup`` to the ``Select`` widget.""" - def __call__(self, field: WTField, **kwargs: t.Any) -> Markup: + def __call__(self, field: SelectFieldBase, **kwargs: t.Any) -> Markup: kwargs.setdefault('id', field.id) if self.multiple: kwargs['multiple'] = True @@ -61,7 +61,7 @@ def __call__(self, field: WTField, **kwargs: t.Any) -> Markup: class Select2Widget(Select): """Add a select2 class to the rendered select widget.""" - def __call__(self, field: WTField, **kwargs: t.Any) -> Markup: + def __call__(self, field: SelectFieldBase, **kwargs: t.Any) -> Markup: kwargs.setdefault('id', field.id) kwargs.pop('type', field.type) if field.multiple: