cherrypy-foundation 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (136) hide show
  1. cherrypy_foundation/__init__.py +0 -0
  2. cherrypy_foundation/components/ColorModes.jinja +70 -0
  3. cherrypy_foundation/components/Datatable.css +47 -0
  4. cherrypy_foundation/components/Datatable.jinja +63 -0
  5. cherrypy_foundation/components/Datatable.js +358 -0
  6. cherrypy_foundation/components/Field.css +10 -0
  7. cherrypy_foundation/components/Field.jinja +66 -0
  8. cherrypy_foundation/components/Field.js +56 -0
  9. cherrypy_foundation/components/Fields.jinja +4 -0
  10. cherrypy_foundation/components/Flash.jinja +13 -0
  11. cherrypy_foundation/components/Icon.jinja +3 -0
  12. cherrypy_foundation/components/LocaleSelection.jinja +13 -0
  13. cherrypy_foundation/components/LocaleSelection.js +26 -0
  14. cherrypy_foundation/components/SideBySideMultiSelect.css +25 -0
  15. cherrypy_foundation/components/SideBySideMultiSelect.jinja +9 -0
  16. cherrypy_foundation/components/SideBySideMultiSelect.js +9 -0
  17. cherrypy_foundation/components/Typeahead.css +55 -0
  18. cherrypy_foundation/components/Typeahead.jinja +106 -0
  19. cherrypy_foundation/components/Typeahead.js +8 -0
  20. cherrypy_foundation/components/__init__.py +51 -0
  21. cherrypy_foundation/components/tests/__init__.py +0 -0
  22. cherrypy_foundation/components/tests/test_static.py +90 -0
  23. cherrypy_foundation/components/vendor/bootstrap-icons/bootstrap-icons.css +2106 -0
  24. cherrypy_foundation/components/vendor/bootstrap-icons/bootstrap-icons.min.css +5 -0
  25. cherrypy_foundation/components/vendor/bootstrap-icons/fonts/bootstrap-icons.woff +0 -0
  26. cherrypy_foundation/components/vendor/bootstrap-icons/fonts/bootstrap-icons.woff2 +0 -0
  27. cherrypy_foundation/components/vendor/bootstrap5/css/bootstrap.css +9262 -0
  28. cherrypy_foundation/components/vendor/bootstrap5/css/bootstrap.css.map +95 -0
  29. cherrypy_foundation/components/vendor/bootstrap5/css/bootstrap.min.css +6 -0
  30. cherrypy_foundation/components/vendor/bootstrap5/css/bootstrap.min.css.map +7 -0
  31. cherrypy_foundation/components/vendor/bootstrap5/js/bootstrap.js +4846 -0
  32. cherrypy_foundation/components/vendor/bootstrap5/js/bootstrap.js.map +1 -0
  33. cherrypy_foundation/components/vendor/bootstrap5/js/bootstrap.min.js +7 -0
  34. cherrypy_foundation/components/vendor/bootstrap5/js/bootstrap.min.js.map +7 -0
  35. cherrypy_foundation/components/vendor/bootstrap5/js/color-modes.js +80 -0
  36. cherrypy_foundation/components/vendor/datatables/css/dataTables.dataTables.css +849 -0
  37. cherrypy_foundation/components/vendor/datatables/css/dataTables.dataTables.min.css +1 -0
  38. cherrypy_foundation/components/vendor/datatables/images/sort_asc.png +0 -0
  39. cherrypy_foundation/components/vendor/datatables/images/sort_asc_disabled.png +0 -0
  40. cherrypy_foundation/components/vendor/datatables/images/sort_both.png +0 -0
  41. cherrypy_foundation/components/vendor/datatables/images/sort_desc.png +0 -0
  42. cherrypy_foundation/components/vendor/datatables/images/sort_desc_disabled.png +0 -0
  43. cherrypy_foundation/components/vendor/datatables/js/dataTables.js +14073 -0
  44. cherrypy_foundation/components/vendor/datatables/js/dataTables.min.js +4 -0
  45. cherrypy_foundation/components/vendor/datatables-extensions/Buttons/css/buttons.dataTables.css +556 -0
  46. cherrypy_foundation/components/vendor/datatables-extensions/Buttons/css/buttons.dataTables.min.css +1 -0
  47. cherrypy_foundation/components/vendor/datatables-extensions/Buttons/js/buttons.html5.js +1700 -0
  48. cherrypy_foundation/components/vendor/datatables-extensions/Buttons/js/buttons.html5.min.js +8 -0
  49. cherrypy_foundation/components/vendor/datatables-extensions/Buttons/js/dataTables.buttons.js +2944 -0
  50. cherrypy_foundation/components/vendor/datatables-extensions/Buttons/js/dataTables.buttons.min.js +4 -0
  51. cherrypy_foundation/components/vendor/datatables-extensions/FixedHeader/css/fixedHeader.dataTables.css +13 -0
  52. cherrypy_foundation/components/vendor/datatables-extensions/FixedHeader/css/fixedHeader.dataTables.min.css +1 -0
  53. cherrypy_foundation/components/vendor/datatables-extensions/FixedHeader/js/dataTables.fixedHeader.js +1202 -0
  54. cherrypy_foundation/components/vendor/datatables-extensions/FixedHeader/js/dataTables.fixedHeader.min.js +4 -0
  55. cherrypy_foundation/components/vendor/datatables-extensions/JSZip/jszip.js +11577 -0
  56. cherrypy_foundation/components/vendor/datatables-extensions/JSZip/jszip.min.js +13 -0
  57. cherrypy_foundation/components/vendor/datatables-extensions/Responsive/css/responsive.dataTables.css +194 -0
  58. cherrypy_foundation/components/vendor/datatables-extensions/Responsive/css/responsive.dataTables.min.css +1 -0
  59. cherrypy_foundation/components/vendor/datatables-extensions/Responsive/js/dataTables.responsive.js +1861 -0
  60. cherrypy_foundation/components/vendor/datatables-extensions/Responsive/js/dataTables.responsive.min.js +4 -0
  61. cherrypy_foundation/components/vendor/datatables-extensions/pdfmake/build/pdfmake.js +75023 -0
  62. cherrypy_foundation/components/vendor/datatables-extensions/pdfmake/build/pdfmake.min.js +3 -0
  63. cherrypy_foundation/components/vendor/datatables-extensions/pdfmake/build/vfs_fonts.js +6 -0
  64. cherrypy_foundation/components/vendor/datatables-extensions/rowgroup/css/rowGroup.dataTables.css +53 -0
  65. cherrypy_foundation/components/vendor/datatables-extensions/rowgroup/css/rowGroup.dataTables.min.css +1 -0
  66. cherrypy_foundation/components/vendor/datatables-extensions/rowgroup/js/dataTables.rowGroup.js +485 -0
  67. cherrypy_foundation/components/vendor/datatables-extensions/rowgroup/js/dataTables.rowGroup.min.js +4 -0
  68. cherrypy_foundation/components/vendor/jquery/jquery.min.js +2 -0
  69. cherrypy_foundation/components/vendor/multi/LICENSE +7 -0
  70. cherrypy_foundation/components/vendor/multi/README.md +109 -0
  71. cherrypy_foundation/components/vendor/multi/multi.css +95 -0
  72. cherrypy_foundation/components/vendor/multi/multi.js +328 -0
  73. cherrypy_foundation/components/vendor/popper/popper.js +1825 -0
  74. cherrypy_foundation/components/vendor/popper/popper.min.js +6 -0
  75. cherrypy_foundation/components/vendor/typeahead/jquery.typeahead.min.css +1 -0
  76. cherrypy_foundation/components/vendor/typeahead/jquery.typeahead.min.js +10 -0
  77. cherrypy_foundation/error_page.py +94 -0
  78. cherrypy_foundation/flash.py +50 -0
  79. cherrypy_foundation/form.py +119 -0
  80. cherrypy_foundation/logging.py +103 -0
  81. cherrypy_foundation/passwd.py +65 -0
  82. cherrypy_foundation/plugins/__init__.py +0 -0
  83. cherrypy_foundation/plugins/db.py +286 -0
  84. cherrypy_foundation/plugins/ldap.py +257 -0
  85. cherrypy_foundation/plugins/restapi.py +74 -0
  86. cherrypy_foundation/plugins/scheduler.py +287 -0
  87. cherrypy_foundation/plugins/smtp.py +223 -0
  88. cherrypy_foundation/plugins/tests/__init__.py +0 -0
  89. cherrypy_foundation/plugins/tests/test_db.py +118 -0
  90. cherrypy_foundation/plugins/tests/test_ldap.py +451 -0
  91. cherrypy_foundation/plugins/tests/test_scheduler.py +100 -0
  92. cherrypy_foundation/plugins/tests/test_scheduler_db.py +107 -0
  93. cherrypy_foundation/plugins/tests/test_smtp.py +140 -0
  94. cherrypy_foundation/sessions.py +93 -0
  95. cherrypy_foundation/tests/__init__.py +72 -0
  96. cherrypy_foundation/tests/templates/test_flash.html +9 -0
  97. cherrypy_foundation/tests/templates/test_form.html +16 -0
  98. cherrypy_foundation/tests/templates/test_url.html +15 -0
  99. cherrypy_foundation/tests/test_error_page.py +78 -0
  100. cherrypy_foundation/tests/test_flash.py +61 -0
  101. cherrypy_foundation/tests/test_form.py +148 -0
  102. cherrypy_foundation/tests/test_logging.py +78 -0
  103. cherrypy_foundation/tests/test_passwd.py +51 -0
  104. cherrypy_foundation/tests/test_sessions.py +89 -0
  105. cherrypy_foundation/tests/test_url.py +161 -0
  106. cherrypy_foundation/tools/__init__.py +0 -0
  107. cherrypy_foundation/tools/auth.py +263 -0
  108. cherrypy_foundation/tools/auth_mfa.py +249 -0
  109. cherrypy_foundation/tools/i18n.py +529 -0
  110. cherrypy_foundation/tools/jinja2.py +158 -0
  111. cherrypy_foundation/tools/ratelimit.py +265 -0
  112. cherrypy_foundation/tools/secure_headers.py +119 -0
  113. cherrypy_foundation/tools/sessions_timeout.py +167 -0
  114. cherrypy_foundation/tools/tests/__init__.py +0 -0
  115. cherrypy_foundation/tools/tests/components/Button.jinja +2 -0
  116. cherrypy_foundation/tools/tests/locales/de/LC_MESSAGES/messages.mo +0 -0
  117. cherrypy_foundation/tools/tests/locales/de/LC_MESSAGES/messages.po +15 -0
  118. cherrypy_foundation/tools/tests/locales/fr/LC_MESSAGES/messages.mo +0 -0
  119. cherrypy_foundation/tools/tests/locales/fr/LC_MESSAGES/messages.po +15 -0
  120. cherrypy_foundation/tools/tests/locales/messages.pot +2 -0
  121. cherrypy_foundation/tools/tests/templates/test_jinja2.html +11 -0
  122. cherrypy_foundation/tools/tests/templates/test_jinjax.html +9 -0
  123. cherrypy_foundation/tools/tests/templates/test_jinjax_i18n.html +22 -0
  124. cherrypy_foundation/tools/tests/test_auth.py +110 -0
  125. cherrypy_foundation/tools/tests/test_auth_mfa.py +369 -0
  126. cherrypy_foundation/tools/tests/test_i18n.py +247 -0
  127. cherrypy_foundation/tools/tests/test_jinja2.py +153 -0
  128. cherrypy_foundation/tools/tests/test_ratelimit.py +109 -0
  129. cherrypy_foundation/tools/tests/test_secure_headers.py +200 -0
  130. cherrypy_foundation/url.py +66 -0
  131. cherrypy_foundation/widgets.py +48 -0
  132. cherrypy_foundation-1.0.0.dist-info/METADATA +71 -0
  133. cherrypy_foundation-1.0.0.dist-info/RECORD +136 -0
  134. cherrypy_foundation-1.0.0.dist-info/WHEEL +5 -0
  135. cherrypy_foundation-1.0.0.dist-info/licenses/LICENSE.md +674 -0
  136. cherrypy_foundation-1.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,200 @@
1
+ # Cherrypy-foundation
2
+ # Copyright (C) 2026 IKUS Software
3
+ #
4
+ # This program is free software: you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation, either version 3 of the License, or
7
+ # (at your option) any later version.
8
+ #
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with this program. If not, see <https://www.gnu.org/licenses/>.
16
+
17
+ import cherrypy
18
+ from cherrypy.test import helper
19
+
20
+ from cherrypy_foundation.tools import secure_headers # noqa
21
+
22
+
23
+ @cherrypy.tools.secure_headers(
24
+ csp={
25
+ "default-src": "'self'",
26
+ "style-src": ("'self'", "'unsafe-inline'"),
27
+ "script-src": ("'self'", "'unsafe-inline'"),
28
+ "img-src": ("'self'", "data:"),
29
+ }
30
+ )
31
+ @cherrypy.tools.proxy(local=None, remote='X-Real-IP')
32
+ class Root:
33
+
34
+ @cherrypy.expose
35
+ @cherrypy.tools.sessions(locking='explicit')
36
+ def index(self):
37
+ return {'var1': 'test-jinja2'}
38
+
39
+ @cherrypy.expose
40
+ @cherrypy.tools.sessions(locking='explicit')
41
+ def logout(self, **kwargs):
42
+ raise cherrypy.HTTPRedirect('/')
43
+
44
+ @cherrypy.expose
45
+ @cherrypy.tools.secure_headers(on=False)
46
+ @cherrypy.tools.sessions(on=False)
47
+ def static(self, value=None):
48
+ return 'OK'
49
+
50
+
51
+ class SecureHeaderTest(helper.CPWebCase):
52
+ interactive = False
53
+
54
+ @classmethod
55
+ def setup_server(cls):
56
+ cherrypy.tree.mount(Root(), '/')
57
+
58
+ def test_cookie_samesite_lax(self):
59
+ # Given a request made to rdiffweb
60
+ # When receiving the response
61
+ self.getPage('/')
62
+ # Then the header contains Set-Cookie with SameSite=Lax
63
+ cookie = self.assertHeader('Set-Cookie')
64
+ self.assertIn('SameSite=Lax', cookie)
65
+
66
+ def test_cookie_samesite_lax_without_session(self):
67
+ # Given not a client sending no cookie
68
+ self.cookies = None
69
+ # When a query is made to a static path (without session)
70
+ self.getPage('/static/blue.css')
71
+ # Then Set-Cookie is not defined.
72
+ self.assertNoHeader('Set-Cookie')
73
+
74
+ def test_cookie_with_https(self):
75
+ # Given an https request made to rdiffweb
76
+ self.getPage('/', headers=[('X-Forwarded-Proto', 'https')])
77
+ # When receiving the response
78
+ self.assertStatus(200)
79
+ # Then the header contains Set-Cookie with Secure
80
+ cookie = self.assertHeader('Set-Cookie')
81
+ self.assertIn('Secure', cookie)
82
+
83
+ def test_cookie_with_http(self):
84
+ # Given an https request made to rdiffweb
85
+ self.getPage('/')
86
+ # When receiving the response
87
+ # Then the header contains Set-Cookie with Secure
88
+ cookie = self.assertHeader('Set-Cookie')
89
+ self.assertNotIn('Secure', cookie)
90
+
91
+ def test_get_with_wrong_origin(self):
92
+ # Given a GET request made to rdiffweb
93
+ # When the request is made using a different origin
94
+ self.getPage('/', headers=[('Origin', 'http://www.examples.com')])
95
+ # Then the response status it 200 OK.
96
+ self.assertStatus(200)
97
+
98
+ def test_post_with_wrong_origin(self):
99
+ # Given a POST request made to rdiffweb
100
+ # When the request is made using a different origin
101
+ self.getPage('/logout', headers=[('Origin', 'http://www.examples.com')], method='POST')
102
+ # Then the request is refused with 403 Forbiden
103
+ self.assertStatus(403)
104
+ self.assertInBody('Unexpected Origin header')
105
+
106
+ def test_post_with_prefixed_origin(self):
107
+ # Given a POST request made to rdiffweb
108
+ # When the request is made using a different origin
109
+ base = 'http://%s:%s' % (self.HOST + 'anything.com', self.PORT)
110
+ self.getPage('/logout', headers=[('Origin', base)], method='POST')
111
+ # Then the request is accepted with 200 OK
112
+ self.assertStatus(403)
113
+ self.assertInBody('Unexpected Origin header')
114
+
115
+ def test_post_with_valid_origin(self):
116
+ # Given a POST request made to rdiffweb
117
+ # When the request is made using a different origin
118
+ base = 'http://%s:%s' % (self.HOST, self.PORT)
119
+ self.getPage('/logout', headers=[('Origin', base)], method='POST')
120
+ # Then the request is accepted with 200 OK
121
+ self.assertStatus(303)
122
+
123
+ def test_post_without_origin(self):
124
+ # Given a POST request made to rdiffweb
125
+ # When the request is made without an origin
126
+ self.getPage('/logout', method='POST')
127
+ # Then the request is accepted with 200 OK
128
+ self.assertStatus(303)
129
+
130
+ def test_clickjacking_defense(self):
131
+ # Given a POST request made to rdiffweb
132
+ # When the request is made without an origin
133
+ self.getPage('/')
134
+ # Then the request is accepted with 200 OK
135
+ self.assertStatus(200)
136
+ self.assertHeaderItemValue('X-Frame-Options', 'DENY')
137
+
138
+ def test_no_cache(self):
139
+ # Given a POST request made to rdiffweb
140
+ # When the request is made without an origin
141
+ self.getPage('/')
142
+ # Then the request is accepted with 200 OK
143
+ self.assertStatus(200)
144
+ self.assertHeaderItemValue('Cache-control', 'no-cache')
145
+ self.assertHeaderItemValue('Cache-control', 'no-store')
146
+ self.assertHeaderItemValue('Cache-control', 'must-revalidate')
147
+ self.assertHeaderItemValue('Cache-control', 'max-age=0')
148
+ self.assertHeaderItemValue('Pragma', 'no-cache')
149
+ self.assertHeaderItemValue('Expires', '0')
150
+
151
+ def test_no_cache_with_static(self):
152
+ self.getPage('/static')
153
+ # Then the request is accepted with 200 OK
154
+ self.assertStatus(200)
155
+ self.assertNoHeader('Cache-control')
156
+ self.assertNoHeader('Pragma')
157
+ self.assertNoHeader('Expires')
158
+
159
+ def test_referrer_policy(self):
160
+ # Given a POST request made to rdiffweb
161
+ # When the request is made without an origin
162
+ self.getPage('/')
163
+ # Then the request is accepted with 200 OK
164
+ self.assertStatus(200)
165
+ self.assertHeaderItemValue('Referrer-Policy', 'same-origin')
166
+
167
+ def test_nosniff(self):
168
+ # Given a POST request made to rdiffweb
169
+ # When the request is made without an origin
170
+ self.getPage('/')
171
+ # Then the request is accepted with 200 OK
172
+ self.assertStatus(200)
173
+ self.assertHeaderItemValue('X-Content-Type-Options', 'nosniff')
174
+
175
+ def test_xss_protection(self):
176
+ # Given a POST request made to rdiffweb
177
+ # When the request is made without an origin
178
+ self.getPage('/')
179
+ # Then the request is accepted with 200 OK
180
+ self.assertStatus(200)
181
+ self.assertHeaderItemValue('X-XSS-Protection', '1; mode=block')
182
+
183
+ def test_content_security_policy(self):
184
+ # Given a POST request made to rdiffweb
185
+ # When the request is made without an origin
186
+ self.getPage('/')
187
+ # Then the request is accepted with 200 OK
188
+ self.assertStatus(200)
189
+ self.assertHeaderItemValue(
190
+ 'Content-Security-Policy',
191
+ "default-src 'self'; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline'; img-src 'self' data:",
192
+ )
193
+
194
+ def test_strict_transport_security(self):
195
+ # Given a POST request made to rdiffweb
196
+ # When the request is made without an origin
197
+ self.getPage('/', headers=[('X-Forwarded-Proto', 'https')])
198
+ # Then the request is accepted with 200 OK
199
+ self.assertStatus(200)
200
+ self.assertHeaderItemValue('Strict-Transport-Security', 'max-age=31536000; includeSubDomains')
@@ -0,0 +1,66 @@
1
+ # Cherrypy-foundation
2
+ # Copyright (C) 2026 IKUS Software
3
+ #
4
+ # This program is free software: you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation, either version 3 of the License, or
7
+ # (at your option) any later version.
8
+ #
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with this program. If not, see <https://www.gnu.org/licenses/>.
16
+
17
+ from urllib.parse import urljoin
18
+
19
+ import cherrypy
20
+
21
+
22
+ def url_for(*args, _relative=None, _base=None, **kwargs):
23
+ """
24
+ Generate a URL for the given endpoint/path (*args) with query params (**kwargs).
25
+
26
+ relative:
27
+ - None: pass through to cherrypy.url (CherryPy default behavior).
28
+ - False: absolute URL (scheme, host, vhost, script_name).
29
+ - True: URL relative to current request path (may include '..').
30
+ - 'server': URL relative to server root (starts with '/').
31
+ Notes:
32
+ - String chunks have leading/trailing slashes stripped and are joined with '/'.
33
+ - Chunks '.' and '..' are allowed as literals (for relative paths).
34
+ - Objects may implement __url_for__() -> str or have a string .url_for attribute.
35
+ - Integers are appended as path segments.
36
+ - When path == "", existing request query parameters are merged (kwargs win).
37
+ """
38
+ # Handle query-string
39
+ qs = [(k, v) for k, v in sorted(kwargs.items()) if v is not None]
40
+
41
+ path = []
42
+ for chunk in args:
43
+ if hasattr(chunk, '__url_for__') and callable(chunk.__url_for__):
44
+ path.append(str(chunk.__url_for__()))
45
+ elif hasattr(chunk, 'url_for'):
46
+ path.append(str(chunk.url_for))
47
+ elif isinstance(chunk, str):
48
+ path.append(chunk)
49
+ elif isinstance(chunk, int):
50
+ path.append(str(chunk))
51
+ else:
52
+ raise ValueError('invalid positional arguments, url_for accept str, bytes, int: %r' % chunk)
53
+ path = '/'.join(path)
54
+ # When path is empty, we are browsing the same page.
55
+ # Let keep the original query_string to avoid loosing it.
56
+ if not path:
57
+ params = cherrypy.request.params.copy()
58
+ params.update(kwargs)
59
+ qs = [(k, v) for k, v in sorted(params.items()) if v is not None]
60
+ elif not path.startswith('.'):
61
+ path = urljoin('/', path)
62
+ # Outside a request, use cherrypy.tools.proxy config
63
+ if not cherrypy.request.app and _base is None:
64
+ _base = cherrypy.config.get('tools.proxy.base', None)
65
+ # Use cherrypy to build the URL
66
+ return cherrypy.url(path=path, qs=qs, relative=_relative, base=_base)
@@ -0,0 +1,48 @@
1
+ # Cherrypy-foundation
2
+ # Copyright (C) 2020-2026 IKUS Software
3
+ #
4
+ # This program is free software: you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation, either version 3 of the License, or
7
+ # (at your option) any later version.
8
+ #
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with this program. If not, see <https://www.gnu.org/licenses/>.
16
+
17
+ import cherrypy
18
+ from markupsafe import Markup
19
+
20
+
21
+ class JinjaWidget:
22
+ """
23
+ Create field widget from Jinja2 templates.
24
+ """
25
+
26
+ filename = None
27
+
28
+ def __init__(self, **options):
29
+ self.options = options
30
+
31
+ def __call__(self, field, **kwargs):
32
+ env = cherrypy.request.config.get('tools.jinja2.env')
33
+ kwargs = dict(self.options, **kwargs)
34
+ # Support JinjaX
35
+ if self.filename.endswith('.jinja'):
36
+ catalog = env.globals['catalog']
37
+ return catalog.irender(self.filename[0:-6], field=field, **kwargs)
38
+ else:
39
+ tmpl = env.get_template(self.filename)
40
+ return Markup(tmpl.render(field=field, **kwargs))
41
+
42
+
43
+ class SwitchWidget(JinjaWidget):
44
+ filename = 'SwitchWidget.jinja'
45
+
46
+
47
+ class SideBySideMultiSelect(JinjaWidget):
48
+ filename = 'SideBySideMultiSelect.jinja'
@@ -0,0 +1,71 @@
1
+ Metadata-Version: 2.4
2
+ Name: cherrypy-foundation
3
+ Version: 1.0.0
4
+ Summary: Cherrypy-foundation
5
+ Author-email: Patrik Dufresne <patrik@ikus-soft.com>
6
+ License: GPLv3
7
+ Project-URL: Homepage, https://gitlab.com/ikus-soft/cherrypy-foundation
8
+ Classifier: Development Status :: 4 - Beta
9
+ Classifier: Framework :: CherryPy
10
+ Classifier: Intended Audience :: System Administrators
11
+ Classifier: Programming Language :: Python :: 3.11
12
+ Classifier: Programming Language :: Python :: 3.12
13
+ Classifier: Programming Language :: Python :: 3.13
14
+ Requires-Python: <4,>=3.11
15
+ Description-Content-Type: text/markdown
16
+ License-File: LICENSE.md
17
+ Requires-Dist: babel
18
+ Requires-Dist: CherryPy
19
+ Requires-Dist: Jinja2
20
+ Requires-Dist: jinjax
21
+ Requires-Dist: pytz
22
+ Requires-Dist: WTForms>=3.2.1
23
+ Provides-Extra: test
24
+ Requires-Dist: apscheduler; extra == "test"
25
+ Requires-Dist: argon2-cffi; extra == "test"
26
+ Requires-Dist: ldap3; extra == "test"
27
+ Requires-Dist: parameterized; extra == "test"
28
+ Requires-Dist: pytest; extra == "test"
29
+ Requires-Dist: requests_oauthlib; extra == "test"
30
+ Requires-Dist: selenium; extra == "test"
31
+ Requires-Dist: sqlalchemy; extra == "test"
32
+ Provides-Extra: ldap
33
+ Requires-Dist: ldap3; extra == "ldap"
34
+ Provides-Extra: oauth
35
+ Requires-Dist: requests_oauthlib; extra == "oauth"
36
+ Provides-Extra: passwd
37
+ Requires-Dist: argon2-cffi; extra == "passwd"
38
+ Provides-Extra: scheduler
39
+ Requires-Dist: apscheduler; extra == "scheduler"
40
+ Dynamic: license-file
41
+
42
+ # Cherrypy-foundation
43
+
44
+ <p align="center">
45
+ <a href="LICENSE"><img alt="License" src="https://img.shields.io/badge/license-GPL--3.0-orange"></a>
46
+ <a href="https://gitlab.com/ikus-soft/cherrypy-foundation/pipelines"><img alt="Build" src="https://gitlab.com/ikus-soft/cherrypy-foundation/badges/master/pipeline.svg"></a>
47
+ <a href="https://sonar.ikus-soft.com/dashboard?id=cherrypy-foundation"><img alt="Quality Gate" src="https://sonar.ikus-soft.com/api/project_badges/measure?project=cherrypy-foundation&metric=alert_status"></a>
48
+ <a href="https://sonar.ikus-soft.com/dashboard?id=cherrypy-foundation"><img alt="Coverage" src="https://sonar.ikus-soft.com/api/project_badges/measure?project=cherrypy-foundation&metric=coverage"></a>
49
+ </p>
50
+
51
+ Cherrypy-foundation is a comprehensive toolkit that accelerates web application development with CherryPy. It provides a curated collection of utilities and integrations that handle common web development tasks, allowing you to focus on building your application's unique features.
52
+
53
+ ## What's Included
54
+
55
+ - **Database Integration**: Seamless SQLAlchemy integration for database operations
56
+ - **Template Engine**: Jinja2 and JinjaX support for flexible, component-based templating
57
+ - **Form Handling**: Enhanced WTForms integration with automatic validation and Bootstrap rendering
58
+ - **URL Management**: Flexible URL generation with `url_for` utility
59
+ - **Error Handling**: Smart error pages that adapt to response content type (HTML, JSON, plain text)
60
+ - **UI Components**: Bootstrap-ready components for rapid interface development
61
+
62
+ ## Who Is This For?
63
+
64
+ Cherrypy-foundation is designed for developers who:
65
+
66
+ - Want to build modern web applications with CherryPy without reinventing the wheel
67
+ - Need a lightweight alternative to full-stack frameworks while maintaining flexibility
68
+ - Prefer convention over configuration but value customization options
69
+ - Want battle-tested components that integrate seamlessly with CherryPy's architecture
70
+
71
+ This documentation will guide you through all available features, from basic utilities to advanced integrations, with practical examples to help you get started quickly.
@@ -0,0 +1,136 @@
1
+ cherrypy_foundation/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ cherrypy_foundation/error_page.py,sha256=GEg_KZGRE63ZsTTtmrEpE9GsYcm6shZvp5KLR53sIMA,3248
3
+ cherrypy_foundation/flash.py,sha256=vraKvmYmjdV1cGsPSxTLVsekwqOnoyiVPqKjv6UW5OU,1646
4
+ cherrypy_foundation/form.py,sha256=8zp72fpYrmMGsIK5LxVY7sL_qqhoMDnIQoMND1s6CXk,3994
5
+ cherrypy_foundation/logging.py,sha256=JyzcuAu3HWzvMTSFBuKpwgnJLz1lRlx-j6EkuTwlb6I,3463
6
+ cherrypy_foundation/passwd.py,sha256=iyz3SgcvpgxsZgPUoTEXiqdKtwOANPrRKYhVPm2d_NQ,2139
7
+ cherrypy_foundation/sessions.py,sha256=6OmjrJtX2Hhjhx5Q8Cy1nwG6_Ur6PwPErfPPA7FfzYg,3180
8
+ cherrypy_foundation/url.py,sha256=WtfD0XEOs5FNmLvxhnBvi9aW4hQpUz0ZZXPfEXd4To8,2849
9
+ cherrypy_foundation/widgets.py,sha256=-wxNv3wIgf7eB8WyyycfsqSCXep3YhZgBK_5PJ1qYbY,1549
10
+ cherrypy_foundation/components/ColorModes.jinja,sha256=Ai2fy1qHFwEgutvyvvGjKJmffcBdNb7wmY20DJqZ8R4,3528
11
+ cherrypy_foundation/components/Datatable.css,sha256=7wSwgdA61vYCdEuQ0bp2o0oSvu5mGLN1c6ovCUSe718,947
12
+ cherrypy_foundation/components/Datatable.jinja,sha256=qUJyp8FCBdpH9J8kIvVzemRyyra0ushpZtTj5BhN9H8,3391
13
+ cherrypy_foundation/components/Datatable.js,sha256=4qHj21GPRQzUBk9lWb3Y04EvuwnWmrENG7he5i91lgE,12072
14
+ cherrypy_foundation/components/Field.css,sha256=CtOkvIbix7ykrOKLJxQJLJsWfEwFqfducJ1BH2vlMvA,244
15
+ cherrypy_foundation/components/Field.jinja,sha256=HuhZvHzv0MtFrcpoavbZHOLLdTdse8RcLIExXXx-Rsk,3319
16
+ cherrypy_foundation/components/Field.js,sha256=SFixZ62WlLq7SSCEazMAGhSnc9EnQ1wg6PZX4ayO6ZE,2047
17
+ cherrypy_foundation/components/Fields.jinja,sha256=_8Or6DOlciKjRao-sdBpLs--bx5V-K80X3hDEA1VKCQ,165
18
+ cherrypy_foundation/components/Flash.jinja,sha256=COy44drQsXpbZajjJS4w_9NMPYFdMfUNdfhd7SbFdYA,442
19
+ cherrypy_foundation/components/Icon.jinja,sha256=Z1RGYBg5xlDEoUy3glqb_k_LEjkJHeCxQXqDEvWzEF4,135
20
+ cherrypy_foundation/components/LocaleSelection.jinja,sha256=NHhQGI6CCJl4LWl-eteu_AIg1_qc1MusuA1fKcrjluQ,509
21
+ cherrypy_foundation/components/LocaleSelection.js,sha256=-iTZD5ejg1R9F3tZASTH7dkgd19upke-pzOhsZ9K_LA,670
22
+ cherrypy_foundation/components/SideBySideMultiSelect.css,sha256=_poMY9O8rvDsOh01pQLf9qtg1Gm4eCM2HsM_ekC5zkk,503
23
+ cherrypy_foundation/components/SideBySideMultiSelect.jinja,sha256=sud1WP-6JzuP7ZLRr-JQqvgMRWZRlXvxUJfguFr_klk,478
24
+ cherrypy_foundation/components/SideBySideMultiSelect.js,sha256=5YMz1pgkXeWC_SRRfDbQI3X-c4PuxiTIpbWJt9sY7Rc,197
25
+ cherrypy_foundation/components/Typeahead.css,sha256=iaLKi4lx01MQqSSRrdDUIDCCD6Q_0INCsMRZ3nqdkuw,1718
26
+ cherrypy_foundation/components/Typeahead.jinja,sha256=TjCotrTIzSx7TujxmgNxLIgxvtequCARLCjqeDzlZXU,3218
27
+ cherrypy_foundation/components/Typeahead.js,sha256=mnsPRwM_1xtI7ImGn_pu46QdFw_LK_PDHNCRKp_CVxc,236
28
+ cherrypy_foundation/components/__init__.py,sha256=rd202TEmfnwBVD2xkJA2NMKuYeUSAPmBR_EBdHeVJLg,2007
29
+ cherrypy_foundation/components/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
30
+ cherrypy_foundation/components/tests/test_static.py,sha256=ELbyEs2Kd-UYj7b3dvrIBa8vHwanB7XRAceS3knYq6c,3814
31
+ cherrypy_foundation/components/vendor/bootstrap-icons/bootstrap-icons.css,sha256=AEMichyFVzMXWbxt2qy7aJsPBxXWiK7IK9BW0tW1zDs,99556
32
+ cherrypy_foundation/components/vendor/bootstrap-icons/bootstrap-icons.min.css,sha256=pdY4ejLKO67E0CM2tbPtq1DJ3VGDVVdqAR6j3ZwdiE4,87008
33
+ cherrypy_foundation/components/vendor/bootstrap-icons/fonts/bootstrap-icons.woff,sha256=9VUTt7WRy4SjuH_w406iTUgx1v7cIuVLkRymS1tUShU,180288
34
+ cherrypy_foundation/components/vendor/bootstrap-icons/fonts/bootstrap-icons.woff2,sha256=bHVxA2ShylYEJncW9tKJl7JjGf2weM8R4LQqtm_y6mE,134044
35
+ cherrypy_foundation/components/vendor/bootstrap5/css/bootstrap.css,sha256=YvcLWEjS0_yWmB66SrjGygy1185wOzsdbW22AbSt8Ts,272886
36
+ cherrypy_foundation/components/vendor/bootstrap5/css/bootstrap.css.map,sha256=RY6fDzZuozBdrr80YhoRP48y2UE9OCmOGgu8emOM-5Q,253914
37
+ cherrypy_foundation/components/vendor/bootstrap5/css/bootstrap.min.css,sha256=eMBxae9ZquEyVpjWKfCBeN1D1qufzXe0maaXLeRu6gg,225105
38
+ cherrypy_foundation/components/vendor/bootstrap5/css/bootstrap.min.css.map,sha256=NC6jEvVd8_BZ96iwZJDXxgM1c3Lz6rN4BPM0l2XD8B4,494723
39
+ cherrypy_foundation/components/vendor/bootstrap5/js/bootstrap.js,sha256=kI5lC_QH52E-AAB5HCUsGngGa-Vc3lz3TdddCieMGco,167195
40
+ cherrypy_foundation/components/vendor/bootstrap5/js/bootstrap.js.map,sha256=zCTDKzJQi0Y4TH31hLo994dmbuaDi2NrpKj1Vsm6F58,328671
41
+ cherrypy_foundation/components/vendor/bootstrap5/js/bootstrap.min.js,sha256=2vIEgwJFRCN4qEELY4ffA_P1yp26Zr0j7HQLHrUZ-Ps,70433
42
+ cherrypy_foundation/components/vendor/bootstrap5/js/bootstrap.min.js.map,sha256=2BeKWatvkz0SqAxVw_Fr51_A4PB2ZGEONRoAFz1_syU,246925
43
+ cherrypy_foundation/components/vendor/bootstrap5/js/color-modes.js,sha256=WD1wQyKwvUFwziA0Jx2-iZ-zYG3cxgR87NU4iFBNPJk,2596
44
+ cherrypy_foundation/components/vendor/datatables/css/dataTables.dataTables.css,sha256=xOuVoVZeiHtRNHE_pMAEjDPQU2ef3HZe0P5raNcJRUo,34206
45
+ cherrypy_foundation/components/vendor/datatables/css/dataTables.dataTables.min.css,sha256=7gm99jeS2GLBJ8-OxxPg3BFLnRQFDfgs8FoDe18Pkzw,30581
46
+ cherrypy_foundation/components/vendor/datatables/images/sort_asc.png,sha256=WVcEw_PPTLZcfZyFCKmedIDhUAlUc_rtMaB8IbEzibg,160
47
+ cherrypy_foundation/components/vendor/datatables/images/sort_asc_disabled.png,sha256=pluPT4TWQnqBw2AoL8U5TVG_mdraXxWeaqD848OWglw,148
48
+ cherrypy_foundation/components/vendor/datatables/images/sort_both.png,sha256=PgFsI65RQXOCtkCuLRnrSAR1MsN61TiUvRhVhlWcz_s,201
49
+ cherrypy_foundation/components/vendor/datatables/images/sort_desc.png,sha256=0I7Q4h8YfdMJAw1GUiTagIURmhWhfWFroOR3u1DG8Q0,158
50
+ cherrypy_foundation/components/vendor/datatables/images/sort_desc_disabled.png,sha256=bA8MGyHvaAcFevyN3BqSXR29IcsR6ScOyE_0rEDZo_o,146
51
+ cherrypy_foundation/components/vendor/datatables/js/dataTables.js,sha256=LBSoo30n9hPqCynmd4HJuzyh4aGB2K-eypmWXZkFddw,390634
52
+ cherrypy_foundation/components/vendor/datatables/js/dataTables.min.js,sha256=5nUE3RC_LHkM_ZpBDLx-AOnPf6Z01T_1Nuovc6uVjGs,97833
53
+ cherrypy_foundation/components/vendor/datatables-extensions/Buttons/css/buttons.dataTables.css,sha256=bCF0TNEZzDWVRsw4_8CFKiTawPIz-1Qt-oiABDzCzLY,14894
54
+ cherrypy_foundation/components/vendor/datatables-extensions/Buttons/css/buttons.dataTables.min.css,sha256=bEz7YWS8ZUkqIwsmobyHg21XHy_WCzepzmqBn4dhTIg,12846
55
+ cherrypy_foundation/components/vendor/datatables-extensions/Buttons/js/buttons.html5.js,sha256=85SVAw5YTAQ6Xr58ijOQbVY0612mJ1k-jkiiFP_ethk,47244
56
+ cherrypy_foundation/components/vendor/datatables-extensions/Buttons/js/buttons.html5.min.js,sha256=XEwbyjxw7bYmYTKlCcTFQO3e7t0b6TVxID9-EGCrJCo,26043
57
+ cherrypy_foundation/components/vendor/datatables-extensions/Buttons/js/dataTables.buttons.js,sha256=13yPkLsIGBGhBs0ZVjJlhXGxZOednPJopFEUIgE92zQ,67693
58
+ cherrypy_foundation/components/vendor/datatables-extensions/Buttons/js/dataTables.buttons.min.js,sha256=vDa7euo8mMEv1aPGLUxKr5QHa885S0ZxqMR2mc3Dgo4,28019
59
+ cherrypy_foundation/components/vendor/datatables-extensions/FixedHeader/css/fixedHeader.dataTables.css,sha256=efLYuXeP9YEC_lVhq6E9NWz0wOihxfnaVsAsegv8-Q8,284
60
+ cherrypy_foundation/components/vendor/datatables-extensions/FixedHeader/css/fixedHeader.dataTables.min.css,sha256=2T8Kt7TU522kVYTzDCmi0heIVCWdzis5rSc-oAu9R-c,247
61
+ cherrypy_foundation/components/vendor/datatables-extensions/FixedHeader/js/dataTables.fixedHeader.js,sha256=TvaPe5Sl9OhRe4lB105ip3AcAqXzd61Ng9_12DX59Gk,31147
62
+ cherrypy_foundation/components/vendor/datatables-extensions/FixedHeader/js/dataTables.fixedHeader.min.js,sha256=2hWY5lFMMBuD4UDmHky7MmjAOnKvaod0UolRj-Eus20,12582
63
+ cherrypy_foundation/components/vendor/datatables-extensions/JSZip/jszip.js,sha256=4uG-XCLT8VsLieZ20-7elGRFKZltmJimsVh8mQinhQY,374191
64
+ cherrypy_foundation/components/vendor/datatables-extensions/JSZip/jszip.min.js,sha256=rMfkFFWoB2W1_Zx-4bgHim0WC7vKRVrq6FTeZclH1Z4,97630
65
+ cherrypy_foundation/components/vendor/datatables-extensions/Responsive/css/responsive.dataTables.css,sha256=CKDN8QXxw0oLxlaRNPTfQGb5ZDu3VgMztemnR9bQ0eQ,6690
66
+ cherrypy_foundation/components/vendor/datatables-extensions/Responsive/css/responsive.dataTables.min.css,sha256=zdpDgkDT9OXHEItgrIG4Ff_UDpl4SCQBxTQEKZaT92k,5841
67
+ cherrypy_foundation/components/vendor/datatables-extensions/Responsive/js/dataTables.responsive.js,sha256=l3TSN2y-_4fGwcUaI3kXj5ItV47OTaHdruKsjmTCtnw,47020
68
+ cherrypy_foundation/components/vendor/datatables-extensions/Responsive/js/dataTables.responsive.min.js,sha256=4_bkr12T60PsXPTYNq3q8RqL3lKf3xOqGOkpI2f_Lew,16086
69
+ cherrypy_foundation/components/vendor/datatables-extensions/pdfmake/build/pdfmake.js,sha256=tWxs38Pdd_GXkjU5b4P0j4utKr8j91bD8iXFUsGqVio,2845715
70
+ cherrypy_foundation/components/vendor/datatables-extensions/pdfmake/build/pdfmake.min.js,sha256=wv06XiTbCWyRObt9Jmdl3kM7C4ZtA7o1bC702a4aU7c,1402214
71
+ cherrypy_foundation/components/vendor/datatables-extensions/pdfmake/build/vfs_fonts.js,sha256=IWRpaQNbz7JMY8T7QaG8iwgC0oYJ2NocHmiN_nEyfgs,830085
72
+ cherrypy_foundation/components/vendor/datatables-extensions/rowgroup/css/rowGroup.dataTables.css,sha256=K4Dq2bC0z84Xj-JDmL8X90byeEFThuu9LEWi5BD0998,1474
73
+ cherrypy_foundation/components/vendor/datatables-extensions/rowgroup/css/rowGroup.dataTables.min.css,sha256=6lFwbYpz191INby9Fz06KV_GDWQTTzQWqZZdau85DLE,1342
74
+ cherrypy_foundation/components/vendor/datatables-extensions/rowgroup/js/dataTables.rowGroup.js,sha256=gKwpsVAmKGaq7iFe9sgr5jZBBrCiqV2KtT-mtt9nBC4,10706
75
+ cherrypy_foundation/components/vendor/datatables-extensions/rowgroup/js/dataTables.rowGroup.min.js,sha256=0TG0u4_pa8sa0yTrgBPpaoOEjnZmuIzm8BJZgBW5bjk,4092
76
+ cherrypy_foundation/components/vendor/jquery/jquery.min.js,sha256=AzeKcltot5FBnYP0fxD_fKWBnH2dHa26nt0m7yzliP0,89037
77
+ cherrypy_foundation/components/vendor/multi/LICENSE,sha256=02vYQ2xQcf4Xtg820F4bWaBxZqJH22jgbV6rsDM8yKM,1055
78
+ cherrypy_foundation/components/vendor/multi/README.md,sha256=u0Co9XsZ1lKFdXc3ACjDZg0xIQrhNLLmhihV4cKgsLo,2858
79
+ cherrypy_foundation/components/vendor/multi/multi.css,sha256=v_SmEr-DJ253DfdGDeH5DaoQ_0W6qE-DXDNBJGooeCA,1862
80
+ cherrypy_foundation/components/vendor/multi/multi.js,sha256=asSr4J04djuWNcEm9-SUrtUgQfkyWEg1kvTgLLxso3o,9864
81
+ cherrypy_foundation/components/vendor/popper/popper.js,sha256=Y0NM43IuAu2ZN2YOPO-CdO11DkA77QeWgH38PRw_q_s,63070
82
+ cherrypy_foundation/components/vendor/popper/popper.min.js,sha256=whL0tQWoY1Ku1iskqPFvmZ-CHsvmRWx_PIoEvIeWh4I,20122
83
+ cherrypy_foundation/components/vendor/typeahead/jquery.typeahead.min.css,sha256=gBsvk2nlQnvCXdG7JITz1SrnqWQrO6EsUo_r06-KRtU,12464
84
+ cherrypy_foundation/components/vendor/typeahead/jquery.typeahead.min.js,sha256=eFBtgouYdW587kYINWsjkN-UR8GVWAG_fQe1fpJfjOw,47828
85
+ cherrypy_foundation/plugins/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
86
+ cherrypy_foundation/plugins/db.py,sha256=S2OqujZ-D_TxUM6NbQW7XGDt8eGDup1Wbhf0XCcYSbs,10108
87
+ cherrypy_foundation/plugins/ldap.py,sha256=Y0gUD5CcFaUAI7SSPIlrlr4IkQ1QePX2--qfZrIBlbo,9861
88
+ cherrypy_foundation/plugins/restapi.py,sha256=1W1mmVh-rIzg_mcFaNQZZXpqF7eN7VhRL9oTEiQOr-w,2843
89
+ cherrypy_foundation/plugins/scheduler.py,sha256=m2XLM7euRjC5bkU4NILvwnRo0w6NWRwmCI19iEiQlE0,10777
90
+ cherrypy_foundation/plugins/smtp.py,sha256=7qZv0VrQxi7gNoVdRds0F6Ya9pyo3LlZ12uFaVpAsms,7658
91
+ cherrypy_foundation/plugins/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
92
+ cherrypy_foundation/plugins/tests/test_db.py,sha256=r2kPdYJOu7mqnUBKrQDSkHamHJZhJibW-sxJl5o-MJs,3921
93
+ cherrypy_foundation/plugins/tests/test_ldap.py,sha256=NysUplX-E8k1IHWPPnJxiHwLdNhHqYUUU2ZDkfDx2s8,17269
94
+ cherrypy_foundation/plugins/tests/test_scheduler.py,sha256=uFLXKisV7lCSHKE-AurE7r6chxqcVm_OCQL8RrndH94,3564
95
+ cherrypy_foundation/plugins/tests/test_scheduler_db.py,sha256=_jw1usLhQlV0aoMbTtdJMBQypA5eSCWmOOsFvfM2zJQ,3101
96
+ cherrypy_foundation/plugins/tests/test_smtp.py,sha256=LYUXjDe8TtyruBSm18N73nSxHidBCIb1Om-9zeG56I4,5462
97
+ cherrypy_foundation/tests/__init__.py,sha256=bbdyalzM2mwBbId-7JBPXYuRzk7oUBCncq33ypD9v3Y,2818
98
+ cherrypy_foundation/tests/test_error_page.py,sha256=EmsCXYkFFMReNSORZYCo7qKvL2x98QgtKIlv1nFKIUU,2399
99
+ cherrypy_foundation/tests/test_flash.py,sha256=NNbT3XI1dHk0hXqJsWndCmPPohK9ig87ZYJaRNPJxR8,1994
100
+ cherrypy_foundation/tests/test_form.py,sha256=-2h38e00hWlYNJeVWrUB2V11UZ3x0FmTcsCez5vWoas,5542
101
+ cherrypy_foundation/tests/test_logging.py,sha256=Lg1yGwFHTSpGbPvNXBi9risypZziJlAOMi1DeennxRs,2623
102
+ cherrypy_foundation/tests/test_passwd.py,sha256=nGqJZYwRPziifLvf5rm3YifxAvIOFdU_6LkHaUvRk8w,1951
103
+ cherrypy_foundation/tests/test_sessions.py,sha256=_jcCn75hMGr7ETucWZnCqWcI3pw5PCdlzPQuxdE4yZE,2873
104
+ cherrypy_foundation/tests/test_url.py,sha256=sSNwK7KZJcrLtnf_XROYQAPQoYNO5lAsa2BjhFjgmws,6434
105
+ cherrypy_foundation/tests/templates/test_flash.html,sha256=b1S4I9v0n-Y1yoTUh2ZKNysR1NMrqv8ldvqONtmInzw,213
106
+ cherrypy_foundation/tests/templates/test_form.html,sha256=liubTm2q74-3hqQb4weaGJU3sq4vdq868GdVahBafSQ,333
107
+ cherrypy_foundation/tests/templates/test_url.html,sha256=xoyRIkIzzM8Q-M39i80P4j7Wo8Lkzh1rIzRq-40Szak,528
108
+ cherrypy_foundation/tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
109
+ cherrypy_foundation/tools/auth.py,sha256=WRXiZdRXJcd4uZFDb8DAGX-ySqiYytdWyjiQiLZb9Vo,9935
110
+ cherrypy_foundation/tools/auth_mfa.py,sha256=hDwfKc2zFY3bxOm1JRLLFQRXVPL9atBQ-PEwQTEQUww,9579
111
+ cherrypy_foundation/tools/i18n.py,sha256=f4m9fc2FKtcdUpXgnLXzhoipn4oLDuHY94Vv3KPSfp0,17126
112
+ cherrypy_foundation/tools/jinja2.py,sha256=hTiOepdb7kyDEqCK4NH2O-v1lrgPGNX4VV3AWZ-OsAc,5967
113
+ cherrypy_foundation/tools/ratelimit.py,sha256=C_bGzkx9waIJlpK-X6_SH8r1rP0I_xr0wLnGZhSEGEo,8742
114
+ cherrypy_foundation/tools/secure_headers.py,sha256=XqmjU5MCK8fTacQ2uTUiODYN4uaa9cCGfQJZVnp4J4g,3921
115
+ cherrypy_foundation/tools/sessions_timeout.py,sha256=M54IpRc3c4rUH0Cbri363O6GhD89EmzrjqvWeul8khc,7484
116
+ cherrypy_foundation/tools/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
117
+ cherrypy_foundation/tools/tests/test_auth.py,sha256=qQxCs8uCgu3C2Of9DRWplpCLLB7zSiJkrV4F9muLkJg,3414
118
+ cherrypy_foundation/tools/tests/test_auth_mfa.py,sha256=qYIlw4tDQUi9R7nPwph6UpMsThWDN1EYW-FrrOF_grQ,15111
119
+ cherrypy_foundation/tools/tests/test_i18n.py,sha256=6lHV3kxriRI5jo-YMnxzKKDFtLhogUrqK7D4X2-m42U,10758
120
+ cherrypy_foundation/tools/tests/test_jinja2.py,sha256=3r96jcm68Jtw_hGwpQOlT8Jao6upPSnwENaScluL-7E,5545
121
+ cherrypy_foundation/tools/tests/test_ratelimit.py,sha256=BZn2lhbuaVeIPq80eUn-SFu0mMN3Mb4ttwVoXbozWUA,3431
122
+ cherrypy_foundation/tools/tests/test_secure_headers.py,sha256=Iu3X7u6VJpWOmuNMv1qZFh0oPWdLZAdoJppRyuTV148,7769
123
+ cherrypy_foundation/tools/tests/components/Button.jinja,sha256=uSLp1GpEIgZNXK_GWglu0E_a1c3jHpDLI66MRfMqGhE,95
124
+ cherrypy_foundation/tools/tests/locales/messages.pot,sha256=5K9piTRL7H5MxDXFIWJsCccSJRA0HwfCQQU8b8VYo30,40
125
+ cherrypy_foundation/tools/tests/locales/de/LC_MESSAGES/messages.mo,sha256=bsJTVL4OefevkxeHDS3VcW3egP6Yq18LFXwjSyoqIng,336
126
+ cherrypy_foundation/tools/tests/locales/de/LC_MESSAGES/messages.po,sha256=glzYY96jmCaGyxYtMqmNF-1q-OYWXBIkMysvbXO4L6E,351
127
+ cherrypy_foundation/tools/tests/locales/fr/LC_MESSAGES/messages.mo,sha256=u3_kl_nqZ3FNaSyKVQKmu4KJzN3xOxxJNVmcdhw37jA,327
128
+ cherrypy_foundation/tools/tests/locales/fr/LC_MESSAGES/messages.po,sha256=6_Sk9Igqm7dtpyyS701p5qc4DvOJE7TRT0ajRZctFAQ,342
129
+ cherrypy_foundation/tools/tests/templates/test_jinja2.html,sha256=s1bHmy-lyf0YW0t-LOx3ugILV2kqFoBNYxziWgrZbo0,216
130
+ cherrypy_foundation/tools/tests/templates/test_jinjax.html,sha256=NImzIW0mUHxilFd61PSoxFC-yu1nayEVwv-5zlgD9yo,179
131
+ cherrypy_foundation/tools/tests/templates/test_jinjax_i18n.html,sha256=yre8j7HBjpTQZHpM0PuB3ASGD3O4vKkJ-y72Fm6STgY,771
132
+ cherrypy_foundation-1.0.0.dist-info/licenses/LICENSE.md,sha256=trSLYs5qlaow_bBwsLTRKpmTXsXzFksM_YUCMqrgAJQ,35149
133
+ cherrypy_foundation-1.0.0.dist-info/METADATA,sha256=MdVr55OyRUTYuG2Ly-LXBSf6e1zS7Jxb8n3GE2igpCA,3548
134
+ cherrypy_foundation-1.0.0.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
135
+ cherrypy_foundation-1.0.0.dist-info/top_level.txt,sha256=B1vQPTLYhpKJ6W0JkRCWyAf8RPcnwJWdYxixv75-4ew,20
136
+ cherrypy_foundation-1.0.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (80.10.2)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+