Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
core.py458 linesDownload Raw Back to fields
1import inspect2import itertools3import warnings4 5from markupsafe import escape6from markupsafe import Markup7 8from wtforms import widgets9from wtforms.i18n import DummyTranslations10from wtforms.utils import unset_value11from wtforms.validators import StopValidation12from wtforms.validators import ValidationError13 14 15class Field:16    """17    Field base class18    """19 20    errors = tuple()21    process_errors = tuple()22    raw_data = None23    validators = tuple()24    widget = None25    _formfield = True26    _translations = DummyTranslations()27    do_not_call_in_templates = True  # Allow Django 1.4 traversal28 29    def __new__(cls, *args, **kwargs):30        if "_form" in kwargs:31            return super().__new__(cls)32        else:33            return UnboundField(cls, *args, **kwargs)34 35    def __init__(36        self,37        label=None,38        validators=None,39        filters=(),40        description="",41        id=None,42        default=None,43        widget=None,44        render_kw=None,45        name=None,46        _form=None,47        _prefix="",48        _translations=None,49        _meta=None,50    ):51        """52        Construct a new field.53 54        :param label:55            The label of the field.56        :param validators:57            A sequence of validators to call when `validate` is called.58        :param filters:59            A sequence of callable which are run by :meth:`~Field.process`60            to filter or transform the input data. For example61            ``StringForm(filters=[str.strip, str.upper])``.62            Note that filters are applied after processing the default and63            incoming data, but before validation.64        :param description:65            A description for the field, typically used for help text.66        :param id:67            An id to use for the field. A reasonable default is set by the form,68            and you shouldn't need to set this manually.69        :param default:70            The default value to assign to the field, if no form or object71            input is provided. May be a callable.72        :param widget:73            If provided, overrides the widget used to render the field.74        :param dict render_kw:75            If provided, a dictionary which provides default keywords that76            will be given to the widget at render time.77        :param name:78            The HTML name of this field. The default value is the Python79            attribute name.80        :param _form:81            The form holding this field. It is passed by the form itself during82            construction. You should never pass this value yourself.83        :param _prefix:84            The prefix to prepend to the form name of this field, passed by85            the enclosing form during construction.86        :param _translations:87            A translations object providing message translations. Usually88            passed by the enclosing form during construction. See89            :doc:`I18n docs <i18n>` for information on message translations.90        :param _meta:91            If provided, this is the 'meta' instance from the form. You usually92            don't pass this yourself.93 94        If `_form` isn't provided, an :class:`UnboundField` will be95        returned instead. Call its :func:`bind` method with a form instance and96        a name to construct the field.97        """98        if _translations is not None:99            self._translations = _translations100 101        if _meta is not None:102            self.meta = _meta103        elif _form is not None:104            self.meta = _form.meta105        else:106            raise TypeError("Must provide one of _form or _meta")107 108        self.default = default109        self.description = description110        self.render_kw = render_kw111        self.filters = filters112        self.flags = Flags()113        self.name = _prefix + name114        self.short_name = name115        self.type = type(self).__name__116 117        self.check_validators(validators)118        self.validators = validators or self.validators119 120        self.id = id or self.name121        self.label = Label(122            self.id,123            label124            if label is not None125            else self.gettext(name.replace("_", " ").title()),126        )127 128        if widget is not None:129            self.widget = widget130 131        for v in itertools.chain(self.validators, [self.widget]):132            flags = getattr(v, "field_flags", {})133 134            # check for legacy format, remove eventually135            if isinstance(flags, tuple):  # pragma: no cover136                warnings.warn(137                    "Flags should be stored in dicts and not in tuples. "138                    "The next version of WTForms will abandon support "139                    "for flags in tuples.",140                    DeprecationWarning,141                    stacklevel=2,142                )143                flags = {flag_name: True for flag_name in flags}144 145            for k, v in flags.items():146                setattr(self.flags, k, v)147 148    def __str__(self):149        """150        Returns a HTML representation of the field. For more powerful rendering,151        see the `__call__` method.152        """153        return self()154 155    def __html__(self):156        """157        Returns a HTML representation of the field. For more powerful rendering,158        see the :meth:`__call__` method.159        """160        return self()161 162    def __call__(self, **kwargs):163        """164        Render this field as HTML, using keyword args as additional attributes.165 166        This delegates rendering to167        :meth:`meta.render_field <wtforms.meta.DefaultMeta.render_field>`168        whose default behavior is to call the field's widget, passing any169        keyword arguments from this call along to the widget.170 171        In all of the WTForms HTML widgets, keyword arguments are turned to172        HTML attributes, though in theory a widget is free to do anything it173        wants with the supplied keyword arguments, and widgets don't have to174        even do anything related to HTML.175        """176        return self.meta.render_field(self, kwargs)177 178    @classmethod179    def check_validators(cls, validators):180        if validators is not None:181            for validator in validators:182                if not callable(validator):183                    raise TypeError(184                        "{} is not a valid validator because it is not "185                        "callable".format(validator)186                    )187 188                if inspect.isclass(validator):189                    raise TypeError(190                        "{} is not a valid validator because it is a class, "191                        "it should be an instance".format(validator)192                    )193 194    def gettext(self, string):195        """196        Get a translation for the given message.197 198        This proxies for the internal translations object.199 200        :param string: A string to be translated.201        :return: A string which is the translated output.202        """203        return self._translations.gettext(string)204 205    def ngettext(self, singular, plural, n):206        """207        Get a translation for a message which can be pluralized.208 209        :param str singular: The singular form of the message.210        :param str plural: The plural form of the message.211        :param int n: The number of elements this message is referring to212        """213        return self._translations.ngettext(singular, plural, n)214 215    def validate(self, form, extra_validators=()):216        """217        Validates the field and returns True or False. `self.errors` will218        contain any errors raised during validation. This is usually only219        called by `Form.validate`.220 221        Subfields shouldn't override this, but rather override either222        `pre_validate`, `post_validate` or both, depending on needs.223 224        :param form: The form the field belongs to.225        :param extra_validators: A sequence of extra validators to run.226        """227        self.errors = list(self.process_errors)228        stop_validation = False229 230        # Check the type of extra_validators231        self.check_validators(extra_validators)232 233        # Call pre_validate234        try:235            self.pre_validate(form)236        except StopValidation as e:237            if e.args and e.args[0]:238                self.errors.append(e.args[0])239            stop_validation = True240        except ValidationError as e:241            self.errors.append(e.args[0])242 243        # Run validators244        if not stop_validation:245            chain = itertools.chain(self.validators, extra_validators)246            stop_validation = self._run_validation_chain(form, chain)247 248        # Call post_validate249        try:250            self.post_validate(form, stop_validation)251        except ValidationError as e:252            self.errors.append(e.args[0])253 254        return len(self.errors) == 0255 256    def _run_validation_chain(self, form, validators):257        """258        Run a validation chain, stopping if any validator raises StopValidation.259 260        :param form: The Form instance this field belongs to.261        :param validators: a sequence or iterable of validator callables.262        :return: True if validation was stopped, False otherwise.263        """264        for validator in validators:265            try:266                validator(form, self)267            except StopValidation as e:268                if e.args and e.args[0]:269                    self.errors.append(e.args[0])270                return True271            except ValidationError as e:272                self.errors.append(e.args[0])273 274        return False275 276    def pre_validate(self, form):277        """278        Override if you need field-level validation. Runs before any other279        validators.280 281        :param form: The form the field belongs to.282        """283        pass284 285    def post_validate(self, form, validation_stopped):286        """287        Override if you need to run any field-level validation tasks after288        normal validation. This shouldn't be needed in most cases.289 290        :param form: The form the field belongs to.291        :param validation_stopped:292            `True` if any validator raised StopValidation.293        """294        pass295 296    def process(self, formdata, data=unset_value, extra_filters=None):297        """298        Process incoming data, calling process_data, process_formdata as needed,299        and run filters.300 301        If `data` is not provided, process_data will be called on the field's302        default.303 304        Field subclasses usually won't override this, instead overriding the305        process_formdata and process_data methods. Only override this for306        special advanced processing, such as when a field encapsulates many307        inputs.308 309        :param extra_filters: A sequence of extra filters to run.310        """311        self.process_errors = []312        if data is unset_value:313            try:314                data = self.default()315            except TypeError:316                data = self.default317 318        self.object_data = data319 320        try:321            self.process_data(data)322        except ValueError as e:323            self.process_errors.append(e.args[0])324 325        if formdata is not None:326            if self.name in formdata:327                self.raw_data = formdata.getlist(self.name)328            else:329                self.raw_data = []330 331            try:332                self.process_formdata(self.raw_data)333            except ValueError as e:334                self.process_errors.append(e.args[0])335 336        try:337            for filter in itertools.chain(self.filters, extra_filters or []):338                self.data = filter(self.data)339        except ValueError as e:340            self.process_errors.append(e.args[0])341 342    def process_data(self, value):343        """344        Process the Python data applied to this field and store the result.345 346        This will be called during form construction by the form's `kwargs` or347        `obj` argument.348 349        :param value: The python object containing the value to process.350        """351        self.data = value352 353    def process_formdata(self, valuelist):354        """355        Process data received over the wire from a form.356 357        This will be called during form construction with data supplied358        through the `formdata` argument.359 360        :param valuelist: A list of strings to process.361        """362        if valuelist:363            self.data = valuelist[0]364 365    def populate_obj(self, obj, name):366        """367        Populates `obj.<name>` with the field's data.368 369        :note: This is a destructive operation. If `obj.<name>` already exists,370               it will be overridden. Use with caution.371        """372        setattr(obj, name, self.data)373 374 375class UnboundField:376    _formfield = True377    creation_counter = 0378 379    def __init__(self, field_class, *args, name=None, **kwargs):380        UnboundField.creation_counter += 1381        self.field_class = field_class382        self.args = args383        self.name = name384        self.kwargs = kwargs385        self.creation_counter = UnboundField.creation_counter386        validators = kwargs.get("validators")387        if validators:388            self.field_class.check_validators(validators)389 390    def bind(self, form, name, prefix="", translations=None, **kwargs):391        kw = dict(392            self.kwargs,393            name=name,394            _form=form,395            _prefix=prefix,396            _translations=translations,397            **kwargs,398        )399        return self.field_class(*self.args, **kw)400 401    def __repr__(self):402        return "<UnboundField({}, {!r}, {!r})>".format(403            self.field_class.__name__, self.args, self.kwargs404        )405 406 407class Flags:408    """409    Holds a set of flags as attributes.410 411    Accessing a non-existing attribute returns None for its value.412    """413 414    def __getattr__(self, name):415        if name.startswith("_"):416            return super().__getattr__(name)417        return None418 419    def __contains__(self, name):420        return getattr(self, name)421 422    def __repr__(self):423        flags = (424            f"{name}={getattr(self, name)}"425            for name in dir(self)426            if not name.startswith("_")427        )428        return "<wtforms.fields.Flags: {%s}>" % ", ".join(flags)429 430 431class Label:432    """433    An HTML form label.434    """435 436    def __init__(self, field_id, text):437        self.field_id = field_id438        self.text = text439 440    def __str__(self):441        return self()442 443    def __html__(self):444        return self()445 446    def __call__(self, text=None, **kwargs):447        if "for_" in kwargs:448            kwargs["for"] = kwargs.pop("for_")449        else:450            kwargs.setdefault("for", self.field_id)451 452        attributes = widgets.html_params(**kwargs)453        text = escape(text or self.text)454        return Markup(f"<label {attributes}>{text}</label>")455 456    def __repr__(self):457        return f"Label({self.field_id!r}, {self.text!r})"458 
codekingpro/portable-devtools · Team Ai