• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

zopefoundation / grokcore.formlib / 16861221675

18 Jun 2025 06:33AM UTC coverage: 96.005%. Remained the same
16861221675

push

github

icemac
Back to development: 5.1

92 of 106 branches covered (86.79%)

Branch coverage included in aggregate %.

701 of 720 relevant lines covered (97.36%)

0.97 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

94.59
/src/grokcore/formlib/components.py
1
##############################################################################
2
#
3
# Copyright (c) 2006-2007 Zope Foundation and Contributors.
4
# All Rights Reserved.
5
#
6
# This software is subject to the provisions of the Zope Public License,
7
# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
8
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
9
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
10
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
11
# FOR A PARTICULAR PURPOSE.
12
#
13
##############################################################################
14
"""Formlib-based components"""
15

16
import datetime
1✔
17
import os
1✔
18
import warnings
1✔
19

20
import pytz
1✔
21

22
from grokcore.view import PageTemplateFile
1✔
23
from grokcore.view import View
1✔
24
from zope.formlib import form
1✔
25
from zope.interface import implementer_only
1✔
26
from zope.interface.common import idatetime
1✔
27
from zope.publisher.publish import mapply
1✔
28

29
from grokcore.formlib import formlib
1✔
30
from grokcore.formlib.interfaces import IGrokForm
1✔
31

32

33
default_form_template = PageTemplateFile(os.path.join(
1✔
34
    'templates', 'default_edit_form.pt'))
35
default_form_template.__grok_name__ = 'default_edit_form'
1✔
36
default_display_template = PageTemplateFile(os.path.join(
1✔
37
    'templates', 'default_display_form.pt'))
38
default_display_template.__grok_name__ = 'default_display_form'
1✔
39

40

41
class GrokForm:
1✔
42
    """Mix-in to consolidate zope.formlib's forms with grok.View and to
43
    add some more useful methods.
44

45
    The consolidation needs to happen because zope.formlib's Forms have
46
    update/render methods which have different meanings than
47
    grok.View's update/render methods.  We deal with this issue by
48
    'renaming' zope.formlib's update() to update_form() and by
49
    disallowing subclasses to have custom render() methods."""
50

51
    actions = form.Actions()
1✔
52

53
    def update(self):
1✔
54
        """Subclasses can override this method just like on regular
55
        grok.Views. It will be called before any form processing
56
        happens."""
57

58
    def update_form(self):
1✔
59
        """Update the form, i.e. process form input using widgets.
60

61
        On zope.formlib forms, this is what the update() method is.
62
        In grok views, the update() method has a different meaning.
63
        That's why this method is called update_form() in grok forms."""
64
        super().update()
1✔
65

66
    def render(self):
1✔
67
        """Render the form, either using the form template or whatever
68
        the actions returned in form_result."""
69
        # if the form has been updated, it will already have a result
70
        if self.form_result is None:
1✔
71
            if self.form_reset:
1✔
72
                # we reset, in case data has changed in a way that
73
                # causes the widgets to have different data
74
                self.resetForm()
1✔
75
                self.form_reset = False
1✔
76
            self.form_result = self._render_template()
1✔
77

78
        return self.form_result
1✔
79

80
    # Mark the render() method as a method from the base class. That
81
    # way we can detect whether somebody overrides render() in a
82
    # subclass (which we don't allow).
83
    render.base_method = True
1✔
84

85
    def __call__(self):
1✔
86
        mapply(self.update, (), self.request)
1✔
87
        if self.request.response.getStatus() in (302, 303):
1✔
88
            # A redirect was triggered somewhere in update().  Don't
89
            # continue rendering the template or doing anything else.
90
            return
1✔
91

92
        self.update_form()
1✔
93
        return self.render()
1✔
94

95

96
@implementer_only(IGrokForm)
1✔
97
class Form(GrokForm, form.FormBase, View):
1✔
98
    # We're only reusing the form implementation from zope.formlib, we
99
    # explicitly don't want to inherit the interface semantics (mostly
100
    # for the different meanings of update/render).
101

102
    template = default_form_template
1✔
103

104
    def applyData(self, obj, **data):
1✔
105
        return formlib.apply_data_event(obj, self.form_fields, data,
1✔
106
                                        self.adapters)
107

108
    # BBB -- to be removed in June 2007
109
    def applyChanges(self, obj, **data):
1✔
110
        warnings.warn("The 'applyChanges' method on forms is deprecated "
×
111
                      "and will disappear by June 2007. Please use "
112
                      "'applyData' instead.", DeprecationWarning, 2)
113
        return bool(self.applyData(obj, **data))
×
114

115

116
class AddForm(Form):
1✔
117
    pass
1✔
118

119

120
@implementer_only(IGrokForm)
1✔
121
class EditForm(GrokForm, form.EditFormBase, View):
1✔
122
    # We're only reusing the form implementation from zope.formlib, we
123
    # explicitly don't want to inherit the interface semantics (mostly
124
    # for the different meanings of update/render).
125

126
    template = default_form_template
1✔
127

128
    def applyData(self, obj, **data):
1✔
129
        return formlib.apply_data_event(obj, self.form_fields, data,
1✔
130
                                        self.adapters, update=True)
131

132
    # BBB -- to be removed in June 2007
133
    def applyChanges(self, obj, **data):
1✔
134
        warnings.warn("The 'applyChanges' method on forms is deprecated "
×
135
                      "and will disappear by June 2007. Please use "
136
                      "'applyData' instead.", DeprecationWarning, 2)
137
        return bool(self.applyData(obj, **data))
×
138

139
    @formlib.action("Apply")
1✔
140
    def handle_edit_action(self, **data):
1✔
141
        if self.applyData(self.context, **data):
1✔
142
            formatter = self.request.locale.dates.getFormatter(
1✔
143
                'dateTime', 'medium')
144

145
            try:
1✔
146
                time_zone = idatetime.ITZInfo(self.request)
1✔
147
            except TypeError:
1✔
148
                time_zone = pytz.UTC
1✔
149

150
            self.status = "Updated on %s" % formatter.format(
1✔
151
                datetime.datetime.now(time_zone)
152
            )
153
        else:
154
            self.status = 'No changes'
1✔
155

156

157
@implementer_only(IGrokForm)
1✔
158
class DisplayForm(GrokForm, form.DisplayFormBase, View):
1✔
159
    # We're only reusing the form implementation from zope.formlib, we
160
    # explicitly don't want to inherit the interface semantics (mostly
161
    # for the different meanings of update/render).
162

163
    template = default_display_template
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc